聊聊大模型实际开发中的问题——微调与推理
最近在实际业务中折腾LLM的微调、部署和推理,踩了不少坑,也攒了一些经验。这篇就当作一次技术复盘,把遇到的那些问题——有解决的,也有还在琢磨的——都摊开来聊聊,给做类似场景的朋友们一个参考。
微调
我们的业务场景偏向心理咨询问询对,对话长度相当可观。转换成ShareGPT格式的JSON文件后,单个数据动不动就是几十甚至上百KB,像下面这样:
其实这里是4个conversations,相当于把一次咨询按主题拆成了四块,再拼到一起。严格来说不拆也可以,直接用一个conversations一次性扔进去,但LLaMA-Factory这个框架不允许微调数据里只有一个conversation,所以只能拆开处理。
数据文件太大,直接导致训练崩盘,OOM报错频频出现。后来换成jsonl格式,文件大小确实缩了,但一样不行。最终被迫换到了ms-swift框架来做微调。
问题还没完。这是一次咨询的数据,训练出一个checkpoint后,还打算基于它继续训练。但显存已经顶不住了——又是一个OOM。
并行训练
并行训练通常分三类:数据并行、模型并行、混合并行。理论上,显卡不够用的时候,靠这几招能顶上去。但现实是,目前我接触到的LLaMA-Factory、ms-swift这些微调框架,它们的模型并行实现都不是标准的。
很多微调框架的并行算法并非标准实现,这一点需要格外留意。也就是说,面对具体场景,得花时间去试,看哪个框架真正扛得住。
微调数据的长度
前段时间longwriter-glm4-9b出来了,想着微调一把,尤其是针对多轮对话。咨询了官方,答复很直白:微调时数据的长度是一个必须认真对待的问题,也需要做好数据并行切分。虽然可以通过max_length、采样策略(top_p、top_k、贪婪搜索、集束搜索)等来约束,但效果依然会受影响。关键在于找到合适的微调数据长度。
如果微调数据不能拆分,那最直接的解法就是数据并行——把数据拆分到每张显卡上单独训练。但这时候又有一个隐形的天花板:单卡下,全量加载模型参数之后,数据长度还能撑多少?这个我在LLaMA-Factory提过一个issue[1],大家可以翻一下。
小结
微调这块,超参数当然值得调,但更值得花心思去审视的是微调数据的长度。至于并行策略,真得结合场景来用,不用盲目迷信某一个。
部署推理
部署和推理往往是绑在一起的,这里又遇到了几个棘手的问题。
并发调用
模型部署起来之后,一个很现实的问题是:开源模型普遍不擅长处理多用户的并行调用。虽然LLaMA-Factory、ms-swift这些框架能支持,但我们在实际落地时还是要心里有数。大致分两种情况:
- 多用户并发调用
- 单用户批次并行调用(即batch inference)
上下文长度
推理时,历史对话长度是个绕不开的坎——对话到底能拉到多长,模型能力才会退化?以vLLM部署为例,有个max_model_len参数在管着。下面这个报错应该不少人都见过:
ValueError: The model's max seq len (19008) is larger than the maximum number of tokens that can be stored in KV cache (3840). Try increasinggpu_memory_utilizationor decreasingmax_model_lenwhen initializing the engine.
说到底,是显存和KV Cache的大小卡住了推理时的历史对话长度。长对话场景下怎么解决?除了堆显存,或者换一个更高效的分布式推理部署框架(算法),暂时还没找到更理想的方案。哪个框架才能真正扛起这个活儿,目前还在探索中。
小结
一个靠谱的推理部署框架,既要能扛住并发调用,又要能应对上下文长度的挑战。这不仅仅是原生基座模型的上下文长度问题,更是基座模型上层中间件的限制。选对算法和框架,很多头疼的问题就能迎刃而解。
[1] issue: https://github.com/hiyouga/LLaMA-Factory/issues/5184
-
- 关于宇宙的好的网名有哪些
- 角色扮演 | 1
- 网名