最简单的中文机器学习教程

我之前在论坛发过一些机器学习的资源,但是这些资源比较难直接下手,必须要先学高数和概率论。那么我今天就把复杂的机器学习算法,写成高中数学形式。

问题:我有1000张猫的照片,1000张狗的照片,请训练一个系统,令其能够分辨猫和狗。

假如每张照片的大小是32x32,那么一张照片就有1024个像素,每个像素的亮度从0到1可变。我们把这1024个像素标记为x0, x1, x2....x1023. 这样,我们就用1024个变量表示了一张输入图片。

blob

这样就可以定义一个1024元函数:y0,y1 = f(x0,x1,x2.......x1023),其中y0是图片为猫的概率p(猫),y1是图片为狗的概率p(狗)。

我们的任务是,找到合适的函数 f(),使得计算f(猫的图片)得到 y0>y1,计算f(狗的图片)得到 y1>y0. 如果找到了这个函数f(),我们就可以计算 f(某张图片) = f(x0,x1,x2....x1023),如果得到的结果[y0,y1]中 y0>y1,比如[0.9, 0.3]或者[1.4, 0.8]或者[3.2, 1.6],就可以确定这张图片是猫。

所谓机器学习的训练过程,就是寻找函数f()的过程。

为了简化描述,我们把y0和y1称为二维矢量Y,把x0,x1,x2...x1023称为1024维矢量X。

表达式就可以简化为: Y = f(X)。

在下文中,我用大写字母表示矢量和矩阵。矢量和矩阵都是表示一组变量的简便方式(比如用矢量X来表示x0...x1023),是《线性代数》的教学内容。这是本教程涉及的唯一大学内容。

把图片中的1024个像素,转换成两个代表概率的数字,这中间的计算过程一定是非常复杂的。对于人脑和肉眼来说,猫或者狗的影像先通过晶状体汇聚到视网膜,再通过视神经传递到大脑的视神经中枢,再经过几次传递,最终得出猫或者狗的结论。这么复杂的神经传递过程,怎么用数学表达呢?人工智能领域的研究者提出,可以用神经元函数模拟神经元的行为。

下面是一个真正的人类神经元。

blob

刺激从dendrites(树突)传入神经元,然后从axon(轴突)传出。

怎么用数学公式描述它的特性呢?下面我介绍目前机器学习领域最常用的神经元函数。

blob

a = max(w0 * x0 + w1 * x1 + w2 * x2...+ w1023 * x1023 + b, 0)

或者简写为

a = max(W * X + b, 0)

其中a是神经元的输出,X(也就是x0...x1023)是神经元的输入,W(分别是w0...w1023)是神经元的权重,b是神经元的偏置,max是最大值函数。

我们注意到,每个神经元的输入可以有很多,但是输出连接只有一个,这和大脑中神经元的特性是类似的。

权重w的作用,是控制每个输入x对神经元的影响。如果w为负,则每个输入x对神经元的贡献就是负数。通过调节每一个w的大小,我们就可以让神经元对不同的输入x,产生不同的反应。如果某个w等于零,那么对应的输入x对后面的神经元就没有影响,相当于这个神经连接断掉了。

调节权重W(以及偏置b)的过程,称为学习或者训练。

神经元的输出有一个max函数,如果计算结果为正就直接输出,如果计算结果小于0就输出0。这是因为人类神经元只能输出正的刺激信号(脉冲),不能输出负的刺激信号。这只是一种直观的说法,实际上选择这个函数的原因非常复杂,可以去看geoff hinton的教程,里面有更加详细的数学解释。

由于f()的输出是两个实数,我们至少需要两个神经元。这两个神经元和图像的1024个输入都是相连接的。

blob

这样我们就实现了函数f()。上图中,两个神经元的输入权重w的序号重复了,为了明确,我们把第一个神经元的偏置和权重分别称为 b0, w0_0, w0_1, w0_2... 把第二个神经元的偏置和权重分别称为b1, w1_0, w1_1, w1_2...

于是f()的计算方法如下:

y0 = a0 = max(x0 * w0_0 + x1 * w0_1 + x2 * w0_2 ...+ x1023 * w0_1023 + b0, 0)

y1 = a1 = max(x0 * w1_0 + x1 * w1_1 + x2 * w1_2 ...+ x1023 * w1_1023 + b1, 0)

如果把x0...x1023称为X,把w0_0...w0_1023称为W0,把w1_0...w1_1023称为W1,上式可以简写为:

y0 = max(X * W0 + b0, 0)

y1 = max(X * W1 + b1, 0)

如果把y0...y1称为Y,把W0和W1称为W(这时W就有1024 * 2=2048个元素了,是一个1024 * 2尺寸的矩阵),b0和b1称为B,上式可以简写为:

Y = f(X) = max(X * W + B, 0)

于是,研究者们把W设为2048个随机数,把B设为两个随机数,然后给函数f()输入一张猫的图片。

f(X) = f(猫的图片) = max(猫的图片 * W + B) = [0.5, 0.5]

结果是y0 = 0.5, y1 = 0.5,也就是我们的神经网络分不清这张图片到底是更像猫还是更像狗。这是很正常的,因为我们的W和B是随机设定的。

(由于W和B都是函数f()的参数,下面我们把W和B统称为W。)

研究者随后对W进行了一点随机微调,并重新计算f(猫的图片)。如果调完之后y0增长了或者y1下降了,就说明调节有效;如果调完之后y1增长了或者y0下降了,就说明调的方向错了。

经过一段时间的调节,研究者发现这样很慢,W一共有2048个元素,每调一次,输出只动一点点,要调到什么时候?于是研究者就想了一个办法:用一个函数E来计算误差的大小。

首先,对输出[y0, y1]应用softmax函数。

$$\sigma(z) _{j}={\frac {e^{z _{j}}}{\sum _{k=1}^{K}e^{z _{k}}}}, j=1,2...K$$

用高中数学来写就是 softmax(Y) = softmax([y0,y1]) = [e^y0, e^y1] / (e^y0 + e^y1)

= [e^y0 / (e^y0 + e^y1), e^y1 / (e^y0 + e^y1)]

经过softmax函数之后,y0和y1的相对大小关系不变,但是他们的和保证等于1。比如说原来求得的猫狗概率是[1.2, 0.6],softmax函数之后就得到[0.65, 0.35]。

然后定义误差函数E:

Y = f(X)

E = - log(softmax(Y)) * y_true

E = - log(softmax(f(X))) * y_true

其中 y_true 代表的是输入图像的真正类别,当输入为猫时为[1,0],当输入为狗时为[0,1]。

我们注意到,因为softmax的结果都在0和1之间,应用log函数之后会得到一个负数,softmax所得的结果越小,log得到负数的绝对值就越大。如果softmax后所得结果接近零,log之后会得到一个非常大的负数。前面再加个负号,就得到一个非常大的正数。

所以E越大,说明我们的判断结果错得越离谱。这是一个很合适的误差函数。

当输入为猫时,输出y0(相对于y1)越小,误差函数E的值就越大,如果输出y0远小于y1,说明错的很严重,误差函数E的值会非常大。我们调节W的时候,就可以以E为参考。

上面讲到,研究者想了一个加速的办法。要怎样调节W,才能使得误差E不断降低呢?对了,可以利用E对W的导数。

我们在高中学过y对x的导数,可以写作$$\frac{dy}{dx}$$

blob

上图中x0处的导数,也就是绿色切线的斜率,是个负数,大概是 -2 。如果把点x0朝导数所指的下坡方向移动,y的值会越来越小。就像下面这样:

blob

如果用公式来描述这个过程:

$$x_1 = x_0 - \frac{dy}{dx}(x_0)$$ $$x_2 = x_1 - \frac{dy}{dx}(x_1)$$ $$x_3 = x_2 - \frac{dy}{dx}(x_2)$$

这相当于不断执行下面的操作:

$$x = x - \frac{dy}{dx}(x)$$

这种【按照y对x在x点的导数来调节x,使得y越来越小】的方法,称为导数下降法。

上面y对x的图像中,y是一维的,我们在一维函数上寻找最小值。如果y是二维的,有两个参数呢?下面是一张2维平面上的图像:

blob

上图中 theta0 和 theta1就是待调节的参数,而J(theta0,theta1)是误差函数。图中演示了两个点是如何通过梯度下降法,找到J()的局部最低点的。

原题中的W是2048个变量,E对W的导数要怎么写?难道要写2048条公式吗?

$$\frac{dE}{dw_{0,0}},\frac{dE}{dw_{0,1}}, ... ,\frac{dE}{dw_{1,1023}}$$

上面这种写法太繁琐了(而且也不正确)。通常我们这样写:

$$\frac{\partial E}{\partial w_{ij}}(W)$$

其中i=0,1 j=0,1,2...1023 称为E对\(w_{ij}\)在W处的偏导数。

之前抛物线函数的例子中,函数y上点x处的斜率是一个数字。而这次函数E上点W的斜率,共有2048个数字,可以记作一个2048维矢量:

$$\left(\frac{\partial E}{\partial w_{0,0}}(W),\frac{\partial E}{\partial w_{0,1}}(W), ... ,\frac{\partial E}{\partial w_{1,1023}}(W)\right)$$

上面这个矢量简称函数E在W处的梯度,它和之前所说的y在x处的斜率是一个意思,只不过由很多个数组成。上面的梯度可以简写为:

$$\nabla E(W)=\left({\frac {\partial E}{\partial w_{0,1}}}(W),\ldots ,{\frac {\partial f}{\partial w_{1,1023}}}(W)\right)$$

因此,只要不断执行:

$$W = W - \alpha \nabla E(W)$$

就可以使得E的值越来越小(假定E是个比较凸的函数)。这种【按照W对E在W处的偏导数来调节W,使得E越来越小】的方法,称为梯度下降法。梯度下降法的一个变种,随机梯度下降法,是目前机器学习领域应用最广泛的优化方法。

其中α是一个可调的量,称为学习率,它决定下降的速度和稳定性。

至此,我们可以把整个训练过程概括为:

  1. 确定Y = f(X)的形式,为了与人脑架构匹配,我们在这里用的是神经网络函数,函数的参数(偏置和权重)为W和B,以下将它们统一称为W;
  2. 对于给定的一批训练图片X(1000张猫,1000张狗),以及当前的W,计算误差 E = -log(softmax(f(X))) * y_true,其中 y_true 是代表对应图片猫狗分类的标签。
  3. 使用梯度下降法,根据E对W在W处的偏导调节W
  4. 重复第2步,直到误差E不再下降为止。
  5. 用经过训练的f()函数,输入猫狗图片并观察其输出,统计正确率。

为了让例子显得简单,我们只使用了2个神经元,而且从输入直接到输出,中间没有隐藏层,最终得到的分类效果是很差的。

如果你想玩这种最简单的神经网络,可以直接访问google的tensorflow神经网络演示页面,那里的分类器虽然不能分类猫和狗,但可以做一些同样有趣的事情。XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/

blob

在实际的视觉分类应用中,神经元的数量会多得多,而且会一层叠一层(警告:以下是大学内容),比如上面就是一个四层的神经网络,有两个隐藏层。

通过增加层数,网络可以表达更加复杂的非线性关系,从而能更好地概括输入数据中隐含的复杂关系。

对于视觉应用,每一层的输入,也不是直接取输入像素的值,而是用一组二维模板,对像素的值分别进行二维卷积,再叠加求和,层和层之间还有pooling(求局部最大值并组成更小的新图像)操作。

blob (LeNet架构,它20年前就学会了怎样分辨人类手写的数字,准确率超过99%)

使用二维卷积和pooling,可以令图像中关键特征获得位移无关性(比如猫的脸在图像中可能会左右移动,这不应该影响最终判断的结果)。

读到这里的同学,以上介绍完了机器学习的基本概念和方法,谢谢你们。如果你觉得这太简单了,下一步的两个可选的教程分别是Andrew Ng的 Machine Learning,以及Geoff Hinton的Neural Networks for Machine Learning

[修改于 5 年前 - 2016-12-15 00:20:51]

来自:计算机科学 / 机器学习
novakon 作者
4年11个月前 修改于 4年11个月前
1楼

补充一点:

上面提到的矩阵与矢量乘法,比如W * X,用星号表示逐项相乘,是为了保证高中数学不超纲。

实际在大学的数学书中,如果X是一个1024维矢量,W是一个1024 * 2尺寸的矩阵,这种运算通常写成:

$$X^TW$$

原文中单层神经元函数因此可以记作:

$$max(X^TW+B,0)$$

常见问题:

  • 我想要很多猫和狗的照片

    请去这里领取:XXXXXXXXXXXXXXXXXXXXXX/c/dogs-vs-cats

  • 神经网络的函数这么复杂,我不是很懂矩阵运算(线性代数)和求偏导(高等数学)怎么办?

    你只需要知道基本的矩阵概念(比如图像是二维矩阵,彩色图像是三维矩阵),以及怎么用python语言操纵矩阵的元素就可以了。谷歌开源的机器学习框架tensorflow就是用来做矩阵计算流程优化的,你可以用它拼接出神经网络,它有办法帮你设置好每一层的权重矩阵,并且帮你优化计算流程。神经网络函数、ReLU函数(就是max(x,0))、softmax函数都是tensorflow内置的。tensorflow可以根据你拼接出的计算流程,帮你求W对E的偏导,也就是说除了处理数据和设计架构,你什么都不用做。它有很多教程可以帮助你学习怎么使用,你应该花一些时间阅读。Github上的Keras框架把tensorflow包了一层,操作起来更简单,前提是你必须知道底下发生了什么。

  • 感觉卷积神经网络比普通神经网络还复杂

    tensorflow也支持卷积神经网络的构建,你大概知道原理就行了,不需要自己写二维卷积代码(很难写对的)。关于卷积神经网络(ConvNet,又称CNN)原理方面的内容,可以阅读Yann LeCun 发表于 2000年以前的论文。

  • 玩机器学习能提高我的数学水平吗?

    我认为是绝对不可能的。如果你数学不好,最好先学数学,千万别碰这个。

回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
CEC0D5F1B6AB
4年11个月前
2楼
真的很简单,收藏起来
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论
acmilan
4年10个月前
4楼
感谢分享。。。
回复
评论
加载评论中,请稍候...
200字以内,仅用于支线交流,主线讨论请采用回复功能。
折叠评论

想参与大家的讨论?现在就 登录 或者 注册

所属专业
上级专业
同级专业
novakon
学者 机友 笔友
文章
1257
回复
8401
学术分
16
2008/03/29注册,3 个月前活动

已走,勿送

%7B%22isDisplay%22%3Atrue%7D

仅供内部学术交流或培训使用,请先保存到本地。本内容不代表科创观点,未经原作者同意,请勿转载。

下载

插入资源
全部
图片
视频
音频
附件
全部
未使用
已使用
正在上传
空空如也~
上传中..{{f.progress}}%
处理中..
上传失败,点击重试
等待中...
{{f.name}}
空空如也~
(视频){{r.oname}}
{{selectedResourcesId.indexOf(r.rid) + 1}}
处理中..
处理失败
插入表情
我的表情
共享表情
Emoji
上传
注意事项
最大尺寸100px,超过会被压缩。为保证效果,建议上传前自行处理。
建议上传自己DIY的表情,严禁上传侵权内容。
点击重试等待上传{{s.progress}}%处理中...已上传
空空如也~
草稿箱
加载中...
此处只插入正文,如果要使用草稿中的其余内容,请点击继续创作。
{{fromNow(d.toc)}}
{{getDraftInfo(d)}}
标题:{{d.t}}
内容:{{d.c}}
继续创作
删除插入插入
{{forum.displayName}}
{{forum.countThreads}}
篇文章,
{{forum.countPosts}}
条回复
{{forum.description || "暂无简介"}}
ID: {{user.uid}}
学术分隐藏
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

支持的图片格式:jpg, jpeg, png
插入公式
分享回复:{{shareId}}
加载中...
评论控制
加载中...
文号:{{pid}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

加载中...
详情
详情
推送到专栏从专栏移除
设为匿名取消匿名
查看作者
回复
只看作者
加入收藏取消收藏
加入关注取消关注
折叠回复
置顶取消置顶
评学术分
鼓励
设为精选取消精选
建议修改
编辑
通过审核
评论控制
退修或删除
历史版本
违规记录
投诉或举报
加入黑名单移除黑名单
查看IP
{{format('YYYY/MM/DD HH:mm:ss', toc)}}
投诉或举报
加载中...
{{tip}}
请选择违规类型:
{{reason.type}}

空空如也

下载资料
{{fileName}}
大小:{{size}}
下载当前附件将花费 {{costMessage}}
{{description}}
你当前剩余 {{holdMessage}}
{{fileName}}
大小:{{size}}
当前附件免费。
你已购买过此附件,下载当前附件不需要花费积分。
加载中...
{{errorInfo}}
附件已丢失
当前账号的附件下载数量限制如下:
时段 个数
{{f.startingTime}}点 - {{f.endTime}}点 {{f.fileCount}}