LibTorch入坑记

一、环境

win10

vs2022

cmake最新版

cuda 11.8

二、LibTorch下载

PyTorchicon-default.png?t=N7T8https://pytorch.org/

注意:我选择了preview版本。因为最新的MKL目前已经不兼容libtorch230了。 

三、LibTorch使用

libtorch解压后如下图: 

最核心的是include和lib这两个文件夹。

另外,我的CUDA路径如下图 

1、include问题

2、lib问题

3、附加依赖项(我添加的不够多,你可在实践中继续添加)

4、两项设置:

(1)把《符合模式》改为否;
(2)《c++语言标准》》改为17

 

5、添加系统变量

6、启用CUDA

 /INCLUDE:?warp_size@cuda@at@@YAHXZ  

四、示例代码

#include <iostream>
#include "torch/script.h"
#include <torch/torch.h>

int main()
{
    torch::Tensor tensor = torch::rand({ 5,3 });
    std::cout << tensor << std::endl;

    if (torch::cuda::is_available())
        std::cout << "cuda 可用";
    else
        std::cout << "cuda 不可用";

    return EXIT_SUCCESS;
}

 

五、更复杂代码

// ConsoleApplication1.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//




#include <iostream>
#include "torch/script.h"
#include <torch/torch.h>

#include <torch/torch.h>

#include <cstddef>
#include <cstdio>
#include <iostream>
#include <string>
#include <vector>


#include<torch/torch.h>
#include<cstddef>
#include<iostream>
#include<vector>
#include<string>
// 继承自Module模块
struct Net : torch::nn::Module
{
    // 构造函数
    Net() :
        conv1(torch::nn::Conv2dOptions(1, 32, 3)), // kernel_size = 5
        conv2(torch::nn::Conv2dOptions(32, 64, 3)),
        fc1(9216, 128),
        fc2(128, 10)
    {
        register_module("conv1", conv1);
        register_module("conv2", conv2);
        register_module("conv2_drop", conv2_drop);
        register_module("fc1", fc1);
        register_module("fc2", fc2);
    }
    // 成员函数:前向传播
    torch::Tensor forward(torch::Tensor x)
    {
        // input:1*28*28
        x = torch::relu(conv1->forward(x)); //conv1:(28 - 3 + 1 = 26), 26*26*32
        // input:26*26*32
        x = torch::max_pool2d(torch::relu(conv2->forward(x)), 2);//conv2:(26 - 3 + 1 = 24),24*24*64; max_poolded:12*12*64 = 9216
        x = torch::dropout(x, 0.25, is_training());
        x = x.view({ -1, 9216 });// 9216*1
        // w:128*9216
        x = torch::relu(fc1->forward(x)); //fc1:w = 128*9216,w * x ->128*1
        x = torch::dropout(x, 0.5, is_training());
        // w:10*128
        x = fc2->forward(x);//fc2:w = 10*128,w * x -> 10*1
        x = torch::log_softmax(x, 1);
        return x;

    }


    // 模块成员
    torch::nn::Conv2d conv1;
    torch::nn::Conv2d conv2;
    torch::nn::Dropout2d conv2_drop;
    torch::nn::Linear fc1;
    torch::nn::Linear fc2;
};

//train
template<typename DataLoader>
void train(size_t epoch, Net& model, torch::Device device, DataLoader& data_loader, torch::optim::Optimizer& optimizer, size_t dataset_size)
{
    //set "train" mode
    model.train();
    size_t batch_idx = 0;
    for (auto& batch : data_loader)
    {
        auto data = batch.data.to(device);
        auto targets = batch.target.to(device);
        optimizer.zero_grad();
        auto output = model.forward(data);
        auto loss = torch::nll_loss(output, targets);
        AT_ASSERT(!std::isnan(loss.template item<float>()));
        loss.backward();
        optimizer.step();

        // 每10个batch_size打印一次loss
        if (batch_idx++ % 10 == 0)
        {
            std::printf("\rTrain Epoch: %ld [%5ld/%5ld] Loss: %.4f",
                epoch,
                batch_idx * batch.data.size(0),
                dataset_size,
                loss.template item<float>());
        }
    }
}

template<typename DataLoader>
void test(Net& model, torch::Device device, DataLoader& data_loader, size_t dataset_size)
{
    torch::NoGradGuard no_grad;
    // set "test" mode
    model.eval();
    double test_loss = 0;
    int32_t correct = 0;
    for (const auto& batch : data_loader)
    {
        auto data = batch.data.to(device);
        auto targets = batch.target.to(device);
        auto output = model.forward(data);
        test_loss += torch::nll_loss(output, targets, /*weight=*/{}, torch::Reduction::Sum).template item<float>();
        auto pred = output.argmax(1);
        // eq = equal 判断prediction 是否等于label
        correct += pred.eq(targets).sum().template item<int64_t>();
    }
    test_loss /= dataset_size;
    std::printf(
        "\nTest set: Average loss: %.4f | Accuracy: %.3f\n",
        test_loss,
        static_cast<double>(correct) / dataset_size);
}

int main()
{
    torch::manual_seed(1);
    torch::DeviceType device_type;
    if (torch::cuda::is_available())
    {
        std::cout << "CUDA available! Training on GPU." << std::endl;
        device_type = torch::kCUDA;
    }
    else
    {
        std::cout << "Training on CPU." << std::endl;
        device_type = torch::kCPU;
    }

    torch::Device device(device_type);

    Net model;
    model.to(device);
    // load train data
    auto train_dataset = torch::data::datasets::MNIST("C://BaiduNetdiskDownload//SimpleNet-main")
        .map(torch::data::transforms::Normalize<>(0.1307, 0.3081))
        .map(torch::data::transforms::Stack<>());

    const size_t train_dataset_size = train_dataset.size().value();
    std::cout << train_dataset_size << std::endl;
    auto train_loader = torch::data::make_data_loader<torch::data::samplers::SequentialSampler>(
        std::move(train_dataset), 64);
    // load test data
    auto test_dataset = torch::data::datasets::MNIST(
        "C://BaiduNetdiskDownload//SimpleNet-main", torch::data::datasets::MNIST::Mode::kTest)
        .map(torch::data::transforms::Normalize<>(0.1307, 0.3081))
        .map(torch::data::transforms::Stack<>());
    const size_t test_dataset_size = test_dataset.size().value();
    auto test_loader =
        torch::data::make_data_loader(std::move(test_dataset), 1000);

    // optimizer
    torch::optim::SGD optimizer(model.parameters(), torch::optim::SGDOptions(0.01).momentum(0.5));

    //train
    for (size_t epoch = 0; epoch < 5; epoch++)
    {
        train(epoch, model, device, *train_loader, optimizer, train_dataset_size);
        test(model, device, *test_loader, test_dataset_size);
    }
    // save
    return 1;
}

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值