在大模型的浪潮下,我对“小模型”的探索与实践之路

本文为稀土掘金技术社区首发签约文章,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库的出现,也让PyTorchTensorFlow这些模型可以相互转化和使用。可以说,国外的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服务器,每台服务器配备4NVIDIA V100 GPU,总共32GPU,至少需要训练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表示运行斯坦福问答数据集SQuADSQuAD(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可以拆分为teacher。那么,如果模型遇到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_filebert_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.tfliteqa.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...

相关推荐
IT古董10 分钟前
【漫话机器学习系列】017.大O算法(Big-O Notation)
人工智能·机器学习
凯哥是个大帅比10 分钟前
人工智能ACA(五)--深度学习基础
人工智能·深度学习
m0_7482329230 分钟前
DALL-M:基于大语言模型的上下文感知临床数据增强方法 ,补充
人工智能·语言模型·自然语言处理
szxinmai主板定制专家35 分钟前
【国产NI替代】基于FPGA的32通道(24bits)高精度终端采集核心板卡
大数据·人工智能·fpga开发
海棠AI实验室38 分钟前
AI的进阶之路:从机器学习到深度学习的演变(三)
人工智能·深度学习·机器学习
机器懒得学习1 小时前
基于YOLOv5的智能水域监测系统:从目标检测到自动报告生成
人工智能·yolo·目标检测
QQ同步助手1 小时前
如何正确使用人工智能:开启智慧学习与创新之旅
人工智能·学习·百度
AIGC大时代1 小时前
如何使用ChatGPT辅助文献综述,以及如何进行优化?一篇说清楚
人工智能·深度学习·chatgpt·prompt·aigc
流浪的小新1 小时前
【AI】人工智能、LLM学习资源汇总
人工智能·学习
martian6652 小时前
【人工智能数学基础篇】——深入详解多变量微积分:在机器学习模型中优化损失函数时应用
人工智能·机器学习·微积分·数学基础