本文为稀土掘金技术社区首发签约文章,30天内禁止转载,30天后未获授权禁止转载,侵权必究!
如今"大模型"一词很火,但我却找不到它的定义。目前业内只存在大语言模型 (large language model, LLM) 一说。其特征就是参数大(10亿级别起步),范围大(通用非垂直领域)。
外行看热闹时,我却遭受着大模型的煎熬。首先,我调研了国内外开源、不开源的大模型。然后,部署搭建、调用、对比分析,进行时间、数据、设备成本的估算和汇总。最后,结合实际情况,给领导上报最佳方案。领导感觉,还是太贵。
拿调用第三方来说,国内的几个"XX大模型"不是很好用,而且你也不好做过程干预。ChatGPT
的生态不错,但是又涨价了,还涉及数据安全问题。
利用开源的项目倒是能自己训练,但是得有GPU
设备啊。买一个RTX 3090
(性能不错的显卡),要万元起步。租云主机倒也可以,但是租几段时间就够买一个的了。一个RTX 3090
跑百万级别的多轮对话数据,需要一个星期才能稍有效果......
对于AI
,你们看到的全是风口,我看到的全是破窟窿。
老板问:没有钱,就不能有人工智能的梦想吗?
一、什么是小模型?
有梦想都是可贵的,和身份无关。我们不能一边说咸鱼有梦想是励志,而老板有梦想就是荒诞。
后来,我又和很多人交流过。大家的情况都差不多,传统行业,想搭AI
的车,不愿花钱,诉求简单。
我一个老同事,产品经理。他去了图书公司。他们集团的信息部就仨人,俩技术,一个产品。所有系统是外包出去的,这仨人负责需求的发布和验收。因为成本低,利润大,所以他们的待遇很高,而且从来不加班。我感觉他活的很明白。
正是通过和这个大明白的交流,让我有了"小模型"的构想。
小模型就是针对不以AI
为卖点的互联网产品,所提出的带有AI
概念的低成本方案。
小模型不大,参数不多,功能不强,由服务端生成,在客户端运行。类似你需要一辆代步车,鉴于你全程跑不到50公里/时,我给你一辆最高时速就到50公里的车。另外,它在客户端部署运行。这又好比你不用长期持有车。当需要进货时,临时租个货车。有人下单了,客户会来仓库自提。
说白了就是人家主业是卖图书、卖糕点,但围绕主业他还有一个附带的互联网小产品。这个小产品,具有AI
概念。作用就是当大家的图书质量都一样,难以区分时,我有的,你没有。
下面是小模型和大模型的成本对比图。
从上图看,在模型制作阶段,小模型和大模型的成本接近。但到了发布后,大模型依然需要依赖AI
服务器提供推理,但小模型只需要提供模型文件下载即可。也就是说,小模型对算法硬件只有临时性需求。一旦生成,即可脱离。
以"大明白"的阅读想法为例。下面是我对小模型思路的具体实践。我通过TensorFlow Lite
,将一个自训练的中文阅读理解问答模型,运行在了Android
手机上。
上面的例子,实现了面对琐碎的资料,不用阅读全文即可从文中快速找到答案。
下面,我将对整个过程进行说明和讲解,并在文末附上相关资料。
二、小模型的制作方法
小模型的生成方式有三种:
- 1、依照大模型生成的路数,后续转化为小模型。
- 2、训练时,直接生成在客户端部署的小模型。
- 3、由客户端训练,可在客户端运行的小模型。
以上三种方式,我会讲解前两种。因为第3种,我没遇到应用场景,也没有实际操作过,因此不敢乱说。之所以提它,是因为有理论依据[参考1]。
2.1 选择平台
不管是直接生成,还是间接转化,小模型都是由开发框架产生的。因此在选择框架上,要考虑多平台支持。令人惊喜的是,目前谷歌有TensorFlow Lite
,Facebook有PyTorch Mobile
,它们都支持客户端AI
。
非但如此,现在Transformers
库的出现,也让PyTorch
、TensorFlow
这些模型可以相互转化和使用。可以说,国外的AI
生态很好,虽然他们相互竞争,但都开源,打明牌,杠实力。
本例中我选择谷歌的TensorFlow
。因为它的民间基础牢固。每年都会有学生问"都2020年了,还学TensorFlow?"、"都2021年了,竟然搭建TensorFlow?"、"2023年了......"。是的,每年都问。这个问题解释起来很费劲。我换一种说法可以辅助你理解,那就是"2023年的中国,你居然还讲究人情世故?"
TensorFlow
也是如此,它在工业界依然有一定的占比。甚至很多企业还跑着篡改的TensorFlow 1.x
版本。你去了......要么重构项目,要么重构自己。
2.2 选择模型
搞小模型,不用选最好的,要选最适合自己的。这就如同你家离单位1公里,你要选择通勤工具。此时,雅阁和雅迪的性能差距不大,但是成本却明显不同。
对于大明白提的书籍段落的阅读理解问答,我选择从谷歌的Bert
框架做微调。
2.2.1 Bert与预训练模型
先别说"都2023年了,还Bert......"。我的目的是低成本解决问题,并非去搞创造性研究(老板们很认可我的话,科学家却朝我吐口水)。
Bert
[参考2]是谷歌2018年推出的一款语言模型,其参数尚未达到十亿级别,因此它还称不上"大语言模型"。即便如此,我给你算算它的训练成本。
训练100GB
的文本数据,需要8
台配置相似的高性能GPU
服务器,每台服务器配备4
个NVIDIA V100 GPU
,总共32
个GPU
,至少需要训练7
天的时间。
咱不算服务器、冷却系统的钱,不算整理数据集的成本,电费也忽略不计。单是额外配的这32个V100
,也要40万
人民币。咱不买,就算租,你租人家40万
的设备,他还得配机房、客服、电工,能给你便宜多少。
值得庆幸的是,在NLP领域,Bert发布了一个叫"预训练模型 "的东西。预训练的概念最早在2013年提出。但真正第一个实现落地的,就是Google Research
团队在Bert
模型身上。
Bert
发布了很多预训练模型的版本,下面列举几个:
- BERT-Base:通用模型,1.1亿个参数。
- BERT-Base, Multilingual:102种语言,1.1亿个参数。
- BERT-Base, Chinese:中文语言,1.1亿个参数。
- BERT-Large:更大、更复杂的版本,3.4亿个参数。
这些预训练模型有什么用呢?
其实就是提供了一个基础认知。你想让计算机实现阅读理解,它首先得有基本的认知。
阅读:朱元璋推翻了元朝建立了明朝。 问题:朱元璋打败了谁?
最终AI
给出答案:元朝。
我们来分析一下,AI
要回答上面的问题,它得具备什么前置知识。
- "打败"和"推翻"指的是一个意思。
- "元朝"是一个特指名称。它没有回答打败了"元朝建"或者"元朝建立"。
- "谁"指的是问一个对象的名称。
就是这样。让计算机理解"人需要呼吸才能活"、"包子是一种食物"、"我、俺、咱指的是同一方"这类常识是最难的。因为我们从小到大都学过,并且我们自然而然地认为计算机也知道。其实不是,它也不知道。
有了基础认知,你再去训练自己提供的数据,AI
才能理解你问的是什么,回答的是什么,并依照数据特征,定制你的口味。
另外,通过预训练模型,我们自训练的效率会有极大提升。甚至你手里的笔记本电脑就可以训练。我给你算算基于预训练模型的训练成本。
训练几千条问答数据,用普通的台式办公电脑(i7处理器,8核,32G内存),运行6个小时,就能有很好的效果。
2.3 整理数据集并训练
首先下载Bert代码,地址是:github.com/google-rese...
环境依赖非常纯净:
makefile
tensorflow: 1.11.0
python: 3.6
虽然看似简洁,但据我了解,很多读者依然会遇到各种各样的困难,比如被pip install tensorflow==1.11.0
这条安装命令,困扰好多天。这类问题就像我说打开易拉罐,结果你一拽拉环断了。只能说,请相信总会有办法解决。
建议大家读它的README.md
文档,一定要耐心去读。因为,我说的步骤也是从文档中摘选的。
环境和代码都准备好后,就可以训练数据了。训练数据,需要执行以下命令:
ini
python run_squad.py \
--vocab_file=$BERT_BASE_DIR/vocab.txt \
--bert_config_file=$BERT_BASE_DIR/bert_config.json \
--init_checkpoint=$BERT_BASE_DIR/bert_model.ckpt \
--do_train=True \
--train_file=$SQUAD_DIR/train-v1.1.json \
--train_batch_size=12 \
--learning_rate=3e-5 \
--num_train_epochs=2.0 \
--max_seq_length=384 \
--doc_stride=128 \
--output_dir=/tmp/squad_base/
2.3.1 训练文件
run_squad.py
表示运行斯坦福问答数据集SQuAD
。SQuAD(Stanford Question Answering Dataset)是斯坦福大学在2016年公开的一个阅读理解数据集。它里面包含了大约1万个问题、段落和答案,全都标记好了。以此提供给语言模型进行训练和测试。
Bert为了落地,就以此问答数据集作为样板供大家使用。我们的诉求也类似,也是通过阅读一段文本,然后从文中寻求答案,所以我们选择它。
除此之外,你也能看到其他应用,比如
run_classifier.py
是文本分类的例子。
2.3.2 预训练模型
命令里提到了一个目录,叫BERT_BASE_DIR
。这是Bert预训练模型的目录,你愿意使用哪一个模型,就指定它为目录。
前面提到的预训练模型,在README.md
文档中都有下载链接。
下载下来的文件结构如下所示:
css
|--bert_config.json
|--bert_model.ckpt.data-00000-of-00001
|--bert_model.ckpt.index
|--bert_model.ckpt.meta
|--vocab.txt
他们有什么区别呢?主要区别在于词汇表vocab.txt
上。我都下载下来了,给大家展示下区别。
首先看标准版BERT-Base
的词汇表。
上图的标准版词汇表,只有200
来个汉字,其他全是英文单词。
词汇表有什么用呢?它会将文本依照词汇表序列化成数字。
我们看到"0"被定义为1014,"1"被定义为1015。当你感觉它多此一举时,到后面又发现"帝"被定义为1838,"心"定义为1849。而再到后面大量的英文单词,也都有所定义。
json
......
"people":2111,"part":2112,"know":2113,
"second":2117,"university":2118,"both":2119,
"national":2120,"##er":2121,"these":2122,
......
这样就实现了文本转为数字,我们称这个步骤叫序列化。
看上面有些形如##er
样式的。这个是Bert的分词机制。它表示这些单词片段还可以再进一步拆分,比如:teacher
可以拆分为teach
和er
。那么,如果模型遇到pythoner
(词典不存在这个词,但是有人这么用),它也能根据python+er
的拆分,知道这表示python开发者
的意思。
我们的中文在这个基础版的体系下是没法使用的。因为中文汉字有9
万多,常用字也有7
千字。这里面只有200
来个中文字。因此,一段正常的文本在序列化时,找不到归属,都会变成[UNK]
。你说啥,它都认为是一样的,根本无法理解。
这可怎么办?那就需要一套中文的词汇表,下载中文预训练模型BERT-Base, Chinese
。我们来看看它的vocab.txt
。
在这里,中文词汇变成了主战场,大约有上万个中文字符。里面也包含了一些的英文单词,因为中文阅读材料会夹杂少量英文。
好了,这么看,我们得选择BERT-Base, Chinese
作为预训练模型。
虽然支持102种语言的
BERT-Base, Multilingual
也包含全部中文词汇。但它的词汇量是Chinese
的5倍,会影响效率。
2.3.3 数据集路径
训练的脚本文件有了,预训练模型定了,下面就开始给他喂数据集。
SQUAD_DIR
指定了训练数据集的路径。官方给的train-v1.1.json
是斯坦福的问答集[参考3]。但是,我们想训练自己的问答数据。因此,你可以模仿它的格式,组织自己的数据。
他的格式是这样的:
json
{
"data": [
{
"title": "文章标题",
"paragraphs": [{
"context": "文章内容",
"qas": [
{
"answers": [
{"answer_start": 0,"text": "答案"}
],
"question": "问题","id": "问题id"
}]}]
}
],
"version": "1.1"
}
其中answer_start
是答案在文中的位置起点。只要我们按照这个格式整理好数据,Bert就能进行训练。
我从ChineseSquad
数据集(SQuAD中文版)[参考4],抽离出了一个地理领域的合集,里面包含:南京、四川、浙江、荷兰、阿尔卑斯山等地理类的阅读文本,形成一个data_geo.json
训练集。
我采用的是
SQuAD v1.1
版本的格式。2.0
版本虽然更高级,但是也更麻烦。
到这里就可以训练了。我的训练命令是:
ini
python run_squad.py \
--vocab_file=chinese/vocab.txt \
--bert_config_file=chinese/bert_config.json \
--init_checkpoint=chinese/bert_model.ckpt \
--do_train=True \
--train_file=datasets/data_geo.json \
--train_batch_size=6 \
--learning_rate=3e-5 \
--num_train_epochs=40 \
--max_seq_length=373 \
--doc_stride=64 \
--output_dir=tmp/squad_chinese/
命令中的output_dir是训练结果保存的路径。
执行后,控制台有如下打印:
于是,经过6
个小时的等待,我就拥有了地理行业的中文理解问答模型。
最终生成的目录结构如下:
css
|--checkpoint
|--model.ckpt-1946.data-00000-of-00001
|--model.ckpt-1946.index
|--model.ckpt-1946.meta
|--graph.pbtxt
|--train.tf_record
2.4 验证数据集
为了验证效果,我自己新组合了一个data_jinan.json
数据集,这里面是关于济南的知识,只有问题,没有答案。
同样,我们也可以运行run_squad.py
来做推理,命令如下:
ini
python run_squad.py \
--vocab_file=chinese/vocab.txt \
--bert_config_file=chinese/bert_config.json \
--init_checkpoint=tmp/squad_chinese/model.ckpt-1946 \
--do_predict=True \
--predict_file=datasets/data_jinan.json \
--output_dir=tmp
请注意,命令中vocab_file
、bert_config_file
还是预训练模型的文件。但是init_checkpoint
变成了我们刚生成的文件。它是在预训练模型的基础上生成的新模型。
最后,会在tmp
文件夹下生成结果文件nbest_predictions.json
。
json
问题:
"context": "济南市的别称有泉城、齐州、泺邑。济南是山东省的省会、副省级市、特大城市、济南都市圈核心城市,属于二线城市,是国务院批复确定的环渤海地区南翼的中心城市。截至2022年,全市下辖10个区、2个县,总面积10244.45平方千米,常住人口941.5万人,城镇人口699.8万人,城镇化率为74.3%。",
"question": "济南的总面积是多少?",
"id": "jn0014"
结果:
{
"jn0014": [
{
"text": "10244.45平方千米",
"probability": 0.9998867035004451,
"start_logit": 8.909591674804688,
"end_logit": 4.485512733459473
}
]
}
上面给大家展示下输出的结构,预测结果以id
对应问题。
其实,文章最开头展示的动图,就是这个模型的能力。它给出了很好的回答。
但是,它是一个小模型。我们这个model.ckpt
模型目前还不是。
2.5 转化小模型
TensorFlow Lite提供了一个转换器[参考5]。它可以支持由其他格式转化为客户端可用的.tflite
格式。
比如通过命令行转换:
ini
tflite_convert \
--saved_model_dir=/tmp/saved_dir \
--output_file=/tmp/mobilebert.tflite
这种方式只能做低级转换。不过,通过调用API
代码,可以做更高级的转换:
python
import tensorflow as tf
converter = tf.lite.TFLiteConverter.from_saved_model(saved_dir)
# todo:可以通过converter做量化处理等操作
tflite_model = converter.convert()
with open('mobilebert.tflite', 'wb') as f:
f.write(tflite_model)
而这个.tflite
文件就是我们需要的小模型。
我们拿到这个小模型之后,可以考虑使用它了。
先去下载手机版的Bert QA安卓项目[参考6]。编译时,gradle
会自动下载mobilebert.tflite
和qa.json
保存到assets
文件夹下。现在还是官方示例,运行一下,看看有没有问题。
然后将我们自己生成的小模型cn_mobilebert.tflite
拷贝进去。并且按照qa.json
的数据格式,自己组一个问题集cn_qa.json
放进去。
然后修改代码,加载我们的小模型与问题集:
ini
1、LoadDataSetClient.kt修改JSON_DIR="qa.json"为"cn_qa.json"。
2、BertQaHelper.kt修改BERT_QA_MODEL="mobilebert.tflite"为"cn_mobilebert.tflite"
3、其他界面和提示语调整
运行一下,就是文章开头的效果了。
说实话,其他模型的转换可以通过这个转化器做。但是这次Bert
的转换,我费了很大一番周折。主要原因是"mobilebert.tflite"的网络结构与原本的model.ckpt
有差异,需要做解剖和重组。这对新手来说很不友好。
但是,幸好还有一个途径,那就是不经过转化,直接生成".tflite"文件。
2.6 生成小模型
TensorFlow Lite
还提供了一个Model Maker
[参考7],可以专门针对手机制作问答小模型。
它不但功能强大,而且操作简单。总体上只需要5
步。
python
# 1、选择预训练模型
spec = model_spec.get('mobilebert_qa')
# 2、加载自己的数据集合
train_data = DataLoader.from_squad(train_data_path, spec, is_training=True)
validation_data = DataLoader.from_squad(validation_data_path, spec, is_training=False)
# 3、训练模型
model = question_answer.create(train_data, model_spec=spec)
# 4、评估预测结果
metric = model.evaluate(validation_data)
# 5、导出为TensorFlow Lite格式
model.export(export_dir)
这种生成方式,更加有针对性。
不过提示给大家一个坑,Windows
下跑不通,会一直报一个错:
ini
No matching distribution found for scann==1.2.6
因为这个scann
库不支持Windows
,虚拟机也不行。不过换成Linux
系统就可以了。
三、小模型的优劣
小模型可在客户端运行,这一点大大降低了企业的使用成本 。因为一旦模型训练好,如果没有功能变化,那么你不用再去关心和AI
开发有关的东西。
另外,同样是因为在客户端运行,客户的数据不会上传到云端进行处理。客户会很有安全感,例如对聊天记录进行分析识别,他们不希望这类敏感内容离开自己的手机。对于保障客户隐私,这又是一个亮点。
我感觉最令人兴奋的,是这种方式降低了企业使用AI
的门槛。让相对节俭的企业也能实现AI梦
。
当然,你别对小模型有太高的奢望,因为它的能力有限。它会对一些你认为显而易见的问题回答不好。
拿"千佛山是泰山的余脉"举例。你问它千佛山是谁的余脉,它能回答是泰山的。但是你问两者有什么联系,它就尴尬了。
而这类问题,大模型却微微一笑。
梦想和妄想是有区别的。
梦想就是"我是高中生,我能做AI开发吗?"、"我是小企业,我能有自主的AI产品吗?"当然可以!
这些东西五年前就存在了,只是限于信息差,你不知道而已。而我恰巧做过移动开发、AI开发、项目管理,现在整合一下告诉了你。
妄想就不一样了,他会问"你这个小成本模型,能超过ChatGPT 4.0吗?"
这不科学!
四、资料参考
参考1:客户端训练模型
Device Training tensorflow.google.cn/lite/exampl...
参考2:Bert官方
Bert github.com/google-rese...
参考3:斯坦福问答数据集
SQuAD rajpurkar.github.io/SQuAD-explo...
参考4:ChineseSquad数据集
ChineseSquad github.com/pluto-junze...
参考5:转换器
TfLite Convert www.tensorflow.org/lite/conver...
参考6:Bert QA手机版
Bert QA Lite tensorflow.google.cn/lite/exampl...
参考7:小模型制作器
Model Maker www.tensorflow.org/lite/models...