當前位置:
首頁 > 最新 > 手把手教你用 TensorFlow 實現文本分類

手把手教你用 TensorFlow 實現文本分類

雷鋒網按:本文作者張慶恆,原文載於作者個人博客,雷鋒網(公眾號:雷鋒網)已獲授權。

由於需要學習語音識別,期間接觸了深度學習的演算法。利用空閑時間,想用神經網路做一個文本分類的應用, 目的是從頭到尾完成一次機器學習的應用,學習模型的優化方法,同時學會使用主流的深度學習框架(這裡選擇tensorflow)。

文章分為兩部分,本文僅實現流程,用簡單的softmax回歸對文本進行分類,後面一篇文章再從流程的各個方面對模型進行優化,達到比較好的效果。收集數據

該部分不是這裡的重點,數據從各大新聞網站爬取新聞文本,分十類保存到本地,包括科技、生活、體育、娛樂等。文本分別保存到training_set和testing_set目錄下,如:

$ tree -L 1 training_set/

training_set/

├── 10_hel

├── 1_ent

├── 2_fin

├── 3_spo

├── 4_tec

├── 5_mil

├── 6_soc

├── 7_lif

├── 8_cul

└── 9_car

文本以text_id.txt的格式保存在不同類的目錄下(如text_1234.txt)。本例保存了共113673個訓練文本和等數量的測試文本(暫時按1:1的比例)。

預處理文本step0

為方便後面處理,預處理文本首先要分別針對訓練文本和測試文本生成唯一的文本ID, 這裡用.txt來標示唯一文本,class_id為類的id,這裡為1-10;text_type為數據類型包括train和test;text_id為類文件夾下的文本id,實現函數:

def get_unique_id(self, data_dir):

"""

get flie unique id famate as _type_.txt.

data_dir is the full path of file

e.g ./training_set/4_tec/4_tec_text/text_2001.txt

where "training" is type, "4" is file class, and "2001" is text id.

modify this function to adapt your data dir fomate

dir_list = data_dir.split("/")

class_id = dir_list[2].split("_")[0]

text_id = dir_list[4].split(".")[0]

type_id = dir_list[1].split("_")[0]

return class_id + "_" + type_id + "_" + text_id

step1: 分詞

通俗來講,文本分類的主要思想,是構建各類文本的漢語詞典,通過對文本進行分析,觀察文本中哪類辭彙比較多,由此判斷文本所屬類別。因此,文本分類需要對文本進行分詞操作,可以選擇的分詞工具很多,這裡選擇Python編寫的jieba開源庫對文本進行分詞,並以行為單位,將文本保存到輸出文件,該部分實現比較簡單:

def splitwords(self, data_dir, data_type):

os.remove(data_type+".txt")

list_dirs = os.walk(data_dir)

for root, _, files in list_dirs:

print root

# get all files under data_dir

for fp in files:

file_id = self.get_unique_id(file_path)

#split words for f, save in file ./data_type.txt

with nested(open(file_path), open(data_type+".txt", "a+")) as (f1, f2):

data = f1.read()

#print data

seg_list = jieba.cut(data, cut_all=False)

f2.write(file_id + " " + " ".join(seg_list).replace("", " ")+"")

print "split word for %s file end." % data_type

return

函數傳入參數為數據集目錄路徑,以及數據集類型(train or test)。結果文件保存形如train.txt,後續的操作在該輸出文件基礎之上。輸出文件格式為:

step2: 去除停用詞

這部分主要刪去文本中的停用詞,停用詞包括一些對於文本分類無用,而且出經常出現的辭彙或符號,如「因此」、「關於」、「嘿嘿」、標點符號等。去除停用詞需根據停用詞典,去除上面經過分詞操作的文本中的停用詞。停用詞典可以根據自己需要生成或在網路上獲得,這裡後面源碼鏈接中會給出使用的停用詞詞典。

def rm_stopwords(self, file_path, word_dict):

#read stop word dict and save in stop_dict

stop_dict = {}

with open(word_dict) as d:

for word in d:

stop_dict[word.strip("")] = 1

# remove tmp file if exists

os.remove(file_path+".tmp")

print "now remove stop words in %s." % file_path

# read source file and rm stop word for each line.

with nested(open(file_path), open(file_path+".tmp", "a+")) as (f1, f2):

for line in f1:

tmp_list = [] # save words not in stop dict

words = line.split()

for word in words[1:]:

if word not in stop_dict:

tmp_list.append(word)

words_without_stop = " ".join(tmp_list)

f2.write(words[0] + " " + words_without_stop + "")

# overwrite origin file with file been removed stop words

shutil.move(file_path+".tmp", file_path)

print "stop words in %s has been removed." % file_path

代碼中經過簡單的按行讀文本,然後搜索停用詞典,如果文本中的辭彙在詞典中,則跳過,否則保存。這裡每行對應數據集中的一個文本。

step3: 生成詞典

上面提到文本分類需要得到能表徵各類文本的漢語詞典,這部分的主要思路是實現tf_idf演算法自動提取關鍵詞,根據詞頻(TF)和逆文檔頻率(IDF)來衡量辭彙在文章中的重要程度。這裡詞頻的計算採用公式:

由於是衡量某類文本的關鍵詞,公式中的「文章」為某類所有文本的總和。逆文檔頻率計算採用公式:

上面的文檔總數為train數據集所有文本的數目。tf-idf為兩個指標的乘積,計算各類文本中所有辭彙的tf-idf,由小到大排序,默認取前500個辭彙作為該類的關鍵詞保存到詞典。最終生成大小為5000的詞典。簡潔考慮,該部分的關鍵代碼(gen_dict方法中):

for k, text_info in class_dict.items():

#print "class %s has %d words" % (k, text_info.file_num)

# get tf in words of class k

for w in text_info.wordmap:

text_info.tf_idf(w, word_in_files[w], text_num)

main_words = []

with open(save_path, "a+") as f:

main_words = text_info.get_mainwords()

print "class %s : main words num: %d" % (k, len(main_words))

f.write("".join(main_words) + "")

class_dict是類id到該類文本信息(text_info)的字典,text_info.wordmap保存了該類文本的所有不重複的辭彙,text_info.tf_idf方法計算該類文本某詞的tf-idf,輸入參數為辭彙,辭彙在整個語料庫出現的文本數和語料庫的文本數。text_info.get_mainwords方法得到該類本前500個關鍵詞。完整的定義與實現參考源碼。

step4: 生成詞袋

該部分實現向量化文本,利用生成的詞典,以行為單位將去停用詞後的文本轉換為向量,這裡向量為5000維。如果文本出現詞典中的某辭彙,則文本向量對應詞典中該辭彙的位置的計數累加。最終生成文件,行數為文本數,列為5000。此外生成對應的label文件,行數為文本數,對應於文本向量文件行,列為1,對應某文本的類別(1-10)。該部分代碼比較簡單,實現在gen_wordbag方法中。

到此完成了文本的預處理,接下來針對不同分類演算法,將有不同的處理,這裡參考tensotflow處理MNIST數據集,讀取預處理後的文本到系統,進行線性回歸。

讀取訓練數據

該部分主要包括兩部分,一是從磁碟讀取向量化後的文本保存到numpy數組,將數據和類別分別存儲,數據保存為二維(text_line_num, 5000)的數組,text_line_num為數據集的文本數,5000為詞典的維度,也是後面模型輸入參數的個數。類別保存為標籤向量(label_line_num, 1),label_line_num,同樣為數據集的大小。

為方便處理,將類別10的標籤保存為0,並對label進行「one_hot」處理,這部分解釋可參考上個tensotflow鏈接。該部分在datasets類中實現。需要注意的是這裡train部分數據最為cv(cross validation)數據,這裡暫時不會用到。此外,由於數據較多,為節省內存,提高整體運算速度,分別讀取train數據集和test數據集。dataset類中保存不同類型的數據集,並實現next_batch方法,獲取指定數目的數據。

訓練數據

該部分利用softmax回歸對數據進行訓練,對於tensorflow的使用這裡不作介紹。完整代碼如下:

#!/usr/bin/python

#-*-coding:utf-8-*-

import tensorflow as tf

from datasets import datasets

data_sets = datasets()

data_sets.read_train_data(".", True)

sess = tf.InteractiveSession()

x = tf.placeholder(tf.float32, [None, 5000])

W = tf.Variable(tf.zeros([5000, 10]))

b = tf.Variable(tf.zeros([10]))

y_ = tf.placeholder(tf.float32, [None, 10])

cross_entropy = -tf.reduce_sum(y_ * tf.log(y + 1e-10))

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

#training

tf.global_variables_initializer().run()

saver = tf.train.Saver()

for i in range(1000):

train_step.run()

print W.eval()

print b.eval()

path = saver.save(sess, "./model2/model.md")

代碼中:

● x : 對於輸入數據,None佔位符標示輸入樣本的數量,5000為單個樣本的輸入維度,對應字典維度。

● W :權重矩陣,行為輸入維度,列為輸出維度,這裡為類別的數目10。

● b : 偏重為10對應輸出的維度

● y : 定義訓練輸出結果,使用softmax作為激勵函數,tf.matmul(x, W) + b為輸入參數,tf.matmul為矩陣乘。

● y_ : 真實樣本的類別,從數據集讀入,None佔位符標示輸入樣本的數量,10為輸出的維度。

● cross_entropy: 交叉熵,衡量真實值與預測值的偏差程度,訓練過程中目的是最小化該值。

訓練對cross_entropy進行梯度下降演算法更新參數,學習率為0.01。迭代1000次,每次使用100個訓練集。最後保存訓練的模型到指定目錄。

測試模型

這部分主要讀取上面保存的模型參數,對測試數據集進行預測,並列印準確率。

!/usr/bin/python

data_sets.read_test_data(".", True)

saver.restore(sess, "./model2/model.md")

# test

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_, 1))

acc = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))

print(acc.eval())

小結

直接通過上面過程訓練模型,得到的準確率大概為65%,雖然比10%高出許多,仍然屬於比較低的準確率。在後面一篇文章重點對上面的過程進行改進,提高預測的準確性。

此外,值得一提的是,一開始,直接參考tensorflow官網給的例子進行訓練會出現準確率為0的現象,觀察TensorBord,發現權重和偏重一直不更新,列印W和b發現值為Nan,最後找到問題所在:

使用交叉熵作為cost function,由於文本矩陣為嚴重稀疏矩陣,導致出現y_ tf.log(y)結果為0log0的現象。導致訓練參數為Nan,給預測值加一個極小的值,防止與測試為0。

雷鋒網

「12小時零基礎入門深度學習班」開課啦!

想要挑戰AlphaGo卻不懂深度學習?

雷鋒網AI慕課學院專門打造了《12小時零基礎入門深度學習》,fastai中文社區最活躍的四位貢獻者親授,矽谷教學模式帶你實操9個深度學習項目!即使零編程基礎,也能在這裡找到適合你的學習路徑!

課程鏈接:http://www.leiphone.com/special/mooc/01.html

雷鋒網版權文章,未經授權禁止轉載。詳情見轉載須知。

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 推酷 的精彩文章:

專訪小米林斌:第100家小米之家開業,今年總銷售額突破1000億不困難
UI設計師需要具備什麼素質
Material Design 控制項之 Toolbar 非完全解析
努比亞真·旗艦Z17,配備三星快閃記憶體反超S8
震驚!iOS 系統居然自帶懸浮窗口調試工具

TAG:推酷 |

您可能感興趣

用TensorFlow Estimator實現文本分類
如何使用Tokenvator和Windows Tokens實現提權
用TensorFlow實現物體檢測的像素級分類
用 TensorFlow 實現物體檢測的像素級分類
谷歌正式開源 Hinton 膠囊理論代碼,即刻用 TensorFlow 實現吧
基於Tensorflow實現DeepFM
用Pytorch 實現的 Capsule Network
使用Tensorflow Object Detection API實現對象檢測
基於TensorFlow的變分自編碼器實現
Android如何實現帶有粘性頭部的ScrollView
如何使用Cron Jobs實現Linux提權
用Python 實現的機器人演算法示例集合——PythonRobotics
Ether Universe項目評測:第四代跨鏈技術實現「異鏈」Tokens直接交換
Machine Learning(一):基於 TensorFlow 實現寵物血統智能識別
分散式框架spring-session實現session一致性使用問題
用TensorFlow 實現的模型集合
Pytorch實現Logistic回歸二分類
SAP Cloud for Customer Extensibility的設計與實現
德國女性已經實現了自我?Deutsche Frauen verwirklichen sich selbst……
在Spark 上實現 TensorFlow 的庫——Sparkflow