基础操作 自动求梯度 1 2 3 4 5 6 7 x = torch.arange(4.0 ) x.requires_grad_(True ) print (x.grad) y = 2 * torch.dot(x, x) y.backward() print (x.grad)
注意 :
1 2 3 4 5 6 7 8 9 10 y = x.sum () y.backward() print (x.grad) x.grad.zero_() y = x.sum () y.backward() print (x.grad)
分离计算 有时,我们希望将某些计算移动到记录的计算图之外。
例如,假设y为x的函数$y=f(x)=x^2$,而z则是作为y和x的函数计算的$z=f(x,y)=x*y=x^3$。 如果我们想计算z关于x的梯度,但希望将y视为一个常数, 只考虑到x在y被计算后发挥的作用。
此时可以定义一个新变量u,该变量与y具有相同的值, 但丢弃计算图中如何计算y的任何信息。 换句话说,梯度不会向后流经u到x。 因此,下面的反向传播函数计算$z=u*x$关于x的偏导数,同时将u作为常数处理, 而不是$z=x^3$关于x的偏导数。
1 2 3 4 5 6 7 x.grad.zero_() y = x * x u = y.detach() z = u * x z.sum ().backward() print (x.grad)
神经网络基本组件 自定义网络层 1 2 3 4 5 6 7 8 9 10 class DiffMeanLayer (nn.Module): """ 一个去除矩阵均值的网络层 """ def __init__ (self ): super ().__init__() def forward (self, X ): return X - X.mean()
1 2 3 4 5 6 7 8 9 10 11 12 13 class diyLinear (nn.Module): """ 一个自定义的全连接层 """ def __init__ (self, in_units, units ): super ().__init__() self.weight = nn.Parameter(torch.randn(in_units, units)) self.bias = nn.Parameter(torch.randn(units,)) def forward (self, X ): linear = torch.matmul(X, self.weight.data) + self.bias.data return F.relu(linear)
网络本体 1 2 3 4 5 6 7 8 9 net = nn.Sequential( nn.Linear(4 , 8 ), nn.ReLU(), nn.Dropout(0.05 ), nn.DiffMeanLayer(), nn.Sigmoid(), nn.diyLinear(8 , 1 ) )
网络参数共享 1 2 3 4 5 6 7 8 shared = nn.Linear(8 , 8 ) net = nn.Sequential( nn.Linear(4 , 8 ), nn.ReLU(), shared, nn.ReLU(), shared, nn.ReLU(), nn.Linear(8 , 1 ) )
网络参数初始化 1 2 3 4 5 6 7 8 9 10 11 net[0 ].weight.data.normal_(0 , 0.01 ) net[0 ].bias.data.fill_(0 ) nn.init.xavier_uniform_(net[0 ].weight) nn.init.constant_(m.weight, 1 ) def init_weights (m ): """如果是全连接层,初始化参数为标准正态分布""" if type (m) == nn.Linear: nn.init.normal_(m.weight, std=0.01 )
损失函数 1 2 3 4 loss = nn.MSELoss() loss = nn.AdaptiveLogSoftmaxWithLoss()
优化器 1 2 3 4 5 6 7 8 9 10 optimzer = torch.optim.SGD(net.parameters(), lr=0.002 ) lambd = 3 optimzer = torch.optim.SGD([ {"params" :net[0 ].weight,'weight_decay' : lambd}, {"params" :net[0 ].bias}], lr=lr )
模型文件读写 张量 1 2 3 4 5 6 7 8 9 10 11 12 x = torch.arange(4 ) torch.save(x, 'x-file' ) torch.save([x,x], 'x-list' ) torch.save({"x" : x}, 'x-dict' ) x2 = torch.load('x-file' ) x_list = torch.load('x-list' ) x_dict = torch.load('x-dict' )
模型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 net = nn.Sequential(nn.Linear(4 , 1 )) nn.init.xavier_uniform_(net[0 ].weight) net[0 ].bias.data.fill_(0 ) X = torch.randn(size=(1 , 4 )) Y = net(X) torch.save(net.state_dict(), 'net.params' ) clone = nn.Linear(4 , 1 ) clone.load_state_dict(torch.load('net.params' )) clone.eval ()
使用GPU运算 这一步应该在你安装pytorch前就应该完成,具体如何安装与配置cuda这里就不多说了,网上有很多教程。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 def try_gpu (i=0 ): """如果存在,则返回gpu(i),否则返回cpu()""" if torch.cuda.device_count() >= i + 1 : return torch.device(f'cuda:{i} ' ) return torch.device('cpu' ) def try_all_gpus (): """返回所有可用的GPU,如果没有GPU,则返回[cpu(),]""" devices = [torch.device(f'cuda:{i} ' ) for i in range (torch.cuda.device_count())] return devices if devices else [torch.device('cpu' )] try_gpu(), try_gpu(10 ), try_all_gpus()
多个gpu时,需要将gpu0中的数据复制至gpu1,才能相互计算。
1 2 3 4 5 6 X = torch.ones(2 , 3 , device=try_gpu(0 )) Y = torch.rand(2 , 3 , device=try_gpu(1 )) Z = X.cuda(1 ) Y + Z
用GPU训练模型 两个要点,把数据迁移至gpu,把模型迁移至gpu
1 2 3 4 5 6 7 8 X = torch.rand(2 , 3 ) X = X.to("cuda" ) print (x.device) net = nn.Linear(3 , 1 ) net = net.to("cuda" ) print (list (net.parameters())[0 ].device)
1 2 3 4 5 6 7 net[0 ].weight.data.normal_(0 ,1 ) net[0 ].bias.data.zero_() net(X)
要注意,只有在比较大的数据上,GPU的又是才能体现,按照样例给的如此小的两个矩阵相乘,计算就很慢,需要十几秒。