深度学习导论(2)深度学习案例:回归问题
深度学习案例:回归问题问题分析优化方法代码采样数据计算误差计算梯度梯度更新main函数结果输出这篇文章将介绍深度学习的小案例:回归问题的问题分析、优化以及实现代码。问题分析如果只采样两个点则会存在较大偏差(如蓝色线),为减小估计偏差,可通过采样多组样本点:{(x(1),y(1)),(x(2),y(2)),...,(x(n),y(n))}\{(x^{(1)},y^{(1)}),(x^{(2)},y^
这篇文章将介绍深度学习的小案例:回归问题的问题分析、优化以及实现代码。
问题分析

如果只采样两个点则会存在较大偏差(如蓝色线),为减小估计偏差,可通过采样多组样本点:
{ ( x ( 1 ) , y ( 1 ) ) , ( x ( 2 ) , y ( 2 ) ) , . . . , ( x ( n ) , y ( n ) ) } \{(x^{(1)},y^{(1)}),(x^{(2)},y^{(2)}),...,(x^{(n)},y^{(n)})\} {(x(1),y(1)),(x(2),y(2)),...,(x(n),y(n))}
然后找出一条“最好”的直线,使得它尽可能地让所有采样点到该直线的误差(Error,或损失Loss)之和最小。
如:求出当前模型的所有采样点上的预测值 w x ( i ) + b wx^{(i)}+b wx(i)+b与真实值 y ( i ) y^{(i)} y(i)之间差的平方和作为总误差L:
L = 1 n ∑ i = 1 n ( w x ( i ) + b − y ( i ) ) 2 L=\frac{1}{n}\sum_{i=1}^{n}(wx^{(i)}+b-y^{(i)})^{2} L=n1i=1∑n(wx(i)+b−y(i))2
即:均方差误差(Mean Squared Error,MSE)
优化方法
- 最简单的方法:暴力搜索,随机试验
- 常用方法:梯度下降方法(Gradient Descent)

(a)函数导数为0的点即为f(x)的驻点(函数取得极大、极小值时对应的自变量点)
(b)函数的梯度(Gradient)定义为对各个自变量的偏导数(Partial Derivative)组成的向量
图中xy平面的红色箭头的长度表示梯度向量的模,箭头的方向表示梯度向量的方向。可以看到,箭头的方向总是指向当前位置函数值增速最大的方向,函数曲面越陡峭,箭头的长度也就越长,梯度的模也越大。
函数在各处的梯度方向▽f总是指向函数值增大的方向,那么梯度的反方向-▽f应指向函数值减少的方向。
按照:
x ′ = x − η ⋅ ∇ f x'=x-\eta\cdot\nabla{f} x′=x−η⋅∇f
迭代更新x,就能获得越来越小的函数值。
代码
采样数据
import numpy as np
# 采样数据
data = [] # 保存样本集的列表
for i in range(100): # 循环采样100个点
x = np.random.uniform(-10., 10.) # 随机采样输入x
eps = np.random.normal(0., 0.1) # 采样高斯噪声
y = 1.477 * x + 0.089 +eps # 得到模型的输出
data.append([x, y]) # 保存样本点
data = np.array(data) # 转换为2D Numpy数组
计算误差
# 计算误差
def mse(b, w, points):
# 根据当前的 w,b参数计算均方差损失
totalError = 0
for i in range(0, len(points)): # 循环迭代所有点
x = points[i, 0] # 获得 i号点的输入 x
y = points[i, 1] # 获得 i号点的输出 y
# 计算差的平方,并累加
totalError += (y - (w * x + b)) ** 2
# 将累加的误差求平均,得到均方差
return totalError / float(len(points))
计算梯度
# 计算梯度
# b_current:当前 b的值
# w_current:当前 w的值
# points:样本点集合
# lr:学习率
def step_gradient(b_current, w_current, points, lr):
# 计算误差函数在所有点上的导数,并更新 w,b
b_gradient = 0
w_gradient = 0
M = float(len(points)) # 总样本数
for i in range(0, len(points)):
x = points[i, 0]
y = points[i, 1]
# 误差函数对 b的导数:grand_b = 2(wx+b-y)
b_gradient += (2/M) * ((w_current * x +b_current) - y)
# 误差函数对 w的导数:grand_w = 2(wx+b-y)*x
w_gradient += (2/M) * x * ((w_current * x +b_current) - y)
# 根据梯度下降算法更新 w,b,其中lr为学习率
new_b = b_current - (lr * b_gradient)
new_w = w_current - (lr * w_gradient)
return [new_b, new_w]
梯度更新
# 梯度更新
def gradient_descent(points, starting_b, starting_w, lr, num_iterations):
# 循环更新 w,b多次
b = starting_b # b的初始值
w = starting_w # w的初始值
# 根据梯度下降算法更新多次
for step in range(num_iterations):
# 计算梯度并更新一次
b, w = step_gradient(b, w, np.array(points), lr)
loss = mse(b, w, points) # 计算当前的均方差,用于监控训练进度
if step%50 == 0: # 打印误差和实时的 w,b值
print(f"iteration:{step}, loss:{loss}, w:{w}, b:{b}")
return [b, w] # 返回最后一次的 w,b
main函数
# main函数
if __name__ == '__main__':
# 加载训练集数据,这些数据是通过真实模型添加观测误差采样得到的
lr = 0.01 # 学习率
initial_b = 0 # 初始化 b为 0
initial_w = 0 # 初始化 w为 0
num_iterations = 1000
# 训练优化1000次,返回最优 w*,b*和训练 Loss的下降过程
[b, w] = gradient_descent(data, initial_b, initial_w, lr, num_iterations)
losses = gradient_descent(data, initial_b, initial_w, lr, num_iterations)
loss = mse(b, w, data) # 计算最优数值解 w,b上的均方差
print(f'Final loss:{loss}, w:{w}, b:{b}')
结果输出
结果输出如下图所示:
在上述迭代过程中,迭代次数与均方差误差MSE之间的关系如下图:
由上图可以看出,虽然我们迭代了1000次,但是在100轮左右就已经收敛了,设在第n轮收敛,则我们只需要记录第n轮时的w和b的值就行,就是我们要求的w和b的值。有了w和b的值后,模型 y = w x + b y=wx+b y=wx+b就有了。
更多推荐

所有评论(0)