c++opencv調用tensorflow模型(以mnist爲例)
0. 環境
win10 + vs2019 + opencv(OpenCV_VERSION 3.4.6) + keras(tensorflow後端)
1. 準備數據
從http://yann.lecun.com/exdb/mnist/下載
“data/t10k-labels-idx1-ubyte.gz”;
“data/t10k-images-idx3-ubyte.gz”;
“data/train-labels-idx1-ubyte.gz”;
“data/train-images-idx3-ubyte.gz”;
用解壓文件直接解壓爲以下文件
“data/t10k-labels-idx1-ubyte”;
“data/t10k-images-idx3-ubyte”;
“data/train-labels-idx1-ubyte”;
“data/train-images-idx3-ubyte”;
2. 讀取mnist文件
使用C++和OpenCV讀取MNIST文件[https://blog.csdn.net/sheng_ai/article/details/23267039]
(代碼可以直接使用)
3. python下使用keras生成tensorflow pb模型
#%%
from keras.datasets import mnist
from keras.models import Model
from keras.layers import Conv2D, MaxPool2D, ReLU, Input, Softmax, Reshape
from keras import backend as K
import tensorflow as tf
#%%
tf.reset_default_graph()
#%%
def net(input_size, optimizer):
input_x = Input(input_size, name="x")
conv1 = Conv2D(20, 5, padding = 'same', kernel_initializer = 'he_normal')(input_x)
pool1 = MaxPool2D(2)(conv1)
relu1 = ReLU()(pool1)
conv2 = Conv2D(50, 5, padding = 'same', kernel_initializer = 'he_normal')(relu1)
pool2 = MaxPool2D(2)(conv2)
relu2 = ReLU()(pool2)
conv3 = Conv2D(10, 5, padding = 'same', kernel_initializer = 'he_normal')(relu2)
pool3 = MaxPool2D(7)(conv3)
out = Reshape([10])(pool3)
out = Softmax(name="output")(out)
model = Model(inputs=input_x, outputs = out)
model.compile(
optimizer=optimizer,
loss = "categorical_crossentropy",
metrics=["accuracy"]
)
return model
(train_x, train_y), (test_x, test_y) = mnist.load_data()
train_x = train_x.reshape(train_x.shape[0], 28, 28, 1) / 255
test_x = test_x.reshape(test_x.shape[0], 28, 28, 1) / 255
train_y = np_utils.to_categorical(train_y, num_classes=10)
test_y = np_utils.to_categorical(test_y, num_classes=10)
rmsprop = keras.optimizers.RMSprop(lr=0.001, rho=0.9, epsilon=1e-08, decay=0.0)
model = net([28, 28, 1], rmsprop)
#%%
print(model.summary())
#%%
print("Training --------------")
model.fit(train_x, train_y, epochs=4, batch_size=32)
print("Testing --------------")
loss, accuracy = model.evaluate(test_x, test_y)
print("test loss: ", loss)
print("test accuracy: ", accuracy)
# 查看所有節點
# tensor_name_list = [tensor.name for tensor in tf.get_default_graph().as_graph_def().node]
# print(tensor_name_list)
#%%
# 輸出Pb模型
sess = K.get_session()
frozen_graph = tf.compat.v1.graph_util.convert_variables_to_constants(
sess,
sess.graph_def,
output_node_names=["output/Softmax"]
)
tf.train.write_graph(frozen_graph, "log/1.2", "mnist.pb", as_text=False)
輸出結果爲:
Epoch 1/4
60000/60000 [==============================] - 13s 216us/step - loss: 0.2229 - acc: 0.9322
Epoch 2/4
60000/60000 [==============================] - 10s 167us/step - loss: 0.0754 - acc: 0.9767
Epoch 3/4
60000/60000 [==============================] - 10s 167us/step - loss: 0.0550 - acc: 0.9828
Epoch 4/4
60000/60000 [==============================] - 10s 168us/step - loss: 0.0450 - acc: 0.9859
Testing --------------
10000/10000 [==============================] - 1s 62us/step
test loss: 0.05498976424507564
test accuracy: 0.9838
4. c++ + opencv讀取pb模型, 驗證測試集
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
#include <opencv2/opencv.hpp>
#include "MNIST.h"
std::vector<int> Argmax(cv::Mat x)
{
std::vector<int> res;
for (int i = 0; i < x.rows; i++)
{
int maxIdx = 0;
float maxNum = 0.0;
for (int j = 0; j < x.cols; j++)
{
float tmp = x.at<float>(i, j);
if (tmp > maxNum)
{
maxIdx = j;
maxNum = tmp;
}
}
res.push_back(maxIdx);
}
return res;
}
float Accuracy(cv::Mat x, cv::Mat y, std::string pbfile)
{
float count = 0.0;
cv::dnn::Net net = cv::dnn::readNetFromTensorflow(pbfile);
// blob輸入時需要至少dims爲3的數據, 其數據形狀爲(圖片數目, 寬度, 高度)
int size[] = { x.rows, 28, 28 };
cv::Mat imgs = cv::Mat(3, size, CV_8UC1, x.data);
cv::Mat blob = cv::dnn::blobFromImages(imgs, 1.0 / 255.0, cv::Size(28, 28), cv::Scalar(), false, false);
net.setInput(blob);
cv::Mat pred = net.forward();
std::vector<int> res = Argmax(pred);
for (int i = 0; i < res.size(); i++)
{
if (*(y.ptr<int>(0) + i) == res[i])
{
count = count + 1;
}
}
return count / x.rows;
}
int main()
{
std::string testLableFile = "data/t10k-labels-idx1-ubyte";
std::string testImageFile = "data/t10k-images-idx3-ubyte";
std::string trainLableFile = "data/train-labels-idx1-ubyte";
std::string trainImageFile = "data/train-images-idx3-ubyte";
cv::Mat trainY = ReadLabels(trainLableFile);
cv::Mat testY = ReadLabels(testLableFile);
cv::Mat trainX = ReadImages(trainImageFile);
cv::Mat testX = ReadImages(testImageFile);
testY.convertTo(testY, CV_32SC1);
std::string pbfile = "mnist.pb";
//testX.convertTo(testX, CV_32FC1, 1.0/255.0, 0);
float acc = Accuracy(testX, testY, pbfile);
std::cout << acc;
return 0;
}
控制檯輸出爲:
[ INFO:0] Initialize OpenCL runtime...
0.9838