深度学习经典优化方法实现

目录

前言

一、梯度下降

二、随机梯度下降

三、小批量梯度下降

四、Adam算法

总结



前言

      参考邱锡鹏老师的《神经网络与深度学习》(俗称蒲公英书),记录一下笔记.一些核心的代码参考李沐的《动手学深度学习》。


一、梯度下降

\theta_{t+1}=\theta_t-\alpha*\frac{1}{N}\sum_{n=1}^{N}\frac{\partial L(y^{(n)},f({x}^{(n)};\theta)}{\partial \theta}

def bgd(params,lr):
    for param in params:
        param.data -= lr*param.grad/1000


二、随机梯度下降

每次迭代只从训练集中取出一个样本更新梯度

\theta=\theta-\alpha*\frac{\partial L(\theta;x^{(n)},y^{(n)})}{\partial \theta}

def sgd(params,lr):
    for param in params:
        param.data -= lr * param.grad

三、小批量梯度下降

\theta_{t+1}=\theta_t-\alpha*\frac{1}{K}\sum_{(x,y\in S_t)}\frac{\partial L(y.f(x;\theta))}{\partial \theta}

四、Adam算法

Adam算法可以看做是动量法与RMSprop的结合。

M_t=\beta_1M_{t-1}+(1-\beta_1)g_t\\ G_t=\beta_2G_{t-1}+(1-\beta_2)g_t\bigodot g_t

{M}'_t=\frac{M_t}{1-\beta_1^t}\\ {G}'_t=\frac{G_t}{1-\beta_2^t}

Adam算法的最终更新参数的方式为:

\Delta\theta_t=-\frac{\alpha}{\sqrt{​{G}'_t+\varepsilon }} {M}'_t

def Adam(params,b1,b2,lr,t,mt=0,vt=0,min_num=1e-8):
    for param in params:
        mt=b1*mt+(1-b1)*param.grad
        vt=b2*vt+(1-b2)*param.grad**2
        mt_e=mt/(1-b1**(t+1))
        vt_e=vt/(1-b2**(t+1))
        param_delata=-lr*mt_e/torch.sqrt(vt_e+min_num)
        param.data+=param_delata
        mt=0
        vt=0

五、总代码

1.构建数据集

import torch
from matplotlib import pyplot as plt
import numpy as np
import random

#制作训练需要的数据 y=w1*x1+w2*x2+b
num_inputs = 2
num_examples = 1000
true_w = [2, -3.4]
true_b = 4.2
features = torch.randn(num_examples, num_inputs,dtype=torch.float32)
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()),dtype=torch.float32)

在小批量梯度下降算法中,需要将总体样本分割为多个batch。

# def data_iter(batch_size, features, labels):
#     num_examples = len(features)
#     indices = list(range(num_examples))
#     random.shuffle(indices)  # 样本的读取顺序是随机的
#     for i in range(0, num_examples, batch_size):
#         j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # 最后一次可能不足一个batch
#         yield  features.index_select(0, j), labels.index_select(0, j)
#loss = squared_loss
#batch_size = 10

# for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
#     # 在每一个迭代周期中,会使用训练数据集中所有样本一次(假设样本数能够被批量大小整除)。X
#     # 和y分别是小批量样本的特征和标签
#     for X, y in data_iter(batch_size, features, labels):
#         l = loss(net(X, w, b), y).sum()  # l是有关小批量X和y的损失
#         l.backward()  # 小批量的损失对模型参数求梯度
#         sgd([w, b], lr)  # 使用随机梯度下降迭代模型参数
#
#         # 不要忘了梯度清零
#         w.grad.data.zero_()
#         b.grad.data.zero_()
#     train_l = loss(net(features, w, b), labels)
#     print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))

2.初始化需要训练的参数

w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32,requires_grad=True)
b = torch.zeros(1, dtype=torch.float32,requires_grad=True)

3.定义模型与损失函数

def linreg(X, w, b):  
    return torch.mm(X, w) + b

def squared_loss(y_hat, y):  
    return (y_hat - y.view(y_hat.size())) ** 2 / 2

4.训练

定义不同的优化方法

def mini_bgd(params, lr, batch_size):  # 本函数已保存在d2lzh_pytorch包中方便以后使用
    for param in params:
        param.data -= lr * param.grad / batch_size # 注意这里更改param时用的param.data

def bgd(params,lr):
    for param in params:
        param.data -= lr*param.grad/1000

def sgd(params,lr):
    for param in params:
        param.data -= lr * param.grad

def Adam(params,b1,b2,lr,t,mt=0,vt=0,min_num=1e-8):
    for param in params:
        mt=b1*mt+(1-b1)*param.grad
        vt=b2*vt+(1-b2)*param.grad**2
        mt_e=mt/(1-b1**(t+1))
        vt_e=vt/(1-b2**(t+1))
        param_delata=-lr*mt_e/torch.sqrt(vt_e+min_num)
        param.data+=param_delata
        mt=0
        vt=0

训练

lr = 0.03
num_epochs = 5000
b1=0.9
b2=0.99
lr=0.001
for epoch in range(num_epochs):
    X = features
    y = labels
    prediction=linreg(X, w, b)
    loss = squared_loss(prediction, y).sum() # l是有关小批量X和y的损失
    print(f'epoch:{epoch},loss:{loss.item()}')
    loss.backward()  # 小批量的损失对模型参数求梯度
    Adam([w, b],b1,b2,lr,epoch)  # 使用随机梯度下降迭代模型参数
    w.grad.data.zero_()
    b.grad.data.zero_()

'''sgd'''
# for epoch in range(num_epochs):
#     random_num=np.random.randint(0,num_examples)
#     X=features[random_num].unsqueeze(0)
#     y=labels[random_num].unsqueeze(0)
#     prediction = linreg(X, w, b)
#     loss = squared_loss(prediction, y).sum() # l是有关小批量X和y的损失
#     print(loss.item())
#     loss.backward()  # 小批量的损失对模型参数求梯度
#     sgd([w, b], lr)  # 使用随机梯度下降迭代模型参数
#     w.grad.data.zero_()
#     b.grad.data.zero_()

'''bgd'''
# for epoch in range(num_epochs):  # 训练模型一共需要num_epochs个迭代周期
#     X = features
#     y = labels
#     prediction=linreg(X, w, b)
#     loss = squared_loss(prediction, y).sum() # l是有关小批量X和y的损失
#     print(loss.item())
#     loss.backward()  # 小批量的损失对模型参数求梯度
#     bgd([w, b], lr)  # 使用随机梯度下降迭代模型参数
#     w.grad.data.zero_()
#     b.grad.data.zero_()
#     #train_l = squared_loss(linreg(features, w, b), labels)
#     #print('epoch %d, loss %f' % (epoch + 1, train_l.mean().item()))
print(true_w, '\n', w)
print(true_b, '\n', b)


总结

任何复杂的神经网络,其复杂的反向传播过程,最核心的一环就是参数梯度的求解,如果参数的梯度已知就可以根据优化算法更新参数

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值