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%の精度で正しく予測が行えました。