了解 OpenAI 的 gpt2 模型结构(2)

5. 如何打印模型参数?

要打印一个预训练模型的参数,你可以使用transformers库中模型的.named_parameters()方法。这个方法会遍历模型的所有参数,并返回一个迭代器,其中包含每个参数的名称和参数本身。下面是一个简化的示例,展示了如何加载GPT-2模型并打印其参数名称和参数大小。命名为 test03.py,文件保存到 newsrc 目录下:

这段代码首先从transformers库中导入了GPT2LMHeadModel类,然后使用from_pretrained方法加载了预训练的GPT-2模型。接下来,它遍历模型的所有参数,打印出每个参数的名称和大小。

这种方式对于理解模型的构造和调试非常有用,特别是当你需要对模型进行微调或者理解其内部工作原理时。请注意,由于GPT-2模型(以及其他大型模型)包含大量的参数,输出会非常长。你可能只想查看特定部分的参数,或者根据参数名称进行筛选。

运行test03.py

6. 词嵌入权重

为了输出特定模型参数的内容,例如transformer.wte.weight(这是GPT-2模型中的词嵌入权重),你可以使用以下代码片段。请注意,由于模型参数可能非常大,直接打印出整个参数的内容可能不是一个好主意,因为这可能导致巨大的输出,难以在终端或笔记本环境中查看和管理。因此,我会展示如何获取并打印这些权重的一小部分(例如,前几个权重)来示范如何访问这些参数。

命名为 test04.py,文件保存到 newsrc 目录下:

这段代码首先加载了预训练的GPT-2模型。然后,它访问transformer.wte.weight参数,这是模型中词嵌入层的权重。最后,代码只打印出这些权重的一小部分,以便于查看和分析。

请确保在运行这段代码前已经安装了transformers库。如果你想要查看更多或不同的权重部分,可以通过调整切片操作(例如,[:5])来实现。这个例子使用了切片来获取前5个权重,但你可以根据需要调整这个范围。

运行test04.py

这些嵌入向量表示的是模型词汇表中前五个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 目录下:

这段代码首先加载了GPT-2模型和对应的分词器。然后,它获取词嵌入矩阵的权重,并打印出矩阵的前5行,这些行对应于词汇表中的前5个token的嵌入向量。之后,它创建了一个包含前5个token ID的列表,并使用分词器将这些ID转换成实际的token(词)。最后,它打印出这些token。

请注意,词汇表的开始通常包含特殊token(如[CLS]、[SEP]、[PAD]等),因此前5个token可能不是常规的“词”。要查看实际的单词或短语,你可能需要选择一个不同的索引范围,具体取决于分词器的词汇表结构。

运行test05.py

8. 对 prompt 进行编码

要对给定的提示“The meaning of life is”使用GPT-2的分词器进行编码,你可以按照以下步骤进行,命名为 test06.py,文件保存到 newsrc 目录下:

这段代码会使用GPT-2分词器将文本转换为模型能够理解的一系列数字(token IDs)。add_special_tokens=False参数告诉分词器不要添加任何特殊的token(如开始或结束token),只对实际提供的文本进行编码。

如果你在自己的环境中运行这段代码,它将输出prompt字符串的编码结果,这是一个整数列表,每个整数代表词汇表中的一个特定token。

当你在调用tokenizer.encode()方法时添加return_tensors='pt'参数,意味着你希望编码后的结果被封装成一个PyTorch的Tensor,而不是返回一个简单的Python列表。这对于将编码后的数据直接用于PyTorch模型是必要的,因为PyTorch模型期望的输入是Tensor格式。

以下是两种调用方式的对比:

  1. 不使用return_tensors='pt'
    • 返回值是一个Python列表,包含了编码后的token ID。
    • 这种方式在你需要对编码后的结果进行进一步的Python级别处理时很有用。
  2. 使用return_tensors='pt'
    • 返回值是一个PyTorch Tensor,该Tensor封装了编码后的token ID。
    • 这种方式直接为模型训练或推理准备了输入数据,无需额外转换步骤。
    • return_tensors='pt'参数确保了编码后的数据可以直接与PyTorch框架兼容,便于进行模型的前向传播。

这里的'pt'代表PyTorch,如果你在使用TensorFlow,你可以使用return_tensors='tf'来获取一个TensorFlow的Tensor。这样,无论是用于训练还是推理,编码后的数据都可以直接被深度学习框架所使用。

运行test06.py

成功地执行了编码操作,并以两种不同的格式获取了结果:

  1. List: [464, 3616, 286, 1204, 318] 这是一个Python列表,包含了由分词器返回的token ID。每个ID对应于分词器词汇表中的一个特定token。这种格式适合进行进一步的Python级别的处理或分析。
  2. Tensor: tensor([[ 464, 3616, 286, 1204, 318]]) 这是一个PyTorch Tensor,同样包含了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 目录下:

这段代码首先加载了GPT-2模型,然后获取了词嵌入矩阵。embedding_matrix是一个大矩阵,其中每一行对应于词汇表中一个token的嵌入向量。通过embedding_matrix[encoded_prompt_list]这行代码,我们使用encoded_prompt_list中的token ID来索引这个矩阵,从而得到对应的嵌入向量。

token_embeddings变量现在包含了你指定的token ID对应的嵌入向量。这些向量是高维空间中的点,它们捕获了与每个token相关的语义和语法信息。

运行test07.py

发表评论

您的邮箱地址不会被公开。 必填项已用 * 标注

滚动至顶部