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

本文为稀土掘金技术社区首发签约文章,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...

相关推荐
陈广亮9 分钟前
构建具有长期记忆的 AI Agent:从设计模式到生产实践
人工智能
会写代码的柯基犬18 分钟前
DeepSeek vs Kimi vs Qwen —— AI 生成俄罗斯方块代码效果横评
人工智能·llm
Mintopia1 小时前
OpenClaw 是什么?为什么节后热度如此之高?
人工智能
爱可生开源社区1 小时前
DBA 的未来?八位行业先锋的年度圆桌讨论
人工智能·dba
叁两4 小时前
用opencode打造全自动公众号写作流水线,AI 代笔太香了!
前端·人工智能·agent
前端付豪4 小时前
LangChain记忆:通过Memory记住上次的对话细节
人工智能·python·langchain
strayCat232554 小时前
Clawdbot 源码解读 7: 扩展机制
人工智能·开源
王鑫星4 小时前
SWE-bench 首次突破 80%:Claude Opus 4.5 发布,Anthropic 的野心不止于写代码
人工智能
lnix4 小时前
当“大龙虾”养在本地:我们离“反SaaS”的AI未来还有多远?
人工智能·aigc