1. 程式人生 > 其它 >優化器統計跟蹤(SYS.EXP_HEAD$ SYS.EXP_OBJ$ SYS.EXP_STAT$不)導致表空間 SYSAUX不斷增長

優化器統計跟蹤(SYS.EXP_HEAD$ SYS.EXP_OBJ$ SYS.EXP_STAT$不)導致表空間 SYSAUX不斷增長

情感分析

如果MNIST是計算機視覺的“hello world”,那麼IMDB評論資料集就是自然語言處理的“hello world”:它提取了來自著名的網際網路電影資料庫的50000條英文電影評論(其中25000條用於訓練,25000條用於測試),每條評論的簡單二元目標值表明了該評論是負面(0)還是正面(1)。就像MNIST一樣,IMDB評論資料集也很受歡迎,這有充分的理由:它足夠簡單,可以在合理的時間內利用膝上型電腦來處理,但又具有挑戰性。Keras提供了一個簡單的函式來載入它:

from tensorflow import keras

(X_train, y_train), (X_test, y_test) = keras.datasets.imdb.load_data()
X_train[0][:10]
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
17465344/17464789 [==============================] - 1s 0us/step
17473536/17464789 [==============================] - 1s 0us/step





[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65]

資料集已經進行了預處理:X_train由一個評論列表組成,每條評論都由一個NumPy整數陣列表示,其中每個整數代表一個單詞。刪除了所有標點符號,然後將單詞轉換為小寫字母,用空格分隔,最後按頻率索引(因此,小的整數對應於常用單詞),整數0、1和2是特殊的:它們分別表示填充令牌、序列開始(SSS)令牌和位置單詞。如果想視覺化評論可以按以下方式對其進行解碼:

word_index = keras.datasets.imdb.get_word_index()
id_to_word = {id_ + 3: word for word, id_ in word_index.items()}
for id_, token in enumerate(("<pad>", "<sos>", "<unk>")):  # 將整數0、1和2視覺化為pad、sos和unk
    id_to_word[id_] = token
' '.join([id_to_word[id_] for id_ in X_train[0][:10]])
'<sos> this film was just brilliant casting location scenery story'

在實際的專案中,不得不自己處理文字。但是可以使用與之前使用的相同的Tokenizer類來執行此操作,但是這次要設定char_level=False(這是預設值)。在對單詞進行編碼時,它濾掉很多字元,包括大多數標點符號、換行符和製表符(但是可以通過filter引數來更改)。最重要的是,它使用空格來表示單詞邊界。對於英文和許多其他在單詞之間使用空格的指令碼(書面語言)這是可以的,但並非所有指令碼都用此方式。中文在單詞之間不使用空格,越南語甚至在單詞中也使用空格,例如德語之類的語言經常將多個單詞附加在一起,而沒有空格。即使在英文中,空格也不總是分詞的最佳方法:例如“San Francisco”

還有更好的選擇,Taku Kudo在20118年發表的論文引入了一種無監督學習技術,用一種獨立於語言的方式在子單詞級別對文字進行分詞和組詞,像對待其他字元一樣對待空格。使用這種方法,即使模型遇到一個從未見過的單詞,也仍然可以合理地猜出其含義。例如,它可能在訓練期間從未見過“smartest”一詞,但可能學會了“smart”一詞,並且還學習到字尾“est”的意思是“the most”,因此它可以推斷出“smartest”的意思。Google的SentencePiece專案提供了一個開源實現,Takku Kudo和John Rihardson在論文中對此進行了描述

Rico Sennrich等人在較早的論文中提出了另一種選擇,探索了建立子單詞編碼的其他方式(例如使用位元組對編碼)。TensorFlow團隊於2019年6月釋出了TF.Text庫,該庫實現了各種分詞策略,包括WordPiece(位元組對編碼的一種變體)

如果想將模型部署到移動裝置或Web瀏覽器上,而又不想每次都編寫不同的預處理函式,那麼可以使用TensorFlow操作來做預處理,因此其包含在模型本身中。首先使用TensorFlow資料集以文字(位元組字串)的形式載入原始的IMDB評論:

import tensorflow as tf
import tensorflow_datasets as tfds

datasets, info = tfds.load('imdb_reviews', as_supervised=True, with_info=True)
train_size = info.splits['train'].num_examples


# 編寫預處理函式
def preprocess(X_batch, y_batch):
    X_batch = tf.strings.substr(X_batch, 0, 300)
    X_batch = tf.strings.regex_replace(X_batch, b'<br\\s*/?>', b' ')
    X_batch = tf.strings.regex_replace(X_batch, b"[^a-zA-z']", b' ')
    X_batch = tf.strings.split(X_batch)
    return X_batch.to_tensor(default_value=b'<pad>'), y_batch
Downloading and preparing dataset Unknown size (download: Unknown size, generated: Unknown size, total: Unknown size) to C:\Users\reion\tensorflow_datasets\imdb_reviews\plain_text\1.0.0...



Dl Completed...: 0 url [00:00, ? url/s]



Dl Size...: 0 MiB [00:00, ? MiB/s]



Generating splits...:   0%|          | 0/3 [00:00<?, ? splits/s]



Generating train examples...: 0 examples [00:00, ? examples/s]



Shuffling imdb_reviews-train.tfrecord...:   0%|          | 0/25000 [00:00<?, ? examples/s]



Generating test examples...: 0 examples [00:00, ? examples/s]



Shuffling imdb_reviews-test.tfrecord...:   0%|          | 0/25000 [00:00<?, ? examples/s]



Generating unsupervised examples...: 0 examples [00:00, ? examples/s]



Shuffling imdb_reviews-unsupervised.tfrecord...:   0%|          | 0/50000 [00:00<?, ? examples/s]


Dataset imdb_reviews downloaded and prepared to C:\Users\reion\tensorflow_datasets\imdb_reviews\plain_text\1.0.0. Subsequent calls will reuse this data.

它從階段評論開始,每條評論僅保留前300個字元:這會加快訓練速度,並且不會對效能產生太大的影響,因此通常可以在第一句話或第二句話中判斷出評論是正面還是負面的。它使用正則表示式用空格來替換<br >標記,還用空格替換字母和引號以外的所有字元。例如,文字"Well, I can't<br >"將變成"Well I can't"。最後preprocess()將評論按空格分割,並返回一個不規則的張量,並將該不規則的張量轉換為密集張良,還使用填充標記""來填充所有評論,以使它們都具有相同的長度

接下來,需要構建詞彙表。這需要依次遍歷整個資料集,應用preprocess()函式,並使用Counter來對每個單詞出現的次數進行計數:

from collections import Counter

vocabulary = Counter()
for X_batch, y_batch in datasets['train'].batch(32).map(preprocess):
    for review in X_batch:
        vocabulary.update(list(review.numpy()))
# 最常見的三個單詞
vocabulary.most_common()[:3]
[(b'<pad>', 224533), (b'the', 61156), (b'a', 38567)]

但是,為了良好的效能,可能不需要模型知道字典中的所有單詞,因此截斷詞彙表,只保留10000個最常見的單詞:

vocab_size = 10000
truncated_vocabulary = [word for word, count in vocabulary.most_common()[:vocab_size]]

現在需要新增一個預處理步驟,以便把每個單詞替換為其ID(即其在詞彙表中的索引),使用out-of-vocabulary(oov)儲存桶來建立一個查詢表

words = tf.constant(truncated_vocabulary)
word_ids = tf.range(len(truncated_vocabulary), dtype=tf.int64)
vocab_init = tf.lookup.KeyValueTensorInitializer(words, word_ids)
num_oov_buckets = 1000
table = tf.lookup.StaticVocabularyTable(vocab_init, num_oov_buckets)
# 然後可以使用此表來查詢幾個單詞的ID:
table.lookup(tf.constant([b'This movie was faaaaaantastic'.split()]))
<tf.Tensor: shape=(1, 4), dtype=int64, numpy=array([[   24,    12,    13, 10053]], dtype=int64)>

在表中可以找到單詞’this‘、’movie‘和’was‘,因此它們的ID低於10000,而單詞“faaaaaantastic”沒找到,因此被對映的ID大於或等於10000的一個ovv桶中

TF Transform提供了一些有用的函式來處理此類詞彙表。例如,檢視tft.compute_and_apply_vocabulary()函式:它會遍歷資料集來查早所有不同的的單詞並構建詞彙表,並將生成對使用此詞彙表的單詞進行編碼所需的TF操作

現在,準備建立最終的訓練集,對評論進行批處理,然後使用preprocess()函式將它們轉換為單詞的短序列,然後使用簡單的encode_words()函式來對這些單詞進行編碼,該函式會使用剛才構建的單詞表,最後預取一下批次:

def encode_words(X_batch, y_batch):
    return table.lookup(X_batch), y_batch


train_set = datasets['train'].batch(32).map(preprocess)
train_set = train_set.map(encode_words).prefetch(1)
# 最後建立模型並對其進行訓練
embed_size = 128
model = keras.models.Sequential([
    keras.layers.Embedding(vocab_size + num_oov_buckets, embed_size, input_shape=[None]),
    keras.layers.GRU(128, return_sequences=True),
    keras.layers.GRU(128),
    keras.layers.Dense(1, activation='sigmoid')
])
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history = model.fit(train_set, epochs=5)
Epoch 1/5
782/782 [==============================] - 9s 10ms/step - loss: 0.6192 - accuracy: 0.6206
Epoch 2/5
782/782 [==============================] - 8s 10ms/step - loss: 0.3875 - accuracy: 0.8297
Epoch 3/5
782/782 [==============================] - 8s 10ms/step - loss: 0.2304 - accuracy: 0.9146
Epoch 4/5
782/782 [==============================] - 8s 10ms/step - loss: 0.1442 - accuracy: 0.9513
Epoch 5/5
782/782 [==============================] - 8s 10ms/step - loss: 0.1087 - accuracy: 0.9624

第一層是嵌入層,它將單詞ID轉換為嵌入。嵌入矩陣需要每個ID(vocab_size+num_oov_buckets)一行,每個嵌入維度一列(這裡使用128維,這是可以調整的超引數)。模型的輸入使形狀為[批處理大小,時間步長]的2D張量,而嵌入層的輸出為[批處理大小,時間步長,嵌入大小]的3D張量

該模型其餘部分先當簡單直接:它由兩個GRU層組成,第二個GRU層僅返回最後一個時間步長的輸出。輸出層只是使用sigmoid啟用函式來輸出估計概率的單個神經元。該概率反映了評論表達了與電影有關的正面情緒。然後可以簡單地編譯模型,並將其擬合到之前準備的資料集中,進行幾個輪次的訓練