赞
踩
Transformers库是一个开源的Python库,用于自然语言处理(NLP)任务。它提供了一套强大的工具和功能,可以轻松地使用和训练预训练的Transformer模型。
几乎所有的开源LLM都可以通过Transformers库使用,该库提供了简洁、一致的API,大幅简化了开源LLM的使用门槛。同时,Transformers库也与Pytorch库兼容,使得开发者同样可以做一些高级操作,以满足不同的个性化需求。
官方文档:https://huggingface.co/docs/transformers/index
源代码:https://github.com/huggingface/transformers
Pipelines是Transformers库提供的最简单的LLM推理工具,对于只需要使用LLM推理而不需要定制其他特殊功能的用户,使用Pipelines是最佳的选择。
Pipelines的使用分为一下两个步骤
pipeline支持很多任务,可以在Transformers的官方文档中找到。而对于LLM的推理,一般会使用text-generation
方法。
Llama2推理(摘自Hugging Face Llama2 Blog):
from transformers import AutoTokenizer import transformers import torch model = "meta-llama/Llama-2-7b-chat-hf" tokenizer = AutoTokenizer.from_pretrained(model) pipeline = transformers.pipeline( "text-generation", model=model, torch_dtype=torch.float16, device_map="auto", ) sequences = pipeline( 'I liked "Breaking Bad" and "Band of Brothers". Do you have any recommendations of other shows I might like?\n', do_sample=True, top_k=10, num_return_sequences=1, eos_token_id=tokenizer.eos_token_id, max_length=200, ) for seq in sequences: print(f"Result: {seq['generated_text']}")
Llama3推理(摘自Transformers Llama3文档):
import transformers
import torch
model_id = "meta-llama/Meta-Llama-3-8B"
pipeline = transformers.pipeline("text-generation", model=model_id, model_kwargs={"torch_dtype": torch.bfloat16}, device_map="auto")
pipeline("Hey how are you doing today?")
源码:https://github.com/huggingface/transformers/blob/f5c0fa9f6fe0eea2ad69bb1b03aff04824aa4870/src/transformers/pipelines/init.py#L562
文档:https://huggingface.co/docs/transformers/main/en/main_classes/pipelines#pipelines
pipeline = transformers.pipeline("text-generation", model=model_id)
常用参数:
参数名 | 类型 | 解释 |
---|---|---|
task | str | 推理任务名称,在LLM推理时一般设置为"text-generation" |
model | Optional[Union[str, “PreTrainedModel”, “TFPreTrainedModel”]] | 推理使用的模型,可以是路径(本地路径,也可以是HuggingFace路径),也可以是一个模型 |
device_map | str or Dict[str, Union[int, str, torch.device] , optional | 可以指定设备如cuda:1(较新版本的transformers支持),也可也设定auto自动选择设备 |
torch_dtype | str or torch.dtype , optional | 加载的datatype,可以设定auto,也可以自己指定。不同模型可以使用不同的dtype,在不了解的情况建议选择auto或bfloat16。比如Llama2的datatype可以详见文章结尾 |
pipeline(text_inputs, **kwargs)
文档:https://huggingface.co/docs/transformers/main/en/main_classes/pipelines#transformers.TextGenerationPipeline
常用参数:
参数名 | 类型 | 解释 |
---|---|---|
text_inputs | str, List[str], List[Dict[str, str]], or List[List[Dict[str, str]]] | 如果输入是字符串或者字符串列表,会将这些字符串作为输入生成对应输出。如果是字典(包含不同角色的对话),会使用model tokenizer对应的模板生成对应prompt作为输入。关于字典的格式见后文。 |
return_tensors | bool, optional, defaults to False | 是否输出为decode的tensor矩阵 |
return_text | bool, optional, defaults to True | 是否输出decode后的文本 |
return_full_text | bool, optional, defaults to True | 如果设定为False,只会输出LLM新生成的文本 |
generate_kwargs | dict, optional | 控制模型生成的参数,比如生成最大长度等等,具体实例可以参照前文Llama2推理示例部分,参数说明可以参照后文 |
返回值:
文本或输出的ids的列表,具体取决于函数接收的参数
返回文本时输出:
输入为单个样例:sample
输入为多个样例:[sample1, sample2, sample3]
其中每个sample的数据格式:
[{"generated_text": generated_content}, ...]
如果text_inputs是List[dict]形式,则generated_content同样也是List[dict]形式返回,不过会在输入的基础上增加{“role”: “assistant”, “content”: …}的输出,否则则是返回正常字符串信息
这里特别注意输出的List套了两层,例如访问第i个样本的输出使用outputs[i][0]["generated_text"][len(batch_prompt[i]) :]
在一些场景中,需要对推理细节做一些修改,或是进行模型训练等操作,这就需要一些抽象程度更低的工具。对于LLM来说,最长使用的分别是model和tokenizer。
model = transformers.AutoModelForCausalLM.from_pretrained(pretrained_model_name_or_path)
通过AutoModel类,可以加载Hugging Face上几乎所有的模型。可以通过指定HF模型路径(可以在本地或HF上的路径),加载对应的模型。
常用参数:
参数名 | 类型 | 解释 |
---|---|---|
pretrained_model_name_or_path | str or os.PathLike | 模型路径 |
device_map | str or Dict[str, Union[int, str, torch.device]] or int or torch.device , optional | 将模型加载到哪个设备上。可以传入auto,也可以自己指定设备 |
torch_dtype | str or torch.dtype , optional | 数据类型 |
模型参数和上文pipeline传递的模型参数基本是一致的。
模型的使用和Pytorch中Model使用类似,不同Model开发者可能会开发不同的功能,可以结合文档或源码进行更深入的研究。下文以较常用的Llama Model为例,简要说明一下与一般Pytorch Model不同的地方
官方文档:https://huggingface.co/docs/transformers/main/en/model_doc/llama2
源码:https://github.com/huggingface/transformers/blob/main/src/transformers/models/llama/modeling_llama.py#L1084
def forward(
self,
input_ids: torch.LongTensor = None,
attention_mask: Optional[torch.Tensor] = None,
position_ids: Optional[torch.LongTensor] = None,
past_key_values: Optional[Union[Cache, List[torch.FloatTensor]]] = None,
inputs_embeds: Optional[torch.FloatTensor] = None,
labels: Optional[torch.LongTensor] = None,
use_cache: Optional[bool] = None,
output_attentions: Optional[bool] = None,
output_hidden_states: Optional[bool] = None,
return_dict: Optional[bool] = None,
cache_position: Optional[torch.LongTensor] = None,
) -> Union[Tuple, CausalLMOutputWithPast]:
特殊参数解释:
loss=output.loss
获取计算的梯度。这里的labels并不是实际做反向传播时的target,不需要提前做移位操作(target后移一位使得input的输出是input下一个序列的输入),模型在计算loss前会自动进行一次移位操作,详细源码可以看这里。模型的generate方法会使用自回归的方法生成文本。在使用pipeline做模型推理时,也是通过generate方法实现的文本生成。
参数 | 类型 | 说明 |
---|---|---|
inputs | torch.Tensor of varying shape depending on the modality, optional | 模型输入的一个batch的prompt,一般为编码后的token形式。其中inputs.shape[0]为batch_size |
generation_config | GenerationConfig, optional | 文本生成参数,常用参数见下表 |
一些可以设置的常用参数:
参数 | 类型 | 说明 |
---|---|---|
do_sample | bool | 输出内容是否随机 |
max_length | int, optional | 输入+输出的最大长度。如果输入文本超过了max_length,可能会报错 |
max_new_tokens | int, optional | 由LLM生成的文本的长度 |
更多参数可以参考HF文档GenerationConfig部分
HF文档:https://huggingface.co/docs/transformers/main/en/main_classes/tokenizer#transformers.PreTrainedTokenizer
Tokenizer的主要功能是将字符串转换为对应的Token,或将Token转换为字符串。Tokenizer主要可以实现以下功能:
tokenizer = transformers.AutoTokenizer.from_pretrained(model_path)
编码类方法的主要功能是将字符串编码为对应的token
__call__
最常用的方法,可以理解为batch_encode
常用参数:
参数名 | 类型 | 解释 |
---|---|---|
text | (str, List[str], List[List[str]], optional) | 需要被编码的字符串 |
padding | bool, str or PaddingStrategy, optional, defaults to False | 是否自动padding。支持max_length和longest两种方法 |
truncation | bool, str or TruncationStrategy, optional, defaults to False | 是否将句子进行截断 |
max_length | int, optional | 设置padding或truncation所使用的最大长度 |
return_tensors | str or TensorType, optional | 是否返回tensor数据类型(默认为list)。可使用pt (Pytorch), tf (TensorFlow), np (Numpy)三种类型。 |
返回类型:BatchEncoding
可以像字典一样进行访问,有以下关键的信息:
常见的用法:
inputs = tokenizer(prompts, return_tensors='pt', padding=True).to(device)
outputs = model(**inputs)
encode
与__call__功能类似,不过主要用于将单一句子encode
输出:List[int], torch.Tensor, tf.Tensor or np.ndarray
解码类函数的功能是将token解码为对应的字符串
batch_decode
输入:sequences (Union[List[int], List[List[int]], np.ndarray, torch.Tensor, tf.Tensor]) — List of tokenized input ids.
输出:List[str] The list of decoded sentences.
decode
输入:token_ids (Union[int, List[int], np.ndarray, torch.Tensor, tf.Tensor]) — List of tokenized input ids.
输出:str The decoded sentence.
许多LLM具有对话功能,用户的输入可以根据对应的模板转换为输入模型的字符串,这就可以使用tokenizer自带的apply_chat_template
方法
例如:
messages = [
{"role": "system", "content": "You are a pirate chatbot who always responds in pirate speak!"},
{"role": "user", "content": "Who are you?"},
]
input_ids = tokenizer.apply_chat_template(
messages,
add_generation_prompt=True,
return_tensors="pt"
).to(model.device)
apply_chat_template
方法的常用参数:
参数名 | 类型 | 解释 |
---|---|---|
conversation | Union[List[Dict[str, str]], List[List[Dict[str, str]]]] | A list of dicts with “role” and “content” keys, representing the chat history so far. |
tokenize | bool, defaults to True | Whether to tokenize the output. If False, the output will be a string. |
padding | bool, defaults to False | Whether to pad sequences to the maximum length. Has no effect if tokenize is False. |
truncation | bool, defaults to False | Whether to truncate sequences at the maximum length. Has no effect if tokenize is False. |
return_tensors | str or TensorType, optional | If set, will return tensors of a particular framework. Has no effect if tokenize is False. |
add_generation_prompt | bool, defaults to False | Whether to end the prompt with the token(s) that indicate the start of an assistant message. This is useful when you want to generate a response from the model. Note that this argument will be passed to the chat template, and so it must be supported in the template for this argument to have any effect. |
返回类型
返回类型 | 函数输入条件 | 备注 |
---|---|---|
List[int] | 不进行额外设置 | |
List[List[int]] | 输入input为一个batch | |
str | tokenize=False且输入单条数据 | |
List[str] | tokenize=False且输入多条数据 | |
torch.Tensor | tokenize=True且return_tensors=‘pt’ | shape为[batch_size, seq_len] |
这个方法和__call__
方法很类似,不同的是该方法接受的输入是dict格式的conversation。如果设置tokenize=False
,则返回使用对话模板生成的对应字符串,反之则返回和__call__
方法类似的输出
conversation的格式:
[{"role": role, "content": content}, ...]
案例:
[{"role": "system", "content": "You are a helpful assistant"},
{"role": "user", "conent": "What is the captical city of China?"}]
一般模型的padding side 为右边,这也是tokenizer默认的做法
但在进行LLM推理时,一般会设置padding side为左边,这样可以使得输入的最后一个字符和输出的第一个字符相连,与attention_mask一起使用可以保证pad后的输出结果与pad前相同
在transformer中只需要设置tokenizer.padding_side='left'
,在后续encode时就是left padding了
Llama2的dtype有点特殊,在训练时使用的是bfloat16,推理时使用的float16。正常使用时可以使用float16,但如果要进行模型训练或者遇到NAN问题,建议把数据类型转换成bfloat16。可以参考HF关于Llama2的说明
(未完待续)
主要用于SFT训练,可以通过data_loader = torch.utils.data.DataLoader(dataset, collate_fn=data_collator_fn)
使用,这样可以不用自己写pad function
其中dataset每个item的数据格式:
{
'input_ids': input_ids
'labels': labels
}
对于seq2seq任务,一般input_ids
和labels
相同。如果想只对LLM生成的文本做梯度,可以在labels
中将不需要做梯度的内容用-100代替即可。一个简单的例子:
return {
"input_ids": prompt_ids + target_ids + [self.eos_token_id],
"labels": [-100] * len(prompt_ids) + target_ids + [self.eos_token_id]
}
常用参数:
参数 | 类型 | 说明 |
---|---|---|
tokenizer | PreTrainedTokenizerBase | 编码器,用于识别pad token id。如果tokenizer不含pad_id(如Llama),记得提取设置一下 |
return_tensors | str, optional, defaults to “pt” | 返回值类型 |
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。