Автор: Hide Inada

Постановка задачи

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

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

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

Он сказал: «Тебе не должно быть так сложно, да!»

Вы хотите обучить как минимум десятки тысяч изображений, что может занять несколько дней. Мало того, вы не совсем уверены в настройках гиперпараметров, поэтому настройка может увеличить время, необходимое для обучения. Кроме того, вы даже не знаете, есть ли у вашей компании достаточно мощное оборудование, чтобы провести это обучение достаточно быстро. Вы помните, когда вы попросили NVIDIA DGX-1 и сказали своему менеджеру цену, ваш менеджер был так шокирован и разлил кофе на ваш стол.

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

Помимо того, что вы порекомендуете своему руководителю пройти курс «Менеджмент 101», вы можете что-нибудь сделать, чтобы уложиться в этот сумасшедший срок?

Да, возможно. Возможно, вам подойдет трансферное обучение.

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

Отказ от ответственности

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

1. Концепция

Обучение модели требует значительных машинных ресурсов и времени, особенно когда много слоев. Например, Inception-v3 имеет 42 слоя [1]. Однако есть способ сократить тренировочный процесс. Это называется трансферным обучением. Ниже показана стандартная сетевая архитектура:

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

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

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

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

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

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

Итак, что вам нужно:

  1. Модель с предварительно натренированными весами
  2. Новый слой с матрицей и смещениями для классификации ваших изображений

Что касается первого, то хорошей новостью является то, что команда TensorFlow предоставила для этого различные предварительно обученные модели на своем веб-сайте под названием TensorFlow Hub.

Для второго они также сделали доступным скрипт под названием «retrain.py» для автоматизации создания и обучения этого нового слоя. Этот скрипт также автоматически загружает предварительно натренированные веса на ваш компьютер, поэтому в основном вам нужно выполнить следующие два шага:

  1. Настройте набор данных с изображениями в вашей файловой системе
  2. Запустите retrain.py

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

2. Шаги по обучению модели.

В этом разделе я подробно рассмотрю два основных этапа.

2.1. Настройте набор данных в вашей файловой системе

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

top image directory
--- image category label 1
------ jpeg files in that category 1
------ jpeg file in that category 1
------ jpeg file in that category 1
...
--- image category label 2
------ jpeg file in that category 2
------ jpeg file in that category 2
------ jpeg file in that category 2
...

Например,

food_images
--- burrito
------ burrito1.jpg
------ burrito2.jpg
...
--- sushi
------ sushi1.jpg
------ sushi2.jpg
...

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

Вы можете использовать любой набор данных, но я использовал набор данных Food-101. Если вы хотите использовать этот набор данных, см. Страницу ниже: https://github.com/hideyukiinada/transfer-learning/blob/master/food101.md

2.2. Обучение с использованием retrain.py

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

  • retrain.py
  • label_img.py

retrain.py и label_img.py были разработаны командой TensorFlow и лицензированы в соответствии с условиями, указанными в верхней части каждого файла.

Если вы хотите проверить наличие более новой версии, вы можете проверить репозитории hub и tensorflow:

git clone https://github.com/tensorflow/hub
diff hub/examples/image_training/retrain.py <path to this retrain.py>
git clone https://github.com/tensorflow/tensorflow
diff tensorflow/tensorflow/examples/label_image/label_image.py <path to this label_img.py>

После того, как у вас есть retrain.py на локальном диске, запустите его с именем каталога изображений верхнего уровня, указанным в параметре - image_dir. Например, если ваши изображения расположены в food_images, введите:

python retrain.py --image_dir=food_images

Если вы клонируете это репо, вы также можете использовать мою оболочку под названием train.bash

#!/bin/bash
# Replace the directory name after the --image_dir
export TFHUB_CACHE_DIR=/tmp/food101/module_cache
time python retrain.py --image_dir=../../../dataset/food101/food-101/images

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

Начнется тренировка.

Когда сценарий будет завершен, проверьте вывод в следующих каталогах:

  • /tmp/output_labels.txt
  • /tmp/output_graph.pb

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

2.3. Предсказывать

Если вы клонировали это репо, вы можете использовать predik.bash. Это оболочка, которая вызывает label_image.py с набором параметров:

#!/bin/bash
python label_image.py \
--graph=/tmp/output_graph.pb \
--labels=/tmp/output_labels.txt \
--input_layer=Placeholder \
--output_layer=final_result \
--image=$1 2>/dev/null

Например, если вы хотите предсказать класс изображения, burger.jpg, введите:

./predict.bash burger.jpg

Вот фактический результат против изображения в верхней части этой статьи:

3. Внутри retrain.py

3.1. Лицензия

Поскольку я просматриваю некоторую часть кода, вот лицензия на код от команды TensorFlow:

# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ==============================================================================
# NOTICE: This work was derived from tensorflow/examples/image_retraining
# and modified to use TensorFlow Hub modules.

3.2. Терминология

Команда TensorFlow использует слово «модуль» для обозначения «автономного фрагмента графа TensorFlow вместе с его весами» [3]. В этом разделе я буду следовать этому соглашению.

3.3. Обзор предметов высокого уровня

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

  1. Проверить аргументы командной строки
  2. Очистите каталог журналов TensorBoard и убедитесь, что он существует (prepare_file_system ())
  3. Убедитесь, что каталог для хранения промежуточного графа существует, если частота хранения указана как больше 0 (prepare_file_system ())
  4. Прочтите каталог и подкаталоги изображений, получите список файлов JPEG в каждом подкаталоге и разделите набор файлов на наборы для обучения, проверки и тестирования в соответствии с соотношением, указанным в аргументах командной строки (create_image_lists ()). Логика разделения набора данных заключается в вычислении хэш-значения каждого имени файла. Каждый хэш преобразуется в int и сопоставляется с диапазоном 0–100 для сравнения с соотношениями валидации и тестового набора, указанными в командной строке.
  5. Определите, указан ли какой-либо аргумент командной строки для увеличения данных (should_distort_images ())
  6. Если они еще не найдены в локальном кеше, загрузите файлы модуля с веб-сайта TensorFlow Hub. Создайте экземпляр ModuleSpec с загруженной моделью и путем к загруженным весам ((hub.load_module_spec ())). Подробную информацию о загрузке см. в atomic_download (), определенном в tensorflow_hub / resolver.py.
  7. Создайте экземпляр объекта Module из ModuleSpec и получите последний слой модуля (create_module_graph ())
  8. Добавьте выходной слой для классификации вашего пользовательского набора данных (add_final_retrain_ops ())
  9. Добавьте операции для изменения размера данных JPEG до размера, ожидаемого модулем (add_jpeg_decoding ())
  10. Если в командной строке указана какая-либо опция увеличения данных, обрезайте, отразите по горизонтали и / или отрегулируйте яркость изображения (add_input_distortions)
  11. Если опция увеличения данных не указана, распространить данные изображения по сети до уровня узких мест и записать значения в файловую систему (cache_bottlenecks)
  12. Добавьте операции для расчета точности путем сравнения прогнозов и фактов и взятия среднего значения (add_evaluation_step ())
  13. Объедините статистику, которую вы хотите показать в TensorBoard, и направьте вывод журнала статистики в файловую систему, создав экземпляры объектов FileWriter.
  14. Создайте экземпляр tf.train.Saver, чтобы подготовиться к экономии веса во время тренировки
  15. Тренируйтесь, повторяя следующие шаги (16–20):
  16. Если указано увеличение данных, считайте каждый файл изображения из файловой системы, примените увеличение данных, перейдите на уровень узких мест (get_random_distorted_bottlenecks ())
  17. Если нет, прочтите кэшированные значения слоя узких мест для каждого изображения из файловой системы (get_random_cached_bottlenecks)
  18. Подайте на график значения узких мест и достоверную информацию и оптимизируйте, используя градиентный спуск, как определено в add_final_retrain_ops
  19. В заранее заданном интервале, расчет точности обучения и точности проверки
  20. В заранее заданном интервале сохранить промежуточный график и веса
  21. По окончании тренировки сохраните веса.
  22. Прогнозирование по набору тестов для измерения точности (run_final_eval ())
  23. Сериализуйте график и сохраните его в файловой системе (save_graph_to_file ())
  24. Если указано в командной строке, сохранять метки в файловой системе
  25. Если указано в командной строке, сохраните модель для обслуживания TensorFlow serve (export_model ()). Обратите внимание, что эта функция использует устаревшую функцию tf.saved_model.simple_save (), поэтому вы можете обновить ее в будущем.

3.4. Модуль

По умолчанию модуль по умолчанию для загрузки и повторного обучения установлен на https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1.
Это можно изменить с помощью аргумента - tfhub_module:

parser.add_argument(
      '--tfhub_module',
      type=str,
      default=(
          'https://tfhub.dev/google/imagenet/inception_v3/feature_vector/1'),
      help="""\
      Which TensorFlow Hub module to use. For more options,
      search https://tfhub.dev for image feature vector modules.\
      """)

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

Перед вызовом retrain.py я указал в скрипте каталог кеша модуля TFHUB:

export TFHUB_CACHE_DIR=/tmp/food101/module_cache

В tensorflow_hub / resolver.py есть функция tfhub_cache_dir (), которая извлекает имя каталога кеша из этой переменной среды, если она определена. (Вы найдете этот файл в каталоге пакетов сайта virtualenv, если вы используете virtualenv).

После запуска скрипта / tmp / food101 / module_cache будет содержать:

/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763/variables
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763/variables/variables.index
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763/variables/variables.data-00000-of-00001
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763/assets
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763/saved_model.pb
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763/tfhub_module.pb
/tmp/food101/module_cache/11d9faf945d073033780fd924b2b09ff42155763.descriptor.txt

3.5. Прямое распространение

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

Первая часть - вычислить значения слоя узкого места для каждого изображения. Если вы не используете увеличение данных, это делается только один раз для выполнения скрипта в функции run_bottleneck_on_image (). Значения кэшируются в файловой системе.

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

3.6 Определение матрицы и смещений для последнего слоя

Матрица и смещения для последнего слоя определяются add_final_retrain_ops ():

layer_name = 'final_retrain_ops'
  with tf.name_scope(layer_name):
    with tf.name_scope('weights'):
      initial_value = tf.truncated_normal(
          [bottleneck_tensor_size, class_count], stddev=0.001)
      layer_weights = tf.Variable(initial_value, name='final_weights')
      variable_summaries(layer_weights)
    with tf.name_scope('biases'):
      layer_biases = tf.Variable(tf.zeros([class_count]), name='final_biases')
      variable_summaries(layer_biases)
    with tf.name_scope('Wx_plus_b'):
      logits = tf.matmul(bottleneck_input, layer_weights) + layer_biases
      tf.summary.histogram('pre_activations', logits)
  final_tensor = tf.nn.softmax(logits, name=final_tensor_name)

Как видите, это очень простая операция.

4. Заключительные слова

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

использованная литература

[1] Кристиан Сегеди и др. Переосмысление начальной архитектуры компьютерного зрения. Https://www.cv-foundation.org/openaccess/content_cvpr_2016/papers/Szegedy_Rethinking_the_Inception_CVPR_2016_paper.pdf, 2016.

[2] Команда TensorFlow. Как перенастроить классификатор изображений для новых категорий. Https://www.tensorflow.org/hub/tutorials/image_retraining.

[3] Джош Гордон. Представляем TensorFlow Hub: библиотеку для многоразовых модулей машинного обучения в TensorFlow. Https://medium.com/tensorflow/introduction-tensorflow-hub-a-library-for-reusable-machine-learning-modules-in-tensorflow-cdee41fa18f9, 2018.