从numpy到pytorch了解BP算法及构建基础的神经网络
目录
1.BP算法的定义
BP算法(即误差反向传播算法)适合于多层神经元网络的一种学习算法,它建立在梯度下降法的基础上。
BP算法的学习过程由正向传播过程和反向传播过程组成。
正向传播:计算输入通过隐藏层之后的输出结果(y_predict)。将y_predict和y_true的误差的平方和作为目标函数(loss)。
反向传播:逐层求出目标函数对各神经元权值的偏导数,构成目标函数对权值向量的梯度值,作为修改权值的依据。
网络的学习在权值修改过程中完成。误差达到所期望值时,网络学习结束。
在进行训练之前,导入必要的包
import numpy as np
import torch
import torch.nn as nn
2.numpy实现基础的神经网络和BP算法
手动推导—>>>
(1)随机构建一些数据
n,d_in,h,d_out=64,1000,100,10 # 设置输入的样本数,维数,隐藏层的个数,输出层的维数
x=np.random.rand(n,d_in) # 输入n*d_in
w1=np.random.rand(d_in,h) # 权重1
bias1=np.random.rand(n,h) # 偏置1
w2=np.random.rand(h,d_out) # 权重2
bias2=np.random.rand(n,d_out) # 偏置2
y=np.random.rand(n,d_out) # 输入n*d_out
(2)进行卷积
for t in range(500):
# 正向传播计算y_predict
cov1=x.dot(w1)+bias1 # 第一层卷积 (点乘+偏置)
relu_1=np.maximum(cov1,0) # relu激活函数 (用于处理非线性关系)
y_predict=relu_1.dot(w2) + bias2 # 预测的y
# 计算损失函数
loss=np.square(y_predict-y).mean() # 此时为MSE
print("numpy实现,第{}次的损失为:{}".format(t,loss))
# backward pass(反向传播计算梯度)
grad_y_predict=2*(y_predict-y) # loss对y_predict求偏导
grad_w2=relu_1.T.dot(grad_y_predict) #反向计算的w2的梯度
grad_bias2=grad_y_predict
grad_relu1=grad_y_predict.dot(w2.T)
grad_cov1 = grad_relu1.copy()
grad_cov1[cov1<0]=0
grad_w1=x.T.dot(grad_cov1)
grad_bias1 = grad_cov1
# 更新参数w1和w2,bias1和bias2 (w1=w1-lr*grad_w1)
w1-=learning_rate*grad_w1
w2 -= learning_rate * grad_w2
bias1-= learning_rate * grad_bias1
bias2-= learning_rate * grad_bias2
结果:
3.torch实现神经网络和BP算法
(1)随机创建一些训练数据
x=torch.rand(n,d_in) # 输入n*d_in
w1=torch.rand(d_in,h) # 权重1
bias1=torch.rand(n,h) # 偏置1
w2=torch.rand(h,d_out) # 权重2
bias2=torch.rand(n,d_out) # 偏置2
y=torch.rand(n,d_out) # 输入n*d_out
(2)进行卷积
pytorch很多都和numpy类似,仅进行少部分修改即可
for t in range(500):
cov1=x.mm(w1)+bias1 # mm实现矩阵相乘
relu_1=cov1.clamp(min=0) # relu激活函数 clamp函数为夹子
y_predict=relu_1.mm(w2) + bias2
# 计算损失函数
loss=(y_predict-y).pow(2).mean().item() # 求平方pow(2)
print("pytorch自己构建梯度实现,第{}次的损失为:{}".format(t,loss))
# backward pass(反向传播计算梯度)
grad_y_predict=2*(y_predict-y)
grad_w2=relu_1.t().mm(grad_y_predict)
grad_bias2=grad_y_predict
grad_relu1=grad_y_predict.mm(w2.t()) # 转置用t()
grad_cov1 = grad_relu1.clone() # 复制用clone()
grad_cov1[cov1<0]=0
grad_w1=x.t().mm(grad_cov1)
grad_bias1 = grad_cov1
# 更新参数w1和w2,bias1和bias2
w1-=learning_rate*grad_w1
w2 -= learning_rate * grad_w2
bias1-= learning_rate * grad_bias1
bias2-= learning_rate * grad_bias2
结果
3.torch的api实现神经网络和BP算法
设置模型
class Net(nn.Module): # Net为torch内含有的一个模块,在进行模型定义时,可用此方法
def __init__(self,d_in,h,d_out):
super(Net,self).__init__() # 继承init
self.Linear1=nn.Linear(d_in,h)
self.Relu=nn.ReLU()
self.Linear2=nn.Linear(h,d_out)
def forward(self,x):
x=self.Relu(self.Linear1(x))
y_pre=self.Linear2(x)
return (y_pre)
model=Net(d_in,h,d_out)
另外一种定义模型的方法
model=torch.nn.Sequential(torch.nn.Linear(d_in,h),
torch.nn.ReLU(),
torch.nn.Linear(h,d_out))
进行训练
# 设置超参数
optimizer=torch.optim.SGD(model.parameters(),lr=learning_rate)
loss_function=nn.MSELoss()
# 进行训练
for t in range(500):
y_predict=model(x)
loss=loss_function(y_predict,y)
print("pytorch实现,第{}次的损失为:{}".format(t,loss.item()))
optimizer.zero_grad()
loss.backward()
optimizer.step()
结果
总结
用不同的方法最后都能得到Loss不断下降的结果,且在训练步数达到一定时,算法都能收敛,但是用pytorch内部的api会使得Loss下降更快,且更易收敛。