libtorch中API介绍

前提

我们一直在使用torch的python 包(pytorch)进行相关项目的开发,但是有时候要用到torch的c++ 库(libtorch)进行开发,这里对libtorch中的有关tensor的API做个简单地介绍。libtorch中的函数和pytorch中的函数非常相近,几乎说是一摸一样,pytorch中有的函数,libtorch中也有(当然不全都有),所以在学习时我们要学会举一反三。

在下面的介绍中,我会直接贴出代码,并加以注释。

Libtorch

创建tensor

    // 方式一, 指定数据创建,后面的是tensor的类型,{5,5}是数据
    torch::Tensor tensor_a = torch::tensor({ 5, 5 }, torch::kFloat32); 
    
    // 方式二,利用API创建,{3,3}是大小,可以有torch::randn,torch::zeros,torch::randint等
    torch::Tensor tensor_b = torch::randn({ 3,3 }, torch::kFloat16); 
    
    // 方式三,从指针创建
    char vec[3] = { 1,2,3 };
    torch::Tensor tensor_c = torch::from_blob(vec, { 3 }, torch::kInt8);
    
    // 方式四,从文件创建
    //torch::Tensor tensor_d = torch::from_file("data.bin");
    
    // 方式5,创建一个空的tensor,大小为2x5
    torch::Tensor tensor_e = torch::empty({2, 5})

    std::cout << "tensor_a: " << tensor_a << std::endl;
    std::cout << "tensor_b: " << tensor_b << std::endl;
    std::cout << "tensor_c: " << tensor_c << std::endl;

可以看到,真的和pytorch非常相似。
这里要指出几个点:

  1. 可以直接使用std::cout进行输出查看tensor的值,但是无法在调试时查看到tensor的值,除非直接查看内存。
  2. pytorch中有的数据类型,这里都有。
  3. {3, 3 }会被解析为at::IntArrayRef size这个类型,可以不用明白这个类型具体是如何定义的,但是当遇到一个函数的参数是这个类型时,直接通过花括号构造一个参数传入试试。

查看tensor的属性

    torch::Tensor tensor_b = torch::randn({ 3,3 }, torch::kFloat16);
    // 维度
    int64_t dim = tensor_b.dim();
    // shape,要打印的话转为vector
    std::vector sizes = tensor_b.sizes().vec();
    // 第0维的大小
    int64_t size_0 = tensor_b.size(0);
    // 元素总数
    int64_t nums = tensor_b.numel();
    // 类型
    std::string tensor_dtype{ tensor_b.dtype().name()};
    // device
    std::string device = tensor_b.device().str();
    // 数据的首地址
    void *data_ptr = tensor_b.data_ptr();

    std::cout << "tensor_b dim: " << dim << std::endl;
    std::cout << "tensor_b sizes: " << sizes << std::endl;
    std::cout << "tensor_b size_0: " << size_0 << std::endl;
    std::cout << "tensor_b nums: " << nums << std::endl;
    std::cout << "tensor_b tensor_dtype: " << tensor_dtype << std::endl;
    std::cout << "tensor_b device: " << device << std::endl;
    std::cout << "tensor_b data_ptr: " << data_ptr << std::endl;

这里只列出了一些平常我们感兴趣的属性,剩余的没有列出。最后一个是tensor数据的地址,这个我们是肯定要掌握的,因为C语言中指针是一个非常重要的东西。我们对tensor赋值等操作就是在修改这块地址指向的空间的值。
注意:这里我为了方便可视化打印,将Tensor原本的一些返回值进行了转换。

tensor的一些操作

    torch::Tensor tensor_b = torch::randn({ 3,3 }, torch::kFloat16);
    // 判断tensor类型
    assert(tensor_b.dtype() == torch::kFloat);
    // reshape
    torch::Tensor tensor_c = tensor_b.reshape({ 1,9 });
    // 展平
    torch::Tensor tensor_d = tensor_b.flatten();
    // 改变数据类型
    torch::Tensor tensor_e = tensor_b.to(torch::kFloat32);
    // 判断tensor是否已经被定义(已经为tensor申请了内存)
    bool status = tensor_b.defined(); // status=false
    // 将tensor类型转为C语言的基本数据类型
    torch::Tensor tensor_f = torch::tensor(5, torch::kFloat32);
    float f_value = tensor_f.item<float>();

这里列出的一些基本的tensor操作,当然还有更多的没有列出来。请记住:pytorch和libtorch基本一一对应。

tensor的索引

索引单个元素

    // tensor_b 大小为2x3x3
    torch::Tensor tensor_b = torch::randn({ 2,3,3 }, torch::kFloat16);
    // python写法=tensor_b[1,1,0]
    torch::Tensor tensor_c = tensor_b[1][1][0];

    std::cout << "tensor_b: " << tensor_b << std::endl;
    std::cout << "tensor_c: " << tensor_c << std::endl;
	/*
	tensor_b: (1,.,.) =
	 -0.2065  0.6694 -1.0439
	  0.0078  0.5747 -1.4287
	  0.2795  0.4495 -0.1368
	
	(2,.,.) =
	  0.2091  0.0972 -1.2266
	  0.3740 -0.4724 -0.1450
	 -0.3074 -1.0127  0.8237
	[ CPUHalfType{2,3,3} ]
	tensor_c: 0.374023
	[ CPUHalfType{} ]
	*/

narrow

    // tensor_b 大小为2x3x3
    torch::Tensor tensor_b = torch::randn({2,3,3 }, torch::kFloat16);
    // 取tensor_b的第1维度,起始行为0,长度为2行,python写法=tensor_b[:,0:0+2,:]
    torch::Tensor tensor_c = torch::narrow(tensor_b, 1, 0, 2);
    
    std::cout << "tensor_b: " << tensor_b << std::endl;
    std::cout << "tensor_c: " << tensor_c << std::endl;
	/*
	tensor_b: (1,.,.) =
	  1.1953  0.2032  0.5410
	  0.5298  0.0441  0.7256
	 -1.1016 -0.4353  0.8569
	
	(2,.,.) =
	  0.5645 -0.7280 -0.1956
	  0.0030 -0.1808 -1.2305
	  0.6509  0.6396  1.4004
	[ CPUHalfType{2,3,3} ]
	tensor_c: (1,.,.) =
	  1.1953  0.2032  0.5410
	  0.5298  0.0441  0.7256
	
	(2,.,.) =
	  0.5645 -0.7280 -0.1956
	  0.0030 -0.1808 -1.2305
	[ CPUHalfType{2,2,3} ]
	*/

slice

    // tensor_b 大小为2x3x3
    torch::Tensor tensor_b = torch::randn({ 2,3,3 }, torch::kFloat16);
    // 在tensor_b的第1维度(行维度),start为0,end为1,python写法=tensor_b[:,0:1,:]
    torch::Tensor tensor_c = torch::slice(tensor_b, 1, 0, 1);

    std::cout << "tensor_b: " << tensor_b << std::endl;
    std::cout << "tensor_c: " << tensor_c << std::endl;
    /*
	    tensor_b: (1,.,.) =
	 -0.9067  0.7256  0.0112
	 -0.8140  1.2236  1.0156
	  0.3337 -0.5962  0.6602
	
	(2,.,.) =
	 -1.4971  0.3647 -0.5298
	 -0.9854  0.4995 -0.8325
	 -0.4475  1.0420 -0.0307
	[ CPUHalfType{2,3,3} ]
	tensor_c: (1,.,.) =
	 -0.9067  0.7256  0.0112
	
	(2,.,.) =
	 -1.4971  0.3647 -0.5298
	[ CPUHalfType{2,1,3} ]
	*/

index

上面的narrowslice现在已经很少使用了,似乎是在torch1.5版本后,提供了index函数来进行tensor的索引。

    // tensor_b 大小为2x3x3
    torch::Tensor tensor_b = torch::randn({ 2,3,3 }, torch::kFloat16);
    // python写法=tensor_b[1,0:2,:]
    torch::Tensor tensor_c = tensor_b.index({1, torch::indexing::Slice(0,2), torch::indexing::Slice(torch::indexing::None)});

    std::cout << "tensor_b: " << tensor_b << std::endl;
    std::cout << "tensor_c: " << tensor_c << std::endl;

这里大概就可以说明index的使用方式,更多的可以查看官方文档,一定要看这个官方文档,因为文档里规定了python对应C++的索引方式。

tensor的赋值

单个元素赋值

    // tensor_b 大小为2x3x3
    torch::Tensor tensor_b = torch::randn({ 2,3,3 }, torch::kFloat16);
    std::cout << "tensor_b: " << tensor_b << std::endl;

    tensor_b[0][0][0] = 5;
    std::cout << "tensor_b: " << tensor_b << std::endl;
  	/*
  	tensor_b: (1,.,.) =
	 -0.6973  1.6992  0.7686
	 -0.1859  0.8291 -0.5312
	  1.1426 -0.7324 -0.8525
	
	(2,.,.) =
	 -0.9258 -0.3289 -1.4180
	 -1.4277 -0.2761 -0.8911
	 -1.4834 -0.7388 -0.9951
	[ CPUHalfType{2,3,3} ]
	tensor_b: (1,.,.) =
	  5.0000  1.6992  0.7686
	 -0.1859  0.8291 -0.5312
	  1.1426 -0.7324 -0.8525
	
	(2,.,.) =
	 -0.9258 -0.3289 -1.4180
	 -1.4277 -0.2761 -0.8911
	 -1.4834 -0.7388 -0.9951
	[ CPUHalfType{2,3,3} ]
	*/

index_put_索引赋值

    // tensor_b 大小为2x3x3
    torch::Tensor tensor_b = torch::randn({ 2,3,3 }, torch::kFloat32);
    std::cout << "tensor_b: " << tensor_b << std::endl;

    torch::Tensor tensor_c = torch::ones({ 2,2 });
    // python写法:tensor_b[1,:2,:2] = tensor_c
    tensor_b.index_put_({ 1, torch::indexing::Slice(torch::indexing::None, 2),torch::indexing::Slice(torch::indexing::None, 2) }, tensor_c);
    std::cout << "tensor_b: " << tensor_b << std::endl;
    /*
    tensor_b: (1,.,.) =
	  1.1883  1.1363  0.8897
	  0.1595  0.9172  1.2951
	  0.1573  2.8680 -0.7158
	
	(2,.,.) =
	 -0.1757 -0.5980 -0.0633
	 -2.0957  0.6987 -0.7565
	  0.4421 -0.0936 -1.5684
	[ CPUFloatType{2,3,3} ]
	tensor_b: (1,.,.) =
	  1.1883  1.1363  0.8897
	  0.1595  0.9172  1.2951
	  0.1573  2.8680 -0.7158
	
	(2,.,.) =
	  1.0000  1.0000 -0.0633
	  1.0000  1.0000 -0.7565
	  0.4421 -0.0936 -1.5684
	[ CPUFloatType{2,3,3} ]
	*/

这里其实就是怎么索引,怎么赋值,自己再体会体会。

split和concatenate

    torch::Tensor tensor_b = torch::randn({ 2,3,3 }, torch::kFloat32);
    std::cout << "tensor_b: " << tensor_b << std::endl;
    // 第0个维度拆分,每一份的大小是1,因此可以拆分出两个tensor
    std::vector<torch::Tensor> tensor_list = torch::split(tensor_b, 1, 0);
    std::cout << "tensor_list_0: " << tensor_list[0] << std::endl;
    std::cout << "tensor_list_1: " << tensor_list[1] << std::endl;

    // 在第0个维度拼起来
    torch::Tensor tensor_c = torch::concatenate(torch::TensorList(tensor_list), 0);
    std::cout << "tensor_c:  " << tensor_c << std::endl;
    /*
    tensor_b: (1,.,.) =
	 -0.4057  0.0450 -0.3379
	  0.3363  0.2346  0.3055
	 -1.6528  0.0728 -0.5779
	
	(2,.,.) =
	 -1.2155  0.0216  0.5399
	 -1.1364  0.8286 -0.7170
	 -0.4326 -1.7718 -1.7367
	[ CPUFloatType{2,3,3} ]
	tensor_list_0: (1,.,.) =
	 -0.4057  0.0450 -0.3379
	  0.3363  0.2346  0.3055
	 -1.6528  0.0728 -0.5779
	[ CPUFloatType{1,3,3} ]
	tensor_list_1: (1,.,.) =
	 -1.2155  0.0216  0.5399
	 -1.1364  0.8286 -0.7170
	 -0.4326 -1.7718 -1.7367
	[ CPUFloatType{1,3,3} ]
	tensor_c:  (1,.,.) =
	 -0.4057  0.0450 -0.3379
	  0.3363  0.2346  0.3055
	 -1.6528  0.0728 -0.5779
	
	(2,.,.) =
	 -1.2155  0.0216  0.5399
	 -1.1364  0.8286 -0.7170
	 -0.4326 -1.7718 -1.7367
	[ CPUFloatType{2,3,3} ]

这里要注意的是:拆分的时候得用一个vector来保存,拼接的时候要将它转换为torch::TensorList类型。

总结

这篇博客我们介绍了一些libtorch中tensor的相关操作,请记住:libtorch和pytorch基本上是一一对应,要学会举一反三。

相关推荐

  1. libtorchAPI介绍

    2024-04-14 07:08:06       151 阅读
  2. Spring Boot的RESTful API详细介绍及使用

    2024-04-14 07:08:06       32 阅读
  3. libtorch学习第二

    2024-04-14 07:08:06       51 阅读
  4. Qualcomm AI Hub-API介绍

    2024-04-14 07:08:06       44 阅读
  5. API介绍

    2024-04-14 07:08:06       64 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-14 07:08:06       98 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-14 07:08:06       106 阅读
  3. 在Django里面运行非项目文件

    2024-04-14 07:08:06       87 阅读
  4. Python语言-面向对象

    2024-04-14 07:08:06       96 阅读

热门阅读

  1. FFmpeg: 自实现ijkplayer播放器--07解复用线程设计

    2024-04-14 07:08:06       40 阅读
  2. 解决在 Ubuntu18.04 上安装 ffmpeg 失败的方法

    2024-04-14 07:08:06       167 阅读
  3. FFmpeg: 自实现ijkplayer播放器--08视频解码线程设计

    2024-04-14 07:08:06       37 阅读
  4. Flume配置案例@Source:文件,Channel+Sink:Kafka

    2024-04-14 07:08:06       35 阅读
  5. Python学习入门(3)—— 高级技巧

    2024-04-14 07:08:06       41 阅读
  6. 删除url的search参数,避免页面刷新

    2024-04-14 07:08:06       37 阅读