简介
对于深度学习,一般使用PYTHON接口的Pytorch或其他库,但由于本人一直使用C++语言,所以打算通过C++接口的Libtorch来搭建神经网络。下面是通过对比网上的一个Pytorch简单的线性网络例子实现的一个拟合代码。
1.神经网络的创建:
class myNet :public torch::nn::Module {
public:
myNet(int64_t n_feature, int64_t n_hidden, int64_t n_output) {
hidden = register_module("hidden", torch::nn::Linear(torch::nn::LinearOptions(n_feature, n_hidden)));
predict = register_module("predict", torch::nn::Linear(torch::nn::LinearOptions(n_hidden, n_output)));
}
//向前传播,即平差中的误差方程的构建
torch::Tensor forward(torch::Tensor x)
{
x = torch::relu(hidden->forward(x));
x = predict->forward(x);
return x;
}
torch::nn::Linear hidden{ nullptr };
torch::nn::Linear predict{ nullptr };
};
2.训练数据的创建
X与Y符合的关系为下式,其中b具有偶然误差,以此生成训练数据。
//训练的数据创建
torch::Tensor x = torch::unsqueeze(torch::linspace(-1, 1, 100), 1);
auto y = x.pow(2) + 0.2 * torch::rand(x.sizes());
3.训练,模型的生成
QVector<double> xNum, yNum; //loss的容器
// 生成模型
auto net = std::make_shared<myNet>(1, 1000, 1);
torch::optim::SGD optimizer(net->parameters(), 0.01);
for (int i = 0; i < 1000; i++)
{
auto prediction = net->forward(x);
auto loss = torch::mse_loss(prediction, y);
optimizer.zero_grad();
loss.backward();
optimizer.step();
if (i % 10 == 0)
{
// std::cout << "" << loss.item<float>();
xNum.append(i);
yNum.append(loss.item<float>());
}
}
//保存模型
// torch::save(net, "./myNet.pt");
torch::serialize::OutputArchive archive;
net->save(archive);
archive.save_to("./myNet2.pt");
4.通过QCustomplot画出loss变化(此步只是看误差变化趋势,如果不想用这步可以跳过)
double mine = *(std::min_element(std::begin(yNum), std::end(yNum)));
double maxi = *(std::max_element(std::begin(yNum), std::end(yNum)));
ui.customPlot->addGraph(); // 添加一个曲线图QGraph
//ui.customPlot->graph(0)->setData(xp,yp); // 为曲线图添加数据
ui.customPlot->graph(0)->setData(xNum, yNum);
ui.customPlot->graph(0)->setName("legend"); // 设置曲线图的名字
ui.customPlot->xAxis->setLabel("x"); // 设置x轴的标签
ui.customPlot->yAxis->setLabel("y");
ui.customPlot->xAxis->setRange(xNum[0], xNum.back()); // 设置x轴的范围为(-1,1)
ui.customPlot->yAxis->setRange(mine-(maxi-mine)/100, maxi);
ui.customPlot->legend->setVisible(true); // 显示图例
5.模型的使用
由于我们只是测试模型的使用,所以就没重新生成数据,我直接使用上面的训练数据x代入模型中。
// 使用模型预测
auto netP = std::make_shared<myNet>(1, 1000, 1);
torch::serialize::InputArchive archive2;
archive2.load_from("./myNet2.pt");
netP->load(archive2);
auto yPrediction = netP->forward(x);
到此已经预测出了预测值。
6. 画出预测值(可跳过)
可以看出预测值大致符合上面二元一次方程公式。
总结:看似代码好像比Pytorch的多,其实主要代码也就是1、3、5步的代码,可能写的啰嗦显的代码多。对于其中所涉及的画图工具,我使用的是Qt的QCustomplot,对于的它的配置网上有很多教程,也简单,所以我就没过多提及。我是在VS2019上写的代码,我把整个项目文件也共享出来了,可通过下面下载链接下载。