5. 如何打印模型参数?
要打印一个预训练模型的参数,你可以使用transformers
库中模型的.named_parameters()
方法。这个方法会遍历模型的所有参数,并返回一个迭代器,其中包含每个参数的名称和参数本身。下面是一个简化的示例,展示了如何加载GPT-2模型并打印其参数名称和参数大小。命名为 test03.py,文件保存到 newsrc 目录下:
1 2 3 4 5 6 7 8 |
from transformers import GPT2LMHeadModel # 加载预训练模型 model = GPT2LMHeadModel.from_pretrained('gpt2') # 打印模型的参数名称和大小 for name, param in model.named_parameters(): print(f"Parameter Name: {name} \t Size: {param.size()}") |
这段代码首先从transformers
库中导入了GPT2LMHeadModel
类,然后使用from_pretrained
方法加载了预训练的GPT-2模型。接下来,它遍历模型的所有参数,打印出每个参数的名称和大小。
这种方式对于理解模型的构造和调试非常有用,特别是当你需要对模型进行微调或者理解其内部工作原理时。请注意,由于GPT-2模型(以及其他大型模型)包含大量的参数,输出会非常长。你可能只想查看特定部分的参数,或者根据参数名称进行筛选。
运行test03.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
python newsrc/test03.py Parameter Name: transformer.wte.weight Size: torch.Size([50257, 768]) Parameter Name: transformer.wpe.weight Size: torch.Size([1024, 768]) Parameter Name: transformer.h.0.ln_1.weight Size: torch.Size([768]) Parameter Name: transformer.h.0.ln_1.bias Size: torch.Size([768]) Parameter Name: transformer.h.0.attn.c_attn.weight Size: torch.Size([768, 2304]) Parameter Name: transformer.h.0.attn.c_attn.bias Size: torch.Size([2304]) Parameter Name: transformer.h.0.attn.c_proj.weight Size: torch.Size([768, 768]) Parameter Name: transformer.h.0.attn.c_proj.bias Size: torch.Size([768]) Parameter Name: transformer.h.0.ln_2.weight Size: torch.Size([768]) Parameter Name: transformer.h.0.ln_2.bias Size: torch.Size([768]) Parameter Name: transformer.h.0.mlp.c_fc.weight Size: torch.Size([768, 3072]) Parameter Name: transformer.h.0.mlp.c_fc.bias Size: torch.Size([3072]) Parameter Name: transformer.h.0.mlp.c_proj.weight Size: torch.Size([3072, 768]) Parameter Name: transformer.h.0.mlp.c_proj.bias Size: torch.Size([768]) Parameter Name: transformer.h.1.ln_1.weight Size: torch.Size([768]) Parameter Name: transformer.h.1.ln_1.bias Size: torch.Size([768]) Parameter Name: transformer.h.1.attn.c_attn.weight Size: torch.Size([768, 2304]) Parameter Name: transformer.h.1.attn.c_attn.bias Size: torch.Size([2304]) Parameter Name: transformer.h.1.attn.c_proj.weight Size: torch.Size([768, 768]) Parameter Name: transformer.h.1.attn.c_proj.bias Size: torch.Size([768]) Parameter Name: transformer.h.1.ln_2.weight Size: torch.Size([768]) Parameter Name: transformer.h.1.ln_2.bias Size: torch.Size([768]) Parameter Name: transformer.h.1.mlp.c_fc.weight Size: torch.Size([768, 3072]) Parameter Name: transformer.h.1.mlp.c_fc.bias Size: torch.Size([3072]) Parameter Name: transformer.h.1.mlp.c_proj.weight Size: torch.Size([3072, 768]) Parameter Name: transformer.h.1.mlp.c_proj.bias Size: torch.Size([768]) ... Parameter Name: transformer.h.11.ln_1.weight Size: torch.Size([768]) Parameter Name: transformer.h.11.ln_1.bias Size: torch.Size([768]) Parameter Name: transformer.h.11.attn.c_attn.weight Size: torch.Size([768, 2304]) Parameter Name: transformer.h.11.attn.c_attn.bias Size: torch.Size([2304]) Parameter Name: transformer.h.11.attn.c_proj.weight Size: torch.Size([768, 768]) Parameter Name: transformer.h.11.attn.c_proj.bias Size: torch.Size([768]) Parameter Name: transformer.h.11.ln_2.weight Size: torch.Size([768]) Parameter Name: transformer.h.11.ln_2.bias Size: torch.Size([768]) Parameter Name: transformer.h.11.mlp.c_fc.weight Size: torch.Size([768, 3072]) Parameter Name: transformer.h.11.mlp.c_fc.bias Size: torch.Size([3072]) Parameter Name: transformer.h.11.mlp.c_proj.weight Size: torch.Size([3072, 768]) Parameter Name: transformer.h.11.mlp.c_proj.bias Size: torch.Size([768]) Parameter Name: transformer.ln_f.weight Size: torch.Size([768]) Parameter Name: transformer.ln_f.bias Size: torch.Size([768]) |
6. 词嵌入权重
为了输出特定模型参数的内容,例如transformer.wte.weight
(这是GPT-2模型中的词嵌入权重),你可以使用以下代码片段。请注意,由于模型参数可能非常大,直接打印出整个参数的内容可能不是一个好主意,因为这可能导致巨大的输出,难以在终端或笔记本环境中查看和管理。因此,我会展示如何获取并打印这些权重的一小部分(例如,前几个权重)来示范如何访问这些参数。
命名为 test04.py,文件保存到 newsrc 目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from transformers import GPT2LMHeadModel, GPT2Tokenizer # 加载预训练模型 model = GPT2LMHeadModel.from_pretrained('gpt2') # 直接获取词嵌入矩阵:transformer.wte.weight wte_weights = model.transformer.wte.weight print("直接打印前5个嵌入向量:") print(wte_weights[:5]) # 另一种方法获取词嵌入矩阵的权重,最后输出结果一样 embedding_weight = model.get_input_embeddings().weight.data # 打印前5个嵌入向量 print("前5个嵌入向量:") print(embedding_weight[:5]) |
这段代码首先加载了预训练的GPT-2模型。然后,它访问transformer.wte.weight
参数,这是模型中词嵌入层的权重。最后,代码只打印出这些权重的一小部分,以便于查看和分析。
请确保在运行这段代码前已经安装了transformers
库。如果你想要查看更多或不同的权重部分,可以通过调整切片操作(例如,[:5]
)来实现。这个例子使用了切片来获取前5个权重,但你可以根据需要调整这个范围。
运行test04.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
python newsrc/test04.py 直接打印前5个嵌入向量: tensor([[-0.1101, -0.0393, 0.0331, ..., -0.1364, 0.0151, 0.0453], [ 0.0403, -0.0486, 0.0462, ..., 0.0861, 0.0025, 0.0432], [-0.1275, 0.0479, 0.1841, ..., 0.0899, -0.1297, -0.0879], [-0.0927, -0.3053, 0.2112, ..., 0.1769, 0.0364, -0.1797], [-0.0506, -0.1111, 0.1058, ..., -0.1149, 0.0664, 0.0574]], grad_fn=<SliceBackward0>) 前5个嵌入向量: tensor([[-0.1101, -0.0393, 0.0331, ..., -0.1364, 0.0151, 0.0453], [ 0.0403, -0.0486, 0.0462, ..., 0.0861, 0.0025, 0.0432], [-0.1275, 0.0479, 0.1841, ..., 0.0899, -0.1297, -0.0879], [-0.0927, -0.3053, 0.2112, ..., 0.1769, 0.0364, -0.1797], [-0.0506, -0.1111, 0.1058, ..., -0.1149, 0.0664, 0.0574]]) |
这些嵌入向量表示的是模型词汇表中前五个token的嵌入。在GPT-2这样的模型中,每个嵌入向量是一个高维空间中的点,代表了相应token的语义和语法属性。这些向量是模型训练过程中学习到的,使得模型能够基于这些嵌入向量来理解和生成文本。
嵌入向量的每个维度都捕捉了一些关于词汇的信息,但这些信息并不是直观可解释的。深度学习模型通过在这些高维空间中操作嵌入向量来完成任务,如分类、生成文本等。
问:根据 transformer.wte.weight Size: torch.Size([50257, 768],应该有50257个嵌入量,每一行有768个值?
是的,你的理解是正确的。在transformer.wte.weight
中,尺寸为torch.Size([50257, 768])
表示这个嵌入矩阵有50257个嵌入向量,每个嵌入向量包含768个值。这里的50257代表模型词汇表的大小,即模型可以识别的不同token的总数;768则是嵌入空间的维度,即每个token被映射到一个768维的向量空间中。
在自然语言处理模型中,词嵌入是将词汇表中的词(或token)转换为固定长度的向量的技术。这些向量捕捉了词的语义信息和语境信息,使得模型能够处理自然语言。对于给定的词(或token),其嵌入向量通过在嵌入矩阵中查找相应的行来获取。例如,如果你想要获取词汇表中第一个token的嵌入向量,你可以简单地查看嵌入矩阵的第一行。
在GPT-2这样的模型中,这些嵌入向量是模型训练过程中学习到的,并且它们是模型理解和生成文本的基础。每个嵌入向量通过在高维空间中的位置来表示其对应的token的特征,包括语义和语法属性。这种表示方法允许模型捕捉词与词之间的复杂关系,如同义词、反义词以及词在不同语境中的使用等。
7. 前5个词如何打印?
在Transformer模型(如GPT-2)中,transformer.wte.weight
是词嵌入矩阵的权重,它将词汇表中的每个单词(或更准确地说,每个token)映射到一个高维空间。每一行对应于词汇表中的一个token的嵌入向量。因此,如果你想查看前5个词的嵌入向量,你可以直接索引这个矩阵的前5行。同样,如果你想知道这些嵌入向量对应的词是什么,你可以使用分词器的convert_ids_to_tokens
方法。
下面是一个如何实现这一点的例子,命名为 test05.py,文件保存到 newsrc 目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
from transformers import GPT2Tokenizer, GPT2Model # 加载预训练的GPT-2模型和分词器 model = GPT2Model.from_pretrained('gpt2') tokenizer = GPT2Tokenizer.from_pretrained('gpt2') # 获取词嵌入矩阵的权重 embedding_weight = model.get_input_embeddings().weight.data # 打印前5个嵌入向量 print("前5个嵌入向量:") print(embedding_weight[:5]) # 获取前5个token的ID first_five_tokens_ids = list(range(5)) # 将这些ID转换为token first_five_tokens = tokenizer.convert_ids_to_tokens(first_five_tokens_ids) # 打印前5个词 print("\n对应的前5个词:") print(first_five_tokens) |
这段代码首先加载了GPT-2模型和对应的分词器。然后,它获取词嵌入矩阵的权重,并打印出矩阵的前5行,这些行对应于词汇表中的前5个token的嵌入向量。之后,它创建了一个包含前5个token ID的列表,并使用分词器将这些ID转换成实际的token(词)。最后,它打印出这些token。
请注意,词汇表的开始通常包含特殊token(如[CLS]、[SEP]、[PAD]等),因此前5个token可能不是常规的“词”。要查看实际的单词或短语,你可能需要选择一个不同的索引范围,具体取决于分词器的词汇表结构。
运行test05.py
1 2 3 4 5 6 7 8 9 10 |
python newsrc/test05.py 前5个嵌入向量: tensor([[-0.1101, -0.0393, 0.0331, ..., -0.1364, 0.0151, 0.0453], [ 0.0403, -0.0486, 0.0462, ..., 0.0861, 0.0025, 0.0432], [-0.1275, 0.0479, 0.1841, ..., 0.0899, -0.1297, -0.0879], [-0.0927, -0.3053, 0.2112, ..., 0.1769, 0.0364, -0.1797], [-0.0506, -0.1111, 0.1058, ..., -0.1149, 0.0664, 0.0574]]) 对应的前5个词: ['!', '"', '#', '$', '%'] |
8. 对 prompt 进行编码
要对给定的提示“The meaning of life is
”使用GPT-2的分词器进行编码,你可以按照以下步骤进行,命名为 test06.py,文件保存到 newsrc 目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
from transformers import GPT2Tokenizer # 加载预训练的GPT-2分词器 tokenizer = GPT2Tokenizer.from_pretrained('gpt2') # 定义prompt prompt = "The meaning of life is" # 对prompt进行编码,返回Python列表 encoded_prompt_list = tokenizer.encode(prompt, add_special_tokens=False) # 对prompt进行编码,返回PyTorch Tensor encoded_prompt_tensor = tokenizer.encode(prompt, return_tensors='pt', add_special_tokens=False) print("List:", encoded_prompt_list) print("Tensor:", encoded_prompt_tensor) # 将这些ID转换为token tokens = tokenizer.convert_ids_to_tokens(encoded_prompt_list) print("tokens:", tokens) |
这段代码会使用GPT-2分词器将文本转换为模型能够理解的一系列数字(token IDs)。add_special_tokens=False
参数告诉分词器不要添加任何特殊的token(如开始或结束token),只对实际提供的文本进行编码。
如果你在自己的环境中运行这段代码,它将输出prompt
字符串的编码结果,这是一个整数列表,每个整数代表词汇表中的一个特定token。
当你在调用tokenizer.encode()
方法时添加return_tensors='pt'
参数,意味着你希望编码后的结果被封装成一个PyTorch的Tensor
,而不是返回一个简单的Python列表。这对于将编码后的数据直接用于PyTorch模型是必要的,因为PyTorch模型期望的输入是Tensor
格式。
以下是两种调用方式的对比:
- 不使用
return_tensors='pt'
:- 返回值是一个Python列表,包含了编码后的token ID。
- 这种方式在你需要对编码后的结果进行进一步的Python级别处理时很有用。
- 使用
return_tensors='pt'
:- 返回值是一个PyTorch
Tensor
,该Tensor
封装了编码后的token ID。 - 这种方式直接为模型训练或推理准备了输入数据,无需额外转换步骤。
return_tensors='pt'
参数确保了编码后的数据可以直接与PyTorch框架兼容,便于进行模型的前向传播。
- 返回值是一个PyTorch
这里的'pt'
代表PyTorch,如果你在使用TensorFlow,你可以使用return_tensors='tf'
来获取一个TensorFlow的Tensor
。这样,无论是用于训练还是推理,编码后的数据都可以直接被深度学习框架所使用。
运行test06.py
1 2 3 4 |
python newsrc/test06.py List: [464, 3616, 286, 1204, 318] Tensor: tensor([[ 464, 3616, 286, 1204, 318]]) tokens: ['The', 'Ġmeaning', 'Ġof', 'Ġlife', 'Ġis'] |
成功地执行了编码操作,并以两种不同的格式获取了结果:
- List:
[464, 3616, 286, 1204, 318]
这是一个Python列表,包含了由分词器返回的token ID。每个ID对应于分词器词汇表中的一个特定token。这种格式适合进行进一步的Python级别的处理或分析。 - Tensor:
tensor([[ 464, 3616, 286, 1204, 318]])
这是一个PyTorchTensor
,同样包含了token ID,但这次它们被封装在一个Tensor对象中。注意这个Tensor有两个维度,其中第一个维度(批次大小)为1。这是因为你编码的是单个文本字符串。这种格式直接适用于作为模型的输入,便于进行批处理和GPU加速。
这两种表示方法各有用途,选择哪一种取决于你接下来的计划。如果你要对这些编码后的ID进行某种处理或分析,使用Python列表可能更方便。如果你准备将这些ID作为输入传递给PyTorch模型进行训练或推理,那么使用Tensor格式会更直接有效。
以将编码后的token ID列表[464, 3616, 286, 1204, 318]
转换回对应的token字符串。这里使用的是tokenizer.convert_ids_to_tokens
方法,它接受token ID列表作为输入,并返回一个包含每个ID对应token的字符串列表。
tokens = tokenizer.convert_ids_to_tokens(encoded_prompt_list) 对于给定的ID列表,这个方法将返回每个ID对应的原始token。在例子中,这个过程会将prompt “The meaning of life is”中每个词(以及可能的特殊字符或子词)的ID转换回可读的文本形式。
这里的输出:
'The'
'Ġmeaning'
'Ġof'
'Ġlife'
'Ġis'
中的'Ġ'
字符(看起来像一个空格,但实际上是一个不间断空格)是GPT-2分词器特有的,用于表示一个单词的开始,除了第一个单词之外。这是因为GPT-2使用的是Byte Pair Encoding(BPE)作为其分词方法,其中'Ġ'
用来区分紧跟在其他单词后面的单词。在实际文本中,这个字符通常不会显示,或者可以被理解为单词之间的空格。
这样的转换是NLP任务中常见的一个步骤,它允许我们在处理文本和模型内部表示之间进行转换,从而可以更容易地理解模型的输入和输出。
问:encoded_prompt_list 返回的实际上是 transformer.wte.weight 权重的词索引值?
是的,你理解得非常正确。在使用分词器对文本进行编码时,返回的encoded_prompt_list
实际上是词汇表中对应单词或token的索引值。这些索引值直接对应于transformer.wte.weight
(即词嵌入权重矩阵)中的行。换句话说,每个索引指向transformer.wte.weight
中的一个特定行,而这一行就是对应单词或token的嵌入向量。
在GPT-2这样的模型中,transformer.wte.weight
是一个巨大的矩阵,其形状通常是[vocab_size, embedding_size]
,其中vocab_size
是分词器词汇表的大小(在GPT-2的情况下是50257),而embedding_size
是嵌入向量的维度(在GPT-2的情况下是768)。这意味着矩阵中的每一行代表一个不同的token的嵌入向量,这些向量在模型训练过程中被学习。
因此,当你通过tokenizer.encode()
获取到一系列索引值时,这些索引值可以被用来从transformer.wte.weight
中检索出相应的嵌入向量。这些嵌入向量随后被用作模型的输入,进行前向传播以执行各种任务,如文本生成、分类等。
9. token ID对应的词嵌入矩阵
如果你想查看与encoded_prompt_list
中的token ID对应的词嵌入矩阵(即transformer.wte.weight
中的具体行),你可以按照下面的方法来实现。这段代码将索引词嵌入权重矩阵,获取特定token ID对应的嵌入向量。
首先,确保你已经有了encoded_prompt_list
这个列表,它包含了你感兴趣的token的ID。然后,使用这些ID来索引transformer.wte.weight
矩阵,命名为 test07.py,文件保存到 newsrc 目录下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from transformers import GPT2Model # 加载预训练的GPT-2模型 model = GPT2Model.from_pretrained('gpt2') # 假设 encoded_prompt_list 已经被定义并包含了感兴趣的token ID # encoded_prompt_list = [464, 3616, 286, 1204, 318] # 获取词嵌入矩阵 embedding_matrix = model.get_input_embeddings().weight.data # 使用encoded_prompt_list中的ID索引嵌入矩阵 token_embeddings = embedding_matrix[encoded_prompt_list] print("Selected token embeddings:") print(token_embeddings) |
这段代码首先加载了GPT-2模型,然后获取了词嵌入矩阵。embedding_matrix
是一个大矩阵,其中每一行对应于词汇表中一个token的嵌入向量。通过embedding_matrix[encoded_prompt_list]
这行代码,我们使用encoded_prompt_list
中的token ID来索引这个矩阵,从而得到对应的嵌入向量。
token_embeddings
变量现在包含了你指定的token ID对应的嵌入向量。这些向量是高维空间中的点,它们捕获了与每个token相关的语义和语法信息。
运行test07.py
1 2 3 4 5 6 7 8 |
python newsrc/test07.py List: [464, 3616, 286, 1204, 318] Selected token embeddings: tensor([[-0.0686, -0.0203, 0.0645, ..., 0.0639, -0.0100, 0.0031], [ 0.1675, -0.0834, 0.0147, ..., -0.0559, -0.2029, -0.0829], [-0.0572, 0.0183, 0.0333, ..., -0.0689, -0.0931, -0.0714], [ 0.2109, 0.1353, 0.0158, ..., -0.0287, -0.0276, -0.1644], [-0.0097, 0.0101, 0.0556, ..., 0.1145, -0.0380, -0.0254]]) |