1. 程式人生 > >tf1: nn實現評論分類

tf1: nn實現評論分類

TensorFlow是谷歌2015年開源的一個深度學習庫,到現在正好一年。和TensorFlow類似的庫還有Caffe、Theano、MXNet、Torch。但是論火爆程度,TensorFlow當之無愧,短短一年就在Github就收穫了4萬+顆星,把前面幾個庫獲得的star加起來也不敵TensorFlow。

TensorFlow使用C++開發,並提供了Python等語言的封裝。如命名一樣,TensorFlow為張量從圖一端流動到另一端的計算過程,可以把張量看作矩陣。TensorFlow並不是一個抽象程度特別高的庫,但是它實現了所有深度學習所需的函式。貌似有幾個高度抽象的庫使用TensorFlow做為後端。

TensorFlow可被用於語音識別或影象識別等多項機器深度學習領域,它可在小到手機、大到數千臺伺服器上執行。

本帖展示怎麼使用TensorFlow實現文字的簡單分類,判斷評論是正面的還是負面的。

使用的資料集

我本想使用Python爬一些淘寶評論,但是指令碼做到一半卡殼了,搞得火起。然後我上網找現成的資料,只找到了英文的電影評論資料(其實不管是英文還是中文,處理邏輯都一樣)。

TensorFlow練習1: 對評論進行分類

如果你有一些好資料願意分享,感激不盡。

由於處理的是字串,我們首先要想方法把字串轉換為向量/數字表示。一種解決方法是可以把單詞對映為數字ID。

第二個問題是每行評論字數不同,而神經網路需要一致的輸入(其實有些神經網路不需要,至少本帖需要),這可以使用詞彙表解決。

程式碼部分

1

$pipinstallnltk

下載nltk資料:

$ python
Python 3.5.2 (v3.5.2:4def2a2901a5, Jun 26 2016, 10:47:25) 
[GCC 4.2.1 (Apple Inc. build 5666) (dot 3)] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>> import nltk
>>> nltk.download()

ntlk有詳細安裝文件。

測試nltk安裝:

>>> from nltk.corpus import brown
>>> brown.words()
['The', 'Fulton', 'County', 'Grand', 'Jury', 'said', ...]

Python程式碼:

# python3
 
import numpy as np
import tensorflow as tf
import random
import pickle
from collections import Counter
 
import nltk
from nltk.tokenize import word_tokenize
"""
'I'm super man'
tokenize:
['I', ''m', 'super','man' ] 
"""
from nltk.stem import WordNetLemmatizer
"""
詞形還原(lemmatizer),即把一個任何形式的英語單詞還原到一般形式,與詞根還原不同(stemmer),後者是抽取一個單詞的詞根。
"""
 
pos_file = 'pos.txt'
neg_file = 'neg.txt'
 
# 建立詞彙表
def create_lexicon(pos_file, neg_file):
	lex = []
	# 讀取檔案
	def process_file(f):
		with open(pos_file, 'r') as f:
			lex = []
			lines = f.readlines()
			#print(lines)
			for line in lines:
				words = word_tokenize(line.lower())
				lex += words
			return lex
 
	lex += process_file(pos_file)
	lex += process_file(neg_file)
	#print(len(lex))
	lemmatizer = WordNetLemmatizer()
	lex = [lemmatizer.lemmatize(word) for word in lex] # 詞形還原 (cats->cat)
 
	word_count = Counter(lex)
	#print(word_count)
	# {'.': 13944, ',': 10536, 'the': 10120, 'a': 9444, 'and': 7108, 'of': 6624, 'it': 4748, 'to': 3940......}
	# 去掉一些常用詞,像the,a and等等,和一些不常用詞; 這些詞對判斷一個評論是正面還是負面沒有做任何貢獻
	lex = []
	for word in word_count:
		if word_count[word] < 2000 and word_count[word] > 20:  # 這寫死了,好像能用百分比
			lex.append(word)        # 齊普夫定律-使用Python驗證文字的Zipf分佈 http://blog.topspeedsnail.com/archives/9546
	return lex
 
lex = create_lexicon(pos_file, neg_file)
#lex裡儲存了文字中出現過的單詞。
 
# 把每條評論轉換為向量, 轉換原理:
# 假設lex為['woman', 'great', 'feel', 'actually', 'looking', 'latest', 'seen', 'is'] 當然實際上要大的多
# 評論'i think this movie is great' 轉換為 [0,1,0,0,0,0,0,1], 把評論中出現的字在lex中標記,出現過的標記為1,其餘標記為0
def normalize_dataset(lex):
	dataset = []
	# lex:詞彙表;review:評論;clf:評論對應的分類,[0,1]代表負面評論 [1,0]代表正面評論 
	def string_to_vector(lex, review, clf):
		words = word_tokenize(line.lower())
		lemmatizer = WordNetLemmatizer()
		words = [lemmatizer.lemmatize(word) for word in words]
 
		features = np.zeros(len(lex))
		for word in words:
			if word in lex:
				features[lex.index(word)] = 1  # 一個句子中某個詞可能出現兩次,可以用+=1,其實區別不大
		return [features, clf]
 
	with open(pos_file, 'r') as f:
		lines = f.readlines()
		for line in lines:
			one_sample = string_to_vector(lex, line, [1,0])  # [array([ 0.,  1.,  0., ...,  0.,  0.,  0.]), [1,0]]
			dataset.append(one_sample)
	with open(neg_file, 'r') as f:
		lines = f.readlines()
		for line in lines:
			one_sample = string_to_vector(lex, line, [0,1])  # [array([ 0.,  0.,  0., ...,  0.,  0.,  0.]), [0,1]]]
			dataset.append(one_sample)
	
	#print(len(dataset))
	return dataset
 
dataset = normalize_dataset(lex)
random.shuffle(dataset)
"""
#把整理好的資料儲存到檔案,方便使用。到此完成了資料的整理工作
with open('save.pickle', 'wb') as f:
	pickle.dump(dataset, f)
"""
 
# 取樣本中的10%做為測試資料
test_size = int(len(dataset) * 0.1)
 
dataset = np.array(dataset)
 
train_dataset = dataset[:-test_size]
test_dataset = dataset[-test_size:]
 
# Feed-Forward Neural Network
# 定義每個層有多少'神經元''
n_input_layer = len(lex)  # 輸入層
 
n_layer_1 = 1000    # hide layer
n_layer_2 = 1000    # hide layer(隱藏層)聽著很神祕,其實就是除輸入輸出層外的中間層
 
n_output_layer = 2       # 輸出層
 
# 定義待訓練的神經網路
def neural_network(data):
	# 定義第一層"神經元"的權重和biases
	layer_1_w_b = {'w_':tf.Variable(tf.random_normal([n_input_layer, n_layer_1])), 'b_':tf.Variable(tf.random_normal([n_layer_1]))}
	# 定義第二層"神經元"的權重和biases
	layer_2_w_b = {'w_':tf.Variable(tf.random_normal([n_layer_1, n_layer_2])), 'b_':tf.Variable(tf.random_normal([n_layer_2]))}
	# 定義輸出層"神經元"的權重和biases
	layer_output_w_b = {'w_':tf.Variable(tf.random_normal([n_layer_2, n_output_layer])), 'b_':tf.Variable(tf.random_normal([n_output_layer]))}
 
	# w·x+b
	layer_1 = tf.add(tf.matmul(data, layer_1_w_b['w_']), layer_1_w_b['b_'])
	layer_1 = tf.nn.relu(layer_1)  # 啟用函式
	layer_2 = tf.add(tf.matmul(layer_1, layer_2_w_b['w_']), layer_2_w_b['b_'])
	layer_2 = tf.nn.relu(layer_2 ) # 啟用函式
	layer_output = tf.add(tf.matmul(layer_2, layer_output_w_b['w_']), layer_output_w_b['b_'])
 
	return layer_output
 
# 每次使用50條資料進行訓練
batch_size = 50
 
X = tf.placeholder('float', [None, len(train_dataset[0][0])]) 
#[None, len(train_x)]代表資料資料的高和寬(矩陣),好處是如果資料不符合寬高,tensorflow會報錯,不指定也可以。
Y = tf.placeholder('float')
# 使用資料訓練神經網路
def train_neural_network(X, Y):
	predict = neural_network(X)
	cost_func = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(predict, Y))
	optimizer = tf.train.AdamOptimizer().minimize(cost_func)  # learning rate 預設 0.001 
 
	epochs = 13
	with tf.Session() as session:
		session.run(tf.initialize_all_variables())
		epoch_loss = 0
 
		i = 0
		random.shuffle(train_dataset)
		train_x = dataset[:, 0]
		train_y = dataset[:, 1]
		for epoch in range(epochs):
			while i < len(train_x):
				start = i
				end = i + batch_size
 
				batch_x = train_x[start:end]
				batch_y = train_y[start:end]
 
				_, c = session.run([optimizer, cost_func], feed_dict={X:list(batch_x),Y:list(batch_y)})
				epoch_loss += c
				i += batch_size
 
			print(epoch, ' : ', epoch_loss)
 
		text_x = test_dataset[: ,0]
		text_y = test_dataset[:, 1]
		correct = tf.equal(tf.argmax(predict,1), tf.argmax(Y,1))
		accuracy = tf.reduce_mean(tf.cast(correct,'float'))
		print('準確率: ', accuracy.eval({X:list(text_x) , Y:list(text_y)}))
 
train_neural_network(X,Y)

執行結果:

TensorFlow練習1: 對評論進行分類

準確率真tm喜人,才60%多,比瞎猜強點有限。

那麼問題出在哪呢?

準確率低主要是因為資料量太小,同樣的模型,如果使用超大資料訓練,準確率會有顯著的提升。

下文我會使用同樣的模型,但是資料量要比本文使用的多得多,看看準確率能提高多少。由於本文使用的神經網路模型(feed-forward)過於簡單,使用大資料也不一定有質的提升,尤其是涉及到自然語言處理。

Share the post "TensorFlow練習1: 對評論進行分類"

如果幫到你了,請讚賞支援: