Kerasでセンチメント分析
Kerasでセンチメント分析を行ってみます。
下記のサンプルを参考にしています。
ライブラリのインポート
import os
os.environ["KERAS_BACKEND"] = "tensorflow"
import keras
import tensorflow as tf
import numpy as np
from keras import layers
映画レビューのテキストデータセットのダウンロード
!curl -O https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
!tar -xf aclImdb_v1.tar.gz
センチメント分析を行うデータセットをダウンロードします。
今回はIMDb映画レビューデータセットです。
IMDb映画レビューデータセットにはtrainとtestディレクトリが含まれており、さらにサブディレクトリとしてポジティブ(posディレクトリ)、ネガティブ(neg)があり、レビューのテキストファイルがあります。
!ls aclImdb/test
labeledBow.feat neg pos urls_neg.txt urls_pos.txt
!ls aclImdb/train
labeledBow.feat neg pos unsup unsupBow.feat urls_neg.txt urls_pos.txt urls_unsup.txt
学習データの分割
batch_size = 32
raw_train_ds = keras.utils.text_dataset_from_directory(
"aclImdb/train",
batch_size=batch_size,
validation_split=0.2,
subset="training",
seed=1337,
)
raw_val_ds = keras.utils.text_dataset_from_directory(
"aclImdb/train",
batch_size=batch_size,
validation_split=0.2,
subset="validation",
seed=1337,
)
raw_test_ds = keras.utils.text_dataset_from_directory(
"aclImdb/test", batch_size=batch_size
)
print(f"Number of batches in raw_train_ds: {raw_train_ds.cardinality()}")
print(f"Number of batches in raw_val_ds: {raw_val_ds.cardinality()}")
print(f"Number of batches in raw_test_ds: {raw_test_ds.cardinality()}")
映画レビューのテキストデータセット(IMDbデータセット)を訓練、検証、テスト用に分割しています。
text_dataset_from_directory関数を使用して、指定されたディレクトリからテキストデータを読み込みます。
テキストデータの前処理
import string
import re
def custom_standardization(input_data):
lowercase = tf.strings.lower(input_data)
stripped_html = tf.strings.regex_replace(lowercase, "<br />", " ")
return tf.strings.regex_replace(
stripped_html, f"[{re.escape(string.punctuation)}]", ""
)
max_features = 20000
embedding_dim = 128
sequence_length = 500
vectorize_layer = keras.layers.TextVectorization(
standardize=custom_standardization,
max_tokens=max_features,
output_mode="int",
output_sequence_length=sequence_length,
)
text_ds = raw_train_ds.map(lambda x, y: x)
vectorize_layer.adapt(text_ds)
テキストを標準化するための関数(custom_standardization)を定義しています。テキストを小文字化して、HTMLタグの改行を削除しています。
TextVectorizationでベクトル化層を作成して適応させています。
これによって各単語に固有のインデックスが割り当てられます。
def vectorize_text(text, label):
text = tf.expand_dims(text, -1)
return vectorize_layer(text), label
train_ds = raw_train_ds.map(vectorize_text)
val_ds = raw_val_ds.map(vectorize_text)
test_ds = raw_test_ds.map(vectorize_text)
train_ds = train_ds.cache().prefetch(buffer_size=10)
val_ds = val_ds.cache().prefetch(buffer_size=10)
test_ds = test_ds.cache().prefetch(buffer_size=10)
先ほどの処理を利用して訓練データ、検証データ、テストデータを処理します。
モデルの構築
inputs = keras.Input(shape=(None,), dtype="int64")
x = layers.Embedding(max_features, embedding_dim)(inputs)
x = layers.Dropout(0.5)(x)
x = layers.Conv1D(128, 7, padding="valid", activation="relu", strides=3)(x)
x = layers.Conv1D(128, 7, padding="valid", activation="relu", strides=3)(x)
x = layers.GlobalMaxPooling1D()(x)
x = layers.Dense(128, activation="relu")(x)
x = layers.Dropout(0.5)(x)
predictions = layers.Dense(1, activation="sigmoid", name="predictions")(x)
model = keras.Model(inputs, predictions)
model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
テキストデータのための畳み込みニューラルネットワーク(CNN)モデルを構築しています。
学習
epochs = 3
model.fit(train_ds, validation_data=val_ds, epochs=epochs)
評価
model.evaluate(test_ds)
82/782 [==============================] - 30s 38ms/step - loss: 0.4055 - accuracy: 0.8601
[0.4055033326148987, 0.8601199984550476]
テスト用データセットに対して86%の精度で正しく予測が行えました。