赞
踩
处理序列数据应选用新的深度神经网络架构RNN。
这里我们所使用的数据发生了变化,包含了一个时间维度。
并且不同于之前的图像分类与识别,这里我们的数据之间是具有相关性的。
1、自回归模型(autoregressive models)
2、隐变量自回归模型(latent autoregressive models)
在自回归模型的近似法中,使用 x(t-1) , … , x(t-τ),而不是 x(t-1) , … , x1 来估计 xt ,如果这种假设是成立的,也就是近似是精确的,可以称为满足马尔科夫条件( Markov condition )
如果 t=1,得到一个 一阶马尔可夫模型(first-order Markov model)
文本预处理的核心思想是如何将文本中的词转化成能够训练的样本。
本节中,我们将解析文本的常见预处理步骤。 这些步骤通常包括:
import collections
import re
from d2l import torch as d2l
d2l.DATA_HUB['time_machine'] = (d2l.DATA_URL + 'timemachine.txt', '090b5e7e70c295757f55df93cb0a180b9691891a')
def read_time_machine():
"""将数据集加载到文本行的列表中"""
with open(d2l.download('time_machine'), 'r') as f:
lines = f.readlines()
return [re.sub('[^A-Za-z]+', ' ', line).strip().lower() for line in lines]
"""去掉回车 将所有字母全部变成小写"""
lines = read_time_machine()
每个文本序列又被拆分成一个词元列表,词元(token)是文本的基本单位。 最后,返回一个由词元列表组成的列表,其中的每个词元都是一个字符串(string)。
tokenize 是 NLP 中一个比较常见的操作:将一个句子或者是一段文字转化成 token(字符串、字符或者是词)
def tokenize(lines, token='word'): #将文本行列表(lines)作为输入
"""将文本行拆分为单词或字符词元"""
if token == 'word':
return [line.split() for line in lines]
elif token == 'char':
return [list(line) for line in lines]
else:
print('错误:未知词元类型:' + token)
tokens = tokenize(lines)
词元的类型是字符串,而模型需要的输入是数字,因此这种类型不方便模型使用。 现在,让我们构建一个字典,通常也叫做词表(vocabulary), 用来将字符串类型的词元映射到从开始的数字索引中。
将拆分的词元映射到数字索引:将文本转换为数字索引序列,方便模型操作。
class Vocab: """文本词表""" def __init__(self, tokens=None, min_freq=0, reserved_tokens=None): if tokens is None: tokens = [] if reserved_tokens is None: reserved_tokens = [] # 按出现频率排序 counter = count_corpus(tokens) self._token_freqs = sorted(counter.items(), key=lambda x: x[1], reverse=True) # 未知词元的索引为0 self.idx_to_token = ['<unk>'] + reserved_tokens self.token_to_idx = {token: idx for idx, token in enumerate(self.idx_to_token)} for token, freq in self._token_freqs: if freq < min_freq: break if token not in self.token_to_idx: self.idx_to_token.append(token) self.token_to_idx[token] = len(self.idx_to_token) - 1 def __len__(self): return len(self.idx_to_token) def __getitem__(self, tokens): if not isinstance(tokens, (list, tuple)): return self.token_to_idx.get(tokens, self.unk) return [self.__getitem__(token) for token in tokens] def to_tokens(self, indices): if not isinstance(indices, (list, tuple)): return self.idx_to_token[indices] return [self.idx_to_token[index] for index in indices] @property def unk(self): # 未知词元的索引为0 return 0 @property def token_freqs(self): return self._token_freqs def count_corpus(tokens): #@save """统计词元的频率""" # 这里的tokens是1D列表或2D列表 if len(tokens) == 0 or isinstance(tokens[0], list): # 将词元列表展平成一个列表 tokens = [token for line in tokens for token in line] return collections.Counter(tokens)
什么是RNN模型?
RNN(Recurrent Neural Network)。中文称作循环神经网络,它一般以序列数据为输入,通过网络内部的结构设计有效捕捉序列之间的关系特征。一般也是以序列形式进行输出。
例如:给机器输入 What time is it?
经过4次循环,分析最终的输出O5来判断用户输入的信息。
① 按照输入和输出结构进行分类
N vs N - RNN
它是RNN最基础的结构形式,最大的特点就是:输入和输出序列是等长的。由于这个限制的存在,使其适用范围比较小,可用于生成等长度的合辙诗句。
N vs 1 - RNN
有时候我们要处理的问题输入是一个序列,而要求输出是一个单独的值而不是序列,我们只要在最后一个隐层输出h,上进行线性变换就可以了,大部分情况下,为了更好的明确结果,还要使用sigmold或者softmax进行处理。这种结构经常被应用在文本分类问题上。
1 vs N - RNN
如果输入不是序列而输出为序列的情况怎么处理呢?我们最常采用的一种方式就是使该输入作用于每次的输出之上。这种结构可用于将图片生成文字任务等。
N vs M - RNN
这是一种不限输入输出长度的RNN结构,它由编码器和解码器两部分组成。两者的内部结构都是某类RNN,它也被称为seq2seq架构。输入数据首先通过编码器,最终输出一个隐含变量c,之后最常用的做法是使用这个隐含变量c作用在解码器进行解码的每一步上,以保证输入信息被有效利用。
② 按照RNN内部结构进行分类
下面根据此分类方法一一介绍。
激活函数tanh的作用:用于帮助调节流经网络的值,tanh函数将值压缩在-1和1之间.
#导入若干工具包 import torch import torch.nn as nn #实例化rnn对象 #第一个参数: input_size(输入张量x的维度) #第二个参数: hidden_size(隐藏层的维度,隐藏层神经元数量) #第三个参数: num_.layers(隐藏层的层数) rnn = nn.RNN(5, 6, 1) #设定输入的张量x #第一个参数: sequence_.length(输入序列的长度) #第二个参数: batch_size (批次的样本数) #第三个参数: input_size(输入张量x的维度) input1 = torch.randn(1, 3, 5) #设定初始化的h0 #第一个参数: num_layers * num_ directions (层数*网络方向数) #第二个参数: batch_size (批次的样本数) #第三个参数: hidden_size(隐藏层的维度) h0 = torch.randn(1, 3, 6) #输入张量放入RNN 得到输出结果 output, hn = rnn(input1, h0) print(output) print(output.shape) print(hn) print(hn.shape) ----------------------------------------- tensor([[[ 0.2020, 0.3738, 0.8060, -0.6857, -0.6111, 0.6123], [-0.9363, 0.3544, -0.2019, 0.8183, -0.1817, -0.6506], [-0.6587, 0.6482, -0.8166, -0.5486, -0.0163, 0.7191]]], grad_fn=<StackBackward0>) torch.Size([1, 3, 6]) tensor([[[ 0.2020, 0.3738, 0.8060, -0.6857, -0.6111, 0.6123], [-0.9363, 0.3544, -0.2019, 0.8183, -0.1817, -0.6506], [-0.6587, 0.6482, -0.8166, -0.5486, -0.0163, 0.7191]]], grad_fn=<StackBackward0>) torch.Size([1, 3, 6])
LSTM (Long Short-Term Memory)也称长短期记忆结构,它是传统RNN的变体,与经典RNN相比能够有效捕捉长序列之间的语义关联缓解梯度消失或爆炸现象。同时LSTM的结构更复杂,它的核心结构可以分为四个部分去解析:遗忘门、输入门、细胞状态、输出门
遗忘门:代表遗忘过去多少的信息
输入门
细胞状态更新图
输出门
#导入若干工具包 import torch import torch.nn as nn #实例化LSTM对象 #第一个参数: input_size(输入张量x的维度) #第二个参数: hidden_size(隐藏层的维度, 隐藏层的神经元数量) #第三个参数: num_layers (隐藏层的层数) lstm = nn.LSTM(5, 6, 2) #初始化输入张量x #第一个参数: sequence_length(输入序列的长度) #第二个参数: batch_size(批次的样本数量) #第三个参数: input_size(输入张量x的维度) input1 = torch. randn(1, 3, 5) #初始化隐藏层张量h0,和细胞状态c0 #第一个参数: num_layers * num_directions (隐藏层的层数*方向数. #第二个参数: batch_size (批次的样本数量) #第三个参数: hidden_size(隐藏层的维度) h0 = torch. randn(2, 3, 6) c0 = torch. randn(2, 3, 6) #将inputI, h0, c0输入lstm中, 得到输出张量结果 output, (hn, cn) = lstm(input1, (h0, c0)) print (output) print (output.shape) print (hn) print (hn.shape) print(cn) print (cn.shape) --------------------------------------- tensor([[[-0.0356, 0.1013, -0.4488, -0.2720, -0.0605, -0.2809], [-0.0743, 0.3319, 0.1953, 0.3076, -0.4295, 0.0784], [-0.2240, 0.1658, 0.1031, 0.3426, -0.2790, 0.3442]]], grad_fn=<StackBackward0>) torch.Size([1, 3, 6]) tensor([[[ 0.1035, 0.0796, -0.0350, 0.3091, -0.0084, -0.0795], [ 0.1013, 0.4979, -0.3049, 0.3802, 0.2845, -0.1771], [ 0.0804, -0.2093, -0.0581, -0.3859, 0.3678, -0.2731]], [[-0.0356, 0.1013, -0.4488, -0.2720, -0.0605, -0.2809], [-0.0743, 0.3319, 0.1953, 0.3076, -0.4295, 0.0784], [-0.2240, 0.1658, 0.1031, 0.3426, -0.2790, 0.3442]]], grad_fn=<StackBackward0>) torch.Size([2, 3, 6]) tensor([[[ 0.1972, 0.1682, -0.0902, 0.9651, -0.0115, -0.1569], [ 0.1968, 1.4286, -0.5794, 0.9468, 0.7288, -0.3405], [ 0.2432, -1.5347, -0.1129, -1.4662, 0.5249, -0.6214]], [[-0.0889, 0.4005, -1.2702, -0.5516, -0.0938, -0.6681], [-0.1985, 0.6989, 0.4673, 1.0849, -0.7235, 0.2078], [-0.4790, 0.4915, 0.3270, 0.6981, -0.6362, 0.6638]]], grad_fn=<StackBackward0>) torch.Size([2, 3, 6])
GRU (Gated Recurrent Unit) 也称控循环单元结构。它也是传统RNN的变体,同LSTM一样能够有效捕捉长序列之间的语义关联,缓解梯度消失或爆炸现象。同时它的结构和计算要比LSTM更简单,它的核心结构可以分为两个部分去解析:更新门、重置门。
#实例化GRU对象 #第一个参数: input_size(输入张量x的维度) #第二个参数: hidden_size(隐藏层的维度, 隐藏层神经元的数量) #第三个参数: num_layers (隐藏层的层数) gru = nn. GRU(5, 6, 2) #初始化输入张量input1 #第一个参数: sequence_.length(序列的长度) #第二个参数: batch_size(批次的样本个数) #第三个参数: input_size(输入张量x的维度) input1 = torch.randn(1, 3, 5) #初始化隐藏层的张量h0 #第一个参数: num_layers * num_ _di rections (隐藏层的层数*方向数) #第二个参数: batch_size(批次的样本个数) #第三个参数: hidden_size(隐藏层的维度) h0 = torch. randn(2, 3, 6) #将input1, h0输入GRU中, 得到输出张量结果 output, hn = gru(input1, h0) print (output) print (output. shape) print (hn) print (hn. shape )
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。