libtorchTensor张量的常⽤操作总结(1)
“ 基于libtorch的深度学习框架,其处理数据的主要基本单位是Tensor张量,我们可以把Tensor张量理解成矩阵,该矩阵的维度可以是1维、2维、3维,或更⾼维。”
本⽂我们来总结⼀下Tensor张量的常⽤操作。
01 打印张量的信息
打印张量的维度信息
要查看张量的维度信息,通常有两种⽅式:打印张量的sizes;或者直接调⽤张量类的print函数:
torch::Tensor b = torch::zeros({ 3, 5 });
cout << b.sizes() << endl; //⽅式⼀,只打印维度信息
b.print(); //⽅式⼆,除了打印维度信息,数据类型也打印出来
运⾏结果:
打印张量的内容
torch::Tensor b = torch::zeros({ 3, 5 });
cout << b << endl;
运⾏结果:
02 定义并初始化张量的值
定义⼀定维度的张量并初始化全部值为0
torch::Tensor b = torch::zeros({ 5, 7 }); //定义5⾏7列的0值张量
cout << b << endl;
运⾏结果如下,得到5⾏7列的张量:
定义⼀定维度的张量并初始化全部值为1
auto b = torch::ones({ 3,4 }); //定义3⾏4列的1值张量
cout << b << endl;
运⾏结果如下,得到3⾏4列的张量:
定义⼀定维度的单位张量
单位张量与单位向量是⼀个概念,即对⾓线值为1,其余值全部为0:
auto b = torch::eye(5); //定义5*5单位张量
cout << b << endl;
运⾏结果如下,得到5⾏5列的单位张量:
定义⼀定维度的张量并设置初始值
auto b = torch::full({ 3,4 }, 10); //定义3⾏4列张量,并初始化全部值为0
cout << b << endl;
运⾏结果如下,得到3⾏4列的张量:
此外,还可以使⽤另⼀个张量的形状作为模板,定义相同形状维度的张量,并填充初始值:
auto b = torch::full({ 3,4 }, 10); //定义3⾏4列的张量b,并填充全部值为10
auto a = torch::full_like(b, 2); //定义与b相同形状的张量a,并填充初始值2
auto a1 = torch::full_like(b, 2.5); //定义与b相同形状的张量a,并填充初始值2.5
auto a2 = torch::full_Type(kFloat), 2.5); //定义与b相同形状的张量a,并填充初始值2.5
cout << b << endl;
cout << a << endl;
cout << a1 << endl;
cout << a2 << endl;
运⾏结果如下,我们注意到张量b的数据默认为long int型,那么使⽤full_like定义张量a、a1时,它们的数据类型也默认为long int型,即使a1填充值为2.5,也被⾃动截断为整型数2了。⽽a2则强⾏把b转换为float型,使a2也是float型数据,因此a2可以使⽤2.5来填充⽽不被⾃动截断为整型数了。
定义n⾏1列的张量,并指定初始值
auto b = torch::tensor({ 1,2,3,4,5,6,7,8 }); //定义8⾏1列的张量,并指定初始值
cout << b << endl;
运⾏结果如下,得到8⾏1列的张量:
linspace函数调用的格式为定义⼀定维度的张量,并使⽤随机数初始化
//定义3⾏4列张量,并使⽤区间[0, 1)的符合均匀分布的随机数初始化
auto r = torch::rand({ 3,4 });
cout << r << endl;
//定义5⾏6列张量,并使⽤符合标准正态分布(均值为0,⽅差为1,即⾼斯⽩噪声)的随机数初始化
r = torch::randn({ 5, 6 });
cout << r << endl;
//定义5⾏5列张量,并使⽤区间[0, 10)的整型数初始化
r = torch::randint(0, 10, { 5,5 });
cout << r << endl;
运⾏结果如下:
使⽤数组或某⼀段内存初始化张量
使⽤数组或某⼀段内存来初始化张量时,通常调⽤torch::from_blob函数来实现:
//使⽤数组来初始化张量内容
int aa[4] = { 3,4,6,7 };
auto aaaaa = torch::from_blob(aa, { 2, 2 }, torch::kInt);
cout << aaaaa << endl;
//使⽤vector迭代容器来初始化张量内容
vector<float> aaaa = { 3,4,6 };
auto aaa = torch::from_blob(aaaa.data(), { 1, 1, 1, 3 }, torch::kFloat);
cout << aaa << endl;
//使⽤Opencv的Mat来初始化张量内容,相当于把Mat转换为Tensor
Mat x = Mat::zeros(5, 5, CV_32FC1);
auto xx = torch::from_blob(x.data, { 1, 1, 5, 5 }, torch::kFloat);
cout << xx << endl;
运⾏结果如下:
神经⽹络的输⼊通常为⼀张单通道灰度图或⼀张三通道的彩⾊图,如果输⼊为Opencv Mat格式的三通道彩⾊图,我们需要格外注意数据维度的顺序,因为Mat格式的三通道图像与libtorch Tensor张量的数据维度是不⼀样的,前者是[Height, Width, channels],后者是[channels, Height, Width],如果展开成⼀维向量来看,Opencv Mat存储RGB图像的顺序为(每个R、G、B像素点交替存储):
libtorch张量存储RGB图像的顺序为(依次存储所有的R、G、B像素点):
因此将Mat格式的三通道图像转换为Tensor张量时,我们应该⾸先把[Height, Width, Channels]的Mat格式数据转换为[Height, Width, Channels]的Tensor张量,然后再调⽤Tensor张量的permute函数把数据的维度顺序调整为[Channels, Height, Width]即可。
Mat x1 = (Mat_<uchar>(5, 5) << 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25);
Mat x2 = x1.clone();
Mat x3 = x1.clone();
vector<Mat> channels;
channels.push_back(x1.clone());
channels.push_back(x2.clone());
channels.push_back(x3.clone());
Mat x123;
merge(channels, x123); //合并成⼀张三通道图像
cout << "[Height, Width, channels]格式的Mat:" << endl;
cout << x123 << endl;
//错误维度顺序⽰范
auto x_t = torch::from_blob(x123.data, { 3, 5, 5 }, torch::kByte);
cout << "直接将[Height, Width, channels]格式Mat转换为的[channels, Height, Width]格式的Tensor,维度不对应:" << endl;
cout << x_t << endl;
//建议的做法,确保Tensor张量的维度顺序为[channels, Height, Width]
x_t = torch::from_blob(x123.data, { 5, 5, 3 }, torch::kByte);
cout << "先将[Height, Width, channels]格式Mat转换为的[Height, Width, channels]格式的Tensor:" << endl;
cout << x_t << endl;
x_t = x_t.permute({ 2, 0, 1 });
cout << "再调整Tensor的维度顺序:[Height, Width, channels]-->[channels, Height, Width]:" << endl;
cout << x_t << endl;
运⾏结果:
此外,调⽤torch::from_blob函数建⽴的Tensor张量,与传⼊的指针是共⽤内存的,该张量并没有重新开辟⼀段内存,这⼀点需要注意。如果需要开辟内存,则通过调⽤clone函数来执⾏深拷贝:
int aa[4] = { 3,4,6,7 };
auto aaaaa = torch::from_blob(aa, { 2, 2 }, torch::kInt).clone();
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论