1 前言
?? 優(yōu)質(zhì)競賽項目系列,今天要分享的是
基于GRU的 電影評論情感分析
該項目較為新穎,適合作為競賽課題方向,學(xué)長非常推薦!
?? 更多資料, 項目分享:文章來源:http://www.zghlxwxcb.cn/news/detail-667801.html
https://gitee.com/dancheng-senior/postgraduate文章來源地址http://www.zghlxwxcb.cn/news/detail-667801.html
1.1 項目介紹
其實,很明顯這個項目和微博謠言檢測是一樣的,也是個二分類的問題,因此,我們可以用到學(xué)長之前提到的各種方法,即:
樸素貝葉斯或者邏輯回歸以及支持向量機都可以解決這個問題。
另外在深度學(xué)習(xí)中,我們可以用CNN-Text或者RNN以及LSTM等模型最好。
當(dāng)然在構(gòu)建網(wǎng)絡(luò)中也相對簡單,相對而言,LSTM就比較復(fù)雜了,為了讓不同層次的同學(xué)們可以接受,學(xué)長就用了相對簡單的GRU模型。
如果大家想了解LSTM。以后,學(xué)長會給大家詳細(xì)介紹。
2 情感分類介紹
其實情感分析在自然語言處理中,情感分析一般指判斷一段文本所表達(dá)的情緒狀態(tài),屬于文本分類問題。一般而言:情緒類別:正面/負(fù)面。當(dāng)然,這就是為什么本人在前面提到情感分析實際上也是二分類問題的原因。
3 數(shù)據(jù)集
學(xué)長本次使用的是非常典型的IMDB數(shù)據(jù)集。
該數(shù)據(jù)集包含來自互聯(lián)網(wǎng)的50000條嚴(yán)重兩極分化的評論,該數(shù)據(jù)被分為用于訓(xùn)練的25000條評論和用于測試的25000條評論,訓(xùn)練集和測試集都包含50%的正面評價和50%的負(fù)面評價。該數(shù)據(jù)集已經(jīng)經(jīng)過預(yù)處理:評論(單詞序列)已經(jīng)被轉(zhuǎn)換為整數(shù)序列,其中每個整數(shù)代表字典中的某個單詞。
查看其數(shù)據(jù)集的文件夾:這是train和test文件夾。
接下來就是以train文件夾介紹里面的內(nèi)容
然后就是以neg文件夾介紹里面的內(nèi)容,里面會有若干的text文件:
4 實現(xiàn)
4.1 數(shù)據(jù)預(yù)處理
?
#導(dǎo)入必要的包
import zipfile
import os
import io
import random
import json
import matplotlib.pyplot as plt
import numpy as np
import paddle
import paddle.fluid as fluid
from paddle.fluid.dygraph.nn import Conv2D, Pool2D, Linear, Embedding
from paddle.fluid.dygraph.base import to_variable
from paddle.fluid.dygraph import GRUUnit
import paddle.dataset.imdb as imdb
#加載字典
def load_vocab():
vocab = imdb.word_dict()
return vocab
#定義數(shù)據(jù)生成器
class SentaProcessor(object):
def __init__(self):
self.vocab = load_vocab()
def data_generator(self, batch_size, phase='train'):
if phase == "train":
return paddle.batch(paddle.reader.shuffle(imdb.train(self.vocab),25000), batch_size, drop_last=True)
elif phase == "eval":
return paddle.batch(imdb.test(self.vocab), batch_size,drop_last=True)
else:
raise ValueError(
"Unknown phase, which should be in ['train', 'eval']")
步驟
-
首先導(dǎo)入必要的第三方庫
-
接下來就是數(shù)據(jù)預(yù)處理,需要注意的是:數(shù)據(jù)是以數(shù)據(jù)標(biāo)簽的方式表示一個句子,因此,每個句子都是以一串整數(shù)來表示的,每個數(shù)字都是對應(yīng)一個單詞。當(dāng)然,數(shù)據(jù)集就會有一個數(shù)據(jù)集字典,這個字典是訓(xùn)練數(shù)據(jù)中出現(xiàn)單詞對應(yīng)的數(shù)字標(biāo)簽。
4.2 構(gòu)建網(wǎng)絡(luò)
這次的GRU模型分為以下的幾個步驟
- 定義網(wǎng)絡(luò)
- 定義損失函數(shù)
- 定義優(yōu)化算法
具體實現(xiàn)如下
?
#定義動態(tài)GRU
class DynamicGRU(fluid.dygraph.Layer):
def init(self,
size,
param_attr=None,
bias_attr=None,
is_reverse=False,
gate_activation=‘sigmoid’,
candidate_activation=‘relu’,
h_0=None,
origin_mode=False,
):
super(DynamicGRU, self).init()
self.gru_unit = GRUUnit(
size * 3,
param_attr=param_attr,
bias_attr=bias_attr,
activation=candidate_activation,
gate_activation=gate_activation,
origin_mode=origin_mode)
self.size = size
self.h_0 = h_0
self.is_reverse = is_reverse
def forward(self, inputs):
hidden = self.h_0
res = []
for i in range(inputs.shape[1]):
if self.is_reverse:
i = inputs.shape[1] - 1 - i
input_ = inputs[ :, i:i+1, :]
input_ = fluid.layers.reshape(input_, [-1, input_.shape[2]], inplace=False)
hidden, reset, gate = self.gru_unit(input_, hidden)
hidden_ = fluid.layers.reshape(hidden, [-1, 1, hidden.shape[1]], inplace=False)
res.append(hidden_)
if self.is_reverse:
res = res[::-1]
res = fluid.layers.concat(res, axis=1)
return res
class GRU(fluid.dygraph.Layer):
def __init__(self):
super(GRU, self).__init__()
self.dict_dim = train_parameters["vocab_size"]
self.emb_dim = 128
self.hid_dim = 128
self.fc_hid_dim = 96
self.class_dim = 2
self.batch_size = train_parameters["batch_size"]
self.seq_len = train_parameters["padding_size"]
self.embedding = Embedding(
size=[self.dict_dim + 1, self.emb_dim],
dtype='float32',
param_attr=fluid.ParamAttr(learning_rate=30),
is_sparse=False)
h_0 = np.zeros((self.batch_size, self.hid_dim), dtype="float32")
h_0 = to_variable(h_0)
self._fc1 = Linear(input_dim=self.hid_dim, output_dim=self.hid_dim*3)
self._fc2 = Linear(input_dim=self.hid_dim, output_dim=self.fc_hid_dim, act="relu")
self._fc_prediction = Linear(input_dim=self.fc_hid_dim,
output_dim=self.class_dim,
act="softmax")
self._gru = DynamicGRU(size=self.hid_dim, h_0=h_0)
def forward(self, inputs, label=None):
emb = self.embedding(inputs)
o_np_mask =to_variable(inputs.numpy().reshape(-1,1) != self.dict_dim).astype('float32')
mask_emb = fluid.layers.expand(
to_variable(o_np_mask), [1, self.hid_dim])
emb = emb * mask_emb
emb = fluid.layers.reshape(emb, shape=[self.batch_size, -1, self.hid_dim])
fc_1 = self._fc1(emb)
gru_hidden = self._gru(fc_1)
gru_hidden = fluid.layers.reduce_max(gru_hidden, dim=1)
tanh_1 = fluid.layers.tanh(gru_hidden)
fc_2 = self._fc2(tanh_1)
prediction = self._fc_prediction(fc_2)
if label is not None:
acc = fluid.layers.accuracy(prediction, label=label)
return prediction, acc
else:
return prediction
4.3 訓(xùn)練模型
?
def train():
with fluid.dygraph.guard(place = fluid.CUDAPlace(0)): # # 因為要進(jìn)行很大規(guī)模的訓(xùn)練,因此我們用的是GPU,如果沒有安裝GPU的可以使用下面一句,把這句代碼注釋掉即可
# with fluid.dygraph.guard(place = fluid.CPUPlace()):
processor = SentaProcessor()
train_data_generator = processor.data_generator(batch_size=train_parameters["batch_size"], phase='train')
model = GRU()
sgd_optimizer = fluid.optimizer.Adagrad(learning_rate=train_parameters["lr"],parameter_list=model.parameters())
steps = 0
Iters, total_loss, total_acc = [], [], []
for eop in range(train_parameters["epoch"]):
for batch_id, data in enumerate(train_data_generator()):
steps += 1
doc = to_variable(
np.array([
np.pad(x[0][0:train_parameters["padding_size"]],
(0, train_parameters["padding_size"] - len(x[0][0:train_parameters["padding_size"]])),
'constant',
constant_values=(train_parameters["vocab_size"]))
for x in data
]).astype('int64').reshape(-1))
label = to_variable(
np.array([x[1] for x in data]).astype('int64').reshape(
train_parameters["batch_size"], 1))
model.train()
prediction, acc = model(doc, label)
loss = fluid.layers.cross_entropy(prediction, label)
avg_loss = fluid.layers.mean(loss)
avg_loss.backward()
sgd_optimizer.minimize(avg_loss)
model.clear_gradients()
if steps % train_parameters["skip_steps"] == 0:
Iters.append(steps)
total_loss.append(avg_loss.numpy()[0])
total_acc.append(acc.numpy()[0])
print("step: %d, ave loss: %f, ave acc: %f" %
(steps,avg_loss.numpy(),acc.numpy()))
if steps % train_parameters["save_steps"] == 0:
save_path = train_parameters["checkpoints"]+"/"+"save_dir_" + str(steps)
print('save model to: ' + save_path)
fluid.dygraph.save_dygraph(model.state_dict(),
save_path)
draw_train_process(Iters, total_loss, total_acc)
4.4 模型評估
結(jié)果還可以,這里說明的是,剛開始的模型訓(xùn)練評估不可能這么好,很明顯是過擬合的問題,這就需要我們調(diào)整我們的epoch、batchsize、激活函數(shù)的選擇以及優(yōu)化器、學(xué)習(xí)率等各種參數(shù),通過不斷的調(diào)試、訓(xùn)練最好可以得到不錯的結(jié)果,但是,如果還要更好的模型效果,其實可以將GRU模型換為更為合適的RNN中的LSTM以及bi-
LSTM模型會好很多。
4.5 模型預(yù)測
?
train_parameters[“batch_size”] = 1
with fluid.dygraph.guard(place = fluid.CUDAPlace(0)):
sentences = 'this is a great movie'
data = load_data(sentences)
print(sentences)
print(data)
data_np = np.array(data)
data_np = np.array(np.pad(data_np,(0,150-len(data_np)),"constant",constant_values =train_parameters["vocab_size"])).astype('int64').reshape(-1)
infer_np_doc = to_variable(data_np)
model_infer = GRU()
model, _ = fluid.load_dygraph("data/save_dir_750.pdparams")
model_infer.load_dict(model)
model_infer.eval()
result = model_infer(infer_np_doc)
print('預(yù)測結(jié)果為:正面概率為:%0.5f,負(fù)面概率為:%0.5f' % (result.numpy()[0][0],result.numpy()[0][1]))
訓(xùn)練的結(jié)果還是挺滿意的,到此為止,我們的本次項目實驗到此結(jié)束。
5 最后
?? 更多資料, 項目分享:
https://gitee.com/dancheng-senior/postgraduate
到了這里,關(guān)于計算機競賽 基于GRU的 電影評論情感分析 - python 深度學(xué)習(xí) 情感分類的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!