- reshape, view, stacking, squeeze(), unsqueeze(),permute()
- torch.tensor 和 numpy 的 array
- 切片,张量里面获取元素值
- 随机种子
1 导入torch
import torch
2 reshape()
tensor_A = torch.arange(1, 11)
tensor_A
tensor_A.reshape(2, 5)
tensor_A.reshape(2, 5)
tensor([[ 1, 2, 3, 4, 5],
[ 6, 7, 8, 9, 10]])
tensor_A.reshape(1, 10)
tensor([[ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]])
tensor_A.reshape(10, 1)
tensor([[ 1],
[ 2],
[ 3],
[ 4],
[ 5],
[ 6],
[ 7],
[ 8],
[ 9],
[10]])
tensor_A.reshape(1, 9)
##### 发现了吗? tensor_A 的每一个成功的reshape,括号中元素乘积都等于 tensor_A 中元素的个数(10)
而失败的 reshape 的乘积为 9 ,所以失败了
告诉我们元素要兼容,就是我可以将你这个 tensor 换个形状, 但你不能多元素也不能少元素, 就是说不能无中生有,也不能顺手牵羊
3 view
tensor_C = torch.arange(1, 10)
tensor_C
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
x = tensor_C.view(3, 3)
x
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
print(tensor_C, tensor_C.shape)
tensor_reshaped = tensor_C.reshape(3, 3)
tensor_viewed = tensor_C.view(3,3)
print(tensor_C, tensor_C.shape)
print(tensor_reshaped, tensor_reshaped.shape)
print(tensor_viewed, tensor_viewed.shape)
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]) torch.Size([9])
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9]) torch.Size([9])
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]) torch.Size([3, 3])
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]) torch.Size([3, 3])
我刚开始还是没看出来 view和 reshape的区别,因为你看,是不是都将原来的张量的形状改变了
x = tensor_C.view(1, 9)
x
tensor([[1, 2, 3, 4, 5, 6, 7, 8, 9]])
好,接下来我们改变 x 中的值,注意这里的 x 是 view 之后的值
x[:,8] = 500
x, tensor_C
(tensor([[ 1, 2, 3, 4, 5, 6, 7, 8, 500]]),
tensor([ 1, 2, 3, 4, 5, 6, 7, 8, 500]))
发现了不, 我改变 view 之后的张量的值,原来的 tensor_C 张量的值也发生了改变,提问:这说明了什么?哎,这说明了什么?
答:这说明了我们俩改的就是同一个东西,即改的内容是内存中同一个地址单元的值
没错,这就是 view 和 reshape 在改变张量形状之间的区别,好,我们用 reshape 做个实验瞅瞅
tensor_D = torch.arange(1, 10)
tensor_D
tensor([1, 2, 3, 4, 5, 6, 7, 8, 9])
y = tensor_D.reshape(3, 3)
y
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
ok, 咱么来改变一下 y 的值,看看原来的 tensor_D 有没有变化, 有变化说明什么?哎,对,说明和view一样
没有变化呢,对,没错,没有变化就说明他俩的区别,一个表示同一个内存里的值, 一个啥也不是,简单的改变一下形状
y[2:3] = 500
y, tensor_D
不是,怎么 reshape 和 view 一样啊
反正在这里看是一样的,等之后遇到问题再说吧,这里的数据都是连续的昂,注意注意
(tensor([[ 1, 2, 3],
[ 4, 5, 6],
[500, 500, 500]]),
tensor([ 1, 2, 3, 4, 5, 6, 500, 500, 500]))
4 stacking
让我们来学习一下张量的堆叠
先创建一个我们需要堆叠的张量
z = torch.arange(2, 50, step=10)
z
tensor([ 2, 12, 22, 32, 42])
这里要注意, torch.stack(), 第一个参数是一个 tuple, 要堆叠多少个张量就填几个该张量
tensor_stacked = torch.stack((z,z,z,z,z), dim=0)
tensor_stacked
tensor([[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42]])
可以看出来, dim=0,表示是堆叠行
tensor_stacked = torch.stack((z, z, z, z), dim=1)
tensor_stacked
tensor([[ 2, 2, 2, 2],
[12, 12, 12, 12],
[22, 22, 22, 22],
[32, 32, 32, 32],
[42, 42, 42, 42]])
dim=1, 表示堆叠列
tensor_stacked = torch.stack((z, z, z, z), dim=2)
tensor_stacked
好,这里试验了一下,报错了,说是[-2,1]之间, 咱们试试看看
tensor_stacked = torch.stack((z, z, z, z), dim=-2)
tensor_stacked
tensor([[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42],
[ 2, 12, 22, 32, 42]])
tensor_stacked = torch.stack((z, z, z, z), dim=-1)
tensor_stacked
tensor([[ 2, 2, 2, 2],
[12, 12, 12, 12],
[22, 22, 22, 22],
[32, 32, 32, 32],
[42, 42, 42, 42]])
从上面的代码和实验结果,咱们不难发现,dim = -2 和 dim = 0是一样的, dim = -1 和 dim = 1是一样的,好记好记得,两个1是列就可以啦
5 squeeze()
去掉单维,使得张量中只有高于一维的
a = torch.ones(1, 3, 3)
a, a.shape
(tensor([[[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]]),
torch.Size([1, 3, 3]))
tensor_squeezed = a.squeeze()
tensor_squeezed, tensor_squeezed.shape
(tensor([[1., 1., 1.],
[1., 1., 1.],
[1., 1., 1.]]),
torch.Size([3, 3]))
看见没,两个张量的 shape 中,是不是 squeeze 之后,单维的没了,就是为 1 的没了
咱们再试一个看看
b = torch.rand(1, 1, 1, 3, 4)
b, b.shape
(tensor([[[[[0.1872, 0.7857, 0.0147, 0.0184],
[0.7243, 0.0842, 0.8350, 0.3980],
[0.6132, 0.1699, 0.5776, 0.1239]]]]]),
torch.Size([1, 1, 1, 3, 4]))
tensor_squeezed = b.squeeze()
tensor_squeezed, tensor_squeezed.shape
(tensor([[0.1872, 0.7857, 0.0147, 0.0184],
[0.7243, 0.0842, 0.8350, 0.3980],
[0.6132, 0.1699, 0.5776, 0.1239]]),
torch.Size([3, 4]))
6 unsqueeze()
张量的扩张,咱们来看看咋扩张的呢
tensor_unsqueezed = tensor_squeezed.unsqueeze(dim=0)
tensor_unsqueezed, tensor_unsqueezed.shape
(tensor([[[0.1872, 0.7857, 0.0147, 0.0184]],
[[0.7243, 0.0842, 0.8350, 0.3980]],
[[0.6132, 0.1699, 0.5776, 0.1239]]]),
torch.Size([3, 1, 4]))
tensor_unsqueezed = tensor_squeezed.unsqueeze(dim=1)
tensor_unsqueezed, tensor_unsqueezed.shape
(tensor([[[0.1872, 0.7857, 0.0147, 0.0184]],
[[0.7243, 0.0842, 0.8350, 0.3980]],
[[0.6132, 0.1699, 0.5776, 0.1239]]]),
torch.Size([3, 1, 4]))
tensor_unsqueezed = tensor_squeezed.unsqueeze(dim=2)
tensor_unsqueezed, tensor_unsqueezed.shape
(tensor([[[0.1872],
[0.7857],
[0.0147],
[0.0184]],
[[0.7243],
[0.0842],
[0.8350],
[0.3980]],
[[0.6132],
[0.1699],
[0.5776],
[0.1239]]]),
torch.Size([3, 4, 1]))
tensor_unsqueezed = tensor_squeezed.unsqueeze(dim=3)
tensor_unsqueezed, tensor_unsqueezed.shape
好,相信通过实验都懂了,unsqueeze(dim = ) 这个函数中必须要有dim的值,同时注意 dim 的范围
这个范围也很好理解,看我们刚开始的张量形状是 torch.Size([3, 4]) 3的维度是0, 4的维度是1,
那我们选择一个地方插入一维向量,0就插入最左边, 1就插入中间,2就插入最右边,相信很好理解啊
7 torch.permute(input, dims)
作用是调换三个维度的值,看例子咱们就瞬间明白了
tensor = torch.rand(size=(224, 224, 3)) # weight, height, color_channel
tensor_permuted = torch.permute(tensor, (2, 0, 1))
print(f"tensor shape:{tensor.shape}")
print(f"tensor_permuted shape:{tensor_permuted.shape}")
tensor shape:torch.Size([224, 224, 3])
tensor_permuted shape:torch.Size([3, 224, 224])
看结果是不是调换顺序啦!对,torch.permute(input, dims) 就是这个意思
torch.tensor 和 numpy 的 array
torch.form_numpy(ndarry) numpy array-> tensor
torch.Tensor.numpy() tensor->array
OK, 接下来我们来学习一下, torch 里面的张量和 numpy 里面的array
8 先导入包numpy
import numpy as np
tensor = torch.arange(1., 10.)
array = np.arange(1., 10.)
print(f"tensor:\n{tensor},{tensor.dtype}")
print(f"\narray:\n{array},{array.dtype}")
tensor:
tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.]),torch.float32
array:
[1. 2. 3. 4. 5. 6. 7. 8. 9.],float64
array 怎么转换为 torch 中的tensor呢
array_to_tensor = torch.from_numpy(array)
array_to_tensor
tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=torch.float64)
注意到这里的 dtype=torch.float64 是因为从上面可以看出 array 的默认数据类型是 float64, 不是张量的默认数据类型
我们可以修改数据类型
array_to_tensor = array_to_tensor.type(torch.float32)
array_to_tensor.dtype
torch.float32
tensor 转换为 array
tensor_to_array = torch.Tensor.numpy(tensor)
tensor_to_array
array([1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32)
array = array + 1
array, array_to_tensor
(array([ 2., 3., 4., 5., 6., 7., 8., 9., 10.]),
tensor([1., 2., 3., 4., 5., 6., 7., 8., 9.]))
tensor = tensor + 1
tensor, tensor_to_array
(tensor([ 2., 3., 4., 5., 6., 7., 8., 9., 10.]),
array([1., 2., 3., 4., 5., 6., 7., 8., 9.], dtype=float32))
从上面我们可以看出,转换的数据与原来的数据不相关
9 切片,张量里面获取元素值
有时候,我们需要从张量中获取特定的元素,比如:第一列或者第二行,所以这个时候我们就需要进行切片操作了
创建一个tensor
x = torch.arange(1, 10).reshape(1, 3, 3)
x
tensor([[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]])
切片顺序是从外部再到里面的
让我们一步一步的开始切片吧
print(f"first square bracket:\n{x[0]}")
print(f"second square bracket:\n{x[0][0]}")
print(f"third square bracket:\n{x[0][0][0]}")
first square bracket:
tensor([[1, 2, 3],
[4, 5, 6],
[7, 8, 9]])
second square bracket:
tensor([1, 2, 3])
third square bracket:
1
我老是把它写成x[0:0:0],试一下好吧,好像不对
x[0:0:0]
这里还有一个步长
x[0:0:1]
反正引以为戒,不要学我老写错
tensor([], size=(0, 3, 3), dtype=torch.int64)
使用’:‘来特指这个维度的所有值,然后使用’,'来增加其它的维度
获得 第0维 和 第一维的索引0的值
x,x[:,0],x.shape
获得所有 第0维 和 第1维 但是只有 第2维 的索引为 1 的值
x[:,:,1]
tensor([[2, 5, 8]])
获得 第0维 的值但只有 第一维 和 第二维 索引为 1 的值
x[:,1,1]
tensor([5])
获得第一维和第二维索引为0的值,然后所有第二维的值
x,x[0, 0, :]
(tensor([[[1, 2, 3],
[4, 5, 6],
[7, 8, 9]]]),
tensor([1, 2, 3]))
10 结果的可复现性,随机种子
大家相比应该都知道,我们做实验的时候需要噪声数据来增加模型的泛化性
那如果我们需要复现结果时,随机数字不固定的话,是很难进行复现的
所以我们需要随机种子,这样它的结果就是固定的
tensor_E = torch.rand(3,4)
tensor_F = torch.rand(3,4)
print(tensor_E == tensor_F)
tensor([[False, False, False, False],
[False, False, False, False],
[False, False, False, False]])
使用随机种子
SEEDNUM = 42 #随便什么值都可以捏
torch.manual_seed(SEEDNUM)
tensor_E = torch.rand(3,4)
tensor_F = torch.rand(3,4)
print(tensor_E == tensor_F)
tensor([[False, False, False, False],
[False, False, False, False],
[False, False, False, False]])
怎么个事,怎么不一样, 好,原来是每使用一次都需要随机种子
SEEDNUM = 42 #随便什么值都可以捏
torch.manual_seed(SEEDNUM)
tensor_E = torch.rand(3,4)
torch.manual_seed(SEEDNUM)
tensor_F = torch.rand(3,4)
print(tensor_E == tensor_F)
tensor([[True, True, True, True],
[True, True, True, True],
[True, True, True, True]])
好,这一下是不是都相等啦!
11 总结一下
咱们学习了
(1) reshape, view, squeeze(), unsqueeze(), permute()
(2) array 和 tensor 的转化
(3) 切片, 随机种子
妈呀,今天我咋学了这么多呢,根本搞不完,明天搞咯,都没时间洗澡了,忙得很
今天被黄焖鸡那个服务员气炸了,不过,没关系,晚上咱们吃的锅包肉很好吃,毛血旺里面都没有什么肉肉,猪血还挺好吃的呢