循环神经网络

允我心安 提交于 2020-02-15 00:59:36

文本预处理

  1. 读入文本
  2. 分词
  3. 建立字典,将每个词映射到一个唯一的索引(index)
  4. 将文本从词的序列转换为索引的序列,方便输入模型
import spacy
nlp = spacy.load('en_core_web_sm')
doc = nlp(text)
print([token.text for token in doc])

from nltk.tokenize import word_tokenize
from nltk import data
data.path.append('/home/kesci/input/nltk_data3784/nltk_data')
print(word_tokenize(text))

语言模型

n元语法
P(w1,w2,,wT)=t=1TP(wtwt(n1),,wt1) P(w_1, w_2, \ldots, w_T) = \prod_{t=1}^T P(w_t \mid w_{t-(n-1)}, \ldots, w_{t-1})
缺点:

  1. 参数空间过大 :预测第n词需要保存前n-1个词的状态
  2. 数据稀疏 : 有很多搭配是不存在的,但是其为的状态还是会保存在状态空间中

文本采样

时序采样:有文本头开始按时序向后移动,依次生成样本和相应的标签,缺点有大量重合部分

随机采样:将文本按照时间步数等分(不足的部分抛弃),每次按batchsize往外取

相邻采样:将文本按batch_size等分(不足部分抛弃),每次从每段中取出时间步数的长度

循环卷积网络基础

XtRn×d  HtRn×h  WxhRd×h  WhhRh×h  bhR1×h  Ht=ϕ(XtWxh+Ht1Whh+bh)WhqRh×q  bqR1×qOt=HtWhq+bq \boldsymbol{X}_t \in \mathbb{R}^{n \times d} \ \ \boldsymbol{H}_t \in \mathbb{R}^{n \times h} \ \ \boldsymbol{W}_{xh} \in \mathbb{R}^{d \times h} \ \ \boldsymbol{W}_{hh} \in \mathbb{R}^{h \times h} \ \ \boldsymbol{b}_{h} \in \mathbb{R}^{1 \times h} \ \ \\ \boldsymbol{H}_t = \phi(\boldsymbol{X}_t \boldsymbol{W}_{xh} + \boldsymbol{H}_{t-1} \boldsymbol{W}_{hh} + \boldsymbol{b}_h) \\ \boldsymbol{W}_{hq} \in \mathbb{R}^{h \times q} \ \ \boldsymbol{b}_q \in \mathbb{R}^{1 \times q} \\ \boldsymbol{O}_t = \boldsymbol{H}_t \boldsymbol{W}_{hq} + \boldsymbol{b}_q

one-Hot编码:每个词对应一个长度和字典相同,对应序号存1,其余存0的向量。

梯度裁剪(解决梯度爆炸)
min(θg,1)gg=iGgi2 \min\left(\frac{\theta}{\|\boldsymbol{g}\|}, 1\right)\boldsymbol{g} \\ ||g|| = \sqrt {\sum_{i \in G }g_i^2}
θ为裁剪阈值,裁剪后梯度的L2范数不超过θ。

困惑度

困惑度是对交叉熵损失函数做指数运算后得到的值。特别地,

  • 最佳情况下,模型总是把标签类别的概率预测为1,此时困惑度为1;
  • 最坏情况下,模型总是把标签类别的概率预测为0,此时困惑度为正无穷;
  • 基线情况下,模型总是预测所有类别的概率都相同,此时困惑度为类别个数。

词语预测训练的不同

  1. 使用困惑度评价模型。
  2. 在迭代模型参数前裁剪梯度。
  3. 对时序数据采用不同采样方法将导致隐藏状态初始化的不同。

示例:


class RNNModel(nn.Module):
    def __init__(self, num_hiddens, vocab_size):
        super(RNNModel, self).__init__()
        self.rnn = nn.RNN(input_size=vocab_size, hidden_size=num_hiddens)
        #词向量的大小 和rnn层的隐藏元个数
        self.hidden_size = rnn_layer.hidden_size * (2 if rnn_layer.bidirectional else 1) 
        self.vocab_size = vocab_size
        self.dense = nn.Linear(self.hidden_size, vocab_size)

    def forward(self, inputs, state):
        # inputs.shape: (batch_size, num_steps)
        X = to_onehot(inputs, vocab_size)
        X = torch.stack(X)  # X.shape: (num_steps, batch_size, vocab_size)
        hiddens, state = self.rnn(X, state)
        hiddens = hiddens.view(-1, hiddens.shape[-1])  # hiddens.shape: (num_steps * batch_size, hidden_size)
        output = self.dense(hiddens)
        return output, state #输出预测输出,隐藏状态
        #[num_step,batchsize,num_hidens]  [1,batchsize,num_hidens]
        
 #########################训练##########################       
     #如使用随机采样,在每个小批量更新前初始化隐藏状态  
     #如使用相邻采样,在epoch开始时初始化隐藏状态
def train_and_predict_rnn_pytorch(model, num_hiddens, vocab_size, device,
                                corpus_indices, idx_to_char, char_to_idx,
                                num_epochs, num_steps, lr, clipping_theta,
                                batch_size, pred_period, pred_len, prefixes):
    loss = nn.CrossEntropyLoss()
    optimizer = torch.optim.Adam(model.parameters(), lr=lr)
    model.to(device)
    for epoch in range(num_epochs):
        l_sum, n, start = 0.0, 0, time.time()
        data_iter = d2l.data_iter_consecutive(corpus_indices, batch_size, num_steps, device) # 相邻采样
        state = None
        for X, Y in data_iter:
            if state is not None:
                # 使用detach函数从计算图分离隐藏状态
                if isinstance (state, tuple): # LSTM, state:(h, c)  
                    state[0].detach_()
                    state[1].detach_()
                else: 
                    state.detach_()
            (output, state) = model(X, state) # output.shape: (num_steps * batch_size, vocab_size)
            y = torch.flatten(Y.T)
            l = loss(output, y.long())
            
            optimizer.zero_grad()
            l.backward()
            grad_clipping(model.parameters(), clipping_theta, device)
            optimizer.step()
            l_sum += l.item() * y.shape[0]
            n += y.shape[0]
        

        if (epoch + 1) % pred_period == 0:
            print('epoch %d, perplexity %f, time %.2f sec' % (
                epoch + 1, math.exp(l_sum / n), time.time() - start))
            for prefix in prefixes:
                print(' -', predict_rnn_pytorch(
                    prefix, pred_len, model, vocab_size, device, idx_to_char,
                    char_to_idx))
                
  #########################预测#############################

def predict_rnn_pytorch(prefix, num_chars, model, vocab_size, device, idx_to_char,
                      char_to_idx):
    state = None
    output = [char_to_idx[prefix[0]]]  # output记录prefix加上预测的num_chars个字符
    for t in range(num_chars + len(prefix) - 1):
        X = torch.tensor([output[-1]], device=device).view(1, 1)
        (Y, state) = model(X, state)  # 前向计算不需要传入模型参数
        if t < len(prefix) - 1:
            output.append(char_to_idx[prefix[t + 1]])
        else:
            output.append(Y.argmax(dim=1).item())
    return ''.join([idx_to_char[i] for i in output])
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!