nlp面试重点

深度学习基本原理:梯度下降公式,将损失函数越来越小,最终预测值和实际值误差比较小。

交叉熵:-p(x)logq(x),p(x)是one-hot形式。如果不使用softmax计算交叉熵,是不行的。损失函数可能会非常大,或者预测的概率是[-0.1,0.3,0.5],log不接收负值。pytorch默认给你加softmax。

如果softmax改成sigmoid也不行,如sigmoid过完以后,[0.9,0.99,0.99],计算以后0.99的影响会被忽略,得到的结果是不正确。

adam和sgd区别:adam会考虑之前的计算,自动调节学习率,在通过上一步计算出来的梯度(放在m_t-1里)和梯度平方(放在v_t-1里)控制学习率的调节,让训练可以比较平稳又可以加速。

transformer和rnn(或lstm)区别:长距离依赖问题,rnn越远影响越弱。

lstm有四个参数,输入门,输出门,记忆门,

调参经验:batch_size,max_length,学习率增大batch_size应该怎么调整,加数据量,打乱数据顺序。

训练词向量:将one-hot乘以一个矩阵进行训练,cbow多个词预测中间一个词,skip-gram一个词预测周围词,共现矩阵,keans聚类。

也可以参考损失函数,用到的损失函数有余弦值、三元组等。用余弦值训练的话,两个相似的词向量,cos值接近1。用余弦值损失函数时,将相似的两个词作为正样本,如你好和您好是输入,真实输出是1,负样本真实输出是-1,来训练模型参数,最后得到词向量数据库。

语言模型:PPL评价语言模型,不能成句也可能PPL比较低,所以PPL评价不太好。

传统方法和预训练方法:

Transformer里的dk是hidden_size/ head_num,是实验结果。

数据稀疏问题:标注更多数据,大模型生成更多数据,换模型,调整阈值,召回率换准确率。重新定义类别,减少类别,增加规则弥补。

文本匹配:表示型,直接计算,交互型,速度慢,更准确。文本向量化:文本和句子分别过一个模型,优化模型,使文本和句子相似,如果是句子和句子可以用相同模型,最后得到的参数作为向量数据库。表示型:一个句子直接向量化,交互型:必须进入两个句子算得分。

向量数据库查找:KD树。

序列标注:crf会用维特比解码,bean search在大模型里使用,n * D *B,复杂度小很多

ner:加标点任务。

序列标注重复:多个模型,生成式任务,输出两个标记。

自回归语言模型:下三角mask,预测下一个词。

teacher-forcing,使用真实标签预测,提高效率。

采样策略:topk,topp,bean-size,temperature(大模型)。

bert变体:albert跨层参数共享,嵌入参数化进行因式分解,nsp任务(相邻句子就是正样本)改成sop任务,sop任务提高训练难度。roberta(动态mask,去掉nsp任务),spanbert:mask掉多个连续的

stf用于大模型问答,相当于encoder-decoder,bert是encoder,通过mask可以实现decoder自回归语言模型(文本生成)。

旋转位置编码:解决词嵌入位置编码长度外推性,找到映射f,满足

< f_q(x_m,m),  f_k(x_n,n)> = g(x_m, x_n, m - n)。初始条件m = 0, f(q,0) = q。

https://zhuanlan.zhihu.com/p/580739696

 qm(1),qm(2)是原来的Wq和xm相乘的局部结果,即xm.dot(Wq)

余弦值位置编码中:固定i,则pos的改变会使位置编码有周期性,固定pos修改i,则一开始周期较小,容易捕捉相邻字的差别,随着i变大,周期越来越长

moe专家模型(一个MLP层就是一个专家),deepseek使用共享专家。deepseek在qkv计算的过程中,q和k拆成两部分,其中一部分注入rope位置信息,另一部分不处理。减少运算量。deepseek还使用了GRPO,在训练奖励模型RM时,奖励指标是硬规则,即要么是要么不是,而且每次输入多个输入输出,一次性训练。

LLM模型先进行sft训练,如果是PPO的话,就还需要训练一个奖励模型即RM模型。然后第三步进行RL强化训练,这里将sft训练得到的模型叫做reference模型,然后复制出来模型,叫做RL模型,或者演员模型,这个演员模型就是最后训练出来的模型,那么损失函数的构成就是RM模型减去演员模型和reference模型组成的KL散度。整个过程可以理解成是对stf训练进行微调,即保证演员模型不会和stf偏离的太远,又让奖励模型得分尽可能高,这样符合人类偏好,所以PPO叫近端策略优化,也可以看做人类偏好优化。

bbpe:解决多语种,不用统计词,既不是中文词表也不是英文词表,具有跨语种的优点,大语言模型用的词表就是采用bbpe。bpe是基于字符,bbpe是转化为unicode编码,然后合并,是基于字节的。

知识图谱:方法一是基于模板+文本匹配,类似于faq库问答,相似度可以用bm25,jaccard距离,或者余弦距离。方法二:拆解成多个分类或抽取问题处理。方法三:利用大语言LLM的生成能力

推荐系统:基于相似用户、相似物品的推荐。

import torch
import math
import numpy as np
from transformers import BertModel

'''
通过手动矩阵运算实现Bert结构
模型文件下载 https://huggingface.co/models
'''

bert = BertModel.from_pretrained(r"/Users/mac/Documents/bert-base-chinese", return_dict=False)
# print(bert)
state_dict = bert.state_dict()
bert.eval()
x = np.array([2450, 15486, 102, 2110]) #假想成4个字的句子
torch_x = torch.LongTensor([x])
seqence_output, pooler_output = bert(torch_x)
print(seqence_output.shape, pooler_output.shape)
# torch.Size([1, 4, 768]) torch.Size([1, 768])

print(bert.state_dict().keys())  #查看所有的权值矩阵名称

#softmax归一化
def softmax(x):
    return np.exp(x)/np.sum(np.exp(x), axis=-1, keepdims=True)

#gelu激活函数
def gelu(x):
    return 0.5 * x * (1 + np.tanh(math.sqrt(2 / math.pi) * (x + 0.044715 * np.power(x, 3))))

class DiyBert:
    #将预训练好的整个权重字典输入进来
    def __init__(self, state_dict):
        self.num_attention_heads = 12
        self.hidden_size = 768
        self.num_layers = 1 #注意这里的层数要跟预训练config.json文件中的模型层数一致
        self.load_weights(state_dict)

    def load_weights(self, state_dict):
        self.word_embeddings = state_dict["embeddings.word_embeddings.weight"].numpy()
        self.position_embeddings = state_dict["embeddings.position_embeddings.weight"].numpy()
        self.token_type_embeddings = state_dict["embeddings.token_type_embeddings.weight"].numpy()
        self.embeddings_layer_norm_weight = state_dict["embeddings.LayerNorm.weight"].numpy()
        self.embeddings_layer_norm_bias = state_dict["embeddings.LayerNorm.bias"].numpy()
        self.transformer_weights = []
        #transformer部分,有多层
        for i in range(self.num_layers):
            q_w = state_dict["encoder.layer.%d.attention.self.query.weight" % i].numpy()
            q_b = state_dict["encoder.layer.%d.attention.self.query.bias" % i].numpy()
            k_w = state_dict["encoder.layer.%d.attention.self.key.weight" % i].numpy()
            k_b = state_dict["encoder.layer.%d.attention.self.key.bias" % i].numpy()
            v_w = state_dict["encoder.layer.%d.attention.self.value.weight" % i].numpy()
            v_b = state_dict["encoder.layer.%d.attention.self.value.bias" % i].numpy()
            attention_output_weight = state_dict["encoder.layer.%d.attention.output.dense.weight" % i].numpy()
            attention_output_bias = state_dict["encoder.layer.%d.attention.output.dense.bias" % i].numpy()
            attention_layer_norm_w = state_dict["encoder.layer.%d.attention.output.LayerNorm.weight" % i].numpy() # 做残差时的线性层
            attention_layer_norm_b = state_dict["encoder.layer.%d.attention.output.LayerNorm.bias" % i].numpy()
            intermediate_weight = state_dict["encoder.layer.%d.intermediate.dense.weight" % i].numpy() # 前馈网络的处理
            intermediate_bias = state_dict["encoder.layer.%d.intermediate.dense.bias" % i].numpy() # 前馈网络的处理
            output_weight = state_dict["encoder.layer.%d.output.dense.weight" % i].numpy() # 前馈网络的处理
            output_bias = state_dict["encoder.layer.%d.output.dense.bias" % i].numpy() # 前馈网络的处理
            ff_layer_norm_w = state_dict["encoder.layer.%d.output.LayerNorm.weight" % i].numpy()
            ff_layer_norm_b = state_dict["encoder.layer.%d.output.LayerNorm.bias" % i].numpy()
            self.transformer_weights.append([q_w, q_b, k_w, k_b, v_w, v_b, attention_output_weight, attention_output_bias,
                                             attention_layer_norm_w, attention_layer_norm_b, intermediate_weight, intermediate_bias,
                                             output_weight, output_bias, ff_layer_norm_w, ff_layer_norm_b])
        #pooler层
        self.pooler_dense_weight = state_dict["pooler.dense.weight"].numpy()
        self.pooler_dense_bias = state_dict["pooler.dense.bias"].numpy()

    #bert embedding,使用3层叠加,在经过一个Layer norm层
    def embedding_forward(self, x):
        # x.shape = [max_len]
        we = self.get_embedding(self.word_embeddings,x) # shpae: [max_len, hidden_size]
        # position embeding的输入 [0, 1, 2, 3]
        pe = self.get_embedding(self.position_embeddings, np.array(list(range(len(x))))) # shpae: [max_len, hidden_size]
        # token type embedding,单输入的情况下为[0, 0, 0, 0]
        te = self.get_embedding(self.token_type_embeddings, np.array([0] * len(x))) # shpae: [max_len, hidden_size]
        embedding = we + pe + te
        # 加和后有一个归一化层
        embedding = self.layer_norm(embedding, self.embeddings_layer_norm_weight, self.embeddings_layer_norm_bias)
        return embedding

    #embedding层实际上相当于按index索引,或理解为onehot输入乘以embedding矩阵
    def get_embedding(self, embedding_matrix, x):
        return np.array([embedding_matrix[index] for index in x]) #不是从0开始的,是每个词对应的位置
    
   #归一化层
    def layer_norm(self, x, w, b):
        x = (x - np.mean(x, axis=1, keepdims=True)) / np.std(x, axis=1, keepdims=True)
        x = x * w + b
        return x
    
    #执行全部的transformer层计算
    def all_transformer_layer_forward(self, x):
        for i in range(self.num_layers):
            x = self.single_transformer_layer_forward(x, i)
        return x
    
    #执行单层transformer层计算
    def single_transformer_layer_forward(self, x, layer_index):
        weights = self.transformer_weights[layer_index]
        #取出该层的参数,在实际中,这些参数都是随机初始化,之后进行预训练
        q_w, q_b, \
        k_w, k_b, \
        v_w, v_b, \
        attention_output_weight, attention_output_bias, \
        attention_layer_norm_w, attention_layer_norm_b, \
        intermediate_weight, intermediate_bias, \
        output_weight, output_bias, \
        ff_layer_norm_w, ff_layer_norm_b = weights
        #self attention层
        attention_output = self.self_attention(x,
                               q_w, q_b,
                               k_w, k_b,
                               v_w, v_b,
                               attention_output_weight, attention_output_bias,
                                self.num_attention_heads,
                                self.hidden_size)
        #bn层,并使用了残差机制
        x = self.layer_norm(x + attention_output,attention_layer_norm_w, attention_layer_norm_b)
        #feed forward层
        feed_forward_x = self.feed_forward(x, intermediate_weight, intermediate_bias, output_weight, output_bias)
        #bn层,并使用了残差机制
        x = self.layer_norm(x + feed_forward_x, ff_layer_norm_w, ff_layer_norm_b) #最后一次归一化+前馈网络
        return x
    

    def self_attention(self, x, q_w, q_b, k_w, k_b, v_w, v_b,attention_output_weight,
                        attention_output_bias,num_attention_heads,hidden_size):
            # x.shape = max_len * hidden_size
            # q_w, k_w, v_w  shape = hidden_size * hidden_size
            # q_b, k_b, v_b  shape = hidden_size
            q = np.dot(x, q_w.T) + q_b # shape: [max_len, hidden_size]
            k = np.dot(x, k_w.T) + k_b # shape: [max_len, hidden_size]
            v = np.dot(x, v_w.T) + v_b # shape: [max_len, hidden_size]
            attention_head_size = int(hidden_size / num_attention_heads)
            # q.shape = num_attention_heads, max_len, attention_head_size
            q = self.transpose_for_scores(q, attention_head_size, num_attention_heads)
            # k.shape = num_attention_heads, max_len, attention_head_size
            k = self.transpose_for_scores(k, attention_head_size, num_attention_heads)
            # v.shape = num_attention_heads, max_len, attention_head_size
            v = self.transpose_for_scores(v, attention_head_size, num_attention_heads)
            # qk.shape = num_attention_heads, max_len, max_len
            qk = np.matmul(q, k.swapaxes(1,2))
            qk /= np.sqrt(attention_head_size)
            qk = softmax(qk)
            # qkv.shape = num_attention_heads, max_len, attention_head_size
            qkv = np.matmul(qk, v)
             # qkv.shape = max_len, hidden_size
            qkv = qkv.swapaxes(0, 1).reshape(-1, hidden_size)
            # attention.shape = max_len, hidden_size
            attention = np.dot(qkv, attention_output_weight.T) + attention_output_bias
            return attention

    # 多头机制
    def transpose_for_scores(self, x, attention_head_size, num_attention_heads):
    # hidden_size = 768  num_attent_heads = 12 attention_head_size = 64
        max_len, hidden_size = x.shape
        x = x.reshape(max_len, num_attention_heads, attention_head_size)
        # swapaxes两轴相转
        x = x.swapaxes(1, 0) # output shape = [num_attention_heads, max_len, attention_head_size]
        return x
    
    #前馈网络的计算
    def feed_forward(self,
                     x, 
                     intermediate_weight, # intermediate_size, hidden_size
                     intermediate_bias, # intermediate_size
                     output_weight, # hidden_size, intermediate_size
                     output_bias # hidden_size
                     ):
        # output shpae: [max_len, intermediate_size]
        x = np.dot(x, intermediate_weight.T) + intermediate_bias
        x = gelu(x)
        # output shpae: [max_len, hidden_size]
        x = np.dot(x, output_weight.T) + output_bias
        return x # 经过feed Forward,结构还是V * hidden_size(768)
    
    #链接[cls] token的输出层
    def pooler_output_layer(self, x):
        x = np.dot(x, self.pooler_dense_weight.T) + self.pooler_dense_bias
        x = np.tanh(x)
        return x

    def forward(self, x):
        x =self.embedding_forward(x)
        sequence_output = self.all_transformer_layer_forward(x)
        pooler_output = self.pooler_output_layer(sequence_output[0])
        return sequence_output, pooler_output


#测试
db = DiyBert(state_dict)
diy_sequence_output, diy_pooler_output = db.forward(x)
#torch
torch_sequence_output, torch_pooler_output = bert(torch_x)
 
print(diy_sequence_output)
print(torch_sequence_output)
 
# print(diy_pooler_output)
# print(torch_pooler_output)
                        

T5:encode-decode模型,

bert:

 

ppo中,主要训练演员(actor)模型一开始和sft模型相同,以及评论家(critic)模型一开始和RM奖励模型相同,演员模型负责生成动作,核心目标是最大化累积奖励。

收集的数据包括状态、动作、动作概率和奖励等信息。使用广义优势函数GAE来计算优势函数。

重要性采样比:

重要性采样比和GAE构成目标损失函数:

利用梯度上升法最大化目标函数,更新演员模型参数θ。 

5.10面试题:

multi-head有什么优点,是否冗余?

dpo和RLHF如何解决模型幻觉问题?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

heine162

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值