前言
欢迎各位接着阅读,本期将讲解文字嵌入,还是一样的我会按照我理解的进行详细讲解
文本嵌入
文本嵌入是自然语言处理中的一个重要概念,它将文本转换为向量形式,在通过自注意力机制进行语言排版,当然后期也会讲解自注意力机制,在上一期教程中我们知道,网络神经是如何工作的,在这里就不细说了,这里我们讲解一下一个新的概念,就是概率,在我们之前讲解的过程中我们知道网络神经的输入层是根据输入东西进行增加的,那要是人工智能学习完全部的汉字那么他的内存不得起飞了,所以我们采用向量,概率,自注意力…等等其他的进行优化,使其对用户的文字进行分析时达到
列如
你好 他会储存为 [0.1,0.2] 又或者 [0.302,0.432] 等等…这样存储
回答时也是一样,通过自注意力机制把推出的向量进行匹配,然后进行输出,把概率高的进行输出,在把高的进行再一次比对,直到输出完毕,这样就完成了一个简单的对话模型,当然说的很简单(仅限于我自己的理解,如有问题请纠正)
声明
本项目为个人学习项目,仅供学习参考,本教程只提供我理解的思路,不保证准确性。
- 欢迎各位指出问题,提出改进意见。
- 需要准确性建议去看GPT的相关论文,或者去看对应的学术论文(本人只是爱好者)
文本生成
emm,这边需要引入一个新的概念RNN,RNN是一种处理序列数据的神经网络结构,它具有记忆能力,能够捕捉序列中的时序信息。RNN在自然语言处理、时间序列预测、语音识别等领域有着广泛的应用全称(Recurrent Neural Network)简称RNN
开始
那么我们也就不客套了,开始吧、
准备材料
一分中文的语料库,可以是你想要的任何文本列如[对话,闲聊,知识库,小说等等]因为是初次尝试,没啥好的建议随便你,格式简单一点,列如:
我会帮助你实现你的一切
你好,我是崽崽,有什么问题吗?
你好,有什么问题吗?
等等,大概是每个对话,就换一行空一行
封装成一个文件,命名为dev.txt
或者其他.txt都行
开始
- 读取文件
with open('input.txt', 'r', encoding='utf-8') as f:
text = f.read()
print("字符数量为:", len(text))
这里我们可以看到输出的字符数量,也就是我们的语料库的长度
我们可以尝试看看读取到的前几十个文字
print(text[:100])
出现类似
- 我会帮助你实现你的一切
- 你好,我是崽崽,有什么问题吗?
- 你好,有什么问题吗? 也就是按照我们资料库显示的前几十个文字即为正常,反之则是未加载成功或者读取错误,需要保证在同目录下
- 转换为字符列表
chars = sorted(list(set(text)))
vocab_size = len(chars)
print(''.join(chars))
print(vocab_size)
在这里我们可以看到我们所有文本转换后的长度,这里我们可以简单看一下文字效果的输出与输出
stoi = {ch: i for i, ch in enumerate(chars)}
itos = {i: ch for i, ch in enumerate(chars)}
encode = lambda s: [stoi[c] for c in s]
decode = lambda l: ''.join([itos[i] for i in l])
print(encode('你好'))
print(decode(encode('你好')))
输出类似为
[156, 710] 你好
还记得我们在网络神经中讲过,字符是如何储存的,这里我们就清晰的看到你储存在156中好储存在710中(说法不一定准确)
- 转换
import torch
data = torch.tensor(encode(text), dtype=torch.long)
print(data.shape,data.dtype)
print(data[:10])
我们把文本转换为整数索引列表,在生成一个长形张量,在打印出形状以及前10个索引
- 切分
x = train_data[:block_size]
y = train_data[1:block_size+1]
for t in range(block_size):
context = x[:t+1]
target = y[t]
print(f"输入为{context},目标为{target}")
这里我们通过切片的方式,把输入和目标进行切分成输入序列 x 和目标序列 y,这里我们通过for循环的方式,把输入和目标进行打印
- 创建模型 这里我们将尝试创建一个简单的bigram语言模型,emm这个是什么呢,bigram语言模型是通过两个字符来预测下一个字符的,比如”ab”,那么模型会根据”ab”来预测下一个字符,这个模型非常简单,但是可以作为基础模型,在训练过程中,模型会根据训练数据来学习到语言的分布,从而预测下一个字符
import torch
import torch.nn as nn
from torch.nn import functional as F
torch.manual_seed(1250)
class BigramLanguageModel(nn.Module):
def __init__(self, vocab_size):
super().__init__()
self.token_embedding_table = nn.Embedding(vocab_size, vocab_size)
def forward(self, idx, targets=None):
logits = self.token_embedding_table(idx)
if targets is None:
loss = None
else:
B,T,C = logits.shape
logits = logits.view(B*T,C)
targets = targets.view(B*T)
loss = F.cross_entropy(logits, targets)
return logits, loss
def generate(self, idx, max_new_tokens):
for _ in range(max_new_tokens):
logits, loss = self(idx)
logits = logits[:, -1, :]
probs = F.softmax(logits, dim=-1)
idx_next = torch.multinomial(probs, num_samples=1)
idx = torch.cat((idx, idx_next), dim=1)
return idx
m = BigramLanguageModel(vocab_size)
logits, loss = m(xb, yb)
print(logits.shape)
print(loss)
print(decode(m.generate(idx = torch.zeros((1, 1),dtype=torch.long),max_new_tokens=10)[0].tolist()))
这个代码摘抄至Andrej Karpathy大佬视频教学,它使用一个嵌入层(Embedding)将索引映射到对应 logits,并在前向传播时可选地计算交叉熵损失。generate 方法通过逐步采样下一个 token 来生成新序列,最后把生成的索引用 decode 函数转回可读文本
- 训练
batch_size = 32
for steps in range(100):# 训练 100 次
xb, yb = get_batch('train')
logits, loss = m(xb, yb)
optimizer.zero_grad(set_to_none=True)
loss.backward()
optimizer.step()
print(loss.item())
输出大概为
8.594120025634766 8.466411590576172 8.443642616271973 8.509449005126953 8.419870376586914 8.50456428527832 8.476265907287598 8.476556777954102
逐渐下降
- 测试
print(decode(m.generate(idx = torch.zeros((1, 1),dtype=torch.long),max_new_tokens=10)[0].tolist()))
这里的输出是10tokens,也就是输出10个字符
总结
讲解了简单的模型,以及认识向量,如有问题请指出修改,后续持续跟进
鸣谢
感谢 Andrej Karpathy 大佬的视频教学,以及他的开源项目,帮助我理解了深度学习
后续
- 继续学习深度学习,包括卷积神经网络、循环神经网络等
- 尝试尝试搭建小型的大模型
- 接着创作好的教程,分享给更多人