{"id":14277,"url":"\/distributions\/14277\/click?bit=1&hash=17ce698c744183890278e5e72fb5473eaa8dd0a28fac1d357bd91d8537b18c22","title":"\u041e\u0446\u0438\u0444\u0440\u043e\u0432\u0430\u0442\u044c \u043b\u0438\u0442\u0440\u044b \u0431\u0435\u043d\u0437\u0438\u043d\u0430 \u0438\u043b\u0438 \u0437\u043e\u043b\u043e\u0442\u044b\u0435 \u0443\u043a\u0440\u0430\u0448\u0435\u043d\u0438\u044f","buttonText":"\u041a\u0430\u043a?","imageUuid":"771ad34a-9f50-5b0b-bc84-204d36a20025"}

Как ваше настроение? Обучение модели для тонального анализа

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

Давайте представим, что у нас есть набор, например, отзывов на новый фильм или публикаций из социальной сети. А наша задача - проанализировать каждый из них на предмет тональной оценки. Можно просматривать все вручную – это вариант, бесспорно. Только есть несколько «но». Даже на небольшой набор, порядка 100-200 записей, уже уйдет уйма времени, а кроме того всегда будет иметь место человеческий фактор, поскольку велика вероятность, о чем-то забыть, запутаться или что-то упустить. Можно ли как-то упростить эту задачу? Данным вопросом люди занимаются уже не один год, и было придумано несколько способов классификации, а именно: методы, использующие правила и тезаурусы (словари), в которых вручную или машинными методами произведен тональный анализ слов; машинное обучение с учителем и без него, а также методы, использующие теоретико-графовые модели — идея которых заключается в построении графа с ранжированием его вершин по весу, где вершинами являются слова из анализируемого текста.

Как вы уже могли заметить сфера применения тонального анализа довольно обширна, в Интернете в общем доступе находятся самые различные корпусы данных для обучения, например, датасеты отзывов с Amazon и Rotten Tomatoes, спам-письма, публикации из различных соц.сетей, записи дебатов и многое другое. Мы рассмотрим обучение модели с учителем на основе готового корпуса размеченных публикаций, собранных из социальной сети Twitter.

Корпус размещен на ресурсе study.mokoron.com, здесь вы можете найти данные в двух форматах — csv и sql. Для работы использовались публикации, сохраненные в формате csv. Далее для унификации требовалось решить задачу предобработки данных. Для начала необходимо было удалить все ненужные символы, пунктуацию и т.д. Здесь удобно использовать регулярные выражения с импортом модуля re. Пример метода представлен ниже, здесь и далее в переменной data хранятся публикации, другими словами твиты:

def delete_rubbish(data): return [re.sub('[^А-Яа-яё| ]', ' ', i) for i in data]

В речи мы часто используем много слов, не несущих никакой эмоциональной окраски, но для нас они могут быть нужны для лучшего понимания смысла высказывания. У модели же такой потребности нет, поэтому все подобные речевые единицы лучше удалять. Корпус таких стоп-слов можно найти в библиотеке для работы с естественным языком NLTK. Кроме того, в методе при обработке данных используется токенизация данных из этой же библиотеки. Токенизация — разбиение предложения на отдельные языковые единицы.

from nltk.corpus import stopwords from nltk.tokenize import word_tokenize

Кроме того, к стоп-словам можно отнести персональные имена. Набор персональных русских имен можно найти в Интернете.

def delete_stop_words(data): #stopwords и PERSON_NAMES - заранее подготовленные наборы слов stop_words = stopwords.words("russian") names = PERSON_NAMES result = [] for item in data: # word_tokenize - токенизация tokens = [token for token in word_tokenize(item) if token not in stop_words and token not in names and token.isalpha() and len(token) > 1] clear_data = " ".join(tokens) result.append(clear_data) return result

Переходим к следующему этапу – лемматизация, т.е. приведение токенов к нормальной словарной форме. Поскольку для модели важна смысловая окраска слова, а не его форма. Например, оценка для токенов «прекрасный» и «прекрасная» должна быть одинаковая. Для лемматизации используется библиотека pymystem3 от Яндекс:

from pymystem3 import Mystem

Лемматизация каждого отдельного предложения довольно затратна по времени, так, например, чтобы обработать наш корпус публикаций понадобится порядка 2-3 часов, в лучшем случае. С целью ускорения этого процесса, данные объединяются в группы вида:«Публикация1 flag Публикация2 flag … flag Публикация1000», где flag – служит разделителем, с помощью которого мы сможем обратно разбить наши данные. Размерность групп в примере кода ниже была равна 1000, но ее также можно менять под свои запросы:

def stemmer_lemmatizer(data): my_stem = Mystem() def function(lst, sz): return [lst[i:i + sz] for i in range(0, len(lst), sz)] tweet = function(data, 1000) result = [] for temp in tweet: all_tweets = ' '.join([txt + ' flag ' for txt in temp]) # лемматизация набора слов words = my_stem.lemmatize(all_tweets) current = [] for word in words: if word != '\n' and word.strip() != '': if word == 'flag': result.append(current) current = [] else: current.append(word) return result

Пример работы:

На этом этапе данные полностью предобработаны, теперь мы можем привести текстовый формат к численному представлению, чтобы начать обучение модели. Для этого воспользуемся методами библиотеки Keras (обеспечивает удобное взаимодействие с нейронными сетями, представляет собой надстройку над фреймворком TensorFlow для машинного обучения), такими как:

from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequence

Значение переменных max_word и max_len выбирается в зависимости от задачи. Далее представлен код векторизации данных:

max_word = 5000 max_len = 200 tokenizer = Tokenizer(num_words=max_words) tokenizer.fit_on_texts(data) sequences = tokenizer.texts_to_sequences(data) tweets = pad_sequences(sequences, maxlen=max_len)

Также векторизуем значения лейблов-оценок:

labels = np.array(data['label']) y = [] for i in range(len(labels)): if labels[i] == 'neutral': y.append(0) elif labels[i] == 'negative': y.append(1) elif labels[i] == 'positive': y.append(2) y = np.array(y) labels = tf.keras.utils.to_categorical(y, 3, dtype="float32") del y

Разбиваем данные на тренировочный набор, на котором наша модель будет обучаться, и проверочный, на котором модель будет проверять точность обучения:

X_train, X_test, y_train, y_test = train_test_split(tweets,labels, random_state=0)

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

model1 = Sequential() model1.add(layers.Embedding(max_words, 20)) model1.add(layers.LSTM(15,dropout=0.5)) model1.add(layers.Dense(3,activation='softmax')) model1.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy']) checkpoint1 = ModelCheckpoint("best_model1.hdf5", monitor='val_accuracy', verbose=1,save_best_only=True, mode='auto', period=1,save_weights_only=False) history = model1.fit(X_train, y_train, epochs=70,validation_data=(X_test, y_test),callbacks=[checkpoint1])

Аналогично обучение нейронной сети с глубиной 2 на 70 эпохах:

model2 = Sequential() model2.add(layers.Embedding(max_words, 40, input_length=max_len)) model2.add(layers.Bidirectional(layers.LSTM(20,dropout=0.6))) model2.add(layers.Dense(3,activation='softmax')) model2.compile(optimizer='rmsprop',loss='categorical_crossentropy', metrics=['accuracy']) checkpoint2 = ModelCheckpoint("best_model2.hdf5", monitor='val_accuracy', verbose=1,save_best_only=True, mode='auto', period=1,save_weights_only=False) history = model2.fit(X_train, y_train, epochs=70,validation_data=(X_test, y_test),callbacks=[checkpoint2])

По итогу обучения были получены две модели с точностями работы ~65% (первая модель) и ~75%(вторая модель). Для дальнейшей работы, конечно, выбирается модель с большей точностью, в нашем случае это нейронная сеть с глубиной 2. Пример ее работы представлен ниже:

from keras.models import load_model model = load_model("best_model2.hdf5") result = model.predict(text)

Построение таких нейронных сетей в настоящий момент является одной из самых популярных задач, а как мы видим, обучить свою нейронную сеть не так уж сложно, главное начать. Далее можно пробовать изменять и корректировать настройки. Либо можно добавить новые этапы предобработки, такие как проверка и исправление орфографии или выделение биграмм (устоявшихся словосочетаний) и др. Все эти изменения и нововведения могут привести к получению более точной модели.

0
2 комментария
Я Чувствую

Интересно, а можно ли определять "сарказм"?

Ответить
Развернуть ветку
NTA
Автор

Полученная модель не предусматривает определение сарказма или иронии, поскольку данные для ее обучения не содержали, так сказать, двусмысленных высказываний. При общении вживую понять лучше собеседника нам помогает его интонация, мимика и жесты. В текстовом формате таких дополнительных данных у нас нет. Поэтому для получения модели, чувствительной к сарказму, необходимо использовать обучающий датасет с соответствующими примерами, а также использовать дополнительные методы для его определения.
Например, считается, что саркастичные высказывания зачастую начинаются с междометия, после которого следует прилагательное или наречие (“Oh wow look at the most realistic doughnuts in a video game”) или же предложения могут иметь контрастную оценку (положительная оценка негативной ситуации и др).

Ответить
Развернуть ветку
-1 комментариев
Раскрывать всегда