標籤:

安裝 TensorFlow 之 textsum 文章自動摘要

前言

這裡不討論演算法的問題,這裡討論如何在Linux上安裝並運行 這個開源項目,面向入門機器學習的讀者,所以我會傾向於寫得詳細(啰嗦)。


介紹和資料

儘管這裡只是說「安裝和運行 textsum」,但是我們還是得簡單知道一些演算法知識,當然,時間不過可以跳過,直接ctrl + F 「安裝」就能看到正文。

在GitHub的TensorFlow開源項目中,基於 LSTM(Long Short-Term Memory)模型的textsum,將輸入的文章導入 RNN(Recurrent Neural Networks) 並輸出得到的文章摘要。

GitHub上TensorFLow開源的 文章自動摘要模型「textsum」,點擊↓訪問GitHub

tensorflow/models?

github.com圖標

seq2seq mdoel

圖註:模型讀取了輸入句子 「ABC」,然後輸出「WXYZ」。模型會在輸出<結束標籤>(<EOS>) 後停止預測內容。 注意!LSTM 是反向讀取序列的,因為這樣子做能建立起許多數據間短期的依賴關係,並讓優化更加容易。

Figure 1: Our model reads an input sentence 「ABC」 and produces 「WXYZ」 as the output sentence. The model stops making predictions after outputting the end-of-sentence token.

Note that the LSTM reads the input sentence in reverse, because doing so introduces many short term dependencies in the data that make the

optimization problem much easier.

簡單的說,textsum 使用的 seq2seq model 就是:

用一個LSTM 去讀取輸入序列,每次用一個 timestep 去得到對輸入序列的一個大的固定矢量描述,然後使用另一個LSTM 從這個矢量里提取出想要的輸出序列。(見上圖)

The idea is to use one LSTM to read the input sequence, one timestep at a time, to obtain large fixeddimensional vector representation, and then to use another LSTM to extract the output sequence from that vector (fig. 1).

By the way,

介紹演算法的paper 在這裡↓,自己去看

Sequence to Sequence Learning with Neural Networks.pdf

為何LSTM 要反向讀取輸入序列?Stack Overflow有較好的回答了↓

NStepLSTM and Seq2Seq model 然後 ctrl+F[reserved]


1.安裝和運行 textsum

這裡使用的是 TensorFlow + Bazel(需要前置 jdk 1.8)

環境 (報錯很多時候與環境有關)

  • Debian 8.9 Linux-3.16.0-4-amd64-x86_64-with-debian-8.9
  • bazel 0.11.1 (構建文件系統)
  • java 1.8.0_121
  • Python 2.7.9 [GCC 4.9.2] on linux2
  • Python 3.4.2 [GCC 4.9.1] on linux
  • TensorFlow 1.6.0 (Python2)
  • TensorFlow 1.6.0 (Python3)

安裝Bazel,JDK 8,TensorFlow

『JDK 8 的安裝』

Installing Bazel on Ubuntu

記得檢查是否已經安裝了 JDK 8,像我喜歡用 PyCharm寫Python,早就裝好了。

安裝 jdk1.8 的一種方法deb [arch=amd64] http://storage.googleapis.com/bazel-apt stable jdk1.8" | sudo tee /etc/apt/sources.list.d/bazel.listcurl https://bazel.build/bazel-release.pub.gpg | sudo apt-key add -

『bazel 的安裝』

sudo apt-get update && sudo apt-get install bazelsudo apt-get upgrade bazel

bazelbuild/bazel←bazel下載地址,打開之後找匹配的版本

等等,好像發現了什麼?長野原美緒?四齋蒸噁心 ( °△°||)︴

『TensorFlow 的安裝』

TensorFlow 推薦直接用Python 的pip 安裝。pip版本推薦大於 9.0.1

pip install tensorflow

注意,我運行的時候,沒有指定運行運行時候的Python 版本,使得我的系統默認調用 Python2來運行這個程序。所以如果你安裝了 TensorFlow 而報錯的時候顯示沒有找到,那麼你可能要看看另外一個版本的Python 是否也安裝了TensorFLow。

『textsum 代碼文件夾的下載』

下載GitHub上 TensorFlow 開源項目的 textsum 模型,就是直接把整個文件夾複製下來

tensorflow/models?

github.com圖標

由於GitHub沒有提供下載某個文件夾的按鈕,似乎想要獲得textsum 就需要下載整個TensorFlow,顯然,這是愚蠢的行為,我們不應該去做。

比較Geek的處理方法是:登錄某些網站(DownGit),粘貼連接,直接下載。

https://minhaskamal.github.io/DownGit/?

minhaskamal.github.io

DownGitDownGit?

minhaskamal.github.io

『檢查』

安裝完 jdk 8,bazel,TensorFLow後,記得看看是否裝上了,我喜歡順便看看版本

java -version java version "1.8.0_121" Java(TM) SE Runtime Environment (build 1.8.0_121-b13) Java HotSpot(TM) 64-Bit Server VM (build 25.121-b13, mixed mode)bazel version Build label: 0.11.1 Build target: bazel-out/k8-opt/bin/src/main/java/com/google/devtools/build/lib/bazel/BazelServer_deploy.jar Build time: Tue May 14 07:48:23 +50148 (1520362424903) Build timestamp: 1520362424903 Build timestamp as int: 1520362424903>>> import tensorflow as tf>>> tf.__version__1.6.0

2.準備工作目錄

參考textsum 目錄(就是上面通過GitDown下載的textsum.zip)中的 README.md 文件,安裝這裡面提供的步驟,構建工作目錄。

當然這一份 README.md ←你已經見過了,就在 GitHub textsum 的那個頁面下方。

首先找一個合適的地方,建立一個不被打擾的工作目錄,比如我

cd Videos # 剛好在資源管理器有按鈕可以直接去mkdir Yonv_CWD # Current Working Directory,Yonv這個名字是我隨便起的cd Yonv_CWD#!注意,這裡新建一個空的文件(注意不是文件夾而是空文件)# WORKSPACE 是 bazel生成工作環境所必須的一個標記touch WORKSPACW# 這裡是放訓練集的,裡面待會需要放入 二進位文件training-* 和 文本文件vocabmkdir data# 然後,退回到原來的 Yonv_CWD,開始用 bazel 建立工作環境cd ..bazel build -c opt --config=cuda textsum/...# 注意,如果你的電腦沒有 CUDA (Compute Unified Device Architecture)# 也就是沒有NVIDIA 的GPU的話,這一項就沒必要加了# 注意,textsum/... 後面的三個「...」 $ bazel build -c opt textsum/..................INFO: Analysed 7 targets (12 packages loaded).INFO: Found 7 targets...INFO: Elapsed time: 2.153s, Critical Path: 0.02sINFO: Build completed successfully, 1 total action# 強行加上也沒關係,反正它只是WARRNING# 再者說,學C++ 的人,難道會在乎終端返回的 WARRNING?$ bazel build -c opt --config=cuda textsum/..................WARNING: Config values are not defined in any .rc file: cudaINFO: Analysed 7 targets (12 packages loaded).INFO: Found 7 targets...INFO: Elapsed time: 3.325s, Critical Path: 0.04sINFO: Build completed successfully, 4 total actions

藍色選中的三個文件是 bazel 運行前必備的,其他的lnk 是運行後才生產的,log 是我自己建立的

3.運行textsum

3.1 準備數據集

在GitHub下載的 textsum中,有用於測試的數據集,作者把這個數據集稱為 toy,這個玩具一樣的測試數據集很小,只有33KB,姑且將就一下。

把 YonvCWD/textsum/data 裡面的 data 和 vocab 文件複製(反正不大)到 Yonv_CWD/data 裡面,然後把 data文件重命名為 training-0(非必要)

cd Yonv_CWDcp testsum/data/vocab data/vocabcp testsum/data/data data/training-0

3.1 生成自己的數據

這個一部分還在施工中,等我中文的數據清洗完,我會再完善這裡的。

值得一提的是:為了加速計算,數據集除了 vocab,像 training-* validation-* test-* 都是二進位的,可以用 textsum/data/convertexample.py 去轉化,轉化的代碼記錄在 這個py文件的開頭備註裡面了,摘抄出來是↓

python data_convert_example.py --command binary_to_text --in_file data/data --out_file data/text_datapython data_convert_example.py --command text_to_binary --in_file data/text_data --out_file data/binary_data

左上:Yonv_CWD/data文件夾中的數據集

左下:Yonv_CWD/textsum/data文件夾中,嘗試用convertexample.py 程序進行二進位 和 文本之間的轉化: data(二進位) → testdata(文本)→ binary_data(二進位)

右二:打開後的vocab文件,可以看到是單詞的頻數表,其中<UNK></d>等是標籤

右一:轉化後的test_data文件,可以看到有 "abstract=" , "article=" 的標記

雖然這裡使用了textsum 提供的測試數據(toy ^_^),少了數據獲取和清洗步驟,但是我們總算是可以繼續進行下去了。

3.2 訓練、評估、輸出

依照README.md 提供的語句,我們有三段腳本需要運行,依次是訓練、評估、輸出

# Run the training.$ bazel-bin/textsum/seq2seq_attention --mode=train --article_key=article # 對應training-0(更名前是data文件)中的 標籤"article" --abstract_key=abstract # 對應training-0(更名前是data文件)中的 標籤"abstract" --data_path=data/training-* # 這個文件是之前準備的 --vocab_path=data/vocab --log_root=textsum/log_root # 中間文件會保留在這裡+ --train_dir=textsum/log_root/train# Run the eval. Try to avoid running on the same machine as training.$ bazel-bin/textsum/seq2seq_attention --mode=eval --article_key=article --abstract_key=abstract --data_path=data/validation-* # 如果你只是想測試依然程序是否正常,直接複製 training-0吧 --vocab_path=data/vocab --log_root=textsum/log_root --eval_dir=textsum/log_root/eval# Run the decode. Run it when the model is mostly converged.$ bazel-bin/textsum/seq2seq_attention --mode=decode --article_key=article --abstract_key=abstract --data_path=data/test-* # 如果你只是想測試依然程序是否正常,直接複製 training-0然後改名吧 --vocab_path=data/vocab --log_root=textsum/log_root --decode_dir=textsum/log_root/decode --beam_size=8

如果運行成功,那麼它們的結果依次是:

training部分

$ bazel-bin/textsum/seq2seq_attention --mode=train --article_key=article --abstract_key=abstract --data_path=data/training-* --vocab_path=data/vocab --log_root=textsum/log_root --train_dir=textsum/log_root/trainWARNING:tensorflow:From /usr/local/lib/python2.7/dist-packages/tensorflow/python/ops/nn_impl.py:1346: softmax_cross_entropy_with_logits (from tensorflow.python.ops.nn_ops) is deprecated and will be removed in a future version.Instructions for updating:Future major versions of TensorFlow will allow gradients to flowinto the labels input on backprop by default.See tf.nn.softmax_cross_entropy_with_logits_v2.WARNING:tensorflow:From /home/user/Videos/CWD/bazel-bin/textsum/seq2seq_attention.runfiles/__main__/textsum/seq2seq_attention.py:96: __init__ (from tensorflow.python.training.supervisor) is deprecated and will be removed in a future version.Instructions for updating:Please switch to tf.train.MonitoredTrainingSession2018-03-19 13:55:43.347757: I tensorflow/core/platform/cpu_feature_guard.cc:140] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMArunning_avg_loss: 9.001080running_avg_loss: 8.945733...吃個飯回來...running_avg_loss: 0.000241running_avg_loss: 0.000298

eval 部分(validation)

$ bazel-bin/textsum/seq2seq_attention --mode=eval --article_key=article --abstract_key=abstract --data_path=data/validation-* --vocab_path=data/vocab --log_root=textsum/log_root --eval_dir=textsum/log_root/evalrunning_avg_loss: 0.000611running_avg_loss: 0.000951running_avg_loss: 0.000459running_avg_loss: 0.000200...

prediction 部分(test)輸出部分

輸出結果會在Yonv_CWD/textsum/log_root/decode 文件夾中看到user@debian:~/Videos/Yonv_CWD/textsum/log_root/decode$ zsh? decode lsdecode1521440441 decode1521445096 ref1521440441 ref1521445096? decode ls -al總用量 1360drwxr-xr-x 2 user user 4096 3月 19 22:31 .drwxr-xr-x 5 user user 4096 3月 19 17:50 ..-rw-r--r-- 1 user user 0 3月 19 14:20 decode1521440441-rw-r--r-- 1 user user 647350 3月 19 17:50 decode1521445096-rw-r--r-- 1 user user 0 3月 19 14:20 ref1521440441-rw-r--r-- 1 user user 729342 3月 19 17:50 ref1521445096

可以看到,如果運行失敗,那麼即便會產出文件,它也是空的

成功產出的文件打開後是這樣的

由於數據集小,所以產出的結果也只能是這樣了

output=czechs outdrink germans in beer-guzzling stakes .output=mexican financial markets end turbulent week .output=abb to sell electrical explosion-proof equipment business .output=mexican financial markets end turbulent week .output=moslem rights group wants narcotic khat legalised .output=abb to sell electrical explosion-proof equipment business .output=mexican financial markets end turbulent week .output=croatians vote in three constituencies .

如果你沒有成功輸出,那麼可以看看我下面的『錯誤處理』

3.3錯誤處理

運行中如果出現類似錯誤,那麼是因為你vocab格式不對,裡面本來會有<標籤>的,你需要17832:

Bad line: ...assert vocab.CheckVocab(data.SENTENCE_START) > 0

運行中如果出現類似錯誤,那麼是因為你數據集 training-0 格式不對,你需要17832:

Exception in thread Thread-24809:...DecodeError: Error parsing message...MemoryError

運行中如果出現類似錯誤,不要理會它,沒事的,相反的,如果你改了state_is_tuple=False,那麼當TensorFlow 版本大於1.0 的時候你反而會出錯:

...state_is_tuple=False...

運行中如果報錯,類似於(出現某個很大的多維數組):

ValueError: Could not flatten dictionary. Key had 2 elements, but value had 1 elements. Key: [<tf.Tensor seq2seq/encoder3/bidirectional_rnn/fw/fw/cond_119/Merge_1:0 shape=(8, 256) dtype=float32>, <tf.Tensor seq2seq/encoder3/bidirectional_rnn/fw/fw/cond_119/Merge_2:0 shape=(8, 256) dtype=float32>], value: [array([[[ 2.723167 , -1.924321 , -0.09930453, ..., -0.57662404, -1.633333 , 5.6171 ], [ 2.723167 , -1.924321 , -0.09930453, ..., -0.57662404, -1.633333 , 5.6171 ], [ 2.723167 , -1.924321 , -0.09930453, ..., -0.57662404, -1.633333 , 5.6171 ], ..., ..., [ 2.723167 , -1.924321 , -0.09930453, ..., -0.57662404, -1.633333 , 5.6171 ], [ 2.723167 , -1.924321 , -0.09930453, ..., -0.57662404, -1.633333 , 5.6171 ], [ 2.723167 , -1.924321 , -0.09930453, ..., -0.57662404, -1.633333 , 5.6171 ]]], dtype=float32)].

那麼是因為TensorFlow 1.0>= 的兼容問題

只要把 seq2seq_attention_model.py 文件中的 [state_is_tuple=True] 改回 [state_is_tuple=False]] (然而好多人需要把這個改回來,是因為想解決之前的另一個報錯,才修改了這個文件(又改回來了))

yONV_CWD/textsum/seq2seq_attention_model.py# replace [state_is_tuple=False] as [state_is_tuple=True]

他們↓ 也遇到這個問題了,並且ctrl+f[fix] 在某一行可以找到解決方法,就是把 文件中的[state_is_tuple=True] 改回 [state_is_tuple=False]

#TextSum# - Error running decode: Could not flatten dictionary. Key had 2 elements, but value had 1 elements · Issue #417 · tensorflow/models

推薦閱讀:

驗證碼識別(1) -- 1 個字元,1 個 softmax 層,正確率 92%
乾貨 | TensorFlow的55個經典案例
怎樣使用tensorflow導入已經下載好的mnist數據集?
Quo Vadis, Action Recognition? A New Model and the Kinetics
一個利用Tensorflow求解幾何問題的例子

TAG:TensorFlow |