网页搜索(ctrl+f)
.xx()表示方法,@xx表示类
-xx表示某些内容的关键字
pytorch
.register_buffer()
-参数
注册参数,跟self.xx差不多,注册完的参数可以通过self的方式调用。buffer会调用_apply方法,model.cuda时跟model一起执行cuda()等方法,self.xx不会;而且在stat_dict中不会被注册。
class TT(nn.Module):
def __init__(self, i):
super(TT, self).__init__()
self.x = torch.zeros(i)
self.register_buffer("y", torch.zeros(i))
model = TT((2,3)).cuda()
print(model.x)
print(model.y)
print(model.state_dict())
>>tensor([[0., 0., 0.],
[0., 0., 0.]])
tensor([[0., 0., 0.],
[0., 0., 0.]], device='cuda:0')
OrderedDict([('y', tensor([[0., 0., 0.],
[0., 0., 0.]], device='cuda:0'))])
@LayerNorm
-层标准化-公式-细节
需要注意这里用到的Var。计算的时候根据论文中公式分母是n
而tensor.var()用的分母是n-1
初始化时需要给出需要norm的shape
input为
B
×
d
1
×
d
2
×
d
3
×
d
4
B\times d_1\times d_2\times d_3\times d_4
B×d1×d2×d3×d4,则初始化的shape需要是
d
3
×
d
4
d_3\times d_4
d3×d4或
d
4
d_4
d4这样后面几个连续的维度,所进行的操作就是对后几个维度拉平后求均值和方差
x = torch.randn(4,3,5,6,7)
model = nn.LayerNorm((6,7))
mx = model(x)
b = x.view(4,3,5,-1) # 拉平
a = (b-b.mean(dim=-1, keepdim=True))/torch.sqrt(b.var(dim=-1, keepdim=True, unbiased=False)+1e-5)
a = a.view_as(mx)
print(torch.sum(a-mx))
>>tensor(3.8086e-06, grad_fn=<SumBackward0>)
如果是中间层的高维特征,比如B x 129 x H x W,这个时候考虑到位置因素,往往只在一个像素点上的129个channels上做标准化,由于LayerNorm是对最后的几个维度做标准化,所以需要把中间的输入做permute,把一个像素点上的所有channel全放到最后,然后设置normalization_shape为channel个数
.var()
-方差-细节-公式
unbiased参数控制分母是n还是n-1
a = torch.randn(3,)
v1 = (a-a.mean()).pow(2).mean()
v2 = (a-a.mean()).pow(2).sum()/2
print(v1, a.var(unbiased=False), v2, a.var(unbiased=True))
>>tensor(0.0338) tensor(0.0338) tensor(0.0507) tensor(0.0507)
.cross_entropy()
-高维-损失函数-输入-交叉熵-高维交叉熵
需要注意输入是logits,在函数内包含了softmax的操作,target是long类型的索引;高维时需要注意输入输出的shape需要对应以及channel所在的维度,参考文档
.contiguous()
-连续-内存-性能-解释-view-permute-flatten-stride
出于性能考虑,tensor的数值以行优先顺序存储在内存中,使用permute\transpose方法会得到一个不连续的tensor,这时只是得到一个stride改变了的指针(共享数值和梯度)。而view只能在连续的tensor上操作(并且得到的也是同一个指针,同一内存段两个view后求导,也会加在同一内存上)所以需要contiguous方法从原来的内存中拷贝一份到新内存并且按permute完的shape组合成连续的tensor从而进行view操作。contiguous就是看flatten后和连续内存上的顺序是不是一样的
- 创建一段连续内存view为2 x 3
- permute后仍未那段连续内存,但是stride改变了,所以flatten后顺序改变,不是连续的了
- contiguous后按新的flatten生成一段新的连续内存
- 如果只是view的话,内存仍为原来的内存,数值和梯度共享
a = nn.Parameter(torch.arange(6).view(2,3).float(), requires_grad=True) # No.1
print(a.data_ptr())
print(a)
print(a.flatten(),a.is_contiguous())
b = a.permute(1,0) # No.2
print(b.data_ptr())
print(b)
print(b.flatten(),b.is_contiguous())
b = b.contiguous() # No.3
print(b.data_ptr())
print(b)
print(b.flatten(),b.is_contiguous())
c = a.view(3,2) #No.4
print(c.data_ptr())
print(c)
print(c.flatten(),c.is_contiguous())
>>2625976178048
Parameter containing:
tensor([[0., 1., 2.],
[3., 4., 5.]], requires_grad=True)
tensor([0., 1., 2., 3., 4., 5.], grad_fn=<ViewBackward>) True
2625976178048
tensor([[0., 3.],
[1., 4.],
[2., 5.]], grad_fn=<PermuteBackward>)
tensor([0., 3., 1., 4., 2., 5.], grad_fn=<UnsafeViewBackward>) False
2625976177024
tensor([[0., 3.],
[1., 4.],
[2., 5.]], grad_fn=<CopyBackwards>)
tensor([0., 3., 1., 4., 2., 5.], grad_fn=<ViewBackward>) True
2625976178048
tensor([[0., 1.],
[2., 3.],
[4., 5.]], grad_fn=<ViewBackward>)
tensor([0., 1., 2., 3., 4., 5.], grad_fn=<ViewBackward>) True
# 这个实验可以看出,view的不同结果,梯度是共享的
a = nn.Parameter(torch.arange(6).view(2,3).float(), requires_grad=True)
b = a.view(6,1)
c = a.view(3,2)
d = torch.sum(2*b)+torch.sum(3*c)
d.backward()
print(a.grad)
>>tensor([[0., 1., 2.],
[3., 4., 5.]], requires_grad=True)
tensor([[5., 5., 5.],
[5., 5., 5.]])
.mulitinominal()
-采样-概率-分布
按照给出的离散分布进行采样,给出的probs必须是softmax后的。
如果允许重复采样(replacement=True),概率大的值采样到的次数就多。
如果不允许重复采样,概率大的先采到。(一共2种情况采样5次肯定有重复的)
以上两个都不是绝对的,下图采5次的第3行0的概率比1大却采到的少
probs = torch.randn(4, 2).softmax(dim=1)
print(probs)
sample = torch.multinomial(probs, 2)
print(sample)
sample = torch.multinomial(probs, 5, replacement=True)
print(sample)
>>tensor([[0.5902, 0.4098],
[0.1258, 0.8742],
[0.5257, 0.4743],
[0.1107, 0.8893]])
tensor([[1, 0],
[0, 1],
[0, 1],
[1, 0]])
tensor([[0, 0, 0, 1, 0],
[1, 1, 1, 1, 1],
[1, 0, 0, 1, 1],
[0, 1, 1, 0, 1]])
.expand()
-扩展-区别-内存
对tensor进行扩展,只能对某个维度为1的维度上进行扩展,跟广播基本一个意思,不开辟新内存,只是将stride改变,如果原数据的发生改变,则expand后的数据同时改变。
.repeat()
-重复-内存
同样是对tensor进行扩展,可以以原tensor作为一个元进行高维扩展,2 x 3的tensor扩展为3 x 3则扩展后的tensor为6 x 9。开辟新内存(但是梯度会落回原tensor)
a = nn.Parameter(torch.arange(3).view(3,1).float(), requires_grad=True)
b = a.expand(3,4)
c = a.repeat(2,4) # 3 x 1的扩展2 x 4后为6 x 4
print(a.data_ptr(),b.data_ptr(),c.data_ptr())
print(b)
print(c)
with torch.no_grad():
a[0,0] = 3
print(b)
print(c)
>>2224894900800 2224894900800 2224868503680
tensor([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.]], grad_fn=<ExpandBackward>)
tensor([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.]], grad_fn=<RepeatBackward>)
tensor([[3., 3., 3., 3.],
[1., 1., 1., 1.],
[2., 2., 2., 2.]], grad_fn=<AsStridedBackward>)
tensor([[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.],
[0., 0., 0., 0.],
[1., 1., 1., 1.],
[2., 2., 2., 2.]], grad_fn=<RepeatBackward>)
.data_ptr()
-调试-指针-内存
得到tensor的内存地址,便于调试时看函数是否开辟新的内存还是对原tensor进行浅拷贝。
@summary
-模型结构-参数-输入输出大小-结构可视化
将模型的参数信息打印出来,第二个参数为一个样本的shape(不带B的维度)
from torchsummary import summary
summary(model.net, (1,20,20))
>>----------------------------------------------------------------
Layer (type) Output Shape Param #
================================================================
MaskConv-1 [-1, 64, 18, 18] 3,200
LayerNorm-2 [-1, 64, 18, 18] 128
...
...
LeakyReLU-40 [-1, 64, 18, 18] 0
MaskConv-41 [-1, 15, 18, 18] 975
================================================================
Total params: 226,447
Trainable params: 226,447
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 5.10
Params size (MB): 0.86
Estimated Total Size (MB): 5.96
----------------------------------------------------------------
python
@enumerate
-迭代
包装一个可迭代的对象,得到同时得到索引和内容
a = ['a', 'b', 'c', 'd']
for i,j in enumerate(a):
print(i, j)
>>0 a
1 b
2 c
3 d
numpy
matplotlib
argparse
模板
parser = argparse.ArgumentParser()
parser.add_argument(’–dataset’, default=‘FLO’, help=‘FLO’)
…
一系列参数
…
opt = parser.parse_args()
参数详情
需求
pytorch指定使用哪块GPU
os.environ['CUDA_VISIBLE_DEVICES']= '0' # 指定0号GPU默认情况
将参数列表连接起来
from itertools import chain
chain(a.parameters(), b.parameters(), c.parameters())
便于多个模型统一设置optimizer
动态变化学习率
for g in optimizer.param_groups:
g['lr'] = f(g['lr'], epoch) # 根据epoch动态得到学习率