使用pytorch可以很方便的训练了网络,并且pytorch的官方网站中放出了很全的python对tensor的操作接口API,但是在部署libtorch的时候,c++对tensor的操作接口API,资料不是很多哦,因此,我收集了我部署libtorch的时候,操作tensor块常用的接口API,其实很多和python的接口和类似。
std::vector<float> scales
torch::Tensor scales_ = torch::tensor(scales);
获取其中元素时,需要使用下标[]操作。
torch::Tensor a = torch::empty({2, 4}, at::kCUDA); // a 在cuda上
torch::Tensor a = torch::empty({2, 4}, at::kLong); // a 数据类型long
torch::Tensor a = torch::empty({2, 4}, at::device(at::kCUDA).dtype(at::kLong())); // cuda上数据类型long
torch::Tensor a = torch::empty({2, 4}, at::device({at::kCUDA, 1})); //在gpu1傻瓜
torch::Tensor a = torch::empty({2, 4}, at::requires_grad());//需要梯度
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} ]
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} ]
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 <<std::endl;
结果:
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} ]
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} ]
第一个参数是维度,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::endl;
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} ]
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} ]
torch::Tensor a = torch::randn({3,4});
cout << a << endl;
std::tuple<torch::Tensor, torch::Tensor> 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} ]
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} ]
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} ]
where返回的是tensor a中数值大于10的坐标位置,where的返回结果是vector,vector的size和a的dims相同。
where 的作用 与 比较符号( >, =, <等)+ nonzero的作用相同
torch::Tensor a = torch::randint(1, 30, {8});
std::cout << a << std::endl;
std::vector<torch::Tensor> index = torch::where( a >= 10);
std::cout << index.size() << std::endl;
std::cout << index[0] <<std::endl;
a结果为:
14
23
28
21
20
21
14
1
[ CPUFloatType{8} ]
index.size() = a.dims = 1
index[0]结果为:
0
1
2
3
4
5
6
[ CPULongType{7} ]
内存共享,
inline Tensor Tensor::slice(int64_t dim, int64_t start, int64_t end, int64_t step)
实际使用的是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} ]
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} ]
在下面的例子中,只能在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} ]
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]
注意: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<torch::Tensor> 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} ]
cx = cx.toType(torch::kFloat);
bool defined() const {
return impl_;
}
torch::Tensor a; 此时的a中的impl_指针是空的,大部分操作都不能做
if (a.defined()) {
做tensor数据的操作,例如 sizes等
}
torch::Tensor a = torch::randint(35, 50, {5, 3, 4});
std::cout << a <<std::endl;
torch::Tensor index = torch::tensor({1, 3});
std::cout << index << std::endl;
torch::Tensor b = torch::rand({index.size(0), 3, 4});
std::cout << b <<std::endl;
a.index_copy_(0, index, b);
std::cout << a <<std::endl;
tensor a的结果为:
(1,.,.) =
43 40 37 38
37 39 36 42
39 43 48 43
(2,.,.) =
42 36 37 41
43 49 38 43
43 49 49 47
(3,.,.) =
40 47 39 44
44 48 44 39
45 43 46 36
[ CPUFloatType{3,3,4} ]
tensor index的结果为:
0
1
[ CPULongType{2} ]
需要替换的tensor b的值为:
(1,.,.) =
0.6358 0.3979 0.5049 0.2738
0.0702 0.1643 0.7301 0.2098
0.1673 0.1662 0.8171 0.9777
(2,.,.) =
0.8396 0.3051 0.4217 0.3356
0.0771 0.1434 0.5754 0.1356
0.1013 0.3377 0.2514 0.9653
[ CPUFloatType{2,3,4} ]
在index的指导下,将a中对应位置的值,用b替换后的结果
(1,.,.) =
0.6358 0.3979 0.5049 0.2738
0.0702 0.1643 0.7301 0.2098
0.1673 0.1662 0.8171 0.9777
(2,.,.) =
0.8396 0.3051 0.4217 0.3356
0.0771 0.1434 0.5754 0.1356
0.1013 0.3377 0.2514 0.9653
(3,.,.) =
40 47 39 44
44 48 44 39
45 43 46 36
[ CPUFloatType{3,3,4} ]
std::cout << a << std::endl;
std::vector<torch::Tensor>> b = torch::split(a, 1, 1)
for(int i = 0; i < b.size(); i++)
{
std::cout << b[i] <<std::endl;
}
a 的结果为:
159.2578 96.9697 346.3506 260.4342
159.6481 96.2015 345.8403 261.2210
[ CUDAFloatType{2,4} ]
b中的元素依次为:
159.2578
159.6481
[ CUDAFloatType{2,1} ]
96.9697
96.2015
[ CUDAFloatType{2,1} ]
346.3506
345.8403
[ CUDAFloatType{2,1} ]
260.4342
261.2210
[ CUDAFloatType{2,1} ]
import torch
x = torch.randn(3,3)
print("number elements of x is ",x.numel())
y = torch.randn(3,10,5)
print("number elements of y is ",y.numel())
结果为:
number elements of x is 9
number elements of y is 150