部署与推理
一些推理方法
Greedy Search 贪婪搜索方式。按照前面的讲解,模型会按照词表尺寸生成概率。贪婪方式会不断选择生成概率最大的token。该方法由于无脑选择了最大概率,因此模型会倾向于生成重复的文字,一般实际应用中很少使用
Beam Search 和贪婪方式的区别在于,beam search会选择概率最大的k个。在生成下一个token时,每个前序token都会生成k个,这样整体序列就有k^2个,从这些序列中选择组合概率最大的k个,并递归地执行下去。k在beam search算法中被称为beam_size
Sample 随机采样方式。按照词表每个token的概率采样一个token出来。这个方式多样性更强,是目前主流的生成方式。
重要推理超参数
do_sample:布尔类型。是否使用随机采样方式运行推理,如果设置为False,则使用beam_search方式
temperature:大于等于零的浮点数。公式为: $$ q_i=\frac{\exp(z_i/T)}{\sum_{j}\exp(z_j/T)}\ $$ 从公式可以看出,如果T取值为0,则效果类似argmax,此时推理几乎没有随机性;取值为正无穷时接近于取平均。一般temperature取值介于[0, 1]之间。取值越高输出效果越随机。
如果该问答只存在确定性答案,则T值设置为0。反之设置为大于0。
top_k:大于0的正整数。从k个概率最大的结果中进行采样。k越大多样性越强,越小确定性越强。一般设置为20~100之间。
实际实验中可以先从100开始尝试,逐步降低top_k直到效果达到最佳。
top_p:大于0的浮点数。使所有被考虑的结果的概率和大于p值,p值越大多样性越强,越小确定性越强。一般设置0.7~0.95之间。
实际实验中可以先从0.95开始降低,直到效果达到最佳。
top_p比top_k更有效,应优先调节这个参数。
repetition_penalty: 大于等于1.0的浮点数。如何惩罚重复token,默认1.0代表没有惩罚。
部署
可用openai接口访问 swift infer --model_id_or_path qwen/Qwen-1_8B-Chat --max_new_tokens 128 --temperature 0.3 --top_p 0.7 --repetition_penalty 1.05 --do_sample true
from swift.llm import (
ModelType,
infer_main,InferArguments
)
model_type=ModelType.qwen1half_0_5b_chat
# model_id_or_path 模型目录
# ckpt_dir 训练监测点checkpoint目录
param=InferArguments(model_type=model_type,
max_new_tokens=128,
infer_backend='pt',
temperature=0.3)
infer_main(
param
)
推理
import os
# os.environ['CUDA_VISIBLE_DEVICES'] = '0'
from swift.llm import (
ModelType,get_default_template_type, get_template,
get_model_tokenizer, inference,inference_stream,
)
from modelscope import BitsAndBytesConfig
from swift.utils import seed_everything
import torch
model_type = ModelType.qwen1half_0_5b_chat
template_type = get_default_template_type(model_type)
print(f'template_type: {template_type}') # template_type: qwen
torch_dtype = torch.bfloat16
quantization_config = BitsAndBytesConfig(load_in_4bit=True,
bnb_4bit_compute_dtype=torch_dtype,
bnb_4bit_quant_type='nf4',
bnb_4bit_use_double_quant=True)
kwargs = {}
# kwargs['use_flash_attn'] = True # 使用flash_attn
model, tokenizer = get_model_tokenizer(model_type,
model_kwargs={'device_map': 'auto',
# 'quantization_config':quantization_config
}
, **kwargs)
# 修改max_new_tokens
model.generation_config.max_new_tokens = 128
template = get_template(template_type, tokenizer)
seed_everything(42)
query = '浙江的省会在哪里?'
response, history = inference(model, template, query)
print(f'query: {query}')
print(f'response: {response}')
query = '这有什么好吃的?'
gen = inference_stream(model, template, query, history,stop_words=['111'])
print(f'query: {query}')
print(f'history: {history}')
print_idx = 0
print(f'query: {query}\nresponse: ', end='')
for response, history in gen:
delta = response[print_idx:]
print(delta, end='', flush=True)
print_idx = len(response)
print(f'\nhistory: {history}')
编码解码及生成模式
a={'query': '猪', 'history': []}
template.encode(a)
messages = [{
'role': 'system',
'content': '123'
}, {
'role': 'user',
'content': '你是猪'
}]
txt=tokenizer.apply_chat_template(
messages,
tokenize=False,
add_generation_prompt=True
)
txt='你是猪'
input_ids = tokenizer(txt, return_tensors='pt')
input_ids = input_ids.to(model.device)
pred = model.generate(**input_ids,max_length=2000)
tokenizer.decode(input_ids['input_ids'][0]),tokenizer.decode(pred[0])
预训练模型与聊天模型的转换
# 这里假设原model是与训练模型,需要转为聊天模型使用
# chat 模型才能传messages
# 用chat的template,才能训练多轮对话。base模型,用chat的template也可以训练多轮对话
messages = [['你是猪', '吗?(\u3000\u3000)\nA. Yes,I am.\nB. No,I am.\n考查汉译英.由题,问句句意为"是猪吗?",A选项符合;B选项为"不,我是.". \n答案:A\n解析:Yes,I am.是的,我是.']]
seed_everything(42)
query = '你是猪'
_model_type = ModelType.qwen1half_0_5b_chat
_template_type = get_default_template_type(_model_type)
_model, _tokenizer = get_model_tokenizer(_model_type, torch.float16,
model_kwargs={'device_map': 'auto'}, **kwargs)
_template = get_template(_template_type, _tokenizer)
response, history = inference(model, _template, query,messages)
print(f'query: {query}')
print(f'response: {response}')
history