File size: 8,513 Bytes
22fb4ec
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
178
179
180
181
182
183
184
185
186
187
188
189
190
191
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
===================================
自定义指令微调数据集(LLM)
===================================

XTuner 支持使用自定义数据集进行指令微调,为便于介绍,本节以
`internlm2_chat_7b_qlora_custom_sft_e1.py <https://github.com/InternLM/xtuner/blob/main/xtuner/configs/custom_dataset/sft/internlm/internlm2_chat_7b_qlora_custom_sft_e1.py>`__
配置文件为基础进行介绍。

数据准备
=================

XTuner 采用 `OpenAI SFT
数据集格式 <https://platform.openai.com/docs/guides/fine-tuning/preparing-your-dataset>`__
作为统一的自定义数据集格式,详细格式如下:

.. code:: json

   [{
       "messages": [
           { "role": "system", "content": "xxx."},
           { "role": "user", "content": "xxx." },
           { "role": "assistant", "content": "xxx."}
       ]
   },
   {
       "messages": [
           { "role": "system", "content": "xxx." },
           { "role": "user", "content": "xxx." },
           { "role": "assistant", "content": "xxx.", "loss": False},
           { "role": "user", "content": "xxx." },
           { "role": "assistant", "content": "xxx.", "loss": True}
       ]
   }]

.. note::
   每条数据除了 OpenAI 标准格式中的 ``role``
   字段和 ``content`` 字段外,XTuner 还额外扩充了一个 ``loss``
   字段,用于控制某轮 ``assistant`` 的输出不计算 loss。

.. note::
   - ``system`` 和 ``user`` 的 ``loss`` 默认为 False
   - ``assistant`` 的 ``loss`` 默认为 True

.. tip::

   若想令某轮对话 "assistant"
   部分的内容不参与 loss 计算,需要手动设置该数据 "loss" 字段的值为
   ``false``\ 。

训练
=============

步骤 1: 导出 config
--------------------------------

``xtuner/configs/custom_dataset/sft`` 目录下有所有 XTuner
支持的模型在自定义数据集下使用 QLora 算法训练的模板 config。可以通过
``xtuner list-cfg -p custom_sft`` 命令来查看候选 config。下面以
`internlm2_chat_7b_qlora_custom_sft_e1.py <https://github.com/InternLM/xtuner/blob/main/xtuner/configs/custom_dataset/sft/internlm/internlm2_chat_7b_qlora_custom_sft_e1.py>`__
为例展开介绍。

可以通过以下命令将 ``internlm2_chat_7b_qlora_custom_sft_e1.py``
导出至当前目录下:

.. code:: console

   $ xtuner copy-cfg internlm2_chat_7b_qlora_custom_sft_e1 .

.. note::

   当前目录下会存在一个新 config
   ``internlm2_chat_7b_qlora_custom_sft_e1_copy.py`` 。

步骤 2:修改 config
----------------------------------

首先,需要修改数据集文件路径:

.. code:: diff

   - data_files = ['/path/to/json/file.json']
   + data_files = ['/path/to/custom_sft1.json', '/path/to/custom_sft2.json', ...]

若期望使用某个目录下所有的 json 文件作为训练数据集,可做如下修改:

.. code:: diff

   #######################################################################
   #                          PART 1  Settings                           #
   #######################################################################
   # Data
   - data_files = ['/path/to/json/file.json']
   + data_dir = '/dir/to/custom_sft'

   #######################################################################
   #                      PART 3  Dataset & Dataloader                   #
   #######################################################################
   train_dataset = dict(
   -   dataset=dict(type=load_dataset, path='json', data_files=data_files),
   +   dataset=dict(type=load_dataset, path='json', data_dir=data_dir),
       ...)

若期望使用 Lora 算法训练,可做如下修改:

.. code:: diff

   #######################################################################
   #                      PART 2  Model & Tokenizer                      #
   #######################################################################
   model = dict(
       type=SupervisedFinetune,
       use_varlen_attn=use_varlen_attn,
       llm=dict(
           type=AutoModelForCausalLM.from_pretrained,
           pretrained_model_name_or_path=pretrained_model_name_or_path,
           trust_remote_code=True,
           torch_dtype=torch.float16,
   -       quantization_config=dict(
   -           type=BitsAndBytesConfig,
   -           load_in_4bit=True,
   -           load_in_8bit=False,
   -           llm_int8_threshold=6.0,
   -           llm_int8_has_fp16_weight=False,
   -           bnb_4bit_compute_dtype=torch.float16,
   -           bnb_4bit_use_double_quant=True,
   -           bnb_4bit_quant_type='nf4')
       ),
       lora=dict(
           type=LoraConfig,
           r=64,
           lora_alpha=16,
           lora_dropout=0.1,
           bias='none',
           task_type='CAUSAL_LM'))

若期望进行全量参数训练,可做如下修改:

.. code:: diff

   #######################################################################
   #                      PART 2  Model & Tokenizer                      #
   #######################################################################
   model = dict(
       type=SupervisedFinetune,
       use_varlen_attn=use_varlen_attn,
       llm=dict(
           type=AutoModelForCausalLM.from_pretrained,
           pretrained_model_name_or_path=pretrained_model_name_or_path,
           trust_remote_code=True,
           torch_dtype=torch.float16,
   -       quantization_config=dict(
   -           type=BitsAndBytesConfig,
   -           load_in_4bit=True,
   -           load_in_8bit=False,
   -           llm_int8_threshold=6.0,
   -           llm_int8_has_fp16_weight=False,
   -           bnb_4bit_compute_dtype=torch.float16,
   -           bnb_4bit_use_double_quant=True,
   -           bnb_4bit_quant_type='nf4')
       ),
   -   lora=dict(
   -       type=LoraConfig,
   -       r=64,
   -       lora_alpha=16,
   -       lora_dropout=0.1,
   -       bias='none',
   -       task_type='CAUSAL_LM')
   )

步骤 3: 开始训练
-----------------------------

.. code:: console

   $ NPROC_PER_NODE=8 xtuner train internlm2_chat_7b_qlora_custom_sft_e1_copy.py --deepspeed deepspeed_zero1

.. tip::
   训练日志及 checkpoint 将默认保存在 ``./work_dirs/``\ ,可以通过命令
   ``xtuner train --work-dir ${SAVE_PATH}`` 指定保存路径。

步骤 4: 模型转换
------------------------------

模型训练后会自动保存成 PTH 模型(例如 ``iter_2000.pth``\ ,如果使用了
DeepSpeed,则将会是一个文件夹),我们需要利用
``xtuner convert pth_to_hf`` 将其转换为 HuggingFace
模型,以便于后续使用。具体命令为:

.. code:: bash

   xtuner convert pth_to_hf ${FINETUNE_CFG} ${PTH_PATH} ${SAVE_PATH}
   # 例如:xtuner convert pth_to_hf internlm2_chat_7b_qlora_custom_sft_e1_copy.py ./iter_2000.pth ./iter_2000_hf

对话
=================

用户可以利用 ``xtuner chat`` 实现与微调后的模型对话。如果使用的是 Lora
或 QLora 算法:

.. code:: console

   $ xtuner chat ${NAME_OR_PATH_TO_LLM} --adapter {NAME_OR_PATH_TO_ADAPTER} --prompt-template ${PROMPT_TEMPLATE} [optional arguments]
   $ # 例如:xtuner chat internlm/internlm2-7b --adapter ./iter_2000_hf --prompt-template internlm2_chat


如果进行的是全量参数的微调:

.. code:: console

   $ xtuner chat ${PATH_TO_LLM} --prompt-template ${PROMPT_TEMPLATE} [optional arguments]
   $ # 例如:xtuner chat ./iter_2000_hf --prompt-template internlm2_chat

.. note::

   其中 ${PROMPT_TEMPLATE} 表示模型的对话模板,需要与训练用的 config 中的
   ``prompt_template`` 字段保持一致,例如
   ``internlm2_chat_7b_qlora_custom_sft_e1_copy.py`` 中的设置为:

   .. code:: python

      prompt_template = PROMPT_TEMPLATE.internlm2_chat

.. _模型合并可选):

模型合并(可选)
======================

如果您使用了 LoRA / QLoRA 微调,则模型转换后将得到 adapter
参数,而并不包含原 LLM
参数。如果您期望获得合并后的模型权重(例如用于后续评测),那么可以利用
``xtuner convert merge`` :

.. code:: console

   $ xtuner convert merge ${LLM} ${LLM_ADAPTER} ${SAVE_PATH}

.. tip::

   模型合并后,就得到了一个可以通过 ``AutoModelForCausalLM.from_pretrained`` 直接加载的模型,可以直接在各种下游工具中直接使用

评测
======================

推荐使用一站式平台
`OpenCompass <https://github.com/InternLM/opencompass>`__
来评测大语言模型,其目前已涵盖 50+ 数据集的约 30 万条题目。