人工智能技术能够把计算机变成像人一样具备思考能力,这看起来非常神奇,很多人以为内部机理一定非常复杂,复杂到只有那些穿着白大褂的大胡子科学家才能明白。诚然技术原理确实不简单,但通过大白话,以普通人能理解的方式把它说清楚其实一点也不难。这里,我抛弃各种高大上的科学词汇和艰深难懂的数学公式,用老妪能懂的普通话向你解释清楚人工智能的技术内核。
我们想象一个会“思考”的机器,我们从一端塞给它一个问题,它从另一端输出答案。
这里写图片描述
问题在于,机器无法思考,它只能根据给定的步骤进行计算,所以机器处理问题的本质如下:
这里写图片描述
也就是说,你必须把数据输入到电脑,电脑能够预先安排好的步骤对输入数据进行处理,最终给出相应结果。例如乘法的本质是将被乘数连续进行乘数次求和,例如3 * 4 中,3是被乘数,4是乘数,算术的结果就是把4连续进行3次加法运算,于是当我们把3*4输入到电脑时,它的运转过程如下:
这里写图片描述
也许你会觉得上面的描述平淡无奇,但当前神乎其神的人工智能就是从这种平淡无奇中演化出来的。我们现实世界所面临的很多问题,我们是不知道中间的处理步骤的,再看一个例子,如果我们想让电脑帮我们把公里数转换成英里,但我们又不知道这个转换过程的具体步骤,那怎么办?
这里写图片描述
既然我们不知道两种间的具体换算步骤,那么我们就知道得知道两者间的大概关系,如果连这个都不知道,那么我们就没有办法利用机器来求解了。假设我们知道两种间的大概关系是,公里与英里之间存在一个线性换算的关系,这就意味着,如果我们把公里数翻一倍,那么对应的英里数也应该翻一倍。在我们确定两者存有线性关系的情况下,那么我们就可以推测出公里数与米数之间存在这种关系:英里 = 公里 * C, 其中C是一个常量,只不过我们不知道这个常量是多少。
现在我们手上有的条件是,我们有一系列数据,这些数据是公里数与对应英里数的配对,格式如:(公里数,米数),例如:
这里写图片描述
上图表明,当公里数是0时,米数也是0,当公里数是100时,英里数是62.137,如此我们如何确定尝试C呢?办法是先随便猜测一个数,然后再拿上面的数据来检测我们猜测的对不对,例如我们一开始猜测C=0.5,当然我们也可以猜测0.3,0.1,0.25等等, 那么让机器根据C=0.5这个规则进行处理,当输入是100时,机器给出的结果是50:
这里写图片描述
但是结果给表中给定的数值比对发现对照不上,按照表中给的结果应该是62.127,因此我们我们计算的结果跟给定的正确结果有误差,误差 = 正确结果 - 我们计算的结果 = 12.137。
这里写图片描述
有了错误怎么办?有错就改啊!问题是怎么改,下一步的改正就不能再胡乱猜,而是要根据上一步所产生的误差来进行。根据公式 英里数 = 公理数 * C, 我们可以知道,只要增加C的值,英里数就能增加,于是误差就能相应的减少。于是我们把0.5增加到0.6,然后根据公式在计算一遍,更改后我们得到新的英里数 = 公里数 * 0.6 = 60,这次运算之后,误差 = 62.137 - 60 = 2.137。这个结果相比于上一个结果,我们有了显著的进步。
这里写图片描述
我们再接再厉,既然增大C值能够让误差减少,那么我们有理由继续增大C值,于是我们把C从0.6增加到0.7。增大后一算得到的结果是 英里数 = 公里数 * 0.7 = 100 * 0.7 = 70, 此时我们发现误差变成了 62.1 - 70 = -7.863, 这意味着C的增大增过头了!
这里写图片描述
既然0.6不够,0.7又太多,那意味着正确的值肯定在0.6和0.7之间。现在我们只知道正确值所处的大概范围,但它具体是多少,我们任然无从得知,于是我们还是拿出老办法:猜!, 我们用0.61试试,当然用0.62,0.67都无所谓,只要值在0.6到0.7之间。当我们使用0.61时,得到的结果为 英里数= 公里数 * 0.61 = 100 * 0.61 = 61,误差为62.137 - 61 = 1.37, 也就是说用0.61计算的效果比用0.6要好。
这里写图片描述
上面的流程反复进行,只要我们能把误差不断减小,如果做到误差为0那么我们就找到了正确的C值,但实际上我们无需如此精确,我们只要做到误差在可以接受的范围内就可以了。
上面这些过程就是机器学习的本质,先由人确定输入与输出之间的高层次相关关系,然后由机器不断运算来确定具体参数。机器先对具体参数做猜测,然后把数据输入进行运算,得到的结果跟正确结果比对,确定误差后,在误差的基础上对参数进行调节,目的是进一步缩小误差,当误差落入可接受的范围后,整个流程可以停止,我们就可以拿机器算出的参数来进行实际应用。
上面的例子过于简单,我们再看看一个更复杂的例子。下面的图示表示的是昆虫的宽和长。
这里写图片描述
横坐标记录昆虫的体宽,纵坐标记录昆虫的体长。红色点表示的是毛毛虫,绿色的点表示瓢虫。从坐标统计上看,毛毛虫又细又长,瓢虫又短又胖。通过观察,我们确定这两组数据可以用一条直线把他们区分开。
这里写图片描述
假设我们真能找到一根将两组数据分开的直线,那么当我们收到新数据点时,我们把数据放到坐标轴上一看,如果数据表示的点在直线的左边,那么我们就可以预测新数据点对应的是毛毛虫,如果新数据点位于直线的右边,我们就有理由预测新数据点对应的是瓢虫。
这里写图片描述
为了得到这条直线,我们需要一系列数据进行校正。下表就是一组数据样本:
这里写图片描述
这组数据样本给出了虫子的长和宽,并给出对应的虫子种类。用于输入到电脑中,用于校正参数的数据我们称之为训练数据。我们看看如何依靠这两组数据去训练机器,使得它能找到区分虫子数据的那条直线,我们先把上表中的两组数据绘制到坐标轴上:
这里写图片描述
我们知道用直线可以把数据区分开,但我们不知道这条直线是怎样的,因此我们需要像前面例子那样,先随机画一条直线,然后看看直线区分数据的效果怎样,根据效果来调整直线的形态。在二维坐标轴上,我们可以用一个方程来表示一条直线: y = A * x, x 对应的就是坐标轴上的宽,y对应坐标轴上的长。这条直线会通过坐标轴的圆点,同时参数A就是直线的斜度,也就是直线与x坐标轴的夹角。显然这个A就是我们需要寻找的参数。
由于我们并不知道A的具体值,因此我们一开始就随便猜一个,就假设A是0.25吧,于是直线的方程为 y = 0.25 * x。根据方程把直线绘制到坐标轴上情况如下:
这里写图片描述
我们不难看出,这条直线对数据的区分效果不是很好。所有的数据点都跑到了这条直线的上方,按照前面的例子,我们需要通过给定数据计算当前直线所产生的误差。我们把训练数据的第一行代入方程得到 y = 0.25 * 3.0 = 0.75。显然方程与数据产生了偏差,我们在调整直线前需要确认的一点是,我们希望这条直线能把绿色点和红色点区分开来,因此我们期望这条直线能位于这两点之间,因此我们希望直线的方程能满足,当x等于3.0时,产出的y值要比1大,如果正好等于1,那么这条直线刚好连接圆点和绿色点,这样的直线仍然不能帮我们区分这两个数据点。如果我们能调整A的参数,使得x=3.0时,y等于1.1,1.2或1.3那么这条直线就可以落入两点之间。同时我们也必须确保y的值不能过大,如果过大的话,两个数据点就会同时位于直线的下方,这样也不行。
倘若我们把理想目标是y = 1.1 (1.2,1.3也可以,只要使得直线在两个数据点之间),这时候我们就可以计算误差 = 1.1 - 0.75 = 0.35,以后我们用字母E来表示误差。
这里写图片描述
我们如何根据当前参数去调整参数A呢?如果我们把参数A的值增加$\Delta$A, 那么改变后的直线方程为 t = (A + $\Delta$A) * x , 它和改变前的直线相互关系如下:
这里写图片描述
如果我们跟上图比较,我们就可以推导出 E = t - y = (A + $\Delta$A) * x - A*x,进一步运算我们有 E = $\Delta$A * x, 我们跳出数学,回过头来再看看我们想要什么,我们想要的是,到底如何根据误差来调整参数A的值,我们的直线才能恰好处于两个数据点之间!根据上面的推导,我们知道,我们只要用误差除以x,所得的结果就是参数A要调整的幅度。根据这个结论,我们调整试试看。
根据原来函数,当x = 3.0 时,y = 0.75, 误差是 E=0.35。用误差除以x得到的调整幅度$\Delta$A = 0.35 / 3.0 = 0.1167。于是我们把当前参数A的值再加上0.1167,也就是0.25 + 0.1167 = 0.3668。于是我们得到参数A的值为0.3668.
我们把第二组数据代入新方程看看, y = 0.3667 * 1.0 = 0.3667,第二组数据给定的y值结果是3.0,我们算出来的值与3.0相差甚远。也就是说,我们当前的直线太偏向与第一组数据,太偏离第二组数据,这样的话就”不公正“,于是第二次调整,我们希望直线能更偏向第二组数据,如果我们往方程中输入1.0时得到的结果是2.9的话,(2.8,2.7都可以,只要是偏向与第二个数据点,并且直线能在两个数据点之间就可以),那么这条直线就足够偏向第二个数据点了,于是我们就以y=2.9为目标做第二次调整。
我们算的第二次调整的误差为 E = 2.9 - 0.3667 = 2.5333, 根据前面的推导,我们对参数A调整的幅度为 $\Delta$A = E / x = 2.5333 / 1.0 = 2.5333, 于是新调整后的参数A = 2.5333 + 0.36667 = 2.9,为了更好理解,我们把直线的三次情况画出来看看:
这里写图片描述
从上图我们看到,最后一次调整,直线居然变得太偏向第二个数据点,它对两个数据点的划分不够”公平“,导致这个问题的根本原因在于,我们每次调整的时候,都是以某个数据点为目标,于是调整后,结果就必然过分靠近与目标,因此每次调整,我们都没有把以前调整所得到的知识加入到当前调整中来,处理这个问题的方法是,每次调整时,我们要控制调整的幅度,假设本次要调整的幅度是$\Delta$A,那么我们调整是,只采用这个幅度的一部分就可以了,这样的话,我们能让直线往目标点的方向偏移,但又不至于一下子偏移那么多,因此我们就把调整的幅度乘以一个小数L,显然L要小于1,这样才能减少幅度,于是每次每次调整的幅度变为: $\Delta$A = L * (E \ x), 这个参数L在机器学习里有一个专门的名称叫”学习率“。
如果我们把L设定为0.5, 那么参数A的初始值为0.25,于是第一次调整的幅度就是 $\Delta$A = 0.5 * (0.35 / 3.0) = 0.0583, 第一次更新后A的值就是0.25 + 0.0583 = 0.3083。接着我们把第二组数据代入新的方式,也就是x = 1.0, A = 0.3083, 得到的y值是1.0 * 0.3083 = 0.3083,这个值与目标值2.9的误差E = (3.9 - 0.3083) = 2.5917。于是第二次参数A调整的幅度为 $\Delta$A = 0.5 * (2.5917 / 1.0) = 1.2958。于是参数A第二次更新为: 0.3083 + 1.2958 = 1.6042.我们把这次更新后的直线绘制出来看看:
这里写图片描述
我们看到,这次调整后,直线似乎不偏不倚的处于两个数据点中间。
以上两个例子其实道尽了机器学习的本质,以后我们会遇到更困难的例子,但是机器学习过程的本质不变,所有步骤和逻辑跟我们这里讲的两个例子其实是一样的,只不过是计算的过程要复杂很多,而且很多数据其实是不能直接用直线来分割的,必须用具备某种性质的曲线来分割,但说一千道一万,无论表层如何复杂,要想理解机器学习的本质逻辑,只要搞懂这两个例子就可以了。
作者:望月从良
链接:https://www.jianshu.com/p/779fb04fe9f9