在C+中运行Tensorflow分类器模型+/Obj-C++;结果与Python的结果不同
我通过教程对InceptionV3模型进行了再培训,能够在我的培训数据和新数据上成功运行label_image.py,并获得准确的正确标签。太棒了 如果我通过我的Mac Obj-C++应用程序运行我的模型,我得到的标签会大不相同 例如,我的培训是对视频帧的“快照类型”进行分类(极端特写、特写、中等、长、极端长),以便对视频编辑内容进行分类 label_image.py将视频中的帧分类为85%可能的特写镜头。 我的C++ /Obj-C应用程序运行在同一帧上,将其分类为“60%”/P> 两者都在使用AVX/SIMD/FMA优化编译的Mac OS X CPU上运行相同版本的Tensorflow(1.1) 我的应用程序管道: 我有一个BGR订购的OpenCV Mat图像,我可以在其他地方成功使用,并从中获得合理的结果。我从映射到BGRA CV Mat的OS X CVPixelBufferRef创建此CV Mat,如下所示:在C+中运行Tensorflow分类器模型+/Obj-C++;结果与Python的结果不同,python,c++,opencv,machine-learning,tensorflow,Python,C++,Opencv,Machine Learning,Tensorflow,我通过教程对InceptionV3模型进行了再培训,能够在我的培训数据和新数据上成功运行label_image.py,并获得准确的正确标签。太棒了 如果我通过我的Mac Obj-C++应用程序运行我的模型,我得到的标签会大不相同 例如,我的培训是对视频帧的“快照类型”进行分类(极端特写、特写、中等、长、极端长),以便对视频编辑内容进行分类 label_image.py将视频中的帧分类为85%可能的特写镜头。 我的C++ /Obj-C应用程序运行在同一帧上,将其分类为“60%”/P> 两者都在使用
cv::cvtColor(BGRAImage, frameMat, cv::COLOR_BGRA2BGR);
我通过从iOS contrib示例中借用的代码将BGR CV Mat(名为frameMat)输入到张量中,如下所示:
void* baseAddress = (void*)frameMat.datastart;
size_t width = (size_t) frameMat.cols;
size_t height = (size_t) frameMat.rows;
size_t bytesPerRow = (size_t) frameMat.cols * 3; // (BGR)
const int wanted_input_width = 299;
const int wanted_input_height = 299;
const int wanted_input_channels = 3;
const float input_mean = 128.0f;
const float input_std = 128.0f;
resized_tensor = tensorflow::Tensor( tensorflow::DT_FLOAT, tensorflow::TensorShape({1, wanted_input_height, wanted_input_width, wanted_input_channels}));
auto image_tensor_mapped = resized_tensor.tensor<float, 4>();
tensorflow::uint8 *in = sourceStartAddr;
float *out = image_tensor_mapped.data();
for (int y = 0; y < wanted_input_height; ++y)
{
float *out_row = out + (y * wanted_input_width * wanted_input_channels);
for (int x = 0; x < wanted_input_width; ++x)
{
const int in_x = (y * (int)width) / wanted_input_width;
const int in_y = (x * image_height) / wanted_input_height;
tensorflow::uint8 *in_pixel = in + (in_y * width * (image_channels)) + (in_x * (image_channels));
float *out_pixel = out_row + (x * wanted_input_channels);
// Interestingly the iOS example uses BGRA and DOES NOT re-order tensor channels to RGB <-> BGR
// Matching that.
out_pixel[0] = ((float)in_pixel[0] - (float)input_mean) / (float)input_std;
out_pixel[1] = ((float)in_pixel[1] - (float)input_mean) / (float)input_std;
out_pixel[2] = ((float)in_pixel[2] - (float)input_mean) / (float)input_std;
}
}
并拉出标签/特征向量(倒数第二层)
NSMutableArray*outputLabels=[NSMutableArray阵列容量:self.labelArray.count];
NSMutableArray*outputScores=[NSMutableArray阵列容量:self.labelArray.count];
//1=标签和分数
自动预测=输出[1]。平坦();
对于(int index=0;index
我试图研究张量排序(NHWC),并检查了张量创建代码,但我可能遗漏了一些其他人显而易见的东西。我也试过改变频道顺序,但没有成功
任何洞察都会大有裨益。谢谢大家! 我调试此类问题的常用方法是:
- 首先从我知道有效的示例输入中保存一个原始的C值数组。例如,确保label_image适用于新训练的模型,然后使用如下伪代码写出从
获得的浮点*数组:input_layer->flat().data()
float*input_data=input_layer->flat().data();
int input_data_count=input_layer->PLAT().size();
printf(“浮点g_测试_输入[]={\n”);
对于(int i=0;i
- 您应该得到一个大数组,可以将其复制到新代码中。覆盖要测试的代码中的任何输入。现在运行它,您将看到与从label_图像中看到的相同的输出。如果你不知道,你知道你正在加载的模型有些不同。如果输出是相同的,那么您就知道输入预处理是不同的
- 假设预处理出错,我的下一步是尝试从磁盘加载图像。iOS示例代码在简单示例中实现了这一点。将一些预期输入保存到图像文件中,然后确保label_image和代码产生相同的结果
- 首先从我知道有效的示例输入中保存一个原始的C值数组。例如,确保label_image适用于新训练的模型,然后使用如下伪代码写出从
获得的浮点*数组:input_layer->flat().data()
float*input_data=input_layer->flat().data();
int input_data_count=input_layer->PLAT().size();
printf(“浮点g_测试_输入[]={\n”);
对于(int i=0;i
- 您应该得到一个大数组,可以将其复制到新代码中。覆盖要测试的代码中的任何输入。现在运行它,您将看到与从label_图像中看到的相同的输出。如果你不知道,你知道你正在加载的模型有些不同。如果输出是相同的,那么您就知道输入预处理是不同的
- 假设预处理出错,我的下一步是尝试从磁盘加载图像。iOS示例代码在简单示例中实现了这一点。将一些预期输入保存到图像文件中,然后确保label_image和代码产生相同的结果 所以这个问题很棘手 我没有提到我在重新训练的图形上运行graph_transform工具,并且正在运行
tensorflow::Status load_graph_status = ReadBinaryProto(tensorflow::Env::Default(), [inception2015GraphPath cStringUsingEncoding:NSUTF8StringEncoding], &inceptionGraphDef);
if (load_graph_status.ok())
{
tensorflow::SessionOptions options;
inceptionSession = std::unique_ptr<tensorflow::Session>(tensorflow::NewSession(options));
tensorflow::Status session_create_status = inceptionSession->Create(inceptionGraphDef);
}
tensorflow::Status run_status = inceptionSession->Run({ {input_layer, resized_tensor} }, {feature_layer, final_layer}, {}, &outputs);
NSMutableArray* outputLabels = [NSMutableArray arrayWithCapacity:self.labelsArray.count];
NSMutableArray* outputScores = [NSMutableArray arrayWithCapacity:self.labelsArray.count];
// 1 = labels and scores
auto predictions = outputs[1].flat<float>();
for (int index = 0; index < predictions.size(); index += 1)
{
const float predictionValue = predictions(index);
NSString* labelKey = self.labelsArray[index % predictions.size()];
NSNumber* currentLabelScore = self.averageLabelScores[labelKey];
NSNumber* incrementedScore = @([currentLabelScore floatValue] + predictionValue );
self.averageLabelScores[labelKey] = incrementedScore;
[outputLabels addObject:labelKey];
[outputScores addObject:@(predictionValue)];
}
// 0 is feature vector
tensorflow::Tensor feature = outputs[0];
int64_t numElements = feature.NumElements();
tensorflow::TTypes<float>::Flat featureVec = feature.flat<float>();
NSMutableArray* featureElements = [NSMutableArray arrayWithCapacity:numElements];
for(int i = 0; i < numElements; i++)
{
[featureElements addObject:@( featureVec(i) ) ];
}
if(self.averageFeatureVec == nil)
{
self.averageFeatureVec = featureElements;
}
else
{
// average each vector element with the prior
for(int i = 0; i < featureElements.count; i++)
{
float a = [featureElements[i] floatValue];
float b = [self.averageFeatureVec[i] floatValue];
self.averageFeatureVec[i] = @( MAX(a,b)) ;
}
}
return @{ kSynopsisStandardMetadataFeatureVectorDictKey : featureElements ,
@"Labels" : outputLabels,
@"Scores" : outputScores,
};