Привет! Меня зовут Елдар, я – Machine Learning Engineer в компании Beeline Казахстан и студент магистратуры в Университете Цукуба. Работаю дистанционно из Японии, занимаюсь улучшением моделей аутентификации лиц.
В моей работе, как и в исследованиях, важно следить за научным прогрессом и понимать ключевые особенности нейронных сетей. Поэтому я решил обучить, сравнить и рассмотреть возможные методы улучшения двух архитектур нейросети: полносвязную сеть и сверточную нейросеть LeNet 5.
Глубокое обучение – это область машинного обучения, где алгоритмы были созданы на основе нейронных соединений в мозге и демонстрируют высокую точность в большинстве задач ИИ. Мой коллега Саян уже рассказывал как применяет компьютерное зрение в своей работе. Но я считаю, что фундаментальные знания предмета важны не меньше, чем их прикладное использование. Поэтому я хочу рассказать, как я реплицировал сравнение нейронных сетей сделанное Яном ЛеКуном в 1995 году, и покажу как много ценного для современного инженера содержится в научных статьях прошлого.
Итак, в 1995 году Ян ЛеКун (нынче вице-президент и ведущий исследователь искусственного интеллекта в Facebook) провел комплексный анализ алгоритмов адаптивного обучения. Почитать об этом подробнее можно в статье “Comparison of learning algorithms for handwritten digit recognition”. По мнению авторов, «классические» методы, такие как метод ближайшего соседа и многослойные персептроны, уступают по производительности методу опорных векторов (SVM) (упоминаемому в статье как OMC – Optimal margin classifier) и сверточным нейронным сетям. Позже, в 2000-х годах, произошел бум SVM и ядерных методов. Сейчас глубокие нейронные сети считаются лучшим методом для задач распознавания, особенно тех, которые связаны с изображениями и текстами.
Чтобы написать эту статью, я реализовал полносвязную многоуровневую сеть и архитектуру LeNet 5 в TensorFlow и протестировал на наборе данных MNIST по таким характеристикам как время обучения, время вывода (inference time), точность (accuracy) и потери (loss). А также сравнил полученные показатели с современными методами. Время обучения включает проверку на валидационной выборке после каждой эпохи. Время вывода показывает время, необходимое для вывода результата после вскармливания одного изображения.
Архитектура модели и обучение
Набор данных MNIST состоит из 60 000 обучающих и 10 000 тестовых изображений, широко используемых в качестве эталонного теста классической классификации. Иными словами это “Hello World!” компьютерного зрения.
Изображения MNIST имеют исходный размер (28, 28), но, поскольку ЛеКун использовал входные данные размера (20, 20) и (32, 32, 1) для полносвязной сети и сети LeNet 5 соответственно, в статье я использовал те же параметры. Для этого я изменил размеры изображений MNIST с сохранением соотношения сторон до соответствующих размеров:
import tensorflow as tf
import keras
from keras.datasets import mnist
import numpy as np
import time
import datetime, os
import cv2
seed = 42 # Для воспроизведения результатов
tf.random.set_seed(seed)
np.random.seed(seed)
(X_train, y_train), (X_test, y_test) = mnist.load_data()
X_t=[]
image_size=(32, 32) #Для полносвязной сети используйте (20,20)
for img in X_train:
X_t.append(cv2.resize(img,image_size))
x_test=[]
for img in X_test:
x_test.append(cv2.resize(img, image_size))
X_t=np.array(X_t)
x_test=np.array(x_test)
X_t = X_t.astype("float32") / 255 #Нормализация изображений
x_test = x_test.astype("float32") / 255
x_train = np.expand_dims(X_t, -1) #увелечение размерности
x_test = np.expand_dims(x_test, -1)
y_train = tf.keras.utils.to_categorical(y_train, 10) #one hot encoding
y_test = tf.keras.utils.to_categorical(y_test, 10)
Архитектура полносвязной сети и ее обучение
Архитектура полносвязной сети представлена в статье 1995 года “Comparison of learning algorithms for handwritten digit recognition”. Архитектуру реализации можно увидеть в этой таблице:
|
---|
В таблице — архитектура полносвязной нейронной сети с количеством обучаемых параметров на каждом уровне.
Полносвязная сеть имеет 400, 300 и 10 нейронов на входном, скрытом и выходном слоях соответственно. Первые два слоя можно рассматривать как экстрактор признаков, а последний – как классификатор. Так как в статье, на которую я опирался, авторы не указали какую именно функцию активации они использовали после скрытого слоя, при реализации архитектуры я руководствовался статьей “Comparing different neural network architectures for classifying handwritten digits”, представленной на Международной совместной конференции по нейросетям в 1989 году так как они ссылались на нее. Таким образом, активация выпрямленного линейного блока (ReLU) используется после скрытого слоя, а активация сигмоида используется после выходного слоя.
#Сети тренируются отдельно. Для использывания Полносвязной сети необходимо
#изменить image_size в коде выше на (20, 20)
batch_size_FC = 8
epochs_FC = 40
sgd=tf.keras.optimizers.SGD(learning_rate=0.01)
FullyConnected = tf.keras.models.Sequential()
FullyConnected.add(tf.keras.layers.InputLayer(input_shape=(400,)))
FullyConnected.add(tf.keras.layers.Dense(300, activation='relu'))
FullyConnected.add(tf.keras.layers.Dense(10, activation='sigmoid'))
FullyConnected.summary()
FullyConnected.compile(loss="mse", optimizer=sgd, metrics=["accuracy"])
Кроме того, общее количество обучаемых параметров составляет около 123 310. Модель обучается с использованием оптимизатора стохастического градиентного спуска (SGD) с функцией потерь среднеквадратичной ошибки (MSE). Коэффициент скорости обучения равен 0,01, а сеть была обучена батчами из 8-ми изображений на протяжении 40 эпох.
start_time = time.time()
logdir = os.path.join("logs", datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
tensorboard_callback = tf.keras.callbacks.TensorBoard(logdir, histogram_freq=1)
FullyConnected.fit(x_train, y_train, batch_size=batch_size_FC, epochs=epochs_FC,
validation_data=(x_test, y_test),
callbacks=[tensorboard_callback])
print("Time to train and validate FC network ", time.time() - start_time)
%load_ext tensorboard #Это для TensorBoard-a, для выведения графиков
%tensorboard --logdir logs #Это для TensorBoard-a, для выведения графиков
start_time = time.time()
FullyConnected.predict_step(np.array( [x_test[0]], ) )
print("Inference time of fully connected network ", time.time() - start_time)
Архитектура и обучение LeNet 5
Детальная архитектура LeNet 5 была подробно описана в статье 1998 года “Gradient-based learning applied to document recognition”. В целом, LeNet 5 состоит из пяти обучаемых слоев — трех сверточных (карты признаков ( feature map) размеров 6, 16 и 120) и двух полносвязных. Отсюда и его название LeNet 5.
Каждый сверточный слой имеет ядра размером 5 на 5 и шагом 1. Сверточные слои разделены активацией гиперболического тангенса, слоем среднего пулинга с размером ядра 2 на 2. Вывод последней сверткий имеет размер (1, 1, 120), который ведет дальнейшому полносвязному соединению.
batch_size = 32
epochs = 15
opt=tf.keras.optimizers.SGD(learning_rate=0.001, momentum=0.0,
nesterov=False, name="SGD")
LeNet5 = tf.keras.models.Sequential()
LeNet5.add(tf.keras.layers.Conv2D(6, 5, activation='tanh',
input_shape=x_train.shape[1:]))
LeNet5.add(tf.keras.layers.AveragePooling2D(2))
LeNet5.add(tf.keras.layers.Conv2D(16, 5, activation='tanh'))
LeNet5.add(tf.keras.layers.AveragePooling2D(2))
LeNet5.add(tf.keras.layers.Conv2D(120, 5, activation='tanh'))
LeNet5.add(tf.keras.layers.Flatten())
LeNet5.add(tf.keras.layers.Dense(84, activation='tanh'))
LeNet5.add(tf.keras.layers.Dense(10, activation='softmax'))
LeNet5.summary()
LeNet5.compile(loss="categorical_crossentropy", optimizer=opt,
metrics=["accuracy"])
|
---|
В статье “Gradient-based learning applied to document recognition” авторы использовали увеличенный гиперболический тангенс и активацию евклидовой радиальной базисной функции (Eucledian RBF). Я же для простоты использовал обычный гиперболический тангенс и активацию softmax, а вместо MSE выбрал категориальную функцию кросс-энтропийных потерь. Оптимизатор SGD с коэффициентом скорости обучения (learning rate) 0,001 использовался для обучения сети на протяжении 15 эпох с размером батчей 32. Количество обучаемых параметров – 61 706.
start_time = time.time()
logdir = os.path.join("logs", datetime.datetime.now().strftime("%Y%m%d-%H%M%S"))
tensorboard_callback = tf.keras.callbacks.TensorBoard(logdir, histogram_freq=1)
LeNet5.fit(x_train, y_train, batch_size=batch_size, epochs=epochs,
validation_data=(x_test, y_test), callbacks=[tensorboard_callback])
print("Time to train and LeNet ",
time.time() - start_time)
%load_ext tensorboard #Это для TensorBoard-a, для выведения графиков
%tensorboard --logdir logs #Это для TensorBoard-a, для выведения графиков
start_time = time.time()
LeNet5.predict_step(np.array( [x_test[0]], ) )
print("Inference time of LeNet network ", time.time() - start_time)
LeNet5.evaluate(x_test, y_test)
Результаты
Я сравнивал LeNet 5 и полносвязную сеть с точки зрения времени обучения, времени вывода, точности и потерь. Среда обучения в обеих сетях была одинаковой: Google Colaboratory с ускорителем GPU, Python 3.7 и TensorFlow 2.5. Так выглядят результаты эксперимента:
|
---|
В таблице — результат эксперимента по времени обучения, времени вывода, точности проверки и потери проверки
LeNet 5 имеет время обучения и время вывода быстрее на 440 сек и 0,002 сек соответственно. Быстроту обучение LeNet 5 можно объяснить наличием в 4 раза большего размера батчей и в 2 раза меньшего количества обучаемых параметров. Параллельные вычисления на GPU также способствуют как быстрому обучению LeNet 5, так и скорейшему выводу результата.
На рисунке показано изменение точности и потерь (Loss) моделей на каждой эпохе. Из рисунков (а) и (с) видно, что точность обучения ниже, чем точность проверки для обеих моделей. Кроме того, на рисунках (b) и (d) показаны потери при обучении и валидации для обеих моделей, где потери при обучении выше, чем потери при проверке. В обоих случаях это объясняется тем, что здесь точность тренировки и потери измеряются во время тренировки и за конечный результат берутся средние значения за эпоху. Поскольку в начале тренировки значение точности ниже, а значение потерь выше, результаты валидации получаются выше при условии что не было переобучения.
LeNet 5 достигает на 5 % выше точность валидации. LeNet 5 достигает точности 91,5 % на первой эпохе, в то время как при полносвязной сети этот показатель достигается только к 16-й эпохе. Более того, LeNet 5 с категориальной кросс-энтропийной потерей сходится быстрее, чем полносвязная сеть с MSE. Можно сделать вывод, что обе модели сошлись и переобучения не было обнаружено.
Такая разница в результате точности объясняется тем что в полносвязной сети каждый нейрон присоединен ко всем нейронам в предыдущем слое, где эти нейроны имеют индивидуальные веса. В сверточных слоях, напротив, каждый нейрон присоединен к группе локальных нейронов равному размеру ядра в предыдущем слое, где эти нейроны имеют общий вес. Говоря простым языком, в задачах с изображениями лучше извлекать информацию из группы близлежащих пикселей чем рассматривать каждый пиксель по одному. Точность полносвязной сети может быть увеличена за счет использования других функций потерь — например, категориальной кросс-энтропии вместо MSE или различных оптимизаторов нейронных сетей, таких как Adam, RAdam и т.п.
Если рассматривать время обучения и время вывода на CPU, эти характеристики LeNet 5 могут значительно увеличиться из-за вычислительной дороговизны сверточных слоев. Поэтому, несмотря на внушительные результаты нейронных сетей 90-ых, их бум произошёл с середины 2000-ых годов, в эпоху дешевых производительных мощностей и памяти.
Чем отличаются современные сети?
Во-первых, ЛеКун и другие ученые использовали функции активации гиперболического тангенса, которые страдают от проблем затухания градиента. Современные решения используют функции активации, которые уменьшают возможность проблемы затухающего градиента. Например, выпрямленный линейный блок (ReLu), и различные его модификации типа ELU, Leaky ReLu и другие.
В статье “Gradient-based learning applied to document recognition” авторы использовали разные коэффициенты скорости обучения для разных эпох и слоев LeNet 5. Сейчас этого можно достичь с помощью планировщиков скорости обучения, косинусный отжиг (cosine annealing) и временное уменьшение (Time-based decay) и другие. Чтобы избежать переобучения, авторы статьи использовали специальный модуль, который производил простые аффинные преобразования как сдвиг, масштабирование, вращение и отклонение. К этому списку можно добавить методы другого характера, например, Dropout, регуляризация и продвинутая оптимизация (Adam, RAdam и т.п.)
Хорошим примером использования оптимизации и регуляризации CNN с увеличением данных и ранним остановом (Early Stopping) является статья 2020 года “Stochastic optimization of plain convolutional neural networks with simple methods”. В ней авторы достигли ошибки 0,17 % для MNIST. К такому результату способствовали слои Max Pooling, Dropout после каждого Max Pooling, активация ReLu перед каждым Max Pooling, и техники преобразования как вращение, cдвиг вверх и вниз и ремасштабирование. Одна из особенностей Early Stopping который останавливает тренировки поскольку в случае если модель превосходит бейзлайн.
Большинство современных решений, которые показывают ошибку менее 0,2 %, используют непоследовательную сложную сетевую архитектуру. Они имеет остаточные соединения, подсети и непоследовательную архитектуру поверх вышеупомянутой техники. Например, CNN с однородными векторными капсулами, описанные в статье “No routing needed between capsules”, показывает ошибку MNIST 0,13 %. Эта модель включает в себя многие распространенные практики как активация ReLu, нормализация батчей и свертки ядрами 3×3. Первый сверточный слой использует 32 фильтра, а каждый последующий слой на 16 фильтров больше. Особенность этой работы, вместо классических полносвязных слоев используемых с скалярными нейронами, тут авторы использовали выход сверток без выпрямления (flatten) с векторнозначными нейронами (капсулы). Так же после 3 последовательных сверток сеть разветвлялась на два отделения где в одном были капсулы и в другом 3 свертки, которые таким же образом разветвлялись. Капсулы умножаются покомпонентно с векторами весов равному количеству классов. Таким образом генерируются logits каждого ответвления, они, 3 вектора logits, в последующих слоях будут сложены и уменьшены до вектора размерностью 3. Последний слой softmax с logits применяется для классификации. Другой пример сложных сетей – EnsNet, представленный в статье “Ensemble learning in CNN augmented with fully connected subnetworks”. Он использует преимущества максимального пулинга, использование полносвязных подсетей и голосование большинством для достижения ошибки 0,16 %.
Важно понимать, чем отличаются разные архитектуры и какая особенность этих сетей позволяет достичь лучшего результата. Все эти методы следует учитывать при рассмотрении архитектуры и улучшении точности модели.
Заключение
Проблема классификации – одна из основных проблем в области машинного обучения. При сравнении полноcвязной многоуровневой нейронной сети и архитектуры сети LeNet 5 по таким характеристикам как точность, потери, время обучения и вывода результата, я обнаружил, что LeNet 5 имеет точность валидации выше на 5 %, время обучения быстрее на 440 секунд и время вывода результата короче на 0,002 секунд. Хотя LeNet 5 быстрее на устройствах с графическим процессором из-за меньшего количества обучаемых параметров, на CPU может потребоваться больше времени для обучения и составления прогнозов. Кроме того, я проанализировал графики потерь и точности на каждой эпохе и сделал вывод, что обе сети сошлись без переобучения.
В качестве методов улучшения текущих характеристик можно пользоваться простыми методами:
-
Dropout;
-
нормализация батчей;
-
методы увеличения и расширения выборки;
-
продвинутая оптимизация;
-
функции активации подобные ReLu.
Также можно воспользоваться сложными методами: подсетевое и капсульное мажоритарное голосование.
Важно помнить, что вышеописанные методы нужно добавлять последовательно, поскольку сочетание разных методов может как улучшить, так и ухудшить качество модели.
Какие статьи я изучил перед тем, как писать материал
-
MNIST handwritten digit database, Y. LeCun, C. Cortes, and C. Burges, ATT Labs, vol. 2, 2010.
-
Comparison of learning algorithms for handwritten digit recognition, Y. LeCun, L. Jackel, L. Bottou, A. Brunot, C. Cortes, J. Denker, H. Drucker, I. Guyon, U. Muller, E. Sackinger, P. Simard, and V. Vapnik, 01, 1995.
-
Comparing different neural network architectures for classifying handwritten digits, I. Guyon, I. Poujaud, L. Personnaz, G. Dreyfus, J. Denker, and Y. LeCun, International 1989 Joint Conference on Neural Networks, 1989, pp. 127–132, vol. 2.
-
Gradient-based learning applied to document recognition, Y. LeCun, L. Bottou, Y. Bengio, and P. Haffner, Proceedings of the IEEE, vol. 86, no. 11, pp. 2278–2324, 1998.
-
Fast and accurate deep network learning by exponential linear units (elus), D.-A. Clevert, T. Unterthiner, and S. Hochreiter, 2016.
-
Deep sparse rectifier neural networks, X. Glorot, A. Bordes, and Y. Bengio, in Proceedings of the Fourteenth International Conference on Artificial Intelligence and Statistics, ser. Proceedings of Machine Learning Research.
-
Sgdr: Stochastic gradient descent with warm restarts, I. Loshchilov and F. Hutter, 2017.
-
Adam: A method for stochastic optimization, D. P. Kingma and J. Ba, 2017.
-
On the variance of the adaptive learning rate and beyond, L. Liu, H. Jiang, P. He, W. Chen, X. Liu, J. Gao, and J. Han, ArXiv, vol. abs/1908.03265, 2020.
-
Imagenet classification with deep convolutional neural networks, A. Krizhevsky, I. Sutskever, and G. E. Hinton, in Advances in Neural Information Processing Systems, F. Pereira, C. J. C. Burges, L. Bottou, and K. Q. Weinberger, Eds., vol. 25. CurranAssociates, Inc., 2012.
-
Rethinking the inception architecture for computer vision, C. Szegedy, V. Vanhoucke, S. Ioffe, J. Shlens, and Z. Wojna, 2015.
-
Stochastic optimization of plain convolutional neural networks with simple methods, Y. Assiri, 2020.
-
No routing needed between capsules, A. Byerly, T. Kalganova, and I. Dear, 2021.
-
Ensemble learning in CNN augmented with fully connected subnetworks, D. Hirata and N. Takahashi, 2020.