1.numpy和pytorch实现梯度下降法
1 import numpy as np 2 3 # N is batch size; 4 N, D_in, H, D_out = 64, 1000, 100, 10 5 6 # 输入输出数据的随机初始化 7 x = np.random.randn(N, D_in) 8 y = np.random.randn(N, D_out) 9 10 # 权值的随机初试化 11 w1 = np.random.randn(D_in, H) 12 w2 = np.random.randn(H, D_out) 13 14 learning_rate = 1e-6 15 for t in range(500): 16 # 前向传播 17 h = x.dot(w1) 18 h_relu = np.maximum(h, 0) 19 y_pred = h_relu.dot(w2) 20 21 # 计算并打印损失 22 loss = np.square(y_pred-y).sum() 23 print(t, loss) 24 25 #根据损失,计算梯度 26 grad_y_pred = 2.0 * (y_pred-y) 27 grad_w2 = h_relu.T.dot(grad_y_pred) 28 grad_h_relu = grad_y_pred.dot(w2.T) 29 grad_h = grad_h_relu.copy() 30 grad_h[h<0] = 0 31 grad_w1 = x.T.dot(grad_h) 32 33 #更新权重 34 w1 -= learning_rate * grad_w1 35 w2 -= learning_rate * grad_w2
torch
1 import torch 2 3 dtype = torch.float 4 device = torch.device("cpu") 5 # device = touch.device("cuda:0") #当运行在GPU时,要加上这行代码 6 7 # N是batch size;D_in是输入的维度 8 # H是隐藏层的维度;D_out是输出的维度 9 N, D_in, H, D_out = 64, 1000, 100, 10 10 11 # 构造随机生成的输入和输出数据 12 # 设置requires_grad=False,表明在后向传播时,我们不需要计算关于这些张量的梯度 13 x = torch.randn(N, D_in, device=device, dtype=dtype) 14 y = torch.randn(H, D_out, device=device, dtype=dtype) 15 16 # 网络权重随机初始化 17 # 设置requires_grad=True,表明在后向传播时,我们需要计算关于这些张量的梯度 18 w1 = torch.randn(D_in, H, device=device, dtype=dtype, requires_grad=True) 19 w2 = torch.randn(H, D_out, device=device, dtype=dtype, requires_grad=True) 20 21 # 学习率 22 learing_rate = 1e-6 23 for t in range(500): 24 # 前向传播:这些与我们使用tensors计算正向传播的操作完全相同,但是我们不需要 25 # 保留对中间值的引用,因为我们没有手动实现反向传播。 26 y_pred = x.mm(w1).clamp(min=0).mm(w2) 27 28 # 使用tensor操作计算并打印损失 29 # 现在loss是一个shape(1,)类型的张量 30 # loss.item()可以获取loss中保存的标量值 31 loss = (y_pred - y).pow(2).sum() 32 print(t, loss.item()) 33 34 # 使用autograd来计算后向传播;这个调用将计算相对于所有requires_grad=True的 35 # 张量的损失的梯度。 36 # After this call w1.grad and w2.grad will be Tensors holding the gradient 37 # of the loss with respect to w1 and w2 respectively. 38 loss.backward() 39 40 # 使用梯度下降手动更新权重。之所以封装于torch.no_grad(),是因为权重的 41 # requires_grad=True,而我们在自动微分中没有必要跟踪这些; 42 # 另一种可选择的操作是operate on weight.data and weight.grad.data. 43 # You can also use torch.optim.SGD to achieve this. 44 with torch.no_grad(): 45 w1 -= learning_rate * w1.grad 46 w2 -= learning_rate * w2.grad 47 48 # 更新权重之后,手动将梯度设置为0 49 w1.grad.zero_() 50 w2.grad.zero_()
2.设定初始值
神经网络的权重初始化方法对模型的收敛速度和性能有着至关重要的影响。主要有四种权重初始化方法:
把w初始化为0
在线性回归,logistics回归中,基本上把参数初始化为0,模型也能很好的工作。但是在神经网络中,这种方法是不可行的。如果把w初始化为0,那么每一层的神经元学到的东西都是一样的。
对w随机初始化
对w进行随机初始化时,要初始化到一个相对较小的值,因为如果X很大的话,W又相对较大,会导致Z非常大,这样如果激活函数是sigmoid,就会导致sigmoid的输出值1或者0,然后会导致一系列问题。但是随机初始化也有缺点,np.random.randn()其实是一个均值为0,方差为1的高斯分布中采样。当神经网络的层数增多时,会发现越往后面的层的激活函数(使用tanH)的输出值几乎都接近于0 。
Xavier initialization
Xavier initialization是 Glorot 等人为了解决随机初始化的问题提出来的另一种初始化方法,他们的思想倒也简单,就是尽可能的让输入和输出服从相同的分布,这样就能够避免后面层的激活函数的输出值趋向于0。虽然Xavier initialization能够很好的 tanH 激活函数,但是对于目前神经网络中最常用的ReLU激活函数,还是无能为力。
He initialization
为了解决上面的问题,我们的何恺明大神提出了一种针对ReLU的初始化方法,一般称作 He initialization。
现在神经网络中,隐藏层常使用ReLU,权重初始化常用He initialization这种方法。
3.求取梯度
1 import torch 2 from torch.autograd import Variable 3 x = Variable(torch.Tensor([1]),requires_grad=True) 4 w = Variable(torch.Tensor([2]),requires_grad=True) 5 b = Variable(torch.Tensor([3]),requires_grad=True) 6 7 y = w*x+b 8 y.backward() 9 print(x.grad) 10 print(w.grad) 11 print(b.grad) 12 13 tensor([2.]) 14 tensor([1.]) 15 tensor([1.])
4.在梯度方向上进行参数的更新
见下面的回归吧
5.numpy和pytorch实现线性回归
numpy
1 import numpy as np 2 3 x_data = np.array([1, 2, 3]) 4 y_data = np.array([2, 4, 6]) 5 6 epochs = 10 7 lr = 0.1 8 w = 0 9 cost = [] 10 11 for epoch in range(epochs): 12 yhat = x_data * w 13 loss = np.average((yhat - y_data) ** 2) 14 cost.append(loss) 15 dw = -2 * (y_data - yhat) @ x_data.T / (x_data.shape[0]) 16 w = w - lr * dw 17 print(w)
pytorch
1 import torch 2 import torch.nn.functional as F 3 import matplotlib.pyplot as plt 4 %matplotlib qt5 5 %matplotlib inline 6 7 torch.manual_seed(1) 8 x = torch.unsqueeze(torch.linspace(-1,1,100),dim=1) 9 y = x.pow(2) + 0.2*torch.rand(x.size()) 10 11 plt.scatter(x.data.numpy(),y.data.numpy()) 12 plt.show() 13 class Net(torch.nn.Module): 14 def __init__(self,n_feature,n_hidden,n_output): 15 super(Net,self).__init__() 16 self.hidden = torch.nn.Linear(n_feature,n_hidden) 17 self.predict = torch.nn.Linear(n_hidden,n_output) 18 19 def forward(self,x): 20 x = F.relu(self.hidden(x)) 21 x = self.predict(x) 22 return x 23 net = Net(n_feature=1,n_hidden=10,n_output=1) 24 print(net) 25 optimizer = torch.optim.SGD(net.parameters(),lr=0.2) 26 loss_func = torch.nn.MSELoss() 27 plt.ion() 28 plt.show() 29 for t in range(100): 30 prediction = net(x) 31 loss = loss_func(prediction,y) 32 33 optimizer.zero_grad() 34 loss.backward() 35 optimizer.step() 36 if t%10 == 0: 37 plt.cla() 38 plt.scatter(x.data.numpy(),y.data.numpy()) 39 plt.plot(x.data.numpy(),prediction.data.numpy(),'r-',lw=5) 40 plt.text(0.5,0,'Loss=%.4f'%loss.data.numpy(),fontdict={'size':20,'color':'red'}) 41 plt.show() 42 plt.pause(0.1) 43 plt.ioff()
6.pytorch实现一个简单的神经网络
1 import torch 2 from torch.autogtad import Variable 3 4 torch.manual_seed(2) 5 x_data = Variable(torch.Tensor([[1.0], [2.0], [3.0]])) 6 y_data = Variable(torch.Tensor([[2.0], [4.0], [6.0]])) 7 8 9 class Model(torch.nn.Module): 10 def __init__(self): 11 super(Model, self).__init__() 12 self.linear = torch.nn.Linear(1, 1, bias=False) 13 14 def forward(self, x): 15 y_pred = self.linear(x) 16 return y_pred 17 18 19 model = Model() 20 21 criterion = torch.nn.MSELoss(size_average=False) 22 23 optimizer = torch.optim.SGD(model.parameters(), lr=0.01) 24 25 epochs = 20 26 cost = [] 27 for epoch in range(epochs): 28 y_pred = model(x_data) 29 loss = criterion(y_pred, y_data) 30 cost.append(loss.data[0]) 31 optimizer.zero_grad() 32 loss.backward() 33 optimizer.step() 34 35 list(model.parameters())
7.参考资料:PyTorch 中文文档 https://pytorch.apachecn.org/docs/1.0/
https://blog.csdn.net/MainTain_/article/details/90216379