Керас и современные сети на ТПУ

1. Обзор

В этой лабораторной работе вы узнаете, как создавать, обучать и настраивать собственные сверточные нейронные сети с нуля с помощью Keras и Tensorflow 2. Теперь это можно сделать за считанные минуты, используя мощь TPU. Вы также изучите множество подходов: от очень простого трансферного обучения до современных сверточных архитектур, таких как Squeezenet. Эта лабораторная работа включает теоретические объяснения нейронных сетей и является хорошей отправной точкой для разработчиков, изучающих глубокое обучение.

Чтение статей по глубокому обучению может быть трудным и запутанным. Давайте посмотрим на современные архитектуры сверточных нейронных сетей.

ca8cc21f6838eccc.png

Что вы узнаете

  • Использовать Keras и тензорные процессоры (TPU) для более быстрого создания собственных моделей.
  • Использовать API tf.data.Dataset и формат TFRecord для эффективной загрузки обучающих данных.
  • Обманывать 😈, используя трансферное обучение вместо построения собственных моделей.
  • Использовать стили последовательной и функциональной модели Keras.
  • Создать свой собственный классификатор Keras со слоем softmax и перекрестной энтропийной потерей.
  • Для точной настройки вашей модели с помощью хорошего выбора сверточных слоев.
  • Изучить современные идеи архитектуры коннетов, такие как модули, глобальный средний пул и т. д.
  • Построить простую современную сеть с использованием архитектуры Squeezenet.

Обратная связь

Если вы заметили что-то неладное в этой лаборатории кода, сообщите нам. Обратная связь может быть предоставлена ​​через вопросы GitHub [ ссылка обратной связи ].

2. Быстрый старт Google Colaboratory

Эта лабораторная работа использует Google Collaboratory и не требует никакой настройки с вашей стороны. Вы можете запустить его с Chromebook. Откройте файл ниже и заполните ячейки, чтобы ознакомиться с блокнотами Colab.

c3df49e90e5a654f.png Welcome to Colab.ipynb

Выберите серверную часть TPU

8832c6208c99687d.png

В меню Colab выберите «Время выполнения» > «Изменить тип среды выполнения» , а затем выберите «TPU». В этой лаборатории по программированию вы будете использовать мощный TPU (тензорный процессор), поддерживающий аппаратное ускорение обучения. Подключение к среде выполнения произойдет автоматически при первом запуске, или вы можете использовать кнопку «Подключиться» в правом верхнем углу.

Исполнение ноутбука

76d05caa8b4db6da.png

Выполняйте ячейки по одной, щелкая ячейку и используя Shift-ENTER. Вы также можете запустить весь блокнот, выбрав «Среда выполнения» > «Выполнить все».

Оглавление

429f106990037ec4.png

Все тетради имеют оглавление. Открыть его можно с помощью черной стрелки слева.

Скрытые ячейки

edc3dba45d26f12a.png

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

Аутентификация

cdd4b41413100543.png

Colab может получить доступ к вашим частным корзинам облачного хранилища Google при условии, что вы пройдете аутентификацию с использованием авторизованной учетной записи. Приведенный выше фрагмент кода запустит процесс аутентификации.

3. [ИНФОРМАЦИЯ] Что такое тензорные процессоры (TPU)?

В двух словах

f88cf6facfc70166.png

Код для обучения модели на TPU в Keras (и использования графического процессора или процессора, если TPU недоступен):

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

Сегодня мы будем использовать TPU для создания и оптимизации классификатора цветов на интерактивной скорости (минуты на тренировочный прогон).

688858c21e3beff2.png

Почему ТПУ?

Современные графические процессоры организованы вокруг программируемых «ядер» — очень гибкой архитектуры, которая позволяет им решать различные задачи, такие как 3D-рендеринг, глубокое обучение, физическое моделирование и т. д. С другой стороны, TPU сочетают в себе классический векторный процессор со специализированным процессором. модуль матричного умножения и преуспейте в любой задаче, где доминируют большие матричные умножения, например, в нейронных сетях.

8eb3e718b8e2ed08.png

Иллюстрация: плотный слой нейронной сети в виде матричного умножения с пакетом из восьми изображений, обрабатываемых нейронной сетью одновременно. Пожалуйста, выполните умножение одной строки на столбец, чтобы убедиться, что оно действительно выполняет взвешенную сумму всех значений пикселей изображения. Сверточные слои также можно представить как умножения матриц, хотя это немного сложнее ( объяснение здесь, в разделе 1 ).

Аппаратное обеспечение

МХУ и ВПУ

Ядро TPU v2 состоит из блока умножения матриц (MXU), который выполняет умножение матриц, и блока векторной обработки (VPU) для всех других задач, таких как активации, softmax и т. д. VPU обрабатывает вычисления float32 и int32. С другой стороны, MXU работает в формате с плавающей запятой смешанной точности (16–32 бита).

7d68944718f76b18.png

С плавающей запятой смешанной точности и bfloat16

MXU вычисляет умножение матриц, используя входные данные bfloat16 и выходные данные float32. Промежуточные накопления выполняются с точностью float32.

19c5fc432840c714.png

Обучение нейронной сети обычно устойчиво к шуму, вносимому пониженной точностью с плавающей запятой. Бывают случаи, когда шум даже помогает оптимизатору сходиться. 16-битная точность с плавающей запятой традиционно использовалась для ускорения вычислений, но форматы float16 и float32 имеют очень разные диапазоны. Уменьшение точности с float32 до float16 обычно приводит к переполнению или потере значения. Решения существуют, но обычно требуется дополнительная работа, чтобы float16 работал.

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

Систолический массив

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

Основным элементом матричного умножения является скалярное произведение строки одной матрицы и столбца другой матрицы (см. иллюстрацию вверху этого раздела). Для матричного умножения Y=X*W одним элементом результата будет:

Y[2,0] = X[2,0]*W[0,0] + X[2,1]*W[1,0] + X[2,2]*W[2,0] + ... + X[2,n]*W[n,0]

На графическом процессоре можно было бы запрограммировать это скалярное произведение в «ядро» графического процессора, а затем выполнить его на таком количестве «ядер», которое доступно параллельно, чтобы попытаться вычислить каждое значение результирующей матрицы одновременно. Если результирующая матрица имеет размер 128x128, для этого потребуется наличие 128x128 = 16 КБ «ядер», что обычно невозможно. Самые большие графические процессоры имеют около 4000 ядер. С другой стороны, TPU использует минимум аппаратного обеспечения для вычислительных блоков в MXU: просто bfloat16 x bfloat16 => float32 умножительные аккумуляторы, и ничего больше. Они настолько малы, что TPU может реализовать 16 КБ из них в MXU 128x128 и обработать умножение матриц за один раз.

f1b283fc45966717.gif

Иллюстрация: систолическая диаграмма MXU. Вычислительные элементы представляют собой многократные аккумуляторы. В массив загружаются значения одной матрицы (красные точки). Значения другой матрицы проходят через массив (серые точки). Вертикальные линии распространяют значения вверх. Горизонтальные линии распространяют частичные суммы. Пользователю остается в качестве упражнения проверить, что по мере прохождения данных через массив вы получаете результат умножения матрицы, выходящий из правой части.

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

Облачный ТПУ

Когда вы запрашиваете один « Cloud TPU v2» на Google Cloud Platform, вы получаете виртуальную машину (ВМ) с платой TPU, подключенной к PCI. Плата TPU имеет четыре двухъядерных чипа TPU. Каждое ядро ​​TPU оснащено VPU (блок векторной обработки) и MXU 128x128 (блок умножения MatriX). Этот «Облачный TPU» затем обычно подключается через сеть к виртуальной машине, которая его запросила. Итак, полная картина выглядит так:

dfce5522ed644ece.png

Иллюстрация: ваша виртуальная машина с сетевым ускорителем Cloud TPU. Сам «Облачный TPU» состоит из виртуальной машины с подключенной к PCI платой TPU с четырьмя двухъядерными чипами TPU.

капсулы ТПУ

В центрах обработки данных Google TPU подключены к межсоединению высокопроизводительных вычислений (HPC), благодаря чему они могут выглядеть как один очень большой ускоритель. Google называет их модулями, и они могут включать в себя до 512 ядер TPU v2 или 2048 ядер TPU v3.

2ec1e0d341e7fc34.jpeg

Иллюстрация: модуль TPU v3. Платы и стойки TPU подключаются через межсоединение HPC.

Во время обучения градиенты обмениваются между ядрами TPU с использованием алгоритма all-reduce ( хорошее объяснение all-reduce здесь ). Обучаемая модель может воспользоваться преимуществами аппаратного обеспечения при обучении на больших размерах пакетов.

d97b9cc5d40fdb1d.gif

Иллюстрация: синхронизация градиентов во время обучения с использованием алгоритма полного сокращения в двухмерной тороидальной сети высокопроизводительных вычислений Google TPU.

Программное обеспечение

Обучение в больших объемах

Идеальный размер пакета для TPU — 128 элементов данных на ядро ​​TPU, но оборудование уже может демонстрировать хорошее использование 8 элементов данных на ядро ​​TPU. Помните, что один Cloud TPU имеет 8 ядер.

В этой лаборатории кода мы будем использовать Keras API. В Keras указанный вами пакет является глобальным размером пакета для всего TPU. Ваши пакеты будут автоматически разделены на 8 и запущены на 8 ядрах TPU.

da534407825f01e3.png

Дополнительные советы по производительности см. в Руководстве по производительности TPU . При очень больших размерах партий в некоторых моделях может потребоваться особая осторожность, более подробную информацию см. в разделе LARSOptimizer .

Под капотом: XLA.

Программы Tensorflow определяют графы вычислений. TPU не запускает код Python напрямую, он запускает граф вычислений, определенный вашей программой Tensorflow. Под капотом компилятор под названием XLA (ускоренный компилятор линейной алгебры) преобразует граф вычислительных узлов Tensorflow в машинный код TPU. Этот компилятор также выполняет множество расширенных оптимизаций вашего кода и структуры памяти. Компиляция происходит автоматически по мере отправки работы в TPU. Вам не обязательно явно включать XLA в цепочку сборки.

edce61112cd57972.png

Иллюстрация: для работы на TPU граф вычислений, определенный вашей программой Tensorflow, сначала преобразуется в представление XLA (ускоренный компилятор линейной алгебры), а затем компилируется XLA в машинный код TPU.

Использование TPU в Keras

TPU поддерживаются через Keras API, начиная с Tensorflow 2.1. Поддержка Keras работает на TPU и модулях TPU. Вот пример, который работает на TPU, графических процессорах и процессоре:

try: # detect TPUs
    tpu = tf.distribute.cluster_resolver.TPUClusterResolver.connect()
    strategy = tf.distribute.TPUStrategy(tpu)
except ValueError: # detect GPUs
    strategy = tf.distribute.MirroredStrategy() # for CPU/GPU or multi-GPU machines

# use TPUStrategy scope to define model
with strategy.scope():
  model = tf.keras.Sequential( ... )
  model.compile( ... )

# train model normally on a tf.data.Dataset
model.fit(training_dataset, epochs=EPOCHS, steps_per_epoch=...)

В этом фрагменте кода:

  • TPUClusterResolver().connect() находит TPU в сети. Он работает без параметров в большинстве облачных систем Google (задания платформы AI, Colaboratory, Kubeflow, виртуальные машины глубокого обучения, созданные с помощью утилиты «ctpu up»). Эти системы знают, где находится их TPU, благодаря переменной среды TPU_NAME. Если вы создаете TPU вручную, либо установите окружение TPU_NAME. вар. на виртуальной машине, из которой вы его используете, или вызовите TPUClusterResolver с явными параметрами: TPUClusterResolver(tp_uname, zone, project)
  • TPUStrategy — это часть, которая реализует распределение и алгоритм синхронизации градиента «все-сокращение».
  • Стратегия применяется через область действия. Модель должна быть определена в области действия стратегии().
  • Функция tpu_model.fit ожидает объект tf.data.Dataset для ввода для обучения TPU.

Распространенные задачи портирования TPU

  • Хотя существует множество способов загрузки данных в модель Tensorflow, для TPU требуется использование API tf.data.Dataset .
  • TPU очень быстрые, и прием данных часто становится узким местом при работе на них. В Руководстве по производительности TPU есть инструменты, которые можно использовать для обнаружения узких мест в данных, а также другие советы по производительности.
  • Числа int8 или int16 обрабатываются как int32. TPU не имеет целочисленного оборудования, работающего с разрядностью менее 32 бит.
  • Некоторые операции Tensorflow не поддерживаются. Список здесь . Хорошей новостью является то, что это ограничение применимо только к обучающему коду, то есть к прямому и обратному проходу через вашу модель. Вы по-прежнему можете использовать все операции Tensorflow в конвейере ввода данных, поскольку они будут выполняться на ЦП.
  • tf.py_func не поддерживается в TPU.

4. Загрузка данных

c0ecb860e4cad0a9.jpegcc4781a7739c49ae.jpeg81236b00f8bbf39e.jpeg961e2228974076bb.jpeg7517dc163bdffcd5.jpeg96392df4767f566d.png

Мы будем работать с набором данных изображений цветов. Цель состоит в том, чтобы научиться разделять их на 5 типов цветов. Загрузка данных осуществляется с помощью API tf.data.Dataset . Для начала давайте познакомимся с API.

Практический

Откройте следующую записную книжку, заполните ячейки (Shift-ENTER) и следуйте инструкциям везде, где вы видите надпись «ТРЕБУЕТСЯ РАБОТА».

c3df49e90e5a654f.png Fun with tf.data.Dataset (playground).ipynb

Дополнительная информация

О наборе данных «цветы»

Набор данных организован в 5 папках. В каждой папке собраны цветы одного вида. Папки названы подсолнухи, ромашки, одуванчики, тюльпаны и розы. Данные размещаются в общедоступном сегменте Google Cloud Storage. Отрывок:

gs://flowers-public/sunflowers/5139971615_434ff8ed8b_n.jpg
gs://flowers-public/daisy/8094774544_35465c1c64.jpg
gs://flowers-public/sunflowers/9309473873_9d62b9082e.jpg
gs://flowers-public/dandelion/19551343954_83bb52f310_m.jpg
gs://flowers-public/dandelion/14199664556_188b37e51e.jpg
gs://flowers-public/tulips/4290566894_c7f061583d_m.jpg
gs://flowers-public/roses/3065719996_c16ecd5551.jpg
gs://flowers-public/dandelion/8168031302_6e36f39d87.jpg
gs://flowers-public/sunflowers/9564240106_0577e919da_n.jpg
gs://flowers-public/daisy/14167543177_cd36b54ac6_n.jpg

Почему tf.data.Dataset?

Keras и Tensorflow принимают наборы данных во всех своих функциях обучения и оценки. После загрузки данных в набор данных API предлагает все общие функции, полезные для данных обучения нейронной сети:

dataset = ... # load something (see below)
dataset = dataset.shuffle(1000) # shuffle the dataset with a buffer of 1000
dataset = dataset.cache() # cache the dataset in RAM or on disk
dataset = dataset.repeat() # repeat the dataset indefinitely
dataset = dataset.batch(128) # batch data elements together in batches of 128
AUTOTUNE = tf.data.AUTOTUNE
dataset = dataset.prefetch(AUTOTUNE) # prefetch next batch(es) while training

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

tf.data.Основы набора данных

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

filenames_dataset = tf.data.Dataset.list_files('gs://flowers-public/*/*.jpg')
# The parameter is a "glob" pattern that supports the * and ? wildcards.

Затем вы «сопоставляете» функцию с каждым именем файла, которая обычно загружает и декодирует файл в фактические данные в памяти:

def decode_jpeg(filename):
  bits = tf.io.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  return image

image_dataset = filenames_dataset.map(decode_jpeg)
# this is now a dataset of decoded images (uint8 RGB format)

Чтобы перебрать набор данных:

for data in my_dataset:
  print(data)

Наборы данных кортежей

При обучении с учителем набор обучающих данных обычно состоит из пар обучающих данных и правильных ответов. Чтобы обеспечить это, функция декодирования может возвращать кортежи. После этого у вас будет набор данных кортежей, и кортежи будут возвращены при его итерации. Возвращаемые значения представляют собой тензоры Tensorflow, готовые к использованию вашей моделью. Вы можете вызвать для них .numpy() , чтобы увидеть необработанные значения:

def decode_jpeg_and_label(filename):
  bits = tf.read_file(filename)
  image = tf.io.decode_jpeg(bits)
  label = ... # extract flower name from folder name
  return image, label

image_dataset = filenames_dataset.map(decode_jpeg_and_label)
# this is now a dataset of (image, label) pairs 

for image, label in dataset:
  print(image.numpy().shape, label.numpy())

Вывод: загрузка изображений по одному происходит медленно!

По мере обработки этого набора данных вы увидите, что можете загружать примерно 1–2 изображения в секунду. Это слишком медленно! Аппаратные ускорители, которые мы будем использовать для обучения, могут выдержать во много раз большую скорость. Перейдите в следующий раздел, чтобы узнать, как мы этого достигнем.

Решение

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

c3df49e90e5a654f.png Fun with tf.data.Dataset (solution).ipynb

Что мы рассмотрели

  • 🤔 tf.data.Dataset.list_files
  • 🤔 tf.data.Dataset.map
  • 🤔 Наборы данных кортежей
  • 😀 перебор наборов данных

Пожалуйста, найдите время и прокрутите этот контрольный список в уме.

5. Быстрая загрузка данных

Аппаратные ускорители Tensor Processing Unit (TPU), которые мы будем использовать в этой лабораторной работе, очень быстрые. Зачастую задача состоит в том, чтобы предоставить им данные достаточно быстро, чтобы они были заняты. Облачное хранилище Google (GCS) способно поддерживать очень высокую пропускную способность, но, как и во всех системах облачного хранения, инициирование соединения требует затрат сети туда и обратно. Поэтому хранить наши данные в тысячах отдельных файлов не идеально. Мы собираемся объединить их в меньшее количество файлов и использовать возможности tf.data.Dataset для параллельного чтения из нескольких файлов.

Чтение

Код, который загружает файлы изображений, изменяет их размер до стандартного размера, а затем сохраняет их в 16 файлах TFRecord, находится в следующем блокноте. Пожалуйста, быстро прочтите его. Выполнять его необязательно, поскольку данные в правильном формате TFRecord будут предоставлены для остальной части кодовой лаборатории.

c3df49e90e5a654f.png Flower pictures to TFRecords.ipynb

Идеальное расположение данных для оптимальной пропускной способности GCS

Формат файла TFRecord

Предпочтительным форматом файлов Tensorflow для хранения данных является формат TFRecord на основе protobuf . Другие форматы сериализации тоже подойдут, но вы можете загрузить набор данных из файлов TFRecord напрямую, написав:

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

Для оптимальной производительности рекомендуется использовать следующий более сложный код для одновременного чтения из нескольких файлов TFRecord. Этот код будет читать N файлов параллельно и игнорировать порядок данных в пользу скорости чтения.

AUTOTUNE = tf.data.AUTOTUNE
ignore_order = tf.data.Options()
ignore_order.experimental_deterministic = False

filenames = tf.io.gfile.glob(FILENAME_PATTERN)
dataset = tf.data.TFRecordDataset(filenames, num_parallel_reads=AUTOTUNE)
dataset = dataset.with_options(ignore_order)
dataset = dataset.map(...) # do the TFRecord decoding here - see below

Шпаргалка по TFRecord

В TFRecords можно хранить три типа данных: байтовые строки (список байтов), 64-битные целые числа и 32-битные числа с плавающей запятой . Они всегда сохраняются в виде списков, один элемент данных будет списком размером 1. Вы можете использовать следующие вспомогательные функции для хранения данных в TFRecords.

запись байтовых строк

# warning, the input is a list of byte strings, which are themselves lists of bytes
def _bytestring_feature(list_of_bytestrings):
  return tf.train.Feature(bytes_list=tf.train.BytesList(value=list_of_bytestrings))

запись целых чисел

def _int_feature(list_of_ints): # int64
  return tf.train.Feature(int64_list=tf.train.Int64List(value=list_of_ints))

запись поплавков

def _float_feature(list_of_floats): # float32
  return tf.train.Feature(float_list=tf.train.FloatList(value=list_of_floats))

написание TFRecord , используя приведенные выше помощники

# input data in my_img_bytes, my_class, my_height, my_width, my_floats
with tf.python_io.TFRecordWriter(filename) as out_file:
  feature = {
    "image": _bytestring_feature([my_img_bytes]), # one image in the list
    "class": _int_feature([my_class]),            # one class in the list
    "size": _int_feature([my_height, my_width]),  # fixed length (2) list of ints
    "float_data": _float_feature(my_floats)       # variable length  list of floats
  }
  tf_record = tf.train.Example(features=tf.train.Features(feature=feature))
  out_file.write(tf_record.SerializeToString())

Чтобы прочитать данные из TFRecords, вы должны сначала объявить структуру сохраненных вами записей. В объявлении вы можете получить доступ к любому именованному полю как к списку фиксированной длины или списку переменной длины:

чтение из TFRecords

def read_tfrecord(data):
  features = {
    # tf.string = byte string (not text string)
    "image": tf.io.FixedLenFeature([], tf.string), # shape [] means scalar, here, a single byte string
    "class": tf.io.FixedLenFeature([], tf.int64),  # shape [] means scalar, i.e. a single item
    "size": tf.io.FixedLenFeature([2], tf.int64),  # two integers
    "float_data": tf.io.VarLenFeature(tf.float32)  # a variable number of floats
  }

  # decode the TFRecord
  tf_record = tf.io.parse_single_example(data, features)

  # FixedLenFeature fields are now ready to use
  sz = tf_record['size']

  # Typical code for decoding compressed images
  image = tf.io.decode_jpeg(tf_record['image'], channels=3)

  # VarLenFeature fields require additional sparse.to_dense decoding
  float_data = tf.sparse.to_dense(tf_record['float_data'])

  return image, sz, float_data

# decoding a tf.data.TFRecordDataset
dataset = dataset.map(read_tfrecord)
# now a dataset of triplets (image, sz, float_data)

Полезные фрагменты кода:

чтение отдельных элементов данных

tf.io.FixedLenFeature([], tf.string)   # for one byte string
tf.io.FixedLenFeature([], tf.int64)    # for one int
tf.io.FixedLenFeature([], tf.float32)  # for one float

чтение списков элементов фиксированного размера

tf.io.FixedLenFeature([N], tf.string)   # list of N byte strings
tf.io.FixedLenFeature([N], tf.int64)    # list of N ints
tf.io.FixedLenFeature([N], tf.float32)  # list of N floats

чтение переменного количества элементов данных

tf.io.VarLenFeature(tf.string)   # list of byte strings
tf.io.VarLenFeature(tf.int64)    # list of ints
tf.io.VarLenFeature(tf.float32)  # list of floats

VarLenFeature возвращает разреженный вектор, и после декодирования TFRecord требуется дополнительный шаг:

dense_data = tf.sparse.to_dense(tf_record['my_var_len_feature'])

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

tf.io.FixedLenFeature([], tf.int64, default_value=0) # this field is optional

Что мы рассмотрели

  • 🤔 сегментирование файлов данных для быстрого доступа из GCS
  • 😓 как писать TFRecords. (Вы уже забыли синтаксис? Ничего страшного, добавьте эту страницу в закладки как шпаргалку)
  • 🤔 загрузка набора данных из TFRecords с помощью TFRecordDataset

Пожалуйста, найдите время и прокрутите этот контрольный список в уме.

6. [ИНФО] Классификатор нейронной сети 101

В двух словах

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

Для моделей, построенных как последовательность слоев, Keras предлагает Sequential API. Например, классификатор изображений, использующий три плотных слоя, можно записать в Keras как:

model = tf.keras.Sequential([
    tf.keras.layers.Flatten(input_shape=[192, 192, 3]),
    tf.keras.layers.Dense(500, activation="relu"),
    tf.keras.layers.Dense(50, activation="relu"),
    tf.keras.layers.Dense(5, activation='softmax') # classifying into 5 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, ... )

688858c21e3beff2.png

Плотная нейронная сеть

Это простейшая нейронная сеть для классификации изображений. Он состоит из «нейронов», расположенных слоями. Первый уровень обрабатывает входные данные и передает их выходные данные на другие уровни. Он называется «плотным», потому что каждый нейрон связан со всеми нейронами предыдущего слоя.

c21bae6dade487bc.png

Вы можете передать изображение в такую ​​сеть, объединив значения RGB всех его пикселей в длинный вектор и используя его в качестве входных данных. Это не лучший метод распознавания изображений, но позже мы улучшим его.

Нейроны, активации, RELU

«Нейрон» вычисляет взвешенную сумму всех своих входных данных, добавляет значение, называемое «смещением», и передает результат через так называемую «функцию активации». Веса и смещение сначала неизвестны. Они будут инициализированы случайным образом и «обучены» путем обучения нейронной сети на большом количестве известных данных.

644f4213a4ee70e5.png

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

Активация Софтмакс

Сеть выше заканчивается слоем из 5 нейронов, поскольку мы классифицируем цветы по 5 категориям (роза, тюльпан, одуванчик, ромашка, подсолнух). Нейроны в промежуточных слоях активируются с помощью классической функции активации RELU. Однако на последнем слое мы хотим вычислить числа от 0 до 1, представляющие вероятность того, что этот цветок будет розой, тюльпаном и так далее. Для этого мы будем использовать функцию активации под названием «softmax».

Применение softmax к вектору осуществляется путем взятия экспоненты каждого элемента и последующей нормализации вектора, обычно с использованием нормы L1 (суммы абсолютных значений), так что сумма значений равна 1 и может интерпретироваться как вероятности.

ef0d98c0952c262d.pngd51252f75894479e.gif

Перекрестная энтропийная потеря

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

Подойдет любое расстояние, но для задач классификации наиболее эффективным является так называемое «перекрестное энтропийное расстояние». Мы назовем это нашей функцией ошибки или «потери»:

7bdf8753d20617fb.png

Градиентный спуск

«Обучение» нейронной сети на самом деле означает использование обучающих изображений и меток для корректировки весов и смещений, чтобы минимизировать функцию перекрестных энтропийных потерь. Вот как это работает.

Перекрестная энтропия — это функция весов, смещений, пикселей обучающего изображения и его известного класса.

Если мы вычислим частные производные перекрестной энтропии относительно всех весов и всех смещений, мы получим «градиент», рассчитанный для данного изображения, метки и текущего значения весов и смещений. Помните, что у нас могут быть миллионы весов и смещений, поэтому вычисление градиента кажется большой работой. К счастью, Tensorflow делает это за нас. Математическое свойство градиента заключается в том, что он направлен «вверх». Поскольку мы хотим пойти туда, где перекрестная энтропия низкая, мы идем в противоположном направлении. Мы обновляем веса и смещения на долю градиента. Затем мы делаем то же самое снова и снова, используя следующие партии обучающих изображений и меток в цикле обучения. Будем надеяться, что это приведет к тому, что перекрестная энтропия будет минимальной, хотя ничто не гарантирует, что этот минимум уникален.

градиентный спуск2.png

Мини-пакетирование и импульс

Вы можете вычислить градиент только на одном изображении-примере и немедленно обновить веса и смещения, но если сделать это, например, на пакете из 128 изображений, получится градиент, который лучше отражает ограничения, налагаемые различными изображениями-примерами, и, следовательно, с большой вероятностью сходится. к решению быстрее. Размер мини-партии является регулируемым параметром.

Этот метод, иногда называемый «стохастическим градиентным спуском», имеет еще одно, более прагматичное преимущество: работа с пакетами также означает работу с более крупными матрицами, и их обычно легче оптимизировать на графических процессорах и TPU.

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

52e824fe4716c4a0.png

Иллюстрация: седловая точка. Градиент равен 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 или более измерениями.

7. Передача обучения

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

Но мы также можем пойти и коротким путем! Для скачивания доступны полностью обученные сверточные нейронные сети. Можно отколоть их последний слой, классификационную головку softmax, и заменить на свой. Все обученные веса и смещения остаются такими же, как они есть, вы только переобучаете добавленный слой softmax. Этот метод называется трансферным обучением, и, что удивительно, он работает до тех пор, пока набор данных, на котором предварительно обучается нейронная сеть, «достаточно близок» к вашему.

Практический

Откройте следующую записную книжку, заполните ячейки (Shift-ENTER) и следуйте инструкциям везде, где вы видите надпись «ТРЕБУЕТСЯ РАБОТА».

c3df49e90e5a654f.png Keras Flowers transfer learning (playground).ipynb

Дополнительная информация

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

b8fc1efd2001f072.png

Иллюстрация: использование сложной сверточной нейронной сети, уже обученной, как черный ящик, переобучающей только классификационную головку. Это трансферное обучение. Позже мы увидим, как работают эти сложные расположения сверточных слоев. Пока это чужая проблема.

Трансферное обучение в Керасе

В Keras вы можете создать экземпляр предварительно обученной модели из коллекции tf.keras.applications.* . MobileNet V2, например, представляет собой очень хорошую сверточную архитектуру, сохраняющую разумные размеры. Выбрав include_top=False , вы получите предварительно обученную модель без финального слоя softmax, чтобы вы могли добавить свой собственный:

pretrained_model = tf.keras.applications.MobileNetV2(input_shape=[*IMAGE_SIZE, 3], include_top=False)
pretrained_model.trainable = False

model = tf.keras.Sequential([
    pretrained_model,
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(5, activation='softmax')
])

Также обратите внимание на настройку pretrained_model.trainable = False . Он замораживает веса и смещения предварительно обученной модели, чтобы вы могли тренировать только свой слой softmax. Обычно это требует относительно небольшого количества весов и может быть выполнено быстро и без необходимости использования очень большого набора данных. Однако если у вас много данных, трансферное обучение может работать еще лучше с pretrained_model.trainable = True . Предварительно обученные веса обеспечивают отличные начальные значения, и их все равно можно корректировать в процессе обучения, чтобы лучше соответствовать вашей проблеме.

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

При таком подходе вы должны получить точность около 75%.

Решение

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

c3df49e90e5a654f.png Keras Flowers transfer learning (solution).ipynb

Что мы рассмотрели

  • 🤔 Как написать классификатор в Керасе
  • 🤓 настроен с последним слоем softmax и потерей перекрестной энтропии
  • 😈 Перенос обучения
  • 🤔 Обучение вашей первой модели
  • 🧐 Следим за его потерей и точностью во время тренировки

Пожалуйста, найдите время и прокрутите этот контрольный список в уме.

8. [ИНФО] Сверточные нейронные сети

В двух словах

Если все термины, выделенные жирным шрифтом в следующем абзаце, вам уже известны, можно переходить к следующему упражнению. Если вы только начинаете с сверточных нейронных сетей, пожалуйста, читайте дальше.

Convotoralal.gif

Иллюстрация: фильтрация изображения с двумя последовательными фильтрами, изготовленными из 4x4x3 = 48 обучаемых весов в каждом.

Так выглядит простая сверточная нейронная сеть в керасе:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=3, filters=24, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=12, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=6, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

688858c21e3beff2.png

Сверточные нейронные сети 101

В слое сверточной сети один «нейрон» выполняет взвешенную сумму пикселей прямо над ней, только через небольшую область изображения. Он добавляет смещение и питает сумму через функцию активации, так же как нейрон в обычном плотном слое. Эта операция затем повторяется по всему изображению, используя те же веса. Помните, что в плотных слоях у каждого нейрона были свои веса. Здесь один «патч» веса скользит по изображению в обоих направлениях («свертка»). Вывод имеет столько значений, сколько и пикселей в изображении (хотя на краях необходимо некоторая заполнение). Это операция фильтрации, используя фильтр 4x4x3 = 48 веса.

Тем не менее, 48 весов будут недостаточно. Чтобы добавить больше степеней свободы, мы повторяем ту же операцию с новым набором весов. Это создает новый набор выходов фильтра. Давайте назовем это «каналом» выходов по аналогии с каналами R, G, B на входном изображении.

Снимок экрана 2016-07-29 в 16.02.37.png

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

D1B557707BCD1CB9.png

Иллюстрация: сверточная нейронная сеть превращает «кубики» данных в другие «кубики» данных.

Подчеркнутые свертки, максимальное объединение

Выполняя свертывание с шагом 2 или 3, мы также можем уменьшить полученный кубик данных в его горизонтальных измерениях. Есть два распространенных способа сделать это:

  • Униженная свертка: скользящий фильтр, как указано выше, но с шагом> 1
  • MAX Pooling: раздвижное окно, применяющее максимальную работу (обычно на пятнах 2x2, повторяется каждые 2 пикселя)

2B2D4263BB8470B.GIF

Иллюстрация: скольжение вычислительного окна на 3 пикселя приводит к меньшему количеству выходных значений. Униженные сознания или максимальное объединение (максимум в окне 2x2, скользящего по шагу 2), являются способом сокращения куба данных в горизонтальных измерениях.

C Onevolutional Classifier

Наконец, мы прикрепляем классификационную головку, выравнивая последний куб данных и подав ее через плотный, активированный Softmax слой. Типичный сверточный классификатор может выглядеть так:

4A61AAFFB6CBA3D1.PNG

Иллюстрация: классификатор изображений с использованием слоев сверточного и софтмакса. Он использует фильтры 3x3 и 1x1. Слои MaxPool принимают максимум групп по точкам данных 2x2. Классификационная головка реализована с плотным слоем с активацией Softmax.

В Керас

Спрощающий стек, проиллюстрированный выше, может быть написан в керах, как это:

model = tf.keras.Sequential([
  # input: images of size 192x192x3 pixels (the three stands for RGB channels)    
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu', input_shape=[192, 192, 3]),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=32, padding='same', activation='relu'),
  tf.keras.layers.MaxPooling2D(pool_size=2),
  tf.keras.layers.Conv2D(kernel_size=3, filters=16, padding='same', activation='relu'),
  tf.keras.layers.Conv2D(kernel_size=1, filters=8, padding='same', activation='relu'),
  tf.keras.layers.Flatten(),
  # classifying into 5 categories
  tf.keras.layers.Dense(5, activation='softmax')
])

model.compile(
  optimizer='adam',
  loss= 'categorical_crossentropy',
  metrics=['accuracy'])

9. Ваша пользовательская конвнета

Практический

Давайте построим и тренируем сверточную нейронную сеть с нуля. Использование TPU позволит нам итерации очень быстро. Пожалуйста, откройте следующий ноутбук, выполните ячейки (введите сдвиг) и следуйте инструкциям, где бы вы ни видели этикетку «Требуется».

C3DF49E90E5A654F.PNG Keras_Flowers_TPU (playground).ipynb

Цель состоит в том, чтобы превзойти точность 75% модели обучения передачи. Эта модель имела преимущество, будучи предварительно обученным на наборе данных с миллионами изображений, в то время как у нас есть только 3670 изображений здесь. Вы можете хотя бы соответствовать этому?

Дополнительная информация

Сколько слоев, насколько велик?

Выбор размеров слоя - это скорее искусство, чем наука. Вы должны найти правильный баланс между слишком мало и слишком большим количеством параметров (веса и смещения). С слишком небольшим количеством весов нейронная сеть не может представлять сложность цветочных форм. С слишком многими, это может быть подвержено «переживлению», т.е. специализируется на учебных изображениях и не может обобщать. С большим количеством параметров, модель также будет медленно тренироваться. В Keras функция model.summary() отображает структуру и количество параметров вашей модели:

Layer (type)                 Output Shape              Param #   
=================================================================
conv2d (Conv2D)              (None, 192, 192, 16)      448       
_________________________________________________________________
conv2d_1 (Conv2D)            (None, 192, 192, 30)      4350      
_________________________________________________________________
max_pooling2d (MaxPooling2D) (None, 96, 96, 30)        0         
_________________________________________________________________
conv2d_2 (Conv2D)            (None, 96, 96, 60)        16260     
_________________________________________________________________
 ... 
_________________________________________________________________
global_average_pooling2d (Gl (None, 130)               0         
_________________________________________________________________
dense (Dense)                (None, 90)                11790     
_________________________________________________________________
dense_1 (Dense)              (None, 5)                 455       
=================================================================
Total params: 300,033
Trainable params: 300,033
Non-trainable params: 0
_________________________________________________________________

Пара советов:

  • Наличие нескольких слоев - это то, что делает «глубокие» нейронные сети эффективными. Для этой простой проблемы распознавания цветов от 5 до 10 слоев имеет смысл.
  • Используйте небольшие фильтры. Обычно фильтры 3x3 хороши везде.
  • Фильтры 1x1 также могут использоваться и дешевы. Они на самом деле не «фильтруют» ничего, кроме разбранных линейных комбинаций каналов. Чередовать их реальными фильтрами. (Подробнее о «1x1 -сверканиях» в следующем разделе.)
  • Для такой проблемы классификации, как эта, часто пример со слоями максимума (или совет с шагом> 1). Вас не волнует, где цветок, только то, что это роза или одуванчик, поэтому потеря информации о X и Y не важна, а фильтрация меньших участков дешевле.
  • Количество фильтров обычно становится аналогичным количеству классов в конце сети (почему? См. В мировом среднем комбайле »ниже). Если вы классифицируете сотни классов, постепенно увеличивайте количество фильтров в последовательных слоях. Для набора данных цветов с 5 классами фильтрации только с 5 фильтрами было бы недостаточно. Вы можете использовать тот же количество фильтров в большинстве слоев, например, 32 и уменьшить его к концу.
  • Последний плотный слой (ы)/дорогой. Это/они могут иметь больше веса, чем все сверточные слои вместе взятые. Например, даже с очень разумным выходом из последнего куба данных из точек данных 24x24x10, 100 нейронный плотный слой будет стоить 24x24x10x100 = 576 000 весов !!! Постарайтесь быть вдумчивым или попробовать средний глобальный бассейн (см. Ниже).

Средний глобальный объединение

Вместо того, чтобы использовать дорогой плотный слой в конце сверточной нейронной сети, вы можете разделить входящие данные «куб» на столько части, сколько у вас есть классы, средние их значения и подавать их с помощью функции активации Softmax. Этот способ построения классификационной головки стоит 0 весов. В Keras синтаксисом является tf.keras.layers.GlobalAveragePooling2D().

93240029f59df7c2.png

Решение

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

C3DF49E90E5A654F.PNG Keras_Flowers_TPU (solution).ipynb

Что мы рассмотрели

  • 🤔 Играет с сверточными слоями
  • 🤓 Экспериментировал с максимальным объединением, шагами, средним глобальным объединением, ...
  • 😀 Итерация на реальной модели быстро, на TPU

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

10. [Информация] Современные сверточные архитектуры

В двух словах

7968830b57b708c0.png

Иллюстрация: сверточный «модуль». Что лучше в этом этапе? Масл. Слои с последующим сверточным слоем 1x1 или другой комбинацией слоев? Попробуйте их все, объедините результаты и позвольте сети решать. Справа: « Начало » сверточная архитектура с использованием таких модулей.

В керах, чтобы создать модели, в которых поток данных может входить и выходить, вы должны использовать «функциональный» стиль модели. Вот пример:

l = tf.keras.layers # syntax shortcut

y = l.Conv2D(filters=32, kernel_size=3, padding='same',
             activation='relu', input_shape=[192, 192, 3])(x) # x=input image

# module start: branch out
y1 = l.Conv2D(filters=32, kernel_size=1, padding='same', activation='relu')(y)
y3 = l.Conv2D(filters=32, kernel_size=3, padding='same', activation='relu')(y)
y = l.concatenate([y1, y3]) # output now has 64 channels
# module end: concatenation

# many more layers ...

# Create the model by specifying the input and output tensors.
# Keras layers track their connections automatically so that's all that's needed.
z = l.Dense(5, activation='softmax')(y)
model = tf.keras.Model(x, z)

688858c21e3beff2.png

Другие дешевые трюки

Маленькие фильтры 3x3

40A7B15FB7DBE75C.PNG

На этой иллюстрации вы видите результат двух последовательных фильтров 3x3. Попробуйте отследить, какие точки данных внесли свой вклад в результат: эти два последовательных фильтра 3x3 вычислили некоторую комбинацию области 5x5. Это не точно такая же комбинация, которую вычислил бы фильтр 5x5, но его стоит попробовать, потому что два последовательных фильтра 3x3 дешевле, чем один фильтр 5x5.

1x1 Своения?

FD7CAC16F8ECB423.png

В математических терминах свертка «1x1» является умножением на постоянную, а не очень полезную концепцию. Однако в сверточных нейронных сетях помните, что фильтр применяется к кубу данных, а не только на 2D -изображение. Следовательно, фильтр «1x1» вычисляет взвешенную сумму столбца данных 1x1 (см. Иллюстрацию), и, когда вы продвигаете ее по данным, вы получите линейную комбинацию каналов ввода. Это на самом деле полезно. Если вы думаете о каналах как о результатах отдельных операций фильтрации, например, фильтр для «заостренных ушей», еще один для «усов» и третий для «щелей», то сверточный слой «1x1» будет вычислять много Возможные линейные комбинации этих функций, которые могут быть полезны при поиске «кошки». Кроме того, слои 1x1 используют меньше весов.

11. Squeezenet

Простой способ собрать эти идеи был продемонстрирован в бумаге "Squeezenet" . Авторы предлагают очень простую конструкцию модуля, используя только сверточные слои 1x1 и 3x3.

1730AC375379269B.PNG

Иллюстрация: архитектура Squeezenet на основе «пожарных модулей». Они чередуются 1x1 слой, который «сжимает» входящие данные в вертикальном измерении, за которым следует два параллельных сверточных слоях 1x1 и 3x3, которые снова «расширяют» глубину данных.

Практический

Продолжайте в своей предыдущей ноутбуке и создайте сверточную нейронную сеть, вдохновленную Squeezenet. Вам придется изменить код модели на керас «функциональный стиль».

C3DF49E90E5A654F.PNG Keras_Flowers_TPU (playground).ipynb

Дополнительная информация

Для этого упражнения будет полезно определить вспомогательную функцию для модуля Squeezenet:

def fire(x, squeeze, expand):
  y = l.Conv2D(filters=squeeze, kernel_size=1, padding='same', activation='relu')(x)
  y1 = l.Conv2D(filters=expand//2, kernel_size=1, padding='same', activation='relu')(y)
  y3 = l.Conv2D(filters=expand//2, kernel_size=3, padding='same', activation='relu')(y)
  return tf.keras.layers.concatenate([y1, y3])

# this is to make it behave similarly to other Keras layers
def fire_module(squeeze, expand):
  return lambda x: fire(x, squeeze, expand)

# usage:
x = l.Input(shape=[192, 192, 3])
y = fire_module(squeeze=24, expand=48)(x) # typically, squeeze is less than expand
y = fire_module(squeeze=32, expand=64)(y)
...
model = tf.keras.Model(x, y)

Цель на этот раз - достичь точности 80%.

Что стоит попробовать

Начните с одного сверточного слоя, затем следуйте с « fire_modules », чередующиеся с слоями MaxPooling2D(pool_size=2) . Вы можете экспериментировать с от 2 до 4 максимальных слоев объединения в сети, а также с 1, 2 или 3 последовательными пожарными модулями между максимальными слоями пула.

В огненных модулях параметр «сжатия» обычно должен быть меньше, чем параметр «развернуть». Эти параметры фактически являются числами фильтров. Они могут варьироваться от 8 до 196, обычно. Вы можете экспериментировать с архитектурами, где количество фильтров постепенно увеличивается через сеть, или простые архитектуры, где все пожарные модули имеют одинаковое количество фильтров.

Вот пример:

x = tf.keras.layers.Input(shape=[*IMAGE_SIZE, 3]) # input is 192x192 pixels RGB

y = tf.keras.layers.Conv2D(kernel_size=3, filters=32, padding='same', activation='relu')(x)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.MaxPooling2D(pool_size=2)(y)
y = fire_module(24, 48)(y)
y = tf.keras.layers.GlobalAveragePooling2D()(y)
y = tf.keras.layers.Dense(5, activation='softmax')(y)

model = tf.keras.Model(x, y)

На этом этапе вы можете заметить, что ваши эксперименты не так хорошо идут и что объектива точности 80% кажется удаленной. Время для нескольких дешевых трюков.

Нормализация партии

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

y = tf.keras.layers.BatchNormalization(momentum=0.9)(y)
# please adapt the input and output "y"s to whatever is appropriate in your context

Параметр импульса должен быть уменьшен с его значения по умолчанию от 0,99 до 0,9, потому что наш набор данных невелик. Не обращайте внимания на эту деталь на данный момент.

Увеличение данных

Вы получите еще пару процентных пунктов, увеличив данные с помощью простых преобразований, таких как левые правые переводы изменений насыщения:

4ed2958e09b487ca.png

AD795B70334E0D6B.PNG

Это очень легко сделать в Tensorflow с API TF.Data.Dataset. Определите новую функцию преобразования для ваших данных:

def data_augment(image, label):
    image = tf.image.random_flip_left_right(image)
    image = tf.image.random_saturation(image, lower=0, upper=2)
    return image, label

Затем используйте его в окончательном преобразовании данных (ячейка «Наборы данных обучения и проверки», функция "get_batched_dataset"):

dataset = dataset.repeat() # existing line
# insert this
if augment_data:
  dataset = dataset.map(data_augment, num_parallel_calls=AUTO)
dataset = dataset.shuffle(2048) # existing line

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

Точность 80% в 35 эпохах теперь должна быть в пределах досягаемости.

Решение

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

C3DF49E90E5A654F.PNG Keras_Flowers_TPU_squeezenet.ipynb

Что мы рассмотрели

  • 🤔 модели кераса «функциональный стиль»
  • Architecture Architecture
  • 🤓 Увеличение данных с помощью tf.data.datset

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

12. xception тонко настроен

Разделяемые свертки

Другой способ реализации сверточных слоев в последнее время набирал популярность: разветвления глубины. Я знаю, это глоток, но концепция довольно проста. Они реализованы в Tensorflow и Keras как tf.keras.layers.SeparableConv2D .

Разделимая свертка также запускает фильтр на изображении, но использует отдельный набор весов для каждого канала входного изображения. Это следует с «сверткой 1x1», серией точечных продуктов, приводящих к взвешенной сумме отфильтрованных каналов. С новыми весами каждый раз, так как многие взвешенные рекомбинации каналов рассчитываются по мере необходимости.

615720b803bf8dda.gif

Иллюстрация: разделяемые свертки. Фаза 1: Совещания с отдельным фильтром для каждого канала. Фаза 2: Линейные рекомбинации каналов. Повторяется с новым набором весов до тех пор, пока не будет достигнуто желаемое количество выходных каналов. Фаза 1 также может повторяться, с новыми весами каждый раз, но на практике это редко.

Разделимые свертки используются в самых последних архитектурах сверточных сетей: MobilenetV2, Xcept, EfficeNet. Кстати, MobilEnetV2 - это то, что вы использовали для перевода обучения ранее.

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

Сверточный слой: 4 x 4 x 3 x 5 = 240

Разделимый сверточный слой: 4 x 4 x 3 + 3 x 5 = 48 + 15 = 63

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

Практический

Перезапустите из ноутбука «Transfer Learning Learning», но на этот раз выберите Xcept в качестве предварительно обученной модели. XCEPTE использует только отдельные свертки. Оставьте все веса обучения. Мы будем настраивать предварительно обученные веса на наших данных вместо использования предварительно обученных слоев как таковых.

C3DF49E90E5A654F.PNG Keras Flowers transfer learning (playground).ipynb

Цель: Точность> 95% (нет, серьезно, это возможно!)

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

Дополнительная информация о тонкой настройке

Xception доступен в стандартных предварительно обученных моделях в tf.keras.application.* Не забудьте оставлять все веса на этот раз.

pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3],
                                                  include_top=False)
pretrained_model.trainable = True

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

9b1af213b2b36d47.png

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

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

def lr_fn(epoch):
  lr = ...
  return lr

lr_callback = tf.keras.callbacks.LearningRateScheduler(lr_fn, verbose=True)

model.fit(..., callbacks=[lr_callback])

Решение

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

C3DF49E90E5A654F.PNG 07_Keras_Flowers_TPU_xception_fine_tuned_best.ipynb

Что мы рассмотрели

  • 🤔 Глубина, разделяющая свертка
  • 🤓 Графики курса обучения
  • 😈 Точная настройка предварительно обученной модели.

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

13. Поздравляю!

Вы построили свою первую современную сверточную нейронную сеть и обучили ее до 90% + точность, итерация на последующих тренировочных пробегах всего за минуты благодаря TPU.

TPU на практике

TPU и графические процессоры доступны в Google Cloud Vertex Ai :

Наконец, мы любим обратную связь. Пожалуйста, скажите нам, если вы видите что -то не так, как в этой лаборатории или вы думаете, что это должно быть улучшено. Обратная связь может быть предоставлена ​​с помощью проблем GitHub [ ссылка на обратную связь ].

Hr.png

Martin Görner id small.jpg
Автор: Мартин Горнер
Twitter: @martin_gorner