在C+中运行Tensorflow分类器模型+/Obj-C++;结果与Python的结果不同

在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> 两者都在使用

我通过教程对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,如下所示:

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,
              };