心法利器

本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有。

2023年新的文章合集已经发布,获取方式看这里:又添十万字-CS的陋室2023年文章合集来袭,更有历史文章合集,欢迎下载。

往期回顾

心法利器[110] | 知识文档处理和使用流程

心法利器[111] | 近期RAG技术总结和串讲(4w字RAG文章纪念)

心法利器[112] | 考古RAG-20年RAG概念提出的论文

心法利器[113] | RAG结构思考:搜索系统范式和大模型作用压缩

心法利器[114] | 通用大模型文本分类实践(含代码)

前沿重器[48-54] 合集:四万字聊搜索系统

之前自己写了一个系列——bad case治疗术,用于详细和大家解释,为什么以及如何做bad case分析,从而逐步更有针对性地优化自己的算法方案,历史传送门在这里:

心法利器[37] | bad case治疗术:认知篇

心法利器[38] | bad case治疗术:现状篇

心法利器[39] | bad case治疗术:分析篇

心法利器[40] | bad case治疗术:解决篇

今天想在这基础上补充一篇,就是实践,借助一个案例,让大家理解整个bad case的修复流程是什么样的,从而让大家更加理解这个系列的内容。

现在开始,我会按照我之前聊的流程,逐步和大家讲这个流程。

案例背景

这次的案例,我选择的是上周讲过的这篇里的方案和数据:心法利器[114] | 通用大模型文本分类实践(含代码)。

首先是数据,直接上连接:https://github.com/aceimnorstuvwxz/toutiao-text-classfication-dataset,这个链接里的样本是各个场景下的文章标题,类目则是文章标题所属的领域,里面大概有15个左右,数据集也不小,有38万,此处就是取了1万出来,测试集1000,训练集9000。

方案上,就用的上期提到的大模型文本分类方案,给定一个待分类的文本query,第一步是从训练集中查出与query相似的样本,取TOP N,第二步是交给大模型做最终决策,看属于这个query属于哪个类,思路上还是比较好理解的,具体的方案细节可以参考我的这篇文章(心法利器[114] | 通用大模型文本分类实践(含代码))以及对应的开源项目:https://github.com/ZBayes/poc\_project/tree/main/llm\_classification。

识别现状

按照bad case治疗术的流程,第一步是识别现状,先回忆一下,我定义的现状是什么样的:

现在有一个基本baseline,baseline自然就有对应的评测集基线方案的效果,这个所谓的效果,就是现状,好or不好,是否需要持续优化,哪个方面需要持续优化,这就是所谓的现状,只有明确了宏观的现状,才能知道我们下一步的动作。

这里有3个要素,评测集、指标、结论。

评测集是评估效果的原料,数量和质量上都有很高的要求,只有评测集正确了,那评估出来的指标才是可靠的。

指标,指标能体现有两个点,一个是好坏,一个是暴露问题,前者很好理解,后者是可以通过构造特地给的指标来观测是什么位置出了问题,这点会在后面展现。

结论,结合指标,给出具体效果好坏以及问题点的初步结论。

然后我们一步步来整。

第一步就是评测集。因为这只是个实验,所以没有生产数据集,只能简单从数据集中随机抽1000条数据作为测试集(请注意,如果是现实应用中,还是应该尽可能拿到和实际应用场景分布一致的测试集,如某个问题在实际应用中出现的概率是1%则测试集也尽量要在1%左右),随机从给定数据里抽是实验是里一个常见的模拟方法了。

第二步是指标,作为多分类问题,常见的指标就是精确率、召回率和F1,详细如下:

precision recall f1-score support

科技-科技 0.64 0.90 0.75 96

国际-国际 0.73 0.71 0.72 79

娱乐-娱乐 0.69 0.81 0.74 91

教育-教育 0.71 0.89 0.79 90

民生-故事 0.54 0.47 0.50 15

证券-股票 0.00 0.00 0.00 1

军事-军事 0.80 0.60 0.69 58

旅游-旅游 0.64 0.84 0.73 58

文化-文化 0.83 0.74 0.79 74

体育-体育 0.87 0.84 0.86 89

房产-房产 0.87 0.73 0.80 45

财经-财经 0.92 0.37 0.53 89

农业-三农 0.84 0.73 0.78 49

电竞-游戏 0.89 0.77 0.83 77

汽车-汽车 0.92 0.87 0.89 89

micro avg 0.76 0.76 0.76 1000

macro avg 0.73 0.69 0.69 1000

weighted avg 0.79 0.76 0.76 1000

可以看到,显然整体效果0.76(weighted avg f1-score)不尽人意,但并能不止于此,进一步分析,要看分类目的F1,可以看到,有一些support比较多的高频类目,效果也并不是很好,比较凸显的“财经-财经”、“军事-军事”都不高,当然低频的类似“证券-股票”、“民生-故事”效果也不是很好,这个跟测试集内的数据量有些关系了。

为了进一步分析,还有一个很好的工具可以使用,那就是混淆矩阵,可以快速定位到一些容易混淆的类目。

from sklearn.metrics import classification_report, confusion_matrix

# 。。。

logger.info("\n{}".format(confusion_matrix(test_list, pred_list, labels=labels)))

执行结果,具体的顺序和上面的classification_report类目顺序是一样:

[[86 1 0 1 0 0 0 2 2 1 0 1 0 1 1]

[ 1 56 6 4 2 0 4 2 1 1 0 0 1 0 1]

[ 0 0 74 2 2 0 0 3 3 1 0 0 0 2 1]

[ 2 0 4 80 0 0 0 3 0 0 0 0 0 1 0]

[ 2 0 1 0 7 0 0 0 1 2 0 0 1 1 0]

[ 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0]

[ 2 12 2 5 0 0 35 0 0 1 0 0 0 0 0]

[ 1 1 1 1 0 0 0 49 3 0 0 0 1 0 1]

[ 2 2 4 5 0 0 1 4 55 0 0 0 0 0 1]

[ 0 0 3 2 0 0 2 0 0 75 0 1 0 2 2]

[ 5 2 2 1 0 0 0 2 0 0 33 0 0 0 0]

[23 2 2 5 2 10 0 2 0 2 3 33 4 0 0]

[ 2 0 2 0 0 0 0 6 1 0 2 0 36 0 0]

[ 4 0 5 2 0 0 2 2 0 3 0 0 0 59 0]

[ 4 1 2 4 0 0 0 1 0 0 0 0 0 0 77]]

倒数第四行第四列是33,对应的就是“财经-财经”,这里横向看,第1列和第6列的数比较大,分别是23和10,说明很多“财经-财经”类的内容被这两个类召走,分别是“科技-科技”、“证券-股票”,说明很大程度和这两个类目之间存在混淆,需要重点优化。

相比总体的指标,细分的指标能帮助我们进一步探知关键问题,这就是我前面所说的“暴露问题”,有了细节指标的信息,我们能对问题点有相对清楚的认识,在后续进一步分析bad case的时候,我们充分参考这些信息,能较快找到问题的根源。

分析bad case

然后,我们就可以开始进行bad case的分析了。这次我们直接拿上面的数据来分析,建议是分成4列,分别是case、实际值、预测值以及是否正确,如下面的样例所示:

caserealpredis_right5月9日15:30 G3017金武段金昌站与水源站之间进行养护维修施工,请注意!汽车-汽车汽车-汽车TRUE瑜伽服务平台Wake宣布完成数千万元A+轮融资科技-科技科技-科技TRUE小米、努比亚、360齐上阵,游戏手机,还是手机的“游戏”?科技-科技科技-科技TRUE深圳地铁“扫码过闸”正式上线:马化腾亲身示范科技-科技科技-科技TRUE中国迎来第三次留学生“归国潮”,为什么他们都选择回来?教育-教育教育-教育TRUE美国在亚洲有多少军事基地,分别在哪里?国际-国际军事-军事FALSE

拿到这些数据后,我们可以结合我们上一步分析到的问题类目来进行分析,也可以直接抽is_right的数据来进行分析,我们先考虑后者,并做出记录。

此处,我以其中一个case为例,讲一下分析的过程:"美国在亚洲有多少军事基地,分别在哪里?",这个句子标注结果是“国际-国际”,但是模型预测为“军事-军事”。此处,因为整个分类经历了多个流程,因此把整个流程的日志都给打出来。

2024-07-28 16:11:53.825 | INFO | __main__:predict:27 - request: 美国在亚洲有多少军事基地,分别在哪里?

2024-07-28 16:11:54.494 | DEBUG | __main__:predict:30 - [[370, ['世界上被美国驻军的国家有哪些?', ['6552991347354108167', '110', 'news\_military', '世界上被美国驻军的国家有哪些?', '', '军事-军事']], 219.74318, 0.7373642921447754], [3601, ['南美洲大军事强国', ['6553019751621198344', '110', 'news\_military', '南美洲大军事强国', '南美洲,阿根廷,哥伦比亚,军事强国,智利', '军事-军事']], 254.86084, 0.692778468132019], [6285, ['南美洲 大军事强国', ['6553019696919085581', '110', 'news\_military', '南美洲大军事强国', '军事强国,智利,南美洲,阿根廷,哥伦比亚', '军事-军事']], 254.86084, 0.692778468132019], [2935, ['欧洲人怎么看待出现在欧洲的美国军队?', ['6552130324262813956', '113', 'news\_world', '欧洲人怎么看待出现在欧洲的美国军队?', '', '国际-国际']], 254.54695, 0.6925537586212158], [752, ['美国一反常态,帮助日本提高海军实力', ['6553052718921941517', '110', 'news\_military', '美国一反常态,帮助日本提高海军实力', '旗风级,军事实力,日本,驱逐舰,军舰', '军事-军事']], 271.53687, 0.6715511083602905]]

2024-07-28 16:11:54.498 | INFO | __main__:predict:58 - 你是一个优秀的句子分类师,能把给定的用户query划分到正确的类目中。现在请你根据给定信息和要求,为给定用户query,从备选类目中选择最合适的类目。

下面是“参考案例”即被标注的正确结果,可供参考:

世界上被美国驻军的国家有哪些?——军事-军事

南美洲大军事强国——军事-军事

欧洲人怎么看待出现在欧洲的美国军队?——国际-国际

美国一反常态,帮助日本提高海军实力——军事-军事

备选类目:

军事-军事,国际-国际

类目概念:

【军事-军事】:权威军事资讯、追踪军事热点、反映军事动态、介绍国内外最新武器发展动态

【国际-国际】:世界新闻、国际博览、新闻人物、评论分析、媒体聚焦

用户query:

美国在亚洲有多少军事基地,分别在哪里?

请注意:

1. 用户query所选类目,仅能在【备选类目】中进行选择,用户query仅属于一个类目。

2. “参考案例”中的内容可供推理分析,可以仿照案例来分析用户query的所选类目。

3. 请仔细比对【备选类目】的概念和用户query的差异。

4. 如果用户quer也不属于【备选类目】中给定的类目,或者比较模糊,请选择“拒识”。

5. 请在“所选类目:”后回复结果,不需要说明理由。

所选类目:

2024-07-28 16:11:55.010 | INFO | __main__:predict:62 - llm response: 军事-军事

2024-07-28 16:11:55.011 | INFO | __main__:predict:70 - parse result: 军事-军事

2024-07-28 16:11:55.012 | INFO | __main__:predict:73 - response: 军事-军事

2024-07-28 16:11:55.013 | INFO | __main__::80 - 军事-军事

我一段段解释,首先是这段:

2024-07-28 16:11:54.494 | DEBUG | __main__:predict:30 - [[370, ['世界上被美国驻军的国家有哪些?', ['6552991347354108167', '110', 'news\_military', '世界上被美国驻军的国家有哪些?', '', '军事-军事']], 219.74318, 0.7373642921447754], [3601, ['南美洲大军事强国', ['6553019751621198344', '110', 'news\_military', '南美洲大军事强国', '南美洲,阿根廷,哥伦比亚,军事强国,智利', '军事-军事']], 254.86084, 0.692778468132019], [6285, ['南美洲 大军事强国', ['6553019696919085581', '110', 'news\_military', '南美洲大军事强国', '军事强国,智利,南美洲,阿根廷,哥伦比亚', '军事-军事']], 254.86084, 0.692778468132019], [2935, ['欧洲人怎么看待出现在欧洲的美国军队?', ['6552130324262813956', '113', 'news\_world', '欧洲人怎么看待出现在欧洲的美国军队?', '', '国际-国际']], 254.54695, 0.6925537586212158], [752, ['美国一反常态,帮助日本提高海军实力', ['6553052718921941517', '110', 'news\_military', '美国一反常态,帮助日本提高海军实力', '旗风级,军事实力,日本,驱逐舰,军舰', '军事-军事']], 271.53687, 0.6715511083602905]]

这个是向量召回的TOP5,可以看到,他们和原始的句子"美国在亚洲有多少军事基地,分别在哪里?",多少都存在一些相似性,说明向量召回这块的问题好像并不是很大,然而无论是前面几个的“军事-军事”的,可见似乎类似的句子,标注上都会划分到这个类,而非'国际-国际'类,这里仅有一条样本是'国际-国际'类,显然就比较少,而且相似度也比不过前几个结果。

__main__:predict:58下的是prompt,初步看和预期的结果一致,没什么大问题。

后续连续的3行分别就是大模型的回复、解析结果以及最终的的回复了,可以看见都没什么问题:

2024-07-28 16:11:55.010 | INFO | __main__:predict:62 - llm response: 军事-军事

2024-07-28 16:11:55.011 | INFO | __main__:predict:70 - parse result: 军事-军事

2024-07-28 16:11:55.012 | INFO | __main__:predict:73 - response: 军事-军事

从此可见,整体流程初步看下都没有什么问题,似乎是标注的标准可能存在一定的混淆,类似的问题需要考虑澄清或者是更新标注,但是因为这是公开数据集,肯定难易处理这种问题,其实这种问题在公开数据集内并不少见,但是要修复只能说是无能为力。

刚才有提到“财经-财经”类下的错误有很多,此时我们就筛选real为“财经-财经”,但是pred不是这个的样本来分析一下,此处以“金融炼金术——里根的“大循环””为例进行分析。

2024-07-28 16:43:19.892 | INFO | __main__:predict:27 - request: 金融炼金术——里根的“大循环”

2024-07-28 16:43:20.471 | DEBUG | __main__:predict:30 - [[4800, ['新手理财首选:陆金所、小宝金融、宜聚网!', ['6553462877376741901', '104', 'news\_finance', '新手理财首选:陆金所、小宝金融、宜聚网!', '陆金所,工薪

族,金融,平安宝-金色人生,宜聚网', '财经-财经']], 311.99478, 0.6219339966773987], [8826, ['大田环球贵金属:现货黄金走势分析操作建议', ['6553455628277252616', '104', 'news\_finance', '大田环球贵金属:现货黄金走势分析操作建议', '铀浓缩,止损3,鲍威尔,ma5,第一目标,FOMC,伊朗', '财经-财经']], 314.15875, 0.6188830137252808], [4861, ['安达比索微交易——四点技巧分分钟赚钱', ['6553173895879328269', '104', 'news\_finance', '安达比索微交易——四点技巧分分钟赚钱', '微交易,投资者', '财经-财经']], 312.19086, 0.6164110898971558], [7637, ['直击全球5大战略金属:最后一种有钱也买不到', ['6552340743468352013', '110', 'news\_military', '直击全球5大战略金属:最后一种有钱也买不到', '国防工业,燃烧弹,耐蚀性,铀235,航天器', '军事-军事']], 315.8933, 0.611515998840332], [3833, ['陶以平:以FICC为抓手助力黄金市场高质量发展', ['6553402235752022536', '104', 'news\_finance', '陶以平:以FICC为抓手 助力黄金市场高质量发展', '黄金市场,兴业银行,陶以平,工商银行,FICC,上海黄金交易所', '财经-财经']], 330.36914, 0.5959779024124146]]

2024-07-28 16:43:20.474 | INFO | __main__:predict:58 - 你是一个优秀的句子分类师,能把给定的用户query划分到正确的类目中。现在请你根据给定信息和要求,为给定用户query,从备选类目中选择最合适的类目。

下面是“参考案例”即被标注的正确结果,可供参考:

新手理财首选:陆金所、小宝金融、宜聚网!——财经-财经

大田环球贵金属:现货黄金走势分析操作建议——财经-财经

安达比索微交易——四点技巧分分钟赚钱——财经-财经

直击全球5大战略金属:最后一种有钱也买不到——军事-军事

陶以平:以FICC为抓手助力黄金市场高质量发展——财经-财经

备选类目:

财经-财经,军事-军事

类目概念:

【财经-财经】:股票、债券、基金、期货、信托、理财、管理等服务新闻

【军事-军事】:权威军事资讯、追踪军事热点、反映军事动态、介绍国内外最新武器发展动态

用户query:

金融炼金术——里根的“大循环”

请注意:

1. 用户query所选类目,仅能在【备选类目】中进行选择,用户query仅属于一个类目。

2. “参考案例”中的内容可供推理分析,可以仿照案例来分析用户query的所选类目。

3. 请仔细比对【备选类目】的概念和用户query的差异。

4. 如果用户quer也不属于【备选类目】中给定的类目,或者比较模糊,请选择“拒识”。

5. 请在“所选类目:”后回复结果,不需要说明理由。

所选类目:

2024-07-28 16:43:20.906 | INFO | __main__:predict:62 - llm response: 金融-财经

2024-07-28 16:43:20.909 | INFO | __main__:predict:70 - parse result: 拒识

2024-07-28 16:43:20.909 | INFO | __main__:predict:73 - response: 拒识

2024-07-28 16:43:20.910 | INFO | __main__::80 - 拒识

这里能很明显的看到,大模型的返回并没有给到我们“备选类目”中的结果,给的是“金融-财经”,这导致最终预测的结果是“拒识”,这是出错的根源。

分析不能掰棒子,我们要把每一条分析结果,都记录下来,并且最好是规范化,方便统计的那种。下面给出一些范例:

caserealpredis_right分析区块链与科技一拍即合,三角形主机开启数字资产的人人时代财经-财经科技-科技FALSE类目标准问题黑龙江省的基本养老金是什么标准?财经-财经农业-三农FALSE多标签问题金融炼金术——里根的“大循环”财经-财经拒识FALSE模型输出内容不符合规范年逾古稀,却要面临着失去房产,是啥逼迫这对老夫妇?财经-财经民生-故事FALSE未召回正确类目升级后的余额宝还值得我们投资吗?财经-财经科技-科技FALSE类目标准问题未来几年最有前途的行业是哪个?财经-财经教育-教育FALSE类目标准问题什么是庞氏骗局?财经-财经科技-科技FALSE相似度阈值

这里给出的是实际值是‘财经-财经’但实际并不是‘财经-财经’这个类目的bad case的分析数据,这里比原始数据多了一列,即分析,分析内给出这个case的归因分析,这里有几个细节需要强调:

可以考虑尽可能用统一的说法,方便归类。

如果出现多个问题,可以都写上去,逗号隔开。

坚持下去,多分析一些,从而体现出各个问题的实际占比,少则50多则100,看得多对问题理解、解决思路都有很大好处。

这个过程毫无疑问是比较枯燥的,但坚持下来,无论是对解决问题,还是对个人成长,都是有巨大好处的,所谓的经验就是从中而来,对问题有了解,在遇到新的问题时能提前预知风险和难题,这都是前期看case积累沉淀下来的,所以这个投入绝对值得。

在逐个对bad case进行分析后,希望大家能够梳理出类似这样的一个文档:

分析X个bad case后,分析出问题按频率排序如下:

1. 类目标准问题,X个,占比30%。

2. 多标签问题,X个,占比20%。

3. 模型输出内容不规范,X个,占比10%。

问题已经定位好了,那我们距离解决就非常接近了。

解决问题

剩下的,就是针对问题提供解决方案了,这是一个非常考验经验和积累的活。上面的问题,其实很多都有一些trick的方式来解决,或者压根就是系统性问题不好解决。

以类目标准问题为例,类目的标准来自开源方,我们无法直接改变这个标准,以及内部的数据标注,但在实际应用中,我们是可以沟通更新解决的,边界明显化不仅是对模型效果收益,在业务层面,也能更加清晰。类似的还有多标签问题,只有把方案升级为多标签方案(包括标签体系),才有机会继续搞。

比较好处理的是分类方案内的细节问题,例如相似度模型错误,相似度阈值,模型输出内容不规范等,都是可以轻松解决的,相似度模型方面可以通过阈值、微调模型之类的来优化,模型输出内容不规范可以优先考虑prompt或者是别的兜底方案,例如参照向量召回的结果。在问题比较明确的情况下,解决问题的方法就逐步明确了。

这里真的非常考验积累,不得不再次强调两个很经典的拷打。

你不会只会微调这招吧。

说得好像微调后,效果就能提升似的。

会针对问题提出方案的能力还是非常重要的,模型外围增加规则或者别的模型进行辅助,根据bad case定向收集更多样本提升覆盖率,调整阈值,增加“垃圾桶”类目(例如拒识)等,都是些技巧,需要多打开思路,也多研究各种分享的案例。

小结

之前的bad case治疗术系列写的比较抽象,这次结合一个具体任务来给大家讲解这里的细节,该分析哪些数据,具体分析哪些方面,具体怎么做有效,怎么对最终的结果有好处,这种思维模式能让我们更聚焦于问题本身,更有针对性,更有利于解决当下问题。

当然,也有缺点,在这里也补充说一下,这个思路容易让我们陷入局部的问题,对更大的,类似模型结构的,大方向上的问题,很容易被忽略,这个还是要注意。