在机器学习中,当准备好数据集并设计好模型后,下一步工作就是训练。训练过程就是把模型中的参数调至最优。训练过程的核心就是数值优化算法。常用的方法为梯度下降与牛顿法,拟牛顿法是在牛顿法上面的改进。

梯度下降

梯度下降算法只需要一阶导数信息就能找到目标函数的极值点。它基于以下认识:

  1. 方向导数取得最大值的方向为梯度。(沿着这个方向下降速度最快)
  2. 沿着梯度的反方向迭代取得极小值;沿着正向迭代取得极大值。

其迭代过程如同下山一样
将f(x)一阶泰勒展开:
$$ f(x)=f(x_0)+(x−x_0)f’(x0)$$
令$Δx=x-x_0=−δf′(x)$
则:
$$ f(x)-f(x_0)=−δf’^2(x_0)$$
因此每次迭代的结果使得f(x)逐渐变小,直至取得极小值。它的优点是简单有效,缺点是在远离极小值的地方下降很快,而在靠近极小值的地方下降很慢。

几种变形的比较:
| 算法 | 概述 | 优点 | 缺点|
|–|–|-|-|
| SGD | 在深度学习中指的是小批量梯度下降,是按照数据分布将总体数据划分为多个小批量数据,然后利用小批量数据对参数进行更新。 | 每一步更新的计算时间不依赖于训练样本数目的多寡,即使训练样本数目非常大时,他们也能收敛。对于足够大的数据集,SGD可能会在处理整个训练集之前就收敛到最终测试机误差的某个容错范围内。 | 选择合适的learning rate比较困难,若设置过大,学习曲线将会剧烈震荡,代价函数值通常会明显增加;太小则学习过程会很缓慢,如果初始学习率太低,那么学习可能会卡在一个相当高的代价值。|
| Momentum动量 | 动量方法旨在加速学习,特别是处理高曲率、小但一致的梯度,或是带噪声的梯度。动量算法积累了之前梯度指数级衰减的移动平均,并且继续沿该方向移动。它模拟的是物体运动时的惯性,即在更新时在一定程度上会考虑之前更新的方向,同时利用当前batch的梯度微调最终的结果,这样可以在一定程度上增加稳定性,从而更快的学习。 | 对方向一致的参数能够加速学习,对梯度改变方向的参数能够减少其更新,因此就是momentum能够在相关方向上加速学习,抑制振荡,从而加速收敛。 | 比较难学习一个较好的学习率。|
| Nesterov动量 | 是momentum动量的一个变种。Nesterov的改进就是让之前的动量直接影响当前的动量,因此Nesterov动量往往可以解释为往标准动量方法中添加了一个校正因子,加快收敛。 | - | -|
| Adagrad | 在更新参数的时候,缩放每个参数反比于其所有梯度历史平均值总和的平方根。
特点:1.这样在训练初期,分母较小,学习率较大,学习比较快,2.后期时,学习会逐渐减慢,3.而且它适合于处理稀疏梯度,具有损失最大偏导的参数相应地有一个快速下降的学习率,而具有小偏导的参数在学习率上有相对较小的下降。 | 适合于处理稀疏梯度 | 1.从训练开始就积累梯度方差会导致有效学习率过早和过量的减小。2.只能解决凸问题,当应用于非凸函数训练神经网络时,学习可能会到达一个局部是凸碗的区域。3.需要一个全局的学习率。|
| RMSProp | RMSProp修改Adagrad以在非凸设定下效果更好(这也是为什么神经网络中多用RMSprop的原因,神经网络的损失函数大多都是非凸的),改变梯度累积为指数加权的移动平均。相比于Adagrad,RMSProp使用指数衰减平均以丢弃遥远过去的历史。
很常用的一个优化算法。 | 1.改进了Adagrad在深度学习中过早结束的问题;2.适用于处理非平稳。 | 依然依赖一个全局学习率。|
| Adam | 结合了动量和RMSProp,利用了梯度的一阶矩估计和二阶矩估计动态调节每个参数的学习率,并且加上了偏置修正。 | - | -|

参考

梯度下降,牛顿法与拟牛顿法
各优化算法的优缺点整理
深度学习的前戏–梯度下降、反向传播、激活函数

目前已经跑路大半年了,回想起来在原来的公司也待了近10个月时间。虽然总觉得在那里呆的不舒畅,没有合适的空间,甚至有些不愿提及。但是毕竟待了那么久,即使有什么不满与失意也不应该否定自己曾经的努力。做错了一些事情就更应该直视错误,努力去改正,并从中吸取经验和教训。牢骚就不说了,还是写一些技术上的收获吧!

项目概述

公司需要开发一套送餐机器人管理程序。虽然他们本来就有送餐机器人在卖,但是自己却没有代码,没法开发。(好迷)开发就开发吧,也没什么大不了的。公司方面给我需求是:

  1. 能够沿着磁轨移动。 主要采用磁导航作为定位手段。
  2. 通过RFID判断桌号。 每个桌子都有唯一的RFID,读取到对应的RFID就停下提示并等待用户取餐。
  3. 识别触摸开关信号。 在机器人的手臂边上安有一个触摸开关,当用手触碰时会产生一个高电平信号。该信号作为用户取餐完毕的信号。即用户触碰后,机器人返回厨房。
  4. 控制界面。 在机器人背后安装一个触碰显示器,显示桌号。服务员点击桌号则机器人开始送餐,并到达预定桌位完成送餐。
  5. 编辑界面。 如果餐厅布局发送改变,那么要提供一个可以修改的界面。
  6. 壁障、减速。 在行驶过程中应该能够避开可能的障碍物,一般轨道上会有客人。障碍物的识别是靠底部的3个和餐盘下方的2个红外传感器实现。机器人应该能够提示并及时停止,同时要做到动作缓慢,减少机器人的抖动。

技术要点

从大的方向来说主要的技术有:位于上位机的导航算法、位于下位机的运动控制

导航算法

由于定位手段只有RFID和磁导航,因此不能精确的知道当前位置。只能通过一定的推理得出当前AGV处于某两个点之间。由于系统设计的原因,在运动过程中有诸多限制:

  1. 转弯角度<60。
  2. 转弯半径>20cm。
  3. 同一时刻只能识别一个岔道。

首先,将地图抽象为有向图,每一个结点对应一个RFID。由1)得一些路径是单向的,即不能做到原路返回。3)得在每一个岔道,只需要判断向左或者向右。

算法实现

首先该算法对轨道有一定限制。

  1. 每个岔道前必须至少有一个RFID来标识。
  2. 所有轨道都必须是一致的
    实验环境
    在工作的地方,轨道设计如图一所示。0 表示起始点,一般指餐厅厨房。三角符号表示RFID,圆代表桌位。

生成图
将实际环境中的轨道信息转换成图,存储在计算机中。其结构如图二所示。

非一致的图
所谓一致,就是当AGV沿着任意轨道顺时针运动时都不会产生冲突。如图三中,假如在左侧有一个AGV顺时针运动,右侧也有一个AGV顺时针运动。那么者两台AGV必将发送冲突(头对头)。其原因在于图中红色的部分使得轨道的方向反转。
纠正
只要按图四中黄色部分修改就可以使得图一致

然后就可以使用Dijkstra寻找目的地的最短路径。这里还需要一个额外的变量direction来表示当前AGV在轨道的方向。一开始AGV是顺时针的,那么0-1也是顺时针的,因此直行就能到达。而0-5是逆时针的,需要掉头才能到达。只要轨道顺序与当前AGV不一致就需要掉头。
PS:当时我花了大半个月设计、并写好这部分代码,感觉足以应对任何地图情况,并且使用寻路算法大大减少了工作量。心里有点小得意,比他们原来的系统不知道高到哪里去了。后来我又给路径之间增加速度调节功能,让AGV在直线的时候加速,弯道上降速,实现智能变速。可是没想到,当我拿给生产部的同事,他们却觉得太麻烦了,一致觉得还是原来的好。最后我了解到,原来他们的想法是轨道就是一个圆环,只要判断到没到点就可以了。那是我明白了吃了不讨好是怎么一回事。回想到我刚来的时候,上司把这个任务交给我,还给了之前同事做的代码,说这个项目已经快做好了。可是我一看代码却发现就写了很基础的一点,基本上什么都没有。结合来看才明白怎么一回事,原来是什么都不需要,自然也就什么都不必有。

运动控制

项目开发中需要用到的技术有:

  1. 运动模型
  2. 定位算法
  3. 控制算法
  4. 控制平滑

运动模型

该AGV由位于底盘中部的两个轮子驱动。属于双轮差速模型。
在实际使用中,我发现使用曲率k和速度v来进行控制更加便捷。它与w,v是等价的k=w/v。在一个实际具体的轨道中,每一个位置的曲率总是固定的。因此一旦得到该位置的曲率,那么通过该点速度是无关的。也就是说在我们的控制算法应该计算出轨道的曲率k,然后AGV以曲率k运动,无论AGV的速度是多少,它始终贴合轨道。所以经过这样的调整,v可以作为参数,调整AGV运动的速度而不改变其稳定性。(实际上我即没办法得到轨道的k,也很难保证AGV的运动轨迹。但是实践效果还是挺好的,v在0.1到0.4的范围内都挺稳定)至于为什么不用r与v。首先r理解起来比较困难,k的话跟w差不多。当v不变时,完全可以把k当作w来看待。其次,当AGV笔直前进的时候,用r表示就难受了,到底取多大才够直?

定位算法 (Magnetic localization algorithm)

地磁场的影响比较大, 而且随着车体方向的改变, 地磁的大小也会改变。
消除地磁影响的方法主要有三种:
( 1)多次测量平均法; ( 2)波峰波谷法; ( 3)双传感器微分法
[参考] [1]
磁条磁场分布近似于磁偶极子:
B=\frac{\left(\mu _0 M\right) \left(3 i x z+3 j y z+k \left(-x^2-y^2+2 z^2\right)\right)}{4 \text{$\pi $r}^5}

r为半径,L0 是磁渗透性, M 是磁钉磁矩

然后通过磁场匹配算法序列算法来确定磁条相对于车体的位置。

三点定位:

我自己提出了一个简化版的磁场匹配算法,只需要取最强的3个点就能使用。实际试验,平均误差约为0.2cm。
设传感器距离磁条中心点的绝对距离为x,磁场分布函数为f(x)。磁传感器的间距为1cm。设当前小车与磁条中心的偏差为a。那么读取到的16个点中最强的3个点为f(a),f(a-1),f(a+1)。然后寻找匹配度最高的a就可用了。

控制算法

控制器尝试了下面2种

  1. 模糊控制器 这个实验中用的多,我在实际应用的时候遇到了一些问题。效果并不理想。
  2. PID控制器。最后只用了PD,由于这个计算简单,操作容易,并且效果良好,最后采用了PD控制器。
    控制输出曲率K。

    平滑控制

    当速度需要发送改变的时候,如检测到障碍物。速度不能立即降为0,否则AGV立马磕头。没错,是真的磕头。本身这个底盘在设计的时候就不对,驱动轮在中间靠前面一点,后面一个万向轮支撑。然后上面的外壳是玻璃钢制的,特别重而且高,重心这就提到上面去了,加上支撑轮靠后,一个急刹就前倾。我试验了两种平滑办法。
  3. 固定加速度。 即速度v在每个时间间隔最大只能改变dv。
  4. 指数逼近。 v=(v_goal-v)*e+v

最后贴上一段视频把

[1] 磁传感系统在室外移动机器人导航中的研究

复制了几篇老文章到hexo中死活生成不出来。怎么看教程都没发现有问题,然后复制别人的categories,并且能够正常编译。难度我打错字了?盯着字母看了半天也没发现不一样。突然发现一些文章里的categories是红褐色的一些是蓝色的,而出错的地方显示是蓝色的。最后移动光标点到冒号后面发现这个冒号2个个字符宽!原来冒号打错了。改完果然能够工作了。

yaml语法

由于这个语法看着挺简单的没专门去了解。结果又踩坑了。详细语法

数组

1
2
3
4
array:
- a1
- a2
array1: [a1, a2]

dictionary

1
2
3
4
5
dict: 
a: v1
b: v2

dict1: {a: v1, b: v2}

注释

1
# sadfk

一定要注意符号后面的空格。如果连在一起就会被认为是一个串。-a不是一个数组而是相当于"-a"