之前有一个用np实现一个简单双层神经网络https://blog.youkuaiyun.com/qq_43040360/article/details/118636136
这次改为使用torch实现
import numpy as np
import torch
#这是超参数,N为有几个训练数据,D_in是输入的维度,H是隐藏层的维度,D_out是输出的维度
N, D_in, H, D_out = 64, 1000, 100, 10
#随机创建一些训练数据
x = torch.randn(N,D_in)
y = torch.randn(N,D_out)
w1 = torch.randn(D_in , H)
w2 = torch.randn(H , D_out)
learning_rate = 1e-6 #设置学习率
for t in range(500): #这里相当于epoch=500,迭代500次
#前向传播
h = x.mm(w1) #N * H的向量,dot方法用于矩阵乘法,在torch中要写成mm(),这样写的意思和w1乘以x一样 H=X*W1
h_relu = h.clamp(min=0) #经过relu激活函数,在torch中clamp函数相当于一个夹子,将张量夹在min和max之间,这里max不用设置,只需要设置min
y_pred = h_relu.mm(w2) # Y=H*W2,也就是神经网络的输出
#计算loss
loss = (y_pred - y).pow(2).sum().item() #平方差损失公式,然后转成item
print(t,'----',loss)
#反向传播
#1、计算导数(grad),其实目的就是算出来W1和W2的导数
#loss = np.square(y_pred - y).sum()
# y_pred = h_relu.dot(w2)
# h_relu = np.maximum(h,0)
# h = x.dot(w1)
#这几个公式,用链式求导法一步步算出w1和w2的导数
grad_y_pred = 2.0 * (y_pred - y) #因为是平方,故是2.0
grad_w2 = h_relu.t().mm(grad_y_pred) #.t()代表将这个矩阵转置
grad_h_relu = grad_y_pred.mm(w2.t())
grad_h = grad_h_relu.clone()
grad_h[h<0] = 0
grad_w1 = x.t().mm(grad_h)
#2、更新W1和W2的权重
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
上述方法还可以写的更精简一些,如下
import torch.nn as nn
x = torch.randn(N,D_in)
y = torch.randn(N,D_out)
#在初始化数据时,w1和w2不必写成上面w1 = torch.randn(D_in , H) w2 = torch.randn(H , D_out)那种形式,而是可以直接写成如下
model = torch.nn.Sequential(
torch.nn.Linear(D_in , H), # 这里就是第一个线性层w1
torch.nn.ReLU(), #relu函数
torch.nn.Linear(H , D_out), #第二个线性层w2
)
learning_rate = 1e-6
loss_fn = nn.MSELoss(reduction = 'sum') #用nn.mesloss方法定义损失函数
for it in range(500):
y_pred = model(x) #这里直接将输入x传进model,就可以得到模型的输出
#计算损失
loss = loss_fn(y_pred , y)
print(it , loss.item())
model.zero_grad
#反向传播
loss.backward() #之前的链式求导法在这里可以写成这种形式
#更新w1,w2
with torch.no_grad():
for param in model.parameters():
param =learning_rate * param.grad #模型封装好了,所有的W都在param里