Pytorch学习记录-更深的TorchText学习02

Pytorch学习记录-更深的TorchText学习02
简单实现torchtext之后,我希望能够进一步学习torchtext。找到两个教程

1. practical-torchtext简介

有效使用torchtext的教程,包括两个部分

  • 文本分类
  • 词级别的语言模型

3. 词级别的语言模型

在本教程中,我们将看到如何使用torchtext中的内置数据集训练语言模型。
教程还将介绍在培训您自己的实用模型时可能需要使用的一些更实用的torchtext功能。

3.1 什么是语言模型

语言建模是构建模型的任务,该模型可以将一系列单词作为输入,并确定该序列作为实际人类语言的可能性。例如,我们希望我们的模型预测“这是一个句子”是一个可能的序列,而“冷却他的书”是不可能的。
通常训练语言模型的方法是训练他们预测下一个单词给出句子中的所有先前单词或多个句子。因此,我们所需要做的语言建模都是大量的语言数据(称为语料库)。
在本教程中,我们将使用着名的WikiText2数据集。

USE_GPU=True
BATCH_SIZE=32

3.2 准备数据

注意
这里会使用spacy作为分词器,torchtext很容易使用spacy作为分词器:我们所要做的就是传递spacy函数。

import torchtext
from torchtext import data
import spacy
from spacy.symbols import ORTH

# 
my_tok=spacy.load('en')
my_tok.tokenizer.add_special_case('<eos>',[{ORTH:'<eos>'}])
my_tok.tokenizer.add_special_case('<bos>',[{ORTH:'<bos>'}])
my_tok.tokenizer.add_special_case('<unk>',[{ORTH:'<unk>'}])
# 这里使用add_special_case,add_special_case只是告诉tokenizer以某种方式解析某个字符串。特殊情况字符串后面的列表表示我们希望如何对字符串进行标记化。
# 举例,如果我们希望将don't分词为do和n't,就可以这样写
# my_tok.tokenizer.add_special_case("don't", [{ORTH: "do"}, {ORTH: "n't"}])
def spacy_tok(x):
    return [tok.text for tok in my_tok.tokenizer(x)]

# 使用spacy分词之后,就要将分词结果放入Field中
TEXT=data.Field(lower=True, tokenize=spacy_tok)

接下来就可以加载内置数据集,在这里有两种方式进行加载

  1. 通过加载Dataset到训练集、验证集和测试集
  2. 作为迭代器加载

dataset提供了更大的方便,教程使用数据集进行加载
教程在这里使用的是WikiText2数据集。
在这里出现了一些问题,这个教程和之前我们做的那个构建语言模型的很类似,但是在这里它是现场下载抽取,我还是放弃这么做了,直接使用之前下载好的Glove词向量,处理确实很慢。

from torchtext.datasets import WikiText2
train, valid, test=WikiText2.splits(TEXT)

现在我们有了数据,建立词汇表。这一次,让我们尝试使用预先计算的单词嵌入。
这次我们将使用200维的GloVe向量。在torchtext中还有各种其他预先计算的单词嵌入(包括具有100和300维度的GloVe向量),它们可以以大致相同的方式加载。

TEXT.build_vocab(train, vectors="glove.6B.200d")

3.3 构建迭代器

搞定之后就可以构建迭代器了。
经过这两天的学习,总结一下流程哈。

  • 处理原始数据,英文直接用分词器,中文应该也是类似的。生成的结果是一个Field格式的TEXT(或者其他什么鬼)
  • 基于这个TEXT,使用数据集记载成为训练集、验证集、测试集
  • 建立词汇表,使用预训练好的词向量进行嵌入。(卧槽,这个嵌入的意思是不是说将已有的或是预先训练好的词向量和我们的数据集/语料库进行整合完成对语料库的嵌入?)很明显我理解错了。在这里提出一个问题语料库、词向量、词嵌入、语言模型之间的关系是什么?
  • 构建迭代器,处理text和target
  • 构建模型
  • 数据放进去训练、验证、测试

在这里和之前的Iterator、BucketIterator不同,这里使用了另一个迭代器BPTTIterator
BPTTIterator为我们做了以下事情:

  1. 将语料库分成序列长度为bptt的批次。
    例如,假设我们有以下语料库:

“Machine learning is a field of computer science that gives computers the ability to learn without being explicitly programmed.”

虽然这个句子很短,但实际的语料库长达数千字,所以我们不可能一次性地提供它。我们想要将语料库划分为更短的序列。在上面的例子中,如果我们想将语料库划分为序列长度为5的批次,我们将得到以下序列:

["Machine", "learning", "is", "a", "field"],
["of", "computer", "science", "that", "gives"],
["computers", "the", "ability", "to", "learn"],
["without", "being", "explicitly", "programmed", EOS]

  1. 生成作为输入序列偏移的批次。
    在语言建模中,监督数据是单词序列中的下一个单词。因此,我们希望生成输入序列偏移1的序列(就是单词后移一个)。在上面的例子中,我们将得到以下序列,我们训练模型进行预测:

["learning", "is", "a", "field", "of"],
["computer", "science", "that", "gives", "computers"],
["the", "ability", "to", "learn", "without"],
["being", "explicitly", "programmed", EOS, EOS]

train_iter, valid_iter, test_iter = data.BPTTIterator.splits(
    (train, valid, test),
    batch_size=BATCH_SIZE,
    bptt_len=30, # 这个就是我们特别提到的句子长度
    device=-1,
    repeat=False)
The `device` argument should be set by using `torch.device` or passing a string as an argument. This behavior will be deprecated soon and currently defaults to cpu.
The `device` argument should be set by using `torch.device` or passing a string as an argument. This behavior will be deprecated soon and currently defaults to cpu.
The `device` argument should be set by using `torch.device` or passing a string as an argument. This behavior will be deprecated soon and currently defaults to cpu.
b = next(iter(train_iter))
vars(b).keys()

dict_keys(['batch_size', 'dataset', 'fields', 'text', 'target'])

在这里我们可以看一下测试的结果,查看b中的text和target的内容。
输出结果中target顺移一位。搞定了可以开始训练模型了。

b.text[:, :3]
tensor([[    9,   953,     0],
        [   10,   324,  5909],
        [    9,    11, 20014],
        [   12,  5906,    27],
        [ 3872, 10434,     2],
        [ 3892,     3, 10780],
        [  886,    11,  3273],
        [   12,  9357,     0],
        [   10,  8826, 23499],
        [    9,  1228,     4],
        [   10,     7,   569],
        [    9,     2,   235],
        [20059,  2592,  5909],
        [   90,     3,    20],
        [ 3872,   141,     2],
        [   95,     8,  1450],
        [   49,  6794,   369],
        [    0,  9046,     5],
        [ 3892,  1497,     2],
        [   24,    13,  2168],
        [  786,     4,   488],
        [   49,    26,  5967],
        [28867,    25,   656],
        [    3, 18430,    14],
        [ 6213,    58,    48],
        [    4,  4886,  4364],
        [ 3872,   217,     4],
        [    5,     5,    22],
        [    2,     2,  1936],
        [ 5050,   593,    59]])
b.target[:, :3]
tensor([[   10,   324,  5909],
        [    9,    11, 20014],
        [   12,  5906,    27],
        [ 3872, 10434,     2],
        [ 3892,     3, 10780],
        [  886,    11,  3273],
        [   12,  9357,     0],
        [   10,  8826, 23499],
        [    9,  1228,     4],
        [   10,     7,   569],
        [    9,     2,   235],
        [20059,  2592,  5909],
        [   90,     3,    20],
        [ 3872,   141,     2],
        [   95,     8,  1450],
        [   49,  6794,   369],
        [    0,  9046,     5],
        [ 3892,  1497,     2],
        [   24,    13,  2168],
        [  786,     4,   488],
        [   49,    26,  5967],
        [28867,    25,   656],
        [    3, 18430,    14],
        [ 6213,    58,    48],
        [    4,  4886,  4364],
        [ 3872,   217,     4],
        [    5,     5,    22],
        [    2,     2,  1936],
        [ 5050,   593,    59],
        [   95,     7,    14]])

3.4 训练语言模型

首先还是构建模型,构建一个RNN

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
from torch.autograd import Variable as V

class RNNModel(nn.Module):
    def __init__(self, ntoken,ninp, nhid, nlayers, bsz, dropout=0.5, tie_weights=True):
        super(RNNModel, self).__init__()
        self.nhid, self.nlayers, self.bsz = nhid, nlayers, bsz
        self.drop=nn.Dropout(dropout)
        self.encoder=nn.Embedding(ntoken,ninp)
        self.rnn=nn.LSTM(ninp, nhid, nlayers, dropout=dropout)
        self.decoder=nn.Linear(nhid,ntoken)
        self.init_weights()
        self.hidden=self.init_hidden(bsz)
    
    def init_weights(self):
        initrange=0.1
        self.encoder.weight.data.uniform_(-initrange, initrange)
        self.decoder.bias.data.fill_(0)
        self.decoder.weight.data.uniform_(-initrange, initrange)
    
    def init_hidden(self, bsz):
        weight = next(self.parameters()).data
        return (V(weight.new(self.nlayers, bsz, self.nhid).zero_()), V(weight.new(self.nlayers, bsz, self.nhid).zero_()))
#         return (V(weight.new(self.nlayers, bsz, self.nhid).zero_().cuda()),
#                 V(weight.new(self.nlayers, bsz, self.nhid).zero_()).cuda())
        
    
    def reset_history(self):
        """Wraps hidden states in new Variables, to detach them from their history."""
        self.hidden = tuple(V(v.data) for v in self.hidden)
    
    def forward(self,input):
        emb=self.drop(self.encoder(input))
        output,self.hidden=self.rnn(emb, self.hidden)
        output=self.drop(output)
        decoded=self.decoder(output.view(output.size(0)*output.size(1),output.size(2)))
        return decoded.view(output.size(0), output.size(1), decoded.size(1))
weight_matrix=TEXT.vocab.vectors
model=RNNModel(weight_matrix.size(0),weight_matrix.size(1),200,1,BATCH_SIZE)
model.encoder.weight.data.copy_(weight_matrix)
# if USE_GPU:
#     model.cuda()
# model.to(device)
tensor([[ 0.0000,  0.0000,  0.0000,  ...,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  ...,  0.0000,  0.0000,  0.0000],
        [-0.0715,  0.0935,  0.0237,  ...,  0.3362,  0.0306,  0.2558],
        ...,
        [ 0.0000,  0.0000,  0.0000,  ...,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  ...,  0.0000,  0.0000,  0.0000],
        [ 0.0000,  0.0000,  0.0000,  ...,  0.0000,  0.0000,  0.0000]])
criterion=nn.CrossEntropyLoss()
optimizer=optim.Adam(model.parameters(),lr=0.001,betas=(0.7,0.99))
n_epochs=2
n_tokens=weight_matrix.size(0)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

from tqdm import tqdm
def train_epoch(epoch):
    epoch_loss=0
    for batch in tqdm(train_iter):
        model.reset_history()
        optimizer.zero_grad()
        text, target=batch.text, batch.target
        prediction=model(text)
        loss=criterion(prediction.view(-1,n_tokens),target.view(-1))
        loss.backward()
        optimizer.step()
        epoch_loss += loss.item() * prediction.size(0) * prediction.size(1)

    epoch_loss /= len(train.examples[0].text)
    
    val_loss = 0
    model.eval()
    for batch in valid_iter:
        model.reset_history()
        text, targets = batch.text, batch.target
        prediction = model(text)
        loss = criterion(prediction.view(-1, n_tokens), targets.view(-1))
        val_loss += loss.item() * text.size(0)
    val_loss /= len(valid.examples[0].text)
    
    print('Epoch: {}, Training Loss: {:.4f}, Validation Loss: {:.4f}'.format(epoch, epoch_loss, val_loss))
for epoch in range(1,n_epochs+1):
    train_epoch(epoch)
Epoch: 1, Training Loss: 6.2106, Validation Loss: 0.1713
Epoch: 2, Training Loss: 5.2644, Validation Loss: 0.1595

Epoch: 1, Training Loss: 6.2106, Validation Loss: 0.1713
Epoch: 2, Training Loss: 5.2644, Validation Loss: 0.1595

结果和原来教程里差别不大,问题来了,这两次都遇到一个问题,就是使用GPU和CPU的问题,在训练时,不像之前直接使用to(device)就可以将数据和模型转移到GPU上,最近总报错,可能需要进一步的学习

b=next(iter(valid_iter))
def word_ids_to_sentence(id_tensor,vocab,join=None):
    if isinstance(id_tensor, torch.LongTensor):
        ids = id_tensor.transpose(0, 1).contiguous().view(-1)
    elif isinstance(id_tensor, np.ndarray):
        ids = id_tensor.transpose().reshape(-1)

    batch = [vocab.itos[ind] for ind in ids]  # denumericalize
    if join is None:
        return batch
    else:
        return join.join(batch)
word_ids_to_sentence(b.text.cpu().data, TEXT.vocab, join=' ')[:210]
'  <eos>   = homarus gammarus = <eos>   <eos>   homarus gammarus , known as the european lobster or common lobster , is a species of <unk> lobster from . <unk> ceo hiroshi <unk> referred to <unk> as one of his f'
arrs = model(b.text).cpu().data.numpy()
import numpy as np
word_ids_to_sentence(np.argmax(arrs, axis=2), TEXT.vocab, join=' ')[:210]
'<unk>   <eos> = = = <eos>   <eos>   <eos>   = the as " <unk> <unk> , <unk> starling " <unk> a <unk> of the , , the <eos> <unk> <unk> <unk> , to the the " of the first , , the , <eos>   <eos> years of the : the '

结果一般啊,教程增加了训练的迭代次数,这里就不再赘述了

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,546评论 6 507
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,224评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,911评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,737评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,753评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,598评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,338评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,249评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,696评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,888评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,013评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,731评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,348评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,929评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,048评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,203评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,960评论 2 355

推荐阅读更多精彩内容