【深度学习】线性回归(二)小批量随机梯度下降及其python实现

概述

本文在我的前一篇博客(【深度学习】线性回归(一)原理及python从0开始实现)的基础上,介绍一下深度学习中的小批量随机梯度下降方法(mini-batch stochastic gradient descent),将其应用在线性回归中。在不使用深度学习框架的前提下,使用Python进行了实现。

本文主要包括以下内容:

  1. 解析解和数值解;
  2. 小批量随机梯度下降算法;
  3. python实现小批量随机梯度下降和线性回归
  4. 相比于前一篇博客,这里会注重对代码的封装

小批量随机梯度下降

解析解和数值解

【深度学习】线性回归(一)原理及python从0开始实现一文中,介绍了线性回归的原理,我们最终的目的就是求解模型中的参数。在具体求解过程中,我们将误差(或损失)表示为参数的函数,通过最小化误差来找到合适的参数值。

当模型和损失函数形式较为简单时,上面的误差最小化问题的解可以直接用公式表达出来。这类解叫做解析解(analytical solution),如最小二乘法。然而,大多数深度学习模型并没有解析解,只能通过优化算法有限次迭代模型参数来尽可能降低损失函数的值。这类解叫做数值解(numerical solution),如梯度下降方法。

小批量随机梯度下降

在求数值解的优化算法中,小批量随机梯度下降(mini-batch stochastic gradient descent)在深度学习中被广泛使用。它的算法很简单:

  1. 我们先选取一组模型参数的初始值,一般采用随机选取;
  2. 接下来对参数进行多次迭代,使得每次迭代都可能降低损失函数的值;
  3. 在每次迭代中,我们先随机均匀采样一个由固定数目训练数据样本所组成的小批量(mini-batch) ;
  4. 然后求小批量中数据样本的平均损失有关模型参数的导数(梯度);
  5. 最后用此结果与学习率的乘积作为模型参数在本次迭代的减小量。

python实现

需要的先验知识

本文以一个简单的线性模型: y = w 1 x 1 + w 2 x 2 + b y=w_1x_1+w_2x_2+b y=w1x1+w2x2+b为例,生成模拟数据集进行实验。我们令 w 1 = 2 , w 2 = − 3.4 , b = 4.2 w_1=2, w_2=-3.4, b=4.2 w1=2,w2=3.4,b=4.2,以一个随机噪声 ϵ \epsilon ϵ生成训练数据集。

这里涉及到MXNet中的NDArray和自动求解梯度操作,可以参考我之前的博客:

代码和实验

# coding=utf-8
# author: BebDong
# 2018.12.11
# 从0开始实现线性回归,拟合y=w1x1+w2x2+b


from IPython import display
from matplotlib import pyplot as plt
from mxnet import autograd, nd
import random


# 矢量图显示
def use_svg_display():
    display.set_matplotlib_formats('svg')


# 设置图片尺寸
def set_figsize(figsize=(3.5, 2.5)):
    use_svg_display()
    plt.rcParams['figure.figsize'] = figsize


# 返回batch_size个随机样本
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 = nd.array(indices[i:min(i + batch_size, num_examples)])
        yield features.take(j), labels.take(j)                            # take函数根据索引返回元素


# 定义需要拟合线性模型
def linreg(X, w, b):
    return nd.dot(X, w) + b


# 定义损失函数
def squared_loss(y_predict, y):
    return (y_predict - y.reshape(y_predict.shape)) ** 2 / 2


# 定义优化算法:小批量随机梯度下降
def mini_batch_gd(params, lr, batch_size):
    for param in params:
        param[:] = param - lr * param.grad / batch_size


# 生成数据集:y=w1x1+w2x2+b+e,其中e表示随机噪声,服从均值为0标准差为0.01的正态分布
num_inputs = 2                              # 特征数为2,x1和x2两个特征
num_example = 1000                          # 训练数据集1000个样本
true_w = [2, -3.4]                          # 模型中的真实参数
true_b = 4.2

features = nd.random.normal(scale=1, shape=(num_example, num_inputs))           # 随机生成测试数据集
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels += nd.random.normal(scale=0.01, shape=labels.shape)                      # 添加随机噪声

# set_figsize()                                                                   # x2和y的散点图
# plt.scatter(features[:, 1].asnumpy(), labels.asnumpy(), 1)
# plt.show()

# batch_size = 10                                                                 # 打印一个batch的样本
# for X, y in data_iter(batch_size, features, labels):
#     print(X, y)
#     break

# 初始化参数并创建梯度
w = nd.random.normal(scale=0.01, shape=(num_inputs, 1))
w.attach_grad()
b = nd.zeros(shape=(1,))
b.attach_grad()

# 训练模型
lr = 0.05
epochs = 10
batch_size = 10
net = linreg
loss = squared_loss

for epoch in range(epochs):
    # 在每一次迭代中需要使用训练集的所有样本一次
    for X, y in data_iter(batch_size, features, labels):
        with autograd.record():
            l = loss(net(X, w, b), y)                         # l表示小批量的损失
        if len(y) < batch_size:                               # 最后一个批次的数据可能小于设定的batch_size
            l = l * batch_size / len(y)
        l.backward()                                          # 小批量损失对模型参数求导
        mini_batch_gd([w, b], lr, batch_size)                 # 调整参数
    train_l = loss(net(features, w, b), labels)                                # 打印当前迭代周期的平均误差
    print('epoch %d, loss %f' % (epoch + 1, train_l.mean().asnumpy()))


# 输出得到的模型参数
print(true_w, w)
print(true_b, b)

结果如下图,红圈圈出来的是使用小批量随机梯度下降得到的参数值,和真实值已经相当接近了。这里的模型和数据集比较简单,实际应用中,超参数(学习率、迭代次数等人为设置的参数)需要多次调节。
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值