1. Обзор
Это руководство было обновлено для Tensorflow 2.2!
В этой лаборатории вы узнаете, как построить и обучить нейронную сеть, распознающую рукописные цифры. Попутно, улучшая свою нейронную сеть для достижения точности 99%, вы также откроете для себя профессиональные инструменты, которые специалисты по глубокому обучению используют для эффективного обучения своих моделей.
В этой кодовой лаборатории используется набор данных MNIST , коллекция из 60 000 размеченных цифр, которая заставляла работать поколения докторов наук в течение почти двух десятилетий. Вы решите проблему, используя менее 100 строк кода Python/TensorFlow.
Что вы узнаете
- Что такое нейронная сеть и как ее обучать
- Как построить базовую однослойную нейронную сеть с помощью tf.keras
- Как добавить больше слоев
- Как настроить график обучения
- Как построить сверточные нейронные сети
- Как использовать методы регуляризации: отсев, пакетная нормализация
- Что такое переоснащение
Что вам понадобится
Просто браузер. Этот семинар можно полностью провести с помощью Google Colaboratory.
Обратная связь
Пожалуйста, сообщите нам, если вы заметили в этой лаборатории что-то не так или считаете, что ее следует улучшить. Мы обрабатываем отзывы через выпуски GitHub [ ссылка на отзыв ].
2. Быстрый старт Google Colaboratory
Эта лаборатория использует Google Colaboratory и не требует никакой настройки с вашей стороны. Вы можете запустить его с Chromebook. Откройте файл ниже и заполните ячейки, чтобы ознакомиться с блокнотами Colab.
Дополнительные инструкции ниже:
Выберите серверную часть графического процессора
В меню Colab выберите «Время выполнения» > «Изменить тип среды выполнения» , а затем выберите «Графический процессор». Подключение к среде выполнения произойдет автоматически при первом запуске, или вы можете использовать кнопку «Подключиться» в правом верхнем углу.
Исполнение ноутбука
Выполняйте ячейки по одной, щелкая ячейку и используя Shift-ENTER. Вы также можете запустить весь блокнот, выбрав «Среда выполнения» > «Выполнить все».
Оглавление
Все тетради имеют оглавление. Открыть его можно с помощью черной стрелки слева.
Скрытые ячейки
В некоторых ячейках будет отображаться только заголовок. Это функция блокнота, специфичная для Colab. Вы можете дважды щелкнуть по ним, чтобы увидеть код внутри, но обычно это не очень интересно. Обычно функции поддержки или визуализации. Вам все равно нужно запустить эти ячейки, чтобы определить функции внутри.
3. Обучите нейронную сеть
Сначала мы будем наблюдать за поездом нейронной сети. Пожалуйста, откройте блокнот ниже и просмотрите все ячейки. На код пока не обращайте внимания, объяснять его мы начнем позже.
Работая с блокнотом, сосредоточьтесь на визуализациях. См. пояснения ниже.
Данные обучения
У нас есть набор данных из рукописных цифр, которые были помечены так, чтобы мы знали, что представляет собой каждая картинка, то есть число от 0 до 9. В блокноте вы увидите отрывок:
Нейронная сеть, которую мы построим, классифицирует рукописные цифры по 10 классам (0, .., 9). Это делается на основе внутренних параметров, которые должны иметь правильное значение, чтобы классификация работала хорошо. Это «правильное значение» изучается в процессе обучения, для которого требуется «маркированный набор данных» с изображениями и соответствующими правильными ответами.
Как мы узнаем, хорошо ли работает обученная нейронная сеть? Использование набора обучающих данных для тестирования сети было бы мошенничеством. Он уже несколько раз видел этот набор данных во время обучения и, безусловно, очень эффективен на нем. Нам нужен еще один размеченный набор данных, который никогда не использовался во время обучения, чтобы оценить «реальную» производительность сети. Это называется « набор данных проверки ».
Обучение
По мере обучения по одной партии обучающих данных обновляются внутренние параметры модели, и модель становится все лучше и лучше распознавать рукописные цифры. Вы можете увидеть это на графике обучения:
Справа «точность» — это просто процент правильно распознанных цифр. По мере обучения он увеличивается, и это хорошо.
Слева мы видим «потерю» . Для управления обучением мы определим функцию «потери», которая показывает, насколько плохо система распознает цифры, и постараемся ее минимизировать. Здесь вы видите, что по мере обучения потери уменьшаются как в обучающих, так и в проверочных данных: это хорошо. Это означает, что нейронная сеть учится.
Ось X представляет количество «эпох» или итераций во всем наборе данных.
Прогнозы
Когда модель обучена, мы можем использовать ее для распознавания рукописных цифр. Следующая визуализация показывает, насколько хорошо он работает с несколькими цифрами, отображаемыми из локальных шрифтов (первая строка), а затем с 10 000 цифрами набора проверочных данных. Прогнозируемый класс отображается под каждой цифрой и красным цветом, если он неправильный.
Как видите, эта первоначальная модель не очень хороша, но некоторые цифры все же распознает правильно. Его окончательная точность проверки составляет около 90%, что не так уж и плохо для упрощенной модели, с которой мы начинаем, но это все равно означает, что она пропускает 1000 проверочных цифр из 10 000. Это гораздо больше, что можно отобразить, поэтому кажется, что все ответы неверны (красный).
Тензоры
Данные хранятся в матрицах. Изображение в оттенках серого размером 28x28 пикселей помещается в двумерную матрицу 28x28. Но для цветного изображения нам нужно больше размеров. На пиксель приходится 3 значения цвета (красный, зеленый, синий), поэтому понадобится трехмерная таблица с размерами [28, 28, 3]. А для хранения пакета из 128 цветных изображений необходима четырехмерная таблица с размерами [128, 28, 28, 3].
Эти многомерные таблицы называются «тензорами» , а список их измерений — это их «форма» .
4. [ИНФО]: нейронные сети 101
В двух словах
Если все термины, выделенные жирным шрифтом в следующем абзаце, вам уже известны, можно переходить к следующему упражнению. Если вы только начинаете глубокое обучение, добро пожаловать и читайте дальше.
Для моделей, построенных как последовательность слоев, Keras предлагает Sequential API. Например, классификатор изображений, использующий три плотных слоя, можно записать в Keras как:
model = tf.keras.Sequential([
tf.keras.layers.Flatten(input_shape=[28, 28, 1]),
tf.keras.layers.Dense(200, activation="relu"),
tf.keras.layers.Dense(60, activation="relu"),
tf.keras.layers.Dense(10, activation='softmax') # classifying into 10 classes
])
# this configures the training of the model. Keras calls it "compiling" the model.
model.compile(
optimizer='adam',
loss= 'categorical_crossentropy',
metrics=['accuracy']) # % of correct answers
# train the model
model.fit(dataset, ... )
Один плотный слой
Рукописные цифры в наборе данных MNIST представляют собой изображения в оттенках серого размером 28x28 пикселей. Самый простой подход к их классификации — использовать 28x28=784 пикселей в качестве входных данных для однослойной нейронной сети.
Каждый «нейрон» в нейронной сети вычисляет взвешенную сумму всех своих входных данных, добавляет константу, называемую «смещением», а затем передает результат через некоторую нелинейную «функцию активации» . «Веса» и «предвзятости» — это параметры, которые будут определены в ходе обучения. Сначала они инициализируются случайными значениями.
На рисунке выше представлена однослойная нейронная сеть с 10 выходными нейронами, поскольку мы хотим классифицировать цифры по 10 классам (от 0 до 9).
С помощью матричного умножения
Вот как слой нейронной сети, обрабатывающий коллекцию изображений, можно представить путем умножения матриц:
Используя первый столбец весов в матрице весов W, мы вычисляем взвешенную сумму всех пикселей первого изображения. Эта сумма соответствует первому нейрону. Используя второй столбец весов, делаем то же самое для второго нейрона и так далее до 10-го нейрона. Затем мы можем повторить операцию для оставшихся 99 изображений. Если мы назовем X матрицей, содержащей наши 100 изображений, все взвешенные суммы для наших 10 нейронов, вычисленные по 100 изображениям, будут просто XW, умножением матрицы.
Теперь каждый нейрон должен добавить свое смещение (константу). Поскольку у нас 10 нейронов, у нас есть 10 констант смещения. Мы назовем этот вектор из 10 значений b. Его необходимо добавить к каждой строке ранее вычисленной матрицы. Используя немного магии под названием «трансляция», мы запишем это простым знаком плюс.
Наконец, мы применяем функцию активации, например «softmax» (поясняется ниже), и получаем формулу, описывающую однослойную нейронную сеть, примененную к 100 изображениям:
В Керасе
С библиотеками нейронных сетей высокого уровня, такими как Keras, нам не понадобится реализовывать эту формулу. Однако важно понимать, что слой нейронной сети — это всего лишь набор умножений и сложений. В Keras плотный слой будет записан как:
tf.keras.layers.Dense(10, activation='softmax')
Иди глубже
Соединить слои нейронной сети в цепочку тривиально. Первый уровень вычисляет взвешенные суммы пикселей. Последующие уровни вычисляют взвешенные суммы выходных данных предыдущих слоев.
Единственная разница, помимо количества нейронов, будет заключаться в выборе функции активации.
Функции активации: relu, softmax и сигмоида
Обычно вы используете функцию активации «relu» для всех слоев, кроме последнего. Последний уровень классификатора будет использовать активацию «softmax».
Опять же, «нейрон» вычисляет взвешенную сумму всех своих входных данных, добавляет значение, называемое «смещением», и передает результат через функцию активации.
Самая популярная функция активации называется «RELU» (выпрямленная линейная единица). Это очень простая функция, как вы можете видеть на графике выше.
Традиционной функцией активации в нейронных сетях была «сигмовидная» , но было показано, что «relu» имеет лучшие свойства сходимости почти везде и теперь является предпочтительным.
Активация Softmax для классификации
Последний слой нашей нейронной сети имеет 10 нейронов, потому что мы хотим классифицировать рукописные цифры по 10 классам (0,..9). Он должен вывести 10 чисел от 0 до 1, представляющих вероятность того, что эта цифра будет 0, 1, 2 и так далее. Для этого на последнем слое мы будем использовать функцию активации под названием «softmax» .
Применение softmax к вектору осуществляется путем взятия экспоненты каждого элемента и последующей нормализации вектора, обычно путем деления его на норму «L1» (т. е. сумму абсолютных значений), так что нормализованные значения в сумме составляют 1 и могут интерпретироваться как вероятности.
Выходные данные последнего слоя перед активацией иногда называют «логитами» . Если этот вектор L = [L0, L1, L2, L3, L4, L5, L6, L7, L8, L9], то:
Перекрестная энтропийная потеря
Теперь, когда наша нейронная сеть выдает прогнозы на основе входных изображений, нам нужно измерить, насколько они хороши, то есть расстояние между тем, что нам сообщает сеть, и правильными ответами, часто называемыми «метками». Помните, что у нас есть правильные метки для всех изображений в наборе данных.
Подойдет любое расстояние, но для задач классификации наиболее эффективным является так называемое «перекрестное энтропийное расстояние». Мы назовем это нашей функцией ошибки или «потери»:
Градиентный спуск
«Обучение» нейронной сети на самом деле означает использование обучающих изображений и меток для корректировки весов и смещений, чтобы минимизировать функцию перекрестных энтропийных потерь. Вот как это работает.
Перекрестная энтропия — это функция весов, смещений, пикселей обучающего изображения и его известного класса.
Если мы вычислим частные производные перекрестной энтропии относительно всех весов и всех смещений, мы получим «градиент», рассчитанный для данного изображения, метки и текущего значения весов и смещений. Помните, что у нас могут быть миллионы весов и смещений, поэтому вычисление градиента кажется большой работой. К счастью, TensorFlow делает это за нас. Математическое свойство градиента заключается в том, что он направлен «вверх». Поскольку мы хотим пойти туда, где перекрестная энтропия низкая, мы идем в противоположном направлении. Мы обновляем веса и смещения на долю градиента. Затем мы делаем то же самое снова и снова, используя следующие партии обучающих изображений и меток в цикле обучения. Будем надеяться, что это приведет к тому, что перекрестная энтропия будет минимальной, хотя ничто не гарантирует, что этот минимум уникален.
Мини-пакетирование и импульс
Вы можете вычислить градиент только на одном примере изображения и немедленно обновить веса и смещения, но если сделать это, например, на пакете из 128 изображений, вы получите градиент, который лучше отражает ограничения, налагаемые различными примерами изображений, и, следовательно, с большой вероятностью сходится. к решению быстрее. Размер мини-партии является регулируемым параметром.
Этот метод, иногда называемый «стохастическим градиентным спуском», имеет еще одно, более прагматичное преимущество: работа с пакетами также означает работу с матрицами большего размера, и их обычно легче оптимизировать на графических процессорах и TPU.
Однако сходимость все еще может быть немного хаотичной и может даже прекратиться, если вектор градиента будет равен нулю. Означает ли это, что мы нашли минимум? Не всегда. Компонент градиента может быть равен нулю в минимуме или максимуме. Для вектора градиента с миллионами элементов, если все они нули, вероятность того, что каждый ноль соответствует минимальной точке и ни один из них не соответствует максимальной точке, довольно мала. В пространстве многих измерений седловые точки встречаются довольно часто, и мы не хотим на них останавливаться.
Иллюстрация: седловая точка. Градиент равен 0, но не является минимальным во всех направлениях. (Атрибуция изображения Wikimedia: Никогуаро — собственная работа, CC BY 3.0 )
Решение состоит в том, чтобы добавить некоторый импульс алгоритму оптимизации, чтобы он мог проходить мимо седловых точек без остановки.
Глоссарий
пакет или мини-пакет : обучение всегда выполняется на пакетах обучающих данных и меток. Это помогает алгоритму сходиться. «Пакетное» измерение обычно является первым измерением тензоров данных. Например, тензор формы [100, 192, 192, 3] содержит 100 изображений размером 192x192 пикселей с тремя значениями на пиксель (RGB).
перекрестная энтропийная потеря : специальная функция потерь, часто используемая в классификаторах.
плотный слой : слой нейронов, где каждый нейрон связан со всеми нейронами предыдущего слоя.
функции : входы нейронной сети иногда называют «функциями». Искусство определения того, какие части набора данных (или комбинации частей) необходимо передать в нейронную сеть для получения хороших прогнозов, называется «инжинирингом функций».
метки : другое название «классов» или правильных ответов в задаче контролируемой классификации.
скорость обучения : доля градиента, с помощью которой веса и смещения обновляются на каждой итерации цикла обучения.
логиты : выходные данные слоя нейронов до применения функции активации называются «логитами». Этот термин происходит от «логистической функции», также известной как «сигмовидная функция», которая раньше была самой популярной функцией активации. «Выходы нейронов перед логистической функцией» были сокращены до «логитов».
loss : функция ошибок, сравнивающая выходные данные нейронной сети с правильными ответами.
нейрон : вычисляет взвешенную сумму своих входных данных, добавляет смещение и передает результат через функцию активации.
горячее кодирование : класс 3 из 5 кодируется как вектор из 5 элементов, все нули, кроме третьего, который равен 1.
relu : выпрямленная линейная единица. Популярная функция активации нейронов.
sigmoid : еще одна функция активации, которая раньше была популярна и до сих пор полезна в особых случаях.
softmax : специальная функция активации, которая действует на вектор, увеличивает разницу между самым большим компонентом и всеми остальными, а также нормализует вектор, чтобы его сумма была равна 1, чтобы его можно было интерпретировать как вектор вероятностей. Используется как последний шаг в классификаторах.
тензор : «Тензор» похож на матрицу, но с произвольным числом измерений. Одномерный тензор — это вектор. Двумерный тензор является матрицей. И тогда у вас могут быть тензоры с 3, 4, 5 или более измерениями.
5. Давайте перейдем к коду
Вернемся к учебной тетради и на этот раз давайте прочитаем код.
Давайте пройдемся по всем ячейкам в этом блокноте.
Ячейка «Параметры»
Здесь определяется размер пакета, количество эпох обучения и расположение файлов данных. Файлы данных размещаются в корзине Google Cloud Storage (GCS), поэтому их адрес начинается с gs://
Ячейка «Импорт»
Сюда импортированы все необходимые библиотеки Python, включая TensorFlow, а также matplotlib для визуализаций.
Ячейка " Утилиты визуализации [RUN ME]****"
Эта ячейка содержит неинтересный код визуализации. По умолчанию он свернут, но вы можете открыть его и просмотреть код, когда у вас будет время, дважды щелкнув по нему.
Ячейка « tf.data.Dataset: анализ файлов и подготовка наборов данных для обучения и проверки »
Эта ячейка использовала API tf.data.Dataset для загрузки набора данных MNIST из файлов данных. На эту ячейку не обязательно тратить слишком много времени. Если вас интересует API tf.data.Dataset, вот руководство, которое его объясняет: Конвейеры данных со скоростью TPU . На данный момент основы таковы:
Изображения и метки (правильные ответы) из набора данных MNIST хранятся в записях фиксированной длины в 4 файлах. Файлы могут быть загружены с помощью специальной функции фиксированной записи:
imagedataset = tf.data.FixedLengthRecordDataset(image_filename, 28*28, header_bytes=16)
Теперь у нас есть набор данных байтов изображения. Их необходимо расшифровать в изображения. Мы определяем функцию для этого. Изображение не сжимается, поэтому функции не нужно ничего декодировать ( decode_raw
практически ничего не делает). Затем изображение преобразуется в значения с плавающей запятой от 0 до 1. Здесь мы могли бы изменить его форму как 2D-изображение, но на самом деле мы сохраняем его как плоский массив пикселей размером 28 * 28, потому что это то, что ожидает наш первоначальный плотный слой.
def read_image(tf_bytestring):
image = tf.io.decode_raw(tf_bytestring, tf.uint8)
image = tf.cast(image, tf.float32)/256.0
image = tf.reshape(image, [28*28])
return image
Мы применяем эту функцию к набору данных, используя .map
, и получаем набор данных изображений:
imagedataset = imagedataset.map(read_image, num_parallel_calls=16)
Мы выполняем такое же чтение и декодирование для меток и .zip
изображения и метки вместе:
dataset = tf.data.Dataset.zip((imagedataset, labelsdataset))
Теперь у нас есть набор пар данных (изображение, метка). Это то, что ожидает наша модель. Мы пока не совсем готовы использовать его в функции обучения:
dataset = dataset.cache()
dataset = dataset.shuffle(5000, reshuffle_each_iteration=True)
dataset = dataset.repeat()
dataset = dataset.batch(batch_size)
dataset = dataset.prefetch(tf.data.experimental.AUTOTUNE)
API tf.data.Dataset имеет все необходимые служебные функции для подготовки наборов данных:
.cache
кэширует набор данных в оперативной памяти. Это крошечный набор данных, поэтому он будет работать. .shuffle
перемешивает его с буфером в 5000 элементов. Важно, чтобы данные обучения были хорошо перетасованы. .repeat
зацикливает набор данных. Мы будем тренироваться на нем несколько раз (несколько эпох). .batch
объединяет несколько изображений и меток в мини-пакет. Наконец, .prefetch
может использовать ЦП для подготовки следующего пакета, пока текущий пакет обучается на графическом процессоре.
Набор данных проверки готовится аналогичным образом. Теперь мы готовы определить модель и использовать этот набор данных для ее обучения.
Ячейка «Модель Керас»
Все наши модели будут представлять собой прямые последовательности слоев, поэтому мы можем использовать стиль tf.keras.Sequential
для их создания. Изначально здесь это один плотный слой. У него 10 нейронов, потому что мы классифицируем рукописные цифры на 10 классов. Он использует активацию «softmax», поскольку это последний уровень классификатора.
Модель Keras также должна знать форму своих входных данных. tf.keras.layers.Input
можно использовать для его определения. Здесь входные векторы представляют собой плоские векторы значений пикселей длиной 28*28.
model = tf.keras.Sequential(
[
tf.keras.layers.Input(shape=(28*28,)),
tf.keras.layers.Dense(10, activation='softmax')
])
model.compile(optimizer='sgd',
loss='categorical_crossentropy',
metrics=['accuracy'])
# print model layers
model.summary()
# utility callback that displays training curves
plot_training = PlotTraining(sample_rate=10, zoom=1)
Настройка модели выполняется в Keras с помощью функции model.compile
. Здесь мы используем базовый оптимизатор 'sgd'
(стохастический градиентный спуск). Модель классификации требует функции потерь перекрестной энтропии, называемой 'categorical_crossentropy'
в Keras. Наконец, мы просим модель вычислить показатель 'accuracy'
, который представляет собой процент правильно классифицированных изображений.
Keras предлагает очень хорошую утилиту model.summary()
, которая печатает детали созданной вами модели. Ваш добрый инструктор добавил утилиту PlotTraining
(определенную в ячейке «Утилиты визуализации»), которая будет отображать различные кривые обучения во время обучения.
Ячейка «Обучение и проверка модели»
Здесь происходит обучение путем вызова model.fit
и передачи наборов данных обучения и проверки. По умолчанию Keras запускает раунд проверки в конце каждой эпохи.
model.fit(training_dataset, steps_per_epoch=steps_per_epoch, epochs=EPOCHS,
validation_data=validation_dataset, validation_steps=1,
callbacks=[plot_training])
В Keras можно добавлять собственные варианты поведения во время обучения с помощью обратных вызовов. Именно так для данного семинара был реализован динамически обновляемый обучающий график.
Ячейка «Визуализация прогнозов»
После обучения модели мы можем получать от нее прогнозы, вызывая model.predict()
:
probabilities = model.predict(font_digits, steps=1)
predicted_labels = np.argmax(probabilities, axis=1)
В качестве теста мы подготовили набор печатных цифр, отрисованных из местных шрифтов. Помните, что нейронная сеть возвращает вектор из 10 вероятностей из своего окончательного «softmax». Чтобы получить метку, нам нужно выяснить, какая вероятность является наивысшей. np.argmax
из библиотеки numpy делает это.
Чтобы понять, зачем нужен параметр axis=1
, помните, что мы обработали пакет из 128 изображений, и поэтому модель возвращает 128 векторов вероятностей. Форма выходного тензора: [128, 10]. Мы вычисляем argmax по 10 вероятностям, возвращаемым для каждого изображения, таким образом, axis=1
(первая ось равна 0).
Эта простая модель уже распознает 90% цифр. Неплохо, но теперь вы значительно улучшите это.
6. Добавляем слои
Чтобы повысить точность распознавания, мы добавим в нейронную сеть больше слоев.
Мы оставляем softmax в качестве функции активации на последнем слое, потому что она лучше всего подходит для классификации. Однако на промежуточных слоях мы будем использовать самую классическую функцию активации: сигмовидную:
Например, ваша модель может выглядеть так (не забудьте запятые, tf.keras.Sequential
принимает список слоев, разделенных запятыми):
model = tf.keras.Sequential(
[
tf.keras.layers.Input(shape=(28*28,)),
tf.keras.layers.Dense(200, activation='sigmoid'),
tf.keras.layers.Dense(60, activation='sigmoid'),
tf.keras.layers.Dense(10, activation='softmax')
])
Посмотрите на «резюме» вашей модели. Теперь у него как минимум в 10 раз больше параметров. Должно быть в 10 раз лучше! Но почему-то это не так...
Потеря, кажется, тоже пронзила крышу. Что-то не совсем так.
7. Особая забота о глубоких сетях
Вы только что познакомились с нейронными сетями в том виде, в каком их проектировали в 80-х и 90-х годах. Неудивительно, что от этой идеи отказались, начав так называемую «зиму ИИ». Действительно, по мере добавления слоев нейронным сетям становится все труднее сходиться.
Оказывается, глубокие нейронные сети со многими слоями (20, 50, даже 100 сегодня) могут работать очень хорошо, если прибегнуть к паре математических трюков, чтобы заставить их сходиться. Открытие этих простых приемов стало одной из причин возрождения глубокого обучения в 2010-х годах.
РЕЛУ активация
Функция активации сигмовидной кишки на самом деле весьма проблематична в глубоких сетях. Он сжимает все значения от 0 до 1, и если вы делаете это неоднократно, выходные сигналы нейронов и их градиенты могут полностью исчезнуть. Это было упомянуто по историческим причинам, но в современных сетях используется RELU (выпрямленная линейная единица), которая выглядит следующим образом:
С другой стороны, relu имеет производную 1, по крайней мере, в правой части. При активации RELU, даже если градиенты, исходящие от некоторых нейронов, могут быть нулевыми, всегда найдутся другие, дающие явный ненулевой градиент, и тренировка может продолжаться в хорошем темпе.
Лучший оптимизатор
В очень многомерных пространствах, подобных этому — у нас порядка 10 тысяч весов и смещений — часто встречаются «седлые точки». Это точки, которые не являются локальными минимумами, но в которых градиент, тем не менее, равен нулю, и оптимизатор градиентного спуска остается там. TensorFlow имеет полный набор доступных оптимизаторов, в том числе те, которые работают с некоторой инерцией и безопасно преодолевают седловые точки.
Случайные инициализации
Искусство инициализации смещений весов перед тренировкой само по себе является областью исследований, по этой теме опубликовано множество статей. Вы можете посмотреть все инициализаторы, доступные в Keras, здесь . К счастью, Keras по умолчанию поступает правильно и использует инициализатор 'glorot_uniform'
который является лучшим почти во всех случаях.
Вам делать нечего, так как Керас уже делает правильные вещи.
НЭН ???
Формула перекрестной энтропии включает логарифм, а log(0) — это не число (NaN, числовой сбой, если хотите). Может ли ввод перекрестной энтропии быть равен 0? Входные данные поступают от softmax, который по сути является экспонентой, а экспонента никогда не равна нулю. Значит, мы в безопасности!
Действительно? В прекрасном мире математики мы были бы в безопасности, но в компьютерном мире exp(-150), представленный в формате float32, равен НУЛЮ, насколько это возможно, и перекрестная энтропия рушится.
К счастью, вам здесь тоже нечего делать, поскольку Keras позаботится об этом и вычисляет softmax, а затем кросс-энтропию особенно осторожным способом, чтобы обеспечить числовую стабильность и избежать ужасных NaN.
Успех?
Теперь вы должны достичь точности 97%. Цель этого семинара — значительно превысить 99%, так что давайте продолжим.
Если вы застряли, вот решение на этом этапе:
8. Снижение скорости обучения
Может, попробуем тренироваться быстрее? Скорость обучения по умолчанию в оптимизаторе Адама составляет 0,001. Попробуем увеличить.
Кажется, что увеличение скорости не очень помогает, и что это за шум?
Кривые обучения очень зашумлены и выглядят как кривые проверки: они прыгают вверх и вниз. Это означает, что мы движемся слишком быстро. Мы могли бы вернуться к прежней скорости, но есть лучший способ.
Хорошее решение — начать быстро и экспоненциально снижать скорость обучения. В Keras это можно сделать с помощью обратного вызова tf.keras.callbacks.LearningRateScheduler
.
Полезный код для копирования:
# lr decay function
def lr_decay(epoch):
return 0.01 * math.pow(0.6, epoch)
# lr schedule callback
lr_decay_callback = tf.keras.callbacks.LearningRateScheduler(lr_decay, verbose=True)
# important to see what you are doing
plot_learning_rate(lr_decay, EPOCHS)
Не забудьте использовать созданный вами lr_decay_callback
. Добавьте его в список обратных вызовов в model.fit
:
model.fit(..., callbacks=[plot_training, lr_decay_callback])
Эффект этого небольшого изменения впечатляет. Вы видите, что большая часть шума исчезла, и точность теста теперь стабильно превышает 98%.
9. Отсев, переобучение
Кажется, что сейчас модель хорошо сходится. Попробуем пойти еще глубже.
Это помогает?
Не совсем, точность по-прежнему составляет 98%, и посмотрите на потери при проверке. Оно растет! Алгоритм обучения работает только с обучающими данными и соответствующим образом оптимизирует потери при обучении. Он никогда не видит данные проверки, поэтому неудивительно, что через некоторое время его работа больше не влияет на потерю проверки, которая перестает падать, а иногда даже отскакивает.
Это не сразу влияет на возможности распознавания реального мира вашей модели, но это помешает вам выполнять много итераций и, как правило, является признаком того, что обучение больше не имеет положительного эффекта.
Это отключение обычно называется «пережитка», и когда вы видите его, вы можете попытаться применить технику регуляризации под названием «Dropout». Техника отсева стреляет случайными нейронами на каждой тренировочной итерации.
Это сработало?
Шум появляется вновь (неудивительно, учитывая, как работает выпадение). Потеря проверки, кажется, больше не ползуется, но в целом она выше, чем без отсева. И точность проверки немного снизилась. Это довольно разочаровывающий результат.
Похоже, что отсечение не было правильным решением, или, может быть, «переосмысление» - более сложная концепция, и некоторые из его причин не поддаются исправлению «выпадающих»?
Что такое «переживание»? Персиджение происходит, когда нейронная сеть учится «плохо», так как это работает для примеров обучения, но не так хорошо для реальных данных. Существуют методы регуляризации, такие как выпадение, которые могут заставить его учиться лучше, но переосмысление также имеет более глубокие корни.
Основное переживание происходит, когда нейронная сеть имеет слишком много степеней свободы для проблемы. Представьте себе, что у нас так много нейронов, что сеть может хранить все наши учебные изображения в них, а затем распознавать их по сопоставлению рисунков. Это потерпит неудачу в реальных данных полностью. Нейронная сеть должна быть несколько ограничена, чтобы она была вынуждена обобщать то, что она учится во время обучения.
Если у вас очень мало учебных данных, даже небольшая сеть может изучить их наизусть, и вы увидите «переосмысление». Вообще говоря, вам всегда нужно много данных для обучения нейронных сетей.
Наконец, если вы сделали все по книге, экспериментировали с различными размерами сети, чтобы убедиться, что ее степени свободы ограничены, применялись и обучались большим количеством данных, которые вы все еще можете застрять на уровне производительности, что ничего не кажется способен улучшить. Это означает, что ваша нейронная сеть в своей нынешней форме не способна извлечь больше информации из ваших данных, как в нашем случае здесь.
Помните, как мы используем наши изображения, сплющенные в один вектор? Это была действительно плохая идея. Рукописные цифры изготовлены из форм, и мы отбросили информацию о форме, когда мы сгладили пиксели. Тем не менее, существует тип нейронной сети, которая может воспользоваться информацией о форме: сверточные сети. Давайте попробуем их.
Если вы застряли, вот решение на данный момент:
10. [Информация] Служба
В двух словах
Если все термины в следующем абзаце уже известны вам, вы можете перейти к следующему упражнению. Если вы только начинаете с сверточных нейронных сетей, пожалуйста, читайте дальше.
Иллюстрация: фильтрация изображения с двумя последовательными фильтрами, изготовленными из 4x4x3 = 48 обучаемых весов в каждом.
Так выглядит простая сверточная нейронная сеть в керасе:
model = tf.keras.Sequential([
tf.keras.layers.Reshape(input_shape=(28*28,), target_shape=(28, 28, 1)),
tf.keras.layers.Conv2D(kernel_size=3, filters=12, activation='relu'),
tf.keras.layers.Conv2D(kernel_size=6, filters=24, strides=2, activation='relu'),
tf.keras.layers.Conv2D(kernel_size=6, filters=32, strides=2, activation='relu'),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(10, activation='softmax')
])
В слое сверточной сети один «нейрон» выполняет взвешенную сумму пикселей прямо над ней, только через небольшую область изображения. Он добавляет смещение и питает сумму через функцию активации, так же как нейрон в обычном плотном слое. Эта операция затем повторяется по всему изображению, используя те же веса. Помните, что в плотных слоях у каждого нейрона были свои веса. Здесь один «патч» веса скользит по изображению в обоих направлениях («свертка»). Вывод имеет столько значений, сколько и пикселей в изображении (хотя на краях необходимо некоторая заполнение). Это операция фильтрации. На приведенной выше иллюстрации он использует фильтр 4x4x3 = 48 веса.
Тем не менее, 48 весов будут недостаточно. Чтобы добавить больше степеней свободы, мы повторяем ту же операцию с новым набором весов. Это создает новый набор выходов фильтра. Давайте назовем это «каналом» выходов по аналогии с каналами R, G, B на входном изображении.
Два (или более) набора весов могут быть обобщены как один тензор, добавив новое измерение. Это дает нам общую форму тензора веса для сверточного слоя. Поскольку количество входных и выходных каналов является параметрами, мы можем начать складывание и цепочку сверточных слоев.
Иллюстрация: сверточная нейронная сеть превращает «кубики» данных в другие «кубики» данных.
Подчеркнутые свертки, максимальное объединение
Выполняя свертывание с шагом 2 или 3, мы также можем уменьшить полученный кубик данных в его горизонтальных измерениях. Есть два распространенных способа сделать это:
- Униженная свертка: скользящий фильтр, как указано выше, но с шагом> 1
- MAX Pooling: раздвижное окно, применяющее максимальную работу (обычно на пятнах 2x2, повторяется каждые 2 пикселя)
Иллюстрация: скольжение вычислительного окна на 3 пикселя приводит к меньшему количеству выходных значений. Униженные сознания или максимальное объединение (максимум в окне 2x2, скользящего по шагу 2), являются способом сокращения куба данных в горизонтальных измерениях.
Последний слой
После последнего сверточного слоя данные находятся в форме «куба». Есть два способа кормить его через последний плотный слой.
Первым является выравнивание куба данных в вектор, а затем подавать его к слою Softmax. Иногда вы можете даже добавить плотный слой перед слоем Softmax. Это, как правило, дорого с точки зрения количества весов. Плотный слой в конце сверточной сети может содержать более половины весов всей нейронной сети.
Вместо использования дорогостоящего плотного слоя мы также можем разделить входящие данные «куб» на столько же частей, сколько у нас есть классы, средние их значения и подавать их с помощью функции активации Softmax. Этот способ построения классификационной головки стоит 0 весов. В Keras есть слой для этого: tf.keras.layers.GlobalAveragePooling2D()
.
Перейдите к следующему разделу, чтобы построить сверточную сеть для задачи.
11. Служба
Давайте создадим сверточную сеть для рукописного распознавания цифр. Мы будем использовать три сверточных слоя сверху, наш традиционный слой считывания Softmax внизу и подключим их с одним полностью подключенным слоем:
Обратите внимание, что второй и третий сверточный слои имеют шаг из двух, что объясняет, почему они снижают количество выходных значений с 28x28 до 14x14, а затем 7x7.
Давайте напишем код кераса.
Особое внимание необходимо перед первым сверточным слоем. Действительно, он ожидает трехмерного куба данных, но наш набор данных до сих пор был настроен для плотных слоев, и все пиксели изображений сгладиваются в вектор. Нам нужно изменить их обратно на изображения 28x28x1 (1 канал для изображений серого):
tf.keras.layers.Reshape(input_shape=(28*28,), target_shape=(28, 28, 1))
Вы можете использовать эту линию вместо слоя tf.keras.layers.Input
, который у вас был до сих пор.
В керах синтаксис для активированного на резолюционном слое:
tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu')
Для укрепленной сверты, вы бы написали:
tf.keras.layers.Conv2D(kernel_size=6, filters=24, padding='same', activation='relu', strides=2)
Чтобы сгладить куб данных в вектор, чтобы его можно было поглощать плотным слоем:
tf.keras.layers.Flatten()
И для плотного слоя синтаксис не изменился:
tf.keras.layers.Dense(200, activation='relu')
Ваша модель преодолела барьер точности 99%? Довольно близко ... но посмотрите на кривую потери проверки. Это звонит колоколом?
Также посмотрите на прогнозы. Впервые вы должны увидеть, что большинство из 10000 тестовых цифр теперь правильно распознаются. Осталось только около 4½ рядов ошибок (около 110 цифр из 10 000)
Если вы застряли, вот решение на данный момент:
12. Снова выбросит
Предыдущая тренировка демонстрирует четкие признаки переосмысления (и до сих пор не соответствует точке 99%). Стоит ли снова попробовать выбросить?
Как все прошло на этот раз?
Похоже, что отступление сработало на этот раз. Потеря проверки больше не ползуется, и окончательная точность должна быть намного выше 99%. Поздравляем!
В первый раз, когда мы попытались применить отступление, мы думали, что у нас есть проблема с переосмыслением, когда на самом деле проблема была в архитектуре нейронной сети. Мы не могли бы пойти дальше без сверточных слоев, и с этим ничего не может сделать.
На этот раз это похоже на то, что переживание было причиной проблемы, и выброс фактически помог. Помните, что есть много вещей, которые могут вызвать разрыв между кривыми обучения и потери проверки, причем потери валидации ползутся. Переполнение (слишком много степеней свободы, которые плохо используются сетью) - это только один из них. Если ваш набор данных слишком мал или архитектура вашей нейронной сети не является адекватной, вы можете увидеть аналогичное поведение на кривых потери, но отсевание не поможет.
13. Нормализация партии
Наконец, давайте попробуем добавить нормализацию партии.
Это теория, на практике, просто помните пару правил:
Давайте пока играем у книги и добавим партированный слой нормы на каждом уровне нейронной сети, но в последний. Не добавляйте его к последнему слою «Softmax». Там не было бы полезно.
# Modify each layer: remove the activation from the layer itself.
# Set use_bias=False since batch norm will play the role of biases.
tf.keras.layers.Conv2D(..., use_bias=False),
# Batch norm goes between the layer and its activation.
# The scale factor can be turned off for Relu activation.
tf.keras.layers.BatchNormalization(scale=False, center=True),
# Finish with the activation.
tf.keras.layers.Activation('relu'),
Как сейчас точность?
При небольшой настройке (batch_size = 64, параметр распада скорости обучения 0,666, скорость отсева на плотном уровне 0,3) и немного удачи, вы можете добраться до 99,5%. Корректировки уровня обучения и отсева были выполнены после «лучших практик» для использования пакетной нормы:
- Пакетная норма помогает нейронным сетям сходиться и обычно позволяет тренироваться быстрее.
- Пакетная норма - регулятор. Обычно вы можете уменьшить количество выбывшего, которое вы используете, или даже не использовать отсевание вообще.
The Solution Notebook имеет 99,5% тренировочный запуск:
14. Тренируйтесь в облаке на мощном аппаратном обеспечении: платформа искусственного интеллекта
Вы найдете готовую к облаку версии кода в папке Mlengine на GitHub , а также инструкции по его запуску на платформе Google Cloud AI . Прежде чем вы сможете запустить эту часть, вам придется создать учетную запись Google Cloud и включить выставление счетов. Ресурсы, необходимые для завершения лаборатории, должны составлять менее пары долларов (при условии 1 часа обучения на одном графическом процессоре). Чтобы подготовить свою учетную запись:
- Создайте проект Google Cloud Platform ( http://cloud.google.com/console ).
- Включить биллинг.
- Установите инструменты командной строки GCP ( GCP SDK здесь ).
- Создайте ведро Google Cloud Storage (PLOT в регионе
us-central1
). Он будет использоваться для постановки учебного кода и хранения вашей обученной модели. - Включите необходимые API и запросите необходимые квоты (запустите команду обучения один раз, и вы должны получить сообщения об ошибках, сообщающие вам, что для включения).
15. Поздравляем!
Вы построили свою первую нейронную сеть и обучили ее до конца 99% точности. Методы, изученные на этом пути, не являются специфическими для набора данных MNIST, на самом деле они широко используются при работе с нейронными сетями. В качестве прощального подарка, вот карта «Примечания Клиффа» для лаборатории, в мультфильме. Вы можете использовать его, чтобы вспомнить, что вы узнали:
Следующие шаги
- После полностью связанных и сверточных сетей вы должны взглянуть на повторяющиеся нейронные сети .
- Чтобы запустить обучение или вывод в облаке на распределенной инфраструктуре, Google Cloud предоставляет платформу AI .
- Наконец, мы любим обратную связь. Пожалуйста, скажите нам, если вы видите что -то не так, как в этой лаборатории или вы думаете, что это должно быть улучшено. Мы обрабатываем обратную связь через проблемы GitHub [ ссылка на обратную связь ].
Автор: Martin Görnertwitter: @martin_gorner |
Все мультипликационные изображения в этой лаборатории Copyright: Alexpokusay / 123RF Стоковые фотографии