0.文本处理整体概况
step1:对原始数据进行分词
step2:对分词后的数据进行去重编号,得到[词语to序号]的列表,和[序号to词语]的字典。将这两部分用作后续训练循环神经网络的数据集。
step3:通过一些采样方法对构建的数据集进行采样,得到训练的批次。常见的采样方法有随机采样和相邻采样。
step4:利用语言模型对上述的数据集进行训练,得到一个nlp模型。语言模型有n元语法模型,RNN模型,LSTM模型等。
1.使用spacy可以进行语言分词
达到很好的直观效果,相较于自己构建的逻辑,更加符合语言本身词意的分词操作,且可以将分词对应的idx对应输出。
import spacy
text = "Mr. Chen doesn't agree with my suggestion."
nlp = spacy.load('en_core_web_sm')
doc = nlp(text)
print([token.text for token in doc])
print([token.idx for token in doc])
#------------------
['Mr.', 'Chen', 'does', "n't", 'agree', 'with', 'my', 'suggestion', '.']
[0, 4, 9, 13, 17, 23, 28, 31, 41]
2.随机采样和相邻采样
2.1 随机采样
下面的代码每次从数据里随机采样一个小批量。其中批量大小batch_size是每个小批量的样本数,num_steps是每个样本所包含的时间步数。 在随机采样中,每个样本是原始序列上任意截取的一段序列,相邻的两个随机小批量在原始序列上的位置不一定相毗邻。
import torch
import random
def data_iter_random(corpus_indices, batch_size, num_steps, device=None):
# 减1是因为对于长度为n的序列,X最多只有包含其中的前n - 1个字符
num_examples = (len(corpus_indices) - 1) // num_steps # 下取整,得到不重叠情况下的样本个数
example_indices = [i * num_steps for i in range(num_examples)] # 每个样本的第一个字符在corpus_indices中的下标
random.shuffle(example_indices)
def _data(i):
# 返回从i开始的长为num_steps的序列
return corpus_indices[i: i + num_steps]
if device is None:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
for i in range(0, num_examples, batch_size):
# 每次选出batch_size个随机样本
batch_indices = example_indices[i: i + batch_size] # 当前batch的各个样本的首字符的下标
X = [_data(j) for j in batch_indices]
Y = [_data(j + 1) for j in batch_indices]
yield torch.tensor(X, device=device), torch.tensor(Y, device=device)
2.2 相邻采样
在相邻采样中,相邻的两个随机小批量在原始序列上的位置相毗邻。
def data_iter_consecutive(corpus_indices, batch_size, num_steps, device=None):
if device is None:
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
corpus_len = len(corpus_indices) // batch_size * batch_size # 保留下来的序列的长度
corpus_indices = corpus_indices[: corpus_len] # 仅保留前corpus_len个字符
indices = torch.tensor(corpus_indices, device=device)
indices = indices.view(batch_size, -1) # resize成(batch_size, )
batch_num = (indices.shape[1] - 1) // num_steps
for i in range(batch_num):
i = i * num_steps
X = indices[:, i: i + num_steps]
Y = indices[:, i + 1: i + num_steps + 1]
yield X, Y
3.语言模型
语言模型的目标就是给定一个通过分词得到的词序列,并且评估该序列是否合理,即计算该序列的概率。语言模型从最初的n-gram方法受限于模型参数大,参数稀疏,计算效率低等不足,发展到现在的基于深度学习的RNN,LSTM等方法,大大的提高了语言模型的能力。
3.1 n-gram
如下描述所示,n-gram语言模型是一种基于统计的方法。该方法通过分词在语料库中的比重
以及条件概率
构建概率模型。由于条件概率的存在,该方法的最终计算需要基于n阶马尔科夫假设。且该方法由于基于分词在语料库中的比重,从而导致很多分词的出现频次很少甚至为零,导致得到的值的稀疏性太强,计算效率低。
3.2 RNN递归神经网络模型
如下描述所示,递归神经网络RNN是一种基于参数学习的语言模型。该类模型通过中间状态位的保留,隐式的实现了上述概率模型中的条件概率模型。而且此种方法学习友好,使用方便。且如下代码所示,RNN模型的参数与输入输出的时间步数无关,因此模型的复用性很强。
vocab_size = 1027
num_inputs, num_hiddens, num_outputs = vocab_size, 256, vocab_size
# num_inputs: d
# num_hiddens: h, 隐藏单元的个数是超参数
# num_outputs: q
def get_params():
def _one(shape):
param = torch.zeros(shape, device=device, dtype=torch.float32)
nn.init.normal_(param, 0, 0.01)
return torch.nn.Parameter(param)
# 隐藏层参数
W_xh = _one((num_inputs, num_hiddens))
print(W_xh.shape)
W_hh = _one((num_hiddens, num_hiddens))
print(W_hh.shape)
b_h = torch.nn.Parameter(torch.zeros(num_hiddens, device=device))
# 输出层参数
W_hq = _one((num_hiddens, num_outputs))
print(W_hq.shape)
b_q = torch.nn.Parameter(torch.zeros(num_outputs, device=device))
return (W_xh, W_hh, b_h, W_hq, b_q)
get_params()
print(num_inputs, num_hiddens, num_outputs)
#--------------------
torch.Size([1027, 256])
torch.Size([256, 256])
torch.Size([256, 1027])
1027 256 1027
网友评论