文章目录
此文章为datawhale2021年7月组队学习task02笔记,开源文件可参考:LeeML-Notes,视频链接:b站视频
回归定义和应用例子
回归定义
regression就是找到一个函数function,通过输入特征x,输出一个数值scalar
应用举例
-
股市预测
输入:过去10年股票的变动、新闻资讯、公司并购咨询
输出:预测股市明天的平均值 -
自动驾驶
输入:无人车上的各个sensor的数据,例如路况、测出的数据
输出:方向盘的角度 -
商品推荐
输入:商品A的特性,商品B的特性
输出:购买商品B的可能性 -
Pokemon攻击力预测
输入:进化前的CP值、物种、血量等
输出:进化后的CP值
模型步骤
把建立回归模型的过程分为三步:
- step1:模型假设,选择模型框架(线性模型)
- step2:模型评估,如何判断众多模型的好坏(loss function)
- step3:模型优化,如何筛选最优的模型
问题引入:
estimating the Combat Power (CP战斗力)of a pokemon after evolution
我们希望找到一个function计算pokemon进化后的cp值
step1:模型假设
单个特征:一元线性模型
假设进化后的cp值只与进化前的cp值有关,所以我们以一个特征xcp为例,线性模型假设 y = b + w·xcp ,w和b可以猜测很多模型:
f1: y = 10.0 + 9.0 · xcp
f2: y = 9.8 + 9.2 · xcp
f3: y = -0.8 - 1.2 · xcp
····
b和w可以是任意参数,因此可以确定一定的function set,从而选择最合理的function
多个特征:多元线性模型
在实际应用中,往往有多种因素影响最后的结果,输入特征肯定不止xcp这一个,物种、血量、重量、高度,特征会有很多。
step2: 模型评估 goodness of function
以下为单个特征的情况
1、收集和查看训练数据
这里定义x1是进化前的CP值,
y
^
1
\hat y^1
y^1表示进化后的cp值,^表示的是真实值
将十组原始数据在二维图中展示,图中的每一个点
(
x
c
p
n
,
y
^
n
)
( x^n _{cp},\hat y^n)
(xcpn,y^n)对应着进化前的CP值和进化后的CP值
2、定义模型的好坏
定义一个损失函数(loss function)来衡量模型的好坏,统计10组原始数据
(
y
^
n
−
f
(
x
c
n
p
)
)
2
(\hat y ^n - f(x^n _cp))^2
(y^n−f(xcnp))2的和,和越小模型越好。如下图所示:
- 上图中的每一个点都代表一组(w, b),也就是对应着一个function
- 该点的颜色对应loss function的结果L(w,b),它表示该点对应的function的表现效果,颜色越红,代表loss的数值越大,这个function的表现越不好
step3:最佳模型 - 梯度下降
【以下仍然是单个特征的情况】
如何筛选最优的模型(参数w,b)
如何才能找到使loss function取最小值时的w和b的值?
先从最简单的只有一个参数w入手,定义
w
∗
=
a
r
g
m
i
n
f
L
(
w
)
w^* = arg \mathop{min}\limits_{f}L(w)
w∗=argfminL(w)
计算方法:
- 1.随机选取一个w;
- 2.计算w=w0时L对w的微分,也就是当前的斜率;
如果斜率为负,则说明该点左侧的loss值更高,需要增加w的值;
- 3.根据学习率移动;
如何确定移动多少步长?1.微分的大小,2.learning rate。
- 4.重复2和3直到找到最低点。
但我们找到的点可能是local minima,并不是全局的最小值,我们在之后会进一步学习。
【两个参数的情况】
随机选取两个参数的初始值,分别计算两个初始值的偏微分
梯度下降推演最优模型的过程
- 等高线上的数值代表loss的值,颜色越深的区域代表损失函数越大;
- 红色的箭头代表等高线的法线方向;
梯度下降在实际应用中面临的挑战
可能存在的问题:
- 当前最优(stuck at local minima)
- 等于0(stuck at saddle point)
- 趋近于0(very slow at the plateau)
注意:在线性模型中,损失函数是凸函数,无论选取哪一个点,最终得到的都是全局最优解,在其他更复杂的模型里面,就会遇到2和3的问题了。
w和b偏微分的计算方法
如何验证训练好的模型的好坏
使用训练集和测试集的平均误差来验证模型的好坏,我们得到的训练集的平均误差为31.9
但我们真正想知道的是在新数据上的错误,使用测试数据得到的平均误差为35.0,如图所示
更加强大复杂的模型:1元N次线性模型
在模型上,我们还可以进一部优化,选择更复杂的模型,使用1元2次方程举例,如图,发现训练集求得平均误差为15.4,测试集的平均误差为18.4
这里我们又提出一个新的问题:是不是能画出直线就是线性模型,各种复杂的曲线就是非线性模型? 其实还是线性模型,因为把
x
c
p
1
=
(
x
c
p
)
2
x_{cp}^1= (x_{cp})^2
xcp1=(xcp)2看作一个特征,那么
y
=
b
+
w
1
⋅
x
c
p
+
w
2
⋅
x
c
p
1
y = b + w_1·x_{cp} + w_2·x_{cp}^1
y=b+w1⋅xcp+w2⋅xcp1其实就是线性模型。
过拟合问题出现
在模型上,我们再可以进一部优化,使用更高次方的模型,如图所示
训练集平均误差【15.4】【15.3】【14.9】【12.8】
测试集平均误差【18.4】【18.1】【28.8】【232.1】
当引入四次函数时,出现过拟合overfitting
步骤优化
更多的input
我们发现种类的影响也很大,因此在step1中,将pokemon的种类也作为特征考虑进去
得到的结果如下图所示,但仍然有不贴合的地方,因此考虑添加更多的参数
重建模型,把所有能想到的参数都考虑进去
但上诉的办法行不通,因此考虑其他的方法
正则化
更多特征,但是权重w 可能会使某些特征权值过高,仍旧导致overfitting,所以加入正则化
w 越小,表示 functionfunction 较平滑的, functionfunction输出值与输入值相差不大
在很多应用场景中,并不是 ww 越小模型越平滑越好,但是经验值告诉我们 ww 越小大部分情况下都是好的。
bb 的值接近于0 ,对曲线平滑是没有影响
总结
案例
import numpy as np
import matplotlib.pyplot as plt
from pylab import mpl
# matplotlib没有中文字体,动态解决
plt.rcParams['font.sans-serif']=['SimHei']
plt.rcParams['axes.unicode_minus']=False
x_data = [338., 333., 328., 207., 226., 25., 179., 60., 208., 606.]
y_data = [640., 633., 619., 393., 428., 27., 193., 66., 226., 1591.]
x_d = np.asarray(x_data)
y_d = np.asarray(y_data)
x = np.arange(-200, -100, 1)
y = np.arange(-5, 5, 0.1)
Z = np.zeros((len(x), len(y)))
X, Y = np.meshgrid(x, y)
# loss
for i in range(len(x)):
for j in range(len(y)):
b = x[i]
w = y[j]
Z[j][i] = 0 # meshgrid吐出结果:y为行,x为列
for n in range(len(x_data)):
Z[j][i] += (y_data[n] - b - w * x_data[n]) ** 2
Z[j][i] /= len(x_data)
# 先给b和w一个初始值,计算出b和w的偏微分
# linear regression
#b = -120
#w = -4
b=-2
w=0.01
lr = 0.000005
iteration = 1400000
b_history = [b]
w_history = [w]
loss_history = []
import time
start = time.time()
for i in range(iteration):
m = float(len(x_d))
y_hat = w * x_d +b
loss = np.dot(y_d - y_hat, y_d - y_hat) / m
grad_b = -2.0 * np.sum(y_d - y_hat) / m
grad_w = -2.0 * np.dot(y_d - y_hat, x_d) / m
# update param
b -= lr * grad_b
w -= lr * grad_w
b_history.append(b)
w_history.append(w)
loss_history.append(loss)
if i % 10000 == 0:
print("Step %i, w: %0.4f, b: %.4f, Loss: %.4f" % (i, w, b, loss))
end = time.time()
print("大约需要时间:",end-start)
# plot the figure
plt.contourf(x, y, Z, 50, alpha=0.5, cmap=plt.get_cmap('jet')) # 填充等高线
plt.plot([-188.4], [2.67], 'x', ms=12, mew=3, color="orange")
plt.plot(b_history, w_history, 'o-', ms=3, lw=1.5, color='black')
plt.xlim(-200, -100)
plt.ylim(-5, 5)
plt.xlabel(r'$b$')
plt.ylabel(r'$w$')
plt.title("线性回归")
plt.show()
横坐标是b,纵坐标是w,标记×位最优解,显然,在图中我们并没有运行得到最优解,最优解十分的遥远。那么我们就调大learning rate,lr = 0.000001(调大10倍),得到结果如下图。
再将learning rate扩大十倍,得到结果如下图
因此给b和w特制化两种learning rate
# linear regression
b = -120
w = -4
lr = 1
iteration = 100000
b_history = [b]
w_history = [w]
lr_b=0
lr_w=0
import time
start = time.time()
for i in range(iteration):
b_grad=0.0
w_grad=0.0
for n in range(len(x_data)):
b_grad=b_grad-2.0*(y_data[n]-n-w*x_data[n])*1.0
w_grad= w_grad-2.0*(y_data[n]-n-w*x_data[n])*x_data[n]
lr_b=lr_b+b_grad**2
lr_w=lr_w+w_grad**2
# update param
b -= lr/np.sqrt(lr_b) * b_grad
w -= lr /np.sqrt(lr_w) * w_grad
b_history.append(b)
w_history.append(w)
# plot the figure
plt.contourf(x, y, Z, 50, alpha=0.5, cmap=plt.get_cmap('jet')) # 填充等高线
plt.plot([-188.4], [2.67], 'x', ms=12, mew=3, color="orange")
plt.plot(b_history, w_history, 'o-', ms=3, lw=1.5, color='black')
plt.xlim(-200, -100)
plt.ylim(-5, 5)
plt.xlabel(r'$b$')
plt.ylabel(r'$w$')
plt.title("线性回归")
plt.show()221
有了新的特制化两种learning rate就可以在10w次迭代之内到达最优点了。