README.md 11.8 KB
Newer Older
yuguo's avatar
update  
yuguo committed
1
2
3
4
5
6
7
8
9
# GLM

## 论文

`GLM: General Language Model Pretraining with Autoregressive Blank Infilling`

- [https://arxiv.org/abs/2103.10360](https://arxiv.org/abs/2103.10360)

## 模型结构
yuguo960516's avatar
glm  
yuguo960516 committed
10
11
2017 年, Google 提出了 Transformer 架构, 随后 BERT 、GPT、T5等预训练模型不断涌现, 并在各项任务中都不断刷新 SOTA 纪录。2022年, 清华提出了 GLM 模型(https://github.com/THUDM/GLM), 不同于上述预训练模型架构,它采用了一种自回归的空白填充方法, 在 NLP 领域三种主要的任务(自然语言理解、无条件生成、有条件生成)上都取得了不错的结果。

chenzk's avatar
chenzk committed
12
<img src="http://developer.sourcefind.cn/codes/modelzoo/glm_oneflow/-/raw/main/glm%E6%A8%A1%E5%9E%8B%E7%BB%93%E6%9E%84.png" alt="glm模型结构.png" style="zoom:50%;" />
yuguo's avatar
update  
yuguo committed
13

yuguo960516's avatar
glm  
yuguo960516 committed
14
15
在LiBai中主要实现了GLM推理部分的工作。

yuguo's avatar
update  
yuguo committed
16
## 算法原理
yuguo960516's avatar
glm  
yuguo960516 committed
17
18
19
20
21
22
当模型规模过于庞大,单个 GPU 设备无法容纳大规模模型参数时,便捷好用的分布式训练和推理需求就相继出现,业内也随之推出相应的工具。

基于 OneFlow 构建的 LiBai 模型库让分布式上手难度降到最低,用户不需要关注模型如何分配在不同的显卡设备,只需要修改几个配置数据就可以设置不同的分布式策略。当然,加速性能更是出众。

用 LiBai 搭建的 GLM 可以便捷地实现model parallel + pipeline parallel推理, 很好地解决单卡放不下大规模模型的问题。

chenzk's avatar
chenzk committed
23
<img src="http://developer.sourcefind.cn/codes/modelzoo/glm_oneflow/-/raw/main/glm%E7%AE%97%E6%B3%95%E5%8E%9F%E7%90%86.png" alt="glm算法原理.png" style="zoom:50%;" />
“yuguo”'s avatar
“yuguo” committed
24

yuguo960516's avatar
glm  
yuguo960516 committed
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
### 分布式推理具有天然优势

要知道,模型的参数其实就是许多 tensor,也就是以矩阵的形式出现,大模型的参数也就是大矩阵,并行策略就是把大矩阵分为多个小矩阵,并分配到不同的显卡或不同的设备上,基础的 LinearLayer 在LiBai中的实现代码如下:

```python
class Linear1D(nn.Module):
    def __init__(self, in_features, out_features, parallel="data", layer_idx=0, ...):
        super().__init__()

        if parallel == "col":
            weight_sbp = dist.get_nd_sbp([flow.sbp.broadcast, flow.sbp.split(0)])
        elif parallel == "row":
            weight_sbp = dist.get_nd_sbp([flow.sbp.broadcast, flow.sbp.split(1)])
        elif parallel == "data":
            weight_sbp = dist.get_nd_sbp([flow.sbp.broadcast, flow.sbp.broadcast])
        else:
            raise KeyError(f"{parallel} is not supported! Only support ('data', 'row' and 'col')")

        self.weight = flow.nn.Parameter(
            flow.empty(
                (out_features, in_features),
                dtype=flow.float32,
                placement=dist.get_layer_placement(layer_idx),  # for pipeline parallelism placement
                sbp=weight_sbp,
            )
        )
        init_method(self.weight)
        ...
    
    def forward(self, x):
        ...
```

在这里,用户可选择去如何切分 Linear 层的矩阵,如何切分数据矩阵,而OneFlow 中的 SBP 控制竖着切、横着切以及其他拆分矩阵的方案(模型并行、数据并行),以及通过设置 Placement 来控制这个 LinearLayer 是放在第几张显卡上(流水并行)。

所以,根据 LiBai 中各种 layer 的设计原理以及基于 OneFlow 中 tensor 自带的 SBP 和 Placement 属性的天然优势,使得用户搭建的模型能够很简单地就实现数据并行、模型并行以及流水并行操作。

yuguo's avatar
update  
yuguo committed
62
63
64
65
## 环境配置

### Docker

chenzk's avatar
chenzk committed
66
提供[光源](https://www.sourcefind.cn/#/service-details)拉取的训练以及推理的docker镜像:image.sourcefind.cn:5000/dcu/admin/base/oneflow:0.9.1-centos7.6-dtk-22.10.1-py39-latest,关于本项目DCU显卡所需torch库等均可从[光合](https://developer.sourcefind.cn/tool/)开发者社区下载安装
yuguo960516's avatar
glm  
yuguo960516 committed
67

yuguo's avatar
update  
yuguo committed
68
69
70
71
    docker pull image.sourcefind.cn:5000/dcu/admin/base/oneflow:0.9.1-centos7.6-dtk-22.10.1-py39-latest
    # <Your Image ID>用上面拉取docker镜像的ID替换
    docker run --shm-size 16g --network=host --name=glm_oneflow --privileged --device=/dev/kfd --device=/dev/dri --group-add video --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v $PWD/glm_oneflow:/home/glm_oneflow -it <Your Image ID> bash
    cd /home/glm_oneflow
yuguo960516's avatar
glm  
yuguo960516 committed
72
73
74
    pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
    pip3 install pybind11 -i https://mirrors.aliyun.com/pypi/simple
    pip3 install -e . -i https://mirrors.aliyun.com/pypi/simple
“yuguo”'s avatar
update  
“yuguo” committed
75
    pip3 install torch-1.10.0a0+git2040069.dtk2210-cp39-cp39-manylinux2014_x86_64.whl
yuguo's avatar
update  
yuguo committed
76
77
78

## 数据集

“yuguo”'s avatar
“yuguo” committed
79
在代码中生成。
yuguo's avatar
update  
yuguo committed
80
81
82

## 权重

chenzk's avatar
chenzk committed
83
需要先准备好模型权重:https://huggingface.co/THUDM/glm-10b-chinese/tree/main 
yuguo960516's avatar
glm  
yuguo960516 committed
84

yuguo's avatar
update  
yuguo committed
85
### Glm-10b-chinese权重的文件结构
yuguo960516's avatar
glm  
yuguo960516 committed
86
87
88
89
90
91
92
93
94
95

```python
$ tree data
path/to/glm-10b-chinese
├── added_tokens.json
├── cog-pretrain.model
├── config.json
└── pytorch_model.bin
```

“yuguo”'s avatar
update  
“yuguo” committed
96
## 推理
yuguo960516's avatar
glm  
yuguo960516 committed
97
98
99

采用1节点,4张DCU-Z100-16G,采用tp=2,pp=2的并行配置。

yuguo's avatar
update  
yuguo committed
100
将模型权重放置与demo.py同一目录下,运行以下代码:
yuguo960516's avatar
glm  
yuguo960516 committed
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

    cd projects/GLM
    # 运行前修改 configs/glm_inference.py 中 `pad_token_id=50000, eos_token_id=50007, bos_token_id=None`
    python3 -m oneflow.distributed.launch --nproc_per_node 4 demo.py

demo.py如下:

    # model parallel + pipeline parallel demo
    
    import oneflow as flow
    from projects.GLM.tokenizer.glm_tokenizer import GLMChineseTokenzier
    from libai.utils import distributed as dist
    from projects.GLM.configs.glm_inference import cfg
    from projects.GLM.modeling_glm import GLMForConditionalGeneration
    from projects.GLM.utils.glm_loader import GLMLoaderHuggerFace
    from omegaconf import DictConfig
    import time
    
    # 只需简单配置并行方案
    parallel_config = DictConfig(
        dict(
            data_parallel_size=1,
            tensor_parallel_size=2,
            pipeline_parallel_size=2,
            pipeline_num_layers=2 * 24
        )
    )
    dist.setup_dist_util(parallel_config)
    
    tokenizer = GLMChineseTokenzier.from_pretrained("glm-10b-chinese")
    input_ids = tokenizer.encode(
        [
            "冬天,中国哪座城市最适合避寒?问题描述:能推荐一些国内适合冬天避寒的城市吗?回答用户:旅游爱好者 回答: [gMASK]"
        ],
        return_tensors="of",
    )
    inputs = {"input_ids": input_ids, "attention_mask": flow.ones(input_ids.size())}
    inputs = tokenizer.build_inputs_for_generation(inputs, max_gen_length=128)
    
    sbp = dist.get_nd_sbp([flow.sbp.broadcast, flow.sbp.broadcast])
    placement = dist.get_layer_placement(0)
    
    loader = GLMLoaderHuggerFace(
        GLMForConditionalGeneration, 
        cfg, 
        "glm-10b-chinese",
        embedding_dropout_prob=0,
        attention_dropout_prob=0,
        output_dropout_prob=0,
    )
    
    T1 = time.time()
    model = loader.load()
    T2 = time.time()
    if dist.is_main_process():
        print('模型加载时间:%s秒' % (T2 - T1))
    
    T3 = time.time()
    outputs = model.generate(
        inputs=inputs['input_ids'].to_global(sbp=sbp, placement=placement), 
        position_ids=inputs['position_ids'].to_global(sbp=sbp, placement=placement), 
        generation_attention_mask=inputs['generation_attention_mask'].to_global(sbp=sbp, placement=placement), 
        max_length=128
    )
    T4 = time.time()
    if dist.is_main_process():
        print('model.generate: %s秒' % (T4 - T3))
    
    T5 = time.time()
    res = tokenizer.decode(outputs[0])
    T6 = time.time()
    if dist.is_main_process():
        print('tokenizer.decode: %s秒' % (T6 - T5))
    
    if dist.is_main_process():
        print(res)

“yuguo”'s avatar
update  
“yuguo” committed
178
## result
yuguo960516's avatar
glm  
yuguo960516 committed
179
180
181
182
183
184

```
>>>Total number of model parameters: 9,879,633,920
[CLS] 冬天,中国哪座城市最适合避寒?问题描述:能推荐一些国内适合冬天避寒的城市吗?回答用户:旅游爱好者 回答: [gMASK] <|endoftext|> <|startofpiece|> 避寒,当然是去海南呀!<n><n>海南的冬天,阳光明媚,温度适宜,而且空气清新,没有雾霾,没有沙尘暴,没有雾霾,没有雾霾!<n><n>海南的冬天,阳光明媚,温度适宜,而且空气清新,没有雾霾,没有沙尘暴,没有雾霾!<n><n>海南的冬天,阳光明媚,温度适宜,而且空气清新,没有雾霾,没有沙尘暴,没有雾霾!
```

yuguo's avatar
update  
yuguo committed
185
## 问答示例
yuguo960516's avatar
glm  
yuguo960516 committed
186
187
188

采用1节点,4张DCU-Z100-16G,采用tp=2,pp=2的并行配置。

yuguo's avatar
update  
yuguo committed
189
将模型权重放置与glm-QA.py同一目录下,运行以下代码:
yuguo960516's avatar
glm  
yuguo960516 committed
190

“yuguo”'s avatar
update  
“yuguo” committed
191
    cd projects/GLM
yuguo960516's avatar
glm  
yuguo960516 committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
    python3 -m oneflow.distributed.launch --nproc_per_node 4 glm-QA.py

程序运行起来后,允许用户在命令行进行问答交互,输入“退出”,可以结束程序,如下所示:

```
输入
> 如何改善睡眠质量
正在生成内容...
> [CLS] 如何改善睡眠质量 回答: [gMASK] <|endoftext|> <|startofpiece|> 睡眠不好,可以试着用以下方法改善: 1、睡前不要喝咖啡、浓茶、吸烟等,也不要喝含咖啡因的饮料,如可乐、咖啡、茶等。 2、睡前不要进行剧烈运动,如剧烈的跑步、跳舞、打球等。 3、睡前不要看刺激性的电视节目,如恐怖电影、凶杀片等。 4、睡前不要思考问题,如回忆今天发生的事情、明天的工作计划等。 5、睡前不要进食,如吃得过饱、过晚、过饱等。 6、睡前不要进行剧烈的体力活动,如跑步、打球、游泳
输入:
> 从北京到郑州有多少公里
正在生成内容...
> [CLS] 从北京到郑州有多少公里 回答: [gMASK] <|endoftext|> <|startofpiece|> 北京到郑州,直线距离约1000公里,开车需要大约12个小时。 <|endofpiece|>
输入:
> 推荐一部高分恐怖电影
正在生成内容...
> [CLS] 推荐一部高分恐怖电影 回答: [gMASK] <|endoftext|> <|startofpiece|> 《恐怖游轮》<n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n><n>
输入:
> 问题:冬天,中国哪座城市最适合避寒?问题描述:能推荐一些国内适合冬天避寒的城市吗?回答用户:旅游爱好者
正在生成内容...
> [CLS] 问题:冬天,中国哪座城市最适合避寒?问题描述:能推荐一些国内适合冬天避寒的城市吗?回答用户:旅游爱好者 回答: [gMASK] <|endoftext|> <|startofpiece|> 避寒,当然是去海南呀,海南的冬天,阳光明媚,温度适宜,而且海南的冬天,没有雾霾,没有沙尘暴,没有寒冷,只有温暖,海南的冬天,是避寒的好地方。 <|endofpiece|>
输入:
> 介绍一下中科曙光公司
正在生成内容...
> [CLS] 介绍一下中科曙光公司 回答: [gMASK] <|endoftext|> <|startofpiece|> 中科曙光公司成立于2000年,是中国科学院计算技术研究所控股的高科技公司,是国家首批创新型企业,是国家规划布局内重点软件企业,是国家863计划成果产业化基地,是国家高技术产业化示范工程,是国家火炬计划重点高新技术企业,是国家创新型企业试点单位,是国家集成电路设计产业化基地,是国家信息安全成果产业化基地,是国家863计划成果产业化基地,是国家集成电路设计产业化基地,是国家信息安全成果产业化基地,是国家火炬计划重点高新技术企业,是国家创新型企业试点单位,是国家集成电路设计产业化基地,是国家信息安全成果产业化基地,是国家863计划成果产业化基地
输入:
> 退出
> 再见
```

yuguo's avatar
update  
yuguo committed
222
223
224
225
226
227
228
229
## 应用场景

### 算法类别

`自然语言处理`

### 热点应用行业

“yuguo”'s avatar
update  
“yuguo” committed
230
`医疗,教育,科研,金融`
yuguo's avatar
update  
yuguo committed
231

yuguo960516yuguo's avatar
1.1  
yuguo960516yuguo committed
232
## 源码仓库及问题反馈
yuguo960516yuguo's avatar
v1.0  
yuguo960516yuguo committed
233

chenzk's avatar
chenzk committed
234
- https://developer.sourcefind.cn/codes/modelzoo/glm_oneflow
yuguo960516's avatar
glm  
yuguo960516 committed
235

yuguo960516's avatar
glm  
yuguo960516 committed
236
237
238
## 参考
* https://github.com/Oneflow-Inc/libai
* https://github.com/Oneflow-Inc/one-glm