libtorch:C++开发深度学习模型算法《张量基本操作》

2022-08-07 12:38:34 浏览数 (2)

环境搭建

CmakeLists.txt

代码语言:javascript复制
cmake_minimum_required (VERSION 3.8)

project(SOLDIER)
set(Torch_DIR "/libtorch/share/cmake/Torch")
set(PYTHON_EXECUTABLE "/usr/bin/python3")


find_package(Torch REQUIRED)
find_package(OpenCV REQUIRED)

set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")


set(CMAKE_BUILD_TYPE Debug)

include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${OpenCV_INCLUDE_DIRS})

add_executable(run main.cpp src/Gun.cpp src/Soldier.cpp)
target_link_libraries(run "${OpenCV_LIBS}" "${TORCH_LIBRARIES}")
set_property(TARGET run PROPERTY CXX_STANDARD 14)

张量基本操作

代码语言:javascript复制
#include <iostream>
#include<torch/torch.h>
using namespace std;

    // 张量 创建一个{3,4}的张量
    auto b = torch::rand({3,4});
    std::cout<<"创建的张量:"<<b<<std::endl;
    b.print();

    // 创建张量
    at::Tensor a = at::ones({2, 2}, at::kInt);
    at::Tensor c = at::randn({2, 2});
    c = c.to(at::kInt);
    std::cout<<"ones tensor size:"<<b.sizes()<<std::endl; //只打印维度信息
    c.print();//打印维度和数据类型
    
    // 判段cuda是否有效
    bool result = torch::cuda::is_available();
    std::cout<<result<<std::endl;

    //test torch
    auto device = torch::Device(torch::kCUDA);
    std::cout<<device<<std::endl;

    //初始化张量的值
    torch::Tensor allZeros = torch::zeros({5,7});

    //定义一定维度的单位张量  对角线为1 其余为0
    auto beye = torch::eye(5);

    // 一定维度的张量并设置初始值
    auto weight = torch::full({3,4},10);

    // 以另一个张量初始化另外一个张量
    auto weight_copy = torch::full_like(weight.toType(torch::kFloat),2.5);

    // 定义n行1列的张量,并初始化值
    auto test  = torch::tensor({1,2,3,4,5,6,7,8});

    // 定义一个在[0,1]之间的符合均匀分布的随机值初始化
    auto tensorrands = torch::rand({3,4});

    // 定义一个5行6列的张量
    tensorrands = torch::randn({5,6});

    // 数组转化为张量
    int aa[4] = {1,2,3,4};
    auto aaa = torch::from_blob(aa,{2,2},torch::kFloat);

    //使用容器来初始化张量
    vector<int> aaaa = {1,2,3};
    auto aaaaTensor = torch::from_blob(aaaa.data(),{1,1,1,3},torch::kFloat);
    std::cout<< aaaaTensor<<std::endl;

    //神经网络的输入通常为一张单通道灰度图或一张三通道的彩色图,如果输入为Opencv Mat格式的三通道彩色图,
    //我们需要格外注意数据维度的顺序,因为Mat格式的三通道图像与libtorch Tensor张量的数据维度是不一样的,
    //前者是[Height, Width, channels],后者是[channels, Height, Width],如果展开成一维向量来看,
    //Opencv Mat存储RGB图像的顺序为(每个R、G、B像素点交替存储)

    // 使用torch::from_blob创建的张量是与传入的指针共用内存,没有开辟内存
    // 重新创建内存需要需要使用clone 函数
    auto newaaa = torch::from_blob(aa,{2,2},torch::kFloat).clone();

    // 张量拼接
    torch::Tensor a1 = torch::rand({ 2,3 });  //2行3列
    torch::Tensor a2 = torch::rand({ 2,1 });  //2行1列
    torch::Tensor cat_1 = torch::cat({ a1, a2 }, 1); //dim参数为1表示按列拼接

    // 张量切片与索引
    //linspace(1, 75, 75)为取范围再1~75之间、长度为75的数组,也即1、2、3、...、75
    auto newnew = torch::linspace(1, 75, 75).reshape({ 3, 5, 5 });  //start -- end -- length
    cout << newnew << endl;

    //对于所有第1维度、第2维度,取第3维度索引号为2的数据
    auto bx = newnew.index({ "...", 2 });  
    cout << bx << endl;

    auto bx1 = newnew.index({ "...", 2, 3 });  //对所有第1维度,取第2维度索引号为2、第3维度索引号为3的数据


    auto bx2 = newnew.index({ 2, "...", 3 });  //对索引号为2的第1维度、索引号为3的第3维度,取所有第2维度数据
    
    auto bx3 = newnew.index({1,2}); //读取第一维度的的1,和第二维度的2的所有数据

    // 通过索引赋值
    // newnew.index_put_({"...","...",1},100);
    // std::cout<<newnew<<std::endl;

    // 切片
    // auto newslice = newnew.index({"...",Slice(1)});
    // cout<< newslice << endl;

    // 张量的压缩与扩张
    auto tensorA = torch::zeros({1,5,3,1});//定义一个1*5*3*1的张量
    std::cout << tensorA.sizes() << std::endl;


    // 删除长度为1的维度改成5*3
    auto tensorB = torch::squeeze(tensorA);
    std::cout << tensorB.sizes()<<std::endl;

    // 删除第0维度,变成5*3*1
    tensorB = torch::squeeze(tensorA, 0); 
    std::cout << "删除第0维度,变成5*3*1:"<<tensorB.sizes()<<std::endl;

    // 在第0维度增加一个长度为1的维度,变成1*1*5*3*1
    tensorB = torch::unsqueeze(tensorA, 0);
    std::cout << "在第0维度增加一个长度为1的维度,变成1*1*5*3*1:"<<tensorB.sizes()<<std::endl;

    // 张量对应位置的计算
    auto tensorC = torch::randint(0,10,{3,5});
    std::cout<<tensorC<<std::endl;
    auto tensorD = torch::randint(0,10,{3,5});
    std::cout << tensorD << std::endl;
    auto tensorE= tensorC   tensorD;
    std::cout<<"加法结果:"<<tensorE <<std::endl;

    //两个张量维度不同
    // 需要满足两个条件:1. 每个张量至少有一个维度;2. 两个张量对应的位置的维度要么相同要么其中一个维度为1,要么不存在
    auto atensor = torch::randint(0, 10, { 1, 4, 4 });
    cout << atensor << endl;
 
    auto btensor = torch::randint(0, 10, { 3, 1, 4 });
    cout << btensor << endl;
 
    auto ctensor = atensor   btensor;
    cout << ctensor << endl;

    // 求张量最大值和最小值
    //求张量a第0维度的最大值
    std::tuple<torch::Tensor, torch::Tensor> max_classes = (torch::max)(atensor, 0); 
    auto max_1 = std::get<0>(max_classes);  //求得最大值
    auto max_index = std::get<1>(max_classes);  //求得最大值的索引
    cout << max_1 << endl;
    cout << max_index << endl;

    // 操作第0维度
    // 无论张量有多少维度,变量[2] 都是对第一维度的特征进行操作
    auto tensorG = torch::rand({3,4,5});
    std::cout << tensorG << std::endl;
    tensorG[1] = torch::zeros({4,5});//将a的第0维度的索引号1张量重新赋值
    std::cout << tensorG << std::endl;

    // 张量的堆叠
    auto linetensorA = torch::linspace(1,10,10).reshape({2,5});
    auto linetensorB = torch::linspace(21,30,10).reshape({2,5});
    //生成维度为2*5的张量a
    //生成维度为2*5的张量b
    auto linetensorC = torch::stack({ linetensorA, linetensorB}, 0);
    cout << "linetensorC"<<linetensorC <<"linetensorB"<< linetensorB<<endl; 

    // 调整维度顺序
    auto tensorH = torch::randn({ 3, 4, 5 });
    cout << "调整前:"<<tensorH.sizes() << endl;
    auto tensorI = tensorH.permute({ 1,0,2 }); //将第0维度和第1维度交换顺序
    cout << "调整后:"<<tensorI.sizes() << endl;

    // 改变张量的形状
    auto tensorJ = tensorH.view({12,5});
    auto tensorK = tensorH.reshape({12,5});
    auto tensorL = tensorH.contiguous().view({12,5});
    cout << tensorJ << tensorK << tensorJ <<endl;
    ```

0 人点赞