0
点赞
收藏
分享

微信扫一扫

李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别


李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_深度学习

文章目录

  • ​​作业说明​​
  • ​​数据集介绍​​
  • ​​数据集下载​​
  • ​​Recurrent Neural Networks​​
  • ​​Download Dataset​​
  • ​​Utils​​
  • ​​Train Word to Vector​​
  • ​​词嵌入 word2vec​​
  • ​​Data Preprocess​​
  • ​​Dataset​​
  • ​​Model​​
  • ​​Train​​
  • ​​Test​​
  • ​​Main​​
  • ​​Predict and Write to csv file​​

作业说明

 1. 本次数据集包括training_data,training_label和training_nolabel三个txt文件,训练集包括有标签(积极的还是消极的)的和没有标签的,测试集为索引和和句子内容。

2. 需要完成的任务根据所给的数据集训练LSTM网络用来判断句子的情感类别。

数据集介绍

下载data数据集后解压得到三个txt文件

李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_深度学习_02


放在hw4.ipynb同级目录下

training_label.txt:有 label 的 training data,约20万句句子。

格式为:标签 +++李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_lstm_03+++ 只是分隔符号,不需要理它)

比如:1 +++$+++ are wtf … awww thanks !

这里的1表示句子“are wtf … awww thanks !”是正面的。

李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_自然语言处理_04

training_nolabel.txt:没有 label 的 training data(只有句子),用来做半监督学习,约120万句句子。

比如: hates being this burnt !! ouch,前面没有0或者1的标签

李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_自然语言处理_05

testing_data.txt:测试数据,最终需要判断 testing data 里面的句子是 0 或 1,约20万句句子(10万句句子是Public,10万句句子是Private)。
具体格式如下,第一行是表头,从第二行开始是数据,第一列是id,第二列是文本

李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_lstm_06

数据集下载

蓝奏云地址:​​https://wwr.lanzoui.com/iGwtvv4w8ej​​

Recurrent Neural Networks

本次作业是要让同学接触NLP当中一个简单的task——语句分类(文本分类)

给定一个语句,判断他有没有恶意(负面标1,正面标0)

# from google.colab import drive
# drive.mount('/content/drive')
# path_prefix = 'drive/My Drive/Colab Notebooks/hw4 - Recurrent Neural Network'
path_prefix = './'

Download Dataset

有三个文件,分別是 training_label.txt、training_nolabel.txt、testing_data.txt

  • training_label.txt:有 label 的 training data(句子配上 0 or 1,+++$+++ 只是分隔符号,不要理它)
  • e.g., 1 +++$+++ are wtf … awww thanks !
  • training_nolabel.txt:沒有 label 的 training data(只有句子),用来做 semi-supervised learning
  • ex: hates being this burnt !! ouch
  • testing_data.txt:你要判断 testing data 里面的句子是 0 or 1

id,text
0,my dog ate our dinner . no , seriously … he ate it .
1,omg last day sooon n of primary noooooo x im gona be swimming out of school wif the amount of tears am gona cry
2,stupid boys … they ’ re so … stupid !

# !wget --no-check-certificate 'https://drive.google.com/uc?export=download&id=1dPHIl8ZnfDz_fxNd2ZeBYedTat2lfxcO' -O 'drive/My Drive/Colab Notebooks/hw8-RNN/data/training_label.txt'
# !wget --no-check-certificate 'https://drive.google.com/uc?export=download&id=1x1rJOX_ETqnOZjdMAbEE2pqIjRNa8xcc' -O 'drive/My Drive/Colab Notebooks/hw8-RNN/data/training_nolabel.txt'
# !wget --no-check-certificate 'https://drive.google.com/uc?export=download&id=16CtnQwSDCob9xmm6EdHHR7PNFNiOrQ30' -O 'drive/My Drive/Colab Notebooks/hw8-RNN/data/testing_data.txt'

# !gdown --id '1lz0Wtwxsh5YCPdqQ3E3l_nbfJT1N13V8' --output data.zip 下载数据集
# !unzip data.zip 解压缩

# 这是用于过滤警告的
import warnings
warnings.filterwarnings('ignore')

Utils

# utils.py
# 这个block用来先定义一些等等常用到的函式
import torch
import numpy as np
import pandas as pd
import torch.optim as optim
import torch.nn.functional as F

def load_training_data(path='training_label.txt'):
# 把training时需要的data读进来
# 如果是'training_label.txt',需要读取label,如果是'training_nolabel.txt',不需要读取label
if 'training_label' in path:
with open(path, 'r') as f:
lines = f.readlines() # lines是二维数组,第一维是行line(按回车分割),第二维是每行的单词(按空格分割)
lines = [line.strip('\n').split(' ') for line in lines]# lines是二维数组,第一维是行line(按回车分割),第二维是每行的单词(按空格分割)
x = [line[2:] for line in lines]#每行按空格分割后,第2个符号之后都是句子的单词
y = [line[0] for line in lines]# 每行按空格分割后,第0个符号是label
return x, y
else:
with open(path, 'r') as f:
lines = f.readlines() # lines是二维数组,第一维是行line(按回车分割),第二维是每行的单词(按空格分割)
x = [line.strip('\n').split(' ') for line in lines]
return x

def load_testing_data(path='testing_data'):
# 把testing时需要的data读进来
with open(path, 'r') as f:
lines = f.readlines()
# 第0行是表头,从第1行开始是数据
# 第0列是id,第1列是文本,按逗号分割,需要逗号之后的文本
X = ["".join(line.strip('\n').split(",")[1:]).strip() for line in lines[1:]]# 除去第一行的id,text,第一列的索引
X = [sen.split(' ') for sen in X]# 将每个句子的单词分离出来,用以后面的W2V
return X

def evaluation(outputs, labels):
# outputs => probability (float)
# labels => labels
outputs[outputs>=0.5] = 1 # 大于等于0.5为正面
outputs[outputs<0.5] = 0 # 小于0.5为负面
correct = torch.sum(torch.eq(outputs, labels)).item()
return

Train Word to Vector

词嵌入 word2vec

​​通俗理解word2vec​​​​CBOW​​ 词嵌入原理(推导过程):​​手推词向量​​ word2vec 即 word to vector 的缩写。把 training 和 testing 中的每个单词都分别变成词向量,这里用到了 Gensim 来进行 word2vec 的操作。没有 gensim 的可以用 conda install gensim 或者 pip install gensim 安装一下。

class gensim.models.word2vec.Word2Vec(
sentences=None,
size=100,
alpha=0.025,
window=5,
min_count=5,
max_vocab_size=None,
sample=0.001,
seed=1,
workers=3,
min_alpha=0.0001,
sg=0,
hs=0,
negative=5,
cbow_mean=1,
hashfxn=<built-in function hash>,
iter=5,
null_word=0,
trim_rule=None,
sorted_vocab=1,
batch_words=10000,
compute_loss=False)

参数含义:

  • size: 词向量的维度。
  • alpha: 模型初始的学习率。
  • window: 表示在一个句子中,当前词于预测词在一个句子中的最大距离。
  • min_count: 用于过滤操作,词频少于 min_count 次数的单词会被丢弃掉,默认值为 5。
  • max_vocab_size: 设置词向量构建期间的 RAM 限制。如果所有的独立单词数超过这个限定词,那么就删除掉其中词频最低的那个。根据统计,每一千万个单词大概需要 1GB 的RAM。如果我们把该值设置为 None ,则没有限制。
  • sample: 高频词汇的随机降采样的配置阈值,默认为 1e-3,范围是 (0, 1e-5)。
  • seed: 用于随机数发生器。与词向量的初始化有关。
  • workers: 控制训练的并行数量。
  • min_alpha: 随着训练进行,alpha 线性下降到 min_alpha。
  • sg: 用于设置训练算法。当 sg=0,使用 CBOW 算法来进行训练;当 sg=1,使用 skip-gram 算法来进行训练。
  • hs: 如果设置为 1 ,那么系统会采用 hierarchica softmax 技巧。如果设置为 0(默认情况),则系统会采用 negative samping 技巧。
  • negative: 如果这个值大于 0,那么 negative samping 会被使用。该值表示 “noise words” 的数量,一般这个值是 5 - 20,默认是 5。如果这个值设置为 0,那么 negative samping 没有使用。
  • cbow_mean: 如果这个值设置为 0,那么就采用上下文词向量的总和。如果这个值设置为 1 (默认情况下),那么我们就采用均值。但这个值只有在使用 CBOW 的时候才起作用。
  • hashfxn: hash函数用来初始化权重,默认情况下使用 Python 自带的 hash 函数。
  • iter: 算法迭代次数,默认为 5。
  • trim_rule: 用于设置词汇表的整理规则,用来指定哪些词需要被剔除,哪些词需要保留。默认情况下,如果 word count < min_count,那么该词被剔除。这个参数也可以被设置为 None,这种情况下 min_count 会被使用。
  • sorted_vocab: 如果这个值设置为 1(默认情况下),则在分配 word index 的时候会先对单词基于频率降序排序。
  • batch_words: 每次批处理给线程传递的单词的数量,默认是 10000。

参考自:​​word2vec 函数的使用​​

# w2v.py
# 这个block是用来训练word to vector的word embedding
# 注意!这个block在训练word to vector时是用cpu,可能要花到10分钟以上
import os
import numpy as np
import pandas as pd
import argparse
from gensim.models import word2vec

def train_word2vec(x):
# 训练word to vector的word embedding
# window:滑动窗口的大小,min_count:过滤掉语料中出现频率小于min_count的词
model = word2vec.Word2Vec(x, size=250, window=5, min_count=5, workers=12, iter=10, sg=1)
return model

if __name__ == "__main__":
print("loading training data ...")
train_x, y = load_training_data('training_label.txt')
train_x_no_label = load_training_data('training_nolabel.txt')

print("loading testing data ...")
test_x = load_testing_data('testing_data.txt')

model = train_word2vec(train_x + train_x_no_label + test_x)
#model = train_word2vec(train_x + test_x)

print("saving model ...")
# model.save(os.path.join(path_prefix, 'model/w2v_all.model'))
model.save(os.path.join(path_prefix, 'w2v_all.model'))

loading training data ...
loading testing data ...
saving model ...

#词向量的个数
with open('w2v_all.model', "rb") as f:
lines = f.readlines()
print(len(lines)-1)#减一是因为第一行并不是个词向量,为是一个标识词向量维度的数值

7472

Data Preprocess

定义一个预处理的类Preprocess():

  • w2v_path:word2vec的存储路径
  • sentences:句子
  • sen_len:句子的固定长度
  • idx2word 是一个列表,比如:self.idx2word[1] = ‘he’
  • word2idx 是一个字典,记录单词在 idx2word 中的下标,比如:self.word2idx[‘he’] = 1
  • embedding_matrix 是一个列表,记录词嵌入的向量,比如:self.embedding_matrix[1] = ‘he’ vector
    对于句子,我们就可以通过 embedding_matrix[word2idx[‘he’] ] 找到 ‘he’ 的词嵌入向量。

Preprocess()的调用如下:

  • 训练模型:preprocess = Preprocess(train_x, sen_len, w2v_path=w2v_path)
  • 测试模型:preprocess = Preprocess(test_x, sen_len, w2v_path=w2v_path)
    另外,这里除了出现在 train_x 和 test_x 中的单词外,还需要两个单词(或者叫特殊符号):
  • PAD:Padding的缩写,把所有句子都变成一样长度时,需要用PAD补上空白符
  • UNK:Unknown的缩写,凡是在 train_x 和 test_x 中没有出现过的单词,都用UNK来表示

# preprocess.py
# 这个block用来做data的预处理
from torch import nn
from gensim.models import Word2Vec

class Preprocess():
def __init__(self, sentences, sen_len, w2v_path="./w2v.model"):
self.w2v_path = w2v_path
self.sentences = sentences
self.sen_len = sen_len
self.idx2word = []
self.word2idx = {}
self.embedding_matrix = []
def get_w2v_model(self):
# 把之前训练好的word to vec模型读进来
self.embedding = Word2Vec.load(self.w2v_path)
self.embedding_dim = self.embedding.vector_size
def add_embedding(self, word):
# 这里的 word 只会是 "<PAD>" 或 "<UNK>"
# 把一个随机生成的表征向量 vector 作为 "<PAD>" 或 "<UNK>" 的嵌入
vector = torch.empty(1, self.embedding_dim)
torch.nn.init.uniform_(vector)# torch.nn.init.uniform_(tensor, a=0, b=1)服从均匀分布U(0,1)
# 它的 index 是 word2idx 这个词典的长度,即最后一个
self.word2idx[word] = len(self.word2idx)
self.idx2word.append(word)
self.embedding_matrix = torch.cat([self.embedding_matrix, vector], 0)
def make_embedding(self, load=True):
print("Get embedding ...")
# 取得训练好的Word2vec word embedding
if load:
print("loading word to vec model ...")
self.get_w2v_model()
else:
raise NotImplementedError
# 制作一个word2idx的dictionary
# 制作一个idx2word的list
# 制作一个word2vector的list
# 遍历嵌入后的单词
for i, word in enumerate(self.embedding.wv.vocab):
print('get words #{}'.format(i+1), end='\r')
#e.g. self.word2index['he'] = 1
#e.g. self.index2word[1] = 'he'
#e.g. self.vectors[1] = 'he' vector
self.word2idx[word] = len(self.word2idx)
self.idx2word.append(word)
self.embedding_matrix.append(self.embedding[word])
print('')
# 把 embedding_matrix 变成 tensor
self.embedding_matrix = torch.tensor(self.embedding_matrix)
# 将“<PAD>”跟“<UNK>”加进embedding里面
self.add_embedding("<PAD>")
self.add_embedding("<UNK>")
print("total words: {}".format(len(self.embedding_matrix)))
return self.embedding_matrix
def pad_sequence(self, sentence):
# 将每个句子变成一样的长度
if len(sentence) > self.sen_len:
sentence = sentence[:self.sen_len]
else:
pad_len = self.sen_len - len(sentence)
for _ in range(pad_len):
sentence.append(self.word2idx["<PAD>"])
assert len(sentence) == self.sen_len
return sentence
def sentence_word2idx(self):
# 把句子里面的字转成相对应的index
sentence_list = []
for i, sen in enumerate(self.sentences):
print('sentence count #{}'.format(i+1), end='\r')
sentence_idx = []
for word in sen:
if (word in self.word2idx.keys()):
sentence_idx.append(self.word2idx[word])
else:
sentence_idx.append(self.word2idx["<UNK>"])
# 将每个句子变成一样的长度
sentence_idx = self.pad_sequence(sentence_idx)
sentence_list.append(sentence_idx)
return torch.LongTensor(sentence_list)
def labels_to_tensor(self, y):
# 把 labels 转成 tensor
y = [int(label) for label in y]
return torch.LongTensor(y)

Dataset

在 Pytorch 中,我们可以利用 torch.utils.data 的 Dataset 及 DataLoader 来"包装" data,使后续的 training 和 testing 更方便。

Dataset 需要 overload 两个函数:lengetitem

  • len必须要传回 dataset 的大小
  • getitem则定义了当函数利用 [ ] 取值时,dataset 应该要怎么传回数据。
    实际上,在我们的代码中并不会直接使用到这两个函数,但是当 DataLoader 在 enumerate Dataset 时会使用到,如果没有这样做,程序运行阶段会报错。

# data.py
# 制作了dataset所需要的'__init__','__getitem__','__len__'好让dataloader能使用
import torch
from torch.utils import data

class TwitterDataset(data.Dataset):
"""
Expected data shape like:(data_num, data_len)
Data can be a list of numpy array or a list of lists
input data shape : (data_num, seq_len, feature_dim)

__len__ will return the number of data
"""
def __init__(self, X, y):
self.data = X
self.label = y
def __getitem__(self, idx):
if self.label is None: return self.data[idx]
return self.data[idx], self.label[idx]
def __len__(self):
return len(self.data)

Model

把句子丢到LSTM中,变成一个输出向量,再把这个输出丢到分类器classifier中,进行二元分类。

关于Pytorch中的LSTM的使用可参见:​​https://zhuanlan.zhihu.com/p/41261640​​

李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_rnn_07

# model.py
# 这个block是要拿来训练的模型
import torch
from torch import nn
class LSTM_Net(nn.Module):
def __init__(self, embedding, embedding_dim, hidden_dim, num_layers, dropout=0.5, fix_embedding=True):
super(LSTM_Net, self).__init__()
# 制作embedding layer
self.embedding = torch.nn.Embedding(embedding.size(0),embedding.size(1))#参数:单词个数,词向量维度
self.embedding.weight = torch.nn.Parameter(embedding)#初始化embedding层
# 是否将embedding fix住,如果fix_embedding为False,在训练过程中,embedding也会跟着被训练
self.embedding.weight.requires_grad = False if fix_embedding else True
self.embedding_dim = embedding.size(1)
self.hidden_dim = hidden_dim
self.num_layers = num_layers
self.dropout = dropout
self.lstm = nn.LSTM(embedding_dim, hidden_dim, num_layers=num_layers, batch_first=True)#hidden_dim是memory
self.classifier = nn.Sequential( nn.Dropout(dropout),
nn.Linear(hidden_dim, 1),
nn.Sigmoid() )
def forward(self, inputs):
inputs = self.embedding(inputs)
x, _ = self.lstm(inputs, None)
# x的dimension(batch,seq_len,hidden_size)取用LSTM最后一层的hidden state
x = x[:, -1, :]
x = self.classifier(x)
return

Train

train_test_split()的使用说明:

  • test_size:样本占比。
  • random_state:随机数的种子。 填0或不填,每次都会不一样。填其他数字,每次会固定得到同样的随机分配。
  • stratify:保持split前类的分布。一般在数据不平衡时使用。

nn.BCELoss与nn.CrossEntropyLoss的区别:

  1. 使用nn.BCELoss前需要加上Sigmoid函数,即二元交叉樀
    李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_自然语言处理_08
  2. 使用nn.CrossEntropyLoss会自动加上Softmax层,
    李宏毅(2020)作业4-hw4_RNN-判断句子的情感类别_lstm_09

# train.py
# 这个block是用来训练模型的
import torch
from torch import nn
import torch.optim as optim
import torch.nn.functional as F

def training(batch_size, n_epoch, lr, model_dir, train, valid, model, device):
total = sum(p.numel() for p in model.parameters())
trainable = sum(p.numel() for p in model.parameters() if p.requires_grad)
print('\nstart training, parameter total:{}, trainable:{}\n'.format(total, trainable))
model.train() # 将model的模式设为train,这样optimizer就可以更新model的参数
criterion = nn.BCELoss() # 定义损失函数,这里我们使用binary cross entropy loss
t_batch = len(train)
v_batch = len(valid)
optimizer = optim.Adam(model.parameters(), lr=lr) # 将模型的参数给optimizer,并给予适当的learning rate
total_loss, total_acc, best_acc = 0, 0, 0
for epoch in range(n_epoch):
total_loss, total_acc = 0, 0
# 做 training
for i, (inputs, labels) in enumerate(train):
inputs = inputs.to(device, dtype=torch.long) # device 为 "cuda",將 inputs 转成 torch.cuda.LongTensor
labels = labels.to(device, dtype=torch.float) # device为 "cuda",將 labels 转成 torch.cuda.FloatTensor,因为等等要喂进criterion,所以型态要是float
optimizer.zero_grad() # 由于loss.backward()的gradient会累加,所以每次喂完一个batch后需要归零
outputs = model(inputs) # 將 input 喂给模型
outputs = outputs.squeeze() # 去掉最外面的dimension,好让outputs可以喂进criterion()
loss = criterion(outputs, labels) # 计算此时模型的 training loss
loss.backward() # 算 loss 的 gradient
optimizer.step() # 更新训练模型的参数
correct = evaluation(outputs, labels) # 计算此时模型的 training accuracy
total_acc += (correct / batch_size)
total_loss += loss.item()
print('[ Epoch{}: {}/{} ] loss:{:.3f} acc:{:.3f} '.format(
epoch+1, i+1, t_batch, loss.item(), correct*100/batch_size), end='\r')
print('\nTrain | Loss:{:.5f} Acc: {:.3f}'.format(total_loss/t_batch, total_acc/t_batch*100))

# 做 validation
model.eval() # 将model的模式设为eval,这样model的参数就会固定住
with torch.no_grad():
total_loss, total_acc = 0, 0
for i, (inputs, labels) in enumerate(valid):
inputs = inputs.to(device, dtype=torch.long) # device为“cuda”,将inputs转成torch.cuda.LongTensor
labels = labels.to(device, dtype=torch.float) # device为“cuda”,将labels转成torch.cuda.FloatTensor,因为等等要喂进criterion,所以型态要是float
outputs = model(inputs) # 将input喂给模型
outputs = outputs.squeeze() # 去掉最外面的dimension,好让outputs可以喂进criterion()
loss = criterion(outputs, labels) # 计算此时模型的validation loss
correct = evaluation(outputs, labels) # 计算此时模型的validation accuracy
total_acc += (correct / batch_size)
total_loss += loss.item()

print("Valid | Loss:{:.5f} Acc: {:.3f} ".format(total_loss/v_batch, total_acc/v_batch*100))
if total_acc > best_acc:
# 如果validation的结果优于之前所有的结果,就把当下的模型存下来以备之后做预测时使用
best_acc = total_acc
#torch.save(model, "{}/val_acc_{:.3f}.model".format(model_dir,total_acc/v_batch*100))
torch.save(model, "{}/ckpt.model".format(model_dir))
print('saving model with acc {:.3f}'.format(total_acc/v_batch*100))
print('-----------------------------------------------')
model.train() # 将model的模式设为train,这样optimizer就可以更新model的参数(因为刚刚转成eval模式)

Test

# test.py
# 这个block用来对testing_data.txt做预测
import torch
from torch import nn
import torch.optim as optim
import torch.nn.functional as F

def testing(batch_size, test_loader, model, device):
model.eval()# 将 model 的模式设为 eval,这样 model 的参数就会被固定住
ret_output = []
with torch.no_grad():
for i, inputs in enumerate(test_loader):
inputs = inputs.to(device, dtype=torch.long)
outputs = model(inputs)
outputs = outputs.squeeze()
outputs[outputs>=0.5] = 1 # 大于等于0.5为正面
outputs[outputs<0.5] = 0 # 小于0.5为负面
ret_output += outputs.int().tolist()

return

Main

# main.py
import os
import torch
import argparse
import numpy as np
from torch import nn
from gensim.models import word2vec
from sklearn.model_selection import train_test_split

# 通过torch.cuda.is_available()的回传值进行判断是否有使用GPU的环境,如果有的话device就设为“cuda”,没有的话就设为“cpu”
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 处理好各个data的路径
train_with_label = os.path.join(path_prefix, 'training_label.txt')
train_no_label = os.path.join(path_prefix, 'training_nolabel.txt')
testing_data = os.path.join(path_prefix, 'testing_data.txt')

w2v_path = os.path.join(path_prefix, 'w2v_all.model') # 处理word to vec model的路径

# 定义句子长度、要不要固定embedding、batch大小、要训练几个epoch、learning rate的值、model的文件夹路径
sen_len = 20
fix_embedding = True # fix embedding during training
batch_size = 128
epoch = 5
lr = 0.001
# model_dir = os.path.join(path_prefix, 'model/') # model directory for checkpoint model
model_dir = path_prefix # model directory for checkpoint model

print("loading data ...") # 把 'training_label.txt' 跟 'training_nolabel.txt' 读进来
train_x, y = load_training_data(train_with_label)
train_x_no_label = load_training_data(train_no_label)

# 对input跟labels做预处理
preprocess = Preprocess(train_x, sen_len, w2v_path=w2v_path)
embedding = preprocess.make_embedding(load=True)
train_x = preprocess.sentence_word2idx()
y = preprocess.labels_to_tensor(y)

# 制作一个model的对象
model = LSTM_Net(embedding, embedding_dim=250, hidden_dim=150, num_layers=1, dropout=0.5, fix_embedding=fix_embedding)
model = model.to(device) # device为“cuda”,model使用GPU来训练(喂进去的inputs也需要是cuda tensor)

# 把data分为training data跟validation data(将一部份training data拿去当作validation data)
X_train, X_val, y_train, y_val = train_x[:180000], train_x[180000:], y[:180000], y[180000:]

# 把data做成dataset供dataloader取用
train_dataset = TwitterDataset(X=X_train, y=y_train)
val_dataset = TwitterDataset(X=X_val, y=y_val)

# 把data转成batch of tensors
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
batch_size = batch_size,
shuffle = True,
num_workers = 8)

val_loader = torch.utils.data.DataLoader(dataset = val_dataset,
batch_size = batch_size,
shuffle = False,
num_workers = 8)

# 开始训练
training(batch_size, epoch, lr, model_dir, train_loader, val_loader, model, device)

loading data ...
Get embedding ...
loading word to vec model ...
get words #55777
total words: 55779
sentence count #200000
start training, parameter total:14186101, trainable:241351

[ Epoch1: 1407/1407 ] loss:0.384 acc:20.312
Train | Loss:0.49161 Acc: 75.447
Valid | Loss:0.44888 Acc: 78.429
saving model with acc 78.429
-----------------------------------------------
[ Epoch2: 1407/1407 ] loss:0.535 acc:16.406
Train | Loss:0.43598 Acc: 79.567
Valid | Loss:0.43925 Acc: 79.309
saving model with acc 79.309
-----------------------------------------------
[ Epoch3: 1407/1407 ] loss:0.417 acc:19.531
Train | Loss:0.41925 Acc: 80.505
Valid | Loss:0.42836 Acc: 79.653
saving model with acc 79.653
-----------------------------------------------
[ Epoch4: 1407/1407 ] loss:0.401 acc:21.094
Train | Loss:0.40651 Acc: 81.298
Valid | Loss:0.42165 Acc: 80.718
saving model with acc 80.718
-----------------------------------------------
[ Epoch5: 1407/1407 ] loss:0.340 acc:21.094
Train | Loss:0.39554 Acc: 81.854
Valid | Loss:0.41412 Acc: 80.812
saving model with acc 80.812
-----------------------------------------------

Predict and Write to csv file

# 开始测试模型并做预测
print("loading testing data ...")
test_x = load_testing_data(testing_data)
preprocess = Preprocess(test_x, sen_len, w2v_path=w2v_path)
embedding = preprocess.make_embedding(load=True)
test_x = preprocess.sentence_word2idx()
test_dataset = TwitterDataset(X=test_x, y=None)
test_loader = torch.utils.data.DataLoader(dataset = test_dataset,
batch_size = batch_size,
shuffle = False,
num_workers = 8)
print('\nload model ...')
model = torch.load(os.path.join(model_dir, 'ckpt.model'))
outputs = testing(batch_size, test_loader, model, device)



举报

相关推荐

0 条评论