心法利器
本栏目主要和大家一起讨论近期自己学习的心得和体会。具体介绍:仓颉专项:飞机大炮我都会,利器心法我还有。
2023年新的文章合集已经发布,获取方式看这里:又添十万字-CS的陋室2023年文章合集来袭,更有历史文章合集,欢迎下载。
往期回顾
之前自己写了一个系列——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、实际值、预测值以及是否正确,如下面的样例所示:
case | real | pred | is_right |
---|---|---|---|
5月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__:<module>: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__:<module>:80 - 拒识
这里能很明显的看到,大模型的返回并没有给到我们“备选类目”中的结果,给的是“金融-财经”,这导致最终预测的结果是“拒识”,这是出错的根源。
分析不能掰棒子,我们要把每一条分析结果,都记录下来,并且最好是规范化,方便统计的那种。下面给出一些范例:
case | real | pred | is_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治疗术系列写的比较抽象,这次结合一个具体任务来给大家讲解这里的细节,该分析哪些数据,具体分析哪些方面,具体怎么做有效,怎么对最终的结果有好处,这种思维模式能让我们更聚焦于问题本身,更有针对性,更有利于解决当下问题。
当然,也有缺点,在这里也补充说一下,这个思路容易让我们陷入局部的问题,对更大的,类似模型结构的,大方向上的问题,很容易被忽略,这个还是要注意。