这段时间里,我一直在尝试将open_nsfw加入到手机,给手机浏览器增加色情图片检测功能,这个分阶段进行,在前面的几篇文章中,都谈到了这方面的尝试:
然而,当我将open_nsfw移植到手机上运行时(源码已上传码云 - https://gitee.com/mogoweb/dpexamples.git ),现实无情的击碎了我的梦想,不是因为识别效果差,而是速度太慢。我在nexus 4手机上进行了测试,检测一张图片大约需要3秒钟时间。虽然nexus 4的硬件配置现在看来有些落伍,但是3秒钟的时间还是远远超过了我的预期。要知道,加载一个网页,图片可能有十几张。网上虽然有人对caffe做了一些优化,但并非出自官方,性能和兼容性难以保证。所以这件事情先暂时搁置,正在考虑换TensorFlow,因为TensorFlow是Google出品,按理应该会对自家的Android移动平台做优化。
还是回到机器学习上来,最新学习的章节是Logistic回归。
假设现在有一些数据点,我们用一条直线对这些点进行拟合(该线称为最佳拟合直线),这个拟合过程就称作回归。使用更加严谨的数学定义为:给定由d个属性描述的示例x=(x1;x2;…;xd),其中xi是x在第i个属性上的取值,线性模型试图学得一个通过属性的线性组合来进行预测的函数,即
f(x) = w1x1 + w2x2 + ... + wdxd + b
线性模型形式简单、易于建模,但却蕴涵着机器学习中一些重要的基本思想。许多功能更为强大的非线性模型可在线性模型的基础上通过引入层级结构或高维映射而得。此外,由于w直观表达了各属性在预测中的重要性,因此线性模型有很好的可解释性。
吴恩达的Machine Learning课程介绍的第一个机器学习算法就是线性回归,课程非常浅显易懂,免费且有中文字母,值得学一学。
在Machine Learning课程中,对于线性回归是以房价预测为例子进行说明的,但若要做的是分类任务该怎么办?答案在广义线性模型中:只需找一个单调可微函数将分类任务的真实标记y与线性回归模型的预测值联系起来。
利用Logistic回归进行分类的主要思想是:根据现有数据对分类边界线建立回归公式,以此进行分类。
考虑二分类任务,其输出标记y = {0, 1},而线性回归模型产生的预测值z是实值,于是,我们需将实值z转换为0/1值。最理想的是“单位阶跃函数”(又称为海维塞德阶跃函数):
然而,海维塞德阶跃函数的问题在于:该函数在跳跃点上从0瞬间跳跃到1,这个瞬间跳跃过程有时很难处理。
幸好,另一个函数也有类似的性质,且数学上更易处理,这就是Sigmoid函数,计算公式如下:
当x为0时,Sigmoid函数值为0.5,随着x的增大,对应的Sigmoid值将逼近于1,而随着x的减小,Sigmoid值将逼近于0。单位阶跃函数与Sigmoid函数如下图所示,可以看出Sigmoid函数看起来很像一个阶跃函数。
在线性回归中,向量w就是我们要找的最佳参数(系数),为了寻找该最佳参数,需要用到最优化理论的一些知识。
其中的一个最优化算法叫做梯度上升法。梯度上升法基于的思想是:要找到某函数的最大值,最好的方法是沿着该函数的梯度方向探寻。这段有点不太容易理解,通俗一些理解就是先给出一组w值,然后通过迭代更新这组w值,直至达到某个停止条件为止,比如迭代次数达到某个指定值或算法达到某个可以允许的误差范围。梯度上升算法的迭代公式公式如下:
注:梯度下降算法与梯度上升算法是一样的,只是公式中的加法需要变成减法。梯度上升算法用来就函数的最大值,而梯度下降算法用来求函数的最小值。
《机器学习实战》一书中给出了梯度上升算法的具体实现,关于最佳参数的迭代,代码为:
h = sigmoid(dataMatrix * weights)
error = (labelMat - h)
weights = weights + alpha * dataMatrix.transpose() * error
书中并没有给出公式的推导,通常情况下,我们也不需要知道。如果需要进一步了解,可以参考Machine Learning课程。
梯度上升算法在每次更新回归系数时都需要遍历整个数据集,该方法在处理1000个左右的数据集尚可,但如果有数十亿样本和成千上万的特征,那么该方法的计算复杂度太高。一种改进方法是一次仅用一个样本来更新回归系数,该方法成为随机梯度上升算法。