【发布时间】:2017-06-05 15:45:08
【问题描述】:
我通过Tensorflow for Poets 教程重新训练了一个 InceptionV3 模型,并且可以成功地在我训练的数据和新数据上运行 label_image.py 并获得准确的正确标签。太棒了!
如果我通过我的 Mac Obj-C++ 应用程序运行我的模型,我得到的标签会大不相同。
例如 - 我的训练是对视频帧的“镜头类型”进行分类(超近、近、中、长、超长),以对视频编辑内容进行分类。
label_image.py 将视频中的帧分类为 85% 的可能特写。 我的 C++ / Obj-C 应用程序以相同的帧运行,将其归类为 Extreme Long,占 60%
两者都在使用 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 贡献示例中借用的代码将 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;
}
}
我的会话创建代码:
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,
};
我试图研究张量排序 (NHWC),并检查了张量创建代码,但我可能遗漏了一些对其他人来说显而易见的东西。我也尝试过更改频道顺序,但无济于事。
任何见解都会非常有帮助。谢谢!
【问题讨论】:
标签: python c++ opencv machine-learning tensorflow