【NLP实战】Task1 数据集探索
一、THUCNews數據集
傳送門
鏈接: https://pan.baidu.com/s/1lziUTaCF7VfnuAKXrGftTw 提取碼: saag
概述
本數據集是清華NLP組提供的THUCNews新聞文本分類數據集的一個子集(原始的數據集大約74萬篇文檔,訓練起來需要花較長的時間)。
本次訓練使用了其中的10個分類(體育, 財經, 房產, 家居, 教育, 科技, 時尚, 時政, 游戲, 娛樂),每個分類6500條,總共65000條新聞數據。
數據集劃分如下:
- cnews.train.txt: 訓練集(50000條)
- cnews.val.txt: 驗證集(5000條)
- cnews.test.txt: 測試集(10000條)
1、預處理
cnews_loader.py為數據的預處理文件。
- read_file(): 讀取文件數據;
- build_vocab(): 構建詞匯表,使用字符級的表示,這一函數會將詞匯表存儲下來,避免每一次重復處理;
- read_vocab(): 讀取上一步存儲的詞匯表,轉換為 {詞:id} 表示;
- read_category(): 將分類目錄固定,轉換為 {類別: id} 表示;
- to_words(): 將一條由 id 表示的數據重新轉換為文字;
- preocess_file(): 將數據集從文字轉換為固定長度的id序列表示;
- batch_iter(): 為神經網絡的訓練準備經過shuffle的批次的數據。
經過數據預處理,數據的格式如下:
| x_train | [50000, 600] | y_train | [50000, 10] |
| x_val | [5000, 600] | y_val | [5000, 10] |
| x_test | [10000, 600] | y_test | [10000, 10] |
2、CNN卷積神經網絡
CNN網絡配置參數和網絡結構,在 cnn_model.py 中。
CNN網絡結構示意圖如下所示:
3、訓練與驗證
# -*- coding; utf-8 -*- import os import sys import time from datetime import timedeltaimport numpy as np import tensorflow as tf from sklearn import metricsfrom cnn_model import TCNNConfig, TextCNN from preprocess import read_vocab, read_category, batch_iter, process_file, build_vocabbase_dir = '/home/jie/Jie/codes/tf/NLP/cnews' train_dir = os.path.join(base_dir, 'cnews.train.txt') test_dir = os.path.join(base_dir, 'cnews.test.txt') val_dir = os.path.join(base_dir, 'cnews.val.txt') vocab_dir = os.path.join(base_dir, 'cnews.vocab.txt')# 最佳驗證結果保存路徑 save_dir = 'checkpoints/textcnn' save_path = os.path.join(save_dir, 'best_validation')def get_time_dif(start_time):"""獲取已使用時間"""end_time = time.time()time_dif = end_time - start_timereturn timedelta(seconds=int(round(time_dif)))def feed_data(x_batch, y_batch, keep_prob):feed_dict = {model.input_x: x_batch,model.input_y: y_batch,model.keep_prob: keep_prob}return feed_dictdef evaluate(sess, x_, y_):"""評估在某一數據上的準確率和損失"""data_len = len(x_)batch_eval = batch_iter(x_, y_, 128)total_loss = 0.0total_acc = 0.0for x_batch, y_batch in batch_eval:batch_len = len(x_batch)feed_dict = feed_data(x_batch, y_batch, 1.0)# 此處計算的loss為平均值loss, acc = sess.run([model.loss, model.acc], feed_dict=feed_dict)total_loss += loss * batch_lentotal_acc += acc * batch_lenreturn total_loss / data_len, total_acc / data_lendef train():print("Configuring TensorBoard and Saver...")# 配置 Tensorboard,重新訓練時,請將tensorboard文件夾刪除,不然圖會覆蓋tensorboard_dir = 'tensorboard/textcnn'if not os.path.exists(tensorboard_dir):os.makedirs(tensorboard_dir)tf.summary.scalar("loss", model.loss)tf.summary.scalar("accuracy", model.acc)merged_summary = tf.summary.merge_all()writer = tf.summary.FileWriter(tensorboard_dir)# 配置 Saversaver = tf.train.Saver()if not os.path.exists(save_dir):os.makedirs(save_dir)print("Loading training and validation data...")start_time = time.time()x_train, y_train = process_file(train_dir, word_to_id, cat_to_id, config.seq_length)x_val, y_val = process_file(val_dir, word_to_id, cat_to_id, config.seq_length)time_dif = get_time_dif(start_time)print("Time usage: ", time_dif)# 創建sesssess = tf.Session()sess.run(tf.global_variables_initializer())writer.add_graph(sess.graph)print("Training and evalution...")start_time = time.time()total_batch = 0 # 總批次best_acc_val = 0.0 # 最佳驗證集準確率last_improved = 0 # 記錄上一次提升批次require_improvement = 1000 # 如果超過1000輪未提升,提前結束訓練flag = Falsefor epoch in range(config.num_epochs):print('Epoch: ', epoch + 1)batch_train = batch_iter(x_train, y_train, config.batch_size)for x_batch, y_batch in batch_train:feed_dict = feed_data(x_batch, y_batch, config.dropout_keep_prob)if(total_batch % config.save_per_batch == 0):# 每多少輪次將訓練結果寫入tensorboard scalars = sess.run(merged_summary, feed_dict=feed_dict)writer.add_summary(s, total_batch)if(total_batch % config.print_per_batch == 0):# 每多少輪次輸出在訓練集和驗證集上的性能feed_dict[model.keep_prob] = 1.0loss_train, acc_train = sess.run([model.loss, model.acc], feed_dict=feed_dict)loss_val, acc_val = evaluate(sess, x_val, y_val)if acc_val > best_acc_val:best_acc_val = acc_vallast_improved = total_batchsaver.save(sess=sess, save_path=save_path)improved_str = '*'else:improved_str = ''time_dif = get_time_dif(start_time)msg = 'Iter: {0:>6}, Train Loss: {1:>6.2}, Train Acc: {2:>7.2%},' \+ 'Val Loss: {3:>6.2}, Val Acc: {4:>7.2%}, Time: {5} {6}'print(msg.format(total_batch, loss_train, acc_train, loss_val, acc_train, time_dif, improved_str))sess.run(model.optim, feed_dict=feed_dict)total_batch += 1if total_batch - last_improved > require_improvement: # 驗證集正確率長期不提升,提前結束訓練print("No optimization for a long time, auto-stopping...")flag = Truebreakif flag:breakdef test():print("Loading test data...")start_time = time.time()x_test, y_test = process_file(test_dir, word_to_id, cat_to_id, config.seq_length)sess = tf.Session()sess.run(tf.global_variables_initializer())saver = tf.train.Saver()# 讀取保存的模型saver.restore(sess=sess, save_path=save_path)print("Testing")loss_test, acc_test = evaluate(sess, x_test, y_test)msg = 'Test Loss: {0:>6.2}, Test Acc: {1:>7.2%}'print(msg.format(loss_test, acc_test))batch_size = 128data_len = len(x_test)num_batch = int((data_len - 1) / batch_size) + 1y_test_cls = np.argmax(y_test, 1)y_pred_cls = np.zeros(shape=len(x_test), dtype=np.int32) # 保存預測結果for i in range(num_batch): # 逐批次處理start_id = i * batch_sizeend_id = min((i + 1) * batch_size, data_len)feed_dict = {model.input_x: x_test[start_id:end_id],model.keep_prob: 1.0}y_pred_cls[start_id:end_id] = session.run(model.y_pred_cls, feed_dict=feed_dict)# 評估print("Precision, Recall and F1-Score...")print(metrics.classification_report(y_test_cls, y_pred_cls, target_names=categories))# 混淆矩陣print("Confusion Matrix...")cm = metrics.confusion_matrix(y_test_cls, y_pred_cls)print(cm) time_dif = get_time_dif(start_time)print("Time usage:", time_dif)if __name__ == '__main__':# if len(sys.argv) != 2 or sys.argv[1] not in ['train', 'test']:# raise ValueError("""usage: python run_cnn.py [train / test]""") print('Configuring CNN model...')config = TCNNConfig()if not os.path.exists(vocab_dir): # 如果不存在詞匯表,重建build_vocab(train_dir, vocab_dir, config.vocab_size)categories, cat_to_id = read_category()words, word_to_id = read_vocab(vocab_dir)config.vocab_size = len(words)model = TextCNN(config)train()# if sys.argv[1] == 'train':# train()# else:# test()(1)訓練
訓練結果
Training and evalution... Epoch: 1 Iter: 0, Train Loss: 2.3, Train Acc: 9.38%,Val Loss: 2.3, Val Acc: 9.38%, Time: 0:00:01 * Iter: 100, Train Loss: 0.91, Train Acc: 76.56%,Val Loss: 1.3, Val Acc: 76.56%, Time: 0:00:02 * Iter: 200, Train Loss: 0.32, Train Acc: 89.06%,Val Loss: 0.71, Val Acc: 89.06%, Time: 0:00:04 * Iter: 300, Train Loss: 0.4, Train Acc: 82.81%,Val Loss: 0.58, Val Acc: 82.81%, Time: 0:00:05 * Iter: 400, Train Loss: 0.25, Train Acc: 89.06%,Val Loss: 0.4, Val Acc: 89.06%, Time: 0:00:06 * ... Iter: 2800, Train Loss: 0.011, Train Acc: 100.00%,Val Loss: 0.23, Val Acc: 100.00%, Time: 0:00:33 Iter: 2900, Train Loss: 0.058, Train Acc: 98.44%,Val Loss: 0.2, Val Acc: 98.44%, Time: 0:00:34 * Iter: 3000, Train Loss: 0.0062, Train Acc: 100.00%,Val Loss: 0.21, Val Acc: 100.00%, Time: 0:00:35 ... Iter: 3700, Train Loss: 0.00073, Train Acc: 100.00%,Val Loss: 0.27, Val Acc: 100.00%, Time: 0:00:43 Iter: 3800, Train Loss: 0.087, Train Acc: 95.31%,Val Loss: 0.3, Val Acc: 95.31%, Time: 0:00:44 Iter: 3900, Train Loss: 0.0085, Train Acc: 100.00%,Val Loss: 0.22, Val Acc: 100.00%, Time: 0:00:45 No optimization for a long time, auto-stopping...驗證集上的最佳效果為98.44%,且只迭代了 5 epochs就結束了
(2)loss、acc可視化
(3)測試
Testing Test Loss: 0.15, Test Acc: 95.78% Precision, Recall and F1-Score...precision recall f1-score support體育 0.99 0.99 0.99 1000財經 0.96 0.99 0.98 1000房產 1.00 1.00 1.00 1000家居 0.98 0.85 0.91 1000教育 0.86 0.95 0.91 1000科技 0.91 0.99 0.95 1000時尚 0.95 0.97 0.96 1000時政 0.96 0.94 0.95 1000游戲 1.00 0.94 0.97 1000娛樂 0.99 0.95 0.97 1000micro avg 0.96 0.96 0.96 10000macro avg 0.96 0.96 0.96 10000 weighted avg 0.96 0.96 0.96 10000Confusion Matrix... [[990 0 0 0 5 4 0 0 1 0][ 0 988 0 0 2 4 0 6 0 0][ 0 0 996 1 2 1 0 0 0 0][ 3 18 2 850 59 26 18 23 0 1][ 1 4 0 5 954 18 10 8 0 0][ 0 0 0 1 7 990 1 0 1 0][ 1 0 0 2 11 7 975 0 0 4][ 0 10 0 2 32 15 0 940 1 0][ 4 5 2 2 11 12 18 1 944 1][ 2 1 0 6 22 8 7 2 1 951]] Time usage: 0:00:05在測試集上的準確率達到了95.78%,且各類的 precision, recall 和 f1-score 基本都超過了0.9。
從混淆矩陣也可以看出分類效果非常優秀。
二、IMDB數據集
傳送門:http://ai.stanford.edu/~amaas/data/sentiment/
1、下載數據
import tensorflow as tf import numpy as np from tensorflow import keras# 獲取數據集 # 如果已下載該數據集,則會使用緩存副本 imdb = keras.datasets.imdb # num_words=10000 會保留訓練數據中出現頻次在前 10000 位的字詞。為確保數據規模處于可管理的水平,罕見字詞將被舍棄。 (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)2、探索數據
(1)初步探索
每個樣本都是一個整數數組,表示影評中的字詞。每個標簽都是整數值 0 或 1,其中 0 表示負面影評,1 表示正面影評。
# 查看樣本數 print("Training entries: {}, labels: {}".format(len(train_data), len(train_labels))) # 查看第一個樣本 # 影評文本已轉換為整數,其中每個整數都表示字典中的一個特定字詞。 print(train_data[0]) # 查看第一條和第二條影評中的字詞數。 # 影評的長度可能會有所不同,由于神經網絡的輸入必須具有相同長度,因此需要解決此問題。 print(len(train_data[0]), len(train_data[1]))輸出結果
在這里插入代碼片(2)將整數轉換回字詞
查詢包含整數到字符串映射的字典對象。
word_index = imdb.get_word_index()word_index = {k:(v+3) for k,v in word_index.items()} word_index["<PAD>"] = 0 word_index["<START>"] = 1 word_index["<UNK>"] = 2 # unknown word_index["<UNUSED>"] = 3reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])def decode_review(text):return ' '.join([reverse_word_index.get(i, '?') for i in text])print(decode_review(train_data[0]))3、準備數據
train_data = keras.preprocessing.sequence.pad_sequences(train_data, value=word_index["<PAD>"], padding='post', maxlen=256) test_data = keras.preprocessing.sequence.pad_sequences(test_data, value=word_index["<PAD>"],padding='post', maxlen=256)# input shape is the vocabulary count used for the movie reviews (10,000 words) vocab_size = 10000# keras.Sequential:新建一個序列模型,根據官方文檔定義,The Sequential model is a linear stack of layers. model = keras.Sequential() # keras.layers.Embedding是將維度為vocab_size的向量轉為維度為16的向量。使用詞向量代替onehot編碼的向量可以降低維度,同時詞向量也可以表示詞之間的相關性。 # 找到一篇教程,對詞向量的本質說的比較清楚 model.add(keras.layers.Embedding(vocab_size, 16)) # keras.layers.GlobalAveragePooling model.add(keras.layers.GlobalAveragePooling1D()) # relu函數 model.add(keras.layers.Dense(16, activation=tf.nn.relu)) # sigmoid model.add(keras.layers.Dense(1, activation=tf.nn.sigmoid))# model.summary()# 訓練數據配置,包括優化器、損失函數、優化的參數 model.compile(optimizer=tf.train.AdamOptimizer(),loss='binary_crossentropy',metrics=['accuracy'])# 配置訓練集中數據和標簽 x_val = train_data[:10000] partial_x_train = train_data[10000:]y_val = train_labels[:10000] partial_y_train = train_labels[10000:]# 訓練數據 history = model.fit(partial_x_train, partial_y_train,epochs=40, batch_size=512,validation_data=(x_val, y_val), verbose=1)# 評估模型結果 results = model.evaluate(test_data, test_labels)# print(results) history_dict = history.history #print(history_dict.keys())# 畫出結果圖 import matplotlib.pyplot as pltacc = history.history['acc'] val_acc = history.history['val_acc'] loss = history.history['loss'] val_loss = history.history['val_loss']epochs = range(1, len(acc) + 1)# "bo" is for "blue dot" plt.plot(epochs, loss, 'bo', label='Training loss') # b is for "solid blue line" plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.xlabel('Epochs') plt.ylabel('Loss') plt.legend()plt.show()plt.clf() acc_values = history_dict['acc'] val_acc_values = history_dict['val_acc']plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.xlabel('Epochs') plt.ylabel('Accuracy') plt.legend()plt.show()三、評價指標
1、基本概念
對于一個二分類問題,預測與真實結果會出現四種情況。
| 正類 | TP(True Positive) | FN(False Negative) |
| 負類 | FP(False Positive) | TN(True Negative) |
我的記憶方法:首先看第一個字母是T則代表預測正確,反之F預測錯誤;然后看P表示預測的結果是正,N表示預測的結果為負。
2、準確率(accuracy)
accuracy表示所有預測正確的占總的比重。
accuracy=TP+TNTP+TN+FP+FNaccuracy = \dfrac{TP + TN }{TP + TN+FP+FN} accuracy=TP+TN+FP+FNTP+TN?
3、精確率(precision)
precision(查準率):正確預測為正的占全部預測為正的比例,也就是真正正確的占所有預測為正的比例。
precision=TPTP+FPprecision = \dfrac{TP}{TP+FP} precision=TP+FPTP?
4、召回率(recall)
recall(查全率):正確預測為正占全部真實為正的比例,也就是真正正確的占所有實際為正的比例。
例如:召回率在醫療方面非常重要。
recall=TPTP+FNrecall = \dfrac{TP}{TP+FN} recall=TP+FNTP?
5、F1值
F1值:精確率和召回率的調和均值,越大越好。
2F1=1precision+1recall\dfrac{2}{F_1} = \dfrac{1}{precision} + \dfrac{1}{recall} F1?2?=precision1?+recall1?
==》 F1=2PRP+R=2TP2TP+FP+FNF_1 = \dfrac{2PR}{P + R} = \dfrac{2TP}{2TP+FP+FN}F1?=P+R2PR?=2TP+FP+FN2TP?
6、roc曲線 vs PR曲線
ROC曲線和PR(Precision - Recall)曲線皆為類別不平衡問題中常用的評估方法。
(1)roc曲線
roc曲線:接收者操作特征曲線(receiver operating characteristic curve),是反映敏感性和特異性連續變量的綜合指標,ROC曲線上每個點反映著對同一信號刺激的感受性。
主要表現為一種真正例率 (TPR) 和假正例率 (FPR) 的權衡。具體方法是在不同的分類閾值 (threshold) 設定下分別以TPR和FPR為縱、橫軸作圖。
下圖是ROC曲線例子。
橫坐標:1-Specificity,偽正類率(False positive rate,FPR,FPR=FP/(FP+TN)),預測為正但實際為負的樣本占所有負例樣本的比例;
縱坐標:Sensitivity,真正類率(True positive rate,TPR,TPR=TP/(TP+FN)),預測為正且實際為正的樣本占所有正例樣本的比例。
真正的理想情況,TPR應接近1,FPR接近0,即圖中的(0,1)點。ROC曲線越靠攏(0,1)點,越偏離45度對角線越好。
AUC值。AUC (Area Under Curve) 被定義為ROC曲線下的面積。取值范圍 [0.5, 1],AUC值越大的分類器,正確率越高。
(2)PR曲線
PR曲線展示的是Precision vs Recall的曲線,PR曲線與ROC曲線的相同點是都采用了TPR (Recall),都可以用AUC來衡量分類器的效果。不同點是ROC曲線使用了FPR,而PR曲線使用了Precision,因此PR曲線的兩個指標都聚焦于正例。類別不平衡問題中由于主要關心正例,所以在此情況下PR曲線被廣泛認為優于ROC曲線。
與50位技術專家面對面20年技術見證,附贈技術全景圖總結
以上是生活随笔為你收集整理的【NLP实战】Task1 数据集探索的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Python】list 之 exten
- 下一篇: 【NLP】Task3:特征选择