Практика распознавания цветов, основанная на глубоком обучении и трансферном обучении

искусственный интеллект глубокое обучение Нейронные сети модульный тест

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

В этой статье будет продемонстрировано, как использовать трансферное обучение для обучения модели, которая может классифицировать различные виды цветов по изображениям, и может достичь точности более 80% для пяти видов цветов (на 60% выше, чем слепой Мэн), и для этого требуется только An обычный домашний компьютер может завершить процесс обучения.

flower

Что такое трансферное обучение

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

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

autopilot_car

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

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

Представляем ВГГ

VGG — модель-победитель конкурса ILSVRC в поле зрения в 2014 году с частотой ошибок 7,3% в наборе данных ImageNet, что значительно побило мировой рекорд предыдущего года в 11,7%. VGG16 в основном наследует AlexNetглубокийидеи и двигаться вперед, чтобы достичьГлубже. AlexNet использует только 8-уровневую сеть, в то время как две версии VGG представляют собой 16-уровневую сетевую версию и 19-уровневую сетевую версию. В следующей практике трансферного обучения мы будем использовать немного более простой VGG16, который имеет почти такую ​​же точность, как VGG19, но быстрее.

Структурная схема VGG выглядит следующим образом:

vgg_architecture

Формат входных данных VGG - данные пикселей 244 * 224 * 3. После серии сверточных нейронных сетей и обработки объединенных сетей выходные данные представляют собой 4096-мерные данные признаков, а затем через трехуровневую полносвязную обработку нейронной сети, и, наконец, результаты классификации получаются путем нормализации softmax.

softmax_demo

Модель VGG16 может пройтиСкачать здесь(пароль 78g9), модель представляет собой файл .npy, который по сути представляет собой огромный объект numpy, содержащий все параметры модели VGG16.Файл имеет размер около 500 МБ, поэтому видно, что обучение таких модель с нуля, с помощью идеи трансферного обучения мы можем напрямую обучаться на основе этой модели.

Далее мы немного объясним о сверточных нейронных сетях и сетях объединения:

Сверточная нейронная сеть

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

convolutional nn

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

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

layer1

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

layer2

Третий уровень изучает некоторые простые объекты, такие как шины и лица.

layer3

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

layer5

Максимальное объединение и выпадение

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

pooling

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

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

Набор данных распознавания цветов

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

Набор данных содержит следующие данные:

вид цветка Количество картинок (шт.)
daisy 633
dandelion 898
roses 641
sunflowers 699
tulips 799

передача практики обучения

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

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

Поэтому, по сути, мы используем VGG16 в качестве экстрактора признаков изображения, а затем выполняем на этой основе обычное обучение нейронной сети, так что исходные данные измерения 244*224*3 преобразуются в 4096 измерений, и каждый объем информации в одно измерение значительно улучшено, что значительно снижает потребление вычислительных ресурсов и реализует применение знаний, полученных при обучении распознаванию объектов, к специальным задачам классификации цветов.

файловая структура

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

Сначала убедитесь, что в рабочем каталоге, где работает код или блокнот Jupyter, есть цветок.фотографии, тензорный потокvgg Эти две папки представляют собой набор данных цветов и тензорный поток.vgg, затем скопируйте ранее загруженный VGG16 в tensorflowпапка вгг.

├── transfer_learning.py(运行代码)
├── flower_phtots
│   ├── daisy
│   ├── dandelion
│   ├── roses
│   └── ...
└── tensorflow_vgg
    ├── vgg16.py
    ├── vgg16.npy
    └── ...

Затем импортируйте необходимые модули Python

import os
import numpy as np
import tensorflow as tf

from tensorflow_vgg import vgg16
from tensorflow_vgg import utils

Загрузите набор данных распознавания цветов

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

data_dir = 'flower_photos/'
contents = os.listdir(data_dir)
classes = [each for each in contents if os.path.isdir(data_dir + each)]

Собственные значения, рассчитанные с помощью VGG16

# 首先设置计算batch的值,如果运算平台的内存越大,这个值可以设置得越高
batch_size = 10
# 用codes_list来存储特征值
codes_list = []
# 用labels来存储花的类别
labels = []
# batch数组用来临时存储图片数据
batch = []

codes = None

with tf.Session() as sess:
    # 构建VGG16模型对象
    vgg = vgg16.Vgg16()
    input_ = tf.placeholder(tf.float32, [None, 224, 224, 3])
    with tf.name_scope("content_vgg"):
        # 载入VGG16模型
        vgg.build(input_)
    
    # 对每个不同种类的花分别用VGG16计算特征值
    for each in classes:
        print("Starting {} images".format(each))
        class_path = data_dir + each
        files = os.listdir(class_path)
        for ii, file in enumerate(files, 1):
            # 载入图片并放入batch数组中
            img = utils.load_image(os.path.join(class_path, file))
            batch.append(img.reshape((1, 224, 224, 3)))
            labels.append(each)
            
            # 如果图片数量到了batch_size则开始具体的运算
            if ii % batch_size == 0 or ii == len(files):
                images = np.concatenate(batch)

                feed_dict = {input_: images}
                # 计算特征值
                codes_batch = sess.run(vgg.relu6, feed_dict=feed_dict)
                
                # 将结果放入到codes数组中
                if codes is None:
                    codes = codes_batch
                else:
                    codes = np.concatenate((codes, codes_batch))
                
                # 清空数组准备下一个batch的计算
                batch = []
                print('{} images processed'.format(ii))

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

Эти два массива можно сохранить на диск с помощью следующего кода:

with open('codes', 'w') as f:
    codes.tofile(f)
    
import csv
with open('labels', 'w') as f:
    writer = csv.writer(f, delimiter='\n')
    writer.writerow(labels)

Подготовьте обучающий набор, проверочный набор и тестовый набор

Тщательное обучение модели должно включать проверку и тестирование. Сначала я заменил категориальные метки в массиве меток на One Hot Encode.

from sklearn.preprocessing import LabelBinarizer

lb = LabelBinarizer()
lb.fit(labels)

labels_vecs = lb.transform(labels)

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

from sklearn.model_selection import StratifiedShuffleSplit

ss = StratifiedShuffleSplit(n_splits=1, test_size=0.2)

train_idx, val_idx = next(ss.split(codes, labels))

half_val_len = int(len(val_idx)/2)
val_idx, test_idx = val_idx[:half_val_len], val_idx[half_val_len:]

train_x, train_y = codes[train_idx], labels_vecs[train_idx]
val_x, val_y = codes[val_idx], labels_vecs[val_idx]
test_x, test_y = codes[test_idx], labels_vecs[test_idx]

print("Train shapes (x, y):", train_x.shape, train_y.shape)
print("Validation shapes (x, y):", val_x.shape, val_y.shape)
print("Test shapes (x, y):", test_x.shape, test_y.shape)

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

Train shapes (x, y): (2936, 4096) (2936, 5)
Validation shapes (x, y): (367, 4096) (367, 5)
Test shapes (x, y): (367, 4096) (367, 5)

обучать сеть

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

# 输入数据的维度
inputs_ = tf.placeholder(tf.float32, shape=[None, codes.shape[1]])
# 标签数据的维度
labels_ = tf.placeholder(tf.int64, shape=[None, labels_vecs.shape[1]])

# 加入一个256维的全连接的层
fc = tf.contrib.layers.fully_connected(inputs_, 256)

# 加入一个5维的全连接层
logits = tf.contrib.layers.fully_connected(fc, labels_vecs.shape[1], activation_fn=None)

# 计算cross entropy值
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(labels=labels_, logits=logits)

# 计算损失函数
cost = tf.reduce_mean(cross_entropy)

# 采用用得最广泛的AdamOptimizer优化器
optimizer = tf.train.AdamOptimizer().minimize(cost)

# 得到最后的预测分布
predicted = tf.nn.softmax(logits)

# 计算准确度
correct_pred = tf.equal(tf.argmax(predicted, 1), tf.argmax(labels_, 1))
accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32))

Для удобного разделения данных на пакеты для уменьшения использования памяти можно также использовать функцию для создания пакетов.

def get_batches(x, y, n_batches=10):
    """ 这是一个生成器函数,按照n_batches的大小将数据划分了小块 """
    batch_size = len(x)//n_batches
    
    for ii in range(0, n_batches*batch_size, batch_size):
        # 如果不是最后一个batch,那么这个batch中应该有batch_size个数据
        if ii != (n_batches-1)*batch_size:
            X, Y = x[ii: ii+batch_size], y[ii: ii+batch_size] 
        # 否则的话,那剩余的不够batch_size的数据都凑入到一个batch中
        else:
            X, Y = x[ii:], y[ii:]
        # 生成器语法,返回X和Y
        yield X, Y

Теперь вы можете запустить обучение,

# 运行多少轮次
epochs = 20
# 统计训练效果的频率
iteration = 0
# 保存模型的保存器
saver = tf.train.Saver()
with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    for e in range(epochs):
        for x, y in get_batches(train_x, train_y):
            feed = {inputs_: x,
                    labels_: y}
            # 训练模型
            loss, _ = sess.run([cost, optimizer], feed_dict=feed)
            print("Epoch: {}/{}".format(e+1, epochs),
                  "Iteration: {}".format(iteration),
                  "Training loss: {:.5f}".format(loss))
            iteration += 1
            
            if iteration % 5 == 0:
                feed = {inputs_: val_x,
                        labels_: val_y}
                val_acc = sess.run(accuracy, feed_dict=feed)
                # 输出用验证机验证训练进度
                print("Epoch: {}/{}".format(e, epochs),
                      "Iteration: {}".format(iteration),
                      "Validation Acc: {:.4f}".format(val_acc))
    # 保存模型
    saver.save(sess, "checkpoints/flowers.ckpt")

тестовая сеть

Следующим шагом является использование тестового набора для проверки эффекта модели.

with tf.Session() as sess:
    saver.restore(sess, tf.train.latest_checkpoint('checkpoints'))
    
    feed = {inputs_: test_x,
            labels_: test_y}
    test_acc = sess.run(accuracy, feed_dict=feed)
    print("Test accuracy: {:.4f}".format(test_acc))

В конце концов я получил точность 88,83% на своем компьютере, вы можете продолжить настройку размера пакета или структуры модели, чтобы получить лучший результат.

Для этой фотографии одуванчика с семизвездной божьей коровкой

dadelion_test

Прогнозируемые значения, данные моделью, следующие:

dadelion_test_result

Видно, что эффект модели довольно стабилен, а наше время расчета во всем процессе составляет всего более 30 минут, в чем прелесть трансферного обучения.

P.S

Конечно, другие фреймворки глубокого обучения также могут легко реализовать трансферное обучение, например здесь.Код КерасаРеализован классификатор переноса VGG для определения пород собак примерно в 20 линиях.

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