

4-1,张量的结构操作
本篇我们介绍张量的结构操作。
张量结构操作主要包括:张量创建,索引切片,维度变换,合并分割。
torch.__version__=2.4.0
一,创建张量
张量创建的许多方法和numpy中创建array的方法很像。
tensor([1., 2., 3.])
tensor([1, 3, 5, 7, 9])
tensor([0.0000, 0.6978, 1.3956, 2.0933, 2.7911, 3.4889, 4.1867, 4.8844, 5.5822, 6.2800])
tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])
tensor([[1, 1, 1], [1, 1, 1], [1, 1, 1]], dtype=torch.int32) tensor([[0., 0., 0.], [0., 0., 0.], [0., 0., 0.]])
tensor([[5., 5., 5.], [5., 5., 5.], [5., 5., 5.]])
tensor([4.9626, 7.6822, 0.8848, 1.3203, 3.0742])
tensor([[ 2.8474, -0.7322, 0.3833], [ 1.1000, -0.0877, 0.4154], [ 0.6426, -2.1881, 0.8920]])
tensor([[ 4.7537, 3.3518, 5.2362], [ 3.2450, 0.3230, 4.2818], [-1.1273, 4.2694, -4.8699]])
tensor([ 1, 11, 19, 14, 12, 6, 5, 9, 8, 18, 15, 4, 2, 3, 7, 13, 0, 10, 16, 17])
tensor([[1., 0., 0.], [0., 1., 0.], [0., 0., 1.]]) tensor([[1, 0, 0], [0, 2, 0], [0, 0, 3]])
二 ,索引切片
张量的索引切片方式和numpy几乎是一样的。切片时支持缺省参数和省略号。
可以通过索引和切片对部分元素进行修改。
此外,对于不规则的切片提取,可以使用torch.index_select, torch.masked_select, torch.take
如果要通过修改张量的某些元素得到新的张量,可以使用torch.where,torch.masked_fill,torch.index_fill
tensor([[4, 7, 0, 1, 3], [6, 4, 8, 4, 6], [3, 4, 0, 1, 2], [5, 6, 8, 1, 2], [6, 9, 3, 8, 4]], dtype=torch.int32)
tensor([4, 7, 0, 1, 3], dtype=torch.int32)
tensor([6, 9, 3, 8, 4], dtype=torch.int32)
tensor(4, dtype=torch.int32) tensor(4, dtype=torch.int32)
tensor([[6, 4, 8, 4, 6], [3, 4, 0, 1, 2], [5, 6, 8, 1, 2]], dtype=torch.int32)
tensor([[6, 8], [3, 0], [5, 8]], dtype=torch.int32)
tensor([[1., 2.], , [0., 0.]])
tensor([[[ 0, 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, 26]]])
tensor([[ 1, 4, 7], [10, 13, 16], [19, 22, 25]])
以上切片方式相对规则,对于不规则的切片提取,可以使用torch.index_select, torch.take, torch.gather, torch.masked_select.
考虑班级成绩册的例子,有4个班级,每个班级5个学生,每个学生7门科目成绩。可以用一个4×5×7的张量来表示。
tensor([[[55, 95, 3, 18, 37, 30, 93], [17, 26, 15, 3, 20, 92, 72], [74, 52, 24, 58, 3, 13, 24], [81, 79, 27, 48, 81, 99, 69], [56, 83, 20, 59, 11, 15, 24]], [[72, 70, 20, 65, 77, 43, 51], [61, 81, 98, 11, 31, 69, 91], [93, 94, 59, 6, 54, 18, 3], [94, 88, 0, 59, 41, 41, 27], [69, 20, 68, 75, 85, 68, 0]], [[17, 74, 60, 10, 21, 97, 83], [28, 37, 2, 49, 12, 11, 47], [57, 29, 79, 19, 95, 84, 7], [37, 52, 57, 61, 69, 52, 25], [73, 2, 20, 37, 25, 32, 9]], [[39, 60, 17, 47, 85, 44, 51], [45, 60, 81, 97, 81, 97, 46], [ 5, 26, 84, 49, 25, 11, 3], [ 7, 39, 77, 77, 1, 81, 10], [39, 29, 40, 40, 5, 6, 42]]], dtype=torch.int32)
tensor([[[55, 95, 3, 18, 37, 30, 93], , [74, 52, 24, 58, 3, 13, 24], , [56, 83, 20, 59, 11, 15, 24]], , , [[72, 70, 20, 65, 77, 43, 51], , [93, 94, 59, 6, 54, 18, 3], , [69, 20, 68, 75, 85, 68, 0]], , , [[17, 74, 60, 10, 21, 97, 83], , [57, 29, 79, 19, 95, 84, 7], , [73, 2, 20, 37, 25, 32, 9]], , , [[39, 60, 17, 47, 85, 44, 51], , [ 5, 26, 84, 49, 25, 11, 3], , [39, 29, 40, 40, 5, 6, 42]]], dtype=torch.int32)
tensor([[[95, 18, 93], [52, 58, 24], [83, 59, 24]], [[70, 65, 51], [94, 6, 3], [20, 75, 0]], [[74, 10, 83], [29, 19, 7], [ 2, 37, 9]], [[60, 47, 51], [26, 49, 3], [29, 40, 42]]], dtype=torch.int32)
tensor([55, 52, 42], dtype=torch.int32)
tensor([95, 93, 92, 81, 81, 99, 83, 81, 98, 91, 93, 94, 94, 88, 85, 97, 83, 95, 84, 85, 81, 97, 81, 97, 84, 81], dtype=torch.int32)
以上这些方法仅能提取张量的部分元素值,但不能更改张量的部分元素值得到新的张量。
如果要通过修改张量的部分元素值得到新的张量,可以使用torch.where,torch.index_fill 和 torch.masked_fill
torch.where可以理解为if的张量版本。
torch.index_fill的选取元素逻辑和torch.index_select相同。
torch.masked_fill的选取元素逻辑和torch.masked_select相同。
tensor([[[0, 1, 0, 0, 0, 0, 1], [0, 0, 0, 0, 0, 1, 1], [1, 0, 0, 0, 0, 0, 0], [1, 1, 0, 0, 1, 1, 1], [0, 1, 0, 0, 0, 0, 0]], [[1, 1, 0, 1, 1, 0, 0], [1, 1, 1, 0, 0, 1, 1], [1, 1, 0, 0, 0, 0, 0], [1, 1, 0, 0, 0, 0, 0], [1, 0, 1, 1, 1, 1, 0]], [[0, 1, 0, 0, 0, 1, 1], [0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 1, 0], [0, 0, 0, 1, 1, 0, 0], [1, 0, 0, 0, 0, 0, 0]], [[0, 0, 0, 0, 1, 0, 0], [0, 0, 1, 1, 1, 1, 0], [0, 0, 1, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0], [0, 0, 0, 0, 0, 0, 0]]])
tensor([[[100, 100, 100, 100, 100, 100, 100], , [ 17, 26, 15, 3, 20, 92, 72], , [100, 100, 100, 100, 100, 100, 100], , [ 81, 79, 27, 48, 81, 99, 69], , [100, 100, 100, 100, 100, 100, 100]], , , [[100, 100, 100, 100, 100, 100, 100], , [ 61, 81, 98, 11, 31, 69, 91], , [100, 100, 100, 100, 100, 100, 100], , [ 94, 88, 0, 59, 41, 41, 27], , [100, 100, 100, 100, 100, 100, 100]], , , [[100, 100, 100, 100, 100, 100, 100], , [ 28, 37, 2, 49, 12, 11, 47], , [100, 100, 100, 100, 100, 100, 100], , [ 37, 52, 57, 61, 69, 52, 25], , [100, 100, 100, 100, 100, 100, 100]], , , [[100, 100, 100, 100, 100, 100, 100], , [ 45, 60, 81, 97, 81, 97, 46], , [100, 100, 100, 100, 100, 100, 100], , [ 7, 39, 77, 77, 1, 81, 10], , [100, 100, 100, 100, 100, 100, 100]]], dtype=torch.int32)
tensor([[[60, 95, 60, 60, 60, 60, 93], , [60, 60, 60, 60, 60, 92, 72], , [74, 60, 60, 60, 60, 60, 60], , [81, 79, 60, 60, 81, 99, 69], , [60, 83, 60, 60, 60, 60, 60]], , , [[72, 70, 60, 65, 77, 60, 60], , [61, 81, 98, 60, 60, 69, 91], , [93, 94, 60, 60, 60, 60, 60], , [94, 88, 60, 60, 60, 60, 60], , [69, 60, 68, 75, 85, 68, 60]], , , [[60, 74, 60, 60, 60, 97, 83], , [60, 60, 60, 60, 60, 60, 60], , [60, 60, 79, 60, 95, 84, 60], , [60, 60, 60, 61, 69, 60, 60], , [73, 60, 60, 60, 60, 60, 60]], , , [[60, 60, 60, 60, 85, 60, 60], , [60, 60, 81, 97, 81, 97, 60], , [60, 60, 84, 60, 60, 60, 60], , [60, 60, 77, 77, 60, 81, 60], , [60, 60, 60, 60, 60, 60, 60]]], dtype=torch.int32)
三,维度变换
维度变换相关函数主要有 torch.reshape(或者调用张量的view方法), torch.squeeze, torch.unsqueeze, torch.transpose
torch.reshape 可以改变张量的形状。
torch.squeeze 可以减少维度。
torch.unsqueeze 可以增加维度。
torch.transpose/torch.permute 可以交换维度。
torch.Size([1, 3, 3, 2]) tensor([[[[126, 195], [ 22, 33], [ 78, 161]], [[124, 228], [116, 161], [ 88, 102]], [[ 5, 43], [ 74, 132], [177, 204]]]], dtype=torch.int32)
torch.Size([3, 6]) tensor([[126, 195, 22, 33, 78, 161], [124, 228, 116, 161, 88, 102], [ 5, 43, 74, 132, 177, 204]], dtype=torch.int32)
tensor([[[[126, 195], [ 22, 33], [ 78, 161]], [[124, 228], [116, 161], [ 88, 102]], [[ 5, 43], [ 74, 132], [177, 204]]]], dtype=torch.int32)
如果张量在某个维度上只有一个元素,利用torch.squeeze可以消除这个维度。
torch.unsqueeze的作用和torch.squeeze的作用相反。
tensor([[1., 2.]]) tensor([1., 2.]) torch.Size([1, 2]) torch.Size([2])
tensor([1., 2.]) tensor([[1., 2.]]) torch.Size([2]) torch.Size([1, 2])
torch.transpose可以交换张量的维度,torch.transpose常用于图片存储格式的变换上。
如果是二维的矩阵,通常会调用矩阵的转置方法 matrix.t(),等价于 torch.transpose(matrix,0,1)。
torch.Size([100, 256, 256, 4]) torch.Size([100, 4, 256, 256])
torch.Size([100, 4, 256, 256])
tensor([[1, 2, 3], [4, 5, 6]]) tensor([[1, 4], [2, 5], [3, 6]])
四,合并分割
可以用torch.cat方法和torch.stack方法将多个张量合并,可以用torch.split方法把一个张量分割成多个张量。
torch.cat和torch.stack有略微的区别,torch.cat是连接,不会增加维度,而torch.stack是堆叠,会增加维度。
torch.Size([6, 2]) tensor([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.], [ 9., 10.], [11., 12.]])
torch.Size([3, 2, 2]) tensor([[[ 1., 2.], [ 3., 4.]], [[ 5., 6.], [ 7., 8.]], [[ 9., 10.], [11., 12.]]])
tensor([[ 1., 2., 5., 6., 9., 10.], , [ 3., 4., 7., 8., 11., 12.]])
tensor([[[ 1., 2.], , [ 5., 6.], , [ 9., 10.]], , , [[ 3., 4.], , [ 7., 8.], , [11., 12.]]])
torch.split是torch.cat的逆运算,可以指定分割份数平均分割,也可以通过指定每份的记录数量进行分割。
tensor([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.], [ 9., 10.], [11., 12.]]) tensor([[1., 2.], [3., 4.]]) tensor([[5., 6.], [7., 8.]]) tensor([[ 9., 10.], [11., 12.]])
tensor([[ 1., 2.], [ 3., 4.], [ 5., 6.], [ 7., 8.], [ 9., 10.], [11., 12.]]) tensor([[1., 2.], [3., 4.], [5., 6.], [7., 8.]]) tensor([[ 9., 10.]]) tensor([[11., 12.]])
如果本书对你有所帮助,想鼓励一下作者,记得给本项目加一颗星星star⭐️,并分享给你的朋友们喔😊!
如果对本书内容理解上有需要进一步和作者交流的地方,欢迎在公众号"算法美食屋"下留言。作者时间和精力有限,会酌情予以回复。
也可以在公众号后台回复关键字:加群,加入读者交流群和大家讨论。



