Создание собственного классификатора изображений с помощью transfer Обучение
Оглавление
- Сводка
- Установка
- Запуск примера — обучение классификатора цветов
- Создание собственного пользовательского классификатора образов
- Использование другой базовой модели
Сводка
Приведенные выше образы — это тестовые образы, используемые во второй части этого руководства. Задача состоит в том, чтобы обучить классификатор, который может различать различные категории изображений (в нашем примере овец и волков), изменив существующую модель классификатора — базовую модель. Здесь мы используем ResNet_18 модель, которая была обучена в корпусе ImageNet. Мы обучаем только 15 изображений на класс за несколько секунд и прогнозируем все 10 тестовых изображений правильно (обратите внимание на несколько зерен соли).
Ниже приведены основные ресурсы для учебника по передаче обучения.
Рецепт | TransferLearning.py и TransferLearning_Extended.py (см . примеры/ Image/TransferLearning). |
предварительно обученные модели | В качестве базовой модели для передачи обучения мы используем предварительно обученную модель ResNet_18. |
Данные | Набор данных "Цветы" с 102 категориями и примерами изображений овец и волков (см. раздел "Настройка"). |
Запуск | Следуйте описанию ниже. |
Настройка
Чтобы запустить код в этом примере, требуется среда CNTK Python (см. здесь справку по настройке).
Чтобы скачать необходимые данные и предварительно обученную модель, выполните следующую команду в папке Examples/Image/TransferLearning :
python install_data_and_model.py
Выполнение примера
В этом разделе мы создадим классификатор для набора данных «Цветы». Набор данных был создан группой визуальных геометрий в Оксфордском университете для задач классификации изображений. Он состоит из 102 различных категорий цветов, общих для Великобритании, и содержит примерно 8000 изображений, которые разделены на три набора раз 6000 и дважды 1000 изображений. Дополнительные сведения см. на домашней странице VGG.
Обучение и оценка модели обучения передачи в наборе данных "Цветы"
python TransferLearning.py
Модель достигает 93 % точности набора данных Цветов после обучения на 20 эпох.
Базовая концепция передачи обучения
При использовании базовой модели для передачи обучения мы по существу опираемся на функции и концепции, которые были изучены во время обучения базовой модели. Для сверточных DNN, ResNet_18 в нашем случае, это означает, например, что мы отрезаем последний плотный слой, отвечающий за прогнозирование меток классов исходной базовой модели и заменяем его новым плотным слоем, который будет прогнозировать метки классов нашей новой задачи. Входные данные старого и нового слоя прогнозирования одинаковы, мы просто повторно будем использовать обученные функции. Затем мы обучим эту измененную сеть, либо только новые весовые коэффициенты нового слоя прогнозирования, либо все весовые коэффициенты всей сети.
Следующий код является частью TransferLearning.py
, которая создает новую модель на основе базовой модели:
# Load the pretrained classification net and find nodes
base_model = load_model(base_model_file)
feature_node = find_by_name(base_model, feature_node_name)
last_node = find_by_name(base_model, last_hidden_node_name)
# Clone the desired layers with fixed weights
cloned_layers = combine([last_node.owner]).clone(
CloneMethod.freeze if freeze else CloneMethod.clone,
{feature_node: Placeholder(name='features')})
# Add new dense layer for class prediction
feat_norm = input_features - Constant(114)
cloned_out = cloned_layers(feat_norm)
z = Dense(num_classes, activation=None, name=new_output_node_name) (cloned_out)
Создание собственного пользовательского классификатора образов
В предыдущем разделе мы обучили классификатор, который отличает 102 различных категорий цветов с использованием примерно 6000 изображений для обучения. В этом разделе мы будем использовать только 15 изображений на категорию для создания классификатора, который может сообщить волку от овец. Мы используем ту же ResNet_18
базовую модель для передачи обучения. Обучение и оценка запуска модели
python TransferLearning_Extended.py
Модель проверяется на пяти изображениях овец и волков и прогнозирует все метки правильно. Выходной файл содержит в строке представление результатов прогнозирования в формате JSON:
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":0.997, "Wolf":0.003}, "image": "..."}]
[{"class": "Sheep", "predictions": {"Sheep":1.000, "Wolf":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "Wolf", "predictions": {"Wolf":1.000, "Sheep":0.000}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.994, "Wolf":0.006}, "image": "..."}]
[{"class": "unknown", "predictions": {"Sheep":0.614, "Wolf":0.386}, "image": "..."}]
[{"class": "unknown", "predictions": {"Wolf":0.980, "Sheep":0.020}, "image": "..."}]
Обратите внимание, что на последних трех изображениях не назначен класс правды, который, конечно, является допустимым сценарием, например для оценки незамеченных изображений в веб-службе. Фактические изображения — это три изображения птиц, показанные ниже. Для них в выходных данных JSON задается unknown
класс истинности. Обратите внимание, что прогнозы для концепций, на которых классификатор был обучен, довольно хорошо, несмотря на несколько обучающих изображений. Это происходит в больших частях из-за предварительно обученной базовой модели. Прогнозы на невидимые понятия, например изображения птиц, конечно, не очень значимы, так как классификатор знает только овец и волков. Подробнее об этом позже.
Структура папок для пользовательских наборов образов
Скрипт можно использовать TransferLearning_Extended.py
с собственными образами. Вот что вам нужно:
class_mapping
— Массив, содержащий имена категорий, например.['wolf', 'sheep']
train_map_file
— Текстовый файл, содержащий каждую строку, сначала URL-адрес изображения и вкладка разделяют соответствующий индекс категории, например0
для волка или1
для овец:test_map_file
— текстовый файл, который сопоставляет тестовые изображения с соответствующей категорией. Для неизвестных категорий в тестовых образах используется-1
в качестве индекса категорий.
Скрипт может создать все три элемента выше, если вы структурируете изображения следующим образом:
<image root folder>
Train
Sheep
Wolf
Test
Sheep
Wolf
<optional: image files with unknown label directly here>
См <cntk root>/Examples/Image/DataSets/Animals/
. пример. Каждая вложенная папка в папке Train
будет считаться одной категорией (только один уровень, без рекурсии). Для обучения отдельных образов в корневой папке Train
игнорируются, так как у них нет назначенной категории. Дополнительные вложенные папки в папке Test
, которые не происходят в папке Train
, игнорируются. Для тестирования отдельных некатегоризированных изображений также используются для оценки, т. е. изображений, которые хранятся непосредственно в папке Test
, как три изображения птиц в нашем примере.
Чтобы использовать папки пользовательских образов, необходимо задать train_image_folder
и test_image_folder
в верхней части скрипта TransferLearning_Extended.py
:
# define data location and characteristics
train_image_folder = "<your_image_root_folder>/Train"
test_image_folder = "<your_image_root_folder>/Test"
Затем просто запустите python TransferLearning_Extended.py
. Использование другой базовой модели описано ниже.
Для оценки вам не нужно использовать test_map_file
, например, если вы хотите оценить отдельные изображения по одному. Просто загрузите обученную модель обучения передачи один раз, а затем вызовите eval_single_image
каждый раз, когда вы хотите получить прогнозы для нового изображения:
# once:
# load the trained transfer learning model
trained_model = load_model(new_model_file)
# for every new image:
# get predictions for a single image
probs = eval_single_image(trained_model, img_file, image_width, image_height)
Несколько зерен соли
Обучающие образы должны охватывать достаточно сценариев, которые вы хотите оценить позже. Если классификатор видит совершенно новые концепции или контексты, скорее всего, будет плохо работать. Всего несколько примеров:
- Вы обучаете только изображения из среды ограничения (скажем, в помещении) и пытаетесь оценить изображения из другой среды (на открытом воздухе).
- Вы обучаетесь только на изображениях определенного сделать и попытаться забить других.
- Тестовые изображения имеют в значительной степени различные характеристики, например, относительно освещения, фона, цвета, размера, положения и т. д.
- Тестовые образы содержат совершенно новые концепции.
Добавление категории catch-all может быть хорошей идеей, но только в том случае, если обучающие данные для этой категории содержат изображения, которые снова достаточно похожи на изображения, ожидаемые во время оценки. Как и в приведенном выше примере, если мы обучим классификатор с изображениями овец и волков и используем его для оценки изображения птицы, классификатор может по-прежнему назначать только метку овец или волка, так как он не знает других категорий. Если бы мы добавили категорию catch-all и добавить к ней обучающие изображения птиц, классификатор может правильно предсказать класс для изображения птицы. Тем не менее, если мы представляем его, например, изображение автомобиля, он сталкивается с той же проблемой, что и раньше, как он знает только овец, волка и птицы (что мы только что случилось, чтобы назвать catch-all). Таким образом, ваши обучающие данные, также для catch-all, должны охватывать достаточно эти концепции и изображения, которые вы ожидаете позже во время оценки.
Другой аспект, который следует учитывать, заключается в том, что определенная базовая модель может работать очень хорошо для некоторых задач обучения, а не так хорошо для других. Например, приведенная выше ResNet_18
модель предварительно обучена на корпусе ImageNet, который содержит множество изображений животных, людей, автомобилей и многих других объектов каждый день. Использование этой базовой модели при передаче обучения для создания классификатора для аналогичных объектов каждый день может хорошо работать. Использование той же модели, что и базовая модель для создания классификатора для изображений микроорганизмов или рисунков карандаша, может дать только посредственные результаты.
Использование другой базовой модели
Чтобы использовать другую модель в качестве базовой модели, необходимо адаптировать следующие параметры в TransferLearning.py
(то же самое для TransferLearning_Extended.py
):
# define base model location and characteristics
_base_model_file = os.path.join(base_folder, "..", "..", "..", "PretrainedModels", "ResNet_18.model")
_feature_node_name = "features"
_last_hidden_node_name = "z.x"
_image_height = 224
_image_width = 224
_num_channels = 3
Чтобы изучить, какие имена узлов находятся в модели и какие из них следует выбрать, так как last_hidden_node
можно распечатать все имена узлов и фигуры узлов, используя следующие строки (см __main__
. метод в TransferLearning.py
):
# You can use the following to inspect the base model and determine the desired node names
node_outputs = get_node_outputs(load_model(_base_model_file))
for out in node_outputs: print("{0} {1}".format(out.name, out.shape))