В моем предыдущем посте показано, как выбирать функции активации и потери последнего слоя для разных задач. В этом посте мы сосредоточимся на многоклассовой классификации с несколькими метками.
Обзор задачи
Мы будем использовать новостной массив Reuters-21578. Наша задача для данной новости - присвоить ей один или несколько тегов. Набор данных разделен на пять основных категорий:
- Темы
- Места
- Люди
- Организации
- Биржи
Например, одна данная новость может иметь эти 3 тега, принадлежащих двум категориям.
- Адреса: США, Китай.
- Темы: торговля
Структура кода
- Прочтите файлы категорий, чтобы получить все доступные 672 тега из этих 5 категорий.
- Прочтите все файлы новостей и найдите 20 наиболее распространенных тегов из 672, которые мы собираемся использовать для классификации. Вот список этих 20 тегов. Для ясности каждая из них имеет префиксы. Например, «pl_usa» означает тег «Места: США», «to_trade» означает «Темы: торговля». и Т. Д.
На предыдущем шаге мы читаем содержание новостей и сохраняем их в списке.
Одна новость выглядит так
average yen cd rates fall in latest week tokyo, feb 27 - average interest rates on yen certificates of deposit, cd, fell to 4.27 pct in the week ended february 25 from 4.32 pct the previous week, the bank of japan said. new rates (previous in brackets), were - average cd rates all banks 4.27 pct (4.32) money market certificate, mmc, ceiling rates for the week starting from march 2 3.52 pct (3.57) average cd rates of city, trust and long-term banks less than 60 days 4.33 pct (4.32) 60-90 days 4.13 pct (4.37) average cd rates of city, trust and long-term banks 90-120 days 4.35 pct (4.30) 120-150 days 4.38 pct (4.29) 150-180 days unquoted (unquoted) 180-270 days 3.67 pct (unquoted) over 270 days 4.01 pct (unquoted) average yen bankers' acceptance rates of city, trust and long-term banks 30 to less than 60 days unquoted (4.13) 60-90 days unquoted (unquoted) 90-120 days unquoted (unquoted) reuter
Начинаем уборку с
- Принимать только символы внутри A-Za-z0–9
- удалить стоп-слова (такие слова, как «в», «на», «от», которые на самом деле не содержат никакой специальной информации)
- лемматизировать (например, превратить слово «ставки» в «ставка»)
После этого наша новость будет выглядеть «дружественной» к нашей модели, каждое слово отделяется пробелом.
average yen cd rate fall latest week tokyo feb 27 average interest rate yen certificatesof deposit cd fell 427 pct week ended february 25from 432 pct previous week bank japan said new rate previous bracket average cd rate bank 427 pct 432 money market certificate mmc ceiling rate weekstarting march 2 352 pct 357 average cd rate city trust longterm bank le 60 day 433 pct 432 6090 day 413 pct 437 average cd rate city trust longterm bank 90120 day 435 pct 430 120150 day 438 pct 429 150180 day unquoted unquoted 180270 day 367 pct unquoted 270 day 401 pct unquoted average yen banker acceptance rate city trust andlongterm bank 30 le 60 day unquoted 413 6090 day unquoted unquoted 90120 day unquoted unquoted reuter
Поскольку небольшой перенос новостей занимает довольно много времени даже после очистки, давайте установим предел максимальной входной последовательности до 88 слов, это покроет 70% всех новостей в полном объеме. Мы могли бы установить больший предел входной последовательности, чтобы охватить больше новостей, но это также увеличит время обучения модели.
Наконец, мы превратим слова в форму идентификаторов и дополним последовательность до предела ввода (88), если она короче.
Обработка текста Keras делает это тривиальным.
from keras.preprocessing.text import Tokenizer from keras.preprocessing.sequence import pad_sequences max_vocab_size = 200000 input_tokenizer = Tokenizer(max_vocab_size) input_tokenizer.fit_on_texts(totalX) input_vocab_size = len(input_tokenizer.word_index) + 1 print("input_vocab_size:",input_vocab_size) # input_vocab_size: 167135 totalX = np.array(pad_sequences(input_tokenizer.texts_to_sequences(totalX), maxlen=maxLength))
Эта же новость будет выглядеть так, каждое число представляет собой уникальное слово в словаре.
array([ 6943, 5, 5525, 177, 22, 699, 13146, 1620, 32, 35130, 7, 130, 6482, 5, 8473, 301, 1764, 32, 364, 458, 794, 11, 442, 546, 131, 7180, 5, 5525, 18247, 131, 7451, 5, 8088, 301, 1764, 32, 364, 458, 794, 11, 21414, 131, 7452, 5, 4009, 35131, 131, 4864, 5, 6712, 35132, 131, 3530, 3530, 26347, 131, 5526, 5, 3530, 2965, 131, 7181, 5, 3530, 301, 149, 312, 1922, 32, 364, 458, 9332, 11, 76, 442, 546, 131, 3530, 7451, 18247, 131, 3530, 3530, 21414, 131, 3530, 3530, 3])
- Встраиваемый слой встраивает последовательность векторов размером 256
- Уровни ГРУ (рекуррентная сеть), которые обрабатывают данные последовательности
- Плотный слой выводит результат классификации по 20 категориям.
embedding_dim = 256 model = Sequential() model.add(Embedding(input_vocab_size, embedding_dim,input_length = maxLength)) model.add(GRU(256, dropout=0.9, return_sequences=True)) model.add(GRU(256, dropout=0.9)) model.add(Dense(num_categories, activation='sigmoid')) model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
Обучив нашу модель 10 эпох примерно за 5 минут, мы достигли следующего результата.
loss: 0.1062 - acc: 0.9650 - val_loss: 0.0961 - val_acc: 0.9690
Следующий код сгенерирует красивый график для визуализации прогресса каждой эпохи обучения.
import matplotlib.pyplot as plt acc = history.history['acc'] val_acc = history.history['val_acc'] loss = history.history['loss'] val_loss = history.history['val_loss'] epochs = range(len(acc)) plt.plot(epochs, acc, 'bo', label='Training acc') plt.plot(epochs, val_acc, 'b', label='Validation acc') plt.title('Training and validation accuracy') plt.legend() plt.figure() plt.plot(epochs, loss, 'bo', label='Training loss') plt.plot(epochs, val_loss, 'b', label='Validation loss') plt.title('Training and validation loss') plt.legend() plt.show()
Перенесите одну очищенную новость (каждое слово разделено пробелом) в тот же входной токенизатор, превратив ее в идентификаторы.
Вызовите метод модели предсказать, на выходе будет список из 20 чисел с плавающей запятой, представляющих вероятности для этих 20 тегов. Для демонстрации возьмем любые теги с вероятностью более 0,2.
textArray = np.array(pad_sequences(input_tokenizer.texts_to_sequences([input_x_220]), maxlen=maxLength)) predicted = model.predict(textArray)[0] for i, prob in enumerate(predicted): if prob > 0.2: print(selected_categories[i])
Это дает три тега
pl_uk pl_japan to_money-fx
основная правда в том
pl_japan to_money-fx to_interest
Модель получила 2 из 3 верных ответов на данную новость.
Резюме
Мы начинаем с очистки необработанных данных новостей для входных данных модели. Создал модель Keras, чтобы выполнять мультиклассовую классификацию с несколькими метками. Визуализируйте результат тренировки и сделайте прогноз. Возможны дальнейшие улучшения
- Лучшая очистка данных
- Использовать более длинный предел входной последовательности
- Больше тренировочных эпох
Исходный код для записной книжки jupyter доступен в моем репозитории GitHub, если вам интересно.
Первоначально опубликовано на www.dlology.com.