tensorflow1.8 c++ロードトレーニング済みモデルピット

6142 ワード

tensorflow c++の下で訓練した図とcheckpointをロードするコードは:
const std::string pathToGraph =  "./model/model.ckpt-29520.meta";
	const std::string checkpointPath = "./model/model.ckpt-29520";

	//gpu option
	tf::SessionOptions session_options;
	session_options.config.mutable_gpu_options()->set_allow_growth(true);

	tf::Session* m_sessionFaceNet = NewSession(session_options);

	// Read in the protobuf graph we exported
	tf::MetaGraphDef graph_def;
	tf::Status m_statusFaceNet = ReadBinaryProto(tf::Env::Default(), pathToGraph, &graph_def);
	if (!m_statusFaceNet.ok())
	{
		//throw std::runtime_error("Error reading graph definition from " + pathToGraph + ": " + m_statusFaceNet.ToString());
		return 0;
	}
	// Add the graph to the session
	m_statusFaceNet = m_sessionFaceNet->Create(graph_def.graph_def());

	// Read weights from the saved checkpoint
	tf::Tensor checkpointPathTensor(tf::DT_STRING, tf::TensorShape());
	checkpointPathTensor.scalar<:string>()() = checkpointPath;
	m_statusFaceNet = m_sessionFaceNet->Run(
	{ { graph_def.saver_def().filename_tensor_name(), checkpointPathTensor }, },
	{},
	{ graph_def.saver_def().restore_op_name() },
		nullptr);

tensorflow 1.2上記のコードは正常に動作していますが、動作の必要性からtensorflowを最近1.8.0にアップグレードし、lib、dllを再コンパイルした後、上記のコードを実行すると、次の2つのリンクバグが発生しました.
error LNK 2001:解析できない外部シンボル「class tensorflow::GraphDefaultTypeInternal tensorflow:_GraphDef_default_instance_」(?_GraphDef_default_instance_@tensorflow@@3VGraphDefDefaultTypeInternal@1@A)
main.obj:error LNK 2001:解析できない外部シンボル「class tensorflow::S a v e r D e f D e f A r t y peInternal tensorflow:_SaverDef_default_instance_」(?_SaverDef_default_instance_@tensorflow@@3VSaverDefDefaultTypeInternal@1@A)
いろいろな方法で振り回した後、解決策を見つけました.修正したコードは:
const std::string pathToGraph =  "./model/model.ckpt-29520.meta";
    const std::string checkpointPath = "./model/model.ckpt-29520";

    //gpu option
    tf::SessionOptions session_options;
    session_options.config.mutable_gpu_options()->set_allow_growth(true);


    /*std::unique_ptr<:session> m_sessionFaceNet;
    Status load_graph_status = LoadGraph(pathToFrozen, &m_sessionFaceNet);
    tf::Status m_statusFaceNet;*/

    tf::Session* m_sessionFaceNet = NewSession(session_options);

    // Read in the protobuf graph we exported
    tf::MetaGraphDef graph_def;
    tf::Status m_statusFaceNet = ReadBinaryProto(tf::Env::Default(), pathToGraph, &graph_def);
    if (!m_statusFaceNet.ok())
    {
        //throw std::runtime_error("Error reading graph definition from " + pathToGraph + ": " + m_statusFaceNet.ToString());
        return 0;
    }
    // Add the graph to the session
    m_statusFaceNet = m_sessionFaceNet->Create(*(graph_def.mutable_graph_def()));

    // Read weights from the saved checkpoint
    tf::Tensor checkpointPathTensor(tf::DT_STRING, tf::TensorShape());
    checkpointPathTensor.scalar<:string>()() = checkpointPath;
    m_statusFaceNet = m_sessionFaceNet->Run(
    { { graph_def.mutable_saver_def()->filename_tensor_name(), checkpointPathTensor }, },
    {},
    { graph_def.mutable_saver_def()->restore_op_name() },
        nullptr); { graph_def.mutable_saver_def()->filename_tensor_name(), checkpointPathTensor }, },
    {},
    { graph_def.mutable_saver_def()->restore_op_name() },
        nullptr);

主要的修改是修改了graph_def函数为mutable_graph_def(),修改saver_def()为mutable_saver_def()。误打误撞解决了问题,原理不理解,后续有时间还要分析tensorflow底层函数。

 

另一个要注意的问题是:

cv::Mat转换为tensorflow::Tensor时,要注意转换的数据格式和模型要求的数据格式一致

两种转换方式:

tf::Tensor input_tensor(tf::DT_FLOAT, tf::TensorShape({ nPersonNum,112,112,1}));

cv::Mat flaotMat;
resizeImg.convertTo(flaotMat, CV_32FC1);

tf::StringPiece tmp_data = input_tensor.tensor_data();
	memcpy(const_cast(tmp_data.data()), (flaotMat.data), flaotMat.rows * flaotMat.cols * sizeof(tf::DT_FLOAT));

別の変換方法の階調図:
//                  ,     32F
resizeImg.convertTo(flaotMat, CV_32FC1);

for (int nTensor = 0; nTensor < nPersonNum; nTensor++)
	{
		const float * source_data = (float*)tmpVecWhitenImages[nTensor].data;
		for (int y = 0; y < tmpVecWhitenImages[nTensor].rows; ++y)
		{
			const float* source_row = source_data + (y * tmpVecWhitenImages[nTensor].cols);
			for (int x = 0; x < tmpVecWhitenImages[nTensor].cols; ++x)
			{
				const float* source_pixel = source_row + x;
				for (int c = 0; c < 1; ++c)
				{
					const float* source_value = source_pixel;
					input_tensor_mapped(nTensor, y, x, c) = *source_value;
				}
			}
		}
	}

 
 
別の変換方式のRGB画像:
 
 
//                  ,     64F
matImgByTF.convertTo(Image2, CV_64FC3);

tf::Tensor input_tensor(tf::DT_FLOAT, tf::TensorShape({ nPersonNum,m_pFaceDescriber->m_nFaceImgWidth,m_pFaceDescriber->m_nFaceImgHeight,m_pFaceDescriber->m_nFaceImgDepth }));
        auto input_tensor_mapped = input_tensor.tensor();

//double*
for (int nTensor = 0; nTensor < nPersonNum; nTensor++)
		{
			const double * source_data = (double*)tmpVecWhitenImages[nTensor].data;
			for (int y = 0; y < tmpVecWhitenImages[nTensor].rows; ++y)
			{
				const double* source_row = source_data + (y * tmpVecWhitenImages[nTensor].cols * m_pFaceDescriber->m_nFaceImgDepth);
				for (int x = 0; x < tmpVecWhitenImages[nTensor].cols; ++x)
				{
					const double* source_pixel = source_row + (x * m_pFaceDescriber->m_nFaceImgDepth);
					for (int c = 0; c < m_pFaceDescriber->m_nFaceImgDepth; ++c)
					{
						const double* source_value = source_pixel + (2 - c);//RGB->BGR
						input_tensor_mapped(nTensor, y, x, c) = *source_value;
					}
				}
			}
		}

 
残された問題:
 
metaとckptを凍結する得ることができる.pbファイルですが、自分で凍結したモデルの実行結果と元のmeta、ckptの実行結果が一致しません.図面を凍結したときにパラメータの設定が不合理な可能性があります.この問題は後で解決します.
 
しばらく記録して、後で詳しく整理する時間があって、もし間違いがあれば、批判の指摘を歓迎します.