Базовая классификация текста

Посмотреть на TensorFlow.org Запускаем в Google Colab Посмотреть исходный код на GitHub Скачать блокнот

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

import matplotlib.pyplot as plt
import os
import re
import shutil
import string
import tensorflow as tf

from tensorflow.keras import layers
from tensorflow.keras import losses
from tensorflow.keras import preprocessing
from tensorflow.keras.layers.experimental.preprocessing import TextVectorization
print(tf.__version__)
2.5.0

Анализ настроений

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

Вы будете использовать Большой Movie Dataset обзора , содержащий текст 50000 обзоров фильмов из базы данных Internet Movie . Они разделены на 25 000 обзоров для обучения и 25 000 обзоров для тестирования. Тренировочные и контрольные наборы сбалансированы, то есть они содержат одинаковое количество положительных и отрицательных отзывов.

Загрузите и изучите набор данных IMDB

Давайте загрузим и извлечем набор данных, а затем исследуем структуру каталогов.

url = "https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz"

dataset = tf.keras.utils.get_file("aclImdb_v1", url,
                                    untar=True, cache_dir='.',
                                    cache_subdir='')

dataset_dir = os.path.join(os.path.dirname(dataset), 'aclImdb')
Downloading data from https://ai.stanford.edu/~amaas/data/sentiment/aclImdb_v1.tar.gz
84131840/84125825 [==============================] - 7s 0us/step
os.listdir(dataset_dir)
['train', 'imdb.vocab', 'README', 'imdbEr.txt', 'test']
train_dir = os.path.join(dataset_dir, 'train')
os.listdir(train_dir)
['pos',
 'neg',
 'urls_neg.txt',
 'urls_pos.txt',
 'unsup',
 'unsupBow.feat',
 'labeledBow.feat',
 'urls_unsup.txt']

В aclImdb/train/pos и aclImdb/train/neg каталоги содержат много текстовых файлов, каждый из которых один фильма обзор. Давайте посмотрим на один из них.

sample_file = os.path.join(train_dir, 'pos/1181_9.txt')
with open(sample_file) as f:
  print(f.read())
Rachel Griffiths writes and directs this award winning short film. A heartwarming story about coping with grief and cherishing the memory of those we've loved and lost. Although, only 15 minutes long, Griffiths manages to capture so much emotion and truth onto film in the short space of time. Bud Tingwell gives a touching performance as Will, a widower struggling to cope with his wife's death. Will is confronted by the harsh reality of loneliness and helplessness as he proceeds to take care of Ruth's pet cow, Tulip. The film displays the grief and responsibility one feels for those they have loved and lost. Good cinematography, great direction, and superbly acted. It will bring tears to all those who have lost a loved one, and survived.

Загрузите набор данных

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

main_directory/
...class_a/
......a_text_1.txt
......a_text_2.txt
...class_b/
......b_text_1.txt
......b_text_2.txt

Для того, чтобы подготовить набор данных для бинарной классификации, вам потребуется две папки на диске, соответствующие class_a и class_b . Они будут положительные и отрицательные обзоры фильмов, которые могут быть найдены в aclImdb/train/pos и aclImdb/train/neg . Поскольку набор данных IMDB содержит дополнительные папки, вы удалите их перед использованием этой утилиты.

remove_dir = os.path.join(train_dir, 'unsup')
shutil.rmtree(remove_dir)

Далее, вы будете использовать text_dataset_from_directory утилиту для создания меченого tf.data.Dataset . tf.data представляет собой мощный набор инструментов для работы с данными.

При запуске машинного обучения эксперимента, это лучшая практика , чтобы разделить набор данных на три расколов: поезд , проверку и испытание .

Набор данных IMDB уже разделен на обучающий и тестовый, но в нем отсутствует набор для проверки. Давайте создадим набор проверки с использованием 80:20 раскол обучающих данных с помощью validation_split аргумент ниже.

batch_size = 32
seed = 42

raw_train_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='training', 
    seed=seed)
Found 25000 files belonging to 2 classes.
Using 20000 files for training.

Как вы можете видеть выше, в папке обучения 25 000 примеров, из которых вы будете использовать 80% (или 20 000) для обучения. Как вы увидите в данный момент, вы можете тренировать модель, передавая массив данных непосредственно в model.fit . Если вы новичок в tf.data , вы можете также итерация по набору данных и распечатать несколько примеров следующим образом .

for text_batch, label_batch in raw_train_ds.take(1):
  for i in range(3):
    print("Review", text_batch.numpy()[i])
    print("Label", label_batch.numpy()[i])
Review b'"Pandemonium" is a horror movie spoof that comes off more stupid than funny. Believe me when I tell you, I love comedies. Especially comedy spoofs. "Airplane", "The Naked Gun" trilogy, "Blazing Saddles", "High Anxiety", and "Spaceballs" are some of my favorite comedies that spoof a particular genre. "Pandemonium" is not up there with those films. Most of the scenes in this movie had me sitting there in stunned silence because the movie wasn\'t all that funny. There are a few laughs in the film, but when you watch a comedy, you expect to laugh a lot more than a few times and that\'s all this film has going for it. Geez, "Scream" had more laughs than this film and that was more of a horror film. How bizarre is that?<br /><br />*1/2 (out of four)'
Label 0
Review b"David Mamet is a very interesting and a very un-equal director. His first movie 'House of Games' was the one I liked best, and it set a series of films with characters whose perspective of life changes as they get into complicated situations, and so does the perspective of the viewer.<br /><br />So is 'Homicide' which from the title tries to set the mind of the viewer to the usual crime drama. The principal characters are two cops, one Jewish and one Irish who deal with a racially charged area. The murder of an old Jewish shop owner who proves to be an ancient veteran of the Israeli Independence war triggers the Jewish identity in the mind and heart of the Jewish detective.<br /><br />This is were the flaws of the film are the more obvious. The process of awakening is theatrical and hard to believe, the group of Jewish militants is operatic, and the way the detective eventually walks to the final violent confrontation is pathetic. The end of the film itself is Mamet-like smart, but disappoints from a human emotional perspective.<br /><br />Joe Mantegna and William Macy give strong performances, but the flaws of the story are too evident to be easily compensated."
Label 0
Review b'Great documentary about the lives of NY firefighters during the worst terrorist attack of all time.. That reason alone is why this should be a must see collectors item.. What shocked me was not only the attacks, but the"High Fat Diet" and physical appearance of some of these firefighters. I think a lot of Doctors would agree with me that,in the physical shape they were in, some of these firefighters would NOT of made it to the 79th floor carrying over 60 lbs of gear. Having said that i now have a greater respect for firefighters and i realize becoming a firefighter is a life altering job. The French have a history of making great documentary\'s and that is what this is, a Great Documentary.....'
Label 1

Обратите внимание , обзоры содержат текст (с пунктуацией и случайным HTML тегами , как <br/> ). В следующем разделе вы покажете, как с ними справиться.

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

print("Label 0 corresponds to", raw_train_ds.class_names[0])
print("Label 1 corresponds to", raw_train_ds.class_names[1])
Label 0 corresponds to neg
Label 1 corresponds to pos

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

raw_val_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/train', 
    batch_size=batch_size, 
    validation_split=0.2, 
    subset='validation', 
    seed=seed)
Found 25000 files belonging to 2 classes.
Using 5000 files for validation.
raw_test_ds = tf.keras.preprocessing.text_dataset_from_directory(
    'aclImdb/test', 
    batch_size=batch_size)
Found 25000 files belonging to 2 classes.

Подготовьте набор данных для обучения

Далее, вы стандартизировать, разметить и векторизации данные , используя полезный preprocessing.TextVectorization слой.

Стандартизация относится к предварительной обработке текста, обычно для удаления знаков препинания или элементов HTML для упрощения набора данных. Токенизация относится к разделению строк на токены (например, разделение предложения на отдельные слова путем разделения на пробелы). Векторизация относится к преобразованию токенов в числа, чтобы их можно было передать в нейронную сеть. Все эти задачи могут быть выполнены с помощью этого слоя.

Как вы видели выше, обзоры содержат различные HTML - теги , как <br /> . Эти метки не будут удалены стандартизатор по умолчанию в TextVectorization слое (который преобразует текст в нижний регистр и полосе пунктуации по умолчанию, но не лишит HTML). Вы напишете специальную функцию стандартизации для удаления HTML.

def custom_standardization(input_data):
  lowercase = tf.strings.lower(input_data)
  stripped_html = tf.strings.regex_replace(lowercase, '<br />', ' ')
  return tf.strings.regex_replace(stripped_html,
                                  '[%s]' % re.escape(string.punctuation),
                                  '')

Далее вы создадите TextVectorization слой. Вы будете использовать этот слой для стандартизации, токенизации и векторизации наших данных. Вы можете установить output_mode в int для создания уникальных целочисленных индексов для каждых маркеров.

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

max_features = 10000
sequence_length = 250

vectorize_layer = TextVectorization(
    standardize=custom_standardization,
    max_tokens=max_features,
    output_mode='int',
    output_sequence_length=sequence_length)

Далее, вы назовете adapt к размеру состояния предварительной обработки слоя в наборе данных. Это заставит модель построить индекс строк для целых чисел.

# Make a text-only dataset (without labels), then call adapt
train_text = raw_train_ds.map(lambda x, y: x)
vectorize_layer.adapt(train_text)

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

def vectorize_text(text, label):
  text = tf.expand_dims(text, -1)
  return vectorize_layer(text), label
# retrieve a batch (of 32 reviews and labels) from the dataset
text_batch, label_batch = next(iter(raw_train_ds))
first_review, first_label = text_batch[0], label_batch[0]
print("Review", first_review)
print("Label", raw_train_ds.class_names[first_label])
print("Vectorized review", vectorize_text(first_review, first_label))
Review tf.Tensor(b'Great movie - especially the music - Etta James - "At Last". This speaks volumes when you have finally found that special someone.', shape=(), dtype=string)
Label neg
Vectorized review (<tf.Tensor: shape=(1, 250), dtype=int64, numpy=
array([[  86,   17,  260,    2,  222,    1,  571,   31,  229,   11, 2418,
           1,   51,   22,   25,  404,  251,   12,  306,  282,    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,    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,    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,    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,    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,    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,    0,    0]])>, <tf.Tensor: shape=(), dtype=int32, numpy=0>)

Как вы можете видеть выше, каждый токен был заменен целым числом. Вы можете поиск маркеров (строка) , что каждое целое число соответствует путем вызов .get_vocabulary() на слое.

print("1287 ---> ",vectorize_layer.get_vocabulary()[1287])
print(" 313 ---> ",vectorize_layer.get_vocabulary()[313])
print('Vocabulary size: {}'.format(len(vectorize_layer.get_vocabulary())))
1287 --->  silent
 313 --->  night
Vocabulary size: 10000

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

train_ds = raw_train_ds.map(vectorize_text)
val_ds = raw_val_ds.map(vectorize_text)
test_ds = raw_test_ds.map(vectorize_text)

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

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

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

.prefetch() перекрывает данные предварительной обработки и выполнение модели во время тренировки.

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

AUTOTUNE = tf.data.AUTOTUNE

train_ds = train_ds.cache().prefetch(buffer_size=AUTOTUNE)
val_ds = val_ds.cache().prefetch(buffer_size=AUTOTUNE)
test_ds = test_ds.cache().prefetch(buffer_size=AUTOTUNE)

Создать модель

Пришло время создать свою нейронную сеть:

embedding_dim = 16
model = tf.keras.Sequential([
  layers.Embedding(max_features + 1, embedding_dim),
  layers.Dropout(0.2),
  layers.GlobalAveragePooling1D(),
  layers.Dropout(0.2),
  layers.Dense(1)])

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
embedding (Embedding)        (None, None, 16)          160016    
_________________________________________________________________
dropout (Dropout)            (None, None, 16)          0         
_________________________________________________________________
global_average_pooling1d (Gl (None, 16)                0         
_________________________________________________________________
dropout_1 (Dropout)          (None, 16)                0         
_________________________________________________________________
dense (Dense)                (None, 1)                 17        
=================================================================
Total params: 160,033
Trainable params: 160,033
Non-trainable params: 0
_________________________________________________________________

Слои располагаются последовательно для построения классификатора:

  1. Первый слой представляет собой Embedding слой. Этот уровень принимает обзоры в целочисленном коде и ищет вектор внедрения для каждого индекса слова. Эти векторы изучаются по мере обучения модели. Векторы добавляют измерение к выходному массиву. Полученные размеры: (batch, sequence, embedding) . Чтобы узнать больше о вложении см слова вложения учебника .
  2. Далее, GlobalAveragePooling1D слой возвращает выходной вектор фиксированной длины для каждого примера путем усреднения по размерности последовательности. Это позволяет модели обрабатывать ввод переменной длины самым простым способом.
  3. Этот выходной вектор фиксированной длины по трубопроводу через полностью подключено ( Dense слой) с 16 скрытых блоками.
  4. Последний слой плотно связан с единственным выходным узлом.

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

Модель нуждается в функции потерь и оптимизаторе для обучения. Так как это бинарная проблема классификации и модель выхода вероятности (один блок-слой с сигмовидной активацией), вы будете использовать losses.BinaryCrossentropy функцию потерь.

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

model.compile(loss=losses.BinaryCrossentropy(from_logits=True),
              optimizer='adam',
              metrics=tf.metrics.BinaryAccuracy(threshold=0.0))

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

Вы будете тренировать модель пропускания dataset объекта в пригонках метода.

epochs = 10
history = model.fit(
    train_ds,
    validation_data=val_ds,
    epochs=epochs)
Epoch 1/10
625/625 [==============================] - 4s 4ms/step - loss: 0.6662 - binary_accuracy: 0.6918 - val_loss: 0.6192 - val_binary_accuracy: 0.7720
Epoch 2/10
625/625 [==============================] - 2s 4ms/step - loss: 0.5538 - binary_accuracy: 0.7974 - val_loss: 0.5026 - val_binary_accuracy: 0.8216
Epoch 3/10
625/625 [==============================] - 2s 4ms/step - loss: 0.4483 - binary_accuracy: 0.8421 - val_loss: 0.4228 - val_binary_accuracy: 0.8470
Epoch 4/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3807 - binary_accuracy: 0.8648 - val_loss: 0.3757 - val_binary_accuracy: 0.8600
Epoch 5/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3378 - binary_accuracy: 0.8784 - val_loss: 0.3463 - val_binary_accuracy: 0.8670
Epoch 6/10
625/625 [==============================] - 2s 4ms/step - loss: 0.3069 - binary_accuracy: 0.8874 - val_loss: 0.3271 - val_binary_accuracy: 0.8706
Epoch 7/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2830 - binary_accuracy: 0.8967 - val_loss: 0.3136 - val_binary_accuracy: 0.8732
Epoch 8/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2644 - binary_accuracy: 0.9037 - val_loss: 0.3040 - val_binary_accuracy: 0.8760
Epoch 9/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2468 - binary_accuracy: 0.9107 - val_loss: 0.2972 - val_binary_accuracy: 0.8784
Epoch 10/10
625/625 [==============================] - 2s 4ms/step - loss: 0.2327 - binary_accuracy: 0.9161 - val_loss: 0.2923 - val_binary_accuracy: 0.8792

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

Посмотрим, как модель работает. Будут возвращены два значения. Потеря (число, которое представляет нашу ошибку, чем ниже значение, тем лучше) и точность.

loss, accuracy = model.evaluate(test_ds)

print("Loss: ", loss)
print("Accuracy: ", accuracy)
782/782 [==============================] - 2s 2ms/step - loss: 0.3108 - binary_accuracy: 0.8722
Loss:  0.3108080327510834
Accuracy:  0.8722400069236755

Этот довольно наивный подход обеспечивает точность около 86%.

Постройте график точности и потерь с течением времени

model.fit() возвращает History объект , который содержит словарь со всем , что произошло во время тренировки:

history_dict = history.history
history_dict.keys()
dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])

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

acc = history_dict['binary_accuracy']
val_acc = history_dict['val_binary_accuracy']
loss = history_dict['loss']
val_loss = history_dict['val_loss']

epochs = range(1, len(acc) + 1)

# "bo" is for "blue dot"
plt.plot(epochs, loss, 'bo', label='Training loss')
# b is for "solid blue line"
plt.plot(epochs, val_loss, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()

plt.show()

PNG

plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend(loc='lower right')

plt.show()

PNG

На этом графике точки представляют потери при обучении и точность, а сплошные линии - потери при проверке и точность.

Обратите внимание , что потеря обучения уменьшается с каждой эпохой и обучение точности возрастает с каждой эпохой. Это ожидается при использовании оптимизации градиентного спуска - она ​​должна минимизировать желаемое количество на каждой итерации.

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

В этом конкретном случае вы можете предотвратить переобучение, просто остановив обучение, когда точность проверки больше не увеличивается. Один из способов сделать это является использование tf.keras.callbacks.EarlyStopping обратного вызова.

Экспорт модели

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

export_model = tf.keras.Sequential([
  vectorize_layer,
  model,
  layers.Activation('sigmoid')
])

export_model.compile(
    loss=losses.BinaryCrossentropy(from_logits=False), optimizer="adam", metrics=['accuracy']
)

# Test it with `raw_test_ds`, which yields raw strings
loss, accuracy = export_model.evaluate(raw_test_ds)
print(accuracy)
782/782 [==============================] - 3s 4ms/step - loss: 0.3108 - accuracy: 0.8722
0.8722400069236755

Вывод по новым данным

Чтобы получить прогнозы для новых примеров, вы можете просто вызвать model.predict() .

examples = [
  "The movie was great!",
  "The movie was okay.",
  "The movie was terrible..."
]

export_model.predict(examples)
array([[0.60349613],
       [0.42510134],
       [0.3445068 ]], dtype=float32)

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

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

Посетите этот учебник , чтобы узнать больше о сохранении моделей.

Упражнение: мультиклассовая классификация по вопросам переполнения стека

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

Набор данные были подготовлены для использования с телом нескольких тысяч вопросов программирования (например, «Как можно отсортировать словарь по значению в Python?») Размещено на переполнение стека. Каждый из них помечен ровно одним тегом (Python, CSharp, JavaScript или Java). Ваша задача - принять вопрос в качестве входных данных и предсказать соответствующий тег, в данном случае Python.

Набор данных вы будете работать с содержат несколько тысяч вопросов , извлеченных из более широкой публики переполнения стеки набора данных на BigQuery , который содержит более 17 миллионов сообщений.

После загрузки набора данных вы обнаружите, что он имеет структуру каталогов, аналогичную набору данных IMDB, с которым вы работали ранее:

train/
...python/
......0.txt
......1.txt
...javascript/
......0.txt
......1.txt
...csharp/
......0.txt
......1.txt
...java/
......0.txt
......1.txt

Чтобы выполнить это упражнение, вам следует изменить эту записную книжку для работы с набором данных Stack Overflow, внеся следующие изменения:

  1. В верхней части ноутбука, обновите код , который загружает IMDB набор данных с кодом для загрузки набора данных переполнения стеки , который был prepreared. Поскольку набор данных Stack Overflow имеет аналогичную структуру каталогов, вам не нужно будет вносить много изменений.

  2. Изменение последнего слоя модели для чтения Dense(4) , так как в настоящее время существует четыре выходных классы.

  3. При составлении модели, измените потери tf.keras.losses.SparseCategoricalCrossentropy . Это правильная функция потерь использовать для задачи классификации мульти-класса, когда метки для каждого класса являются целыми числами (в этом случае они могут быть 0, 1, 2 или 3). Кроме того, изменение метрики для metrics=['accuracy'] , так как это задача классификации мульти-класса ( tf.metrics.BinaryAccuracy используется только для бинарных классификаторов).

  4. При построении точности с течением времени, изменения binary_accuracy и val_binary_accuracy к accuracy и val_accuracy соответственно.

  5. Как только эти изменения будут внесены, вы сможете обучать мультиклассификатор.

Узнать больше

В этом руководстве с нуля была введена классификация текста. Чтобы узнать больше о классификации процесса текста в целом, проверьте руководство Текст классификации от Google Developers.

# MIT License
#
# Copyright (c) 2017 François Chollet
#
# Permission is hereby granted, free of charge, to any person obtaining a
# copy of this software and associated documentation files (the "Software"),
# to deal in the Software without restriction, including without limitation
# the rights to use, copy, modify, merge, publish, distribute, sublicense,
# and/or sell copies of the Software, and to permit persons to whom the
# Software is furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.