目标
:基于pytorch
、transformers
做中文领域的nlp开箱即用的训练框架,提供全套的训练、微调模型(包括大模型、文本转向量、文本生成、多模态等模型)的解决方案;数据
:
百GB
规模的数据,也是轻而易举;流程
:每一个项目有完整的模型训练步骤,如:数据清洗、数据处理、模型构建、模型训练、模型部署、模型图解;模型
:当前已经支持gpt2
、clip
、gpt-neox
、dolly
、llama
、chatglm-6b
、VisionEncoderDecoderModel
等多模态大模型;多卡串联
训练时
、推理时
中文名称 | 文件夹名称 | 数据 | 数据清洗 | 大模型 | 模型部署 | 图解 |
---|---|---|---|---|---|---|
中文文本分类 | chinese_classifier | ✅ | ✅ | ✅ | ❌ | ✅ |
中文gpt2 |
chinese_gpt2 | ✅ | ✅ | ✅ | ✅ | ❌ |
中文clip |
chinese_clip | ✅ | ✅ | ✅ | ❌ | ✅ |
图像生成中文文本 | VisionEncoderDecoderModel | ✅ | ✅ | ✅ | ❌ | ✅ |
vit核心源码介绍 | vit model | ❌ | ❌ | ❌ | ❌ | ✅ |
Thu-ChatGlm-6b (v1 ) |
simple_thu_chatglm6b | ✅ | ✅ | ✅ | ✅ | ❌ |
chatglm-v2 -6b |
chatglm_v2_6b_lora | ✅ | ✅ | ✅ | ❌ | ❌ |
中文dolly_v2_3b |
dolly_v2_3b | ✅ | ✅ | ✅ | ❌ | ❌ |
中文llama |
chinese_llama | ✅ | ✅ | ✅ | ❌ | ❌ |
中文bloom |
chinese_bloom | ✅ | ✅ | ✅ | ❌ | ❌ |
中文falcon (注意:falcon模型和bloom结构类似) |
chinese_bloom | ✅ | ✅ | ✅ | ❌ | ❌ |
中文预训练代码 | model_clm | ✅ | ✅ | ✅ | ❌ | ❌ |
百川大模型 | model_baichuan | ✅ | ✅ | ✅ | ✅ | ❌ |
模型修剪✂️ | model_modify | ✅ | ✅ | ✅ | ||
llama2 流水线并行 | pipeline | ✅ | ✅ | ✅ | ❌ | ❌ |
本部分,介绍中文的文本分类模型,适用于二分类、多分类等情况。使用transformers库。
code_01_processdata.ipynb
code_01_processdata.ipynb
文件跑完之后,就可以看到在data_all
里面有一个data
,里面有三个文件,样式都是像下面这样的上图是一个batch
的数据,或者所有的文本分类的数据样式:
text
下面的红色条,就是一个个句子。label
里面有红色有绿色,就是表示标签分类。transformers
包做分类的时候,数据要求就这两列。注意点:
train_data.csv
,test_data.csv
,valid_data.csv
,这三个csv
文件注意是使用,
分割开的。label
,text
label
:表示标签,最好为整型数值。0,1,2,3,4等text
:表示文本,(看你需求,可以有符号,也可以没有标点符号)train_data.csv
,test_data.csv
,valid_data.csv
这三个数据里面,不要有数据相同的,不然会造成数据泄漏。code_02_trainmodel.ipynb
数据训练流程
以一个batch为例:
Tokenizer
会将数据中的text
转换成三个矩阵(或者叫三个Tensor
),分别叫input_ids
,token_type_ids
,attention_mask
,至于怎么转换的,我们先不做详细介绍(本仓库后续会介绍)。pretrained model
在被加载之前,需要设置一大堆模型的参数,至于要设置什么参数,我们也不做详细介绍。Trainer
就是一个训练器,也需要预先设置好一大堆参数。至于要设置什么参数,我们也不做详细介绍。Trainer
会把input_ids
,token_type_ids
,attention_mask
;还有数据自带的标签label
;还有pretrained model
都加载进来,进行训练;your new model
就诞生了。大模型做nlp分类
的任务,其实不需要考虑那么多细节,只需要注意数据流程。注意点:
batch_size
,eval_size
大小取决于显存大小。Tokenizer
把所有的文本转换成input_ids
,token_type_ids
,attention_mask
,然后在训练的时候,这步就不再做了,目的是减少训练过程中cpu处理数据的时间,不给显卡休息时间。Tokenizer
把所有的文本做转换的期间,如果设置的文本的长度上限为64,那么会把大于64的文本截断;那些少于64的文本,会在训练的时候,在喂入模型之前,把长度补齐,这么做就是为了减少数据对内存的占用。预测code_03_predict.ipynb
这个时候,就是搞个句子,然后丢给一个pipeline
(这个就是把Tokenizer
和你的大模型
放在一起了),然后这个pipeline
就给你返回一个分类结果。
常见的就是使用pipeline
,如果更加复杂的话,比如修改模型,这个时候,就比较复杂了(后面会再次介绍)。
部署
简单的部署
相对于预测
,其实就是再加一层web端口,fastapi包就可以实现。
高级一点的部署
相对于预测
,就需要把模型从pytorch
转换成onnx
格式的,这样可以提高推理效率(也不一定,就是举个例子),可能也不会使用web端口(http协议)了,会使用rpc协议等方法。这部分现在先不看。
612万
个样本,每个样本有512个tokens,总共相当于大约31亿个tokens
需要准备好环境,也就是安装需要的包
pip install -r requirements.txt
像是pytorch
这种基础的包肯定也是要安装的,就不提了。
数据来源
统计学人
】,然后回复【gpt2
】即可获得。31亿个tokens
),在一张3090上,训练了60多小时)数据格式
.csv
格式的文件。其中有一列数据是content
content
就代表一句话datasets
glob
包就能完成。训练代码train_chinese_gpt2.ipynb
tokenizer
、gpt2_model
、Trainer
tokenizer
使用的是bert-base-chinesebos_token
、eos_token
、pad_token
。gpt2_model
使用的是gpt2,这里的gpt2我是从0开始训练的。而不是使用别人的预训练的gpt2
模型。Trainer
训练器使用的就是transformers
的Trainer
模块。(支撑多卡并行,tensorboard等,都写好的,直接调用就行了,非常好用)模型
推理代码infer.ipynb
这个是chinese-gpt2
的推理代码
model_name_or_path = "checkpoint-36000"
里面的"checkpoint-36000"
,修改为模型所在的路径。chatbot.py
model_name_or_path = "checkpoint-36000"
python chatbot.py
huggingface
文档、教程度过来的.Tokenizer
改成中文的了,然后也整理了数据,别的大部分东西,都不是我做的了.其实,我更喜欢做应用,但是也要理解相关的背后原理,目前还在研究相关的gpt2原理还有相关的推理细节,这是我整理的链接,希望可以共同进步
CLIP的英文全称是Contrastive Language-Image Pre-training,即一种基于对比文本-图像对的预训练方法或者模型。
CLIP是一种基于对比学习的多模态模型,与CV中的一些对比学习方法如moco和simclr不同的是,
CLIP的训练数据是文本-图像对
:一张图像和它对应的文本描述,这里希望通过对比学习,
模型能够学习到文本-图像对的匹配关系。
如下图所示,CLIP包括两个模型:
Text Encoder和Image Encoder,其中Text Encoder用来提取文本的特征,可以采用NLP中常用的text transformer模型;
Image Encoder用来提取图像的特征,可以采用常用CNN模型或者vision transformer。
上面这段文字来源于https://zhuanlan.zhihu.com/p/493489688
text - text
。只不过现在都是text - image
了。text-model
:负责把text
转换成向量。image-model
:负责把image
转换成向量。image-model
处理图像的,其实也可以改为处理视频、处理3d模型等。那简直是格局打开了。我现在没有数据,后面也打算做一个。text-image
=> text-image-video-3d
这样联合起来,是不是更好。没数据,没机器,做不了。你这人,就知道TMD吹牛
,来来来,我带你研究研究clip模型的源码。test-2.6w.csv
、train-137w.csv
放在文件夹bigdata/raw_data
里面。processdta_01.ipynb
、processdta_02.ipynb
、processdta_02.ipynb
用来处理数据。processdta_01.ipynb
:用来下载数据,大概下载了10多个小时。processdta_02.ipynb
:用来筛选数据,不是所有的图片数据都是可以用的,这一步非常坑。需要留意。如果图片没有筛选好,在你训练到中间的时候,突然一下因为图片无法加载导致错误,从而训练中断了。processdta_03.ipynb
:用来把数据干净的数据处理好,合并好,生成新的,漂亮的训练数据。说到底,你的数据只要整理成这样的一个样式即可
text | image_path |
---|---|
河南一村民继承祖上的一金碗,专家鉴定:此碗是溥仪皇帝用过的 | bigdata/image_data/test-9282.jpg |
著名钢琴家郎朗:我永远不会放弃演奏 | bigdata/image_data/test-2644.jpg |
科幻动作电影《超体》10月24日来袭 | bigdata/image_data/test-13199.jpg |
text
:这一列对应图片的标注,或者和图片相关的文本。image_path
:这一列对应图片所在你电脑本地上的路径。这里的数据预处理,是我随便起的名字。说白了,就是这么会是:
使用tokenizer
把text
转换成input_ids
和attention_mask
.
使用processor
把image
转换成pixel_values
.
处理text
,那还是很快的。百万级别的数据,可能2~3分钟就行了。
因为image
太大了,只能在训练的时候,每一batch,才能去加载image
,这就导致训练的时候特别慢。倒不是因为我的3090算力不行,全都TMD
卡在计算机IO上了,非常让人难受。
终于讲解到clip的模型部分了。这个clip模型实在是太灵活了,你可以做很多个版本,这里我们挑几个比较常见的结构,来分享一下。
这里值得是常见的clip模型,特指的是transformers
包的clip模型。
CLIPTextTransformer
,一个是CLIPVisionTransformer
,说白了就是一个处理text,一个处理image。CLIPTextTransformer
和CLIPVisionTransformer
的核心,都共用了一个模型结构CLIPEncoder
Q:有些人就问了,text和image两个生成的数据都不一样,比如text
转换成input_ids
和attention_mask
;image
转换成pixel_values
;他们怎么可以使用一个模型结构CLIPEncoder
?
A:这个也是非常好回答的,因他俩又不是直接使用CLIPEncoder
,前后都加了一些万金油的模型组件(比如embedding
、linear
等),模型输出的时候,也是这么做的。还是应了那句话,就看你怎么吧数据转换成hidden_states
,以及怎么把hidden_states
输出出去。
Q:CLIPTextTransformer
和CLIPVisionTransformer
输出的维度也不一定一样吧,怎么计算交叉损失?
A: 也很简单啦,加个linear
对齐一下就行了。
看看CLIPTextTransformer
和CLIPVisionTransformer
的内心:
上面的常见的clip模型
,确实是好,其实你只要换一个支持中文的新tokenizer
,然后从0️⃣开始训练即可。
但是这么搞,没什么创意呀。其实我第一次就是这么干的,直接支持中文的新tokenizer
。但是训练了一天,loss基本上没变化。我内心其实是崩溃的。
后来,我研究了一下transformers
包里面的chinese-clip
模型代码。我发现,chinese-clip
相对于clip
。就是把常规的CLIPTextTransformer
换成了bert
版本的。啊对,这就破案了。这个奉上代码截图。
100GB
clip
模型的vit
部分先固定住,然后训练bert来拟合vit-output
。Encoder
,然后计算相似度。之前在huggingfacehttps://huggingface.co/nlpconnect/vit-gpt2-image-captioning上看到这个模型.
clip
训练其实挺失败的,loss
没有下降.主要也就是抱着学习的态度,把源码看懂,把流程跑通。分享中间的细节和踩坑经历。
vit
来作为encoder
部分,输出encoder_hidden_states
,绿色部分1
。gpt2
来作为decoder
部分,接受encoder_hidden_states
,绿色部分3
。encoder
输出的encoder_hidden_states
和decoder
接受的encoder_hidden_states
维度不一样,就加个linear
,绿色部分2
。pixel_value
:image
通过processor
生成label
:text
通过tokenizer
生成的input_ids
。loss
的时候,其实和gpt2
一模一样的(自回归,本质上就是向后错位一下)。目前已经把训练好的模型,发布在huggingface
上了。https://huggingface.co/yuanzhoulvpi/vit-gpt2-image-chinese-captioning
本模块处理数据的方式和clip
模型差不多,可以看隔壁文件夹,训练clip
的数据处理思路。
processdta_02.ipynb
文件替换即可。processdta_01.ipynb
、processdta_02.ipynb
、processdta_03.ipynb
。训练部分train_encoder_decoder.ipynb
"google/vit-base-patch16-224"
模型。"yuanzhoulvpi/gpt2_chinese"
模型。VisionEncoderDecoderModel
粘起来。训练的信息
gpu使用的是3090,模型大概是2.16亿个参数。花了超过20个小时。但是大部分时间都是卡在IO上(加载图片上)
推理用你自己训练
参考infer_encoder_decoder.ipynb
直接用
from transformers import (VisionEncoderDecoderModel,
AutoTokenizer,ViTImageProcessor)
import torch
from PIL import Image
vision_encoder_decoder_model_name_or_path = "yuanzhoulvpi/vit-gpt2-image-chinese-captioning"#"vit-gpt2-image-chinese-captioning/checkpoint-3200"
processor = ViTImageProcessor.from_pretrained(vision_encoder_decoder_model_name_or_path)
tokenizer = AutoTokenizer.from_pretrained(vision_encoder_decoder_model_name_or_path)
model = VisionEncoderDecoderModel.from_pretrained(vision_encoder_decoder_model_name_or_path)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model.to(device)
max_length = 16
num_beams = 4
gen_kwargs = {"max_length": max_length, "num_beams": num_beams}
def predict_step(image_paths):
images = []
for image_path in image_paths:
i_image = Image.open(image_path)
if i_image.mode != "RGB":
i_image = i_image.convert(mode="RGB")
images.append(i_image)
pixel_values = processor(images=images, return_tensors="pt").pixel_values
pixel_values = pixel_values.to(device)
output_ids = model.generate(pixel_values, **gen_kwargs)
preds = tokenizer.batch_decode(output_ids, skip_special_tokens=True)
preds = [pred.strip() for pred in preds]
return preds
predict_step(['bigdata/image_data/train-1000200.jpg'])
clip
、image-encoder-decoder
。现在哪里还怕搞不懂vit
.vit
的最核心的部分。vit想法非常牛,但是数据处理的思想更牛,之前都没提出来过。
载对于一个图片,将一个图片分割成N块。巧妙的使用nn.Conv2d
。
import torch
from torch import nn
#base parameter
image_size=224 # 图片的width和height
patch_size=16 # 将图片的分为块,每一块的大小为16x16,这样就有(224//16)^2 = 14 ^2 = 196个
num_channels=3 # R,G, B
hidden_size=768 # 输出的hidden_size
batch_size = 16 # 一批数据有多少
batch
)#分块器
project = nn.Conv2d(num_channels, hidden_size, kernel_size=patch_size, stride=patch_size)
#样本数据(一个`batch`)
#batch_size, num_channels, height, width = pixel_values.shape
pixel_values = torch.randn(batch_size, num_channels, image_size, image_size)
pixel_values.shape
project(pixel_values).shape
#> torch.Size([16, 768, 14, 14])
image_embedding = project(pixel_values).flatten(2).transpose(1, 2)
image_embedding.shape
#> torch.Size([16, 196, 768]) # batch_size, seq_length, embedding_dim
这个时候,就已经和文本的数据一样了。维度都是(batch_size, seq_length, embedding_dim
),再向下推导,就是transformers
了。没什么可介绍的了。
项目链接:https://github.com/yuanzhoulvpi2017/zero_nlp
更多优质内容请关注公号:汀丶人工智能;会提供一些相关的资源和优质文章,免费获取阅读。