相关知识
神经网络训练的一般步骤
- 一般先建立一个词或字符的字典,这个字典是将词或字符映射为数字(这个数字就是这个词或字符在当前数据中唯一的表示)
- 创建合适的训练数据:就是输入和预测目标
- 将训练数据转换为张量(将词或者字符换为对应的数字)
- 创建合适的神经网络类
实现在此类中有两个函数:init()和forward(),后者一般就是网络结构,向前传播的过程
- 初始化神经网络
- 选择合适的损失函数
- 选择合适的优化器
- 开始训练,多个epoch(可以理解为训练多个循环)
训练时注意梯度归零,反向传播,更新参数
pytorch中的词嵌入
- 就是建立一个词的矩阵用来表示词,然后可以索引取出词的向量表示
- 刚开始这个矩阵是随机的,我们 的很多任务就是训练这个矩阵
- 必须将词处理为字典形式{“word”:index}
- 索引的时候必须是Long型的tensor
word_to_ix = {"hello":0,"world":1}
embeds = nn.Embedding(2,5) # 2个词,在5维的空间 ,开始是随机的
lookup_tensor = torch.tensor([word_to_ix['hello']],dtype=torch.long) # 索引必须是Long型的tensor
print(lookup_tensor) # 索引
hello_embed = embeds(lookup_tensor)
print(hello_embed) # 词的向量表示,现在没有训练,所以是随机的
- 输出如下
tensor([0]) #print(lookup_tensor)
tensor([[ 0.6614, 0.2669, 0.0617, 0.6213, -0.4519]],
grad_fn=<EmbeddingBackward>) #print(hello_embed)
一般的处理方法
- 例如,以下面的句子为例
test_sentence = """When forty winters shall besiege thy brow,
And dig deep trenches in thy beauty's field,
Thy youth's proud livery so gazed on now,
Will be a totter'd weed of small worth held:
Then being asked, where all thy beauty lies,
Where all the treasure of thy lusty days;
To say, within thine own deep sunken eyes,
Were an all-eating shame, and thriftless praise.
How much more praise deserv'd thy beauty's use,
If thou couldst answer 'This fair child of mine
Shall sum my count, and make my old excuse,'
Proving his beauty by succession thine!
This were to be new made when thou art old,
And see thy blood warm when thou feel'st it cold.""".split()
- 建立的字典如下:
vocab = set(test_sentence) # 去重
word_to_ix = {word: i for i, word in enumerate(vocab)} # 一个词对应一个下标
print(word_to_ix)
- 输入的结果如下:
{"'This": 0, 'When': 1, "youth's": 2, 'Thy': 3, 'held:': 4, 'Were': 5, 'praise.': 6, "totter'd": 7, 'thine': 8, 'couldst': 9, 'small': 10, 'in': 11, 'gazed': 12, 'beauty': 13, 'thou': 14, 'count,': 15, 'of': 16, 'by': 17, 'on': 18, 'it': 19, 'own': 20, 'my': 21, 'praise': 22, 'to': 23, "beauty's": 24, 'deep': 25, 'This': 26, 'art': 27, 'sum': 28, 'And': 29, 'the': 30, 'now,': 31, 'livery': 32, 'made': 33, 'see': 34, 'days;': 35, 'fair': 36, 'thine!': 37, 'trenches': 38, 'shall': 39, 'thriftless': 40, 'How': 41, 'where': 42, 'treasure': 43, 'say,': 44, 'his': 45, 'Then': 46, 'To': 47, 'shame,': 48, 'mine': 49, 'worth': 50, 'Will': 51, 'sunken': 52, 'child': 53, 'If': 54, 'old,': 55, 'a': 56, 'asked,': 57, 'being': 58, 'Proving': 59, "feel'st": 60, 'all': 61, 'besiege': 62, 'use,': 63, 'answer': 64, 'succession': 65, 'brow,': 66, 'blood': 67, 'were': 68, 'new': 69, "excuse,'": 70, 'dig': 71, 'so': 72, 'lusty': 73, 'all-eating': 74, 'proud': 75, 'much': 76, 'cold.': 77, 'winters': 78, 'Shall': 79, 'forty': 80, 'thy': 81, 'be': 82, 'old': 83, 'lies,': 84, 'warm': 85, 'within': 86, 'make': 87, 'weed': 88, "deserv'd": 89, 'when': 90, 'Where': 91, 'more': 92, 'and': 93, 'field,': 94, 'an': 95, 'eyes,': 96}
创建一个神经网络
- 继承Module
import torch
import torch.nn as nn # 损失函数,全连接等
import torch.nn.functional as F # 激活函数等
import torch.optim as optim # 优化器,梯度下降等
- 必须调用父类构造函数
class NGramLanguageModeler(nn.Module):
def __init__(self, vocab_size, embedding_dim, context_size):
super(NGramLanguageModeler, self).__init__() # 调用父类的构造函数
pass
- 必须实现forward函数
class NGramLanguageModeler(nn.Module):
def __init__(self, vocab_size, embedding_dim, context_size):
super(NGramLanguageModeler, self).__init__() # 调用父类的构造函数
pass
def forward(self,input_data): # 必须实现
pass
创建训练数据
- 有监督数据就要建立一个训练数据元祖
,神经网络输入
,我们的目标是通过训练得到
创建损失函数
loss_function = nn.NLLLoss()
初始化
model = NGramLanguageModeler(len(vocab), EMBEDDING_DIM, CONTEXT_SIZE)
选择一个优化器
- 就是反向传播时用什么去优化,最基础的就是梯度下降(SGD)
- lr就是学习率
- 所有更新的参数在model.parameters()中
# 直接用这个更新
optimizer = optim.SGD(model.parameters(), lr=0.001)
一个完整的训练过程
for epoch in range(10): # 这里就训练了10个epoch
total_loss = 0
for context, target in trigrams:# context是前两个词,target是第三个词
# 获取context中词的表示[1,80],转换为tensor
context_idxs = torch.tensor([word_to_ix[w] for w in context] , dtype=torch.long)
model.zero_grad() # 每一轮梯度归零
#像调用方法一样调用实例化的对象,其直接执行forward方法
log_probs = model(context_idxs) # 得到模型的输出
# 损失函数,输出和目标的tensor
loss = loss_function(log_probs, torch.tensor([word_to_ix[target]], dtype=torch.long))
loss.backward() # 反向传播
optimizer.step()# 更新参数
total_loss += loss.item() # 统计损失函数
losses.append(total_loss)# 每一轮的损失函数结果放入列表,方便以后作图等
N-Gram模型的处理
- 设定N-Gram中的N,即,根据几个词判断下一个词,一般设置为2, CONTEXT_SIZE = 2
trigrams = [([test_sentence[i], test_sentence[i + 1]], test_sentence[i + 2]) for i in range(len(test_sentence) - 2)]
# 输出前3行,先看下是什么样子。
print(trigrams[:3])
- 输出前3行,先看下是什么样子
[(['When', 'forty'], 'winters'), (['forty', 'winters'], 'shall'), (['winters', 'shall'], 'besiege')]
-
上面输出的每个元祖就是我们的一个训练数据,比如根据'When', 'forty' 预测下一个词是'winters'
-
在神经网络中,要用到词嵌入
class NGramLanguageModeler(nn.Module):
def __init__(self, vocab_size, embedding_dim, context_size):
super(NGramLanguageModeler, self).__init__()
# 这里就是词嵌入,表示vocab_size个词在embedding_dim维空间
self.embeddings = nn.Embedding(vocab_size, embedding_dim)
self.linear1 = nn.Linear(context_size * embedding_dim, 128) # 2个词的词向量作为第一个参数
self.linear2 = nn.Linear(128, vocab_size)
def forward(self, inputs):
embeds = self.embeddings(inputs).view((1, -1))
out = F.relu(self.linear1(embeds))
out = self.linear2(out)
log_probs = F.log_softmax(out, dim=1)
return log_probs
- 神经网络的输入是:
比如对于(['When', 'forty'], 'winters')这个训练数据,输入的就是tensor([ 1, 80]) ,When的value是1,forty对应的value是80
# 获取context中词的表示[1,80],转换为tensor
context_idxs = torch.tensor([word_to_ix[w] for w in context] , dtype=torch.long)
- 神经网络的目标是:
比如对于(['When', 'forty'], 'winters')这个训练数据,target就是'winters',目标就是tensor([78]) ,'winters'对应的value就是78
torch.tensor([word_to_ix[target]], dtype=torch.long)
连续词袋模型的处理(CBOW)
- 和N-Gram不同之处就是它是根据中心词预测周围的词
所以下面的程序中context就是一个词的前后两个词,target就是目标词
for i in range(2 ,len(test_sentence ) - 2):
context = [raw_text[i - 2], raw_text[i - 1], raw_text[i + 1], raw_text[i + 2]]
target = raw_text[i]
data.append((context,target))
print(data[:5])
- 输出的前五个训练数据
[(['When', 'forty', 'shall', 'besiege'], 'winters'), (['forty', 'winters', 'besiege', 'thy'], 'shall'), (['winters', 'shall', 'thy', 'brow,'], 'besiege'), (['shall', 'besiege', 'brow,', 'And'], 'thy'), (['besiege', 'thy', 'And', 'dig'], 'brow,')]
- 输入数据和N-Gram也不同
以(['When', 'forty', 'shall', 'besiege'], 'winters')为列子,我们是根据'When', 'forty', 'shall', 'besiege'预测其中的单词'winters'
def make_context_vector(context, word_to_ix):
idxs = [word_to_ix[w] for w in context]
return torch.tensor(idxs, dtype=torch.long)
print(make_context_vector(data[0][0],word_to_ix))# 例子
上面的程序输出为:When 的value是1,'forty'的value是83,shall是39,besiege是62
tensor([1, 80, 39, 62])
- 然后通过上面得到的tensor在词嵌入矩阵索引到词的向量表示,作为输入给神经网络
网友评论