欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

基于循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)實(shí)現(xiàn)影評(píng)情感分類

 更新時(shí)間:2018年03月26日 10:39:00   作者:筆墨留年  
這篇文章主要為大家詳細(xì)介紹了基于循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)實(shí)現(xiàn)影評(píng)情感分類,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

使用循環(huán)神經(jīng)網(wǎng)絡(luò)(RNN)實(shí)現(xiàn)影評(píng)情感分類

作為對(duì)循環(huán)神經(jīng)網(wǎng)絡(luò)的實(shí)踐,我用循環(huán)神經(jīng)網(wǎng)絡(luò)做了個(gè)影評(píng)情感的分類,即判斷影評(píng)的感情色彩是正面的,還是負(fù)面的。

選擇使用RNN來(lái)做情感分類,主要是因?yàn)橛霸u(píng)是一段文字,是序列的,而RNN對(duì)序列的支持比較好,能夠“記憶”前文。雖然可以提取特征詞向量,然后交給傳統(tǒng)機(jī)器學(xué)習(xí)模型或全連接神經(jīng)網(wǎng)絡(luò)去做,也能取得很好的效果,但只從端對(duì)端的角度來(lái)看的話,RNN無(wú)疑是最合適的。

以下介紹實(shí)現(xiàn)過程。

一、數(shù)據(jù)預(yù)處理

本文中使用的訓(xùn)練數(shù)據(jù)集為https://www.cs.cornell.edu/people/pabo/movie-review-data/上的sentence polarity dataset v1.0,包含正負(fù)面評(píng)論各5331條??梢渣c(diǎn)擊進(jìn)行下載。

數(shù)據(jù)下載下來(lái)之后需要進(jìn)行解壓,得到rt-polarity.negrt-polarity.pos文件,這兩個(gè)文件是Windows-1252編碼的,先將它轉(zhuǎn)成unicode處理起來(lái)會(huì)更方便。

補(bǔ)充一下小知識(shí),當(dāng)我們打開一個(gè)文件,發(fā)現(xiàn)亂碼,卻又不知道該文件的編碼是什么的時(shí)候,可以使用pythonchardet類庫(kù)進(jìn)行判斷,這里的Windows-1252就是使用該類庫(kù)檢測(cè)出來(lái)的。

在數(shù)據(jù)預(yù)處理部分,我們要完成如下處理過程:

1.轉(zhuǎn)碼

即將文件轉(zhuǎn)為unicode編碼,方便我們后續(xù)操作。讀取文件,轉(zhuǎn)換編碼,重新寫入到新文件即可。不存在技術(shù)難點(diǎn)。

2.生成詞匯表

讀取訓(xùn)練文件,提取出所有的單詞,并統(tǒng)計(jì)各個(gè)單詞出現(xiàn)的次數(shù)。為了避免低頻詞的干擾,同時(shí)減少模型參數(shù),我們只保留部分高頻詞,比如這里我只保存出現(xiàn)次數(shù)前9999個(gè),同時(shí)將低頻詞標(biāo)識(shí)符<unkown>加入到詞匯表中。

3.借助詞匯表將影評(píng)轉(zhuǎn)化為詞向量

單詞是沒法直接輸入給模型的,所以我們需要將詞匯表中的每個(gè)單詞對(duì)應(yīng)于一個(gè)編號(hào),將影評(píng)數(shù)據(jù)轉(zhuǎn)化成詞向量。方便后面生成詞嵌入矩陣。

4.填充詞向量并轉(zhuǎn)化為np數(shù)組

因?yàn)椴煌u(píng)論的長(zhǎng)度是不同的,我們要組成batch進(jìn)行訓(xùn)練,就需要先將其長(zhǎng)度統(tǒng)一。這里我選擇以最長(zhǎng)的影評(píng)為標(biāo)準(zhǔn),對(duì)其他較短的影評(píng)的空白部分進(jìn)行填充。然后將其轉(zhuǎn)化成numpy的數(shù)組。

5.按比例劃分?jǐn)?shù)據(jù)集

按照機(jī)器學(xué)習(xí)的慣例,數(shù)據(jù)集應(yīng)被劃分為三份,即訓(xùn)練集、開發(fā)集和測(cè)試集。當(dāng)然,有時(shí)也會(huì)只劃分兩份,即只包括訓(xùn)練集和開發(fā)集。

這里我劃分成三份,訓(xùn)練集、開發(fā)集和測(cè)試集的占比為[0.8,0.1,0.1]。劃分的方式為輪盤賭法,在numpy中可以使用cumsumsearchsorted來(lái)簡(jiǎn)潔地實(shí)現(xiàn)輪盤賭法。

6.打亂數(shù)據(jù)集,寫入文件

為了取得更好的訓(xùn)練效果,將數(shù)據(jù)集隨機(jī)打亂。為了保證在訓(xùn)練和模型調(diào)整的過程中訓(xùn)練集、開發(fā)集、測(cè)試集不發(fā)生改變,將三個(gè)數(shù)據(jù)集寫入到文件中,使用的時(shí)候從文件中讀取。

下面貼上數(shù)據(jù)預(yù)處理的代碼,注釋寫的很細(xì),就不多說了。

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午2:28
# @Author : AaronJny
# @Email : Aaron__7@163.com
import sys

reload(sys)
sys.setdefaultencoding('utf8')
import collections
import settings
import utils
import numpy as np


def create_vocab():
 """
 創(chuàng)建詞匯表,寫入文件中
 :return:
 """
 # 存放出現(xiàn)的所有單詞
 word_list = []
 # 從文件中讀取數(shù)據(jù),拆分單詞
 with open(settings.NEG_TXT, 'r') as f:
 f_lines = f.readlines()
 for line in f_lines:
 words = line.strip().split()
 word_list.extend(words)
 with open(settings.POS_TXT, 'r') as f:
 f_lines = f.readlines()
 for line in f_lines:
 words = line.strip().split()
 word_list.extend(words)
 # 統(tǒng)計(jì)單詞出現(xiàn)的次數(shù)
 counter = collections.Counter(word_list)

 sorted_words = sorted(counter.items(), key=lambda x: x[1], reverse=True)
 # 選取高頻詞
 word_list = [word[0] for word in sorted_words]

 word_list = ['<unkown>'] + word_list[:settings.VOCAB_SIZE - 1]
 # 將詞匯表寫入文件中
 with open(settings.VOCAB_PATH, 'w') as f:
 for word in word_list:
 f.write(word + '\n')


def create_vec(txt_path, vec_path):
 """
 根據(jù)詞匯表生成詞向量
 :param txt_path: 影評(píng)文件路徑
 :param vec_path: 輸出詞向量路徑
 :return:
 """
 # 獲取單詞到編號(hào)的映射
 word2id = utils.read_word_to_id_dict()
 # 將語(yǔ)句轉(zhuǎn)化成向量
 vec = []
 with open(txt_path, 'r') as f:
 f_lines = f.readlines()
 for line in f_lines:
 tmp_vec = [str(utils.get_id_by_word(word, word2id)) for word in line.strip().split()]
 vec.append(tmp_vec)
 # 寫入文件中
 with open(vec_path, 'w') as f:
 for tmp_vec in vec:
 f.write(' '.join(tmp_vec) + '\n')


def cut_train_dev_test():
 """
 使用輪盤賭法,劃分訓(xùn)練集、開發(fā)集和測(cè)試集
 打亂,并寫入不同文件中
 :return:
 """
 # 三個(gè)位置分別存放訓(xùn)練、開發(fā)、測(cè)試
 data = [[], [], []]
 labels = [[], [], []]
 # 累加概率 rate [0.8,0.1,0.1] cumsum_rate [0.8,0.9,1.0]
 rate = np.array([settings.TRAIN_RATE, settings.DEV_RATE, settings.TEST_RATE])
 cumsum_rate = np.cumsum(rate)
 # 使用輪盤賭法劃分?jǐn)?shù)據(jù)集
 with open(settings.POS_VEC, 'r') as f:
 f_lines = f.readlines()
 for line in f_lines:
 tmp_data = [int(word) for word in line.strip().split()]
 tmp_label = [1, ]
 index = int(np.searchsorted(cumsum_rate, np.random.rand(1) * 1.0))
 data[index].append(tmp_data)
 labels[index].append(tmp_label)
 with open(settings.NEG_VEC, 'r') as f:
 f_lines = f.readlines()
 for line in f_lines:
 tmp_data = [int(word) for word in line.strip().split()]
 tmp_label = [0, ]
 index = int(np.searchsorted(cumsum_rate, np.random.rand(1) * 1.0))
 data[index].append(tmp_data)
 labels[index].append(tmp_label)
 # 計(jì)算一下實(shí)際上分割出來(lái)的比例
 print '最終分割比例', np.array([map(len, data)], dtype=np.float32) / sum(map(len, data))
 # 打亂數(shù)據(jù),寫入到文件中
 shuffle_data(data[0], labels[0], settings.TRAIN_DATA)
 shuffle_data(data[1], labels[1], settings.DEV_DATA)
 shuffle_data(data[2], labels[2], settings.TEST_DATA)


def shuffle_data(x, y, path):
 """
 填充數(shù)據(jù),生成np數(shù)組
 打亂數(shù)據(jù),寫入文件中
 :param x: 數(shù)據(jù)
 :param y: 標(biāo)簽
 :param path: 保存路徑
 :return:
 """
 # 計(jì)算影評(píng)的最大長(zhǎng)度
 maxlen = max(map(len, x))
 # 填充數(shù)據(jù)
 data = np.zeros([len(x), maxlen], dtype=np.int32)
 for row in range(len(x)):
 data[row, :len(x[row])] = x[row]
 label = np.array(y)
 # 打亂數(shù)據(jù)
 state = np.random.get_state()
 np.random.shuffle(data)
 np.random.set_state(state)
 np.random.shuffle(label)
 # 保存數(shù)據(jù)
 np.save(path + '_data', data)
 np.save(path + '_labels', label)


def decode_file(infile, outfile):
 """
 將文件的編碼從'Windows-1252'轉(zhuǎn)為Unicode
 :param infile: 輸入文件路徑
 :param outfile: 輸出文件路徑
 :return:
 """
 with open(infile, 'r') as f:
 txt = f.read().decode('Windows-1252')
 with open(outfile, 'w') as f:
 f.write(txt)


if __name__ == '__main__':
 # 解碼文件
 decode_file(settings.ORIGIN_POS, settings.POS_TXT)
 decode_file(settings.ORIGIN_NEG, settings.NEG_TXT)
 # 創(chuàng)建詞匯表
 create_vocab()
 # 生成詞向量
 create_vec(settings.NEG_TXT, settings.NEG_VEC)
 create_vec(settings.POS_TXT, settings.POS_VEC)
 # 劃分?jǐn)?shù)據(jù)集
 cut_train_dev_test()

二、模型編寫

數(shù)據(jù)處理好之后,開始模型的編寫。這里選用循環(huán)神經(jīng)網(wǎng)絡(luò),建模過程大致如下:

1.使用embedding構(gòu)建詞嵌入矩陣

在數(shù)據(jù)預(yù)處理中,我們將影評(píng)處理成了一個(gè)個(gè)單詞編號(hào)構(gòu)成的向量,也就是說,一條影評(píng),對(duì)應(yīng)于一個(gè)由單詞編號(hào)構(gòu)成的向量。

將這樣的向量進(jìn)行embedding,即可構(gòu)建出詞嵌入矩陣。在詞嵌入矩陣中,每個(gè)詞由一個(gè)向量表示,矩陣中不同向量之間的差異對(duì)應(yīng)于它們表示的詞之間的差異。

2.使用LSTM作為循環(huán)神經(jīng)網(wǎng)絡(luò)的基本單元

長(zhǎng)短時(shí)記憶網(wǎng)絡(luò)(LSTM)能夠自動(dòng)完成前文信息的“記憶”和“遺忘”,在循環(huán)神經(jīng)網(wǎng)絡(luò)中表現(xiàn)良好,已經(jīng)成為在循環(huán)神經(jīng)網(wǎng)絡(luò)中大部分人的首選。這里我選擇使用LSTM作為循環(huán)神經(jīng)網(wǎng)絡(luò)的基本單元。

3.對(duì)embedding和LSTM進(jìn)行隨機(jī)失活(dropout)

為了提高模型的泛化能力,并減少參數(shù),我對(duì)embedding層和LSTM單元進(jìn)行dropout。

4.建立深度為2的深度循環(huán)神經(jīng)網(wǎng)絡(luò)

為了提高模型的擬合能力,使用深度循環(huán)神經(jīng)網(wǎng)絡(luò),我選擇的深度為2。

5.給出二分類概率

對(duì)深度循環(huán)神經(jīng)網(wǎng)絡(luò)的最后節(jié)點(diǎn)的輸出做邏輯回歸,通過sigmoid使結(jié)果落到0-1之間,代表結(jié)果是正類的概率。

損失函數(shù)使用交叉熵,優(yōu)化器選擇Adam。

此部分代碼如下(注:代碼中裝飾器的作用為劃分命名空間以及保證張量運(yùn)算只被定義一次):

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午2:57
# @Author : AaronJny
# @Email : Aaron__7@163.com
import tensorflow as tf
import functools
import settings

HIDDEN_SIZE = 128
NUM_LAYERS = 2


def doublewrap(function):
 @functools.wraps(function)
 def decorator(*args, **kwargs):
 if len(args) == 1 and len(kwargs) == 0 and callable(args[0]):
 return function(args[0])
 else:
 return lambda wrapee: function(wrapee, *args, **kwargs)

 return decorator


@doublewrap
def define_scope(function, scope=None, *args, **kwargs):
 attribute = '_cache_' + function.__name__
 name = scope or function.__name__

 @property
 @functools.wraps(function)
 def decorator(self):
 if not hasattr(self, attribute):
 with tf.variable_scope(name, *args, **kwargs):
 setattr(self, attribute, function(self))
 return getattr(self, attribute)

 return decorator


class Model(object):
 def __init__(self, data, lables, emb_keep, rnn_keep):
 """
 神經(jīng)網(wǎng)絡(luò)模型
 :param data:數(shù)據(jù)
 :param lables: 標(biāo)簽
 :param emb_keep: emb層保留率
 :param rnn_keep: rnn層保留率
 """
 self.data = data
 self.label = lables
 self.emb_keep = emb_keep
 self.rnn_keep = rnn_keep
 self.predict
 self.loss
 self.global_step
 self.ema
 self.optimize
 self.acc

 @define_scope
 def predict(self):
 """
 定義前向傳播過程
 :return:
 """
 # 詞嵌入矩陣權(quán)重
 embedding = tf.get_variable('embedding', [settings.VOCAB_SIZE, HIDDEN_SIZE])
 # 使用dropout的LSTM
 lstm_cell = [tf.nn.rnn_cell.DropoutWrapper(tf.nn.rnn_cell.BasicLSTMCell(HIDDEN_SIZE), self.rnn_keep) for _ in
  range(NUM_LAYERS)]
 # 構(gòu)建循環(huán)神經(jīng)網(wǎng)絡(luò)
 cell = tf.nn.rnn_cell.MultiRNNCell(lstm_cell)
 # 生成詞嵌入矩陣,并進(jìn)行dropout
 input = tf.nn.embedding_lookup(embedding, self.data)
 dropout_input = tf.nn.dropout(input, self.emb_keep)
 # 計(jì)算rnn的輸出
 outputs, last_state = tf.nn.dynamic_rnn(cell, dropout_input, dtype=tf.float32)
 # 做二分類問題,這里只需要最后一個(gè)節(jié)點(diǎn)的輸出
 last_output = outputs[:, -1, :]
 # 求最后節(jié)點(diǎn)輸出的線性加權(quán)和
 weights = tf.Variable(tf.truncated_normal([HIDDEN_SIZE, 1]), dtype=tf.float32, name='weights')
 bias = tf.Variable(0, dtype=tf.float32, name='bias')

 logits = tf.matmul(last_output, weights) + bias

 return logits

 @define_scope
 def ema(self):
 """
 定義移動(dòng)平均
 :return:
 """
 ema = tf.train.ExponentialMovingAverage(settings.EMA_RATE, self.global_step)
 return ema

 @define_scope
 def loss(self):
 """
 定義損失函數(shù),這里使用交叉熵
 :return:
 """
 loss = tf.nn.sigmoid_cross_entropy_with_logits(labels=self.label, logits=self.predict)
 loss = tf.reduce_mean(loss)
 return loss

 @define_scope
 def global_step(self):
 """
 step,沒什么好說的,注意指定trainable=False
 :return:
 """
 global_step = tf.Variable(0, trainable=False)
 return global_step

 @define_scope
 def optimize(self):
 """
 定義反向傳播過程
 :return:
 """
 # 學(xué)習(xí)率衰減
 learn_rate = tf.train.exponential_decay(settings.LEARN_RATE, self.global_step, settings.LR_DECAY_STEP,
   settings.LR_DECAY)
 # 反向傳播優(yōu)化器
 optimizer = tf.train.AdamOptimizer(learn_rate).minimize(self.loss, global_step=self.global_step)
 # 移動(dòng)平均操作
 ave_op = self.ema.apply(tf.trainable_variables())
 # 組合構(gòu)成訓(xùn)練op
 with tf.control_dependencies([optimizer, ave_op]):
 train_op = tf.no_op('train')
 return train_op

 @define_scope
 def acc(self):
 """
 定義模型acc計(jì)算過程
 :return:
 """
 # 對(duì)前向傳播的結(jié)果求sigmoid
 output = tf.nn.sigmoid(self.predict)
 # 真負(fù)類
 ok0 = tf.logical_and(tf.less_equal(output, 0.5), tf.equal(self.label, 0))
 # 真正類
 ok1 = tf.logical_and(tf.greater(output, 0.5), tf.equal(self.label, 1))
 # 一個(gè)數(shù)組,所有預(yù)測(cè)正確的都為True,否則False
 ok = tf.logical_or(ok0, ok1)
 # 先轉(zhuǎn)化成浮點(diǎn)型,再通過求平均來(lái)計(jì)算acc
 acc = tf.reduce_mean(tf.cast(ok, dtype=tf.float32))
 return acc

三、組織數(shù)據(jù)集

我編寫了一個(gè)類用于組織數(shù)據(jù),方便訓(xùn)練和驗(yàn)證使用。代碼很簡(jiǎn)單,就不多說了,直接貼代碼:

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午3:33
# @Author : AaronJny
# @Email : Aaron__7@163.com
import numpy as np
import settings


class Dataset(object):
 def __init__(self, data_kind=0):
 """
 生成一個(gè)數(shù)據(jù)集對(duì)象
 :param data_kind: 決定了使用哪種數(shù)據(jù)集 0-訓(xùn)練集 1-開發(fā)集 2-測(cè)試集
 """
 self.data, self.labels = self.read_data(data_kind)
 self.start = 0 # 記錄當(dāng)前batch位置
 self.data_size = len(self.data) # 樣例數(shù)

 def read_data(self, data_kind):
 """
 從文件中加載數(shù)據(jù)
 :param data_kind:數(shù)據(jù)集種類 0-訓(xùn)練集 1-開發(fā)集 2-測(cè)試集
 :return:
 """
 # 獲取數(shù)據(jù)集路徑
 data_path = [settings.TRAIN_DATA, settings.DEV_DATA, settings.TEST_DATA][data_kind]
 # 加載
 data = np.load(data_path + '_data.npy')
 labels = np.load(data_path + '_labels.npy')
 return data, labels

 def next_batch(self, batch_size):
 """
 獲取一個(gè)大小為batch_size的batch
 :param batch_size: batch大小
 :return:
 """
 start = self.start
 end = min(start + batch_size, self.data_size)
 self.start = end
 # 當(dāng)遍歷完成后回到起點(diǎn)
 if self.start >= self.data_size:
 self.start = 0
 # 返回一個(gè)batch的數(shù)據(jù)和標(biāo)簽
 return self.data[start:end], self.labels[start:end]

四、模型訓(xùn)練

訓(xùn)練過程中,額外操作主要有兩個(gè):

1.使用移動(dòng)平均

我使用移動(dòng)平均的主要目的是使loss曲線盡量平滑,以及提升模型的泛化能力。

2.使用學(xué)習(xí)率指數(shù)衰減

目的是保證前期學(xué)習(xí)率足夠大,能夠快速降低loss,后期學(xué)習(xí)率變小,能更好地逼近最優(yōu)解。

當(dāng)然,就是說說而已,這次的訓(xùn)練數(shù)據(jù)比較簡(jiǎn)單,學(xué)習(xí)率衰減發(fā)揮的作用不大。

訓(xùn)練過程中,定期保存模型,以及checkpoint。這樣可以在訓(xùn)練的同時(shí),在驗(yàn)證腳本中讀取最新模型進(jìn)行驗(yàn)證。

此部分具體代碼如下:

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午4:41
# @Author : AaronJny
# @Email : Aaron__7@163.com
import settings
import tensorflow as tf
import models
import dataset
import os

BATCH_SIZE = settings.BATCH_SIZE

# 數(shù)據(jù)
x = tf.placeholder(tf.int32, [None, None])
# 標(biāo)簽
y = tf.placeholder(tf.float32, [None, 1])
# emb層的dropout保留率
emb_keep = tf.placeholder(tf.float32)
# rnn層的dropout保留率
rnn_keep = tf.placeholder(tf.float32)

# 創(chuàng)建一個(gè)模型
model = models.Model(x, y, emb_keep, rnn_keep)

# 創(chuàng)建數(shù)據(jù)集對(duì)象
data = dataset.Dataset(0)

saver = tf.train.Saver()

with tf.Session() as sess:
 # 全局初始化
 sess.run(tf.global_variables_initializer())
 # 迭代訓(xùn)練
 for step in range(settings.TRAIN_TIMES):
 # 獲取一個(gè)batch進(jìn)行訓(xùn)練
 x, y = data.next_batch(BATCH_SIZE)
 loss, _ = sess.run([model.loss, model.optimize],
  {model.data: x, model.label: y, model.emb_keep: settings.EMB_KEEP_PROB,
  model.rnn_keep: settings.RNN_KEEP_PROB})
 # 輸出loss
 if step % settings.SHOW_STEP == 0:
 print 'step {},loss is {}'.format(step, loss)
 # 保存模型
 if step % settings.SAVE_STEP == 0:
 saver.save(sess, os.path.join(settings.CKPT_PATH, settings.MODEL_NAME), model.global_step)

五、驗(yàn)證模型

加載最新模型進(jìn)行驗(yàn)證,通過修改數(shù)據(jù)集對(duì)象的參數(shù)可以制定訓(xùn)練/開發(fā)/測(cè)試集進(jìn)行驗(yàn)證。

加載模型的時(shí)候,使用移動(dòng)平均的影子變量覆蓋對(duì)應(yīng)變量。

代碼如下:

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午5:09
# @Author : AaronJny
# @Email : Aaron__7@163.com
import settings
import tensorflow as tf
import models
import dataset
import os
import time

# 為了在使用GPU訓(xùn)練的同時(shí),使用CPU進(jìn)行驗(yàn)證
os.environ['CUDA_VISIBLE_DEVICES'] = ''

BATCH_SIZE = settings.BATCH_SIZE

# 數(shù)據(jù)
x = tf.placeholder(tf.int32, [None, None])
# 標(biāo)簽
y = tf.placeholder(tf.float32, [None, 1])
# emb層的dropout保留率
emb_keep = tf.placeholder(tf.float32)
# rnn層的dropout保留率
rnn_keep = tf.placeholder(tf.float32)

# 創(chuàng)建一個(gè)模型
model = models.Model(x, y, emb_keep, rnn_keep)

# 創(chuàng)建一個(gè)數(shù)據(jù)集對(duì)象
data = dataset.Dataset(1) # 0-訓(xùn)練集 1-開發(fā)集 2-測(cè)試集

# 移動(dòng)平均變量
restore_variables = model.ema.variables_to_restore()
# 使用移動(dòng)平均變量進(jìn)行覆蓋
saver = tf.train.Saver(restore_variables)

with tf.Session() as sess:
 while True:
 # 加載最新的模型
 ckpt = tf.train.get_checkpoint_state(settings.CKPT_PATH)
 saver.restore(sess, ckpt.model_checkpoint_path)
 # 計(jì)算并輸出acc
 acc = sess.run([model.acc],
  {model.data: data.data, model.label: data.labels, model.emb_keep: 1.0, model.rnn_keep: 1.0})
 print 'acc is ', acc
 time.sleep(1)

六、對(duì)詞匯表進(jìn)行操作的幾個(gè)方法

把對(duì)詞匯表進(jìn)行操作的幾個(gè)方法提取出來(lái)了,放到了utils.py文件中。

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午2:44
# @Author : AaronJny
# @Email : Aaron__7@163.com
import settings


def read_vocab_list():
 """
 讀取詞匯表
 :return:由詞匯表中所有單詞組成的列表
 """
 with open(settings.VOCAB_PATH, 'r') as f:
 vocab_list = f.read().strip().split('\n')
 return vocab_list


def read_word_to_id_dict():
 """
 生成一個(gè)單詞到編號(hào)的映射
 :return:單詞到編號(hào)的字典
 """
 vocab_list = read_vocab_list()
 word2id = dict(zip(vocab_list, range(len(vocab_list))))
 return word2id


def read_id_to_word_dict():
 """
 生成一個(gè)編號(hào)到單詞的映射
 :return:編號(hào)到單詞的字典
 """
 vocab_list = read_vocab_list()
 id2word = dict(zip(range(len(vocab_list)), vocab_list))
 return id2word


def get_id_by_word(word, word2id):
 """
 給定一個(gè)單詞和字典,獲得單詞在字典中的編號(hào)
 :param word: 給定單詞
 :param word2id: 單詞到編號(hào)的映射
 :return: 若單詞在字典中,返回對(duì)應(yīng)的編號(hào) 否則,返回word2id['<unkown>']
 """
 if word in word2id:
 return word2id[word]
 else:
 return word2id['<unkown>']

七、對(duì)模型進(jìn)行配置

模型的配置參數(shù)大多數(shù)都被提取出來(lái),單獨(dú)放到了settings.py文件中,可以在這里對(duì)模型進(jìn)行配置。

# -*- coding: utf-8 -*-
# @Time : 18-3-14 下午2:44
# @Author : AaronJny
# @Email : Aaron__7@163.com

# 源數(shù)據(jù)路徑
ORIGIN_NEG = 'data/rt-polarity.neg'

ORIGIN_POS = 'data/rt-polarity.pos'
# 轉(zhuǎn)碼后的數(shù)據(jù)路徑
NEG_TXT = 'data/neg.txt'

POS_TXT = 'data/pos.txt'
# 詞匯表路徑
VOCAB_PATH = 'data/vocab.txt'
# 詞向量路徑
NEG_VEC = 'data/neg.vec'

POS_VEC = 'data/pos.vec'
# 訓(xùn)練集路徑
TRAIN_DATA = 'data/train'
# 開發(fā)集路徑
DEV_DATA = 'data/dev'
# 測(cè)試集路徑
TEST_DATA = 'data/test'
# 模型保存路徑
CKPT_PATH = 'ckpt'
# 模型名稱
MODEL_NAME = 'model'
# 詞匯表大小
VOCAB_SIZE = 10000
# 初始學(xué)習(xí)率
LEARN_RATE = 0.0001
# 學(xué)習(xí)率衰減
LR_DECAY = 0.99
# 衰減頻率
LR_DECAY_STEP = 1000
# 總訓(xùn)練次數(shù)
TRAIN_TIMES = 2000
# 顯示訓(xùn)練loss的頻率
SHOW_STEP = 10
# 保存訓(xùn)練模型的頻率
SAVE_STEP = 100
# 訓(xùn)練集占比
TRAIN_RATE = 0.8
# 開發(fā)集占比
DEV_RATE = 0.1
# 測(cè)試集占比
TEST_RATE = 0.1
# BATCH大小
BATCH_SIZE = 64
# emb層dropout保留率
EMB_KEEP_PROB = 0.5
# rnn層dropout保留率
RNN_KEEP_PROB = 0.5
# 移動(dòng)平均衰減率
EMA_RATE = 0.99

八、運(yùn)行模型

至此,模型構(gòu)建完成。模型的運(yùn)行步驟大致如下:

1.確保數(shù)據(jù)文件放在了對(duì)應(yīng)路徑中,運(yùn)行python process_data對(duì)數(shù)據(jù)進(jìn)行預(yù)處理。

2.運(yùn)行python train.py對(duì)模型進(jìn)行訓(xùn)練,訓(xùn)練好的模型會(huì)自動(dòng)保存到對(duì)應(yīng)的路徑中。

3.運(yùn)行python eval.py讀取保存的最新模型,對(duì)訓(xùn)練/開發(fā)/測(cè)試集進(jìn)行驗(yàn)證。

我簡(jiǎn)單跑了一下,由于數(shù)據(jù)集較小,模型的泛化能力不是很好。

當(dāng)訓(xùn)練集、開發(fā)集、測(cè)試集的分布為[0.8,0.1,0.1],訓(xùn)練2000個(gè)batch_size=64的mini_batch時(shí),模型在各數(shù)據(jù)集上的acc表現(xiàn)大致如下:

訓(xùn)練集 0.95

開發(fā)集 0.79

測(cè)試集 0.80

更多

轉(zhuǎn)行做機(jī)器學(xué)習(xí),要學(xué)的還很多,文中如有錯(cuò)誤紕漏之處,懇請(qǐng)諸位大佬拍磚指教…

項(xiàng)目GitHub地址:https://github.com/AaronJny/emotional_classification_with_rnn

以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評(píng)論