一.归一化
归一化的原因:不同评价指标(即特征向量中的不同特征就是所述的不同评价指标)往往具有不同的量纲和量纲单位,这样的情况会影响到数据分析的结果,为了消除指标之间的量纲影响,需要进行数据标准化处理,以解决数据指标之间的可比性。
归一化的目的:就是使得预处理的数据被限定在一定的范围内(比如[0,1]或者[-1,1]),从而消除奇异样本数据导致的不良影响。
所有TorchVision 数据集都有两个参数
transform
修改特征
target_transform
修改标签 - 接受包含转换逻辑的可调用对象。
对于训练,我们需要将特征作为归一化张量,将标签作为单热编码张量。为了进行这些转换,我们使用ToTensor
和Lambda
。
transform=ToTensor(),
target_transform=Lambda(lambda y: torch.zeros(10, dtype=torch.float).scatter_(0, torch.tensor(y), value=1))
注意:ToTensor 将 PIL 图像或 NumPyndarray
转换为FloatTensor
. 并在 [0., 1.] 范围内缩放图像的像素强度值;
Lambda 转换适用于任何用户定义的 lambda 函数。在这里,我们定义了一个函数来将整数转换为单热编码的张量。它首先创建一个大小为 10(我们数据集中的标签数量)的零张量,并调用 scatter_,它value=1
在标签给定的索引上分配 a y
二.维度变换
2.1 squeeze vs unsqueeze 维度增减
squeeze()
:对 tensor 进行维度的压缩,去掉维数为1
的维度。用法:torch.squeeze(a)
将 a 中所有为 1 的维度都删除,或者a.squeeze(1)
是去掉a
中指定的维数为1
的维度。unsqueeze()
:对数据维度进行扩充,给指定位置加上维数为1
的维度。用法:torch.unsqueeze(a, N)
,或者a.unsqueeze(N)
,在a
中指定位置N
加上一个维数为1
的维度。
squeeze
用例程序如下:
a = torch.rand(1,1,3,3)
b = torch.squeeze(a)
c = a.squeeze(1)
print(b.shape)
print(c.shape)
程序输出结果如下:
torch.Size([3, 3]) torch.Size([1, 3, 3])
unsqueeze
用例程序如下:
x = torch.rand(3,3)
y1 = torch.unsqueeze(x, 0)
y2 = x.unsqueeze(0)
print(y1.shape)
print(y2.shape)
程序输出结果如下:
torch.Size([1, 3, 3]) torch.Size([1, 3, 3])
2.2 transpose vs permute 维度交换
torch.transpose()
只能交换两个维度,而 .permute()
可以自由交换任意位置。函数定义如下:
transpose(dim0, dim1) → Tensor # See torch.transpose()
permute(*dims) → Tensor # dim(int). Returns a view of the original tensor with its dimensions permuted.
在 CNN
模型中,我们经常遇到交换维度的问题,举例:四个维度表示的 tensor:[batch, channel, h, w]
(nchw
),如果想把 channel
放到最后去,形成[batch, h, w, channel]
(nhwc
),如果使用 torch.transpose()
方法,至少要交换两次(先 1 3
交换再 1 2
交换),而使用 .permute()
方法只需一次操作,更加方便。例子程序如下:
import torch
input = torch.rand(1,3,28,32) # torch.Size([1, 3, 28, 32]
print(b.transpose(1, 3).shape) # torch.Size([1, 32, 28, 3])
print(b.transpose(1, 3).transpose(1, 2).shape) # torch.Size([1, 28, 32, 3])
print(b.permute(0,2,3,1).shape) # torch.Size([1, 28, 28, 3]
三.合并分割
3.1,torch.cat 和 torch.stack
可以用 torch.cat
方法和 torch.stack
方法将多个张量合并,也可以用 torch.split
方法把一个张量分割成多个张量。torch.cat
和 torch.stack
有略微的区别,torch.cat
是连接,不会增加维度,而 torch.stack
是堆叠,会增加一个维度。
>>> a = torch.arange(0,9).view(3,3)
>>> b = torch.arange(10,19).view(3,3)
>>> c = torch.arange(20,29).view(3,3)
>>> cat_abc = torch.cat([a,b,c], dim=0)
>>> print(cat_abc.shape)
torch.Size([9, 3])
>>> print(cat_abc)
tensor([[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8],
[10, 11, 12],
[13, 14, 15],
[16, 17, 18],
[20, 21, 22],
[23, 24, 25],
[26, 27, 28]])
>>> stack_abc = torch.stack([a,b,c], axis=0) # torch中dim和axis参数名可以混用
>>> print(stack_abc.shape)
torch.Size([3, 3, 3])
>>> print(stack_abc)
tensor([[[ 0, 1, 2],
[ 3, 4, 5],
[ 6, 7, 8]],
[[10, 11, 12],
[13, 14, 15],
[16, 17, 18]],
[[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]])
>>> chunk_abc = torch.chunk(cat_abc, 3, dim=0)
>>> chunk_abc
(tensor([[0, 1, 2],
[3, 4, 5],
[6, 7, 8]]),
tensor([[10, 11, 12],
[13, 14, 15],
[16, 17, 18]]),
tensor([[20, 21, 22],
[23, 24, 25],
[26, 27, 28]]))
3.2,torch.split 和 torch.chunk
torch.split()
和 torch.chunk()
可以看作是 torch.cat()
的逆运算。
split()
作用是将张量拆分为多个块,每个块都是原始张量的视图。
torch.split(tensor, split_size_or_sections, dim=0)
chunk()
作用是将 tensor
按 dim
(行或列)分割成 chunks
个 tensor
块,返回的是一个元组。
torch.chunk(input, chunks, dim=0) → List of Tensors
实例如下:
>>> a = torch.arange(10).reshape(5,2)
>>> a
tensor([[0, 1],
[2, 3],
[4, 5],
[6, 7],
[8, 9]])
>>> torch.split(a, 2)
(tensor([[0, 1],
[2, 3]]),
tensor([[4, 5],
[6, 7]]),
tensor([[8, 9]]))
>>> torch.split(a, [1,4])
(tensor([[0, 1]]),
tensor([[2, 3],
[4, 5],
[6, 7],
[8, 9]]))
>>> torch.chunk(a, 2, dim=1)
(tensor([[0],
[2],
[4],
[6],
[8]]),
tensor([[1],
[3],
[5],
[7],
[9]]))