Jean's Blog

一个专注软件测试开发技术的个人博客

0%

人工智能系统架构

人工智能与大数据

为什么说大数据是人工智能的基础

已经了解了人工智能的原理,那么就可以理解算法是在数据中学习规律的。所以数据越多,越丰富,算法学习的效果就会越好。 但问题在于 数据量越大,算法迭代的时间就越长。 所以现代的人工智能往往都伴随着大数据技术出现才会有那么好的效果。 机器学习的分支深度学习由于要组建 很深的神经网络,所以导致对算力的要求极其的苛刻。 这也是为什么深度学习是近些年才会流行起来的原因。 因为近些年的算力爆炸以及各种大数据技术 的蓬勃发展才为深度学习带来了生存空间。

所以大数据技术成为了人工智能中非常重要的角色,接下来让我们看一下大数据通常在人工智能系统中扮演怎样的角色。

数据中心

image-20250723091611691

一个人工智能场景的流程往往先从采集用户数据开始,业务使用数据库往往适合OLTP(联机事务处理),它适合业务上的增删查改。 却不适合与大规模的数据分析。

所以往往需要从业务数据库中把数据导入到OLAP(联机分析处理)数据库中。 比如hdfs,hive,kudu,clickhouse等等都是OLAP常用的技术选型。

数据中心担任着非常重要的职责,除了上面讲到的它需要从业务数据源中抓取数据并保存在自身的存储外, 还需要管理所有数据的生命周期,比如在上图中下面的部分建模工程师需要频繁的进行ETL(Extract, Transform, Load),特征工程以及模型训练的过程, 这会产生大量的中间数据(因为需要不停的调整特征,调整超参数来调试模型)。所以他必须 负责所有数据的生命周期。让我们整理一下一般会有什么地方会出现大量的中间数据。

  • 建模工程师:在整个建模过程中,需要不停的探索数据和特征。这些计算会产生非常多的中间数据。

  • 高频自学习:定时触发,每隔一段时间都会获取最新的数据并训练新模型代替老的模型,这会产生很多中间数据和老旧的模型。

  • 批量推理:当模型被训练好后,可能会有定时或手动触发的模型推理任务,使用采集来的数据灌给模型进行推理。这个过程同样需要一些特征工程,所以仍然会产生不少中间数据。

所以数据中心一般需要有一套完整的针对数据的生命周期管理机制。如果管理机制缺失,系统在长时间的运行后可能会丢失数据与任务的关系或者丢失数据的元信息,造成我们常说的野数据—已经不受系统管理,或者已经无法追溯这批数据是哪个任务创建出来的,从而不敢清理,总之这部分数据已经无法追溯也没有什么特别的价值,但你又不敢删除。

所以一个人工智能平台的产品,需要一些策略来管理这些数据的生命周期,并有一定的机制来删除一些过期数据,比如:

  • 给数据设置TTL(过期时间), 当时间到了以后自动进行删除。

  • 为用户设置一个方便的清理工具, 把数据进行归类, 比如按任务,按项目进行整合, 然后有一键清理功能(也可以按时间清理)。

  • 设计好数据血缘(数据地图),能让用户方面的知道哪些数据是可以放心删除的。

补充:什么是ETL

ETL是数据仓库和数据集成的关键组成部分,用于从多个不同的数据源中提取数据,对数据进行转换和清洗,最后加载到目标数据存储中。

  1. 数据提取(Extract):从各种数据源(如数据库、文件、API等)中提取数据。
  2. 数据转换(Transform):对提取的数据进行清洗、转换和加工,确保数据的质量、一致性和完整性。
  3. 数据加载(Load):将转换后的数据加载到目标数据仓库、数据库或数据湖等存储系统中。

数据血缘

我们看一下一般的模型流程:

image-20250723092136206

建模工程师需要不断重复上图左方的流程来针对模型进行调整, 有些时候是需要改变特征抽取的字段, 有些时候需要改变超参数,这样不停的尝试,来争取 获取一个更好的模型。 而在这里面工程师需要反复的对比之前的模型和现有的模型, 或者对比不同的历史版本的效果。这样工程师才能慢慢的总结出一些规律。 比如说一些参数的值, 或者获得一些有用的特征。 所以需要针对这些中间数据进行管理的同时,也需要能追溯到这份数据是从哪里产生的。 建模工程师在 反复尝试后,发现还是之前某个版本的模型效果更好, 所以他想知道这个模型是哪个样本表(经过特征工程后的表叫样本表)训练出来的,也想知道这个样本表 是经过了哪些处理产生的。

所以一般的人工智能平台产品,都需要有数据血缘(或者叫数据地图)的设计,用来帮助工程师来追溯相关的数据。

小文件治理

小文件治理,对于分布式计算来说,海量的小文件不管对于运算性能还是对于存储系统来说都是灾难级的:

  • 对于hdfs这样的分布式文件系统来说,一个文件需要被切分成很多的碎片保存到不同的机器中,而根据hdfs的设计,一个文件块按128M进行切分保存,如果不足128m也会按128m存储处理。所以海量的小文件会浪费存储空间,也会为存储系统的元数据服务器带来负担。

  • 根据分布式计算的原理,每一个数据分片都要启动一个线程来进行处理。 所以数据分片越多,线程越多,消耗的cpu越多。

如果系统中产生过多的小文件,需要产品有机制可以规避相关风险

  • 定期的小文件合并工作, 减少碎片化文件的影响。

  • 在运行任务之前,先扫描文件数量,然后合并文件之后再进行正常计算。

流计算与幂等

有些时候数据来源不仅仅是通过离线导入的,也会是实时的从业务传输过来。有可能会存到数据中心中,也可以是传输给一个已经上线的模型进行实时的模型推理。 下图是一个流计算的一般流程。

image-20250723101911389

对于上图简单说明:

用户行为数据 (User Behavior Data): 这是整个流程的起始点,代表了用户在应用程序、网站等产生的各种交互数据。

Kafka: 用户行为数据首先被发送到 Kafka。Kafka 是一个分布式流处理平台,常用于高吞吐量的实时数据管道,作为数据采集和缓冲层。

Flink: Kafka 中的数据被 Flink 实时消费并处理。Flink 是一个流处理引擎,能够进行有状态的流计算。

  • Watermark 生成 (Watermark Generation): 在流处理中,Watermark 用于处理事件时间乱序问题,确保窗口计算的正确性。
  • 窗口计算 (Window Calculation): Flink 会对数据进行窗口聚合计算,例如统计某个时间窗口内的用户行为次数、平均值等。
  • 自定义Sink (Custom Sink): 经过 Watermark 生成和窗口计算后的数据,会通过一个自定义Sink输出。这个自定义Sink会将处理结果分发到两个不同的下游系统:
    • Elasticsearch: 处理结果的一部分(例如,用于数据查询和分析的原始数据或聚合数据)会被发送到 Elasticsearch。
    • WebSocket: 处理结果的另一部分(通常是需要实时展示的聚合指标或事件)会通过 WebSocket 发送。

Elasticsearch: 一个分布式、RESTful 风格的搜索和分析引擎。在这里,它用于存储 Flink 处理后的数据,以便进行快速查询。

Kibana数据查询与可视化 (Kibana Data Query and Visualization): Kibana 是与 Elasticsearch 配套的数据可视化工具,可以连接 Elasticsearch 中的数据,进行查询、创建仪表盘、生成图表等,方便用户洞察数据。

WebSocket: 一种在客户端和服务器之间建立持久连接的网络协议,允许双向实时通信。

大屏展示 (Large Screen Display): 通过 WebSocket 接收到的实时数据,会被用于在大屏幕上进行实时展示,例如实时监控仪表盘、运营数据看板等。

流计算最容易出现数据一致性问题, 比如数据在传输过程中的丢失或者重复计算。

image-20250723102146267

在上图中,当消息推送到服务端后,服务端会把数据保存在本地,然后返回一个ACK通知生产者。 在这个过程中,如果消息推送的过程中出现了网络抖动,数据 就会丢失,这时候要怎么办呢, 一般可以让生产者进行重试。 但重试是有副作用的。 比如当网络问题出现在了返回ACK的时候,这时候虽然数据已经保存 在了服务端,但是生产者没有收到ACK,它会认为数据推送失败了,所以它仍然会重试。 这时候消息就会有重复推送的风险。 所以这时候就需要上下游 有幂等的设计, 幂等可以理解为一种去重的机制。 服务端可以判断出接收到的数据是否是重复的。

测试方法

经过上面的一些介绍,我们已经知道了大数据在人工智能系统中起到的重要作用, 所以我们需要针对数据进行完善的测试。 尤其是在性能方面的。 而大数据系统 属于典型的用大数据技术去测试大数据的领域。 比如在性能测试的时候,需要模拟大量的不同的数据进行测试, 比如:

  • 不同的数据规模(行,列)。

  • 不同的数据分布。

  • 海量小文件。

  • 不同的数据源

创建这样的数据时,为了花尽量少的时间,往往会使用类似spark这样的技术,利用分布式计算的原理加速造数过程。

如果是测试功能,或者数据质量监控, 往往也需要使用类似spark这样的技术去编写扫描脚本来分析待测数据是否符合质量要求。

人工智能中的云计算与边缘计算

什么是云

image-20250723102627171

上图是云时代下,研发人员部署时的流程。 不同于以往的服务与机器绑定的模式,在云的背景下,研发人员只需要声明服务所需资源,云平台会负责决定服务调度到哪个节点行。

什么是边缘计算

根据百度百科的定义,边缘计算是指在靠近设备或数据源头的一侧,采用网络、计算、存储、应用核心能力为一体的开放平台,就近提供最近端服务。其应用程序在边缘侧发起,产生更快的网络服务响应,满足行业在实时业务、应用智能、安全与隐私保护等方面的基本需求。但想必在之前没有接触过边缘计算的读者是无法通过这么一段晦涩不清的文字就能理解边缘计算的内容,所以我在这里想通过自己的语言来描述边缘计算的关键内容

云计算的不足

云计算与边缘计算都属于当今云领域中应用非常广泛的场景,它们要面对的场景和解决的问题是完全不同的,同时它们也是一种互补的关系,边缘计算正是为了弥补云计算的不足而存在,所以对比这两者的特点有助于帮助理解边缘计算的架构。想必从字面上应该可以大概看出来云计算与边缘计算的一些区别,对于云计算来说会把任务和服务集中在云端调度,属于典型的集中式计算架构。服务在云端调度有诸多好处,正因为用户的服务都集中在云端调度部署,所以云端才可以抽象出很多通用的能力供用户使用,这些在云端调度的服务可以共享云端的存储,网络,资源以及相关服务,用户只需要把精力集中在自己的产品中即可。在云计算中不管是IaaS,PaaS还是SaaS都很好的为用户供了开箱即用的能力,由此用户上云后就可以使用云上的服务从而节省大量人力和资源的开销。

而随着软件行业的发展,人们发现云计算的设计仍然存在一些不足,企业在很多场景中都需要计算庞大的数据并希望能够得到即时的反馈,在这类场景中云计算就需要面临以下的挑战:

  • 大数据量的传输:由于产品在远离用户和终端设备的云环境中部署,所以这些服务与用户和终端设备之间存在复杂的网络环境,而随着用户和设备的增多,海量的数据从终端传输到云端将变得十分困难,此时网络带宽也会成为产品最大的瓶颈。

  • 数据处理的实时性:现今世界的软件对性能要求越来越高,企业希望用户能够从软件中尽早的得到反馈以提升用户体验。而云计算的设计方案需要把终端数据传输给云端处理后再从云端发送回给终端,这一来一回的传输开销注定降低了业务反馈的实时性。所以即便业务没有海量的数据传输,与计算仍然很难满足这种高实时性场景的需要。

  • 数据的隐私安全:云计算将身体可穿戴、医疗、工业制造等设备采集的隐私数据传输到数据中心的路径比较长,容易导致数据丢失或者信息泄露等风险。并且客户的隐私数据保存在云端本身就是一件不安全的选择,所以客户往往也会希望数据保存在自己信任的机房中。

就近计算的设计

随着云计算的不足愈演愈烈,人们开始慢慢的把视线转移到了边缘计算上。那么边缘计算能为用户提供什么样的能力呢。简单来说如果云计算是一种集中式计算架构,那么边缘计算就是彻头彻尾的分散式架构。它把关键的服务和任务分散在更靠近用户和终端设备的地域进行调度部署。 这种就近计算的设计可以有效解决因为数据传输而带来的性能和数据安全问题,企业把服务架设在距离用户和中心设备更近的机房中,这样便规避了复杂的网络环境。基于此设计,企业需要根据用户和终端设备的分布在不同的地域架设机房。并且从软件设计上让终端设备优先去请求离自己最近的机房进行计算。

image-20250723103026873

上图描述的是一个典型的边缘计算系统的架构,这里存在3个角色:

  • 云:边缘计算是代替不了云计算的,它与云计算更像是相辅相成的关系。在边缘计算的业务中,仍然需要把部分服务部署在云端中心集群中来控制整体业务的策略。

  • 边:部署在每个地域的边缘机房,它们与终端设备距离最近并部署了绝大部分计算服务,接收到终端设备的请求后就开始就地计算并进行实时的反馈。

  • 端:终端设备的统称,这些设备可以是手机,可穿戴设备,工厂中的工控机或是路旁的摄像头。它们负责采集数据并传递给距离自己最近的边缘机房进行计算。

我喜欢把这种架构简称为云边端,分别代表了在边缘计算中这3种不同的角色。当然完成这样的架构是非常困难的,从物理设施角度看,通常终端设备分布在非常多的地域中,企业需要在这些地域架设大量的机房。而从软件角度看,产品的架构要能够完成所有边缘节点的统一管理,完成机器的区域划分,服务的统一下发以及网络的分发策略等等。

人工智能与边缘计算

大数据是人工智能的基础,所以理应也大量的也应用到了边缘计算业务,尤其在计算机视觉场景中,需要从边缘的拍摄设备中获取大量的数据。而在这种场景里一般就需要面对安全和性能两个难关:

  • 性能:图像数据在网络中传输,会耗费大量的带宽, 但人工智能场景中,对于模型推理的速度一般都是很高的。所以需要把模型部署在边缘机房加快处理速度。
  • 安全:很多图像数据都涉及个人隐私,上传到云端数据中心往往不符合用户的要求

自学习与数据闭环

什么是自学习

推荐系统属于一种典型的特征随着时间发生巨变,为了保证模型的时效性 需要引入自学习机制使用每天最新的数据更新模型。流程如下:

image-20250723142811973

它的原理是比较简单的, 假如我们在线下使用了 N 天的数据进行了模型训练并上线。 那么在 n+1 天的时候数据采集系统会收集到最新一天的数据, 这时候我们会抛弃最老的一天的数据,因为它的已经过了时效性。 之后加入新的数据参与模型训练来保证模型的时效性。 这就是自学习的一个简单的原理说明。

但自学习并不是简单的把数据加入到模型中并更新线上模型的过程。 模型上线是第一个很严肃的事情,中间出现了偏差会导致很大数额的经济损失。

也许我们会有一种错觉就是我们的模型算法,参数,和抽取特征的方式都已经在线下固定下来了。自学习只是重复之前线下的步骤, 已经可以不用作测试了。 这是不对的,因为我们作为源头的数据已经发现了变化, 我们并不能假设这份数据是正确的,并且是符合预定的用户画像的。 所以我们起码要在自学习中有下面这样一个数据闭环的流程。

数据闭环

image-20250723143109821

首先我们要有数据采集系统收集每天最新的数据。 这是数据回流, 然后对数据本身做测试和预警, 我们要对数据进行扫描,统计,分析来保证这份数据是符合建模场景的。 一个是因为数据本身是可能在数据采集中出现错误的, 比如某类商品是有一个价格区间的,但是由于数据采集问题或者上游系统的 bug,可能会出现这个商品的价格的异常波动。 或者另一个是因为某些外界因素导致用户行为的突变。 比如情人节那天,双十一那天。

在某种情况下用户行为跟过去产生了一些颠覆性行为,而且这些行为持续的时间可能很短暂,比如过了双十一那一天以后,可能用户的行为就回归到正常的模式。那么我们还要不要把这一天的数据加入到模型中去预测第二天的行为呢? 这个其实就有待商榷了。 总之不管是什么原因导致的数据本身的分布异常,都要做出预警,大家一起来判断一下要不要使用这份数据,或者说要不要做一些处理后再使用。

所以我们的数据预警机制要每天扫描数据检查异常字段, 要和过去的数据做对比,统计数据是否出现了异常分布。比如前一天我们产品还是女性用户比较多,但突然今天的数据男性用户暴增。 这时候就要看看是什么导致的用户行为的变化。是不是要调整模型训练策略。

经过了数据预警后,我们把数据传递给算法进行模型训练。但有些时候即便模型评估报告中的指标很好,我们心里还是没底。 会不会评估报告不准确? 所以这里我们还会加入 A/B Test 去对比线上模型和新模型的效果。 我们线上的流量导入到线上模型的同时,也会 copy 一份流量到自学习训练出的新模型上, 对比模型之间的效果。

当我们确定了新模型起码不比老模型差的时候,才会切换线上模型。 当然了这里也有一种策略不是一下子切换的,而是根据时间或者效果慢慢的切换,比如先是只把 10% 的流量导到新模型上,90% 的流量还是放在老模型上。

这样一点一点的把流量切到新模型上。 有一个缓冲。 这里怎么做就看具体情况了。 那么我们经过了 A/B Test 以后就将模型上线了。 当然线上也会有监控系统来统计当日的 AUC 等等一些指标做最后的确认。 监控这方面就不详细讲了。 模型上线之后在线上产生价值,产生新数据。 最后通过数据采集系统,数据回流到自学习系统中。 一个数据闭环就这么形成了。

要想做自学习系统就要完成这个数据闭环。 当然我们对这个数据闭环的效率是有一定的要求的, 自学习迭代的快就能尽快的让模型上线,就能尽快的保证模型的时效性, 让模型产生最大的价值。 因为我们说过这类场景的数据特征随时间变化的很快,所以自学习的迭代速度也要快。

模型的实时训练与更新(迁移学习)

什么是迁移学习

随机梯度下降算法的原理,模型实际上就是一个数据库,里面保存着特征与权重。而在梯度下降中,我们可以把一份大规模的数据按照batch size进行切分, 每一次迭代只训练其中一小部分的数据,让梯度下降算法走下去。 每来一小批数据,就会训练一次,并到模型中更新一次特征与权重的值。

所以这里我们思考一个问题,这种可以用一小批一小批数据只能用于离线的模型训练的过程中么, 假如有一个已经训练好的模型, 我们可以不可以再用一份新的数据再训练一次,然后把新的参数更新到模型里呢。 答案是可以的,并且这些数据可以不用来自于同一个数据源。

比如我们有一个OCR的模型(Optical Character Recognition:是指光学字符识别技术,它可以将扫描或拍摄的图像中的文字识别出来,并转换为可编辑的文本格式),它可以识别超市中的小票:

image-20250723143557142

这个模型工作的很好, 但我们想把业务扩展到另一家超市中, 但这家超市的小票格式与原来的不一样,所以识别的仍会有偏差, 这种偏差不是因为算法的问题,而是因为算法拟合的是上一家超市的数据,所以算法基本的逻辑是对的,为了识别出文字而提取的特征也是正确的。只是可能小票中的一小部分特征前后有所区别。

所以这个时候模型本身大部分的参数都是合理的,我们只需要更新那一小部分参数就可以满足新的小票场景。 所以我们只需要在这个模型的基础上,只需要使用一小部分的新的超市的数据进行训练,并将参数更新到原来的模型里, 模型就可以很好的适应新的场景了。

这就是迁移学习,使用一小部分新的数据进行训练,并更新到其他相似场景的模型中。 我们都知道人工智能是依赖大量的数据的,但如果用户自己并没有这样规模的数据,就可以选择下载网络上开源的模型,或者购买付费模型来做迁移学习, 这也是现在很多人工智能的业务的重要的盈利模式之一。

实时训练与更新

在讲解自学习时,我们说过有一些业务场景是需要高频的自学习系统来更新模型,比如推荐系统。 但可能有些场景对模型的更新频率有着更严苛的要求。 我们假设这样一种场景,在一个视频网站中,一个新用户到来并开始搜索了他感兴趣的视频, 这时候系统希望能尽最大的努力留住这个用户,所以它希望能根据用户的喜好来推荐一些他感兴趣的视频。或者一个老用户突然开始查询一些他平寻不关注的视频,这时我们也希望能尽快给他推送这些相关的视频内容。 所以我们需要根据用户刚刚的操作行为作为数据做一次mini batch的训练并更新到模型中。

image-20250723143649897

这种实时的训练与更新的要求是很高的,它要求整个模型更新的过程是全自动化的。 包括其中数据标注的部分。所以能够应用这种架构的场景也是有限的。