程序人生 A log of my life

coursera的机器学习课程

断断续续学完了这个经典课程,记录下。

概念

机器学习:一个程序,从经验E中学习,解决问题T,性能度量为P,当有了E之后,经过P评判,处理T的性能得到提升。

简化: 利用经验改善系统自身的性能。

其中:

  • 从经验(数据)中产生模型的的算法即学习算法。
  • 有了算法,我们再把经验数据传给它,称为学习或者训练(Training)。
  • 产生的模型就可以对新的数据进行预测(判断),这个过程称为测试(Testing)。

机器学习从输入来看可以分为:

  • 监督学习:学习数据是有正确答案的,比如预测肿瘤等,这里的答案通常也称为标签。
  • 无监督学习:学习数据并没有标签,比如google的新闻分类。

如果从输出角度来看,可以分:

  • 回归问题(regression),输出是一个连续值。
  • 分类问题(classification),输出是一个离散值,常见的一种是二元分类问题,输出就是二选一。
  • 聚类(clustering),就比如上方的新闻分类。

通常来说回归问题,分类问题是属于监督学习,聚类问题属于无监督学习。

线性回归

代价函数:

梯度下降

线性回归问题可以使用梯度下降算法,算法核心是每一轮迭代时同时修改参数:

对于两个参数的线性回归问题,可以等价为:

梯度下降因为涉及多步迭代,参数的选择非常重要,如果参数差异非常大,迭代效果不佳(甚至不能收敛),这时需要做参数正规化处理,结果是需要保证参数在-0.5~0.5范围,最常用的方法就是减去平均值再除以range。

多元线性回归

对于多个特征值的线性回归问题,我们称为多元线性回归,使用线性代数得方程,可以大大简化h函数的写法。

注意右上角的T为转置。

正规方程

对于线性回归算法,也可以用正规方程直接求解参数,无需梯度下降

注意上方的-1为求逆矩阵。

正规方程 vs 梯度下降:

  • 正规方程一步求解,比较方便,也不需要做参数的缩放。但正规方程的算法涉及矩阵求逆,是个O(n^3)算法,所以参数少时,正规方程很快,但参数达到10000以上,要考虑性能问题,n太大时,还是梯度下降更快。
  • 正规方程只能用于特征变量少的线性回归算法,在其他算法里,梯度下降算法仍可以用,但却不能使用正规方程了。

分类问题

y等于0或者1,称之为二元分类问题,但直接输出0或1的h函数不是那么有意义,更常见的场景是,h函数的输出是y为1的概率,也就是说我们将h函数仍然定义为一个连续量(从0到1),比如把预测肿瘤是良性还是恶性(二元分类问题)改变为预测肿瘤为恶性的概率。这样基本上把一个分类问题转换为了一个回归问题,我们称之为逻辑回归。

于是这个h函数可以使用概率论中的P表达式

对于这样的h函数,比较好的拟合算法不再是线性方程,而是S函数,或者说逻辑函数,如下图

S函数在x大于0时,输出0.5以上的值,在x小于0时,输出0.5以下的值,同时可以引出一个概念,决策边界,就是h函数等于0.5的区域。

逻辑回归

对于上述逻辑回归的h函数定义,cost函数不能使用原先线性回归的定义,那样会导致cost函数有大量局部优化解,不利于梯度下降等算法的求解,所以我们为逻辑回归问题定义新的cost函数

选择这个cost函数,是因为这个函数是凸函数,便于参数的求解,我们依然可以使用梯度下降来求解参数,并且神奇的是,这个公式和线性回归一模一样。

当然,可以使用向量来简化公式:

除了梯度下降,还有一些更高级或者说复杂的算法来计算θ,可以不需要选择alpha,但是这些算法复杂的多,通常不需要了解实现细节,一些函数库将他们封装好,直接使用。

多元分类

当y取值大于2个,这种分类问题称为多元分类,可以将多元分类,分解为多个二元分类来求解,这样:

神经网络

对于复杂的非线性分类问题,上述的算法都不再适用,因为非线性问题导致的输入参数过多,n个特征值的二次函数,总参数为O(n^2),计算量过大,如果用三次函数则为O(n^3),更多了。比如图像识别等,因此神经网络更为适合。

神经网络中的基本元素是神经元,神经元做的事情很简单,一个线性变换加一个激活变换(非线性)。

之所以加激活函数,这个是神经网络的灵魂,没这个函数,再多层的神经网络叠加后本质上还是只是一个线性变换,当然为了梯度下降算法能够应用,我们需要激活函数可以连续微分。激活函数到目前为止,常用的有:

之所以最早使用sigmoid函数,因为它的输出是0~1,符合很多分类预测问题概率输出的需要。但实际情况中,sigmoid并非最佳。

  • sigmoid 现在常用在二元分类网络的输出层,输出0~1间的概率分布。
  • relu函数的梯度更大,更适合梯段下降算法,常用于hidden layer,tanh也还不错。

softmax layer 常用在多分类网络的输出层,它很简单,把上一层的每个分类的可能性输出转换为0~1的概率。

训练神经网络的方法通常为梯度下降法, Loss函数可以用最大似然估计来求解,可以得到三个函数(求解过程略):

  • Binary Cross entropy
  • Cross entropy
  • Squared loss function

线性回归的python实现

可以用线性回归来作机器学习的入门,因为它最简单,但揭示了很多机器学习的概念。简单的线性回归问题是可以有解析解的,但问了演示,我们还是通过数值方式来解。

它的代价函数通常为RMSE - 均方根误差,也可以用MSE-均方误差, 下面是一个最小二乘法(Least Squares)实现的回归例子(最小二乘可以直接用方程推导)。

import pylab
import numpy
pylab.ion()

x = numpy.linspace(-1,1,100)
signal = 2 + x + 2 * x * x
noise = numpy.random.normal(0, 0.1, 100)
y = signal + noise
x_train = x[0:80]
y_train = y[0:80]

degree = 9
X_train = numpy.column_stack([numpy.power(x_train,i) for i in xrange(0,degree)])
model = numpy.dot(numpy.dot(numpy.linalg.inv(numpy.dot(X_train.transpose(),X_train)),X_train.transpose()),y_train)
pylab.plot(x,y,'g')
pylab.xlabel("x")
pylab.ylabel("y")
predicted = numpy.dot(model, [numpy.power(x,i) for i in xrange(0,degree)])
pylab.plot(x, predicted,'r')
pylab.legend(["Actual", "Predicted"], loc = 2)
train_rmse1 = numpy.sqrt(numpy.sum(numpy.dot(y[0:80] - predicted[0:80], y_train - predicted[0:80])))
test_rmse1 = numpy.sqrt(numpy.sum(numpy.dot(y[80:] - predicted[80:], y[80:] - predicted[80:])))

解释一下numpy的几个api:

  • numpy.column_stack
  • numpy.dot 点积/点乘/内积

这是一个典型的欠拟合,将degree改为3和9,分别可以得到2阶和8阶多项式拟合的结果,结果分别对应比较好的拟合和过拟合,因为实验数据解来自于二阶多项式加噪声,可以理解为什么二阶拟合最佳,但实际情况中很难知道实验数据是几阶的,所以调节模型的阶数并不容易。另外,如果学习数据量很小,也不能用过高的阶数的拟合,比如50个学习数据,如果用50阶来拟合,就100%过拟合,没有任何意义。

为了解决过拟合问题,一种方法当然是提高训练集数量,另一个方法是引入正则化概念,在模型上引入一个正则项,用于惩罚过多的阶数,正则后的模型可以更好的防止过拟合。