从入门到放弃, 只需要….
人工智能是计算机科学的一个分支,它企图了解智能的实质,并生产出一种新的能以人类智能相似的方式做出反应的智能机器 (来自百度百科)
当前<人工智能导论>, <人工智能>等书籍中关于人工智能的定义大抵类似.
从以人类相似方式作出反映为基准, 传统编程如果目的是为了模仿或者代替人类操作完成某些过程, 都可以算作智能. 如游戏ai, 物联网控制系统, 早期的tts, 大部分可以看作通过传统编程方法实现的.
人工智能的这种定义可谓十分模糊, 比如计算机视觉领域的sift算法, 单纯用它提取图像特征点, 那么通常认为它并不智能, 因为人不用做这种事. 而如果给他加个壳, 变成在任意图像中查找特定物品(比如立方体), 通常就认为它智能了. 而在实际使用习惯中”人工智能”的含义经常被狭义化, 我们通常会认为, “人工智能”就是一个像人一样的机器或者程序, 它可能需要具备类人的各个方面特点.
机器学习是人工智能的一个子集, 它做的事情可以描述为, 把原先需要完整编写的程序过程部分通过非直接编写, 而是从该过程已有的采样数据中学习的方式完成.
目前主流的机器学习案例, 大多是通过预建模, 预训练后形成固定的模型用于生产, 这些模型本质上还是程序.
相对传统编程可以完全由人编写的程序而言, 机器学习可以看作是机器在人的辅助下编写的程序. 而机器学习的一个经典目标就在这一过程中让机器做的事尽可能多, 人做的事尽可能少.
从人工到智能
手动(人工)
现在设置一个简单的跨栏小游戏, 左侧的方块代表主角小x, 右侧的方块代表栅栏, 两者以一定的速度接近, 可以控制的量只有使小x在地面上起跳(按A键). 游戏的目标就是控制小x在恰当的时机跳起, 避免其碰上栅栏.栅栏通过加1分,撞到栅栏减1分.
这个小游戏的输入是跳或不跳, 条件是栅栏与小x间的距离, 输出是游戏得分, 是最简单的单一输出,单一输入,单一条件环境.
手动模式
下, 我需要观察栅栏的运动,然后通过适当的时候按键来完成游戏.
传统编程方法实现的弱人工智能
阈值逻辑
现在, 想让机器帮我完成这个动作, 首先需要找到输入的接口(控制起跳的函数), 其次我可以简单观察到当栅栏接近到某一个距离的适合跳起来基本上可以达到跨过的目的. 于是我设置了一个阈值x,当距离小于x时就向游戏环境输入”跳”的指令,反之不跳.
由于每个栅栏的速度是在某范围内随机的, 这个阈值可以处理大部分情况, 但还是会与部分栅栏发生碰撞
(只有固定速度的情况下阈值逻辑可以很好地解决问题)
最优解
使用阈值逻辑自动控制这一过程显然有很大缺陷. 于是我基于对这个游戏环境中的运动模型认知, 根据加速度,速度与距离的关系, 可以求解得到针对每个栅栏的最优起跳点.
为了达到上述目的, 需要对模拟环境的输出进行扩展, 单一的距离条件显然无法判断出速度, 好在模拟环境还有一个隐含的条件—时间轴.
于是条件就变为了, 当前距离, 上一次的距离, 时间间隔三个.
此外, 这个最优解模型还需要一些先验知识:
- 小x每次跳起的初速度已知(这里是4m/s)
- 环境重力加速度已知(这里是10m/s)
- 向上和向右为正方向
- 栅栏的运动是匀速的
- 游戏环境不受其他因素干扰
如此一来, 小x每次跳起到落地的时间是固定的. 栅栏匀速运动其运动距离与时间成正比.为了使小x完整地跳过栅栏, 可以让小x跳跃至最高点时(滞空时间的一半)栅栏刚好处于其正下方
于是可以设计模型如下:
1 | 小x滞空时间 = 小x起跳初速度 / 重力加速度 |
机器学习方法实现的弱人工智能
上述两种传统编程方案实际上包含了针对游戏环境的两种模型. 在使用机器学习方法解决问题时通常也需要一个基础的模型, 可以用上面的针对特定问题的模型, 也可以使用如神经网络等相对”万能”的模型.
上述最优解的方案设计过程中, 用到了模拟环境中栅栏匀速运动, 小x起跳的初速度,环境的重力加速度等先验知识. 其中具体参数起跳初速度和重力加速度是已知的, 这得益于自产自销.
然而现实中我想要给一个已经封装好的过程编写程序外挂来自动控制, 而这个过程不是我写的, 那么我不可能知道其中具体的参数, 只能观察到一些表象. 比如, 栅栏是水平匀速运动的, 小x跳起来后一段时间落地并且这一过程是固定的. 这样一来想要以人工的方式编写一个”最优解”来玩这个游戏, 就需要测量小x跳起到落地这段滞空时间, 通常可以使用秒表, 多次测量取平均值. 那么如果游戏中一些参数改变了(比如我增加了起跳的初速度), 就需要重新人工测量.
通过机器学习的方法可以针对同一类问题在后续少人工干预的情况下自适应参数的变化.
白盒
借用白盒的概念, 是为了表示在针对跳栅栏这一游戏建模的过程中, 在模型本身可认知, 可解释的情况下对参数进行学习, 例如上述最优化模型中潜在的运动规律不变, 但是起跳速度和重力加速度未知(即滞空时间未知), 可以通过直接机器学习的方法学习得到滞空时间这一参数.
蒙特卡罗法
所谓蒙特卡罗法(Monte Carlo), 指的是一类通过大量随机动作的反馈来推理模型参数的方法. 当然为了顺利设计实验需要预先对实验对象有充分的认知.
针对跳栅栏问题中需要求解的滞空时间这一参数, 求解的实验可以这样设置:
1 | 每一个栅栏与小x的碰撞剩余时间从某个值S到0的过程视作一个独立事件(S值可以取适中值比如4秒, 实际采样中因速度过快,从出现开始碰撞剩余时间就小于4秒的样本直接丢弃) |
随着上述实验次数的增加, 估计的滞空时间会逐渐接近实际值.
梯度下降法
梯度下降隐含了两重含义, 一是沿着参数对结果的梯度减小方向调整参数, 使得参数达到局部最优;二是调节参数过程中每次调整的量参照梯度数值大小适当调整, 达到快速收敛的目的.
梯度下降法还有一个明显的优势, 那就是无惧模型的复杂性, 只需要可以视为连续的模型, 都可以用这类方法反向传递误差求解.
针对跳栅栏问题中需要求解的滞空时间这一参数.
首先,为正向传播模型选定一个连续的误差评价指标.
1 | loss = (起跳时栅栏与小x的距离-落地时栅栏与小x的距离)^2/2 |
上述loss越小则小x跳跃到最高点时栅栏越接近正下方, 且仅受滞空时间这一参数的影响, 与每次栅栏的速度无关. 这一点很重要, 这种情况可以不用预先采样;如果loss还受到所求参数以外的因素影响, 就需要先充分采样, 确保一系列训练样本集中其他因素的影响基本可以忽略不记.
接下来,设置一个初始的滞空时间, 可以选择一个较小的值,以保证开始时起跳点和落点分别位于栅栏的两边.
1 | 滞空时间 = 1秒 |
根据正向传播过程:
1 | 栅栏速度 = (当前距离 - 上一个距离) / 时间间隔 |
可以粗略地得出loss反向传播过程:
1 | loss = (起跳时栅栏与小x的距离 + 落地时栅栏与小x的距离)^2/2 |
每一个栅栏运动中可以利用反向传播模型对滞空时间进行修正使其逼近实际值.
考虑到输入的不稳定实际操作过程中为了避免跑偏,通常还需要给每一次的修正量定义一个上限和一个下限.
遗传进化类算法
遗传进化类算法是一类模拟自然选择过程对模型中所求参数复制, 变异, 优胜劣汰不断迭代从而接近最优解的方法.
与梯度下降法类似, 首先需要设计一个连续的评价指标. 这里直接用上面的误差评价指标即可
1 | loss = (起跳时栅栏与小x的距离+落地时栅栏与小x的距离)^2/2 |
其次是预设的模型, 同样使用上面的正向传播模型:
1 | 栅栏速度 = (当前距离 - 上一个距离) / 时间间隔 |
模型只有一个需要求解的参数, 即滞空时间.
对每一代模型的迭代过程可以设计如下:
1 | 1.对本代中的每一个模型, 计算loss, 丢弃loss最高的2/3 |
其中, 复制过程即直接拷贝滞空时间参数到下一个模型;变异过程将滞空时间+randn(0,1)
作为下一个模型的滞空时间(randn为正态分布的随机数).
(–待补–)
黒盒(前馈神经网络)
区别与上面的白盒, 当我不但不了解参数, 也不了解匀速运动等基本信息, 甚至看不到图像, 面对只有输入和输出的情况. 可以反复实验获得大量样本,而后使用一些”万能模型”强行对表象进行学习. 但是学习完成的模型对原始过程通常是不可解释的.
此处仅介绍较为通用的前馈神经网络作为黒盒模型.
构建一个黒盒模型, 不需要考虑实际模型的具体细节, 只考虑输入和输出.
跳栅栏问题中输入是前后两次采样的距离, 输出一个适合起跳的距离, 也就是作为典型的回归问题来考虑.(之所以不考虑分类是因为可能面临类不平衡,会增加问题的复杂程度)
输入和输出都不复杂, 可以尝试用一个简单的单隐层神经网络作为模型, 输入层2个神经元, 隐藏层10个神经元, 输出层1个神经元.
(–待补–)
评价指标可以参考前面的loss.
1 | loss1 = (起跳时栅栏与小x的距离 + 落地时栅栏与小x的距离)^2/2 |
梯度下降法
梯度下降法中要求损失函数lossbp与所求参数间具备可传播的函数关系.
模拟环境不变的情况下, 前面的评价指标loss1中两个距离参数都由神经网络的输入输出唯一确定, 每个独立过程中都是可计算的确定值, 这个loss1值越小时越应该跳起. 它可以作为输出控制量的依据.
也就是说神经网络中实际使用的的损失函数为:
1 | lossbp = (输出的控制量 - loss1)^2 / 2 |
其他内容待补, 可参考任意搜索引擎的’梯度下降法’结果.
(–待补–)
遗传进化类算法
过程同上述白盒模型的遗传进化类算法设计.
模型部分使用了上面定义的单隐层神经网络, 可训练参数为神经网络每个神经元的权重和偏置, 评价指标沿用上面的loss
(–待补–)
无模型(QLearning)
QLearning是强化学习中最简单的一种, 无需建模.
QLearning的基本原理是构建一个从状态到动作的映射. 它的实现方式是构建一个表(Q-Table),用于存储(状态, 动作)对的权重(Q值).
可以看出, 简单的QLearning最好状态是离散化的, 状态可以选用前后两次的距离, 但这样一来状态空间会比较大(达到了n^2,其中n为离散化的距离总数)不利于演示. 为了节约成本, 将两个距离状态处理成剩余碰撞时间并整除0.1做离散化作为实际状态;动作方面用单一动作0代表不跳,1代表跳.
(–待补–)