(1)仍然不能很好地捕捉长距离的词依赖。2-gram假设一个词只和它前面的一个词相关,但在实际的语言中,一个词可能和它前面更远的词相关。例如,在"The cat, which already had its dinner, is sleeping on the sofa"这个句子中,"is sleeping"和"cat"有关,但它们之间隔了好几个词。
这里的W表示一条语料,N表示这条语料包含的token的个数。就是模型生成这个句子的概率。之所以要施加(-1/N)次幂,是因为要考虑语料长度的影响。如果一个句子越长,这个句子出现的概率可能会越低(比如“你好”和“你是我心中最美的云彩”这两句话,前者出现的概率很高)。开 N 次方,是把整段文字的概率换算成每个 token 的尺度;再取倒数,就是让模型越难猜到的文本,困惑度越高。
fromdatasetsimportDatasetfromtransformersimportAutoTokenizer,AutoModelForCausalLM,DataCollatorForSeq2Seq,TrainingArguments,Trainerdevice="cuda"model=AutoModelForCausalLM.from_pretrained("Langboat/bloom-1b4-zh",cache_dir='/home/notebook/data/group/huggingface/Bloom-models-dirs').to(device)tokenizer=AutoTokenizer.from_pretrained("Langboat/bloom-1b4-zh",cache_dir='/home/notebook/data/group/huggingface/Bloom-models-dirs')fromdatasetsimportload_datasettest=load_dataset("wikitext","wikitext-2-raw-v1",split="test")encodings=tokenizer("\n\n".join(test["text"]),return_tensors="pt")importtorchfromtqdmimporttqdmmax_length=model.config.seq_lengthstride=512seq_len=encodings.input_ids.size(1)total_nll=0.0total_tokens=0prev_end_loc=0forbegin_locintqdm(range(0,seq_len,stride)):end_loc=min(begin_loc+max_length,seq_len)trg_len=end_loc-prev_end_loc# may be different from stride on last loopprint('begin_loc:'+str(begin_loc)+' end_loc:'+str(end_loc)+' trg_len:'+str(trg_len))#第一次是0-4096,第二次是512-4608,第三次是1024-5120,trg_len是512input_ids=encodings.input_ids[:,begin_loc:end_loc].to(device)target_ids=input_ids.clone()print(target_ids.shape)#torch.Size([1, 4096])target_ids[:,:-trg_len]=-100withtorch.no_grad():outputs=model(input_ids,labels=target_ids)# 模型会丢掉窗口的第一个标签,再跳过标成 -100 的位置。n_tokens=(target_ids[:,1:]!=-100).sum().item()ifn_tokens>0:total_nll+=outputs.loss.item()*n_tokenstotal_tokens+=n_tokensprev_end_loc=end_locifend_loc==seq_len:breakppl=torch.exp(torch.tensor(total_nll/total_tokens,dtype=torch.float64))print(ppl)
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer
device = "cuda"
model = AutoModelForCausalLM.from_pretrained("Langboat/bloom-1b4-zh", cache_dir='/home/notebook/data/group/huggingface/Bloom-models-dirs').to(device)
tokenizer = AutoTokenizer.from_pretrained("Langboat/bloom-1b4-zh", cache_dir='/home/notebook/data/group/huggingface/Bloom-models-dirs')
text = '<s>May I know what is your name'
encodings = tokenizer(text, return_tensors="pt")
device = "cuda"
input_ids = encodings['input_ids'].to(device)
target_ids = input_ids.clone().to(device)
print(input_ids.shape)
print(target_ids.shape)
print(tokenizer.decode(input_ids[0]))
import torch
with torch.no_grad():
outputs = model(input_ids, labels=target_ids)
a = outputs[1]
print(a.shape)
a = a.squeeze(0) # 删除第一维度,输出形状将变为torch.Size([50, 46145])
indices = torch.argmax(a, dim=1) # 在词汇表维度上找到概率最大的索引
tokenizer.decode(indices)
在这个实验中,我把'<s>May I know what is your name'送到模型里。这句话的token数一共有9个,模型的输出是torch.Size([1, 9, 46145])的矩阵。如果我把每个分量概率最大的token拿出来,发现模型的输出是', I askno what you the name?'。
这似乎有些奇怪:怎么把每一行分数最高的 token 拼起来,没得到原来的句子?
因为每一行都在回答一个不同的问题:给定前面这几个词,下一个词最可能是什么?
比如看到 May I,模型如果觉得后面最可能接 ask,这也很正常。可原文接的是 know,算困惑度就要看模型给 know 打了多少分。
(当然,一般情况下,只有最后一个token才有意义,这里最后一个token的预测结果是问号,的确是符合要求的,从这个意义来说,这个模型是正常的。因为'<s>May I know what is your name'的后面一般是接一个问号)
如果我换一个模型,会不会存在同样的情况呢?
我换成了7b的intern2-chat-7b模型。
当text = '<s>May I know what is your name'时,模型的输出是:
TheThe ask the is the favorite?
当text = '<s>May I know what is your'时,模型的输出是:
TheThe ask the is the favorite
如果从模型最后一个token的角度来看,两者的输出并无不妥。 '<s>May I know what is your name'之后,模型认为的下一个词是问号。 '<s>May I know what is your'之后,模型认为下一个词是favorite,也能说得过去。
当text = '<s>May I know what is your name'时,模型的输出是:
<< ask how is the opinion?
当text = '<s>May I know what is your'时,模型的输出是:
<< ask how is the opinion
换了模型,逐行取最高分再拼起来,照样不一定是原句。
第二个实验,我想看看,如果把input_ids截断,那么模型的输出是不是也是截断后的结果?
我把text从'<s>May I know what is your name'改为 '<s>May I know what is your',仿照上面的步骤,得到最终的输出是', I askno what you the name',发现inputs_ids经过截断后,产生的输出也是单纯的截断。这一点是比较符合直觉的。(为什么?因为transformer中自注意力的机制中,对于q1,q2,...qn序列,qk只和k之前的值有关,比如q3,只和第0/1/2个token有关,与第2个以后的token都没有关系,详情见kvcache相关的内容)
text = '<s>May I know what is your name'
encodings = tokenizer(text, return_tensors="pt")
device = "cuda"
input_ids = encodings['input_ids'].view(1,-1).to(device)
target_ids = input_ids.clone().to(device)
print(input_ids.shape)
print(target_ids.shape)
import torch
with torch.no_grad():
outputs = model(input_ids, labels=target_ids)
a = outputs[1]
print(a.shape)
text = '<s>May I know what is your'
encodings = tokenizer(text, return_tensors="pt")
device = "cuda"
input_ids = encodings['input_ids'].view(1,-1).to(device)
target_ids = input_ids.clone().to(device)
print(input_ids.shape)
print(target_ids.shape)
import torch
with torch.no_grad():
outputs = model(input_ids, labels=target_ids)
b = outputs[1]
print(b.shape)
print(torch.allclose(a[0,:8,:], b[0,:8,:], rtol=1e-03)) # 输出: True
发现两者的确是相等的。
注意,这里有一个细节,把texe从'<s>May I know what is your name'改为 '<s>May I know what is your',是否等价于单纯地截断,这一点需要验证。因为分词机制,单纯地在原始文本的后面删除词汇,并不等价于对应的input_ids中删除词汇。在本例中,经过验证,两者是等价的。
transformer的代码的思路是,第一次推理,将第0-4096个token送进模型里,然后计算loss得到。后面每个窗口也这么算。一个窗口算了多少个 token,它的平均 loss 就要乘回多少。再把这些损失加起来,除以计分的 token 总数,最后取指数。下面的 n 就是每个窗口实际计分的 token 数:
<|im_start|>system
You are ChatGPT, a large language model trained by OpenAI. Answer as concisely as possible.
Knowledge cutoff: 2021-09-01
Current date: 2023-03-01<|im_end|>
<|im_start|>user
How are you<|im_end|>
<|im_start|>assistant
I am doing well!<|im_end|>
<|im_start|>user
How are you now?<|im_end|>
可以看到有三种角色:system、user、assistant
system prompt是系统级提示词,该内容会在整个会话过程中持久地影响模型的回复,且相比于普通 Prompt 具有更高的重要性。我们一般设置 System Prompt 来对模型进行一些初始化设定,例如,我们可以在 System Prompt 中给模型设定我们希望它具备的人设如一个个人知识库助手等。System Prompt 一般在一个会话中仅有一个。在通过 System Prompt 设定好模型的人设或是初始设置后,我们可以通过 User Prompt 给出模型需要遵循的指令。
from datasets import Dataset
from transformers import AutoTokenizer, AutoModelForCausalLM, DataCollatorForSeq2Seq, TrainingArguments, Trainer
import os
加载intern模型(从hf下载,下载下来的模型需要从cache导入):
tokenizer = AutoTokenizer.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True, cache_dir='/home/notebook/data/group/huggingface/Intern-models-dirs')
model = AutoModelForCausalLM.from_pretrained("internlm/internlm-chat-7b", trust_remote_code=True, cache_dir='/home/notebook/data/group/huggingface/Intern-models-dirs').cuda()
或者加载intern2模型(从ms下载,下载下来的模型,直接传入下载路径即可):
tokenizer = AutoTokenizer.from_pretrained('/home/notebook/data/group/huggingface/Intern-models-dirs/Shanghai_AI_Laboratory/internlm2-chat-7b', device_map="auto", trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained('/home/notebook/data/group/huggingface/Intern-models-dirs/Shanghai_AI_Laboratory/internlm2-chat-7b', device_map="auto", trust_remote_code=True)
推理(多轮对话):
response, history = model.chat(tokenizer, "hello", history=[])
response, history = model.chat(tokenizer, "please provide three suggestions about time management", history=history)
"""We only support the following three scenarios:
1. Incremental pretraining dataset.
example['conversation'] = [
{
'input': '',
'output': '### Human: Can you write xxx'
}
]
2. Single-turn conversation dataset.
example['conversation'] = [
{
'input': 'Give three tips for staying healthy.',
'output': '1.Eat a balanced diet xxx'
}
]
3. Multi-turn conversation dataset.
example['conversation'] = [
{
'input': 'Give three tips for staying healthy.',
'output': '1.Eat a balanced diet xxx'
},
{
'input': 'Please expand on the second point.',
'output': 'Here is an expanded explanation of the xxx'
}
]
"""
model = AutoModelForCausalLM.from_pretrained("/home/notebook/code/personal/aigc/intern/xtuner-main/ft-oasst1/merged",
device_map="auto",trust_remote_code=True)
PROMPT_TEMPLATE = ConfigDict(
default=dict(
SYSTEM='<|System|>:{system}\n',
INSTRUCTION='<|User|>:{input}\n<|Bot|>:',
SEP='\n'),
zephyr=dict(
SYSTEM='<|system|>\n{system}\n',
INSTRUCTION='<|user|>\n{input}\n<|assistant|>\n',
SEP='\n'),
internlm_chat=dict(
SYSTEM='<|System|>:{system}\n',
INSTRUCTION='<|User|>:{input}<eoh>\n<|Bot|>:',
SUFFIX='<eoa>',
SUFFIX_AS_EOS=True,
SEP='\n',
STOP_WORDS=['<eoa>']),
internlm2_chat=dict(
SYSTEM='<|im_start|>system\n{system}<|im_end|>\n',
INSTRUCTION=('<|im_start|>user\n{input}<|im_end|>\n'
'<|im_start|>assistant\n'),
SUFFIX='<|im_end|>',
SUFFIX_AS_EOS=True,
SEP='\n',
STOP_WORDS=['<|im_end|>']),
moss_sft=dict(
SYSTEM='{system}\n',
INSTRUCTION='<|Human|>: {input}<eoh>\n',
SEP='\n',
STOP_WORDS=['<eoc>', '<eom>']),
llama2_chat=dict(
SYSTEM=(
'[INST] <<SYS>>\n You are a helpful, respectful and honest '
'assistant. Always answer as helpfully as possible, while being '
'safe. Your answers should not include any harmful, unethical, '
'racist, sexist, toxic, dangerous, or illegal content. Please '
'ensure that your responses are socially unbiased and positive in '
'nature.\n{system}\n<</SYS>>\n [/INST] '),
INSTRUCTION='[INST] {input} [/INST]',
SEP='\n'),
code_llama_chat=dict(
SYSTEM='{system}\n', INSTRUCTION='[INST] {input} [/INST]'),
chatglm2=dict(
SYSTEM='{system}\n',
INSTRUCTION='[Round {round}]\n\n问:{input}\n\n答:',
SEP='\n\n'),
chatglm3=dict(
SYSTEM='<|system|>\n{system}',
INSTRUCTION='<|user|>\n{input}<|assistant|>\n',
SEP='\n'),
qwen_chat=dict(
SYSTEM=('\n<|im_start|>system\n{system}<|im_end|>'),
INSTRUCTION=(
'\n<|im_start|>user\n{input}<|im_end|>\n<|im_start|>assistant\n'),
SUFFIX='<|im_end|>',
SUFFIX_AS_EOS=True,
SEP='\n',
STOP_WORDS=['<|im_end|>', '<|endoftext|>']),
baichuan_chat=dict(
SYSTEM='{system}\n',
INSTRUCTION='<reserved_102>{input}<reserved_103>',
SEP='\n'),
baichuan2_chat=dict(
SYSTEM='{system}\n',
INSTRUCTION='<reserved_106>{input}<reserved_107>',
SEP='\n'),
wizardlm=dict(
SYSTEM=('A chat between a curious user and an artificial '
'intelligence assistant. The assistant gives '
'helpful, detailed, and polite answers to the '
'user\'s questions. {system}\n '),
INSTRUCTION=('USER: {input} ASSISTANT:'),
SEP='\n'),
wizardcoder=dict(
SYSTEM=(
'Below is an instruction that describes a task. '
'Write a response that appropriately completes the request.\n\n'
'{system}\n '),
INSTRUCTION=('### Instruction:\n{input}\n\n### Response:'),
SEP='\n\n'),
vicuna=dict(
SYSTEM=('A chat between a curious user and an artificial '
'intelligence assistant. The assistant gives '
'helpful, detailed, and polite answers to the '
'user\'s questions. {system}\n '),
INSTRUCTION=('USER: {input} ASSISTANT:'),
SEP='\n'),
deepseek_coder=dict(
SYSTEM=('You are an AI programming assistant, utilizing '
'the DeepSeek Coder model, developed by DeepSeek'
'Company, and you only answer questions related '
'to computer science. For politically sensitive '
'questions, security and privacy issues, and '
'other non-computer science questions, you will '
'refuse to answer. {system}\n'),
INSTRUCTION=('### Instruction:\n{input}\n### Response:\n'),
SEP='\n'),
# TODO: deprecation, v0.2.0
deepseekcoder=dict(
SYSTEM=('You are an AI programming assistant, utilizing '
'the DeepSeek Coder model, developed by DeepSeek'
'Company, and you only answer questions related '
'to computer science. For politically sensitive '
'questions, security and privacy issues, and '
'other non-computer science questions, you will '
'refuse to answer. {system}\n'),
INSTRUCTION=('### Instruction:\n{input}\n### Response:\n'),
SEP='\n'),
deepseek_moe=dict(
SYSTEM=('[INST] {system} [/INST]\n'),
INSTRUCTION=('[INST] {input} [/INST]'),
SEP='\n'),
mistral=dict(
SYSTEM=('[INST] {system} [/INST]\n'),
INSTRUCTION=('[INST] {input} [/INST]'),
SEP='\n'),
mixtral=dict(
SYSTEM=('[INST] {system} [/INST]\n'),
INSTRUCTION=('[INST] {input} [/INST]'),
SEP='\n'),
)
细节8:关于loss
这是模型中计算loss的代码:
hidden_states = outputs[0]
logits = self.lm_head(hidden_states)
if labels is not None:
# Shift so that tokens < n predict n
shift_logits = logits[..., :-1, :].contiguous()
shift_labels = labels[..., 1:].contiguous()
# Flatten the tokens
loss_fct = CrossEntropyLoss()
shift_logits = shift_logits.view(-1, self.config.vocab_size)
shift_labels = shift_labels.view(-1)
# Enable model parallelism
shift_labels = shift_labels.to(shift_logits.device)
loss = loss_fct(shift_logits, shift_labels)
这里的配置是:"system": "You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions."
xtuner chat ./merged --system "You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions." --prompt-template internlm_chat
学习效果:
这个log显示在模型训练过程中。每隔500个iter,模型会推理一遍这个问题。
我用第一轮的结果去推理,发现幻觉很明显:
用第30轮的结果去推理,可以看到有些过拟合,但是至少说明学到了东西:
处理数据的细节
由于在本示例中,使用的是没有内置配置的数据集,因此需要进入源码探究下背后是怎么处理数据的。
首先,修改launch.json
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": [
{
"name": "Python: xtuner",
"type": "python",
"request": "launch",
// "module": "xtuner",
"program": "/opt/conda/envs/transformers2/bin/xtuner",
"console": "integratedTerminal",
"justMyCode": false,
"args": [
"train",
"internlm_chat_7b_qlora_medqa2019_e3.py",
],
"cwd": "/home/notebook/code/personal/aigc/intern/xtuner-main/ft-medqa/"
}
]
}
{'conversation': [{'input': 'where does fluorouracil come from', 'output': 'dailymed list of manufacturers', 'system': "You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions."}]}
" <s><|System|>:You are a professional, highly experienced doctor professor. You always provide accurate, comprehensive, and detailed answers based on the patients' questions.\n<|User|>:where does fluorouracil come from<eoh>\n<|Bot|>:dailymed list of manufacturers<eoa>\n"
classLlamaRMSNorm(nn.Module):def__init__(self,hidden_size,eps=1e-6):"""
LlamaRMSNorm is equivalent to T5LayerNorm
"""super().__init__()self.weight=nn.Parameter(torch.ones(hidden_size))self.variance_epsilon=epsdefforward(self,hidden_states):input_dtype=hidden_states.dtypehidden_states=hidden_states.to(torch.float32)variance=hidden_states.pow(2).mean(-1,keepdim=True)hidden_states=hidden_states*torch.rsqrt(variance+self.variance_epsilon)returnself.weight*hidden_states.to(input_dtype)
举个例子,当前hidden_states.shape=4*30*2048。在代码中,variance.shape 是 [4, 30, 1]。每条序列的每个 token 各算一个平方平均数,加上 eps,再开平方作分母。经过这一操作后,hidden_states的形状仍然保持为4 x 30 x 2048。经过了这一标准化处理,hidden_states的维度仍然保持不变,但其数值分布已经得到了调整和对齐,可以用来提高模型训练的稳定性和性能。
res = llamamodel(input_ids=input_ids, labels=input_ids)
以下是计算loss的源码:
# Shift so that tokens < n predict nshift_logits=logits[...,:-1,:].contiguous()#torch.Size([4, 29, 32000])shift_labels=labels[...,1:].contiguous()#torch.Size([4, 29])# Flatten the tokensloss_fct=CrossEntropyLoss()shift_logits=shift_logits.view(-1,self.config.vocab_size)#torch.Size([116, 32000])shift_labels=shift_labels.view(-1)# torch.Size([116])# Enable model parallelismshift_labels=shift_labels.to(shift_logits.device)loss=loss_fct(shift_logits,shift_labels)
importnumpyasnpimportmatplotlib.pyplotaspltfromscipy.statsimportnorm# Parameters: mean (mu) and standard deviation (sigma)mu,sigma=0,1# Generate some x values evenly over the range of the distributionx=np.linspace(mu-4*sigma,mu+4*sigma,1000)# Calculate the probability density function (pdf) for the normal distributionpdf=norm.pdf(x,mu,sigma)plt.figure(figsize=(10,6))plt.plot(x,pdf,label='Normal Distribution')# Calculate quantiles using the cumulative distribution function (CDF)quantiles=norm.ppf([i/8foriinrange(1,8)],mu,sigma)# Draw vertical lines at quantile positionsforquantileinquantiles:plt.axvline(quantile,color='r',linestyle='--')# Highlight regions between quantiles to show potential 'clamping' effectforiinrange(len(quantiles)-1):plt.fill_betweenx(pdf,quantiles[i],quantiles[i+1],color='y',alpha=0.5)# Highlight the first and last regionplt.fill_betweenx(pdf,mu-4*sigma,quantiles[0],color='y',alpha=0.5)plt.fill_betweenx(pdf,quantiles[-1],mu+4*sigma,color='y',alpha=0.5)# Annotate quantiles on the plotfori,quantileinenumerate(quantiles):plt.text(quantile,0.02,f'{(i+1)*12.5}%',ha='center',va='bottom',color='black')plt.title('Normal Distribution with Equal Area Quantiles')plt.legend()plt.xlabel('Values')plt.ylabel('Probability Density')plt.grid(True)plt.show()
3.最大值减去最小值的分布
importnumpyasnpimportmatplotlib.pyplotasplt# 设置随机种子,用于结果复现np.random.seed(0)# 指定生成的数据组数num_samples=100000# 创建一个空列表来存储每组数值的最大值和最小值之差max_min_diffs=[]# 对于每组64个标准正态分布的随机数,找到最大值和最小值之差,并添加到列表中for_inrange(num_samples):values=np.random.randn(64)max_val=np.max(values)min_val=np.min(values)max_min_diff=max_val-min_valmax_min_diffs.append(max_min_diff)# 可视化结果plt.figure(figsize=(10,6))plt.hist(max_min_diffs,bins=50,alpha=0.7,color='blue')plt.title('Distribution of the Difference Between Max and Min Values (64 Normal Samples)')plt.xlabel('Max - Min Value')plt.ylabel('Frequency')plt.grid(True)plt.show()
参数高效微调方法有很多很多种,大体来说可以分为3类,第一类是增加额外参数,用A来简称。第二类是选取一部分参数更新,用S来简称。第三类是重参数化,用R来简称。下面的列表显示了很多不同的参数高效微调方法。方法名后面依次是类型、存储、内存、反向传播和推理开销。 这张表来自 《Scaling Down to Scale Up》 的表 1。
现在的库已经封装得特别好了,我们要做的只有两件事,就是把lora注入到哪里,以及秩要指定为多少。理论上有全连接层的地方都可以放。我们回顾transformer有哪些地方有全连接层呢?有七个地方。一开始的embedding层,每一个transformer层的Wq/Wk/Wv/Wo四个全连接层,每一个transformer层的前馈层包括两个全连接层。只挑少数位置来加的话,q 和 v 可以先试。比如在llama中,是将lora注入到所有自注意力层的q/v矩阵,在chatglm中,则是将lora注入到所有自注意力层的q/k/v矩阵。
我们可以通过一个实际的例子来详细说明。正如下图所演示的那样,这是BERT预训练阶段的任务之一——即完形填空任务。考虑原句“the cat sat on the mat”,模型首先随机遮盖掉一些词汇,在本例中,“cat”被掩盖并用“mask”占位符替代。句子经过embedding嵌入处理后,送入transformer的编码器层。最终,我们取出替代了“mask”的部分的输出,通过一个softmax分类器来让模型预测被掩盖的词是“cat”。
I love this movie.Overall, it was a _ movie.这句话中,I love this movie.是原始句子,Overall, it was a _ movie.是template。这两个句子合在一起,被送进模型中,让模型做完形填空的任务。这个时候,模型输出的就不是一个概率值了,而是每个词汇的概率值,然后我们选出概率最高的那个词。比如,模型的输出是“nice”或者“good”或者“fantastic”,那么我们就认为这个句子的感情是正向的。
换言之,我们用完形填空的方式来解决原本的二分类问题。
如果换一个模板,比如“这句话的情感是__”,那就转变成了一个生成任务,用生成的方式来解决分类问题。
或者,如果我们把模板改为“The Chinese translation of this sentence is_”,是不是就实现了一个机器翻译的任务?
这样就不用每次换任务都先去改模型结构,可以先试着换个模板。
手写提示怎么做分类
做分类的时候,这里有两步:
构建模板(Template Construction):选择合适的模板来指示模型需要执行的任务。它直接告诉模型预期的回答类型。例如,在情感分析任务中,提示可能是 “这篇评价是积极的还是消极的:”。设计有效的提示是很重要的,因为它可以显著影响模型的性能。就像例子中的“Overall, it was a _ movie”,这个模板是人为构建的,而且构造模板有许多方法和策略,接下来会进一步讲解。
标签词映射(Label Word Verbalizer):verbalizer定义了类别标签和模型预测词之间的映射关系。以情感分类为例,模型可能输出像“good”、“nice”、“fantastic”这样的词,我们可以很容易地判断出它们都是正向的情绪。然而,我们最终只关心情感是正面还是负面,不在乎具体用了哪个词。标签词映射正好用于此,它帮助我们定义哪些词应该映射到正面情绪,哪些应映射到负面情绪。
在embedding阶段,增加一个参数量为11*98304的embedding层。这里的98304是怎么来的?我当前的用来举例的模型一共有24个transformer层,hidden_size是2048,2*24*2048=98304.这里的2048是每层 K 或 V 的宽度。换模型时,要用那个模型实际的 K、V 宽度来算。至于为什么是这些值相乘,我待会在讲kvcache的时候会说明。
kvcache具体要存储多少信息呢?要存的数有 batchsize×seq_length×层数×2×每层 K 或 V 的宽度(按 K、V 一样宽、每层宽度一样来算)。每个token产生的key和value都要储存下来。这里的2,指的是key和value。seq_length,指的是当前的序列的长度。比如生成到“我爱美丽的”时候,token数为5,此时seq_length=5.然后生成到“我爱美丽的长”时候,token数为6,此时seq_length=6.也就是说,kvcache里的数量,是随着生成的过程而递增的。
FLOPs(floating point operations)表示浮点数运算次数,衡量模型计算量的大小。我们可以近似认为:在一次前向传递中,对于每个token,每个模型参数,需要进行2次浮点数运算,即一次乘法法运算和一次加法运算。一次训练迭代包含了前向传递和后向传递,后向传递的计算量是前向传递的2倍。因此,对于每个token,每个模型参数,需要进行6次浮点数运算。对于GPT3,模型参数量为 174600M,训练数据量为 300B,那么FLOPs是:6*174600*10^6*300*10^9=3.1428*10^23
这是研究人员(《Are Emergent Abilities of Large Language Models a Mirage?》 arxiv.org/pdf/2304.15004.pdf)替换评估指标后发现的规律。这是GPT模型做数学加法乘法任务的表现结果。第一排以accuracy为评估指标,可以看到,模型在10的10次方处(对应的是10B)有明显的分界线,这就是大家所说的涌现。但是如果换一个评估指标,这里用的是token编辑距离,模型表现出了平滑的、可预测的性能提升。