Привет! Меня зовут Елдар, я – 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 с сохранением соотношения сторон до соответствующих размеров:

Это примеры изображений набора данных MNIST разного размера: (a) (28, 28), (b) (20, 20) и (c) (32, 32)
Это примеры изображений набора данных MNIST разного размера: (a) (28, 28), (b) (20, 20) и (c) (32, 32)
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)

0

Скрытый

(, 300)

120 300

Выходной

(, 10)

3 010

В таблице — архитектура полносвязной нейронной сети с количеством обучаемых параметров на каждом уровне.

Полносвязная сеть имеет 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"])

Тип слоя

Размер вывода

Количество параметров

Свертка

(, 28, 28, 6)

156

Средний пулинг

(,14, 14, 6)

0

Свертка

(,10, 10, 16)

2 416

Средний пулинг

(, 5, 5, 16)

0

Свертка

(,1, 1, 120)

48 120

Полносвязный

(, 84)

10 164

Полносвязный

(, 10)

850

В статье “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. Так выглядят результаты эксперимента:

Model Name

Время обучения (s)

Время вывода (s)

Accuracy (%)

Loss (%)

Полносвязная

562.74

0.009

0.935

0.123

LeNet 5

122.72

0.006

0.985

0.043

В таблице — результат эксперимента по времени обучения, времени вывода, точности проверки и потери проверки

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.

Также можно воспользоваться сложными методами: подсетевое и капсульное мажоритарное голосование.

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

Какие статьи я изучил перед тем, как писать материал

  1. MNIST handwritten digit database, Y. LeCun, C. Cortes, and C. Burges, ATT Labs, vol. 2, 2010.

  2. 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.

  3. 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.

  4. 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.

  5. Fast and accurate deep network learning by exponential linear units (elus), D.-A. Clevert, T. Unterthiner, and S. Hochreiter, 2016.

  6. 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.

  7. Sgdr: Stochastic gradient descent with warm restarts, I. Loshchilov and F. Hutter, 2017.

  8. Adam: A method for stochastic optimization, D. P. Kingma and J. Ba, 2017.

  9. 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.

  10. 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.

  11. Rethinking the inception architecture for computer vision, C. Szegedy, V. Vanhoucke, S. Ioffe, J. Shlens, and Z. Wojna, 2015.

  12. Stochastic optimization of plain convolutional neural networks with simple methods, Y. Assiri, 2020.

  13. No routing needed between capsules, A. Byerly, T. Kalganova, and I. Dear, 2021.

  14. Ensemble learning in CNN augmented with fully connected subnetworks, D. Hirata and N. Takahashi, 2020.

Комментарии (4)


  1. toxano
    20.01.2022 08:42

    Есть вопрос касательно время вывода. К примеру, есть библиотека распознавания и готовая модель. Настраиваем на сервере и все работает. Вот только время вывода желает лучшего. Какие способы существуют для ускорения?


    1. YeldarT Автор
      20.01.2022 10:38
      +2

      Доброго времени суток. Есть несколько решений данной проблемы, но важно понимать что ускорить модель без потерь в accuracy довольно сложно.

      Популярный метод который доказывает свою эффективность на практике это Квантование (Quantization https://arxiv.org/pdf/2103.13630.pdf), поскольку сразу решает две проблемы: облегчает модель и ускоряет время вывода. Осуществляется по принципу округления значений весов на более низкий уровень. Например, использовать числа половинной точности вместо чисел двойной точности.

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

      Методы выше можно применять без обучения, но если рассматривать возможность обучения новых моделей то Knowledge distillation стоит рассмотреть обязательно. Эта техника подразумевает использование тяжёлой модели в роли "учителя" и тренировки легкой модели как "ученика". Преимуществом данного метода является возможность использования неразмеченных данных в обучении.


      1. toxano
        20.01.2022 13:03

        Как понял. Квантованием обычно понижается количество чисел после запятой, получаем понижение потребление памяти и ускорение вычислений. Обрезкой удаляем не критичные части. Дистилляцией выжимаем главное. Но как понимаю они работаю при создании новой модели и с потерей качества. Если ли способы ускорения внешнего воздействия при уже имеющийся модели?


  1. Bersano
    20.01.2022 15:15
    -1

    Мне кажется правильнее было бы сравнивать полносвязную сеть с CNN, используя одни и те же функции потерь. Но вообще, как мне кажется, такое сравнение не соберёт большого внимания, т.к. на сегодня есть сети точнее и куда более интереснее, чем LeNet или FCNN