Построение моделей классификации текста с использованием TensorFlow Hub и оценщиков

искусственный интеллект TensorFlow Kaggle NumPy

Автор: Сара Робинсон, инженер по продвижению технологий разработки

Источник | Публичный аккаунт TensorFlow

Примеры применения трансферного обучения к моделям компьютерного зрения распространены, но что, если бы его использовали для классификации текста? Ознакомьтесь с TensorFlow Hub, библиотекой контента для улучшения моделей TF с помощью трансферного обучения. Трансферное обучение — это процесс использования весов и переменных существующей модели, которая была обучена на больших объемах данных, и применения их к вашим собственным данным и задачам прогнозирования.

Одним из многих преимуществ трансферного обучения является то, что вам не нужно предоставлять свои собственные большие объемы обучающих данных, как при обучении с нуля. Но откуда берутся эти существующие модели? Именно здесь вступает в игру TensorFlow Hub: он предоставляет полный репозиторий существующих контрольных точек модели для различных типов моделей (изображения, текст и т. д.). В этом сообщении блога я опишу, как использовать текстовый модуль TensorFlow Hub для построения модели, предсказывающей жанры фильмов на основе связанных описаний.

Вы можете использовать Colab для запуска этой модели в своем браузере без какой-либо настройки.

Импорт данных и предварительная обработка

В этой модели мы будем использовать набор данных Kaggle Movie, отличный общедоступный ресурс. Набор данных содержит данные для более чем 45 000 фильмов, каждый из которых содержит большое количество данных, связанных с каждым фильмом. Для краткости мы используем только описание фильма (так называемое «введение») и жанр фильма из этого набора данных. Вот предварительный просмотр набора данных в Kaggle: Примечание. Ссылка на набор данных Kaggle MovieВуоооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооооо)

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

1    import numpy as np 
2    import pandas as pd
3
4    import tensorflow as tf
5    import tensorflow_hub as hub
6
7    from sklearn.preprocessing import MultiLabelBinarizer

Я поместил CSV-файл этого набора данных в общедоступную корзину облачного хранилища. Мы можем запустить следующую команду, чтобы загрузить данные в наш экземпляр Colab и прочитать их в формате фрейма данных Pandas:

1    !wget 'https://storage.googleapis.com/movies_data/movies_metadata.csv'
2    data = pd.read_csv('movies_metadata.csv')
3
4    descriptions = data['overview']
5    genres = data['genres']

Для краткости ограничим возможные типы следующими:

1    top_genres = ['Comedy', 'Thriller', 'Romance', 'Action', 'Horror', 'Crime', 'Documentary', 'Adventure', 'Science Fiction']

Мы ограничиваем набор данных фильмами, которые описывают непустые в этих жанрах, а затем делим данные на обучение и тестирование в соотношении 80% обучения и 20% тестирования:

1    train_size = int(len(descriptions) * .8)
2
3    train_descriptions = descriptions[:train_size]
4    train_genres = genres[:train_size]
5
6    test_descriptions = descriptions[train_size:]
7    test_genres = genres[train_size:]

Создание слоя встраивания с помощью TF Hub

Для создания слоя внедрения с помощью TF Hub требуется очень мало кода. Наша модель имеет только одну функцию (описание) и будет представлена ​​в виде столбца встраивания. Встраивание текста обеспечивает способ представления текстового содержимого в векторном пространстве таким образом, что похожие слова или предложения располагаются ближе друг к другу в пространстве встраивания (подробнее об этом можно прочитать здесь). Вы можете создавать векторы встраивания текста с нуля, полностью используя свои собственные данные. TF Hub упрощает этот процесс, предоставляя встраивания текста, которые были обучены с использованием различных текстовых данных. Примечание. Текстовые встроенные ссылкиWoohoo.tensorflow.org/Hubei/modules…

Для английского текста TF Hub предоставляет различные встраивания, которые были обучены различным типам текстовых данных:

Универсальный кодировщик предложений: для ввода более длинного текста ELMo: глубокие встраивания, обученные с использованием теста 1B Word Встраивание языковых моделей нейронных сетей: обучение с помощью Google News Word2vec: обучено из Википедии

Предварительно обученное встраивание текста, которое вы выбираете, является гиперпараметром в вашей модели, поэтому рекомендуется поэкспериментировать с различными вложениями текста, чтобы увидеть, какое из них имеет наибольшую точность. Начните с модели, обученной на тексте, наиболее близком к вашему. Поскольку все наши описания фильмов представляют собой длинные входные данные, я обнаружил, что вложения с использованием универсального кодировщика предложений были наиболее точными. Это может закодировать наше описание как многомерный текстовый вектор. Обратите внимание, что эта конкретная модель большая и занимает 1 ГБ емкости. Примечание. Ссылка на кодировщик общих инструкцийWoohoo.tensorflow.org/Hubei/modules…

Мы можем использовать hub.text_embedding_column, чтобы создать столбец функций для этого слоя в одной строке кода, передав ему имя нашего слоя («movie_descriptions») и URL-адрес модели TF Hub для использования:

1    description_embeddings = hub.text_embedding_column( 
2        "movie_descriptions", 
3        module_spec="https://tfhub.dev/google/universal-sentence-encoder/2" 
4    ) 

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

Самым большим преимуществом этой операции является то, что мы можем передавать текстовые описания предварительно обученным вложениям слов без какой-либо предварительной обработки. Если построить эту модель с нуля, нам нужно будет самостоятельно преобразовать описание в вектор, но с помощью столбца TF Hub мы можем передать строку описания непосредственно в модель.

Превратите этикетки в мультигорячее кодирование Поскольку фильм имеет несколько жанров, наша модель возвращает несколько возможных меток для каждого фильма. В настоящее время наш тип имеет список строк для каждого фильма (например, ['Action', 'Adventure']). Так как каждая метка должна быть одинаковой длины, мы преобразуем эти списки в мультигорячие векторы из 1 и 0 (соответствующие типу в конкретном описании). Мульти-хот-вектор для приключенческого боевика выглядит так: Примечание. Несколько возможных ссылок на тегиEn. Wikipedia.org/wiki/multi-…

1    # Genre lookup, each genre corresponds to an index    
2    top_genres = ['Comedy', 'Thriller', 'Romance', 'Action', 'Horror', 'Crime', 'Documentary', 'Adventure', 'Science Fiction']
3
4    # Multi-hot label for an action and adventure movie 
5    [0 0 0 1 0 0 0 1 0]

Чтобы преобразовать строковые метки в многоцелевые векторы всего за несколько строк кода, нам нужно использовать утилиту Scikit Learn под названием MultiLabelBinarizer:

1    encoder = MultiLabelBinarizer()    
2    encoder.fit_transform(train_genres)    
3    train_encoded = encoder.transform(train_genres)    
4    test_encoded = encoder.transform(test_genres)    
5    num_classes = len(encoder.classes_) 

Вы можете напечатать encoder.classes_, чтобы увидеть список всех строковых классов, предсказанных моделью.

Создайте и обучите модель DNNEstimator

Для нашей модели мы будем использовать DNNEstimator для построения глубокой нейронной сети, способной возвращать мульти-хот-векторы, поскольку у каждого ролика будет 0 или более возможных меток (в отличие от моделей, у которых ровно одна метка на выход). Первый параметр, который мы передаем DNNEstimator, называется head, и этот параметр определяет тип меток, которые, как ожидается, будет иметь наша модель. Мы хотим, чтобы наша модель выводила несколько меток, поэтому здесь мы используем multi_label_head:

1    multi_label_head = tf.contrib.estimator.multi_label_head( 
2            num_classes,
3            loss_reduction=tf.losses.Reduction.SUM_OVER_BATCH_SIZE
4    )

Теперь, когда мы создаем экземпляр DNNEstimator, мы можем передать его. Параметр hidden_units представляет количество слоев в нашей сети. Эта модель имеет 2 слоя, первый слой имеет 64 нейрона, а второй слой имеет 10. Количество слоев и размер слоя являются гиперпараметрами, поэтому вам следует поэкспериментировать с различными значениями, чтобы увидеть, какое из них лучше всего подходит для вашего набора данных. Наконец, мы передаем столбец признаков оценщику. В этом случае у нас есть только один столбец функций (то есть описание), и он был определен выше как столбец внедрения TF Hub, поэтому здесь мы можем передать его в виде списка:

1    estimator = tf.contrib.estimator.DNNEstimator(
2            head=multi_label_head, 
3            hidden_units=[64,10],
4            feature_columns=[description_embeddings]
5    )  

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

1    # Format our data for the numpy_input_fn    
2    features = {    
3        "descriptions": np.array(train_descriptions)    
4    }    
5    labels = np.array(train_encoded)    
6    
7    train_input_fn = tf.estimator.inputs.numpy_input_fn(
8            features,    
9            labels,    
10            shuffle=True,    
11            batch_size=32,    
12            num_epochs=20    
13    )

Оба параметра batch_size и num_epochs в нашей входной функции являются гиперфункциями. batch_size сообщает нашей модели, сколько примеров будет передано модели за одну итерацию, а num_epochs — это количество раз, когда наша модель завершила весь обучающий набор.

Теперь мы можем приступить к обучению нашей модели. Всего одна строка кода:

1    estimator.train(inpu
```t_fn=train_input_fn)

为了评估模型的准确性,我们用自己的测试数据创建一个 eval 函数 input_function,然后调用 estimator.evaluate():


1 eval_input_fn = tf.estimator.inputs.numpy_input_fn({"descriptions": np.array(test_descriptions).astype(np.str)}, test_encoded.astype(np.int32), shuffle=False)
2
3 estimator.evaluate(input_fn=eval_input_fn)


此模型的 AUC 达到 91.5%,而查准率/查全率为 74%。您的结果可能稍有不同。


## 使用我们已训练的模型生成预测结果
现在到了最精彩的部分:根据我们的模型从未见过的数据生成预测结果。首先,我们设置一个包含一些描述的数组(我从 IMDB 中获取这些描述):


1 raw_test = [
2 "An examination of our dietary choices and the food we put in our bodies. Based on Jonathan Safran Foer's memoir.", # Documentary
3 "A teenager tries to survive the last week of her disastrous eighth-grade year before leaving to start high school.", # Comedy
4 "Ethan Hunt and his IMF team, along with some familiar allies, race against time after a mission gone wrong." # Action, Adventure
5 ]


然后,我们定义预测输入函数并调用 predict():


1 predict_input_fn = tf.estimator.inputs.numpy_input_fn({"descriptions": np.array(raw_test).astype(np.str)}, shuffle=False) 2 3 results = estimator.predict(predict_input_fn)

Наконец, мы можем перебрать результаты и отобразить 2 лучших жанра, найденных для каждого фильма, вместе с их значениями достоверности:

1 for movie_genres in results:
2 top_2 = movie_genres['probabilities'].argsort()[-2:][::-1]
3 for genre in top_2:
4 text_genre = encoder.classes_[genre]
5 print(text_genre + ': ' + str(round(movie_genres['probabilities'][genre] * 100, 2)) + '%')


我们的模型能够正确标记上述所有电影描述。


## 使用入门
想用 TF Hub 开始构建自己的模型吗?请参阅此文档和教程。您可以在 GitHub 或 Colab 上找到本文所述的完整模型代码。在之后的博文中,我会介绍如何导出此模型,以用于 TensorFlow Serving 或 Cloud ML Engine,并构建可根据新描述生成预测结果的应用。
注:文档链接
https://www.tensorflow.org/hub/
教程链接
https://www.tensorflow.org/hub/tutorials/text_classification_with_tf_hub
GitHub 链接
https://github.com/tensorflow/workshops/blob/master/extras/tfhub-text/movie-classification.ipynb
Colab 链接
https://colab.research.google.com/github/tensorflow/workshops/blob/master/extras/tfhub-text/movie-classification.ipynb

如果您有疑问或反馈,请通过 Twitter 联系我 (@SRobTweets)。
注:@SRobTweets 链接
https://twitter.com/srobtweets