背景
AI最近又开始火了尝试上手玩玩,我水平还停留在MNIST入门阶段,哪写的不对欢迎大佬指正。
基本概念
模型是一个或一组文件,里面存储了权值的集合,理论上就是一堆浮点数的集合。
模型的生成过程叫做训练,执行过程叫做推理。训练过程中和训练好后的模型可以持久化到硬盘中,结合结构信息可以反向序列化加载到硬件中。
(资料图片仅供参考)
默认的浮点数精度一般是32bit浮点(32fp,32bit,4byte), 半精度.half()就是16bit(16fp,16bit,2byte)
量化说的是把浮点数据继续缩减空间,4bit定点(int4,0.5byte),8bit定点(int8,1byte)
文本是可以转换成高维向量表示的,向量的每个维度都可以用浮点数表达,transformer模型计算(推理)的过程实际是对输入的向量进行补全。
和AI对话只是表现形式,本质上是根据上文猜测下文在概率上最大可能性的结果并进行补全,重复进行这个过程直到长度上限或终止符,然后再以对话形式展现。
huggingface提供了大量模型和数据可供下载,常见的模型是pytorch生成的,格式上大多是一个或多个bin文件,加上一个index.json。
至于模型是怎么训练的暂时还不是很清楚,这种格式能否以更可视化的方式获取信息也不知道。(有没有一种方式能自动计算当前硬件资源,给出合理的模型加载方式呢?)
huggingface同时提供了常用的python库可以方便的自定义模型结构、加载预训练的模型,利用accelerate库可以把模型拆开加载到不同的设备。
nvidia-smi可以看到显卡的显存占用,使用watch -n 1 -c nvidia-smi可以实时监控显存。
工程结构
目前见到的几个模型的项目工程结构从上到下一般为
web-ui(可选):自己手写或者从其他地方抄,常见的是gradio,server_name可以指定监听IP(和其他的软件一样,设置成127.0.0.1仅限本地访问,设置成0.0.0.0监听所有网卡地址), server_port可以指定监听端口,一般不要开启share=True否则会发布到公网
示例代码demo: 一般从github下,里面经常包含一个model(s)的目录
模型本身+模型配置(可选) : 一般从huggingface下,内容会和github有部分重叠。我暂时粗暴的把模型以外的东西复制到model(s)下一份方便python中引用和修改,模型本体存别处
conda虚拟环境:使用conda可以做到和venv、nvm类似的方式管理虚拟环境并相互隔离,包含pytorch底层和其他的python依赖
模型加载技巧记录
huggingface提供了众多抽象好的预训练模型结构,可以通过mixin等方式复用
from_pretrained是个使用python动态实现的模型加载器,内部会动态实例化预训练的模型,直接追踪我没找到链路,但可以通过type(model)的方式获取运行时类名从而debug到真实的模型实现类
from_pretrained参数支持设置load_in_8bit=True,可以在加载时候进行量化。
这个方法底层实际调用的还是pytorch,pytorch中加载模型可以指定map_location。
加载模型的行为默认是加载到内存,然后再转移到显存中。
如果模型太大无法完全加载到内存会报错,根据报错信息可以定位到/conda/envs/py38/lib/python3.8/site-packages/transformers/modeling_utils.py文件,把map_location="cpu" 全部替换为map_location="cuda" 就能直接加载到显卡而不经过内存
如果正常方式无法加载模型,可以借助accelerate库分开加载一个模型的不同部分到不同的设备
主要的变更是用load_checkpoint_and_dispatch替代from_pretrained,关键参数如下
device_map参数可以指定加载策略, auto可以自动分割模型来最大化利用硬件,infer_auto_device_map也可以生成device_map
也可以传入dict结构指定每个部分使用什么设备加载cpu
是使用RAM加载 disk
是使用磁盘加载,数字编号是显卡的编号
打印model.hf_device_map可以看到自动生成的device_map结构
max_momory可以限制每个设备初始加载最多可用的资源,dict的key定义同device_map的value,例如:max_memory = {0: "30GIB", 1: "46GiB", "cpu": "32GiB"}
注意这个参数只是设置加载时候的限制,实际推理过程还需要显存,因此使用此种方式需要注意给显卡预留足够的空间用于推理,剩下的部分用CPU RAM凑。
(做个梦:啥时候显存价格能降低到和硬盘一样啊)
如果device_map中出现了disk,则需要指定offload_folder来指定目录,我一般用f"{model_path}/tmp"
记录
chatglm-6b 成功,但有点弱智还需要调教
stablelm-7b 成功,比chatglm强点有限
codegen-6b 16b 失败,加载不了,推迟
MOSS-plugin 成功,看文档是基于codegen的,理论上代码能力应该还可以才对。但单张显卡无法直接加载,利用cpu分段加载后速度太慢,等待量化模型再测试。
参考
https://gradio.app/docs/
https://github.com/IST-DASLab/gptq
https://github.com/qwopqwop200/GPTQ-for-LLaMa
https://github.com/openai/triton
https://github.com/TimDettmers/bitsandbytes
https://github.com/OpenLMLab/MOSS/issues/35
https://huggingface.co/docs/transformers/main/en/autoclass_tutorial
https://www.zhihu.com/question/362131975/answer/2182682685
https://arxiv.org/pdf/1607.04683.pdf
https://zhuanlan.zhihu.com/p/38328685
https://blog.csdn.net/lai_cheng/article/details/118961420
https://huggingface.co/docs/optimum/concept_guides/quantization
https://huggingface.co/docs/transformers/main/en/main_classes/quantization
https://pytorch.org/docs/stable/quantization.html
https://deepspeed.readthedocs.io/en/latest/memory.html
https://pub.towardsai.net/run-very-large-language-models-on-your-computer-390dd33838bb
https://huggingface.co/docs/accelerate/v0.18.0/en/package_reference/big_modeling
https://huggingface.co/docs/accelerate/v0.18.0/en/usage_guides/big_modeling#designing-a-device-map
https://huggingface.co/docs/accelerate/v0.18.0/en/usage_guides/big_modeling#loading-weights
https://github.com/OpenLMLab/MOSS/issues/38