Pytorch学习记录-torchtext学习Field
重新又看了一遍,这东西还得实际做,具体内容看注释。
等会还会用中文分词试一下,希望之后文本处理可以使用torchtext做预处理。
和 torchvision 类似 torchtext 是为了处理特定的数据和数据集而存在的。
正如 NLP和 CV的热度一样, torchtext的热度也较 torchvision 少了许多,至今还在积极开发中,甚至在使用过程中你可能会遇见一些 bug。但是, torchtext 的可用性是肯定的,它提供了一整套文本数据处理流程。
本文使用的数据集也是Kaggle的情感分类数据集。
import pandas as pd
import numpy as np
import torch
import random
import os
import torchtext
from torchtext import data
from torchtext.vocab import Vectors
from torch.nn import init
from tqdm import tqdm
tokenize=lambda x:x.split()
# sequential数据是不是按顺序来
# tokenize传入刚才切分好的数据
# lower小写
# fix_length补齐最大长度
# use_vocab是否使用Vocab对象。如果为False,则此字段中的数据应已为数字。默认值:True。
# 在这里其实就是获取分词后的文本和标签
TEXT=data.Field(sequential=True, tokenize=tokenize,lower=True,fix_length=200)
LABEL=data.Field(sequential=False, use_vocab=False)
# train_path='./data/train_one_label.csv'
# valid_path='./data/valid_one_label.csv'
# test_path='./data/test.csv'
# data=pd.read_csv(train_path)
# data.head()
# for text , label in tqdm(zip(data['comment_text'],data['toxic'])):
# print(text)
# 构建数据集-自定义类
# 可以使用继承Dataset类的MyDatase
# 训练集、验证集、测试集的路径
train_path='./data/train_one_label.csv'
valid_path='./data/valid_one_label.csv'
test_path='./data/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):
# 将文本中id、评论、标签放入field中
fields=[("id",None),
("comment_text",text_field),
("toxic",label_field)]
examples=[]
# 使用pandas读取数据,在这里传入的是一个path
csv_data=pd.read_csv(path)
print('read data from {}'.format(path))
# 对数据进行判断,如果是test数据,就不包含label内容,如果不是,就要读取toxic
if test:
for text in tqdm(csv_data['comment_text']):
examples.append(data.Example.fromlist([None, text, None], fields))
else:
for text , label in tqdm(zip(csv_data['comment_text'], csv_data['toxic'])):
# 判定是否要增强,就是是否要做随机删除处理,大于0.5,随机删除;其余打乱
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)
def shuffle(self, text):
# 使用permutation来打乱数据,但是shuffle会更快一些
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)
# 构建数据集-构建数据集
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)
print(train[0].__dict__.keys())
print(valid[0].__dict__.keys())
print(test[0].__dict__.keys())
read data from ./data/train_one_label.csv
25it [00:00, 5013.27it/s]
read data from ./data/valid_one_label.csv
25it [00:00, 4177.59it/s]
read data from ./data/test.csv
100%|██████████| 33/33 [00:00<00:00, 16598.16it/s]
dict_keys(['comment_text', 'toxic'])
dict_keys(['comment_text', 'toxic'])
dict_keys(['comment_text'])
# 构建词表
TEXT.build_vocab(train)
# 构建数据集迭代器
from torchtext.data import Iterator,BucketIterator
# train_iter,valid_iter=BucketIterator.splits(
# (train,valid),
# batch_size=(8,8),
# device=-1,
# sort_key=lambda x: len(x.comment_text),
# sort_within_batch=False,
# repeat=False
# )
# 好吧,源代码中是上面那么写的,在pycharm里面可以运行,但是在jupyter中报错,这里拆开来写了,效果一样
train_iter = data.BucketIterator(dataset=train, batch_size=8, shuffle=True, sort_within_batch=False, repeat=False)
valid_iter = data.BucketIterator(dataset=valid, batch_size=8, shuffle=True, sort_within_batch=False, repeat=False)
test_iter=Iterator(test,batch_size=8,device=-1,sort=False,sort_within_batch=False,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.
for idx, batch in enumerate(train_iter):
print(batch)
text, label = batch.comment_text, batch.toxic
print(text.shape, label.shape)
[torchtext.data.batch.Batch of size 8 from GRAND DATASET]
[.comment_text]:[torch.LongTensor of size 200x8]
[.toxic]:[torch.LongTensor of size 8]
torch.Size([200, 8]) torch.Size([8])
[torchtext.data.batch.Batch of size 8 from GRAND DATASET]
[.comment_text]:[torch.LongTensor of size 200x8]
[.toxic]:[torch.LongTensor of size 8]
torch.Size([200, 8]) torch.Size([8])
[torchtext.data.batch.Batch of size 1 from GRAND DATASET]
[.comment_text]:[torch.LongTensor of size 200x1]
[.toxic]:[torch.LongTensor of size 1]
torch.Size([200, 1]) torch.Size([1])
[torchtext.data.batch.Batch of size 8 from GRAND DATASET]
[.comment_text]:[torch.LongTensor of size 200x8]
[.toxic]:[torch.LongTensor of size 8]
torch.Size([200, 8]) torch.Size([8])
# 接下来就是构造一个LSTM模型,然后训练一下
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
weight_matrix=TEXT.vocab.vectors
class LSTM(nn.Module):
def __init__(self):
super(LSTM,self).__init__()
self.word_embedding=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_embedding(sentence)
print(embeds.shape)
lstm_out=self.lstm(embeds)[0]
print(lstm_out.shape)
final=lstm_out[-1]
y=self.decoder(final)
return y
model=LSTM()
model.train()
optimizer=optim.Adam(filter(lambda p:p.requires_grad,model.parameters()),lr=0.01)
crition=F.cross_entropy
for epoch , batch in enumerate(train_iter):
optimizer.zero_grad()
predicted=model(batch.comment_text)
loss=crition(predicted,batch.toxic)
loss.backward()
optimizer.step()
print(loss.item())
torch.Size([200, 8, 300])
torch.Size([200, 8, 128])
0.8496901392936707
torch.Size([200, 8, 300])
torch.Size([200, 8, 128])
0.5025582909584045
torch.Size([200, 1, 300])
torch.Size([200, 1, 128])
3.7277133464813232
torch.Size([200, 8, 300])
torch.Size([200, 8, 128])
0.1662883162498474