如何从零开始训练一个语言模型

如何从零开始训练一个语言模型

RLHF SFT Pretrain SFT Data Pretrain Data SSL SFT Reward Model Human Align Dataset LLM SFT Dataset Base Model Language Model SSL Dataset GPT4指令数据 BELLE指令数据 X X指令数据集 维基百科 百度百科 X X百科 任何开源文本 Pretrain Process SFT Process

本文主要三个方面介绍语言模型的训练过程,主要包括:数据集介绍(包含预训练数据和微调数据),数据的预处理,模型训练和微调,但不涉及对齐阶段(RLHF),对齐需要对齐的数据,也需要不同的预处理方式,对齐的目的是构建一个可以与人类价值观保持一致的LLM,减少虚假有害信息的输出。

数据集

Pretrain Data:

预训练数据主要来自从互联网上收集的文本数据,token的规模大概在trillion级别,整体质量偏低。

SFT Data:

SFT(Supervised Fine-Tuning)数据一般由指令,输入,响应组成,指令和输入一起组成prompt,作为模型的输入,响应作为标签。这类数据对质量要求较高,一般由人工构造,也可由GPT4生成。

预处理

分词Tokenizer:把文本序列转为为token序列。

Pretrain Process:

预训练是通过自监督(SSL)的方式训练,也就是预测下个词(token),数据处理方式如下:

python 复制代码
def __getitem__(self, index: int):
    sample = self.data[index]
    X=np.array(sample[:-1]).astype(np.int64)
    Y=np.array(sample[1:]).astype(np.int64)
    return torch.from_numpy(X),torch.from_numpy(Y)

例如:文本分词后:sample = [1, 2, 3, 4, 5, 6]

  • x : 1, 2, 3, 4, 5
  • y : 2, 3, 4, 5, 6
SFT Process:

SFT(Supervised Fine-Tuning)阶段喂给模型的示例遵循(prompt、response)的格式,prompt包含:指令+输入,也称为指令数据,数据处理方式如下:

  • 拼接指令和输入
python 复制代码
# 拼接指令和输入字符
q_lst, a_lst = [],[]
for per in data:
    q=per['instruction']
    i=per['input']
    a=per['output']
    q=q+i
    q_lst.append(q)
    a_lst.append(a)
df=pd.DataFrame(columns=['prompt','answer'])
df['prompt']=q_lst
df['answer']=a_lst
  • 拼接提示和响应,并添加分割符,同时生成掩码,掩码的作用是在计算loss时屏蔽prompt部分。
python 复制代码
def __getitem__(self, index: int):
    sample = self.df.iloc[index]
    # 分词tokenizer
    prompt = self.tokenizer.encode(sample['prompt'],add_special_tokens=False)
    answer = self.tokenizer.encode(sample['answer'],add_special_tokens=False)
    # 截断最大长度
    if len(prompt) > self.prompt_max_len:
        prompt = prompt[:self.prompt_max_len-2]
    if len(answer) > self.answer_max_len:
        answer = answer[:self.answer_max_len-2]
    # 拼接提示和响应,同时添加特殊token,标识提示和响应结束
    inputs = prompt+[self.bos]+answer+[self.eos]
    # 掩码长度=提示长度
    prompt_length = inputs.index(self.bos)
    mask_position = prompt_length - 1
    # 填充至最大长度
    pad_len = self.max_length - len(inputs)
    inputs = inputs + [self.pad] * pad_len
    if pad_len==0:
        # 屏蔽提示和填充位置
        loss_mask = [0]*prompt_length+[1]*(len(inputs[mask_position+1:]))
    else:
        loss_mask = [0]*prompt_length+[1]*(len(inputs[mask_position+1:-pad_len])) + [0]*pad_len
    
    inputs = np.array(inputs)
    X=np.array(inputs[:-1]).astype(np.int64)
    Y=np.array(inputs[1:]).astype(np.int64)
    loss_mask=np.array(loss_mask[:-1])
    return torch.from_numpy(X),torch.from_numpy(Y),torch.from_numpy(loss_mask)

例如:bos : 8, eos : 16, pad : 0,max_length = 16

inputs = prompt + [bos] + answer + [eos] = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12, 13, 14, 15, 16],

  • pad_len = 0:

  • prompt = [1, 2, 3, 4, 5, 6, 7]

  • answer = [9, 10, 11, 12, 13, 14, 15]

  • inputs = prompt + [bos] + answer + [eos] = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12, 13, 14, 15, 16]

    • x = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
    • y = [2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]
    • mask = [0, 0, 0, 0, 0, 0, 1 , 1, 1, 1, 1, 1, 1, 1, 1]
  • pad_len > 0:

  • prompt = [1, 2, 3, 4, 5, 6, 7]

  • answer = [9, 10, 11, 12, 13]

  • inputs = prompt + [bos] + answer + [eos] + [pad]*2 = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12, 13, 16, 0, 0]

    • x = [1, 2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12, 13, 16, 0, 0]
    • y = [2, 3, 4, 5, 6, 7, 8 , 9, 10, 11, 12, 13, 16, 0, 0]
    • mask = [0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0]

预训练阶段

预训练阶段采用标准的语言模型建模来最大化目标函数:

L p r e t r a i n ( X ) = ∑ i l o g P ( x i ∣ x i − k , . . . , x i − 1 ; Θ ) L_{pretrain}(\mathcal{X}) = \sum_i logP(x_i|x_{i-k},...,x_{i-1};\mathcal{\Theta}) Lpretrain(X)=i∑logP(xi∣xi−k,...,xi−1;Θ)

  • x = x 1 , . . . , x n \mathcal{x} = {x_1, ..., x_n} x=x1,...,xn :语料

  • k k k : 上下文长度

  • P P P : 条件概率由参数为 Θ \Theta Θ的神经网络模型建模

神经网络模型(包含多个transformer模块),模型输入经过分词后(tokenzier)后的token序列,首先经过嵌入层,然后经过transformer_block,最后经过输出层输出token概率分布。

h 0 = X W e + W p h_0 = XW_e + W_p h0=XWe+Wp

h l = t r a n s f o r m e r b l o c k ( h l − 1 ) , ∀ i ∈ [ 1 , n ] h_l = transformer_{block}(h_{l-1}), \forall i \in [1,n] hl=transformerblock(hl−1),∀i∈[1,n]

P ( u ) = s o f t m a x ( h n W e T ) P(u) = softmax(h_nW_e^T) P(u)=softmax(hnWeT)

  • W e W_e We : 嵌入矩阵
  • W p W_p Wp : 位置嵌入矩阵

微调阶段

微调阶段的数据前面已经提过,由3部分组成: X = { X i n s t r u c t i o n , X i n p u t , X a n s w e r } \mathcal{X} = \{X_{instruction} , X_{input},X_{answer}\} X={Xinstruction,Xinput,Xanswer}

经过预处理后: X = X i n s t r u c t i o n + X i n p u t + b o s + X a n s w e r + e o s \mathcal{X} = X_{instruction}+X_{input}+bos+X_{answer}+eos X=Xinstruction+Xinput+bos+Xanswer+eos

在微调阶段,模型结构不变,目标改变为:

L s f t ( X a n s w e r ) = ∑ i = l o c a l ( b o s ) l o c a l ( e o s ) l o g P ( x i ∣ x i − k , . . . , x i − 1 ; Θ ) L_{sft}(\mathcal{X_{answer}}) = \sum_{i=local(bos)}^{local(eos)} logP(x_i|x_{i-k},...,x_{i-1};\mathcal{\Theta}) Lsft(Xanswer)=i=local(bos)∑local(eos)logP(xi∣xi−k,...,xi−1;Θ)

在微调阶段只关注answer部分token序列的联合概率分布最大化。

经过SFT(Supervised Fine-Tuning)阶段,通过给模型展示如何正确地响应不同的提示(指令)(例如问答,摘要,翻译等)的示例,模型会学会模仿示例数据中的响应行为,学会问答、翻译、摘要等能力。指令微调优势在于,对于任何特定任务的专用模型,只需要在通用大模型的基础上通过特定任务的指令数据进行微调,就可以解锁LLM在特定任务上的能力,不在需要从头去构建专用的小模型。

相关推荐
飞哥数智坊2 小时前
AI编程实战:Cursor+Claude4助力15分钟完成大屏开发
人工智能·claude·cursor
Kier6 小时前
基于YOLO实现一个智能条码识别
人工智能·python·ai编程
我是王大你是谁6 小时前
SmolVLA:一种用于经济实惠和高效的机器人视觉-语言-动作模型
人工智能·llm
MarkGosling6 小时前
【语音合成】B 站开源 IndexTTS :声音克隆,吊打真人发音,断句精准度 98%
人工智能·python
数据智能老司机6 小时前
AI产品开发的艺术——搜索与检索增强生成
人工智能·产品经理·产品
机器之心6 小时前
逐个token太慢!大模型原生并行出token,CMU、英伟达新作Multiverse
人工智能·llm
AI大模型技术社7 小时前
⚙️企业级Transformer优化:混合精度×梯度裁剪×权重初始化最佳实践
人工智能·llm
机器之心7 小时前
首个转型AI公司的新势力,在全球AI顶会展示下一代自动驾驶模型
人工智能
机器之心7 小时前
同一天开源新模型,一推理一编程,MiniMax和月之暗面开卷了
人工智能
腾讯云开发者7 小时前
腾讯云TVP走进青岛啤酒,解码数字化驱动智慧零售增长引擎
人工智能