May 2, 2024

Nyanko训练手札

记录训练Nyanko的一部分想法。

该文章会长期更新。

2024-05-04 记3

**Yanray Plan更名为Nyanko,人设已经想好了但是现在不想发(或者之后屏蔽一些人再偷偷摸摸发一下🥵)。

昨天晚上试了试ChatGLM的8K和32K,半精和INT8、INT4的输出测试,明显的感觉到同样是INT8,32K的模型就是比8B的“聪明”一点,一些逻辑漏洞问题都很机智的跳过去了,相比较之下纵使没有量化的8K也不如32K,应该是32K的长文本数据集质量比较高的原因。

同时还试了试Qwen1.5,相比较之下体验就比较糟糕了。尽管Qwen官方提供了已经量化为INT8的GPTQ和GGUF 7B模型,但是实测对逻辑问题依旧反应不过来(比如“我应该如何称呼我亲哥哥的妈妈”)。甚至huggingface上110B版本的有些逻辑问题还不如6B的ChatGLM质量来的好。

此外Qwen1.5 7B的GPTQ量化模型占用显存依旧很逆天(13G),必须要量化到INT4才能整个加载到我的卡上。感觉Qwen是在很努力做了但是练度不够。

还有Baichuan3模型,不过看样子是重点偏向领域权威的内容了,和我准备做的方向不太一样,就懒得测试了。


显卡和AI能够碰撞在一起,其实是一个非常巧合的情况。显卡为了渲染三维图形,必然要计算空间中每个点的坐标,坐标以浮点数表示,一般都会精准到单精度水准(fp32)。换句话说显卡的算力强,指的是浮点算力很强。并且显卡的计算单元是并行的,可以在一瞬间计算T级别的浮点计算。而以Transformer架构的模型为例,无论是推理还是训练都要计算大量的注意力权重(多维向量),同样需要大量的浮点算力。

而cpu本身设计的时候并没有对浮点算力有着极高的要求(CPU要做的事情多的很,不可能重点偏向浮点计算)。
以14900K为例,fp32的算力是2.5TFlops(每秒2.5万亿次计算)。
但我手上这张P102大矿卡,单精度也有11.7TFlops。
而消费级最强显卡4090是100TFlops。
中国特供版4090D是82.6TFlops。
目前已发售的最强计算卡H100是1513TFlops

更何况,现在大部分模型都是在半精情况下跑的,新架构的N卡半精跑的速度比单精快太多了。从fp32损失到fp16的精度对于AI来讲几乎没什么太大影响,带来的受益却是实实在在的显存需求降低、推理速度提升。

此外,由于CUDA(使用GPU做图形以外的计算)生态的存在,大部分的AI框架都是采用N卡作为首选加速卡。
与之相对应的AMD的ROCm,想要撼动老黄早在十年前补下的局,还需要一段时间。
微软的DirectML也许有点意思,但好像目前没多少框架吃微软这一套。
至于摩尔线程,尽管声称完全支持CUDA API调用,我只能说未来可期。

2024-05-03 记2

*Yanray训练手札 2:

手札的所有内容均同步至博客,由于书写语法为MarkDown,为了获得更好的阅读体验,建议去博客阅读:https://blog.eurekac.cn/p/27917125.html

下载了ChatGLM-6B-32K,好在ZhiPuAI把文件都备份到了国内ModelScope上,下载并没有费太多时间。

然后尝试直接用demo的cli_demo.py跑模型,跑是跑起来了,但是推理速度异常缓慢,大概40s左右出一个字。

使用nvtop查看了显卡状态,发现推理时RX直接拉满到480MB/s,仔细检查之后发现默认demo里面加载方式居然是Transformer的.eval(),直接fp32干到显卡里面去跑。而模型在cuda内完全展开要用20GB显存,显卡只有10GB。所以eval用法会把一部分layer卸载到内存中,到需要的时候才会从内存加载。

然而,手头这张P102本身就是老黄阉割的产物,PCIE只有可怜的1.1x4(*雪上加霜的是之前一不小心磨坏了背板上的两颗电容现在只有1.1x2了,理论带宽只有480MB/s)。将layer反复地从内存卸载加载在这张卡上自然出奇的慢。

没办法,只能在之前加上.half().cuda()来尝试以fp16加载显卡中,然后这时候就崩了个CUDA Out Of Memory,查询github上的文档后发现fp16也需要13GB的显存。

唯一的方式只能是用官方给的.quantize()方法量化,以更低的精度来加载到显存中。文档上提示INT8的量化允许在8G显存跑推理,9G显存跑微调,刚刚好适用于我的情况。

官方并没有chatglm3-6b-int4量化版本,只能自己量化。根据注释提醒,应当在量化时使用cuda。然而实测这种法子肯定会爆显存,正解应当是先加载到cpu中用cpu做好量化,然后再load到gpu。为了避免反复量化开销,我干脆写了个小脚本单独量化模型并保存起来。

将已经量化好的模型作为模型路径载入cli_demo中,结果崩了个错can't set attribute 'eos_token'。好在官仓里面已经有一个close的issue,简单浏览后得知量化保存的时候Transformer会把冗余的参数写入tokenizer的配置文件,但是推理的时候载入冗余参数会出错。只要将原有的仓库中的tokenizer_config.json移过去就行了。

最后跑起来了,int8下显存占用7.5G,且性能与colab中使用T4跑的fp16大致相同。由于模型可以整个加载到显存中,实际推理无需通过PCIE交互,推理速度也达到了一个可用的水平。

2024-05-02 记1

其实很早就有自己定制一个AI Assitant的想法了,大约22年3.5刚出的时候就幻想自己做一个Virtual GirlFriend。可惜当时忙着应付考试,也就止步于幻想。

所有的LLM(Large Language Model)本质上都是文本预测器,是在预测一段文本接下来会输出什么。而不论ChatGPT、Claude还是ChatGLM、Qwen,追根到底都是让模型预测一段文本中“Assistant”会说什么。本质上输入模型的格式都是如下所示:

1
2
3
System: You are an assitant.Your name is Yanray. 
User: <|input|>
Assitant: <|output|>

input为用户输入的问题,模型只要补齐在这段对话里面Assitant会输出什么就行了,然后Filter单独把模型的输出作为output截出来,包装好丢给api出口,在用户看起来,就是一个聊天机器人。

事实上做一个属于自己的AI Assitant很简单,也不需要太大的资源。我的最初的设想是一个比较小巧(6B-13B)的LLM作为一个主模型,合理使用各类工具API加持(比如浏览器、计算器之类)。只要给LLM一些最基本的语言逻辑,还要“教”会LLM输出指定的格式能够被Filter检测并调用,并且LLM要会正确读取Filter返回的数据即可。例如:

1
2
System: `/calculate` can use calculate tools
User: pls calculate 6.5*7.5

模型只要能正确输出/calculate 6.5*7.5,Filter就能拦截命令,直接计算数据,然后补齐在对话内:

1
2
3
4
<<...
Assitant: /calculate 6.5*7.5
Tools: 48.75
Assitant: Result is 48.75

包括让模型上网都可以用这种简单的方式实现。不过据我之前随手查询的资料,langchain貌似已经很好的做到了这一点。今天把手头的B事处理完之后去看一下langchain部署的难易度,如果实在麻烦不如直接将使用方式作为prompt丢给模型,“教”它简单使用就行,反正做Yanray就是给自己爽的,没必要用什么很高大上的东西。

目前计划采用的主模型是ChatGLM3-6B-32K,主要是够小,压着精度能够跑在我P102上,而且如果可以的话用LLaMA Factory在本机上跑微调或者Lora,10G虽然够呛,P102算力也难绷,但是能跑就行。

关于本文

由 CyanFalse 撰写, 采用 CC BY-NC 4.0 许可协议.

LLM微调模型

Wait...