Некоторое время назад во время проекта коллега использовал когнитивный API Azure для анализа настроений в форме обратной связи. Мне было любопытно, как сделать это с нуля, и хотя наличие API очень удобно, если вы хотите сделать с ним что-то особенное, вам нужно иметь возможность его адаптировать. И то, что я хотел сделать, - это попытаться извлечь сантименты из сообщений чата разногласий, а не из среднего обзора.

И хотя у них нет такой же структуры и контекста, как у прямого обзора, между очень эмоционально нагруженными комментариями есть сходства, и это те, которые я хотел уловить.

Поэтому я провел небольшое исследование и нашел для начала два очень многообещающих набора данных.

Данные

Первым набором данных был набор данных настроений IMDB при обзоре, он пригодился, потому что это были данные прямого обзора. И хотя я не собирался анализировать обзоры, слова и контекст каждого обзора похожи на то, из чего может состоять очень положительно или отрицательно нагруженный комментарий, поэтому я использовал этот набор данных в качестве индекса слов. И, как плюс, этот набор данных теперь поставляется с Keras! Выиграть!

word_dict = imdb.get_word_index()
def encode_sentence(text):
    result = []
    arr = text_to_word_sequence(text, lower=True, split=" ")
    for word in arr:
        w = encode_word(word)
        if w is not None:
            result.append(w)
    return result
def encode_word(word):
    if word not in word_dict:
        return None
    return word_dict[word]

Второй набор - это набор данных настроений Twitter, который состоит из 1,5 миллионов твитов и соответствующих меток настроений. Это набор данных, который я использовал для обучения.

def build_dataset(max_len):
    df = pd.read_csv("data/twitter.csv", delimiter=",", names=["y", "X"], usecols=[1,3], header=None, nrows=6000)
    Xts = df["X"].values
    arr = []
    for text in Xts:
        arr.append(encode_sentence(text))
    X = sequence.pad_sequences(arr, maxlen=max_len)
    y = df["y"].values
    return (X, y)

Вы можете найти ссылку на этот набор данных здесь: http://thinknook.com/twitter-sentiment-analysis-training-corpus-dataset-2012-09-22/

Модель

def build_model(words, vec_len, review_len):
    model = Sequential()
    model.add(Embedding(words, vec_len, input_length=review_len))
    model.add(Dropout(0.25))
    model.add(Conv1D(32, 3, padding="same"))
    model.add(MaxPooling1D(pool_size=2))
    model.add(Conv1D(16, 3, padding="same"))
    model.add(Flatten())
    model.add(Dropout(0.25))
    model.add(Dense(100, activation="sigmoid"))
    model.add(Dropout(0.25))
    model.add(Dense(1, activation="sigmoid"))
    model.compile(loss="binary_crossentropy", optimizer="adam", metrics=["accuracy"])
    model.summary()
    return model

Как вы можете видеть, модель представляет собой линейную модель Кераса, начинающуюся с ввода встраивания слова, проходящую через несколько одномерных сверток и максимальных пулов, прежде чем она будет сглажена, пройдена через активированный сигмовидной кишкой плотный слой и завершится одним нейроном, активируемым сигмовидной кишкой, который это наш результат.

Обучение

Я обучил сеть более чем 20 эпохам из 6000 твитов и словарю, составленному из 10000 наиболее распространенных слов, используемых в обзорах IMDB. Вы можете увеличить это, но я был на ноутбуке с одним графическим процессором 940mx, поэтому у меня не было такой доступной вычислительной мощности. «Обзоры» здесь - это твиты, которые, очевидно, имеют максимальную длину 128 символов.

# Parameters
words = 10000
review_len = 128
vec_len = 300
patience = 5
batch_size = 15
epochs = 20
# Load data
X, y = build_dataset(review_len)
# Build model
model = build_model(words, vec_len, review_len)
# Early stopping
early_stopping_monitor = EarlyStopping(patience=patience, monitor="loss", mode="auto")
# Fit model
model.fit(X, y, epochs=epochs, callbacks=[early_stopping_monitor], batch_size=batch_size, verbose=1, validation_split=0.25)

Результаты и тестирование

Я интегрировал модель в рудиментарного бота Discord на базе nodejs и протестировал с несколькими предложениями.

Полученный результат соответствует тому, что я хотел, он оценивает отрицательные комментарии близко к 0, а положительные комментарии - к 1.

Хотя это не идеальная модель и, вероятно, слишком много подходит, она служит хорошим введением в анализ настроений для тех, кто хочет начать, получайте удовольствие!

Github

Https://github.com/dscplatform/discordbot/tree/master/cognitive/emotion