异度部落格

学习是一种生活态度。

0%

本文介绍了作者多年构建的独特知识获取与管理方法论,旨在帮助读者优化日常工作和学习。文中详细介绍了一系列实用工具,如微信读书、Readwise和Obsidian等,用于阅读、笔记同步、信息管理和回顾,以及如何利用这些工具提高学习和信息管理的效率。

Read more »

本文介绍了作者多年构建的独特知识获取与管理方法论,旨在帮助读者优化日常工作和学习。文中首先介绍了关键的工具和技术,如笔记软件和任务管理工具,以及如何使用这些工具来捕捉灵感、整理思路和管理待办事项。知识管理工作流被分为三个主要阶段:输入、内化和输出。输入阶段涉及从多个信息源采集信息;内化阶段则是通过个人理解转化这些信息;输出阶段则是通过撰写、演讲等方式验证并分享所学知识。作者还强调了费曼学习法的重要性,即通过教学来加深理解和发现知识盲点。

Read more »

引言

QLoRA(Quantized Low-Rank Adapter)是一种高效的微调方法,是LoRA的量化版本(什么是LoRA?)。该调优方法由华盛顿大学发表于论文《QLORA: Efficient Finetuning of Quantized LLMs》。通过降低内存使用,实现在单个GPU上对大型语言模型进行微调。它可以在单个48GB GPU上微调650亿个参数的模型,并且能够保持完整的1 6位微调任务性能。 7f7733856584f50e20ddf3fdf1711a9d.png

基础技术介绍

Block-wise k-bit Quantization

量化指的是将连续或高精度的数值转换为较低精度(比如较少的位数)的表示形式的过程。这通常用于减少模型的存储需求和加快其运算速度。例如,将一个FP32的tensor转成Int8: \[X^{\text{Int8}} = \text{round}\left(\frac{127}{\text{absmax}(X^{\text{FP32}})} \cdot X^{\text{FP32}}\right)=round(c^{\text{FP32}})\] 其中,c为量化常数。逆量化公式则为: \[\text{dequant}(c^{\text{FP32}}, X^{\text{Int8}}) = \frac{X^{\text{Int8}}}{c^{\text{FP32}}}\] 这种常规的量化方法的局限性也非常明显,当tensor中有一个非常大的数字(一般称为outlier)时,将影响最终的量化结果。

因此,Block-wise k-bit Quantization方法就是把tensor线性平展开,然后分割成B段,每段有自己的量化常数c,独自量化。

Low-rank Adapters

LoRA,全称为“Low-Rank Adaptation”,尤其是在大型预训练语言模型(比如 GPT-3)的微调领域中。它是一种参数高效的模型微调技术,通过引入低秩的权重矩阵来修改预训练模型的自注意力机制。

在大型语言模型的背景下,LoRA的关键优势是它能够在增加极少量参数的情况下,有效地适应新的任务或数据集。这一点尤其重要,因为全面重新训练这些大型模型需要大量的计算资源,而LoRA提供了一种更为节能的替代方案。

具体来说,LoRA的工作原理是在自注意力模块的键(key)和值(value)矩阵中引入低秩矩阵。这些低秩矩阵与原始的键值对进行相乘,产生新的键值对,用于微调模型。因为这些矩阵的秩很低,所以新增加的参数数量较少,但这些参数的引入足以让模型学习到新任务的特定特征。

LoRA的这种设计旨在保持预训练模型的大部分权重不变,同时仅对模型进行必要的小规模修改,从而快速适应新的任务。这样的方法在保持模型性能的同时,还能显著减少部署和运行大型模型所需的资源。

b0baa4e120421c06f465b976b92f3af9.png

PEFT

PEFT(Parameter- Efficient Finetune)是一种在自然语言处理(NLP)中常用的方法,特别是在大型预训练语言模型的微调阶段。PEFT方法的关键思想是,在保持大部分预训练模型参数固定不变的同时,只微调一小部分参数。这些参数可以是添加到模型的新参数,也可以是模型内部的一小部分可训练参数。这样做的好处是显著减少了微调过程中的内存和计算需求,同时仍然保持了模型的表现力。

核心技术

4 bit Normal Quantization

论文中提出的4-bit NormlFLoat量化是对Quantile Quantization(分位量化)进行了改进,并结合上诉Block-wise Quantization,降低计算复杂度和误差。

以4-bit量化为例,参数将被映射到16个可能的值(从0到15)中的某一个,类似于四舍五入的方式。然而,这种传统量化方法的一个主要缺点是,量化后的参数分布可能与原始分布相差甚远。比如,如果有一个极大的值,那么大多数参数可能都会被量化到0,从而导致模型性能显著下降。

为了解决这一问题,作者采用了分位量化(Quantile Quantization)方法。那么,分位量化是什么呢?仍然以4-bit量化为例,这意味着有16个不同的值可以选择。在分位量化中,首先将输入参数按大小排序(Quantile),然后将它们等分成16份(Block-Wise),每份对应一个量化值。这种方法在量化过程中能够更好地保持参数的原始分布,从而在降低参数精度的同时,尽可能减少对模型性能的影响。

上述分位量化会额外引入明显的计算开销,因为每次有参数输入进来都需要对齐进行排序并等分。
作者发现预训练的参数基本上都服从均值为0的正态分布,可以将其缩放到[-1, 1]的范围中。同时可以将正态分布N(0,1)划分为2^k+1份,并缩放到[-1, 1]的范围中。这样就能直接将参数映射到对应的分位,不用每次都对参数进行排序。 但是这样做饭也会有一个缺点,参数0量化后可能不在0的位置上了,就没法表达0的特殊意义了。为此作者还做了一点改进,即分别将负数和整数部分划分为2^k-1份,参数0还是放在0原本的位置上。 1d324b80c45e95df588cc34eca486fc0.png

Double Quantization

分块量化中每个block都会额外产生一个量化常数c。以量化32bit参数、block大小64为例,每个block会引入32bit的量化常数,对应每个参数会额外引入32/64=0.5bit的额外开销。
论文采用了双重量化方法,如下图所示: 967074c14c1ea352c40d440d2f704242.png 在第一次量化后,并不会直接储存量化常数c1,而是按照block大小256对量化常数再量化到8bit上去储存,这个阶段会再引入一个量化常数c2。最终保存的额外参数为8/64 + 32/(64 · 256)=0.127bits,也就是每个参数减少0.5-0.127=0.373bits

Paged Optimizers

Paged Optimizer将优化器需要存储的数据(例如权重和梯度)分成多个小块或“页”。在每个训练步骤中,只加载当前需要的数据页到内存中,而不是一次性将所有数据加载进内存。这种方法允许在相对较小的内存中有效地处理大型模型,因为任何时候都只有部分数据被加载。

QLoRA训练

所以QLoRA最终训练的表达为: \[ Y^{\text{BF16}} = X^{\text{BF16}} \text{doubleDequant}\left(c_{1}^{\text{FP32}}, c_{2}^{\text{k-bit}}, W^{\text{NF4}}\right) + X^{\text{BF16}}{L_1}^{\text{BF16}}{L_2}^{\text{BF16}} \]

其中: \[ \text{dequant}\left(c_1^{\text{FP32}},c_2^{\text{FP32}}, W^{\text{k-bit}}\right) = dequant(dequant(c_1^{FP32}, c_2^{k-bit}), W^{NF4})=W^{BF16} \]

参考资料

前言

Transformer是一种在自然语言处理(NLP)任务中广泛使用的深度学习架构。它由Google于2017年在Attention Is All You Need论文提出,其设计初衷是为了解决序列到序列(seq2seq)任务中的长期依赖问题,同时也提高了处理序列数据的效率。

目前Transformer不仅仅运用在NLP领域,同时迁移到了CV领域,是大语言模型如GPT-3、Llama等模型的模型基础。 # Transformer整体架构

Transformer的基本结构包括Encoder(编码器)和Decoder(解码器)两部分。每部分都包含多层,每层又包含多个子模块,如自注意力机制和前馈神经网络。 b33db265c29eb4a55656384b9a382cb8.png # Transformer的输入 Transformer中的单词输入表示通常由词嵌入(Word Embedding)和位置编码(Positional Encoding)相加得到。3a76d3af87347ccf24bb91ff785a045f.png ## 词嵌入(Word Embedding) 单词的 Embedding 有很多种方式可以获取,例如可以采用 Word2Vec、Glove 等算法预训练得到,也可以在 Transformer 中训练得到。 ## 位置编码(Positional Encoding) 因为 Transformer 不采用 RNN 的结构,而是使用全局信息,不能利用单词的顺序信息,而这部分信息对于 NLP 来说非常重要。所以 Transformer 中使用位置 Embedding 保存单词在序列中的相对或绝对位置。PE的维度需要与WE相同。在论文中采用的是 0c05cd00e777aae57081d43be030f1bf.png 其中,pos 表示单词在句子中的位置,d 表示 PE的维度 (与词 Embedding 一样),2i 表示偶数的维度,2i+1 表示奇数维度 (即 2i≤d, 2i+1≤d)。使用这种公式计算 PE 有以下的好处: - 使 PE 能够适应比训练集里面所有句子更长的句子,假设训练集里面最长的句子是有 20 个单词,突然来了一个长度为 21 的句子,则使用公式计算的方法可以计算出第 21 位的 Embedding。 - 可以让模型容易地计算出相对位置,对于固定长度的间距 k,PE(pos+k) 可以用 PE(pos) 计算得到。因为 Sin(A+B) = Sin(A)Cos(B) + Cos(A)Sin(B), Cos(A+B) = Cos(A)Cos(B) - Sin(A)Sin(B)。

Self-Attention(自注意力机制)

Self-Attention 的结构

c82728af8e6ae6ad762ca5b342c1fdcd.png ## Self-Attention计算过程 dc938f7dcb9d394ecb4b79758075e5b5.png 08aa9832620f2eddea6684da47a87160.png 08aa9832620f2eddea6684da47a87160.png 49d41d9774687ec5b76f2b27ef422ea9.png 01f596ed74f67d255ba0233eba51d1d8.png befdfcadd5d7d8c3b647c07a03864dee.png dcb303ff8e8301e724e23f6531260ff3.png ## Self-Attention输出 1f49200ea7bcd771ac53d58d91eb3b07.png ## Multi-Head Attention Multi-Head Attention相比Self-Attention,会将q, k, v进行分裂 af8dffd0986bdc1c48a02ba28b277231.png 下面是2-head attention的计算过程 8f6287c9fa9b70fe78d9f837ae585eb0.pngPasted image 20231020160435.png # Transformer模型算力要求和内存估算 ## 模型算力要求 估算训练一个 transformer 模型所需的算力成本:

1
C=C前向+C后向=2PD+4PD=6PD
其中,P是 transformer 模型的参数量;D是数据集大小,表示为数据集的总词元数 ## 模型内存估算 Transformer 模型通常由其 参数尺寸 来描述。但是,根据给定一组计算资源确定要训练哪些模型时,你需要知道该模型将占用多少空间 (以字节为单位)。这不仅需要考虑你的本地 GPU 可以推理多大的模型,还需要考虑给定训练集群中的总可用 GPU 内存可供训练多大的模型。

大多数 transformer 模型都使用混合精度进行训练,可以是 fp16 + fp32 或是 bf16 + fp32。混合精度降低了模型训练和推理所需的内存量。推理时,我们还可以将语言模型从 fp32 转换为 fp16 甚至 int8,而没有实质性的精度损失。 bbd1ecc8e81e3f2fd0ee993ef04d5a7f.png

训练

模型训练所需内存主要受到下面几方面影响: #### 模型内存 - 纯 fp32,模型内存=4字节 * 参数量 - 纯 fp16,模型内存=2字节 * 参数量 - 混合精度(fp16/bp16+fp32),模型内存=2字节 * 参数量

优化器内存

对于纯AdamW,优化器内存=12字节 * 参数量 - fp32 主权重: 4 字节 * 参数量 - 动量 (momentum): 4 字节 * 参数量 - 方差 (variance): 4 字节 * 参数量

对于像bitsandbytes 8 位优化器,优化器内存=6字节 * 参数量 - fp32 主权重: 4 字节 * 参数量 - 动量: 1 字节 * 参数量 - 方差: 1 字节* 参数量

对于含动量的类 SGD 优化器,优化器内存=8字节 * 参数量 - fp32 主权重: 4 字节 * 参数量 - 动量: 4 字节 * 参数量

梯度内存

梯度可以存储为 fp32 或 fp16 (请注意,梯度数据类型通常与模型数据类型匹配。因此,我们可以看到在 fp16 混合精度训练中,梯度数据类型为 fp16),因此它们对内存开销的贡献为: - 对于 fp32,梯度内存=4字节 * 参数量 - 对于 fp16,梯度内存=2字节 * 参数量 #### 激活内存 激活重计算 (activation recomputation,或称为激活检查点 (activation checkpointing) ) 就成为一种非常流行的以计算换内存的方法。激活重计算 / 检查点主要的做法是重新计算某些层的激活而不把它们存在 GPU 内存中,从而减少内存的使用量。内存的减少量取决于我们选择清除哪些层的激活。

下面给出存储 transformer 模型激活所需内存的基本公式: 4734b6cfa9f179a7c3fb1634310bf077.png 其中: -  s是序列长度,即序列中词元的个数 -  b是每个 GPU 的 batch size -  h是每个 transformer 层的隐含维度 -  L是 transformer 模型的层数 -  a是 transformer 模型中注意力头 (attention heads) 的个数 -  t是张量并行度 (如果无张量并行,则为 1) - 我们假设没有使用序列并行 - 我们假设激活数据类型为 fp16

总的来说,可以用下述公式来获得不错的估计:

1
训练内总内存=模型内存 + 优化器内存 + 梯度内存 + 激活内存

推理

除了存储模型权重所需的内存外,实际中前向传播过程中还会有少量额外开销。根据我们的经验,此开销在 20% 以内,该比例通常与模型无关。

总的来说,可以用下述公式来获得不错的估计:

1
推理内存 = 1.2 * 模型内存
# 参考资料 * Transformer * Transformer模型详解(图解最完整版) * The Illustrated Transformer * Transformer 估算 101

第一步:复制读书标注

6ed4ee24fdc1207fd845e86c57f9f0af.png

第二步:将格式转换为Readwise导入格式

访问:https://notepal.randysoft.org/ 6507e4b5aaaf250b2b48240b3d5cffba.png

前言

我第一次接触 GTD 大约在 8 年前,这 8 年里不断在各种工具和 App 选择上反复横跳,也尝试过各种任务分类方式,始终无法找到最合适自己。导致 GTD 的实践断断续续。直到去年自己终于总结出了一套适合自己的 GTD 的实践方法,并在实践了半年后写下本文。

什么是 GTD?

GTD 代表"Getting Things Done",是一种时间管理和生产力提高方法,由大卫·艾伦(David Allen)在他的书籍《井然有序的人生》(Getting Things Done: The Art of Stress-Free Productivity)中提出。GTD 方法旨在帮助人们有效地组织和处理任务、项目和信息,以减轻压力、提高工作效率和实现目标。

GTD 方法的核心理念是将所有的任务和想法从大脑中转移到一个外部的信任系统中,这样就可以避免遗漏和分散注意力。这一方法的步骤包括:

  1. 捕捉:将所有想法、任务和承诺记录下来,不论大小。可以使用笔记本、手机应用程序或任何其他工具来收集这些信息。
  2. 清理:对收集到的任务和信息进行处理,分为以下几类:完成、删除、委派、将其变成一个具体的下一步行动,或者将其归档为参考材料。
  3. 组织:将清理阶段中确定的下一步行动安排到合适的上下文和时间,以便在适当的时候提醒自己。
  4. 回顾:定期回顾任务列表和项目清单,以确保所有的任务都得到适当的处理和跟进。
  5. 执行:按照计划执行下一步行动,专注于当前任务,避免分心和拖延。

工具选择

“工欲善其事,必先利其器”,好的工具可以让你事半功倍。我的工具选择之路也是极其漫长:纸笔->doit.im -> any.do -> Wunderlist -> Todoist -> Microsoft ToDo -> Todoist -> 滴答清单 -> Todoist。其中 Todoist、Microsoft ToDo 和滴答清单使用的时间最长。下面我评判 GTD 工具的几个维度:

特性 对比
界面美观,交互简洁 Microsoft ToDo = Todoist > 滴答清单
跨平台(Mac+iOS+Web) 三款都是基于 Web 技术,所以都是全平台
任务多层级管理 Todoist = 滴答清单 > Microsoft ToDo
软件价格 Todoist(付费)> 滴答清单(付费) > Microsoft ToDo = Todoist(免费) = 滴答清单(免费)
生态集成 Todoist > 滴答清单 > Microsoft ToDo
支持优先级和标签 都支持

通过横评 Todoist 基本上就是我心中完美的 Todoist 工具,唯一的缺点估计就是贵了,一年 278。最终还是选择回归了 Todoist 且付费(不过我最近也在考虑是否直接使用免费版的 Todoist)。

我也简单评价下 Microsoft ToDo 和滴答清单:

  • Microsoft ToDo 是微软收购了 Wunderlist 后推出的待办软件,整体还是保留了 Wunderlist 的简洁。尤其是 My Today 功能用于规划你今天的工作,堪称我的最爱,如果和现在的 AI 再结合下估计能非常出彩。
  • 滴答清单是非常难得的国产 App 精品,但也有很多国产 App 的毛病 - 功能太多了,交互复杂,UI 样式老旧。在核心功能上都比 Todoist 差点意思,好在订阅便宜一年 100 多。

常规任务组织:领域式 vs 项目式 vs 时间式

任务组织讲道理是因人而异的,不过不外乎是三类:

  • 领域式:把任务分为个人、工作、学习、生活等不同领域。
  • 项目式:把任务根据项目来划分,比如 XXX 项目,XXX 购物清单等
  • 时间式:把任务分为今天,接下来 7 天,本月,今年等不同时间维度,代表人物 Carl Pullein

领域式 vs 项目式 vs 时间式

组织方式 优点 缺点
领域式 简单,创建的任务总是可以找到一个分类进行放置 人非常容易成为一个任务分类的工具,也不方便我们整体做计划,到底哪些是当前需要关注的,哪些是可以推迟的
项目式 目的明确,完成后清单销毁 对于一些执行力不够的同学,可能会有非常多的项目在进行中或者未完成
时间式 计划感会非常强,更方便任务的聚焦和执行 需要更多的时间进行任务整理和计划]

我的任务组织方式

所以有没有办法将常规的三种任务组织方式结合起来呢?实际上是可以的,通过我自己学习和实践总结出来下面的任务组织方式:

  • Inbox:无论任务大小都先丢入 Inbox,然后等待任务的组织和扩充。
  • One-Off Task:用于管理目标和执行时间明确的一次性的任务,然后执行。比如说从淘宝上买本《Getting Things Done》。
  • Projects:对于一些可预见的复杂任务或者随着任务执行的进行可能会不断产生新的任务出来的这类任务。比如房屋装修,拟定计划,签合同,买材料等等,都是没法一次性完全规划好的,会随着任务进行而不断产生新的任务,但是最后也会全部完成。
  • Recurring:针对一些周期性任务,比如说归还信用卡
  • Someday/Maybe:放置一些当前无法直接开始或者无法继续下去的任务。可以理解为是一个 Backlog,为了方便管理可以添加不同的 Area,例如 Someday/Maybe - Personal 和 Someday/Maybe - Work
  • Miscellaneous:这类主要放置一些长期持续更新且分类明确任务清单,比如说书单,想看的电影等。

接下来我结合 GTD 的工作流介绍下我的任务工作流: b88e22599e9066f4601fde27e1dc840e.png

仅有这些分类在实际的日常使用时是不够的,所以我会额外引入标签系统:

  • 优先级的标签:P1、P2、P3 和 P4
  • 任务状态的标签:in_progress、pending 和 delegated
  • 任务执行场所:home、office、computer 和 mobile
  • 特定任务标签:blog_writing

最后

GTD 的工具和实践方式因人而异,找到自己最好方式后,do it now!

论文原文:Hidden Technical Debt in Machine Learning Systems

在文章的开篇,Google工程师们就指出:虽然开发和部署机器学习系统相对快速并且成本低廉,但是持续的维护比较困难且成本高昂。这是由于:

首先,机器学习系统本质上也是一种软件系统,所以它具有其它软件系统中存在的技术债务。更复杂的是,机器学习系统又有很多机器学习相关的技术债务。而这些问题往往存在于系统级别 (system level),而不是代码级别 (code level)。

基于上面的判断,作者们给出了基于他们实践经验的技术债务总结。

复杂模型侵蚀边界 (Complex Models Erode Boundaries)

作者们指出的是:在传统的软件工程中,人们往往需要用封装、模块化等等手段来定义一些抽象边界,以达到改善软件系统的可维护性的目的。然而,在机器学习系统中,由于其依赖于大量的外部数据,这样的边界变得难以准确描述和定义了。

举个例子,如果一个机器学习系统中的模型使用了特征x1, x2, ..., xn。当x1的分布情况变化时,原有模型的其他特征的权重也会发生改变,这就给系统的管理带来了很大的挑战。作者们把这种影响叫做CACE原则:

Changing Anything Changes Everything. (改变任何一个就改变了所有)

这个问题称做Entanglement,作者们给出了两个方案来改善这一问题:隔离模型专注检测模型预测中的变化

数据依赖比代码依赖成本更高(Data Dependencies Cost More than Code Dependencies)

在传统的软件工程中,人们往往可以借助于静态分析(Static Analysis)来发现和分析代码依赖关系。然而在机器学习系统中数据的依赖关系要更难以分析。

第一个问题就是数据的依赖关系可能很不稳定(Unstable data dependencies)。一个简单的例子就是一个机器学习系统可能把另一个系统的输出作为一个输入。然后,这种输入是不稳定的,并且变化是难以觉察的。作者们给出了一个可行的方案是对输入进行版本控制。

另一个问题就是不必要的数据依赖(Underutilized data dependencies),比如随着系统的变化不再需要的软件包。作者们建议用 leave-one-feature-out 的方法,来定期的检查和去除非必要的软件包。

由于数据依赖方面静态分析(Static analysis of data dependencies)工具的缺失,作者们也建议开发相应的工具来帮助分析数据依赖。

反馈循环(Feedback Loops)

对于在线学习系统而言,一个非常重要的特性就是模型需要持续更新。一种常见的实践是建立一个反馈循环,用于持续更新模型。

机器学习系统的反模式(ML-System Anti-Patterns)

在一个实际的机器学习系统中,仅仅一小部分代码是用于学习和预测的。随着时间的推移,一个机器学习系统中会出现各种各样系统设计中的反模式。 f2bd64181b33c5bbf7f894d8042093e6.png

胶水代码(Glue Code)

作者们发现机器学习工程师们倾向于使用各种通用的机器学习库来编写代码,这就导致了系统中存在着大量的来自于庞大的通用机器学习库的代码。作者们的建议是把这些胶水代码用相同的API封装起来。

管道丛林(Piepline Jungles)

这里主要指的是数据准备(data preparation)阶段可能存在的问题。如果不加以注意,随着时间的推移,越来越多的输入信号加入到数据准备中,导致其变成一个混杂着各种爬虫、连接、取样等各种数据操作的丛林。有意思的是,作者们给出的解决方案是让工程师和科研工作者更多的合作,譬如在一个团队中,来帮助减少这种问题。

无用的实验代码路径(Dead Experimental Codepaths)

机器学习常常伴随着大量的试验,很容易导致在原有代码中产生各种条件分支。而后,随着条件分支越来越多,系统的技术债务也随之增加。作者们建议定期检查并删除这些无用的代码路径。

抽象债务(Abstraction Debt)

那么为什么会有这么多的技术债务问题呢?作者们的观点是我们目前还是缺乏用来描述机器学习系统的强抽象。无论是 MapReduce 还是 pramater-server 都达不到需要的抽象描述。

常见味道(Common Smells)

在软件工程中,有一个词语常常用来描述可能的代码结构问题,叫做坏的代码味道(bad code smell)。那么这里呢,作者们也列举了几个他们发现的可能的机器学习系统的坏的代码味道。

  • 基础数据类型(Plain-Old-Data Type Smell)
  • 多种语言(Multiple-Language Smell)
  • 原型(Prototype Smell)

配置债务(Configuration Debt)

由于机器学习系统和算法的复杂性,一个大型的机器学习系统中常常存在着大量的配置,譬如使用哪些特征、数据如何选取、具体算法的参数设置、预处理的方式等等。作者们强调了配置的可维护性和易读性。譬如,配置也应该经过代码评审并提交到代码库中。

处理外部环境的变化(Dealing with Changes in the External World)

一个机器学习系统常常要和外部世界交互。然而,一个不容忽视的问题就是外部环境常常存在着各种变化。这无疑给机器学习系统的维护带来了极大的挑战。比如,一个机器学习系统应该如何监测呢?我们知道一个模型上线后,随着时间的推移以及新的数据的注入,常常会发生概念偏移(Concept drift),模型的准确率可能会有较大的变化。所以持续的监控和预警也就是非常必要的了。

论文原文:Hidden Technical Debt in Machine Learning Systems

在文章的开篇,Google工程师们就指出:虽然开发和部署机器学习系统相对快速并且成本低廉,但是持续的维护比较困难且成本高昂。这是由于:

首先,机器学习系统本质上也是一种软件系统,所以它具有其它软件系统中存在的技术债务。更复杂的是,机器学习系统又有很多机器学习相关的技术债务。而这些问题往往存在于系统级别 (system level),而不是代码级别 (code level)。

基于上面的判断,作者们给出了基于他们实践经验的技术债务总结。

复杂模型侵蚀边界 (Complex Models Erode Boundaries)

作者们指出的是:在传统的软件工程中,人们往往需要用封装、模块化等等手段来定义一些抽象边界,以达到改善软件系统的可维护性的目的。然而,在机器学习系统中,由于其依赖于大量的外部数据,这样的边界变得难以准确描述和定义了。

举个例子,如果一个机器学习系统中的模型使用了特征x1, x2, ..., xn。当x1的分布情况变化时,原有模型的其他特征的权重也会发生改变,这就给系统的管理带来了很大的挑战。作者们把这种影响叫做CACE原则:

Changing Anything Changes Everything. (改变任何一个就改变了所有)

这个问题称做Entanglement,作者们给出了两个方案来改善这一问题:隔离模型专注检测模型预测中的变化

数据依赖比代码依赖成本更高(Data Dependencies Cost More than Code Dependencies)

在传统的软件工程中,人们往往可以借助于静态分析(Static Analysis)来发现和分析代码依赖关系。然而在机器学习系统中数据的依赖关系要更难以分析。

第一个问题就是数据的依赖关系可能很不稳定(Unstable data dependencies)。一个简单的例子就是一个机器学习系统可能把另一个系统的输出作为一个输入。然后,这种输入是不稳定的,并且变化是难以觉察的。作者们给出了一个可行的方案是对输入进行版本控制。

另一个问题就是不必要的数据依赖(Underutilized data dependencies),比如随着系统的变化不再需要的软件包。作者们建议用 leave-one-feature-out 的方法,来定期的检查和去除非必要的软件包。

由于数据依赖方面静态分析(Static analysis of data dependencies)工具的缺失,作者们也建议开发相应的工具来帮助分析数据依赖。

反馈循环(Feedback Loops)

对于在线学习系统而言,一个非常重要的特性就是模型需要持续更新。一种常见的实践是建立一个反馈循环,用于持续更新模型。

机器学习系统的反模式(ML-System Anti-Patterns)

在一个实际的机器学习系统中,仅仅一小部分代码是用于学习和预测的。随着时间的推移,一个机器学习系统中会出现各种各样系统设计中的反模式。

ml-code-in-real-world.jpg

胶水代码(Glue Code)

作者们发现机器学习工程师们倾向于使用各种通用的机器学习库来编写代码,这就导致了系统中存在着大量的来自于庞大的通用机器学习库的代码。作者们的建议是把这些胶水代码用相同的API封装起来。

管道丛林(Piepline Jungles)

这里主要指的是数据准备(data preparation)阶段可能存在的问题。如果不加以注意,随着时间的推移,越来越多的输入信号加入到数据准备中,导致其变成一个混杂着各种爬虫、连接、取样等各种数据操作的丛林。有意思的是,作者们给出的解决方案是让工程师和科研工作者更多的合作,譬如在一个团队中,来帮助减少这种问题。

无用的实验代码路径(Dead Experimental Codepaths)

机器学习常常伴随着大量的试验,很容易导致在原有代码中产生各种条件分支。而后,随着条件分支越来越多,系统的技术债务也随之增加。作者们建议定期检查并删除这些无用的代码路径。

抽象债务(Abstraction Debt)

那么为什么会有这么多的技术债务问题呢?作者们的观点是我们目前还是缺乏用来描述机器学习系统的强抽象。无论是 MapReduce 还是 pramater-server 都达不到需要的抽象描述。

常见味道(Common Smells)

在软件工程中,有一个词语常常用来描述可能的代码结构问题,叫做坏的代码味道(bad code smell)。那么这里呢,作者们也列举了几个他们发现的可能的机器学习系统的坏的代码味道。

  • 基础数据类型(Plain-Old-Data Type Smell)
  • 多种语言(Multiple-Language Smell)
  • 原型(Prototype Smell)

配置债务(Configuration Debt)

由于机器学习系统和算法的复杂性,一个大型的机器学习系统中常常存在着大量的配置,譬如使用哪些特征、数据如何选取、具体算法的参数设置、预处理的方式等等。作者们强调了配置的可维护性和易读性。譬如,配置也应该经过代码评审并提交到代码库中。

处理外部环境的变化(Dealing with Changes in the External World)

一个机器学习系统常常要和外部世界交互。然而,一个不容忽视的问题就是外部环境常常存在着各种变化。这无疑给机器学习系统的维护带来了极大的挑战。比如,一个机器学习系统应该如何监测呢?我们知道一个模型上线后,随着时间的推移以及新的数据的注入,常常会发生概念偏移(Concept drift),模型的准确率可能会有较大的变化。所以持续的监控和预警也就是非常必要的了。

论文原文:A Berkeley View of Systems Challenges for AI

这又是篇不涉及过多技术的一篇论文,不过其中提到的Challenges确是目前AI Systems一直在努力解决的。

文中提到的几点关于AI System的Challenge:

  • Design AI systems that learn continually by interacting with a dynamic environment, while making decisions that are timely, robust, and secure.
  • Design AI systems that enable personalized applica- tions and services yet do not compromise users’ privacy and security.
  • Design AI systems that can train on datasets owned by different organizations without compromising their confidentiality, and in the process provide AI capabilities that span the boundaries of potentially competing organization.
  • Develop domain-specific architectures and soſtware systems to address the performance needs offuture AI applications in the post-Moore’s Law era, including custom chips for AI work-loads, edge-cloud systems to efficiently process data at the edge, and techniques for abstracting and sampling data.

在论文中也提出了一些解决上述Challenge的研究方向: ca8b63b2530cd83225cd07e4ef8f8767.png

论文原文:A Berkeley View of Systems Challenges for AI

这又是篇不涉及过多技术的一篇论文,不过其中提到的Challenges确是目前AI Systems一直在努力解决的。

文中提到的几点关于AI System的Challenge: * Design AI systems that learn continually by interacting with a dynamic environment, while making decisions that are timely, robust, and secure. * Design AI systems that enable personalized applica- tions and services yet do not compromise users’ privacy and security. * Design AI systems that can train on datasets owned by different organizations without compromising their confidentiality, and in the process provide AI capabilities that span the boundaries of potentially competing organization. * Develop domain-specific architectures and soſtware systems to address the performance needs offuture AI applications in the post-Moore’s Law era, including custom chips for AI work-loads, edge-cloud systems to efficiently process data at the edge, and techniques for abstracting and sampling data.

在论文中也提出了一些解决上述Challenge的研究方向: A_mapping_from_trends_to_challenges_and_research_topics