Pytorch學習記錄-torchtext學習Field

Pytorch學習記錄-torchtext學習Field

Pytorch學習記錄-torchtext學習Field

昨天寫的那個太粗糙了。又找了一個教程來看。

主要包括三個方面

  • 使用torchtext進行文本預處理
  • 使用Keras和PyTorch構建數據集進行文本預處理
  • 使用gensim加載預訓練的詞向量,並使用PyTorch實現語言模型

和 torchvision 類似 torchtext 是為了處理特定的數據和數據集而存在的。

正如 NLP和 CV的熱度一樣, torchtext的熱度也較 torchvision 少了許多,至今還在積極開發中,甚至在使用過程中你可能會遇見一些 bug。但是, torchtext 的可用性是肯定的,它提供了一整套文本數據處理流程。

本文使用的數據集也是Kaggle的情感分類數據集。

1. 使用torchtext進行文本預處理

1.1 引入庫並查看數據

import pandas as pd 

import numpy as np
import torch
import time
import random
import os
data1 = pd.read_csv('./data/torchtextdata/train_one_label.csv').head()
data2=pd.read_csv('./data/torchtextdata/test.csv').head()

1.2 使用torchtext構建數據集

和昨天一樣,對於評論文本,我們把想對字段做的預處理以傳遞關鍵字參數的形式傳入。我們給字段一個分詞器,告訴它把輸入都轉換為小寫,告訴它輸入是順序序列。

  • sequential是否表示順序數據。默認值:True
  • tokenize用於將使用此字段將字符串標記為順序示例的函數。如果是“spacy”,則使用SpaCy標記器。如果將非序列化函數作為參數傳遞,則該字段將無法序列化。默認值:string.split。
  • 因此,如果希望使用spacy,在前面的tokenize部分要加上tokenize = lambda x: x.split('spacy')
  • fix_length使用此字段的所有示例都將填充到的固定長度,或者對於靈活的序列長度,為None。默認值:無。
  • 在這裡是200的長度。
from torchtext import data
from torchtext.vocab import Vectors

from torch.nn import init
from tqdm import tqdm
tokenize = lambda x: x.split()
TEXT = data.Field(sequential=True, tokenize=tokenize, lower=True, fix_length=200)
LABEL = data.Field(sequential=False, use_vocab=False)

1.3 自定義Dataset

Fields知道如何處理原始數據,用戶告訴Fields去哪裡處理,在這裡就要使用Dataset。torchtext內置有Dataset。

torchtext的Dataset是繼承自pytorch的Dataset,提供了一個可以下載壓縮數據並解壓的方法(支持.zip, .gz, .tgz)

splits方法可以同時讀取訓練集,驗證集,測試集

TabularDataset可以很方便的讀取CSV, TSV, or JSON格式的文件

可以直接使用torchtext.data.Dataset來構建數據集,昨天教程就是這樣做的。

# 定義數據路徑
train_path = './data/torchtext/train_one_label.csv'
valid_path = './data/torchtext/valid_one_label.csv'
test_path = './data/torchtext/test.csv'
# 定義Dataset
class MyDataset(data.Dataset):
name = 'grand dataset'
@staticmethod
def sort_key(ex):
return len(ex.text)
# 配置信息
def __init__(self, path, text_field, label_field, test=False, aug=False, **kwargs):
fields = [("id", None),
("comment_text", text_field),
("toxic", label_field),
]
examples = []
csv_data = pd.read_csv(path)

print('read data from {}'.format(path))
# 如果是測試數據,就沒有label,其餘的有label
if test:
for text in tqdm(csv_data['comment_text'], csv_data['toxic']):
examples.append(data.Example.fromlist([None, text, None], fields))
else:
for text, label in tqdm(zip(csv_data['comment_text'], csv_data['toxic'])):
if aug:
rate = random.random()
if rate > 0.5:
text = self.dropout(text)
else:
text = self.shuffle(text)
examples.append(data.Example.fromlist([None, text, label], fields))
# 之前是一些預處理操作,此處調用super調用父類構造方法,產生標準Dataset
super(MyDataset, self).__init__(examples, fields)
# 使用permutation來打亂數據,但是其shuffle會更快一些
def shuffle(self, text):
text = np.random.permutation(text.strip().split())
return ' '.join(text)
def dropout(self, text, p=0.5):
# 字符串處理,刪除空白,然後分句?
text = text.strip().split()
len_ = len(text)
indexs = np.random.choice(len_, int(len_ * p))
for i in indexs:
text[i] = ''
return ' '.join(text)

1.4 構建數據集

# 構建數據集
train = MyDataset(train_path, text_field=TEXT, label_field=LABEL, test=False, aug=1)
valid = MyDataset(valid_path, text_field=TEXT, label_field=LABEL, test=False, aug=1)
test = MyDataset(test_path, text_field=TEXT, label_field=None, test=True, aug=1)

1.5 構建詞表

TEXT.build_vocab(train) 

當然還可以通過預訓練的方式來構建詞表

cache = 'mycache'
if not os.path.exists(cache):
os.mkdir(cache)
vectors = Vectors(name='/Users/wyw/Documents/vectors/glove/glove.6B.300d.txt', cache=cache)
# 指定 Vector 缺失值的初始化方式,沒有命中的token的初始化方式
vectors.unk_init = init.xavier_uniform_
TEXT.build_vocab(train, min_freq=5, vectors=vectors)
# 查看詞表元素
TEXT.vocab.vectors

1.6 構建數據迭代器

from torchtext.data import Iterator, BucketIterator
# 同時對訓練集和驗證集進行迭代器構建
train_iter, val_iter = BucketIterator.splits(
(train, valid),
batch_sizes=(8, 8),
device=0,
sort_key=lambda x: len(x.comment_text),
sort_within_batch=False,
repeat=False
)
test_iter = Iterator(test, batch_size=8, device=0, sort=False, sort_within_batch=False, repeat=False)
for idx, batch in enumerate(train_iter):
print(batch)
text, label = batch.comment_text, batch.toxic
print(text.shape, label.shape)

1.7 訓練LSTM網絡進行分類

在這部分,用的是cpu,我沒找到怎麼使用GPU,好像device那個不行,要調整為cuda什麼的

import torch.nn as nn 

import torch.nn.functional as F
import torch.optim as optim
weight_matrix = TEXT.vocab.vectors
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
class LSTM(nn.Module):
def __init__(self):
super(LSTM, self).__init__()
self.word_embeddings = nn.Embedding(len(TEXT.vocab), 300)
self.lstm = nn.LSTM(input_size=300, hidden_size=128, num_layers=1)
self.decoder = nn.Linear(128, 2)
def forward(self, sentence):
embeds = self.word_embeddings(sentence)
lstm_out = self.lstm(embeds)[0]
final = lstm_out[-1]
y = self.decoder(final)
return y
# model = LSTM().to(device)
model = LSTM()
model.train()
optimizer = optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr=0.01)
loss_funtion = F.cross_entropy
for epoch, batch in enumerate(train_iter):
optimizer.zero_grad()
predicted = model(batch.comment_text)
loss = loss_funtion(predicted, batch.toxic)
loss.backward()
optimizer.step()
print(loss)


分享到:


相關文章: