В этом посте представлено руководство, в котором с помощью TensorFlow мы обучим модель нейронной сети классифицировать отзывы к фильмам как позитивные или негативные, используя текст отзыва. Это пример бинарной, или двухклассовой, классификации, важного и широко применимого типа задач машинного обучения.
Мы будем использовать IMDB набор данных, который содержит тексты 50 000 отзывов к фильмам из Internet Movie Data Вase (IMDB). Они разделены на 25 000 отзывов для тренировки и 25 000 отзывов для тестирования. Тренировочный и тестовый наборы сбалансированы - это означает, что они содержат одинаковое количество позитивных и негативных отзывов.
Это руководство использует tf.keras - высокоуровневое API для построения и тренировки моделей в TensorFlow.
# TensorFlow и tf.keras
import tensorflow as tf
from tensorflow import keras
# NumPy библиотека
import numpy as np
print(tf.version)
1.9.0
Загрузка IMDB набора данных
IMDB набор данных поставляется в комплекте с TensorFlow. Он уже предобработан так, что отзывы (последовательности слов) конвертированы в последовательности чисел, где каждое число представляет специфичное слово в словаре.
Следующий код загружает IMDB набор данных на вашу машину (или использует кэшированную копию если вы уже загружали его):
imdb = keras.datasets.imdb
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
Downloading data from https://s3.amazonaws.com/text-datasets/imdb.npz
17465344/17464789 [==============================] - 3s 0us/step
Аргумент num_words=10000 сохраняет 10 000 наиболее часто встречающихся слов в тренировочных данных. Редкие слова отсеиваются, чтобы сохранить размер данных управляемым.
Исследование данных
Рассмотрим формат данных. Набор приходит предобработанным: каждый пример - это массив чисел, представляющих слова в отзыве фильма. Каждая метка - число со значением 0 или 1, где 0 означает негативный отзыв, а 1 - позитивный отзыв.
print("Training entries: {}, labels: {}".format(len(train_data), len(train_labels)))
Training entries: 25000, labels: 25000
Текст отзывов конвертирован в числа, где каждое число представляет специфичное слово в словаре. Вот как выглядит первый отзыв:
print(train_data[0])
[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]
Отзывы фильмов могут быть разной длины. Код ниже показывает количество слов в первом и втором отзывах. Ввиду того, что вводные данные нейронной сети должны иметь одинаковую длину, нам потребуется разрешить это позже.
len(train_data[0]), len(train_data[1])
(218, 189)
Преобразование чисел обратно в слова
Это может быть полезным - знать как преобразовывать числа обратно в текст. Здесь мы создадим вспомогательную функцию для выполнения запросов к объекту словаря, который содержит картирование чисел в строки:
# Индексы словаря связи слов и соотвествующих им чисел
word_index = imdb.get_word_index()
# Первые индексы зарезервированы
word_index = {k:(v+3) for k,v in word_index.items()}
word_index["
word_index["
word_index["
word_index["
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
def decode_review(text):
return ' '.join([reverse_word_index.get(i, '?') for i in text])
Downloading data from https://s3.amazonaws.com/text-datasets/imdb_word_index.json
1646592/1641221 [==============================] - 1s 1us/step
Теперь мы можем использовать decode_review функцию, чтобы отобразить текст для первого отзыва:
decode_review(train_data[0])
" this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert is an amazing actor and now the same being director father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also to the two little boy's that played the of norman and paul they were just brilliant children are often left out of the list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all"
Подготовка данных
Отзывы - массивы чисел - должны быть преобразованы в тензоры прежде чем передавать их в нейронную сеть. Это преобразование может быть выполнено двумя путями:
- Одноразовое кодирование (one-hot-encoding) массивов для преобразования их в вектора нулей и единиц. Например, последовательность [3, 5] станет вектором с 10 000 измерений, которые все равны 0, исключая индексы 3 и 5, которые будут равны 1. Затем сделаем первый слой нашей сети - Dense слой - который может обрабатывать нецельночисловые данные векторов. Этот подход затрачивает много памяти, поскольку требует матрицу размера num_words * num_reviews (количество слов * количество отзывов).
- С другой стороны, мы можем заполнить массивы, чтобы все они имели одинаковую длину, затем создадим цельночисловой тензор формы max_length * num_reviews (максимальная длина * количество отзывов). Мы можем использовать встроенный слой (embedding layer) способный обрабатывать такую форму как первый слой сети.
В этом руководстве мы будем использовать второй подход.
Ввиду того что отзывы должны быть одинаковой длины мы используем pad_sequences функцию, чтобы стандартизировать длину:
train_data = keras.preprocessing.sequence.pad_sequences(train_data,
value=word_index["
test_data = keras.preprocessing.sequence.pad_sequences(test_data,
value=word_index["
Взглянем на длину примеров теперь:
len(train_data[0]), len(train_data[1])
(256, 256)
И проверим (теперь заполненный) первый отзыв:
print(train_data[0])
[ 1 14 22 16 43 530 973 1622 1385 65 458 4468 66 3941
4 173 36 256 5 25 100 43 838 112 50 670 2 9
35 480 284 5 150 4 172 112 167 2 336 385 39 4
172 4536 1111 17 546 38 13 447 4 192 50 16 6 147
2025 19 14 22 4 1920 4613 469 4 22 71 87 12 16
43 530 38 76 15 13 1247 4 22 17 515 17 12 16
626 18 2 5 62 386 12 8 316 8 106 5 4 2223
5244 16 480 66 3785 33 4 130 12 16 38 619 5 25
124 51 36 135 48 25 1415 33 6 22 12 215 28 77
52 5 14 407 16 82 2 8 4 107 117 5952 15 256
4 2 7 3766 5 723 36 71 43 530 476 26 400 317
46 7 4 2 1029 13 104 88 4 381 15 297 98 32
2071 56 26 141 6 194 7486 18 4 226 22 21 134 476
26 480 5 144 30 5535 18 51 36 28 224 92 25 104
4 226 65 16 38 1334 88 12 16 283 5 16 4472 113
103 32 15 16 5345 19 178 32 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0 0 0 0 0 0 0 0 0 0 0
0 0 0 0]
Продолжение этого руководства по классификации текста на TensorFlow читайте в следующем посте.