文章目录

  • 用numpy和torch实现单层神经网络对比
  • 1. 使用numpy实现
  • 2. 使用torch实现
  • 3. 使用optim自动更新的代码


用numpy和torch实现单层神经网络对比

单层神经网络的基本原理请参考机器学习——神经网络(四):BP神经网络 主要的过程为:

  • forward pass (正向传递)
  • loss (计算损失)
  • backward pass (反向更新)

1. 使用numpy实现

import numpy as np
import matplotlib.pyplot as plt
N,D_in,H,D_out = 64,1000,100,10  # N是输入数据个数,每个输入数据是1000维,中间层是100维,10维输出

# 随机创建训练数据
x_data = np.random.randn(N,D_in)
y_data = np.random.randn(N,D_out)

# 初始化权重
w1 = np.random.randn(D_in,H)
w2 = np.random.randn(H,D_out)

# 定义学习参数
learning_rate = 1e-6
iteration = 1000
for it in range(iteration):
    h = x_data.dot(w1) # .dot矩阵乘法
    h_relu = np.maximum(h,0)
    y_pred = h_relu.dot(w2)
    
    # compute loss
    loss = np.square(y_pred - y_data).sum()
    if it%10==0:
        print(it,loss)
    
    # backward pass
    # 1.compute the gradient
    grad_y_pred = 2.0*(y_pred - y_data)
    grad_w2 = h_relu.T.dot(grad_y_pred)
    grad_h_relu = grad_y_pred.dot(w2.T)
    grad_h = grad_h_relu.copy() #复制grad_h_relu
    grad_h[h<0] = 0
    grad_w1 = x_data.T.dot(grad_h)
    
    # 2.update weight of w1 and w2
    w1 -= learning_rate * grad_w1
    w2 -= learning_rate * grad_w2 
    
    # 绘图
    plt.figure(1)
    plt.scatter(it,loss)
plt.show()

结果视图:


BP神经网络和CNN卷积神经网络 bp神经网络pytorch_python


函数解释:

  1. numpy.random.randn(d0,d1,…,dn)
  • randn函数返回一个或一组样本,具有标准正态分布。
  • dn表格每个维度
  • 返回值为指定维度的array
  1. np.maximum(X, Y, out=None)
  • X和Y逐位进行比较,选择最大值. 最少接受两个参数
  1. .dot()

矩阵相乘
如果处理的是一维数组,则得到的是两数组的內积
如果是二维数组(矩阵)之间的运算,则得到的是矩阵积(mastrix product)

  1. .T

矩阵的转置

2. 使用torch实现

代码:

# 在pytorch中的求导很简单

N,D_in,H,D_out = 64,1000,100,10  # N是输入数据个数,每个输入数据是1000维,中间层是100维,10维输出

# 随机创建训练数据
x_data = torch.randn(N,D_in)
y_data = torch.randn(N,D_out)

# 初始化权重
model = torch.nn.Sequential(
    torch.nn.Linear(D_in,H), # w_1*x+b1
    torch.nn.ReLU(),
    torch.nn.Linear(H,D_out),
)
# 直接初始化的模型下降非常缓慢,修改其初始化参数优化非常明显,改变lr也比较明显
torch.nn.init.normal_(model[0].weight)
torch.nn.init.normal_(model[2].weight)

# loss functoin
loss_fn = torch.nn.MSELoss(reduction = 'sum')

# learning rate and iteration
learning_rate = 1e-6
iteration = 1000

# caculate the result
for it in range(iteration):
    # model forward
    y_pred =model(x_data)
    
    # compute loss
    loss =loss_fn(y_pred,y_data) # computation graph
    if it%10==0:
        print(it,loss.item())
    
    # backward pass
    	# 1.compute the gradient(使用backward的grad会不断地叠加)
    loss.backward()
    	# 2.update weight of w1 and w2
    with torch.no_grad():
        for param in model.parameters():
            param -= learning_rate*param.grad
    model.zero_grad() # 注意要清空grad参数结果,否则会在上一次计算的结果上进行叠加

不同之处:

  1. 所有的numpy.random.randn函数变为torch.randn
  2. torch中使用区间限定函数.clamp(min=num1,max=num2)来替代了numpy中常用numpy.maximum
  3. torch中的矩阵乘法使用.mm()替代numpy中的.dot()
  4. torch中的装置使用.t()替代numpy中的.T
  5. 在pytorch中有已经定义好的神经网络训练函数
  6. torch库中可以调用loss.backward()直接得到与函数相关的参数的梯度,进而进行梯度下降计算;其中的注意点我将在下一个博客单独说明。
  7. 当下降不是很明显的时候可以从:①learning rate的大小 ②初始化参数 两个方面进行考虑,learning rate越大下降得越快,但有欠拟合的缺点,初始化参数就比较玄学了。

改变初始化参数的代码为:

torch.nn.init.normal_(model[0].weight) torch.nn.init.normal_(model[2].weight)

  1. torch中可以使用optim来自动更新参数而非自己手动更新。optim包有很多的优化方法比如SCD+momentum,RMSProp,Adam等都可以直接调用。(在后面将继续介绍)

3. 使用optim自动更新的代码

步骤就是不用自动更新了,定义一个optimizer,将model的参数和learning rate传递进torch.optim.Adam中去;在迭代的过程中使用optimizer.zero_grad()方法和optimizer.step()方法进行更新即可(注意这里删掉了上方更改初始化的代码)

# 在pytorch中的求导很简单

N,D_in,H,D_out = 64,1000,100,10  # N是输入数据个数,每个输入数据是1000维,中间层是100维,10维输出

# 随机创建训练数据
x_data = torch.randn(N,D_in)
y_data = torch.randn(N,D_out)

# 初始化权重
model = torch.nn.Sequential(
    torch.nn.Linear(D_in,H), # w_1*x+b1
    torch.nn.ReLU(),
    torch.nn.Linear(H,D_out),
)

# modle = model.cuda() 通常我们是需要在GPU上运行的,当然也要传递各种参数

loss_fn = torch.nn.MSELoss(reduction = 'sum')

# 定义学习参数
learning_rate = 1e-4

# 定义优化方法optimizer
optimizer = torch.optim.Adam(model.parameters(),lr=learning_rate)
iteration = 1000

for it in range(iteration):
    # model forward
    y_pred =model(x_data)
    
    # compute loss
    loss =loss_fn(y_pred,y_data) # computation graph
    if it%10==0:
        print(it,loss.item())
        
    optimizer.zero_grad()
    # backward pass
    loss.backward()
    
    # update model parameters
    optimizer.step()