神经网络之文本情感分析(四)
2017-11-09 15:48
429 查看
Project 4
在Project 3中,我们对神经网络做了一丢丢的改变就使得准率上升了一大截在这个Project中,我们将对神经网络进行改进,使得训练的速度更快。
如何实现呢?我们的网络存在很多不必要的计算,只要排除这些不必要的计算,那么速度就会飞起。下面举个例子说明一下为什么我们的网络存在很多不必要的计算
import numpy as np import sys import time import pandas as pd # 读取数据 reviews = pd.read_csv('reviews.txt', header=None) labels = pd.read_csv('labels.txt', header=None)
0 | |
---|---|
0 | bromwell high is a cartoon comedy . it ran at … |
1 | story of a man who has unnatural feelings for … |
2 | homelessness or houselessness as george carli… |
3 | airport starts as a brand new luxury pla… |
4 | brilliant over acting by lesley ann warren . … |
# 统计出现的单词 review_vocab = set() for review in reviews.values[0:10]: words = review[0].split(' ') review_vocab.update(words) vocab = list(review_vocab)
# 构建word2idx word2idx = dict() for i, word in enumerate(vocab): word2idx[word] = i
def get_input(review): layer_0 = np.zeros( len(vocab) ) words = review.split(' ') for word in words: word = word.lower() if word in word2idx : idx = word2idx[word] layer_0[idx] = 1 return layer_0
get_input("This moive is very good")
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 1., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
我们可以看到,对于”This moive is very good”这条review来说,在数字化之后,其实只有五个地方有值,其余地方都是0
0乘以任何数都是零,这些0就是所谓的不必要的运算,那么如何避免这些不必要的运算呢?我们再举个小栗子
接下来:layer_0就是我们的输入,weights_0_1就是输入层到隐层的权重,我们利用加法模拟np.dot( layer_0, weights_0_1 )的过程
layer_0 = np.zeros(10) layer_0
array([ 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.])
layer_0[5] = 1 layer_0[9] = 1 layer_0
array([ 0., 0., 0., 0., 0., 1., 0., 0., 0., 1.])
weights_0_1 = np.random.rand(10, 5)
np.dot( layer_0, weights_0_1 )
array([ 0.91279175, 0.40723046, 0.39995155, 0.53770514, 0.93818865])
weights_0_1[5] + weights_0_1[9]
array([ 0.91279175, 0.40723046, 0.39995155, 0.53770514, 0.93818865])
看上面的例子,np.dot 完全可以利用加法进行替代。
np.dot( layer_0, weights_0_1 )进行了5*10次乘法,而下面只计算了两次加法,计算效率提高了好多好多倍
改造我们的网络
改造的地方主要有两个我们不再需要layer_0。layer_0原本是输入,用于np.dot( layer_0, weights_0_1 ),也就是计算隐层layer_1,但是现在我们不需要计算np.dot了,而是通过加法,直接获得layer_1,因此我们直接保存layer_1即可
反向传播中,利用同样的思想对weights_0_1进行更新
具体内容请看代码,修改部分已注释
class SentimentNetwork(object): def __init__(self, reviews, labels, hidden_nodes=10, learning_rate = 0.1): """ 参数: reviews(dataFrame), 用于训练 labels(dataFrame), 用于训练 hidden_nodes(int), 隐层的个数 learning_rate(double),学习步长 """ np.random.seed(1) self.pre_process_data(reviews, labels) self.init_network(len(self.review_vocab), hidden_nodes, 1, learning_rate) def pre_process_data(self, reviews, labels): """ 预处理数据,统计reviews中出现的所有单词,并且生成word2index """ # 统计reviews中出现的所有单词, review_vocab = set() for review in reviews.values: word = review[0].split(' ') review_vocab.update(word) self.review_vocab = list(review_vocab) # 统计labels中所有出现的label(其实在这里,就+1和-1两种) label_vocab = set() for label in labels.values: label_vocab.add(label[0]) self.label_vocab = list(label_vocab) # 构建word2idx,给每个单词安排一个"门牌号" self.word2index = dict() for idx, word in enumerate(self.review_vocab): self.word2index[word] = idx def init_network(self, input_nodes, hidden_nodes, output_nodes, learning_rate): """ 初始化网络的参数 """ self.learning_rate = learning_rate self.input_nodes = input_nodes self.hidden_nodes = hidden_nodes self.output_nodes = output_nodes self.weights_0_1 = np.random.normal( 0.0, self.input_nodes**-0.5, (self.input_nodes, self.hidden_nodes) ) self.weights_1_2 = np.random.normal( 0.0, self.hidden_nodes**-0.5, (self.hidden_nodes, self.output_nodes) ) self.layer_1 = np.zeros((1, self.hidden_nodes)) # (改)我们不再需要这个函数 # def update_input_layer(self, review): # """ # (改)删除layer_0,直接计算并保留layer_1 # """ # self.layer_1 *= 0 # for word in review.split(' '): # if word.lower() in self.word2idx: # idx = self.word2idx[word.lower()] # # 在出现的单词位置设置为1,不再使用出现次数作为输入 # self.layer_0[0,idx] = 1 # # self.layer_0[0,idx] += 1 def sigmoid(self, x): return 1 / (1 + np.exp(-x)) def sigmoid_output_2_derivative(self, output): return output * (1 - output) def get_target_for_label(self,label): if label == 'positive': return 1 else: return 0 # # (改) training_reviews_raw 用于表示纯文本数据 def train(self, training_reviews_raw, training_labels): assert(len(training_reviews_raw) == len(training_labels)) # (改) 将纯文本进行转换,转换成单词出现下标的集合 # 听上去有点绕,回想"This moive is very good"这个例子,这个纯文本数据将会变成类似[20, 150, 300, 312, 500], # 数字为对应单词的"门牌号" training_reviews = list() for review in training_reviews_raw.values: words = review[0].split(' ') indicates = set() for word in words: word = word.lower() if word in self.word2index.keys(): indicates.add(self.word2index[word]) training_reviews.append(list(indicates)) assert(len(training_reviews) == len(training_labels)) correct_so_far = 0 start = time.time() # (改)进行训练 # 直接计算layer_1,删除所有与layer_0有关的代码 for i in range(len(training_reviews)): review = training_reviews[i] label = training_labels.iloc[i,0] # (改) 我们不再需要这个函数 #self.update_input_layer(review) # (改) 我们不再用np.dot计算 #layer_1_i = np.dot( self.layer_0, self.weights_0_1 ) self.layer_1 *= 0 for index in review: self.layer_1 += self.weights_0_1[index] layer_1_o = self.layer_1 layer_2_i = np.dot( layer_1_o, self.weights_1_2 ) layer_2_o = self.sigmoid( layer_2_i ) layer_2_error = layer_2_o - self.get_target_for_label(label) layer_2_delta = layer_2_error * self.sigmoid_output_2_derivative(layer_2_o) layer_1_error = np.dot( layer_2_delta, self.weights_1_2.T ) layer_1_delta = layer_1_error # 权重更新 self.weights_1_2 -= np.dot(layer_1_o.T, layer_2_delta) * self.learning_rate # (改)我们不再使用np.dot进行权重的更新 #self.weights_0_1 -= np.dot(self.layer_0.T, layer_1_delta) * self.learning_rate for index in review: self.weights_0_1[index] -= layer_1_delta[0] * self.learning_rate if(layer_2_o >= 0.5 and label=='positive'): correct_so_far += 1 elif(layer_2_o < 0.5 and label=='negative'): correct_so_far += 1 elapsed_time = float(time.time() - start) reviews_per_second = i / elapsed_time if elapsed_time > 0 else 0 sys.stdout.write("\rProgress:" + str(100 * i/float(len(training_reviews)))[:4] \ + "% Speed(reviews/sec):" + str(reviews_per_second)[0:5] \ + " #Correct:" + str(correct_so_far) + " #Trained:" + str(i+1) \ + " Training Accuracy:" + str(correct_so_far * 100 / float(i+1))[:4] + "%") if(i % 2500 == 0): print("") def test(self, testing_reviews, testing_labels): assert(len(testing_reviews) == len(testing_labels)) correct = 0 start = time.time() for i in range(len(testing_reviews)): review = testing_reviews.iloc[i,0] label = testing_labels.iloc[i,0] pred = self.run(review) if pred == label: correct += 1 elapsed_time = float(time.time() - start) reviews_per_second = i / elapsed_time if elapsed_time > 0 else 0 sys.stdout.write("\rProgress:" + str(100 * i/float(len(testing_reviews)))[:4] \ + "% Speed(reviews/sec):" + str(reviews_per_second)[0:5] \ + " #Correct:" + str(correct) + " #Tested:" + str(i+1) \ + " Testing Accuracy:" + str(correct * 100 / float(i+1))[:4] + "%") # (改)不再需要layer_0 def run(self, review): #self.update_input_layer(review) #layer_1_i = np.dot( self.layer_0, self.weights_0_1 ) indicates = set() for word in review.lower().split(' '): if word in self.word2index.keys(): indicates.add( self.word2index[word] ) self.layer_1 *= 0 for idx in indicates: self.layer_1 += self.weights_0_1[idx] layer_1_o = self.layer_1 layer_2_i = np.dot( layer_1_o, self.weights_1_2 ) layer_2_o = self.sigmoid( layer_2_i ) if layer_2_o >= 0.5: return 'positive' else: return 'negative'
训练
mlp = SentimentNetwork(reviews, labels, hidden_nodes=12, learning_rate=0.1)
mlp.train(reviews[:-1000], labels[:-1000])
Progress:0.0% Speed(reviews/sec):0 #Correct:1 #Trained:1 Training Accuracy:100.% Progress:10.4% Speed(reviews/sec):1403. #Correct:1959 #Trained:2501 Training Accuracy:78.3% Progress:20.8% Speed(reviews/sec):1274. #Correct:4006 #Trained:5001 Training Accuracy:80.1% Progress:31.2% Speed(reviews/sec):1243. #Correct:6133 #Trained:7501 Training Accuracy:81.7% Progress:41.6% Speed(reviews/sec):1251. #Correct:8290 #Trained:10001 Training Accuracy:82.8% Progress:52.0% Speed(reviews/sec):1230. #Correct:10449 #Trained:12501 Training Accuracy:83.5% Progress:62.5% Speed(reviews/sec):1238. #Correct:12593 #Trained:15001 Training Accuracy:83.9% Progress:72.9% Speed(reviews/sec):1242. #Correct:14711 #Trained:17501 Training Accuracy:84.0% Progress:83.3% Speed(reviews/sec):1240. #Correct:16882 #Trained:20001 Training Accuracy:84.4% Progress:93.7% Speed(reviews/sec):1242. #Correct:19070 #Trained:22501 Training Accuracy:84.7% Progress:99.9% Speed(reviews/sec):1244. #Correct:20387 #Trained:24000 Training Accuracy:84.9%
可以看到,经过加速之后,训练速度达到了1200以上的,大大的加快了训练速度。
测试
mlp.test(reviews[-1000:], labels[-1000:])
Progress:99.9% Speed(reviews/sec):2041. #Correct:858 #Tested:1000 Testing Accuracy:85.8%
相关文章推荐
- 神经网络之文本情感分析(一)
- TensorFlow-RNN循环神经网络 Example 2:文本情感分析
- 神经网络之文本情感分析(三)
- 神经网络之文本情感分析(二)
- [置顶] 【python keras实战】多层全连接神经网络训练情感分析
- 两个基于神经网络的情感分析模型
- tensorflow 实践(一)使用神经网络做中文情感分析
- 使用循环神经网络训练情感分析
- 情感分析︱网络公开的免费文本语料训练数据集汇总
- 神经网络之情感分析(一)
- matlab动态神经网络进行时间序列预测分析
- 人工智能系统通过网络提高其性能 “信息提取”系统转换纯文本为可以统计分析的数据
- 实时的神经网络:Faster-RCNN技术分析
- snownlp文本情感分析使用
- 文本情感分析的基础在于自然语言处理、情感词典、机器学习方法等内容。以下是我总结的一些资源。
- 文本情感分析+python+正面和负面新闻+新浪微博+情感字典+机器学习
- CNTK API文档翻译(18)——多对多神经网络处理文本数据(2)
- Coursera deeplearning.ai 深度学习笔记2-1-Practical aspects of deep learning-神经网络实际问题分析(初始化&正则化&训练效率)与代码实现
- 实例分析神经网络传播过程
- CNTK API文档翻译(17)——多对多神经网络处理文本数据(1)