Deep learning with Python 學習筆記(5)

本節講深度學習用於文本和序列html

用於處理序列的兩種基本的深度學習算法分別是循環神經網絡(recurrent neural network)和一維卷積神經網絡(1D convnet)
與其餘全部神經網絡同樣,深度學習模型不會接收原始文本做爲輸入,它只能處理數值張量。文本向量化(vectorize)是指將文本轉換爲數值張量的過程。它有多種實現方法算法

  • 將文本分割爲單詞,並將每一個單詞轉換爲一個向量
  • 將文本分割爲字符,並將每一個字符轉換爲一個向量
  • 提取單詞或字符的 n-gram,並將每一個 n-gram 轉換爲一個向量。n-gram 是多個連續單詞或字符的集合(n-gram 之間可重疊)

將文本分解而成的單元(單詞、字符或 n-gram)叫做標記(token),將文本分解成標記的過程叫做分詞(tokenization)。全部文本向量化過程都是應用某種分詞方案,而後將數值向量與生成的標記相關聯。這些向量組合成序列張量,被輸入到深度神經網絡中數據庫

n-gram 是從一個句子中提取的 N 個(或更少)連續單詞的集合。這一律念中的「單詞」也能夠替換爲「字符」
The cat sat on the mat 分解爲二元語法(2-gram)的集合
{"The", "The cat", "cat", "cat sat", "sat", "sat on", "on", "on the", "the", "the mat", "mat"}
分解爲三元語法(3-gram)的集合
{"The", "The cat", "cat", "cat sat", "The cat sat",
"sat", "sat on", "on", "cat sat on", "on the", "the",
"sat on the", "the mat", "mat", "on the mat"}
這樣的集合分別叫做二元語法袋(bag-of-2-grams)三元語法袋(bag-of-3-grams)。這裏(bag)這一術語指的是,咱們處理的是標記組成的集合。這一系列分詞方法叫做詞袋(bag-of-words)。詞袋是一種不保存順序的分詞方法,所以它每每被用於淺層的語言處理模型,而不是深度學習模型網絡

將向量與標記相關聯的方法
對標記作 one-hot 編碼(one-hot encoding)標記嵌入[token embedding,一般只用於單詞,叫做詞嵌入(word embedding)]app

one-hot 編碼是將標記轉換爲向量的最經常使用、最基本的方法dom

它將每一個單詞與一個惟一的整數索引相關聯,而後將這個整數索引 i 轉換爲長度爲 N 的二進制向量(N 是詞表大小),這個向量只有第 i 個元素是 1,其他元素都爲 0 (也能夠進行字符級的 one-hot 編碼)機器學習

Keras one-hot編碼Demo函數

from keras.preprocessing.text import Tokenizer


samples = ['The cat sat on the mat.', 'The dog ate my homework.']
# 只考慮前1000個最多見的單詞
tokenizer = Tokenizer(num_words=1000)
# 構建單詞索引
tokenizer.fit_on_texts(samples)
# 找回單詞索引
word_index = tokenizer.word_index
print(word_index)
# 將字符串轉換爲整數索引組成的列表
sequences = tokenizer.texts_to_sequences(samples)
print("轉換成的索引序列 ", sequences)
text = tokenizer.sequences_to_texts(sequences)
print("轉會的文本 ", text)
# 獲得 one-hot 二進制表示
one_hot_results = tokenizer.texts_to_matrix(samples, mode='binary')
one_num = 0
for items in one_hot_results:
    for item in items:
        if item == 1:
            one_num += 1
print("1的數量爲 ", one_num)
print(one_hot_results)

結果
學習

one-hot 編碼的一種變體是所謂的 one-hot 散列技巧(one-hot hashing trick),若是詞表中惟
一標記的數量太大而沒法直接處理,就可使用這種技巧測試

將單詞散列編碼爲固定長度的向量,一般用一個很是簡單的散列函數來實現

這種方法的主要優勢在於,它避免了維護一個顯式的單詞索引,從而節省內存並容許數據的在線編碼,缺點就是可能會出現散列衝突

詞嵌入
one-hot 編碼獲得的向量是二進制的、稀疏的、維度很高的(維度大小等於詞表中的單詞個數),而詞嵌入是低維的浮點數向量。與 one-hot 編碼獲得的詞向量不一樣,詞嵌入是從數據中學習獲得的。常見的詞向量維度是 25六、512 或 1024(處理很是大的詞表時)。與此相對,onehot 編碼的詞向量維度一般爲 20 000 或更高。所以,詞向量能夠將更多的信息塞入更低的維度中

獲取詞嵌入有兩種方法

  • 在完成主任務(好比文檔分類或情感預測)的同時學習詞嵌入。在這種狀況下,一開始是隨機的詞向量,而後對這些詞向量進行學習,其學習方式與學習神經網絡的權重相同
  • 在不一樣於待解決問題的機器學習任務上預計算好詞嵌入,而後將其加載到模型中。這些詞嵌入叫做預訓練詞嵌入(pretrained word embedding)

利用 Embedding 層學習詞嵌入
詞嵌入的做用應該是將人類的語言映射到幾何空間中,咱們但願任意兩個詞向量之間的幾何距離)應該和這兩個詞的語義距離有關。可能還但願嵌入空間中的特定方向也是有意義的
Embedding 層的輸入是一個二維整數張量,其形狀爲 (samples, sequence_length),它可以嵌入長度可變的序列,不過一批數據中的全部序列必須具備相同的長度

簡單Demo

from keras.datasets import imdb
from keras import preprocessing
from keras.models import Sequential
from keras.layers import Flatten, Dense, Embedding
import matplotlib.pyplot as plt


max_features = 10000
maxlen = 20
(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features, path='E:\\study\\dataset\\imdb.npz')
x_train = preprocessing.sequence.pad_sequences(x_train, maxlen=maxlen)
x_test = preprocessing.sequence.pad_sequences(x_test, maxlen=maxlen)
model = Sequential()
model.add(Embedding(10000, 8, input_length=maxlen))
model.add(Flatten())
model.add(Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
model.summary()
history = model.fit(x_train, y_train, epochs=10, batch_size=32, validation_split=0.2)


acc = 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)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()

結果

當可用的訓練數據不多,以致於只用手頭數據沒法學習適合特定任務的詞嵌入,你能夠從預計算的嵌入空間中加載嵌入向量,而不是在解決問題的同時學習詞嵌入。有許多預計算的詞嵌入數據庫,你均可如下載並在 Keras 的 Embedding 層中使用,word2vec 就是其中之一。另外一個經常使用的是 GloVe(global vectors for word representation,詞表示全局向量)

沒有足夠的數據來本身學習真正強大的特徵,但你須要的特徵應該是很是通用的,好比常見的視覺特徵或語義特徵

新聞情感分類Demo,使用GloVe預訓練詞

import os
from keras.preprocessing.text import Tokenizer
from keras.preprocessing.sequence import pad_sequences
import numpy as np
from keras.models import Sequential
from keras.layers import Embedding, Flatten, Dense
import matplotlib.pyplot as plt


imdb_dir = 'E:\\study\\dataset\\aclImdb'
train_dir = os.path.join(imdb_dir, 'train')
labels = []
texts = []
for label_type in ['neg', 'pos']:
    dir_name = os.path.join(train_dir, label_type)
    for fname in os.listdir(dir_name):
        if fname[-4:] == '.txt':
            f = open(os.path.join(dir_name, fname))
            texts.append(f.read())
            f.close()
            if label_type == 'neg':
                labels.append(0)
            else:
                labels.append(1)
# 對 IMDB 原始數據的文本進行分詞
maxlen = 100
training_samples = 200
validation_samples = 10000
max_words = 10000
tokenizer = Tokenizer(num_words=max_words)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
word_index = tokenizer.word_index

data = pad_sequences(sequences, maxlen=maxlen)
labels = np.asarray(labels)
print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', labels.shape)
# 打亂數據
indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]

x_train = data[:training_samples]
y_train = labels[:training_samples]
x_val = data[training_samples: training_samples + validation_samples]
y_val = labels[training_samples: training_samples + validation_samples]

#  解析 GloVe 詞嵌入文件
glove_dir = 'E:\\study\\models\\glove.6B'

embeddings_index = {}
f = open(os.path.join(glove_dir, 'glove.6B.100d.txt'))
for line in f:
    values = line.split()
    word = values[0]
    coefs = np.asarray(values[1:], dtype='float32')
    embeddings_index[word] = coefs
f.close()
print('Found %s word vectors.' % len(embeddings_index))

# 準備 GloVe 詞嵌入矩陣(max_words, embedding_dim)
embedding_dim = 100
embedding_matrix = np.zeros((max_words, embedding_dim))
for word, i in word_index.items():
    if i < max_words:
        embedding_vector = embeddings_index.get(word)
        if embedding_vector is not None:
            embedding_matrix[i] = embedding_vector

#  模型定義
model = Sequential()
model.add(Embedding(max_words, embedding_dim, input_length=maxlen))
model.add(Flatten())
model.add(Dense(32, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
model.summary()
# 將預訓練的詞嵌入加載到 Embedding 層中,並凍結
model.layers[0].set_weights([embedding_matrix])
model.layers[0].trainable = False
# 訓練與評估
model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
history = model.fit(x_train, y_train, epochs=10, batch_size=32, validation_data=(x_val, y_val))
model.save_weights('pre_trained_glove_model.h5')

acc = 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)
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.legend()
plt.figure()
plt.plot(epochs, loss, 'bo', label='Training loss')
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.legend()
plt.show()

# 對測試集數據進行分詞
test_dir = os.path.join(imdb_dir, 'test')
labels = []
texts = []
for label_type in ['neg', 'pos']:
    dir_name = os.path.join(test_dir, label_type)
    for fname in sorted(os.listdir(dir_name)):
        if fname[-4:] == '.txt':
            f = open(os.path.join(dir_name, fname))
            texts.append(f.read())
            f.close()
            if label_type == 'neg':
                labels.append(0)
            else:
                labels.append(1)
sequences = tokenizer.texts_to_sequences(texts)
x_test = pad_sequences(sequences, maxlen=maxlen)
y_test = np.asarray(labels)
# 在測試集上評估模型
model.load_weights('pre_trained_glove_model.h5')
model.evaluate(x_test, y_test)

數據下的時間太長放棄了,233

Deep learning with Python 學習筆記(6)
Deep learning with Python 學習筆記(4)

相關文章
相關標籤/搜索