创建已知分布的张量
正态分布(Normal Distribution)和均匀分布(Uniform Distribution)是最常见的分布之一,创建采样自这 2 个分布的张量非常有用,「比如在卷积神经网络中,卷积核张量
初始化为正态分布有利于网络的训练;在对抗生成网络中,隐藏变量
一般采样自均匀分布。」
通过torch.normal(mean,std,generator=None,out=None)
可以创建均值为 mean,标准差为 std 的正态分布
,先来简单看一看这些参数:
- mean(Tensor) - 传入参数 mean 的张量中的每个元素都是对应输出元素的正态分布的均值;
- std(Tensor) - 传入参数 std 的张量中的每个元素都是对应输出元素的正态分布的标准差;
- generator = None(torch.Generator, optional) - 用于采样的伪随机数,可以暂时不用关注;
- out = None(Tensor, optional) - 指定输出的张量。比如执行
torch.normal(mean = torch.tensor(0.), std = torch.tensor(1.), out = tensor_a)
,相当于执行tensor_a = torch.normal(mean = torch.tensor(0.), std = torch.tensor(1.))
;
torch.normal(mean,std,generator=None,out=None)
函数传入的 mean 和 std 参数的两个张量的形状不一定要匹配,但是这两个张量中的元素总个数必须相等,「这里需要注意此时两个张量中的元素总个数必须相等不仅仅包括显式的相等,还包含隐式的相等。」
- 显式相等非常好理解,简单来说就是传入张量的元素总个数相等。比如传入参数 mean 的张量形状为 [1, 4],那么传入参数 std 的张量形状必须是 [1, 4]、[2, 2]、[4, 1] 中的任意一个,必须满足 mean.numel() == std.numel()(tensor.numel() 函数返回 tensor 中的元素个数);
- 隐式相等其实就是 PyTorch 中的广播机制,PyTorch 中的广播机制和 TensorFlow 以及 Numpy 中的广播机制类似。比如传入参数 mean 的张量形状为 [1, 2],而传入参数 std 的张量形状为 [2, 2],PyTorch 会根据广播机制的规则将传入 mean 参数的张量形状广播成 [2, 2]。「虽然传入的两个张量元素总个数不相等,但是通过 PyTorch 中的广播机制可以将符合广播机制的张量扩展成相同元素总个数的两个张量;」
>>> import torch
>>> # 传入mean和std的两个张量:
>>> # 1. 形状不匹配
>>> # 2. 两个张量中的元素个数显式相等
>>> normal_a = torch.normal(mean = torch.full([1, 4], 0.),std = torch.full([2, 2], 1.))
>>> print(normal_a.size())
torch.Size([1, 4])
>>> print(normal_a)
tensor([[-1.7489, -1.4797, 1.1246, 0.4521]])
>>> # 传入mean和std的两个张量:
>>> # 1. 形状不匹配
>>> # 2. 两个张量中的元素个数显式不相等,但是符合广播机制的规则
>>> normal_b = torch.normal(mean = torch.full([1, 2], 0.),std = torch.full([2, 2], 1.))
>>> print(normal_b.size())
torch.Size([2, 2])
>>> print(normal_b)
tensor([[-1.1370, -1.1644],
[-1.5242, -0.9315]])
>>> # 传入mean和std的两个张量:
>>> # 1. 形状不匹配
>>> # 2. 两个张量中的元素个数显式不相等,且不符合广播机制的规则
>>> # 程序会报错error
>>> # normal_c = torch.normal(mean = torch.full([1, 3], 0.),
>>> # std = torch.full([2, 2], 1.))
PyTorch 的官方文档中强调:"当输入参数 mean 和 std 的张量形状不匹配的时候,输出张量的形状由传入 mean 参数的张量形状所决定。"通过前面的介绍后这句话非常好理解,因为不管传入 mean 和 std 参数的张量形状如何,只要代码正确,最终都会被转换为相同的形状。
不过有可能会有 UserWarning 的警告(我的 PyTorch 为 1.5),这个警告因为 torch.normal(mean = torch.full((1, 4), 0.),std = torch.full((2, 2), 1.))
代码段,「这是因为当传入的两个张量形状不匹配,但是元素总个数相等的情况下,PyTorch 会使用 reshape 函数将传入参数 std 的张量形状改变成和传入 mean 参数张量相同的形状,这可能会引发一些问题,所以在 PyTorch 1.6 以后的版本这种方法将会舍弃,这里只需要注意一下即可。」
通过torch.randint(low=0,high,size,generator=None,out=None,dtype=None,layout=torch.strided,device=None,requires_grad=False)
函数能够创建采样自 [low, high) 区间(包左不包右)的均匀分布的张量,函数中的很多参数都介绍过,这里不再赘述,这里只关注 low 和 high 两个参数。
- low(int, optional) - 从均匀分布中采样的最小整数,默认为 0;
- high(int) - 从均匀分布中采样的最大整数,不包括最大整数;
>>> import torch
>>> # 创建采样自[1, 10)均匀分布的0D张量
>>> scalar_a = torch.randint(1, 10, ())
>>> print(scalar_a.size())
torch.Size([])
>>> print(scalar_a)
tensor(4)
>>> # 创建采样自[2, 5)均匀分布的1D张量
>>> vec_b = torch.randint(2, 5, (3, ))
>>> print(vec_b.size())
torch.Size([3])
>>> print(vec_b)
tensor([2, 2, 2])
>>> # 创建采样自[0, 10)均匀分布的2D张量
>>> mat_c = torch.randint(10, (2, 2))
>>> print(mat_c.size())
torch.Size([2, 2])
>>> print(mat_c)
tensor([[3, 8],
[4, 2]])
通过torch.randint(low,high,size)
函数创建采样自 [low, high) 均匀分布的 0D 张量、1D 张量和 2D 张量,创建 nD 张量与之类似,这里不再赘述。*size 参数指定创建张量的形状。
torch.normal() 函数相对比较复杂,而 torch.randint() 函数和前面介绍的函数类似,只不过需要指定采样的区间范围。针对比较常见的标准正态分布和采样自 [0, 1)区间的均匀分布,PyTorch 又提供了torch.randn(*size,out=None,dtype=None,layout=torch.strided,device=None,requires_grad=False)
和torch.rand(*size,out=None,dtype=None,layout=torch.strided,device=None,requires_grad=False)
两个函数。
>>> import torch
>>> # 创建采样自均值0.标准差1.正态分布的2D张量
>>> # 等价torch.normal(mean = torch.full([2, 2], 0.)
>>> # std = torch.full([2, 2], 1.))
>>> normal_a = torch.randn([2, 2])
>>> print(normal_a)
tensor([[-0.4471, -0.2377],
[ 0.6442, -0.1024]])
>>> # 创建采样自[0, 1)均匀分布的2D张量
>>> # !不等价torch.randint(0, 1, [2, 2])
>>> uniform_b = torch.rand([2, 2])
>>> print(uniform_b)
tensor([[0.9690, 0.6938],
[0.1431, 0.4861]])
还有一点需要注意:「torch.randint() 函数只能采样指定范围均匀分布的整数,而 torch.rand() 函数能够采样 [0, 1) 范围内均匀分布的浮点数,如果你想要采样自指定范围内的浮点数,可以使用 torch.rand() 函数进行改造,不过最简单的方法就是使用torch.nn.init.uniform_(tensor,a=0.0,b=1.0)
函数。」
比如创建一个采样自 [2, 10) 范围均匀分布且形状为 [2, 2] 的 2D 张量。
代码语言:javascript复制>>> import torch
>>> uniform_c = torch.FloatTensor(2, 2).uniform_(2, 10)
>>> print(uniform_c)
tensor([[8.9692, 6.4037],
[4.4121, 7.0056]])
Tips:
- 增添了自己的理解与看法
- 龙良曲深度学习与PyTorch入门实战:https://study.163.com/course/introduction/1208894818.htm