机器学习吴恩达老师课堂笔记(五)
这一部分就是机器学习课程的最后一部分了,前面的内容可以参考机器学习吴恩达老师课堂笔记(一)、机器学习吴恩达老师课堂笔记(二)、机器学习吴恩达老师课堂笔记(三)和机器学习吴恩达老师课堂笔记(四)。前面一节讲完了无监督学习,这里来讲一下几种常见的算法,然后以图片 OCR 为例来介绍一下机器学习系统的设计过程。
4. 一些特殊算法
4.1 推荐系统(Recommender system)
以电影推荐系统为例,每个用户都会对部分电影进行打分,推荐系统需要根据每部的电影的不同特征学习每个用户对于不同电影的喜好程度,从而预测用户对于没看过的电影的打分情况,从而推荐得分较高的电影。
首先规定一下符号:
- r代表用户是否对电影进行过打分,r(i,j)=1表明用户j给电影i打过分
- y代表用户给电影打的分数, y ( i , j ) = 1 y^{(i,j)}=1 y(i,j)=1表明用户j给电影i打的分数(当且仅当r(i,j)=1的时候代表有效数据)
- x ( i ) \boldsymbol{x}^{(i)} x(i)代表电影i的特征变量的取值
- m ( j ) m^{(j)} m(j)代表用户j打过分的电影的数目
- n代表电影特征变量的个数
- n m n_m nm代表电影总数, n u n_u nu代表用户总数
学习的时候期望学得用户打分的表达式
(
θ
(
j
)
)
T
x
(
i
)
(\boldsymbol{\theta}^{(j)})^T\boldsymbol{x}^{(i)}
(θ(j))Tx(i),而优化目标就是这里的学习参数:
min
θ
(
j
)
[
1
2
m
(
j
)
∑
i
:
r
(
i
,
j
)
=
1
(
(
θ
(
j
)
)
T
x
(
i
)
−
y
(
i
,
j
)
)
2
+
λ
2
m
(
j
)
∑
k
=
1
n
(
θ
k
(
j
)
)
2
]
\min_{\boldsymbol{\theta}^{(j)}}\left[\frac{1}{2m^{(j)}}\sum_{i:r(i,j)=1}\left((\boldsymbol{\theta}^{(j)})^T\boldsymbol{x}^{(i)}-y^{(i,j)}\right)^2+\frac{\lambda}{2m^{(j)}}\sum_{k=1}^n\left(\boldsymbol{\theta}_k^{(j)}\right)^2\right]\\
θ(j)min
2m(j)1i:r(i,j)=1∑((θ(j))Tx(i)−y(i,j))2+2m(j)λk=1∑n(θk(j))2
实际上这是一个有监督学习过程
θ
(
j
)
,
x
(
i
)
∈
R
n
+
1
\boldsymbol{\theta}^{(j)},\boldsymbol{x}^{(i)}\in\mathbb{R}^{n+1}
θ(j),x(i)∈Rn+1,不过这里只是对单独的一个用户进行计算,实际上一个推荐系统需要对每个用户都单独计算代价函数:
min
θ
(
1
)
,
θ
(
2
)
,
⋯
,
θ
(
n
u
)
[
1
2
∑
j
=
1
n
u
∑
i
:
r
(
i
,
j
)
=
1
(
(
θ
(
j
)
)
T
x
(
i
)
−
y
(
i
,
j
)
)
2
+
λ
2
∑
j
=
1
n
u
∑
k
=
1
n
(
θ
k
(
j
)
)
2
]
\min_{\boldsymbol{\theta}^{(1)},\boldsymbol{\theta}^{(2)},\cdots,\boldsymbol{\theta}^{(n_u)}}\left[\frac{1}{2}\sum_{j=1}^{n_u}\sum_{i:r(i,j)=1}\left((\boldsymbol{\theta}^{(j)})^T\boldsymbol{x}^{(i)}-y^{(i,j)}\right)^2+\frac{\lambda}{2}\sum_{j=1}^{n_u}\sum_{k=1}^n\left(\boldsymbol{\theta}_k^{(j)}\right)^2\right]\\
θ(1),θ(2),⋯,θ(nu)min
21j=1∑nui:r(i,j)=1∑((θ(j))Tx(i)−y(i,j))2+2λj=1∑nuk=1∑n(θk(j))2
不过实际上对于每一部电影,很难获得其所有特征变量,因此需要其他方法来解决这个问题。首先需要搜集一批用户对于不同电影的喜好程度(相当于人工搜集参数
θ
\boldsymbol{\theta}
θ),然后根据搜集到的数据优化出电影的各特征变量的值:
min
x
(
1
)
,
x
(
2
)
,
⋯
,
x
(
n
m
)
[
1
2
∑
i
=
1
n
m
∑
j
:
r
(
i
,
j
)
=
1
(
(
θ
(
j
)
)
T
x
(
i
)
−
y
(
i
,
j
)
)
2
+
λ
2
∑
i
=
1
n
m
∑
k
=
1
n
(
x
k
(
j
)
)
2
]
\min_{\boldsymbol{x}^{(1)},\boldsymbol{x}^{(2)},\cdots,\boldsymbol{x}^{(n_m)}}\left[\frac{1}{2}\sum_{i=1}^{n_m}\sum_{j:r(i,j)=1}\left((\boldsymbol{\theta}^{(j)})^T\boldsymbol{x}^{(i)}-y^{(i,j)}\right)^2+\frac{\lambda}{2}\sum_{i=1}^{n_m}\sum_{k=1}^n\left(\boldsymbol{x}_k^{(j)}\right)^2\right]\\
x(1),x(2),⋯,x(nm)min
21i=1∑nmj:r(i,j)=1∑((θ(j))Tx(i)−y(i,j))2+2λi=1∑nmk=1∑n(xk(j))2
在数据不稀疏的情况下,如果每个用户都对每个电影进行了评价,我们就可以利用上面的两套步骤反复迭代最终收敛出一组合适的电影特征变量取值和观众取向参数,这就是协同过滤算法。不过实际上想要实现这个目标没有必要反复迭代,只需要重新写出一个代价函数为:
J
(
x
(
1
)
,
x
(
2
)
,
⋯
,
x
(
n
m
)
,
θ
(
1
)
,
θ
(
2
)
,
⋯
,
θ
(
n
u
)
)
=
1
2
∑
(
i
,
j
)
:
r
(
i
,
j
)
=
1
(
(
θ
(
j
)
)
T
x
(
i
)
−
y
(
i
,
j
)
)
2
+
λ
2
∑
j
=
1
n
u
∑
k
=
1
n
(
θ
k
(
j
)
)
2
+
λ
2
∑
i
=
1
n
m
∑
k
=
1
n
(
x
k
(
j
)
)
2
J(\boldsymbol{x}^{(1)},\boldsymbol{x}^{(2)},\cdots,\boldsymbol{x}^{(n_m)},\boldsymbol{\theta}^{(1)},\boldsymbol{\theta}^{(2)},\cdots,\boldsymbol{\theta}^{(n_u)})\\ =\frac{1}{2}\sum_{(i,j):r(i,j)=1}\left((\boldsymbol{\theta}^{(j)})^T\boldsymbol{x}^{(i)}-y^{(i,j)}\right)^2+\frac{\lambda}{2}\sum_{j=1}^{n_u}\sum_{k=1}^n\left(\boldsymbol{\theta}_k^{(j)}\right)^2+\frac{\lambda}{2}\sum_{i=1}^{n_m}\sum_{k=1}^n\left(\boldsymbol{x}_k^{(j)}\right)^2\\
J(x(1),x(2),⋯,x(nm),θ(1),θ(2),⋯,θ(nu))=21(i,j):r(i,j)=1∑((θ(j))Tx(i)−y(i,j))2+2λj=1∑nuk=1∑n(θk(j))2+2λi=1∑nmk=1∑n(xk(j))2
而优化目标就是同时对整个式子两套参数进行优化:
min
x
(
1
)
,
x
(
2
)
,
⋯
,
x
(
n
m
)
θ
(
1
)
,
θ
(
2
)
,
⋯
,
θ
(
n
u
)
J
(
x
(
1
)
,
x
(
2
)
,
⋯
,
x
(
n
m
)
,
θ
(
1
)
,
θ
(
2
)
,
⋯
,
θ
(
n
u
)
)
\mathop{\min_{\boldsymbol{x}^{(1)},\boldsymbol{x}^{(2)},\cdots,\boldsymbol{x}^{(n_m)}\atop\boldsymbol{\theta}^{(1)},\boldsymbol{\theta}^{(2)},\cdots,\boldsymbol{\theta}^{(n_u)}}}J(\boldsymbol{x}^{(1)},\boldsymbol{x}^{(2)},\cdots,\boldsymbol{x}^{(n_m)},\boldsymbol{\theta}^{(1)},\boldsymbol{\theta}^{(2)},\cdots,\boldsymbol{\theta}^{(n_u)})\\
θ(1),θ(2),⋯,θ(nu)x(1),x(2),⋯,x(nm)minJ(x(1),x(2),⋯,x(nm),θ(1),θ(2),⋯,θ(nu))
值得注意的就是这里将参数合并以后为了计算方便丢弃了截距项
θ
0
\boldsymbol{\theta}_0
θ0以及预设的
x
0
\boldsymbol{x}_0
x0,因为现在的结果可以等效被归算到特征变量中去。
完成优化以后就可以开始推荐了,我们可以估计出用户对于他还没看过的电影的预期评分,按照评分排序进行推荐,也可以找到用户刚刚给出好评的电影,找到特征向量之差的模长最短的电影(最相似的电影)进行推荐。
实际上上述算法会存在的问题就是,如果有一个用户没有对任何电影进行打分,那么按照随机初始化的思路由于该用户没有进行任何打分所以该用户不会对代价函数中的第一项产生任何贡献,反而正则化项会使得该用户的
θ
\boldsymbol{\theta}
θ快速迭代为0向量,于是推荐算法无法给出任何一个推荐电影。为了解决这个问题,可以对学习得到的参数矩阵:
Θ
=
[
(
θ
(
1
)
)
T
(
θ
(
2
)
)
T
⋮
(
θ
(
n
m
)
)
T
]
\boldsymbol{\Theta}=\begin{bmatrix} \left(\boldsymbol{\theta}^{(1)}\right)^T\\ \left(\boldsymbol{\theta}^{(2)}\right)^T\\ \vdots\\ \left(\boldsymbol{\theta}^{(n_m)}\right)^T\\ \end{bmatrix}\\
Θ=
(θ(1))T(θ(2))T⋮(θ(nm))T
进行均值规范化操作,也就是计算所有用户对于每部电影的均值打分(包括预测出来的分数)得到均值向量:
μ
=
[
μ
1
μ
2
⋮
μ
n
m
]
=
1
n
u
[
(
θ
(
1
)
)
T
(
θ
(
2
)
)
T
⋮
(
θ
(
n
m
)
)
T
]
[
1
1
⋮
1
]
\boldsymbol{\mu}=\begin{bmatrix} \mu_1 \\ \mu_2\\ \vdots \\ \mu_{n_m} \end{bmatrix}=\frac{1}{n_u}\begin{bmatrix} \left(\boldsymbol{\theta}^{(1)}\right)^T\\ \left(\boldsymbol{\theta}^{(2)}\right)^T\\ \vdots\\ \left(\boldsymbol{\theta}^{(n_m)}\right)^T\\ \end{bmatrix}\begin{bmatrix} 1 \\ 1 \\ \vdots \\ 1 \end{bmatrix}\\
μ=
μ1μ2⋮μnm
=nu1
(θ(1))T(θ(2))T⋮(θ(nm))T
11⋮1
然后将参数矩阵 Θ \boldsymbol{\Theta} Θ的每一列都与该均值向量做差称为新的参数矩阵,使用这种方法等价于新注册的用户的默认参数矩阵都是大众的平均值,于是就可以进行算法推荐了。不过要注意的就是在计算评分的时候还是需要将这个均值向量重新加上,即最终评分为: ( θ ( j ) ) T x ( i ) + μ i (\boldsymbol{\theta}^{(j)})^T\boldsymbol{x}^{(i)}+\mu_i (θ(j))Tx(i)+μi.
4.2 大规模机器学习
随着数据集体量的增大,梯度下降需要的计算量越来越大,网络的训练速度越来越慢,因此需要额外的算法来帮助加快梯度下降。
4.2.1 随机梯度下降(Stochastic gradient descent)
梯度下降过程需要考虑代价函数对于每一个参数的偏导数,这就导致当数据体量非常大的时候,梯度的计算会变得非常困难,这里一般把这种每次梯度下降过程将所有数据样本都考虑在内的梯度下降算法称为“批量梯度下降”(Batch gradient descent)。
为了避免批量梯度下降导致的每次梯度计算都需要遍历整个数据集的问题,这里提出了随机梯度下降的概念,这里以线性回归为例,首先回忆一下无正则化项的线性回归的算法结构:
- 每个训练周期:
- 遍历每个参数
θ
j
\theta_j
θj(注意数据的更新是同步的):
θ j : = θ j − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) \theta_j:=\theta_j-\alpha\frac{1}{m}\sum_{i=1}^m\left(h_{\boldsymbol{\theta}}(x^{(i)})-y^{(i)}\right)x_j^{(i)}\\ θj:=θj−αm1i=1∑m(hθ(x(i))−y(i))xj(i)
- 遍历每个参数
θ
j
\theta_j
θj(注意数据的更新是同步的):
这里会导致算法计算速度慢的就是每次计算都要反复遍历每个数据样本(如果数据量大的话就是需要反复访问硬盘)。于是考虑随机梯度下降,首先定义对于单个数据样本的损失函数:
cost
(
θ
,
(
x
(
i
)
,
y
(
i
)
)
)
=
1
2
(
h
θ
(
x
(
i
)
−
y
(
i
)
)
)
2
\textrm{cost}(\boldsymbol{\theta},(x^{(i)},y^{(i)}))=\frac{1}{2}\left(h_{\boldsymbol{\theta}}(x^{(i)}-y^{(i)})\right)^2\\
cost(θ,(x(i),y(i)))=21(hθ(x(i)−y(i)))2
此时不难发现整体代价函数可以写作:
J
(
θ
)
=
1
m
∑
i
=
1
m
cost
(
θ
,
(
x
(
i
)
,
y
(
i
)
)
)
J(\boldsymbol{\theta})=\frac{1}{m}\sum_{i=1}^m\textrm{cost}(\boldsymbol{\theta},(x^{(i)},y^{(i)}))\\
J(θ)=m1i=1∑mcost(θ,(x(i),y(i)))
据此可以写出随机梯度下降的算法结构:
- 首先将训练集数据随机打乱。
- 每个训练周期:
- 遍历每个数据样本i:
- 遍历每个参数
θ
j
\theta_j
θj(注意数据的更新是同步的):
θ j : = θ j − α ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) \theta_j:=\theta_j-\alpha\left(h_{\boldsymbol{\theta}}(x^{(i)})-y^{(i)}\right)x_j^{(i)}\\ θj:=θj−α(hθ(x(i))−y(i))xj(i)
- 遍历每个参数
θ
j
\theta_j
θj(注意数据的更新是同步的):
- 遍历每个数据样本i:
这就相当于不需要反复遍历整个训练集从而带来计算时间缩短的好处。这里的做法就是对每一个数据样本进行单独的梯度下降使得每一轮内循环结束的时候都是对于当前数据点的最优。不过会带来的问题就是训练更可能会停留在局部最优解、最终结果反复震荡等等。不过相比较于批量梯度下降过程的超长计算时间而言这也是可以接受的。下图就是描述随机梯度下降和批量梯度下降的下降路径的曲线:(红色是批量梯度下降而粉色是随机梯度下降)
其实随机梯度下降还会带来其他的好处,也就是外循环训练次数可以降低,所以整体而言训练时间会被大幅度缩短。
这里还有一个问题就是判断随机梯度下降的收敛性问题。在批量梯度下降中一般通过绘制迭代次数和总代价函数的曲线来判断,不过在随机梯度下降中中途停止随机梯度下降计算一次整体代价函数其实不太现实(速度又会被大幅度拖慢),因此这里还是考虑采用前面定义的对于单个样本的损失函数。可以考虑在每1000轮迭代结束以后绘制一下前1000轮迭代中的平均损失函数。通过观察该图可以大致看出算法是否在正常收敛。不过显而易见的就是这种计算方式会存在比较大的噪声,下面就是四种可能出现的情况:
- 左上图描述的是两种学习率下平均损失函数的可能表现情况,红线的学习率低于蓝线,可以发现下降速度可能更慢但是也有可能得到一个更小的平均损失函数。这来源于实际上随机梯度下降会在最优解附近震荡,而减小学习率可以减小震荡
- 右上图描述的是增大平均损失函数的平均数量以后可能的计算结果,注意这里没有改变网络的训练过程,红线相比蓝线更加平滑但是略显滞后
- 左下图描述的是一种震荡情况,从这种震荡中很难观察到算法是不是在正常梯度下降,可以考虑增大参与平均的损失函数点数,如果平均完以后是红线说明正在缓慢地进行梯度下降,而如果是粉线则说明没有在正常学习
- 右下图说明损失函数发散了,说明需要调整学习率或者查找一下程序中是存在bug
为了避免随机梯度下降最后在全局最优解附近反复正常,有一种方法就是随着训练代数的增大逐渐减小学习率,比如这样:
α
=
c
1
c
2
+
iterationNum
,
(
c
1
,
c
2
∈
R
+
)
\alpha=\frac{c_1}{c_2+\textrm{iterationNum}},(c_1,c_2\in\mathbb{R}_+)\\
α=c2+iterationNumc1,(c1,c2∈R+)
代价就是增加了两个超参数。
4.2.2 小批量梯度下降(Mini-batch gradient descent)
到现在为止已经介绍了两种梯度下降——批量梯度下降和随机梯度下降。这两个整体而言是这样的:
- 批量梯度下降:在每一轮迭代中使用所有的训练样本点
- 随机梯度下降:在每一轮迭代中只使用一个训练样本点
而这里要提出的小批量梯度下降则介于两者之间,每一轮迭代使用b个数据样本,这里的b是一个可调参量,被称为mini-batch的大小,典型值2~100.算法流程大概就是这样的:
- 每个训练周期:
- 取i=1,b+1,2b+1,3b+1,…
- 遍历每个参数
θ
j
\theta_j
θj(注意数据的更新是同步的):
θ j : = θ j − α 1 b ∑ k = i i + b − 1 ( h θ ( x ( k ) ) − y ( k ) ) x j ( k ) \theta_j:=\theta_j-\alpha\frac{1}{b}\sum_{k=i}^{i+b-1}\left(h_{\boldsymbol{\theta}}(x^{(k)})-y^{(k)}\right)x_j^{(k)}\\ θj:=θj−αb1k=i∑i+b−1(hθ(x(k))−y(k))xj(k)
- 遍历每个参数
θ
j
\theta_j
θj(注意数据的更新是同步的):
- 取i=1,b+1,2b+1,3b+1,…
显然小批量梯度下降的运算速度是快于批量梯度下降的,具体原因和随机梯度下降是一样的这里就不介绍了;而依赖于更多的向量计算库,小批量梯度下降的速度可能略优于随机梯度下降。唯一不足的点就是引入了一个新的超参数b。如果b选得比较好,训练的过程将会大大加快。
4.2.3 在线学习
在网站上,如果存在连续的大量数据流,就可以构建在线学习网络,每次使用输入的数据样本进行随机梯度下降然后丢弃,这种方法的优势就是可以根据用户喜好动态调整销售策略。比如手机销售网站就可以根据用户的搜索信息构建出特征向量 x \boldsymbol{x} x(描述字符与各个手机的匹配程度等等)和点击商品情况y学习出 p ( y = 1 ∣ x ) p(y=1|\boldsymbol{x}) p(y=1∣x)函数,从而在用户进行搜索的时候就可以按照用户的输入使用学习出来的函数输出从高到低对用户进行推荐。
4.2.4映射减少(Map reduce)与并行运算
主要思路就是将求梯度中的加法运算分发到多个处理器上单独进行然后汇总,可以提高学习速度。
5. 例子:照片OCR(Photo Optical Character Recognition)
5.1 整体介绍
整体而言,照片OCR完成的任务主要是四步:文字检测、字符拆分、字符识别、拼写校正。
首先是文字检测,就是从图中框选出有文字的部分,这一部分可以使用滑动窗口法,使用不同大小的滑动窗口扫描图像,检测窗口中是否存在文字,此时就可以训练监督学习网络从图像中判断是否存在文字。
比如上图通过滑动窗口法得到了左下角的灰度图,该图中灰度代表了网络认为这个位置存在文字的可能性,然后通过放大算子(可能是闭运算),最后删除长款比例明显不符合要求的内容就可以了。
接下来是字符拆分,仍然还是采用监督学习网络来学习滑动窗口中是否存在分隔字符,可以像这样构造数据集:
然后就可以通过这个网络对整块的字符串进行划分得到单个的字符,最后使用多分类的监督学习网络分别识别每个字符即可。
5.2 人工数据合成
为了获得更大体量的数据集,会使用到人工数据合成的方法,人工数据合成也分为两种——从头合成新的数据以及根据已有数据进行变形扩充得到新数据。
以OCR任务为例,从头生成新的数据就是可以从网上下载字体库并生成相应的图片,不过为了和真实场景下拍照得到的图片相吻合一般来说要进行一些其他变换操作,这种变换操作的逼真程度就决定了数据集的质量。
变形扩充主要就在已有的数据集的基础上进行一些操作变换实现扩充的效果,比如下图就实现了16倍的数据扩充:
不过这些变形操作需要注意会不会引起数据原始信号的丢失,以及加入的变形是否有意义,比如这个例子中加入高斯噪声的意义就不是很大,可以被认为是无效变换。
最后有几点值得讨论:
- 在进行人工数据合成之前最好需要先观察一下学习曲线看看数据集的加入是否确实会给网络性能带来比较大的提升,否则数据合成就是无意义的。
- 进行数据合成需要花费多少精力(人工变形扩充、数据集标注、外包)
5.3 上限分析
上限分析在优化决策中体现得尤为重要,简单来说就是测试一下系统中的每个模块的性能提升给整体系统的性能提升带来多大的改善。然后可以来讨论是否值得在某个模块上花大量时间做改进(找到主要矛盾)。
以这里的 OCR 识别为例:
我们可以先测量在测试集下整体系统的工作准确率,然后使用人工方式完成文字检测(比如在看到一张图片以后人为框出有文字的部分,相当于模拟了一个工作准确率100%的模块)然后再测量整套系统的工作准确率,这一部分准确率的提升就是优化文字检测模块能带来的上限,依次类推。比如如果最后测量到的各种操作下的系统准确率是这样的:
这就说明在文字分割部分花大把精力做性能提升就是没什么意义的。
至此吴恩达老师机器学习的课程内容就全部结束了,下阶段可能继续学习深度学习的内容。