大家好。前几天整了个小活,把Gadio从创始到23年末的2300多期电台内容做成了可以用语意搜索的向量数据库,所以就出现了这么一个所谓的"Gadio高维空间定位系统",名字起的可谓是有理由中二(理由我们后文再说)。今天稍有闲时,于是起意用一篇小文来记录一下这件事的过程里觉得值得聊的事情,以及自己的收获。
用这个系统大概率可以搜到一些我们记忆中的电台片段到底出自哪一期节目,比如说后来成为了“机组曼德拉效应”的代表片段:酒馆里猫被酒毒死了到底是不是四十二说的?
再比如下面的这么几个自己曾经想找却没找到的片段↓也都秒速找到了出处。(看来我就是对中元夜话记得特别多……)
现在这个系统已经上线了,感谢@alizoed 老哥提供部署。如果您马上就想要测试一下,请直接拉到文末找到链接与使用指南。因为这个纯语意搜索系统和传统的关键词搜索用法不太一样,所以推荐您一定先看一眼使用说明。
简陋科普:基于语意的搜索是怎么做到的??
项目简介:本项目的技术栈和大概构架
使用说明和注意事项
一、如何让电脑理解“恐惧”和“害怕”这两个词具有相似性?
这是个非常有意思的问题,“恐惧”和“害怕”这两个词,除了都是由两个字组成之外,从字形和读音上判断,几乎是毫无相似之处,但你说他俩完全等效吗?也肯定不是。那么是不是有一种方法,可以让电脑能够处理这种微妙的相似和不同呢?人类这么聪明肯定能想出办法来,而且这个办法确实很精彩。
请在脑海中想象一个失重的空间,这个空间里漂浮着汉语里所有的词汇,围绕着你,非常纷繁复杂,但所有的词的位置,都是固定不动的。此时,你稍作观察,找到了“恐惧”和“害怕”这两个词,发现他俩都处于你左前方的那个角落里,而且贴的很近很近。然后你飞过去仔细观察,发现这两个词附近的空间你还能找到“惊悚”“吓人”这种近意词,稍微再拓宽一点点视野,你会找到如“梦魇”“魔鬼”这种虽然意思不一样,但是含义上也会有微妙重合的词。显然,这个空间里漂浮的词,他们是根据相似的含义聚集在一起的,越是相似的词,就聚拢得越近。那么……
此时你福至心灵,回望自己出发的原点,朝着相反的方向望去,果然,你在那里找到了“幸福”“开心”这种词。
这个空间,我们可以暂时叫它“语意空间”,每个词在里面都有一个点。通过点的坐标,我们也可以非常容易地计算出两个点之间的距离远近。至此,这种难以捉摸的微妙相似性被转化为了纯粹的数学问题。
读到这里,显然,这设想还只是个饼,落不了地啊~最关键的一点没解决——要怎么才能有效地把词语和句子转化成有语意特征的坐标点呢?总不能有一个人在那一个个放点吧……这就是自然语言处理(NLP)领域的重要突破——词嵌入(Word Embedding) 。这个过程是通过一个训练好的神经网络模型完成的,这个模型的输入是一个词,或者一句话,甚至是一段话,输出则是一个高维向量,也就是坐标值,只不过数量上超过了xyz三个坐标数字,来到了几百上千个维度。(哎,回收封面啊,这就是为啥要叫“高维”定位的原因,合法中二。)
下一个问题,则是为何这个Embedding模型可以做到这一点?简单来说,这个模型是通过在巨量的文本里面寻找词语出现的规律,来学习词语的语意相似性。比如,在它看过的数亿个句子里,出现了好多好多次类似“令人恐惧/害怕的东西经常会出现在噩梦/梦魇中。”这种表达,有时候句子里用的是“恐惧”有时候用的是“害怕”,那么这个模型就会基于此,学到这两个词是相似的。当然,实际情况还要复杂得多,比如除了同义词,近义词,还会学到反义词,上下位词,但究其根本,是统计学意义上的规律。具体的展开各位可以搜索Embedding模型训练原理,肯定有大佬做过更有效的讲述,此处不多展开(避免露怯)
至此,我们居然做到了随便给一句话或者一段话,就能把它变成高维空间中的一个有着具体位置的点。(在Gadio这个项目里用到的是阿里的 damo/nlp_gte_sentence-embedding_chinese-base这个模型,没记错的话是768维度。也就是说你给它输入一个词或者句子,它会返回给你768个数字,代表了一个768维空间中的点,这个点的位置,就包含了输入文字的语意特征。)
那么剩下的就简单很多了,我们只需要把电台的所有文本都逐个喂给Embedding模型,然后把向量存起来,到时候查询的人来了,把查询的内容也转换成768维度的空间中的一个点,就好像一个灯塔,只要把它周围距离最近的几个点抓回来,也就是我们的搜索结果了。
这里面落地的过程中还有很多细碎的问题,我直接枚举到下方,也就直接交代清楚了这个项目的流程。
第一个任务:语音转文字。这个过程一开始用的是OpenAI的Whisper,后来发现非常不好用!首先很慢,其次中文的准确度和稳定性都很差,动不动就一整篇的无限复读重复,就不截图了。总之,最后用的是阿里家的 funasr 里面的 paraformer-zh 这个模型,效果拔群,经过一张4090显卡150小时的奋战,成功将2300多期电台转化为了170m大小的TXT。(之前记错了以为是15m,抱歉!!!)
第二个任务:文字切块。这个过程基本是把一整个电台的文本切成小块,这样语意的特征会更加集中,会更容易按某一个具体的内容搜索到正确的结果。这里采用了很常规的方法,就是为了防止恰好内容被切断,每一个块都和它的前后有50%的重叠。也感谢语音识别模型稳定的发挥,得以让我们在标点符号处切割,至少不会把句子截断。这样切割后,文字量直接翻倍。
第三个任务:向量化。无需多言,一片片文本塞给Emebedding模型,然后把得到的向量一个个保存好。向量化之后数据量直接来到了5G,5个G全是数字啊朋友们,打开一看老吓人了。
第四个任务:整理元数据+灌库。以上整个过程里做好数据的标签,保证最后的每一个向量都能准确地反过去查找到“原文”、“时间戳”、“电台节目名字”、“电台网址”这几个东西,然后联合向量,变成一条条的数据灌入ChromaDB(一个最近还挺流行的免费向量数据库工具。)为啥要用数据库呐?因为快和方便~如果直接是硬搜,会导致每一次查询都和5个G的数据一条条对比,很灾难。但是向量数据库会自动把内容分簇,先找到最接近的那一簇,然后再往下面的分支里走,这样可以很快就找到结果。
这里还可以再展开聊一个“欧式距离”和“余弦距离”的事儿,也很有意思。这是两种不同的计算空间中两个点的距离的方法,很微妙地反应出了数学算法和抽象语意之间的关系。
简单说,余弦距离是站在坐标原点看角度,只要这两个点,从我坐标原点看过去几乎重合,哪怕他俩在空间中距离很远,我也算他俩很接近。好比我们人看到金星凌日,金星撞进太阳里了,其实人家俩距离远着呢,只是从我们的角度看很近。
乍一听是不是很不合理?哎~好玩就在这里,人们发现用这种方法去求距离的时候,可以忽略文本长度!也就是说,如果我输入的搜索文本只有10个字,但是电台里这个事儿他们花了100个字才把这事儿说完,用这个方法就可以更有效地匹配到我的输入和电台文本之间的相似关系。欧式距离呢,就是真正的两个点之间连条线,这个线的长度。毫无疑问,在我们的这个场景里,更适合用余弦距离。(我当时学会这个区别的时候简直从椅子上蹦起来。)
我注:感谢评论区前辈 catbaron 提醒,以上这段内的观点是有争议的内容,我确实也没有去寻找相关文献和研究作为作证。请各位谨慎对待。唯一可以理性明确的是,不管100个字还是10个字,经过embedding模型的处理,输出的向量维度是固定的,且向量的范数长度也不一定和文本的字数完全正相关。另一个可以理性明确的是,余弦距离比欧式距离确实舍弃了一些东西,而被舍弃掉的这些东西到底是什么,则不是能言之凿凿确定的。所以也有一种观点认为,如果对文本的具体表达方法(如词汇语法结构等)敏感的场景会更适合欧式距离,但这和“文本长度论”类似,也是一种观点。可能后续我有机会的时候会深入做一些综述研究,到时候如果有新的成果再来此处更新。 第五个任务:编写后端服务和前端网页。具体不展开啦!这里也比较枯燥~(我也不咋会主要是……)
相信如果您不是跳到这里的话,使用方法不用我来赘言了。请直接移步地址。但如果您真的是跳过来的,请参考下面这一点点说明:
注意这个不是关键词搜索系统,是语义搜索系统,所以描述长一点反而比单独一个词更容易搜到。能想起来的上下文越多越容易搜到。不用准确。也不用说“电台”字样。这里需要大家走出传统的搜索思路。
“圣经 莎士比亚 46”
“42评论往日之影结局”
“重轻老师讲调式那期节目”
成为你的剑
另外这个系统目前不认识人名或者专有名词,所以“西蒙说xxxxx”这种就直接写“xxxxx”的内容就可以了。(也可以写上,万一呢)
唯一宗旨:用节目里人的说话内容来搜,而不要用局外人的角度。因为毕竟检索的文本本体是电台内容的语音识别稿。
(如果按了按钮没有出现结果,估计是故障了,欢迎私信俺)
既然我们已经拿到了所有节目的向量,那如果把每个节目里的向量求个平均值,是不是这个平均向量就能代表这个节目的特征呢?
于是我们成功地使用自动聚类算法把2300期节目分成了n个类别。而且随着类别的增多,我们会发现各种有意思的小细节。比如"核市节目确实是非常“独树一帜”地特征鲜明,总能做到自己一类",还有“最像常规节目的新闻节目”,“最不Pro的pro节目”(冒犯)之类的。。。
而且随着类量的增多,可以明显看出来分类依据有从“内容范式和结构”向“具体垂直领域划分”变化的趋势。比如下图是100类的时候出现的
显然,被蛮荒之地这期节目打动的我,找到了很多也非常值得重温的节目,而这些节目里的大多数都不是“浪潮的把戏”系列里的,还算蛮惊喜~
当我们对某一个节目引起共鸣的时候,也可以通过这种方法来给自己“算法推荐”一波哈哈哈哈哈。具体下期我们再展开聊,我再探索探索还有没有别的好玩的。另外站内文章也正在做嗷。
这个时代发展的真太快了,如果有在这个领域了解多一些的朋友肯定会知道一件事情,就是本项目里使用的技术其没有一个是2023年这一波爆火的AI新突破里的。这种把文字向量化之后用于搜索的行为其实在很多很多年之前就已经有了。大家仔细观察一下搜索引擎的行为就会发现,现在的搜索引擎并不是纯脆只做关键词匹配的。
也在评论区和私信有幸遇到同志与老师,交流中提及了一些对项目的改进想法,尤其是站在23年这一波生成式AI技术井喷的背景下,是不是能结合新技术做出一些更好的功能来?顿时觉得这也是一个很适合行文的选题,所以先把一些提纲挈领的思考列在下面,也是希望能抛砖引玉和大家一起讨论,有对的不对的欢迎大家斧正,共同进步。
首先,为什么没有选择类似ChatGPT那种对话式交互。
这个确实也是项目初期有郑重考虑过的问题,但是因为以下几个原因放弃了
对话交互这种形态的产品,如果不是陪聊,而是提供准确的信息,那么基本构架思路大概率是RAG(检索增强生成),简单说就是把用户提问和我们正文里说的数据库检索结果一起发给大语言模型,然后让它综合二者生成一段自然语言的回复。主流RAG技术栈里的LLM作用重点在于扩充问题,甄别召回结果和充当UI界面,但这三个功能在本场景下其实都不太适用。↓
扩充问题方面,本质无非是向query中填充生成的细节,显然这大多数情况下会降低用户回忆起来的(很有限的那一点点)具体信息的密度。如果我们做的是“发现没听过的电台里的相关内容”,或许这一点用进去才是成立的。
甄别召回结果方面,这个地方纯粹是因为使用体验和成本考虑。因为比如我们从数据库中拿出10个结果只需要0.1秒,但是把这十个结果发给LLM再等到它的回复可能就得是10s起了。另外我在寻找记忆中模糊的片段的时候,描述方法可能并不是那么理性,这时候让LLM根据Query去做判断准确率会很低,(比如有时候用户看到搜索结果都不用读正文,只要看到了题目就知道对了就是这个。)权衡下来最好还是给用户自己判断。(另外性能好点的LLM也不便宜哇)
充当UI,这个就不用说了,因为经过LLM转写一遍的搜索结果必然会集中在它认为和Query相关度高的信息,丢失掉其他信息。而我们的场景里,“其他信息”可能非常关键。
其次,如果有了电台文本,是否可以通过对大语言模型训练和微调,做出什么更有意思的东西
这个我其实非常期待,但确实从我对技术现阶段的理解,并没有找到能成立的产品思路。原因如下(这里的观点非常主观,由衷希望有真技术大佬批评教导)
电台文本经过STT转写,目前并不是问答对话的形式(其实电台内容本身的上下文也很难说是一种严格意义上的对话形式),所以它很难直接作为常规的对话交互微调样本。
另一方面电台文本内容五花八门,内容和知识并不垂直集中,讲述人也很多,而且STT的过程里还有不少识别错误的地方。。。所以如果是作为类似挖空mask这种类似预训练的微调样本,可能品质还不如开源的通用文本训练集。
如果直接做出一个纯粹为了整活的“Gadio文本生成器”呢?感觉其实2000多期的样本还有点少。。。而且充满了识别错字和不分说话人的问题,生成出来也没什么可读性的感觉。。。
使用加入MetaData或者和传统的字符匹配搜索结合的方式提高搜索准确度
开源: https://github.com/jlmaoju/Gadio_Vec/
初次尝试开发项目,路子很野,代码仅供参考。内含聚类结果,可用于发掘相似节目推荐。本来自己把txt的转录内容也开源上去了,但是有法律的朋友告诉我说如果是纯的转录内容的话,版权可能是不属于我的,那么我直接开源是一种不合适的行为。所以原文还是暂不发出来了。请各位海涵。 注:付费节目从一开始就没包括。 以上,由衷感谢有好多朋友都很感兴趣,这确实真的是我的(并列)第一个开发项目,刚开始学代码2个月不到,连github都不会用,完全是无知者无畏的架势。。。有胆子闯入这个领域其实初心是为了给自己已经离开的建筑设计行业做一些有价值的事情,比如说这个。是个(希望)能自动帮助建筑师一键完成案例研究的工具↓(年后想搞波内测)
所以也希望在此方向各位前辈多多提点,不论是针对Gadio还是建筑领域都是,感谢感谢。
评论区
共 82 条评论热门最新