实现将文本数据(input_text)转换为input_embeddings的操作
前言: 我们在使用大模型时,如何将我们理解的文字转换为大模型所理解的文字。
"This is an example." ----->"input_embeddings:tensor([[ 1.4505, 0.3492, -0.9276],[-0.7003, -0.0176, -0.3906],[-2.3738, 1.0161, 1.9516],[ 0.1207, 0.6159, -0.3712],[-0.9073, 2.7757, 2.0496]]"
1、理解token,embed 操作
1、Token(标记/词元)
Token是NLP中将文本分解的基本单位,可以理解为文本的"碎片"或"片段"。
Token的创建过程
分词(Tokenization):将原始文本分割成token
方法包括:
空格分词(英文常用)
子词分词(如BERT的WordPiece,GPT的Byte Pair Encoding)
字符级分词
Token的特点:
可以是单词、子词或字符
每个token通常会被映射为一个唯一的ID(在模型的词汇表中)
如何通俗易懂的理解token操作:
现在有一个句子:
“我爱学习编程。”
第一种切法:按完整词语切分(词级别)
---> '我','爱','学习','编程' ,'。'
第二种切法:按单个字切分(字级别)
---->'我','爱','学',’习‘,'编','程' ,'。'
为什么要有这个操作:
像人读书要一个字/词一个字/词看一样,计算机也需要把句子拆解成它能处理的小单元。
才能:
理解每个部分的意思
分析它们之间的关系
最终理解整个句子
2、embed
就是将离散的token转换为连续向量表示的过程。
Embedding的特性
可学习性:嵌入矩阵通常是模型训练过程中学习得到的(朽木可以雕)
模型通过大量数据训练,能把最初随机初始化的数字矩阵(一堆无意义的数字)"雕刻"成富含语义的嵌入矩阵。语义编码:相似的token在嵌入空间中的距离较近(关系好的离得近)
"篮球"和"足球"的向量会靠近(都是运动)
"数学"和"物理"会靠近(都是理科)
"篮球"和"草莓"则离得远维度固定:无论原始token是什么,嵌入后的向量维度相同([身高],[体重],[单/双眼皮],[头发颜色],……)类似这样的维度去拆解。但是在实际中单个维度的数值没有明确的人类可解释的含义
每个维度是模型自动学习的混合特征,可能糅合了:语法角色(如主语/宾语倾向)
语义属性(如"人类/动物/物体")
使用频率
与其他词共现的模式
若[我]
第3维=0.3,[你]
第3维=0.28,[他]
第3维=0.25。第三个维度可能隐含"人称代词"的强度表征
2、学习文本数据处理的操作
具体步骤可以拆解为如下:
`input_text` -(split text)-> `tokenized_text`
-(token_to_ids)-> `token_ids` -(embed)-> `token_embeddings`
为了简便的使用tokenizer,这里使用tiktoken来调用gpt2的tokenizer。
import tiktokentokenizer = tiktoken.get_encoding('gpt2')
input_text
input_text ='This is an example.'
token_text
Tokenized_text =[tokenizer.decode([item]) for item in tokenizer.encode(input_text)]
print("Tokenized text:\t"'|'+'| |'.join(Tokenized_text),end='|')# Tokenized text: |This| | is| | an| | example| |.|
token_ids
token_ids =tokenizer.encode(input_text)
print("Token IDs: ",token_ids)# Token IDs: [1212, 318, 281, 1672, 13]
此处得到的 token_ids与图中不一样的原因在于tokenizer的不同。不同tokenizer的vocab不同,vocab是存储{'token':id}的一个'字典'
token_embeddings
torch.manual_seed(123)
embedding_layer = torch.nn.Embedding(max(token_ids)+1, 3)
token_embeddings = embedding_layer(torch.tensor(token_ids))
print("token_embeddings:", token_embeddings,end=' ')# token_embeddings: tensor([[ 1.1132, 0.5270, -0.6240],[-0.1123, -0.3662, -1.0509],[-2.1542, 1.3953, 1.1845],[ 1.3132, -0.0824, 1.0386],[-1.0867, 0.8805, 1.5542]], grad_fn=<EmbeddingBackward0>)
3、简单实现tokenizer
Tokenizer(分词器) 是自然语言处理(NLP)中的关键组件,负责将原始文本拆分成模型可处理的离散单元(如单词、子词或字符),并转换为数字ID。
1、拆解文本为token
import re
input_text = 'This is an example.'
token_text =re.split(r'([,.:;?_!"()\'])|\s+', input_text)
token =[t for t in token_text if t]
print(token)# ['This', 'is', 'an', 'example', '.']
2、将token 转为id
vocab ={token:id for id,token in enumerate(token)}
print(vocab)# {'This': 0, 'is': 1, 'an': 2, 'example': 3, '.': 4}
def encode_text(input_text):token_text =re.split(r'([,.:;?_!"()\'])|\s+', input_text)tokens =[t for t in token_text if t]id =[ vocab[token] for token in tokens]return id
encode_text('example')
3、将id 还原为token
def decode_text(ids):id_token ={id:token for token,id in vocab.items()}token =[id_token[id] for id in ids]return tokendecode_text([2,3,4])# ['an', 'example', '.']
完整代码
class Tokenizer:def __init__(self,vocab):self.vocab =vocab def encode_text(self,input_text):token_text =re.split(r'([,.:;?_!"()\'])|\s+', input_text)tokens =[t for t in token_text if t]id =[ self.vocab[token] for token in tokens]return iddef decode_text(self,ids):id_token ={id:token for token,id in self.vocab.items()}token =[id_token[id] for id in ids]return token
使用:
text = 'This is an example.'
tokenizer = Tokenizer(vocab)
print(tokenizer.encode_text(input_text=text))
print(tokenizer.decode_text(ids=[2,4])# [0, 1, 2, 3, 4]
# ['an', '.']