以前の実装:弾性検索を適用しましたが、ユーザーが「必要」のようなテキストを入力するため、精度は非常に低くなります==「したい」
データセット情報:データセットには、各行がテキスト(または段落)およびラベル(ページ番号として)として含まれています。ここではデータセットのサイズは小さく、500行しかありません。
NLPを適用
結果:テストデータ(または検証データ)の精度は23%ですが、列車データの精度は91%です。
import time
from time import strftime
import numpy as np
from keras.callbacks import CSVLogger, ModelCheckpoint
from keras.layers import Dense, Input, LSTM, ActivityRegularization
from keras.layers import Embedding, Dropout,Bidirectional
from keras.models import Model
from keras.preprocessing.sequence import pad_sequences
from keras.preprocessing.text import Tokenizer
from keras.regularizers import l2
from keras.utils import to_categorical
import pickle
from DataGenerator import *
BASE_DIR = ''
GLOVE_DIR = 'D:/Dataset/glove.6B' # BASE_DIR + '/glove.6B/'
MAX_SEQUENCE_LENGTH = 50
MAX_NB_WORDS = 20000
EMBEDDING_DIM = 300
VALIDATION_SPLIT = 0.2
# first, build index mapping words in the embeddings set
# to their embedding vector
np.random.seed(1337) # for reproducibility
print('Indexing Word vectors.')
t_start = time.time()
embeddings_index = {}
if os.path.exists('pickle/glove.pickle'):
print('Pickle found..')
with open('pickle/glove.pickle', 'rb') as handle:
embeddings_index = pickle.load(handle)
else:
print('Pickle not found...')
f = open(os.path.join(GLOVE_DIR, 'glove.6B.300d.txt'), encoding='utf8')
for line in f:
values = line.split()
Word = values[0]
coefs = np.asarray(values[1:], dtype='float32')
embeddings_index[Word] = coefs
f.close()
with open('pickle/glove.pickle', 'wb') as handle:
pickle.dump(embeddings_index, handle, protocol=pickle.HIGHEST_PROTOCOL)
print('Found %s Word vectors.' % len(embeddings_index))
# second, prepare text samples and their labels
print('Processing text dataset')
texts = [] # list of text samples
labels = [] # list of label ids
labels_index = {} # dictionary mapping label name to numeric id
(texts, labels, labels_index) = get_data('D:/PolicyDocument/')
print('Found %s texts.' % len(texts))
# finally, vectorize the text samples into a 2D integer tensor
tokenizer = Tokenizer(nb_words=MAX_NB_WORDS)
tokenizer.fit_on_texts(texts)
sequences = tokenizer.texts_to_sequences(texts)
Word_index = tokenizer.Word_index
print('Found %s unique tokens.' % len(Word_index))
data = pad_sequences(sequences, maxlen=MAX_SEQUENCE_LENGTH)
labels = to_categorical(np.asarray(labels))
print('Shape of data tensor:', data.shape)
print('Shape of label tensor:', labels.shape)
# split the data into a training set and a validation set
indices = np.arange(data.shape[0])
np.random.shuffle(indices)
data = data[indices]
labels = labels[indices]
num_validation_samples = int(VALIDATION_SPLIT * data.shape[0])
x_train = data[:-num_validation_samples]
y_train = labels[:-num_validation_samples]
x_val = data[-num_validation_samples:]
y_val = labels[-num_validation_samples:]
# prepare embedding matrix
num_words = min(MAX_NB_WORDS, len(Word_index))
embedding_matrix = np.zeros((num_words + 1, EMBEDDING_DIM))
print('Preparing embedding matrix. :', embedding_matrix.shape)
for Word, i in Word_index.items():
embedding_vector = embeddings_index.get(Word)
if embedding_vector is not None:
# words not found in embedding index will be all-zeros.
embedding_matrix[i] = embedding_vector
# load pre-trained Word embeddings into an Embedding layer
# note that we set trainable = False so as to keep the embeddings fixed
embedding_layer = Embedding(embedding_matrix.shape[0],
embedding_matrix.shape[1],
weights=[embedding_matrix],
input_length=MAX_SEQUENCE_LENGTH,
mask_zero=True,
trainable=False)
print('Training model.')
csv_file = "logs/training_log_" + strftime("%Y-%m-%d %H-%M", time.localtime()) + ".csv"
model_file = "models/Model_" + strftime("%Y-%m-%d %H-%M", time.localtime()) + ".mdl"
print("Model file:" + model_file)
csv_logger = CSVLogger(csv_file)
# train a 1D convnet with global maxpooling
sequence_input = Input(shape=(MAX_SEQUENCE_LENGTH,), dtype='int32')
embedded_sequences = embedding_layer(sequence_input)
rate_drop_lstm = 0.15 + np.random.Rand() * 0.25
num_lstm = np.random.randint(175, 275)
rate_drop_dense = 0.15 + np.random.Rand() * 0.25
x = LSTM(num_lstm, return_sequences=True, W_regularizer=l2(0.001))(embedded_sequences)
x = Dropout(0.5)(x)
x = LSTM(64)(x)
x = Dropout(0.25)(x)
x = ActivityRegularization(l1=0.01, l2=0.001)(x)
preds = Dense(len(labels_index), activation='softmax')(x)
model = Model(sequence_input, preds)
model.compile(loss='categorical_crossentropy',
optimizer='adam',
metrics=['acc'])
model_checkpoint = ModelCheckpoint(model_file, monitor='val_loss', verbose=0, save_best_only=True,
save_weights_only=False, mode='auto')
model.fit(x_train, y_train,
batch_size=1,
nb_Epoch=600,
validation_data=(x_val, y_val), callbacks=[csv_logger, model_checkpoint])
score = model.evaluate(x_val, y_val, verbose=0)
print('Test score:', score[0])
print('Test accuracy:', score[1])
t_end = time.time()
total = t_end - t_start
ret_str = "Time needed(s): " + str(total)
print(ret_str)
ドロップアウトとBNは、フィードフォワードNNで非常に効果的です。ただし、RNNで問題が発生する可能性があります(このトピックについては多くの論文が公開されています)
RNNモデルをより一般化する最良の方法は、データセットのサイズを増やすことです。あなたのケース(約200セルのLSTM)では、トレーニングするために、ラベル付けされたサンプルを100,000以上注文したいと思うでしょう。
一部のレイヤーの埋め込みサイズやユニット数などのパラメーターを単純に減らすだけでなく、LSTMの再発ドロップアウトを調整することもできます。
LSTMは非常に簡単に適合しすぎるようです(そのため、私は読みました)。
次に、各dropout
レイヤーのパラメーターとしてのLSTM
とrecurrent_dropout
の使用を Kerasのドキュメント で確認できます。
任意の数値の例:
x = LSTM(num_lstm, return_sequences=True, W_regularizer=l2(0.001), recurrent_dropout=0.4)(embedded_sequences)
x = Dropout(0.5)(x)
x = LSTM(64,dropout=0,5, recurrent_dropout=0,3)(x)
その他の原因が間違っているか、データが不十分である可能性があります:
テストと検証データを一緒に入れ替えて、新しいトレインと検証セットを作成してみましたか?
トレーニングデータには何文ありますか?あなたは小さなセットで試していますか?セット全体を使用するか、dadaの拡張を試してください(新しい文とその分類を作成しますが、これはテキストでは非常に扱いにくい場合があります)。
あなたが説明することは、過剰適合のように聞こえます。データに関する詳細情報がない場合は、より強力な正則化手法を試すことをお勧めします。 @Danielは、使用していないドロップアウトパラメータdropout
およびrecurrent_dropout
を使用することをすでに提案しています。また、ドロップアウトレイヤーの比率を増やして、W_regularizer
パラメーターでより強い正則化を使用することもできます。
ダニエルの提案を試したかどうか、結果はどのようなものかなど、他のオプションを開くこともできます。
(正則化の平均としての)敵対的なトレーニング方法は、検討する価値があるかもしれません。 半教師付きテキスト分類の敵対的トレーニング方法