Pytorch学习记录-torchtext学习

Pytorch学习记录-torchtext学习

1. Field

Field是核心,指定了用户希望如何处理字段。
它包含一个Vocab对象,用于定义字段元素的可能值集及其对应的数字表示。 Field对象还包含与数据类型应如何数字化相关的其他参数,例如标记化方法和应生成的Tensor类型。
如果传递的字段是默认被数字化的,并且不是顺序序列(比如这里的label),则应该传递参数use_vocab = False和sequential = False。

对于评论文本,我们把想对字段做的预处理以传递关键字参数的形式传入。我们给字段一个分词器,告诉它把输入都转换为小写,告诉它输入是顺序序列。

from torchtext.data import Field

tokenize = lambda x: x.split()

Text = Field(sequential=True, tokenize=tokenize, lower=True)
LABEL = Field(sequential=False, use_vocab=False)

2. 构建Dataset

Fields知道如何处理原始数据,用户告诉Fields去哪里处理,在这里就要使用Dataset。
torchtext内置有Dataset,看下面处理csv的实例。

from torchtext.data import TabularDataset

tv_datafields = [('id', None),
                 ('comment_text', Text),
                 ('toxic', LABEL),
                 ('severe_toxic', LABEL),
                 ("threat", LABEL),
                 ("obscene", LABEL),
                 ("insult", LABEL),
                 ("identity_hate", LABEL)
                 ]
trn, vld = TabularDataset.splits(
    path=r'D:\DesktopBackup\right\practical-torchtext-master\data',
    train='train.csv',
    validation='valid.csv',
    format='csv',
    skip_header=True,
    fields=tv_datafields
)

tst_datafields = [('id', None),
                  ('comment_text', Text)]

tst = TabularDataset(
    path=r'D:\DesktopBackup\right\practical-torchtext-master\data\test.csv',
    format='csv',
    skip_header=True,
    fields=tst_datafields
)

print(trn[0].__dict__.keys())
print(trn[4].comment_text)

3. 构建迭代器

在torchvision和PyTorch中,数据的处理和批处理由DataLoaders处理。 出于某种原因,torchtext相同的东西又命名成了Iterators。 基本功能是一样的,但我们将会看到,Iterators具有一些NLP特有的便捷功能。
以下是如何初始化训练迭代器,验证和测试数据的代码。

from torchtext.data import Iterator, BucketIterator

train_iter, val_iter = BucketIterator.splits((trn, vld),
                                             batch_sizes=(25, 25),
                                             device=-1,
                                             sort_key=lambda x: len(x.comment_text),
                                             sort_within_batch=False,
                                             repeat=False)
test_iter = Iterator(tst, batch_size=64,
                     device=-1,
                     sort=False,
                     sort_within_batch=False,
                     repeat=False)

sort_within_batch参数设置为True时,按照sort_key按降序对每个小批次内的数据进行排序。当你想对padded序列使用pack_padded_sequence转换为PackedSequence对象时。
BucketIterator是torchtext最强大的功能之一。它会自动将输入序列进行shuffle并做bucket。当需要填充输入序列使得长度相同才能批处理。 例如,序列,填充量由batch中最长的序列决定。似乎在Transformer里面的mask也需要。
在这里,教程使用sort_key=lambda x: len(x.comment_text)作为bucket的依据,就是comment_text的长度。

4. 封装迭代器

迭代器返回一个名为torchtext.data.Batch的自定义数据类型。
Batch类具有与Example类相似的API,将来自每个字段的一批数据作为属性。
但是这样的自定义数据在重用时有问题。教程里做了封装,把batch转换为形式为(x,y)的元组,其中x是自变量(模型的输入),y是因变量(标签数据)。

class BatchWrapper:
    def __init__(self, dl, x_var, y_vars):
        self.dl, self.x_var, self.y_vars = dl, x_var, y_vars  # 传入自变量x列表和因变量y列表

    def __iter__(self):
        for batch in self.dl:
            x = getattr(batch, self.x_var)  # 在这个封装中只有一个自变量

            if self.y_vars is not None:  # 把所有因变量cat成一个向量
                temp = [getattr(batch, feat).unsqueeze(1) for feat in self.y_vars]
                y = torch.cat(temp, dim=1).float()
            else:
                y = torch.zeros((1))

            yield (x, y)

    def __len__(self):
        return len(self.dl)


train_dl = BatchWrapper(train_iter, "comment_text",
                        ["toxic", "severe_toxic", "obscene", "threat", "insult", "identity_hate"])
valid_dl = BatchWrapper(val_iter, "comment_text",
                        ["toxic", "severe_toxic", "obscene", "threat", "insult", "identity_hate"])
test_dl = BatchWrapper(test_iter, "comment_text", None)

print(next(train_dl.__iter__()))

5. 构建一个LSTM演示处理好的数据

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


class SimpleLSTMBaseline(nn.Module):
    def __init__(self, hidden_dim, emb_dim=300, num_linear=1):
        super().__init__()
        self.embedding = nn.Embedding(len(Text.vocab), emb_dim)
        self.encoder = nn.LSTM(emb_dim, hidden_dim, num_layers=1)
        self.linear_layers = []

        for _ in range(num_linear - 1):
            self.linear_layers.append(nn.Linear(hidden_dim, hidden_dim))
            self.linear_layer = nn.ModuleList(self.linear_layers)

        self.predictor = nn.Linear(hidden_dim, 6)

    def forward(self, seq):
        hdn, _ = self.encoder(self.embedding(seq))
        feature = hdn[-1, :, :]
        for layer in self.linear_layers:
            feature = layer(feature)
        preds = self.predictor(feature)

        return preds

em_sz = 100
nh = 500
model = SimpleLSTMBaseline(nh, emb_dim=em_sz)

6. 训练模型和预测

import tqdm
import numpy as np

optim = optim.Adam(model.parameters(), lr=1e-2)
loss_func = nn.BCEWithLogitsLoss()

epochs = 2
for epoch in range(1, epochs + 1):
    running_loss = 0.0
    running_corrects = 0
    model.train()
    for x, y in tqdm.tqdm(train_dl):
        optim.zero_grad()
        preds = model(x)
        loss = loss_func(y, preds)
        loss.backward()
        optim.step()

        running_loss += loss.item()* x.size(0)
    epoch_loss = running_loss / len(trn)

    val_loss = 0.0
    model.eval()  # 评估模式
    for x, y in valid_dl:
        preds = model(x)
        loss = loss_func(y, preds)
        val_loss += loss.item()* x.size(0)

    val_loss /= len(vld)
    print('Epoch: {}, Training Loss: {:.4f}, Validation Loss: {:.4f}'.format(epoch, epoch_loss, val_loss))

test_preds = []
for x, y in tqdm.tqdm(test_dl):
    preds = model(x)
    preds = preds.data.numpy()
    # 模型的实际输出是logit,所以再经过一个sigmoid函数
    preds = 1 / (1 + np.exp(-preds))
    test_preds.append(preds)
    test_preds = np.hstack(test_preds)

print(test_preds)

这一篇写得太烂了,torchtext刚开始,学习目的就是为了处理文本信息,和之后的模型对接上。

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