Sweetkang 的机器学习实验室 (1)

前言

近年来,Machine Learning 在许多领域上已然取得了可喜的成就,非常火热。就我个人来讲,有意将业余 Sport Programming 的范围扩展一下,譬如 Topcoder Marathon。在解决实际问题中,方法太 Naive 往往效果不怎么样,依旧需要学习一下相关的基础知识。
本系列文章主要基于 Coursera 的 Machine Learning,我社内部 Machine Learning 课里能说的一部分,wikipedia,以及一些其他的读物。

一些概念

机器学习的定义

对于某类任务T和性能度量P,如果一个计算机程序在T上以P衡量的性能随着经验E而自我完善,那么我们称这个计算机程序从经验E中学习。
这是一个比较严谨的界定机器学习问题的 Guideline。如果有什么问题搞不清楚是不是这个范畴,可以尝试套用定义来检查:任务是什么,性能度量是什么,经验是什么,性能是否由于经验而提升。

一些机器学习应用

  • 手写识别,Optical character recognition
  • 文本分类,识别垃圾邮件,工口反动内容等
  • 语音识别,机器翻译等
  • 图像识别,人脸识别
  • 识别钓鱼网站
  • 机器人,无人机等

一些机器学习问题

  • 分类(Classification):给每组输入打一个 tag,譬如手写识别,实际上相当于对一个图像进行分类
  • 回归(Regression):对每组输入,预测一个实数值,譬如预测股市行情
  • Ranking:将输入排序,譬如对搜索引擎的搜索结果,推荐系统等
  • 聚类(Clustering):将输入数据分成若干类
  • 降维(Dimensionality reduction):寻找输入数据的低维表示

一些定义

  • 样例(Example):某个实体
  • Features:实体的属性集合,通常用向量来表示
  • Label:对于分类问题,就是样例属于哪一类;对于回归问题,就是实数值
  • 训练集(Training Data):用来训练模型
  • Validation set:往往用来调整学习的参数
  • 测试集(Test Data):用来评估模型的表现
  • 监督学习:从给定的训练数据集中学习出一个函数,当新的数据到来时,可以根据这个函数预测结果
  • 非监督学习:训练集没有人为标注的结果
  • 区别:训练数据有没有标注

机器学习三要素:模型,策略,算法

  • 模型:就是所要学习条件概率分布或决策函数
  • 策略:按照什么样的准则来学习或者挑选模型
  • 算法:学习模型的具体计算方法,即用什么样的方法来求得最优解

个人理解,模型代表着你如何看待这个问题。譬如识别一个东西是不是汽车,如果你认为识别的依据是:金属壳 + 车灯 + 反光镜 + 车轮子 … = 汽车,这个思路就比较接近基于规则,决策树,贝叶斯;如果你考虑这个东西和见过的什么东西比较相似,就是 KNN 的思路。之后我们要不断学习的实际上都是模型。

常见的两个策略是经验风险最小化和结构风险最小化。经验风险最小化意味着我们倾向于对训练数据取得精准的预测。这个想法很直接,且有一定道理:模型在训练数据上表现不佳,更无法指望在测试数据上取得好结果。但是,在训练集上表现好的模型,未必在测试集上表现好。通常来讲,简单的模型会更有通用性,而复杂的模型,往往会有一些 hardcode 了训练数据的感觉,效果反而不一定好。结构风险最小化在经验风险最小化的情况下,加入一些因子来限制模型的复杂度。

根据策略,可以列出一个需要最优化的式子。算法就是求这个式子最优或者较优解的方法。最常见的方法是梯度下降,其他技能还没有 get,就暂不讨论了。

梯度下降法(Gradient Descent)

暂时忘记机器学习,现在需要优化一个形如 \( y = f(\theta) \) 的式子,求 \( x = argmax f(\theta) \) 或 \( x = argmin f(\theta) \),有什么好的办法么?
梯度下降法,基于这样的观察:如果实值函数\( F(x) \)在点 a 处可微且有定义,那么函数 \( F(x) \)在 a 点沿着梯度相反的方向 \( -F\nabla(a) \) 下降最快。因此,如果 \( b = a - \gamma\nabla F(a) \) 对于 \( \gamma > 0 \) 且为一个够小数时成立,那么 \( F(a) \geq F(b) \)。换句话说,我们给出一个对极值的估计 a,不断迭代求 \( a = a - \gamma\nabla F(a) \) ,就能取得一个极值。

用一个实际例子来演示一下:对二次函数 \( f(y) = x^{2} + 2x + 10 \) ,使用梯度下降法求 \( min f(x) \) 和 \( argmin f(x) \),函数图像如下:

结论无论是从图像还是初中数学的角度来看都很简单。我们看看梯度下降算法是如何进行的:

f <- function(x) {
    x^2 + 2 * x + 10
}
df <- function(x) {
    2 * x + 2
}

x <- 5
y <- f(x)
learning.rate <- 0.3
plot(f, -5, 5)

while (TRUE) {
    nx = x - df(x) * learning.rate
    ny = f(nx)
    if (abs(x - nx) < 0.01) 
        break
    arrows(x, y, nx, ny, col = "red")
    x = nx
    y = ny
    print(c(x, ny))
}

plot of chunk unnamed-chunk-1

## [1]  1.40 14.76
## [1] -0.040  9.922
## [1] -0.616  9.147
## [1] -0.8464  9.0236
## [1] -0.9386  9.0038
## [1] -0.9754  9.0006
## [1] -0.9902  9.0001

无论是简单问题还是复杂问题,参数 learning.rate,也就是前文中提到的\( \gamma \)的选择非常重要。Learning rate 过小则需要更多的迭代。Learning rate 过大则会出现之字下降,甚至之字上升。

看一个非凸,多元函数的例子:Rosenbrock函数:\( f(x, y) = (1-x)^2 + 100(y-x^2)^2 \) 很显然 x = y = 1 的时候可以取得最优解,但是求解过程却是很坑的。咱们把 x = y = 1 附近的图像画出来:

plot of chunk unnamed-chunk-2

再研究一下 x = 1 时的切面:

plot of chunk unnamed-chunk-3

大概能看出来,这个函数在解附近有个很大的很平的底。。。贴一段代码,大家可以 play 一下:

f <- function(x, y) { (1 - x) ** 2 + 100 * (y - x ** 2) ** 2}
df.dx <- function(x, y) { x * 2 - 2 - 400 * y + 400 * x ** 3}
df.dy <- function(x, y) { 200 * y - 200 }

x <- runif(1, 0, 2)
y <- runif(1, 0, 2)
z = f(x, y)
learning.rate = 1E-6
eps <- 1E-10

while (TRUE) {
  new.x = x - df.dx(x, y) * learning.rate
  new.y = y - df.dy(x, y) * learning.rate
  new.z = f(new.x, new.y)
  if (abs(new.z - z) < eps) break
  x = new.x
  y = new.y
  z = new.z
  print(c(x, y, z))
}

可以调整一些参数,譬如 learning.rate,eps 去看看某些现象。我们可以看到他最后几步的收敛极为缓慢,如果 learning.rate 过大,还会之字上升等等。总的来讲,选择一个合适的 learning rate 是非常重要的,除去经验性的技巧,往往也只好枚举了,看看 cost function 的变化情况,如果下降过慢,则需要增大 learning rate,如果反而增长了,则需要减少 learning rate。这也就是为什么某些时候我们需要一个比较小的 validate set,我们可以定期的在训练中的模型上跑一下 validate set,看一下 cost function 的变化,从而决定 learning rate 的调整。

一元线性回归

以 Stanford Machine Learning 为例:根据房子的面积预测房价。咱们来把一些概念对上号:

  • Training Set:m 个二元对 \( (x_{i},y_{i}) \)
  • feature:房屋面积,即 \( x_{i} \)
  • label:房价,即 \( y_{i} \)
  • 这是监督学习,因为测试数据是标注过的
  • 这是回归问题,因为 label 是连续值
  • 模型:一元线性回归,这个想法很显然
  • 策略:\[ minimize J(\theta_{0}, \theta_{1}) = \sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i})^2 \]

  • 算法:注意此时我们要求解的是 \( \theta_{0},\theta_{1} \),而 \( x_{i},y_{i} \) 都是已知量,可以考虑求偏导,然后用梯度下降求解,这就是技能范围以内的东西了,因为每次迭代用了所有的 Training Data,所以这个做法叫 Batch Gradient Descent。

实际应用中,比较好用的算法是 Stochastic Gradient Descent,Batch Gradient Descent 每次迭代,对 \( \sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i})^2 \) 求导,相当于 \[ \theta_{0} = \theta_{0} - 2\alpha\sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i})x_{i} \] \[ \theta_{1} = \theta_{1} - 2\alpha\sum_{i=1}^{m}(\theta_{0}x_{i} + \theta_{1} - y_{i}) \] 而 Stochastic Gradient Descent 相当与把 Batch Gradient Descent 的 1 次迭代拆成了 m 次,每次对 \( (\theta_{0}x_{i} + \theta_{1} - y_{i})^2 \) 求导,然后 \[ \theta_{0} = \theta_{0} - 2\alpha(\theta_{0}x_{i} + \theta_{1} - y_{i})x_{i} \] \[ \theta_{1} = \theta_{1} - 2\alpha(\theta_{0}x_{i} + \theta_{1} - y_{i}) \]

Batch Gradient Descent 可以求得更精确的解,但是如果模型复杂,或者数据量大,就很难直接 Batch Gradient Descent 了。

posted on 2014-03-22 17:33  康某-  阅读(1535)  评论(0编辑  收藏  举报

导航