SegmentFault 高德技术最新的文章
2023-11-16T10:52:29+08:00
https://segmentfault.com/feeds/blogs
https://creativecommons.org/licenses/by-nc-nd/4.0/
视觉BEV基本原理和方案解析
https://segmentfault.com/a/1190000044393308
2023-11-16T10:52:29+08:00
2023-11-16T10:52:29+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>BEV(Bird’s-Eye-View)是一种鸟瞰视图的传感器数据表示方法,它的相关技术在自动驾驶领域已经成了“标配”,纷纷在新能源汽车、芯片设计等行业相继量产落地。BEV同样在高德多个业务场景使用,例如:<strong>高精地图地面要素识别</strong>、<strong>车道线拓扑构建</strong>、<strong>车端融合定位</strong>中都扮演了重要角色。如图1‑1所示:</p><p><img src="/img/remote/1460000044393310" alt="" title=""></p><p>图1‑1 BEV在高德应用场景(仅列举部分)a)高精底图 b)地面要素识别 c)车道线拓扑构建[1] d)车端融合定位(BEV特征和底图匹配)[2]</p><p>本文分享的内容主要包括两个部分:视觉BEV基本原理、方案解析。</p><p><strong>1.BEV基础</strong></p><p><strong>1.1.引言</strong></p><p>如图1‑2所示,BEV具有如下优势:</p><p><strong>1) BEV视图尺度变化小</strong>。在PV空间(即透视图,类似通常行车记录仪所采集的车辆前视图)中,物体近大远小,物体的大小和类别、远近都有关,而在BEV空间中,物体的大小只和类别有关;</p><p><strong>2) BEV空间是决策友好空间</strong>。BEV空间更接近3D真实空间的平面空间,而PV空间是真实物理世界在透视投影下的视图,以图1‑2的车道线举例,在真实世界中平行的两条车道线,在BEV空间下还是平行的,在PV空间却是相交的。相比之下,BEV空间下的信息能更方便地被下游规控模块理解和使用。</p><p>本章将介绍BEV基础知识。首先介绍BEV的核心<strong>“视角转换模块”的基本原理</strong>,包括2D->3D和3D->2D两种路线,然后介绍BEV使用的<strong>魔法“可形变模块”</strong>,最后介绍<strong>BEV方案中常用的损失函数</strong>。</p><p><img src="/img/remote/1460000044393311" alt="" title=""></p><p>图1‑2 BEV空间和PV空间的图像可视化,a) BEV空间 b) PV空间</p><p><strong>1.2.视角转换</strong></p><p>如1.1所述,在BEV空间下进行数据处理和操作具有尺度变化小、决策友好的优势,但原始的图像数据是在PV空间下的,如何将PV空间的数据转换到BEV空间或者是3D空间(有3D空间下的数据,将其拍扁就能转到BEV空间)呢?这就是视角转换模块要干的事。</p><p><strong>1.2.1. 2D->3D转换模块</strong></p><p>2D->3D转换模块基本思想是从2D像素或者特征出发去找3D空间下的对应表示,类似深度估计。下面介绍主流的2D->3D转换方法。</p><p>LSS(Lift-Splat-and-Shot)[3]是主流的2D->3D转换方法,如图1‑3所示,Lift指对各相机的图像显式地估计特征点的深度分布,得到包含图像特征的视锥(点云);Splat——结合相机内外参把所有相机的视锥(点云)分配到BEV空间的网格中,对每个格子中的多个视锥点进行pooling计算,形成BEV特征图;Shoot——用task head处理BEV特征图,输出感知结果。最后将C维的特征和D维的深度分布做外积,得到每个深度下的特征,深度概率越大,对应特征响应就越强。</p><p><img src="/img/remote/1460000044393312" alt="" title=""></p><p>图1‑3 LSS示意,每个特征点生成系列离散深度点,再为深度点生成特征[3]</p><p>Pseudo-LiDAR是另一种2D->3D转换方法,如图1‑4所示,相比LSS为特征点预测一系列离散深度,Pseudo-LiDAR直接预测深度图,每个像素都有且仅有一个深度。</p><p><img src="/img/remote/1460000044393313" alt="" title=""></p><p>图1‑4 Pseudo-LiDAR示意,预测深度图,根据原始图像和深度图映射至3D空间[4]</p><p><strong>1.2.2. 3D->2D转换模块</strong></p><p>3D->2D转换模块基本思想是根据3D点查找对应的2D特征,类似3D空间投影到PV空间。下面介绍主流的3D->2D转换方法。</p><p>如图1‑5所示,将3D参考点根据成像原理投影到PV空间获取对应图像特征的方式可以认为是显式映射,这里的参考点可以使用预设的BEV空间的参考点,也可以使用网络生成。</p><p><img src="/img/remote/1460000044393314" alt="" title=""></p><p>图1‑5 显式映射[5]</p><p>相比显式映射,隐式映射不再通过投影映射,而是让网络自己学特征和3D坐标的映射。如图1‑6所示,它先生成视锥空间下的一系列点,再转换到3D空间下,然后将提取的图像特征和3D点传入encoder,encoder处理后输出的就是带有3D坐标信息的特征。</p><p><img src="/img/remote/1460000044393315" alt="" title=""></p><p>图1‑6 隐式映射[6]</p><p><strong>1.3. 可形变模块</strong></p><p>要介绍的可形变模块有两种,<strong>可形变卷积</strong>和<strong>可形变注意力</strong>,可形变模块的作用更容易通过可形变卷积理解,所以先介绍可形变卷积。</p><p>可形变卷积是在卷积的基础上添加offset得到的,如图1‑7最左边的a) 所示,普通卷积通过人工设计的pattern整合pattern内采样点的信息,其pattern设计好后就是固定的,可形变卷积,如图1‑7 b) 所示,可以计算出每个采样点的offset,采样点+offset才是真实的采样点,使得卷积的pattern形式更加灵活,且一定程度上可学习。</p><p><img src="/img/remote/1460000044393316" alt="" title=""></p><p>图1‑7 可形变卷积示意,a) 普通卷积 b) 可形变卷积[7]</p><p>如图1‑8所示,注意力机制需要通过Q (query) 找到K (key),获得K的信息,这个过程也存在可变形的操作空间,让网络自己学习参考点的偏移量。</p><p><img src="/img/remote/1460000044393317" alt="" title=""></p><p>图1‑8 可变形注意力示意[8]</p><p><strong>1.4. 损失函数</strong></p><p>损失函数大部分与任务相关,且大同小异,这里集中介绍下后续方案解析需要用到的一些共性的损失函数。</p><p>Box Loss (包围盒损失函数) 是目标检测常用的几何损失函数,常采用L1 Loss的形式:</p><p><img src="/img/remote/1460000044393318" alt="" title=""></p><p>Focal Loss是交叉熵损失函数的拓展,常用于分类问题。普通交叉熵损失函数在正负样本不均衡时表现不佳,因此引入平衡交叉熵。另外普通交叉熵损失函数对于难例无法重点学习,因此引入难例聚焦。最终形式为:</p><p><img src="/img/remote/1460000044393319" alt="" title=""></p><p><strong>2. 视觉BEV方案解析</strong></p><p><strong>2.1. 引言</strong></p><p>第一章的内容为第二章的方案解析打下知识基础,接下来第二章主要解析具有代表性的视觉BEV方案,主要根据视角转换模块的类型对方案进行分类,首先介绍2D->3D的代表性方案,然后介绍3D->2D的代表性方案。</p><p><strong>2.2. 2D->3D代表性方案解析</strong></p><p>2D->3D的代表性BEV方案有<strong>BEVDet</strong>和<strong>BEVDepth</strong>,下面我们逐一介绍。</p><p><strong>2.2.1. BEVDet</strong></p><p>3D目标检测跟踪由基于PV空间的方法主导,BEV语义分割跟踪由基于BEV空间的方法主导,那么PV空间和BEV空间哪个更适合做自动驾驶感知呢?是否可以在同一的框架下做这些任务?作者为了回答这两个问题,提出了如图2‑1所示的基于BEV空间的3D目标检测框架,BEVDet。BEVDet主要由四个部分组成,分别为图像特征编码器,视角转换模块,BEV特征编码器,检测头。</p><p><img src="/img/remote/1460000044393320" alt="" title=""></p><p>图2‑1 BEVDet框架[9]</p><p>图像特征编码器(Image-view Encoder)使用2D Backbone网络,如ResNet、SwinTransformer等,对输入的多视角图像做多尺度特征提取,得到多尺度特征。</p><p>视角转换模块(View Transformer)对输入的多视角图像特征使用LSS进行离散深度分布预测,获得3D视锥特征。</p><p>3D视锥特征经过pooling操作拍扁到BEV空间,BEV特征编码器(BEV Encoder)对BEV空间下的特征做多尺度特征提取,得到BEV特征。</p><p>最后送入检测头进行3D目标检测,分类监督使用的损失函数为Focal loss,包围盒监督使用的损失函数为L1 loss。</p><p><strong>2.2.2. BEVDepth</strong></p><p>作者实验发现LSS估计的深度替换成随机值影响不大,而采用真值深度对指标提升很大,因此得出LSS估计深度不准的结论,如图2‑2所示,在没有明确的深度监督的情况下,很难输出准确,泛化性强的深度感知结果,要想获得更好的检测结果,需要更准的深度,因此引入深度监督训练深度子网络。</p><p><img src="/img/remote/1460000044393321" alt="" title=""></p><p>图2‑2 LSS的深度预测结果和BEVDepth的深度预测结果的对比[10]</p><p>图2‑3是BEVDepth的框架,也能大致分为图像特征编码器,视角转换模块,BEV特征编码器,检测头四个部分。图像特征编码模块大同小异,后续不再展开说明。</p><p><img src="/img/remote/1460000044393322" alt="" title=""></p><p>图2‑3 BEVDepth框架[10]</p><p>视角转换模块的核心是深度估计,深度估计网络DepthNet的框架如图2‑4所示,首先使用MLP对相机内参进行特征化,然后用SE (Squeeze-and-Extraction) 对图像特征进行通道加权,然后经过3个残差块以及可形变卷积,得到深度。深度再与图像特征进行外积,得到3D视锥特征。</p><p><img src="/img/remote/1460000044393323" alt="" title=""></p><p>图2‑4 深度估计网络框架[10]</p><p>相机和用于监督的点云之间的外参可能不准,内参也可能不准,都会导致深度估计有偏,因此BEV特征编码器引入深度修正对3D视锥特征的深度进行修正,然后进行高效体素池化获得BEV特征。</p><p>检测头所使用的损失函数和BEVDet是一致的,不做赘述。深度监督使用的损失函数为二分类交叉熵。</p><p><strong>2.3. 3D->2D代表性方案解析</strong></p><p>前面介绍的2D->3D的方案始终绕不过深度估计,深度估计难免会引入误差,换个思路,先有3D点,再根据3D点找2D特征的方式无需进行深度估计,避免了这部分误差。3D->2D的代表性方案有Detr3D、BEVFormer和PETR。</p><p><strong>2.3.1. Detr3D</strong></p><p>如图2‑5所示,Detr3D是Detr在3D目标检测的扩展,也是使用query进行特征获取,然后进行检测。Detr3D的图像特征编码器大同小异,不再赘述。</p><p><img src="/img/remote/1460000044393325" alt="" title=""></p><p>图2‑5 Detr3D框架[5]</p><p>特征转换模块首先使用object query生成3D参考点,将参考点投影到PV空间获取图像特征,获取到的图像特征能进一步优化物体的3D表征,得到物体的3D特征。</p><p>将特征送入检测头进行目标检测,可以得到一系列的检测结果。普遍地,大家会用NMS等后处理方式获得最终用于Loss计算的检测结果,如图2‑6所示,Detr3D继承了Detr的做法,采用双边图匹配获得与真值一一对应的检测结果。损失函数与前面所述并未本质差异,不做赘述了。</p><p><img src="/img/remote/1460000044393326" alt="" title=""></p><p>图2‑6 双边图匹配获得与真值一一对应的检测结果[11]</p><p><strong>2.3.2. BEVFormer</strong></p><p>行车过程有天然的时序特点,当前帧看到的车道线,在后续几帧大概率也是存在且可见的,如何利用这个时序特点是前述方案没有考虑的。BEVFormer引入时序信息进一步增强BEV的检测能力。BEVFormer的图像特征编码模块和前述大同小异,不做赘述。</p><p>BEVFormer的核心是中间的BEV特征编码模块,BEV特征编码模块的核心是时序自注意力(Temporal Self-Attention)和空间交叉注意力(Spatial Cross-Attention),时序注意力是为了利用历史帧BEV特征增强当前帧BEV特征,空间交叉注意力则是为了从图像特征获取信息。</p><p><img src="/img/remote/1460000044393327" alt="" title=""></p><p>图2‑7 BEVFormer框架[12]</p><p>具体地,BEVFormer的时序自注意力首先利用车辆运动信息将当前帧BEV特征和历史帧BEV特征进行对齐,然后再使用自注意力融合两者信息,由于车辆运动信息可能不准,不同时刻周围的可利用信息分布也不一致,所以具体使用的是图2‑8所示的可变形注意力机制。</p><p><img src="/img/remote/1460000044393328" alt="" title=""></p><p>图2‑8 时序可变形自注意力[12]</p><p>BEVFormer的空间交叉注意力首先为每个格子在Z方向上采样4个值,得到一个格子上的4个参考点,然后与图像特征进行交叉注意力,获得图像特征。如图2‑9所示,这里的交叉注意力也采用可变形注意力机制。</p><p><img src="/img/remote/1460000044393329" alt="" title=""></p><p>图2‑9 空间可变形交叉注意力[12]</p><p>损失函数的计算和Detr3D一致,不再赘述。</p><p><strong>2.3.3. PETR</strong></p><p>3D->2D的方案一般都需要将参考点投影到PV空间,再取图像特征,PETR避免了复杂的3D->2D转换及特征采样,直接让网络自己学习2D-3D的映射。PETR的框架如图2‑10所示,包括图像特征编码器、3D坐标生成器、3D特征编码器(3D Position Encoder)、3D特征解码器和检测头。图像特征编码器大同小异,不再赘述。</p><p><img src="/img/remote/1460000044393330" alt="" title=""></p><p>图2‑10 PETR框架[6]</p><p>3D坐标生成器生成视锥空间的一系列3D点,具体地,首先将相机视锥空间离散成大小为的网格,网格中的每一点用表示。3D空间中一个点用表示。通过相机内外参可以将相机视锥空间转换到3D空间中。最后再进行归一化。</p><p>2D图像特征和3D坐标一起送入到3D特征编码器中,2D特征进行卷积通道降维,3D坐标进行位置编码,然后将处理后的2D特征和3D坐标编码整合,最后特征展平。</p><p><img src="/img/remote/1460000044393331" alt="" title=""></p><p>图2‑11 3D特征编码器[6]</p><p>3D特征解码器先在3D空间生成一系列随机点,再通过MLP生成可学习的query,query在3D特征中取特征,最后使用检测头进行检测。损失函数与Detr3D大同小异,不再赘述。</p><p><strong>3. 总结展望</strong></p><p>本文从BEV的基础出发,介绍了视觉BEV具有代表性的方案。视觉BEV已经展现出强大的场景理解能力。但是还存在很多值得探索且有挑战的方向[13]:</p><p>深度估计是BEV的核心,LSS、Pseudo-LiDAR、激光蒸馏、立体视觉或运动恢复结构等都是有前景的方向。</p><p>如何融合传感器的信息也是至关重要的,使用Transformer的自注意力、交叉注意力融合不同模态的特征已经被证明是个可行的方向。多模态中CLIP的文本-图像对也是个很有启发的思路。</p><p>泛化性是深度学习亘古不变的话题和努力的方向,在一个设备(数据)上训练好的模型在另一个设备(数据)表现是否一样好。每个设备都要付出训练成本是让人难以接受的。如何将模型和设备解耦在未来一段时间都将是重要的研究方向。</p><p>大模型或者基础模型已经在不同领域上取得令人印象深刻的结果,并一举成为SOTA。在BEV感知中如何利用大模型中丰富的知识,在更多的任务上取得更好的效果,这将会逐步引起人们的重视。</p><p><strong>4. 参考文献</strong></p><p>[1] Bencheng Liao, Shaoyu Chen, Xinggang Wang, et al. Maptr: Structured modeling and learning for online vectorized hd map construction[J]. arXiv preprint arXiv:2208.14437,2022,</p><p>[2] Yuzhe He, Shuang Liang, Xiaofei Rui, et al. EgoVM: Achieving Precise Ego-Localization using Lightweight Vectorized Maps[J]. arXiv preprint arXiv:2307.08991,2023,</p><p>[3] Jonah Philion and Sanja Fidler. Lift, splat, shoot: Encoding images from arbitrary camera rigs by implicitly unprojecting to 3d[A]. Springer: 194-210</p><p>[4] Yan Wang, Wei-Lun Chao, Divyansh Garg, et al. Pseudo-lidar from visual depth estimation: Bridging the gap in 3d object detection for autonomous driving[A]. 8445-8453</p><p>[5] Yue Wang, Vitor Campagnolo Guizilini, Tianyuan Zhang, et al. Detr3d: 3d object detection from multi-view images via 3d-to-2d queries[A]. PMLR: 180-191</p><p>[6] Yingfei Liu, Tiancai Wang, Xiangyu Zhang, et al. Petr: Position embedding transformation for multi-view 3d object detection[A]. Springer: 531-548</p><p>[7] Jifeng Dai, Haozhi Qi, Yuwen Xiong, et al. Deformable convolutional networks[A]. 764-773</p><p>[8] Xizhou Zhu, Weijie Su, Lewei Lu, et al. Deformable detr: Deformable transformers for end-to-end object detection[J]. arXiv preprint arXiv:2010.04159,2020,</p><p>[9] Junjie Huang, Guan Huang, Zheng Zhu, et al. Bevdet: High-performance multi-camera 3d object detection in bird-eye-view[J]. arXiv preprint arXiv:2112.11790,2021,</p><p>[10] Yinhao Li, Zheng Ge, Guanyi Yu, et al. BEVDepth: Acquisition of Reliable Depth for Multi-View 3D Object Detection[J]. Proceedings of the AAAI Conference on Artificial Intelligence,2023,37(2): 1477-1485</p><p>[11] Nicolas Carion, Francisco Massa, Gabriel Synnaeve, et al. End-to-end object detection with transformers[A].Springer: 213-229</p><p>[12] Zhiqi Li, Wenhai Wang, Hongyang Li, et al. Bevformer: Learning bird’s-eye-view representation from multi-camera images via spatiotemporal transformers[A].Springer: 1-18</p><p>[13] Hongyang Li, Chonghao Sima, Jifeng Dai, et al. Delving into the Devils of Bird's-eye-view Perception: A Review, Evaluation and Recipe[J]. arXiv preprint arXiv:2209.05324,2022,</p>
重新认识架构—不只是软件设计
https://segmentfault.com/a/1190000044222604
2023-09-15T17:03:55+08:00
2023-09-15T17:03:55+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>前言</strong></p><p><strong>什么是架构?</strong></p><p>通常情况下,人们对架构的认知仅限于在软件工程中的定义:架构主要指软件系统的结构设计,比如常见的SOLID准则、DDD架构。一个良好的软件架构可以帮助团队更有效地进行软件开发,降低维护成本,提高系统的可扩展性和可维护性。这里的架构定义有更多元化的理解:架构不仅是对软件开发设计和流程规范的定义,也包含了参与架构设计的人员、以及项目过程中和架构有关的活动,都可以称为架构。</p><p>从<strong>广义</strong>角度来理解架构,意味着更全面的思考和新的融合。</p><p><img src="/img/remote/1460000044222606" alt="" title=""></p><p>按这张图理解,架构是指<strong>架构师</strong>以商业价值为导向、以用户为核心,在所处的商业、文化、技术环境中,利用有限的资源和成本,设计架构<strong>方案</strong>、组织或参与研发活动,从而达到既定目标的一项复杂且持续的<strong>活动</strong>。</p><p>架构师面对实际问题,在复杂的环境中如何做出正确的选择,如何确保架构活动顺利进行,保障项目落地,可以从目标、资源、行为、趋势这四个层面来梳理。</p><p><strong>架构</strong></p><p><strong>目标</strong></p><p>明确目标:在开始新事物时,可能需要面对各种各样的选择和挑战。在这种情况下,明确具体的目标并非易事。</p><ul><li><strong>可实现</strong>:目标需要具有可实现性,过高或过低的目标都可能导致挫败感和疲惫。要在充分评估自己能力、资源和环境的基础上,设定合理的目标。</li><li><strong>具体、明确</strong>:目标应该具体、明确,易于衡量,以便对自己的进展进行有效跟踪和调整。将目标细化为若干小目标,有助于更好地管理和实现目标。</li><li><strong>有弹性</strong>:目标制定过程需要有一定弹性,能够应对不确定性和变化。当遇到挫折或不可预测的因素时,可以适时调整目标,以保持积极的心态和动力。</li><li><strong>持续关注和调整</strong>:目标制定并非一劳永逸,需要根据实际情况进行持续关注和调整。通过定期评估进展、学习经验教训,可以保持目标与现实的一致性,并提高实现目标的可能性。</li></ul><p>上面4条是指导原则,实际情况更为复杂,比如技术人员通常以技术驱动去探索目标,但是它不一定适合商业活动。拿MQ的对比Kafka和Pulsar,后者相较更新、更快,技术极客们通常会毫不犹豫的选择探索后者并将它应用到实际工作中。从普适性很强的成熟方案切换到新颖高性能的方案,除了考虑切换的成本外,还要考虑切换后带来的收益,以及团队成员掌握Pulsar的成本。从发展的角度上看,除非Kafka有致命的缺陷且不被修复,那么随着时间推移Kafka可以一直演进迭代也会变得更出色。所以单纯从短期的技术先进性上看并不可取,也要关注技术的生态,这也就是常说的对技术的生态有一定的前瞻性。</p><p>结合自身的情况,在线业务为什么要切GBF,是要基于领域建设提高复用度,达到降本增效。架构活动的所有目标都是为了降本增效。切框架短期内会使业务迭代成本变高,中期途中就会陷入一个悖论:当上下游环境协调成本高时,如果从自身妥协方案,会使得US短中期成本增高,且如果没有改进的情况下无论是从US自身还是纵观全局看长期收益降低,但是又不能影响进度,或者说可不可以等时机成熟再进行,我感受到过不小的压力。</p><p>这些原则说起来比较简单:确保长期目标不动摇,临时方案做取舍。做下来就会有犯难的时候:如果临时方案做得多了容易形成包袱,影响长期收益,最终会使定制的目标打折扣。阶段目标保障和长期收益并不是完全对立的,实际工作中也会存在需要做取舍的情况,当阶段目标和长期收益出现矛盾时,需要架构人员争取资源或做好取舍。纵使做完决定选择阶段目标临时放弃长期收益时,这也只是一个<strong>短期</strong>的决定,并不能代表<strong>将来</strong>,也就是说在时机成熟的时候(例如上下游在自身的演进中做了理想态的改造),那么作为部门自身也需要时刻关注并及时跟进。</p><p>谈到取舍,深有感触:作为决策者或有决策权限的角色,在决策范围内需要做好取舍。如果当事人不做取舍,那么就只能让别人来替他做取舍。执行者大都选择丢掉休息选择加班、或者跳过总结归纳改进的环节,长此以往这种决策低效且不科学。决策人员需要做好清晰的取舍,避免无限度的索求(全都要),因为很有可能无法被完全满足,导致取舍权分散给执行者。取舍权分散给执行者有什么不妥?个人认为取舍的决策权下放分散给执行者存在问题是:执行者接触到的信息有限、经验不足易导致决策过于片面,不容易有全局观,容易做出错误的决策,项目风险加大。</p><p><strong>资源</strong></p><p>资源,是有限的。</p><p>作为一个架构师,要在有限的资源下最大化商业价值。如何让技术人员站在商业的角度来理解这句话?</p><p>这里描述是一项架构师参与的商业活动,既然是商业活动那么必定要有商业价值。大部分技术人员并不关注商业的价值逻辑,通常只关注技术方案是否优越,容易忽略技术方案落地过程中客观存在的资源、环境以及协作等因素。如何让技术人员理解商业价值,可以从代码和设计的三个作用来阐述:</p><p><img src="/img/remote/1460000044222607" alt="" title=""></p><p>技术人员主要通过上面这三个途径为公司赚钱。员工的工资和各种收入,来自于公司的商业收入和融资。</p><p>结合自身的理解,从公司到组织到个人,都有属于自身层面的商业逻辑,科学合理可持续发展的商业逻辑也是支撑公司、组织和个人发展的基础,脱离了合理商业逻辑的事物,短期内看并不一定会有明显的结果,长期看会衍生出各种各样的问题,问题的原因不仅仅归咎于问题本身及产生的过程,更深层次上看是整个的商业逻辑是否合理、可持续。</p><p>那么作为个人来讲,如何做到利用手中的资源最大化商业价值,对公司、组织、个人都能受益?</p><p>a.理解你所在的企业或团队的商业模式</p><p>b.理解你在自己所处环境中创造的商业价值</p><p>c.保障架构活动的长期商业价值</p><p>d.在架构规划中寻找扩大收入的机会</p><p>e.在架构规划中寻找减少成本的机会</p><p>前两点商业模式和商业价值,每个人的认知不一样,通俗讲就是这个公司、这项业务是不是核心、有没有前景。对于公司业务前景经常会有不同的声音,常见于新兴业务,属于仁者见仁智者见智,不过也从侧面了印证了最近比较流行的一句话:人们通常赚不到认知以外的财富。行业、企业的发展作为自然人很难影响和撼动,历史和趋势中个人只有选择的空间。</p><p>那么第三条对我们来讲说是一个长期面对的事情:当做出选择后,如何在工作中确保自己和团队都能够有持续的、足量的、正向的价值和收益。和经济学一样,技术的边际效益也是递减的,因为技术一直在发展,个人的价值和优势主要体现在增量价值上,也就是说个人通过工作创造的价值,是在平均价值之上,才能说这个人具有一定的优势。然而这些优势并不是一成不变的,因为开源的解决方案也在源源不断的提升,越来越多的人掌握,那么个人的增量价值响应的就会减少,甚至不存在。这也就需要个人不断的学习、提升自己来持续提高竞争力。</p><p>文中提到的资源和经济学中的生产资料、生产成本类似,商业价值依赖资源,商业公司和组织对员工的期望是最小成本生产最大商业价值,这些无论是从短期还是长期来看都要关注,目标过于抽象时为了避免不同的人理解不一致,可以根据每个人的环境、岗位具象专属的目标,最好是根据时间粒度分散成阶段性的目标,也就是说于员工个人而言,更多的是对阶段性精确目标的最大化投入来取得收益。目标的定制依据这里已经介绍完了。</p><p>当目标确认完后,就要奔着目标,发挥自身的最大价值。也就是两个方面:<strong>发掘机会和减少成本</strong>。</p><p>机会需要发现,无论是来自于科学的数理统计、分析挖掘还是日常中的一些小Tips,都是在发掘机会。这一点我在业务侧会接触到比较多的机会,版本迭代中通常会和产品聊本次更新的动机是什么,收益在哪,作为C端的产品逻辑,除了这些收益,我们还要从用户体验出发,这些变化会给用户带来什么样的方便,以及我们会不会有额外的代价和成本。最常见的例子就是如何在有限的屏效中将活动信息、分享裂变、推荐合理的展示给用户、引导用户,以及每个模块能否让大部分用户心领神会设计的初衷,交互能否适应人群的习惯等等。但目前我还没有精力投入到指标的研究和跟踪中去分析验证,只是有兴趣,后面有机会需留意这块。</p><p>除了业务的机会,也有技术的机会。比如发现并抓住开发中遇到的痛点。很多同学在开发或推进过程中会遇到各种各样的痛点,非常多的情况就是考虑到时间、精力有限等因素后为了保障任务按期完成,选择性忽略这个痛点,当任务完成后又投入到其他事项中。这些痛点虽然造成了体感上的影响或者影响了一点点效率,但并没有被抓住解决掉,因为单论这一个问题不会被放大,也不影响KPI或OKR,痛点存在还会继续影响其他将要遇到的“幸运同学”,当忽略的次数变得多起来,量变易引发质变:框架不够好用。如何应对这种现象,个人觉得可以设计一种机制,强化痛点发现、上报、跟进、解决、反馈提升,也会从侧面提醒项目Owner除了关注任务的进度,也要关注任务完成的质量。</p><p>成本包括人力成本、时间成本、机会成本,也包括技术迁移的成本,作为架构师,需要从各类复杂成本中去衡量,按时间轴推演,保障中长期的收益。</p><p><strong>行为</strong></p><p>技术同学每天沉浸在逻辑中,容易陷入一个思维区域:世界由逻辑和数字主宰。合理的结构中商业活动需要和技术解耦,因为技术自身不会给企业和组织带来价值,而是大多数企业和组织作为一个平台,使用技术盈利。技术落地的过程鲜有单兵作战,大都是团队协作、组织协同。上面这句话推导的逻辑是:商业价值 --> 组织活动 --> 人在组织 --> 活动主体是人 --\> 遵循人性。</p><p>提到人性,就会提马斯洛需求层次模型。尽管每个人所处的环境、接触的信息、个人的观念各有不同,需求层次模型也会有千差万别,但是从公司、组织和员工的角度来看,这一模型相对稳定清晰。动机的抢占模型也可以理解为需求的压制模型如下图:</p><p><img src="/img/remote/1460000044222608" alt="" title=""></p><p>有时候任务推进会感觉到超乎寻常的艰难,合适的沟通方式表面上可以避免一些矛盾,本质上是作为被推进方,或者当事人的资源不足(例如需求排不开),通常推进方并不了解合作方的需求优先级或依赖层次,和他要配合做这件事的成本,有些事只是在推进放看来比较简单,就会有一个求证的过程,这个过程有没有必要我自己也不太清楚。当这些需求得不到满足的情况下,合作方会自动诱发动机,主导的意识和行为通常让人难以理解,遇到这种事情的解决方式是分析他的需求优先级,是否存在动机压制,以及能否协调调整优先级,改变动机压制的重要性和次序。</p><p>在最近的工作中经常遇到的一个现象是:方案可行,但是协同方没资源。因为组织的资源不单单为我所在的一个项目提供,而是要支撑当下阶段的各个目标。如何在多样目标和复杂的组织资源协调中找到最优解,是非常困难的一件事情。作为参与方,尽量去解,临时做兜底。一次次兜底就是一个个小包袱,还要不忘提醒自己包袱不要太多。</p><p>动机优先级中每个人的认知和安排是不一样的,有一个可以<strong>参照的依据</strong>:设计思维的精髓在于深度理解和尊重用户,对技术人员来讲到底是被动地迭代方案,执着于填补设计的漏洞;还是从共情用户的角度出发,脱离现有技术方案的束缚。同时忘记现有的技术方案的优势, 把关注点放在深度理解用户、解决用户的痛点上,进而拓展技术设计空间,找到更完美的技术路径。答案不言自明。</p><p>上面提到的这些只是理论,也就是我们常说的理想态,能否很好的落地就变得复杂起来,因为单纯从理论上来看这些对每个人的要求非常高,无论是职业素养还是主观能动性上,做到的都是少数。同时伴随着边际效益递减、35岁危机、996等热门社会现象,底层逻辑是人们没有安全感导致行为偏重自保,这些能不能带来商业价值是值得分析和审视的。这里提到的安全感是指能够影响人做出科学决策的环境压力,并不和居安思危中的危机感对立。</p><p>结合自己在技改项目的过程中,有同学反馈担心会失去手里的业务和之前负责的一些方向,也有同学有需求压制导致参与度不高,有的会在交谈中表达,有些虽然不明说,但种种迹象表明团队协作或工作内容没有安全感。我给出的反馈和建议是:当前目标是降本增效,业务的前景很宽广,当下还在高速发展,完全没理由缩编,但是这并不意味着可以无限度的扩张。我们需要在思考如何在不扩编的情况下更高效的做更多的事情,花更短的时间,支撑更多的行业。消除危机感的同时,还需引导良好的设计思维,刚才提到的深度理解和尊重用户,很多同学是需要这种自我满足感的,但是当节奏变得紧张、感受到环境不宽松时,这些也就随之被抛诸脑后转而去满足更原始和低层次的动机,也就是面对源源不断的需求和迭代,将任务填满日程表,从而持续不断的投入到紧张的迭代中。</p><p>顺势—天时、地利、人和</p><p>如何看清行业的周期、把握新技术。</p><p><img src="/img/remote/1460000044222609" alt="" title=""></p><p>俗话讲,你永远叫不醒一个装睡的人。是这个人不愿意醒吗?我看未必。而是人性的一些弱点导致这个人不愿意接受现实、害怕变化、对过往的路径严重依赖、或者思维僵化,导致他不想醒。<strong>自我麻痹</strong>源自处于风险或者压力下的自我保护机制:当个体面临压力、困境或威胁时,为了保护自己的心理健康和自尊,会出现一些消极的应对策略。这些策略通常表现为对现实的否认、回避或者对问题的轻视,从而使个体在心理上暂时免受困境带来的痛苦。然而,长期的自我麻痹可能导致问题恶化,无法解决现实生活中的问题,不能全力探寻新的出路,甚至用勤奋弥补内心的不安,容易陷入于目标无用的布朗运动——目标不清晰、动作不连续。</p><p><strong>畏惧变化</strong>:当人感受到压力时,对变化感知异常慎重。在繁忙的事务中如何保持专注,历史的包袱能不能放下,如何卸载,短时间内卸载不掉那如何长线对待,如何同时支撑好业务,当同时面临这些问题时,每种取舍都有它自身的底层逻辑,当我们面向未来去思考这些问题时,就知道当下该如何选择。</p><p>对于<strong>路径依赖</strong>可以很好的用一句话解释:成功可以借鉴,但不会复刻。技术的生命周期,可以从技术社区中获取,技术的周期源于大多数人对该技术的定位。如果工程师们对这项技术不再有需求,那么这项技术的命运将会毫不犹豫的被抛弃。</p><p>对技术周期的了解作为架构师的基本功,这里不再作分析。当一个架构师的技术掌握优秀时,又要避免一个误区:拿着锤子看什么都是钉子。技术是实现商业价值的一个手段,并不是唯一路径。在这个前提下技术不能拖累商业价值的最大化。所以说架构师面对公司、组织、以及工作开展的实际情况,要选择合适的技术方案。</p><p>如何定义合适的技术方案?先看三个不同的研发活动的层次:</p><p><img src="/img/remote/1460000044222610" alt="" title=""></p><p>架构师在这三个层次的研发活动中侧重点是不一样的,技术驱动需要保证技术的先进性、产品驱动保障客户的体验、业务驱动保障业务指标的全盘增长。</p><p>影响技术体系建设的外部因素还有行业发展、企业内部指标的压力、组织结构的影响等等,需要架构师获取全面的信息,通盘抓重点,找到保障商业价值最大化的关键因素和节点。</p><p><strong>总结</strong></p><p>最近在学习郭东白的架构课,本篇文章主要是结合自身实际的经历阐述架构师定位、架构活动如何保障企业、组织实现商业价值,以及从员工层面的执行、管理角度分析各层次的定位、方向,通过这些思考总结沉淀,帮助我们在工作中更好地做技术落地和业务支撑。</p>
高德Android高性能高稳定性代码覆盖率技术实践
https://segmentfault.com/a/1190000044167818
2023-08-31T10:30:50+08:00
2023-08-31T10:30:50+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>前言</strong></p><p><strong>代码覆盖率</strong>(Code coverage)是软件测试中的一种度量方式,用于反映代码被测试的比例和程度。</p><p>在软件迭代过程中,除了应该关注测试过程中的代码覆盖率,用户使用过程中的代码覆盖率也是一个非常有价值的指标,同样不可忽视。因为伴随着业务扩展和功能更新,产生了大量过时和废弃的代码,这些代码或者很少甚至完全不再使用,或者“年久失修”,缺少维护,不仅对应用包体积有影响,还可能带来稳定性风险。此时,能够采集生产环境的代码覆盖率,了解线上代码的使用情况,为下线无用代码提供依据,就十分重要了。</p><p><strong>目标</strong></p><p>我们的目标很明确:<strong>根据云端配置,采集线上每个类的触达和使用频次,上传到云端,在平台进行处理,并提供查询和报表展示能力</strong>。</p><p><img src="/img/remote/1460000044169535" alt="" title=""></p><p></p><p>如上图所示,我们期望代码覆盖率数据能在平台上进行查询和直观的展示,在需要时可以直接查看,为下线旧代码、资源调度和分配等提供决策依据,最终为用户提供更小的App安装包,更好的功能使用体验。</p><p>通过云控中心,我们可以控制是否启用覆盖率采集,也可以根据覆盖率(类使用频次)动态调整App中金刚位、线程等资源的调度分配策略。其中覆盖率采集方案是最为重要的一环,业界也有很多成熟的方案,但都有各自适合的场景,而我们的诉求是在尽量不影响用户使用和App运行的前提下,采集类粒度的代码使用覆盖率。使用的采集方案应该<strong>少Hack,实现简单,兼顾稳定性和性能,同时也不会侵入打包流程,带来包体积影响</strong>等,在经过深入探索后,我们自研出了一套完美满足这些要求的全新方案。</p><p><strong>方案对比</strong></p><p>下表为常见方案与自研方案的各项指标对比,绿色表示更优。</p><p><img src="/img/remote/1460000044169536" alt="" title=""></p><p>从表格中可以看出:</p><p><strong>Jacoco方案</strong></p><p>类似的还有Emma、Cobertura等,他们都通过插桩实现,可以支持所有版本所有粒度的采集,但是插桩带来了一定的包体积和性能影响,不适合线上大范围使用。</p><p><strong>Hook PathClassLoader方案</strong></p><p>实现简单,无源码侵入,且支持所有Android版本,但Hook PathClassLoader不仅带来了性能影响,甚至可能波及App稳定性。</p><p><strong>Hack访问ClassTable方案</strong></p><p>能够按需采集,对App性能几乎没有影响,但Hack可能带来兼容性问题,且实现较复杂。</p><p><strong>自研方案</strong></p><ul><li>性能优异,支持按需采集,无损App性能</li><li>实现简单,未使用任何“黑科技”,稳定性和兼容性极好</li><li>支持跨进程和插件采集</li></ul><p>对比得知自研方案能更好的满足我们采集线上代码覆盖率的诉求,因为它不仅有着很好的稳定性,而且有着优异的性能,几乎不会对用户产生任何影响。那么它是如何做到高性能和高稳定性的呢?请看下文介绍。</p><p><strong>方案介绍</strong></p><p><strong>原理</strong></p><p>要采集类粒度的代码覆盖率,其实就是要知道在App运行过程中,加载和使用了哪些类。在Java应用中,这可以通过调用ClassLoader的findLoadedClass方法直接查询得到,而在Android App中却没那么简单。原因是Android系统做了这样一个优化:</p><p><strong>为了提升启动性能,对于App自定义的类,即PathClassLoader加载的类,如果直接调用findLoadedClass进行查询,即使这个类没有加载,也会执行加载操作。</strong></p><p>这不是我们期望的。</p><p>虽然我们没办法直接调用FindLoadedClass方法查询类的加载状态,但是经过深入研究和分析,我们发现ClassLoader最终是通过查询它的ClassTable字段得到类加载状态的,如果我们也能访问ClassTable,问题不就迎刃而解了吗?沿着这个思路,我们创新性地提出了<strong>复制ClassTable指针,通过标准API间接访问类加载状态</strong>的方案。</p><p>该方案巧妙地实现了对ClassTable的无Hack访问;同时完美绕开了我们不需要的类加载优化,寥寥数行代码就实现了类加载情况的获取,巧妙且简洁,同时它还具备以下优势:</p><ul><li><strong>采集速度是普通方案的5倍以上</strong>,性能优异</li><li>使用标准API访问ClassTable,兼容性与稳定性极佳</li><li>仅使用一次反射,无任何“黑科技”,简单稳定</li><li>不影响类加载及App运行</li><li>完美支持多进程和插件的采集</li></ul><p>不过有一点需要注意:</p><p>ClassTable字段是从Android N开始引入的,所以该方法只适用于Android N及以上。出于必要性和ROI考虑,我们也未对Android N以下版本进行适配。</p><p><strong>采集流程</strong></p><p>基于上述的方案,我们设计了完整的代码覆盖率采集功能,关键流程如下:</p><p><img src="/img/remote/1460000044169537" alt="" title=""></p><p>可以看到整个端侧的采集流程是串行的,非常便于流程控制和数据整合。下面说明一下设计思路:</p><ul><li>采集时将App分为两部分,一部分是主进程和子进程使用的宿主类数据,另一部分是插件类数据。</li><li>基于查询方式采集,主进程、子进程、插件分别提供查询类加载状态的接口。</li><li>流程基于串行方式,由主进程控制,依次调用相应的接口采集主进程、子进程和插件的数据。</li><li>每个版本只采集和上报未加载过的类数据,首次采集时,以类全集为输入;后续的每次采集,以上一版本未加载的类为输入,采集次数越多,需要查询的类越少。</li><li>主进程和子进程依次查询,查询都以上一次查询后剩余的未加载类为输入,因此越靠后的子进程所需查询的数量越少,同一个插件在不同进程的实例的查询也与此类似。</li></ul><p>如下图所示:</p><p><img src="/img/remote/1460000044169538" alt="" title=""></p><ul><li>采集结束时,会生成一份宿主类数据和N份插件类数据(假如有N个插件)。这些数据会分别与之前的采集结果做Diff,将增量数据上传服务。</li><li>服务平台进行存储、解Mapping、模块关联等处理,最后以报表形式聚合展示。</li></ul><p>值得注意的是:</p><ul><li>主进程与子进程使用的类都属于宿主,采集结果应该合并为一份数据;同理,一个插件无论在多少个进程加载,最后也只应生成一份该插件的数据。</li><li>采集时我们将数据分为两部分,这样可以提高采集效率,也方便后续解混淆;在平台展示时,合并展示更有意义。</li></ul><p><strong>版本管理</strong></p><p>Android App的代码大都会经过混淆处理,混淆后的类名会因版本而异,这就需要根据App版本来管理覆盖率数据。</p><p>按版本管理数据后,每个版本会清除上一版本的数据,避免数据错乱;一个特定的类,在当前版本已经使用过之后,会记录下来,后续此版本的采集不再重复查询它的使用情况。</p><p>每个版本首次采集时,需要以App的类名全集作为输入,每一次采集会产生一个未使用类的集合,作为下一次采集的输入。这样,一个版本中每次采集需要关注的类数量会逐步减少,可避免无意义的查询,提升采集性能。</p><p><strong>类名数据获取</strong></p><p>类名数据可以通过两种方式获取:</p><p><strong>1.从安装包获取</strong></p><p>安装包内的类名数据可以从PathClassLoader中获取,插件则可以从对应的BaseDexClassLoader中获取,使用如下方法即可:</p><pre><code>public static List<String> getClassesFromClassLoader(BaseDexClassLoader classLoader) throws ClassNotFoundException, IllegalAccessException {
//类名数据位于BaseDexClassLoader.pathList.dexElements.dexFile中,可以通过反射获取
//先获取pathList字段
Field pathListF = ReflectUtils.getField("pathList", BaseDexClassLoader.class);
pathListF.setAccessible(true);
Object pathList = pathListF.get(classLoader);
//获取pathList中的dexElements字段
Field dexElementsF = ReflectUtils.getField("dexElements", Class.forName("dalvik.system.DexPathList"));
dexElementsF.setAccessible(true);
Object[] array = (Object[]) dexElementsF.get(pathList);
//获取dexElements中的dexFile字段
Field dexFileF = ReflectUtils.getField("dexFile", Class.forName("dalvik.system.DexPathList$Element"));
dexFileF.setAccessible(true);
ArrayList<String> classes = new ArrayList<>(256);
for (int i = 0; i < array.length; i++) {
//获取dexFile
DexFile dexFile = (DexFile) dexFileF.get(array[i]);
//遍历DexFile获取类名数据
Enumeration<String> enumeration = dexFile.entries();
while (enumeration.hasMoreElements()) {
classes.add(enumeration.nextElement());
}
}
return classes;
}
</code></pre><p>这种方式简单直接,不过会一次性将DexFile中的所有类名加载到内存中,而根据我们的测试,每一万个类大约占0.8mb内存,对于动辄数万个类的大型App来说,会是一个不小的内存开销。所以还可以考虑第二种方式。</p><p><strong>2.云化下载</strong></p><p>从构建平台获取类名数据,上传到云化平台,App在需要的时候下载使用。</p><p>至于选用哪种方式,直接根据类数量来选取就好。类数量特别多时,如大型App场景,建议使用云化方式;普通App或插件,直接从安装包类获取即可。</p><p><strong>子进程采集</strong></p><p>主进程未加载的类,我们会交给子进程再次查询。这就需要子进程提供支持跨进程调用的查询接口,我们选择了简单可靠,且容易复用的AIDL方案来实现。</p><p>具体做法是:</p><p><strong>通过AIDL定义查询接口,并定义对应的Action,在Service的onBind方法中根据Action返回查询接口的Binder实现类用于远程调用。</strong></p><p>同时考虑到跨进程的成本较高,如果对每个类都调用一次查询接口,无疑是难以接受的。于是我们想到了文件+批量查询的方式:利用文件作为数据载体,将已加载的类和未加载的类都写入到文件中,在接口间传递文件路径。文件操作还可以采用BufferedReader和BufferedWriter以提升性能。</p><p>调用过程如图:</p><p><img src="/img/remote/1460000044169539" alt="" title=""></p><p>这样做的好处也显而易见:</p><ul><li>采集一个进程仅需一次跨进程调用,成本极低</li><li>避免数据序列化的内存开销</li><li>绕开大数据无法直接跨进程传递的问题</li><li>采集流程更简单,可按需采集需要的进程</li><li>方便数据过滤,避免重复查询已加载类,提升采集性能</li></ul><p><strong>插件采集</strong></p><p>对于宿主类,查询PathClassLoader对应的ClassTable即可。</p><p>而插件一般通过BaseDexClassLoader或其派生类进行加载,需要查询相应ClassLoader的ClassTable。</p><p>对于在子进程中使用的插件,只是多了跨进程接口调用,将已加载类和剩余类返回给主进程进行处理的操作。</p><p>采集步骤如下:</p><ul><li>查询子进程类时,会同时查询该进程中运行的插件类,将数据写入按插件名划分的文件。</li><li>对主进程插件的采集是整个流程的最后一个环节,此时会检测每个插件对应的数据文件(子进程生成),并进行合并处理,最后将数据文件删除。</li><li>最后再处理剩余的插件数据文件,这部分文件属于只在子进程运行的插件。</li></ul><p>到此,就得到了所有插件的类加载数据。</p><p><strong>解Mapping</strong></p><p>查看代码覆盖率数据时,我们期望看到原始的类名,所以解Mapping是必经之路。</p><p>解Mapping操作可以在端上进行,也可以在服务侧进行,出于安全性考虑,我们选择了服务侧。</p><p>Mapping文件由打包过程生成,每个安装包对应一份。我们的做法是在构建平台打正式包的时候通过脚本生成混淆类与明文类的映射文件,服务端在需要的时候通过App版本信息获取对应的映射文件,反解出原始类名,并与模块进行关联。</p><p>最终展示到平台的就是解完Mapping,并与模块、插件完成关联的代码覆盖率数据。</p><p><strong>数据存储及增量计算</strong></p><p>采集的数据需要存储起来,为了方便计算增量数据,我们选择了数据库作为存储方案,因为它天生具备去重及排序功能,而且性能也不错。具体的做法是:</p><ul><li>创建一张数据表,只需包含一个名为class的列就行,该列声明为主键,不接受空值和重复。</li><li>每次采集前,获取其中的行数,采集过程中,将已加载的类名数据更新到表中,让数据库自动完成去重。采集完成后,再次获取数据行数,与采集前的行数相减得出的offset就是增量部分,我们只需要将这部分数据上传到服务。</li></ul><p><strong>性能和稳定性</strong></p><p>经过我们的反复测试和调优,对5w+类的采集平均耗时约0.5s/次,采集期间内存增长在500kb左右,CPU无明显上涨。</p><p>同时也经过高德地图线上多个版本验证,未发现相关崩溃及ANR。</p><p><strong>其他</strong></p><p><strong>绕开黑灰名单</strong></p><p>Android P以后,官方将ClassTable成员变量加入了黑灰名单,在使用反射访问之前,需绕开SDK限制。我们采用的是元反射+设置豁免的方式,具体的实现可以参考GitHub上的开源项目FreeReflection,想要了解更多可自行Google查询。</p><p><strong>采集时机和频率</strong></p><p>虽然采集过程短暂无感,但为了最小的影响App的运行,我们将采集工作放在子线程中,并选择在App退后台一段时间后开始执行。</p><p>同时由于我们只需要知道代码使用的比例和大致情况,每次冷启后只采集一次即可。</p><p>多位用户多次冷启后的数据,已经足以反映真实的代码使用情况了。如果需要每个类的使用频次数据,在服务端聚合统计也能得到。</p><p><strong>写在最后</strong></p><p>代码覆盖率作为一种度量方式,不仅能为我们下线旧代码提供依据,同时还能反映某个功能的使用热度,可以为资源分配、调度决策等提供依据,是软件开发中一项不可或缺的重要工具。</p><p>我们这套全新的方案,简洁而不简单,巧妙地实现了无Hack采集,在保证高稳定性和不侵入源码的前提下,优雅地实现了生产环境代码覆盖率的高性能采集,已经过高德地图多版本验证,是一套成熟、稳定且高效的方案。在此分享出来,希望能为有同样诉求的同学提供一些借鉴和思路。</p>
走近高德驾车ETA(预估到达时间)
https://segmentfault.com/a/1190000043978979
2023-07-06T18:38:01+08:00
2023-07-06T18:38:01+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>1. 什么是驾车ETA</strong></p><p>临近节假,长途自驾返乡的你是否曾为无法预知路上到底有多堵而纠结?通勤上班,作为有车一族的你是否在为路况变幻莫测的早晚高峰而烦恼?外出旅行,赶火车、赶飞机的你是否还在为担心错过班次而焦虑?不要慌,高德的驾车ETA帮你预知未来路况,让每个用户轻松成为“时间管理大师”!</p><p><strong>ETA(Estimated Time of Arrival),即预估到达时间,指的是用户在当前时刻出发按照给定路线前往目的地预计需要的时长。</strong>如图1展示了驾车ETA在导航软件的前端页面上呈现的形态,用户在使用过程中会主要参考这一数据安排行程时间、进行出行相关决策;对于打车的场景,平台呈现给用户的预估价也基于这一数据进行计算。因此,如何准确地预估ETA对于高德地图的诸多业务板块都起到至关重要的作用。</p><p><img src="/img/remote/1460000043978981" alt="" title=""></p><p>图1 ETA在高德地图上的前端展示</p><p>为方便后文表述,这里先简单介绍一下ETA相关的技术概念:</p><p><strong>link</strong>:路段,是分叉口之间基本的道路组成单元。</p><p><strong>trace</strong>:轨迹,对应的是一个由一连串link组成的序列。</p><p><strong>SP(Speed Profile)</strong>:同一特征日相同时间区间的历史平均速度,按10min聚合。例如每周一早上9:00-9:10,某个link上所有轨迹,可以将过去几周聚合求一个平均速度,这个平均速度可以代表对这个link在未来周一早上9:00-9:10这个时间区间内通行速度的静态预测。</p><p><strong>AutoLR(Autonavi Location Reference)</strong>:实时路况,道路当前通行耗时,每分钟都会发布新的值。</p><p><strong>link通行耗时真值</strong>:在一个5min的时间窗口内进入某一link的所有轨迹,在完成去噪后求取平均值,即得到该link在该5min窗口内的通行耗时真值。</p><p><strong>2. 业务板块</strong></p><p>图2展示了ETA业务的各个板块。</p><p><img src="/img/remote/1460000043978982" alt="" title=""></p><p>图2 ETA整体框架</p><p><strong>基础数据层面</strong>,link场景分层根据历史实走真值将link归为不同类别。每类link预测的难度不同,例如有些link的通行时间每天鲜有拥堵,则可直接利用静态SP预测,因此调用的预测模块也不尽相同。真值生产及推演系统首先将各个link上5min窗口的实走轨迹聚合求平均通行时间,得到link通行耗时真值;同时利用真值推演工具可推算给定trace的通行耗时真值。link级、trace级的通行耗时真值是模型训练、模型评估、线上问题调查等一系列工作的数据基石。</p><p><strong>预测模块层面</strong>,有三大预测模块可用于link级预测。</p><p><strong>一是静态SP</strong>:该方法通过历史均值进行预测,不利用实时信息。</p><p><strong>二是线性模型</strong>,该模块在ETA服务中被调用,通过实时信息AutoLR和历史信息SP来拟合link级真值。</p><p><strong>三是精准预测</strong>,该模块作为算法服务提供link级预测结果,通过深度学习模型利用实时通行速度、流量等信息对较为复杂的突发路况进行预测。</p><p><strong>预测功能层面</strong>,除link级预测外,ETA服务还提供trace级预测功能,对用户规划的整条路线进行ETA预测;以及准点率预测功能,对给定trace级预测结果的可信度做出判断。</p><p><strong>应用场景层面</strong>,自驾、打车业务都需使用ETA,但两者样本分布以及重点关注的场景不尽相同。ETA的算法能力在前端页面还涉及到一些其他形式的透出,例如拥堵段预计通过耗时、拥堵未来趋势说明,以及准点率等等。</p><p><strong>效果评测层面</strong>,涉及到自身link级、trace级基础指标评测,对真值推演结果的评测、各个场景的效果评估。监控干预层面,涉及到实时捞取头部问题case、对问题link的ETA进行自动干预、人工干预等。</p><p><strong>3. ETA的预测流程</strong></p><p>线上的ETA服务为其他服务提供ETA预测计算接口。精准预测模型部署在另外的算法服务中,该服务每分钟将link级多时间跨度预测值写入缓存,ETA服务按需查取相应值。对某个link进行预测时,有精准预测值的情况下将优先使用精准预测结果。ETA服务中的线性模型提供link级多时间跨度预测能力。在精准预测没有被触发的情况下,查看是否有实时路况以及待预测时刻与发起预测时刻时间差是否在1小时以内,满足上述条件则使用线性模型预测的结果。SP数据加载在ETA服务内存中,由于是静态历史均值,预测时间跨度可达未来一周。link级预测中,最低优先级的是利用SP进行静态预测。</p><p>link级预测结果可按照上述方案获取,那么整条路线的ETA要如何计算呢?这里就要用到link序列ETA推演的功能。假如用户规划的路线如图3所示,则在进行预测时,link1应选取对应距离当前[0min, 5min)时间跨度的通行时间预测值,例如该预测值为11min;则用户预计进入link2的时刻为11min之后,在link2上的通行时间应该选取link2对应[10min, 15min)时间跨度的通行时间预测值……依此逻辑推演到最后一根link(若推演到的某根link累积时间已超出1h,则用SP作为预测值),从而得到对整条路线ETA的预测。</p><p><img src="/img/remote/1460000043978983" alt="" title=""></p><p>图3 link序列ETA推演</p><p><strong>4. ETA预测的难点及解决方案</strong></p><p>在一些出行量大且拥堵规律复杂多变的场景,准确预估ETA的挑战性极大。例如工作日的早晚高峰,路况非常复杂,而且学校寒暑假后的开学、以往疫情期的反复、一些特殊日期(例如七夕、圣诞等)出行需求的剧增,都会使得历史规律无法直接复用。</p><p>为了能让深度模型<strong>提前感知拥堵的到来</strong>,我们在预测中<strong>引入了“未来流量”</strong>。想象这样的场景:来自北京的用户A由于家到公司较远,每天早上6点就要开车途径北五环去公司。9月1日,他像往常一样早上6点开车出门。走到北五环,用户A发现今天格外堵。直到在北五环上堵得快要迟到,才突然醒悟,原来今天是开学第一天,早高峰车流量大幅增加,后悔自己没有出发前没早点打开高德看看ETA。</p><p>我们注意到,由于用户A出发很早,出发时刻全程路况仍非常畅通,此时各个link流量也基本和8月无区别。这样,想要让模型能预判未来会出现比往常严重很多的拥堵,就必须引入能在用户出发时刻就与8月相同时间有明显区分度的特征。用户A的例子中,在他刚刚出发时,北五环上车流很小,但已经有很多像他一样早起且需要走北五环的用户开着导航从家里出发了,这些人虽然还没有上五环,但只要他们不偏航且完全按照ETA预估的时间行进,那么未来任意时刻这些用户的位置我们都可以推算得到,这意味着我们可以统计“未来的交通流量”。也就是说,这些已经在导航中的用户,未来各个时间片上会在北五环的各个link上分别形成多大的交通流量,都可以统计到(注:这里统计到的流量是匿名的聚合总量)。如图4所示,我们把这个统计量称作“<strong>未来的交通流量</strong>”特征。上面的例子中,早上6点,有很多需要上北五环的用户已经出发了,因此此时五环上的link已经显著高于8月份。</p><p><img src="/img/remote/1460000043978984" alt="" title=""></p><p>图4 计划中的交通流量</p><p>模型层面,我们提出了一种<strong>新的用于通行时间预测的深度学习框架:混合时空图卷积网络(H-STGCN)</strong>,该框架利用上述<strong>计划中交通流量</strong>提升模型效果。</p><p>在该模型中,我们设计了域转换器,以此整合异质模态的交通流量特征。同时,我们设计了复合邻接矩阵使得图卷积层能够更好地捕捉路段间的接近性。实验发现,在真实场景数据集上,H-STGCN和较先进的其他时空预测模型相比取得了显著更优的效果,在突发拥堵的预测上优势尤为明显。这项研究成果在为用户带来更优出行体验的同时,<strong>相应论文也被AI领域国际顶级会议KDD2020接收</strong>。</p><p><strong>5. ETA的效果评估</strong></p><p>对应link级预测与trace级预测,ETA效果的评估也有link级评测与trace级评测。</p><p>5.1. link级评测</p><p>trace计算参与的角色众多,涉及到方方面面(实时信息、历史统计信息、道路推演等)都会给trace级别的ETA带来影响,我们为了更好的衡量在单独link上ETA的计算质量,我们提出了link eta的评估方法。</p><p><strong>bad link率</strong></p><p>bad link率计算方法为,bad link批次总数同总link批次数的比值。bad link率越低,link级预测效果越好。bad link批次的定义如公式:</p><p><img src="/img/remote/1460000043978985" alt="" title=""></p><p>i表示批次id,满足这个条件即为bad link。</p><p><strong>MSE</strong></p><p><img src="/img/remote/1460000043978986" alt="" title=""></p><p>这里的n指的是link数量,k指的是评估批次数量。MSE越低,link级预测效果越好。</p><p>5.2. trace级评测</p><p>通过对比用户实走时长和ETA行前预测的结果,可以对用户全行程轨迹的ETA质量进行评估。使用trace级评测,可以监控trace的MSE、MAE、MAPE、优良率、恶劣率等指标。</p><p><strong>6. 总结</strong></p><p>本文对高德驾车ETA整体的业务板块进行了简要的介绍。</p>
ARHUD驾车导航技术概览
https://segmentfault.com/a/1190000043953535
2023-06-30T10:01:50+08:00
2023-06-30T10:01:50+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><img src="/img/remote/1460000043953537" alt="" title=""></p><p><strong>ARHUD</strong> (Augmented Reality Head Up Display),即增强现实与抬头显示的结合,是一种将渲染元素投影在真实世界的技术,也是目前用户理解成本最低的展示方式。</p><p>HUD功能第一次应用是在二战中,被应用在枪械和战斗机上,80年代初期开始转向民用,90年代初期技术概念被正式提出,并被演变成为汽车上的功能。其实,汽车上还有很多军用转民用的配置,例如惯导装置。</p><p><strong>ARHUD驾车导航,就是把车速限速、转向动作、引导线等重要的导航信息,投影到驾驶员视野正前方</strong> ,让驾驶员尽量做到不低头、不转头就能看驾驶引导信息。</p><p><strong>高德在ARHUD驾车导航方面做了大量研发工作并拥有业界领先的技术储备和实践经验,在2022年8月,高德地图与北汽、华为合作,推出北汽魔方ARHUD导航。</strong></p><p><strong>1.虚像距离(Virtual Image Distance)</strong></p><p><img src="/img/remote/1460000043953538" alt="" title=""></p><p><strong>虚像距离,Virtual Image Distance,简称VID,简单点说就是虚像到人眼的视觉距离</strong> ,大家都知道人的眼睛也是有焦距的,看远和看近的焦距不同,因此如果VID的距离不够远,在看向较远的地方时ARHUD的显示会由于眼睛焦距的原因而虚化。</p><p>传统HUD的VID距离也就是在2.5米左右,而AR HUD的VID距离往往在10米以上,要做到跨车道显示的话,需要投影距离达到20米才行。</p><p>传统W-HUD其实可以理解为一个投影仪,将图像反射,投影到了挡风玻璃上(例如手机高德地图的HUD投影功能),实际上相当于把原本显示在仪表盘上的信息,投射到挡风玻璃上。其实这也是HUD设计的初衷——驾驶员不需要低头即可获得车辆行驶的相关信息。</p><p>但是W-HUD的图像尺寸有限(通常投影距离3m,显示尺寸15-20寸),能显示的信息较少,且图像不会与道路融合,驾驶员仍然需要将视线从路面上移开,重新对焦才能获得信息,这实际上违背了HUD的设计初衷。</p><p><strong>2.视场角(Field Of View)</strong></p><p><img src="/img/remote/1460000043953539" alt="" title=""></p><p><strong>视场角,Field Of View,简称FOV,视场角包括了以驾驶员眼睛为中心的水平视场角和垂直视场角。</strong> 传统HUD的FOV很小,一般只有5度。而AR HUD的水平视场角要在10°以上,理想ONE的ARHUD能够达到20°,问界M5的ARHUD也能够达到13°。</p><p><strong>3.人眼位置(Eye Point)</strong></p><p>人眼坐标(x, y, z),相对于车体坐标系的位置,以车头中心为坐标原点,单位 米。</p><p>人眼坐标会随着驾驶者的高矮、坐姿、头部位置移动而动态调整。</p><p><img src="/img/remote/1460000043953540" alt="" title=""></p><p><img src="/img/remote/1460000043953541" alt="" title=""></p><p><strong>4.虚像旋转角度(三自由度)</strong></p><p><strong>4.1. 沿X轴旋转角度(LDA、下视角)</strong></p><p><img src="/img/remote/1460000043953542" alt="" title=""></p><p><strong>4.2. 沿Y轴旋转角度(横滚角)</strong></p><p><img src="/img/remote/1460000043953543" alt="" title=""></p><p><strong>4.3. 沿Z轴旋转角度(朝向角)</strong></p><p><strong>5.虚像坐标转换(世界坐标转虚像坐标)</strong></p><p>首先,看一下在相机投影中,世界坐标 转 像素坐标。</p><p><img src="/img/remote/1460000043953544" alt="" title=""></p><p>然后,看一下在HUD投影中,世界坐标 转 虚像坐标(单位也是像素)。</p><p>在已知 虚像距离、视场角、人眼位置、虚像角度 的前提下,就可以进行 世界坐标 与 虚像坐标 的互相转换。</p><p><img src="/img/remote/1460000043953545" alt="" title=""></p><p>通过对比相机投影 和 HUD投影 可以发现,相机投影中的焦距 与 HUD投影中的虚像距离 有着紧密联系。</p><p>人的眼睛也是有焦距的,看远和看近的焦距不同,因此如果虚像距离不够远,在看向较远的地方时ARHUD的显示会由于眼睛焦距的原因而虚化。</p><p>所以,虚像距离 联系着 人眼的焦距。</p><p>如果虚像距离过小,驾驶员需要将视线从路面上移开,重新对焦才能看清HUD上的信息,这实际上违背了HUD的设计初衷。</p><p><strong>6.坐标转换的应用</strong></p><p><img src="/img/remote/1460000043953546" alt="" title=""></p><p><strong>6.1. 验证虚像投影是否准确</strong></p><p><strong>面临问题</strong> :虚像投影主要目的是将真实世界坐标投影在虚像中,如果无法做到准确对应,会影响ARHUD准确性。</p><p><strong>解决方法</strong> :由硬件系统方传入投影参数——虚像距离、视场角、人眼位置、虚像分辨率、虚像角度,计算出投影矩阵,通过该矩阵可进行 虚像坐标 与 车体世界坐标 的转换。</p><p>取虚像上几个具有代表性的像素坐标(一般是九个点),转换成车体世界坐标,即可计算出虚像可视范围——最远可见、最近可见、最左可见、最右可见、中心可见。</p><p><img src="/img/remote/1460000043953547" alt="" title=""></p><p>在计算出的可视范围上放置标识物体(车前方),查看该标识物体在虚像中的位置,是否与九个点重合,如果重合则代表投影准确,如果不重合则投影误差较大,需要通知硬件系统方进行调整。</p><p><strong>6.2. 解决变道引导线超出虚像显示区</strong></p><p><strong>面临问题</strong> :AR导航中的变道引导线是贴合真实世界指向相邻应行驶车道的,如果虚像可视范围无法覆盖相邻车道,则会导致变道线超出显示区。</p><p><strong>解决方法</strong> :根据变道信息(向左变道、向右变道、变到几车道),在虚像上取几个趋势性像素坐标,转换成 车体世界坐标,最终投影出来。因为是在虚像上取的坐标,所以始终不会超出虚像显示区域。</p><p><img src="/img/remote/1460000043953548" alt="" title=""> </p><p><strong>7.ARHUD 硬件技术</strong></p><p><strong>7.1. TFT</strong></p><p>即TFT-LCD,其原理是LED发出的光透过液晶单元后将屏幕上的信息投射出去。</p><p><strong>优点</strong> :该方案是业界最早开发的投影方案,方案成熟,相对成本低。(目前国外供应商能做到2500-3000左右,本土供应商能做到2000左右。随着技术的成熟和相关产业链的发展,成本应该可以进一步做到2000以内)。</p><p><strong>缺点</strong> :阳光倒灌问题难以解决。亮度不够,在白天显示效果较差。</p><p><img src="/img/remote/1460000043953549" alt="" title=""></p><p><strong>7.2. DLP</strong></p><p>即Digital Light Processing的缩写,采用TI的DMD芯片,把影像信号经过数字处理再投射出来。</p><p><strong>优点</strong> :DMD芯片可确保投影的活动影像色彩艳丽、细腻逼真、自然真实。由于经过数字化处理,可将图像中的缺陷抹去。DMD芯片更小、更易于携带。</p><p><strong>缺点</strong> :造价更贵(成本在5000元以上)。</p><p>DLP可能出现彩虹效应,影像信号在数字处理过程中颜色混合及转换异常。</p><p>DLP显示屏由于需要采用TI的DMD芯片,涉及到技术专利,因此只有奔驰和传祺两家车型在用。</p><p><img src="/img/remote/1460000043953551" alt="" title=""></p><p><strong>7.3. LCOS</strong></p><p>即Liquid Crystal on Silicon的缩写,即液晶附硅,也叫硅基液晶,是一种基于反射模式,尺寸比较小的矩阵液晶显示装置。这种矩阵采用CMOS技术在硅芯片上加工制作而成。目前国内主要是华为跟一数科技采用这种方案。</p><p><strong>优点</strong> :在整体反射模式下,光利用效率高,画面更加自然。价格可控,CMOS技术由多家厂商掌握,避免DMD芯片只由德州仪器独家垄断的情况。反光层和硅基板电路之间具有一层金属遮光层,可以有效防止阳光倒灌。</p><p><strong>缺点</strong> :目前整体技术还不太成熟,没有大规模量产,有待进一步发展。HUD可视区域较小,投影光机体积相对较大。</p><p><img src="/img/remote/1460000043953552" alt="" title=""></p><p><img src="/img/remote/1460000043953553" alt="" title=""></p><p><strong>8.ARHUD主要技术难点</strong></p><ul><li><strong>市场角小</strong></li></ul><p>目前市面上的ARHUD设备FOV过小,影像只能呈现在驾驶者视线范围中的一小部分。</p><ul><li><strong>投影亮度</strong></li></ul><p>HUD影像的亮度,为了对应不同的外部光线、气候等影响,需要更高的亮度来达到较佳的影像品质与视觉效果。</p><ul><li><strong>硬件体积</strong></li></ul><p>降低HUD的系统整体体积,现有TFT/DLP等模组本身的限制,加上需求较大的FOV,都会让HUD系统的体积越来越大,与车体的空间分配冲突。</p><ul><li><strong>实景贴合</strong></li></ul><p>需要通过各种路网数据、传感器数据、GPS信号等,进行实时矫正。确保AR的图形和真实路况匹配。</p><ul><li><strong>人眼位置</strong></li></ul><p>如何动态监测人眼位置,调整ARHUD投射的画面,使之避免出现画面发虚、错位等问题,比较考验HUD厂商的能力。</p><p><strong>结语</strong></p><p>ARHUD技术发展至今,已成为驾车导航产业必争之地。可以预期的是,苹果公司的ARHUD在未来也会逐渐向驾车导航靠拢。当然,还有很多技术难点需要攻克,来提升用户体验,真正实现 导航视野内“所见即所得”。值得欣慰的是,在ARHUD技术迅猛发展过程中,见到了很多国内企业努力的身影。希望未来有更多中国技术在ARHUD领域大放异彩!</p><p>注:文中部分配图来自网络,如有侵权,请联系我们删除。</p>
从GFS到GPT,AI Infra的激荡20年
https://segmentfault.com/a/1190000043796554
2023-05-17T11:12:05+08:00
2023-05-17T11:12:05+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<h3><strong>导读</strong></h3><p>最近AIGC和LLM的浪潮层层迭起,大有把AI行业过去十年画的饼,一夜之间完全变现的势头。而 <strong>AI Infra</strong> (构建AI所需的基础设施),也成了讨论的焦点之一。大众对AI Infra的关注点,往往放在AI算力上——比如A100/H100的芯片封锁;比如马斯克又买了一万张GPU,等等。</p><p>算力无疑是AI浪潮中至关重要的一环,然而AI Infra并不只与算力相关。冰冻三尺非一日之寒,正如GPT并不是突然的成功一样,AI Infra行业其实也经历了漫长的积累与迭代。笔者最近跟同事、朋友不断地在讨论AI的各种发展,每每聊到AI Infra,心里总会涌出千言万语却又难以言表,于是今天决定动手把想说的都写下来。</p><p>如标题所说,整个AI的发展离不开大数据,而大数据的开端,自然是谷歌的三大件:Google File System、MapReduce和BigTable。其中GFS论文发表于2003年,距今刚好整整20年。这20年,也是大数据、AI、互联网发展突飞猛进的20年。</p><p><strong>本文试图去梳理这20年间AI Infra的一个个里程碑事件</strong> 。因为当我们身处其中时,往往分不清炒作与干货,也看不清局部领先和最终取胜的架构之争。只有当回顾历史,观察长周期的变革时,一些规律才会涌现。话不多说,让我们就此开始!</p><p><strong>目录索引</strong></p><p>【2003/2004年】【框架】:Google File System & MapReduce</p><p>【2005年】【数据】:Amazon Mechanical Turk</p><p>【2007年】【算力】:CUDA 1.0</p><p>【2012/2014年】【研发工具】:Conda/Jupyter</p><p>【小结】</p><p>【2012年】【框架】:Spark</p><p>【2013/2015/2016年】【框架】:Caffe/Tensorflow/Pytorch</p><p>【2014年】【框架/算力/研发工具】:Parameter Server & Production Level Deep learning</p><p>【2017年】【算力】:TVM/XLA</p><p>【2020年】【数据/算力】:Tesla FSD</p><p>【2022年】【数据】:Unreal Engine 5.0</p><p>【2022年】【数据/研发工具】:HuggingFace融资1亿美元</p><p>【当下】OpenAI有什么AI Infra?</p><p>【结语】</p><hr><p><strong>【2003/2004年】【框架】:Google File System & MapReduce</strong></p><p>2003年谷歌发布的GFS论文,可谓是掀开了这场20年大戏的序幕,宣告人类社会正式进入互联网大数据的时代。一个小插曲是谷歌虽然开放了论文,却没有开源实现,导致后来的Apache Hadoop以「一言难尽」的性能占领了开源生态(也为Spark日后横空出世埋下伏笔),而开源社区爆发式的发展想必也影响了后来谷歌对开源系统的态度。</p><p>GFS和MapReduce可以说是开启了分布式计算的时代,同时也在传统单机操作系统、编译器、数据库这些领域之外,让「 <strong>Infrastructure</strong> 」这个词开始逐步深入人心。关于GFS这里不多说,重点想讨论下 <strong>MapReduce的「问题和缺点」</strong> 。不知道有没有人在第一次学习MapReduce编程模式后,也跟笔者一样在心里犯嘀咕:这个Map和Reduce是有什么特殊之处嘛?为什么是它们而不是别的接口?为啥一定要用这个范式编程呢?是倒排索引必须用MR才能建么?种种疑问即便是后来通读了Paper也未能完全理解。</p><p>而且后来发现,吐槽的还不止笔者一个。2008年,当时还没获得图灵奖的数据库大牛Michael Stonebraker 就撰文狠批《MapReduce: A major step backwards》,还直接点名批评西海岸某学校:“Berkeley has gone so far as to plan on teaching their freshman how to program using the MapReduce framework.” 。而Stonebraker教授主要抨击的点,便是MR缺失了传统数据库的一大堆Feature,尤其是Schema & 高阶SQL语言、Indexing查询加速等等。咱阿里的同学看到这想必心里乐了:“嘿嘿,您老说的这些Feature,咱MaxCompute的湖仓一体/SQL查询/自动加速,现在全都有啦!MR也可以棒棒滴”。</p><p>不过这已经是现代了,让我们先回到2004年,看看为什么在没有日后这些高级Feature的情况下,谷歌依然要推出MapReduce并定义了整个开源大数据生态的模式。这里想说是:「 <strong>了解成功架构的缺点,才能真正理解其优点到底带来多大的收益,以至于可以抹杀掉所有的不足</strong> 」。MapReduce并不见得是一个好的编程范式(后来的发展也证明有各种更好的范式),它让算法实现变得复杂&教条,它只能实现很少一部分算法,它的性能可能比原问题的最优实现差之甚远。但是它在2004年的时候,让普通程序员使用大规模分布式计算变得非常简单!不需要了解Mpi,不需要了解分布式通信同步原理,写完Mapper和Reducer,你就能在上千台服务器的集群上运行程序,关键是还不用担心出现机器故障等等各种异常问题。</p><p><strong>归根结底,MapReduce是一个妥协</strong></p><p>MR牺牲了灵活性,牺牲了性能,却让用户获得了稳定可靠的分布式计算能力。而各种各样的「妥协」,在后面一代代的AI Infra中,已然就是主旋律。不过我们也能惊喜地看到,随着现代工程技术的发展,在灵活性、性能、稳定性三个维度均得高分的系统比比皆是。当然,新的妥协点依旧会存在,这也是AI Infra或者说Large-Scale Computer System这个领域令人着迷的原因之一。</p><p>关于GFS和MR要说的还有最后一点,那便是「 <strong>面向Workload的设计</strong> 」,谷歌在论文里也说了,整个大数据系统的设计与他们的搜索引擎业务息息相关:文件系统只会Append写而不会删除,读取主要是顺序读而不是随机读,需要MR的任务也以扫库建索引为主。而传统数据库、文件系统对于其他通用需求的支持,必然也导致它们在大数据处理这个任务下,不会是最优解。</p><p>好了,读到这有读者可能会问,光一个20年前的GFS你就讲这么多,我关心的GPT在哪里?怎么才能造出GPT?别急,太阳底下无新事,20年前对框架的设计思考,与最新的AI Infra相比未必有什么本质不同。</p><p><strong>【2005年】【数据】:Amazon Mechanical Turk</strong></p><p>时间来到2005,让我们从系统领域抽出来,看看AMT给世界带来了什么样的惊喜。其实Web1.0刚开始的时候,也是互联网泡沫期嘛,可能跟咱们现在的感觉也差不多,整个社会在一个癫狂的状态。也不知道是谁在亚马逊突发奇想,基于互联网搞了这么个众包平台,但这可乐坏了在学校研究所里依靠学生、人工招募对象来标注数据的老师们。于是乎,Stanford的Fei-Fei Li团队,开始基于AMT来标注了CV有史以来最大的一个Image Classification数据集:ImageNet,并从2010年开始举办比赛,最终在2012年AlexNet技惊四座,引发了第一次深度学习革命。</p><p>关于AMT和ImageNet这里想说3个点:</p><p>1.事后看关于「数据」方面的历次革命,特点就很明显了,每一次要么是极大地降低了获取数据标注的成本,要么是极大地提高了数据的规模量。正是AMT或者说互联网,让人类第一次可以很方便地,为了研究AI而大规模地获取标注数据。而到了2023年的LLM,大家对这个问题其实也想得很清楚了:『 <strong>原来根本不用什么众包平台,每个在互联网上说过话的人,以及之前写过书的古人,其实都是在帮AI标数据</strong> 』。</p><p>2.很多同学不知道为什么ImageNet有个Net,或者以为ImageNet的Net和AlexNet的Net一样都指神经网络,其实根本不是。这里可以参考ImageNet的原始论文,主要是因为之前有另一个项目WordNet,是类似知识图谱或者大词典的一个工作,将各种范畴和概念都进行了记录和网状关联。ImageNet在WordNet的基础上,选择性地构造了1000类物体类别,对视觉分类任务进行了设计。从现代来看,这叫图文多模态,但其实这是很早就有的一个范式:「 <strong>借用NLP的Taxonomy,对CV的分类任务进行定义</strong> 」。</p><p>3.Fei-Fei Li有很多非常有意思的CV论文,Citation量一般都不高,因为其切入点经常与众不同。另外Fei-Fei Li的高徒Andrej Karpathy想必大家都非常熟悉,虽然AK的论文大家倒是不一定记得(甚至不知道他也在ImageNet的author list里),但AK的博客和Github却是有极高的影响力,从最早的《Hacker's guide to Neural Networks》到最近的nanoGPT,而且AK的博士论文题目就是:《Connecting Images and Natural Language》</p><p><strong>【2007年】【算力】:CUDA 1.0</strong></p><p>2007年,当游戏玩家们还在纠结买啥显卡能跑孤岛危机时,NVIDIA悄然发布了第一代CUDA。之所以用悄然一词,是因为估计当时没激起什么水花。因为几年后笔者听到做图像处理的师兄对CUDA的评价无一例外都是:「 <strong>真难用</strong> 」。是啊,毕竟已经被编译器和高级语言惯坏了这么多年了,突然跟你说写个程序还得思考GPU硬件是怎么运行的,还得手动管理高速缓存,稍微一不注意程序反而会变得死慢死慢,谁能喜欢得起来呢?而且更要命的是CUDA的浮点数精度问题。当年笔者第一次用CUDA,兴冲冲写完一个矩阵乘法后,一对比发现,咦?怎么结果差这么多,难道哪里写错了?排查半天无果,毕竟「 <strong>用CPU的时候,结果有错从来都是我的错不会是硬件的错</strong> 」。后来经同学指点,原来是CUDA的浮点数精度不够,需要用上Kahan Summation.就是下面这段代码:</p><pre><code>
float kahanSum(vector<float> nums) {
float sum = 0.0f;
float c = 0.0f;
for (auto num : nums) {
float y = num - c;
float t = sum + y;
c = (t - sum) - y;
sum = t;
}
return sum;
}</code></pre><p>加上后结果就神奇地对了。而如今每天用着V100/A100,然后吐槽NPU/PPU这不好那不能适配的同学可能未必知道,当年CUDA刚推广的时候,也好不到哪里去。尤其在高性能计算领域,由于大客户都是各种跑偏微分方程的科研机构,常年使用科学家们写的上古Fortran代码,而硬件上从来都是CPU双精度浮点数保平安。所以相当长一段时间,CUDA压根不在考虑范围内。Intel在高性能领域也成为绝对的霸主。</p><p>另外,在此还要介绍一位曾经被Intel寄予厚望的主角: <strong>Xeon Phi。</strong> Xeon Phi芯片最早发布于2010年,就是为了对抗CUDA而研发的众核架构。笔者在13年参加ASC超算比赛时,当年Intel免费赞助了一大批Phi并直接出了一道题让大家试用Phi。大家用完的体感嘛......方便是真方便,毕竟主打的是编译器包办所有事情,原有的高性能分布式代码一行不用改,直接适配众核架构。这也是Intel一直以来做CISC架构CPU和编译器的思路:「 <strong>底层实现复杂的指令集,编译器完成所有转译和优化</strong> 」,上层用户完全无感,每年付费即可享受摩尔定律的红利(值得一提的是,Intel的Icc高性能编译器和MKL库都是要额外付费的)。可惜的是,Phi的目标和愿景虽然很美好,但它的编译器和众核架构没有做到标称所说的,一键切换后,性能得到极大提升。Phi项目始终没有积累大量用户,也在2020最终关停。</p><p>另一方面,CUDA却取得了节节胜利:人们发现,写SIMD模式的高性能应用时,CUDA其实比CPU更好用。原因恰恰是「 <strong>编译器做得少</strong> 」。写CUDA时,所写即所得,不用再像写CPU高性能应用那样,时常需要编译出汇编码去检查向量化有没有生效、循环展开对不对。由于无法对CPU Cache进行直接管理,更是只能靠经验和实测来了解当前Cache的分配情况。这里也引出一个问题:「 <strong>编译器和语言设计一定要满足所有人的需求么?</strong> 」想必不是的,找准这个语言的真正用户(高性能工程师)可能才是关键。</p><p>而与本文最相关的是,CUDA找到了AI这样一个神奇的客户。说它神奇,因为AI算法真的要让《数值分析》的老师拍案叫绝,让《凸优化》老师吐血。为什么呢?这么大规模的一个数值计算应用,居然说「 <strong>精度不重要</strong> 」,而且「 <strong>全是CUDA最擅长的基本矩阵运算</strong> 」。机器学习不需要双精度,直接单精度浮点数搞定,甚至在推理时连单精度都嫌多,半精度、int8、int4都能用。而在优化角度,也是打破了凸优化的所有传统认知:一个非凸优化问题,传统各种算法通通不需要。而且搞全量数据优化反而效果不好,SGD的mini-batch虽然会自带噪音,但噪音反而对训练有益。于是乎,GPU另一个软肋:显存受限,在mini-batch的算法下,也变得不是问题了。</p><p>总之,CUDA和GPU似乎就是为AI而生,缺点最终全变成了Feature,也让老黄变成了厨房霸主,核弹之王。而目前集举国之力攻坚自研芯片的我们也不要忘了,CUDA发布这16年以来,除了底层的芯片之外,软件层工具链和用户习惯用户生态是怎样从0到1一步步演进的。GPU未来是不是一定就一家独大?TPU/NPU/PPU会不会弯道超车?让我们静观其变。</p><p><strong>【2012/2014年】【研发工具】:Conda/Jupyter</strong></p><p>聊完了框架、数据和算力,我们再来看看AI的研发工具是什么情况。而这里不得不讨论的问题便是:为什么AI的主流语言是Python?其实,不只是AI,Python的普及率本来就在逐年上升。开源社区很早就发现为一个项目提供Python接口后,用户使用量会大增,而且大家更倾向于使用Python接口。究其原因,无需编译的动态脚本语言的魅力实在是太大了。在这里无需多言,毕竟大家都知道:</p><p><strong>人生苦短,我用Python</strong></p><p>而Python的生态本身也在不断的完善,基于Pip的包管理本来就很方便,2012年推出Conda之后,更是让「 <strong>虚拟环境管理</strong> 」变得极为容易。要知道,对于一个频繁需要复用开源软件包的开发领域,这绝对是一个Killer Feature。</p><p>除了包管理,Python的另一大突破便是基于IPython的Jupyter 。它把Python本来就好用的交互功能提升到了新的标杆,并且打造了大家喜闻乐见的Jupyter Notebook。至于说Notebook算不算AI Infra,看看谷歌的Colab,看看目前各种AI开源项目的导引教程、以及咱们自己的PAI-DSW就能知道,Notebook已经是AI研发和知识分享中不可或缺的一环。其隔离后端集群的Web端的研发体验,让用户一站式操控海量算力资源,再也不用只能用Vim或是远程同步代码了。</p><p>而对于笔者来说,写Data相关Python实验代码的第一选择也早已不是IDE,而是Jupyter Notebook.原因很简单:处理图像、Dataframe、Json这样的数据,并且需要频繁「 <strong>迭代不同的算法策略</strong> 」时,「 <strong>代码怎么写取决于其内在数据格式和前面的算法结果</strong> 」。而数据和算法结果都是在运行时才能看到其具体形式,所以,「 <strong>一边运行代码一边写代码</strong> 」是数据处理、AI算法工程师的家常便饭。很多不理解这一点的Infra工程师,设计出来的框架或者工具,难免让人一言难尽。后面我们也会看到,在交互性和动态性上开倒车的Tensorflow,用户也在一点点的流失。</p><p><strong>【小结】</strong></p><p>通过前面这4个板块代表性工作的介绍,我们不难看到AI Infra全貌的雏形:</p><ol><li><strong>算力</strong> :需要强大的CPU/GPU为各种数值计算任务提供算力支持,同时编译器需要为高性能工程师提供良好的编程接口。</li><li><strong>框架</strong> :针对特定的Workload抽象出一个既有通用性,又满足一定约束的编程范式。使得执行引擎可以一站式提供诸如分布式计算、容灾容错、以及各种运维监控的能力。</li><li><strong>研发工具</strong> :AI和数据算法研发期望在代码编写时是能实时交互反馈的;开源社区要求代码和其他生产资料能够被很容易地打包、发布、集成、以及版本管理。</li><li><strong>数据</strong> :需要一个提供AI训练所需海量数据的工具或模式。</li></ol><p>带着这些思路,其实就很容易能看清后来AI Infra发展的基本脉络了,让我们继续来看看。</p><p><strong>【2012年】【框架】:Spark</strong></p><p>还是2012年,这一年Berkeley的Matei Zaharia发表了著名的Resilient Distributed Datasets 论文,并且开源了Spark框架。Spark彻底改变了Hadoop生态「慢」和「难用」的问题,借助Scala和Pyspark/Spark SQL的普及,将很多编程语言领域的最新进展引入了大数据开源社区。其实目前来看,RDD是不是In Memory可能都不是最重要的,毕竟大部分Job并不是Iterative的。但是,光是借助Scala interactive shell实现的Spark shell,对于动辄启动任务就要分钟级别的Hadoop,本身就是颠覆性的(想想你告诉一个天天写Java based MR接口的同学,你现在可以在Python命令行里搞大数据计算了是什么感受)。更别提Scala的各种语法糖,以及对海量算子的支持了。</p><p>总而言之: <strong>Spark 用Scala、Python、SQL语言的极好交互式体验对笨重的Java实现了降维打击,并提供了更优的系统性能。</strong> 而人们也看到,只要「 <strong>用户体验</strong> 」足够好,即便是一个成熟的开源生态也是可以被颠覆的。开源大数据生态也因此进入了百花齐放的阶段。</p><p><strong>【2013/2015/2016年】【框架】:Caffe/Tensorflow/Pytorch</strong></p><p>2013年,最接近大众认为的AI Infra工作来啦。那就是贾扬清大牛开源的Caffe,自此Deep Learning的门槛被大大降低,通过模型配置文件,就能搭建网络,完成训练,利用GPU的算力。一时间模型创新开启了大爆发时代。其实同一时期开源框架还有Theano,以及基于Lua的Torch,不过使用方式各有差异。随后,大公司纷纷入局,谷歌和FB分别在15和16年发布了Tensorflow和PyTorch,再加上日后Amazon背书的MxNet,以及百度的<a href="https://link.segmentfault.com/?enc=5L7BBVkI7ZdHvvj%2BchDL7A%3D%3D.oCuVzcFEAfR5rrVaJRnoC5XmM%2FaPS8%2FJLOw6bSOP6ptkQQp6WBrlntJaUFq59AtF" rel="nofollow">PaddlePaddle</a>,机器学习框架迎来了百家争鸣的时代。关于机器学习框架可以讨论的点太多了,公开的资料也很多,这里只讨论其中的两个点:</p><p>一个是从框架设计方面的「 <strong>Symbolic vs. Imperative</strong> 」。这个讨论最早可以追溯到MxNet的技术博客 Deep Learning Programming Paradigm 。而MxNet也是最早两种模式均支持的框架,并在博客里点明了:Imperative更灵活易用,Symbolic性能更好。再看看其他框架早期的版本,则专一到其中一种范式:Tensorflow是Symbolic,PyTorch是Imperative。而后面的事情大家也都知道了,Pytorch完整继承了Python语言的优点,一向以灵活、适合科研使用著称;TF则在工程化部署时更友好,但牺牲了交互性。而后经过漫长的迭代,两种范式也基本走向了融合。TF也支持Eager模式,后面还直接推出了新框架Jax;Pytorch也可以把Symbolic Graph进行导出和操作,比如TorchScript、Torch.fx。如同MapReduce是一种妥协,各个机器学习框架也都在「 <strong>易用性</strong> 」和「 <strong>性能</strong> 」上做着某种妥协。但整体看,主打Imperative,保持与Python使用习惯吻合的Pytorch还是在用户量上逐渐占据上峰。当然,现在下任何结论都还为时尚早。机器学习框架的发展和迭代远没有结束。</p><p>另一个可讨论的点是「 <strong>机器学习框架演进和算法演进</strong> 」之间的关系,之所以要讨论这个点,是因为很多算法研发团队和工程框架团队习惯于甲方乙方的工作模式。把框架研发和框架升级理解为:算法科学家为了实现某个模型或者想法,发现现有框架无法支持,于是给工程团队提一些关于算子Op实现、新的分布式计算范式、性能优化方面的新需求。这样的模式有很多弊端,比如只能支持局部的小创新,而且创新的周期可能会很长,甚至会出现经常被工程团队吐槽的:「 <strong>上一个需求还没实现完,算法侧又换了新想法</strong> 」。所以如何打磨好算法团队和工程团队的协作模式,是很重要的课题:比如 <strong>Co-Design</strong> 的方法论,双方都要换位思考,提前预判技术路径。比如工程团队不能把日常工作变成帮科学家实现功能代码,而是要提供一个灵活的上层接口让科学家自行探索,框架层重点解决卡脖子的工程技术问题。而且最重要的是:双方一定要意识到:「 <strong>目前的模型结构和框架实现,可能只是历史演讲过程中的一个偶然</strong> 」,而「 <strong>模型设计和框架实现,会不断地互相影响着对方的演进路线</strong> 」</p><p><img src="/img/remote/1460000043796556" alt="" title=""></p><p></p><p>原因也很简单,在模型创新最前沿,有一个鸡生蛋蛋生鸡的问题:算法科学家只能实现并验证那些现有框架能实现的Idea,而框架支持的功能,往往又都是以往成功过的算法架构或是科学家提出了明确需求的架构。那么 <strong>真正的系统级创新如何发生呢</strong> ?可能还真回到了阿里的老话:</p><p><strong>因为相信,所以看见</strong></p><p>此外,算法与框架的共生关系,近年来也引发了大量的讨论。比如最近讨论比较多的,LLM为什么是Decoder Only架构?还有《The Hardware Lottery》一文里提出的 “ <em>A research idea wins because it is suited to the available software and hardware</em> ”。</p><p>总而言之,对于机器学习框架而言,「框架」的意义早已超出了MapReduce/Spark这种大数据框架帮助工程师实现各种Data ETL功能的范畴。因为算法、模型的形态本身就是在变化在革新的,框架如果限制过死,就反而会制约算法的迭代和创新。</p><p><strong>【2014年】【框架/算力/研发工具】:Parameter Server & Production Level Deep Learning</strong></p><p>开源社区的框架引发了AI的新浪潮,而在互联网大厂的搜推广业务里,大家也开始琢磨,Deep Learning的成功是否能在传统Ctr算法中复现呢?答案是肯定的!基本上所有大厂都开始了相关的研发。这里打个广告,以笔者熟悉的阿里妈妈展示广告业务线为例,从2013年的 <a href="https://link.segmentfault.com/?enc=AAzzpo7%2FcPUb3wkdGgXoGA%3D%3D.HKtH613TEKD5HV7ao0j0R0k7C7ZxAAxbLarP0mPTAF3WSODvw7TiRzTfJtzw9X6ASmlUFKzvrQNMCEWgEiPaL49GV73awiqa2IEDvW%2FOxJ2FCrbRHbxPxbmuTRXiKIaufhqx0fcTOPkpsWKf8%2FnkkgqdJp2C8tOITcvp8AwQAVwtAnNWLPldqHc2sUzQevqM" rel="nofollow">MLR</a> ,再到后来的大规模分布式训练框架 <a href="https://link.segmentfault.com/?enc=Q15wzsUSREcI%2B7F27yxrtw%3D%3D.PypLfKz1ViF50PiIQfmHgc0U%2BQi4pReYeum1PGLFeChs1zq7muvsC1NbFO59c0ors5xXfMrk9lkrx4lw2Xk4YPiVpzpIbjuMshG4KLO6OWHpYkpfnGZGM4fAq3to56%2BvT7949WpHfvxJsmk0110%2BM57F%2BFFR7JO4A6PHO2ZsR6uZPCOAbQTcuBI5dKQTy8sL" rel="nofollow">XDL</a> ,再到 <a href="https://link.segmentfault.com/?enc=QNa1R4gykIoRbrGiRWpUSg%3D%3D.cTn9n2WN2sHkO07xK68gqWucjSkf69f6dYbl%2FC3PgN5rn6T6pjCnZqlb%2BEBHdFTbSZFxE4VMrKHXRGTBxiUREjJFaBJJOyZLwmRFB4uLQyRA1djAvv%2FzQSYcxz4%2Fl9pT97XvEAKggfDF4W4UpRVQF8kIzn8pHldWbhuhYYBiWOFp8WvzouQn4uUslg35RJh%2B" rel="nofollow">DIN</a> 和 <a href="https://link.segmentfault.com/?enc=2xgstE7KYC5qpzuGHcWbsA%3D%3D.c1X%2BZv8A1MgWIzwv%2Blm8ndoHXbY8d9CvaGuUYbza1J08BdBw%2BKOUJ%2B25Wi5d5At1UTmg1pHKmai70H33YCS%2BB6LhbKGqTo7whNxWMMoeuaMtCAPzMNATFBqsCvbGxA8USfcR3aZjtQsMWZB5qVN7u9AY9QVNhsHToRDE0%2FHWT2kVjrSXUC0debv9EpJQx0FQ" rel="nofollow">STAR</a> ,搜推广的同学们应该都非常了解了。开源框架不支持大规模Embedding Table和靠谱的分布式训练,这也让自研的类Parameter Server框架迎来了发展空间。大规模分布式训练的框架也成为了这几年搜推广算法迭代的主要推手。而与上文说的一样,在模型高频迭代,大促提效常态化的背景下,算法创新和框架演进是一个复杂的共生关系,这里也推荐大家看看怀人老师写的 <a href="https://link.segmentfault.com/?enc=hCB1mv1HTm9wVGeRE9vG2w%3D%3D.Kq4oO%2BmBf7HMK6Wes2eCH%2BTZ0THFZQPJyIdo7V3WZgC0cueOghgjMOysQPVmloNdLP%2BnRkakxxhRTL%2F%2F7Dzrj5yvvc%2FqZ1yzVJi8nq9seVmzKNkYEH4bt0UDx9tQsYnHBSUECG1cQ7yoHGiAPfxUUky4HK6aeehJaIQ%2Bzuosl%2F%2FFx6fl8SOfLOnDJ9mcL1W5" rel="nofollow">广告推荐技术发展周期</a> ,完整描述了整个算法架构的演进历程。</p><p>另一方面,训练引擎仅仅只是整个搜推广算法工程化的冰山一角。模型推理引擎,实时数据流,ABTest实验平台,容器调度平台等等都需要一整套完整的Infrastrature,这里写得最详细的当然是五福老师的 <a href="https://link.segmentfault.com/?enc=d7x7EE2m%2Fz1c%2BhB8TqIStw%3D%3D.0io8%2BSdrNwDVmJxwfiAZWNWSbaRpkefmoDYQuFuJJJ8TKYHFS14nkOqZFs1%2BF8eMebJEIQ3XfPbruSF8vsNB3q3F%2FIMGTHHyCtBzjt3b0VnYdRx3BLoOUS0koHIPTI1QlGmWJPJN9BvAAthwR6L7DaHJSj4JFtO5nHAfltLx0hBfLoTavVKvRoctJ218iv80" rel="nofollow">AI OS综述</a> 。笔者也在下图大致梳理了在工业级机器学习应用中,面临的一些常见问题。</p><p><img src="/img/remote/1460000043796557" alt="" title=""></p><p>在这里不得不说,搜推广的Ctr模型,由于与互联网业务、营收高度相关,一直是大厂里的技术高地。经过无数人日积月累的不断打磨,可以说是把 <strong>y = f(x)</strong> 这个学习范式的每个细节都做到了极致,上图的每个小框都值得10+篇技术分享。而在GPT时代LLM、半监督学习范式以及未来前景广阔的AI应用中,阿里在这一块的积累一定可以得到迁移和复用,继续发光发热。</p><p><strong>【2017年】【算力】:TVM/XLA</strong></p><p>时间到了2017年,TVM和XLA都在这一年发布,而AI编译器这个话题也值得我们单独讨论一下。与机器学习框架主要解决易用性问题不同,AI编译器重点解决的是性能优化、计算芯片最优适配的问题。一般通过对单算子的底层计算代码生成,或是对计算图的重组和融合,来提升模型推理的性能。在芯片断供、自研芯片百花齐放的当下,AI编译器也成了目前AI Infra发展最为迅猛的领域之一。阿里PAI团队的杨军老师也写过关于AI编译器的综述。</p><p>既然是编译器,则又会出现我们前文所说的,编译器用户是谁以及接口约定的问题。此外还有通用编译优化 vs. 专有编译优化的问题。比如搜推广业务,由于其模型结构的特殊性,往往就会自建专有编译优化,专门总结出某些优化Pattern以支撑模型迭代带来的海量推理算力需求。而通用的编译优化算法,其实很难将这些特定的Pattern抽象整合到优化规则中去。</p><p>另一方面,AI编译器的图优化算法往往对普通算法同学不太友好,原因在于很可能稍微对模型进行一些改动,就会导致原有优化规则无法命中。而无法命中的原因,往往也不会给出提示。这就又回到了前文所说的CPU高性能编译器的问题,虽然编译器看似很强大很通用,可以隐藏硬件细节。但 <strong>实际能写出高性能代码的用户,一般还是需要对硬件的底层逻辑有充分的了解</strong> ,并且了解编译器的实现逻辑以进行检查和验证。</p><p>所以AI编译器到底是像torch.compile那样帮助小白用户一键提升性能,还是仅作为一个自动化工具,为具备底层认知的高性能模型工程师提高研发效率呢?目前来看两者均有,比如OpenAI也在2021年发布了Triton,可以用Python的语法更加方便地进行类CUDA GPU编程。像Triton这样的工作就是既需要程序员大致了解GPU多线程模型的原理,又大幅降低了入门门槛。而TVM也同样在不断升级,比如可以看看天奇大神写的 <a href="https://link.segmentfault.com/?enc=HnIy6Cz9rhq1hPoCmJ5OwA%3D%3D.TRquYHynlEA7E4juIszcB9HQBh6zyhwbl48r9GMba8VWvgZfQLCh9uvuq14hG%2F7qjVcQT9373Kg1dmAVFjkFPezvaQoH2VTUy%2B6%2B9bft46jjzpgTrQ1FMfzjax%2FpF0EBJ%2BhHBxswxWIp5mpZmaKSbmDa1mRBdWHPO2KF2NfplK0czHrHav8Zn9TOf6Ek09yv" rel="nofollow">《新一代深度学习编译技术变革和展望》</a> 。未来的AI编译器会如何发展,让我们拭目以待!</p><p><strong>【2020年】【数据/算力】:Tesla FSD</strong></p><p>时间来到21世纪的第三个10年,此时公众感知到的AI领域稍微会有点沉闷。因为上一波AlphaGo带起的RL革命还没有在实际场景中取得大量收益,L4无人驾驶也陷入瓶颈,其他AI之前画的饼都还在纸上。搜推广的工程架构也从3.0做到了4.0再到5.0,6.0,7.0......</p><p>正当大家还在思考,AI有什么搞头时,这一年Andrej Karpathy带队的的Tesla突然放了大招,发布了纯视觉架构的Full Self-Driving无人驾驶方案,还直接在随后每年的Tesla AI Day上公布完整的技术方案:BEV感知、数据闭环Data Engine、端上FSD芯片,云端Dojo超大规模训练引擎等。一石激起千层浪,Tesla一下改变了行业的认知,在国内大部分自动驾驶公司的PR稿里,都能看到其影子。</p><p><img src="/img/remote/1460000043796558" alt="" title=""></p><p></p><p><img src="/img/remote/1460000043796559" alt="" title=""></p><p><img src="/img/remote/1460000043796560" alt="" title=""></p><p>配图来自Tesla AI day</p><p>可以说,Tesla把监督学习的工程架构又拔到了一个新高度:大规模的半自动标注引擎、大规模的主动难例数据收集、大规模的分布式训练和模型验证,底层的AI Infra支撑着几十个感知规控模型的持续迭代。</p><p><strong>【2022年】【数据】:Unreal Engine 5</strong></p><p>时间来到2022年4月,ChatGPT还有8个月到达战场,而这个月UE5正式发布。关注的同学想必都知道,效果那是无比的惊艳:Nanite的超大规模三角面片实时渲染,Lumen的动态全局光照。在官方DEMO《The Matrix Awakens》里我们也能看到现今实时渲染到底能做到什么水平。</p><p><img src="/img/remote/1460000043796561" alt="" title=""></p><p>配图来自Unreal Engine官网</p><p>那UE 5是不是AI Infra呢?答案也是肯定的。首先,基于UE4的各种开源仿真渲染工具比如AirSim,CARLA早就在无人机、无人驾驶上被大规模用来生成训练数据。而在GTA里面训练无人车,在MuJoCo训练小人跑步(MuJoCo已在2021年被Deepmind收购)也都不是新鲜事了。UE5如此革命性的更新,外加整个材质构建、3D模型产线的发展,也必然会让实时渲染仿真的效果一步步逼近真实的物理世界。</p><p>恩,DeepMind + MuJoCo + UE5会不会在未来某天放大招?让我们拭目以待。</p><p><strong>【2022年】【数据/研发工具】:HuggingFace融资1亿美元</strong></p><p><img src="/img/remote/1460000043796562" alt="" title=""></p><p>关注AI、GPT的同学最近肯定经常看到这个笑脸,可是Hugging Face到底做了什么,为什么也能成为AI Infra的关键一环并在2022年成功融资一个亿呢?如果你知道OpenCrawl、Pile、Bigscience、Bigcode、PubMed这些项目,那你一定也是在研究LLM训练数据的老兄。而你会惊奇地发现,原来很多语料库数据,都已经被整理好放在Hugging Face上了。他们还整了个Python包,名字就叫Datasets!</p><p>不知不觉中,Hugging Face已经成为了AI(至少NLP)领域的Github for Data & Model。看到这里有同学要问了,搞了这么多年AI的人脸识别、搜推广、自动驾驶公司,从来都说数据就是最强壁垒,没听说过谁家会把最珍贵的数据和模型开源放到网上呀。但事情到了LLM、到了GPT这,却发生了本质性的改观。目前多模态大模型使用的这些数据,天然就是存在于互联网上的,本身就是Open的,获取比较容易(版权问题除外)。所以现在的模式变成了大家一点点地帮忙收集、整理数据,最终制作出了大量高质量的原始语料库(比如LAION组织的创始人就是一位 <a href="https://link.segmentfault.com/?enc=tvCfTskqpTkqb452TtrxWw%3D%3D.Ilx1f7iJmYM0Rn%2BjbdUywwghtglwHsy6mIxSApwFa%2FMZU4m5es7kWQN9Dxa7Z4RgXPf547s84XnfEGL8khb3uqy208gnoVbB2NmD59FVDEY%2BbD5GuJzaoaIrg06lq%2Fp%2FXlj0Ls2v5%2Fp%2BofkPCIqYM0riKWz0Ai6piY1Kb7oOAIUsyn5F9IqTbO%2FNxkeJ4brr" rel="nofollow">高中老师</a> )。</p><p>其实对于LLM和AGI,未来很可能是这样格局:数据 + 算力 + 算法这个传统AI三要素中,数据由于开源可能反而不是唯一壁垒了,在有芯片硬件的大厂里,最后比拼的就是算法和基于AI Infra打造的迭代速度了!</p><p><strong>【当下】:OpenAI有什么AI Infra?</strong></p><p>那么,AI Infra对于打造GPT有什么帮助呢?从OpenAI被公开的 <a href="https://link.segmentfault.com/?enc=p37PZsCeJliHPFX%2BKFVXLw%3D%3D.5UpQDH4ZtdrhmuZj60fbUkjSFwjYcEW8WKRUvIOl%2BXD01bMnt17Sb29x51dCx7tG33nUqQgncA1Vnkwus4WU8BmLs9KGIoINzTsr1Ts7BsYGaCTEYteyc2vXGkS%2Fs1wu8D76jBmmUFqyLT%2BaVmqszX01J%2F8Nb1gRy27f2JZiEg2NEST6IBfli4SdZJJkC8Yj" rel="nofollow">架构</a> 来看,上文提到的方方面面基本都有涉及。而在Compute和Software-Engineering两Topic下,也可以看到OpenAI自己发表的大量关于AI Infra的博客。其中很多是在算力-算法Co-Design的方向。比如在2021年初,OpenAI管理的K8S集群达到了7500个节点的规模(4年前是2500节点)。而后在21年7月份开源了前面提到的Trition,一个能用Python语法实现GPU高性能编程的编译器。22年的时候也花很大的篇幅介绍了他们进行大规模分布式训练的技巧。</p><p>不难看出,最大限度地让算法研发用上用好海量的算力资源,是OpenAI Infra的头号目的。另一方面,从AI and Compute和AI and Efficiency两篇文章中能看到,OpenAI花了不少精力在分析随着时间的演进,最强模型所需算力的增量曲线,以及由于算法改进而导致的算力效率变化曲线。而类似这样的分析,也在GPT-4的 <strong>Predictable scaling</strong> 中得到了体现。也就是说,给定训练算法, <strong>所消耗的算力与所能达到的智能程度是可被预测的</strong> 。这种「 <strong>算力算法Co-Design</strong> 」的指标就能很好地去指导算法研发 vs. 工程架构升级的节奏和方向。</p><p>除了算力这条线,AI开源社区的进展也是日新月异,想必很多也为GPT的出现做出了贡献。除了Hugging Face,还有很多值得称道的AI创业公司不断涌现,在此笔者还来不及去细细分析各家公司的工作和意义。但变革已然在不断发生,新事物的出现速度已然是以周为单位。</p><p><strong>【结语】</strong></p><p>最近几个月AI的发展速度,确实远超笔者之前的认知。毫无疑问,AI2.0的时代已经到来,上一代基于纯监督学习的范式已然不够用。AI画的饼大家也都吃进了嘴里,而且真香!作为AI从业者,过去几个月也让笔者心潮澎湃。虽然看完了本文,你还是无法做出GPT,但想必你也看到了AI Infra这20年的发展。无论未来AI算法往哪走, <strong>底层的算力层和底层的系统依然会是算法研发的基石</strong> 。</p><p>回望这20年的发展,从03年到13年这十年是Web1.0的时代,笔者还是个孩子;13~23年笔者全程目睹了AI1.0和Web2.0的发展浪潮,但更多时候也只是个吃瓜群众。而未来的十年,自然是AI2.0和Web3.0革命性的十年,笔者完全无法想象10年后的今天,世界会是什么样的样子。但唯一确定的是,这一次终于可以完整参与其中,跟志同道合的小伙伴们一起做出能影响行业的事情!</p><p>话都说到这里了,不发广告怎么行呢?我们是 <strong>高德视觉技术中心的训练工程平台团队</strong> ,负责支持数据闭环、大规模训练、算法服务化等各种算法工程化需求。我们力求在AI2.0时代打造有技术差异性的 <strong>端云协同一体AI Infra</strong> ,一方面会复用集团和阿里云大量的中间件,一方面会自建很多专用AI工具链。而 <strong>高德视觉,目前也成为了集团最大的视觉算法团队之一,支持高精地图、车道级导航、智能出行等多种业务</strong> ,涉及感知识别、视觉定位、三维重建和渲染等多个技术栈。</p>
【定位不准的烦心事系列】第2篇:卫星信号弱到底是咋回事
https://segmentfault.com/a/1190000041483506
2022-03-02T14:25:38+08:00
2022-03-02T14:25:38+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>对于每个使用手机导航App的用户来说,最怕听到的就是“卫星导航信号弱”这个提示,因为这意味着定位不准了,用户可能无法获得准确的指引。那么信号弱到底是咋回事呢?明明没有遮挡,咋就收不到信号呢。今天我们简单讲一下信号弱的产生原因,以及规避的方法。</p><p>目前高德地图播报信号弱的时机,是在导航过程中,手机没有上报卫星定位结果。我们对信号弱问题进行了一个分析,原因如下:</p><p><img src="/img/remote/1460000041483508" alt="" title=""></p><p>可见,<strong>在大部分情况下(80%),确实是卫星信号弱</strong>,不足以进行卫星定位,少数情况下卫星数够,信号也够强,但是仍然无法定位,原因可能是设备收到的卫星报文存在异常,导致无法顺利解算出卫星位置,或者不同卫星给出的报文信息相互矛盾,难以确定用户的真实位置。</p><p>那么,什么原因导致设备搜不到星,或者能搜到星但是信号微弱呢?这里面存在两种可能:</p><p><strong>1.手机周边存在电磁干扰源,导致卫星信号被掩盖在其他信号之下,无法锁定卫星。</strong>卫星信号从2万公里远的卫星处发出,到达地面时信号强度已经严重衰减,与4G/5G信号对比,其强度只有4G/5G信号的一万亿分之一,所以大家印象中的卫星信号接收天线一般是这样的:</p><p><img src="/img/remote/1460000041483509" alt="" title=""></p><p>普通用户没有这个条件,起码也得是星链这种</p><p><img src="/img/remote/1460000041483510" alt="" title=""></p><p>但实际上为了移动性,定位卫星天线都做的很小,比如</p><p><img src="/img/remote/1460000041483511" alt="" title=""></p><p><img src="/img/remote/1460000041483512" alt="" title=""></p><p>这个尺寸还是没法做进手机,手机里的天线长这样</p><p><img src="/img/remote/1460000041483513" alt="" title=""></p><p>天线变的这么小,信号接收效果肯定差很多,所以定位信号在设计上做了很多处理,使得即使很微弱也能被识别和解码。<strong>主要的方法,就是降低数据传输速率</strong>(根据香农定理),用更长的时间发送一个比特,最终GPS的数据发送速率只有50Bit/秒,要发送一个完整的定位报文需要6秒。作为对比,5G的数据速率可以达到Gb/s。尽管如此,终端设备还是有一定的概率无法成功读取卫星报文,特别是在强电磁环境下。</p><p>强电磁环境并不是我们想象中的大功率信号源附近,因为定位信号十分微弱,任何信号源都可能对定位信号造成干扰,特别是定位信号的频段内,主要是1.1G-1.6GHz这个区间,这个区间内的干扰源很多,一些其他频段信号的谐波也会干扰到定位信号,比如车上的各种电子设备。</p><p>现在一些手机厂商在做一些检测工具能够识别车上的干扰源,在这个功能完善以前,普通用户可以尝试在车内改变手机的摆放位置,比如远离中控台,放在靠近挡风玻璃的地方,看看信号是否能恢复。注意,由于一个卫星报文需要6秒才能读取完毕,所以改变位置后需要等待几秒钟才能看到效果。有条件的话,可以走到车外,彻底排除车内的干扰。如果车外可以车内不行,则说明不是手机的问题。</p><p>说一个题外话,Spacex发射了星链卫星后,很多人想象,以后是不是可以直接用手机打卫星电话,从原理上讲其实不太现实,虽然星链卫星轨道比定位卫星轨道低很多(几百公里 vs 2万公里),但信号的衰减是不可避免的,即使能收到卫星信号,其数据速率也非常低,更困难的是让卫星接收到手机的信号(定位信号是完全单向的,手机不需要反向发信息)。之前铱星给出的方法是配一个巨大的天线。这可能是未来解决信号弱问题的一个办法(手机增加一个插孔,可以外接天线)</p><p><img src="/img/remote/1460000041483514" alt="" title=""></p><p><strong>2. 如果在完全空旷的地方,在车外还是无法定位,而且周边也没有其他电子设备,那大概率就是手机的问题。</strong>这种情况下,只能通过“重启大法”来解决了。很多用户在出现问题后会尝试重新导航,或者重启地图App,其实这种方式大概率没用,因为此时是手机系统无法定位了,而不是地图App无法定位,重启App没有效果。</p><p>据我们观察,各个手机厂商的手机,都不同程度的存在这种问题,这主要受GNSS芯片和天线影响,一般而言,高端机型采用的芯片质量会更好一些,卫星信号的跟踪和解算能力也更强一些,而老旧机型出问题的概率相对更高。</p><p>最后,如果用户找不到干扰源,又不想重启手机,就没有办法导航了么?当然不是,高德地图做了大量工作去优化弱信号下的导航体验。从2019年开始,高德地图上线了<strong>智能定位功能</strong>,就是为弱信号的场景提供持续定位的能力。智能定位主要采用以下能力提供持续的定位能力:</p><ul><li><strong>传感器推算</strong>:利用手机上的加速度计、陀螺仪、地磁计去判断手机的速度变化和方向变化,再配合地图匹配来判断当前所处的道路,这样即使在进入隧道以后,车标也可以持续移动。这种惯导方式在30秒内可以保持较高的定位精度,时间再长就要结合其他定位方法来保持精度了。</li><li><strong>网络点推算</strong>:网络定位是手机上另一个重要的定位能力,在室内没有卫星信号的时候都是通过网络定位来实现定位的,其原理是利用扫描到的周边基站和Wifi来完成定位,其精度在30米-200米不等。一般是市区内Wifi比较密集,定位效果比较好,在郊区或高速上只能依靠基站,车标更新会有一些卡顿或者延迟。</li><li><strong>卫星弱信号解算</strong>:针对手机设备有扫描到卫星,但是无法给出定位结果的场景,高德做了一些算法优化,使得在这种情况下仍然可以提供卫星定位结果。</li></ul><p><img src="/img/remote/1460000041483515" alt="" title=""></p>
【定位不准的烦心事系列】第1篇:谈谈卫星定位的位置干扰
https://segmentfault.com/a/1190000041444522
2022-02-22T19:32:59+08:00
2022-02-22T19:32:59+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>现代人的生活已经离不开手机,离不开地图,一旦遇到定位不准的问题,就会产生很多问题,而且有些会很严重,比如打车找不到车、外卖找不到顾客,更惨的是开车的时候在高速上转圈圈,多跑个100公里也是有可能的。</p><p>大家把定位准确当做一个理所应当的事情,现在定位技术这么发达,北斗3代成功组网,定位怎么还会不准呢?确实,随着时间的推进,定位的精度是越来越高的,但是有一个潜在风险,会导致定位精度下降。</p><p>这个风险来自<strong>卫星定位欺骗技术的泛滥</strong>。卫星定位欺骗,或者位置干扰,是通过地面上的卫星伪基站广播定位信号,让周边的定位设备误以为接受到了真实的定位信号,从而将定位结果设置为干扰者预设的一个位置。之前我们比较多的听说一些人用伪通信基站去群发垃圾短信,而今天,位置干扰也越来越普遍,比如:</p><ul><li><strong>驾考作弊</strong>:驾校学习都会要求学员上车练习,而且车上有一些设备会记录学员的练习轨迹,作为学员完成学习的证据,但是一些学员不想花时间学车,于是有一些人员会利用伪基站播发伪信号,让车辆记录仪的定位点自动围绕驾校道路行驶,即使这个设备在远离驾校的地点。这样学员不需要花1分钟学车,就可以达到所要求的学车时长。</li><li><strong>远程打卡</strong>:一些企业会基于轨迹对员工进行工时统计,少数员工可能会通过伪造自身位置的方法作假。</li><li><strong>打车刷单</strong>:一些司机为了获取接单奖励或者挑单,用作弊办法修改自己的定位点,让平台以为他在某个指定的位置,或者完成了某个订单。</li><li><strong>无人机反制</strong>:一些企业不希望无人机靠近自己的场所,于是对无人机的位置进行干扰,让其误以为进入禁飞区自动降落,或者偏离航线。</li><li><strong>反跟踪</strong>:运营车辆上都装有北斗定位装置,一些企业或个人不希望自己的真实位置被发现,于是进行位置干扰。</li></ul><p>定位伪造方法有很多种,有些只影响单一的设备(比如在设备上直接修改定位结果),而卫星伪基站的方法,则是技术含量比较高的方法,这个方法可以将附近所有设备的位置全部干扰,具体的影响范围和基站的发射功率有关,小功率的基站只影响附近几米的范围,而大功率的基站,可以影响周边几十公里,甚至在室内接受不到卫星信号的情况下,都会被干扰。</p><p>这种干扰能够将定位点定位到任意位置,而且运动速度、方向都可以指定。于是用户可能发现自己的定位点在几千公里之外,或者轨迹成为一个奇怪的形状,比如画圆圈或者沿某条道路在行驶。</p><p>位置干扰技术的原理是什么呢?简单来说,卫星定位是通过接收到卫星信号,读取信号报文,获得时间戳,然后用时间戳和本地时间相减计算出和卫星的距离,再求解一个4元方程组(x,y,z坐标以及本地时钟偏移量)。</p><p><img src="/img/remote/1460000041444524" alt="" title=""></p><p>由于卫星信号的规格是公开的,我们可以将任意的时间填充到信号报文中,再通过特定的载波信号发射出去,就可以让其他设备获得错误的定位信号。最简单的方法,是直接把某个地点的信号录下来,然后在另一个位置回放。要定位到指定位置,只需要用该位置计算出每颗星播发的时间戳即可。而现在已经有人把整个报文编写、载波调制、信号发射这一系列步骤做了封装,成为货架产品,任何人只要买了设备就可以自己输入目标经纬度以及速度方向,甚至是整段轨迹,然后就可以进行位置干扰了。</p><p>比如,HackRF是一款设备,可以发射自定义的信号,有一些开源软件可以生产GNSS的软信号,再通过HackRF发射出去,就成了一个伪基站。而且,一个设备可以同时发送多路信号,模拟多颗卫星。</p><p><img src="/img/remote/1460000041444525" alt="" title=""></p><p>为什么卫星信号这么容易被干扰呢?因为GPS设计之初并没有在安全性上考虑的很严谨,所以报文完全没有加密,用户侧也没有做鉴权,是完全开放的。</p><p>后续的伽利略、格洛纳兹、北斗也都遵循相同的设计理念,报文、调制过程都是类似的,都会被干扰。安全性比较好的方式,是军码,这种报文采用专门的频率进行发射,其报文规格、编码方式都是保密的,要读取报文需要专门的秘钥,因此难以破解或者干扰,但这种方法无法解决民用设备的安全性问题。</p><p>目前一些芯片厂商,以及高德,在做一些工作去发现这种干扰,从而避免影响到用户。具体的方法包括:</p><p><strong>1.载波校验</strong>:真信号和假信号同时出现时,可以检查信号强度是否有异常(假信号往往信号很强,才能覆盖真信号)。</p><p><strong>2.信号方向校验</strong>:检测信号的来源方向,如果不是来自天空,则有异常(对天线有要求)。</p><p><strong>3.报文一致性校验</strong>:检查报文的每个字段是否和真实信号一致。</p><p><strong>4.解算校验</strong>:解算后发现某些卫星的距离异常,比如同时收到真信号和假信号。</p><p><strong>5.多源校验</strong>:结合惯导、网络定位以及其他定位方式校验卫星定位的结果是否异常。</p><p>以上这些方法可以在一定程度上降低被干扰的概率,但是还是无法彻底杜绝。对于普通用户来讲,<strong>当发现自己的定位结果异常时,如何发现是由于卫星信号干扰导致呢?</strong></p><p>1.首先,看自己的定位结果是不是出现在机场、油库、驾校这些地点,或者自己的位置附近是否有油库或者是一些敏感设施。</p><p>2.然后,确认自己设备的定位结果来自卫星定位而不是网络定位,如果是安卓用户可以下载一个<strong>AndroiTS GPS Test</strong>软件,如果显示Fix或ON,则代表卫星定位成功,否则是网络定位。</p><p><img src="/img/remote/1460000041444526" alt="" title=""></p><p>对于iPhone,下载<strong>phyphox</strong>,进入GPS页面,如果速度为负说明是网络定位,否则是卫星定位。</p><p><img src="/img/remote/1460000041444527" alt="" title=""></p><p>3.此外,在明确手机定位方式是卫星定位的情况下,如果周边的多台手机都定位在了错误的位置(至少偏离了200米以上,如果偏离距离不远,有可能是卫星定位点漂移了),则大概率此地被某个周边的伪卫星基站给干扰了。</p><p>有些干扰未必是干扰者的本意,他本来可能只想控制某个小范围的设备,但是天线功率设置不合理,信号被扩散到很远的地方。</p><p>能够明确有干扰,如何解决呢?只能向政府部门寻求帮助,<strong>可以打电话给当地的无线电管理部门</strong>,要求排查。无线电管理部门有专门的仪器可以检测伪基站信号,确定位置,并将设备关停。欢迎大家举报非法的无线电干扰行为。</p><p>具体电话可参考</p><p><a href="https://link.segmentfault.com/?enc=PvhOYMHlNb0iPGb0Y08XKw%3D%3D.5lBtRQ4euSl1EoFVhefzxEC81aNBOBTK6oW0LB1jfU%2BfZaXOVrKixDloArMQzFiFI3KuSNDmfHxXJHRclLxOKBXXVp2mXVuwxGyA3Dro7bSGLaGM3lmDSx916JMu8fY0" rel="nofollow">https://www.miit.gov.cn/gzcy/cydh/art/2020/art_ba58d28194884d66b0032861a11e0bd2.html</a></p><p><img src="/img/remote/1460000041444528" alt="" title=""></p>
高德「渲染练习生计划」启动,开启专业渲染技术人旅程!
https://segmentfault.com/a/1190000041322298
2022-01-21T18:06:10+08:00
2022-01-21T18:06:10+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>伴随着数字化、元宇宙时代的带来,作为图形技术的核心部分,渲染技术正从幕后走向台前,进入我们生活的方方面面。渲染技术在游戏、影视、地图应用、电商、AR交互、自动驾驶、数据可视化等领域都有着丰富的应用场景,其重要性和迅猛发展已经成为业界共识。</p><p>对于很多在校大学生,也把渲染技术作为未来走向职场的重要技术储备和发展方向,大家在学校期间也或多或少接触到一些图像图像渲染技术的内容,但很多时候困惑于缺乏体系化学习,难以全面了解渲染技术的前沿技术,以及在企业界的最新应用实践情况。</p><p>高德作为国民级的出行生活服务平台,渲染技术在高德业务场景中有着丰富且深入的应用,在地图、导航、自动驾驶、高精地图、新一代的AR & 车道级导航等场景均有着业界领先的技术研发和应用实力。</p><p>为了让高校同学们有更多机会了解渲染技术在数字世界的最新发展,让更多有兴趣系统学习渲染技术的同学早日掌握实战级的能力,甚至为行业培养更多的渲染技术后备军,高德启动了「<strong>渲染练习生计划</strong>」。</p><p><img src="/img/remote/1460000041322300" alt="" title=""></p><p></p><p>本计划由阿里巴巴-高德发起,面向符合条件的在校本科、硕士、博士等在校生免费开放。我们旨在挖掘和培养对渲染技术感兴趣或致力于成为渲染研发精英的在校学生,提供一个学习的渠道,通过体系化的学习、真实的经验分享,在阿里及高德师兄们的陪伴下开启渲染研发之旅。</p><p>高德「渲染练习生计划」将推出7大方向、近40节课程。在这儿,你可以了解渲染领域,从理论到实践,还可以与业务一线的渲染研发资深从业者1v1探讨沟通,互相启发。不仅于此,你还能在课堂和项目中结交到一群志同道合的朋友,大家共同学习,共同成长。</p><p><strong>面向群体</strong></p><p>对渲染研发领域感兴趣的2023、2024年毕业的本科、硕士、博士在校学生。</p><p><strong>学习方式</strong></p><p>在线学习</p><p><strong>时间安排</strong></p><p>报名时间:2022年1月21日——2022年2月20日</p><p>开课时间:2022年2月下旬</p><p><strong>整体流程</strong></p><p><img src="/img/remote/1460000041322301" alt="" title=""></p><p><strong>报名方式</strong></p><p><a href="https://link.segmentfault.com/?enc=bboBhB5M2ZVjK%2B3LCAu3yQ%3D%3D.VSyngplVuDnxl%2Bc5djAxu7ltALVD3JC0iIXRfXhZIIXXc9L6CRAX5e%2FIHsBeeE7T" rel="nofollow">https://yida.alibaba-inc.com/...</a></p><p><strong>课程简介</strong></p><p>本次高德「渲染练习生计划」将包含以下7大方向的培训课程。</p><p><strong>地图渲染技术的前景:</strong>从技术视角出发,结合XR、自动驾驶、数字孪生、元宇宙等热点技术话题,聊一聊地图渲染技术的发展前景。</p><p><strong>渲染基础:</strong>以渲染实战视角了解所需要的C++及渲染的基础知识。探讨C++三大特性以及三维数据成像原理。</p><p><strong>GIS基础:</strong>地理信息系统(简称GIS),是一门综合性学科,结合了地理学、地图学以及遥感和计算机科学。本课程将介绍地图中用到了哪些GIS技术,以及相关的基础知识。</p><p><strong>渲染特效:</strong>渲染特效,是指如何以符合审美或风格的方式用计算机画出各类元素和效果,将会结合地图以及业界最新应用,简单介绍常用的光照模型、阴影、动画、贴图技术,基础特效和高级特效。</p><p><strong>几何算法:</strong>本章是计算几何的入门课程,包含几何相交(碰撞)算法与三角化算法两部分内容。带你直观地体会计算机算法的技巧与魅力!</p><p><strong>三维建模:</strong>本章主要介绍样条线与几类典型的三维模型生成与修改方法,带大家了解如何通过程序与参数来生成一些常见的几何体。</p><p><strong>渲染引擎:</strong>通过对OSG开源渲染引擎的基本框架及运行逻辑的剖析,以及市面上常用的几款商业引擎特点的分析,使你对渲染引擎有个初步了解。</p><p><strong>划重点啦,课程收获</strong></p><ul><li><strong>视野开拓</strong>:宏观了解渲染领域的发展历程与未来前景,增加一种从业可能性;</li><li><strong>技能收获</strong>:体系化的渲染技术,理论与实践相结合;</li><li><strong>师长好友</strong>:渲染技术专家、学长学姐沟通交流机会,相互学习;</li><li><strong>面试机会</strong>:优秀学员可获得阿里巴巴-高德的渲染等岗位直通面试机会;</li><li><strong>学习资料</strong>:课程视频反复多次观看,打破时间限制,不错过每一个精彩瞬间;</li><li><strong>权威证书</strong>:学习全部课程并完成结业项目,获得「阿里巴巴-高德“渲染练习生计划”」结业证书。</li></ul><p>持续学习是这个大变革时代最核心的能力,时代和行业都在变,而不变的是我们总能用所掌握的技能,去对世界带来微小而美好的改变。</p><p>欢迎大家的加入!</p>
高德渲染网关Go语言重构实践
https://segmentfault.com/a/1190000040599303
2021-08-31T11:41:22+08:00
2021-08-31T11:41:22+08:00
高德技术
https://segmentfault.com/u/amap_tech
2
<p><strong>1.导读</strong></p><p>高德启动Go业务建设已经有段时间了,主要包含<strong>Go应用落地</strong>,<strong>Go中间件建设</strong>,<strong>云原生</strong>三个部分。经过持续的发力,在这些方面取得了不错的进展。高德Go业务落地过程是如何实现的,遇到过哪些问题,如何解决?本文将为大家介绍相关经验,希望对感兴趣的同学有所帮助。</p><p><strong>2. 高德为什么要落地Go应用</strong></p><p>现在高德内主流的语言还是Java,Java应用最多,机器数十分惊人。而且高德整体业务也在快速向前奔跑,成本增加的速度非常快。<strong>在减少机器负载方面,Go语言在语言级别对Java语言有相当优势。减少机器成本是我们落地Go应用的第一个考虑因素。</strong></p><p>其次,Go语言近几年发展势头迅猛,不论是阿里集团内部,还是在高德内部,对使用Go语言的呼声越来愈高。落地Go应用可以很好的验证Go中间件的稳定性。当然我们可以通过混沌工程等手段去验证,但经过生产环境考验才最具有说服力。<strong>验证沉淀Go语言中间件稳定性是我们落地Go应用的第二个考虑因素。</strong></p><p>最后,Go语言作为云原生基础框架使用较多的语言,提前落地Go应用,对后续落地云原生可以减少不少阻力。高德目前落地的Serverless/Faas规模相当大。<strong>落地Go应用的第三个考虑因素是为后续云原生落地铺路。</strong></p><p><strong>3. 大流量场景Go应用落地</strong></p><p><strong>3.1 渲染网关介绍</strong></p><p>本文所述中提到的高德渲染网关,是我们落地的Go应用中业务流量、改造难度、风险,收益均处前列的应用。渲染网关在接入层,占高德总流量的一半,重要性可想而知。</p><p>接下来简要介绍下渲染网关承接的业务,方便大家有一些更立体的认识。</p><p>渲染网关承接高德手机App、车机、开放平台等来源所有的图面渲染。大家在使用高德时,看到的建筑物、地形图、名称、路线、地铁站、公交站、红绿灯等等所有图面,都是由渲染引擎通过渲染网关透出到端。下面放几张图,方便大家有一些更感性的认识。</p><p><img src="/img/remote/1460000040599305" alt="" title=""></p><p>上面图一为行前,图二为行中,图三为打车页面,图四为景区手绘图。渲染网关涉及业务众多,以上仅为举例,其他业务就不在这里贴图了。</p><p><strong>3.2 重构难点</strong></p><p>做过重构项目的同学相信都深有体会,<strong>重构项目中最大难点有二,一是要保证业务正确性,二是要保证服务稳定性。</strong></p><p>对于保证业务正确性,一般来说,重构的服务大多数为老服务,老服务面临的最大问题是历史逻辑复杂,人员更迭,文档缺失,这些因素都是重构过程中的“拦路虎”。</p><p>渲染网关重构同样如此,它涉及高德手机端、车机端、开放平台、打车等各个业务线,所有的历史版本,再加上上述因素,所以保证业务正确性是一件非常困难的工作。</p><p>对于保证服务稳定性,做过网关的同学应该都知道,网关本身的属性就决定了它并不会有频繁的业务迭代,稳定性是网关的第一诉求。我们要保证,无论外部环境/依赖是否正常,网关始终能保持高可用。由于<strong>Go版本中间件缺乏在大流量场景的充分验证</strong>,这一难点需要仔细评测,用合适的方法和手段,尽可能的在仿真环境里验证各种边界情况,从而保证在生产环境不出问题。</p><p><strong>3.3 技术方案</strong></p><p>在重构高德渲染网关时,我们整体技术方案分三大步走:</p><p><img src="/img/remote/1460000040599306" alt="" title=""></p><p>3.3.1 线上流量对比</p><p>如何验证新服务的业务正确性呢?我们采用了线上流量对比的方式。</p><p>我们前期做了大量调研,希望找到一个<strong>满足(近)实时,二进制级对比的工具</strong>,但可惜并没有找到一个满足要求的工具。由于渲染业务的特殊属性,渲染网关绝大多数接口返回的是二进制矢量数据,所以理想的工具不仅要能支持常规数据对比,也要能支持二进制级对比。</p><p>二进制级对比的另一个好处是,可以排除字符集差异,不同语言库函数差异。更能保证对比的准确性。有些同学可能会想到打日志,然后离线读取比较的方式来做对比,这种方式有很多弊端。</p><p>首先,流量无法重放至指定机器。其次,这种使用方式一般为固定语料,语料完整度不够,不能完全模拟线上环境。此外,打日志对比带来的字符集和语言库函数差异,会对比较准确性有较大影响,特别是对于特殊字符(当7层协议为二进制协议时更加明显)。没有现成的称手工具,怎么办?"逢山开路,遇水搭桥"。</p><p>我们<strong>自主研发了一款(近)实时流量对比工具</strong>,它保障了此次重构的业务正确性,并且还能服务于高德其他业务的重构。其技术细节对TCP/IP涉及较多,非常有意思,感兴趣的同学可以直接跳至《流量对比工具(ln)技术细节》一节。</p><p>3.3.2 仿真环境压测</p><p>做服务的同学相信都深有体会,想让服务保障做到5个9的可用性并不是一件容易的事。真实生产环境中可能会出现各种情况,我们要想办法验证各种边界情况下服务的稳定性,才能保障服务高可用。对于重构完成的新服务,更需要一个仿真环境,进行各种情况验证。</p><p>构建仿真环境,我们需要保持<strong>机器基线、外部依赖、外部流量</strong>均一致(比如从线上引流)。仿真环境不仅要提供正常态环境的能力,更要能提供异常态环境的能力。</p><p>异常态包括断网,网络丢包等等。有句话说的好:20%的代码完成功能,80%的代码来处理各种异常情况。我们<strong>在实践中构建异常态的主要手段为混沌工程</strong>,通过混沌工程模拟下至操作系统级的异常(如断网,丢包等),上至应用层的异常(如消息中间件积压,JVM方法前后Hook模拟业务异常等等)。</p><p>在仿真环境里,同时进行长时间极限压测,语料从线上导流,压测在正常态,异常态均进行,观察服务在一段较长时间内的表现,从而得出服务的稳定性,可用性结论。</p><p>观测指标包括<strong>基础指标</strong>,例如CPU、磁盘利用率、内存利用率、连接数,以及业务指标,例如业务接口成功率、成功量、总量、TP99。通过这种方式,基本上完全覆盖了可能出现各种情况,充分保证了服务稳定性和高可用。</p><p>3.3.3 平滑灰度切流</p><p>前边讲了如何保证业务正确性和服务稳定性。接下来说说如何保证平滑灰度切流。牢牢遵守<strong>阿里发布三原则</strong>是平滑灰度切流的“法宝”:<strong>可灰度</strong>,<strong>可监控</strong>,<strong>可回滚</strong>。</p><p>在具体实践中,我们按照如下步骤<strong>灰度切流</strong>:</p><p>a. 原Java集群不动,新申请一套Go集群。修改路由规则,部分白名单用户使用Go集群服务。</p><p>b. 逐个接口修改路由规则至Go集群,慢慢灰度,期间密切观察机器姿态,业务日志,监控指标。如有异常一键切回至Java集群。</p><p>c. 接口全量切至Go集群后,Java集群/Go集群同时共存一段时间。</p><p>d. 逐渐下掉Java集群机器。</p><p><strong>3.4 主要收益</strong></p><p>第一个重要收益:<strong>降本提效</strong>。高德渲染网关由Java换成Go语言之后,机器数减少近一半。用原来一半的资源完成了相同的工作,大大降低了成本,提高了资源利用率,更好支持了业务发展,大大降低了业务流量快速增长带来的接入层机器增长速度。</p><p>第二个重要的收益是:<strong>验证了高德与集团合作共建的Go版本中间件的稳定性</strong>,一定程度上完善繁荣了集团Go生态。在大流量场景考验过后,高德与集团合作共建的Go版本中间件稳定性得到了相当充分的验证。</p><p>第三个重要的收益是:<strong>为网关云原生化铺路</strong>。网关Go化只是第一步,Go是云原生基础设施实现使用较多的语言,第一步抹平语言差异,对于网关后续云原生化,好处多多,可降低改造风险和成本。</p><p>当然,高德渲染网关重构过程中还有许多非常有用的工具沉淀。可为后续业务重构提供关键性保障,比如自研的流量对比工具ln。</p><p><strong>4. 技术干货</strong></p><p><strong>4.1 流量对比工具(ln)技术细节</strong></p><p>先提一个问题,做一款(近)实时流量对比工具需要完成哪些功能?没错,就是流量复制,流量解析,流量重放,流量比对。其实不止这些,在实践中更多是一个流量回归闭环,如下图:</p><p><img src="/img/remote/1460000040599307" alt="" title=""></p><p>4.1.1 流量复制</p><p>为了支持所有的7层协议,流量获取必须从3层或4层开始。有同学会立马想到tcpdump。没错,就是tcpdump。tcpdump出的文件就是实实在在的流量。复制流量这一步已经有着落了,至于实时,可以两到三个进程错开时间,时间段首尾互相重叠即可完成实时。</p><p>另外,设计此工具的另一个考量点是,对线上机器不能有太重的负载,避免对线上机器产生稳定性影响。此种流量复制方式非常轻量,对线上机器增加的负载非常小,可以忽略不计。</p><p>4.1.2 流量上传&流量拉取</p><p>流量上传和流量拉取均使用内部文件服务。</p><p>4.1.3 流量对比</p><p>流量对比为了保证对比的严谨性,排除可能的字符集干扰/不同库函数实现干扰,我们原生支持了二进制流对比。</p><p>4.1.4 问题流量本地重放Debug</p><p>回归流量时,可能会发现部分流量比对不一致,这时我们希望只重放特定流量到指定机器,以便于Debug或其他操作,ln原生支持了此功能。</p><p>4.1.5 流量解析</p><p>流量解析非常有意思,这种单纯的快乐来自于对网络协议的"把玩"。</p><p>实际做法就是如何解析tcpdump文件,拿到tcp payload,还原出http请求。</p><p>这里有两个关键点,一是我们如何从tcpdump文件中拿到tcp payload,二是我们如何把四层的tcp payload重新聚合成七层的http请求。</p><p>4.1.5.1 tcpdump文件格式</p><p>先说如何从tcpdump文件拿到tcp payload,如果能知道tcpdump文件的格式,不就可以知道tcp payload在哪个位置,长度如何了么?这一趴我们就来看看tcpdump文件格式。</p><p>先看tcpdump文件总览</p><p><img src="/img/remote/1460000040599308" alt="" title=""></p><p>文件头的格式和长度都是固定的,如下:</p><p><img src="/img/remote/1460000040599309" alt="" title=""></p><p>我们可以在读取tcpdump文件后,往后移动23字节,然后开始处理每个数据包。每个数据包的格式如下:</p><p><img src="/img/remote/1460000040599310" alt="" title=""></p><p>我们处理每个数据包,将前边的包头,数据链路头,ip层头,tcp协议头依次跳过,最终偏移到tcp payload第一个字节位置。其中的更多实现细节(不同层的头字段值的判断,不同长度的判断,大小端的判断,请求数据包与响应数据包如何对应等等)在此不再展开。这里只介绍大体思路,感兴趣的同学可以深挖网络协议。</p><p>4.1.5.2 tcp payload还原http请求</p><p>这一部分介绍如何将tcp payload还原成http请求(此处http指http1.0/1.1,不含http2),ln工具中的完整实现是由tcp payload还原出请求及对应的响应,此处为了便于理解,仅讲解如何解析http请求。解析出http请求实际上已可以重新分别请求新老服务,对比响应二进制流。</p><p><img src="/img/remote/1460000040599311" alt="" title=""></p><p>一条tcp连接,多个payload发送(这里仅做示意,判断丢包重发等诸多情况属于代码细节,在此不再展开)。可能多个payload对应一个http请求;也可能一个payload的前一部分对应一个http请求,后一部分对应另一个http请求。我们要做的就是把多个payload形成的字节流读入,按http帧的格式,聚合http请求即可。另外,http2的请求不能按这种方式聚合。</p><p><strong>4.2 一些go语言最佳实践</strong></p><p>4.2.1 sync.pool 实践</p><p>由于Go语言和Java语言的内存管理机制不相同,在内存的申请,释放开销也有差别。</p><p>对于Go语言来说,sync.pool是复用内存的一把利器。sync.pool优点有许多,比如减少内存的申请,减少了系统调用,减少了gc的压力。但事物都有两面性,sync.pool同样如此,我们在使用sync.pool的时候需要注意,存放在sync.pool里的对象会在不通知的情况下被回收掉,所以类似数据库连接等资源不适合使用sync.pool。</p><p>总之,sync.pool可以复用内存,减少机器负载,非常适合临时对象。</p><p>4.2.2 Golang Byte</p><p>Go语言Byte类型为无符号,Java语言Byte类型为有符号,在Java服务迁移Go服务过程中,Java代码中Byte类型正、负、零的比较要注意。</p><p>4.2.3 Golang字节切片与字符串高效转换</p><p>字节切片转字符串</p><pre><code>func Bytes2String(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}</code></pre><p>字符串转字节切片</p><pre><code>func String2Bytes(s string) []byte {
x := (*[2]uintptr)(unsafe.Pointer(&s))
h := [3]uintptr{x[0], x[1], x[1]}
return *(*[]byte)(unsafe.Pointer(&h))
}</code></pre><p>使用此种方式转换,性能很高。原因在于底层无新的内存申请与拷贝。但是不论是字节切片转字符串,还是字符串转字节切片,字节切片中的值更改都会影响字符串的值,使用者要根据业务逻辑判断能否接受,要更精确的把控生命周期。</p><p>4.2.4 Golang库函数重写</p><p>对于网关来说,耗CPU比较多的一部分是Hash函数/编解码函数/加解密函数/序列化反序列化函数等。在实践中我们重写了相关的库函数,在CPU负载上做了大量优化。</p><p>想要降低CPU负载,我们得先知道CPU是如何工作的,才能知道如何写代码会更好的降低CPU负载。这里会介绍粗略的CPU工作原理。</p><p>放张CPU 流水线工作步骤图</p><p><img src="/img/remote/1460000040599312" alt="" title=""></p><ul><li>指令读取(instruction fetch,IF)</li><li>指令解码(instruction decode,ID)</li><li>执行(execute,EXE)</li><li>内存访问(memory access,MEM)</li><li>寄存器回写(register write-back,WB)</li></ul><p>主要优化MEM步骤,利用CPU缓存尽可能减少MEM步骤所占时钟周期,从而降低CPU负载。</p><p><img src="/img/remote/1460000040599313" alt="" title=""></p><p>类似NUMA架构,affinity等降低CPU负载的方式也是同样的思想,尽可能减少Load数据所需的时钟周期。</p><p>对于优化Golang库函数来说,可以提升的点有两个:优化算法本身;优化CPU缓存亲和度。</p><p>我们专注于第二种,拿base64编解码函数举例,传入的Byte切片与返回Byte切片,底层并非为同一数组,同一内存。这中间就涉及两块可以额外消耗CPU时钟周期的点,一是内存的申请与释放,二是两块内存分别访问带来的CPU缓存争用问题(与伪共享不完全一样)。</p><p>如果我们复用传入的内存呢?即边解码边覆写同一块内存。美妙的事情发生了,上边所说的问题不存在了。用更少的时钟周期完成了一样的工作。需要注意的是,由于函数的输入和输出使用同一块内存,对程序开发者来说有更高的编码要求,即对数据在程序中流转的生命周期有更精准的把控力,代码要打磨的很细致。</p><p><strong>5.未来展望</strong></p><p>网关的下一步是<strong>云原生化</strong>,采用<strong>Service Mesh</strong>方式实现。这可以解决目前中心化网关的弊端,去中心化可以提升接入层稳定性,减少爆炸半径,增强隔离能力,实现更精细粒度的管控。</p><p>其次,<strong>降低机器成本</strong>,按照目前内部压测及业界已有的实践压测结论,Mesh化后成本会进一步减少,考虑到现有RPC框架本身的消耗,成本会进一步缩减。且数据面代理也在不断优化中,后续性能表现会更优异,额外两跳对机器的负载将进一步下降。</p><p>再有,<strong>网络层能力集大大增强。</strong>网关Mesh化,可以带动上游业务Mesh化,最后在整个网络层做一个能力超集。</p><p>现有的Service Mesh框架提供的能力可以概括为Connect,Secure,Control,Observe四大部分,其能力是现有网关能力的超集,可以做到之前做不到的事情,最明显的是Observe能力带来的好处,可大大加强全链路服务可观测性,这于对后续开展服务稳定性,全链路故障快速定位等工作有极大帮助。</p><p>以上要做的事情任重而道远,另外我们在会做更多云原生的试点和落地,技术同学都清楚,从技术选型到技术原型,再到实际业务落地,中间有很长的路要走。但路选对了,就不怕远。</p><p><strong>诚招同路人</strong></p><p>笔者所在团队求贤若渴,盼有热情的技术小伙伴一起做些有趣的事,各技术栈均可,有意愿的小伙伴请尽情砸简历到邮箱<a href="mailto:gdtech@alibaba-inc.com">gdtech@alibaba-inc.com</a>,邮件主题为:姓名-技术方向-来自高德技术。</p><p>Happy Hacking!</p><p><img src="/img/remote/1460000040599314" alt="" title=""></p>
地图采集车的那些事 | 惯性导航
https://segmentfault.com/a/1190000040534449
2021-08-18T13:31:50+08:00
2021-08-18T13:31:50+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>一、背景</strong></p><p>高精地图、高精采集车,是做地图和出行领域同学经常挂在嘴上的一些常用词儿。但是,圈外的同学可能会问,到底什么是高精?</p><p>高精是指<strong>高精度定位</strong>,高精地图是指包含丰富地理信息数据、具有高精度坐标的地图。当然,高精采集车就是采集制作高精地图数据的特种作业车。</p><p>有些好奇的小伙伴会打破砂锅问到底,高精是怎么实现的呢?怎样才能叫高精度?</p><p>事实上,目前高精度的标准并不是很确定,但基本认为<strong>厘米级以上</strong>的精度才能算是高精度。高精的实现,主要是靠各类传感器,其中最重要的就是高精度定位定向系统,包括卫星定位及惯性导航两部分。</p><p>本文主要从硬件角度给大家介绍一些这方面的情况,以及在实际工作中对它的运用。</p><p><strong>二、术语解释</strong></p><p><strong>定位定向系统</strong>:POS系统(Position and Orientation System, POS),是指惯性导航+GNSS卫星导航组合的高精度位置与姿态测量系统,利用装在载体上的卫星接收机精确测定空间位置,利用惯性测量装置测定瞬间传感器姿态,通过精确时钟将两者结合起来,最后经过运算,获取载体的速度和姿态、位置等信息。</p><p><strong>惯性导航系统</strong>:简称惯导,是以陀螺和加速度计为敏感器件的导航参数解算系统,根据陀螺/加速度计的输出,建立导航坐标系,解算出载体在导航坐标系中的速度和位置。</p><p><strong>IMU</strong>:惯性测量单元(Inertial Measurement Unit),是测量物体三轴姿态角(或角速率)以及加速度的装置。IMU是惯性导航系统的一部分。</p><p><strong>GNSS:</strong>全球导航卫星系统(Global Navigation Satellite System),泛指所有的卫星导航系统,包括全球的、区域的和增强的,如美国的GPS、俄罗斯的Glonass、欧洲的Galileo、中国的北斗卫星导航系统,以及相关的增强系统,如美国的WAAS(广域增强系统)、欧洲的EGNOS(欧洲静地导航重叠系统)和日本的MSAS(多功能运输卫星增强系统)等,还涵盖在建和以后要建设的其他卫星导航系统。</p><p>备注:我们内部习惯把定位部分简称为惯导,实际不仅仅包含惯导设备,是指包含整套软硬件的定位定向系统。</p><p><strong>三、高精度定位定向系统包括什么</strong></p><p>采集车上的高精度定位定向系统,一般主要由下面几部分组成:</p><p><img src="/img/remote/1460000040534451" alt="" title=""></p><p>定位定向系统的构成</p><p><img src="/img/remote/1460000040534452" alt="" title=""></p><p>算法过程</p><p>整个系统由硬件和配套的软件及算法组成,由于组合解算的算法在业界有非常多的研究,各种方法和思路也是百花齐放,在高德内部有相关的同学做这方面的开发工作。因此,本文仅侧重于硬件角度的介绍。</p><p>低精度、高精度定位系统的组成内容差不多,区别只是传感器(IMU、GNSS)的精度等级不同。</p><p><strong>四、各传感器的作用和角色</strong></p><p><strong>1.GNSS</strong></p><p>类似以前常说的GPS,但是随着科技进步,咱们国家的北斗系统BD在精度和可靠性上也能匹敌GPS了,在实际运用中发挥着重要作用。</p><p>从几十元的模组,到上万元的高精GNSS板卡,定位原理基本一致,都是测量出已知位置的卫星到用户接收机之间的距离,然后综合多颗卫星的数据就可知道接收机的具体位置。卫星位置可以根据星载时钟所记录的时间在卫星星历中查出。</p><p>但是在信噪比、频段、星座数量、通道数、信号捕获跟踪等能力上,高精度GNSS板卡显著优于普通的GPS,例如手机一般仅支持GPS L1频段的C/A码,但是专业级的板卡基本都支持L1/L2/L5多频段、多通道。</p><p>除了在实时定位精度上显著优于普通模组,专业的GNSS板卡还可以进行后处理,精度达毫米级,这就是专业接收机板卡的价值所在。</p><p>业内主要的卫星接收机厂商包括国外的天宝Trimble、诺瓦泰Novatel、徕卡LeiCa、拓普康等,以及国内的北斗星通、华测、中海达、司南等。</p><p>GNSS在系统中的主要作用是获取当前位置的绝对坐标,优点是不存在位置误差累积,缺点是更新频率低,一般最高不超过10~50HZ。</p><p><strong>2.IMU</strong></p><p>事实上,IMU才是俗称惯导的高精度定位定向系统的核心,价格上也反应了这一点:如某个近百万元的设备,卫星接收机部分仅占数万元,其余大部分都是IMU费用。</p><p>从某种程度上讲,选定位定姿系统,其实重点是选IMU,因为GNSS部分选型相对简单直观。</p><p>本文后面也主要以IMU为侧重阐述对象。</p><p>IMU通常由三个单轴的加速度计和三个单轴的陀螺仪组成,加速度计检测载体在坐标系统中独立三轴的加速度信号,而陀螺仪检测载体相对于坐标系的角速度信号,对这些信号进行处理之后,便可解算出载体的姿态。</p><p>值得注意的是,IMU及惯性推算算法提供的是一个相对的原始定位信息,它的作用是测量相对于起点所运动的路线,所以它并不能提供你所在的具体位置的信息。因此,它常常和GNSS一起使用,当在某些GNSS信号微弱甚至缺失的地方时,IMU就可以发挥它的作用,可以让载体持续获得绝对位置姿态信息。</p><p>IMU的更新频率较高,一般可达几百至1KHz。使用三个加速度值,通过两次积分可获得位移,以此实现位置定位,有角速度值积分可以获取姿态信息,结合在一起可获得物体的实际状态。</p><p>别看IMU这个技术说起来比较陌生,其实我们每天使用的手机,以及汽车、飞机,乃至宇宙飞船都会使用到IMU,区别在于材料、成本和精度。</p><p>根据不同的使用场景,对IMU的精度有不同的要求,精度高,也意味着成本高。咱们高精车,当然使用最高等级的。</p><p><img src="/img/remote/1460000040534453" alt="" title=""></p><p>IMU的价格和精度对比</p><p><strong>3.里程计</strong></p><p>标准的里程计一般外挂安装在车轮上,内置一个旋转编码器,通过车轮带动共同旋转。作用是测量车辆移动的线性距离,并在卫星失锁时帮助抑制漂移误差。里程计的形式有多种多样,除外挂旋转编码器外,磁栅式、霍尔式等等都有应用。</p><p><strong>4.增强、辅助手段</strong></p><p>主要是一些陆基和星基增强技术,包括RTK、RTD、PPK、PPP、DGPS、各种SBAS等,我们平时作业时很少会用到星基增强系统,主要用到的是陆基增强系统。高精采集一般采用事后差分解算处理的方法。</p><p><strong>五、惯性导航是怎么炼成的</strong></p><p>前面已经说过,定位定向系统包含惯性导航,惯性导航的主要硬件是IMU,而IMU是由陀螺和加速度计两大部分组成的。</p><p><strong>1.陀螺仪</strong></p><p>先看看陀螺是啥样子?是的,就是下面这个东东。</p><p><img src="/img/remote/1460000040534454" alt="" title=""></p><p>这个陀螺和我们平时理解的惯性导航设备内的角速度传感器有什么关系?</p><p>从制作工艺和材料、原理上讲,没太大关系,是两种不同的东西。但是这些东西,都可当作旋转角速度传感器用,而这种类似机械陀螺形态的产品最先使用,先入为主了,所以后来把这种角速度传感器,都叫做陀螺仪。</p><p>事实上陀螺仪的种类很多,根据物理原理大体上可分为机械陀螺、激光陀螺和光纤陀螺、微机械(MEMS)陀螺等等。</p><p><strong>机械陀螺仪</strong>:在早期的飞机曾大量使用。它体积大、结构复杂、精度差。后期有一些改进的类型,如:滚珠轴承自由陀螺仪、液浮陀螺仪等。</p><p><strong>激光陀螺</strong>:利用萨格纳克理论中的光程差来测量旋转角速度。其要点是:当光束在一个环形的通道中前进时,如果环形通道本身具有一个转动速度,那么光线沿着通道转动的方向前进所需要的时间、要比沿着这个通道转动相反的方向前进所需要的时间要多。</p><p><img src="/img/remote/1460000040534455" alt="" title=""></p><p>萨格纳克实验</p><p>这个萨格纳克理论很有意思,感兴趣的同学可以自行加深了解。</p><p>激光陀螺实际上是一种环形激光器。在闭合光路中,由同一光源发出的沿顺时针方向和反时针方向传输的两束光和光干涉,利用检测相位差或干涉条纹的变化,就可以测出闭合光路旋转角速度。当环形激光器处于静止状态时,两束激光绕行一周的光程相等,因而频率相同,两个频率之差(频差)为零,干涉条纹为零。</p><p>当环形激光器绕垂直于闭合光路平面的轴转动时,与转动方向一致的那束光的光程延长,波长增大,频率降低;另一束光则相反,因而出现频差,形成干涉条纹。</p><p>激光陀螺没有内部运动器件,数据漂移率低,可靠性高,测量精度高。由于光程差的关系,激光陀螺会有一定的速度门限,低于这个门限,可能会检测不到角速度变化。另外,因为要使用环形激光器的缘故,整个器件体积大、成本高。</p><p><strong>光纤陀螺</strong>:严格讲也属于激光陀螺,原理与激光陀螺仪一样,只不过用光纤代替了环型激光器。光纤的成本低,但是易受温度变化造成的热胀冷缩不均以及缠绕时张力变化影响,故精度稍低。激光陀螺的光在谐振腔中传播,受外界影响小,因此精度较高,但谐振腔成本昂贵。因为在成本、体积上更有优势,所以光纤陀螺在实践中获得了大量运用。</p><p><strong>微机械陀螺</strong>:即MEMS陀螺,是用半导体技术刻蚀出来的微型机械结构和CMOS电路技术相结合的产品。它的特色是体积小、成本低,便于大批量生产,广泛应用于手机、便携式设备和其他一些对性能要求不高的领域。此外,随着技术进步,某些高端MEMS陀螺,精度已经可以媲美光纤陀螺了。</p><p>MEMS陀螺的原理是利用科里奥利力——旋转物体在有径向运动时所受到的切向力来传感角速度。振动物体被柔软的弹性结构悬挂在基底之上。整体动力学系统是二维弹性阻尼系统,在这个系统中振动和转动诱导的科里奥利力把正比于角速度的能量转换到传感模式,并计算输出。</p><p><strong>2.加速度计</strong></p><p>加速度计的作用是测量载体的加速度力,以确定载体在空间中的位置并监测起的运动,加速度是矢量、是速度的变化率 。</p><p>加速度计的类型较多,从<strong>材料</strong>上,有石英挠性、液浮加速度计和MEMS几种。</p><p>按<strong>传感元件</strong>分类,大体上又可以分为几种类型:压电式加速计、压阻式加速计和电容式加速计,此外还有热流式、谐振式。</p><p><strong>压电式加速度计</strong>利用压电效应(压电材料在受到物理应力时产生电)来感知加速度的变化。压电加速度计最常用于振动和冲击测量。压阻式加速度计比压电式加速度计灵敏度低得多,更适合于车辆碰撞试验。压阻式加速度计的电阻与施加在其上的压力成比例。</p><p>最常用的加速度计是<strong>电容式加速度计</strong>,它是利用电容的变化来确定物体的加速度。当传感器经历加速度时,其电容板之间的距离随着传感器膜片的移动而变化,从而探测出加速度值。</p><p><strong>3.为什么要做组合导航</strong></p><p>实际应用中,单一的导航定位模式是很难满足导航性能要求的,提高导航系统整体性能的有效途径是采用组合导航技术,即用两种或两种以上的非相似导航系统对同一导航信息作测量并解算,以形成量测值,从这些量测值中计算出各导航系统的误差并校正。</p><p>例如陀螺仪测角速度,加速度测线性加速度。前者是惯性原理,后者是利用的力平衡原理。加速度计在较长时间的测量值是正确的,而在较短时间内由于信号噪声的存在,有误差。陀螺仪在较短时间内则比较准确,而较长时间则会有与漂移而存有误差。因此,需要两者相互调整来确保信号的正确。</p><p>又例如在整个系统中,IMU提供载体姿态,并可推算相对位置,其优点是更新频率高,输出连续,数据平稳,短期稳定性好,但缺点是存在误差累积,精度随时间而发散,长期稳定性差,因为位置信息和姿态信息是积分求得的。而GNSS卫星导航的优点是不存在位置误差累积,长期稳定性好,缺点是更新频率低,且信号存在不连续的可能。</p><p>所以GNSS和IMU两者可以实现互补,通过GNSS实现长时间绝对定位,在GNSS位置更新的间隙可以采取IMU进行推算定位,并利用GNSS修正误差。</p><p>由于IMU和GNSS在性能上正好形成互补,因此采用这两种设备组合起来作为定位定向系统设计是业内公认的最佳方案。</p><p><strong>六、IMU的主要参数</strong></p><p>对于性能参数要求,需要从加速度计和陀螺仪两个方面入手,相关的指标较多,一般主要是关注以下这些:</p><p><img src="/img/remote/1460000040534456" alt="" title=""></p><p><strong>七、影响精度的误差因素</strong></p><p>惯性导航系统中,硬件部分对精度造成影响的主要是IMU性能好坏,其误差源如下图所示:</p><p><img src="/img/remote/1460000040534457" alt="" title=""></p><p>惯性导航误差源</p><p><strong>1.陀螺仪影响因素</strong></p><p>作为惯性导航设备上的核心传感器,陀螺仪的重要程度不言而喻。姿态推算数据很大程度上需要依赖角速度的数据质量,因此陀螺仪的精确性将直接影响解算的优劣程度,换句话说,最后IMU能否正确感知载体的姿态就是依靠陀螺仪的精度性能。</p><p><strong>2.加速度计影响因素</strong></p><p>在IMU中,加速度计对其的影响主要体现在加速度计的稳定性和精度两个方面。其中加速度计的高精度是为保障后续数据处理的精确性,加速度计的稳定性则是直接影响IMU能否发挥出正常性能的关键因素之一。</p><p><strong>3.温度影响因素</strong></p><p>传感器在温度发生变化时,其精度会产生较大的差异,一般情况下,惯性器件的工作环境不可能是恒温环境,尤其是陀螺的精度受到严重影响,因此温度的影响不能忽略。</p><p><strong>4.误差处理</strong></p><p>定位定向系统的误差源很多,在惯性器件的硬件方面误差一般分成两类:系统性误差和随机误差。系统性误差本质就是能找到规律的误差,所以可以实时补偿掉,主要包括常值偏移、比例因子、安装误差等。</p><p>但是随机误差一般指噪声,无法找到合适的关系函数去描述噪声,所以很难处理。一般采用allan方差、时间序列分析法等手段对零点偏移的数据进行误差建模分析,例如可以用卡尔曼滤波算法减小随机噪声的影响。</p><p><strong>八、怎么选定位系统</strong></p><p>设计高精采集系统的方案时,一个重要的事情就是惯性导航设备的选取,因为它不仅关系到硬件成本,还关乎到最终产品的精度性能。具体选型时,主要任务之一是考察其中的IMU,无外乎要关注如下几个方面,然后根据产品需求进行取舍。</p><ul><li>传感器的各项指标参数是否满足需求。</li><li>传感器的价格是否合理,供应链是否完善。</li><li>配套软硬件的设计难度是否可以接受。</li><li>厂商的技术支持能力、配套服务是否良好。</li></ul><p>这其中最主要的是第一项,也是先决条件,只有当技术性能满足要求,才会去进行下一步的成本、商务方面的考量。</p><p><strong>1.指标分析</strong></p><p>我们还是从最重要的技术方面分析,介绍几个在陀螺选型过程中比较关键的指标:</p><p><strong>量程</strong></p><p>量程是在选用传感器的时候要首先确定的,所选传感器用于什么领域,一般对车载来说,陀螺选择在300度/秒以内、加速度计在4G以内就可以了,其他的根据自己的使用场景做选择,比如说机载的量程需要大一些,轨道交通上的可以更小。高精度的情况下,量程小一点对应的精度会高一些。</p><p><strong>零偏及零偏稳定性</strong></p><p>从原理上来讲,陀螺仪上电或开始工作时会出现漂移,又分为<strong>常值漂移</strong>和<strong>随机漂移</strong>两种,其中常值漂移就叫零偏,也可称为零漂,单位为°/h、°/s。通过获取陀螺仪的零偏,我们就可以在后续使用中对其进行补偿,但补偿的是多次测量的均值,在补偿后常值漂移在陀螺的输出中还会有一部分残余,因此,就出现了陀螺测试中的零偏重复性指标,它表征陀螺每次零偏的接近重复程度,零偏重复性好的陀螺经过标定补偿后,残余的常值漂移比较小,可以达到更高的精度。</p><p>零偏稳定性则是计算一次通电过程中陀螺输出数据的方差得到,计算方差时上面提到的常值漂移被扣除,因此零偏稳定性反映的是陀螺的随机漂移指标,又称随机噪声。</p><p>零偏及零偏稳定性,很大程度上反应了陀螺和加速度计的性能,长久以来它被视为惯性器件规格的关键指标。选型时应根据成本和精度要求,选择合适的型号。</p><p><strong>角度随机游走</strong></p><p>当陀螺仪处于零输入状态时,输出信号为白噪声和慢变随机函数的叠加。漫变随机函数可用来确定零偏和零偏稳定性指标。</p><p>陀螺随机游走所产生的姿态和速度长值误差为零,但速度和姿态存在一定的震荡误差,震荡幅值与陀螺漂移随机游走大小相关。随机游走会引起震荡幅值较大的位置误差,但位置误差均值并不随时间线性增长,而是呈现随机游走过程。</p><p>随机游走反映了陀螺仪的研制水平,也反映了陀螺仪最小可检测的角速率。</p><p><strong>物理条件</strong></p><p>(1)外形尺寸</p><p>评估外形尺寸主要需根据实际车辆安装情况,选择合适的尺寸,且需要IMU具有良好的环境适应性。对于IMU本体来说,其质心位置应尽量与IMU物理中心贴近。</p><p>(2)电气及接口要求</p><p>常规的车辆供电为9-16V,选型应考虑其工作电压范围是否符合,否则需要增加电源转换模块。此外,需考察是否有短路、过压等自我保护功能。</p><p>接口方面,需明确接口类型和线缆形式,如USB/以太网/串口等,数据速率与通讯形式是否匹配等,避免使用中出现数据中断丢失等情况。</p><p>(3)环境要求</p><p>惯性传感器对温度变化都很敏感,因此需注意其温度漂移相关指标,对某些温漂大的设备,应注意安装环境,并尽量提供稳定的工作环境温度,例如加风扇/空调散热,或是加温装置等。</p><p>此外,需注意IMU的防护等级,选择车外或车内安装,并做好相应的防水防尘措施。</p><p>(4)相关标准及规范要求</p><p>包括并不限于:</p><ul><li>车载卫星导航设备通用规范(GB/T 19392-2013)。</li><li>车载电子设备可靠性测试标准(ISO 16750)。</li><li>道路车辆功能安全国际标准(ISO 26262 2018)。</li><li>道路车辆电气及电子设备的环境条件和试验(GB/T 28046)。</li></ul><p><strong>2.注重测试</strong></p><p>对于惯性导航设备这类注重性能、功能单一的产品,需着重考察其实际表现,不能完全相信技术手册中的指标,例如下面二款常用的大厂出品的主流设备,可以看到参数差别不大,精度也都很高,实际表现如何呢?</p><p>Trimble POS LV 510标称精度指标:</p><p><img src="/img/remote/1460000040534458" alt="" title=""></p><p>Novatel SPAN-CPT标称精度指标:</p><p><img src="/img/remote/1460000040534459" alt="" title=""></p><p>其实一分钱一分货,价格也自然代表了性能,POS LV510精度实际上大幅优于CPT,所以二者的应用场景也不同,510可以做高精采集,CPT只用来做更新或者ADAS采集。</p><p>另外不要被指标迷惑了,标称的0.02米的精度,那是理想作业情况的结果。</p><p>除了看指标,还能怎么选呢?</p><p>俗话说是骡子是马,拉出来溜溜,这话放在选型上也适用,我们的办法就是:实测。毕竟实践是检验真理的唯一标准。</p><p>目前,<strong>定位定向系统级测试方法主要有:实际运动试验,软件仿真测试,软件-硬件结合的半物理实物仿真测试</strong>。这里面,实际运动试验显然是最直观真实的,我们通常采用跑车试验来考察精度情况。</p><p>试验阶段一般分设备准备、路线规划、数据采集、数据分析几个步骤。</p><p><strong>设备准备</strong>:做定位定向系统的精度评估,需要一个参考标准,这样当行驶同样的路线时,被测设备的轨迹及姿态误差情况才能够得到准确的量化,实践中往往是用一个等级很高的设备作为基准,即真值,与被测设备共同安装在同一载体平台上,采集同一路线的轨迹和载体姿态。</p><p>安装时,含有IMU的部分需要牢固的安装在平台上,本体测量方向保持和车辆的前进、水平方向正交/平行,不可自由晃动;天线的安装位置应保证无遮挡,收星状态良好,附近无干扰源。必要的情况下需接入里程计。电源及数据线缆按照规定连接。</p><p><strong>线路规划</strong>:不同的场景对定位系统的需求会不一样,但对我们来说,主要是道路数据采集,并且是全路况采集,这就不仅仅是高速路、乡村道路这种卫星信号良好、对惯性导航要求不高的路段,也包括城市普通路、环线、高架桥上下、停车场、普通国道等卫星信号有遮蔽甚至中断的场景,因此测试路段选择,需尽可能全面,覆盖这些场景。</p><p>除正常测试的场景要求外,因为惯导往往有初始化的需求,因此在测试线路的起点和终点,都应选择开阔地、卫星信号好的地方。</p><p><strong>数据采集</strong>:数据采集相对简单,遵守相关作业规范,按照规定线路采集被测设备和真值设备的数据即可。为保证可靠性和一致性并便于对比,往往是同一线路做多次往复采集。参考站方面,可以自行架设,也可以使用千寻等服务商的数据。</p><p><strong>数据分析</strong>:跑车结束后,采集的惯导、GNSS原始数据,及参考站数据进入后处理软件进行各项预处理、格式转换、滤波、差分解算、融合、平滑处理等一系列过程后,输出轨迹和姿态数据。</p><p><img src="/img/remote/1460000040534460" alt="" title=""></p><p>数据分析</p><p>可以选取多条轨迹,在平面位置、高程、航向角、翻滚俯仰角等指标上与真值设备的输出做对比,得出各种场景下的误差范围,据此分析被测设备的性能,为选型做依据。</p><p>除了使用更高等级的设备作为真值来检验被测设备的精度外,也可以使用其他方法,例如,标定好的近景摄影测量采集系统+控制场的方法,来估算精度情况。</p><p><strong>九、小结</strong></p><p>本文从硬件角度大致介绍了定位定向系统中惯性导航设备及其传感器的基本情况。实际上,这些传感器在应用中,仍有很多环节需要处理,才能够达到最终用户使用的状态。像出厂前的环境试验、老化、筛选、转台标定等等,也是十分重要的,而组合推算算法更是关键,这些组合拳一整套都打下来,才有了高精。</p><p>对定位、惯性导航感兴趣的同学,推荐阅读<strong>西工大秦永元</strong>、<strong>严龚敏</strong>老师的系列书籍,写的很系统。</p><p><img src="/img/remote/1460000040534461" alt="" title=""></p>
手把手教你玩转HarmonyOS版地图应用开发
https://segmentfault.com/a/1190000040428826
2021-07-30T14:32:38+08:00
2021-07-30T14:32:38+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>一、导读</strong></p><p>7月31日,华为HarmonyOS开发者日将在杭州举行。为了方便更多开发者,高德开放平台地图SDK已在业内率先实现鸿蒙化迁移和重构,<strong>全面适配HarmonyOS并面向开发者免费发布</strong>。开发者可到高德开放平台官网了解更多内容,获取版本下载、开发文档、常见问题等支持。</p><p>访问高德开放平台:<a href="https://link.segmentfault.com/?enc=C7jPn8dsvpZz5ez93hWnjQ%3D%3D.lyfaeTWyoN2%2BOQnBXvXaEb9x0UsAwxn16v3BxkyHUGE%3D" rel="nofollow">https://lbs.amap.com/</a></p><p>在今年6月2日,华为就正式发布了HarmonyOS。由于HarmonyOS在兼容Android上有特殊要求,如果APP应用是用Android API开发,开发者可以直接使用Android的SDK。</p><p>但如果APP用了HarmonyOS的API开发,就不能用Android的SDK而需要使用HarmonyOS版本的SDK。</p><p>为了方便开发者在HarmonyOS的相应设备中进行LBS服务的开发,高德开放平台率先进行了HarmonyOS适配,首批适配范围包括地图和搜索SDK,支持嵌入搭载HarmonyOS的手机、Pad及其他智能终端设备。</p><p><img src="/img/remote/1460000040428828" alt="" title=""></p><p><strong>二、HarmonyOS地图SDK特性介绍</strong></p><p><strong>与高德开放平台Android地图SDK平滑切换</strong></p><ul><li>已集成高德开放平台Android地图SDK的开发者可无缝切换到HarmonyOS地图SDK,无额外开发量。HarmonyOS与Android系统间的接口变化由高德开放平台SDK适配层消化,SDK对外接口保持不变。</li><li>高德底层引擎对接HarmonyOS NDK,上层代码全面对接HarmonyOS SDK,所有系统接口均使用HarmonyOS API。</li></ul><p><img src="/img/remote/1460000040428829" alt="" title=""></p><p><strong>继承高德开放平台Android/iOS地图SDK功能亮点</strong></p><ul><li>开发者可以通过高德开放平台API和SDK,轻松完成地图的构建工作,将地图精致地呈现在您的应用中。地图SDK不仅提供丰富的地图覆盖物绘制能力,也支持搜索、多种路径规划、坐标转换、距离测量、面积计算等功能。</li><li>适配HarmonyOS后的地图SDK依旧支持与自定义地图SaaS平台等周边工具配合使用,开发者可以在平台中定制区域面、建筑物、水系、天空、道路、标注、行政边界共7大类40余种地图元素,灵活设计心仪的地图样式。更多地图SDK基础能力、自定义、可视化能力详情请参考高德开放平台官网。</li></ul><p><img src="/img/remote/1460000040428830" alt="" title=""></p><p><strong>HarmonyOS版地图SDK整体框架</strong></p><p>HarmonyOS和Android系统差异很大,几乎所有的API都有调整,不少API都调整了实现方案,所以不能通过改包名来实现适配。我们将原生SDK中所有调用Android的代码均切换为适配层,在适配层将SDK的接口一一适配到HarmonyOS接口。</p><p>HarmonyOS版地图SDK整体框架大致如下:</p><p><img src="/img/remote/1460000040428831" alt="" title=""></p><p><strong>三、如何集成-从零开始</strong></p><p><strong>第一步 搭建HarmonyOS开发环境</strong></p><p>完成DevEco Studio安装、环境配置和工程创建,参考HarmonyOS官网说明:<a href="https://link.segmentfault.com/?enc=u8szFeIiOnFzhe12%2FZGbBw%3D%3D.KiITDUpKaAPhLk4H7fYevOunGVAt2%2FoNfINYytiLnNf4NK8KSsCF%2B00v8%2FFaYS%2FNZJQQ4h0x9IfGdSyvgFjdajlPscy%2BupmWmwjImxMdsZm0r9N%2B5%2FBxDWekiSNWR7r9" rel="nofollow">https://developer.harmonyos.c...</a></p><p><strong>第二步 配置应用的签名信息</strong></p><p>应用工程创建完成后,需要配置签名信息,才可以使用真机调试和发布应用。</p><p><strong>第三步 获取应用的appId</strong></p><p>配置完签名信息之后,就可以获取当前应用的appId了,这个appId主要用于申请高德的apiKey,请确定最终发布应用的appId,防止最终高德SDK鉴权失败。</p><p>通过代码获取应用的appId方式如下:</p><pre><code>getApplicationContext().getBundleManager().getBundleInfo(getBundleName(), 0).getAppId()</code></pre><p><strong>注意</strong>:目前通过DevEco Studio连接云真机获取到的appId不全,只获取到了"包名_", 使用云真机调试高德地图SDK时会导致鉴权不通过。正确的appId形式为:"包名_签名信息", 例如:com.amap.demo_BGtGgVB3ASqU7XXXXV2/zhoYh6tFQHAd5DASWVTEAgvZfzrEGljjs=</p><p><strong>第四步 在高德开放平台官网控制台申请API Key</strong></p><p><strong>创建新应用</strong></p><p>从开放平台官网右上角入口-控制台,创建一个新应用。如果您之前已经创建过应用,可直接跳过这个步骤。</p><p><img src="/img/remote/1460000040428832" alt="" title=""></p><p><img src="/img/remote/1460000040428833" alt="" title=""></p><p><strong>添加新Key</strong></p><p>在创建的应用上点击"添加新Key"按钮,在弹出的对话框中,依次:输入应用名名称,选择绑定的服务为“Harmony平台SDK”,输入AppID,如下图所示:</p><p>需要注意:1个Key只能用于一个应用(多渠道安装包属于多个应用),1个Key在多个应用上使用会出现服务调用失败。</p><p><img src="/img/remote/1460000040428834" alt="" title=""></p><p>在阅读完高德地图API服务条款后,勾选此选项,点击“提交”,完成Key的申请,此时您可以在所创建的应用下面看到刚申请的Key了。</p><p><strong>第五步 在代码中设置申请的Key</strong></p><p>请使用API的方式将申请的高德API Key设置给高德地图SDK。</p><pre><code>/**
* 动态设置apiKey。
*
* @param apiKey 在高德官网上申请的apiKey。
*/
MapsInitializer.setApiKey(String apiKey)</code></pre><p>注意:请确保在调用任何高德地图SDK的接口之前将API Key设置给高德地图SDK,建议放到Application的初始化之中。</p><p>完成以上5步之后,就可以愉快的使用HarmonyOS版高德地图SDK了。</p><p><strong>四、如何使用-创建地图</strong></p><p>使用地图SDK之前,需要在config.json文件中进行相关权限设置,确保地图功能可以正常使用。</p><p><strong>第一步 配置config.json</strong></p><p>首先,声明权限。</p><pre><code>...
"reqPermissions": [
{
"usedScene": {
"ability": [
"com.example.harmonysearchsdk.MainAbility"
],
"when": "always"
},
"reason": "request internet",
"name": "ohos.permission.INTERNET"
}
]
...</code></pre><p><strong>第二步 向工程中添加地图开发包</strong></p><p>将har包放入libs目录下,依次添加依赖。</p><pre><code>dependencies {
implementation files("libs/xxx.har")
//...
}</code></pre><p>或者直接使用引入libs下所有har包的方式:</p><pre><code>dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
//...
}</code></pre><p><strong>第三步 初始化地图容器</strong></p><p><strong>设置Key</strong></p><p>获取Key方式请参考上方“从零开始”章节第四步。</p><pre><code>MapsInitializer.setApiKey("您的key");</code></pre><p><strong>创建MapView</strong></p><pre><code>public class BasicMapDemoSlice extends Ability {
private MapView mapView;
@Override
protected void onStart(Intent intent) {
super.onStart(intent);
initMapView();
}
private void initMapView() {
mapView = new MapView(this);
mapView.onCreate(null);
mapView.onResume();
DirectionalLayout.LayoutConfig config = new DirectionalLayout.LayoutConfig(
DirectionalLayout.LayoutConfig.MATCH_PARENT, DirectionalLayout.LayoutConfig.MATCH_PARENT);
mapView.setLayoutConfig(config);
super.setUIContent(mapView);
}
@Override
protected void onStop() {
super.onStop();
if (mapView != null) {
mapView.onDestroy();
}
}
}</code></pre><p><strong>初始化地图并获取AMap对象</strong></p><pre><code>AMap aMap = mapView.getMap();
aMap.setOnMapLoadedListener(new AMap.OnMapLoadedListener() {
@Override
public void onMapLoaded() {
// todo
}
});</code></pre><p>至此就可以看到地图展示,并且拿到AMap对象后,就可以往地图上添加点线面等覆盖物了。</p><p><strong>五、获取更多详情和开发支持</strong></p><p>访问高德开放平台:<a href="https://link.segmentfault.com/?enc=plltVhgi36jUh3Ve8A%2FGAg%3D%3D.tAtzJDJ4yuxH5cRVdcEIxmAR%2FHWMpRAM8UyXnlKOqLE%3D" rel="nofollow">https://lbs.amap.com/</a></p><p>获取HarmonyOS版高德地图SDK下载、开发文档、Demo等开发支持:<a href="https://link.segmentfault.com/?enc=8V6q%2BconfUxf8YVuQ3zrsA%3D%3D.jgibabNqaawCiqBQbBaXQplHimXNfPboSi0YOCLNfY%2Fpq0kmzlcgksGJ0SizoiZZ" rel="nofollow">https://lbs.amap.com/api/harm...</a></p><p><img src="/img/remote/1460000040428835" alt="" title=""></p>
经验总结 | 重构让你的代码更优美和简洁
https://segmentfault.com/a/1190000040358117
2021-07-16T15:12:20+08:00
2021-07-16T15:12:20+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>1. 前言</strong></p><p>最近,笔者有幸对高德打车订单Push项目进行了重构,与大家分享一下代码重构相关的工作经验,希望对大家有所启发。</p><p>有时候,我们在做某个功能需求时,需要花掉大量的时间,才能找到和需求有关联的代码。或者,我们在阅读别人写的代码、接手别人的项目时,总是“头皮发麻”,当你面对结构混乱、毫无章法的代码结构,词不达意的变量名、方法名时,我相信你根本没有读下去的心情。这不是你的问题,而是你手中的代码需要进行重构了。</p><p><img src="/img/remote/1460000040358119" alt="" title=""></p><p><strong>2. 何为重构</strong></p><p>每个人对重构都有自己的定义,我这里引用的是“Martin Fowler”的,他从两个维度对重构进行了定义。</p><blockquote><p>作为名词:重构是对软件内部结构的一种调整,目的是在不改变软件可观察行为前提下,提高其可理解性,降低其修改成本。 </p><p>作为动词:重构是使用一系列重构手法,在不改变软件可观察行为的前提下,调整其结构。</p></blockquote><p><strong>我在本文提到的代码重构,更偏向它作为动词的定义</strong>,而根据重构的规模程度、时间长短,我们可以将代码重构分为<strong>小型重构</strong>和<strong>大型重构</strong>。</p><p><strong>小型重构</strong>:是对代码的细节进行重构,主要是针对类、函数、变量等代码级别的重构。比如常见的规范命名(针对词不达意的变量再命名),消除超大函数,消除重复代码等。一般这类重构修改的地方比较集中,相对简单,影响比较小、时间较短。所以难度相对要低一些,我们完全可以在日常的随版开发中进行。</p><p><strong>大型重构</strong>:是对代码顶层进行重构,包括对系统结构、模块结构、代码结构、类关系的重构。一般采取的手段是进行服务分层、业务模块化、组件化、代码抽象复用等。这类重构可能需要进行原则再定义、模式再定义甚至业务再定义。涉及到的代码调整和修改多,所以影响比较大、耗时较长、带来的风险比较大(项目叫停风险、代码Bug风险、业务漏洞风险)。这就需要我们具备大型项目重构的经验,否则很容易犯错,最后得不偿失。</p><p>其实大多数人都是不喜欢重构工作的,就像没有人愿意给别人“擦屁股”一样,主要可能有以下几个方面的担忧:</p><ul><li>不知道怎么重构,缺乏重构的经验和方法论,容易在重构中犯错。</li><li>很难看到短期收益,如果这些利益是长远的,何必现在就付出这些努力呢?长远看来,说不定当项目收获这些利益时,你已经不负责这块工作了。</li><li>重构会破坏现有程序,带来意想不到的Bug,不想去承受这些意料之外的Bug。</li><li>重构需要你付出额外的工作,何况可能需要重构的代码并不是你编写的。</li></ul><p><strong>3. 为何重构</strong></p><blockquote>如果我纯粹为今天工作,明天我将完全无法工作。</blockquote><p>程序有两面价值:“今天可以为你做什么” 和 “明天可以为你做什么”。大多数时候,我们都只关注自己今天想要程序做什么。不论是修复错误或是添加特性,都是为了让程序力更强,让它在今天更有价值。但是我为什么还是提倡大家要在合适的时机做代码重构,原因主要有以下几点:</p><ul><li><strong>让软件架构始终保持良好的设计。</strong>改进我们的软件设计,让软件架构向有利的方向发展,能够始终对外提供稳定的服务、从容的面对各种突发的问题。</li><li><strong>增加可维护性,降低维护成本,对团队和个人都是正向的良性循环,让软件更容易理解。</strong>无论是后人阅读前人写的代码,还是事后回顾自己的代码,都能够快速了解整个逻辑,明确业务,轻松的对系统进行维护。</li><li><strong>提高研发速度、缩短人力成本。</strong>大家可能深有体会,一个系统在上线初期,向系统中增加功能时,完成速度非常快,但是如果不注重代码质量,后期向系统中添加一个很小的功能可能就需要花上一周或更长的时间。而代码重构是一种有效的保证代码质量的手段,良好的设计是维护软件开发速度的根本。重构可以帮助你更快速的开发软件,因为它阻止系统腐烂变质,甚至还可以提高设计质量。</li></ul><p><img src="/img/remote/1460000040358120" alt="" title=""></p><p><img src="/img/remote/1460000040358121" alt="" title=""></p><p><strong>4. 如何重构</strong></p><p><strong>小型重构</strong></p><p>小型重构大部分都是在日常开发中进行的,一般的参考标准即是我们的开发规范和准则,目的是为了解决代码中的坏味道,我们来看一下常见的坏味道都有哪些?</p><p><strong>泛型擦除</strong></p><pre><code>//{"param1":"v1", "param2":"v2", "param3":30, ……}
Map map = JSON.parseObject(msg); //【1】
……
// 将map作为参数传递给底层接口
xxxService.handle(map); //【2】
//看一下底层接口定义
void handle(Map<String, String> map); //【3】</code></pre><p>【2】处将已经泛型擦除的map传递给底层已经泛型限定的接口中,相信在接口实现中都是使用“String value = map.get(XXX)”这种方式获取值的,这样一旦map中有非String类型的值,这里就会出现类型转换异常。读者肯定和我一样好奇,为何该业务系统中未抛出类型转换异常,原因是业务系统取值的方式并未转换成String类型。可想而知,一但有人使用标准的方式获取值时,就会踩雷。</p><pre><code>// 文本1${param1}文本2${param2}文本3${param3}
String[] terms = ["文本1","$param1", "文本2", "$param2", "文本3", "$param3"];
StringBuilder builder = new StringBuilder();
for(String term: terms){
if(term.startsWith("$")){
builder.append(map.get(term.substring(1)));
}else{
builder.append(term);
}
}</code></pre><p><strong>无病呻吟</strong></p><pre><code>Config config = new Config();
// 设置name和md5
config.setName(item.getName());
config.setMd5(item.getMd5());
// 设置值
config.setTypeMap(map);
// 打印日志
LOGGER.info("update done ({},{}), start replace", getName(), getMd5());
......
ExpiredConfig expireConfig = ConfigManager.getExpiredConfig();
// 为空初始化
if (Objects.isNull(expireConfig)) {
expireConfig = new ExpiredConfig();
}
......
Map<String, List<TypeItem>> typeMap = ……;
Map<String, Map<String, Map<String, List<Map<String, Object>>>>> jsonMap = new HashMap<>();
// 循环一级map
jsonMap.forEach((k1, v1) -> {
// 循环里面的二级map
v1.forEach((k2, v2) -> {
// 循环里面的三级map
v2.forEach((k3, v3) -> {
// 循环最里面的list,哎!
v3.forEach(e -> {
// 生成key
String ck = getKey(k1, k2, k3);
// 为空处理
List<TypeItem> types = typeMap.get(ck);
if (CollectionUtils.isEmpty(types)) {
types = new ArrayList<>();
typeMap.put(ck, types);
}
// 设置类型
}
}
}
}</code></pre><p>代码本身一眼就能看明白是在干什么,写代码的人非要在这个地方加一个不关痛痒的注释,这个注释完全是口水话,毫无价值可言。</p><p><strong>if-else过多</strong></p><pre><code>try {
if (StringUtils.isEmpty(id)) {
if (StringUtils.isNotEmpty(cacheValue)) {
if (StringUtils.isNotEmpty(idPair)) {
if (cacheValue.equals(idPair)) {
// xxx
} else {
// xxx
}
}
} else {
if (StringUtils.isNotEmpty(idPair)) {
// xxx
}
}
if(xxxx(xxxx){
// xxx
}else{
if(StringUtils.isNotEmpty(idPair)){
// xxx
}
// xxx
}
}else if(!check(id, param)){
// xxx
}
} catch (Exception e) {
log.error("error:", e);
}</code></pre><p>这样的代码,让代码的阅读性大大降低,令很多人望而却步。除非被逼的迫不得已,否则估计开发人员是不会动这样的代码的,因为你不知道你动的一小点,可能会让整个业务系统瘫痪。</p><p><strong>其他坏味道</strong></p><p><img src="/img/remote/1460000040358122" alt="" title=""></p><p>这里就不再罗列相关案例了,相信大家在日常也经常看到很多代码书写不合理,让人不适应的地方,总结一下代码中常见的坏味道和解决办法:</p><p><strong>重复代码</strong></p><p>代码坏味道最多的恐怕就是重复代码,如果你在一个以上的地方看到相同的代码结构,那么可以肯定:设法将它们合而为一,程序会变得更好。</p><p>最常见的一种重复场景就是在“<strong>同一个类的两个函数含有相同的表达式</strong>”,这种形式的重复代码可以在当前类提取公用方法,以便在两处复用。</p><p>还有一种和这类场景相似,就是在“<strong>两个互为兄弟的子类含有相同的表达式</strong>”,这种形式可以将相同的代码提取到共同父类中,针对有差异化的部分,使用抽象方法延迟到子类实现,这就是常见的模板方法设计模式。如果两个毫不相干的类出现了重复代码,这个时候应该考虑将重复代码提炼到一个新类中,然后在这两个类中调用这个新类的方法。</p><p><strong>函数过长</strong></p><p>一个好的函数必须满足单一职责原则,短小精悍,只做一件事。过长的函数体和身兼数职的方法都不利于阅读,也不利于进行代码复用。</p><p><strong>命名规范</strong></p><p>一个好的命名需要能做到“名副其实、见名知意”,直接了当,不存在歧义。</p><p><strong>不合理的注释</strong></p><p>注释是一把双刃剑,好的注释能够给我们好的指导,不好的注释只会将人误导。针对注释,我们需要做到在整合代码时,也把注释一并进行修改,否则就会出现注释和逻辑不一致。另外,如果代码已清晰的表达了自己的意图,那么注释反而是多余的。</p><p><strong>无用代码</strong></p><p>无用代码有两种方式,一种是没有使用场景,如果这类代码不是工具方法或工具类,而是一些无用的业务代码,那么就需要及时的删除清理。另外一种是用注释符包裹的代码块,这些代码在被打上注释符号的时候就应该被删除。</p><p><strong>过大的类</strong></p><p>一个类做太多事情,维护了太多功能,可读性变差,性能也会下降。举个例子,订单相关的功能你放到一个类A里面,商品库存相关的也放在类A里面,积分相关的还放在类A里面……试想一下,乱七八糟的代码块都往一个类里面塞,还谈啥可读性。应该按单一职责,使用不同的类把代码划分开。</p><p>这些都是比较常见的代码“坏味道”,实际开发中当然还会存在其他的一些“坏味道”,比如代码混乱,逻辑不清晰,类关系错综复杂,当闻到这些不同的“坏味道”时,都应该尝试去解决掉,而不是放纵不管不顾。</p><p><strong>大型重构</strong></p><p>相对小型重构,大型重构需要考虑的事情比较多,需要定好节奏,按部就班的执行,因为在大型重构中,情况多变。</p><p>将大象装进冰箱的步骤一般可以分成三步:1)把冰箱门打开(事前);2)把大象推进去(事中);3)把冰箱门关上(事后)。日常所有的事情都可以采用三步法进行解决,重构也不例外。</p><p><img src="/img/remote/1460000040358123" alt="" title=""></p><p><strong>事前</strong></p><p>事前准备作为重构的第一步,这一部分涉及到的事情比较杂,也是最重要的,如果之前准备不充分,很有可能导致在事中执行或重构上线后产生的结果和预期不一致的现象。</p><p>在这个阶段大致可分为三步:</p><ul><li><strong>明确重构的内容、目的以及方向、目标</strong></li></ul><p>在这一步里面,最重要的是把方向明确清楚,而且这个方向是经得起大家的质疑,能够至少满足未来三到五年的方向。另外一个就是这次重构的目标,由于技术限制、历史包袱等原因,这个目标可能不是最终的目标,那么需要明确最终目标是怎么样的,从这次重构的这个目标到最终的目标还有哪些事情要做,最好都能够明确下来。</p><ul><li><strong>整理数据</strong></li></ul><p>这一步需要对涉及重构部分的现有业务、架构进行梳理,明确重构的内容在系统的哪个服务层级、属于哪个业务模块,依赖方和被依赖方有哪些,有哪些业务场景,每个场景的数据输入输出是怎样的。这个阶段就会有产出物了,一般会沉淀项目部署、业务架构、技术架构、服务上下游依赖、强弱依赖、项目内部服务分层模型、内容功能依赖模型、输入输出数据流等相关的设计图和文档。</p><ul><li><strong>项目立项</strong></li></ul><p>项目立项一般是通过会议进行,对所有参与重构的部门或小组进行重构工作的宣讲,周知大概的时间计划表(粗略的大致时间),明确各组主要负责的人。另外还需要周知重构涉及到哪些业务和场景、大概的重构方式、业务影响可能有哪些,难点及可能在哪些步骤出现瓶颈。</p><p><strong>事中</strong></p><p>事中执行这一步骤的事情和任务相对来说比较繁重一些,时间付出相对比较多。</p><ul><li><strong>架构设计与评审</strong></li></ul><p>架构设计评审主要是对标准的业务架构、技术架构、数据架构进行设计与评审。通过评审去发现架构和业务上的问题,这个评审一般是团队内评审,如果在一次评审后,发现架构设计并不能被确定,那就需要再调整,直到团队内对方案架构设计都达成一致,才可以进行下一步,评审结果也需要在评审通过后进行邮件周知参与人。</p><p>该阶段产出物:重构后的服务部署、系统架构、业务架构、标准数据流、服务分层模式、功能模块UML图等。</p><ul><li><strong>详细落地设计方案与评审</strong></li></ul><p>这个落地的设计方案是事中执行最重要的一个方案,关系到后面的研发编码、自测与联调、依赖方对接、QA测试、线下发布与实施预案、线上发布与实施预案、具体工作量、难度、工作瓶颈等。这个详细落地方案需要深入到整个研发、线下测试、上线过程、灰度场景细节处包括AB灰度程序、AB验证程序。</p><p>在方案设计中最重要的一环是AB验证程序和AB验证开关,这是评估和检验我们是否重构完成的标准依据。一般的AB验证程序大致如下:</p><p><img src="/img/remote/1460000040358124" alt="" title=""></p><p>在数据入口处,使用相同的数据,分别向新老流程都发起处理请求。处理结束之后,将处理结果分别打印到日志中。最后通过离线程序比较新老流程处理的结果是否一致。遵循的原则就是在相同入参的情况下,响应的结果也应该一致。</p><p>在AB程序中,会涉及到两个开关。<strong>灰度开关</strong>(只有它开启了,请求才会被发送到新的流程中进行代码执行)。<strong>执行开关</strong>(如果新流程中涉及到写操作,这里需要用开关控制在新流程写还是在老流程中写)。转发之前需要将灰度开关和执行开关(一般配置到配置中心,能随时调整)写入到线程上下文中,以免出现在修改配置中心开关时,多处获取开关结果不一致。</p><ul><li><strong>代码的编写、测试、线下实施</strong></li></ul><p>这一步就是按照详细设计的方案,进行编码、单测、联调、功能测试、业务测试、QA测试。通过后,在线下模拟上线流程和线上开关实施过程,校验AB程序,检查是否符合预期,新流程代码覆盖度是否达到上线要求。如果线下数据样本比较少,不能覆盖全部场景,需要通过构造流量覆盖所有的场景,保证所有的场景都能符合预期。当线下覆盖度达到预期,并且AB验证程序没有校验出任何异常时,才能执行上线操作。</p><p><strong>事后</strong></p><p>这个阶段需要在线上按照线下模拟的实施流程进行线上实施,分为上线、放量、修复、下线老逻辑、复盘这样几个阶段。其中最重要最耗费精力的就是放量流程了。</p><ul><li><strong>灰度开关流程</strong></li></ul><p>逐步放量到新的流程中进行观察,可以按照1%、5%、10%、20%、40%、80%、100%的进度进行放量,让新流程逐步的进行代码逻辑覆盖,注意这个阶段不会打开真实执行写操作的开关。当新流程逻辑覆盖度达到要求、并且AB验证的结果都符合预期后,才可以逐步打开执行写操作开关,进行真实业务的执行操作。</p><ul><li><strong>业务执行开关流程</strong></li></ul><p>在灰度新流程的过程中符合预期后,可以逐步打开业务执行写操作开关流程,仍然可以按照一定的比例进行逐步放量,打开写操作后,只有新逻辑执行写操作,老逻辑将关闭写操作。这个阶段需要观察线上错误、指标异常、用户反馈等问题,确保新流程没有任何问题。</p><p>放量工作结束后,在稳定一定版本后,就可以将老逻辑和AB验证程序进行下线,重构工作结束。如果有条件可以开一个重构复盘会,检查每个参与方是否都达到了重构要求的标准,复盘重构期间遇到的问题、以及解决方案是什么样的,沉淀方法论避免后续的工作出现类似的问题。</p><p><strong>5. 总结</strong></p><p><strong>代码技巧</strong></p><ul><li>写代码的时候遵循一些基本原则,比如单一原则、依赖接口/抽象而不是依赖具体实现。</li><li>严格遵循编码规范、特殊注释使用 TODO、FIXME、XXX 进行注释。</li><li>单元测试、功能测试、接口测试、集成测试是写代码必不可少的工具。</li><li>我们是代码的作者,后人是代码的读者。写代码要时刻审视,做前人栽树后人乘凉、不做前人挖坑后人陪葬的事情。</li><li>不做破窗效应的第一人,不要觉得现在代码已经很烂了,没有必要再改,直接继续堆代码。如果是这样,总有一天自己会被别人的代码恶心到,“出来混迟早是要还的”。</li></ul><p><strong>重构技巧</strong></p><ul><li>从上至下,由外到内进行建模分析,理清各种关系,是重构的重中之重。</li><li>提炼类,复用函数,下沉核心能力,让模块职责清晰明了。</li><li>依赖接口优于依赖抽象,依赖抽象优于依赖实现,类关系能用组合就不要继承。</li><li>类、接口、抽象接口设计时考虑范围限定符,哪些可以重写、哪些不能重写,泛型限定是否准确。</li><li>大型重构做好各种设计和计划,线下模拟好各种场景,上线一定需要AB验证程序,能够随时进行新老切换。</li></ul><p><img src="/img/remote/1460000040358125" alt="" title=""></p>
地图采集车的那些事 | 时间同步
https://segmentfault.com/a/1190000040320215
2021-07-09T12:16:01+08:00
2021-07-09T12:16:01+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>1. 概述</strong></p><p>地图采集车上有相机、激光、惯导等多种传感器设备,采集的数据为图像、激光点云、轨迹等,生成地图数据的流程中,需要将这些数据关联起来,但是这些设备都是各自独立运行的,而能完成这个任务的就是<strong>时间同步系统</strong>。</p><p>时间同步系统是以GPS(Global Positioning System,全球定位系统)的时间信息为基础进行时间授时的。本文主要讲述时间系统中GPS授时原理、授时方法、授时过程以及授时中的异常情况。</p><p><strong>2. GPS 授时原理</strong></p><p>GPS卫星上搭载有高精度原子钟(铯原子),它能够让各个卫星之间保持高精度的时间同步,并且各自的时间起始时刻也能够对的很准。由于用户接收机与卫星存在钟差,对零点做时间参考系至少需要四颗卫星才能实现导航定位。</p><p>当用户解算出自己和卫星的钟差之后就可以校正自己本地的时钟,将其和卫星精准的时钟同步到同一个时刻,这个过程就叫<strong>授时</strong>。</p><p>原子钟的原理:原子中的电子从一个能级跃迁到另一个能级的时候,频率非常稳定,以此为钟摆就能得到非常精准的时间。</p><p>GPS授时原理是GPS接收机在任意时刻能同时接收其视野范围内>=4颗卫星信号,经解码和处理后从中提取并输出两种时间信号:</p><p>(1)时间间隔为1S的同步脉冲信号PPS( Pulse Per Second,秒脉冲),其脉冲前沿与国际标准时间的同步误差<1us.</p><p><img src="/img/remote/1460000040320217" alt="" title=""></p><p>(2)串行口输出的信息是与PPS前沿对应的国际标准时间和日期,应用最为广泛的是NMEA-0183协议,如$GPGGA,$GPRMC等。</p><p>GPRMC:Recommended Minimum SpeGPS / TRANSIT Data(RMC)推荐定位信息。</p><p>协议格式:</p><p>$GPRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>*hh<CR><LF></p><p>样例数据:</p><p>$GPRMC,161229.487,A,3723.2475,N,12158.3416,W,0.13,309.62,120598,*10 </p><p><img src="/img/remote/1460000040320218" alt="" title=""></p><p><strong>3. GPS授时方法</strong></p><p><strong>3.1 PPS与NMEA关系</strong></p><p>要讲述GPS的授时方法,要先了解PPS与NMEA的关系及作用,如下图所示,在GPS定位的情况下,PPS会先到,NMEA数据后到,但是不同GPS厂商设置的两者之间的时间间隔不尽相同,有的几毫秒,而有的几百毫秒。</p><p><img src="/img/remote/1460000040320219" alt="" title=""></p><p>PPS与NMEA</p><p>黄色:PPS,上升沿为整秒零时刻。</p><p>蓝色:NMEA,GPS时间信息,包含年月日、时分秒。</p><p><strong>3.2 GPS授时过程详解</strong></p><p><img src="/img/remote/1460000040320220" alt="" title=""></p><p>GPS授时系统结构图</p><p>如上图所示的GPS授时系统结构图:</p><p>(1)GPS接收机在定位的情况下产生输出PPS脉冲信号,以及有效的GPS时间信息,此信息以串行通信输出,TTL/RS232信号类型,ASCII码,波特率9600bps~460800bps,可配置,遵循的是NMEA-0183协议,此协议的数据信息有十几种之多,而提取GPS时间信息的语句,通常RMC足以满足要求。</p><p>(2)晶振可以为MCU(Microcontroller Unit,微控制单元或者单片机)提供精确的时钟源,维持系统运行,受环境影响较大,特别是温度变化。可选用OCXO—恒温晶振,温度特性达到3ppb。</p><p>(3)具体的做法如下:</p><ul><li>通过提取RMC中的GPS时间信息,得到时分秒、年月日,并赋值给以晶振为时钟源的系统时间,使MCU的系统时间校正为UTC时间。</li><li>MCU利用IO的中断机制得到PPS的脉冲时刻,以此为基础将毫秒及以下时间清零,从而校正系统时间的整秒零时刻。</li><li>Check时间,等3秒后,再取GPS时间与系统时间对比,是否吻合,验证PPS授时整秒时可能出现的+1秒或-1秒的情况。</li></ul><p><img src="/img/remote/1460000040320221" alt="" title=""></p><p>如上图所示,是授时后测试的数据样例。利用GPS接收机的EVENT功能和MCU同时记录同一个信号脉冲,然后做时间对比,测试的路段有高架桥、商场、环线、街道等多场景。测试时长为5小时38分钟,对比结果为:秒差值=0,微秒差值<=4us。</p><p><strong>3.3 时间同步系统的应用之相机同步</strong></p><p>图像数据来源是采集车上的传感器——相机,我们的采集车上安装有多个相机,分布在车顶平台的不同位置,朝向各个方向,采集道路标识、POI等,这些图像信息要与位置轨迹信息匹配才能作为地图数据,时间同步系统就可以将这些数据进行唯一匹配。</p><p><img src="/img/remote/1460000040320222" alt="" title=""></p><p>时间同步系统之相机时间同步结构图</p><p>如上图所示,时间同步系统的应用之一相机时间同步结构图,在时间系统已授时的情况下,简单讲述相机时间同步方法:</p><p>(1)相机工作在外触发模式,MCU提供触发源,也就是脉冲信号,并记录脉冲序号。</p><p>(2)相机拍照时,曝光时刻会产生脉冲对外输出,由MCU捕获,并记录此时刻时间及序号。</p><p>(3)记录的时间信息及序号会存储起来,照片的存储会一一对应序号,时间信息也可以与位置轨迹匹配起来,这样就完成了照片与位置的关联。</p><p><strong>4. GPS授时异常处理</strong></p><p>上面介绍了GPS的授时原理、方法及过程,即可完成时间的授时,但是实际的应用情景是复杂且随机的,由于GPS接收机从失锁到定位的过程不是固定的时间,设备、环境因素都有影响。以晶振为时钟源的MCU的系统时间在授时之前是自由运行状态。这些因素都对GPS授时带了未知的情况,在此列举一些异常情况;</p><p><strong>4.1 PPS与晶振</strong></p><p><img src="/img/remote/1460000040320223" alt="" title=""></p><p>如上图所示,PPS与晶振时钟的对齐存在三种情况:</p><p>(1)PPS上升沿与晶振时钟对齐,此为理想状态,是晶振经分频、倍频后为MCU系统时间提供了完美的1秒时长,但这种情况几乎不存在。</p><p>(2)MCU的系统时长慢于1秒,PPS到来进入下1秒,而系统时间还未结束当前秒,此时要做特殊处理,提前结束系统时间的整秒,立即进入下1秒的零时刻,时间信息的秒及以上单位对应“+1”。</p><p>(3)MCU的系统时长快于1秒,在PPS到来之前,系统时间已经进入下1秒,并运行一段时长,此时要将系统时间重新归到此秒的零时刻,时间信息的秒无需“+1”或者“-1”。</p><p><strong>4.2 PPS与GPS时间信息</strong></p><p><img src="/img/remote/1460000040320224" alt="" title=""></p><p>通常PPS与GPS时间信息NMEA数据是相对时间间隔稳定的,但是也有特殊情况。如上图所示:“GNRMC”语句的输出时间是变化的。</p><p>此情况会带来时间“回跳”的现象:当时间信息在0.999秒到的时候,它所包含的时间信息为当前秒,在时间信息传输与解析完成之前,下1秒的PPS到来,时间进入下1秒零时刻,再经过若干时间(一般100ms内),时间信息授时系统时间,此时秒信息是上1秒的时间,这样就出现了秒回跳的情况。</p><p>处理的方法是多种的,可自行思考。</p><p><strong>5. 小结</strong></p><p>了解GPS的授时原理与方法,更能设计出稳定、高精度的时间同步系统。在此基础上,可尝试使用不同厂家的GPS设备,在复杂环境下试验,差异补缺,完善授时方法。</p><p><strong>6. 附录</strong></p><p><img src="/img/remote/1460000040320225" alt="" title=""></p><p>PPS信号处理:抗干扰,滤除杂波干扰</p><p><img src="/img/remote/1460000040320226" alt="" title=""></p><p>GPS时间信号电平转换</p><p><img src="/img/remote/1460000040320227" alt="" title=""></p><p>晶振处理信号:控制时钟电压幅度,隔直流滤波</p><p><img src="/img/remote/1460000040320228" alt="" title=""></p>
WEB 三维引擎在高精地图数据生产的探索和实践
https://segmentfault.com/a/1190000040239935
2021-06-25T13:47:28+08:00
2021-06-25T13:47:28+08:00
高德技术
https://segmentfault.com/u/amap_tech
4
<p><strong>1. 前言</strong></p><p>高精地图(High Definition Map)作为自动驾驶安全性不可或缺的一部分,能有效强化自动驾驶的感知能力和决策能力,提升自动驾驶的等级。对于自动驾驶来说,高精地图主要是给机器用的,但是在制作和分析过程中依然需要人能够理解。本文将为大家简单介绍下,在过去的一段时间里高德高精地图业务团队,在WEB三维引擎技术方面的一些探索和实践,如何让复杂抽象的地理数据呈现在人们面前,满足其业务编辑和分析的诉求。</p><p>高精地图主要是对道路交通层对象(如:车道地面标线、交通灯、交通牌、防护栏、杆等)的精细化表达,包含其几何位置和属性。由于对精度要求极高,它的制作主要还是依赖<strong>激光点云</strong>,通常都是海量的数据,一个路口的点云量就可能上亿,这就对渲染引擎的性能有较高要求,要满足对<strong>海量点云实时渲染</strong>和<strong>拾取编辑</strong>。</p><p>起初,我们调研了市面上主流的Web三维地图引擎:Mapbox、Cesium、JS API、L7等,它们普遍对点云的加载处理能力支持不够,偏向于对抽象的点、线、面表达,精细化渲染能力不足,同时也满足不了作为编辑工具对复杂Topo关联关系的编辑能力。对于高德高精数据编辑分析的业务场景,需要更多的底层抽象能力建设。于是,我们在高精业务中开启了<strong>三维引擎eagle.gl</strong>的探索实践之路。</p><p>先通过一个视频简单了解下目前高德三维引擎eagle.gl的能力,它实现了一套2/3D统一的地图数据编辑和可视化解决方案,具备很好的可扩展能力,目前已应用在高德高精地图数据生产、数据分析、以及新基建项目等业务。</p><p><strong>2. 引擎方案设计实现</strong></p><p>基于上面的分析,我们需要实现一套满足高德业务场景需求的数据制作引擎能力。为了不重复造轮子,最大程度利用已有的开源能力,我们最终选用Threejs当作渲染层框架依赖。基于该框架,在上层构建GIS可视化和复杂编辑能力,最终实现构建一套2/3D一体化渲染引擎。同时面向未来智慧城市、5G IOT方向,构建数据团队面向业界看齐的GIS 3D可视化能力。</p><p><img src="/img/remote/1460000040239937" alt="" title=""></p><p>Figure 2.1 面向高精地图的2/3D一体化数字引擎</p><p>整个引擎工作可以拆分为三个部分(点云地图、矢量地图、模型地图),前端团队整体工作需要围绕这三个点去展开。</p><ul><li>点云地图:对接多种点云资料格式的可视化(las/laz/bc/xbc/rds/bin),支持海量点云的实时渲染和编辑,满足主产线对点云资料的作业吸附能力。</li><li>矢量地图:主要对接在线生产产线矢量化成图能力,通过数据快照、命令行编辑模式、空间数据索引等能力实现矢量化3D数据的增删改查能力。</li><li>模型地图:主要面向数据成果应用层,进行数据预处理建模、实时建模编辑等,实现数据能力与高德客户端车道级渲染能力拉齐。</li></ul><p><strong>3. 技术解题</strong></p><p>下面简单介绍一下各个核心模块能力。</p><p><strong>3.1 全幅面精细化渲染</strong></p><p>高精数据有着更精确更丰富的信息,支持更精细的数据渲染,更好地还原真实世界。</p><p><img src="/img/remote/1460000040239938" alt="" title=""></p><p>Figure3.1.1 全幅面精细化渲染</p><p>高精原始的产出数据是<strong>矢量化骨架数据</strong>,这一层数据是真实世界的数字化的点线面抽象,怎么根据原始的矢量数据进行模型化渲染展示呢?原始矢量数据是面向自动驾驶等机器使用,为了能够更好的核实数据质量,进行数据问题调查分析,我们需要把点线面矢量数据进行建模渲染,达到最终模型化精细化渲染效果,方便人工进行快速的问题核实。</p><p><img src="/img/remote/1460000040239939" alt="" title=""></p><p>Figure3.1.2 原始的矢量化数据成果</p><p><img src="/img/remote/1460000040239940" alt="" title=""></p><p>Figure3.1.3 端上实时数据建模精细化渲染成果</p><p>为了支持精细化的渲染效果,eagle.gl引擎目前支持常用的点、线、面、体、文本、模型等多种可视化图层,并且通过配置化的方式实现了数据渲染实现。</p><p>整个建模渲染分为以下核心模块流程, 主体流程是原始点线面矢量数据拉取,根据规则进行数据解析,数据建模处理,数据合并和Instance处理,数据渲染。其中<strong>工作量最大的部分在于数据预建模处理</strong>,因为原始数据的表达更加抽象,为了更加真实的还原世界,需要做很多的逻辑计算,例如斑马线/导流带数据表述中只有外边的边框轮廓,为了渲染的更真实,需要根据数据的长短边规格和交通路网规范,进行过程中实时建模生成。</p><p><img src="/img/remote/1460000040239941" alt="" title=""></p><p>Figure3.1.4 端上渲染建模核心流程</p><p><img src="/img/remote/1460000040239942" alt="" title=""></p><p>Figure.3.1.5 斑马线原始几何</p><p><img src="/img/remote/1460000040239943" alt="" title=""></p><p>Figure.3.1.6 斑马线建模后几何</p><p>通过同样的处理方式,我们就能够实现数百种高精数据定制化建模能力。但是好几百种数据规格如果通过硬编码的形式进行建模会导致整个代码结构的腐化和不可维护。因此我们在引擎层实现数据配置驱动地图图面样式展现的能力。</p><p><img src="/img/remote/1460000040239944" alt="" title=""></p><p>Figure.3.1.7 多种高精数据建模成果表达</p><p>对于style的定义我们区分为两种类型,一种是基本的feature要素对应的展现行为,这层style目前定义为静态的style配置;另外一种style是tile数据源驱动的styleSchema,这种style会定义动态的属性以及空间场景、灯光等共有属性定义。</p><p>基础要素层对应的style我们主要分为以下几个类型:</p><p>IBaseStyle | ILineStyle | ITextStyle | IPointStyl | IPolygonStyle | IModelStyle | ICustomStyle</p><p><img src="/img/remote/1460000040239945" alt="" title=""></p><p>举个例子,我们用模型样式类ModelStyle,新增模型的样式定义,继承自IBaseStyle。</p><pre><code>mapView.addDataLayer({
id: 'model', // 图层id,id为唯一标识,不能重复
style: {
type: 'model',
resources: {
type: 'gltf',
base:
'//cn-zhangjiakou-d.oss.aliyun-inc.com/fe-zone-daily/eagle.gl/examples/assets/theme/default/model/',
files: ['ludeng_0.glb'],
},
translate: [0, 0, 0],
},
features: [
{
geometry: {
type: 'Point',
coordinates: [[116.46809296274459, 39.991664844795196, 0]],
},
},
],
});</code></pre><p><strong>属性</strong></p><p>置为灰色部分表示继承自BaseStyle属性</p><p><img src="/img/remote/1460000040239946" alt="" title=""></p><p><strong>ModelResource资源定义</strong></p><p><img src="/img/remote/1460000040239947" alt="" title=""></p><p>通过上面的API调用就可以实现模型数据的加载渲染。整个地图图面的全量要素表达都可以通过这种形式进行可视化描述。</p><p><img src="/img/remote/1460000040239948" alt="" title=""></p><p>Figure.3.1.8 gltf模型如何通知配置样式进行定义加载</p><p><strong>3.2 多源异构数据一体化渲染</strong></p><p>对于HD的数据生产,点云和DEM高程分为对应采集和应用侧最核心的资料数据表达。作为引擎的特色能力,目前引擎实现了DEM高程渲染和多维度的点云着色能力,后续还会进行BIM/倾斜摄影等多源模型能力的接入,实现基于一张图进行宏观/微观一体化展示能力。</p><p>3.2.1 DEM高程渲染</p><p><img src="/img/remote/1460000040239949" alt="" title=""></p><p>Figure.3.2.1.1 DEM渲染效果DEMO</p><p>高精的数据是XYZ的三维数据表达,但是我们很多传统的路网数据都是二维的,如何实现多源矢量数据的混合叠加,我们采用接入DEM高程方案,把无高程的传统背景数据/路网数据拔投影到海拔高度。原始输入的为tiff图像文件,通过利用数据预处理进行QMesh渲染矢量生成,主体数据处理流程如下:</p><p><img src="/img/remote/1460000040239950" alt="" title=""></p><p>Figure.3.2.1.2 DEM数据渲染处理流程</p><p>QMesh渲染方案是Cesium推荐的现在及未来使用的地形切片格式,与Heightmap格式相比较,具有更高的性能优势和更小的数据存储。基于性能更优的QMesh几何处理方案,实现全国山体地形实时加载,同时支持在worker中进行地形实时细分,可以基于低级别三角面动态计算渲染至21级地形。</p><p><img src="/img/remote/1460000040239951" alt="" title=""></p><p>Figure.3.2.1.3 多源异构数据融合一体化渲染 - DEM高程方案</p><p>3.2.2 点云地图</p><p>点云作为高精特色的采集资料,与传统的照片资料相比,能够最大精度的还原真实世界的三维位置信息。为了实现真实世界的高度精细化描述,Web海量点云加载和渲染在我们日常工作中是非常重要的内容。</p><p>点云渲染的最大问题是海量数据实时加载和动态拾取,eagle.gl实现了基于全球ECEF统一坐标索引下点云实时从网络加载,能够实现支持内存中同时800w以上海量点云LOD实时加载以及根据反射率/高度/MIX混合着色能力,渲染帧率可以保持在60fps,通过GpuPicker和Raycast混合拾取方案实现数据拾取交互的实时性。</p><p><img src="/img/remote/1460000040239952" alt="" title=""></p><p>Figure.3.2.2.1 基于LOD点云的实时吸附编辑能力</p><p><strong>3.3 交互和扩展能力</strong></p><p>对于地图数据生产,数据可视化展示是第一步,如何在数据可视化展示的基础上进行上层复杂的GIS编辑能力建设是业务增值的重要一环。</p><p>3.3.1 交互能力</p><p>为了满足高精产线复杂的数据编辑诉求,拾取是编辑最底层的能力, 融合射线拾取与GPU拾取,能精准满足对海量数据20ms以内的快速拾取能力。</p><p><img src="/img/remote/1460000040239953" alt="" title=""></p><p>Figure.3.3.1.1 海量数据拾取能力</p><p><strong>数据裁剪能力</strong>:立交场景下,数据间的互相遮挡会对数据分析产生一定的影响,我们默认提供了数据裁剪能力以满足复杂场景的数据编辑&分析需求。</p><p><img src="/img/remote/1460000040239954" alt="" title=""></p><p>Figure.3.3.1.2 数据实时裁剪</p><p>3.3.2 插件体系</p><p>引擎支持插件开发,用户可以根据自己的需求定制插件,目前我们提供了测距、编辑和框选三个插件供大家参考。同时,引擎还支持图层和控制器的定制化开发,满足多样的业务场景。</p><p><img src="/img/remote/1460000040239955" alt="" title=""></p><p>Figure.3.3.2.1 测距插件体系</p><p><strong>3.4 其他能力 - 视觉&动效</strong></p><p>3.4.1 飞行</p><p>平滑的飞行效果和基于滤镜的背景换肤能力。</p><p><img src="/img/remote/1460000040239956" alt="" title=""></p><p>Figure.3.4.1.1 平滑的飞行效果/背景换肤</p><p>3.4.2 光影</p><p>模拟一天中的时间,实现光照阴影能力。</p><p><img src="/img/remote/1460000040239957" alt="" title=""></p><p>Figure.3.4.2.1 光照阴影</p><p>3.4.3 后处理</p><p>深度定制扩展threejs,实现扩展的后处理渲染管线,并且抽象出通用三方后处理基础库,该库增加了引擎的后处理能力,用于提升可视化效果,为未来大屏项目做准备。</p><p><img src="/img/remote/1460000040239958" alt="" title=""></p><p>Figure.3.4.3.1 后处理</p><p>3.4.4 3D地球</p><p>23D一体化,支持墨卡托投影和球投影的自由切换,增强可视化效果。</p><p><img src="/img/remote/1460000040239959" alt="" title=""></p><p>Figure.3.4.4.1 2/3D一体化球展示</p><p><strong>4. 总结规划</strong></p><p>目前,eagle.gl引擎广泛应用到了高德高精团队的数据生产、数据分析和新基建项目能力建设当中。后续随着引擎的能力完备,一方面立足于高精业务实现面向自动驾驶的仿真平台搭建;另一方面通过真实世界数字化的刻画,实现多源异构数据(DEM/BIM/倾斜摄影等行业相关)融合渲染,最终达到数字孪生能力。</p><p>以上的事情要最终实现任重道远,欢迎联系加入我们共同构建一个数字世界。欢迎对通用平台前端、在线编辑IDE、3D可视化方向感兴趣的小伙伴加入我们,一起做一些有意义的事情。投递简历到 gdtech@alibaba-inc,com, 邮件主题为: 姓名-技术方向-来自高德技术, 欢迎自荐或推荐。</p><p><img src="/img/remote/1460000040239960" alt="" title=""></p>
6月开播 | 高德开放平台系列公开课来啦,大量技术干货强势来袭
https://segmentfault.com/a/1190000040199763
2021-06-18T18:40:25+08:00
2021-06-18T18:40:25+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><img src="/img/remote/1460000040199765" alt="" title=""></p><p>高德开放平台公开课来啦,大量技术干货强势来袭~</p><p>精彩主题抢先看:<strong>自定义地图与个性化展示</strong>,<strong>地图空间搜索</strong>,<strong>猎鹰轨迹服务</strong>,<strong>导航原理及应用</strong>...</p><p>6月<strong>首期公开课将于6月23日晚7点</strong>在<strong>高德开放平台钉钉群(钉钉扫描海报里的二维码或者搜索钉群号:31886791)</strong>中与大家见面!</p><p>更有免费调用量等福利等你入群来拿哦!快来参与吧!</p>
高精地图数据应用分发引擎建设实践
https://segmentfault.com/a/1190000040199307
2021-06-18T17:31:18+08:00
2021-06-18T17:31:18+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>1. 什么是高精数据分发引擎</strong></p><p><strong>1.1 高精地图概述</strong></p><p>高精地图(High Definitation Map,HD MAP),和普通导航电子地图的主要区别是精度更高、信息更丰富。精度更高主要体现在高精地图的绝对坐标精度更高(指的是地图上某个目标和外部的真实世界事物所在位置之间的精度),可以精确到厘米级别;信息更丰富主要体现在高精地图不仅包含了道路信息,还涵盖了几乎所有与交通相关的周围静态信息。</p><p>相比于普通导航电子地图,高精度地图所包含的道路交通信息更丰富和准确。除此以外,在应用场景方面,普通导航地图主要供驾驶员使用,而高精度地图是面向机器的、供自动驾驶汽车使用的地图。</p><p><strong>精度</strong>是高精度地图与普通导航电子地图的最大区别。普通车载电子导航地图的精度一般在10米左右,高精度地图应用在自动驾驶领域,需要<strong>精确定位到具体某条车道上</strong>,<strong>还需要知道周围所有可能参与自动驾驶决策的道路和交通信息</strong>,精度需要达到<strong>10~20厘米</strong>,这样的精度基本上和一个车道边线的宽度差不多,才能保证智能驾驶的汽车不会跨越到其他车道,避免与其他车辆发生侧面碰撞的风险。</p><p><img src="/img/remote/1460000040199309" alt="" title=""></p><p>普通导航电子地图要描绘出<strong>道路(link)</strong>,而高精度地图不仅要描绘道路,还会描绘出一条道路上有多少条<strong>车道(lane)</strong>,真实地反映出道路的实际样式。</p><p>高精度地图信息更丰富主要体现在以下几个方面:</p><p><strong>准确的道路形状</strong>:每条车道的坡度、曲率、航向、高程,侧倾的数据。</p><p><strong>详细的车道线信息</strong>:车道之间的车道线是虚线、实线还是双黄线,线的颜色,道路隔离带,隔离带的材质都会有描述。</p><p>此外,人行横道,道路沿线看板,限速标志,红绿灯,路边电话亭等等,这类通常统称为<strong>LandMark Object的绝对地理坐标</strong>,物理尺寸以及他们的特质特性等也都会出现在高精度数据中。</p><p><strong>1.2 </strong><strong>高精数据分发引擎</strong></p><p>ADAS(Advanced Driver Assistant System,高级驾驶辅助系统)应用需要用车辆前方路网及属性数据信息用于决策控制及判断,普通数字地图数据通常仅供导航系统使用,但高精地图数据可供车辆内的其他ADAS应用使用,因此需要依赖高精数据及用于高精数据播发的高精数据分发引擎。</p><p><img src="/img/remote/1460000040199310" alt="" title=""></p><p>ADASIS(ADAS接口规范)定义了<strong>“ADAS电子地平线”</strong>的概念,“ADAS电子地平线”表达了车辆前方的路网及路网属性信息。为了实现这种表达方式,我们需要构建车辆的位置模型以及车辆前方路网的各个可能行驶的道路模型,可以通过一个树状的层次结构来表达可通行的道路。此外,道路的几何形状及相关属性也会建立相关的属性模型来表达。“ADAS电子地平线”数据通过车载以太网络来序列化及传输。</p><p><strong>1.3 名词解释</strong></p><p><strong>ADAS</strong>(Advanced DriverAssistance System)</p><p>即高级驾驶辅助系统,利用车载传感器感知车辆环境,并融合计算,预先让驾驶者察觉可能发生的危险,有效提升车辆驾驶的安全性、经济性和舒适性。</p><p><strong>ADASIS</strong>(Advanced DriverAssistance System Interface Specification)</p><p>ADAS论坛制定的行业国际标准,用于规范地图数据和车辆ADAS应用之间交换地图数据的标准接口协议。</p><p><strong>AHP</strong>(ADAS Horizon Provider)</p><p>即高精数据分发引擎,为ADAS应用提供超视距的前方道路和数据信息。</p><p><strong>AHR</strong>(ADAS Horizon Reconstructor)</p><p>用于解析AHP发出的消息并重建地图数据,供终端ADAS应用模块使用。</p><p><strong>2. 为什么需要高精数据的分发引擎</strong></p><p><strong>高精数据分发引擎作为高精数据及ADAS应用的桥梁</strong>,其价值总结下来有以下几个方面:</p><ul><li>自动驾驶远程视距的需要,高精地图作为自动驾驶的地图传感器,可以提供更可靠的超视距范围,支持更可靠的决策判断。</li><li>精度提高的需要,由导人到导车的转变使得对精度要求提高了。</li><li>高精地图数据分发的接口标准化。</li></ul><p><strong>3. 高精数据分发引擎的建设</strong></p><p><strong>3.1 高精数据分发引擎与ADAS应用的关系</strong></p><p><img src="/img/remote/1460000040199311" alt="" title=""></p><p>数据分发引擎涉及到以下几个部分组成及交互:</p><ul><li>AHP</li><li>AHR</li><li>ADASIS V3 Protocol</li><li>ADAS应用,详见上图的终端应用部</li></ul><p><strong>3.2 高精数据分发引擎架构</strong></p><p>高精数据分发引擎由多个层级组成,包括引擎层、协议组织层、系统适配层,相关的平台及工具支撑如下图所示:</p><p><img src="/img/remote/1460000040199312" alt="" title=""></p><ul><li>引擎层:高精数据的加载,解析及车道路网数据的组织。</li><li>协议层:主要将引擎层提供的数据组装协议消息,并向适配层传递分发。</li><li>适配层:主要负责和系统对接及交互,并将组织的协议数据分发给ADAS应用。</li></ul><p><strong>3.4 高精数据分发引擎的模型表达</strong></p><p>3.4.1 路网模型的抽象及表达</p><p>数据分发引擎的路网模型包含三层的模型抽象,首先经由现实世界模型抽象成高精路网模型,再由高精路网模型进一步组织及划分抽象为Path及Offset表达的树状模型。</p><ul><li>现实世界的抽象模型的表达</li></ul><p><img src="/img/remote/1460000040199313" alt="" title=""></p><ul><li>数字化地图模型及用户设置的导航路径,地图要素的表达</li></ul><p><img src="/img/remote/1460000040199314" alt="" title=""></p><ul><li>在数据化地图模型的车辆位置及路网表达</li></ul><p><img src="/img/remote/1460000040199315" alt="" title=""></p><ul><li>在车辆位置附近的路网模型通过links来表达路网之间的连接关系。在数字地图数据库中,道路网表示为一组连接和定义链接之间的节点组成。</li></ul><p><img src="/img/remote/1460000040199316" alt="" title=""></p><ul><li>从ADAS应用角度来看,对车辆后方的路网并不关心,因此数据分发引擎由车辆前方的路网组成。</li></ul><p><img src="/img/remote/1460000040199317" alt="" title=""></p><ul><li>将车辆前方路网按Path来组织,每个Path是一组link的集合。车前方的路网数据可以通过两种算法来表达。</li></ul><p>简单Path方式,从车所在link开始,每个可以通行的路径都独立表达为Path.</p><p><img src="/img/remote/1460000040199318" alt="" title=""></p><p>优化路径组织方式,这种方式减少了数据冗余,也可以完整表达车辆前方的路网数据。</p><p><img src="/img/remote/1460000040199319" alt="" title=""></p><p>因此,数据分发引擎根据车辆前方及其周围环境的路网形状描述为不同路径和地图数据属性的集合,组成预测树。这个预测树由多条路径连接而成,每一条路径代表一部分道路,及道路与道路之间的交叉点。</p><p>一旦车辆移动更改其位置时,预测视图也会更改,一些车后方的的路径可能会被删除,或车前方的路径可能会添加新的。路径的特征表达为一组属性,如高速及城快路网本身包括的车道数、几何形状、曲率等。属性在路径上的位置用一组偏移值表示,偏移值是一种距离标记,通过定义沿路径本身的绝对距离,以厘米表示。一条路径的原点是零偏移值点,属性的偏移值表示属性本身和路径原点之间的距离。如果路径是新开始的并且没有父路径,则偏移值0点为车辆所在的起始位置。</p><p>3.4.2 高精数据分发引擎的属性模型</p><p>数据分发引擎的属性模型数据来源于高精路网上的属性信息,定义为沿着Path表达,并定义在Path上的位置,通过Offset来表达。例如,速度限制属性为路径上的点提供速度限制值。</p><p>属性模型根据插值类型可以分为以下三种不同的类型,即Spot, Step, Linear类型</p><p><img src="/img/remote/1460000040199320" alt="" title=""></p><p>Spot类型的属性只有在Path内某一给定的Offset位置有效,属性的不同由不同的Offset位置来表达。例如交通灯可以定义为Spot类型的属性,因为可以被表达为Path内某一位置存在这个点属性</p><p>Step类型的属性定义为到下一属性的Offset位置处一直有效。属性表达为Path上的Offset到EndOffset区间范围内的值。</p><p><img src="/img/remote/1460000040199321" alt="" title=""></p><p>如上图所示例子中,Path长度为200。速度限制80是整体有效,从Offset 0点到200。从偏移量50和100开始有两个限速值。因此整个图上属性分布如下:</p><ul><li>偏移量0:开始限速值80。</li><li>偏移量50:引入雨天限速值60,限速80的属性继续。</li><li>偏移量100:重复速度限制80,新增雾天限制50,雨天的限速60结束。</li><li>偏移量150:重复速度限制80,雾天的速度限制50结束。</li></ul><p>Linear类型的属性定义为在给定的位置间进行线性差值表达。</p><p><img src="/img/remote/1460000040199322" alt="" title=""></p><p>线性插值型属性不是连续表达的,在同一个Offset处,左边的值和右边的值是不同的,属性模型用以下方式来表达这种不连续的属性值。</p><ul><li>在Offset处,存储一个属性,值存储左边的属性值,EndOffset为0。</li><li>在同一个Offset存储一个属性,值存储右边的属性值,但EndOffset > Offset</li></ul><p>3.4.3 车的位置信息模型</p><p>在数据分发引擎中,车的位置信息可以通过Path, Offset来表达。在不确定情况下,车的位置可能存在于多个Path上,因此需要用一个集合来描述车的位置信息。通过车位置信息可以表达以下信息:</p><ul><li>车信息是否脱离了数据区域。</li><li>车信息是否匹配到了Path的数据范围。</li><li>车信息是否匹配到了个多个Path上。</li><li>车信息是否进入及离开了数据区域范围。</li></ul><p>车位置信息的TimeStamp值表达了接收到传感器信息的时间时刻值。</p><p><img src="/img/remote/1460000040199323" alt="" title=""></p><p>车的位置信息还可以表达前方更可能选择的Path路径。</p><p><img src="/img/remote/1460000040199324" alt="" title=""></p><p>如上图中左边可能选择的路径是P1, 右图为P3。</p><p>3.4.4 高精数据分发引擎与接收端的同步机制</p><p>数据分发引擎通过pathControl消息来同步AHP及AHR之间的路网Path数据。</p><ul><li>当pathControl消息不包含某一Path时,AHR收到消息后删除路网中的Path。</li><li>当pathControl消息和上次维持不变时,AHR收到消息后维持当前路网不变。</li><li>当pathControl消息增加了某一Path时,AHR收到消息后增加Path信息</li></ul><p>通过profileControl同步属性数据。</p><p><img src="/img/remote/1460000040199325" alt="" title=""></p><p>3.4.5 高精数据分发引擎与接收端的交互机制</p><p>数据分发引擎(AHP)与接收端(AHR)有以下几种交互机制:</p><ul><li>广播方式</li><li>请求/提供方式</li><li>订阅/发布模式</li></ul><p><img src="/img/remote/1460000040199326" alt="" title=""></p><p>目前高精数据分发引擎建设时采用的是“请求/提供”方式,AHP向AHR发送 ADAS message, AHR可以请求及反馈信息。</p><p><img src="/img/remote/1460000040199327" alt="" title=""></p><p>3.4.6 辅助AHP及ADAS应用融合</p><p>3.4.6.1 主AHP及辅助AHP</p><p>ADASIS协议中并不是所有的数据都由数据分发引擎提供,也可以增加辅助的AHP引擎。辅助的AHP引擎可以发送传感器信息或传感器的融合信息。</p><p><img src="/img/remote/1460000040199328" alt="" title=""></p><p>形成的主数据分发引擎及辅助的AHP引擎。</p><p>3.4.6.2 ADAS应用的两种融合方式</p><p>根据主AHP及辅助AHP引擎,可以实现2种ADAS应用的融合方式,即下游融合及上游融合。</p><p><img src="/img/remote/1460000040199329" alt="" title=""></p><p><strong>下游融合</strong></p><p>在AHP端不做融合处理,通过通信方式把各个传感器数据及高精地图数据传给AHR端,进行融合的处理,然后再传给ADAS功能应用。</p><p><img src="/img/remote/1460000040199330" alt="" title=""></p><p><strong>上游融合</strong></p><p>在AHP端做融合处理,将融合结果通过协议传给AHR处理,直接作用于ADAS功能。</p><p><img src="/img/remote/1460000040199331" alt="" title=""></p><p><strong>4. 质量建设</strong></p><p>为了保证软件质量,高精数据分发引擎建设中采用了如下技术手段:</p><ul><li>单元测试</li><li>功能测试</li><li>质检工具</li></ul><p>可视化工具</p><ul><li>可视化工具截图</li></ul><p><img src="/img/remote/1460000040199332" alt="" title=""></p><p><strong>5. 典型架构应用形态</strong></p><p>根据高精数据分发引擎构架可以分为以下的几种集成形态:</p><p><strong>5.1 数据分发引擎(即EHP引擎)集成在地图盒子内</strong></p><p><img src="/img/remote/1460000040199333" alt="" title=""></p><p><strong>地图盒子概念</strong></p><p>用于承载“地图数据+高精定位”能力的车规级软硬一体化产品,有别于纯软件的产品形态。(以下名称都指高精地图盒子:定位盒子/MAP ECU/MAP BOX/HDLM...其中L:Localization M:Module)</p><p><strong>包含内容</strong></p><ul><li>地图及相关应用:HD数据、AHP、定位、OTA...</li><li>基础软件:系统、底层驱动、诊断...</li><li>基础硬件:系统级芯片(SoC)、内存、存储、IMU(可选),保护壳体...</li><li>网络及通讯接口:CAN/以太输入、以太输出、USB接口...</li></ul><p><strong>方案特点</strong></p><p><strong>任务分工清晰</strong>:车企能将以这种架构将功能拆解为小模块,分别提出产品要求进行管控,避免全黑盒方案无从下手。遇到交付风险时可以替换供应商。</p><p><strong>功能安全方面的考虑</strong>:芯片选型、硬件设计、网络安全、系统诊断等细节工作可以交给专业的供应商;地图质量、在线更新以及回传等功能安全层级存在不确定性、需要与AD ECU隔离开,以使AD ECU满足功能安全要求。</p><p><strong>便于高配低配等产品管理</strong>:可选用供应商的不同配置的产品。</p><p><strong>减轻域控制器的算力负担</strong>:便于寻找满足算力要求的功能安全硬件。</p><p><strong>5.2 集成在IHU内</strong></p><p><img src="/img/remote/1460000040199334" alt="" title=""></p><p><strong>方案特点</strong></p><p><strong>降低成本</strong>:不需要额外采购硬件模块。</p><p><strong>集成V2方案、降低不确定性</strong>:AHP V2大多在车机端,方案已跑通,所以将地图和V3采用相似的方式可以规避新架构的不确定性。</p><p><strong>车企内部原因容易推进</strong>:部分车企,高精地图业务规划导航地图部门,若自下而上推进盒子方案,对整体架构改动较大,很难推进。</p><p><strong>5.3 集成在域控制器内</strong></p><p><img src="/img/remote/1460000040199335" alt="" title=""></p><p><strong>方案特点</strong></p><p><strong>减少跨域通信对车载网络带宽的占用</strong>:用于感知的传感器大多与域控制器相连,如果将地图及定位放在域控制器,后端应用不需要跨域通信就可以直接或间接使用地图,减少对于车载网络带宽的占用。</p><p><strong>更适用于走自研路线及选用整体方案的车企</strong>:对于走自研路线的车企,以及选用单一方案商提供完整方案,没有必要将功能模块分开部署。</p><p><strong>6. 场景应用举例</strong></p><p><strong>6.1 高精定位应用</strong></p><p><img src="/img/remote/1460000040199336" alt="" title=""></p><p>结合高精数据辅助进行横向定位及纵向定位。</p><p>纵向定位多结合路牌obj、车道几何等相关信息,横向定位多结合车道线、护栏等相关信息。</p><p>主动安全应用多结合传感器(毫米波雷达、摄像头)信息和地图数据进行匹配纠偏,从而提升定位精度。</p><p><strong>6.2 高速自动驾驶(HWP)</strong></p><p><strong>功能激活</strong></p><p>驾驶环境主要依赖地图判断:(1)高速城快;(2)车道线清晰;(3)曲率坡度;(4)无引发报警或制动的物体或事件:包含动态道路环境;(5)非夜晚,天气状况良好(能见度200米以上)。</p><p><strong>实现功能</strong></p><p>以本车道巡航横向控制及异常场景本车道自主停车为例:</p><ul><li><strong>车道类型</strong>:自动驾驶依靠车道类型来划分可行驶区域,如果类型错误会导致车辆行驶在非行驶区域,会给自车带来安全隐患;同时在自主安全停车的场景中,如果车道类型错误会直接导致自主安全停 车的的自主性和安全性。</li><li><strong>车道线类型</strong>:辅助摄像头进行车道线线型识别;和摄像头进行对比检查,进而进行车道保持。</li></ul><p><strong>6.3 基于导航路线自动巡航</strong></p><p><img src="/img/remote/1460000040199337" alt="" title=""></p><p><strong>功能激活</strong></p><p>工况环境依赖地图判断:</p><ul><li>道路等级:高速/城块。</li><li>PartOfcalculateRoute(导航路径标识)是否连续无断开。</li><li>天气类型:晴天/小雨/阴天等天气状况下,允许功能激活。</li></ul><p><strong>实现功能</strong></p><ul><li>上/下JCT,会根据导航路径标识和车辆前方路网判断是否上/下JCT,并提前对变道匝道侧进行提醒。</li><li>自动变道进入JCT/合入高速,会根据车道线线型辅助摄像头进行车道线线型识别,并和摄像头进行检测对比,线型的虚实判断车辆变道的时机。</li></ul><p><strong>7. 未来演进</strong></p><p>一方面,考虑进一步融合AHP V2,V3的架构设计,更好的辅助自动驾驶。此外,作为数据闭环的一部分,丰富数据提供及回收能力等。</p><p><img src="/img/remote/1460000040199338" alt="" title=""></p>
视觉感知未来,高德数据采集模型部署实践!
https://segmentfault.com/a/1190000040119118
2021-06-04T11:18:56+08:00
2021-06-04T11:18:56+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>1. 导读</strong></p><p>作为DAU过亿的国民出行服务平台,高德地图每天为用户提供海量的检索、定位和导航服务,实现这些服务需要有精准的道路信息,比如电子眼位置、路况信息、交通标识位置信息等。读者是否会好奇,高德是如何感知到现实世界的道路信息,并提供这些数据给用户呢?</p><p>事实上,我们有很多的方法将现实世界的道路要素采集回收,并更新到高德地图App上。其中一种非常重要的方法是利用计算机视觉的手段,将视觉算法部署到客户端,通过对图片的检测识别,快速将道路的信息回收。</p><p>为了低成本,高实时性地实现道路要素回收,我们借助<strong>MNN引擎</strong>(一个轻量级的深度神经网络推理引擎),将卷积神经网络模型部署到客户端,在客户端进行端侧的模型推理,从而完成在<strong>计算能力低,内存小的客户端</strong>进行道路要素采集的任务。</p><p>传统的CNN(卷积神经网络)计算量非常大,且业务场景需要部署多个模型。<strong>如何在低性能的设备上部署多个模型,并在不影响实时性的情况下保证应用的"小而优"是一个非常大的挑战</strong>。本文将分享利用MNN引擎在低性能设备上部署深度学习应用的实战经验。</p><p><strong>2. 部署</strong></p><p><strong>2.1 背景介绍</strong></p><p>如Figure2.1.1所示,业务背景是将道路要素识别相关的CNN模型部署到客户端,在端侧进行模型推理,并提取道路要素的位置和矢量等信息。</p><p>由于该业务场景的需要,目前端上需同时部署10+甚至更多的模型,以满足更多的不同道路要素的信息提取需要,对于低性能设备来说是非常大的挑战。</p><p><img src="/img/remote/1460000040119120" alt="" title=""></p><p>Figure 2.1.1 高德数据采集</p><p>为了达到应用的"小而优",MNN引擎部署模型的过程中遇到了很多问题和挑战。下面就这些问题和挑战分享一些经验和解决办法。</p><p><strong>2.2 MNN部署</strong></p><p><strong>2.2.1 内存占用</strong></p><p>应用运行内存对于开发者来说是始终绕不开的话题,而模型推理产生的内存在应用运行内存中占有很大的比例。因此,为了使模型推理内存尽可能小,在模型部署的过程中,作为开发者必须清楚模型运行产生内存的主要来源。根据我们的部署经验,部署单模型的过程中,内存主要来源于以下四个方面:</p><p><img src="/img/remote/1460000040119121" alt="" title=""></p><p>Figure 2.2.1 单模型部署内存占用</p><p><strong>ModelBuffer</strong>: 模型反序列化的buffer,主要存储模型文件中的参数和模型信息,其大小和模型文件大小接近。</p><p><strong>FeatureMaps: </strong>Featuremaps的内存,主要存储模型推理过程中,每一层的输入和输出。</p><p><strong>ModelParams: </strong>模型参数的内存,主要存储模型推理所需的Weights, Bias, Op等内存。其中Weights占用了该部分的大部分内存。</p><p><strong>Heap/Stack: </strong>应用运行中产生的堆栈内存。</p><p><strong>2.2.2 内存优化</strong></p><p>知晓模型运行内存占用后,就能方便理解模型运行时的内存变化。经过多个模型部署实践, 为了降低部署模型的内存峰值,我们采取的措施如下:</p><ul><li>模型反序列化(createFromFile)并创建内存(createSession)后,将模型Buffer释放(releaseModel), 避免内存累加。</li><li>处理模型输入,图像内存和inputTensor可内存复用。</li><li>模型后处理,模型输出Tensor和输出数据的内存复用。</li></ul><p><img src="/img/remote/1460000040119122" alt="" title=""></p><p>Figure 2.2.2.1 MNN模型部署内存复用方案</p><p>经过内存复用,以部署1个2.4M的视觉模型为例,模型运行时从加载到释放,中间各阶段所占用内存变化可以用以下曲线表示:</p><p><img src="/img/remote/1460000040119123" alt="" title=""></p><p>Figure 2.2.2.2 单模型应用内存曲线(Android memoryinfo统计)</p><ul><li>模型运行前,模型占用内存为<strong>0M</strong>。</li><li>在模型加载(createFromFile)和创建内存(createSession)后,内存升到<strong>5.24M</strong>, 来源于模型反序列化和Featuremaps内存创建。</li><li>调用releaseModel内存降低至<strong>3.09M</strong>,原因是释放了模型反序列化后的buffer。</li><li>InputTensor和图像内存复用,应用内存增加到<strong>4.25M</strong>, 原因是创建了存储模型输入的Tensor内存。</li><li>RunSession(),应用内存增加到<strong>5.76M</strong>,原因是增加了RunSession过程中的堆栈内存。</li><li>在模型释放后,应用恢复到了模型加载前的内存值。</li></ul><p>经过多次模型部署的实践,下面总结了部署单模型到端的内存峰值预估公式:</p><p><img src="/img/remote/1460000040119124" alt="" title=""></p><p><strong>MemoryPeak</strong>:单模型运行时内存峰值。</p><p><strong>StaticMemory</strong>:静态内存,包括模型Weights, Bias, Op所占内存。</p><p><strong>DynamicMemory</strong>:动态内存,包括Feature-maps所占内存。</p><p><strong>ModelSize</strong>:模型文件大小。模型反序列化所占内存。</p><p><strong>MemoryHS</strong>:运行时堆栈内存(经验取值0.5M-2M之间)。</p><p><strong>2.2.3 模型推理原理</strong></p><p>本章节分享模型推理原理,以便于开发者遇到相关问题时,快速定位和解决问题。</p><p><strong>模型推理前模型的调度</strong>: MNN引擎推理保持了高度的灵活度。即可以指定模型不同的运行路径,也可以对不同的运行路径指定不同的后端,以提高异构系统的并行性。此过程主要是调度或者任务分发的过程。</p><p>对于分支网络,可以指定当前运行分支,也可以调度分支执行不同后端,提高模型部署的性能。图Figure2.2.3.1所示为一个多分支模型, 两个分支分别输出检测结果和分割结果。</p><p><img src="/img/remote/1460000040119125" alt="" title=""></p><p>Figure 2.2.3.1 多分支网络</p><p>部署时可做如下优化 :</p><ul><li>指定模型运行的Path。当仅需检测结果时,只跑检测分支,无需跑完两个分支, 减小模型推理时间。</li><li>检测和分割指定用不同的后端。比如检测指定CPU, 分割指定OpenGL,提高模型并行性。</li></ul><p><strong>模型推理前的预处理</strong>: 本阶段会根据上一步的模型调度信息进行预处理,本质是利用模型信息和用户输入配置信息,进行Session(持有模型推理数据)的创建。</p><p><img src="/img/remote/1460000040119126" alt="" title=""></p><p>Figure 2.2.3.2 根据Schedule创建Session</p><p>本阶段根据模型反序列化的模型信息和用户调度配置信息来进行运算调度。用于创建运行的Piplines和对应的计算后端。如Figure2.2.3.3所示。</p><p><img src="/img/remote/1460000040119127" alt="" title=""></p><p>Figure 2.2.3.3 Session创建</p><p><strong>模型的推理</strong>: 模型推理本质是根据上一步创建的Session,依次执行算子的过程。运算会根据预处理指定的模型路径和指定后端进行模型每层的运算。值得一提的是,算子在指定的后端不支持时,会默认恢复到备用后端执行计算。</p><p><img src="/img/remote/1460000040119128" alt="" title=""></p><p>Figure 2.2.3.4 模型推理计算图</p><p><strong>2.2.4 模型部署时间</strong></p><p>本部分统计了单模型部署过程各阶段耗时,方便开发者了解各阶段的耗时,以便更好的设计代码架构。(不同设备有性能差异,耗时数据仅供参考)</p><p><img src="/img/remote/1460000040119129" alt="" title=""></p><p>Figure 2.2.4.1 模型推理计算图</p><p>模型反序列化和Session创建相对耗时较长,进行多张图的推理时,尽量执行一次。</p><p><strong>2.2.5 模型误差分析</strong></p><p>模型部署时,开发者难免会遇到部署端和X86端(Pytorch, Caffe, Tensorflow)训练模型输出结果有偏差的情况。下面分享误差原因, 定位思路以及解决办法。</p><p>模型Inference示意图如Figure 2.2.5.1所示:</p><p><img src="/img/remote/1460000040119130" alt="" title=""></p><p>Figure 2.2.5.1 模型Inference示意图</p><p><strong>模型误差的确定</strong>: 查看是否有模型误差最直观的方法是,固定部署端模型和X86端模型的输入值,分别推理,对比部署端模型和X86端模型输出值,可确认是否有误差。</p><p><strong>模型误差的定位</strong>: 当确定有模型误差时,先排除因模型输入误差导致的模型输出误差。因为X86端和部分Arm设备浮点的表示精度不一致,输入误差在某些模型中会被累积,最终造成较大的输出误差。用什么方法来排除是输入误差导致的问题呢?我们提供一种方法是将模型输入设置为0.46875(原因是该值在X86设备和部分Arm设备表示一致,本质是1经过移位获得的浮点数在两种端上表示均一致)。然后观察输出是否一致即可。</p><p><strong>模型误差的定位思路</strong>: 在排除模型输入误差导致模型输出误差(即模型输入一致时,模型输出不一致)的情况下,很可能是模型某些算子导致的误差了。如何定位模型哪个OP导致的误差呢?通过下述的步骤可以定位模型内部引起误差的原因:</p><p>1)通过runSessionWithCallBack来回调模型每个OP的中间计算结果。目的是定位模型从哪个Op开始出现误差。</p><p>2)定位到该层之后,即可定位到产生误差的算子。</p><p>3)定位到算子后,通过指定的后端信息即可定位到对应的算子执行代码。</p><p>4)定位到对应的执行代码后,调试定位产生误差的代码行,从而定位到产生模型误差的根本原因。</p><p><strong>3. 总结</strong></p><p>MNN引擎是一个非常好的端侧推理引擎,作为开发者来说,模型的端上部署和性能优化在关注业务逻辑优化的同时,也需关注对引擎计算过程,框架设计和模型加速的思想,反过来可以更好的优化业务代码,做出真正"小而优"的应用。</p><p><strong>4.未来规划</strong></p><p>随着设备性能的普遍提升,后续的业务会搭载到性能更高的设备,我们会利用更丰富的计算后端做模型的加速,比如OpenCL, OpenGL等, 从而加速模型的推理。</p><p>未来设备会搭载更多的模型到客户端,用于实现更多品类道路要素信息的回收,我们也会利用MNN引擎,探究更高效,更高实时性的代码部署框架,以更好的服务于地图采集业务。</p><p>我们是<strong>高德地图数据研发团队</strong>,团队中有大量HC,欢迎对Java后端、平台架构、算法端上工程化(C++)、前端开发感兴趣的小伙伴加入,请发送您的简历到 gdtech@alibaba-inc.com ,邮件标题格式: 姓名-技术方向-来自高德技术。我们求贤若渴,期待您的加入。</p><p><img src="/img/remote/1460000040119131" alt="" title=""></p>
高德Serverless平台建设及实践
https://segmentfault.com/a/1190000040079795
2021-05-28T12:01:50+08:00
2021-05-28T12:01:50+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>导读</strong></p><p>高德启动Serverless建设已经有段时间了,目前高德Serverless业务的峰值早已超过十万QPS量级,平台从0到1,QPS从零到超过十万,成为<strong>阿里集团内Serverless应用落地规模最大的BU</strong>。这个过程如何实现,遇到过哪些问题?本文将和大家分享高德为何要搞Serverless/Faas,如何做,技术方案是什么?目前进展以及后续计划有哪些,希望对感兴趣的同学有所帮助。</p><p><strong>1. 高德为什么要搞Serverless</strong></p><p>背景原因是高德当年启动了一个<strong>客户端上云项目</strong>,项目<strong>主要目的是为了提升客户端的开发迭代效率</strong>。以前客户端业务逻辑都在端上,产品需求的变更需要走客户端发版才能发布,而客户端发版需要走各种测试流程,灰度流程,解客户端崩溃等问题。</p><p>客户端上云之后,某些易变的业务逻辑放到云上来。新的产品需求通过在云端来开发,不用走月度的版本发布,加快了需求的开发迭代效率,离产研同频的理想目标又近了一步(为什么要说“又”,是因为高德之前也做了一些优化往产研同频的方向努力,但是我们希望云端一体化开发能是其中最有效的一个技术助力)。</p><p><img src="/img/remote/1460000040079797" alt="" title=""></p><p><strong>1.1 目标:客户端开发模式——端云一体</strong></p><p>虽然开发模式从以前的端开发转变为现在的云 + 端开发,开发同学应该还是原来负责相应业务的同学,而大家知道,服务端开发和客户端开发显然是有差异的,客户端开发往往是面向单机模式的开发,服务端开发通常是集群模式,需要考虑分布式系统的协调、负载均衡,故障转移降级等各种复杂问题。</p><p>如果使用传统的服务端模式来开发,这个过渡风险就会比较大。Faas很好的解决了这一问题。我们结合高德客户端现有的xbus框架(一套客户端上的本地服务注册、调用的框架),扩展了xbus-cloud组件,使得云上的开发就像端上开发一样,<strong>目标是一套代码,两地运行</strong>,一套业务代码既能在客户端上运行,也能在服务端上运行。</p><p>高德客户端主要有三个端:iOS、Android、车机(类Linux操作系统)。主要有两种语言,C++和Node.js。传统地图功能:如地图显示,导航路径显示,导航播报等等,由于需要跨三个端,采用C++语言来开发。地图导航基础之上的一些地图应用功能,如行前、行后卡片,推荐目的地等主要是用Node.js来开发的。</p><p>在阿里集团,淘系前端团队开发了Node.js Faas Runtime。高德客户端上云项目,Node.js的部分就采用了现有的淘系的Node.js Runtime,来接入集团的Faas平台,完成Node.js这部分的一些业务上云。2020年十一很好的支撑了高德的十一出行节业务。</p><p>C++ Faas没有现有的解决方案,因此我们<strong>决定在集团的基础设施之上做加法,新建C++ Faas基础平台</strong>,来助力高德客户端上云。</p><p><strong>1.1.1 端云一体的最佳实践关键:客户端和Faas之间的接口抽象</strong></p><p>原本客户端的逻辑移到Faas服务端上来,或者新的需求一部分在Faas服务端上开发,这里的<strong>成败关键点在于:客户端和Faas的接口协议定义,也就是Faas的API定义。</strong>好的API定义除了对系统的可维护性有好处以外,对后续支撑业务的迭代开发也很重要。</p><p>理想情况下:客户端做成一个解析Faas返回结果数据的一个浏览器。浏览器协议一旦定义好,就不会经常变换,你看IE,Chrome就很少更新。</p><p>当然我们的这个浏览器会复杂一些,我们这个浏览器是地图浏览器。如何检验客户端和Faas之间的接口定义好不好,可以看后续的产品需求迭代,如果有些产品需求迭代只需要在Faas上完成,不需要客户端的任何修改,那么这个接口抽象就是成功的。</p><p><strong>1.2 BFF层开发提效</strong></p><p>提到高德,大家首先想到的应该是其工具属性:高德是一个导航工具,(这个说法现在已经不太准确了,因为高德这几年在做工具化往平台化转型,高德的交易类业务正在兴起,高德打车、门票、酒店等业务发展非常迅猛)。针对高德导航来说,相比集团其他业务,相比电商来说,有大量的只读场景是高德业务的一大技术特点。</p><p>这些只读场景里,大量的需求是BFF(Backend For Frontend)类型的只读场景。为什么这么说,因为导航的最核心功能,例如routing, traffic, eta等都是相对稳定的,这部分的主要工作在用持续不断的优化算法,使得高德的导航更准,算出的路径更优。这些核心功能在接口和功能上都是相对比较稳定的,而前端需求是多变的,例如增加个路径上的限宽墩提示等。</p><p><img src="/img/remote/1460000040079798" alt="" title=""></p><p>Faas特别适合做BFF层开发,在Faas上调用后端相对稳定的各个Baas服务,Faas服务来做数据和调用逻辑封装,快速开发、发布。在业界,<strong>Faas用的最多的场景也正是BFF场景</strong>(另外一个叫法是SFF场景,service for frontend)。</p><p><strong>1.3 Serverless是云时代的高级语言</strong></p><p>虽然<strong>高德已经全面上云</strong>了,但是目前还不是云时代的终局,目前主要是全面Docker化并上云,容器方面做了标准化,在规模化,资源利用率方面可以全面享受云的红利,但是业务开发模式上基本还和以前一样,还是一个大型的分布式系统的写法。</p><p>对于研发模式来说还并没有享受云的红利,<strong>可以类比为我们现在是在用汇编语言的方式来写跑在云上的服务</strong>。而Serverless、云原生可以理解为云时代的高级语言,真正做到了Cloud as a computer,只需要关注于业务开发,不需要考虑大型分布式系统的各种复杂性。</p><p><strong>1.4 Go-Faas补充Go语言生态</strong></p><p>前面讲到了因为客户端上云项目,我们在阿里云FC(函数计算)团队之上做加法,开发了C++ Faas Runtime。</p><p>不仅如此,我们还开发了<strong>Go-Faas</strong>,为什么会做Go-Faas呢,这里也简单介绍一下背景,高德服务端Go部分的QPS峰值已超百万。高德已补齐了阿里各中间件的Go客户端,和集团中间件部门共建。可观测性、自动化测试体系也基本完善,目前Go生态已基本完善。补齐了Go-Faas之后,我们就既能用Go写Baas服务,又能用Go写Faas服务了,在不同的业务场景采用不同的服务实现方式,Go-Faas主要应用于上文提到的BFF场景。</p><p><strong>2. 技术方案介绍——在集团现有基础设施之上做加法</strong></p><p><strong>2.1 整体技术架构</strong></p><p>上文讲了我们为什么要做这个事情,现在来讲一下我们具体是怎么做这个事情:如何实现,具体的技术方案是什么样的。</p><p>我们本着<strong>在集团现有的基础设施、现有的中间件基础之上做加法的思想</strong>,我们和CSE,阿里云FC函数计算团队合作共建,开发了C++ Faas Runtime 和 Go Faas Runtime。整体和集团拉通的技术架构如下图所示,主要分为研发态、运行态、运维态三个部分。</p><p><img src="/img/remote/1460000040079799" alt="" title=""></p><p><strong>2.1.1 运行态</strong></p><p>先说运行态,业务流量从网关进来,调用到FC API Server,转发到C++/Go Faas Runtime,Runtime来完成用户函数里的功能。Runtime的架构下一章节来具体介绍。</p><p>和Runtime Container一起部署的有监控、日志、Dapr各种Side car,Side car来完成各种日志采集上报功能,Dapr Side car来完成调用集团中间件的功能。</p><p>另外,目前Dapr还在试点的阶段,调用中间件主要是通过Broker和各个中间件Proxy来完成,中间件调用的有HSF,Tair,Metaq,Diamond等中间件Proxy。</p><p>最后Autoscaling模块来管理函数实例的扩缩容,达到函数自动伸缩的目的。这里的调度就有各种策略了,有根据请求并发量的调度,函数实例的CPU使用率的调度。也能提前设置预留实例数,避免缩容到0之后的冷启动问题。</p><p>底层调用的是集团ASI的能力,ASI可以简单理解为集团的K8S + Sigma(集团的调度系统),最终的部署是FC调用ASI来完成函数实例部署。弹性伸缩的,部署的最小单位是上图中的POD,一个POD里包含Runtime Container和Sidecar Set Container。</p><p><strong>2.1.2 研发态</strong></p><p>再来看研发态,运行态是决定函数是如何运行的,研发态关注的函数的开发体验。如何方便的让开发者开发、调试、部署、测试一个函数。</p><p>C++ Faas有个跨平台的难点问题,C++ Faas Runtime里有一些依赖库,这些依赖库没有Java依赖库管理那么方便。这些依赖库的安装比较麻烦,Faas脚手架就是为了解决这个问题,调用脚手架,一键生成C++ Faas示例工程,安装好各种依赖包。为了本地能方便的Debug,开发了一个C++ Faas Runtime Boot模块,函数Runtime启动入口在Boot模块里,Boot模块里集成Runtime和用户Faas函数,可以对Runtime来做Debug单步调试。</p><p>我们和集团Aone团队合作,函数的发布集成到Aone环境上了,可以很方便的在Aone上来发布Go或者C++ Faas,Aone上也集成了一键生成Example代码库的功能。</p><p>C++和Go Faas的编译都依赖相应的编译环境,Aone提供了自定义编译镜像的功能,我们上传了编译镜像到集团的公共镜像库,函数编译时,在函数的代码库里指定相应的编译镜像。编译镜像里安装了Faas的依赖库,SDK等。</p><p><strong>2.1.3 运维态</strong></p><p>最后来看函数的运维监控,Runtime内部集成了鹰眼、Sunfire采集日志的功能,Runtime里面会写这些日志,通过Sidecar里的Agent采集到鹰眼、或者Sunfire监控平台上去(FC是通过SLS来采集的)之后,就能使用集团现有的监控平台来做Faas的监控了。也能接入集团的GOC报警平台。</p><p><strong>2.2 C++/Go Faas Runtime架构</strong></p><p>上面讲的是和Aone,FC/CSE,ASI集成的一个整体架构,Runtime是这个整体架构的一部分,下面具体讲讲Runtime的架构是怎样的,Runtime是如何设计和实现的。</p><p><img src="/img/remote/1460000040079800" alt="" title=""></p><p>最上面部分的用户Faas代码只需要依赖Faas SDK就可以了,用户只需要实现Faas SDK里的Function接口就能写自己的Faas。</p><p>然后,如果需要调用外部系统,可以通过SDK里的Http Client来调用,如果要调用外部中间件,通过SDK里的Diamond/Tair/HSF/Metaq Client来调用中间件就可以。SDK里的这些接口屏蔽了底层实现的复杂性,用户不需要关心这些调用最后是如何实现,不需要关心Runtime的具体实现。</p><p>SDK层就是上面提到的Function定义和各种中间件调用的接口定义。SDK代码是开发给Faas用户的。SDK做的比较轻薄,主要是接口定义,不包含具体的实现。调用中间件的具体实现在Runtime里有两种实现方式。</p><p>再来看上图中间蓝色的部分,是Runtime的一个整体架构。Starter是Runtime的启动模块,启动之后,Runtime自身是一个Server,启动的时候根据Function Config模块的配置来启动Runtime,Runtime启动之后开启请求和管理监听模式。</p><p>往下是Service层,实现SDK里定义的中间件调用的接口,包含RSocket和Dapr两种实现方式,RSocket是通过RSocket broker的模式来调用中间件的,Runtime里集成了Dapr(distributed application runtime) ,调用中间件也可以通过Dapr来调用,在前期Dapr试点阶段,如果通过Dapr调用中间件失败了,会降级到RSocket的方式来调用中间件。</p><p>再往下就是RSocket的协议层,封装了调用RSocket的各种Metadata协议。Dapr调用是通过GRPC方式来调用的。最下面一层就是集成了RSocket和Dapr了。</p><p>RSocket调用还涉及到Broker选择的问题,Upstream模块来管理Broker cluster,Broker的注册反注册,Keepalive检查等等,LoadBalance模块来实现Broker的负载均衡选择,以及事件管理,连接管理,重连等等。</p><p>最后Runtime里的Metrics模块负责鹰眼Trace的接入,通过Filter模式来拦截Faas链路的耗时,并输出鹰眼日志。打印Sunfire日志,供Sidecar去采集。下图是一个实际业务的Sunfire监控界面:</p><p><img src="/img/remote/1460000040079801" alt="" title=""></p><p><strong>2.2.1 Dapr</strong></p><p>Dapr架构见下图所示,具体可以参考看官方文档</p><p><img src="/img/remote/1460000040079802" alt="" title=""></p><p>Runtime里以前调用中间件是通过RSocket方式来调用的,这里RSocket Broker会有一个中心化问题,为了解决Outgoing流量去中心化问题,高德和集团中间件团队合作引入了Dapr架构。只是Runtime层面集成了Dapr,对于用户Faas来说无感知,不需要关心具体调用中间件是通过RSocket调用的还是通过Dapr调用的。后面Runtime调用中间件切换到Dapr之后,用户Faas也是不需要做任何修改的。</p><p><strong>3. 业务如何接入Serverless</strong></p><p>如前文所述,统一在Aone上接入。我们提供了C++ Faas/Go Faas的接入文档。提供了函数的Example代码库,代码库有各种场景的示例,包括调用集团各种中间件的代码示例。</p><p>C++ Faas/Go Faas的接入面向整个集团开放,目前已经有一些高德以外的BU,在自己的业务中落地了C++ /Go Faas了。</p><p>Node.js Faas使用淘宝提供的Runtime和模板来接入,Java Faas使用阿里云FC提供的Runtime和模板来接入就可以了。</p><p><strong>3.1 接入规范——稳定性三板斧:可监控、可灰度、可回滚</strong></p><p>针对落地新技术大家可能担心的稳定性问题,应对法宝是阿里集团的稳定性三板斧:可监控、可灰度、可回滚。建立Faas链路保障群,拉通上下游各相关业务方、基础平台一起,按照集团的1-5-10要求,做到1分钟之内响应线上报警,快速排查,5分钟之内处理;10分钟之内恢复。</p><p>为了规范接入过程,避免犯错误引发线上故障,我们制定了Faas接入规范和CheckList,来帮助业务方快速使用Faas。</p><p>可监控、可灰度、可回滚是硬性要求,除此之前,业务方如果能做到可降级就更好了。我们的C++客户端上云业务,在开始试点的阶段,就做好了可降级的准备,如果调用Faas端失败,本次调用将会自动降级到本地调用。基本上对于客户端功能无损,只是会增加一些响应延迟。</p><p>另外,客户端上该功能的版本,可能会比服务端稍微老一点,但是功能是向前兼容的,基本不影响客户端使用。</p><p><strong>4. 我们目前的情况</strong></p><p><strong>4.1 基础平台建设情况</strong></p><ul><li>Go/C++ Faas Runtime开发完成,对接FC-Ginkgo/CSE、Aone完成,已发布稳定的1.0版本。</li><li>做了大量的稳定性建设、优雅下线、性能优化、C编译器优化,使用了阿里云基础软件部编译器优化团队提供的编译方式来优化C++ Faas的编译,性能提升明显。</li><li>C++/Go Faas接入鹰眼、Sunfire监控完成,函数具备了可观测性。</li><li>池化功能完成,具备秒级弹性的能力。池化Runtime镜像接入CSE,扩一个新实例的时间由原来的分钟级变为秒级。</li></ul><p><strong>4.2 高德的Serverless业务落地情况</strong></p><p>C++ Faas和Go Faas以及Node.js Faas在高德内部已经有大量应用落地了。举几个例子:</p><p><img src="/img/remote/1460000040079803" alt="" title=""></p><p>上图中的前两个图是C++ Faas开发的业务:长途天气、沿途搜。后两个截图是Go-Faas开发的业务:导航Tips,足迹地图。</p><p>高德是阿里集团内Serverless应用落地规模最大的BU,已落地的Serverless应用,日常峰值早已超过十万QPS量级。</p><p><strong>4.3 主要收益</strong></p><p>高德落地了集团内规模最大的Serverless应用之后,都有哪些收益呢?首先,<strong>第一个最重要的收益是:开发提效</strong>。我们基于Serverless实现的端云一体组件,助力了客户端上云,解除了需求实现时的客户端发版依赖问题,提升了客户端的开发迭代效率。基于Serverless开发的BFF层,提升了BFF类场景的开发迭代效率。</p><p><strong>第二个收益是:运维提效。</strong>利用Serverless的自动弹性扩缩容技术,高德应对各种出行高峰就更从容了。例如每年的10-1出行节,5-1、清明、双旦、春节的出行高峰,不再需要运维或者业务开发同学在节前提前扩容,节后再缩容了。</p><p>高德业务高峰的特点还不同于电商的秒杀场景。出行高峰的流量不是在一秒内突然涨起来的,我们目前利用池化技术实现的秒级弹性的能力,完全能满足高德的这个业务场景需求。</p><p><strong>第三个收益是:降低成本。</strong>高德的业务特点,白天流量大、夜间流量低,高峰值和低谷值差异较大,时间段区分明显。利用Serverless在夜间流量低峰时自动缩容技术,极大的降低了服务器资源的成本。</p><p><strong>5. 后续计划</strong></p><ul><li>FC弹内函数计算使用优化,和FC团队一起持续优化弹内函数计算的性能、稳定性、使用体验。用集团内的丰富的大流量业务场景,不断打磨好C++/Go Faas Runtime,并最终输出到公有云,普惠数字化转型浪潮中的更多企业。</li><li>Dapr落地,解决Outcoming流量去中心化问题,逐步上线一些C++/Go Faas,使用Dapr的方式调用集团中间件。</li><li>Faas混沌工程,故障演练,逃生能力建设。Faas在新财年也会参与我们BU的故障演练,逐一解决演练过程中发现的问题。</li><li>接入边缘计算。端云一体的场景下,Faas + 边缘计算,能提供更低的延时,更好的用户体验。</li></ul><p>以上要做的事情任重道远,另外我们未来还会做更多云原生的试点和落地,技术同学都知道,从技术选型、技术原型到实际业务落地,这之间还有很长的路要走。</p><p>欢迎对Serverless、云原生、或者Go应用开发感兴趣的小伙伴,想一起做点事情的同学来加入我们(不管之前是什么技术栈,英雄不问出处,投简历到 gdtech@alibaba-inc.com,邮件主题为:姓名-技术方向-来自高德技术),这里有大规模的落地场景和简单开放的技术氛围。欢迎自荐或推荐。</p><p><img src="/img/remote/1460000040079804" alt="" title=""></p>
高德客户端低代码系统架构实践
https://segmentfault.com/a/1190000040041509
2021-05-21T14:05:28+08:00
2021-05-21T14:05:28+08:00
高德技术
https://segmentfault.com/u/amap_tech
4
<p><strong>导读</strong></p><p>过去的一段时间里,高德地图App大前端团队一直在对<strong>前端低代码搭投技术</strong>进行探索,目前已经在客户端多个业务场景落地,充分验证了搭投技术支撑业务快速迭代的潜力。</p><p>在低代码的实践中,我们发现,除了前端可视化拖拽搭建技术,Serverless、智能化等技术都有助于低代码的业务落地。本文将介绍高德低代码系统架构以及一些新技术的应用方法。</p><p><img src="/img/remote/1460000040041511" alt="" title=""></p><p><strong>1.背景</strong></p><p>开始之前,先简单介绍下高德搭投的技术背景。</p><p>首先,高德地图客户端采用自研跨端框架进行前端开发,框架基于JS引擎实现移动端原生应用跨平台开发,具有动态化、高性能的特点。</p><p>另一方面,在实际业务开发中,客户端各业务线面临越来越重的推荐类卡片(或页面)需求。推荐类需求特点是重展示,轻交互,快速迭代。尤其对迭代速度要求非常强,很多卡片要不断微调以适应市场和业务需求。这对前端技术的动态能力提出了新的要求,也带来了不少问题:</p><p><img src="/img/remote/1460000040041512" alt="" title=""></p><p>为了解决这些问题,我们希望通过搭投技术提高推荐类业务的动态化能力并降低相应的开发成本。</p><p><strong>2.可视化搭建</strong></p><p>整套搭投系统,其实就是搭建+投放。其中搭建是系统的基石,搭建的本质是通过可视化操作维护一份JSON格式的DSL schema,该schema基于一套标准的协议可以描述搭建的产物。</p><p>在相关领域,阿里集团已有多年积累,有代表性的产品包括阿里云钉钉的宜搭系统和蚂蚁的云凤蝶系统。集团也沉淀了核心搭建引擎,低代码搭建协议等工具,我们团队也选择基于阿里统一搭建引擎进行搭建平台的建设。</p><p>针对高德客户端自研框架开发环境,团队开发了组件入料、样式模拟器、设置器定制、模板管理系统、客户端搭建渲染引擎等模块。</p><p>一期建设时,我们选择面向专业开发者进行搭建平台的建设,所以在搭建流程上非常类似前端开发的流程。前端可以在搭建画布上为元素修改样式,绑定事件,甚至手动编写页面生命周期。</p><p><img src="/img/remote/1460000040041513" alt="" title=""></p><p>在后期的实践中,我们发现明确搭建系统最终的用户群体是非常关键的。如果系统面向专业前端开发,那么搭建就必须做到比专业研发手写代码高效,这对引擎的性能提出了很高的要求。</p><p>如果系统面向产品运营及其他非专业前端,那么系统的易用性就必须提高到首位,不应该让一个运营同学研究什么是onClick,而应该先研发便捷的可拖拽组件让运营同学只需要随便绑定个数据就可以在搭建画布上看到想要的所有效果。</p><p><strong>3.投放</strong></p><p>不难看出如果仅有搭建,无法在客户端渲染搭建schema。一个强大的投放系统成为了随之而来的重大需求,我们也开始把重点从搭建这个单一维度上升到全链路能力的建设。</p><p>在没有投放系统时,客户端请求是一个标准的前中后端经典模式,目的在于获取服务数据。例如,高德地图App发送请求打到高德网关,网关负责请求下游庞大的数据服务,对请求进行数据聚合并返回结果。</p><p><img src="/img/remote/1460000040041514" alt="" title=""></p><p>投放系统目的是把前端搭建的产物也聚合进服务请求,客户端在请求数据的同时也在请求前端模板。架构如下:</p><p><img src="/img/remote/1460000040041515" alt="" title=""></p><p>架构思路是面向API,以API为维度分发卡片。</p><p>搭建平台作为独立应用负责搭建。把搭建产物和一个客户端API绑定到一起后保存到服务域服务。服务应用再负责把卡片+API注册到高德网关。高德网关接到一个API请求后,会查看该API是否在投放在线服务与某些搭建schema绑定注册了。如果是,则在已有数据聚合逻辑中,把搭建schema聚合进返回结果对象中。</p><p>这套系统的优点是:</p><ul><li>高德网关继续以API维度收口管控所有端内流量;</li><li>完美匹配当前的高德网关架构,开发成本低,稳定性强。</li></ul><p>这套系统的问题是:</p><ul><li>高德网关仅覆盖高德客户端内业务,还不支持高德端外众多的H5运营活动。</li></ul><p><strong>4.Serverless技术在低代码的应用</strong></p><p>虽然系统成功落地并表现出了坚如磐石的稳定性,但我们不满足于此。为了支持更丰富的业务场景,我们决定对系统架构做优化升级。</p><p>彼时,Node.js Serverless技术逐渐进入了我们的视野。Node.js Serverless的目标之一就是解决重数据逻辑的编排问题,让前端业务有机会对数据进行业务处理。这正是投放服务亟需补充的能力,如果可以通过一个统一的FaaS函数做搭建投放,就可以对接各路数据源,自研框架和H5同时支持的需求也可以满足了。</p><p>所以,我们决定在全套链路中加入一层FaaS函数,也从那时起我们为高德搭投平台起名为Amap Lowcode。</p><p><img src="/img/remote/1460000040041516" alt="" title=""></p><p>通过一层FaaS函数,投放既可以成为原有链路的下游服务,也可以直接为H5运营活动提供前端页面。在应用Serverless的技术中,我们总结出两大收益:</p><ul><li>自动扩容伸缩保障了该前端服务在十一峰值流量时的稳定性;</li><li>无人值守运维为函数的维护节约了大量成本,函数发布上线调试监控一步到位,非常便捷。</li></ul><p>这套架构的缺点是:</p><ul><li>链路较长,业务研发上手难度较大</li></ul><p><strong>5.智能化技术在低代码的应用</strong></p><p>随着业务的大规模接入,我们收到了大量关于链路复杂、上手难度大的反馈。我们也在思考如何通过技术手段提供便捷的搭建体验。智能化技术由此进入了我们的视野。我们与高德设计师团队、阿里集团智能化团队深度合作,率先在搭建平台落地了智能D2C能力。</p><p>具体操作步骤主要分两大部分。设计师在设计稿阶段通过设计插件的辅助可以智能标注所设计区块的组件名称,并生成一个集成了相关数据的数字化设计稿。</p><p><img src="/img/remote/1460000040041517" alt="" title=""></p><p>开发人员拿到设计稿后,可以选择一键跳转到Lowcode搭建平台。进入平台后,样式布局自动生成,直接省掉大部分设计稿还原时间。(下图中的搭建内容全部为自动生成)</p><p><img src="/img/remote/1460000040041518" alt="" title=""></p><p>随后,经过数据编排,FaaS投放等环节,就是我们在高德地图首屏上滑后看到的场景推荐卡片。</p><p><img src="/img/remote/1460000040041519" alt="" title=""></p><p>另外,我们还研发了schema to code功能。如果一个前端业务还不能应用搭投的投放链路,也可以选择在搭建阶段一键导出代码。</p><p>由此一来,任何前端研发都可以通过智能化提高自己的开发效率。</p><p>智能化技术的加入,直接为低代码平台打开了想象力的大门。本着为业务方提供便捷体验的原则,我们还相继拓展出了<strong>智能预览功能</strong>和<strong>标准投放位容器</strong>。</p><p>智能预览可以根据设计稿的数据源智能选择预览上下文和环境,帮助业务方在实际页面效果中预览搭建产物效果。</p><p>标准投放位容器可以让业务方仅输入一个唯一id及少量配置信息就自动承接投放功能,一些业务在接入后,无需再开发客户端代码就可以完成客户端迭代。</p><p><strong>6.总结</strong></p><p>高德Lowcode平台共有四大特性:从第一天起,它就具备了面向toC客户端的特性;在Serverless技术的帮助下,高德Lowcode平台具备了同时支持自研框架和H5的双技术栈能力特性;为了支撑运营活动同学的H5搭建,在搭建环节研发了简易版搭建流程,平台具备同时面向专业研发和运营活动同学的特性;最后,设计稿一键转化D2C等功能为平台带来了智能化的特性。</p><p>以上这些特性使得高德Lowcode平台可以在同业中处于领先水平。最后,附送整套智能化搭投系统大图:</p><p><img src="/img/remote/1460000040041520" alt="" title=""></p><p>期待与读者们一起交流低代码领域的相关经验和感想。如果你同样对低代码技术抱有热忱,更欢迎你加入我们的团队一同前进。我们团队业务上负责驾车导航等高德地图App核心场景,技术上在多个前端方向均有成果落地。感兴趣的同学请发送简历到 gdtech@alibaba-inc.com,邮件主题为:姓名-技术方向-来自高德技术。</p><p>我们还在路上,未来会更加努力,让出行更美好。</p><p><img src="/img/remote/1460000040041521" alt="" title=""></p>
数据人必读!玩转数据可视化用这个就够了——高德LOCA API 2.0升级来袭!
https://segmentfault.com/a/1190000039981317
2021-05-11T15:19:12+08:00
2021-05-11T15:19:12+08:00
高德技术
https://segmentfault.com/u/amap_tech
4
<p><strong>引言</strong></p><p>“一图胜千言”,大数据时代来临,数据与人们生活密切相关。复杂难懂且体量庞大的数据给人的感觉总是冷冰冰的,让人难以获取到重点信息,也找不出规律和特征,数据价值发挥不出来。空间数据可视化就是为了解决这些问题,用通俗易懂的图形符号还原数据,表达多纬度数据信息,让你的数据“活”起来!</p><p>高德 LOCA 数据可视化旨在为各领域企业和个人提供便捷高效的可视化应用技术,提供基于 WebGL 和高德 JSAPI 的大规模地理数据可视化开发框架,应用于地理空间数据的可视化领域。与高德静态底图结合,深度定制,拥有丰富的可视化类型,将高性能海量数据渲染能力、丰富的案例场景、酷炫表达以简单易用的方式提供给用户,让人人都能玩转酷炫的地理数据可视化。</p><p><strong>一句话概括,你可以轻轻松松把一堆枯燥无味的数据通过酷炫的方式展示到地图上,并顺手生成那个牛气哄哄的可视化方案!</strong></p><p><strong>LOCA数据可视化API 2.0全新升级</strong></p><p>LOCA2.0不仅具有简单易用的 API 文档,丰富的场景案例灵活选择。还升级了90余种图层能力其中包括数据交互功能及点、线、面、蜂窝、热力等动画支持,让数据鲜活有温度、易理解、可交互。技术上运用全新的渲染管线和架构模式,极大提升了数据处理能力和数据渲染能力。</p><p><strong>LOCA 2.0新特性</strong></p><p><strong>视觉&动效</strong></p><p><strong>1.用这些配色既好看,又能传递数据语义</strong></p><p>LOCA 的基础配色,结合数据关联关系、分布趋势、特征属性等特点,精细化配置颜色在数据维度上的衡量和心理感知。所有案例均使用辨识度高、准确、可信的配色策略,<strong>包括:分类色、单双相连续色、发散色、语义色。</strong>通过颜色的视觉通道来理解和观测数据,用户可根据 LOCA 案例场景取对应配色方案使用,后续将提供浅色地图的可视化配色主题。</p><p><img src="/img/remote/1460000039981319" alt="" title=""></p><p><strong>2.简单易懂的图形符号,让你做出人人都懂的可视化</strong></p><p>在实现可视化映射时,LOCA 采用图形易变量的思路,定义了视觉变量的种类:形状、尺寸、方向、颜色,将数据点映射到图形时,基于数据的类别、顺序和数值特性,匹配合适的视觉图形。如图所示,LOCA 所使用的视觉变量及可视化编码。</p><p><img src="/img/remote/1460000039981320" alt="" title=""></p><p><strong>3.高度自定义镜头,支持多数据场景切换</strong></p><p>高度自定义的镜头。在地图场景中如何运用镜头语言来展现信息内容尤为重要,<strong>因此我们提供了 Pitch、Zoom、Rotation、Center 四个镜头相关变量</strong>,自定义轨迹动画曲线缓入、缓出等,实现对镜头参数顺心所欲的控制。</p><p><img src="/img/remote/1460000039981321" alt="" title=""></p><p><strong>4.平滑自然的动画效果,让数据转场不再突兀</strong></p><p>更多图层要素动效。<strong>支持三十多种动画线,高度、半径、透明度、海拔等属性</strong>都拥有动画过渡特效,解决图层出现消失时的突兀问题,让数据之间的转场过渡平滑自然。</p><p><img src="/img/remote/1460000039981322" alt="" title=""></p><p><strong>5.多光源分布,增强场景视效</strong></p><p>一个场景支持多点布光。多种光照类型,多光源分布,<strong>可控制光照强度、范围、颜色、位置等,通过参数控制光照随时间的转场效果,</strong>增加场景光照明暗的视觉层次。</p><p><img src="/img/remote/1460000039981323" alt="" title=""></p><p><strong>6.表达AB点脉冲和轨迹动画效果,让数据鲜活起来</strong></p><p>PulseLine 轨迹线支持脉冲效果,脉冲<strong>可控制数量、动画时长、线段宽度等</strong>,动画方向和速率均可传递数据意义,例速度快则数据线路繁忙,慢则反之。Scatter 图层支持图标动效绘制。</p><p><img src="/img/remote/1460000039981324" alt="" title=""></p><p><strong>图层能力&渲染性能</strong></p><p><strong>1.三维空间高度线和楼层能力,还原真实空间数据效果</strong></p><p>三维空间支持。线图、热力图、网格图、蜂窝图等都已支持地理单位(米)的设置,并且对于线数据图层可设置每一个节点的海拔高度,定义节点之间不同的垂直距离。<strong>三维高度面能力,还原实际楼层高度及内部构造,</strong>可灵活设置单个楼层和内部面的厚度、透明度和颜色等属性。</p><p><img src="/img/remote/1460000039981325" alt="" title=""></p><p><strong>2.个性化定制独特的图形,让可视化效果丰富多样</strong></p><p>数据驱动的自定义视觉变量控制。样式字段支持对图层中单个数据进行函数回调,可以针对每一个数据设置独特的图形符号,灵活的配置图形符号半径、透明度、透明度等属性。</p><p><img src="/img/remote/1460000039981326" alt="" title=""></p><p><strong>3.数据渲染可达百万级,效率提升近10倍</strong></p><p>通过全新的架构渲染管线,优化数据处理和样式解析过程,充分发挥 WebGL 的渲染性能,突破 LOCA 1.3 大数据量渲染的瓶颈,<strong>数据响应速度快可轻松处理大规模数据集。</strong></p><p><img src="/img/remote/1460000039981327" alt="" title=""></p><p><strong>4.支持多图层任意组合,大小场景实时观测</strong></p><p>在业务场景中,通常观测宏观趋势时也希望可以看到微观场景下数据分布和数值,辅助数据分析及决策。LOCA 提供双图层融合能力,可对单个图层自定义颜色、尺寸、样式和组合过渡效果。以 3D 热图结合点图层为例,通过镜头控制地图逐级下钻,<strong>满足从全局到局部可视的读取数据的需求。</strong></p><p><img src="/img/remote/1460000039981328" alt="" title=""></p><p><strong>5.数据精准拾取,满足复杂场景的展示和交互</strong></p><p>支持图面海量要素的快速获取,细颗粒度控制要素的自定义样式和独立渲染,鼠标滑过元素即高亮反馈并透出数据信息,<strong>点、线、面、体最小像素选中后数据精准透出</strong>,来满足复杂场景的展示和交互。</p><p><img src="/img/remote/1460000039981329" alt="" title=""></p><p><strong>LOCA 业务场景应用</strong></p><p>LOCA 可视化 API 旨在帮助企业和个人打造空间数据可视化表达与分析解决方案,适用于众多业务场景。例如:<strong>交易分析、选址投放、交通指数、城市健康度、事件响应、研判分析、疫情迁徙等场景的应用</strong>。LOCA 2.0 全面提升了业务场景表达能力,多维度解读数据,使业务数据表达更专业、精准。也为用户提供了丰富的业务场景案例 Demo,供广大用户参考使用。</p><p><strong>结语</strong></p><p>正如约翰·图基所说:图像最大的价值在于促使我们关注到意想不到的东西。地理可视化通过数据的计算转化,让颜色变得更有温度,数据变得更有份量,动画更有意义,让地理空间数据更具活力。未来还有越来越多的可视化前沿场景等着我们去挖掘去钻研,<strong>依托于高德地图的 LOCA 将持续提升空间数据的计算和表达能力,增强数据交互体验,让数据可视化发挥更巨大的商业价值,</strong>这也是我们不断前进的动力。</p><hr><p><strong>访问高德开放平台</strong></p><p><a href="https://link.segmentfault.com/?enc=JP48gOXTFfZl5i1GzkxYDg%3D%3D.zsRcONvyzDVBrYva5eoh5FVbYbfFgIN%2BMP3aZ0xox6M%3D" rel="nofollow">lbs.amap.com</a></p><p>高德数据可视化主页:<a href="https://link.segmentfault.com/?enc=E%2BNR%2FrLoi%2BWK9wm7x341ag%3D%3D.kfmac7q%2F%2BJlgxZDNbo3VB0uRXWNwgKjwWwmnjfItccazMesT2APvZUVhEp0bAbrL" rel="nofollow">https://lbs.amap.com/product/loca#/</a></p><p><img src="/img/remote/1460000039981330" alt="" title=""></p>
高德技术开放日活动预告 | 聊聊技术与成长那些事,锁定4月10日
https://segmentfault.com/a/1190000039787904
2021-04-07T18:09:00+08:00
2021-04-07T18:09:00+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>又到一年毕业季,即将开启(实习及正式)职场生涯的同学们会有不少疑惑。比如,热门技术如何在工业级业务场景落地并带来更好的用户体验?学术界科研与工业级研发的区别有哪些?智慧出行核心技术有哪些,目前主流的技术栈未来发展前景如何?校招同学进入互联网领域需要具备什么样的能力,如何准备简历和面试,职场环境如何?</p><p>为帮助大家解疑答惑,阿里巴巴高德地图为大家准备了本次<strong>高德技术开放日</strong>活动,并邀请到了核心工程师与大家一起聊聊智慧出行核心技术以及职场实习、成长那些事。<strong>4月10日(周六)上午9点半</strong>直播,与大家不见不散,我们也准备了大量的互动好礼等你来拿~</p><p><img src="/img/remote/1460000039787906" alt="" title=""></p><p><strong>部分直播话题剧透:</strong></p><ul><li><p>高德如何深耕技术打造出<strong>亿级用户</strong>的<strong>国民级智慧出行服务平台</strong></p></li><li><p>最前沿的<strong>人工智能、算法、大数据、云计算、AR、Serverless</strong>技术如何落地实践驱动业务增长</p></li><li><p>作为业界领先的<strong>自动驾驶</strong>技术服务商,自动驾驶核心技术有哪些?发展前景如何?</p></li><li><p><strong>校招生</strong>进入互联网<strong>算法</strong>或<strong>工程研发</strong>领域,需要具备什么样的能力?在高德能获得哪些成长机会?</p></li><li><p>如何选择<strong>本专业</strong>或<strong>跨专业</strong>的工作?找工作有哪些TIPS?各岗位<strong>简历投递</strong>技巧,专业<strong>面试</strong>考察重点有哪些?</p></li></ul><p><strong>直播时间:</strong><strong>2021年4月10日09:30-15:30</strong></p><p><strong>直播平台:</strong></p><ul><li><p><strong>B站(高德技术)</strong></p></li><li><p><strong>抖音(高德技术)</strong></p></li><li><p><strong>微信视频号(高德技术)</strong></p></li></ul><p><strong>直播互动礼品全场不停,每位讲师分享环节都有互动礼品,高德公仔、星巴克咖啡、高德打车券…让你拿到手软。</strong></p><p>大量应届生实习岗、社招岗开放,欢迎对高德地图感兴趣的同学,随时投递简历,加入我们一起创造更美好的出行~</p><p><strong>简历投递邮箱</strong>:xz2022@alibaba-inc.com</p><p><strong>关于高德地图</strong>:</p><p>高德地图是国内唯一日活过亿的国民出行平台,作为国内领先的数字地图和实时交通位置服务提供商,充分发挥流量,数据和技术等优势,致力于连接真实世界,让出行更美好。除地图导航外,高德地图还为用户提供打车、酒店、门票等一站式出行服务。每年为用户节省出行时间超过21亿小时,为30多万移动应用提供位置服务。</p>
高德POI数据生产中的计算机视觉技术
https://segmentfault.com/a/1190000039696447
2021-03-23T16:57:02+08:00
2021-03-23T16:57:02+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<blockquote>前言:又到春招季!作为国民级出行服务平台,高德业务快速发展,大量校招/社招名额开放,欢迎大家投递简历,详情见文末。为帮助大家更了解高德技术,我们策划了<strong>#春招专栏#</strong>的系列文章,组织各业务团队的高年级同学以<strong>业务科普+技术应用实践</strong>为主要内容为大家做相关介绍。</blockquote><p>本文是#春招专栏#系列的第 <strong>3</strong> 篇,根据 <strong>高德视觉技术中心基础研发部</strong> 负责人郝志会在AT技术讲坛分享的<strong>《视觉技术在POI名称自动化生成的实践》</strong>内容整理而成,在不影响原意的情况下略作删节。</p><p><strong>AT技术讲坛(Amap Technology Tribune)</strong>是高德发起的一档技术交流活动,每期围绕一个主题,我们会邀请阿里集团内外的专家以演讲、QA、开放讨论的方式,与大家做技术交流。</p><p>郝志会所在团队涉及到计算机视觉方面很多技术:包括目标的检测、识别、分割,几何重建、视觉定位,等等。</p><p><strong>高德POI数据的采集</strong></p><p>高德有7000万以上的POI(Point of Interest,兴趣点)数据。每年还会出现很多新增的POI,也会有一部分POI停止营业、关门倒闭。<strong>这些POI如何制作和更新?</strong>从采集方式来看会有很多获取POI的方式,有一种重要而且直观的采集方式,高德通过众包方式采集街边店铺的图像,利用计算机视觉技术(以及人工辅助)从图像中提取POI数据。</p><p>下图演示了一次众包化采集过程。高德的采集人员从这条街走过,拍摄连续图像。最后把图像和GPS坐标,上传给高德。</p><p><img src="/img/remote/1460000039696455" alt="" title=""></p><p>下图是一个POI从采集到生产,再到使用的示意图。输入的是连续采集的图像,对于生产环节,最重要的是计算每个POI的内容和位置。然后和母库中的POI匹配,确认这个POI是已经存在的,还是需要新增。从图像中识别POI的名称,计算坐标,都需要用到计算机视觉技术。</p><p>本文主要介绍的是名称的部分。实际上,高德的POI生产不是全自动化的,而是人机结合的方式。当机器不能自动化,或者置信度较低时,交给人工作业。</p><p><img src="/img/remote/1460000039696452" alt="" title=""></p><p>高德的POI数据采集—生产—使用流程示意图</p><p>POI数据丰富多彩的呈现形式,给自动化的处理过程带来了挑战,包括:文字的识别、是否为POI、文字之间关系、如何命名(定名)…</p><p>以下图为例,从原始图像,到自动生成POI的名称,包含了以下<strong>几项关键的计算机视觉技术</strong>:<strong>自然场景文字识别</strong>、<strong>文本属性判定和结构化处理</strong>、<strong>名称自动生成</strong>…</p><p><img src="/img/remote/1460000039696451" alt="" title=""></p><p><strong>自然场景文字识别</strong></p><p>文字识别,简单说,就是从一张图片中,找到里面的文本,给出正确的字符。从文字识别问题的发展过程来看,它包含了不同的子问题。</p><p>首先,大家比较熟悉的名词是<strong>OCR</strong>,中文翻译过来是<strong>光学字符识别</strong>。原意是利用光学扫描仪,将印刷体文字读成二进制数据,再识别成ascii码字符,输出出来。</p><p>OCR问题历史比较悠久,上个世纪80、90年代,就有不少研究论文,以及商业化产品。比如我们熟悉的深度学习创始人之一Yann Lecun,他在90年代初,就用神经网络识别手写的邮政编码,被美国银行商用化了。</p><p>随着文字识别技术的发展,它的应用范围也变多了。除了印刷体、手写体之外,任何一张普通的包含了文字的图片,是不是都可以识别出来呢?</p><p>在下图中,中间一列的问题叫做born-digitial,也就是说文字是由电脑生成的,文字的字体、版式,相对比较固定。</p><p>第3列是自然场景的文字识别问题,称为<strong>STR</strong>,也就是在真实存在的文字,比如店铺名称、路牌,这种文字识别问题,因为拍照的角度问题、光照问题、图片质量问题,应该说难度是最大的。也是现在学术界研究比较多的一种类型。</p><p><img src="/img/remote/1460000039696456" alt="" title=""></p><p>当然,现在的STR技术,会面临很多的挑战:包括字体问题、排版问题、多语言问题,以及由拍摄带来的光照问题、模糊问题。</p><p>一个店铺门匾上的文字,比其他场景的会更复杂,因为它要表达自己的特点,要让你“过目不忘”,所以更容易出现各种艺术字、各种不同的装饰效果。</p><p>而且,高德地图要维护全国的POI数据,在不同城市上,它的地名、店铺名、品牌名,本身是一个非常大的词库。</p><p><strong>STR技术发展:传统算法(before 2012)</strong></p><p><img src="/img/remote/1460000039696464" alt="" title=""></p><p>先简单介绍一下STR技术。</p><p>自然场景文字识别(STR)的发展大致可以分为两个阶段,<strong>以2012年为分水岭,之前是以传统图像算法为主;之后,进入了深度学习算法的阶段。</strong></p><p>2012年之前,文字识别的主流算法都依赖于传统图像处理技术和统计机器学习方法实现。分为文本行检测、文字识别两部分。</p><p><strong>文本行检测</strong>,一般是先预处理,利用二值化、连通域分析、MSER显著性区域算子等算法,定位文字区域,提取文本行候选,然后通过分类,去除掉无效候选。</p><p><strong>文字识别</strong>,一般是通过切割,找出字符/单词的候选,再通过机器学习分类器,对每个字符/单词进行分类。</p><p>传统的文字识别方法,在简单的场景下能达到不错的效果,但是不同场景下都需要独立设计各个模块的参数。遇到复杂的场景,很难调整参数,得到泛化性能好的模型。</p><p><strong>STR技术发展:深度学习算法(after 2012)</strong></p><p>大概从2012年开始,跟其他的计算机视觉问题一样,STR也进入了深度学习的阶段。</p><p>上面讲到的文本行检测、文字识别两个子问题,分别都有一些深度学习的模型来解决。下面列举几个比较典型的工作。</p><p><img src="/img/remote/1460000039696457" alt="" title=""></p><p>最左边,是一个文本行检测模型,华中科技大学的Textboxes++,它是在类似SSD的网络结构的基础上,对四边形的四个顶点的坐标分别做回归,以解决长宽比、旋转这类问题。</p><p>中间是一个序列识别模型。可以说这是在深度学习阶段以后,出现的一类新的解题方法。输入一个字符序列的图像,传统的方案是必须要切割成单个字符,或者单词,再对它们做分类,有了LSTM这种RNN模型,可以对前后特征序列做编码,再通过引入CTC loss,就可以训练一个完整的序列识别模型。</p><p>除了将文本行检测、识别两个环节改造成深度学习的方案以外,也有一些工作在试图把两者整合起来,形成一个end-to-end的方案。整合的目的是什么呢?不难想象,如果能够识别出文本的内容,理论上应该可以检测的更准。比如,如果可以识别出“深度学”这3个字,那是不是可以通过某种网络的反馈信号告诉检测器,后面应该还有一个“学习的习”字。</p><p>第三列是一个end-to-end的工作,他是把faster r-cnn和LSTM接到同一个网络里,在对每个proposal做分类和坐标回归的同时,也做字符的识别。</p><p><strong>高德的STR技术</strong></p><p>高德在STR上的技术,其实也是分成文本行检测、字符识别两部分。</p><p>在实际工作中并没有使用“端到端”的模型,因为这种分模块的模型,更容易优化局部的效果,比如为某一个模块增加样本,或者换一个模型。</p><p><img src="/img/remote/1460000039696453" alt="" title=""></p><p>在字符识别的环节,可以看到高德是平行使用了两种方案。上面的分支是单字符的检测和识别,下面的分支是整个文本序列的识别。</p><p><strong>高德的STR技术——文本行检测</strong></p><p>首先看文本行检测。在早期的时候,大概2017年之前,使用语义分割模型,比如FCN、deeplab来分割文本行。</p><p>到2017年Mask R-CNN出现之后,Instance segmentation技术越来越成熟,我们发现实例分割在文本行检测这个问题上的效果,也超过了语义分割模型。最重要的是,因为要单独识别每个文本行,实例分割很自然地就解决了这个问题。</p><p>而语义分割,还要做大量的后处理,才能把不同的文本行区分开。</p><p>当然除了Mask R-CNN以外,我们也会使用其他的实例分割模型。</p><p>在实际的业务问题上,高德的文本行检测的效果。不管是文本行密集、还是模糊的情况下,检测的效果都达到了很高的水平。</p><p><strong>高德的STR技术——文字识别</strong></p><p>文字识别,高德实际上是用了两个分支,单字符的检测识别,以及序列的识别。最终识别结果,是这两个分支的输出的融合。</p><p>为什么要用两个分支?</p><p><img src="/img/remote/1460000039696450" alt="" title=""></p><p>可以看这个例子,对于“一二三四的一”,单字符是不容易准确地检测到的,因为它很容易和背景混淆。</p><p>但是因为它位于文本行中间,通过整个序列是可以识别出来的。</p><p>那只依靠序列识别,把单字符的分支去掉,是否可以?或者说会有什么问题?这个留给同学们自己思考。</p><p><strong>序列识别模型</strong></p><p>早期的序列识别模型,主要是使用 LSTM + CTC loss,后来替换成了带有attention layer的LSTM。引入了attention,可以使在每一个timestep输出时,网络对特征输入更聚焦,预测的效果也更好。</p><p>通过这些方法,对于不同的字体、不同方向、甚至不同语言,识别效果都是不错的。</p><p><strong>Hard case的挖掘和生成</strong></p><p>在实际的工作中,除了模型的设计和优化,也会面临很多其他的问题。</p><p><img src="/img/remote/1460000039696449" alt="" title=""></p><p>一个比较大的问题是,汉字的字符很多。常用汉字有大概3000-5000个,但是在POI中看到的字符,会远远超过这个数字。</p><p>高德地图有7000万个POI,大家可以想想会是个什么数字。</p><p>针对这个问题,我们有几个不同的解决方案。比如可以从POI的名称里,找到感兴趣的字符,再找到采集图片,再交给人工去标注。也可以通过电脑的字库,加上一些渲染效果,合成一些样本。</p><p><img src="/img/remote/1460000039696454" alt="" title=""></p><p>高德是从2016年左右,开始研发文字识别技术,到现在还在持续优化。为了检验技术能力,高德视觉技术团队也参加过一些竞赛。OCR领域比较大的一个竞赛是 ICDAR,高德参加了2017年,2019年的文本行定位、字符识别的比赛,也有一些不错的成绩。</p><p><strong>文本属性判定和结构化处理</strong></p><p>在对场景中的文字进行检测和识别以后,需要判断哪些文字和POI名称有关。因此,需要判断每个文本行的属性;同时,临近的多个文本行往往是有关系的,需要计算它们的关系,进行结构化的输出。</p><p><strong>文本属性判定问题</strong></p><p><img src="/img/remote/1460000039696458" alt="" title=""></p><p>这个问题是有挑战性的。一个文本行是否为POI名称,和它的文本内容、所处的位置,都有关系。以上图为例,仅看“会员上网,2元/小时”,基本可以猜出来,这不是一个POI名称。而同样都是“百世快递”,当它处在店铺上方的牌匾上时,它大概率是一个POI名称;当它处在快递车身上时,它不是我们想制作的名称。</p><p>文本属性的判定,<strong>最直接的一个任务是降噪:将明显无效的POI文本排除掉。高德使用了图像和文本双通道的卷积神经网络,取得了比较明显的降噪效果。</strong></p><p>既然可以将文本行判定成POI名称和噪声两个类别,扩展一下,还可以将POI名称相关的文本分成多个属性类别,包括主名称、分店名、营业范围、联系方式等。在制作POI名称时,人工会根据一定的工艺规范,选取其中一部分文本,也会根据这些文本的属性,自动选取或舍弃,以及排序,最终生成POI名称。</p><p>另外,高德也引入了牌匾的语义分割,确定每个牌匾独立的边界。有边界的情况下,主名称是唯一的。</p><p><strong>名字自动生成</strong></p><p>最后,看一下名称自动生成的问题,以及解法。</p><p>在文字识别、属性判定之后,怎样自动生成POI名称呢?人在掌握了作业工艺之后,可以根据挂牌推断出这个店的正确名称(这也是一个合格的挂牌的基本功能)。那么,机器能否学习和掌握命名规则,从而根据挂牌生成名称呢?</p><p>在现实世界中,这个问题的难度并不低。以下方的这个牌子为例,正确的POI名称是什么呢?</p><p><img src="/img/remote/1460000039696459" alt="" title=""></p><p>来看更多的例子:</p><p><img src="/img/remote/1460000039696460" alt="" title=""></p><p><strong>名称自动生成模型</strong></p><p><img src="/img/remote/1460000039696462" alt="" title=""></p><p>如上,输入的是多个文本行,输出是这些文本行的标签(是否被选择作为最终名称的一部分),以及顺序。如果不考虑图像信息,这是个NLP问题。可以采用BERT模型训练。把问题定义成一个双任务的学习问题,包括分类任务和回归任务。</p><p>把图像信息也加入到模型中。输入是所有文本行的bounding box,使用一个Graph Attention Network将其编码成特征,和BERT模型特征连接起来。最终提升了模型的学习能力。</p><p><img src="/img/remote/1460000039696461" alt="" title=""></p><p>进一步地,受到微软的工作的启发,高德也使用了VL-Bert模型。名称生成的质量,最终提升到了95%。</p><p><img src="/img/remote/1460000039696463" alt="" title=""></p><p>这是名称自动生成的一些效果。前3个例子,尽管排版各不相同,模型都能够比较好地学习到名称生成的规则。</p><p>当然,如图中的bad case,当挂牌的版式不常见时,模型的预测会出现问题。这也是后面的优化方向。</p><p><strong>关于高德视觉团队</strong></p><p>由分布在西雅图、硅谷、北京等地的杰出科学家和工程师组成,是高德地图视觉算法核心团队。为地图、导航和出行的新未来解决难题,探索创新技术。涵盖图像理解、视频分析、多源融合等技术,面向地图及高精地图制作、定位、交通及预测、AR导航、辅助驾驶以及信息娱乐等领域。是高德地图高精尖技术发展的核心引擎。</p><p><img src="/img/remote/1460000039696465" alt="" title=""></p>
高精地图技术专栏 | 基于空间连续性的异常3D点云修复技术
https://segmentfault.com/a/1190000039425483
2021-03-16T11:17:01+08:00
2021-03-16T11:17:01+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>1.背景</p><hr><p><strong>1.1 高精资料采集</strong></p><p>高精采集车是集成了测绘激光、高性能惯导、高分辨率相机等传感器为一体的移动测绘系统。高德高精团队经过多年深耕打造的采集车,具有精度高、速度快、数据产生周期短、自动化程度高、安全性高、信息量大等特点。</p><p>为了保证高精地图制作的精度,在高精采集车中,我们使用了目前业界最先进的激光测距仪,具有测量距离远、点云密度大等优点,扫描频率可以达到每秒100万点。</p><p><strong>1.2 激光MTA问题</strong></p><p>高速的扫描频率带来高质量数据的同时,也引入了一些特有的噪声和干扰,MTA就是其中的一种。什么是<strong>MTA(Multi-Time-Around)</strong>呢?我们可以看一下图1,通过上下两图的对比可以看到,MTA问题实际就是激光的测距问题,激光将远处的点错误的拉到了近处,导致远处的楼房成为了近处路面上的噪声。</p><p>MTA问题会给后续资料处理、自动识别、地图制作等工艺流程带来很大的困难,导致识别以及人工流程出现错误。</p><p>我们需要通过激光的内部机制和数据处理算法,将这些噪声恢复到它本来的位置。本文会从<strong>MTA问题产生的原理</strong>、<strong>激光应对MTA的内部机制</strong>、<strong>数据处理算法</strong>三方面来介绍高精资料处理是如何解决这个问题的。</p><p><img src="/img/remote/1460000039425486" alt="" title=""></p><p>图1 MTA问题数据</p><h2><strong>2.MTA原理</strong></h2><p>那么,MTA究竟是怎样产生的呢?这要从激光的测量原理说起。</p><p><strong>2.1 激光测距原理</strong></p><p>典型的激光扫描仪是采用<strong>TOF(time of flight)</strong>原理进行测量的,即激光传感器在测量时每隔固定时间发射一个脉冲,然后测量返回的脉冲能量,根据发射和接收的时间差计算点的距离:</p><p><img src="/img/remote/1460000039425487" alt="" title=""></p><p>通过周期性地“发射激光-接收回波”,即可根据光飞行参数得到一系列测量点距离,结合激光自身的位置和姿态即可计算出反射点的位置。</p><p><strong>2.2 MTA多区间</strong></p><p>激光受自身功率的限制,通常能够探测到的最远物体距离有限,为Dmax。而激光脉冲的发射间隔为dt,在下一个脉冲发射前,当前激光脉冲能够探测到的最远距离为:</p><p><img src="/img/remote/1460000039425488" alt="" title=""></p><p>高精采集车使用的激光频率为100万点/秒,对应的Dpluse为150m。</p><p>通常情况下,激光的发送和接收是按顺序进行的,即发送-接收-发送-接收,空中始终只有一个激光脉冲,接收和发送是一一匹配的。</p><p>但是,当Dmax大于Dpluse时,如果测量物体比较远,就可能在空中出现多个脉冲,多个脉冲到达接收器的顺序不再和脉冲发射的顺序一致,接收器无法正确计算脉冲的TOF,从而不能正确的得出物体的测距。这就是MTA(Multi-Time-Around),如下图2所示。</p><p>通常将反射信号可能跨过的收发周期数称为“MTA区间”,匹配时间上最近的一个发射信号为MTA1,次近的发射信号为MTA2…依此类推。</p><p>Dpluse就是每个MTA的区间长度。如果物体离激光的距离超过这个长度,就会发生MTA问题,高精采集车激光的MTA区间长度是150m,因此对于超过150m的远处高楼就发生了MTA现象。</p><p><img src="/img/remote/1460000039425489" alt="" title=""></p><p>图2 MTA区间</p><h2>3.激光应对MTA的内部机制</h2><p>为了应对MTA问题,激光厂家也做了一些努力,通过利用测量物体的表面连续性的假设和变周期测量技术,找到了一些解决思路。</p><p><strong>3.1 邻域连续性假设</strong></p><p>在现实世界中大多数物体,例如道路、标牌、建筑物等人造物,这些实物都具有表面连续性,一般不会出现剧烈的几何变化和纹理。因此,连续的激光脉冲测距应该变化不大,如图3所示。</p><p>如果能够找到一种办法,使得当激光测距放错MTA区间时,相邻激光点不再具有连续性的特征,就可以将点云放到正确的MTA区间。变周期测量技术就是基于这一思路而产生的。</p><p><img src="/img/remote/1460000039425491" alt="" title=""></p><p>图3 相邻激光点测距连续性</p><p><strong>3.2 变周期测量技术</strong></p><p>为了识别MTA问题,激光厂商设计了一系列专利技术,其核心是“激光发射间隔可变”,即相邻激光脉冲发射的时间间隔是不同的,如图4。而且这个发射间隔的变化具备周期性,其周期特点如图5所示。当将点云放错MTA区间时,其测距不再是连续的,而是如图5中列表第3列所示,来回跳跃。如图6,错误的MTA区间,相邻点来回跳跃,形成图中的分层。</p><p><img src="/img/remote/1460000039425490" alt="" title=""></p><p>图4 变周期发射技术</p><p><img src="/img/remote/1460000039425493" alt="" title=""></p><p>图5 变周期参数</p><p><img src="/img/remote/1460000039425494" alt="" title=""></p><p>图6 错误MTA区间</p><h2><strong>4.MTA修正算法</strong></h2><p>根据MTA问题的原理以及邻域连续性假设,结合硬件上的变周期测量技术,确定MTA问题处理方案。首先进行邻域划分,找到相邻激光点,然后对相邻点计算放到不同MTA区间的统计权值,权值大的为真实MTA区间。同时为了提高算法性能,利用激光本身安装位置参数避免不必要的权值计算。</p><p><strong>4.1 邻域设置与检测</strong></p><p>首先确定邻域,因为Lidar是一圈圈扫描的,既要考虑时间上连续的点相邻,也要考虑连续圈的相邻。其基本思路如下:</p><ul><li>数据分圈:以一个圆周(线)为基本处理单元;</li><li>连续性计算区域:对于某个点,取其当前圈的邻近点以及前后相邻两圈的邻近点作为连续性计算区域,如图7;</li><li>对每个点计算其测距连续性权值以及反射率连续性权值,即与方差成反比例然后得出MTA区域。</li></ul><p><img src="/img/remote/1460000039425492" alt="" title=""></p><p>图7 邻域查找</p><p><strong>4.2 加权统计策略</strong></p><p>总的加权策略是距离方差越大,权重越小;反射率方差越大,权重越小。具体权值选择采用高斯函数或三角函数。</p><p>经过实际大批量数据统计分析,距离方差的权重采用高斯函数,其中u=0,δ=0.25,反射率方差的权重也采用高斯函数,其中u=0,δ=4</p><p><img src="/img/remote/1460000039425485" alt="" title=""></p><p>图8 加权函数选取</p><p>具体计算过程如下:</p><ul><li>对每个点,分别获取其作为MTA1与MTA2的测量数据,主要为测距值、反射率;</li><li>对每个点,分别获取其MTA1与MTA2邻居点集合;</li><li>计算每个点的每个邻居的测距权值和反射率权值,然后求和,最终根据权值大小确定MTA区域。</li></ul><p><strong>4.3 处理效果</strong></p><p>算法的处理效果如下图9,图10.</p><p><img src="/img/remote/1460000039425496" alt="" title=""></p><p>图9 MTA处理效果:未处理MTA</p><p><img src="/img/remote/1460000039425495" alt="" title=""></p><p>图10 MTA处理效果:MTA恢复结果</p><p><strong>4.4 性能优化</strong></p><p>使用基本的处理方案可以较好地恢复MTA错误问题,但是由于搜索区间较大,而且必须逐点处理,效率很低,不能满足效率的要求,需要进行优化。考虑的优化方向包括减少搜索区间和算法优化两方面。</p><p><strong>4.4.1 减小搜索区间</strong></p><p>我们使用的激光设备探测范围参数如下,不超过300m,也就是2个MTA区间,因此可以只考虑MTA1和MTA2区间两种可能,这就大大降低了计算量。</p><p>设备探测范围参数:</p><ul><li>探测距离最大 235m(80%高反射率);</li><li>低反射率物体不到 100m;</li><li>针叶林 100m;</li><li>柏油沥青 120m;</li><li>阔叶林 150m;</li><li>建筑砖头 200m左右;</li><li>白色灰泥 250m。</li></ul><p><strong>4.4.2 算法优化</strong></p><p>根据扫描特性进一步进行算法优化。</p><ul><li>考虑到发生MTA错误都发生在地面以上,即激光实际能扫描到的很远的物体都在地面以上,可先根据车高信息剔除地面附近点;</li><li>对于多次回波,点的连续性只取第一次回波来计算;</li><li>分圈后按扫描角和测距值判断空间相邻;</li><li>分圈处理,多线程并行加速;</li><li>对于不同区域的连续性都很差的点作为孤立点进行剔除。</li></ul><h2><strong>5.总结与展望</strong></h2><p>MTA处理算法作为点云解算模块的一部分,是采集资料处理上云的重要环节,不解决MTA问题,就无法实现采集资料处理的自动化。同时MTA处理算法去除了资料处理环节对激光厂商软件的依赖,为公司节省了大量成本。</p><p>在算法设计阶段尝试利用SVM,RF等机器学习手段按点云分类思路解题,初步测试发现样本制作困难、正负样本量级差异过大等问题。另一方面,机器学习方法批次处理需要考虑合适的空间范围,对于每个分块动辄亿级的点数,其处理效率将无法满足产线需求。</p><p>在算法效果评估阶段,原本打算使用厂商处理的结果作为真值。但评测下来发现,厂商处理结果的效果不如自研算法,不能作为评测真值。最终我们结合产线工艺需求,专门制作了评估方案,算法目标对焦到业务需求,从而客观、可靠、快速地完成了算法的评测工作。</p><p>目前MTA处理算法已经进入了线上生产,处理了上万公里点云数据,目前运行稳定,达到预期。</p><h2><strong>关于高精地图业务中心</strong></h2><p>高精地图是高德<strong>最具创新性</strong>的业务之一,致力于用传感器丈量世界,用算法理解世界,用数据重新定义世界。我们几乎涵盖最热门前沿学科,<strong>高精地图和自动驾驶是多学科交叉的应用工程体系</strong>。基于感知理解,三维重建,融合定位,计算几何技术自动化生成高精数字化三维地图。利用边缘计算,大数据处理,云服务,进行实时海量数据地图重建。通过5G/V2X信息交换,实现地图对象间的数据互通,构建一张活地图。我们不仅仅是数据制作者,更是新生活的定义者。加入我们,未来“由”你。</p><p><img src="/img/bVby2A6" alt="image" title="image"></p>
面向自动驾驶的高精地图及数据采集生产体系
https://segmentfault.com/a/1190000039404890
2021-03-12T19:46:35+08:00
2021-03-12T19:46:35+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<blockquote>前言:又到春招季!作为国民级出行服务平台,高德业务快速发展,大量校招/社招名额开放,欢迎大家投递简历,详情见文末。为帮助大家更了解高德技术,我们策划了<strong>#春招专栏#</strong>的系列文章,组织各业务团队的高年级同学以<strong>业务科普+技术应用实践</strong>为主要内容为大家做相关介绍。</blockquote><p>本文是#春招专栏#系列的第 <strong>2</strong> 篇,根据<strong>高德高精地图</strong>业务总经理向哲在AT技术讲坛分享的<strong>《面向自动驾驶的高精地图及采集生产体系》</strong>内容整理而成。在不影响原意的情况下对内容略作删节。</p><p><strong>AT技术讲坛(Amap Technology Tribune)</strong>是高德发起的一档技术交流活动,每期围绕一个主题,我们会邀请阿里集团内外的专家以演讲、QA、开放讨论的方式,与大家做技术交流。</p><p>向哲本次主要分享了两方面的内容:</p><p><strong>1.面向自动驾驶的高精地图是什么;</strong></p><p><strong>2.当下的高精地图数据采集生产体系建设现状和思考。</strong></p><p>高精地图是自动驾驶汽车不可或缺的核心条件,它需要准确表达现实世界各类要素的空间位置和相对关系,因此高精地图的生产对采集资料的精度要求很高。</p><p><strong>工业级的自动驾驶分类</strong></p><p>向哲结合自动驾驶在工业级的应用现状开始讲起。</p><p><img src="/img/remote/1460000039404892" alt="" title=""></p><p>目前工业级自动驾驶大致可以分为两类,<strong>第一类是以特斯拉、小鹏等造车新势力为用户生产的具备“辅助驾驶功能”的智能车为代表</strong>。用户在使用这些自动驾驶功能时,要随时接管驾驶,驾车过程中出现的法律问题责任主要在人类。</p><p>高德和市场上主流的造车新势力厂商在高精地图方面有深度合作。以小鹏汽车为例,它的辅助驾驶功能使用了高德所提供的高精地图能力。目前用户可以享受到什么样的辅助驾驶能力呢?基本已经实现了<strong>高速公路上点到点的自动驾驶功能</strong>。</p><p>比如,从北京开车走高速到广州,途中会遇到<strong>若干段高速的切换</strong>,即从一段高速通过匝道换到另一段高速,以及在<strong>高速上的变道超车</strong>。小鹏汽车的NGP辅助驾驶能力具备了以上两种能力,基本具备了从北京到广州的全程自动驾驶功能。</p><p>但在行车过程中,司机要随时盯着路况,在自动换道等时候如果有剐蹭的风险要人工接管驾驶,继续手动驾驶完成换道。这意味着,驾驶过程中,司机要随时准备接管驾驶。</p><p>另外,在途经收费站的时候,司机也需要手动接管汽车的驾驶,因为目前高精地图还没做到收费站里的车道级信息。在接近收费站的时候,语音助手会提示司机,前方收费站道路没有高精地图,需要手动接管驾驶。以上的自动驾驶能力都会应用到小鹏所有P7车型上。</p><p><strong>第二类工业级自动驾驶就是典型的L4。</strong>例如谷歌在做的在城市里自动驾驶的出租车,物流干线货车等,跟第一类自动驾驶相比,这类L4自动驾驶理论上在车上是没有司机的。虽然现在在验证阶段,司机席还有司机。据向哲预测,这类L4无人驾驶出租车要想走进普通人的生活中还要有4~5年的时间。</p><p>以上的两类自动驾驶都强依赖于高精地图。</p><p><strong>高精地图与自动驾驶</strong></p><p>高精地图是自动驾驶车辆“脑子”里的地图,能够让车辆知道接下来"看不见"的路况是什么样的。<strong>自动驾驶的四个关键功能:感知、高精定位、决策规划、车辆控制。</strong>这里面至少有三个功能都强依赖于高精地图。</p><p><img src="/img/remote/1460000039404896" alt="" title=""></p><p><strong>感知</strong>:人类驾驶汽车时要观察周边的车道线、交通牌、杆等信息。智能车上的传感器会感知道路周边的物体信息。高精地图提供了上帝视角的超视觉感知能力。尤其是在车前方有大货车等遮挡物导致人眼和传感器无法看清前方车道线等信息的时候,高精地图数据可以告知车辆前方道路信息。</p><p><strong>高精定位</strong>:自动驾驶的汽车要精确知道车在地图中的位置,前提就要依靠高精地图所提供的底图。自动驾驶的车要知道自己在地图中的位置,基于两个能力,一是基于GPS、惯导、千寻等定位能力所提供的绝对位置信息。绝对位置信息跟地图经纬坐标相匹配,可以判定得到车辆在地图中的具体位置(依赖于传感器进行绝对位置定位的能力)。</p><p>但仅有绝对位置定位还不够,在特殊区域,例如高楼、峡谷等会发生遮挡信号的时候,绝对定位精度会变差,自动驾驶需要借助于观察周围的车道线、信号牌、杆子进行的相对定位来辅助,需要跟高精地图中的地图数据进行匹配判断。在实际项目中,高德通过和主流车厂的深度合作,一起来判断通过哪些技术能获得更加精准的相对定位能力。</p><p><strong>决策规划</strong>:自动驾驶要符合驾驶规则,所以要高度依赖车道线、交通限制设施、红绿灯等道路元素的。</p><p>以上的几个功能都是彼此支撑关系。</p><p><strong>面向自动驾驶的高精地图</strong></p><p>几个关键要素:道路层、车道层、定位对象、动态层。</p><p><img src="/img/remote/1460000039404895" alt="" title=""></p><p><strong>道路层</strong>:HD(高精地图)和SD(普通地图)的数据是紧密匹配的。目前几乎所有自动驾驶都是先由用户告诉智能系统,我要从某地开往某地,这两个地点之间的驾驶路线规划由SD道路数据来支持。HD数据并不孤立,要和SD数据连接。SD数据能力是高德的传统强项,加上业界领先的HD能力,这种匹配高德一定是业界做的最好的。这也是汽车厂商在选择地图服务商时很看重的一点。</p><p><strong>车道层</strong>:所有的自动驾驶底层的对车辆的控制都依赖于高精地图数据。</p><p><strong>定位对象</strong>:高德跟车厂密切合作,车厂基于哪些技术来做相对定位,选择哪些参考对象,精度做到什么水平等等,双方一起沟通联合研发。</p><p><strong>动态层</strong>:未来的高精地图一定会含动态层,实时数据,某条车道在某个时刻发生哪些动态交通事件。</p><p><strong>高精地图在城市普通路的挑战</strong></p><p>目前高德的高精度地图已经完成了对高速和城市快速路段超30万公里道路的采集,正在进入稳定的定期更新状态。相比高速城快,更难的题在城市普通路。</p><p>城市高精地图数据的一个关键挑战在于路口,很多路口的地面缺乏交通线绘制。自动驾驶的汽车在路口间转向的时候,车辆驶过地面没有交通线(油漆),这时候就要依赖于高精地图事先做好的数据。当然,要考虑的当然不只是路口的地面交通线,还要考虑大量其他交通元素。但城市普通路的自动驾驶肯定是地图服务商和造车新势力未来会投入很大精力的重要场景。</p><p><strong>高精地图的采集和生成</strong></p><p>常规的高精地图生产可以概括为“采集”、“生产”、“产品化”三个阶段。</p><p><img src="/img/remote/1460000039404893" alt="" title=""></p><p>采集车是由多种先进测量传感器精密集成的移动采集系统,一般会包含Lidar、惯导、相机等设备,根据采集场景不同搭载不同型号的传感器设备。<strong>高德高精团队经过多年深耕,自研了高精采集车系统,具有精度高、速度快、数据产生周期短、自动化程度高、安全性高、信息全等特点。</strong></p><p><img src="/img/remote/1460000039404897" alt="" title=""></p><p>采集设备把外部现实世界里含精度的数据采集回来以后,还要通过图像识别、精度处理、人工处理等步骤才能“变成”可以用的高精地图数据。</p><p><strong>“鲜”的高精地图</strong></p><p><img src="/img/remote/1460000039404894" alt="" title=""></p><p>现实生活中的道路数据处在不停的变化之中,如何才能做到“鲜”的高精地图。</p><p>首先,最开始的时候要用成本相对昂贵的<strong>专业打底车</strong>,在全国道路范围内测量和采集高精地图数据。这种采集要同时保证相对精度和绝对精度。然后,用相对廉价的<strong>专业更新车</strong>来采集路面信息的局部变化(相对变化)图识,例如重新刷过地面标识,新竖立的牌、杆等。同时,我们也用更廉价的<strong>众包设备</strong>做更快速的采集更新。</p><p>为实现对既有数据的快速更新,提升数据数据鲜度。高德的高精团队,搭建了专业打底车、专业更新车、众包更新三级能力的采集体系,结合在一起解决精度、鲜度的问题。<strong>在真实业务场景里需要在精度和鲜度找到平衡,反复的迭代。</strong></p><p><strong>要解决高精地图数据的“高精度”、“大规模”、“足够鲜”等诸多挑战,需要在很多技术点上进行突破。</strong></p><p>比如:如何设计制造不同成本、不同精度、不同部署能力的采集测绘设备;</p><p>如何协同不同类设备协同进行采集,同时满足精度、鲜度上的产品要求;</p><p>如何设计和应用算法,提升采集资料的绝对精度、相对精度,并保证多次采集资料之间彼此对齐严丝合缝;</p><p>如何综合应用图像和点云做好识别,提升生产的自动化水平。</p><p>高德高精地图团队的同学分别专注在不同方向上,并以开放的心态接受业务挑战,共同讨论和设计方案,也取得了很多成绩。</p><p>凭借这份国内精度最高、覆盖最广的高精地图,高德成功拿下了国内外多款主流车厂的商业订单,开始为智能驾驶车型提供高精定位、超视距感知、车道级导航等服务。作为高德在自动驾驶生态中重点突破的领域,高德高精地图业务发展快,机会多,希望大家一起加入。</p><p><strong>关于高精地图业务中心</strong></p><p>高精地图是高德<strong>最具创新性</strong>的业务之一,致力于用传感器丈量世界,用算法理解世界,用数据重新定义世界。我们几乎涵盖最热门前沿学科,<strong>高精地图和自动驾驶是多学科交叉的应用工程体系</strong>。基于感知理解,三维重建,融合定位,计算几何技术自动化生成高精数字化三维地图。利用边缘计算,大数据处理,云服务,进行实时海量数据地图重建。通过5G/V2X信息交换,实现地图对象间的数据互通,构建一张活地图。我们不仅仅是数据制作者,更是新生活的定义者。加入我们,未来“由”你。</p><p><img src="/img/bVby2A6" alt="image" title="image"></p>
AI在出行场景的应用实践:路线规划、ETA、动态事件挖掘…
https://segmentfault.com/a/1190000039345985
2021-03-05T15:02:55+08:00
2021-03-05T15:02:55+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<blockquote>前言:又到春招季!作为国民级出行服务平台,高德业务快速发展,大量校招/社招名额开放,欢迎大家投递简历,详情见文末。为帮助大家更了解高德技术,我们策划了<strong>#春招专栏#</strong>的系列文章,组织各业务团队的高年级同学以<strong>科普+应用实践</strong>为主要内容为大家做相关介绍。</blockquote><p>本文是<strong>#春招专栏#</strong>系列的第1篇,根据<strong>高德机器学习研发部</strong>负责人damon在AT技术讲坛所分享的<strong>《AI在出行领域的应用实践》</strong>的内容整理而成。在不影响原意的情况下对内容略作删节。</p><p><strong>AT技术讲坛(Amap Technology Tribune)</strong>是高德发起的一档技术交流活动,每期围绕一个主题,我们会邀请阿里集团内外的专家以演讲、QA、开放讨论的方式,与大家做技术交流。</p><p>damon根据用户在出行前,出行中和出行后如何使用导航服务,分别选取了几个典型的业务场景来介绍AI算法在其中的应用,最后对未来做了一些展望。</p><p><img src="/img/remote/1460000039345988" alt="" title=""></p><p>以某位同学周末和朋友相约去“木屋烧烤”店撸串为例,假设这位同学选择驾车前往目的地,我们来看下AI算法是如何在导航过程中起到作用的。</p><p>出行前,先做路线规划,ETA(预估到达时间),不要迟到;出行中,最怕的就是遇到突发动态事件而影响到出行时间;出行后(到目的地),餐馆是否还在正常营业,也需要通过技术挖掘,帮助用户提前规避白跑一趟的风险。</p><p>下面分别介绍。</p><p><strong>出行前-路线规划</strong></p><p>路线规划,和网页搜索,商品搜索的推荐算法很相似,为用户推荐一条符合个人喜好的优质路线。推荐的路线要符合以下几个条件:</p><ul><li>能走:此路能通,按照路线可以到达终点。</li><li>好走:路线质量在当前地点时间下确保优质。</li><li>千人千面:不同用户在保证路线优质的前提下,个性化调整更符合用户偏好。</li></ul><p>同时,在不对用户产生误导的前提下,提供更多的对比参考给用户来选择:</p><ul><li>优质:相比首路线/主路线,有一定的、用户可感受到的优势。</li><li>多样:相比首路线/主路线,尽可能有自己的特长。</li></ul><p><strong>路线规划算法的特点</strong></p><p>从用户产生出行需求,到需求得到满足。在用户搜索的时候,上传的Query除了有起终点和导航策略,也会像其他搜索一样,有隐含的需求,比如<strong>个性化和场景化</strong>。在导航业务里面,个性化可以拆分成<strong>熟路</strong>和<strong>偏好</strong>两个维度,熟路比较容易理解,偏好是指用户对<strong>时间、距离、红绿灯、收费</strong>等不同维度上的偏好。</p><p>那么,对应的解决方案,我们引入<strong>用户ID</strong>,存储记忆了用户的起终点对应的熟路信息。对用户的偏好,类似DIN的网络结构,对用户历史导航序列进行建模,获取用户偏好信息。</p><p>在用户提交搜索需求之后,对导航引擎来说,也分为<strong>召回</strong>,<strong>排序</strong>和<strong>过滤</strong>几部分。</p><p>对于导航的召回,对性能要求比较高,所以目前召回的结果较少。对排序来说,同样是多目标,而且多目标之间要进行平衡的业务。类比到电商推荐领域,不仅希望用户更多地对商品进行点击浏览,还希望用户在看完商品介绍之后进行购买,提高GMV。</p><p><strong>对于地图出行,不仅希望用户更多的使用导航且按照推荐的路线走,还希望实走时间要尽可能短,用户反馈尽量好。</strong></p><p>而且,和其他领域类似,多个目标之间会存在冲突,比如电商CTR和GMV。在导航领域,让用户尽可能的走封闭道路,没有出口,那肯定实走覆盖率就上升了,但是这样规划的路线会绕远,时间和距离都变差。</p><p>多目标的平衡,如何在“帕累托最优”的情况下,进行多个目标之间的取舍、平衡,是大家一直在探索的问题,我们目前采用的是<strong>带约束的最优化问题来进行建模,就是保证其他指标不变差的情况下,把某个指标最优化。</strong></p><p>最后,用户拿到导航引擎返回的路线结果,特点是信息少,用户只能看到整条路线的总时间、总距离和收费等统计信息,对于这条路好不好走,能不能走很难知道。</p><p>而且,大部分用户是在陌生场景下用导航,对导航依赖很重,很难决策走哪条路更好,这就导致<strong>排序在首条的方案选择率很高</strong>,达到90%以上,这个偏置是很严重的,在训练实走覆盖率的时候,我们设计了<strong>偏置网络</strong>,来吸收用户这种倾向。</p><p>导航还有一个特点,一旦出错,对用户伤害特别大,比如遇到小路,用户的车可能会出现刮蹭;遇到封路,用户可能就得绕路,付出相当的时间和金钱成本。这往往会比信息搜索给用户带来的影响和伤害更大。所以,我们在过滤阶段,<strong>对Badcase的过滤也是严格作为约束要求的。</strong></p><p><strong>路线规划召回算法</strong></p><p>路线规划算法,经典的是教科书上的Dijkstra算法,存在的问题就是性能比较差,线上实际应用都做了优化,这里就不展开介绍了。</p><p>当起终点距离超过500公里,性能基本就不可接受了,虽然有启发式A star算法,但是A star算法有可能丢最优解,并不是完美解决性能问题的方法。</p><p>解决性能问题的思路,一个是分布式,一个是Cache,而最短路线搜索并不像网页搜索,分布式并不能很好的解决性能问题,所以目前工业界实际使用的算法都是基于Cache的方法。</p><p>Cache的方法就是<strong>提前把一些起终点对之间的最短路线计算好(Shortcuts)</strong>,在用户请求过来的时候,利用好这些Shortcuts,达到加快求路的目的(简单举例子,比如从北京到广州,如果提前计算好了从北京到济南,济南到南京,南京到广州的最短路径,那就可以在计算北京到广州的时候,利用这些提前计算好的最短路线)。</p><p>其中最为经典的一个算法就是<strong>CH算法(Contraction Hierarchies)</strong>,在预处理阶段,对所有节点进行了重要性排序,逐渐把不重要的点去掉,然后增加Shortcuts;Query查询阶段,从起点和终点分别开始双向求路,只找重要性高的点,来达到加速的目的。</p><p>既然是Cache,就会面临一个更新的问题,比如原始路网的路况变化了,或者原始路网某条路封路了,那么提前缓存好的Shortcuts也需要更新。</p><p>这个时候CH的算法,由于Shortcuts结构设计不够规律,更新就很慢,无法响应实时路况的变化。于是,路线规划算法推进到了下一代,<strong>CBR算法(Cell based Routing)</strong>,这个算法通过分而治之的思想,在预处理阶段,把全国路网切分成n个子图,切分的要求是子图之间连接的边(边界边)尽可能的少。</p><p>在每个子图内,再继续往下切分,进而形成金字塔结构,预处理阶段就是把边界边之间的最短路径都提前算好,Cache下来求路的时候,就可以利用这些Shortcuts了。</p><p>CBR的优点是,在预处理阶段,路网的切分是分层的,每一层都足够小,在更新这一层的Shortcuts的时候,可以把数据都放到CPU的L1 Cache里去,所以计算速度特别快。</p><p><strong>总结一下CBR和CH的区别:</strong></p><ul><li>Query查询性能,CH更快,CH是0.1ms级别,CBR是1-2ms级别。</li><li>Shortcuts更新性能,CH全国路网更新最快能做到10分钟,而CBR能做到15秒更新全国,可以满足实时路况变化和路网实时更新的需求。</li><li>CH的Shortcuts不规律,导致不同策略之间(躲避拥堵,高速优先等)不能很好的复用Shortscuts的起终点结构,所以不同策略需要单独重建Shortcuts,内存占用非常大。</li></ul><p><img src="/img/remote/1460000039345989" alt="" title=""></p><p>这是我们排序的网络结构,左边是用户偏置网络,把路线排序的顺序,以及引导路线之间的相似度信息输入进去,期望尽可能消除掉偏置带来的影响。中间输入的用户历史统计信息和用户导航序列信息,用来提取用户的个性化偏好。<strong>优化的主要目标是实走覆盖率。</strong></p><p>新一代的路线规划算法,要求提供<strong>随时间推演的能力</strong>。比如8:00从起点出发,后面要走 1 2 3 ..n条路到达目的地,假设8:10走到第2条道路,8:20走到第3条道路,那么我们在8:00计算Shortcuts的时候,就不能只用到8:00的路况,需要把后续进入某个道路的时刻考虑进来,用那个时刻的路况来计算,这就是TDR求路算法,目前是高德首创的,能真正实现躲避未来的拥堵,并利用未来的畅通来规划路径。</p><p><strong>出行前-ETA(预估到达时间)</strong></p><p><img src="/img/remote/1460000039345990" alt="" title=""></p><p>上面三幅图,选取的是北京西单金融街附近的区域,展示了在三个相邻时间点上的交通状况。其中绿色、黄色、红色代表交通路况不同的状态。</p><p>假设现在是18点整,路况预测的目标就是预估未来时刻的交通状况,需要依赖每条道路的历史信息,以及周边邻居的道路拥堵信息,对时空两个维度进行建模。</p><p>对时间序列的建模,用RNN,LSTM等SEQ2SEQ的序列,也有采用CNN,TCN等。对空间信息的建模,目前主流的方法是用GRAPH.</p><p>尽管模型在不断升级,越来越复杂,但是对于突发事件导致的拥堵,根据历史统计信息,很难预测精准,比如去年9月份在上海世博园区举行外滩大会,世博园平时很少有人去,历史路况都是畅通,而在开会期间,车很多导致很堵。</p><p>这个时候靠历史信息是很难预测准确,我们需要一个能代表未来的信号,才能预测,这就是路线规划的信息,如果想去世博园的人很多,那么规划的量就会很多,我们根据规划的量,就能知道未来有很多人想要去世博园,就会导致世博园拥堵。</p><p><img src="/img/remote/1460000039345987" alt="" title=""></p><p>所以,我们把规划的量,通过一个流量往时间域的转换,引入到路况预测模型,效果取得明显提升,尤其是在突发拥堵的时候,高德的这个研究成果被KDD2020收录,并且已经在业务场景中得到了应用,有兴趣的同学可以详细查看我们的论文。</p><p><strong>行中-用文本数据挖掘动态交通事件</strong></p><p>继续向餐馆前进,导航途中,最怕遇到拥堵,封路等事件,所以高德会想尽一切办法挖掘这些动态事件,帮助用户规避开。现在高德用到了多个维度的数据源,其中的行业和互联网情报都是文本数据,要用到NLP的技术来挖掘。</p><p>介绍一下怎么用AI算法来挖掘动态事件。</p><p>下面一段文本就是典型的来自于网络媒体的信息:</p><p><img src="/img/remote/1460000039345992" alt="" title=""></p><p>G0612(西和)高速南绕城路段西山隧道ZK33+844(兰州方向)应急车道停一辆故障大客车暂时封闭,行车道和超车道正常通行,请车辆注意避让、减速慢行。</p><p>这段信息是非结构化的,需要我们做预处理,要素提取,再进行事件的组织,组织成架构化的信息,才能自动化的应用。</p><p>很自然的,针对要素提取,我们用BERT模型建模,但是BERT模型太复杂,性能比较差,线上实际应用带来很大的挑战。</p><p><img src="/img/remote/1460000039345991" alt="" title=""></p><p>我们采取了<strong>知识蒸馏</strong>的方法,训练一个简单的Student的网络,来解决性能问题。知识蒸馏最主要的是如何捕捉潜在语义信息。高德<strong>在业界率先提出了用对比学习框架进行知识蒸馏</strong>,同时,在计算样本之间距离的时候,提出COS-距离代替欧氏距离的方法,能够让模型有效的学习到潜在语义表达信息。</p><p><img src="/img/remote/1460000039345993" alt="" title=""></p><p>对于Student表达的特征向量与Teacher特征向量距离靠近,而要远离负例。使用余弦距离,比如欧式距离,能够更好适应Teacher网络和Student网络,输出的特征向量长度分布不一致的问题,这个工作成果发表在了AAAI2021上。</p><p><strong>出行后-POI数据过期(增强现势性)的问题</strong></p><p>人们在高德地图上会看到很多地理位置兴趣点(Point of Interest,缩写为POI),例如餐厅、超市、景点、酒店、车站、停车场等。对POI数据的评价维度包括现势性、准确性、完备性和丰富性。</p><p>其中,现势性就是地图所提供的地理空间信息反映当前最新情况的程度,简而言之,增强现势性就是指尽可能快速地发现已停业、搬迁、更名、拆迁的过期冗余POI数据,并将其处理成下线状态的过程。这部分可以参考我们之前发布的文章《高德地理位置兴趣点现势性增强演进之路》。</p><p>以上仅是AI算法在出行场景应用的一些举例,更多的技术方案欢迎大家来和我们一起探讨。</p><p><strong>出行前景-全局调度</strong></p><p>对网页搜索来说,结果是信息,可以无限复制,互不影响;对电商搜索来说,结果是商品,可以认为商品足够多,不够再生产,所以也可以认为互不影响。</p><p>不同的是,导航搜索出来的道路资源是有限的,你用的多了,我就用的少。比如,一条路畅通,我们把人导过去,那么这条路就堵死了,所以我们要做全局调度,提高道路资源的使用率。</p><p>我们希望全局调度系统能和交通信号灯打通,在一个交通仿真的环境下,用多智能体强化学习的方法,学习到更大规模的交通系统上如何统筹协调车辆、交通灯,充分利用道路资源,进一步缓解拥堵。我们一起来探索!</p><p><strong>春招火热进行中,2022届毕业生看过来!</strong></p><p><strong>春招火热进行中,2022届毕业生看过来!</strong></p><p><strong>春招火热进行中,2022届毕业生看过来!</strong></p><p><img src="/img/remote/1460000039345994" alt="" title=""></p>
2020高德技术年刊:18万字、750页+,智慧出行最佳技术实践都在这了
https://segmentfault.com/a/1190000039193288
2021-02-08T11:21:39+08:00
2021-02-08T11:21:39+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><img src="/img/remote/1460000039193290" alt="" title=""></p><p>年味逾浓,春节渐近。</p><p>高德技术年刊如期而至。</p><p>过去的一年里,高德业务快速发展,国庆出行节的日活跃用户数突破1.5亿,又创新高。高德技术人在支撑业务快速发展的同时也在持续创新:导航个性化、引擎服务化、基建架构升级、全面上云、共享打车、信息服务、汽车前后装、大云图等方面实现新的突破;车道级导航、高精地图落地等领域取得行业领先;车载环境下的手机定位技术获得国际顶赛冠军······</p><p>在这些过程中,我们做了大量的技术实践总结和思考,并以文章等形式沉淀下来,与大家一起分享成功的经验和踩坑的教训。</p><p>在2021年春节即将到来之际,我们精选了几十篇高德技术的干货文章及数篇国际顶会论文,制作成了一本厚达750页+的电子书,作为新年礼物赠送给大家。</p><p>这本电子书内容覆盖了大前端、算法、架构、汽车工程、质量等多个领域,以及数篇高德入选顶会论文的解读,希望能对大家拓展技术思路有所帮助。</p><p>如果大家有意愿针对书中的技术问题深入探讨,想与我们做更多交流,或者有更好的建议,欢迎扫描下方高德技术公众号二维码与我们联系。</p><p>希望大家喜欢本书,欢迎推荐给身边感兴趣的朋友。</p><p>衷心感谢大家一直以来的支持和陪伴!</p><p>最后,祝大家牛年快乐,平安健康,阖家幸福。</p><p><strong>【附上年刊目录】</strong></p><p><img src="/img/remote/1460000039193291" alt="" title=""></p><p><img src="/img/remote/1460000039193293" alt="" title=""></p><p><img src="/img/remote/1460000039193292" alt="" title=""></p><p><img src="/img/remote/1460000039193295" alt="" title=""></p><p><strong>【如何免费获取】</strong></p><p>长按识别下图的二维码,关注“高德技术”微信公众号,在对话框回复“<strong>2020年刊</strong>”,即可免费下载。温馨提示:年刊18万字、750页+,文件约26M。</p><p><img src="/img/remote/1460000039193294" alt="" title=""></p>
高德地图驾车导航内存优化原理与实战
https://segmentfault.com/a/1190000039064262
2021-01-22T18:12:42+08:00
2021-01-22T18:12:42+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>背景</strong></p><p>根据Apple官方WWDC的回答,减少内存可以让用户体验到更快的启动速度,不会因为内存过大而导致Crash,可以让APP存活的更久。</p><p>对于高德地图来说,根据线上数据的分析,内存过高会导致导航过程中系统强杀OOM。尤其区别于其他APP的地方是,一般APP只需要关注前台内存过高的系统强杀FOOM,高德地图有不少用户使用后台导航,所以也需要关注后台的内存过高导致的系统强杀BOOM,且后台强杀较前台强杀更为严重。为了提升用户体验,内存治理迫在眉睫。</p><p><strong>原理剖析</strong></p><p><strong>OOM</strong></p><p>OOM是Out of Memory的缩写。在iOS APP中如果内存超了,系统会把APP直接杀死,一种另类的Crash,且无法捕获。发现OOM时,我们可以从<strong>设备->隐私->分析与改进->分析数据</strong>中找到以<strong>JetsamEvent</strong>开头的日志,日志里面记录了很多信息:手机设备信息、系统版本、内存大小、CPU时间等。</p><p><strong>Jetsam</strong></p><p>Jetsam是iOS系统的一种资源管理机制。不同于MacOS、Linux、Windows等,iOS中没有内存交换空间,所以在设备整体内存紧张时,系统会将一些<strong>优先级不高或者占用内存过大</strong>的直接Kill掉。</p><p>通过iOS开源的XNU内核源码可以分析到:</p><ul><li>每个进程在内核中都存在一个优先级列表,JetSam在受到内存压力时会从优先级列表最低的进程开始尝试杀死,直到内存水位恢复到正常水位。</li><li>Jetsam是通过get_task_phys_footprint获取到phys_footprint的值,来决定要不要杀掉应用。</li></ul><p>Jetsam机制清理策略可以总结为以下几点:</p><ul><li>单个APP物理内存占用超过上限会被清理,不同的设备<strong>内存水位线</strong>不一样。</li><li>整个设备物理内存占用受到压力时,优先清理后台应用,再清理前台应用。</li><li>优先清理内存占用高的应用,再内存占用低的应用。</li><li>相比系统应用,会优先清理用户应用。</li></ul><p>Android端为Low Memory Killer:</p><ul><li>根据APP的优先级和使用总内存的多少,系统会在设备内存吃紧情况下强杀应用。</li><li>内存吃紧的判断取决于系统RSS(实际使用物理内存,包含共享库占用的全部内存)的大小。</li><li>关键参数有3个:</li></ul><p>1)oom_adj:在Framework层使用,代表进程的优先级,数值越高,优先级越低,越容易被杀死。</p><p>2)oom_adj threshold:在Framework层使用,代表oom_adj的内存阈值。Android Kernel会定时检测当前剩余内存是否低于这个阀值,若低于则杀死oom_adj ≥该阈值对应的oom_adj中,数值最大的进程,直到剩余内存恢复至高于该阀值的状态。</p><p>3)oom_score_adj:在Kernel层使用,由oom_adj换算而来,是杀死进程时实际使用的参数。</p><p><strong>数据分析</strong></p><p>phys_footprint获取iOS应用总的物理内存,具体可以参考官方说明iOS Memory Deep Dive.</p><pre><code>std::optional<size_t> memoryFootprint()
{
task_vm_info_data_t vmInfo;
mach_msg_type_number_t count = TASK_VM_INFO_COUNT;
kern_return_t result = task_info(mach_task_self(), TASK_VM_INFO, (task_info_t) &vmInfo, &count);
if (result != KERN_SUCCESS)
return std::nullopt;
return static_cast<size_t>(vmInfo.phys_footprint);
}</code></pre><p><strong>Instruments-VM Tracker</strong>可以用来分析具体内存分类,比如Malloc部分是堆内存,Webkit Malloc部分是JavaScriptCore占用的内存等。需要注意的是每个分类的内存值 = Dirty Size + Swapped。</p><p>通过Instruments VM Tracker抓取导航中内存分布进行对比分析。导航前台静置时,高德地图的总内存数值非常高,其中IOKit、WebKit Malloc和Malloc堆内存为内存占用大头。</p><p>在分析过程中可以使用的工具很多,各有优缺点,需要配合使用,相互弥补。我们在分析的过程中主要用到Intruments VM Tracker、Allocations、Capture GPU Frame、MemGraph、dumpsys meminfo 、Graphics API Debugger、Arm Mobile Studio、AJX 内存分析工具、自研Malloc分析工具等。</p><ul><li>IOKit内存为地图渲染显存部分。</li><li>WebKit Malloc内存为AJX JS业务内存。</li><li>Malloc堆内存,我们通过Hook Malloc分配内存的API,通过抓取堆栈分析具体内存消费者。</li></ul><p><strong>治理优化</strong></p><p>根据上面的数据分析,很容易做出从大头开始抓起的思路。我们在治理过程中的大体思路:</p><ul><li>分析数据:从内存大头开始,分析各内存归属业务,以便业务进一步分析优化。</li><li>内存治理:优化技术方案减少内存开销、高低端机功能分级和智能容灾(即内存告警时通过功能降级等策略释放内存)。</li></ul><p><strong>分而治之</strong></p><p>据数据分析,高德地图三大内存消耗分别是地图渲染(Graphic显存)、功能业务(JavaScriptCore)和通用业务(Malloc)。我们也主要从这三个方面入手优化。</p><p><strong>地图Graphic显存优化</strong></p><p>Xcode自带Debug工具Capture GPU Frame,可以分析出具体显存占用,显存主要分为纹理Texture部分和Buffer部分,通过详细的地址信息分析具体消耗。Android端类似分析显存工具可以用Google的Graphics API Debugger。</p><p><img src="/img/remote/1460000039064265" alt="" title=""></p><p>根据分析,Texture部分我们通过FBO绘制方式调整、矢量路口大图背景优化、图标跨页面释放、文字纹理优化、低端机关闭全屏抗锯齿等减少显存消耗。Buffer部分通过开启低显存模式、关闭四叉树预加载、切后台释放缓存资源等。</p><p><strong>Webkit Malloc优化</strong></p><p>高德地图使用的是自研的动态化方案,依赖于iOS系统提供的框架JavaScriptCore,使用的业务内存消耗大多会被系统归类到WebKit Malloc,从系统工具Instruments上的VM Tracker可以看出。此处有两个思路,一个是业务自身优化内存消耗,第二个是动态化引擎和框架优化内存消耗。</p><p>业务自身优化,动态化方案的IDE提供内存分析工具可以清晰的输出具体业务内存消耗在什么地方,便于业务同学分析是否合理。</p><p>动态化引擎和框架优化,我们通过优化对系统库JavaScriptCore的使用方式,即多个JSContextRef上下文共享同一份JSContextGroupRef的方式。多个页面可以共享一份框架代码,从而减少内存开销。</p><p><strong>Malloc堆内存优化</strong></p><p>iOS端堆内存分配基本上使用的libmalloc库,其中包含以下几个内存操作接口:</p><pre><code>// c分配方法
void *malloc(size_t __size) __result_use_check __alloc_size(1);
void *calloc(size_t __count, size_t __size) __result_use_check __alloc_size(1,2);
void free(void *);
void *realloc(void *__ptr, size_t __size) __result_use_check __alloc_size(2);
void *valloc(size_t) __alloc_size(1);
// block分配方法
// Create a heap based copy of a Block or simply add a reference to an existing one.
// This must be paired with Block_release to recover memory, even when running
// under Objective-C Garbage Collection.
BLOCK_EXPORT void *_Block_copy(const void *aBlock)
__OSX_AVAILABLE_STARTING(__MAC_10_6, __IPHONE_3_2);</code></pre><p>通过hook内存操作API记录下内存分配的堆栈、大小,即可分析内存使用情况。</p><p>同时源码中还存在一个全局钩子函数malloc_logger ,可输出Malloc过程中的日志,定义如下:</p><pre><code>// We set malloc_logger to NULL to disable logging, if we encounter errors
// during file writing
typedef void(malloc_logger_t)(uint32_t type,
uintptr_t arg1,
uintptr_t arg2,
uintptr_t arg3,
uintptr_t result,
uint32_t num_hot_frames_to_skip);
extern malloc_logger_t *malloc_logger;</code></pre><p>iOS堆内存分析方案,可通过hook malloc系列API,也可以设置malloc_logger的函数实现,即可记录下堆内存使用情况。</p><p>此方案有几个难点问题,每秒钟内存分配的量级大、内存有分配有释放需要高效查询和堆栈反解聚合。为此我们设计了一套完整的Malloc堆内存分析方案,来满足快速定位堆内存归属,以便分发到各自业务Owner分析优化。</p><p><strong>统一管理</strong></p><p>随着业务的增长给高德地图这个超级APP带来了极大资源压力,因此我们沉淀了一套自适应资源管理框架,来满足不同业务场景在有限资源下能够做到功能和体验极致均衡。主要的设计思路是通过监测用户设备等级、系统状态、当前业务场景以及用户行为,利用调度算法进行实时推算,统一管理协调APP当前资源状态分配,对用户当前不可见的内存等资源进行回收。</p><p><strong>自适应资源管理框架-内存部分</strong></p><p>可以根据不同的设备等级、业务场景、用户行为和系统状态来管理资源。各业务都可以很容易的接入此框架,目前已经应用到多个业务场景,均有不错的收益。</p><p><img src="/img/remote/1460000039064266" alt="" title=""></p><p><strong>数据验收</strong></p><p>通过三个版本的连续治理,前后台导航场景均有50%的收益,同时Abort率也有10%~20%的收益。整体收益算是比较乐观,但是随之而来的挑战是我们该如何守住成果。</p><p><strong>长线管控</strong></p><p>所谓打江山容易守江山难,如果没有长线管控的方案,随着业务的版本迭代,不出三五个版本就会将先前的优化消耗。为此我们构建了一套APM性能监控平台,在研发测试阶段发现并解决问题,不把问题带上线。</p><p><strong>APM性能监控平台</strong></p><p>为了将APP的性能做到日常监控,我们建设了一套线下「APM性能监控平台」,平台能够支持常规业务场景的性能监控,包括:内存、CPU、流量等,能够及时的发现问题并进行报警。再配合性能跟进流程,为客户端性能保障把好最后一关。</p><p><strong>内存分析工具</strong></p><p>Xcode memory gauge:在Xcode的Debug navigator中,可以粗略查看内存占用的情况。</p><p>Instruments - Allocations:可以查看虚拟内存占用、堆信息、对象信息、调用栈信息、VM Regions信息等。可以利用这个工具分析内存,并针对地进行优化。</p><p>Instruments - Leaks:用于检测内存泄漏。</p><p>Instruments - VM Tracker:可以查看内存占用信息,查看各类型内存的占用情况,比如dirty memory的大小等等,可以辅助分析内存过大、内存泄漏等原因。</p><p>Instruments - Virtual Memory Trace:有内存分页的具体信息,具体可以参考WWDC 2016 - Syetem Trace in Depth。</p><p>Memory Resource Exceptions:从Xcode 10开始,内存占用过大时,调试器能捕获到EXC_RESOURCE RESOURCE_TYPE_MEMORY异常,并断点在触发异常抛出的地方。</p><p>Xcode Memory Debugger:Xcode中可以直接查看所有对象间的相互依赖关系,可以非常方便的查找循环引用的问题。同时,还可以将这些信息导出为memgraph文件。</p><p>memgraph + 命令行指令:结合上一步输出的memgraph文件,可以通过一些指令来分析内存情况。vmmap可以打印出进程信息,以及VMRegions的信息等,结合grep可以查看指定VMRegion的信息。leaks可追踪堆中的对象,从而查看内存泄漏、堆栈信息等。heap会打印出堆中所有信息,方便追踪内存占用较大的对象。malloc_history可以查看heap指令得到的对象的堆栈信息,从而方便地发现问题。</p><p><strong>总结</strong>:malloc_history ===> Creation;leaks ===> Reference;heap & vmmap ===> Size。</p><p>MetricKit:iOS 13新推出的监控框架,用于收集和处理电池和性能指标。当用户使用APP的时候,iOS会记录各项指标,然后发送到苹果服务端上,并自动生成相关的可视化报告。通过Window -> Organizer -> Metrics可查,包括电池、启动时间、卡顿情况、内存情况、磁盘读写五部分。也可以MetricKit集成到工程里,将数据上传到自己的服务进行分析。</p><p>MLeaksFinder:通过判断UIViewController被销毁后其子view是否也都被销毁,可以在不入侵代码的情况下检测内存泄漏。</p><p>Graphics API Debugger:Google开源的一系列的Graphics调试工具,可以检查、微调、重播应用对图形驱动的API调用。</p><p>Arm Mobile Studio: 专业级GPU分析工具。</p><p><img src="/img/remote/1460000039064264" alt="" title=""></p>
3倍+提升,高德地图极致性能优化之路
https://segmentfault.com/a/1190000038991537
2021-01-15T14:04:01+08:00
2021-01-15T14:04:01+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>1.导读</strong></p><p>随着移动互联网的成熟发展,移动应用技术上呈现出多样化的趋势,业务上倾向打造平台及超级入口,超级应用应运而生。但业务快速扩张与有限的系统资源必然是冲突的,如何实现多(能力服务的高增长)、快(体验流畅)、好(兼容稳定)、省(资源成本低),让大象也能跳舞,成为摆在超级应用面前必须解决的问题。</p><p>伴随着高德地图APP近几年的高速发展,也面临到这些问题,从2019年开始,我们开启了一系列性能优化专项,对高德地图APP进行了深入性能分析和极致优化,取得比较显著的效果。在这个过程中总结了一系列优化思路和技术方案,希望对同样面临超级应用性能问题的你有所帮助。</p><p>经过一系列优化动作,我们在保证业务需求正常迭代新增的基础上,启动、核心链路交互、行中内存、包大小等多方面均实现了性能的成倍提升,尤其是低端机上达到了3倍+的提升,从多个维度改善了用户性能体验。</p><p><img src="/img/remote/1460000038991540" alt="" title=""></p><ul><li>启动攻坚:启动耗时降低70%+,实现2s地图元素完成展示,并管控保持在稳定低水位,呈下降趋势。</li><li>核心链路交互优化:在搜索、路线等链路上实现中高端机型秒开、低端机型2s内打开,整体提升用户流畅交互体验 。</li><li>行中内存优化:全机型优化了30%左右,提高稳定性。</li><li>包大小攻坚:双端体积降低20%,提高安装转换率。</li></ul><p><strong>2.性能优化业务背景</strong></p><p>某段时间,高德地图APP面临着性能恶化、管控困难的问题。以启动耗时为例,双端启动等待体感明显,并且历史上治理后出现反复,整体呈上升趋势,我们思考问题背后的问题,主要有以下几个方面:</p><p><strong>业务庞大</strong></p><p>超级应用一般都经历这样的发展过程。首先,应用提供服务给用户,用户开始增长,增长的用户会产生更多的需求。应用为满足新增需求不断迭代,提供新的服务。新的服务推动用户进一步增长,进入下一个循环。正是在这个正循环发展中,应用像滚雪球一样越滚越大,终于成为超级应用。</p><p>然而,随着业务需求的不断增长,业务量和复杂度也随着上升,系统资源会越占越多。但机器资源是有限的,资源的争夺不可避免地会导致性能问题,从而影响用户体验和业务扩展,成为超级应用正循环发展的拦路虎。</p><p><img src="/img/remote/1460000038991544" alt="" title=""></p><p>高德地图也同样经历了这样的过程,随着这几年的快速发展,应用从手机扩展到了车机,平台从iOS、Android扩展了Windows和Liunx,覆盖10多种出行方式的同时,还在不断提供组队、视频、语音、AR等新服务。与此相应的是单端代码行超百万行,线程上百,任务上千,造成了持续的性能压力。</p><p><strong>环境复杂</strong></p><p>性能问题面临的另一个主要挑战是超级应用的环境复杂。一方面,随着移动设备的长线发展,系统碎片化情况越来越严重,Android系统横跨11个主版本,iOS横跨14个主版本,加之设备厂商对系统进行各种各样的改造,进一步增加了系统的碎片化;另一方面,用户移动设备的环境是非常不稳定的,电量、温度的变化以及其他应用的抢占都会造成内存、CPU、GPU等资源波动。复杂不可控的环境为一致的性能体验的保持增加了很大的难度。</p><p>但作为大用户体量的超级应用,任何环境的体验都要保证。特别是地图领域,用户习惯对不同产品直接对比,任何环境下性能体验问题,都会直接影响产品的整体口碑,导致用户流失。所以需要兼顾所有环境,不只是主流机型系统和场景,在长尾场景与机型系统上也必须流畅运行,这就要求超级应用这头大象不但要在舞台上跳舞,在凳子上、甚至在水里也能跳舞。</p><p><strong>技术链路长</strong></p><p>为了满足研发效率提升、产品动态化等多样需求,移动应用技术上除支持原生开发外,也要支持小程序、Web H5、C基础库等跨平台、容器化、动态化开发。从高德APP来看,最顶层业务除了OC、Java外,还支持JS开发。支撑层提供了AJX、小程序、原生、C等多种容器框架,同时还涉及JS、JNI等桥接层。最下面则用C++提供地图各个引擎能力,这里包括OpenGL、定位传感器融合等多种底层能力。技术链路自上而下开始变得长且复杂,链路上任何一环都可能导致性能问题,原有的单技术语言的排查工具已经无法定位明确性能卡点模块,为性能排查和管控带来挑战。</p><p><strong>3.解法:低成本优化迁移,长线管控</strong></p><p>基于上面的问题,原有传统的一招鲜的优化方案,显然解决不了需求日益增长和复杂环境下的性能一致体验。所以,我们在专项实践过程中,沉淀了一套自适应资源调度框架,解决历史性能问题的同时,能够在不影响现有的研发效率的情况下,低成本优化迁移,实现新业务高性能的开发。此外,从系统底层进行全维度资源监控,自动定位分发问题,来实现长线管控,避免先治理后反弹的情况。</p><p><strong>自适应资源调度框架</strong></p><p>自适应资源调度框架在应用运行过程中,感知采集运行环境。然后对不同环境状态进行不同的调度决策,生成相应的性能优化策略,最终根据优化策略执行对应优化功能。与此同时,监测调度上下文以及调度策略执行效果,并将其反馈给调度决策系统,从而为进一步的决策调优提供信息输入。这样,可以做到在不同的运行环境下都能达到可预期的极致性能体验。并且,整个过程,对业务无需额外开发,做到无感接入,避免影响业务开发效率。</p><p><img src="/img/remote/1460000038991542" alt="" title=""></p><p>• 环境感知</p><p>感知环境分为硬件设备、业务场景、用户行为和系统状态四个维度:</p><ul><li>硬件设备上,一方面通过集团实验室对已知设备进行评测跑分确定高中低端机型,另一方面在用户设备上本地对硬件进行实时算力评估。</li><li>业务场景上,将业务分为前台展示、后台运行、交互操作等几类,一般情况下前台正在进行交互操作的业务场景优先级最高,后台数据预处理业务场景优先级最低。对于同类别业务场景,根据业务UV、交易量、资源消耗等维度进行PK,确定细分优先级。</li><li>用户行为上,结合服务用户画像和本地实时推算,确定用户功能偏好和操作习惯,为下一步针对用户的精准优化决策做准备。</li><li>系统状态上,一方面通过系统提供接口获取诸如内存警告、温度警告及省电模式等来获取系统极端状态,另一方面通过对内存、线程、CPU和电量进行监控,来实时确定系统性能资源情况。</li></ul><p>• 调度决策</p><p>感知到环境状态之后,调度系统将结合各种状态与调度规则,进行业务以及资源调配决策:</p><ul><li>降级规则:在低端设备上或者系统资源紧张告警(如内存、温度告警)时,关闭高耗能功能或者低优先级功能。</li><li>避让规则:高优先级功能运行时,低优先级功能进行避让,如用户点击搜索框时到搜索结果完全展示到时间段内,后台低优任务进行暂停避让,保证用户交互体验。</li><li>预处理规则:依据用户操作及习惯进行预处理,如某用户通常在启动3s后,点击搜索,则在3s之前对该用户搜索结果进行预加载,从而在用户点击时呈现极致的交互体验效果。</li><li>拥塞控制规则:在设备资源紧张时,主动降低资源申请量,如CPU繁忙时,主动降低线程并发量;这样在高优任务到来时,避免出现资源紧缺申请不到资源性能体验问题。</li></ul><p>• 策略执行</p><p>策略执行分为任务执行和硬件调优:其中任务执行,主要是通过内存缓存、数据库、线程池和网络库对相应任务的进行运行控制,来间接实现对各类资源的调度控制。而硬件调优,则是通过与系统厂商合作,直接对硬件资源进行控制,如CPU密集的高优业务开始运行时,将提高CPU频率,并将其运行线程绑定到大核上,避免线程来回切换损耗性能,最大化地调度系统资源来提升性能。</p><p>• 效果监测</p><p>在资源调度过程中对各个模块进行监测,并将环境状态、调度策略、执行记录、业务效果、资源消耗等情况反馈给调度系统,调度系则统以此来评判本次调度策略的优劣,以做进一步的调优。</p><p><strong>全维度资源监控</strong></p><p>由于技术链路长、关联模块复杂,原来出现性能问题时,需要所有相关方集中排查,check所有的改动代码,依赖个人经验判断代码的成本来定位问题,协作和排查成本都很高,导致性能管控有效落地阻力很大。所以我们就思考,性能问题的根本是硬件资源的竞争,那能不能逆向解题,反过来对资源成本进行监控,如果发现异常再回溯产生成本的代码,以及分发给相应owner.</p><p><img src="/img/remote/1460000038991541" alt="" title=""></p><p>那基于这个思路,在构建的时候,首先通过代码扫描建立代码模块关联库。然后,进行成本和调用栈采集。采集完成后,对基线版本和当前版本的成本进行对比,如果发现异常,则通过符号反解异常成本的调用栈直接定位到问题代码。另外,基于问题代码查找代码模块关联库,来定位问题模块,最后将问题准确分发给模块相应的owner,最终实现问题的自动定位和分发,支持团队并行解题。</p><p><strong>管控流程体系</strong></p><p>性能的有效长线管控,除了上面的资源监控平台,还需要配套的流程体系及组织保障。所以在APP的生命周期每个阶段都建立了从测试分析到修复验证的闭环管控。前置监控在迭代开发阶段,早发现早解决。在集成阶段监控每一个改动,保证及时处理。线上通过实时监控和动态下发,实现快速修复。</p><p><img src="/img/remote/1460000038991543" alt="" title=""></p><p><strong>4.总结与思考</strong></p><p><strong>决心大于方案</strong></p><p>超级应用的性能问题往往关联多方业务,需要多方团队协作,所以自上而下对性能的重视程度和优化决心是决定成败的关键,打通任督二脉,才能事半功倍,把优化方案顺利落地。</p><p><strong>攻城难,守城更难</strong></p><p>业务与技术都在快速迭代,要想保证优化成果防止反弹,管控是必须的,而管控就会有束缚和效率影响,管控过程中就难免会遇到各种各样的阻力。所以一方面技术上,建立标准规则,配合提效工具和优化流程,尽量避免影响业务开发。另一方面,团队需要具有共同认知,性能体验与功能体验同等重要,用户对比心智很强,性能体验往往与产品口碑直接挂钩。</p><p><strong>性能优化永远在路上</strong></p><p>目前,我们很多优化策略以及数据参数还是从实验室调校而来。未来,我们会进一步探索云端一体、端智能等技术,做到更懂用户,贴合业务和用户特点,实现性能体验的个性化提升。</p><p><img src="/img/remote/1460000038991545" alt="" title=""></p>
高德地理位置兴趣点现势性增强演进之路
https://segmentfault.com/a/1190000038898238
2021-01-08T18:04:22+08:00
2021-01-08T18:04:22+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>1.导读</strong></p><p>人们在高德地图上会看到很多地理位置兴趣点(Point of Interest,缩写为POI),例如餐厅、超市、景点、酒店、车站、停车场等。对POI数据的评价维度包括现势性、准确性、完备性和丰富性。其中,现势性就是地图所提供的地理空间信息反映当前最新情况的程度,简而言之,<strong>增强现势性</strong>就是指尽可能快速地发现已停业、搬迁、更名、拆迁的过期冗余POI数据,并将其处理成下线状态的过程。</p><p><img src="/img/remote/1460000038898254" alt="" title=""></p><p>在线的过期冗余数据会伤害用户体验,经过推算,头部在线数据的一个过期率百分点年度影响用户体验3亿次。因此,POI过期问题的解决势在必行,以增强现势性,减少用户伤害。</p><p>POI过期问题的解决分为发现和处理两个环节。发现采用挖掘线主导,采集线和舆情线补位的方式。采集的天然优势是自带核实资料,劣势也很明显,成本高、下发频率低,因而发现的时效性不高,且采集线发现过期需要经过挖掘线;互联网舆情时效性高,但覆盖少且ROI低;作为覆盖高、时效高、成本低的大数据挖掘是绝对主力。</p><p><strong>处理环节有人工核实、自动化打标和自动化下线三种手段。</strong>人工核实存在缺少核实资料从而导致核实率低的问题,这是因为挖掘所依赖的观测资料不能提供过期的实锤证据,观测资料不等于核实资料,且过期的数据更倾向于核实不到,即能发现、难处理,从而伴随着挖掘的演进,衍生了自动化打标和自动化下线两种处理手段以及相应的风险控制机制(打标回捞、下线回捞),一方面提高了处理能力,另一方面降低了人工成本。</p><p><img src="/img/remote/1460000038898251" alt="" title=""></p><p>注:自动化打标是一种与前端搜索联动灰度处理高疑似过期数据的方式—打标数据非精搜不展现,精搜伴有话术提示。其背后的核心思路是由传统图商的实锤思维向互联网思维转变,及时触达用户,快上快下。</p><p><img src="/img/remote/1460000038898242" alt="" title=""></p><p>本篇文章将主要介绍挖掘的演进历程,作为过期发现的核心手段,挖掘在不同阶段分别面临缺资料、提准难、资料薄三大问题,站在今天回首过去,这个过程可以分为三个阶段:</p><ul><li>基于自身属性的POI过期挖掘</li><li>基于使用行为的POI过期挖掘</li><li>基于人地关系的POI过期挖掘</li></ul><p>我们利用策略、机器学习和深度学习等数据挖掘技术,从点到面、由粗到精地攻克POI过期挖掘业务,POI现势性增强的模式已经发生了深刻的变化。</p><p><strong>2.数据挖掘手段的演进</strong></p><p><strong>2.1阶段一:基于自身属性的POI过期挖掘</strong></p><p>早期的主要矛盾是缺少挖掘资料,如果同时做资料的POI挂接和基于挂接资料的挖掘策略会导致挖掘链路长、项目风险高。因此,在提升新资料的POI聚合能力的同时,以POI自身属性作为主要的挖掘资料。高德POI团队在信息聚合、融合方面有长时而丰富的积累<strong>,POI属性可大致分为三类:基础信息、深度/动态信息和关系信息。</strong></p><p><strong>基础信息</strong>:表征实体,包括名称、坐标、地址、行业、电话、时间、来源等。</p><p><strong>深度/动态信息</strong>:增加POI数据丰富性,包括:图片、评分、评论、团购、报价等。</p><p><strong>关系信息</strong>:POI间通过语义、时空建立的关联,包括:亲子、引用、共现等。</p><p>针对不同的属性,我们设计不同的策略去挖掘过期POI。根据复杂程度,我们将策略主要分为:基于单POI的挖掘和基于多POI的挖掘。二者的最大区别在于是否使用POI间的关系信息。下面介绍几个比较典型的策略:</p><p><img src="/img/remote/1460000038898248" alt="" title=""></p><p>策略特征使用表</p><p>◎代表关键特征,△表示辅助特征</p><p>评论过期语义挖掘是比较典型的基于单POI的挖掘策略。深度/动态信息中的评论是获取用户对POI反馈的有效途径之一,其中也包括对过期POI的反馈,我们通过匹配关键词很容易找到这种评论。上、下文的语境会导致关键词的语义发生变化,为此,我们利用TextCNN模型实现语义分类以达到消歧的目的,筛选出真正表达POI过期的评论。如下所示:</p><p><img src="/img/remote/1460000038898244" alt="" title=""></p><p>“原”关系挖掘使用POI间的引用关系,是一种基于多POI的挖掘策略。我们在含有“原”关键字的POI名称、别名或地址中通过实体抽取技术,得到“原”关系(新旧关系)的两个POI名称,通过聚合技术找到旧名称所对应的过期POI。</p><p>同地址策略则利用地址门牌冲突关系来挖掘。其逻辑是:相同的门牌号(包括室内水牌)上通常只有唯一的经营实体,若地址上存在两个或多个实体且不是聚集实体(商场、园区等),则应当存在过期POI。我们采用图论对问题建模,取门牌相同的POI集合,将POI视为节点,POI间关系(亲子、兄弟、共现、参考引用等)为边。利用最大连通分解算法将集合划分为K个连通子图,每个子图看作是一个实体或聚合实体。若K=2,则将更新时间较早的子图作为疑似过期集合输出。</p><p>同电话策略是为数不多能与具体过期现象对应的策略。取有相同电话的POI的集合,与同地址策略类似,通过名称语义计算、空间计算、共现关系、亲子关系等,剔除掉聚集实体、连锁店、疑似重复数据等噪音,并根据名称相似性和距离关系,分辨出更名和搬迁现象。电话实际上代表着POI背后真正的人,通过人的行为变化可以判断一个POI过期与否,甚至可以推断出该POI具体的过期现象。 </p><p>伴随着POI聚合多种新数据源的能力的日渐成熟,新的挖掘资料已具备。我们的重心也逐步转移至基于使用POI行为的挖掘。</p><p><strong>2.2阶段二:基于使用行为的POI过期挖掘</strong></p><p>步入阶段二,缺少挖掘资料已不再是解题的主要矛盾,人工核实率低、处理能力不足的问题凸显,从而迫切需要建立自动化打标/下线能力(提准)。过期挖掘的实质是感知伴随POI过期而发生的变化,进行事后观测式挖掘,比如,过期一般都会伴随着POI活跃度(运单量等)的下降。</p><p>前文已提到,挖掘所依赖的观测资料不能提供过期的实锤证据(比如,运单消失并不是过期实锤);且过期强相关因子种类偏少、天然引入上游误差以及真实世界存在贝叶斯误差;外加随着解题推进,在线POI数据现势性增强、过期率下降,在观测资料固定的前提下,过期挖掘的产量及精确率均随过期率的下降而自然下降,上述这些都会导致精确率难提高,因此,提准难成为该阶段的主要矛盾。</p><p>特征层面我们通过去噪、精细化加以应对,受篇幅所限,本文暂不做展开介绍。而算法层面则是通过技术升级来应对。路线图:从规则到模型;从浅层模型到深度模型;从单源决策到多源信息融合;从决策层多源信息融合到特征层多源信息融合。</p><p>根据是否需要参考历史情况,我们将基于使用行为的POI过期挖掘划分为时序异常和事件异常两类。</p><p><strong>2.2.1时序异常</strong></p><p>POI的存活状态可以通过关联的使用行为量活跃度间接反映出来,从使用行为量的趋势角度尝试迭代解题。</p><p><img src="/img/remote/1460000038898245" alt="" title=""></p><p>趋势模型的主要思想是,统计某个时间窗口关联的使用行为量活跃度来衡量POI的存活状态,并通过分析活跃度相对于历史情况的衰减程度来判断POI是否过期,其基本假设是时序趋势下降与POI过期正相关。以已知活跃度信息的逐月统计量时间序列为特征,我们完成了RF->RNN->模型融合->Wide&Deep四个迭代阶段的研发。</p><p>鉴于RF在分类决策问题中表现出的精度高、不易过拟合、对数据集适应能力强、落地高效以及对于规则思维的天然吻合度,可成为验证解题方案可行性的首选。方案是将每种特征的每个时间节点值作为一个输入维度来构建模型。RF凭借高准确和高产出落地投产,验证了行为量趋势应用于过期挖掘的重要意义。</p><p><img src="/img/remote/1460000038898241" alt="" title=""></p><p>之后,针对RF存在的一些不足来做进一步的技术升级。首先,模型无法学到连续时间节点之间的趋势关联性,时序信息未得到充分利用;其次,对于不同种类特征缺失、长短序列融合等问题需要建立定制化模型来解决,多模型增加了维护负担。因此,要选择时序领域优势明显的RNN模型进行迭代升级。</p><p>通过构建多层LSTM深度网络实现了趋势关联信息的深度挖掘,同时针对不同热度分段的数据分布差异性,采取各自最优的缺失特征填充方式,避免了多模型式的解题方案,便于业务维护。RNN模型使发现能力,特别是自动化能力得到较大提升。</p><p><img src="/img/remote/1460000038898243" alt="" title=""></p><p>虽然RNN相对于RF提升了对于时序特征的学习能力,但信息不足依然限制了模型的自动化能力。我们进一步开发了能够实现多源信息融合决策的融合模型。思想是将RF、RNN、拆迁区域等现有各基线模型、策略以及白名单作为子分类器纳入统一框架内考虑,在此基础上构建贝叶斯网络,做决策层的多源信息融合。相较于特征层的多源信息融合,它落地快且效果明确,为过期业务提供了稳定的高准确自动化下线产出,自动化能力大幅提升。</p><p><img src="/img/remote/1460000038898252" alt="" title=""></p><p>第四个阶段是从多源信息融合的角度进一步优化。一方面,决策层融合相比特征层融合存在更多的信息损失;另一方面,一些模型/策略只在部分品类的POI上满足业务投产的准确率标准,导致不达标品类的产出结果未得到充分利用。因此,从实现特征层多源信息融合的角度出发,借鉴Wide&Deep思想搭建新业务模型。</p><p>整体思路是,将众多不可量化或比较的属性特征和状态信息特征进行编码表征,再经过一层全连接层降维后作为Wide部分;将RNN模型作为Deep部分,最后将两部分耦合。模型经过多轮迭代优化可稳定投产,自动化能力得到进一步提升,已成为过期挖掘业务中覆盖行业广、自动化解题能力突出的综合性模型。</p><p><img src="/img/remote/1460000038898246" alt="" title=""></p><p>综合以上,人机解题比大幅下降,解决了人工核实率低、处理能力不足的问题,并且大幅降低了成本。</p><p><strong>2.2.2事件异常</strong></p><p>现有的时序异常模型主要依赖于使用行为量的趋势特征做判断,存在挖掘资料覆盖上的天花板,以加油站、ATM、公共厕所等为例,这些类型的POI因自身属性的原因导致无挖掘资料,趋势模型无能为力。因而提出基于日志(Session)的异常事件模型,统计陌生群体到达过期POI后需求不满足引发的异常事件,补位时序异常模型的挖掘盲区,即无需参考历史情况,仅利用日志抽取POI关联的异常行为事件,累积近期异常事件衡量POI的存活状态是否正常。</p><p><strong>日志挖掘难点</strong></p><p>海量的日志行为。直接使用不仅消耗资源大,且有大量的冗余数据造成干扰。如何在海量行为中抽取与过期相关的特征是一个艰难的工程。</p><p>行为随机性大。例如,很多情景里快到终点前会提前结束导航从而无法判断是否到达目的地;有些情景是规划去一个目的地但从末端轨迹可以判断实际去的地点天差地别。</p><p><img src="/img/remote/1460000038898247" alt="" title=""></p><p><strong>解题框架</strong></p><p>针对上述问题,主要通过实地评测的过期POI case分析来构建具体的异常事件场景,例如到达后试图报错、到达后快速发起二次同质化导航等,以上统计量作为特征输入,由此可聚焦相关日志片段并降低随机行为噪音。整体解题框架如上图所示,从不同的Session源解析与POI相关的事件,按照时间顺序组合成场景1、场景2、场景…,加入外部属性如类型、城市等,以目的地POIID按照时间窗口归并生成相应的统计特征,输入LR模型,输出POI的过期得分。目前采用LR,优点是简单粗暴压住噪声。</p><p><strong>挖掘效果</strong></p><p>Session异常事件模型有效补充其他手段未能覆盖的解题集合,专攻汽车服务、生活服务、娱乐场所、金融保险服务等品类POI,是过期挖掘不可或缺的组成部分,且未来仍有较大的泛化提召回空间。</p><p><strong>2.3阶段三:基于人地关系的POI过期挖掘</strong></p><p><strong>2.3.1 人地关系建设</strong></p><p>趋势特征丰富(厚)的过期POI,容易被趋势模型挖出。而当趋势特征(使用行为)稀少(薄)时,模型发现能力较差。所以该阶段需要解决资料薄的问题,通过对关键群体(>2)线索的捕捉,降低对资料厚度的依赖。洞察POI的关键群体的行为,有可能找到发现甚至解释POI过期的特征。</p><p>因此,第一步我们需要建设人地关系,找出所谓的关键群体,称之为内部群体,是指:对POI有依赖的群体,这种人地关系,我们称之为内部关系,其它均为外部关系。</p><p>第二步基于内部群体的时空运动模式的变化发现过期POI,补位趋势特征稀疏时的召回问题,局限性:内部群体基本不变的POI更名等场景不可解。第一步人地关系建设基本完成,大体分为数据层、行为层和模型层三层,分别介绍如下:</p><p>在数据层,收集可能与POI相关的数据源,打通各个数据孤岛,将不同类型的数据关联到高德POI上。</p><p>在行为层,将行为特征表达在窗口为X天的二维矩阵上,如图所示。矩阵表示能够更加清楚地反映行为的周期性规律。不同行为序列可以看作是不同通道的矩阵,很好地适配行为数据的异步性,同时保持可扩展性(每多一种行为,可增加一个通道表示)。</p><p><img src="/img/remote/1460000038898249" alt="" title=""></p><p>在模型层,面向多通道的矩阵特征,采用深度卷积网络完成分类任务,其基本结构如下:</p><p><img src="/img/remote/1460000038898250" alt="" title=""></p><p>该结构一定程度地缓解由于数据不完备导致的特征稀疏,有效地学习行为的时间规律,取得符合预期的结果,验证了模型的可用性。在模型层,通过补充的召回策略,帮助将内部关系对POI的覆盖度进一步提升,完成从0->1的建设。</p><p><strong>总结</strong></p><p>过期挖掘已经成为增强POI现势性的绝对主力手段。这条以大数据挖掘为主导的路线还远远没有达到终局,未来的演进方向至少有以下几个:内部群体时空转移本质化通盘解题,降低对资料厚度的依赖;面向过期现象的定向挖掘能力提升;POI生命力画像构建;生态探索,从逆向解题向逆向+正向解题渗透。我们将致力于为提供给用户更美好的出行服务体验而努力。</p><p><img src="/img/remote/1460000038898253" alt="" title=""></p>
为亿级用户的美好出行而战!高德地图首届算法大赛落幕 95后北邮在读博士带队夺冠
https://segmentfault.com/a/1190000038437022
2020-12-10T13:12:48+08:00
2020-12-10T13:12:48+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>日前,高德地图联合阿里云天池平台举办的AMAP-TECH算法大赛落幕。本次大赛以“基于车载视频图像的动态路况分析”为赛题,来自15个国家和地区的880支战队经过数轮激烈角逐后,1996年出生的北京邮电大学博士三年级学生朱奕达带领的战队夺得冠军。</p><p><img src="/img/remote/1460000038437025" alt="" title=""></p><p>(高德地图技术委员会主席李小龙给冠军队伍颁奖,从左到右的三位同学分别是北京邮电大学研究生一年级学生谢志庆、广州大学方滨兴班研究生二年级学生黄文锋、北京邮电大学博士三年级学生朱奕达)</p><p>本次竞赛的赛题来源于高德真实的业务场景。路况信息不仅影响用户选择出行的路线、出行的方式,预估到达的时间,对于交通管理部门和城市规划部门也有重要的价值。</p><p>此次高德地图号召全球的开发者利用人工智能技术探索动态路况难题,收到了国内外顶尖学府、科研机构以及一线知名技术企业等产学研各界技术爱好者的积极响应。历经4个月的初赛、复赛,五强战队从来自于15个国家和地区,309所高校和256家+公司的参赛者组成的880支战队中脱颖而出进入到现场决赛答辩。</p><p>决赛评审上,北京大学教授、机器感知与智能教育部重点实验室主任查红彬,中科院自动化所研究员、模式识别国家重点实验室主任王亮,高德地图技术委员会主席李小龙,高德地图首席科学家任小枫,阿里巴巴达摩院自动驾驶实验室负责人王刚组成的专家评审团从创新性、实用性和扩展性以及现场表现三个维度对各队方案进行现场的综合评审。</p><p>评委们认为,朱奕达战队以模块化的方式设计了一个端到端序列分类模型, 使用了比较新颖的滑动窗口法对数据进行扩充。在简洁模型结构中充分利用了图像序列信息,并实现了较为优异的性能。在比赛过程中,算法的鲁棒性优秀,并具备良好的可扩展能力。同时模型设计过程中使用了学术研究领域相对前沿的技术方法,落地和实用性的潜力在决赛的几个作品里更突出。</p><p>北京大学教授、机器感知与智能教育部重点实验室主任查红彬表示,针对交通场景,选手们对深度学习网络结构方面下了很大的功夫。交通场景的问题是个动态变化的自适应性问题,希望同学们能够更多从在线学习角度考虑相关问题。</p><p>高德地图技术委员会主席、研究员李小龙在决赛现场发言时表示,动态路况分析是智慧出行场景的重要课题,高德通过智能化手段解决动态路况分析就需要用到人工智能、大数据等技术,这个问题的解决对于精准导航和人们美好出行具有重要的现实意义。他鼓励同学们通过更多系统性的深度思考,把更多学术界的前沿方法用到工业界的实际业务场景中,带来新的突破方向。</p>
高德全链路压测——精准控压的建设实践
https://segmentfault.com/a/1190000038228521
2020-11-19T17:42:08+08:00
2020-11-19T17:42:08+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>导读</strong></p><p>作为国民级出行生活服务平台,高德服务的稳定性不论是平时还是节假日都是至关重要的,服务稳定性一旦出问题,可能影响千万级甚至上亿用户。春节、十一等节假日激增的用户使用量,给高德整体服务的稳定性带来了不小的挑战。每年在大型节假日前我们都会做整体服务的全链路压测。通过常态化全链路压测项目的推进,已具备了月度级别的常态化全链路压测能力,把战前演练提到日常,持续推进稳定性保障建设。</p><p>TestPG压测平台2018年9月启动,在2019年春节第一次支撑高德全链路压测任务,当时前后花了近2周的时间才完成3个机房的压测任务。后来成立了常态化全链路压测项目,通过对流程的优化以及压测平台技术能力的升级,现在已经具备了1天内完成全国3个机房全链路压测的能力。大型节假日的全链路压测周期缩短到了3天。</p><p>全链路压测的常态化不仅对高德整体服务的稳定性建设起到了推动作用,而且也推动了流程上的优化以及压测平台在技术能力上的改进提升。具体而言,我们主要从压测前的语料准备和压测过程中的压力调控两个方面入手,通过语料平台化生产,规范语料生成流程,对语料生产提效;通过压测过程中对发压能力的精准调控,使我们能够灵活调整压力模型,从而使其更加接近于线上真实情况,让全链路压测过程平滑流畅,效率提升。本文会重点介绍TestPG压测平台在发压能力精准调控方面的建设实践。</p><p><strong>压力调控的两个主要问题</strong></p><p>下图是现阶段高德全链路压测的一个大致流程</p><p><img src="/img/remote/1460000038228526" alt="" title=""></p><p>高德全链路压测涉及到接入层的上百个接口,每个压测接口的压测流量需要在链路梳理阶段由运维和相关同学事先预估给定。压测前会在压测场景里对每个接口的流量进行分配,通过流量占比事先配置好,这是我们全链路压测的压力模型。压测启动之后,会逐步加压,直到整体压测流量到达预估值,在整个过程中,可能会对事先配置的压力模型不断做出调整,最终使压测流量模型符合预期的线上流量模型。</p><p>高德全链路压测涉及的链路比较长,压测流量流经接入层,服务层最终到达引擎层,有可能出现实际到达引擎的流量与预估流量之间存在差异。这时候会先停止压测,更新压测场景里的接口压测流量占比配置,然后再启动压测。</p><p>在高峰期,压测集群中可能有百十台施压机同时施压,停止压测,更改压测场景里的接口流量占比配置,再启动压测,然后再一次逐步加压,这样一整套流程会非常耗时而且效率低下,有时只为了更新一两个接口的流量占比配置,不得不把前面的步骤再走一次,导致过多耗费时间精力。不断起停也使整个过程不连贯,无端拉长了全链路压测周期。</p><p>再者,在全链路压测过程中,整体压力是逐步增加的,多轮加压,每一轮加压后都会监控服务的各项指标来决定是否进一步增加压力。TestPG压测平台采用分布式集群施压模式,增压是通过往压测集群里调度新的施压机实现的,这样带来的问题就是,增加压测流量的时候,需要相关人员根据压测时候的单机施压能力大致估算出需要增加多少机器。由于增减的压力=单机施压能力*n台施压机,这样的压力调控粒度也是比较粗糙的。比如要加压1w qps,单机的施压能力是3k qps, 那么需要增加3台或4台施压机,那么实际增加的压力为9k或者1.2w。</p><p>最后,也是最重要的,高德业务系统对接口特征参数(对服务的功能/性能有重大影响的接口参数)尤为敏感,比如长短距离导航对后台服务的算力和资源消耗都是不同,这就提出了更高的要求,我们需要有能力在全链路压测中对接口的压力调控精确到特征参数级别。</p><p>简单总结一下,在压测过程中,针对压力调控,我们面临两个主要问题,一是压力调控效率低下,二是无法做到细粒度的精准调控。</p><p><strong>实现路径</strong></p><p>全链路压测是以真实流量提前对系统进行验证。只有以接近于线上真实流量的压力模型对系统进行压测,才更能发现可能隐藏的稳定性问题,压测才能更有价值。由于我们的压力模型是预估给出的,难免会与实际服务预期的流量存在差异。所以压测过程中通过对差异流量做调整,最终使压测流量模型符合预期的线上流量模型。</p><p>既然现阶段压测过程中,压力调整在所难免,并且由于其效率低下,已经影响到了全链路压测的顺利进行,那么就可以以此为抓手,在压力调控能力上做技术改进。首先是解决压力调整效率低下问题,保障全链路压测的流畅进行,提升效率。然后结合语料智能化项目,实现精准压测,使压测流量(压力模型+压测场景)更加接近于线上真实流量。未来可以进一步探索,提供丰富的压力模型以更好地支撑场景化压测的诉求。</p><p>接下来会介绍TestPG压测平台,在施压能力精准调控建设上的技术方案和落地成果。</p><p><strong>技术方案</strong></p><p>TestPG压测平台采用分布式集群施压模式,多台施压机构成一个压测集群。平台的整个架构是典型的master-slaver结构,压测的时候master调度slaver进行施压。这样的架构其实非常适合我们实现压力动态调控的一个自动控制系统。</p><p><img src="/img/remote/1460000038228524" alt="" title=""></p><p>上图是压力调控系统的一个抽象示意图。</p><p>压力调控中心是压力调控系统的大脑。其主要作用是根据压力调控策略向压测集群中的施压机下发压力调控指令,并且能够根据调控反馈数据,决定进一步的调控策略。</p><p>压测集群作为压力调控对象,接收压力调控中心下发的调控指令,并实施具体的压力调控动作。</p><p>压测集群与压力调控中心之间存在一个反馈渠道,这样压力调控中心就可以知道调控的效果,并根据反馈数据,对下一步的调控进行决策。</p><p><strong>落地架构</strong></p><p><img src="/img/remote/1460000038228525" alt="" title=""></p><p>以上是TestPG压测平台精准控压建设的一个落地架构示意图。</p><p>API Gateway模块承接用户压力调控指令,并把压力调控指令转发到Stress Contoller(压力调控中心)。</p><p>Stress Controller是压力调控的大脑,会根据压力调控策略向压测集群中的施压机下发调控指令,并根据反馈数据,决定下一步调控策略。</p><p>TestPG基于Redis实现了动态配置缓存。压力调控指令通过动态配置缓存下发到压测集群,更具体来说是下发到压测集群中的每台施压机上,目前TestPG采用两种方式实现动态配置的下发,分别是施压机主动拉取和通过发布订阅模式进行实时推送。</p><p>压力调控指令下达到施压机后,压测引擎运行实例会加载压力调控配置,实时调整压力。</p><p>每个压测引擎都会实时上报自己到压测指标(比如qps, rt等)和施压机的性能指标(比如cpu占用率,load率等)到TSDB时序数据库,TSDB建立了压测集群和压力调控中心之间的反馈渠道。Stress Controller定期查询TSDB,获取每台施压机以及整个压测集群的压测指标作为反馈数据,根据这些反馈数据判定单机压力调控成功与否,整个压测集群压力调控成功与否,并且会根据反馈数据决策是否进行进一步的调控。</p><p>基于以上架构,TestPG压测平台在精准控压建设上,已实现了集群和接口两个级别的精准调控。</p><p><strong>集群压力调控</strong></p><p>通过集群压力精准调控,在压测过程中,可以随时指定要压的预期qps,如果是下调压力,平台会非常快的把压测集群的输出流量,压到指定的预期qps。如果是上调压力,当前压测集群中的施压机整体输出压力上调后不能达到预期的qps,系统会从施压机公共资源池调配一定数量的施压机进入压测集群,确保在服务容量以内,压测流量能够上调到预期qps。通过这个功能,压测过程中增减压力,我们不再需要人工根据单机施压能力估算要增减多少施压机,整个压力调控过程完全是由系统自动进行的。集群的整体压力也实现了精准调控,达到平台在压力输出能力上指哪打哪能力。</p><p><strong>功能介绍</strong></p><p>在压测过程进行中,可以对压测任务预期qps进行指定。</p><p><img src="/img/remote/1460000038228529" alt="" title=""></p><p>压测集群整体压力输出根据指定的预期qps实时调整.</p><p><img src="/img/remote/1460000038228527" alt="" title=""></p><p><strong>接口压力调控</strong></p><p>接口级别的压力调控,目前平台已经落地了接口流量占比动态调整能力,压测过程中可以随时对接口差异流量做调整,实现了在不停压测的情况下对接口流量占比的即时调整能力。该功能对保障全链路压测的顺利进行起到了关键作用,让我们可以方便高效地对压力模型做调整,使全链路压测得以平滑顺利进行,提升了全链路压测参与各方的幸福感。</p><p>今年十一全链路压测,由于业务增长较快,导致压力预估模型与实际预期有较大出入,通过接口比例动态调整功能,在不停压测的情况下我们对压力模型进行了近百次调整,保证了全链路压测的流畅度,保障了全链路压测的顺利进行。</p><p>针对于接口特征参数级别的精准调控,我们的解决方案是:通过语料智能化生产,对接口特征参数提取和统计,可以把压测接口按特征参数分布拆分为多个,结合接口调压能力,最终在接口级别压力调控上,可以进一步实现接口特征参数级别的更精细调控,这对于高德业务系统的全链路压测来说是非常重要,可以使我们实施更加精准的压测。</p><p><strong>功能介绍</strong></p><p>在压测过程中,对压测接口流量占比实时调整。</p><p><img src="/img/remote/1460000038228528" alt="" title=""></p><p>接口发压流量占比实时调整效果。</p><p><img src="/img/remote/1460000038228531" alt="" title=""></p><p><strong>总结</strong></p><p>通过发压能力精准调控的建设,目前TestPG压测平台具备了集群和接口两个级别的高效精准压力调控能力。提升了全链路压测效率,有效缩短了全链路压测的周期,在全链路压测过程中可以使我们方便高效地对压力模型做调整,使其更加接近于线上真实情况。</p><p>全链路压测的目的在于验证服务稳定性保障措施是否符合预期,提前发现服务稳定性问题。压测的真实性至关重要,这里的真实性是指压测的语料数据与线上用户场景相符合,压力模型也要与线上相符合。目前我们的压力模型是通过计算和预估的方式给出的,往往与线上压力模型存在出入;而压测数据虽然是基于线上流量生产的,但与春节、十一当天的场景还是有差异的。</p><p>在真实性保障上,目前TestPG压测平台也已经有了相应的解决方案,那就是语料智能化生产加上精准控压。未来,我们期望通过语料智能化项目的推进,借助机器学习等手段,通过对压力模型,以及用户场景的预测,并结合精准控压技术,让全链路压测的压测流量模型更加接近于春节、十一等节假日线上真实情况,实现真正意义上的精准压测。</p><p><strong>未来思考</strong></p><p>精准控压技术,赋予了平台对压力的精准调控能力,解决了全链路压测过程中,压力调控效率低下问题,保障了全链路压测的顺畅度;并且通过对压力模型的方便高效调整,也使得全链路压测的压力模型更加符合线上真实情况。但是精准控压技术的用武之地不应该局限于此。</p><p>未来我们可以在压测类型上做进一步探索。目前从TestPG压测平台的使用情况大致来看,日常压测上大家并没有有意识的区分压测类型。绝大多少情况下大家都是以固定qps持续对系统施压。但是,线上系统面临的真实流量有时候并不是固定,有可能出现极限尖峰脉冲等情况。平时系统如果没有压测过这种极限场景,那么线上系统遇到这种异常流量时就有可能被打挂。</p><p>基于精准控压技术,我们可以在压力模型上做进一步深挖,未来可以在平台上提供多种压测类型支持,比如负载测试、压力测试、系统容量预估测试等等。并为每种压测类型配备相应的压力模型,比如可以提供负载递增的压力模型,这样可以方便我们探查系统容量极限;又比如通过提供极限脉冲压力模型,可以有效测试系统在遭遇异常流量时候的表现。我们期望通过提供丰富的压测类型支持,把系统性能的各方面都测到,把系统压测做全做得更专业。</p><p><img src="/img/remote/1460000038228530" alt="" title=""></p>
高德全链路压测——语料智能化演进之路
https://segmentfault.com/a/1190000037771593
2020-11-09T14:10:59+08:00
2020-11-09T14:10:59+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>背景</strong></p><p>高德地图作为日活过亿的国民级出行生活服务平台,承载着海量用户服务的是后台的超大规模集群。从用户角度,如果出问题,影响会很大。3机房异地部署造成线上环境复杂,链路复杂。在这样的条件下,如何避免因故障造成用户的伤害,以及在复杂链路条件下做好容量规划,做好灾备,并在第一时间发现问题,通过流量控制和预案演练做应急响应就显得至关重要,而所有的工作都不能等到事情发生之后才做,我们需要有一种验证手段来做好提前性能摸底,这就是全链路压测,让真实的流量提前到来。</p><p>全链路压测作为线上服务稳定性保障的重要手段,对高德来说也是非常重要的。高德全链路压测平台TestPG从无到有,在经历过常态化压测后,已基本可以保障高德的所有全链路压测和日常压测,达到了平台初期快速、准确压测和全链路压测的目标。而语料生产(流量处理)作为全链路压测的重要环节,本文将对此做重点介绍。</p><p>一次全链路压测可简单总结为3步:压测前的流量处理(也就是生产语料)、压测中确定压力模型启动压测、压测后的结果分析与问题定位。每次全链路压测,压测前的流量处理是整个压测过程中最耗时的一环。过去往往由运维采集日志交给测试同学写脚本处理,耗时相当严重、成本巨大,且存在请求过期等诸多问题。基于这些问题,高德全链路压测平台TestPG前期已规范了高德压测的语料格式,统一了高德压测的流量处理流程。但随着高德全链路压测的演进,后续面临两个主要问题:</p><ul><li>语料生产流程缺乏统一管控。虽然平台前期已规范了语料格式,但各业务只是按照语料规范处理流量,生产流程缺乏统一、标准化管控,导致语料生产成本依然很大。尤其对于全链路压测来说,语料准备是最耗时的环节。</li><li>接口级别的精准控压无法满足需求。高德作为国民级的出行应用,流量受天气、地形、节假日的影响比较大。比如拿驾车导航来说,日常大多都是短距离的驾车导航,而国庆、春节大多都是长距离的驾车导航,而长距离的驾车导航对后端算力的要求是非线性增加的,甚至是成倍增加。但长短距离的驾车导航对压测平台来说是同一个接口,而平台目前的精准控压只能做到接口级别,无法模拟接口特征级别的压测。</li></ul><p>基于以上两大问题,高德全链路压测团队设立语料智能化专项,重点解决以上相关问题。</p><p><strong>解题思路和路径</strong></p><p><strong>引流标准化</strong></p><p>高德的全链路压测彼时已基本拉通大多业务,但还属于一个演进阶段。对于语料处理,主要由各业务自行处理后用来压测,语料处理的来源缺乏统一性,日志、ODPS、流量等处理来源司空见惯。对于语料生产流程的统一管控,我们首先想到的是统一语料处理来源,必须选择一个低成本、高效率的方式作为语料生产的输入,而流量录制的方式就很切合。经过调研,发现高德其他业务场景对流量录制也有很大的需求。但高德过去的流量录制方式并不统一,各业务线自行拷贝流量经常会引起线上机器不稳定等问题。所以首先要做的是统一高德的流量录制,标准化引流。</p><p><strong>语料生产平台化</strong></p><p>要统一管控语料的生产流程,上面已经统一了语料生产的输入,接下来就是如何把流量转化为符合平台规范的语料,把整个转化流程平台化。但对于高德业务来说,各个业务都有其自身的特点,如果让平台为每个业务提供定制化的处理逻辑成本巨大,再加上平台对各个业务并不是特别熟悉,也很容易出错。而整个语料处理过程也存在一些通用的处理逻辑,所以我们必须提供一种既支持各业务定制化需求,又可以满足平台通用处理逻辑的方案。我们最终选择通过Flink来完成整个流量处理逻辑。</p><p>引流已经标准化,业务方只需查看流量的格式内容,编写Flink的UDF(用户自定义函数),处理自身业务定制化的需求即可,而后续通用的语料存储等逻辑可通过Flink的sink插件来完成。这样既可以提供通用处理逻辑,又给业务的特殊需求提供了支持,扩展性良好。</p><p><strong>语料智能化</strong></p><p>上面已经提到高德这种国民级出行应用受各种环境影响比较大,如何达到接口特征级别的精准控压,是当时面临的又一大难题。平台已具备接口级别的精准控压,只需把接口按照特征分类,提供真实流量的特征分布即可。但流量的特征分布是实时变化的,如何提供符合流量高峰的特征分布是语料智能化的最终目标。</p><p>要实现语料智能化需要经历3个阶段。第一阶段是流量特征统计。我们需要明确影响流量变化的因素,体现到流量上就是具体的参数分布,具体有哪些参数会随着外界环境的变化而变化。当然这块高德大多业务线都有一些粗略的分析结果,前期可以直接采用,后期就需要有更细粒度的特征分析。</p><p>第二阶段是流量特征提取。有了具体的特征参数后,就需要对特征参数进行提取统计,后续可用来做智能预测。但特征参数的提取到底应该如何去做呢?经过综合分析发现放到语料生产的环节最合适。引流拷贝流量,语料生产环节用来处理流量,在这个环节提取特征参数再好不过了。而整个语料生产扩展性良好,对用户的特殊需求通过UDF完成,整个流量特征提取刚好可以在通用逻辑里面完成。</p><p>第三阶段就是智能预测与机器学习。有了特征参数的统计数据,就可以借助往年高德地图国庆或春节的流量特征,加上今年随着业务的流量变化趋势,智能预测出符合今年国庆或春节流量特征的数据,做到接口特征级别的精准压测,做到真正意义上的全链路压测,为高德地图服务的稳定性保驾护航。后续也可以借助机器学习自动发现影响流量变化的特征参数,自动采集分析,做到真正意义的语料智能化。</p><p><strong>整体方案</strong></p><p><img src="/img/remote/1460000037771597" alt="" title=""></p><p>整个引流工作将由开发的统一引流平台来完成,引流平台通过引流插件把流量缓存到Kfaka,最终落盘到ODPS。而整个语料生产服务直接对接引流平台,处理来自ODPS的流量即可。</p><p>语料生产服务的整体处理过程都由Flink来完成。用户只需编写Flink的UDF来完成自己业务线定制化的需求即可。而且整个Flink的UDF支持多参数传递,用户可灵活编写UDF,在执行过程中动态传递相关参数,解决请求过期等问题。</p><p>Flink sink是由平台开发的一个Flink源表解析插件,主要包括流量的特征分析与提取,以及把生产好的语料按照接口命名写入OSS供平台压测使用。目前流量的特征由各业务线自己提供,通过在平台添加完成。Flink sink在执行过程中调用平台开放API获取特征数据进行采集,最终上报给平台,平台后续再根据这些数据进行机器学习,智能预测出符合流量高峰的流量特征,供全链路压测使用。</p><p><strong>核心功能介绍</strong></p><p><strong>Iflow引流平台</strong></p><p>基于上面的问题分析,高德工程效率团队积极迎接挑战,短短几个月开发了Iflow引流平台,对高德的引流进行了统一管控,具体如下图所示:</p><p><img src="/img/remote/1460000037771596" alt="" title=""></p><p>Iflow引流平台以任务的方式对高德的引流进行管理。目前采用引流插件的方式进行流量拷贝(后续将支持更多引流方式),流量通过Kafka缓存,最终写入ODPS供大家使用。用户只需要从ODPS提取需要的数据即可。而启动引流需要相关负责人审批,周知到关联业务,有效的降低了引流引起事故后排查的成本。</p><p><strong>TestPG语料智能化</strong></p><p>高德全链路压测平台语料智能化主要由3个模块组成:业务线管理、压测名单管理和接口比例管理。业务线管理主要用来管理高德各个链路的相关数据,包括关联引流任务、启动引流、引流记录、语料路径、压测header管理和触发语料生产等功能。一条业务线就是一条压测链路,从引流到语料生产以及语料特征分析等都是在业务线维度完成的。具体如下图所示:</p><p><img src="/img/remote/1460000037771598" alt="" title=""></p><p>功能介绍:</p><ul><li>关联引流任务:主要完成和引流平台任务的关联以及配置相关的参数。</li><li>启动引流任务:启动引流平台任务,在引流结束后会自动触发语料生产,通过执行用户编写的Flink UDF和平台开发的Flink插件,完成语料的生产和特征参数的提取。</li><li>语料路径:在每次启动引流触发语料生产后平台会自动生成语料路径,用户可在创建语料的时候自主选择。</li><li>压测header管理:每条业务线都有自身的业务特点,在header上的体现也不同,这里主要用来管理压测http服务发送的header内容。</li><li>触发语料生产:语料生产有2条途径,一是关联好引流任务启动引流后会自动触发语料生产,包括特征参数提取等一系列的操作;二是在引流成功后,用户可能对UDF等参数有所修改,也可以通过此按钮来触发语料生产。</li></ul><p>压测名单管理主要用来管理压测的接口。一个公司开始做压测,业务肯定是需要跟着去适配的,随之而来的就是业务改造,这是一个漫长的过程。为了方便管理,高德全链路压测平台对高德这边的接口进行统一管理。具体如下图所示:</p><p><img src="/img/remote/1460000037771599" alt="" title=""></p><p>压测名单是在引流过程中自动上报的,引流只要发现未在压测名单的接口就会自动上报压测平台,平台根据关联应用去关联对应的负责人,并推动确认。如果可压测就确认为压测名单,下次语料生产作为白名单正常引流。如果不能压测就区分为免压接口或待跟进接口。待跟进接口平台后续会以消息通知的形式推动业务线改造,最终达到真正意义的接口覆盖全、链路覆盖全的全链路压测。</p><p>接口比例管理前期主要是用来管理BI提供的、以及每次全链路压测调整的比较贴近真实情况的接口比例数据,作为后续全链路压测的一个参考。后期将通过语料生产提取流量特征的统计数据,智能分析预测出符合真实情况的流量比例,供全链路压测直接使用,具体如下图所示:</p><p><img src="/img/remote/1460000037771600" alt="" title=""></p><p><strong>平台优势</strong></p><p><strong>语料平台化生产</strong></p><p>整个语料生产对接了引流平台,并通过Flink来完成。既支持了业务方定制化的需求,也支持平台通用化的处理逻辑,扩展性良好。通用逻辑通过Flink sink来实现,并加入了流量特征提取等功能,推动了语料智能化的顺利进行。用户只需要学习Flink完成UDF的编写,然后在平台完成相关配置即可。很大程度上提高了语料生产的效率和质量,是语料从格式标准化向生产流程标准化的一大飞跃。</p><p><strong>语料智能化</strong></p><p>平台在整个语料生产的过程中,通过Flink插件完成了特征参数的统计汇总。目前用户只需在平台完成相关特征的配置,平台在语料生产过程中就会分析特征并统计汇总。有了特征参数的统计数据,将有助于平台后续的智能分析与预测,达到接口特征级别的精准控压,最终达到完全意义的全链路压测。</p><p>平台目前已经完成了语料的自动生产,并加入了语料智能化相关的工作。整个压测名单也是通过引流自动上报,后续将通过消息通知自动拉通业务线改造解决。接口比例管理模块也已支持接口比例的展示和调整,最终通过语料特征的智能预测,即可生产出符合流量高峰真实特征的语料。这些都将推动高德全链路压测智能化的演进。</p><p><strong>未来展望</strong></p><p>高德全链路压测平台语料智能化发展已经有一段时间了,通过大家的不懈努力,语料智能化已完成了语料的自动生产,以及特征参数的汇总和提取,为后续智能化奠定了基础。未来平台将通过机器学习的方式分析学习采集到的特征数据,根据往年流量高峰的特征情况,加今年流量的变化趋势预测出符合今年流量高峰的特征情况,做到接口特征级别的精准控压,完全模拟真实流量压测达到真正意义的全链路压测。</p><p>此外,平台将会借助机器学习自动分析发现影响流量变化的参数,自动提取分析,提高语料生产的准确性。</p><p>平台也会有置信度评估系统,分别对比真实的流量特征和预测的流量特征,分析产生误差的原因,进一步提高预测的精准度,做到完全真实的流量生产。后续配合平台的精准压测、压力模型和监控等功能达到真正意义的无人化、智能化的全链路压测。</p><p><img src="/img/remote/1460000037771601" alt="" title=""></p>
业内首发车道级导航背后——详解高精定位技术演进与场景应用
https://segmentfault.com/a/1190000037748414
2020-11-06T15:31:06+08:00
2020-11-06T15:31:06+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>导读</strong></p><p>10月30日,华为联合高德、千寻发布了业内首家面向手机用户的车道级导航应用。在这背后是高精度定位技术不断演进发展,最终走向成熟量产的过程。本文将结合高德地图在车道级导航及自动驾驶等领域的工作,分享我们对于高精度定位技术演进的思考,以及在高精定位实际落地应用中的一些实践。</p><p> <img src="/img/remote/1460000037748419" alt="" title=""></p><p><strong>一、高德定位技术概述</strong></p><p>定位技术是支撑高德地图的导航、交通等核心业务的关键基础技术,他的主要任务是确定物体(通常是人或车)在一个相对固定的坐标系中的位置和姿态。我们用手机高德地图作为例子来说明都有哪些技术在实际应用场景中发挥作用。 </p><p>通常手机的基础定位能力是由手机的GNSS芯片提供的,它为我们在室外的绝大部分场景下提供了5~10米的定位精度。但是在卫星信号不好的时候,定位可能会漂移,我们需要识别出这种情况。另外,当信号受到干扰的时候,位置可能出现有规律的偏移,我们也要识别出干扰,并且在可能的情况下重新解算出正确的位置。当GNSS定位不准的时候,想要持续定位,可以利用传感器识别出步行/驾车状态,再进行航位推算(PDR、VDR)。当进入室内卫星信号丢失了,常用的定位方法是根据手机扫描的基站和Wifi、蓝牙等信号做网络定位。</p><p>上面这些技术提供了基础的位置坐标,而在导航过程中,我们更关心的是行驶在哪条路上,有没有偏航,距离下个路口有多远,想得到这些信息就需要用到地图匹配技术。在一些非常复杂的场景下,比如高架桥、主辅路,判断道路变得非常困难,这时候还需要用到一些专门的识别模型来解决匹配问题。</p><p> <img src="/img/remote/1460000037748417" alt="" title=""></p><p>图1 手机高德地图中的定位技术</p><p>上面提到的只是具体一个业务场景中的部分技术,下面展示了高德定位技术的一个更完整的大图。总的来讲,我们是通过构建一套“云+端+数据”的完整的技术体系,并建设质量迭代系统保证各技术模块的持续更新迭代,来支撑众多的定位业务应用。</p><p> <img src="/img/remote/1460000037748418" alt="" title=""></p><p>图2 高德定位技术大图</p><p><strong>二、定位技术如何向高精演进</strong></p><p>回到图1,我们可以看到这里提到的定位技术尽管扩展了用户场景,但在定位精度方面并没有明显提升。如果要实现前面提到的车道级导航,乃至更加智能化的自动驾驶,就要求定位精度显著提高到亚米级,甚至厘米级。那么怎么做到这一点?我们下面会从技术的角度做一个分析梳理。</p><p>首先,我们把图2中涉及的,以及其他更广泛的定位技术,按照定位原理分成三类,分别是航位推算、几何定位和特征定位。针对不同的定位类型分析影响精度的因素,总结提升精度的方法,最终期望找到实现高精定位的技术路径。</p><p><img src="/img/remote/1460000037748420" alt="" title=""></p><p>表1 不同定位技术的分析汇总</p><p><strong>1. 航位推算</strong></p><p>航位推算的基本原理是从上一时刻位置出发,根据运动方向和距离推算下一时刻的位置。显然这种定位方法需要一个已知的起始位置,否则就只能得到相对的位置变化。同时在推算过程中定位误差会不断累积增大,所以影响精度的直接因素就是推算时间或距离。</p><p>此外,推算精度还受到每个时刻的测量精度的影响,对于惯性传感器,这就直接由惯性器件的精度决定。例如,精度最高的战略级惯导,随时间发散的位置误差可达30m/hr,相比之下,战术级惯导精度要差3个数量级,而我们常用的消费级微机械(MEMS)惯导精度比战术级要再差1~2个数量级。</p><p>除了器件精度,推算过程中的模型精度也会影响定位精度,这包含两个方面:一是对器件测量误差的补偿模型,二是对计算误差的补偿模型。通常只有当器件本身的精度足够高时,才需要考虑更精确的补偿模型。</p><p><strong>2. 几何定位</strong></p><p>几何定位是对已知位置的参考设备进行测距或者测角,再通过几何计算确定自身位置。根据几何计算的方式不同,包括RSS(信号强度)、TOA(到达时间)、AOA(到达角)、TDOA(到达时间差)等多种方法。对于测角定位方法,一个小的角度测量误差可能在距离定位设施较远的地方产生很大的位置误差,因此这种方法(如采用AOA方法的蓝牙定位)的定位精度通常受范围限制。在测距方法中,采用时间到达模型(如采用TOA方法的GNSS定位,采用TDOA方法的UWB定位)比信号强度模型(如采用RSS方法的蓝牙和Wifi定位)更有可能获得较高的定位精度。但在实际应用中,最终的定位精度受到距离测量精度的影响,尤其是在卫星定位这一类长距离信号传播的场景中,如何消除信号传播路径上的测量误差,就成为决定定位精度的关键。此外,几何定位的精度也受到定位设施数量和分布的影响,同时观测的设施越多、分布越均匀,精度通常也越高。</p><p><strong>3. 特征定位</strong></p><p>特征定位方法首先获取周围环境的若干特征,如基站id、Wifi指纹、地磁场、图像、Lidar点云等。接下来有两种处理方式,一种是把接收到的特征和事先采集的特征地图进行匹配,确定在特征地图中的位置;另一种是没有特征地图,通过对比前后帧的特征变化来进行位置姿态推算(即SLAM技术),达到类似航位推算的相对定位效果。显然,影响特征定位精度的直接因素是特征的数量、质量和区分度。</p><p>因此,采用信号指纹特征(如Wifi指纹)的定位方法因为指纹的稀疏性通常精度有限。基于环境感知特征的定位方法在采集的特征足够密集的情况下(如高线数Lidar,中高分辨率图像等)可以达到很高的精度,但是在实际应用中受环境影较大,当环境特征单一的时候(如天空、雪天)精度就会下降甚至无法定位。另外,特征地图匹配方法的定位精度也受到特征地图精度的限制,特征推算方法(如视觉SLAM)的定位误差会随距离累积,具有类似航位推算的发散效果。</p><p>综合上面的分析,可以筛选出具备高精度定位能力的技术选型。完整的高精定位方案首先需要至少一项高精度绝对定位技术,如几何定位中的GNSS定位,特征定位中的Lidar点云匹配等;其次,针对这些方案中的场景限制,辅助相对定位手段,如DR、SLAM技术等,进行补充。 </p><p><img src="/img/remote/1460000037748421" alt="" title=""></p><p>表2 高精定位的技术路线</p><p><strong>三、高精定位业务场景与解决方案</strong></p><p>上面从技术的角度分析了高精定位可能的实现路径,接下来我们从高德的具体业务场景出发,看一看这些技术在实际业务中是如何落地的。</p><p><strong>1. 实际业务场景需要什么样的高精定位能力</strong></p><p>出行场景是高德地图的核心业务场景。以驾车出行为例,传统的出行应用是以TBT(Turn-by-turn)导航为代表的道路级应用,它对于定位精度的要求在10m左右。更精细的导航体验,如车道级导航,需要将汽车定位到车道上,这就需要位置精度达到1米以内。对于智能驾驶场景,为了保证机器自动驾驶的安全性,对定位精度的要求更高,一般在道路横向的精度需要小于20厘米。</p><p><img src="/img/remote/1460000037748423" alt="" title=""></p><p>图3 驾车出行场景的高精应用</p><p>除了对精度的要求,不同业务场景对于高精定位能力还提出了其他维度的要求。</p><p><strong>1)可靠性(或完整性)</strong>:这主要用来衡量定位系统是不是有能力发现可能的错误,这对于依赖定位进行智能驾驶的应用尤其重要。比如,系统需要对当前的位置给出一个精度半径,当实际的位置精度小于这个半径时,系统就是可靠的。所以,对于可靠性要求比较高的应用,这个半径的估计通常是保守的。</p><p><strong>2)可用性</strong>:如果系统能够准确的判断当前的定位精度满足导航、自动驾驶等业务的要求,这时系统就是可用的。显然,可用性要求精度半径的估计不能太大,否则系统会频繁认为定位不可靠,导致相关的功能无法使用。</p><p><strong>3)算力</strong>:作为传统导航应用的升级,车道级导航对于算力的敏感度较高,通常要求满足目前的手机、车机导航的算力限制。智能驾驶根据不同的智能程度分级(SAE Level1~Level5),对算力的要求也不同。通常低等级智能驾驶搭载的传统汽车电气架构无法提供更多的算力资源,而高等级智能驾驶使用的集中计算单元可以提供的算力资源更丰富。</p><p>除此之外还有许多与实际应用相关的需求,比如输出定位结果的时间稳定性,定位能够覆盖的场景范围等。</p><p>总结一下,车道级导航需要的核心能力是识别当前车道,这一般要求定位精度小于1米,同时作为导航应用,需要在传统导航的基础上提高道路匹配的准确率。低等级智能驾驶(L3以下)要求车道识别和道路匹配(这主要是为了保证智能驾驶只在允许的道路范围内打开,如高速路)的准确率更高,更进一步要求横向位置精度达到20厘米,另外对系统的可靠性要求也更高。</p><p>上面的两类应用是我们目前最主要的业务场景,它们都要求在较低算力条件下实现高精定位功能。为了满足这些业务的需要,我们开发了轻量级的一体化融合定位引擎。</p><p><strong>2. 轻量级的一体化融合定位解决方案</strong></p><p>这里我们使用的定位技术主要包括:RTK-GNSS技术,图像语义匹配,IMU或汽车模型DR技术等。其中,图像语义匹配使用视觉设备(通常为车上装载的智能摄像头,如mobileye等)识别的车道线、地面标志等信息作为输入,与高精地图数据进行匹配定位,这一过程处理的语义要素有限,所以算力消耗不大。至于其他技术在传统导航定位中已经涉及,所以方案整体的算力消耗可以控制在和普通导航同一量级。</p><p><img src="/img/remote/1460000037748422" alt="" title=""></p><p>图4 一体化融合定位解决方案</p><p>上面的一体化方案框架可以接收全部或部分定位信号输入,同时提供道路级和车道级的定位结果,保证了在全场景下定位的连续性。在具体应用中落地时,方案的形式又有所不同。</p><p>对于智能驾驶应用,高可靠性要求系统具备更多的冗余信息来容错,因此通常需要RTK-GNSS、IMU、视觉语义等所有信息输入,在收到这些信息之后需要解决两个问题:1)如何判断输入信号哪些是可靠的,2)如何充分利用所有信息进行融合定位。</p><p>这里我们采用了基于多假设的粒子滤波作为高精融合定位的基本算法,并且设计实现了下面的算法改进:</p><ul><li>根据假设特征缩减粒子维度,减少计算量; </li><li>采用分层归一化解决微小系统误差导致的粒子退化问题; </li><li>基于上下文的后验置信度计算,解决输入信号置信度缺失或错误;</li><li>基于信号窗口的输入信号延迟和乱序处理;</li><li>利用高精卫星定位和高精地图数据辅助传感器校准,提升DR能力。</li></ul><p>目前该算法已经在一款L3级别智能驾驶车型上落地,正在进行大规模实验验证。</p><p>对于车道级导航应用,由于成本和使用条件的限制,通常无法获取所有输入信息。但是根据表2,我们至少需要RTK-GNSS或者视觉语义其中之一进行高精度绝对定位。在手机终端上,比较便捷的实现方案是升级手机GNSS芯片支持RTK差分来提升精度。在前面华为手机上首发的车道级导航应用就是综合了华为和千寻的相关技术和服务来实现高精度的绝对定位。</p><p>对于车机,可以将车上用于低等级智能驾驶功能的智能摄像头信息接入导航,直接升级车道级导航功能。在这个应用场景下的高精融合定位仍然是以上面的粒子滤波算法作为基础,但需要在算法和工程上灵活适配各种不同的输入信号类型和信号特征。</p><p>另外,针对导航场景的特点,一体化融合定位还根据车道级定位结果,比如汽车是不是在出口车道上,来辅助判断主辅路、高架桥等复杂路况条件下的偏航情况,提升用户导航的整体体验。</p><p>目前基于华为手机的车道级导航要发布上线,车机的车道级项目也正在实施落地,不久就会和大家见面。</p><p><strong>3. 面向复杂场景的多元紧耦合SLAM技术</strong></p><p>上面的轻量级融合定位方案可以解决室外大部分遮挡少、语义清晰场景的高精度定位问题,但是对于更复杂的场景,比如室内、停车场、城市复杂路口等,高精度GNSS可能无效,视觉语义信息也较少,这时候就需要融合更丰富的定位手段。在高等级智能驾驶(L4以上)中通常使用Lidar点云匹配,和/或高精度惯导DR来保证持续的高精度定位,但Lidar和高精惯导的成本很高,大规模应用受限。SLAM技术可以用低成本视觉传感器,持续推算高精度位置和姿态,可以作为低成本高精定位的有效手段。相比上面的轻量级方案,它的算力成本较高,但是在目前终端算力持续升级的大环境下,仍然具有很好的落地潜力。</p><p>我们的思路是用一套紧耦合的方案,尽可能充分利用各种低成本传感器:GNSS、IMU、视觉等提供的信息,依据这些信息在不同维度上的误差特征,建立最优化模型,实现最优的位置姿态估计。</p><p><img src="/img/remote/1460000037748424" alt="" title=""></p><p>图5 多元紧耦合SLAM算法框架</p><p>我们在公开数据集EuRoc和Kaist上对比了这一套多元紧耦合SLAM算法和目前流行的视觉-IMU融合算法、视觉-IMU-GNSS融合算法的效果,其位置精度提升1倍以上。接下来我们将在手机、车机终端上优化算法的算力消耗,并在未来面向全场景的高精度导航、智能驾驶应用中落地。</p><p><strong>四、总结与展望</strong></p><p>定位技术的发展由来已久。事实上,如果我们回到二三十年前甚至更早,那时候就已经产生了用于测绘的专业的高精定位技术,所以定位精度本身并不是问题。但是今天在人们出行方式深刻变革的背景下再提高精定位,我们面临的问题是怎么样构建用户用得起,又真正能够为出行提供便利的技术和应用。</p><p>所以,未来的高精定位首先需要扩展场景应用,从室外到室内,从驾车到步行,最终达到全场景覆盖。针对场景应用的特点,明确对高精定位在精度、可靠性、成本等各个维度上的需求。充分结合当前快速发展的传感、通讯、计算等领域技术,设计最佳的解决方案。可能的研发方向包括:</p><ul><li>更低成本的高精GNSS技术,如PPP-RTK技术等; </li><li>基于最新通信技术(如5G)的高精度定位; </li><li>基于最新感知技术(如低成本Lidar)的高精度定位; </li><li>对各种定位技术的更深度的融合方案(如IMU、视觉辅助RTK解算)。 </li></ul><p><img src="/img/remote/1460000037748425" alt="" title=""></p>
关于卫星定位,你想知道的一切
https://segmentfault.com/a/1190000037667090
2020-10-30T14:12:28+08:00
2020-10-30T14:12:28+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p>5G和北斗,是国之重器。北斗作为卫星定位系统,目前在国际上已处于领先地位,而且已经渗透到我们工作和生活的方方面面。本文将简要介绍卫星定位的原理和应用情况,方便大家对北斗、卫星定位有更多的了解。</p><p><strong>卫星定位的原理</strong></p><p>卫星定位系统的英文是Global Navigation Satellite System(GNSS),虽然直接翻译过来是导航卫星系统,但它真正提供的能力是定位,能定位后,导航就变得相对简单了。卫星定位的原理,是利用卫星播发时间信号,当设备接收到后,可以根据信号发射时间和本地时间,计算出信号传输时间,再结合光速获得卫星-设备距离。</p><p><img src="/img/remote/1460000037667094" alt="" title=""></p><p>有了多颗卫星的信号,可以列出一组方程,求解4个未知数:设备的三维坐标x/y/z,以及本地时间与GNSS系统的时间差。</p><p>式中的代表卫星j的三维坐标,这个坐标可以通过卫星星历计算获得。</p><p><img src="/img/remote/1460000037667093" alt="" title=""></p><p>星历是描述卫星运行轨道的一组参数,卫星轨道是一个椭圆,通过几个参数和时间,可以唯一确定卫星的准确位置。</p><p>星历的获取有两种方式,一种是卫星直接播发,这种方式的好处是定位过程不依赖卫星信号以外的任何输入,即使没有网络也可以定位成功,但问题是卫星链路带宽很小,要下载完整星历,需要30秒左右的时间,早期的手机和一些车载设备定位过程很慢,就是由于这个原因。</p><p>另一种方式,是通过互联网播发,这种方式叫A-GNSS,具体的传输协议叫SUPL(Secure User Plane Location),这种数据一般不对应用层透出,在手机上,操作系统会在底层定时请求SUPL数据,然后将获得的星历注入GNSS芯片。有了A-GNSS,设备就可以在秒级获得定位,不需要任何等待过程,目前所有的手机都支持这种方式。A-GNSS的服务提供商,主要是通信运营商,以及一些定位服务商,比如谷歌、千寻等。</p><p>卫星不间断的向地面广播信号,这个信号主要包括以下信息:</p><ul><li>卫星编号。用于从星历中查找卫星轨道,再结合时间戳获得当前卫星位置</li><li>当前时间戳。用于获得卫星位置,另一方面计算伪距。伪距是(本地时间-信号发射时间)*光速,之所以叫伪距,是因为本地时间与卫星时间不同步,所以这个距离并不是真正的设备-卫星距离。</li><li>星历数据。用于计算卫星位置。</li></ul><p>像其他所有的通信技术一样,这些信息也是以报文的形式发送的,以GPS为例,卫星会每隔6秒发出一个包,而这个包会分解为数据位-CA码序列-载波波形,通过天线发射到地面。地面设备持续锁定卫星,在解算时,计算每颗卫星当前时刻的时间戳(用最近一次收到的时间戳加上报文偏移量),然后进行位置解算。</p><p><img src="/img/remote/1460000037667096" alt="" title=""></p><p>载波的频率是1.5G左右,波长20厘米左右,比移动通信的波长稍长一些,所以信号的穿透性还是比较好的(波长越长,越容易绕开障碍物),可以穿透比较薄的墙壁或屋顶,所以在一些情况下即使无法直接看到天空,也是能定位的。但是卫星信号是从上往下,在室内很难穿越多层建筑。</p><p>卫星定位的另一个特点是可以解算出速度,其依据是多普勒频移原理(与交警用的测速仪原理一样)。当信号源与接收设备存在相对运动时,接收到的信号频率会发生变化。</p><p><img src="/img/remote/1460000037667095" alt="" title=""></p><p>频率变化量与相对速度存在如下公式:</p><p><img src="/img/remote/1460000037667097" alt="" title=""></p><p>其中,公式左边是频差和波长,v是设备运动速度(矢量),vj是卫星运动速度(矢量),1j是卫星的投影方向,dt'是本地设备的频漂速度。只要测量了4颗星的频差,就可以解出本地设备的运动速度(与设备姿态无关)。</p><p>除了定位和测速,定位卫星还可以完成全球授时(解算过程中获得本地钟差),这也是目前成本最低的高精度授时方法,比绝大部分设备自带的时钟都要准确。</p><p>一般而言,伪距测量值精度不如频率测量精度高(伪距定位精度在10米左右,而多普勒定速精度可以达到0.2米/秒以内,授时精度在20ns),原因是伪距测量容易受到多种路径误差影响(后面会介绍),而频率测量的干扰因素少很多。</p><p><strong>卫星定位发展历程</strong></p><p>最早的卫星定位系统,是美国在1960年代开发的子午仪系统,后续在70年代开发出了GPS定位系统,目前的GPS系统由24颗卫星构成。除了GPS,世界多国也开发出了自己的卫星定位系统,主要的有中国的北斗系统、欧盟的伽利略系统、俄罗斯的格洛纳兹系统,此外日本和印度在开发区域定位系统。</p><p><img src="/img/remote/1460000037667098" alt="" title=""></p><p>除了天上的卫星,各定位系统还需要地面站对卫星的运行进行监测,包括健康度、轨道参数(计算完成后要注入卫星实现全球播发)、信号质量等,另外还需要对卫星进行控制。</p><p>各种卫星定位系统使用的技术类似,大多采用中轨道卫星(MEO,卫星高度2万公里),少数采用了地球同步轨道(GEO,卫星高度4万公里)和地球倾斜同步轨道(IGSO)。同时,信号播发大多采用CDMA技术,实现在同一个频率上传输多颗卫星的信号。为了让地面设备能够较好的接收来自几万公里外的信号,信号的数据速率都比较低,比如GPS L1频段的数据传输速率只有50字节/s,根据香农定理,C=B*log2(1+S/N), 在频率带宽B固定的情况下,随着传输速率C的降低,接收端在信噪比(S/N)比较低的时候也可以解出正确的信号,有利于持续的锁定、跟踪卫星信号。</p><p>与其他定位系统相比,北斗的特点主要有:</p><ul><li>亚太地区覆盖好。北斗系统由3颗地球同步卫星、3颗地球倾斜轨道同步卫星和24颗中轨道卫星构成,与GPS相比,北斗有6颗星持续覆盖亚太地区,极大提升了亚太地区可见卫星的颗数,一方面提高定位成功率,另一方面也能提升精度(改善了GDOP,减少了误差)。</li><li>北斗的同步卫星可用来进行通信,地面设备可以将短报文发送到卫星(只用GEO卫星支持短报文)上,然后转发给目标终端,这种通信是免费的,但是需要专门的天线和设备(需要将信号发射到4万公里远的地方,普通手机肯定是不行的)。 </li></ul><p><img src="/img/remote/1460000037667100" alt="" title=""></p><p>多个卫星定位系统的信号同时被收到时,所有的卫星可以一同参与解算(每增加一个系统,只需增加一个新的参数,即这个系统相对于GPS系统的时间差),使得定位精度可以获得提升。目前手机上无法选择参与定位的星座或者卫星,所以我们无法指定只用北斗或者不用GPS定位。</p><p>我们对比了手机端GNSS定位时,使用不同系统的占比,可以看出GPS和格洛纳兹由于发展的比较早,在手机芯片侧的渗透率比较高,因此被使用的比例也最高,其次就是北斗。</p><p><img src="/img/remote/1460000037667099" alt="" title=""></p><p>按参与定位的卫星颗数统计,北斗排在第二位,仅次于GPS。 </p><p><img src="/img/remote/1460000037667101" alt="" title=""></p><p>因为各系统技术类似,其定位精度也是类似的,北斗也不例外,水平定位误差一般在10米以内。垂直定位精度一般会差一些,主要是由于卫星都分布在设备的一侧,垂直方向上的误差难以修正。</p><p><strong>卫星定位接收机构成</strong></p><p><img src="/img/remote/1460000037667102" alt="" title=""></p><p>卫星定位接收机的原理图如上图所示,主要的模块包括:</p><ol><li>天线</li></ol><p>用于接收卫星信号。由于卫星信号微弱,天线当然是越大越好,但是由于接收机需要移动,天线尺寸受到制约。天线的主要作用是放大信号和抑制多径,主要的类型有以下几种</p><p><img src="/img/remote/1460000037667103" alt="" title=""></p><p>左边的是比较常见的天线,内部是陶瓷天线,外部带磁铁,可以吸附在车顶;中间的是专业天线,旁边带扼流圈,可以抑制来自四周和地面反射的信号,只接收从天顶方向来的信号,这种天线的效果最好,一般用于专业研究和高精测绘;右侧是手机天线,长度只有几厘米,效果最差。</p><p>卫星信号的电磁波是圆极化的(传播时在垂直于传播方向的一个平面上波动),因此,采用圆极化天线(如平面的陶瓷天线)接收效果最好。但手机上天线尺寸太小,只能采用线极化天线,信号捕获能力大幅下降,再加上缺乏信号屏蔽(扼流圈),极易受到多径效应以及其他信号干扰。 </p><ol><li>射频前端</li></ol><p>这个模块主要是将原始信号进行下变频、功率放大以及滤波,提取真正有用的信号,便于解码处理。</p><ol><li>基带处理</li></ol><p>这个模块是对卫星信号进行解码,获得卫星报文。每颗卫星的信号需要一个单独的通道进行处理,如果有100颗卫星,2个频段,那可能需要200个通道才能有效处理这些信息。通道数越多,可以获得的卫星观测值也就越丰富,定位精度也就越高。</p><p> 解码的过程,分为搜索-锁定-跟踪三步,首先生成每颗卫星的伪码,然后与信号进行自相关操作,相关度达到一定程度就可以锁定卫星,然后进行码锁定、位同步、帧同步,最终提取出报文。这个过程要持续进行,因为多普勒效应,信号的频率会不断变化,所以本地生成的伪码也要不断变换频率去适配卫星的变化。一旦失去锁定,就会丢失信号,也就无法定位了。</p><ol><li>PVT解算</li></ol><p>PVT包括Position,Velocity和Time。这一步是真正进行定位的步骤,是利用基带解码获得的报文,提取出时间戳、星历等信息,代入公式进行计算,然后将计算结果输出给应用程序。</p><p><strong>定位误差来源与精度提升</strong></p><p>卫星定位虽然已经很准确了,但是在某些场景下,还是无法满足需求,比如,打车的时候定位点离车辆有一定距离、步导的时候难以区分方向甚至会定位到马路对面、静止的时候定位点总数飘来飘去、室内的时候定位点乱飘。这需要从卫星信号的发射、传输、接收过程来解释。</p><p><img src="/img/remote/1460000037667105" alt="" title=""></p><p>卫星信号从发射到被设备接收,需要经过大气层,其中,大气电离层有数千公里厚,这部分大气非常稀薄,但是存在大量被电离的电子,这部分电子会让电磁波变慢一点,从而产生延迟。在对流层,也会产生一定的延迟。在地表附近,由于各种建筑、山体、水面的影响,卫星信号可能被反射或折射(多径效应),产生延迟。</p><p>在卫星信号发射侧和接收侧,也有很多系统相关的误差,比如时钟偏差、处理延迟等,这些延迟加上传输延迟,使得卫星信号的传输时间,并不是准确的等于物理距离/光速,另一方面,卫星的星历也有误差,卫星位置和真实位置存在偏差,最终造成了定位结果产生偏差。</p><p>要提升定位精度,需要想办法消除这些误差,主要有以下几种方案。</p><p><strong>双频GNSS</strong></p><p>不同频率的电磁波通过电离层时会有不同的延迟,人们发现,对两个或多个频率的观测值进行线性组合,可以消除电离层误差,从而能提升精度。这就是双频GNSS定位的原理。小米8是业界第一款支持双频GNSS定位的手机,后续各大厂商均进行了跟进,一些高端手机均采用双频定位。消除电离层误差后,定位精度可以提升到5米以内。</p><p><strong>地基/星基增强</strong></p><p>星历误差、卫星时钟误差、甚至是电离层和对流层误差都是可以观测或建模的,一旦计算出了实时的误差值,就可以通过一个单独的通道进行播发,接收设备在定位过程中使用这些修正项,就可以提升定位精度。播发的通道一般有两种,一种是直接通过卫星播发,称为SBAS(Satellite-Based Augmentation System),好处是覆盖广,但设备需要增加额外的信号接收通道;另一种是地基增强,比如通过互联网,这需要设备具备联网能力。</p><p>这些增强方式对于精度提升是有限的,还是有很多误差项无法消除,比如电离层误差。</p><p><strong>高精定位-差分定位(RTK)</strong></p><p>RTK是Real - time kinematic的缩写,是一种差分定位。其原理是利用一个参考站提供基准观测值,然后用设备的观测值与基准站的观测值进行差分,差分后可以消掉星历误差、卫星钟差、电离层误差,再进行星间差分后可以进一步消除掉设备的钟差,最终可以算出设备相对基准站的相对坐标,如果基准站位置已知,就可以完成准确的绝对坐标,精度可以达到厘米级甚至毫米级。</p><p>RTK能提升精度的另一个原因是引入了载波相位观测,相比伪距观测值,载波相位观测值的误差更小。</p><p>使用RTK,需要在附近20km内有参考站(距离太远,电离层误差不一样,做差分无法完全消除误差),同时需要持续不断的获得参考站的观测数据(一般通过互联网传输,使用RTCM协议),因此相对普通的定位,RTK定位成本较高,但对于一些对精度要求很高的场景,比如车道级定位、自动驾驶等,是必不可少的。</p><p>RTK服务一般由专业服务商提供,如千寻、六分,这些服务商在全国范围内部署了数千个基准站,持续对订阅用户播发数据。</p><p><strong>高精定位-精密单点定位(PPP)</strong></p><p>RTK需要布设密集的参考站,有没有办法不依赖参考站?PPP(precise point positioning)就是一种方法,它的原理是对每一种误差进行准确建模,最终求解出卫星和设备之间的准确距离。为了确定准确的误差,PPP定位时需要不断的迭代内部参数,而且,一些卫星的误差只有当卫星位置变化后才能体现出来,所以PPP需要比较长的收敛时间,一般需要30分钟才能收敛到理想的精度,如何更快的收敛是目前学术界的一个研究热点。</p><p><strong>组合定位</strong></p><p>卫星定位的一个最大问题,就是丢失卫星信号后如何定位,这就需要其他定位方式来补充。组合定位是利用卫星信号和其他定位技术,比如惯性导航,来完成定位,二者相互配合。最简单的一个例子,就是卫星定位是有一个最高频率的,一般最多是10Hz,在两次定位之间,可用惯导来进行位置推算,获得更高频率的位置输出。而组合导航最重要的作用,是提升精度,比如,利用卡尔曼滤波方法,用惯导计算推算位置,用卫星定位提供观测量,对推算位置进行修正,这可以让定位结果更加平滑,而且可以对异常的卫星观测量进行过滤或降权。</p><p><strong>手机上的卫星定位</strong></p><p>在移动互联网出现以前,卫星定位终端是一个很专业的领域,只有测绘、军事等领域会应用这种技术,定位需要使用专用的接收机,比如Trimble、ublox等。随着智能手机将卫星定位芯片集成,卫星定位的应用得到爆发式增长,终端数量一下子提升到几十亿量级,也产生了海量的位置数据。</p><p>手机上的卫星定位与专业接收机,还是存在比较大的差异,主要体现在:</p><ul><li>手机受限于尺寸,天线比较小,对原始信号的捕获、锁定、去噪能力都比较差,造成接收到的信号质量天然不如专业接收机。</li><li>手机上芯片成本比较低,支持的通道数比较有限,一次定位能够解码的卫星数量和系统数量都比较少,主要是单频,少数是双频,没有三频。 </li><li>手机上对功耗、性能开销的要求比较高,不能花费大量资源在定位上,解算算法的复杂度比较低,效果也比较有限,精度比较差。</li></ul><p><strong>苹果手机</strong></p><p>苹果手机的定位能力是完全封闭的,对外只透出定位结果,外部基本无法拿到任何定位相关的原始观测量,比如卫星数量、类型等。好消息是,iPhone12终于开始支持北斗了。从苹果的API上,外界甚至无法区分定位结果到底是来自卫星定位还是网络定位(目前仅能通过速度的符号来判断,但苹果对此没有任何承诺)。所以,基于苹果手机,我们基本无法做出优化,苹果手机上高德地图的定位点都是iOS底层直接提供的。</p><p><strong>安卓手机</strong></p><p>安卓手机比苹果手机开放的多,在定位能力方面提供了一系列API:</p><ul><li>可以单独获取卫星定位结果或网络定位结果,也可以同时进行两种定位。 </li><li>提供了NMEA格式(一种卫星定位结果的规范化表达)的结果数据,可以获取每颗卫星的ID、类型、信号强度,以及xDOP等细粒度的误差描述。</li><li>提供了GnssStatus来描述每颗卫星的状态,内容比NMEA更全面。</li><li>提供了GnssMeasurement来描述原始观测量,包括伪距测量值、载波相位测量值、卫星锁定状态等。</li><li>提供了GnssClock描述本地时钟的状态。</li><li>提供了GnssNavigation透出最原始的未解码报文。</li></ul><p>有了这些信息,通过一些App就可以实时看到当前的卫星状态,例如Androits gps test, GPStest等</p><p><img src="/img/remote/1460000037667104" alt="" title=""></p><p>另外,我们还可以进行卫星定位的软解算,对卫星定位结果进行修正,甚至替代。我们主要尝试解决两类问题:</p><ul><li>定位不准:对卫星定位结果进行质量判断,识别其中的大误差点,优化精度,或者优化精度半径,使下游使用定位点的时候,能够差异化的处理。</li></ul><p><img src="/img/remote/1460000037667106" alt="" title=""></p><p>定位不准的原因,主要是来自卫星信号中含有误差,而影响最严重,也是最难抑制的,就是多径造成的影响。</p><p>另一类定位不准的问题,是系统将其他定位结果伪造为卫星定位结果。比如,将网络点冒充为卫星定位点。</p><ul><li>无法定位:系统不输出定位结果时,尝试进行软件解算。 </li></ul><p>无法定位最主要的原因,是信号接收条件不好,比如室内遮挡、高架遮挡、高楼遮挡。在开阔地带无法定位,一般是设备Bug,重启设备后一般都能解决。</p><p><strong>卫星定位未来展望</strong></p><p>随着移动用户量持续增长,以及物联网的大范围普及,卫星定位技术还会持续快速发展。</p><p>在卫星侧,将出现低轨定位卫星(距地面几百公里)。传统上的定位卫星由于要覆盖较大的地理范围,高度一般都比较高,运行在中轨轨道上。随着火箭发射技术的革命,卫星发射成本急剧下降,向太空发射大批量低成本卫星的方案成为可能。比如spacex已经发射了上千颗“星链”卫星。</p><p>低轨卫星进行定位有几个好处:</p><ul><li>距离近,信号更强,设备侧接收到的卫星信号更好。</li><li>可以传输更多的数据,比如各种修正数据。</li><li>位于电离层底部,电离层误差小。</li><li>卫星仰角变化快,PPP定位可以更快收敛。</li></ul><p>在设备侧,高精定位将大范围普及,华为P40是首个支持RTK的智能手机,可以做到0.5米的精度。高通也即将发布支持RTK的移动芯片,在2021年上半年,更多支持RTK的智能手机将会上市。</p><p>在应用侧,高精定位的应用场景会不断涌现,现在的一些典型应用场景包括:</p><ul><li>传统测绘 </li><li>精准农业,机械化自动化种植和收割</li><li>车道级导航和自动驾驶</li><li>共享单车的精准停放</li><li>无人机导航</li></ul><p><strong>参考资料</strong></p><p>北斗官方网站 <a href="https://link.segmentfault.com/?enc=2JeqWTgV5BMD5Wodp1XdRw%3D%3D.zphpS3DZAfU8wW66BzQMASfN%2F4egez2xB6Jv6I%2BL4xo%3D" rel="nofollow">http://www.beidou.gov.cn/</a></p><p>GPS官方网站 <a href="https://link.segmentfault.com/?enc=Gw7qUvB%2FAp7AgPxqjZOuiQ%3D%3D.hsrUnOCdUEofJSQaq8V7c38GvbT7UluD8Lhb3wUG8u0%3D" rel="nofollow">https://www.gps.gov/</a></p><p>伽利略官方网站 <a href="https://link.segmentfault.com/?enc=UeazVJneQkFwHPSB1UWulA%3D%3D.RQyoPWS0Nr65ffHBbYQCmu9lDpUEcLVBDT4uzu5AeaA%3D" rel="nofollow">https://www.gsa.europa.eu/</a></p><p><img src="/img/remote/1460000037667107" alt="" title=""></p>
机器学习在高德地图轨迹分类的探索和应用
https://segmentfault.com/a/1190000037499166
2020-10-16T14:59:33+08:00
2020-10-16T14:59:33+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>1.背景</strong></p><p>当我们打开导航,开车驶向目的地的过程中,有时候会碰到这样的问题:前方明明没有路,可能在施工封闭,可是导航仍然让我们往前开车,以至于我们无法顺利到达目的地。全国道路千千万,每天都有巨量的道路变得不可通行,那么如何动态的识别出哪些道路走不通了呢?</p><p><img src="/img/remote/1460000037499169" alt="" title=""></p><p>图中所示即为因封路事件导致的导航路线改变</p><p>道路不通往往导致该条道路汽车流量突然降低。监控汽车流量的变化是挖掘封路事件的重要指标。但是,目前业务中遇到的一个重要问题是,针对汽车无法通行的封路事件,行人、自行车可能都可以穿行,这些行人、自行车等的噪声流量大大削弱了道路流量变化。</p><p>因此,如果能够对行人、自行车、汽车的轨迹进行分类,就可以对道路流量的噪声进行过滤,仅仅关注汽车流量,流量随着封路事件的变化将更为显著,从而便于道路封闭的挖掘。本文主要针对非机动车、机动车分类探索轨迹分类问题。</p><p><strong>2.样本获取与标签制定</strong></p><p>由于轨迹数据缺少原始真值,我们将用户导航模式作为轨迹分类的伪标签。例如当时用户采用汽车导航,其轨迹对应的标签即为汽车。由于汽车导航数据远远多于非机动车,不同伪标签样本比例差异巨大,存在严重的样本不平衡问题。此外,用户导航模式与用户实际出行方式可能并不一致。比如有些用户可以根据汽车导航步行到达目的地。下文介绍的标签-概率混合贝叶斯模型将分析并试图解决上述2个问题。</p><p><strong>3.特征分析</strong></p><p>可以将轨迹分类相关特征划分为5类。分别是:</p><ul><li>轨迹概况特征集,包括轨迹耗时、轨迹长度、轨迹开始时间等。</li><li>速度相关特征集,包括最大速度、平均速度、速度标准差等。</li><li>时间相关特征集,包括道路末端等待红灯时间,调头时间,左转时间等。</li><li>行为相关特征集,包括调头行为,往复活动,左转减右转时间等。</li><li>用户画像特征集,包括用户职业、有车概率。</li></ul><p>下面以轨迹开始时间特征为例,解释该特征的物理意义。其概率密度函数如下所示(drv,汽车;byc,自行车;wlk,步行):</p><p><img src="/img/remote/1460000037499170" alt="" title=""></p><p>早晨(5:00~10:00)汽车轨迹概率较高,可能是早高峰导致。</p><p>午时(11:00~13:00)自行车轨迹概率较高,可能是由于外卖送餐。</p><p>傍晚(17:00~20:00)步行、自行车概率均较高,可能是由于下班散步以及外卖送餐。</p><p><strong>4.贝叶斯模型的概率分布视角</strong></p><p>选择基于贝叶斯分类器进行改进的原因如下:</p><ul><li>贝叶斯分类器属于生成模型,依赖于条件概率密度函数,具有明确的统计学意义。此外,如前面提到的条件概率图示,通过观察不同轨迹、标签的概率密度函数,能够逐个分析、说明特征的有效性。</li><li>贝叶斯分类器可以表示为:</li></ul><p><img src="/img/remote/1460000037499171" alt="" title=""></p><ul><li>通过增添、删减、改动特征的概率密度函数,可以快速完成贝叶斯分类器的迭代改进。并且相较于决策树,贝叶斯分类器不会对某一个特征的变动过于敏感。</li><li>贝叶斯分类器最终输出为概率值,可以作为置信度。</li></ul><p>4.1 标签-概率混合贝叶斯模型</p><p>当前轨迹分类问题为样本不平衡(Data Unbalanced)标签不准确(Noisy Label)问题。</p><p><img src="/img/remote/1460000037499173" alt="" title=""></p><p>Tanaka等人基于卷积神经网络提出了伪标签损失函数,通过交叉熵损失函数与伪标签损失函数的迭代优化完成了错误标签的修正[2]。受此启发,贝叶斯模型同样能够建立伪标签损失函数完成样本清洗。</p><p>我们基于贝叶斯分类器的分类结果,提出基于伪标签极大似然估计的伪标签损失函数,完成错误样本清洗,再迭代完成贝叶斯分类。该模型的迭代流程如下图所示。</p><p><img src="/img/remote/1460000037499172" alt="" title=""></p><p>标签-概率混合优化贝叶斯模型迭代流程。</p><p><img src="/img/remote/1460000037499174" alt="" title=""></p><p><img src="/img/remote/1460000037499175" alt="" title=""></p><p>4.2 联合概率密度函数计算</p><p>由于贝叶斯分类器假设各变量相互独立,因此不可避免的会对一些场景下的样本产生错误预测。例如,外卖骑手以及快递员应当被判定为非机动车。这种类型轨迹长度可能较长(超过10公里),最大速度适中(小于50公里每小时)。在假设行驶距离与最大速两个特征相互独立的情况下,容易错误地把外卖骑手以及快递员的行驶轨迹判定为汽车。</p><p><img src="/img/remote/1460000037499176" alt="" title=""></p><p>自行车轨迹行驶距离以及最大速度联合概率密度函数</p><p><img src="/img/remote/1460000037499178" alt="" title=""></p><p>汽车轨迹行驶距离以及最大速度联合概率密度函数</p><p>但是,行驶距离与最大速两个维度的特征并不相互独立。上图构建了针对汽车轨迹这两个维度的联合概率密度函数,可以发现,对汽车轨迹而言,行驶距离越长,最大速可能越高,当汽车行驶距离超过10公里时,其最大速度小于50公里每小时的可能性很低。因此,通过构建行驶距离与最大速度两个维度的联合概率密度函数,替换两个独立概率的相乘,可以帮助解决长距离非机动车轨迹被误判为汽车的问题。</p><p>4.3 基于贝叶斯的轨迹分类实验结果</p><p>评测团队抽样约100条数据并人工标记真值。最终模型分类效果如表所示。</p><p><img src="/img/remote/1460000037499177" alt="" title=""></p><p><strong>5.深度学习模型的图像编码视角</strong></p><p>由于轨迹数据缺少原始真值,我们将用户导航模式作为轨迹分类的伪标签。例如当时用户采用汽车导航,其轨迹对应的标签即为汽车。本次基于深度学习的探索不考虑标签噪声的问题。</p><p>5.1 轨迹信息的两种观察方式</p><p>深度学习的优势在于能够从原始数据中学习到有效信息,无需人工挖掘特征。针对轨迹数据的特点,存在两种观察轨迹的方式,分别是时间序列与空间分布。</p><p><img src="/img/remote/1460000037499179" alt="" title=""></p><p>时间序列:轨迹当中的GPS点数据随时间推移依次上传至数据库中。轨迹数据天然具备时间序列属性。因此,可以采用TCN或RNN构建模型,学习轨迹中的时间序列信息,完成轨迹分类。</p><p>空间分布:将轨迹数据绘制在地图中,则轨迹构成图片中的一条线。如果能够将速度、方向、等待时间编码到线的颜色当中,则能够采用CNN从轨迹图像中学习到有效信息[3]。</p><p><img src="/img/remote/1460000037499180" alt="" title=""></p><p>图左侧大概率为快递员轨迹,图右侧大概率为汽车轨迹。GPS点的空间分布能够为轨迹分类提供有效信息。因此,我们采用空间分布模式构建模型,探索基于深度学习的轨迹分类。</p><p>轨迹颜色编码:从GPS点中获取的主要信息为速度、方向、等待时长。将这3个维度的信息进行轨迹颜色编码有2种方式,分别是RGB编码与HSV编码。其中HSV即色相(Hue)、饱和度(Saturation)、亮度(Value)。</p><p><img src="/img/remote/1460000037499181" alt="" title=""></p><p>由于方向信息为0~360度的角度值,与HSV色彩空间种的色相H完全一致。因此,本文采用HSV色彩空间对速度、方向、等待时长进行编码,编码方式为速度:V,方向:H,时长:S。编码后将轨迹缩放为256×256的图片。对地图轨迹的编码结果如下图所示。</p><p><img src="/img/remote/1460000037499182" alt="" title=""></p><p>5.2 双流神经网络模型</p><p>基于编码生成的轨迹图片依然缺失一些重要信息,包括将轨迹缩放至256×256图片的缩放因子,以及GPS点所在的位置。可以将轨迹匹配结果中通过国道、省道、城市快速路等不同类型道路的比例构造出特征集表征GPS点所在的位置信息,加入缩放因子构造一个一维静态特征向量。</p><p><img src="/img/remote/1460000037499183" alt="" title=""></p><p>将卷积神经网络学习到的特征向量以及该一维特征向量合并,最终通过全连接层完成轨迹分类。最终卷积神经网络选择ResNet50结构。</p><p>5.3 基于深度学习的轨迹分类实验结果</p><p>评测团队抽样约100个样本,人工标记真值。</p><p><img src="/img/remote/1460000037499184" alt="" title=""></p><p>如上表所示,以人工标记标签为真值验证深度学习模型,深度学习模型能够取得有效的轨迹分类精度,但是最终分类效果弱于提出的贝叶斯模型。可能的原因有如下几点:</p><ul><li>ResNet50并不是学习轨迹图像的最优模型。</li><li>仅采用8月17日的样本训练模型,样本多样性不足。</li><li>所选择的特殊场景样本分布与深度学习中的训练集样本分布差异巨大。</li></ul><p><strong>6.小结</strong></p><p>轨迹分类对于准确及时地挖掘道路封闭事件具有重要意义。本文从给予概率密度分布的贝叶斯模型视角与基于轨迹点图像编码的深度学习视角分别探索了轨迹分类可能的技术方案。未来轨迹分类模型还可以从聚焦应用场景,优化应用以及拓展上游数据,优化特征两个方面进行改进。</p><p><strong>参考文献</strong></p><p>[1].Frénay B, Verleysen M. Classification in the presence of label noise: a survey[J]. IEEE transactions on neural networks and learning systems, 2013, 25(5): 845-869.</p><p>[2].Tanaka D, Ikami D, Yamasaki T, et al. Joint optimization framework for learning with noisy labels[C]//Proceedings of the IEEE Conference on Computer Vision and Pattern Recognition. 2018: 5552-5560.</p><p>[3].Liu Y, Wang X, You W. Non-intrusive Load Monitoring by Voltage-Current Trajectory Enabled Transfer Learning[J]. IEEE Transactions on Smart Grid, 2018.</p><p><strong>招聘</strong></p><p>阿里巴巴高德地图在线引擎和安全运维中心团队长期招聘机器学习算法、C++、Java 资深工程师/技术专家/高级专家,职位地点:北京。欢迎投递简历到 gdtech@alibaba-inc.com,邮件主题为:姓名-应聘团队-应聘方向。</p><p><img src="/img/remote/1460000037499185" alt="" title=""></p>
高德AR & 车道级导航技术演进与实践
https://segmentfault.com/a/1190000025153141
2020-09-28T14:01:09+08:00
2020-09-28T14:01:09+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p>2020云栖大会于9月17日-18日在线上举行,阿里巴巴高德地图携手合作伙伴精心组织了“智慧出行”专场,为大家分享高德地图在打造基于DT+AI和全面上云架构下的新一代出行生活服务平台过程中的思考和实践,并重点分享了「高精地图、高精算法、智能时空预测模型、自动驾驶、AR导航、车道级技术」等话题。</p><p>「高德技术」把讲师分享的主要内容整理成文并陆续发布出来,本文为第2篇。</p><p>阿里巴巴高级地图技术专家王前卫分享的话题是《AR&车道级导航技术演进与实践》。他为大家介绍了这些领域的核心技术、阶段成果及未来方向。</p><p>王前卫主要分享了三部分的内容:</p><ul><li>技术背景</li><li>当前进展</li><li>核心技术</li></ul><p>以往,高德通过全球卫星定位系统和数字化的电子地图为用户提供了一款道路级的导航服务,帮助用户方便快捷的到达目的地。现在通过引入更能理解环境,感知环境的视觉感知系统,以及通过引入更贴近现实,更精细的车道级数据,为用户精心打造了一款基于实景的车道级导航产品。它能为用户带来一种全新的导航体验,做到所见即所得。</p><p>这款产品包含哪些功能呢?AR导航通过视频增强技术实现了引导信息与现实世界更完美的贴合,为用户提供简单易懂的方向性指引。这样用户再也不会因为走到复杂路口而走错路;在距离路口较近,且用户行驶在非正确的车道上时,高德AR导航也能进行及时准确的变道提醒;在路口等红绿灯的时候,帮助用户实时观察周边环境,及时提醒用户,红灯已变绿灯,或者前车已经启动。AR导航功能一经上线就获得了用户的好评。</p><p><strong>核心技术揭秘</strong></p><p>高德AR导航需要具备三方面的能力:</p><ul><li>对周边环境实时的感知能力</li><li>车道级的高精定位能力</li><li>道路数据的精细化表达能力</li></ul><p><strong>环境实时感知</strong></p><p>在环境感知上,高德AR导航选择了成本较低但目前使用广泛的视觉技术,通过深度学习算法来感知周围的环境。其中最大的挑战在于如何设计一款轻量化的深度学习模型,既能在低算力的设备上实时运行,同时能保证较高识别精度。高德主要在三个方面进行了优化:</p><p>第一,在数据上,高德采用了海量多源大数据的融合和提取来保证训练样本的多样性和覆盖度;第二,在算法上,主要通过优化网络模型,特征共享等方法来保证算法的准确度;第三,在性能上,通过知识蒸馏,模型的量化算法,多任务的跟踪等方法来保证在低算力上能流畅运行。</p><p><img src="/img/remote/1460000025153144" alt="" title=""></p><p><strong>高精定位</strong></p><p>GPS定位精度不足,信号干扰大,特别是在遇到城市森林或者是天气不好的时候,会产生信号漂移、精度无法保证。目前精度不足已经成为大多数导航产品用户体验提升的瓶颈。基于此,高德提出了一种基于云端一体化视觉定位技术,基于端上图像,结合云端视图大数据,通过神经网络回归出设备绝对位姿。与此同时,通过端上识别车道线、道路边沿等标识,进行相对定位。最终结合时空一致性,进行云和端的融合,大幅提升了定位精度,将定位误差提升了一个数量级。</p><p><img src="/img/remote/1460000025153145" alt="" title=""></p><p>在没有网络的时候,如何使用高精度定位呢?基于成本较低的GPS、惯导和视觉传感器,高德设计研发了多源紧耦合SLAM(MT-SLAM)技术,通过算法的深度融合实现低成本高精度的位置姿态估计,为高精地图众包采集、车道级AR导航等业务提供很好的能力支撑。其相对位置精度30cm占比在82%以上。</p><p>位置姿态的提升,主要是根据GNSS不同信息的精度特性,采用分层紧耦合的融合框架,对信息充分利用,同时考虑运动约束,在减少优化维度的同时也提高精度;根据实际场景的精度特点,缩减内层优化对象,来提升优化效率;根据协方差应用场景,采用增量递归的方式提升协方差恢复效率。</p><p><img src="/img/remote/1460000025153147" alt="" title=""></p><p>在实际的用户场景中,定位遇到的环境是比较复杂的,在实现方式上,有的是基于手机RTK技术,有的是基于视觉传感技术。在不同场景下,有的需要标准精度定位,也有的需要高精度的定位能力。</p><p>如何降低成本,提升效率,以成本最小化的方式来实现一体化定位技术应用和落地呢。高德设计了一套高精/高标一体化融合定位系统。基于成熟的差分卫星定位或环境语义信息,构建轻量化的高精定位能力,并且和标精的导航定位结合形成一体化的融合定位引擎,满足自动驾驶、车道级导航等不同业务的需要。</p><p>一体化定位引擎,已具备完整的道路级标精、车道级高精定位能力,高精、标精定位结果独立输出又相互关联,为导航和自动驾驶联动提供便利,确保在全场景下的定位结果输出,保证定位连续性。</p><p><img src="/img/remote/1460000025153146" alt="" title=""></p><p><strong>道路数据的精细化表达</strong></p><p>现在有了车道级高精的定位,也有了对周边环境的实时感知,最后还需要考虑的是如何把标准精度数据表达得更加精细,如何通过建立道路模型,使引导信息的表达更加贴近现实场景。</p><p>大家首先能想到的是通过高精数据。高精数据的厘米级精度,确实能更真实的反映真实世界。然而,为了追求低成本,高覆盖,高德选择了利用标准数据精度,加上道路属性信息,通过算法来构建高精道路数据模型。</p><p><img src="/img/remote/1460000025153148" alt="" title=""></p><p>高德主要通过两个方面来进行模型构建,一是道路的模型,主要是利用SD的形点数据,结合道路的车道属性信息,通过对路口的切分、建模、还原等算法来建立道路的三维模型。二是实景中的引导信息展示,主要利用规划路径信息和引导信息,结合实时的道路图像特征提取信息,再加融合的高精定位,在不同的场景下来分别构建对应的引导线模型。</p><p>目前高德的这套模型构建算法,已在实际项目中落地。其车道级三维模型已经能够很好的反映真实世界,更加逼近现实世界;其AR导航的指示引导的铺路线和引导线,在绝大多数场景已经做了和实景道路的贴合。</p><p><img src="/img/remote/1460000025153149" alt="" title=""></p>
阿里巴巴高德地图首席科学家任小枫:高精算法推动高精地图落地
https://segmentfault.com/a/1190000024569551
2020-09-24T13:32:18+08:00
2020-09-24T13:32:18+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p>2020云栖大会于9月17日-18日在线上举行,阿里巴巴高德地图携手合作伙伴精心组织了“智慧出行”专场,为大家分享高德地图在打造基于<strong>DT+AI</strong>和<strong>全面上云架构</strong>下的<strong>新一代出行生活服务平台</strong>过程中的思考和实践,并重点分享了「高精地图、高精算法、智能时空预测模型、自动驾驶、AR导航、车道级技术」等话题。</p><p>「高德技术」把本场讲师分享的主要内容整理成文并陆续发布出来,本文为第1篇。</p><p>阿里巴巴高德地图首席科学家任小枫分享的话题是《高精算法推动高精地图落地》。任小枫从算法出发,介绍了高精地图制作和落地的挑战,以及高德如何打磨和突破关键技术,把高精地图做到业界领先。</p><p>去年云栖大会,任小枫给大家整体介绍了视觉技术在高德的应用,主要分享了常规地图和AR导航、视觉定位方面的工作。今年时间比较短(每位讲师只有12分钟的演讲时间),主要介绍高精算法方面的工作。</p><p>什么是高精地图?主要是给自动驾驶场景用的地图。它和我们平时开车时所用到的地图很不一样。一个关键就是要精准。高精地图需要有精准元素,精确位置,精细表示。例如下图中的杆子、车道线、行驶轨迹等都需要在高精地图中精确的表示出来。</p><p><img src="/img/remote/1460000024569554" alt="" title=""></p><p>自动驾驶要成功落地,高精地图是必须做成的事情。高精地图有很多用途:给自动驾驶用来定位;静态目标的建模“识别”;路径/行为规划。这些对于自动驾驶来说是非常重要的功能。</p><p><strong>高精地图落地的挑战主要在哪里?</strong></p><p><strong>精度!精度!精度!</strong>(重要的话说3遍)其他的挑战还有规模、成本、时效。</p><p>首先是精度。高德对高精地图制作的首要原则就是要准!要做到很高的精度,百米相对精度10厘米。就是在真实世界中,如果有两个元素在真实世界中相距100米,那他们的相对位置,跟真实世界比起来的误差必须在10厘米之内。这是一个非常高的目标。在这样一个高目标下,生产效率和成本就成了非常大的挑战,具体细节这里不展开解释了,目前高德已经做到了行业领先的水平。此外,还有鲜度和更新,最早期的时候以年为单位,后来到了月更新,周更新,日更新甚至更快,这样才能真正做到地图信息是准确有效的。</p><p>算法在解决高精地图面临的挑战中有很重要的作用。算法相关的工作主要有三部分:</p><ul><li>资料精度与对齐</li><li>识别和生产自动化</li><li>变化发现与更新</li></ul><p><strong>资料精度</strong></p><p>高精地图的首要原则是精准。高德从一开始就做了很大的投入,使用了很贵的采集车。用的高精度Riegl采集车,高精度激光雷度,它的测距精度能达到5mm,1M/sec;高精度的组合惯导;千寻基站解算…但即使这样大的投入和采集车配备,也并不意味着采集的数据资料就没问题了,还是会出现问题。比如轨迹,静止或运动的时候都会出错,出错的时候并不是很多,可能只有0.5%的比例,但出错的时候就会造成点云资料出问题,比如点云分层,工程师们需要做很多算法方面的工作去检测,在点云分层的时候把它修复。</p><p>经过一系列工作后,能在轨迹错误率上有明显的降低。单趟资料采集精度的问题解决后,很快就会遇到多躺资料对齐的问题。举例来说,一条路上很可能做多次采集,多次采集回来的点云,如果不做处理的话就会出现非常明显的重影,它是不贴在一起的,需要用算法的手段把它对齐。这也有很大的挑战,因为对精度的要求很高,在5cm以内。</p><p>各种场景的挑战很多,比如植被的影响。在不同季节的时候采集数据就会遇到这种情况,这些树和灌木会造成非常大的影响。同时在对齐的时候需要保持轨迹的刚性。因为原来采集回来的时候,轨迹的相对精度是很好的。在对齐过程中不能破坏和降低相对精度。而是要在原有基础上去提高相对精度,包括上下行的场景,如果是一条路,上下行不同两个方向和观测角度采集到的资料,以及桥上桥下,因为共视区域有限,对齐的挑战就更高了。</p><p><strong>资料对齐</strong></p><p>资料对齐怎么做?分为前端和后端两个部分。</p><p>前端有一个比较核心的算法就是<strong>点云匹配</strong>。比较常见的比如ICP或者GICP算法。但光是注意点云匹配是不够的,要把这个题解好,还需要解决很多其他的问题。比如稀疏点云特征提取,快速点云语义分割,快速车道线分割。这两块跟语义相关,在效率上是比较大的挑战。因为点云的资料数据量非常大,在计算时间上不能花太多时间。</p><p>前端做了很多工作,那对齐后端做什么呢,<strong>后端主要做大规模优化</strong>。因为轨迹的修整不能在单点做,需要很多条轨迹,甚至在整个城市的规模上一起去做调整。</p><p>高德也花了很多时间在做优化算法。比如做了一条基于样条曲线的稀疏优化算法。把它稀疏化以后就能达到百倍级的加速。能够比较好的解决在一个城市规模下的点云对齐问题。</p><p><strong>识别和生产自动化</strong></p><p>对齐问题解决后就是生产效率,即识别和生产自动化的问题。高精地图里元素很多,比如线性元素里就有车道线、护栏、路缘石、自然边界,还有所谓的OBJ,即地面标识、杆状物、交通标牌、桥、龙门架等等。这些都需要制作出来,采用自动化的方法,算法的方法就是非常重要的环节。它的输入有<strong>点云</strong>和<strong>图像识别</strong>。可以通过算法来生成HD地图元素。可以用算法来提高人工效率。</p><p>举几个有挑战性的例子。比如说下图的4种情况:</p><p><img src="/img/remote/1460000024569555" alt="" title=""></p><p>怎么解决? </p><p>输入主要是点云和图像。高德花了很长时间在优化模型能力和提高精度。包括:</p><ul><li>点云语义分割(多级随机聚合网络)</li><li>图像全景分割(检测/分割深度融合)</li><li>点云/图像融合(前融合+后融合)</li><li>传统算法辅助(e.g. 拟合,三维)</li><li>矢量化及建模(深度特征+图模型) </li></ul><p>高德在这些方法做到了很高的水准:高准确度召回>98%;部分实现跳点作业,达到>99.5%召回;部分实现免人工检查,达到>99.5准确率。</p><p><strong>变化发现与更新</strong></p><p>在地图更新方面,高德有两套方案都在做,应用于不同的场景。一种是用激光的方法,一种是用视觉的方法。</p><p><strong>激光的方法</strong>。因为要控制成本,所以使用了相对低成本的激光和相对低成本的组合惯导。输入的资料质量比较低,需要做很多事情去提高资料的精度。包括:</p><ul><li>紧耦合Lidar Slam/LIO</li><li>实时语义分割</li><li>定位地图:多重特征图层</li><li>In-the-loop重定位</li><li>协方差模型</li><li>全局位姿优化</li><li>定位图层更新</li></ul><p>上面这些都有相对比较成熟的解决方案。虽然输入资料差,但在更新场景下还是能达到很好的精度。</p><p><strong>视觉的方法</strong>。由极低成本消费级相机和极低成本消费级组合惯导来做,这中间有很多视觉的算法。包括:</p><ul><li>紧耦合Visual Slam/VIO</li><li>定位特征图层和语义图层</li><li>特征+语义重定位</li><li>全局位姿优化(融合VIO/重定位)</li><li>定位特征图层及更新</li></ul><p>现在已经做到15厘米;在严格评测的条件下已经是业界领先水平了。后续会继续提高精度。</p><p>视觉更新技术可以直接应用于构建地图。下面的图显示的是视觉建图和卫星影像的重叠。</p><p><img src="/img/remote/1460000024569557" alt="" title=""></p><p><strong>变化发现的问题,高精地图如何做到更高的精度和更高频率的更新?</strong></p><p>假设有一个极低成本的方案去采集图像,采集回来的肯定是一些质量很差的图像,在这些图像基础上要做对比,和真实世界的变化,比如下图里的两张图片里都有个电子眼,其实是同一个电子眼,但在图片上看着很不一样,需要用算法的手段来判断这是否为同一个电子眼。这里面就有很多图像算法的工作要做。包括:</p><p><img src="/img/remote/1460000024569556" alt="" title=""></p><p>这些方面高德都在做,也已经有了比较好的结果。这是高精地图制作过程中的一个必需的过程。这也是高德的特色所在,因为使用这些低成本的设备,能用现有的低成本的资料发现物理世界的变化。</p><p>高精地图是高德未来的一个重要方向。它的制作和落地是一个系统性的工程,除了算法以外,还有很多其他的关键工作要做。让我们一起努力。</p><p><img src="/img/remote/1460000024569558" alt="" title=""></p>
2020云栖大会智慧出行专场:聚焦高精地图/算法、智能模型、自动驾驶、AR导航
https://segmentfault.com/a/1190000024424174
2020-09-11T14:02:11+08:00
2020-09-11T14:02:11+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>2020云栖大会将于9月17日-18日在线举行,届时将通过官网为全球科技人带来前沿科技、技术产品、产业应用等领域的系列重要分享。 </p><p>阿里巴巴高德地图携手合作伙伴精心筹备了“智慧出行”专场。我们将为大家分享高德地图在打造基于DT+AI和全面上云架构下的新一代出行生活服务平台过程中的思考和实践,同时邀请了合作伙伴和业内资深专家分享行业动态、理论发展方向以及在业界和学术界的最新应用案例。 </p><p>大量前沿、创新性技术目前已经广泛应用于高德地图各项产品中,本论坛将着重讲述「高精地图、高精算法、智能时空预测模型、自动驾驶、AR导航、车道级技术」等话题,全面解析最新技术进展和场景化的实践经验,并与开发者们一起交流、讨论。</p><p><img src="/img/bVbOEvv" alt="image" title="image"></p><p>欢迎大家预约参加<strong>2020云栖大会智慧出行专场</strong>。</p><p>直播网址:<a href="https://link.segmentfault.com/?enc=AhEviMtNkiwz5o%2BQji%2BOVg%3D%3D.9vhuxJDjBapdRx9zObB0rGlF4rjwBd5jKjcafEzIKGRbIOxQy4ksHDvARxsvbuc9" rel="nofollow">https://yunqi.aliyun.com/2020...</a></p><p><strong>【讲师/议题摘要】</strong></p><p><strong>1.高精算法推动高精地图落地</strong></p><p><img src="https://pic2.zhimg.com/v2-7ebec263af5d4dc3ff13be79eb0819bd_b.png" alt="" title=""></p><p>分享嘉宾:任小枫 阿里巴巴高德地图首席科学家、研究员</p><p>话题摘要:高精地图是自动驾驶走向落地的重要和必要环节,也是高德的一大未来方向。高精地图的生产,在精度、鲜度、效率等方面都提出了全新挑战。要想把高精地图做好,必须有技术上的飞跃。本次分享会从算法出发,整体介绍高德如何打磨和突破关键技术,把高精地图做到业界领先。</p><p><strong>2.面向自动驾驶时代的“节奏式”交通控制</strong></p><p><img src="https://pic4.zhimg.com/v2-3a9f14ae057dbf833ecdf5d22ee97cd3_b.png" alt="" title=""></p><p>分享嘉宾:李萌 清华大学副教授、博导 </p><p>话题摘要:交通拥堵是困扰人类近百年的全球性难题,随着自动驾驶、车路协同等技术的发展,交通信号灯和道路设计也将迎来一场重大变革。“节奏式”控制是一种面向自动驾驶时代的全新交通控制模式,它从冲突根源出发释放交叉口乃至路网的巨大潜力,描绘出想象力丰富的未来交通画面。本次将主要分享这种全新交通控制模式的技术和应用成果。 </p><p><strong>3.混合时空图卷积网络:更精准的时空预测模型</strong></p><p><img src="https://pic1.zhimg.com/v2-c007af6c785f52c518ecdf0ef5f301d4_b.png" alt="" title=""></p><p>分享嘉宾:冀晨光 阿里巴巴高级算法专家 </p><p>话题摘要:交通预测是智慧出行行业的核心能力,为新一代路线规划、车辆调度等技术的落地提供了重要支撑。高德提出的时空图卷积算法,能巧妙利用海量用户的导航规划信息,“推导”出未来拥堵状况,显著提升预测准确度。本次分享会重点介绍这一业界领先的技术及其在高德业务中的应用。</p><p><strong>4.小鹏汽车的自动驾驶技术实践</strong></p><p><img src="https://pic3.zhimg.com/v2-16eccd14240fb9e7e7cccba1c092ac66_b.png" alt="" title=""></p><p>分享嘉宾:吴新宙 小鹏汽车自动驾驶副总裁</p><p>话题摘要:小鹏汽车自研的全闭环XPILOT自动驾驶辅助系统,在高速公路实现了准L3级自动驾驶场景表达,可根据导航和路况选择最优车道并自动变道。本次分享将会介绍小鹏汽车如何针对中国特色驾驶场景和用户习惯,融合高精地图,在“自动化”和“本土化”方面实现技术突破。 </p><p><strong>5.AR&车道级导航技术演进与实践</strong></p><p><img src="https://pic4.zhimg.com/v2-7d21845f49650b18fbec6945f4c26d93_b.png" alt="" title=""></p><p>分享嘉宾:王前卫 阿里巴巴高级地图技术专家</p><p>话题摘要:路径级导航已经把用户快速、准确引导到目的地。如何让用户在导航驾驶中更安全、更简单,做到所见即所得,是我们探索的下一个方向。AR和车道级导航就是利用摄像头将前方道路的真实场景实时捕捉下来,再结合深度学习、视觉定位、位姿融合、场景识别、车道级建模等技术进行融合计算,为用户提供一种全新的导航体验。本次将主要分享其核心技术、阶段成果及未来方向。</p><p>作为全球顶尖的科技盛会,云栖大会已经成为科技创新的风向标。今年是云栖大会首次在线举办,以“3+300”的内容场次设置,为全球科技人带来三场主论坛和展厅、100场分论坛和专场、100个城市站点线上线下联动和100大新品发布,涵盖云计算、人工智能、机器学习、量子计算、芯片、AIoT、组织协同、新零售、新金融、数字政府等领域。</p><p>大会聚集上千名科学家、技术大咖和国内外知名企业领军人,超过一万名开发者将以在线编程的方式参与到大会当中。同时在35个城市的百个站点设置线上线下联动的“百城汇”会场,与区域经济及产业进行深入互动。</p><p><img src="https://img2020.cnblogs.com/blog/1521790/202009/1521790-20200911135454252-208304414.jpg" alt="" title=""></p>
远程调试在Linux车机中的应用
https://segmentfault.com/a/1190000023802065
2020-08-28T11:32:46+08:00
2020-08-28T11:32:46+08:00
高德技术
https://segmentfault.com/u/amap_tech
3
<p><strong>导读</strong></p><p>在软件开发过程中,调试是必不可少的环节,嵌入式操作系统的调试与桌面操作系统的调试相比有很大差别,嵌入式系统的可视化调试能力比桌面操作系统要弱一点。对于导航这种业务场景比较复杂的程序开发,可视化调试环境能让我们业务场景开发事半功倍,也能快速定位导航业务与车机中其他模块交互出现的问题,提高开发过程中的调试效率。</p><p>远程调试是真机调试中最便捷的一种,开发者只需借用在PC端强大的调试器就能完成业务场景的调试。</p><p><strong>背景</strong></p><p>Thrift是一种接口描述语言和二进制通讯协议,它被用来定义和创建跨语言的服务,是一种RPC(远程过程调用)通信框架,由Facebook为“大规模跨语言服务开发”。在车机系统中,各模块之间也可以使用Thrift通信框架进行通信。导航作为一个单独的为进程提供服务的模块,只提供导航相关的业务以及地图渲染的能力,导航的HMI界面是车机系统中统一的操作界面,系统HMI界面与导航之间的交互接口则是通过已经定义好的接口描述语言(IDL),使用自动化工具生成本地可调用的接口,然后使用Thrift框架传输完成系统HMI与导航之间的通信。</p><p> <img src="/img/remote/1460000023802070" alt="" title=""></p><p><strong>调试手段</strong></p><p>为了开发过程中调试方便,我们在PC上做了一套模拟器,能在PC上进行地图渲染。还实现了一套在PC上使用的系统HMI模拟命令发送工具,模拟工具是作为客户端连接导航提供的服务,这样能在PC端模拟发送命令,帮助导航简单业务的开发,但这种方式存在着以下<strong>弊端</strong>:</p><ul><li>模拟命令工具,只能模拟简单的业务场景,有多个交互的场景无法模拟。</li><li>无法操作地图HMI,也看不到HMI界面显示以及过程中的反馈。</li><li>无法滚动地图,后面接了Win32上面的鼠标事件,能用鼠标实现滚动,但这种方式与车机中滚动流程不一致。 </li><li>PC端无法使用车机中的设备,如导航过程中没有导航音,无法使用USB等。 </li><li>PC端拿不到车机中的数据,比如车身数据、GPS信号等。</li></ul><p><strong>调试方案优化</strong></p><p>针对当前调试手段存在的以上问题。我们对调试方案进行了优化,我们可以借助车机中系统HMI来与导航进行交互。实现了使用车机环境中的信号对PC端导航业务场景进行调试。主要有以下几点功能:</p><p><strong>1.PC端模拟器接收车机发来的信号</strong></p><p>在该项目中,导航的相关业务都是作为服务端向车机中其他模块提供服务,在车机系统中,系统HMI连接导航服务的地址是固定的,我们在车机中开发了一个代理--Sandwich,主要作用是启动导航服务,这个导航服务并不实现真正的导航业务,而是启动了一个空服务,让车机中其他模块能成功建立连接,同时Sandwich作为客户端连接PC端模拟器提供的导航服务,PC端的导航服务真正实现导航业务,Sandwich负责接收车机发送过来的业务请求,并将请求转发给PC端模拟器,这样PC端模拟器就能接收到车机中的信号,收到的业务请求并做处理再将处理结果通过Thrift反馈到车机端。</p><p>这个流程我们打通了车机中信号发送到PC端模拟器,并可以将处理完的数据反馈给车机端。</p><p> <img src="/img/remote/1460000023802069" alt="" title=""> </p><p><strong>2.PC端模拟器向车机发送信号</strong></p><p>导航也需要连接车机中其他模块提供的服务,如,获取车身数据、获取GPS定位信号,将导航语音数据发送到车机语音播放模块等。</p><p>PC端模拟器需要作为客户端来连接车机中的服务,真正连接的是车机中Sandwich提供的服务,Sandwich作为客户端连接车机中其他模块的服务,比如Sandwich连接Sound模块,GPS模块,CarData模块等。PC端模拟器需要使用车机设备播放导航音,需要将播放内容发送给Sandwich,Sandwich收到播放内容后,再发送给车机中的Sound模块,导航音就能播放了。PC端连接车机中其他模块的工作原理也是一样。</p><p> <img src="/img/remote/1460000023802068" alt="" title=""></p><p><strong>3. 将PC端模拟器中显示的地图投射到车机端显示</strong></p><p>实现了以上两步,一个使用车机信号调试PC端导航程序的环境基本完成了。已经能实现车机信号与PC进行双向接收,但是此时导航的渲染能力还是停留在PC端,车机中还只是显示了一个系统HMI界面,无法看到导航地图展现的效果,这样就会带来一个问题,一些需要强依赖地图的操作可能就无法精准操作,比如点击地图上某个POI等。此时需要将PC端的展现同步到车机侧。</p><p>要实现这一目的,一般我们有两种方法:</p><ul><li><strong>车机与PC同步渲染</strong></li></ul><p>车机中的导航正常运行,当导航接收到系统模块业务请求时,先是车机导航进行处理,处理完毕后将信号转发到PC端处理,这种方案两端导航业务逻辑并行运行,复杂的业务场景下,两端会同时跟车机进行交互,此时可能会产生互斥,会有两端逻辑不同步的场景,达不到预期效果。</p><ul><li><strong>将车机中渲染的数据投射到车机端</strong></li></ul><p>在这里我们可以将PC上程序每渲染一帧地图则将结果传到车机端,由车机端Sandwich负责接收,当Sandwich接收到一帧地图像素数据后,负责将此帧数据渲染到车机屏幕上,此时车机中呈现的效果跟PC端一致。在该项目中我们采用了这一方案,这种方案中,真正的导航业务逻辑是来自PC端,车机中只是一个转发过程,所以不会存在第一种方案中的问题。</p><p> <img src="/img/remote/1460000023802072" alt="" title=""></p><p>但在某些特定的环境下,导航描画会很频繁,发送给车机的数据也会很多,频繁的数据发送可能会带来一定的性能开销,表现上可能会出现延迟。这里可以使用降低图像质量来减少图像数据,例如,可以使用16位或者8位BMP来传输,还可以压缩传输,这样1920*720分辨率图像传输大小能控制在30-50k左右。</p><p><strong>小结</strong></p><p>基于车机系统中Thrift通信框架,实现的这套远程调试方案,实质是在车机中使用Sandwich程序接管车机系统中与导航有交互的全部接口处理,通过RPC通信转发,实现了使用真实车机信号调试导航的目的。有了这套调试环境,我们甚至可以直接在真车上边路测边调试,跟以前的路测拿Log回来分析、重现相比,整个调试过程,简单,便捷,直观。大大提高了开发效率。</p><p>基于RPC通信的特性,我们还可以对调试方案再进一步优化,可以加入多客户端调试功能,使用同一台车机环境,不同的模块负责人可以同时进行复杂业务场景的联合调试。</p><p> <img src="/img/remote/1460000023802071" alt="" title=""></p>
揭秘!文字识别在高德地图数据生产中的演进
https://segmentfault.com/a/1190000023633391
2020-08-14T15:54:40+08:00
2020-08-14T15:54:40+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>导读</strong>:丰富准确的地图数据大大提升了我们在使用高德地图出行的体验。相比于传统的地图数据采集和制作,高德地图大量采用了图像识别技术来进行数据的自动化生产,而其中场景文字识别技术占据了重要位置。商家招牌上的艺术字、LOGO五花八门,文字背景复杂或被遮挡,拍摄的图像质量差,如此复杂的场景下,如何解决文字识别技术全、准、快的问题?本文分享文字识别技术在高德地图数据生产中的演进与实践,介绍了文字识别自研算法的主要发展历程和框架,以及未来的发展和挑战。</p><p><strong>一 背景</strong></p><p>作为一个DAU过亿的国民级软件,高德地图每天为用户提供海量的查询、定位和导航服务。地图数据的丰富性和准确性决定了用户体验。传统的地图数据的采集和制作过程,是在数据采集设备实地采集的基础上,再对采集资料进行人工编辑和上线。这样的模式下,数据更新慢、加工成本高。为解决这一问题,高德地图采用图像识别技术从采集资料中直接识别地图数据的各项要素,实现用机器代替人工进行数据的自动化生产。通过对现实世界高频的数据采集,运用图像算法能力,在海量的采集图片库中自动检测识别出各项地图要素的内容和位置,构建出实时更新的基础地图数据。而基础地图数据中最为重要的是POI(Point of Interest)和道路数据,这两种数据可以构建出高德地图的底图,从而承载用户的行为与商家的动态数据。</p><p>图像识别能力决定了数据自动化生产的效率,其中场景文字识别技术占据了重要位置。不同采集设备的图像信息都需要通过场景文字识别(Scene Text Recognition,STR)获得文字信息。这要求我们致力于解决场景文字识别技术全、准、快的问题。在POI业务场景中,识别算法不仅需要尽可能多的识别街边新开商铺的文字信息, 还需要从中找出拥有99%以上准确率的识别结果,从而为POI名称的自动化生成铺平道路;在道路自动化场景中,识别算法需要发现道路标志牌上细微的变化,日处理海量回传数据,从而及时更新道路的限速、方向等信息。与此同时,由于采集来源和采集环境的复杂性,高德场景文字识别算法面对的图像状况往往复杂的多。主要表现为:</p><ul><li>文字语言、字体、排版丰富:商家招牌上的艺术字体,LOGO五花八门,排版形式各式各样。</li><li>文字背景复杂:文字出现的背景复杂,可能有较大的遮挡,复杂的光照与干扰。</li><li>图像来源多样:图像采集自低成本的众包设备,成像设备参数不一,拍摄质量差。图像往往存在倾斜、失焦、抖动等问题。</li></ul><p>由于算法的识别难度和识别需求的复杂性,已有的文本识别技术不能满足高德高速发展的业务需要,因此高德自研了场景文字识别算法,并迭代多年,为多个产品提供识别能力。</p><p><strong>二 文字识别技术演进与实践</strong></p><p><strong>STR算法发展主要历程</strong> <br>场景文字识别(STR)的发展大致可以分为两个阶段,以2012年为分水岭,分别是传统图像算法阶段和深度学习算法阶段。</p><p><strong>传统图像算法</strong> <br>2012年之前,文字识别的主流算法都依赖于传统图像处理技术和统计机器学习方法实现,传统的文字识别方法可以分为图像预处理、文字识别、后处理三个阶段:</p><ul><li>图像预处理:完成文字区域定位,文字矫正,字符切割等处理,核心技术包括连通域分析,MSER,仿射变换,图像二值化,投影分析等;</li><li>文字识别:对切割出的文字进行识别,一般采用提取人工设计特征(如HOG特征等)或者CNN提取特征,再通过机器学习分类器(如SVM等)进行识别;</li><li>后处理:利用规则,语言模型等对识别结果进行矫正。 </li></ul><p>传统的文字识别方法,在简单的场景下能达到不错的效果,但是不同场景下都需要独立设计各个模块的参数,工作繁琐,遇到复杂的场景,难以设计出泛化性能好的模型。</p><p><strong>深度学习算法</strong> <br>2012年之后,随着深度学习在计算机视觉领域应用的不断扩大,文字识别逐渐抛弃了原有方法,过渡到深度学习算法方案。在深度学习时代,文字识别框架也逐渐简化,目前主流的方案主要有两种,一种是文本行检测与文字识别的两阶段方案,另一种是端到端的文字识别方案。</p><p>1)两阶段文字识别方案 <br>主要思路是先定位文本行位置,然后再对已经定位的文本行内容进行识别。文本行检测从方法角度主要分为基于文本框回归的方法,基于分割或实例分割的方法,以及基于回归、分割混合的方法,从检测能力上也由开始的多向矩形框发展到多边形文本,现在的热点在于解决任意形状的文本行检测问题。文本识别从单字检测识别发展到文本序列识别,目前序列识别主要又分为基于CTC的方法[4]和基于Attention的方法。</p><p>2)端到端文字识别方案 <br>通过一个模型同时完成文本行检测和文本识别的任务,既可以提高文本识别的实时性,同时因为两个任务在同一个模型中联合训练,两部分任务可以互相促进效果。</p><p><strong>文字识别框架</strong> <br>高德文字识别技术经过多年的发展,已经有过几次大的升级。从最开始的基于FCN分割、单字检测识别的方案,逐渐演进到现有基于实例分割的检测,再进行序列、单字检测识别结合的方案。与学术界不同,我们没有采用End-to-End的识别框架,是由于业务的现实需求所决定的。End-to-End框架往往需要足够多高质量的文本行及其识别结果的标注数据,但是这一标注的成本是极为高昂的,而合成的虚拟数据并不足以替代真实数据。因此将文本的检测与识别拆分开来,有利于分别优化两个不同的模型。</p><p>如下图所示,目前高德采用的算法框架由文本行检测、单字检测识别、序列识别三大模块构成。文本行检测模块负责检测出文字区域,并预测出文字的掩模用于解决文本的竖直、畸变、弯曲等失真问题,序列识别模块则负责在检测出的文字区域中,识别出相应的文字,对于艺术文本、特殊排列等序列识别模型效果较差的场景,使用单字检测识别模型进行补充。 </p><p><img src="/img/remote/1460000023633397" alt="" title=""></p><p>文字识别框架</p><p><strong>文本行检测</strong> <br>自然场景中的文字区域通常是多变且不规则的,文本的尺度大小各异,成像的角度和成像的质量往往不受控制。同时不同采集来源的图像中文本的尺度变化较大,模糊遮挡的情况也各不相同。我们根据实验,决定在两阶段的实例分割模型的基础上,针对实际问题进行了优化。</p><p>文本行检测可同时预测文字区域分割结果及文字行位置信息,通过集成DCN来获取不同方向的文本的特征信息,增大mask分支的feature大小并集成ASPP模块,提升文字区域分割的精度。并通过文本的分割结果生成最小外接凸包用于后续的识别计算。在训练过程中,使用online的数据增广方法,在训练过程中对数据进行旋转、翻转、mixup等,有效的提高了模型的泛化能力。具体检测效果如下所示: </p><p><img src="/img/remote/1460000023633396" alt="" title=""></p><p>检测结果示例</p><p>目前场景文本检测能力已经广泛应用于高德POI、道路等多个产品中,为了验证模型能力,分别在ICDAR2013(2018年3月)、ICDAR2017-MLT(2018年10月)、ICDAR2019-ReCTS公开数据集中进行验证,并取得了优异的成绩。 </p><p><img src="/img/remote/1460000023633398" alt="" title=""></p><p>文本行检测竞赛成绩</p><p><strong>文字识别</strong> <br>根据背景的描述,POI和道路数据自动化生产对于文字识别的结果有两方面的需求,一方面是希望文本行内容尽可能完整识别,另外一方面对于算法给出的结果能区分出极高准确率的部分(准确率大于99%)。不同于一般文字识别评测以单字为维度,我们在业务使用中,更关注于整个文本行的识别结果,因此我们定义了符合业务使用需求的文字识别评价标准:</p><ul><li>文本行识别全对率:表示文字识别正确且读序正确的文本行在所有文本行的占比。</li><li>文本行识别高置信占比:表示识别结果中的高置信度部分(准确率大于99%)在所有文本行的占比。</li></ul><p>文本行识别全对率主要评价文字识别在POI名称,道路名称的整体识别能力,文本行识别高置信占比主要评价算法对于拆分出识别高准确率部分的能力,这两种能力与我们的业务需求紧密相关。为了满足业务场景对文字识别的需求,我们针对目前主流的文字识别算法进行了调研和选型。</p><p>文字识别发展到现在主要有两种方法,分别是单字检测识别和序列识别。单字检测识别的训练样本组织和模型训练相对容易,不被文字排版的顺序影响。缺点在某些"上下结构","左右结构"的汉字容易检测识别错误。相比之下序列识别包含更多的上下文信息,而且不需要定位单字精确的位置,减小因为汉字结构导致的识别损失。但是现实场景文本的排版复杂,"从上到下","从左到右"排版会导致序列识别效果不稳定。结合单字检测识别和序列识别各自的优缺点,采用互补的方式提高文字识别的准确率。 </p><p><img src="/img/remote/1460000023633399" alt="" title=""></p><p>单字检测识别和序列识别结果融合</p><p>1)单字检测识别 <br>单字检测采用Faster R-CNN的方法,检测效果满足业务场景需求。单字识别采用SENet结构,字符类别支持超过7000个中英文字符和数字。在单字识别模型中参考identity mapping的设计和MobileNetV2的结构,对Skip Connections和激活函数进行了优化,并在训练过程中也加入随机样本变换,大幅提升文字识别的能力。在2019年4月,为了验证在文字识别的算法能力,我们在ICDAR2019-ReCTS文字识别竞赛中获得第二名的成绩(准确率与第一名相差0.09%)。 </p><p><img src="/img/remote/1460000023633400" alt="" title=""></p><p>单字检测识别效果图</p><p>2)文本序列识别 <br>近年来,主流的文本序列识别算法如Aster、DTRT等,可以分解为文字区域纠正,文字区域特征提取、序列化编码图像特征和文字特征解码四个子任务。文字区域纠正和文字区域特征提取将变形的文本行纠正为水平文本行并提取特征,降低了后续识别算法的识别难度。序列化编码图像特征和文字特征解码(Encoder-Decoder的结构)能在利用图像的纹理特征进行文字识别的同时,引入较强的语义信息,并利用这种上下文的语义信息来补全识别结果。 </p><p><img src="/img/remote/1460000023633401" alt="" title=""></p><p>通用序列识别结构</p><p>在实际应用中,由于被识别的目标主要以自然场景的短中文本为主,场景文本的几何畸变、扭曲、模糊程度极为严重。同时希望在一个模型中识别多个方向的文本,因此我们采用的是的TPS-Inception-BiLSTM-Attention结构来进行序列识别。主要结构如下所示: </p><p><img src="/img/remote/1460000023633403" alt="" title=""></p><p>文本序列识别模型</p><p>对于被检测到的文本行,基于角点进行透视变换,再使用TPS变换获得水平、竖直方向的文本,按比例缩放长边到指定大小,并以灰色为背景padding为方形图像。这一预处理方式既保持了输入图像语义的完整,同时在训练和测试阶段,图像可以在方形范围内自由的旋转平移,能够有效的提高弯曲、畸变文本的识别性能。将预处理完成的图像输入CNN中提取图像特征。再使用BiLSTM编码成序列特征,并使用Attention依次解码获得预测结果。如下图所示,这一模型通过注意力机制在不同解码阶段赋予图像特征不同的权重,从而隐式表达预测字符与特征的对齐关系,实现在一个模型中同时预测多个方向文本。文本序列识别模型目前已覆盖英文、中文一级字库和常用的繁体字字库,对于艺术文本、模糊文本具有较好的识别性能。 </p><p><img src="/img/remote/1460000023633402" alt="" title=""></p><p>序列识别效果</p><p>3)样本挖掘&合成 <br>在地图数据生产业务中经常会在道路标志牌中发现一些生僻的地点名称或者在POI牌匾中发现一些不常见的字甚至是繁体字,因此在文字识别效果优化中,除了对于模型的优化外,合理补充缺字、少字的样本也是非常重要的环节。为了补充缺字、少字的样本,我们从真实样本挖掘和人工样本合成两个方向入手,一方面结合我们业务的特点,通过数据库中已经完成制作的包含生僻字的名称,反向挖掘出可能出现生僻字的图像进行人工标注,另一方面,我们利用图像渲染技术人工合成文字样本。实际使用中,将真实样本和人工合成样本混合使用,大幅提升文字识别能力。 </p><p><img src="/img/remote/1460000023633404" alt="" title=""></p><p>样本挖掘和合成方案</p><p><strong>文字识别技术小结</strong> <br>高德文字识别算法通过对算法结构的打磨,和多识别结果的融合,满足不同使用场景的现实需要。同时以文字识别为代表的计算机视觉技术,已广泛应用于高德数据自动化生产的各个角落,在部分采集场景中,机器已完全代替人工进行数据的自动化生产。POI数据中超过70%的数据都是由机器自动化生成上线,超过90%的道路信息数据通过自动化更新。数据工艺人员的技能极大简化,大幅节约了培训成本和支出开销。</p><p><strong>三 未来发展和挑战</strong> <br>目前高德主要依赖深度学习的方式解决场景文字的识别问题,相对国外地图数据,国内汉字的基数大,文字结构复杂导致对数据多样性的要求更高,数据不足成为主要痛点。另外,图像的模糊问题往往会影响自动化识别的性能和数据的制作效率,如何识别模糊和对模糊的处理也是高德的研究课题之一。我们分别从数据,模型设计层面阐述如何解决数据不足和模糊识别的问题,以及如何进一步提高文字识别能力。</p><p><strong>数据层面</strong> <br>数据问题很重要,在没有足够的人力物力标注的情况下,如何自动扩充数据是图像的一个通用研究课题。其中一个思路是通过数据增广的方式扩充数据样本。Google DeepMind在CVPR 2019提出AutoAugment的方法, 主要通过用强化学习的方法寻找最佳的数据增广策略。另一种数据扩充的解决办法是数据合成,例如阿里巴巴达摩院的SwapText利用风格迁移的方式完成数据生成。</p><p><strong>模型层面</strong> <br><strong>模糊文本的识别</strong> <br>模糊通常造成场景识别文本未检测和无法识别的问题。在学术界超分辨率是解决模糊问题的主要方式之一,TextSR通过SRGAN对文本超分的方式,还原高清文本图像,解决模糊识别的问题。对比TextSR,首尔大学和马萨诸塞大学在Better to Follow文中提出通过GAN对特征的超分辨率方式,没有直接生成新的图像而是将超分辨率网络集成在检测网络中,在效果接近的同时,由于其采用End-to-End的模式,计算效率大幅提高。</p><p><strong>文字语义理解</strong> <br>通常人在理解复杂文字时会参考一定的语义先验信息,近年来随着NLP(Natural Language Processing)技术的发展,使得计算机也拥有获得语义信息的能力。参考人理解复杂文字的方式,如何利用语义的先验信息和图像的关系提高文字识别能力是一个值得研究的课题。例如SEED在CVPR 2020提出将语言模型添加到识别模型中,通过图像特征和语义特征综合判断提高文字识别能力。</p><p><strong>其他发展</strong> <br>除此之外,从云到端也是模型发展的一个趋势,端上化的优势在于节约资源,主要体现在节约上传至云端的流量开销和云端服务器的计算压力。在端上化设计上,针对OCR算法的研究和优化,探索高精度、轻量级的检测和识别框架,压缩后模型的大小和速度满足端上部署的需要,也是我们今后需要研究的一个课题。</p><hr><p><strong>温馨提示</strong>:由阿里巴巴高德地图发起,阿里云天池平台作为支撑平台的AMAP-TECH算法大赛初赛已经开启,赛题为基于车载视频图像的动态路况分析,权威评委、丰厚奖金、终面通道、荣誉证书,欢迎同学们踊跃参与,一起用技术帮助更多人美好出行!</p><p>初赛时间:7月8日-8月31日(UTC+8)。</p><p>更多比赛详情:<a href="https://link.segmentfault.com/?enc=RBhC%2Bsl8m7uFhefFUhc0fw%3D%3D.agBOzUvnK5BoosFCIM8lVZX6qvpaLNacIV385w1m0pqCZLDGCLCljLSlrtqrwGc2Y%2BWZR1QowKQ27nihqxdBNkbqBzI3ZpDD3kGZbfNrgME%3D" rel="nofollow">https://tianchi.aliyun.com/competition/entrance/531809/introduction</a></p><p><img src="/img/bVby2A6" alt="image" title="image"></p>
高德SD地图数据生产自动化技术的路线与实践(道路篇)
https://segmentfault.com/a/1190000022737236
2020-05-25T13:53:23+08:00
2020-05-25T13:53:23+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>一、背景及现状</strong></p>
<p>近些年,国内道路交通及相关设施的基础建设日新月异。广大用户日常出行需求旺盛,对所使用到的电子地图产品的数据质量和现势性提出了更高的要求。传统的地图数据采集和生产过程,即通过采集设备实地采集后对采集资料进行人工处理的模式,其数据更新慢、加工成本高等问题矛盾日益突显。</p>
<p>高德地图凭借视觉AI和大数据技术优势引领地图数据产业变革,通过图像AI技术从采集资料中直接识别提取各类数据要素,为实现机器代替人的作业模式提供最坚实的技术基础。</p>
<p>高德地图通过对现实世界高频高密度的数据采集,运用图像视觉AI能力,在海量的采集图片库中自动检测识别并确定出各种交通标志标线标牌的内容及位置,再通过与历史资料信息的对比,能快速发现现实世界的变化信息,同时结合强大而专业的数据融合能力,实现100%信息融入,从而构建出高现势性的全国基础地图。</p>
<p>综上,通过算法、地图工程的深度技术合作,以及与资料采集、数据生产的业务拉通,搭建一条以图像识别、位置服务、差分过滤、数据融合等为核心技术的基础地图数据生产全自动化产线,从而建立起从真实世界到地图应用终端,高效高质量的数据信息流水线生产通道。</p>
<p><strong>二、自动化产线的可行性及重点</strong></p>
<p>从图像物体分类和检测进展来看,图像物体的分类和检测已经有几十年的历史,涌现了一系列经典的算法。近些年随着图像识别技术特别是深度学习技术的快速发展及GPU计算能力的发展,分类和检测技术有了极大的提升。</p>
<p>从自动化需要的大数据来看,高德地图专注地图数据制作十几年,积累了覆盖全国、丰富且准确的数据,加之每天拥有大量采集信息的汇入,这些数据都成为算法训练天然的样本池;同时一整套专业化、标准化的地图生产作业规范为数据融合打下了坚实的理论基础。</p>
<p>因此,从算法储备能力、数据和工艺的积累来看,自动化产线搭建具有较强的可行性,其重点围绕着以下四部分组成:</p>
<p><strong>图像识别</strong>:图像识别的目标是从输入图像中解析出地图数据相关的现实信息,通过检测、识别图片中的交通标志标线标牌信息,细分其类型,并理解其中的数字和文字,以文本形式表达内容。此外,由于输入的是连续图像,单个标志标线标牌可以在多个图像上观察到,因此整合多张图像中的同一信息,并选择最合适的图像作为主图展示。</p>
<p><strong>位置服务</strong>:基于低精度GPS和采集图像,位置服务推算出自身和场景物体的精确位置,并映射到地图数据中。其中包括图像道路理解、标志位置解析、采集轨迹匹配等核心能力。依据轨迹特性和道路连通性,建立对定位位置、角度、速度等与候选道路关系的匹配概率模型,将轨迹关联到地图数据上。通过对多张图片中场景的理解,给出图片相对于路口的相对位置,结合地图道路数据的形态,进一步确定物体的作用位置。</p>
<p><strong>图像差分和语义过滤</strong>:目的是将新采集资料与已有母库中的数据进行一致性对比,自动将相同的信息进行差分与过滤操作,留下变化的信息。两者不同之处在于前者是检测相同位置新一次采集的图片相对于历史采集图片是否有变化,从轨迹和图像本身的角度对比;后者从数据的角度看图像识别后内容,对于母库数据是否有变化,从地图语义的角度做比较。</p>
<p><strong>基于位置的数据融合</strong>:图像识别的成果,结合位置服务提供的作用位置,获取到作用道路。通过抽象路口的模型,在该道路或路口做数据融合,即新增或者更新地图数据。</p>
<p><strong>三、 关键技术能力</strong></p>
<p><strong>1.图像识别</strong></p>
<p>图像识别主要面临三大挑战:一方面场景多样,类型繁多。待检测对象种类繁多,如交通标志标牌、地面引导线、电子眼等。比如正常的方向信息标牌如下图:</p>
<p><img src="/img/remote/1460000022737239" alt="" title=""></p>
<p>特殊的方向信息牌标牌:</p>
<p><img src="/img/remote/1460000022737241" alt="" title=""></p>
<p>而同类检测对象的样式也是繁杂的,国标通用的交通标志有几百个类型,而各地也会有一些地方特色的交通标志,所以需支持定制化检测识别。常见标牌形状多样,三角、圆形、方形、菱形、八边形等,同时颜色分布广泛,如黄色、红色、蓝色、绿色、黑色、白色等,另外,还需要排除自然场景内一些类似交通标志的标语、广告牌等,以减少对识别准确率的影响。</p>
<p><img src="/img/remote/1460000022737242" alt="" title=""></p>
<p>另一方面,在自然场景下图片质量差异巨大,其中很多图像质量偏低。再加上面临遮挡、逆光、雨雪天等极端户外场景。这些在检测环节都是要重点考虑及解决的问题。</p>
<p><img src="/img/remote/1460000022737240" alt="" title=""></p>
<p>最后,待检测对象的尺寸差异较大,大如方牌(几百个像素大小),小如电子眼、交通灯(十几个像素大小)。而小尺度检测,辨识度很差,对检测算法有比较高的要求。</p>
<p>综上,对于算法能力本身而言,交通标志检测实际上是一个多类型的目标检测任务,主流的方法是基于深度学习的End2End方案,在一个网络中同时完成检测与细分类任务。常用的dataset一般是PASCAL VOC(20类)和COCO(90类)等。</p>
<p>根据业务的实际需要,整个方案分为目标检测与精细分类两部分组成,目标检测阶段通过Faster-RCNN在图片中检测所有的交通标志,该阶段要求极高的召回率和执行速度,相应在准确率方面可以放宽要求;精细分类阶段对目标检测阶段得到候选框,然后进行精细分类并滤除噪声,最终保证极高的召回率和准确率。</p>
<p><strong>2.位置服务</strong></p>
<p>轨迹漂移对位置匹配地图的准确性一直都是极大的挑战,一方面平行路、高架场景,尤其是主辅路这种距离1-2个车道的平行路,需要很高的定位精度,常规的GPS定位精度在5-10m,很难达到80%的主辅路识别率。另外基础地图数据本身也存在GPS精度问题。</p>
<p>通过规则及隐马尔科夫模型的学习、推理以及维特比算法等基础理论以外,合理地抵抗定位漂移问题,是轨迹匹配成功的关键。通过对轨迹形态进行学习和总结,找出其规律,建立符合其特性的概率模型,精准地表达匹配建立过程,合理地平衡匹配准确性和抗漂移能力二者之间的关系。另外,通过长轨迹的连通性和图像识别车道数或道路位置关系,以解决平行路的部分场景的问题。</p>
<p>而对作用道路和作用位置的确定,目前依赖于图像识别对于路口位置的识别及融合对地图数据场景的理解和判断,例如标牌对路或路口的相对位置靠识别本身很难确定,需要融合对数据路网数据特性的理解和判断,这种判断比较复杂,人一眼就看明白了,但是机器很难用规则去描述。所以,通过路段中直行、路口中直行及拐弯等场景的分析,对比地图路段或路口的模型,来确定作业道路,根据不同属性计算作用位置。</p>
<p><strong>3.图像差分和语义过滤</strong></p>
<p>图像差分主要会面临资料对齐问题,即同一位置的多次采集资料,会受GPS自身精度及因卫星信号遮挡导致的漂移带来的所在道路判断偏差的影响。另外,在语义识别上,受自然环境下的环境因素,如遮挡、模糊、阴影、雨雪天气、视角变化等,会影响后续算法对图像的深层语义信息(如类型、内容等)的解析。两种因素的叠加,在多张图像和语义的一致性比对时,难度就提高了不少。</p>
<p>这方面,算法大幅快速提升了识别和一致性判断的准确率,以避免错误匹配对数据更新的影响。图像差分分为资料对齐和局部匹配两部分,资料对齐回答两次采集图像是否在同一位置、视角等,通过GPS轨迹粗筛、图像匹配等手段,判断两张图像的位置关系。局部匹配则需要回答两个物体是否为同一类型,对于有文本内容的物体,还需要检测版式、文本的一致性。因此除引入常见的点特征匹配技术外,也使用了基于深度学习的图像匹配网络。对于文本内容部分,借助OCR能力完成内容的理解和解析,最终判断两次采集的内容完全一致性。</p>
<p><strong>4.基于位置的数据融合</strong></p>
<p>由于现实世界的复杂性,地图生产经验积累形成了大量标准化地图数据制作规范,这些都是能合理抽象、准确表达现实世界的无形资产。即便现实路网形态千奇百怪,但都能通过模型进行抽象归类,建立不同场景下相对通用的地图数据模型,从而在其上建立沉淀大量的地图数据处理的工具类和方法,以确保数据自动化融合能力的广泛使用。</p>
<p><strong><img src="/img/remote/1460000022737244" alt="" title=""></strong></p>
<p><strong>四、总结</strong></p>
<p>高德SD基础地图数据生产自动化实现,本质上就是在基础地图数据生产过程中,引入图像AI技术和数据融合技术,结合多年地图数字化生产作业规范及经验,创新出一套面向资料的自动化生产线,形成自动化解放人工持续提供高效高质量的地图数据,以解决地图供应商生产产线专业化程度高、人工成本大、作业效率低等产线问题,最终满足广大用户出行过程对电子地图产品数据现势性的需求。</p>
<p><img src="/img/remote/1460000022737243" alt="" title=""></p>
高德前端这五年:动态化技术的研发历程和全面落地实践
https://segmentfault.com/a/1190000022641269
2020-05-14T14:19:28+08:00
2020-05-14T14:19:28+08:00
高德技术
https://segmentfault.com/u/amap_tech
8
<p><strong>前言</strong> <br>2015年-2020年,历经5年发展,高德地图应用开发前端团队在业务快速发展中不断成长。一路走来,从小团队主要负责短期运营活动开发的散兵游勇,到现在团队规模100人+,覆盖高德5大业务线,上百个模块的坚甲利兵。本文将分享随着业务快速增长高德前端的技术发展历程,总结动态化技术的落地实践,以及高德前端未来的发展方向。</p>
<p>高德(应用开发)前端技术的发展按照时间线来看,大致可以分为 4 个阶段:</p>
<ul>
<li>2015 年 ,业务上大量拉新的诉求,活动需求暴增,应用前端开始登上高德技术大舞台。</li>
<li>2016 年 - 2017 年,业务高速发展,对于效率以及双端一致性的诉求,带来了前端发展的契机,动态化技术开始落地。</li>
<li>2017 年 - 2019 年,动态化在高德全面落地,前端开发的角色越来越重要,业务半径不断延展。</li>
<li>2019 年 - 至今,这是目前的发展阶段,更加关注支撑的稳定性和延展性,让业务更好的活在未来。</li>
</ul>
<p>一言蔽之就是“顺势而为,乘风破浪”。 <br><img src="/img/remote/1460000022641273" alt="" title=""><br><strong>2015 年:小荷才露尖尖角</strong></p>
<p>2014 年底,高德地图提出专注用户需求,专注做地图导航产品和导航产品的技术研发,未来三年无商业化目标的新战略。没有了商业化的压力,一心专注产品和用户体验的高德地图,技术就此踏上了高速发展的轨道。 </p>
<p><strong>运营活动开发需求暴增,“工程、效率”解题</strong></p>
<p>围绕促进日活和留存的战略, 大量运营活动的开发需求应运而生,这个阶段的活动特点是“短平快”,开发周期短,一周内交付验证,活动时效期过后即可下线,完全不需要维护。对于代码的可维护性、技术上的创新要求不高,目标是快速响应热点事件,完成活动开发。这种模式给当时人员稀少的前端团队带来了非常大的考验,因为很多运营活动搭建需要在前端完成。而此时的前端团队在技术沉淀上较为薄弱,重复劳动明显。基于此,我们首先要完成的是效率上的提升,主要工作包括:</p>
<ul>
<li>组件化:和运营同学一起规范、建设活动常用组件。</li>
<li>模版化:拼图,通过模版化解决简单页面的搭建问题。</li>
<li>流程化:CLI 加速工作流。</li>
</ul>
<p>正是在基础能力上的耕耘,在之后多个热点事件时,我们才能游刃有余,在短时间内完成业务开发、上线。</p>
<p><img src="/img/remote/1460000022641272" alt="" title=""></p>
<p><strong>十一全民出行节,“性能、体验”沉淀</strong></p>
<p>时间回到 2015 年 10 月 1 日,为了配合“十一全民出行节”,第一个大型运营活动“十一挖宝”就此诞生,也拉开了每年出行高峰必有大型活动的序幕。我们通过开发更加简单、有趣的交互设计提升用户的游戏体验,强烈的社交属性例如 PK,排行榜等促进用户之间传播。</p>
<p>这一年的活动在公司内外进行了大范围的运营推广,“寻宝嘉年华,十六台 Smart 汽车送不停”,“斗鱼主播全场直播挖宝” 小伙伴们应该还有印象, 当时直播间非常火热,我们却战战兢兢,如履薄冰,特别担心直播时出现卡顿、白屏等问题,把火热的“全网挖宝”变成全网大型吐槽节目,运气比较好,我们担心的事情没有发生。</p>
<p>尽管如此,后背发凉的回忆使我们意识到,技术上如何完善复杂游戏的性能体验必将成为日后的课题,基于此我们又完成了基础技术(体验、性能)能力上的沉淀,包括:音频语音交互解决方案,大型游戏性能的最佳实践。</p>
<p><img src="/img/remote/1460000022641275" alt="" title=""></p>
<p>到 2015 年底整个前端团队初具雏形,团队开始建立规范化,标准化,体系化的思维,在技术上也积攒了不少家底。为了应对可预见的考验,前端团队也招入了很多有能力的新人。正是这些人才,使我们在接下来的多线作战中游刃有余。 </p>
<p><strong>2016 年 - 2017 年:忽如一夜春风来</strong></p>
<p>随着高德地图业务沿着扩品类、在垂直品类做精做细,景区、酒店、银行商铺、充电桩等个性化定制需求凸显,对前端展现提出了更高的要求,对“快速应变”要求也越来越高,这段时间主要面临以下痛点:</p>
<ul>
<li>业务要求快速发版试错。</li>
<li>研发资源越来越无法满足业务的快速增长。</li>
</ul>
<p><strong>契机,高德动态化技术诞生</strong></p>
<p>这些问题也在不断地督促我们去反思,到底有没有一种架构既能象 H5 一样快速的开发、发布又能保持原生 Native 的体验?实际上,在 2015 年,我们就开始做动态化了,那时候业内有 React Native, 团队做了技术调研,发现不能完全满足业务上的需要,尤其是性能方面,因此我们决定自研一套动态化技术。在项目伊始就有一些难点摆在我们面前:</p>
<ul>
<li>布局怎么做?RN 的 yoga、iOS 的绝对布局还是 Android 的 RelativeLayout?</li>
<li>Runtime framework 放在哪里?C++ 、JS 谁来承载?</li>
<li>模块化的机制是什么样的?Node Require、Webpack Require?</li>
<li>通信、动画怎么做等诸多问题需要我们探索,抉择。</li>
</ul>
<p>经过团队内部多次思想上的碰撞、激烈的讨论, 最终确定以下核心设计思想。 </p>
<p><strong>核心</strong></p>
<p>核心处理尽量下沉动态化引擎层,双端尽量做薄,动态化引擎(C++)以 Webkit、Node 为参考,即可以通过 HTML、CSS、JavaScript 编写原生应用,又可以像 Nodejs 一样使用文件操作等与原生应用的交互能力。这样的设计在上层对接前端生态时更加灵活,在处理复杂、频繁交互的大型页面时也会有更好的性能。</p>
<p><strong>优化</strong></p>
<p>除常规动画外,还设计了关联动画解决高频联动动画,关联动画本质上并非是一种播放类型的动效,是基于观察者模式设计的,被观察者的属性变化会影响观察者的属性变化,它将关联关系提前绑定好,一次性由 JS 线程传递给 UI 线程,这样能够很好的保证交互性能。</p>
<p>在方案明确后,整个团队也投入到能力建设中来,尽管每周都在发现问题、解决问题中艰难前行,但大家仍然乐此不疲,对于这种打怪升级的过程乐在其中。在基础能力、辅助工具齐备的背景下,我们开始着手动态化业务的落地实践,最终我们选择了 POI 业务。POI 即(Point ofInterest)兴趣点,如学校、酒店、饭店、加油站、超市等,高德地图上有数千万的 POI。 </p>
<p><strong>起航,动态化技术落地 POI</strong></p>
<p><strong><img src="/img/remote/1460000022641274" alt="" title=""></strong></p>
<p>首先看一看 POI 业务的特点:</p>
<ul>
<li>UI 复杂,多品类,多种多样的展现形式。</li>
<li>与地图有存在交互。</li>
<li>性能要求高,长列表,数据量大。</li>
<li>富交互,大量手势交互,关联动画。</li>
<li>多人协作开发问题</li>
</ul>
<p>为了快速验证能力,项目的排期非常紧张,为此前端同学 All in,业务上看尽管 POI 只有一个页面,但是却有多个行业,而行业是由多个模块拼接而成,每个模块在不同行业展现形式也不尽相同,如何解决协作问题就成为项目成败的关键之一。</p>
<p>为此我们完成了 Framework 框架开发,可以用 JSX 语法实现基本组件化,在组件这个级别进行 CURD 解决了模块化开发的问题。</p>
<p><strong>调试问题</strong></p>
<p>在项目之初我们并不存在完备的调试方式,甚至可以说不存在调试能力,只是通过 print 将 log 输出到手机端展现。这在开发 POI 时遇到了极大的问题,业务场景复杂大量实时日志无法查看,导致效率极低。</p>
<p>为此我们完成了 websdk,mock 能力,在浏览器端完成了 POI 页面的预览,调试。</p>
<p>尽管 POI 落地过程中,遇到了各种各样的问题,但结果是美好的,动态化技术也经受住了业务的考验,新的 POI 不仅完全覆盖了之前 H5 的功能,在手势动画、List 展现上还体现了更加卓越的交互体验和性能。伴随着业务上线,基建一期也基本完成,这个阶段以满足业务为中心,主要围绕支撑能力的设计和基本的开发体验。</p>
<p><img src="/img/remote/1460000022641277" alt="" title=""></p>
<p>POI 的圆满落地也标志着前端技术有能力在高德地图中承担更复杂、更核心、更大的业务场景,前端开发也即将迎来春天。</p>
<p><strong>2017 年 - 2019 年:千树万树梨花开</strong></p>
<p>POI 业务上的成功落地,标志着动态化技术解决方案趋于稳定,可以应对各种各样的复杂业务,随之而来的是大量业务的考验。随着动态化技术应用的深入、主要业务模块的全面接入,支撑能力不完善、动态化技术开发人员缺乏导致改造压力越来越大。 </p>
<p><strong>团队壮大,“小前端”到 “大前端”</strong> </p>
<p>人员的问题主要从内外两方面解决,外部启动招聘,大量吸纳有相关背景的前端同学。内部 Native 同学加强技术培训,转向动态化技术开发也正式提上日程。</p>
<p>不少同学一定有这样的经历,如果让其去调研一门新的技术大家一定非常乐意,充满干劲,对未知领域的探索,求知渴望是研发的共同点。不过如果让其持续朝着这门技术发展就会有非常多的疑虑。</p>
<p><img src="/img/remote/1460000022641276" alt="" title=""></p>
<p>通过培训等方式,解决大家对于技术不确定性和前景的担忧,大量同学开始转向动态化技术,到 2019 年初整个动态化“大前端”团队得到快速增加。</p>
<p><strong>基建完善,“研发闭环,逐个突破”</strong></p>
<p><strong><img src="/img/remote/1460000022641280" alt="" title=""></strong></p>
<ul>
<li>通过 IDE 将开发、调试能力打通。</li>
<li>通过工程平台进行发布、回滚、更新、监控、分析操作。</li>
</ul>
<p><strong>业务增长,“横跨 5 大业务线,高德核心业务全覆盖”</strong></p>
<p>富有战斗力的团队、渐渐完善的基建使业务从小步慢走到大步快跑,从用户的核心诉求我在哪(主图,定位),我去哪(搜索,POI),怎么去(规划,导航) 到用户的延伸诉求怎么去(打车) 怎么玩(景区)高德 5 大业务线 60 多个模块全面接入动态化技术。</p>
<p><img src="/img/remote/1460000022641278" alt="" title=""></p>
<p>这个阶段动态化业务发展迅猛,“前端团队”不断壮大,由“小前端”转变为“大前端”,基建方面也是围绕业务全面展开,不断完善。有了稳定的开发环境, 2017 年 - 2018 年,不到 2 年的时间我们完成代码量从 3W 到 60W,模块数量从 1 到 60+,开发人员井喷式增长。业务发版频次渐渐加快、加密,从单月版→快迭双周版。 </p>
<p><strong>2019 年 - 至今:九层之台,起于垒土</strong></p>
<p>面对着越来越复杂的业务,仍有不少细节问题需要进一步解决, 如何更好的为业务赋能再次成为重点,阿里前端大咖玉伯之前的分享中有句话给我们印象颇深:</p>
<p>愿等花开,坚持长期主义,要快,但不能急。</p>
<p>回到自身来说,前面几年都是保证业务赢在当下, 支撑上都是大刀阔斧快速建设,完成 0 到 1 的过程。接下来应该帮助业务更好的活在未来,在当前基础能力具备的情况下,需要闭关审视自身,从功能的完整性,延展性等方面做到精细化。</p>
<p>未来,我们也将从研发生态、工程中台、智能化 3 大方向上以精细化、标准化、差异化为基础要求,不断补足能力,逐渐完成中台化、智能化的基础建设工作,围绕 IDE 打造更好的一站式场景化开发体验。</p>
<p>五化基建方针</p>
<ul>
<li>精细化:切中痛点,系统解题。</li>
<li>标准化:集团生态、业界标准。</li>
<li>差异化:标准化基础上,提供 Amap 能力扩展。</li>
<li>智能化:低代码,物料复用,UI 自动生成。</li>
<li>中台化:前台通用能力下沉到中台,不再局限高德。</li>
</ul>
<p>技术大图</p>
<p><img src="/img/remote/1460000022641279" alt="" title=""></p>
<p>接下来的重点方向</p>
<ul>
<li>工具链路稳定性、延展性持续优化。</li>
<li>平台能力中台化。</li>
<li>全链路监控:快速分析、定位问题。</li>
<li>物料:缩短开发到资源路径,沉淀更多基础能力。</li>
<li>智能化:低代码、零代码。</li>
</ul>
<p>以上是 5 年来高德地图前端技术的发展历程,过程中有失有得,我们还在路上,未来会更加努力,让出行更美好。<br><img src="/img/bVby2A6" alt="关注图.jpg" title="关注图.jpg"></p>
深度学习在高德POI鲜活度提升中的演进
https://segmentfault.com/a/1190000022590588
2020-05-09T14:27:48+08:00
2020-05-09T14:27:48+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>1.导读</strong></p>
<p>高德地图拥有着数千万的POI(Point of Interest)兴趣点,如学校、酒店、加油站、超市等。其中伴随着众多POI创建的同时,会有大量的POI过期,如停业、拆迁、搬迁、更名。这部分POI对地图鲜活度和用户体验有着严重的负面影响,需要及时有效地识别并处理。</p>
<p><img src="/img/remote/1460000022590593" alt="" title=""></p>
<p>由于实地采集的方式成本高且时效性低,挖掘算法则显得格外重要。其中基于趋势大数据的时序模型,能够覆盖大部分挖掘产能,对POI质量提升有着重要意义。</p>
<p>过期POI识别本质上可以抽象为一个数据分布非对称的二分类问题。项目中以多源趋势特征为基础,并在迭代中引入高维度稀疏的属性、状态特征,构建符合业务需求的混合模型。</p>
<p>本文将对深度学习技术在高德地图落地的过程中遇到的业务难点,和经过实践检验的可行方案进行系统性的梳理总结。</p>
<p><strong>2.特征工程</strong></p>
<p>过期挖掘的实质是感知伴随POI过期而发生的变化,进行事后观测式挖掘,一般都会伴随着POI相关活跃度的下降。因此时序模型的关键是构建相关联的特征体系。同时在实践中我们也构造了一些有效的非时序特征进行辅助校正。</p>
<p><strong>2.1时序特征</strong></p>
<p>时序特征方面,建立了POI和多种信息的关联关系,并分别整合为月级的统计值,作为时序模型的输入;时间序列窗口方面,考虑到一些周期性的规律的影响,需要两年以上的序列长度来训练模型。</p>
<p><strong>2.2辅助特征</strong></p>
<p>辅助特征方面,首先是将人工核实历史数据进行有效利用。方式是构造一个时间序列长度的One-Hot向量,将最后一次人工核实存在的月份标记为1,其他月份为0。人工核实存在表示该时间结点附近过期概率较低,若人工更新在趋势下降之后,说明趋势表征过期的概率不高。</p>
<p>其次,调研发现不同行业类型的POI有着不同的过期概率,如餐饮和生活服务类过期概率较高,而地名或公交站点等类型则相对低很多。因此将行业类型编号构建为一个时间序列长度的等值向量,作为静态辅助特征。</p>
<p>第三种辅助特征是在分析业务中的漏召回问题时总结构造的。发现有相当部分的新诞生POI,其入库创建后至今的时长短于序列长度。意味着这部分序列前期存在较多数值为零的伪趋势,会对尾部的真实下降趋势造成干扰从而误判。对此提出了两种优化思路:</p>
<ul>
<li>采用可变长度的RNN模型,只截取POI创建时间之后部分的序列作为输入。</li>
<li>序列长度不变,添加一维“门”序列特征,序列在POI创建时间之前的部分数值为0,之后为1。如图所示。</li>
</ul>
<p> <img src="/img/remote/1460000022590600" alt="" title=""></p>
<p>对比采用第二种方案效果更优。考虑到我们只有POI的入库创建时间信息,而不了解门店的具体诞生时间,直接按入库时间截取序列,会造成门店诞生和POI创建时间段内的特征信息损失;而添加“门”序列则可以在保持信息完备的同时约束高可信区间。最后构建的混合特征示意图如下所示。</p>
<p><strong><img src="/img/remote/1460000022590599" alt="" title=""></strong></p>
<p><strong>3.RNN阶段</strong></p>
<p>循环神经网络(RNN, Recurrent Neural Network)凭借强大的表征能力在序列建模问题上有非常突出的表现,业务中采用了其变种模型LSTM。</p>
<p><strong>3.1RNN1.0</strong></p>
<p>以前述的时序特征和辅助特征为基础,我们采用多层LSTM搭建了第一版RNN过期挖掘模型,结构如图所示。主要逻辑为,将逐时间点对齐后的特征输入到深度LSTM中,在网络最后时刻的输出后,接入一层SoftMax计算过期概率。最后根据结果匹配不同的置信度区段,分别进行自动化处理或人工作业等任务。模型初步验证了RNN在过期趋势挖掘领域落地的可行性和优势。</p>
<p><strong><img src="/img/remote/1460000022590591" alt="" title=""></strong></p>
<p><strong>3.2 RNN2.0</strong></p>
<p>高德地图基于导航、搜索或点击等操作频度对POI进行了热度排名。头部的热门POI如果过期但未及时发现对用户体验的伤害更大。2.0版本模型升级的主要目标便是进一步提升头部热门段位的过期POI发现能力。</p>
<p>分析发现热门POI的数据分布相比尾部有较大差异性。头部POI的数据量丰富,且数值为0的月份很少;相反尾部POI则数据稀疏,且有数值月份量级可能也仅为个位数。对于这种头部效应特别明显的状况,单独开发了高热度段特征的头部RNN模型,实现定制化挖掘。</p>
<p>另一方面,对于单维度特征缺失的情况,也区分热度采用了不同的填充方式。头部POI特征信息丰富,将缺失维度补零让其保持“静默”防止干扰;而尾部特征稀疏,本身已有较多零值,需要插值处理使缺失特征和整体保持相近趋势。方法为将其他维度的数据规范化处理后,采用加权的方式得到插值。</p>
<p><img src="/img/remote/1460000022590592" alt="" title=""></p>
<p>2.0版模型对头部和尾部的召回能力都有提升,对头部的自动化能力提升尤为明显。</p>
<p><strong>4.Wide&Deep阶段</strong></p>
<p>RNN模型能够充分发掘时序特征的信息,但特征丰富度不足成为制约自动化能力进一步提升的瓶颈。因此整合业务中的其他数据,从多源信息融合角度升级模型便成为新阶段的工作重点。主要的整合目标包括非时序的静态信息和状态信息,以及新开发的时序特征信息。</p>
<p>模型升级主要借鉴了Wide&Deep的思想,并做了很多结合业务实际情况的应用创新。首先我们要把已有的RNN模型封装为Deep模块后和Wide部分联合,相当于重新构建了一个混合模型,涉及到模型结构维度的整合。其次,既有Deep的时序信息,又有Wide部分的实时状态信息,涉及到数据时间维度的整合。最后是Wide部分包含大量的不可量化或比较的类型特征需要编码表征处理,涉及到数据属性维度的整合。</p>
<p><strong>4.1 Wide & LSTM</strong></p>
<ul><li><strong>特征编码</strong></li></ul>
<p>我们将非时序特征经过编码后构建Wide模块。主要包括属性、状态,以及细分行业类型三种特征。</p>
<p>考虑到某些POI属性存在缺失的情况,故编码中第1位表示特征是否存在的标志位,后面则为One-Hot编码后的对应的属性类型;对于状态特征,同样有一位表示是否特征缺失的标志位,而后面的One-Hot编码则表示最新时刻的状态类型;由于不同行业类型有着不同的背景过期率,我们将细分的行业类型做One-Hot编码后作为第三种特征。最后将各特征编码依次连接,得到一个高维度的稀疏向量。特征编码的过程如图所示。</p>
<p><strong><img src="/img/remote/1460000022590594" alt="" title=""></strong></p>
<ul><li><strong>特征耦合</strong></li></ul>
<p>特征完备之后,将各类特征耦合及模型训练便成为关键。耦合点选在了SoftMax输出的前一层。对于Deep部分的RNN结构,参与耦合的便是最后时间节点的隐层;而对于Wide部分的高维度稀疏向量,我们通过一层全连接网络来降维,便得到Wide部分的隐层。最后将两部分的隐层连接,输出到SoftMax来计算过期概率。</p>
<p>模型采用同步输入Wide和Deep部分特征的方式联合训练,并调节两部分的耦合隐层的维度来平衡两部分的权重。过期挖掘场景的Wide & LSTM模型结构如图所示。</p>
<p><img src="/img/remote/1460000022590597" alt="" title=""></p>
<p>模型经过多次迭代优化后稳定投产,已成为过期挖掘业务中覆盖行业广、自动化解题能力突出的综合性模型。</p>
<p><strong>4.2 Wide & Dual-LSTM</strong></p>
<p>在做模型升级迭代的同时,基础特征的建设工作也在同步进行。在扩充新的趋势特征的时候面临这样一个问题,新特征维数较多且时间序列较短,这样将长时序特征和短时序特征逐时间点匹配时会出现很大部分的数值缺失。</p>
<p>由于新特征缺失部分较多且维度较大,缺失值填充的负面影响会过于严重而不适合采用。项目中采用了分而治之的方案,分别建立两个RNN模块,其中长RNN模块输入无新特征的长序列,短RNN模块输入有新特征的短序列,最后将双RNN的Hidden层和Wide部分一起耦合,得到了Wide & Dual-RNN模型,结构如图所示。</p>
<p><img src="/img/remote/1460000022590596" alt="" title=""></p>
<p>双RNN结构能够很好地将新特征融入到现有模型并提升判断准确率,不足的地方是结构较复杂影响计算效率。故后期进行了新阶段的研发,采用更灵活的时序模型TCN进行迭代。</p>
<p><strong>4.3 Wide & Attention-TCN</strong></p>
<p>TCN主要有如下三方面优点使其能胜任时间序列的建模:首先,架构中的卷积存在因果关系,即从未来到过去不会存在信息泄漏。其次,卷积架构可以将任意长度的序列映射到固定长度的序列。另外,它还利用残差模块和空洞卷积来构建长期依赖关系。</p>
<p>性能对比上,TCN可以将时间序列作为向量并行化处理,相比RNN的逐时间点顺序计算的方式有更快的计算速度。此外,TCN可以输入延展成一维的序列,从而避免了特征需要逐时间点对齐。因此在验证了Wide&Deep的思路有效后,我们尝试将Deep部分的RNN结构升级为TCN。</p>
<p>首先,对于输入部分的特征进行了Flatten处理,即将每个维度的时间序列依次首尾相连,如图所示,拼接成为一个长向量后作为输入。这样便实现了长特征和短特征的有效整合。</p>
<p><img src="/img/remote/1460000022590595" alt="" title=""></p>
<p>其次,对于输出结构,引入序列维度的Attention机制进行优化。主要思想是不再只读取序列最后节点的隐向量的浓缩信息,而是对所有序列节点的隐向量信息加权处理后,得到汇总的隐向量信息,使所有节点的学习结果得到充分利用。</p>
<p>最后将Attention-TCN后得到的汇总隐向量和Wide部分的隐层进行耦合,得到的Wide&Attention-TCN模型结构如图所示。</p>
<p><img src="/img/remote/1460000022590598" alt="" title=""></p>
<p>通过引入新的轻量TCN时序模型和Attention机制,新的模型性能有了进一步提高,但调优过程相对RNN更加复杂。多轮参数调整与结构优化后,最终落地版本与Wide & Dual-LSTM版相比,计算效率和业务扩招回能力均有可观提升。</p>
<p><strong>5.总结与展望</strong></p>
<p><img src="/img/remote/1460000022590601" alt="" title=""></p>
<p>深度学习在过期挖掘场景中的落地,经历了不断摸索尝试、总结问题、优化方案、验证效果的迭代演进的过程。期间以提升过期发现能力为核心目标,对特征扩展、特征构造和模型结构优化的角度都进行了探索,并总结了如上的业务场景落地经验。其中,丰富可靠的特征、合适的特征表征方式和符合场景的模型结构设计是提升业务问题解决能力的关键。</p>
<p>当前模型主要是基于信息和趋势进行宏观性的规律总结,并判断具备这类特征情况下的POI过期的概率。而现实生活中POI的具体地理环境、自身经营状况、周边竞争态势等个性化因素的影响往往不可忽略。因此,未来规划将综合考虑整体规律性特征和个体差异性,实现精细化挖掘。</p>
<p><strong>6.参考文献</strong></p>
<p>1.Sepp Hochreiter and Jurgen Schmidhuber, Long Short-Term Memory, Neural Computation 1997</p>
<p>2.B. Hidasi, A. Karatzoglou, L. Baltrunas, and D. Tikk. Session-based recommendations with recurrent neural networks. CoRR, abs/1511.06939, 2015</p>
<p>3.Heng-Tze Cheng, Levent Koc, Jeremiah Harmsen, Tal Shaked, Tushar Chandra, Hrishi Aradhye, GlenAnderson, Greg Corrado, Wei Chai, Mustafa Ispir, Rohan Anil, Zakaria Haque, Lichan Hong, Vihan Jain, Xiaobing Liu, and Hemal Shah. Wide&Deep learning for recommender systems. In Proc. 1st Workshop on Deep Learning for Recommender Systems, pages 7–10, 2016.</p>
<p>4. Paul Covington, Jay Adams, and Emre Sargin. Deep neural networks for youtube recommendations. In Proceedings of the 10th ACM Conference on Recommender Systems. ACM, 191–198, 2016.</p>
<p>5.Bai S , Kolter J Z , Koltun V . An Empirical Evaluation of Generic Convolutional and Recurrent Networks for Sequence Modeling[J]. 2018.</p>
<p>6.Pappas N , Popescu-Belis A . Multilingual Hierarchical Attention Networks for Document Classification[J]. 2017.</p>
<p><img src="/img/remote/1460000022590602" alt="" title=""></p>
高德技术评测建设之路
https://segmentfault.com/a/1190000022589902
2020-05-09T13:29:12+08:00
2020-05-09T13:29:12+08:00
高德技术
https://segmentfault.com/u/amap_tech
1
<p><strong>前言</strong></p>
<p>近几十年是互联网高速发展的时代。随着互联网行业的发展壮大,必然会出现角色的细分,从而演化出了不同的职能岗位。随着日益激烈的市场竞争,修炼内功,提升产品效果也成为了各公司发展的重要工作。产品效果如何评估?用户体验如何度量?本文试图阐述<strong>评测</strong>这一新岗位在高德的主要职责,发展进化过程,以及这一岗位所负责的产品效果评估手段与体系搭建。</p>
<p>当你在各搜索引擎输入评测二字时,看到的相关搜索通常是这样的:</p>
<p><img src="/img/remote/1460000022589911" alt="" title=""></p>
<p><img src="/img/remote/1460000022589905" alt="" title=""></p>
<p>这些问题其实能代表大部分人对评测的了解——就是除了游戏评测、手机评测、汽车评测、生活用品评测之外,人们对评测其实不太了解。互联网公司里Title是评测的同学又是做什么的呢?也许大家的了解就更少了。</p>
<p>做了三年多的评测,在第一年经常面对的灵魂拷问就是:“你们评测是做什么的?”这种问题回答起来,基本类似于哲学的终极三问了:“你是谁?你从哪儿来?你到哪儿去?”</p>
<p>评测是谁?这是评测的定位问题。评测从哪儿来?这是评测的根基和起源。评测要到哪儿去?这是评测的发展目标和方向。</p>
<p><strong>评测是谁?</strong></p>
<p>简单地说,<strong>评测是评估产品效果的团队</strong>。希望能站在用户的角度,在上线前验证需求效果,在上线后通过对自身、用户数据和竞品的全面分析,建立起产品立体的效果评估体系,也就是评测体系。</p>
<p><strong>评测从哪儿来?</strong></p>
<p>要回答这个问题,其实就是——为什么要评测?</p>
<p>如同每个版本更新,我们都会关心性能如何一样,当上线了新的策略时,大家也会同样关心产品的效果。产品效果如何评估?策略相关的需求开发完成之后,研发实现的实际效果是否和产品经理的预期一致?实际效果又是否和用户的预期一致?在理想情况下,这三者应该是无差异的。但我们也应该有衡量它们之间是否有差异的方式,给出效果变化是否正向的结论,以更好地保障用户的使用体验。</p>
<p>此外,即使上线前,所有人都一致给出了正向结论,认为需求上线后一定会给用户体验带来极大提升。真实的产品体验如何,仍然得用户说了算。比较大的修改可以通过AB实验的方式圈出小部分用户,快速收集用户数据,进一步对需求效果是否正向做出评价。或者直接上线,通过对行为数据及用户反馈的分析来完成线上评估。</p>
<p>同时,要在市场上找准自己的位置,对竞品的分析必不可少。</p>
<p>有了这些效果评估及分析的需求,就有了评测团队。</p>
<p><strong><img src="/img/remote/1460000022589907" alt="" title=""></strong></p>
<p><strong>如何进行评测</strong></p>
<p>上线前的离线效果评测及分析、AB实验及分析、上线后的指标监控及问题分析、问题挖掘,竞品监控和分析是常见的评测手段。</p>
<p><strong><img src="/img/remote/1460000022589908" alt="" title=""></strong></p>
<p><strong>一、离线评测</strong></p>
<p>上线前,针对产品的需求,评测的职责是通过各种方式分析及验证产品效果,给出是否能达到上线标准的结论,同时分析出头部问题所在。</p>
<p>技术评测团队成立之初,主要建设的部分有:确定合作流程、建设评测专业能力和建设评测工具。</p>
<ul><li><strong>合作流程</strong></li></ul>
<p>对标一个版本开发的项目流程,从需求确定到开发,到测试验证再到上线。评测从需求串讲阶段开始,明确有哪些需求涉及到效果变化。再根据变化情况制定评测方案,同时检查工具是否符合需要,如否则进入工具快速开发阶段。然后获取评测数据,进入评估验证阶段,最后发送报告,给出需求是否通过评测的结论,并对出现的问题进行总结分类。</p>
<p><img src="/img/remote/1460000022589906" alt="" title=""></p>
<p>对于评测介入的不同业务线来说,评测的流程大致相同。但由于业务不同,评测方案与方式会有很大不同。</p>
<ul><li><strong>评测方案</strong></li></ul>
<p>根据产品需求,明确效果修改影响范围,从而确定评测样本、评测方式和评测标准。</p>
<ul><li><strong>评测样本</strong></li></ul>
<p>评测样本通常会根据需求影响范围的不同,区分为随机语料和特定语料。</p>
<p>特定语料一般针对需求修改的特定维度、类型进行抽取,目的是保证评测任务的覆盖率。随机语料则是为了反映需求的真实影响范围。当一个评测任务需要使用特定语料时。通常建议使用特定及随机语料各一份,以同时保证足够的覆盖,同时了解真实影响范围,确保不会出现不符合预期的变化。</p>
<p>除真实语料外,在特定场景下也会使用自己构建的语料。通常原因为:1)策略上线之前没有真实线上语料;2)影响的场景太小,在真实语料中很难找到足够的Case。</p>
<ul><li><strong>评测标准</strong></li></ul>
<p>评测标准通常涉及到一个概念,即真值。当某类数据在现实世界中有唯一正确答案时,即有绝对真值存在,如数据信息。因此我们对这类数据的评价标准就是是否跟真值一致。</p>
<p>另一类是相对真值。来源可以是用户日志。例如,当我们在判断提供给用户的预计到达时间(ETA)是否正确时,可以用用户在起终点之间的真实行驶时间作为真值和我们的预估时间进行对比。但由于单一用户的实际行驶时间受个人行驶习惯以及单次的行驶情况所影响,并不是完全准确的。因此是相对真值。在搜索等业务线,用户的点击行为,也可以成为相对真值,从而成为效果评测的标准。</p>
<p>是否有真值,真值是否容易获取,能否大批量自动化的获取,是在确认评测标准时需要做的判断。</p>
<ul><li><strong>评测方式</strong></li></ul>
<p>对应不同的评测目的,我们给出不同的离线评测方式。有真值的业务,通过真值的自动获取或者标注,可以实现自动化评测。而无真值的业务线,判断效果好坏的成本较高,通常需要进行人工评测或者半自动化评测。</p>
<p><img src="/img/remote/1460000022589910" alt="" title=""></p>
<p>人工评测,顾名思义,就是靠人力打分。各搜索公司大概是最早对自己的产品进行效果评估的,谷歌、微软、百度、苹果等,都采用了类似的方式对质量进行评价。</p>
<p>Google曾经发布过长达164页的人工质量评估指南。百度和必应也发布过类似的文档。</p>
<p>苹果在介绍自己的评测体系时,也曾经专门解释过Human Judgement metrics, why we track them?</p>
<ul>
<li>可以在上线前发现版本问题。</li>
<li>人工评测的指标与定量指标紧密关联。</li>
<li>可以定义一个版本的整体质量,并可持续跟进效果变更。</li>
<li>比用户反馈更详细,更容易定位问题。</li>
</ul>
<p>人工评测缺点不用多说,成本高、覆盖面小、效率偏低。因为它的优点,目前仍然是各公司评测体系不可缺少的一部分。与别的评测手段结合使用时,能起到很好的效果。</p>
<p>要保证人工评测的质量和效率,有三个关键点,一是标准,二是流程,三是工具。</p>
<p>标准文档,类似于操作手册,目的是降低人员培训成本,并在一些较难判断的Case上,尽量减少大家认知上的差异。所以标准文档应该越傻瓜越好。定义明确、所有的特殊和例外场景都有示例、在实践中反复检验,并且保持更新频率。文档更新应该有专人负责,并且明确更新周期,同时将更新点同步到所有评估人员。</p>
<p>人工操作错误在所难免,没人能达到百分百的准确。同时需要人工评测的评测对象,通常本身没有客观统一的确定答案,因此大家难免在判断上有差异。这些问题都需要从流程上加以保障。如同一Case必须多人标注,仅保留一致率较高的Case,否则便丢弃。或者采用初审复审制,经验较少的人员进行初审,高级人员进行复审。</p>
<p>盲审,这种方式通常在对比时使用,去掉新旧版或者左右版的标识,并且让结果随机出现,从而保证评测人员的客观性,不受主观因素影响。</p>
<p>人工评测中的人,通常也有两种身份。一种是普通用户,一种是专家。专家评测需要站在更专业的视角,结合自己对业务的理解和经验才能得出结论。另一种则是普通用户也能站在自己的视角给出效果好坏。后一种可以进行众测,达到较大范围的收取用户体验与反馈,同时获得一些真实数据支持迭代优化的效果。地图导航由于其专业性,通常需要进行专家评测。</p>
<ul><li><strong>评测工具</strong></li></ul>
<p>评测工具是评测效率和质量的保证。核心功能包括,数据仓库、任务管理、任务的抓取和解析,diff统计和筛选,任务实例的展示、评测、流转,抽样、分配,结果管理、自动化报告。</p>
<p><img src="/img/remote/1460000022589909" alt="" title=""></p>
<p>通用流程之外的任务类型、打分方式、 Case形态都可以自己定义。由于大部分是对比类的评测任务,如何做diff也非常关键,尽量把业务关注的各个重点都进行diff差分。以便快速了解迭代效果影响面,以及快速定位问题。专家型评测在分析和定位问题时,还需要辅助分析或者判断的数据及工具。工具的接入常常能极大地提高评测效率。</p>
<p>人工评测能够良好运行,有了一定的评测经验积累和业务了解之后,开始进行半自动化和自动化的评测建设。</p>
<p>方式包括定义指标波动阈值和极端Case的冒烟评测,及模拟人工评测的自动打分模型。</p>
<p><strong>自动打分模型</strong>通过学习人工评测的特征,自动给出GSB的评分,统计评分结果,对评测任务的效果进行初步判定。目前可以成为辅助判断的参考手段。</p>
<p><strong><img src="/img/remote/1460000022589912" alt="" title=""></strong></p>
<p><strong>冒烟评测</strong>先定义出业务核心关注的场景和维度,设定指标。并根据既往评测经验计算出可接受的波动阈值。另外定义出在效果变化上不可接受的恶劣Case。对于部分需要快速验证上线的实验,可以实现缩短评测周期,并保证无异常的效果。在部分业务线借此实现了自动发布上线的过程。</p>
<p><strong>指标分析+异常检验</strong>的评测方式,是目前无真值业务线离线评测的最佳实践方式之一。通过定义整体指标、场景指标、异常指标,形成较为全面的指标体系。观察新版本在不同情况下的指标整体波动和分布变化。在过程中筛出异常Case再进行人工校验。最终根据指标变化情况和人工检验结果给出结论。如无异常则可以快速通过评测。</p>
<p>最后,<strong>路测</strong>是导航产品效果验证的终极手段。从用户视角体验并评估全过程。虽然成本高,效率低,但必不可少,与其他手段并用,也是上线前效果保障的方式之一。</p>
<p><strong>二、AB实验</strong></p>
<p>部分需求尤其是模型调优。需要上线观察效果。因此在快速通过离线评测之后,进入AB阶段进行效果评估。</p>
<p><img src="/img/remote/1460000022589913" alt="" title=""></p>
<p>AB的核心链路是分流打标、指标观测和实验结论产出。关键点是实验的科学性。效果评估链路中,AB能力的具备不难,但AB实验的建设是个长期的过程,在此不赘述。</p>
<p><strong>三、线上验证</strong></p>
<p>经过离线验证、AB实验,证明效果都是正向之后,需求通常全量上线,上线之后的效果如何,需要对线上指标进行分析,并观察用户反馈情况,了解是否在核心指标上有预期的收益,以及观察指标是否有异常变化。</p>
<p>一个产品的核心是满足用户需求,创造用户价值。因此是否满足了用户需求,用户满意度如何,产品在市场上的情况怎么样,必然是一个产品创造者要长期关注和回答的问题。以上便是我们试图去回答这些问题的方式。</p>
<p><strong>结语</strong></p>
<p>评测的建设过程,其实也是产品效果评估立体体系的搭建过程。这个职责在任何一个互联网公司都需要有人承担。不过角色也许是测试、也许是产品、也许是运营。在高德,之所以把这个角色独立出来,源于对用户体验和产品效果的重视。这一体系当然远远未臻完美,还在不断搭建进化的过程中,我们始终希望能够通过不断努力,让出行更美好。</p>
<p><img src="/img/remote/1460000022589914" alt="" title=""></p>
高德地图首席科学家任小枫QA答疑汇总丨视觉+地图技术有哪些新玩法?
https://segmentfault.com/a/1190000022504474
2020-04-29T10:49:20+08:00
2020-04-29T10:49:20+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p>上周,阿里巴巴高德地图首席科学家任小枫在#大咖学长云对话#的在线直播活动上就计算机视觉相关技术发展以及在地图出行领域的应用与大家做技术交流,直播间互动火爆,尤其在QA环节,学弟学妹们纷纷就感兴趣的视觉应用、AR导航、定位技术、5G、职业发展等话题提问,任小枫做了精彩回答。我们整理了问答内容,分享给大家。</p>
<p><strong>视频回放地址</strong>:</p>
<p><a href="https://link.segmentfault.com/?enc=zPyYBLInilJqrkWesbn7uw%3D%3D.y5ebU%2FSVZRoGccANVSyXff124HHVHaLQjwJMrQbflAQwVB9htoRqRM4bCic8tkZa" rel="nofollow">https://vku.youku.com/live/il...</a></p>
<p> <img src="/img/remote/1460000022504477" alt="" title=""></p>
<p>任小枫博士,现任阿里巴巴高德地图首席科学家,研究员,主要负责视觉技术在地图和出行领域的应用和创新。加入阿里巴巴前,他在2013到2017年间供职于亚马逊,是亚马逊的资深主任科学家和AMAZON GO的算法负责人。浙江大学本科毕业,加州大学伯克利分校博士,华盛顿大学计算机系客座教授,CVPR/ICCV/AAAI等会议领域主席,IEEE PAMI副主编。</p>
<p><strong>视觉技术发展及应用</strong></p>
<p>提问:计算机视觉在高精度地图构建中的应用有哪些?</p>
<p><strong>任小枫</strong>:视觉算法对于高精度地图构建是核心的技术,主要应用在资料对齐和精度保证、识别和地图数据自动化生成、视觉定位和高精地图更新等。</p>
<p>提问:您觉得现有的基础学科研究水平与硬件水平能否保证视觉技术的快速发展?视觉技术发展在近期会不会遇到较难突破的瓶颈?</p>
<p><strong>任小枫</strong>:经过了前几年深度学习技术在视觉各个领域的快速发展,一定程度上说,深度学习和视觉的基础技术现在都遇到了瓶颈。或者说,没有开始的时候发展的那么快,有很多难题需要解决,也可能需要创造新的技术。对于应用而言,我觉得基础技术和硬件水平目前大致是够用的,更重要的是如何把技术用好,有针对性的去突破技术瓶颈。</p>
<p>提问:单目标跟踪SOT(给定模版跟踪单个目标,类别无关/可跨域)近两年的进展非常显著,具有解决快速跟踪的潜质,想请问目前有没有在地图业务这边比如视觉定位(VO中跟踪路标)/AR导航(短时跟踪)中应用的前景?如果有的话,请问需要解决什么样的需求问题(鲁棒/速度等)?</p>
<p><strong>任小枫</strong>:跟踪是一个视觉基础技术,在很多场景都有应用。对于导航和出行,确实在AR导航、定位上能起到核心作用,减少识别(检测)的计算需求,并增加鲁棒性和平滑性。但是在很多实际应用中,跟踪的使用和需求和学术界单目标跟踪的设置会有所不同。</p>
<p>提问:视觉特征是否能结合语义给地图的导航出行服务带来更好的体验呢?</p>
<p><strong>任小枫</strong>:视觉可以提供高精度的定位,也可以提供场景的语义理解,肯定可以带来导航和出行更好的体验。但是具体的产品体验和技术实现还需要进一步的探索和积累。</p>
<p>提问:计算机视觉下一步的重难点是哪个方向?未来的前景如何?</p>
<p><strong>任小枫</strong>:计算机视觉是一种通用的感知手段,信息量很大,可以用于多种感知任务,可以远距离观测,应用的前景是很广阔和美好的。下一步的难点,除了基础技术需要进步和突破外。还有:如何找到视觉能发挥核心作用的应用场景,如何根据实际问题综合各类算法设计整体方案,如何较好的解决计算资源的问题,如何结合其他传感器和先验知识等问题。</p>
<p><strong>AR导航</strong></p>
<p>提问:AR导航是实时图像计算的吗?设备算力可以打标吗?</p>
<p><strong>任小枫</strong>:AR导航是实时图像计算,在低算力的条件下实现导航和辅助驾驶功能。我们也尽可能的进行“预计算”,事先计算好环境中的一些元素,来配合实时计算。</p>
<p>提问:AR导航最后通过什么来展示内容?显示屏还是HUD?</p>
<p><strong>任小枫</strong>:AR导航有多种产品形态:中控屏、HUD、后视镜、仪表盘,这些都是正在使用/潜在使用的展示方式。</p>
<p>提问:有一个非技术性的问题,AR导航会不会过度吸引驾驶员的注意力,导致他/她忽略车辆两侧的交通?</p>
<p><strong>任小枫</strong>:这是一个产品设计的好问题,也是我们一直在打磨和寻求平衡的问题。一个设计的好的AR导航产品,会考虑到不过多吸引注意力。</p>
<p>提问:安全辅助驾驶会有疲劳驾驶检测吗?</p>
<p><strong>任小枫</strong>:高德的AR导航目前只有朝外的单目相机,没有支持疲劳驾驶检测。对车内的监控,包括疲劳检测,是视觉技术在安全辅助驾驶的一个重要应用。</p>
<p><strong>定位技术</strong></p>
<p>提问:室内定位现在主流实现技术有哪些?基于声信号的室内导航前景好吗?</p>
<p><strong>任小枫</strong>:室内定位有多种基于传感器的技术,包括WiFi,Bluetooth,RFID,Ultra-Wideband,也包括声信号。我觉得室内定位的发展,如果需要部署传感器,很大程度上不是取决于技术和定位精度,而是是否有好的应用。WiFi定位的普及是因为室内网络需要WiFi。iPhone 11装了UWB芯片可以近距离文件传输。</p>
<p>提问:GPS定位那么大的差距是什么原因导致的?因为多路径效应吗?</p>
<p><strong>任小枫</strong>:GPS定位不准有多个原因,主要是在“城市峡谷”(高楼林立)的场景。多路径效应是其中最重要的因素,因为环境的折射(特别是像玻璃这样的高反光材料),导致GPS位置计算不准。其他方面还有因为楼宇/高架桥的遮挡导致能观察到的卫星数降低,空气(特别是带电离子和水蒸气)的干扰,等多种原因。</p>
<p>提问:高德如何解决GPS漂移的问题?</p>
<p><strong>任小枫</strong>:这是一个复杂的问题。基于手机传感器,我们结合实际的驾驶和步行场景做了很多优化,包括GPS置信度分析,和IMU结合,和路网结合等。视觉定位是我们在开拓的解决定位不准的一个新方向。</p>
<p><strong>地图基础技术</strong></p>
<p>提问:目前高德地图图层有哪些?是语义级高精度地图吗?</p>
<p><strong>任小枫</strong>:高德地图有多种地图数据形态,从标准地图(高德App上看到的),到车道级地图,到高精地图。精度不同,对应的应用不同。多种地图中都有语义信息,但是语义信息的内容和精度会有不同。</p>
<p>提问:深度相机和普通的相机有什么区别?</p>
<p><strong>任小枫</strong>:普通相机获取的信息是二维RGB图像,没有三维信息。深度相机在每个像素上,除了RGB颜色之外,也同时获取深度(距离)信息,一般是利用主动模式(time-of-flight, structured light等)。现在很多主流手机上都已经配备了深度相机。</p>
<p>提问:高德地图对道路信息是怎么采集的,道路有变化地图会实时更新么?</p>
<p><strong>任小枫</strong>:高德地图道路信息有多个来源,主要是依靠低成本的车载视频资料。道路相关信息是在随时变化的,我们会不断的采集最新资料并制作更新地图数据,及时上线应用。</p>
<p>提问:室内三维空间(比如多层的商业大楼)地图绘制的难点有哪些?</p>
<p><strong>任小枫</strong>:室内三维地图绘制最大的难点在于数据采集。三维重建的方法需要有多个角度的图像。基于深度相机的移动建模方法精度上不一定能满足需求。</p>
<p><strong>新人职业成长</strong></p>
<p>提问:从视觉和图像领域的学术研究领域到公司商业计算机视觉应用技术开发需要补充哪些知识?</p>
<p><strong>任小枫</strong>:我觉得主要要考虑的不是补充具体的知识,而是要注意培养自己的各方面的能力:(1)对实际问题的分析和解决的能力;(2)动手能力;(3)快速学习和拓展知识的能力。</p>
<p>提问:从事计算机视觉领域该如何制定职业规划?</p>
<p><strong>任小枫</strong>:和其他行业和技术方向的职业规划没有本质的区别,要结合自身的长/短处和兴趣,找到自己合适的工作方向,逐步提高技术深度,广度,高度,综合能力,一步步做出实际结果发展职业。</p>
<p>提问:请问现在从事视觉领域工作是否一定要具备深度学习的技能?</p>
<p><strong>任小枫</strong>:计算机视觉现在大量的使用深度学习技术,深度学习的知识和技术我觉得是必须的。有一些和几何相关的子领域,比如三维重建、SLAM/VIO,深度学习应用的还不多,但是(1)后续预计会有更多的深度学习应用;(2)从提高技术广度和视野出发,也需要一定程度上了解深度学习。</p>
<p><strong>业界热点及其他</strong></p>
<p>提问:自动驾驶会用到5G技术吗?</p>
<p><strong>任小枫</strong>:目前看来,5G技术会在自动驾驶上有多种应用,但对于L4/L5全自动驾驶,我觉得5G并不能从根本上解决自动驾驶安全性(和舒适性)的难题。</p>
<p>提问:跟踪和定位中的计算端和云如何配合?</p>
<p><strong>任小枫</strong>:大体上来说,实时性要求高的,和传感器结合密切的,会在端上完成;和地图结合密切的,需要用到大量参考数据的,会在云上完成。</p>
<p>提问:谷歌地图有一个街景地图的模块用到了许多图像识别的技术,街景地图怎么拼成的?以及街景发展趋势是怎样的?</p>
<p><strong>任小枫</strong>:谷歌地图的街景地图主要来自于谷歌自己的街景采集车,车上载有高质量的相机和组合惯导等传感器。街景地图主要是一个拼接的过程。街景地图很有意思,但还没有对导航和出行的体验带来根本的变化。谷歌最近的AR步行导航(这个和高德的车载AR导航不同)是基于街景地图的一个新应用。</p>
<p>提问:可穿戴设备(类似眼镜、智慧助手等)在视觉技术上如何更好的落地以及产品化?</p>
<p><strong>任小枫</strong>:硬件(AR展示,算力)和体验是可穿戴设备要真正落地和普及的主要问题。Google Glass作为一个超前的产品,在硬件上受限制太大。目前AR眼镜的应用主要在企业场景。我个人觉得可穿戴设备作为个人助手(包括导航,信息展示等)的应用前景是很好的,但现在硬件条件可能还不成熟。</p>
<p><img src="/img/remote/1460000022504478" alt="" title=""></p>
高德APP启动耗时剖析与优化实践(iOS篇)
https://segmentfault.com/a/1190000022431156
2020-04-20T15:03:41+08:00
2020-04-20T15:03:41+08:00
高德技术
https://segmentfault.com/u/amap_tech
6
<p><strong>前言</strong><br>最近高德地图APP完成了一次启动优化专项,超预期将双端启动的耗时都降低了65%以上,iOS在iPhone7上速度达到了400毫秒以内。就像产品们用后说的,快到不习惯。算一下每天为用户省下的时间,还是蛮有成就感的,本文做个小结。</p>
<p><img src="/img/remote/1460000022431164" alt="" title=""></p>
<p><img src="/img/remote/1460000022431163" alt="" title=""></p>
<p>(文中配图均为多才多艺的技术哥哥手绘)</p>
<p><strong>启动阶段性能多维度分析</strong></p>
<p>要优化,首先要做到的是对启动阶段的各个性能纬度做分析,包括主线程耗时、CPU、内存、I/O、网络。这样才能更加全面的掌握启动阶段的开销,找出不合理的方法调用。</p>
<p>启动越快,更多的方法调用就应该做成按需执行,将启动压力分摊,只留下那些启动后方法都会依赖的方法和库的初始化,比如网络库、Crash库等。而剩下那些需要预加载的功能可以放到启动阶段后再执行。</p>
<p>启动有哪几种类型,有哪些阶段呢?</p>
<p>启动类型分为:</p>
<ul>
<li>Cold:APP重启后启动,不在内存里也没有进程存在。</li>
<li>Warm:APP最近结束后再启动,有部分在内存但没有进程存在。</li>
<li>Resume:APP没结束,只是暂停,全在内存中,进程也存在。</li>
</ul>
<p>分析阶段一般都是针对Cold类型进行分析,目的就是要让测试环境稳定。为了稳定测试环境,有时还需要找些稳定的机型,对于iOS来说iPhone7性能中等,稳定性也不错就很适合,Android的Vivo系列也相对稳定,华为和小米系列数据波动就比较大。</p>
<p>除了机型外,控制测试机温度也很重要,一旦温度过高系统还会降频执行,影响测试数据。有时候还会设置飞行模式采用Mock网络请求的方式来减少不稳定的网络影响测试数据。最好是重启后退iCloud账号,放置一段时间再测,更加准确些。</p>
<p>了解启动阶段的目的就是聚焦范围,从用户体验上来确定哪个阶段要快,以便能够让用户可视和响应用户操作的时间更快。</p>
<p>简单来说iOS启动分为加载Mach-O和运行时初始化过程,加载Mach-O会先判断加载的文件是不是Mach-O,通过文件第一个字节,也叫魔数来判断,当是下面四种时可以判定是Mach-O文件:</p>
<ul>
<li>0xfeedface对应的loader.h里的宏是MH_MAGIC</li>
<li>0xfeedfact宏是MH_MAGIC_64</li>
<li>NXSwapInt(MH_MAGIC)宏MH_GIGAM</li>
<li>NXSwapInt(MH_MAGIC_64)宏MH_GIGAM_64</li>
</ul>
<p>Mach-O主要分为:</p>
<ul>
<li>中间对象文件(MH_OBJECT)</li>
<li>可执行二进制(MH_EXECUTE)</li>
<li>VM 共享库文件(MH_FVMLIB)</li>
<li>Crash 产生的Core文件(MH_CORE)</li>
<li>preload(MH_PRELOAD)</li>
<li>动态共享库(MH_DYLIB)</li>
<li>动态链接器(MH_DYLINKER)</li>
<li>静态链接文件(MH_DYLIB_STUB)符号文件和调试信息(MH_DSYM)这几种。</li>
</ul>
<p>确定是Mach-O后,内核会fork一个进程,execve开始加载。检查Mach-O Header。随后加载dyld和程序到Load Command地址空间。通过 dyld_stub_binder开始执行dyld,dyld会进行rebase、binding、lazy binding、导出符号,也可以通过DYLD_INSERT_LIBRARIES进行hook。</p>
<p>dyld_stub_binder给偏移量到dyld解释特殊字节码Segment中,也就是真实地址,把真实地址写入到la_symbol_ptr里,跳转时通过stub的jump指令跳转到真实地址。dyld加载所有依赖库,将动态库导出的trie结构符号执行符号绑定,也就是non lazybinding,绑定解析其他模块功能和数据引用过程,就是导入符号。</p>
<p>Trie也叫数字树或前缀树,是一种搜索树。查找复杂度O(m),m是字符串的长度。和散列表相比,散列最差复杂度是O(N),一般都是 O(1),用 O(m)时间评估 hash。散列缺点是会分配一大块内存,内容越多所占内存越大。Trie不仅查找快,插入和删除都很快,适合存储预测性文本或自动完成词典。</p>
<p>为了进一步优化所占空间,可以将Trie这种树形的确定性有限自动机压缩成确定性非循环有限状态自动体(DAFSA),其空间小,做法是会压缩相同分支。</p>
<p>对于更大内容,还可以做更进一步的优化,比如使用字母缩减的实现技术,把原来的字符串重新解释为较长的字符串;使用单链式列表,节点设计为由符号、子节点、下一个节点来表示;将字母表数组存储为代表ASCII字母表的256位的位图。</p>
<p>尽管Trie对于性能会做很多优化,但是符号过多依然会增加性能消耗,对于动态库导出的符号不宜太多,尽量保持公共符号少,私有符号集丰富。这样维护起来也方便,版本兼容性也好,还能优化动态加载程序到进程的时间。</p>
<p>然后执行attribute的constructor函数。举个例子:</p>
<pre><code>#include <stdio.h>
\_\_attribute\_\_((constructor))
static void prepare() {
printf("%s\\n", "prepare");
}
\_\_attribute\_\_((destructor))
static void end() {
printf("%s\\n", "end");
}
void showHeader() {
printf("%s\\n", "header");
}
</code></pre>
<p>运行结果:</p>
<pre><code>ming@mingdeMacBook-Pro macho\_demo % ./main "hi"
prepare
hi
end</code></pre>
<p>运行时初始化过程分为:</p>
<ul>
<li>加载类扩展。</li>
<li>加载C++静态对象。</li>
<li>调用+load函数。</li>
<li>执行main函数。</li>
<li>Application初始化,到applicationDidFinishLaunchingWithOptions执行完。</li>
<li>初始化帧渲染,到viewDidAppear执行完,用户可见可操作。</li>
</ul>
<p><img src="/img/remote/1460000022431166" alt="" title=""></p>
<p>也就是说对启动阶段的分析以viewDidAppear为截止。这次优化之前已经对Application初始化之前做过优化,效果并不明显,没有本质的提高,所以这次主要针对Application初始化到viewDidAppear这个阶段各个性能多纬度进行分析。</p>
<p>工具的选择其实目前看来是很多的,Apple提供的System Trace会提供全面系统的行为,可以显示底层系统线程和内存调度情况,分析锁、线程、内存、系统调用等问题。总的来说,通过System Trace能清楚知道每时每刻APP对系统资源的使用情况。</p>
<p>System Trace能查看线程的状态,可以了解高优线程使用相对于CPU数量是否合理,可以看到线程在执行、挂起、上下文切换、被打断还是被抢占的情况。虚拟内存使用产生的耗时也能看到,比如分配物理内存,内存解压缩,无缓存时进行缓存的耗时等。甚至是发热情况也能看到。</p>
<p>System Trace还提供手动打点进行信息显式,在你的代码中导入sys/kdebug_signpost.h后,配对kdebug_signpost_start和kdebug_signpost_end就可以了。这两个方法有五个参数,第一个是id,最后一个是颜色,中间都是预留字段。</p>
<p>Xcode11开始XCTest还提供了测量性能的Api。苹果在<a href="https://link.segmentfault.com/?enc=78K9eu0822SUDanIeGq%2Bvw%3D%3D.gLeSVOmxO8L3PGoxiANhw6DM8brJ2rAUlskTkIVoBrxkodvrZoxf%2BxjEttW8BSaoZc7WzFQL0XVj4BbX6%2FVjXQ%3D%3D" rel="nofollow">2019年WWDC启动优化专题</a>:</p>
<p>也介绍了Instruments里的最新模板App launch如何分析启动性能。但是要想达到对启动数据进行留存取均值、Diff、过滤、关联分析等自动化操作,App launch目前还没法做到。</p>
<p>下面针对主线程耗时、CPU、网络、内存、I/O 等多维度进行分析:</p>
<p><img src="/img/remote/1460000022431160" alt="" title=""></p>
<ul><li>主线程耗时</li></ul>
<p>多个纬度性能分析中最重要、最终用户体感到的是主线程耗时分析。对主线程方法耗时可以直接使用Massier,这是<a href="https://link.segmentfault.com/?enc=lr1xA68Bg0OR66mxNPoTWQ%3D%3D.LiovQe4O9E84mvCuDWAmsRSkJ5JTfyRU3FQPLqU50B%2Fgr4s1dYOyYOWUY8vuXRdS" rel="nofollow">everettjf开发的一个Objective-C方法跟踪工具</a>:</p>
<p>生成trace json进行分析,或者参看这个代码</p>
<p><a href="https://link.segmentfault.com/?enc=vl8N%2BR18bA9hdWcZT4uqrw%3D%3D.DrMUzFP7OMs%2BOvjLMhe4phcT0UChG29Kw2ke6i%2BHQPhGVbLSlXc7prLOeyiFpQnNESLYtvWbtIoxYlUfJ%2FTG4tZC0J22bVU5e%2FmIim%2BaKjJPsHJSHOxXpkXx0oXH%2BQK%2F2sLPlP5nfBX9zXsyV0S5ToK8BDBWU2SiLp1mCpr5%2Bvg%3D" rel="nofollow">GCDFetchFeed/SMCallTraceCore.c at master · ming1016/GCDFetchFeed · GitHub</a></p>
<p>自己手动hook objc_msgSend生成一份Objective-C方法耗时数据进行分析。还有种插桩方式,可以解析IR(加快编译速度),然后在每个方法前后插入耗时统计函数。</p>
<p>文章后面我会着重介绍如何开发工具进一步分析这份数据,以达到监控启动阶段方法耗时的目的。</p>
<p>hook所有的方法调用,对详细分析时很有用,不过对于整个启动时间影响很大,要想获取启动每个阶段更准确的时间消耗还需要依赖手动埋点。</p>
<p>为了更好的分析启动耗时问题,手动埋点也会埋的越来越多,也会影响启动时间精确度,特别是当团队很多,模块很多时,问题会突出。但是每个团队在排查启动耗时往往只会关注自己或相关某几个模块的分析,基于此,可以把不同模块埋点分组,灵活组合,这样就可以照顾到多种需求了。</p>
<ul><li>CPU</li></ul>
<p>为什么分析启动慢除了分析主线程方法耗时外,还要分析其它纬度的性能呢?</p>
<p>我们先看看启动慢的表现,启动慢意味着界面响应慢、网络慢(数据量大、请求数多)、CPU超负荷降频(并行任务多、运算多),可以看出影响启动的因素很多,还需要全面考虑。</p>
<p>对于CPU来说,WWDC的</p>
<p><a href="https://link.segmentfault.com/?enc=rUVbpxPRmoqJzViTNsvotA%3D%3D.C8Nztwrag5RRj0gM5rN5d3NxKULtChWzdagu93emlToId97M1HR2po5U9c7bmj55IpLvlMIv2RDSsJqLmAxQFQ%3D%3D" rel="nofollow">What’s New in Energy Debugging - WWDC 2018 - Videos - Apple Developer</a></p>
<p>介绍了用Energy Log来查CPU耗电,当前台三分钟或后台一分钟CPU线程连续占用80%以上就判定为耗电,同时记录耗电线程堆栈供分析。还有一个MetrickKit专门用来收集电源和性能统计数据,每24小时就会对收集的数据进行汇总上报,Mattt在<a href="https://link.segmentfault.com/?enc=zs%2BOqfQ8NuEE%2B%2BJcnK9Xsw%3D%3D.vpVb6c6JIO2dVvYwAeh5T8x%2F3P3koFlXtyLhn6TptLEAlUFHus3tB7FVeLjJbzJk" rel="nofollow">NShipster网站上也发了篇文章</a>专门进行介绍:</p>
<p>那么,CPU的详细使用情况如何获取呢?也就是说哪个方法用了多少CPU。</p>
<p>有好几种获取详细CPU使用情况的方法。线程是计算机资源调度和分配的基本单位。CPU使用情况会提现到线程这样的基本单位上。task_theads的act_list数组包含所有线程,使用thread_info的接口可以返回线程的基本信息,这些信息定义在thread_basic_info_t结构体中。这个结构体内的信息包含了线程运行时间、运行状态以及调度优先级,其中也包含了CPU使用信息cpu_usage。</p>
<p>获取方式参看:</p>
<p><a href="https://link.segmentfault.com/?enc=kEnEpP6xMG8iyCqCi2mSaw%3D%3D.zawrEPuywF1ya%2BglB7mmrsxn%2FaueI9jdYHwaUjJHtlhc%2B21eYqhZ0D%2FjbCXjA5IHAIKtR2llBjM%2B8BeCmFl6%2Ftyjbihrbcacv%2BbvSNyB4QyryP%2BSm8TJj%2FVNwNthGA7i" rel="nofollow">objective c - Get detailed iOS CPU usage with different states - Stack Overflow</a></p>
<p><a href="https://link.segmentfault.com/?enc=UxeCWhUISRzg%2FgihYsVIqQ%3D%3D.xPeIedffcVWIN43t89EFp7T3jUV6QDzaFi0eTVtUUDA%3D" rel="nofollow">GT GitHub - Tencent/GT</a></p>
<p>也有获取CPU的代码。</p>
<p>整体CPU占用率可以通过host_statistics函数取到host_cpu_load_info,其中cpu_ticks数组是CPU运行的时钟脉冲数量。通过cpu_ticks数组里的状态,可以分别获取CPU_STATE_USER、CPU_STATE_NICE、CPU_STATE_SYSTEM这三个表示使用中的状态,除以整体CPU就可以取到CPU的占比。</p>
<p>通过NSProcessInfo的activeProcessorCount还可以得到CPU的核数。线上数据分析时会发现相同机型和系统的手机,性能表现却截然不同,这是由于手机过热或者电池损耗过大后系统降低了CPU频率所致。</p>
<p>所以,如果取得CPU频率后也可以针对那些降频的手机来进行针对性的优化,以保证流畅体验。获取方式可以参考:</p>
<p><a href="https://link.segmentfault.com/?enc=NfjxX%2FUGqQv0Kdku65X1jQ%3D%3D.uHokkPRhVTbKJ1OkP3iIWa32hk7d6%2FOcfKf0fSSWmD4tNvNJ%2Bqbx%2BskkJCCYAMZhQ0p%2FXN8fEyjH%2BiIpesq6qg%3D%3D" rel="nofollow">https://github.com/zenny-chen...</a></p>
<ul><li>内存</li></ul>
<p>要想获取APP真实的内存使用情况可以查<a href="https://link.segmentfault.com/?enc=UMl6zrguuK1kOApdKNxtxg%3D%3D.m1jkTbcTZbhEsUVgV4S213rfTyvD9pJBfIYa8Gco%2FleofUrGX4SsbsRAekW%2BPR8P2yJCsBjGLSmW27GAuqzhLDIlj14sw6qvkYccFlEjQkfsq8TCk%2F2csREQpQQjt%2BdKHZYfEmNHeQHeDgwazHUeDcqlwMpyOxMEn7%2FTnQjQ81Y%3D" rel="nofollow">看WebKit的源码</a>:</p>
<p>JetSam会判断APP使用内存情况,超出阈值就会杀死APP,JetSam获取阈值的<a href="https://link.segmentfault.com/?enc=JdlodOHRhG5D0CQVHGmSog%3D%3D.%2Fzso%2BtvC1VJXIruliDk7bLO7T2t8vDlR4xFdcPJHS4SYyUYKizUBdj6Ff3vJzhcjsWanJIB1fA7LSsSNmbborGyPsePPmnS8%2Fd98cyXm%2BN8sk4xFQjunILqM%2BHLNIKcFDxMfLMJ5Ucn7BoegN2jG9Q%3D%3D" rel="nofollow">代码在这里</a>:</p>
<p>整个设备物理内存大小可以通过NSProcessInfo的physicalMemory来获取。</p>
<ul><li>网络</li></ul>
<p>对于网络监控可以使用Fishhook这样的工具Hook网络底层库CFNetwork。网络的情况比较复杂,所以需要定些和时间相关的关键的指标,指标如下:</p>
<ul>
<li>DNS时间</li>
<li>SSL时间</li>
<li>首包时间</li>
<li>响应时间</li>
</ul>
<p>有了这些指标才能够有助于更好的分析网络问题。启动阶段的网络请求是非常多的,所以HTTP的性能是非常要注意的。以下是WWDC网络相关的Session:</p>
<p><a href="https://link.segmentfault.com/?enc=QTK9HNmyNtCcS%2FTDZwSEUg%3D%3D.rMUKifcHS7m8wv08xQtWE%2BvIHo9Xe0TI9Yq5P5JUSMNl0lLyJQp1WeuFiwYHEE7eqjyr4T8798JfOGmMBk0IRA%3D%3D" rel="nofollow">Your App and Next Generation Networks - WWDC 2015 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=MagXj6QRdG9WS3hDUdr0Qg%3D%3D.WTmxcU0m05ro46lO5e8y9NoxsmQe0uRqA5%2BXLPWE7ahNy4%2Fzc2IsBe4YJeFirLI%2FCn3SqBzh2i2%2FHNIl5aWKhw%3D%3D" rel="nofollow">Networking with NSURLSession - WWDC 2015 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=3mx3WBF5qqv8U%2BXRIk9YQw%3D%3D.GG7vG0ijKdnrTxwCQGyFHyo19mILSgYfNu0nEz3bZ1pDzeoYVdqwuKBvNtzaCDIEiseu7C5n9bCDNqYVOnydPg%3D%3D" rel="nofollow">Networking for the Modern Internet - WWDC 2016 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=DyW2mQ8NX%2BKxZFgb%2FeSWvg%3D%3D.NqKygs6fgMwytyV0KbekO32qNSGHyUub7dkPUVYuQi7RoDEZWiq4ABxFPEfn3Zh6sIo6IBsd4cZhY7cMGGXFgw%3D%3D" rel="nofollow">Advances in Networking, Part 1 - WWDC 2017 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=86ZBDsKrgz80cGxqoEakAg%3D%3D.dqbKkSI2dXJIr0Zr6YIKH4xRyde1oWUCfUcpaFsphuWGNTPBMRtuSPrCh77I3C0UTlNidGsTgkJIeEa9i1ZTTw%3D%3D" rel="nofollow">Advances in Networking, Part 2 - WWDC 2017 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=TU9AXKwZtJJJGzmPFlRomQ%3D%3D.y%2F5Uq3eVkv6IBh98keE9RkTuXoCiHLr5z5aWwZLM6HWG3UJ1ZtaPxOWr91OvNJ2ULdMut2ZNIgTwoIA1yldgyA%3D%3D" rel="nofollow">Optimizing Your App for Today’s Internet - WWDC 2018 - Videos - Apple Developer</a></p>
<ul><li>I/O</li></ul>
<p>对于I/O可以使用</p>
<p><a href="https://link.segmentfault.com/?enc=H5bGrzUvbljFbN5%2BrF74TA%3D%3D.uQd0ZN90OGX5%2BLZluv8pqEApmniNG6wmGrR9trBHC9w%3D" rel="nofollow">Frida • A world-class dynamic instrumentation framework | Inject JavaScript to explore native apps on Windows, macOS, GNU/Linux, iOS, Android, and QNX</a></p>
<p>这种动态二进制插桩技术,在程序运行时去插入自定义代码获取I/O的耗时和处理的数据大小等数据。Frida还能够在其它平台使用。</p>
<p>关于多维度分析更多的资料可以看看历届WWDC的介绍。下面我列下16年来 WWDC关于启动优化的Session,每场都很精彩。</p>
<p><a href="https://link.segmentfault.com/?enc=WHlfnSWfS4rVpeoRjrHImw%3D%3D.rsuImPRyMNVuUflcbOELu0i3aRGw1PCsep04clIGEqOjZ8EInkGxTgzybzE19YvM8mDELabnt3nfE5lVJ0fLpQ%3D%3D" rel="nofollow">Using Time Profiler in Instruments - WWDC 2016 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=1SAclbeoNou0x5ZZpVNxAQ%3D%3D.2nZKfU4QiCSPcFiZJIAvgKz4F1bq4VGObyTUC%2FfYThXVXcKD4jYKPszk%2FLwU%2B5pv4v7%2BioLLH6o6cD5v2Y4pow%3D%3D" rel="nofollow">Optimizing I/O for Performance and Battery Life - WWDC 2016 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=Ij2BS5z63B%2BpPzx%2FFHeUkA%3D%3D.UZfntmNjyQBePkYU%2BZukpIphusnEtIZx3yVRwt0n7LLDvtpifDQh8UC8Rg6YKfoqs74i%2BDRpD6LbpbE8oxhxLg%3D%3D" rel="nofollow">Optimizing App Startup Time - WWDC 2016 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=8xtT4SFoxDUK7DgSz8Qpbg%3D%3D.6dtLM2yLk887NwPuNEoRWOvidi%2FWbvYhX4QoqOmHu5L0CK0TIwi4SMm9Y1YSk4kARQ7837zdZPZ9cyGxB8RcGQ%3D%3D" rel="nofollow">App Startup Time: Past, Present, and Future - WWDC 2017 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=3xTh8qgigBGdmhnA6CqFkw%3D%3D.nw3XqeIUIXFoEGotOFzvS4%2FH2IMabNZzNWLVunyBud4lyrNNUzd6tUtdYHk9ZlFkJQun2f7V%2BPF9qz4Q2GRPUA%3D%3D" rel="nofollow">Practical Approaches to Great App Performance - WWDC 2018 - Videos - Apple Developer</a></p>
<p><a href="https://link.segmentfault.com/?enc=aQZiF0pg4ZKwFwxPIWtZNw%3D%3D.csZTtZ%2BlCAfwkxZpylwTFg3AmcPU%2BzFzgSs7oYAb3FDVpZlkdxmMV3asEgKEFCEKT1%2BYkIgFstQbZp6yVcNYhg%3D%3D" rel="nofollow">Optimizing App Launch - WWDC 2019 - Videos - Apple Developer</a></p>
<p><strong>延后任务管理</strong></p>
<p><img src="/img/remote/1460000022431165" alt="" title=""></p>
<p>经过前面所说的对主线程耗时方法和各个纬度性能分析后,对于那些分析出来没必要在启动阶段执行的方法,可以做成按需或延后执行。</p>
<p>任务延后的处理不能粗犷的一口气在启动完成后在主线程一起执行,那样用户仅仅只是看到了页面,依然没法响应操作。那该怎么做呢?套路一般是这样,创建四个队列,分别是:</p>
<ul>
<li>异步串行队列</li>
<li>异步并行队列</li>
<li>闲时主线程串行队列</li>
<li>闲时异步串行队列</li>
</ul>
<p>有依赖关系的任务可以放到异步串行队列中执行。异步并行队列可以分组执行,比如使用dispatch_group,然后对每组任务数量进行限制,避免CPU、线程和内存瞬时激增影响主线程用户操作,定义有限数量的串行队列,每个串行队列做特定的事情,这样也能够避免性能消耗短时间突然暴涨引起无法响应用户操作。使用dispatch_semaphore_t在信号量阻塞主队列时容易出现优先级反转,需要减少使用,确保QoS传播。可以用dispatch group替代,性能一样,功能不差。异步编程可以直接GCD接口来写,也可以使用阿里的协程框架</p>
<p><a href="https://link.segmentfault.com/?enc=bM94XSZQpZoFyTUHi%2B3jNw%3D%3D.%2Fu4dAJ9BwW6Cs0sOcojZcbc52hxExHQfMmqePwCwb6FJNY%2BXQ9UOscP3JCb54wOh" rel="nofollow">coobjc GitHub - alibaba/coobjc</a></p>
<p>闲时队列实现方式是监听主线程runloop状态,在kCFRunLoopBeforeWaiting时开始执行闲时队列里的任务,在kCFRunLoopAfterWaiting时停止。</p>
<p><strong>优化后如何保持?</strong></p>
<p>攻易守难,就像刚到新团队时将包大小减少了48兆,但是一年多一直能够守住,除了决心还需要有手段。对于启动优化来说,将各个性能纬度通过监控的方式盯住是必要的,但是发现问题后快速、便捷的定位到问题还是需要找些突破口。我的思路是将启动阶段方法耗时多的按照时间线一条一条排出来,每条包括方法名、方法层级、所属类、所属模块、维护人。考虑到便捷性,最好还能方便的查看方法代码内容。</p>
<p>接下来我通过开发一个工具,详细介绍下怎么实现这样的效果。</p>
<ul><li>解析json</li></ul>
<p>如前面所说在输出一份Chrome trace规范的方法耗时json后,先要解析这份数据。这份json数据类似下面的样子:</p>
<pre><code> {"name":"\[SMVeilweaa\]upVeilState:","cat":"catname","ph":"B","pid":2381,"tid":0,"ts":21},
{"name":"\[SMVeilweaa\]tatLaunchState:","cat":"catname","ph":"B","pid":2381,"tid":0,"ts":4557},
{"name":"\[SMVeilweaa\]tatTimeStamp:state:","cat":"catname","ph":"B","pid":2381,"tid":0,"ts":4686},
{"name":"\[SMVeilweaa\]tatTimeStamp:state:","cat":"catname","ph":"E","pid":2381,"tid":0,"ts":4727},
{"name":"\[SMVeilweaa\]tatLaunchState:","cat":"catname","ph":"E","pid":2381,"tid":0,"ts":5732},
{"name":"\[SMVeilweaa\]upVeilState:","cat":"catname","ph":"E","pid":2381,"tid":0,"ts":5815},
…</code></pre>
<p>通过Chrome的Trace-Viewer可以生成一个火焰图。其中name字段包含了类、方法和参数的信息,cat字段可以加入其它性能数据,ph为B表示方法开始,为E表示方法结束,ts字段表示。</p>
<p>很多工程在启动阶段会执行大量方法,很多方法耗时很少,可以过滤那些小于10毫秒的方法,让分析更加聚焦。</p>
<p><img src="/img/remote/1460000022431161" alt="" title=""></p>
<p>耗时的高低也做了颜色的区分。外部耗时指的是子方法以外系统或没源码的三方方法的耗时,规则是父方法调用的耗时减去其子方法总耗时。</p>
<p>目前为止通过过滤耗时少的方法调用,可以更容易发现问题方法。但是,有些方法单次执行耗时不多,但是会执行很多次,累加耗时会大,这样的情况也需要体现在展示页面里。另外外部耗时高时或者碰到自己不了解的方法时,是需要到工程源码里去搜索对应的方法源码进行分析的,有的方法名很通用时还需要花大量时间去过滤无用信息。</p>
<p>因此接下来还需要做两件事情,首先累加方法调用次数和耗时,体现在展示页面中,另一个是从工程中获取方法源码能够在展示页面中进行点击显示。</p>
<p>完整思路如下图:</p>
<p><img src="/img/remote/1460000022431162" alt="" title=""></p>
<ul><li>展示方法源码</li></ul>
<p>在页面上展示源码需要先解析.xcworkspace文件,通过.xcworkspace文件取到工程里所有的.xcodeproj文件。分析.xcodeproj文件取到所有.m和.mm源码文件路径,解析源码,取到方法的源码内容进行展示。</p>
<p>解析.xcworkspace</p>
<p>开.xcworkspace,可以看到这个包内主要文件是contents.xcworkspacedata。内容是一个xml:</p>
<pre><code><?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:GCDFetchFeed.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace></code></pre>
<p><img src="/img/remote/1460000022431170" alt="" title=""></p>
<p>解析.xcodeproj</p>
<p><img src="/img/remote/1460000022431172" alt="" title=""></p>
<p>通过XML的解析可以获取FileRef节点内容,xcodeproj的文件路径就在FileRef节点的location属性里。每个xcodeproj文件里会有project工程的源码文件。为了能够获取方法的源码进行展示,那么就先要取出所有project工程里包含的源文件的路径。</p>
<p>xcodeproj的文件内容看起来大概是下面的样子。</p>
<p><img src="/img/remote/1460000022431168" alt="" title=""></p>
<p>其实内容还有很多,需要一个个解析出来。</p>
<p>考虑到xcodeproj里的注释很多,也都很有用,因此会多设计些结构来保存值和注释。思路是根据XcodeprojNode的类型来判断下一级是key value结构还是array结构。如果XcodeprojNode的类型是dicStart表示下级是key value结构。如果类型是arrStart就是array结构。当碰到类型是dicEnd,同时和最初dicStart是同级时,递归下一级树结构。而arrEnd不用递归,xcodeproj里的array只有值类型的数据。</p>
<p>有了基本节点树结构以后就可以设计xcodeproj里各个section的结构。主要有以下的section:</p>
<ul>
<li>PBXBuildFile:文件,最终会关联到PBXFileReference。</li>
<li>PBXContainerItemProxy:部署的元素。</li>
<li>PBXFileReference:各类文件,有源码、资源、库等文件。</li>
<li>PBXFrameworksBuildPhase:用于framework的构建。</li>
<li>PBXGroup:文件夹,可嵌套,里面包含了文件与文件夹的关系。</li>
<li>PBXNativeTarget:Target的设置。</li>
<li>PBXProject:Project的设置,有编译工程所需信息。</li>
<li>PBXResourcesBuildPhase:编译资源文件,有xib、storyboard、plist以及图片等资源文件。</li>
<li>PBXSourcesBuildPhase:编译源文件(.m)。</li>
<li>PBXTargetDependency:Taget的依赖。</li>
<li>PBXVariantGroup:.storyboard文件。</li>
<li>XCBuildConfiguration:Xcode编译配置,对应Xcode的Build Setting面板内容。</li>
<li>XCConfigurationList:构建配置相关,包含项目文件和target文件。</li>
</ul>
<p>得到section结构Xcodeproj后,就可以开始分析所有源文件的路径了。根据前面列出的section的说明,PBXGroup包含了所有文件夹和文件的关系,Xcodeproj的pbxGroup字段的key是文件夹,值是文件集合,因此可以设计一个结构体XcodeprojSourceNode用来存储文件夹和文件关系。</p>
<p>接下来需要取得完整的文件路径。通过recusiveFatherPaths函数获取文件夹路径。这里需要注意的是需要处理 ../ 这种文件夹路径符。</p>
<p>解析.m .mm文件</p>
<p><img src="/img/remote/1460000022431167" alt="" title=""></p>
<p>对Objective-C解析可以参考LLVM,这里只需要找到每个方法对应的源码,所以自己也可以实现。分词前先看看LLVM是怎么定义token的。定义文件<a href="https://link.segmentfault.com/?enc=dnDq7zcUMTw%2B%2FouCL9hzpA%3D%3D.akZbB%2BER%2BHvEVq1tbEyhhhHmaSCmFCRooD91QQiP2OJ8Jfvdn6pkgffYLIfhd0hOOPq4E2ahXDZxQtA3Pn2aS80B4WUzq2R24ZScKI4OIDB5XlkAF%2BFQavqy39dSVfmtlPalAuM0fUTN31cu5KVLGA%3D%3D" rel="nofollow">在这里</a>:</p>
<p>根据这个定义我设计了token的结构体,主体部分如下:</p>
<pre><code>// 切割符号 \[\](){}.&=\*+-<>~!/%^|?:;,#@
public enum OCTK {
case unknown // 不是 token
case eof // 文件结束
case eod // 行结束
case codeCompletion // Code completion marker
case cxxDefaultargEnd // C++ default argument end marker
case comment // 注释
case identifier // 比如 abcde123
case numericConstant(OCTkNumericConstant) // 整型、浮点 0x123,解释计算时用,分析代码时可不用
case charConstant // ‘a’
case stringLiteral // “foo”
case wideStringLiteral // L”foo”
case angleStringLiteral // <foo> 待处理需要考虑作为小于符号的问题
// 标准定义部分
// 标点符号
case punctuators(OCTkPunctuators)
// 关键字
case keyword(OCTKKeyword)
// @关键字
case atKeyword(OCTKAtKeyword)
}</code></pre>
<p>完整的定义在这里:</p>
<p><a href="https://link.segmentfault.com/?enc=%2BjdrWabdOFEEsDEI9yug9g%3D%3D.34P7zz%2B6X60cR4Uqm7V%2F5KkhZHuTJXI%2BaQ96aAAupSfTUtcucPdljZyDBzxP2hCgxjxNpNhveO9aloKAR2otskW1XWddsZhomw89adHYYoxVKlp%2FXEKs6nHjW2pqaMNDbbrWz9gBdlpZm6Mfdz7t6w%3D%3D" rel="nofollow">MethodTraceAnalyze/ParseOCTokensDefine.swift</a></p>
<p>分词过程可以参看LLVM的实现:</p>
<p><a href="https://link.segmentfault.com/?enc=WdJ2EWAhkyBcgkNGkjMf9A%3D%3D.wdEjmrUwNu6EzXsp0dv%2F%2BvYhgBLDh3m%2FYH9DzYtwCNG5Y3bDs22P3e2b6q1%2FztyCiHCmKKp2R3MJTXMY5ZyCFQ%3D%3D" rel="nofollow">clang: lib/Lex/Lexer.cpp Source File</a></p>
<p>我在处理分词时主要是按照分隔符一一对应处理,针对代码注释和字符串进行了特殊处理,一个注释一个token,一个完整字符串一个token。我分词实现代码:</p>
<p><a href="https://link.segmentfault.com/?enc=TJrW64eB8H6uSTRW6l6hBQ%3D%3D.VWyUtqvW2CjXdHgbqv18j9odI0l1De3ulaBIQH9SMVv30FjTuYcdFbxGBpda7bnaod77RdxpEPQ3PXKmHmZSU1i67%2FZeeyc3hjkCguVZh7pfatqWyDjIG7B8EmU3sTBpxVEp5U7HyeYqNXHssnX4yw%3D%3D" rel="nofollow">MethodTraceAnalyze/ParseOCTokens.swift</a></p>
<p>由于只要取到类名和方法里的源码,所以语法分析时,只需要对类定义和方法定义做解析就可以,语法树中节点设计:</p>
<pre><code>// OC 语法树节点
public struct OCNode {
public var type: OCNodeType
public var subNodes: \[OCNode\]
public var identifier: String // 标识
public var lineRange: (Int,Int) // 行范围
public var source: String // 对应代码
}
// 节点类型
public enum OCNodeType {
case \`default\`
case root
case \`import\`
case \`class\`
case method
}</code></pre>
<p>其中lineRange记录了方法所在文件的行范围,这样就能够从文件中取出代码,并记录在source字段中。</p>
<p>解析语法树需要先定义好解析过程的不同状态:</p>
<pre><code>private enum RState {
case normal
case eod // 换行
case methodStart // 方法开始
case methodReturnEnd // 方法返回类型结束
case methodNameEnd // 方法名结束
case methodParamStart // 方法参数开始
case methodContentStart // 方法内容开始
case methodParamTypeStart // 方法参数类型开始
case methodParamTypeEnd // 方法参数类型结束
case methodParamEnd // 方法参数结束
case methodParamNameEnd // 方法参数名结束
case at // @
case atImplementation // @implementation
case normalBlock // oc方法外部的 block {},用于 c 方法
}</code></pre>
<p>完整解析出方法所属类、方法行范围的代码在这里:</p>
<p><a href="https://link.segmentfault.com/?enc=SVBa1fJwkK%2BOkwsnFl4i2w%3D%3D.2JOdAaI67VSJ%2BzdfBObDQNUZfHAuS2a5trhzKrpiJsDaiae33e2l2hHaHKFVeFQEjNqdD2UWgZflfTYq6azP4oQTrwUwdk4abuh8QXRoUTR7xNEY%2F1V38e5aslxcmwHFA%2BafZX9lvCtXkbixEH%2FQ6g%3D%3D" rel="nofollow">MethodTraceAnalyze/ParseOCNodes.swift</a></p>
<p>解析.m和.mm文件,一个一个串行解的话,对于大工程,每次解的速度很难接受,所以采用并行方式去读取解析多个文件。经过测试,发现每组在60个以上时能够最大利用我机器(2.5 GHz双核Intel Core i7)的CPU,内存占用只有60M,一万多.m文件的工程大概2分半能解完。</p>
<p>使用的是dispatch group的wait,保证并行的一组完成再进入下一组。</p>
<p><img src="/img/remote/1460000022431171" alt="" title=""></p>
<p>现在有了每个方法对应的源码,接下来就可以和前面trace的方法对应上。页面展示只需要写段js就能够控制点击时展示对应方法的源码。</p>
<p>页面展示</p>
<p>在进行HTML页面展示前,需要将代码里的换行和空格替换成HTML里的对应的和 。</p>
<pre><code>let allNodes = ParseOC.ocNodes(workspacePath: “/Users/ming/Downloads/GCDFetchFeed/GCDFetchFeed/GCDFetchFeed.xcworkspace”)
var sourceDic = \[String:String\]()
for aNode in allNodes {
sourceDic\[aNode.identifier\] = aNode.source.replacingOccurrences(of: “\\n”, with: “</br>”).replacingOccurrences(of: “ “, with: “&nbsp;”)
}</code></pre>
<p>用p标签作为源码展示的标签,方法执行顺序的编号加方法名作为p标签的id,然后用display: none; 将p标签隐藏。方法名用a标签,click属性执行一段js代码,当a标签点击时能够显示方法对应的代码。这段js代码如下:</p>
<pre><code>function sourceShowHidden(sourceIdName) {
var sourceCode = document.getElementById(sourceIdName);
sourceCode.style.display = “block”;
}</code></pre>
<p>最终效果如下图:</p>
<p><img src="/img/remote/1460000022431169" alt="" title=""></p>
<p>将动态分析和静态分析进行了结合,后面可以通过不同版本进行对比,发现哪些方法的代码实现改变了,能展示在页面上。还可以进一步静态分析出哪些方法会调用到I/O函数、起新线程、新队列等,然后展示到页面上,方便分析。</p>
<p>读到最后,可以看到这个方法分析工具并没有用任何一个轮子,其实有些是可以使用现有轮子的,比如json、xml、xcodeproj、Objective-C语法分析等,之所以没有用是因为不同轮子使用的语言和技术区别较大,当格式更新时如果使用的单个轮子没有更新会影响整个工具。开发这个工具主要工作是在解析上,所以使用自有解析技术也能够让所做的功能更聚焦,不做没用的功能,减少代码维护量,所要解析格式更新后,也能够自主去更新解析方式。更重要的一点是可以亲手接触下这些格式的语法设计。</p>
<p><strong>结语</strong></p>
<p>本文小结了启动优化的技术手段,总的来说,对启动进行优化的决心的重要程度是远大于技术手段的,决定着是否能够优化的更多。技术手段有很多,我觉得手段的好坏区别只是在效率上,最差的情况全用手动一个个去查耗时也是能够解题的。<br><img src="/img/bVby2A6" alt="关注图.jpg" title="关注图.jpg"></p>
高德深度信息接入的平台化演进
https://segmentfault.com/a/1190000022327618
2020-04-10T14:06:30+08:00
2020-04-10T14:06:30+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>导读</strong> <br>本文介绍了高德地图中POI深度信息接入在平台化过程中的一些思考和实践,从最开始的单体应用,随着业务发展面临挑战,从业务角度提出解决问题的思路和方案,进而转化成技术设计并落地实现的过程。</p>
<p><strong>背景</strong> <br>POI是Point of Interest的缩写,即我们通常理解的地点信息。对普通用户而言,<strong>POI数据除包含名称、坐标等基本信息外,还会展示图片、评论、营业信息等内容,这些我们统称为深度信息。</strong>作为真实世界在线上的直接体现,其丰富度、准确度、新鲜度对用户的出行决策起到了至关重要的作用,也是高德地图从生活服务等多方面服务大众的基础。</p>
<p>为了丰富深度信息,我们通过多种途径对接采集数据。每个数据接入源称之为一个CP(Content Provider)。最初只有少量CP的时候,每个CP建立一个应用,完全独立的存储、独立的代码,甚至采用的是完全不同的技术栈。</p>
<p>然而,随着接入规模不断上涨,这种单体应对模式逐渐无力支撑,无法批量生产、更新、运维、监控等问题成为了业务迭代路上的绊脚石,大家花在基础维护等事务上的精力占比甚至超过了业务迭代。</p>
<p>用一组数据说明下深度业务的发展速度:一个季度工作日130天左右,新接入的任务数量却多达到120个以上。截止目前接入的任务总数是研发人数的100倍以上,单日处理数据量达十亿规模。基于对这个趋势的预判,深度团队提前开始了平台化的探索。</p>
<p><strong>平台化实践</strong> <br>平台化的思路是明确的,但是平台化的具体设计实施却有诸多不同的选择。</p>
<p>大多数数据接入系统的设计目标都相对比较纯粹:作为接入系统,只要把数据拿到并输入到本业务体系内就可以,剩余的如数据解析,业务处理都由下游的其他系统再次加工才可形成真正的业务数据,即接入系统从设计之初就是无状态的,对数据本身的理解也基本与业务无关。</p>
<p>但是考虑高德深度信息接入业务的特殊性,我们平台化时并没有采用这个方案,而是采用一种更集约化的思路,接入平台本身对数据就需要有充分的理解,不仅负责数据接入,还要负责数据解析、维度对齐、规格映射及生命周期维护等相关内容,平台直接内置了深度信息处理流程的全部管控逻辑。</p>
<p>另外,不同于一般的接入系统,除研发(RD)外,产品(PM)也是系统的第一用户,平台需要有能力让PM在了解有限技术约束的条件下自主完成全流程数据接入、分析和调试,这就对平台所见即所得的实时设计调试能力提出了极高的要求。从平台设计角度要解决以下一些难点:</p>
<ul>
<li>
<strong>数据规模不均匀</strong>:不同CP的数据量和数据体积相差巨大,有的源数据量有几亿条,最少的CP甚至只有一条数据。具体到每条数据大小也差距悬殊,如部分数据单条达到7.5M,有的则只有一个字段,仅几个字节。</li>
<li>
<strong>业务场景不收敛</strong>:深度数据来源多且杂:有三方合作接口、离线文件、经济体内OSS、ODPS、MetaQ等,且CP数据结构和关联匹配规则多种多样、无法预知,需要平台在设计上能支持各种场景下的维度对齐。</li>
<li>
<strong>映射清洗逻辑复杂</strong>:这里还有一个和常规业务不同的点,高德深度数据采用Schema比较松散的JSON方式组织,有多层嵌套对象及数组字段,且不同行业的规格并不一样,平台最终需要把数据组织成近百套不同规格的数据,这种松散的、非扁平二维表的数据处理也是挑战之一,尤其是存在数组上下文的场景里。</li>
</ul>
<p><img src="/img/remote/1460000022327622" alt="" title=""></p>
<p>最终我们设计出如图所示的平台架构,平台集成了基础、转换、推送和任务调度四个模块,配合完成深度信息接入的全部工作。</p>
<p><img src="/img/remote/1460000022327621" alt="" title=""></p>
<p>平台分为几个模块:</p>
<p><strong>基础模块</strong>:负责CP、行业、规格、权限等基础信息的在线化,实现统一管理。</p>
<p><strong>转换模块</strong>:负责数据获取、维度对齐、规格映射等处理。</p>
<p><strong>推送模块</strong>:负责转换后规格数据推送至下游准入服务。</p>
<p><strong>任务模块</strong>:负责对任务的管理,如任务类型、积压策略和数据差分等。</p>
<ul><li><strong>转换引擎设计</strong></li></ul>
<p>转换模块由转换引擎、转换管理器、设计器和调试器四部分组成。</p>
<p>为了降低系统的设计复杂度,所有业务规则的自定义部分均由转换模块支持。转换模块作为业务自由度最高的模块,使用相同的底层支持了上层业务的预转换、转换和数据分析三种场景,是系统能支持各种复杂业务场景的核心部分,转换引擎要支持数据获取、维度对齐、规格映射清洗等配置化及调试功能最复杂多变的部分。</p>
<p><strong>数据获取</strong> <br>数据获取能力不仅要支持常见的HTTP、OSS、ODPS、MTOP、MetaQ及Push服务等多种方式,而且还要支持组合叠加。比如先从OSS下载一个文件,解析文件行,根据解析的数据,再调用HTTP服务等场景。</p>
<p>为了支持近乎无限的业务叠加能力和所见即所得的设计效果,我们调研了阿里经济体内外的多种解决方案,如Blink、Stream平台等,没有发现可以直接满足我们业务需求的组件,主要问题为:</p>
<ul>
<li>基于技术维度组织,需要大量写代码或理解技术语义,无法提供业务视角,对数据PM的理解和使用有极大的障碍。</li>
<li>步骤数据视图是扁平二维表,无法实现松散结构传递和处理。如果在步骤间自定义业务约束及协议则过于复杂。</li>
<li>无法支持实时无副作用调试,运行流程和调试流程数据会互相污染。</li>
</ul>
<p>基于以上分析,我们决定不在上述平台上进行二次开发,而且直接基于当前业务场景定制一套引擎,虽然这些引擎无法直接使用,但是PDI的步骤组织及驱动方式和我们的业务场景比较匹配,从自由度、表达力和直观性几个角度考虑,转换引擎舍弃了DAG这种依赖计算和并行调度都相对容易的技术模型,使用和PDI类似的有向图模型进行组织。</p>
<p><img src="/img/remote/1460000022327624" alt="" title=""></p>
<p>为了最大限度的支持PM直接对业务场景进行描述,我们最终采纳了PDI的转换引擎设计思路,直接以原始有向图方式对步骤进行驱动执行,最大限度保持设计直觉和运行时的逻辑一致,从而不需要实现引擎层面的翻译器、优化器、执行器等复杂组件。</p>
<p><img src="/img/remote/1460000022327623" alt="" title=""></p>
<p>为了保证引擎的执行效率和安全性,我们保证步骤间数据传递不会跨进程,所有数据交互全部在内存内完成,且步骤之间均为异步并行执行,通过背压感知机制从后向前传导,平衡各步骤间的处理速度差异。</p>
<p><strong>维度对齐</strong> <br>维度对齐是指把不同数据源、不同维度的数据通过给定的业务规则关联整合成某一种维度的数据,比如深度信息业务一般需要整合成POI维度的数据。理论上有了引擎提供,能直观表达并堆叠业务的能力可以实现维度对齐的需求。但是,深度信息还有一个问题要解,即面对数据PM使用实时调试的需求,所以无论复杂还是简单的转换都需要能随时调试,并直观地展示结果,方便数据PM快速分析和排查。</p>
<p>常规ETL里都会涉及维度对齐的问题,但是由于常规业务一般都是二维数据表间的关联整合,所以像PDI之类的方案基本都是通过SQL+临时表的方案进行处理,在设计时即绑定了输入输出,调试和运行并无本质的区别,或者调试时需要修改配置,强制输出到一个临时存储,这意味转换引擎需要依赖特定的外部环境(如特定的数据库表),造成调试和运行时的数据会互相污染。</p>
<p>我们的数据天然不是二维结构,无法平铺到表中,自然也就无法使用这种方案。我们采用的是只依赖本机内存+磁盘的方式进行数据处理,如flatten这种数据打散的需求直接用内存实现,不需要借助存储;像merge join等可能全量数据交叉运算的直接采用本地磁盘做辅助,实现了全部功能都不需要外部特殊环境支持,秉承这个思路,我们最终实现了具备如下能力的转换引擎:</p>
<p><strong>纯引擎</strong></p>
<ul>
<li>不写数据,不生成执行记录。</li>
<li>不依赖任务及特殊执行环境。</li>
<li>可以随时初始化并执行。</li>
</ul>
<p><strong>数据透出</strong></p>
<ul>
<li>转换配置不需要指定输出,数据输出步骤动态挂接。</li>
<li>多种场景管理器:任务场景会写到DB,调试场景通过WebSocket回传到前端页面。</li>
</ul>
<p>有了这样的引擎,综合考虑调试场景的要求,转换在设计时不再需要指定输出目标,输出目标会在运行时由场景管理器根据调试场景和正常运行场景动态挂接,避免数据互相污染。平台在Web端支持几乎所有层次的所见即所得的调试分析功能,覆盖了预转换、转换、清洗、推送等几乎所有环节。</p>
<p><strong>规格映射清洗</strong></p>
<p>为了支持松散Schema映射和透明扩展,转换的行模型(RowSchema)创新性的设计为双容器结构。</p>
<ul>
<li>主数据:承载上游步骤的直接结果数据。</li>
<li>数据托盘:承载转换参数、步骤变量、映射结果等内容。</li>
</ul>
<p><img src="/img/remote/1460000022327626" alt="" title=""></p>
<p>映射步骤通过映射类型、映射规则和清洗参数支持映射清洗一体化。</p>
<ul>
<li>正向映射:自上而下进行数据提取,以扩展JSONPath表达式(扩展了主数据、数据托盘、数组循环item等上下文语义)为主,多种映射类型为辅。</li>
<li>反向清洗:自下而上逐层清洗,可任意叠加策略。</li>
</ul>
<p>转换模块通过步骤、映射、字段清洗三个层次对数据进行处理,PM使用时只需要通过Web界面拖拽对应组件并简单填写一些业务参数即可完成配置。</p>
<p>为了避免业务黑盒问题,系统设计不同于Stream平台的一个地方是系统组件会向后兼容,步骤插件、映射插件、清洗插件都没有版本的概念。系统不支持的自定义业务在各个系统模块均可以写脚本(Groovy)的方式托底实现,但是不允许上传二进制包,代码必须以配置形式直接体现,避免后期的维护问题。</p>
<p><strong>生命周期管理</strong></p>
<p>生命周期是指系统要在适当的时机触发数据的新增、更新、删除操作。站在数据接入的角度,删除是一个较为复杂的过程,业务术语称之为下线。要说清楚下线问题得先说下深度信息的任务模型。</p>
<p>目前我们支持批处理和流处理两种模型,如大家直观理解的,批处理任务每次执行都会递增一个批次号,比如常见的定时任务类型。流模型指任务一旦打开就会始终保持运行,数据一般是通过MetaQ、Push服务等方式被动接收的,没有批次概念。</p>
<p>为了满足业务需求我们支持批次过期、时间过期、条件下线三种策略,且支持多策略叠加使用。而这些策略设计时也有各自要考虑的内容,如批次过期怎样避免扫描全批次的历史记录、历史和重试场景批次号的共享递增问题;时间过期如何避免对每条记录绑定定时器造成的定时器数量爆炸等等。</p>
<p>生命周期管理涉及到比较多的任务模块设计内容,比如任务调度模型及多机分片机制设计,任务预警熔断逻辑设计,存储表的设计等,由于深度信息业务的集成需求,接入平台没有选用开源或阿里经济体现有的任务调度框架,而是自己定制开发了一个,篇幅有限这里不再展开论述。</p>
<p><strong>小结展望</strong> <br>深度信息接入平台见证了高德深度接入飞速发展的几年,以极低的人力投入支撑了高德在各垂类领域的深耕拓源,为高德向生活服务类高频应用拓展提供了底层数据支持。未来我们还将在全链路Debug、运营精细化场景支持、非标数据处理、自由业务编排平台等方面继续深化和演进。</p>
<p><img src="/img/remote/1460000022327625" alt="" title=""></p>
高德车载导航的差分更新优化实践
https://segmentfault.com/a/1190000022122966
2020-03-24T08:33:33+08:00
2020-03-24T08:33:33+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>导读</strong> <br>随着车载设备联网化,越来越多的车载设备从离线走到了线上。高德车载导航也早已从过去的离线安装包更新演进到了在线迭代更新。但原车载设备的Android硬件配置远低于手机,主要表现在处理器主频低、内存和存储空间有限,导致车载导航在车机上会出现无法下载新版本数据包、更新过程耗时长导致卡顿的情况,对导航应用的性能提出了要求。</p>
<p>为提高用户体验,高德技术团队立项解决了该问题。本文小结了高德车载导航在版本自更新演进过程中二进制差分解决方案的性能优化实践。</p>
<p><strong>差分更新方案比较</strong></p>
<p>对于应用程序的版本更新迭代,除了分发全量的安装包,还有一种更低成本的方式是分发增量包,即通过下发前后两个版本的差异部分(这个过程下面简称Diff),然后在客户端对原版本进行补丁更新(这个过程下面简称Patch)。因此也叫差分更新。</p>
<p><strong>业内比较流行的差分方案主要有: bsdiff、Xdelta3和Courgette。</strong>最后一个方案Courgette来自于谷歌,主要解决的是可执行文件的差分,而导航更新资源不仅包含可执行文件,还包含了图片等各种资源文件。所以,我们主要对比bsdiff和Xdelta3方案。</p>
<p><strong>bsdiff和Xdelta3方案比较</strong></p>
<p>下面是我们对选取的几个文件做的bsdiff和Xdelta3差分性能对比:</p>
<p><img src="/img/remote/1460000022122971" alt="" title=""></p>
<p>bsdiff的优势是压缩比高,生成的差分文件非常小,但Patch过程耗时。而Xdelta3的优势是Patch过程耗时极短,但内存消耗非常大。</p>
<p>相比高德车载导航自身运行内存开销不足100MB的情况,Xdelta3的Patch内存消耗无法接受。因此我们选用了bsdiff作为自更新方案。</p>
<p><strong>原生bsdiff方案缺陷与改进</strong></p>
<p>原生bsdiff方案使得压缩比问题得到解决,但在车载导航自更新中还存在下面两个缺陷:</p>
<ul>
<li>内存消耗大,整个过程会占用10~35MB左右的内存。</li>
<li>耗时长,整个包更新时间在3分钟左右。</li>
</ul>
<p>在对bsdiff的优化探索中我们发现Chromium开源项目中存在一份基于bsdiff的优化版本。该版本将bsidff的默认sufsort算法替换成了divsufsort算法,在Patch时间上有了较大的提升。</p>
<p><img src="/img/remote/1460000022122974" alt="" title=""></p>
<p><img src="/img/remote/1460000022122969" alt="" title=""></p>
<p>使用Chromium版本的bsdiff, 高德车载导航的自更新性能如下:</p>
<ul>
<li>内存消耗在10~20MB。</li>
<li>整个Patch过程耗时仍然长达25秒左右。</li>
</ul>
<p>耗时依然很长。</p>
<p>由于Patch过程是一个CPU密集型的操作,且车载设备CPU的性能普遍不足,这意味着在整个升级过程中用户能明显感受到导航的操作卡顿。同时,更新时间越长意味着遭遇断电的可能性也越大。</p>
<p>基于以上分析,我们决定对Chromium版本的bsdiff进行CPU和内存上的性能优化。</p>
<p><strong>bsdiff在车载自更新业务中的性能优化实践</strong></p>
<p>在车载自更新业务上,我们设定的目标是整体更新时间小于6秒,且内存开销小于2MB。整个优化的过程就是围绕时间和空间的取舍。</p>
<p><strong>内存优化方案</strong></p>
<p>经过对bsdiff源码的分析,其Patch内存主要开销来自文件内容在内存中的读写暂存和Bzip2的解压开销。通过调整Bzip2参数可以降低部分内存,但无法达到期望。而文件读写的内存占用主要来自于其在内存中的暂存。</p>
<p>基于bsdiff差分Patch包的文件格式,我们增加了滑动窗口缓冲区的Patch特性,使其在文件的流式处理上能够有更好的内存消耗可控性。每次读取和写入指定的滑动窗口大小数据,使数据即来即走。</p>
<p><strong>算法优化方案</strong></p>
<p>经过上述的优化后,Patch过程的主要性能瓶颈在于Bzip2的解压算法中,即使调整Bzip2参数也无法减少本身的计算量。</p>
<p><img src="/img/remote/1460000022122973" alt="" title=""></p>
<p>bsdiff差分算法的一个特性就是差分出的Patch数据包含了大量连续的01冗余数据,而Bzip2算法的优点就是对这类数据可以做到高度的压缩,这也是bsdiff压缩比高的原因。不过现在是目前的瓶颈。</p>
<p>此外,我们会制作软件整体的压缩差分包(即生成tar.bz2或zip格式文件),也就是说针对每个Bzip2压缩后的差分文件还要再经过一次压缩归档。这也意味着在客户段要进行两次的解压。</p>
<p><strong>替换压缩算法</strong></p>
<p>类似的冗余压缩算法有RLE(Run-length encoding),这个算法也是Bzip2算法的第一步。简单来说RLE算法就是针对连续多个冗余字节去掉其冗余字节,仅保留冗余的长度信息。这个算法相对更简单。</p>
<p>因此,我们将Bzip2压缩算法替换成了RLE算法,实际结果发现生成的Patch文件很大, 压缩比很低。但是可以通过再次压缩归档制作一次差分包,就可以达到和Bzip2几乎相同的压缩比效果。唯一的不足就是在客户端解压后会占用多一些磁盘空间, 而这个代价相对廉价多了。</p>
<p><strong>优化性能对比</strong></p>
<p>经过上述整体优化后,性能对比如下:</p>
<p><img src="/img/remote/1460000022122970" alt="" title=""></p>
<p>经过内存优化后的方案空间复杂度将为了O(1)。</p>
<p><img src="/img/remote/1460000022122972" alt="" title=""></p>
<p>上面的耗时差异在ARM车机会更明显:</p>
<p><img src="/img/remote/1460000022122976" alt="" title=""></p>
<p>最终优化收益:内存消耗控制在2MB以内,整体Patch更新耗时3~5秒。</p>
<p><strong>小结</strong> <br>通过对bsdiff的优化,高德车载导航在自更新性能上取得了较大收益。大幅缩短了用户下载和更新时间,降低了对ARM车机的硬件资源要求。为推动车载导航OTA更新提供了技术基础,对未来高德车载导航在分发新功能、新业务上铺平了道路。</p>
<p><img src="/img/remote/1460000022122975" alt="" title=""></p>
卫星影像识别技术在高德数据建设中的探索与实践
https://segmentfault.com/a/1190000022115482
2020-03-23T15:38:38+08:00
2020-03-23T15:38:38+08:00
高德技术
https://segmentfault.com/u/amap_tech
0
<p><strong>导读</strong> <br>对于地图服务而言,地图数据的准确率和覆盖率是服务质量的关键因素,而地图数据的更新,依赖于多种信息源,如轨迹热力,实采图像,卫星影像等。近年来,由于遥感卫星数量的增多及高分辨率光谱相机的出现,以及卫星影像图自身覆盖广、视角好、信息丰富的特点,卫星影像作为地图数据更新的信息源起到了越来越重要的作用。</p>
<p>对于卫星影像的使用方式,高德经历了由前端用户展示,到人工数据作业参考,再到主动发现更新地图数据的进化过程,这同时也是我们不断挖掘影像数据价值的过程。本文会介绍高德视觉团队将卫星影像从被动参考升级为主动发现的过程中的探索和实践。</p>
<p><strong>卫星影像关键元素</strong></p>
<p>按照几何结构划分,影像元素可分为三大类:道路元素(road),地物元素(region),建筑物元素(building):</p>
<p><strong>道路元素</strong>:包含普通道路,精细道路(主/辅路/非机动车道,提前右转路),连接点(贯穿路、出入口、掉头口、路口等)。</p>
<p><strong>地物元素</strong>:包含建筑区域、拆迁区域、水域、农田、山区、林地、大棚等。</p>
<p><strong>建筑物元素</strong>:建筑物楼块。</p>
<p><img src="/img/remote/1460000022115485" alt="" title=""></p>
<p><strong>卫星影像在数据更新上的优势</strong></p>
<p>路网是地图数据的基础,所有的道路属性、动态事件、POI引导都需要基于准确的路网数据信息。而卫星影像由于具有上帝视角,对区域内路网的连接关系、复杂的路口关系、平立交关系的判断具有全局而丰富的信息支撑。同时,由于卫星影像覆盖广、成本低的特点,对于热力稀疏或者采集车难以覆盖的区域,可以进行很好的路网数据补充。</p>
<p><img src="/img/remote/1460000022115486" alt="" title=""></p>
<p>路网三大信息源:热力、卫星影像、实采</p>
<p>作为用户导航的终点,POI(“Point of interest”的缩写,在地图数据中,一个POI可以是一栋房子、一个商铺、一个公交站等)坐标位置的准确性十分重要。通过高德POI中Top1000w的统计,70%的POI需要与楼块进行绑定,POI到达点与沿街楼块具有强依赖关系。</p>
<p><img src="/img/remote/1460000022115487" alt="" title=""></p>
<p>POI与楼块强相关性</p>
<p><strong>卫星影像识别技术探索实践</strong></p>
<p><strong>卫星影像精细语义分割(Semantic)</strong></p>
<p>在语义分割上,为了提升算法精度,我们将主要方向聚焦在上下文信息的结合,如使用了U-Net结构、ASPP、Non-local等对信息的聚合具有作用的结构。同时引入了Attention加强了网络对图像显著区域,即当前分割任务所关注的类别进行了注意力聚焦,使得效果达到进一步提升。</p>
<ul><li><strong>U-Net结构</strong></li></ul>
<p>由于影像图像语义较为简单、结构较为固定,高级语义信息和低级特征都显得很重要,因此我们选用了U-Net作为网络的基础结构。Encoder-Decoder分别下采样4次+上采样4次,将Encoder得到的高级语义特征图恢复到原图片的分辨率。</p>
<p>相比于FCN和Deeplab等,U-Net共进行了4次上采样,并在同一个Stage使用了Skip Connection,而不是直接在高级语义特征上进行监督和Loss反传,这样就保证了最后恢复出来的特征图融合了更多Low-Level的Feature,也使得不同Scale的Feature得到了融合,从而可以进行多尺度预测和DeepSupervision。4次上采样也使得分割图恢复边缘等信息更加精细。</p>
<ul><li><strong>ASPP</strong></li></ul>
<p>使用不同扩张率的扩张卷积,并进行特征结合,得到多尺度特征,同时得到全局信息和局部信息。</p>
<ul><li><strong>Attention</strong></li></ul>
<p>关注图像显著区域,将U-Net的浅层和对应的深层进行信息结合后,得到Attention的参数,再作用于当前深层,得到最终Attention的结果输出。</p>
<ul><li><strong>Non-local</strong></li></ul>
<p>特定层的卷积核在原图上的感受野(local)是有限的,Non-local通过将空间中不同像素间的关系编码到当前层的输出,从而将全局信息加入到输出结果中,就能很好地解决local操作无法看清全局的情况,为后面的层带去更丰富的信息。</p>
<p><img src="/img/remote/1460000022115488" alt="" title=""></p>
<p>U-Net结构(左上) Attention(左下) Non-local(右上) ASPP(右下)</p>
<p><strong>影像楼块实例分割(Instance)</strong></p>
<p>实例分割有两种主流方法,第一种是基于目标检测,在得到目标检测框之后再在框内做语义分割前景和背景,由于这种方法需要借助目标检测中的区域提议,因此该方法称为Proposal-Based方法。</p>
<p>另一种方法是,在语义分割图的基础上,将像素聚集到不同的实例上,这种被称为Proposal-Free方法。我们对两种主流方法进行了对比实验,由于楼块具有多样性、“矮胖结构”的特点,Proposal-Based方法效果要优于Proposal-Free方法。</p>
<p>对于楼块数据而言,重要的表达内容是楼块的底座位置及其形状。然而由于影像拍摄视角问题,部分高楼在视觉上呈现斜射的效果,部分基座边缘被遮挡,为识别造成了极大的难度。</p>
<p>经过数据分析与推算,我们发现绝大多数的楼块底座形状是和楼顶形状一致的,因此我们采用了楼顶分割+楼顶到基座偏移量的多任务学习方案,将分割出的楼顶形状加上一个楼顶到基座的偏移向量,对基座的形状和位置进行了一个比较理想的还原。</p>
<p><img src="/img/remote/1460000022115490" alt="" title=""></p>
<p><strong>多元素识别效果展示</strong></p>
<p>针对卫星影像不同元素的图像特征与拓扑结构关系,我们设计了多个识别模型,包含普通道路识别、精细路网识别、地物分类识别、楼块识别等,作用于高德多种类别的数据更新。</p>
<p><img src="/img/remote/1460000022115489" alt="" title=""></p>
<p>普通道路识别(左上) 精细路识别(右上) 地物分类(左下) 楼块识别(右下)</p>
<p><strong>未来展望&挑战</strong></p>
<ul><li><strong>路网数据的准确/快速更新</strong></li></ul>
<p>用户在使用导航过程中可能会遇到一些场景:比如为什么这里有条新路却给导航了一条绕远的路?为什么导航了一条已经不能走的路?为什么本来这里可以掉头却还要往前多走几公里才能掉头?这些由路网数据错误导致的导航偏差,是我们未来需要解决的核心问题,也是业界的难题。未来我们期望通过视觉算法层面的优化,通过多采集源的融合预测,通过提前发现建设中道路等一系列手段,来快速感知到现实世界中发生的路网变化。</p>
<ul><li><strong>数字城市中的楼块与AOI建设</strong></li></ul>
<p>对于数字城市来说,楼块和AOI(兴趣区,Area Of interest)是重要的元素之一:如用户想要前往某个店铺,实际导航的到达点是店铺所在的楼块;用户想要前往某个小区的某个楼,实际导航的到达点是小区的入口,因此楼块与AOI的准确与完备直接影响到用户导航最后几百米的使用感受。同时结合最近的疫情防控,数字城市中的楼块和AOI信息可以对写字楼、小区等区域的疫情防控提供有力的数据支持。未来我们期望通过结合卫星影像的发现能力,进一步完善数字城市的数据建设,连接真实世界,让出行更美好。</p>
<p><img src="/img/remote/1460000022115491" alt="" title=""></p>