Введение:

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

Набор данных:

Я использовал набор данных Reuters от Кераса (https://keras.io/datasets/). Данные, подходящие для решения задачи классификации тематик новостной ленты. Набор данных содержит 11 228 новостных лент Рейтер и более 46 тем.

Каждый провод кодируется как последовательность индексов слов. Слова индексируются по частоте в данных, например, целое число «4» кодирует четвертое по частоте слово в наборе данных. В нашем случае индексация начинается с «3», а «0» означает неизвестное слово.

Набор данных разбивается для ансамбля следующим образом:

Я решил использовать процентное соотношение для разделения иначе, чем указано в источнике. Сначала тестовые данные (0.2) были отделены от всего набора данных. Из оставшихся данных 40% были извлечены как данные обучения и 60% как данные проверки. Идея заключалась в том, чтобы использовать больше данных для модели обучающего ансамбля.

from keras.datasets import reuters
from sklearn.model_selection import train_test_split
(X_data, y_data), (X_test, y_test) = reuters.load_data(path=”reuters.npz”, num_words=None, skip_top=0, maxlen=None, test_split=0.2, seed=113, start_char=1, oov_char=2, index_from=3)

В случае, если вы получаете ошибку Pickle, вы можете попробовать изменить версию numpy:

!pip install numpy==1.16.1

Модель Кашари имеет особый входной формат. Чтобы преобразовать данные Reuters в нужный формат, используйте следующее:

#Constructing data to available input format at Kashgari
X_train = [[str(j) for j in i ]for i in X_train ]
y_train = [ str(i) for i in y_train ]
X_val = [[str(j) for j in i ]for i in X_val ]
y_val = [ str(i) for i in y_val ]
X_test = [[str(j) for j in i ]for i in X_test ]
y_test = [ str(i) for i in y_test ]

Предварительное ансамблирование нейронной сети:

Используемые архитектуры предварительного ансамбля взяты из https://github.com/BrikerMan/Kashgari.

Архитектура модели CNN следующая:

1. Входной слой (встраивание word2vec)

2. Сверточный слой («фильтры»: 128, «размер_ядра»: 5, «активация»: «relu»).

3. Глобальный максимальный пул 1D

4. Полностью связанный слой («units»: 64, «activate»: «relu»)

5. Выходной слой («единицы»: «количество классов», «активация»: «softmax»).

Оптимизатор (‘name’: ‘Adam’, ‘params’: {‘lr’: 1e-3, ‘decay’: 0,0})

Функция потерь («потеря»: «категориальная_кросцентропия»)

Проверьте ссылку: https://github.com/BrikerMan/Kashgari/blob/master/kashgari/tasks/classification/models.py.

class CNNModel(ClassificationModel): __architect_name__ = ‘CNNModel’
__base_hyper_parameters__ = { 
‘conv1d_layer’: { ‘filters’: 128, ‘kernel_size’: 5, ‘activation’: ‘relu’ }, 
‘max_pool_layer’: {}, 
‘dense_1_layer’: { ‘units’: 64, ‘activation’: ‘relu’ }, ‘activation_layer’: { ‘activation’: ‘softmax’ }, 
‘optimizer’: { ‘module’: ‘keras.optimizers’, ‘name’: ‘Adam’, ‘params’: { ‘lr’: 1e-3, ‘decay’: 0.0 } }, 
‘compile_params’: { ‘loss’: ‘categorical_crossentropy’, # ‘optimizer’: ‘adam’, ‘metrics’: [‘accuracy’] } }

Для вызова модели:

Установите Kashagri из исходников или с помощью pip (для жесткой классификации):

!pip uninstall kashgari

Импортируйте модель CNN из Кашгари:

from kashgari.tasks.classification import CNNModel

По умолчанию Kashgari предоставляет модель классификации жесткого текста. Результатом для каждой выборки является предсказанный класс.

Чтобы получить также мягкую классификацию (вероятности для каждого класса), был изменен исходный код (https://github.com/BrikerMan/Kashgari/blob/master/kashgari/tasks/classification/base_model.py).

Функция прогноз получает новую переменную ‘soft’, которая по умолчанию имеет значение False. Если функция получает значение soft = True, функция возвращает прогнозируемые вероятности каждого класса для каждой выборки перед проверкой порога.

Применение нейронных сетей в ансамбле:

Здесь я описываю применяемые методы ансамбля.

Подача на выходы ансамблевой классификации:

Сначала я обучил пять классификационных моделей CNN с идентичной архитектурой на данных поезда с epocs = 3. Затем эти пять моделей использовались для прогнозирования вероятностей меток данных валидации и суммирования результатов. Результат предсказания данных валидации снова был передан в модель CNN. Мотивация использования моделей с одинаковой структурой взята из https://machinelearningmaster.com/stacking-ensemble-for-deep-learning-neural-networks/.

Описанный метод применялся как к жесткой, так и к мягкой классификации.

Жесткая классификация:

В этом случае результаты отдельных моделей имеют предсказанные классы.

Пре-ансамблевые модели:

predict = list()
models = list()
for i in range(5):
  classifier = CNNModel()
  classifier.fit(X_train,y_train, multi_label=True, epochs = 3)
  models.append(classifier)
  predicted = classifier.predict(X_train)
  print(accuracy_score(predicted, y_train))

Модель ансамбля:

classifier = CNNModel()
val_predict = list()
for model in models:
  pr = model.predict(X_val)
  print(accuracy_score(pr, y_val))
  val_predict.append(pr)
X_predict =  np.array(val_predict).T
X_predict = [[str(j) for j in i ]for i in X_predict ]
classifier.fit(X_predict, y_val, epochs=3)
accuracy_score(classifier.predict(X_predict), y_val)

Прогноз:

test_predict = list()
for model in models:
  pr = model.predict(X_test)
  print(accuracy_score(pr, y_test))
  test_predict.append(pr)
X_predict =  np.array(test_predict).T
X_predict = [[str(j) for j in i ]for i in X_predict ]
accuracy_score(classifier.predict(X_predict), y_test)

Результаты:

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

#Accuracies
0.6415850400712377
0.6219946571682992
0.647373107747106
0.6433659839715049
0.6567230632235085
Ensemble: 
0.680320569902048

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

Мягкий:

Пре-ансамблевые модели:

predictions = None
models = list()
for i in range(5):
 classifier = CNNModel()
 classifier.fit(X_train,y_train, multi_label=True, epochs = 3)
 models.append(classifier)
 predicted = classifier.predict(X_train, soft=True)
 if predictions is None:
   predictions = np.array(predicted)
 else:
   predictions = dstack((predictions, np.array(predicted)))

Модель ансамбля:

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

classifier = CNNModel()
val_predictions = None
for model in models:
  pr = model.predict(X_val, soft=True)
  if val_predictions is None:
    val_predictions = np.array(pr)
  else:
    val_predictions = dstack((val_predictions, np.array(pr)))
X_predict =  val_predictions.reshape(val_predictions.shape[0], val_predictions.shape[1]*val_predictions.shape[2])
X_predict = np.around(X_predict, 2)
X_predict = [[str(j) for j in i ]for i in X_predict ]
classifier.fit(X_predict, y_val, epochs=5)
ensemble_pr = classifier.predict(X_predict)

Прогноз:

test_predictions = None
for model in models:
  pr = model.predict(X_test, soft=True)
  model.evaluate(X_test, y_test)
  if test_predictions is None:
  test_predictions = np.array(pr)
  else:
  test_predictions = dstack((test_predictions, np.array(pr)))
X_predict = test_predictions.reshape(test_predictions.shape[0], test_predictions.shape[1]*test_predictions.shape[2])
X_predict = np.around(X_predict, 2)
X_predict = [[str(j) for j in i ]for i in X_predict ]
accuracy_score(classifier.predict(X_predict), y_test)

Результаты:

#Accuracies
0.6652
0.6634
0.6451
0.6434
0.6598
Ensemble: 
0.6522

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

Подача на ансамбль выходов мягкой классификации с разной архитектурой:

Я пробовал использовать для последнего описанного анализа отдельные модели с разной архитектурой. Отобранными архитектурами из Кашгари, которые показали четыре лучших результата, были CNNModel, BLSTMModel, DropoutBGRUModel и KMaxCNNModel. Архитектура слоев, точность обучения и потери показаны ниже:

Чтобы объединить эти отдельные модели, я использовал ранее описанную архитектуру CNN. Окончательная точность тестовых данных составила:

0.6367

Результат оказался даже ниже, чем в предыдущих экспериментах. Причина может быть в том, что архитектура CNN не очень подходит в качестве окончательной модели ансамбля. Для выяснения причины необходимы дальнейшие исследования.

Этот метод будет подробно описан в следующих публикациях.

Обработка выходных данных классификации как дополнительных характеристик:

Третий эксперимент объединяет выходы и входные данные предварительных моделей для передачи в нейронную сеть ансамбля.

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

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

Жесткая классификация:

Модель ансамбля:

classifier = CNNModel()
val_predict = list()
for model in models:
  pr = model.predict(X_val)
  print(accuracy_score(pr, y_val))
  val_predict.append(pr)
X_predict =  np.array(val_predict).T
X_predict = [[str(j) for j in i ] + k for k,i in zip(X_val, X_predict)]
classifier.fit(X_predict, y_val, epochs=3)
accuracy_score(classifier.predict(X_predict), y_val)

Прогноз:

test_predict = list()
for model in models:
  pr = model.predict(X_test)
  print(accuracy_score(pr, y_test))
  test_predict.append(pr)
X_predict =  np.array(test_predict).T
X_predict = [[str(j) for j in i ] + k for k,i in zip(X_test, X_predict) ]
accuracy_score(classifier.predict(X_predict), y_test)

Результаты:

#Accuracies
0.6415850400712377
0.6219946571682992
0.647373107747106
0.6433659839715049
0.6567230632235085
Ensemble:
0.695013357079252

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

Мягкий:

Модель ансамбля:

classifier = CNNModel()
val_predictions = None
for model in models:
  pr = model.predict(X_val, soft=True)
  if val_predictions is None:
    val_predictions = np.array(pr)
  else:
    val_predictions = dstack((val_predictions, np.array(pr)))
X_predict =  val_predictions.reshape(val_predictions.shape[0], val_predictions.shape[1]*val_predictions.shape[2])
X_predict = np.around(X_predict, 2)
X_predict = [[str(j) for j in i ] + k for k,i in zip(X_val, X_predict)]
classifier.fit(X_predict, y_val, epochs=5)
ensemble_pr = classifier.predict(X_predict)

Прогноз:

test_predictions = None
for model in models:
  pr = model.predict(X_test, soft=True)
  model.evaluate(X_test, y_test)
  if test_predictions is None:
    test_predictions = np.array(pr)
  else:
    test_predictions = dstack((test_predictions, np.array(pr)))
X_predict =  test_predictions.reshape(test_predictions.shape[0], test_predictions.shape[1]*test_predictions.shape[2])
X_predict = np.around(X_predict, 2)
X_predict = [[str(j) for j in i ] + k for k,i in zip(X_test, X_predict) ]
accuracy_score(classifier.predict(X_predict), y_test)

Результаты:

#Accuracies
0.6603
0.6451
0.6598
0.6598
0.6616
Ensemble: 
0.7351

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

Результаты:

Здесь я сообщаю о точности предварительных ансамблевых моделей (NNcl1, NNcl2, NNcl3, NNcl4, NNcl5), ансамблей нейронных сетей (EnsNN1, EnsNN2) и ансамбля голосования (голосование) для жесткой классификации (в качестве основы).

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

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

Будущая работа будет содержать следующее:

  1. Улучшение индивидуальных моделей.
  2. Пробуем разные гиперпараметры.
  3. Объединение моделей на разных слоях.

Исходный код доступен по адресу https://github.com/aghabayli/ensemble.

Ссылки:

Https://github.com/BrikerMan/Kashgari

Https://www.researchgate.net/publication/254043720_Improving_classification_through_ensemble_neural_networks

Https://arxiv.org/pdf/1704.01664.pdf

Https://machinelearningmaster.com/stacking-ensemble-for-deep-learning-neural-networks/