300万行到100行:机器学习造就更好的开发体验

本文转载自公众号“读芯术”(ID:AI_Discovery)。

这个场景想想就很灾难了:为了找到发生在第100万行上的bug或回归,不得不在一个失败的软件构建中浏览2.5GB的日志条目(也就是300万行),这简直难以靠人工手动完成!

还好,有一个巧妙的方法能解救你——执行diff命令,将这些行与最近成功的软件构建进行对比,期望bug在日志中生成异常行。

300万行到100行:机器学习造就更好的开发体验

标准的md5 diff命令执行速度很快,但它显示了行之间的字符级差异,因此仍然会生成至少数十万候选行以供浏览。使用机器学习中K-最邻近聚类的模糊diffing算法(logreduce所做的事情)能产生大约40000条候选行,但需要一个小时才能完成。

而我们的解决方案是在20分钟的计算时间内生成20000行候选行——而且得益于开放源码,只需要大约100行Python代码就能实现。

该应用程序结合了神经嵌入(将单词和句子中的语义信息进行编码)和局部敏感哈希算法(高效地将大致邻近的项分配到相同的储存器,而将远处的项分配到不同的储存器)。将嵌入式系统与LSH(Locality Sensitive Hashing,局部敏感哈希)结合是个不错的想法,而这一想法的诞生还不到十年!

300万行到100行:机器学习造就更好的开发体验

我们急不可待地在CPU上使用了Tensorflow 2.2,用于迁移学习,而将scikit-learnNearestNeighbor用于K-最邻近算法。实际上,有一些复杂的近似最邻近实现会更有助于实现基于模型的最邻近解决方案。

嵌入式系统是什么?为什么需要它们?

构建k-hot词袋模型是一个典型的出发点,常常针对非结构化或半结构化文本的重复数据删除、搜索和相似性问题,这类词袋编码看起来很像一个包含单个单词及其计数的字典。下面以“log in error, checklog”这句话为例:

{“log”: 2,“in”: 1, “error”: 1, “check”: 1} 

这种编码还可以借助向量表示,其中索引对应一个单词,值是计数。下面以“log in error, checklog” 为例展示其如何用向量表示,其中第一个条目保留为“log”单词计数,第二个条目保留为“in”单词计数,以此类推:

[2, 1, 1,1, 0, 0, 0, 0, 0, …] 

注意,这个向量由许多0组成。零值条目表示所有存在于字典中,但未出现在本句中的所有其他单词。可能出现的向量条目总数,或向量的维数,是你语言字典的容量,通常可达几百万条或更多,可以通过一些巧妙的技巧精简到几十万条。

现在来看看“problem authentication”的字典和向量表示,与前五个向量条目对应的单词根本不会出现在新句子中。

{“problem”:1, “authenticating”: 1} 
[0, 0, 0, 0, 1, 1, 0, 0, 0, …] 

这两个句子在语义上是相似的,也就是说它们的意思本质上是一样的,但是在词汇上是截然不同的,它们没有出现相同的词。在模糊区分设置中,可能这些句子太相似而不能突出显示,但是K最邻近算法中的md5和k-hot文档编码不支持该功能。

降维使用线性代数或人工神经网络的方式将语义相似的单词、句子和日志行邻近放在一个新的向量空间中,用“嵌入”来表示。在示例中,“log in error,check log”可能有一个五维嵌入向量:

[0.1, 0.3,-0.5, -0.7, 0.2] 

“problem authenticating”可能是:

[0.1,0.35, -0.5, -0.7, 0.2] 

与它们的k-hot词袋模型向量不同,这些嵌入向量通过距离度量的方式(比如余弦相似度)彼此接近,密集、低维的表示对于诸如构建行或系统日志的短文档十分有用。

实际上,你需要用100个而不是5个信息丰富的嵌入维,来替换几千个或更多个字典维,最先进的降维方法包括单词共现矩阵的奇异值分解(GloVe)和专门的神经网络(word2vec, BERT,ELMo)。

聚类是什么?让我们再回到构建日志应用程序

我们开玩笑说Netflix是一个日志制作服务商,它有时会传输视频。在异常监视、日志处理和流处理等领域,每秒会处理几十万个请求。如果我们想在遥测和日志空间中应用机器学习,必须要扩展NLP解决方案。

300万行到100行:机器学习造就更好的开发体验

图源:unsplash

这就是为什么我们关注扩展文本重复数据删除、语义相似度搜索和文本异常值检测等问题——如果需要实时解决业务问题,这是唯一的办法。

diff命令解决方案包括将每个行嵌入到一个低维向量中(可选择“微调”或同时更新嵌入模型),将其分配到一个聚类中,并将不同聚类中的行标识为“不同”。局部敏感哈希是一种概率算法,它允许常数时间的聚类分配和近常数时间的最邻近搜索。

LSH的工作原理是将一个向量表示映射到一个标量数字,或者更准确地说是映射到一个标量的集合。标准哈希算法的目标是避免任何两个不相同的输入之间的冲突,而LSH的目标是在输入距离较远的情况下避免冲突,输入不同但在向量空间中彼此靠近的情况下促进冲突。

“log in error, checklog”的嵌入向量可以映射到二进制数01(01表示集群)。“problem authenticating”的嵌入向量很有可能映射到相同的二进制数01。这就是LSH如何实现模糊匹配、反问题和模糊区分,LSH早期应用于高维词袋模型向量空间。

300万行到100行:机器学习造就更好的开发体验

使用LSH将字符放在同一个储存器中,但方向颠倒。

在构建日志的文本离群点检测中应用LSH和神经嵌入,它将允许工程师查看日志的一小部分行来识别和修复潜在的关键业务软件中的错误,并且它还允许我们实时获取几乎任何日志行的语义聚类。

现在,将语义LSH的这一优势应用到Netflix的每个构建中。语义部分允许我们基于含义对看似不同的项目进行分组,并将它们标注在异常值报告中。