c++ 部署libtorch 时对Tensor块的常用操作API (例如vector转换为torch、squeeze、select、select_indxe、max等)

使用pytorch可以很方便的训练了网络,并且pytorch的官方网站中放出了很全的python对tensor的操作接口API,但是在部署libtorch的时候,c++对tensor的操作接口API,资料不是很多哦,因此,我收集了我部署libtorch的时候,操作tensor块常用的接口API,其实很多和python的接口和类似。
文章目录1、vector 转为 tensor 块2、torch::tensor.sizes() 返回的是{c10::ArrayRef} 类型3、torch::empty(), torch::ones()4、torch::squeeze() 在指定dim增加维度5、* 或者torch::mul  乘法操作6、+ 或者torch:: add 乘法操作7、torch::select   在某个维度上获取index指定的行或列8、torch::index_select   在某个维度上,获取某些行或者某些列9、torch::max,tensor数据块中每个维度上,求最大值以及最大值下标10、torch::nonzero获取tensor数据块中非零数的下标,返回下标11、>  大于符号,tensor数据中的每一位做比较,返回对应位置的bool值12 、Tensor::slice,取tensor数据块中roi区域的数据,不复制13、  []下标操作,一定是对tensor数据块的第0维进行操作14、torch::stack()  增加新的维度进行堆叠15、torch::cat()  对数据沿着某一维度进行拼接。cat后数据的总维数不变.16、permute,交换维度, 适合多维数据,更灵活的transpose17、torch::meshgrid 创建网格点矩阵18、toType Tensor数据类型转换
1、vector 转为 tensor 块
std::vector scales
torch::Tensor scales_ = torch::tensor(scales);
12
2、torch::tensor.sizes() 返回的是{c10::ArrayRef} 类型
获取其中元素时,需要使用下标[]操作。
3、torch::empty(), torch::ones()
torch::Tensor a = torch::empty({2, 4});
std::cout << a << std::endl;
torch::Tensor b = torch::ones({2, 4});
std::cout << b<< std::endl;
结果:
 1.7171e+10  4.5796e-41  9.7406e-08  3.0815e-41
 0.0000e+00  0.0000e+00  0.0000e+00  0.0000e+00
[ CPUFloatType{2,4} ]
 1  1  1  1
 1  1  1  1
[ CPUFloatType{2,4} ]
1234567891011
4、torch::squeeze() 在指定dim增加维度
torch::squeeze(const Tensor & self, int64_t dim)
std::cout << a << std::endl;
std::cout << torch::unsqueeze(a, 1) << std::endl;

结果:
 1.0000
 1.4142
 0.7071
[ CPUFloatType{3} ]
 1.0000
 1.4142
 0.7071
[ CPUFloatType{3,1} ]
123456789101112
5、* 或者torch::mul  乘法操作
a与b做*乘法,原则是如果a与b的size不同,则以某种方式将a或b进行复制,使得复制后的a和b的size相同,然后再将a和b做element-wise的乘法。 torch::mul与 *用法相同。
std::cout << a << std::endl;
std::cout << b << std::endl;
std::cout << a * b < 结果:
 21.0000
 30.7409
[ CPUFloatType{2,1} ]
1.0000  1.4142  0.7071
[ CPUFloatType{1,3} ]
21.0000  29.6985  14.8492
30.7409  43.4741  21.7371
[ CPUFloatType{2,3} ]
123456789101112
6、+ 或者torch:: add 乘法操作
5和6都是按位加或者乘,这里就用到了广播机制(broadcastable),1、相同size的一定可以广播;2、每个tensor至少有一个dim;3、遍历对比两个tensor尺寸大小时,两个tensor对应位置上的dim要么相同,要么其中一个是1,要么不存在,如果都不是,说明两个tensor不能广播。
例如下面:
尺寸{1, 4, 4} 和 尺寸{3, 1,4}进行遍历比较:1、1和3有一个是1;2、4和1有一个是1;3、4和4相同,因此tensor a 和 b可以广播
torch::Tensor a = torch::randint(0, 10, {1, 4, 4});
std::cout <<  a << std::endl;
torch::Tensor b = torch::randint(0, 10, {3, 1, 4});
std::cout <<  b << std::endl;
std::cout << a+b << std::endl;
//tensor a
(1,.,.) = 
  7  1  9  8
  3  5  9  6
  0  4  7  6
  0  6  2  2
[ CPUFloatType{1,4,4} ]
//tensor b
(1,.,.) = 
  4  4  5  3
(2,.,.) = 
  6  4  9  9
(3,.,.) = 
  7  5  3  6
[ CPUFloatType{3,1,4} ]
//tensor a + b
(1,.,.) = 
  11   5  14  11
   7   9  14   9
   4   8  12   9
   4  10   7   5
(2,.,.) = 
  13   5  18  17
   9   9  18  15
   6   8  16  15
   6  10  11  11
(3,.,.) = 
  14   6  12  14
  10  10  12  12
   7   9  10  12
   7  11   5   8
[ CPUFloatType{3,4,4} ]
12345678910111213141516171819202122232425262728293031323334353637
7、torch::select   在某个维度上获取index指定的行或列
第一个参数是维度,0是取行,1是取 列,第二个参数是索引的序号,下面的例子是,取a的第2列,这个取出来的数据和原始tensor内存共享,即可以避免不必要的复制。
另外,目前发现,select和index_select的区别是,index_select可以取好几个索引,select只可以取一个,index_select没有内存共享。
函数接口:Tensor Tensor::select(int64_t dim, int64_t index) const
torch::Tensor a = torch::rand({2, 3});
torch::Tensor b = a.select(1, 2);
cout << b << endl;
a[0][2] = 0;
std::cout << a < std::cout << b << std::endl;
结果:
//tensor a 的值为:
 0.3086  0.3939  0.0189
 0.2826  0.7672  0.5433
[ CPUFloatType{2,3} ]

//取出来的tensor b 的值为:
 0.0189
 0.5433
[ CPUFloatType{2} ]
//改变tensor a中坐标为[0,2]的数据
 0.3566  0.8933  0.0000
 0.4275  0.4000  0.5178
[ CPUFloatType{2,3} ]
//发现取出来的tensor b也受到了影响。
 0.0000
 0.5178
[ CPUFloatType{2} ]
123456789101112131415161718192021222324
8、torch::index_select   在某个维度上,获取某些行或者某些列
Tensor index_select(const Tensor & self, Dimname dim, const Tensor & index);
第一个参数是索引的对象,第二个参数0表示按行索引,1表示按列进行索引,第三个参数是一个tensor,就是索引的序号,例如下面的例子,是在a上取0,3,1,2行。下面的实验说明,没有内存共享。
 //索取的下标
 std::cout << indices << std::endl;
 //索取的对象
 std::cout << a << std::endl;
 //按照下标进行索取获得b
 torch::Tensor b = torch::index_select(a, 0, indices);
 std::cout << b << std::endl;
//改变a的值,看b有没有改变
a[0][0] = 0;
std::cout << a<< std::endl;
std::cout << b << std::endl;

结果:
//索取的下标
 0
 3
 1
 2
[ CPULongType{4} ]
//索取的对象a
 -6  -6  14  14
-11  -3  18  10
 -3 -11  10  18
-11 -11  18  18
-18  -7  25  14
 -7 -18  14  25
[ CPUFloatType{6,4} ]
//按照下标进行索取获得b
 -6  -6  14  14
-11 -11  18  18
-11  -3  18  10
 -3 -11  10  18
[ CPUFloatType{4,4} ]
//改变a的值
  0  -6  14  14
-11  -3  18  10
 -3 -11  10  18
-11 -11  18  18
-18  -7  25  14
 -7 -18  14  25
[ CPUFloatType{6,4} ]
// 看b有没有改变, 发现b没有改变,说明没有共享内存
 -6  -6  14  14
-11 -11  18  18
-11  -3  18  10
 -3 -11  10  18
[ CPUFloatType{4,4} ]
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647
9、torch::max,tensor数据块中每个维度上,求最大值以及最大值下标
torch::Tensor a = torch::randn({3,4});
cout << a << endl;
std::tuple max_classes = torch::max(a, 1);
auto max_1= std::get<0>(max_classes);
auto max_index= std::get<1>(max_classes);
cout << max_1 << endl;
cout << max_index << endl;
结果
tensor a 的值为:
[0.4388 -0.8234  0.3935  0.0000
0.0121  1.0354  0.0000  1.5286
 0.1590  2.7148 -0.0737 -0.5168]
 [ CPUFloatType{3,4} ]

max_1 是最大值,值为:
 0.3935
 1.5286
 2.7148 
 
max_index是最大值的下标,值为:
[ CPUFloatType{3} ]
 2
 3
 1
[ CPULongType{3} ]
12345678910111213141516171819202122232425
10、torch::nonzero获取tensor数据块中非零数的下标,返回下标
torch::Tensor a = torch::randn({3,4});
a[2][3] = 0;
a[1][2] = 0;
cout << a << endl;
auto b = torch::nonzero(a);
 cout << b << endl;
 结果:
 **tensor a 的值为:**
-0.4388 -0.8234  0.3935  0.0000
 0.0121  1.0354  0.0000  1.5286
 0.1590  2.7148 -0.0737 -0.5168
[ CPUFloatType{3,4} ]

**tensor b 的 值是非0值对应的下标,如下:**
 0  0
 0  1
 0  2
 1  0
 1  1
 1  3
 2  0
 2  1
 2  2
 2  3
[ CPULongType{10,2} ]
12345678910111213141516171819202122232425
11、>  大于符号,tensor数据中的每一位做比较,返回对应位置的bool值
torch::Tensor a = torch::randn({3,4});
cout << ( a > 0.1) << endl;
结果:
tensor a 的值为:
-0.4388 -0.8234  0.3935  0.0000
 0.0121  1.0354  0.0000  1.5286
 0.1590  2.7148 -0.0737 -0.5168
[ CPUFloatType{3,4} ]

 0  0  1  0
 0  1  0  1
 1  1  0  0
[ CPUBoolType{3,4} ]
12345678910111213
12 、Tensor::slice,取tensor数据块中roi区域的数据,不复制
内存共享,
inline Tensor Tensor::slice(int64_t dim, int64_t start, int64_t end, int64_t step)
1
13、  []下标操作,一定是对tensor数据块的第0维进行操作
实际使用的是select操作
inline Tensor Tensor::operator[](int64_t index) const {
return select(0, index);
}
torch::Tensor c = torch::rand({2, 3, 4});
cout << c << endl;
c[1] = 0;
cout << c << endl;
修改前的c:
(1,.,.) = 
  0.0738  0.7569  0.4918  0.5285
  0.7943  0.0340  0.4274  0.1421
  0.9166  0.6404  0.3730  0.8922

(2,.,.) = 
  0.8411  0.6094  0.9797  0.1298
  0.6040  0.2223  0.8214  0.2652
  0.3887  0.7544  0.1205  0.4937
[ CPUFloatType{2,3,4} ]

修改后的c:
(1,.,.) = 
  0.0738  0.7569  0.4918  0.5285
  0.7943  0.0340  0.4274  0.1421
  0.9166  0.6404  0.3730  0.8922

(2,.,.) = 
  0  0  0  0
  0  0  0  0
  0  0  0  0
[ CPUFloatType{2,3,4} ]
123456789101112131415161718192021222324252627
14、torch::stack()  增加新的维度进行堆叠
static inline Tensor stack(TensorList tensors, int64_t dim)
这里的dim是增加哪个维度,如果dim=0,结果tensor的sizes为 4x6
如果dim=1,结果tensor的sizes为6x4
std::cout << a << std::endl;
std::cout << b << std::endl;
torch::Tensor c = torch::stack({a, b}, 1);
std::cout << c << std::endl;
[ 21.0000
 29.6985
 14.8492
 30.7409
 43.4741
 21.7371
[ CPUFloatType{6} ]
 21.0000
 14.8492
 29.6985
 30.7409
 21.7371
 43.4741
[ CPUFloatType{6} ]
 21.0000  21.0000
 29.6985  14.8492
 14.8492  29.6985
 30.7409  30.7409
 43.4741  21.7371
 21.7371  43.4741
[ CPUFloatType{6,2} ]
12345678910111213141516171819202122232425
15、torch::cat()  对数据沿着某一维度进行拼接。cat后数据的总维数不变.
在下面的例子中,只能在dim=0上进行cat,因为a和b只有一个维度,dim=1将报错,因为cat不能增加维度。
这里的dim是沿着哪个维度进行拼接。
std::cout << a << std::endl;
std::cout << b << std::endl;
torch::Tensor c = torch::cat({a, b}, 0);
std::cout << c << std::endl;

[ 21.0000
 29.6985
 14.8492
 30.7409
 43.4741
 21.7371
[ CPUFloatType{6} ]
 21.0000
 14.8492
 29.6985
 30.7409
 21.7371
 43.4741
 [ CPUFloatType{6} ]
 21.0000
 29.6985
 14.8492
 30.7409
 43.4741
 21.7371
 21.0000
 14.8492
 29.6985
 30.7409
 21.7371
 43.4741
[ CPUFloatType{12} ]
1234567891011121314151617181920212223242526272829303132
16、permute,交换维度, 适合多维数据,更灵活的transpose
torch::Tensor x = torch::randn({2,3,4});
std::cout << x.sizes() << std::endl;
torch::Tensor x_p = x.permute({1,0,2}); //将原来第1维变为0维,同理,0→1,2→2
std::cout << x_p.sizes() << std::endl;

[2, 3, 4]
[3, 2, 4]
1234567
17、torch::meshgrid 创建网格点矩阵
注意:args[0]是y的坐标变换, args[1]是x的坐标变换,另外args里面的元素的数据类型是CUDALongType
torch::Tensor shift_x = torch::arange(0, 3, device = device);
torch::Tensor shift_y = torch::arange(0, 3, device = device);
std::cout << shift_x << std::endl;
std::cout << shift_y << std::endl;
//torch::meshgrid中的shift_y,shift_x表示生成的结果是shift_y行,shift_xlie
//另外args[0]是y上的坐标遍历
//另外args[1]是x上的坐标遍历
std::vector args = torch::meshgrid({shift_y, shift_x});
std::cout << args[0] << std::endl;
std::cout << args[1] << std::endl;
结果:
 0
 1
 2
[ CUDALongType{3} ]
 0
 1
 2
[ CUDALongType{3} ]
 0  0  0
 1  1  1
 2  2  2
[ CUDALongType{3,3} ]
 0  1  2
 0  1  2
 0  1  2
[ CUDALongType{3,3} ]
123456789101112131415161718192021222324252627
18、toType Tensor数据类型转换
cx = cx.toType(torch::kFloat)

 

原文链接:https://blog.csdn.net/weixin_45209433/article/details/103495558

你可能感兴趣的:(libtorch)