In [ ]:
#@title Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

Классификация текстов обзоров фильмов с Keras и TensorFlow Hub

Note: Вся информация в этом разделе переведена с помощью русскоговорящего Tensorflow сообщества на общественных началах. Поскольку этот перевод не является официальным, мы не гарантируем что он на 100% аккуратен и соответствует официальной документации на английском языке. Если у вас есть предложение как исправить этот перевод, мы будем очень рады увидеть pull request в tensorflow/docs репозиторий GitHub. Если вы хотите помочь сделать документацию по Tensorflow лучше (сделать сам перевод или проверить перевод подготовленный кем-то другим), напишите нам на docs-ru@tensorflow.org list.

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

Учебное руководство демонстрирует применение переноса обучения (transfer learning) с использованием TensorFlow Hub и Keras.

Мы будем использовать набор данных IMDB содержащий тексты 50,000 обзоров фильмов из Internet Movie Database. Они разделены на 25,000 обзоров для обучения, и 25,000 обзоров для проверки модели. Обучающая и тестовая выборка сбалансированы, т.е. содержат одинаковое количество позитивных и негативных обзоров.

Здесь мы будем использовать tf.keras, высокоуровневый API для построения и обучения моделей в TensorFlow и TensorFlow Hub, библиотека и платформа для переноса обучения. Для более продвинутого руководства по классификации текстов с использованием tf.keras, см. Руководство по классификации текстов MLCC.


In [ ]:
import numpy as np

import tensorflow as tf

import tensorflow_hub as hub
import tensorflow_datasets as tfds

print("Version: ", tf.__version__)
print("Eager mode: ", tf.executing_eagerly())
print("Hub version: ", hub.__version__)
print("GPU is", "available" if tf.config.experimental.list_physical_devices("GPU") else "NOT AVAILABLE")

Скачайте датасет IMDB

Датасет IMDB доступен в датасетах TensorFlow. Следующий код скачивает датасет IMDB на ваш компьютер (или в среду выполнения Colab):


In [ ]:
# Разобьем обучающую выборку в пропорции 60% на 40%, и у нас будет 15,000 примеров
# для обучения, 10,000 примеров для валидации и 25,000 примеров для проверки.
train_validation_split = tfds.Split.TRAIN.subsplit([6, 4])

(train_data, validation_data), test_data = tfds.load(
    name="imdb_reviews", 
    split=(train_validation_split, tfds.Split.TEST),
    as_supervised=True)

Исследуйте данные

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

Выведем первые 10 примеров.


In [ ]:
train_examples_batch, train_labels_batch = next(iter(train_data.batch(10)))
train_examples_batch

Также напечатаем первые 10 меток.


In [ ]:
train_labels_batch

Постройте модель

Нейронная сеть создается послойно - это требует три основных архитектурных решения:

  • Как представить текст?
  • Сколько слоев использовать в модели?
  • Сколько скрытых нейронов использовать в каждом слое?

В этом примере, входные данные состоят из предложений. Метки которые нужно предсказать являются 0 либо 1.

Одним из способов представления текста является преобразование предложений в векторные представления слов. Мы можем использовать предварительно обученное векторное представление текста в качестве первого слоя. Это имеет три преимущества:

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

Для этого примера мы используем предобученную модель векторного представления текста из TensorFlow Hub называемую google/tf2-preview/gnews-swivel-20dim/1.

Есть еще три другие предварительно обученных модели подходящие для этого руководства:

Давайте сначала создадим слой Keras, который использует модель TensorFlow Hub для векторного представления предложений, и опробуем его на нескольких входных примерах. Обратите внимание, что независимо от длины входного текста, размерность векторного представления будет следующей: (num_examples, embedding_dimension)


In [ ]:
embedding = "https://tfhub.dev/google/tf2-preview/gnews-swivel-20dim/1"
hub_layer = hub.KerasLayer(embedding, input_shape=[], 
                           dtype=tf.string, trainable=True)
hub_layer(train_examples_batch[:3])

Давайте построим полную модель:


In [ ]:
model = tf.keras.Sequential()
model.add(hub_layer)
model.add(tf.keras.layers.Dense(16, activation='relu'))
model.add(tf.keras.layers.Dense(1, activation='sigmoid'))

model.summary()

Для построения классификатора зададим слои последовательно:

  1. Первый слой это слой TensorFlow Hub. Этот слой использует предобученную Saved Model, отображающую предложения в векторные представления. Предобученная модель векторного представления слов которую мы используем (google/tf2-preview/gnews-swivel-20dim/1) разбивает предложение на токены, встраивает каждый токен и затем объединяет вложения. В результате получаются размерности: (num_examples, embedding_dimension).
  2. Получившийся в результате вектор фиксированной длины пропускается сквозь полносвязный (Dense) слой состоящий из 16 скрытых нейронов.
  3. Последний слой плотно связан с единственным выходным нейроном. С использованием функции активации сигмоида, значение получается между 0 и 1, представляя вероятность или уровень доверия.

Давайте скомпилируем модель.

Функция потерь и оптимизатор

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

Это не единственный выбор для функции потерь: Вы можете, например, выбрать mean_squared_error. Но обычно binary_crossentropy лучше справляется с вероятностями - она измеряет "дистанцию" между распределениями вероятностей, или, как в нашем случае, между истинным распределением и предсказаниями.

Далее, когда мы исследуем задачи регрессии (например, предсказание цен на недвижимость), мы посмотрим как использовать другую функцию потерь, которая называется среднеквадратическая ошибка (MSE).

А сейчас настроим модель с использованием оптимизатора и функции потерь:


In [ ]:
model.compile(optimizer='adam',
              loss='binary_crossentropy',
              metrics=['accuracy'])

Обучите модель

Обучите модель за 20 эпох в мини-батчах по 512 образцов. Это 20 итераций по всем образцам данных в тензорах x_train и y_train. Во время обучениЯ следите за функцией потерь и точностью на 10 000 примеров из проверочного набора данных:


In [ ]:
history = model.fit(train_data.shuffle(10000).batch(512),
                    epochs=20,
                    validation_data=validation_data.batch(512),
                    verbose=1)

Оцените модель

Давайте посмотрим как работает модель. Она будет возвращать два значения. Потери (число, показывающее нашу ошибку, меньшие значения - лучше) и точность (accuracy).


In [ ]:
results = model.evaluate(test_data.batch(512), verbose=2)
for name, value in zip(model.metrics_names, results):
  print("%s: %.3f" % (name, value))

Этот довольно наивный подход достиг точности около 87%. С более продвинутыми методами модель бы приблизилась к 95%.

Для дальнейшего чтения

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