C++ 手写数字识别:使用卷积神经网络和 TensorFlow
以下是一个使用卷积神经网络识别手写数字的 C++ 代码示例,代码使用了 OpenCV 库和 TensorFlow 库。
#include <iostream>
#include <fstream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <tensorflow/core/public/session.h>
#include <tensorflow/core/framework/tensor.h>
#include <tensorflow/core/platform/env.h>
using namespace std;
using namespace cv;
using namespace tensorflow;
int main()
{
// 读取手写数字图片
Mat image = imread('digit.png', IMREAD_GRAYSCALE);
resize(image, image, Size(28, 28));
// 转换为 TensorFlow 格式
Tensor input_tensor(DT_FLOAT, TensorShape({1, 28, 28, 1}));
auto input_tensor_mapped = input_tensor.tensor<float, 4>();
for (int i = 0; i < 28; i++) {
for (int j = 0; j < 28; j++) {
input_tensor_mapped(0, i, j, 0) = (255 - image.at<uchar>(i, j)) / 255.0;
}
}
// 加载模型
Session* session;
Status status = NewSession(SessionOptions(), &session);
if (!status.ok()) {
cerr << 'Failed to create session: ' << status.ToString() << endl;
return -1;
}
GraphDef graph_def;
status = ReadBinaryProto(Env::Default(), 'model.pb', &graph_def);
if (!status.ok()) {
cerr << 'Failed to read protobuf: ' << status.ToString() << endl;
return -1;
}
status = session->Create(graph_def);
if (!status.ok()) {
cerr << 'Failed to create graph: ' << status.ToString() << endl;
return -1;
}
// 运行模型
vector<Tensor> outputs;
status = session->Run({{'conv2d_input:0', input_tensor}}, {{'dense_2/Softmax:0'}}, {}, &outputs);
if (!status.ok()) {
cerr << 'Failed to run model: ' << status.ToString() << endl;
return -1;
}
// 输出结果
auto output_tensor_mapped = outputs[0].tensor<float, 2>();
int prediction = 0;
float max_prob = 0;
for (int i = 0; i < 10; i++) {
if (output_tensor_mapped(0, i) > max_prob) {
max_prob = output_tensor_mapped(0, i);
prediction = i;
}
}
cout << 'The digit is ' << prediction << endl;
return 0;
}
代码中的模型是一个简单的卷积神经网络,包含两个卷积层和两个全连接层。模型的结构如下所示:
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 26, 26, 32) 320
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 13, 13, 32) 0
_________________________________________________________________
conv2d_1 (Conv2D) (None, 11, 11, 64) 18496
_________________________________________________________________
max_pooling2d_1 (MaxPooling2 (None, 5, 5, 64) 0
_________________________________________________________________
flatten (Flatten) (None, 1600) 0
_________________________________________________________________
dense (Dense) (None, 128) 204928
_________________________________________________________________
dropout (Dropout) (None, 128) 0
_________________________________________________________________
dense_1 (Dense) (None, 64) 8256
_________________________________________________________________
dropout_1 (Dropout) (None, 64) 0
_________________________________________________________________
dense_2 (Dense) (None, 10) 650
=================================================================
Total params: 232,650
Trainable params: 232,650
Non-trainable params: 0
代码的主要流程如下:
- 读取手写数字图片,将其转换为 TensorFlow 格式。
- 加载模型,读取模型文件(.pb)并创建 Session。
- 运行模型,将输入 Tensor 输入到模型中并得到输出 Tensor。
- 输出结果,找到输出 Tensor 中概率最高的数字。
代码中的关键部分是将图片转换为 TensorFlow 格式和运行模型,这里我们做一些详细解释。
第一步,我们将图片转换为 TensorFlow 格式。TensorFlow 要求输入的数据必须是 Tensor 格式,而且还需要指定其大小和数据类型。这里我们使用了 TensorFlow 提供的 Tensor 类来创建输入 Tensor,其大小为 1x28x28x1(即一张 28x28 的灰度图像),数据类型为 float。然后我们遍历图片的每个像素,将像素值(0~255)归一化到 0~1 之间,并将其赋值给 Tensor 的对应位置。
第二步,我们加载模型并创建 Session。模型文件是一个 protobuf 文件,其中包含了卷积神经网络的结构和参数。我们使用 TensorFlow 提供的 ReadBinaryProto 函数读取模型文件,并使用 Session 的 Create 函数创建 Session。
第三步,我们运行模型并得到输出 Tensor。Session 的 Run 函数可以接收输入 Tensor 和输出 Tensor 的名字,并将输入 Tensor 输入到模型中,得到输出 Tensor。这里我们使用了模型的最后一层的 Softmax 输出作为预测结果。
第四步,我们输出结果。输出 Tensor 是一个大小为 1x10 的 Tensor,每个位置表示对应数字的概率。我们遍历这个 Tensor,找到概率最高的数字作为预测结果。
希望这份代码示例能帮助你理解如何使用 C++、OpenCV 和 TensorFlow 实现一个手写数字识别系统。
原文地址: https://www.cveoy.top/t/topic/oZbH 著作权归作者所有。请勿转载和采集!