一、用numpy实现两层神经网络
一个全连接的RELU神经网络,一个隐藏层,为了简单起见不用bais。作用是从x预测y。
Loss 函数为:
假设输入为x,所以第一层的输出为,然后经过RELU激活函数,得到的结果为h_relu。当时不太清楚为什么要用激活函数,查了一下感觉这篇博客讲的挺好。链接:https://www.cnblogs.com/ya-qiang/p/9258714.html
h_relu又作为第二层的输入,输出为y_pred = h_relu*w2。
然后计算损失函数
到目前为止前向神经网络和loss就计算好了,这时候就要反向传播来修正w1,w2。
先把所有公式理一下:h = x*w1 h_relu = relu(h) y_pred = h_relu*w2 loss = (y_pred-y)²
这样通过链式法则可以求得w1和w2的梯度,也就是,
relu函数的导数也就是大于0的部分为1,小于0的部分是0
然后修正w1,w2。
以上的步骤循环进行500次,完整代码如下:
N, D_in,H,D_out = 64, 1000, 100, 10
# 随机创建一些训练数据
x = np.random.randn(N,D_in)
y = np.random.randn(N,D_out)
w1 = np.random.randn(D_in,H)
w2 = np.random.randn(H,D_out)
learning_rate = 1e-6
for it in range(500):
# forward pass
h = x.dot(w1) # 矩阵的点积运算 得到的是 N*H
h_relu = np.maximum(h,0) # h和0逐位比较取大者 relu激活函数
y_pred = h_relu.dot(w2) # N*D_out
# computer loss
loss = np.square(y_pred - y).sum() #计算各元素的平方
print(it, loss) #输出损失值
# Backward pass
# compute the gradient
grad_y_pred = 2.0 * (y_pred - y)
grad_w2 = h_relu.T.dot(grad_y_pred) #矩阵的乘法法则,需要转置.T
grad_h_relu = grad_y_pred.dot(w2.T)
grad_h = grad_h_relu.copy()
grad_h[h<0] = 0
grad_w1 = x.T.dot(grad_h)
# update weights of w1 and w2
w1 -= learning_rate * grad_w1
w2 -= learning_rate * grad_w2
运行结果如下:
可以看到loss的值在慢慢变小。
二、用Pytorch实现
这里先将里面的一些语法改成用pytorch实现就行,用pytorch就不用手撸一遍梯度下降了,直接用loss.backward(),注意要梯度清零。
import torch
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, requires_grad=True) #需要对w1求梯度
w2 = torch.randn(H,D_out,requires_grad=True)
learning_rate = 1e-6
for it in range(500):
# forward pass
h = x.mm(w1) # 矩阵的点积运算 得到的是 N*H
h_relu = h.clamp(min=0) # h和0逐位比较取大者 relu激活函数
y_pred = h_relu.mm(w2) # N*D_out
# computer loss
loss = (y_pred - y).pow(2).sum() #计算各元素的平方,item() tensor转数字
print(it, loss.item())
# Backward pass
# compute the gradient
loss.backward()
# update weights of w1 and w2
with torch.no_grad(): #避免计算图占内存
w1 -= learning_rate * w1.grad
w2 -= learning_rate * w2.grad
w1.grad.zero_() #每次清零,否则梯度会累积
w2.grad.zero_()
运行之后可以发现效果一样。
其实pytorch自带的torch.nn在构造神经网络的时候会方便很多,先这样,以后再用。