Libtorch c++ 搭建全连接网络识别MINST手写数字

35 篇文章 6 订阅
7 篇文章 3 订阅

这是个完整的例子,用全连接网络方法识别手写数字,分为三部分,(1)搭建网络,(2)读取MNIST数据,(3)优化器设置,(4)训练网络。

1、网络搭建部分

用struct的方式建立自定义网络Net,它继承自torch::nn::Module,实现了forward函数,

该网络中注册的内置网络模块是三个线性网络,fc1,fc2,fc3

神经元的个数,fc1为(784,64),fc2(64,32),fc3(32,10),fc1的输入层个数为784,是因为MNIST图像的像素为28*28=784,网络的最后一层是log_softmax,输入是fc3的输出,fc3的输出神经元个数为10。它的输出神经元个数与输入个数一致,还是10,log_softmax()层的作用是接受一个实数向量计算概率分布然后取对数。整体的网络结构如下:

MNIST picture->tensor->fc1(784, 64)->relu()->dropout()->fc2(64,32)->relu()->fc3(32, 10)->log_softmax()->prediction

可以知道输入是长度为784的向量,输出是长度为10的概率分布的对数。

2、数据读取部分

与pytorch类似,libtorch也要求必须用make_data_loader这种多线形成数据加载的方式加载数据。这个没有新建数据集,而是采用了libtorch自带的MNIST数据集(libtorch通过torch::data::datasets封装了一些常见的数据集,方便使用),直接加载即可。然后通过map映射的方式把数据形成批量的,数据转化方式是栈(stack)的方式

3、优化器设置

优化器设置比较简单,选择的是随机提取下降,固定学习率。

4、训练部分

通过for训练的方式进行迭代训练,每个循环内,重置梯度为0,然后计算损失函数loss,通过loss的反向计算backward计算梯度,通过优化器optimizer.step()调正网络的权重,然后执行下次训练,每个一定次数保存当前的网络。

其中损失函数选择的是nll_loss,它输入要求是一个对数概率向量和一个目标标签. 它不会为我们计算对数概率. 适合网络的最后一层是log_softmax.

保存当前网络的方法是,torch::save(net, "net.pt")

#include <iostream>
#include <torch/script.h>
#include <torch/csrc/api/include/torch/torch.h>

// Define a new Module.
struct Net : torch::nn::Module {
    Net() {
        // Construct and register two Linear submodules.
        fc1 = register_module("fc1", torch::nn::Linear(784, 64));
        fc2 = register_module("fc2", torch::nn::Linear(64, 32));
        fc3 = register_module("fc3", torch::nn::Linear(32, 10));
    }

    // Implement the Net's algorithm.
    torch::Tensor forward(torch::Tensor x) {
        // Use one of many tensor manipulation functions.
        x = torch::relu(fc1->forward(x.reshape({ x.size(0), 784 })));
        x = torch::dropout(x, /*p=*/0.5, /*train=*/is_training());
        x = torch::relu(fc2->forward(x));
        x = torch::log_softmax(fc3->forward(x), /*dim=*/1);
        return x;
    }

    // Use one of many "standard library" modules.
    torch::nn::Linear fc1{ nullptr }, fc2{ nullptr }, fc3{ nullptr };
};

int main()
{
    std::cout << "Hello World!\n";
    //torch::Tensor tensor = torch::eye(3);
    torch::Tensor tensor = torch::rand({ 2,3 });
    std::cout << tensor << std::endl;
    torch::save(tensor, "tensor.pt");

    const static int WIDTH = 512, HEIGHT = 512;

    // Create a new Net.
    auto net = std::make_shared<Net>();

    // Create a multi-threaded data loader for the MNIST dataset.
    auto data_loader = torch::data::make_data_loader(
        torch::data::datasets::MNIST("../../pytorchCpp/data/mnist/MNIST/raw").map(
            torch::data::transforms::Stack<>()),
        /*batch_size=*/64);

    // Instantiate an SGD optimization algorithm to update our Net's parameters.
    torch::optim::SGD optimizer(net->parameters(), /*lr=*/0.01);
    
    std::vector<double> lossVec;
    for (size_t epoch = 1; epoch <= 10; ++epoch) {
        size_t batch_index = 0;
        // Iterate the data loader to yield batches from the dataset.
        for (auto& batch : *data_loader) {
            // Reset gradients.
            optimizer.zero_grad();
            // Execute the model on the input data.
            torch::Tensor prediction = net->forward(batch.data);
            // Compute a loss value to judge the prediction of our model.
            torch::Tensor loss = torch::nll_loss(prediction, batch.target);
            // Compute gradients of the loss w.r.t. the parameters of our model.
            loss.backward();
            // Update the parameters based on the calculated gradients.
            optimizer.step();
            // Output the loss and checkpoint every 100 batches.
            if (++batch_index % 100 == 0) {
                std::cout << "Epoch: " << epoch << " | Batch: " << batch_index
                    << " | Loss: " << loss.item<float>() << std::endl;
                lossVec.push_back(loss.item<double>());
                // Serialize your model periodically as a checkpoint.
                torch::save(net, "net.pt");
            }
            
        }
    }
  
        
    
}

 

 损失函数

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
MindSpore是华为推出的开源深度学习框架。它使用了自动并行和自动微分的技术,能够高效地进行模型训练和推理。Mnist是一个经典的手写数字数据集,包含了60000个用于训练和10000个用于测试的数字图片。我们可以使用MindSpore来构建一个用于识别Mnist手写数字的模型。 首先,我们需要使用MindSpore读取Mnist数据集,并进行预处理。MindSpore提供了各种数据处理的接口,我们可以使用这些接口来加载Mnist数据集、进行图片的归一化、标签的独热编码等操作。 接下来,我们可以使用MindSpore搭建一个深度学习模型,用于识别手写数字。这个模型可以使用卷积神经网络(CNN)或者其他常见的深度学习网络结构。MindSpore提供了丰富的网络层和激活函数的实现,我们可以根据自己的需求来选择适合的网络结构。 在网络搭建完成后,我们需要使用MindSpore提供的优化算法和损失函数来对模型进行训练。MindSpore支持多种优化算法,如随机梯度下降(SGD)、Adam等。我们可以根据自己的需求选择适合的优化算法,并设定合适的超参数。 训练完成后,我们可以使用MindSpore对测试数据进行预测。通过将测试数据输入到已经训练好的模型中,我们可以得到模型对手写数字的预测结果。 最后,我们可以使用MindSpore提供的评估指标来评估模型在Mnist数据集上的准确率。通过对模型的准确率进行评估,我们可以了解模型的性能并进行优化。 总之,MindSpore作为一款功能强大的深度学习框架,可以帮助我们高效地实现Mnist手写数字识别任务。通过合理地使用MindSpore提供的功能,我们可以构建出准确率较高的模型,并为手写数字识别等相关领域的研究和应用提供支持。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

oceanstonetree

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值