Простая реализация LSTM с Keras

Некоторое время я хотел выполнить небольшой проект, связанный с классификацией текста, и решил опробовать архитектуру, которую я раньше не использовал: долговременная краткосрочная память (LSTM). Вкратце: LSTM - это тип рекуррентной нейронной сети (RNN), которая может запоминать информацию в течение длительного времени (преимущество перед обычным RNN). Если вы хотите получить более подробную информацию: вот отличное и подробное объяснение архитектуры LSTM.

Хорошо, приступим!

Я нашел на Kaggle набор данных как настоящих, так и фейковых новостей: Набор данных фейковых и настоящих новостей. Я попытался сделать это локально в Jupyter Notebook, но как только я добрался до тренировочной части, мой компьютер чуть не взорвался - расчетное время прибытия для одной эпохи составляло не менее 2 часов. Я переместил все в экземпляр Google Colab с ускорением на GPU, и все прошло намного гладко. Вот ссылка для просмотра записной книжки.

# load datasets into a panda's dataframe
real = pd.read_csv('data/True.csv')
fake = pd.read_csv('data/Fake.csv')

Теперь посмотрим, как выглядят данные.

real.head()
fake.head()

Одна вещь, которую я сразу заметил, - это тег «(Reuters)» в настоящих новостных статьях. Оказывается, практически все настоящие новости исходили от Рейтер, и почти ни одна из фейковых новостей не содержала этого слова. Хочу в итоге сравнить модель как со словом, так и с удаленным словом.

real.loc[real.text.str.contains('Reuters')].count()/real.count()
> title      0.998179
> text       0.998179
> subject    0.998179
> date       0.998179
fake.loc[fake.text.str.contains('Reuters')].count()/fake.count()
> title      0.013247
> text       0.013247
> subject    0.013247
> date       0.013247

Теперь давайте дадим метки данных и объединим их в один набор данных для обучения, а затем обучим / протестируем их разделение.

# Give labels to data before combining
fake['fake'] = 1
real['fake'] = 0
combined = pd.concat([fake, real])
## train/test split the text data and labels
features = combined['text']
labels = combined['fake']
X_train, X_test, y_train, y_test = train_test_split(features, labels, random_state = 42)

Теперь обрабатываем текстовые данные с помощью объекта Tokenizer из Keras. Мы не будем удалять стоп-слова, поскольку имеет значение контекст каждого слова и то, как формируются предложения и абзацы. Я считаю, что есть основная разница в качестве письма в этих двух классах. У журналистов Reuters действительно есть редакторы!

# the model will remember only the top 2000 most common words
max_words = 2000
max_len = 400
token = Tokenizer(num_words=max_words, lower=True, split=' ')
token.fit_on_texts(X_train.values)
sequences = token.texts_to_sequences(X_train.values)
train_sequences_padded = pad_sequences(sequences, maxlen=max_len)

А теперь давайте построим модель!

embed_dim = 50
lstm_out = 64
batch_size = 32
model = Sequential()
model.add(Embedding(max_words, embed_dim, input_length = max_len))
model.add(LSTM(lstm_out))
model.add(Dense(256))
model.add(Activation('relu'))
model.add(Dropout(0.5))
model.add(Dense(1, name='out_layer'))
model.add(Activation('sigmoid'))
model.compile(loss = 'binary_crossentropy', optimizer='adam',\
               metrics = ['accuracy'])
print(model.summary())

Теперь давайте обучим модель.

model.fit(train_sequences_padded, y_train, batch_size=batch_size, epochs = 5, validation_split=0.2)

Теперь давайте оценим по сравнению с набором тест / выдержка.

test_sequences = token.texts_to_sequences(X_test)
test_sequences_padded = pad_sequences(test_sequences,\ 
                                       maxlen=max_len)

Довольно, очень хорошо.

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

99% - хороший результат, однако помните, что во всех настоящих новостях есть «Рейтер»? Конечно, это всего лишь одно слово, я хочу увидеть, как удаление его из текста повлияет на производительность модели (если вообще повлияет). Я думаю, что как в выборе слов, так и в редактировании должно быть много других шаблонов, которые могут упростить классификацию для модели.

После удаления «Reuters» из всего текста новостей, оценка тестового набора полученной модели имела точность 98,5%. Итак, небольшое снижение (разница на 0,6%) его предсказательной способности. Я вроде как думал, что будет больше.

Получение такого отличного результата почти сразу же должно заставить вас больше задуматься об основных данных. Если это слишком хорошо, чтобы быть правдой, то, вероятно, так оно и есть! Новости Reuters опираются на руководство по стилю и тщательно редактируются, чего я не могу сказать о фейковых новостях. Эти базовые шаблоны могут позволить модели учиться на этом конкретном наборе данных, но как это обобщить на новости, найденные в естественных условиях из разных источников?

Я нашел статью Business Insider о самых просматриваемых фейковых новостных статьях, просматриваемых на Facebook в 2019 году. Было сложно отследить полнотекстовые статьи некоторых из этих примеров.

Для рассказа № 5 под названием «Омар проводит тайные сборщики денег с исламскими группами, связанными с террором» модель предсказывала это как НАСТОЯЩЕЕ.

В общей истории №1 под названием «дед Трампа был сутенером и уклонялся от налогов; его отец был членом KKK », модель предсказала это как Ложные новости .

Я также схватил нынешний заголовок на CNN: « Трамп продлевает федеральные правила социального дистанцирования до 30 апреля », и модель предсказывала его как НАСТОЯЩЕЕ.

Вывод

Модель казалась очень мощным предсказателем для обучающих и тестовых наборов данных, однако она не может хорошо обобщаться за пределами этого. Когда представлена ​​ложная новость, выходящая за рамки установленной, используется модель 1 к 2. Этот размер выборки довольно мал, и я хотел бы попытаться отследить больше фальшивых новостей за пределами этого набора данных и посмотреть, как они работают. Я также хотел бы опробовать больше современных моделей (ELMo / BERT). Надеюсь, вам понравилось читать!