numpy和pytorch实现简单的线性神经网络

numpy实现

说明:
一个全连接ReLU神经网络,一个隐藏层,没有bias。用来从x预测y,使用L2 Loss。

  • h = W 1 X h = W_1X h=W1X
  • a = m a x ( 0 , h ) a = max(0, h) a=max(0,h)
  • y h a t = W 2 a y_{hat} = W_2a yhat=W2a

这一实现完全使用numpy来计算前向神经网络,loss,和反向传播。

  • forward pass
  • loss
  • backward pass

numpy ndarray是一个普通的n维array。它不知道任何关于深度学习或者梯度(gradient)的知识,也不知道计算图(computation graph),只是一种用来计算数学运算的数据结构。

import numpy
length, input_size, hidden_size, out_size = 64, 1000, 100, 10 # 定义数据的维度
x = numpy.random.randn(length, input_size) # 构造数据x
y = numpy.random.randn(length, out_size) # 构造标签y


w1 = numpy.random.randn(input_size, hidden_size) # 初始化权重参数w1
w2 = numpy.random.randn(hidden_size, out_size) # 初始化权重参数w2

learning_rate = 1e-6
for it in range(500):
    # 前向传播
    hidden = x.dot(w1)# N * H
    hidden_relu = numpy.maximum(hidden, 0) # N * H
    y_pred = hidden_relu.dot(w2)# N * D_out  
    # 计算loss
    loss = numpy.square(y_pred - y).mean()  # item()是将一个数的tensor转换为标量
    print(it, loss)
    # 反向传播
    # 计算梯度,链式法则 ∂loss/∂w1 = (∂loss/∂y_pred) * (∂y_pred/∂a) * ∂a/∂h * ∂h/∂w1 = 2.0 * (y_pred - y) * W_2T * [0|1]* xT
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = hidden_relu.T.dot(grad_y_pred)
    grad_hidden_relu = grad_y_pred.dot(w2.T)
    grad_hidden = grad_hidden_relu.copy() # 为什么要复制呢,因为不复制就会改变原有的梯度
     # 因为在对relu求导时,大于0的数为本身即*1,<0 的数梯度为0,即*0,结果为0,所以在这里我们将隐层的梯度值小于0的数据置0
    grad_hidden[hidden<0] = 0
    grad_w1 = x.T.dot(grad_hidden)
    # 更新 w1 和 w2
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

print(w1)
print(w2)

pytorch实现

import torch

length, input_size, hidden_size, out_size = 64, 1000, 100, 10

x = torch.randn(length, input_size)
y = torch.randn(length, D_out)

w1 = torch.randn(input_size, hidden_size)
w2 = torch.randn(hidden_size, out_size)

learning_rate = 1e-6
for it in range(500):
    hidden = x.mm(w1)
    hidden_relu = hidden.clamp(min=0)
    y_pred = hidden_relu.mm(w2) # N * D_out

    loss = (y_pred - y).pow(2).sum().item()
    print(it, loss)
    
    grad_y_pred = 2.0 * (y_pred - y)
    grad_w2 = h_relu.t().mm(grad_y_pred)
    grad_hidden_relu = grad_y_pred.mm(w2.t())
    grad_hidden = grad_hidden_relu.clone()
    
    grad_hidden[hidden<0] = 0
    grad_w1 = x.t().mm(grad_hidden)
    
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2

print(w1)
print(w2)

pytorch内置函数实现

length, input_size, hidden_size, out_size = 64, 1000, 100, 10
# 随机创建一些训练数据
x = torch.randn(length, input_size)
y = torch.randn(length, out_size)

w1 = torch.randn(input_size, hidden_size, requires_grad=True)
w2 = torch.randn(hidden_size, out_size, requires_grad=True)

learning_rate = 1e-6
for it in range(500):
    # 前向传播
    y_pred = x.mm(w1).clamp(min=0).mm(w2)	    
    # computation graph,注意这里把item()去掉了,因为使用了这个之后loss就是一个标量,不是图了,就不能使用.backward()
	loss = (y_pred - y).pow(2).sum()
	print(it, loss.item())
    # 反向传播
    loss.backward()
    with torch.no_grad(): # 为了让计算图不占内存,并且忘记w1和w2的梯度,需要做这个操作
    	w1 -= learning_rate * w1.grad
        w2 -= learning_rate * w2.grad
        w1.grad.zero_()  # 计算完参数的梯度之后,需要将这一步的梯度清零,不然会越来越大,他是叠加的
        w2.grad.zero_()
print(w1)
print(w2)

你可能感兴趣的:(NLP,pytorch)