python - 如何使用opencv dnn模型加载张量流的预训练模型
问题描述
readNetFromTensorflow 函数无法加载 tensorflow 预训练模型 (.pb)。
第一步:训练张量流的模型。线性回归代码的Tensorflow模型如下:
#!/usr/bin/python
import tensorflow as tf
import numpy as np
x_ = tf.placeholder(np.float32, [None, 1], 'input')
y_ = tf.placeholder(np.float32, [None, 1], 'label')
#layer1
w1 = tf.Variable(tf.random_normal([1,3]))
b1 = tf.Variable(tf.random_normal([3]) )
a1 = tf.add(b1,tf.matmul(x_,w1))
#layer2
w2 = tf.Variable(tf.random_normal([3,1]))
b2 = tf.Variable(tf.random_normal([1]) )
a2 = tf.add(b2,tf.matmul(a1,w2),name="output")
#global steps
steps = 5000
x = []
y = []
for i in range(1,200,5):
temp = (1.0 * i)/10
x.append([temp])
y.append([3. + 2. * temp])
x = np.array(x)
y = np.array(y)
#loss function
loss = tf.reduce_mean(tf.reduce_sum(tf.square(a2-y_)))
#optimizer
optimizer = tf.train.GradientDescentOptimizer(0.00001).minimize(loss)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
length = len(x)
#training...
for i in range(steps):
sess.run(optimizer,feed_dict={x_:x,y_:y})
result = sess.run(loss,feed_dict={x_:x,y_:y})
if i % 50 == 0:
print("loss: ",result,"\tstep: ",i)
saver = tf.train.Saver()
saver.save(sess,"./model/model.ckpt")
tf.train.write_graph(sess.graph.as_graph_def(), "./model/", "graph.pbtxt")
print("predict...")
pre = sess.run(a2,feed_dict={x_:[[0]]})
print("x = 2 pre: ",pre)
第二步:将模型保存为tensorflow的.pb文件。怎么做?
步骤 3:使用 C++ 的 opencv3.4.1 的 readNetFromTensorflow 函数加载 .pb 文件。像这样的代码:
#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
using namespace dnn;
std::vector<std::string> classes;
int main(int argc,char**argv)
{
if(argc != 2)
{
cout<<"Usage: ./main [tensorflow modle path(.pb)]"<<endl;
return -1;
}
String model = argv[1];
Net net = cv::dnn::readNetFromTensorflow(model,argv[2]);
cout<<"load Net OK!!"<<endl;
float inp[1*1] = {2};
Mat Matrix(1,1,CV_32FC1,inp);
cout<<"Matrix:\n"<<Matrix<<endl;
net.setInput(Matrix);
Mat output = net.forward();
cout<<"output: " << output <<endl;
return 0;
}
结果应该是 7。有两个问题。一是如何生成训练好的模型的完整.pb文件,二是如何将opencv3.4.1 dnn中的预训练模型与C++一起使用?
解决方案
我发现了这个程序发生了什么。问题出现在第 2 步。必须使用 tensorflow 函数 convert_variables_to_constants 将默认图转换为新图。然后使用 tf.train.write_graph 可以完全保存旧的预训练模型。最后只需修改第2步中的代码,预训练好的模型就可以加载成功了。步骤2的新代码如下:
#!/usr/bin/python
import tensorflow as tf
import numpy as np
x_ = tf.placeholder(np.float32, [None, 1], 'input')
y_ = tf.placeholder(np.float32, [None, 1], 'label')
#layer1
a1 = tf.layers.dense(input=x_,units=3,name="layer1")
#layer2
a2 = tf.layers.dense(input=x_,units=1,name="layer2")
#global steps
steps = 5000
x = []
y = []
for i in range(1,200,5):
temp = (1.0 * i)/10
x.append([temp])
y.append([3. + 2. * temp])
x = np.array(x)
y = np.array(y)
#loss function
loss = tf.reduce_mean(tf.reduce_sum(tf.square(a2-y_)))
#optimizer
optimizer = tf.train.GradientDescentOptimizer(0.00001).minimize(loss)
with tf.Session() as sess:
sess.run(tf.global_variables_initializer())
length = len(x)
#training...
for i in range(steps):
sess.run(optimizer,feed_dict={x_:x,y_:y})
result = sess.run(loss,feed_dict={x_:x,y_:y})
if i % 50 == 0:
print("loss: ",result,"\tstep: ",i)
#save the .pbtxt file of the pre-trained model.
tf.train.write_graph(sess.graph.as_graph_def(), "./model/",
#transfrom default graph and save as a new graph.
# the param 'output_node_names' should be the last op's name in the pre-trained model. In this model, last op's name is "layer2/BiasAdd" that found in the .pbtxt file like this:
#node{
# name: "layer2/BiasAdd"
# op: "BiasAdd"
# .....
output_graph_def = tf.graph_util.convert_variables_to_constants(sess,sess.graph_def,output_node_names=['layer2/BiasAdd'])
tf.train.write_graph(output_graph_def, "./model/", "graph.pbtxt",as_txt = False)
print("predict...")
pre = sess.run(a2,feed_dict={x_:[[0]]})
print("x = 2 pre: ",pre)
C++ 代码与上面的代码几乎相同:
#include <fstream>
#include <sstream>
#include <iostream>
#include <opencv2/dnn.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
using namespace std;
using namespace cv;
using namespace dnn;
std::vector<std::string> classes;
int main(int argc,char**argv)
{
if(argc != 2)
{
cout<<"Usage: ./main [tensorflow modle path(.pb)]"<<endl;
return -1;
}
String model = argv[1];
Net net = cv::dnn::readNetFromTensorflow(model,argv[2]);
if(net.empty())
{
cout<<"load Net failed"<<endl;
return -1;
}
cout<<"load Net OK!!"<<endl;
float inp[1*1] = {0};
Mat Matrix(1,1,CV_32FC1,inp);
cout<<"Matrix:\n"<<Matrix<<endl;
net.setInput(Matrix);
Mat output = net.forward();
#the value of the output should be equal to the output of the Step 1.
cout<<"output: " << output <<endl;
return 0;
}
另外,当我使用 w1、b1 和 w2、b2 而不是 tf.layers.dense 构建网络时,出现了一个我现在不明白的错误:
Error: Unspecified error (More than one input is Const op) in getConstBlob, file /home/wy/Downloads/opencv 3.4.1/modules/dnn/src/tensorflow/tf_importer.cpp, line 571
例外:OpenCV(3.4.1)/home/wy/Downloads/opencv-3.4.1/modules/dnn/src/tensorflow/tf_importer.cpp:571:错误:(-2)多个输入是函数中的Const op getConstBlob
推荐阅读
- powershell - 如何使用 powershell 将焦点放在模式对话框上?
- python - 如何签出和合并分支到 master - GITPYTHON
- reporting-services - SSRS:使用来自用户的输入并将其传递给子报表
- azure-ad-graph-api - graph.microsoft.com/v1.0/me/calendars 上的 400 InvalidAuthenticationToken
- postgresql - 如何获得一个月中某一天的下一个日期
- python - 如何抓取具有交替行的网站?
- python - 如何在换行符处从文本文件中拆分文本?
- javascript - 如何在先前的更改事件触发并将动态选项加载到该选择框后更改选择框的值
- java - 在按钮单击时向 UI 添加内容
- windows - 我应该安装什么,除了 Visual Studio 本身,Microsoft.Common.props 出现在 c:\Program Files (x86)\MSBuild\14.0\ 下?