Эта статья включена в:blog.aistudyclub.com
Relation Net - это документ CVPR2018, ссылка на документ:АР Вест V.org/ABS/1711.06…
Глубокое обучение достигло больших успехов в задачах визуального распознавания.Автор статьи указал, что для обучения модели требуется большое количество размеченных изображений, а для обучения параметров требуется многократное повторение. Всякий раз, когда добавляется новая категория объектов, требуется время для аннотирования, а некоторые новые категории объектов и категории редких объектов могут вообще не иметь большого количества помеченных изображений. Люди, с другой стороны, могут достичь обучения за несколько шагов (FSL) и обучения без выборки (ZSL) с небольшим когнитивным обучением. Автор привел пример, пока ребенок знает зебру на картинке или в книге, или просто слышит описание зебры как «полосатой лошади», он без труда узнает зебру. Чтобы решить проблему, заключающуюся в том, что эффект классификации модели с небольшим количеством выборок в глубоком обучении будет плохим, и, вдохновленный способностями людей к обучению с малой выборкой и без нее, обучение с малой выборкой вновь обрело некоторую популярность. В некоторых случаях технология тонкой настройки в глубоком обучении может использоваться с относительно небольшим количеством выборок, но в случае только одной или нескольких выборок, даже если используются методы увеличения и регуляризации данных, все равно будут возникать проблемы переобучения. В настоящее время механизм рассуждений при другом обучении на малых выборках более сложен, поэтому автор статьи предлагает модель Relation Net, которую можно обучать от начала до конца и которая имеет простую структуру.
В задаче FSL набор данных обычно делится на три набора данных: набор для обучения / набор для поддержки / набор для тестирования. Опорный набор и проверочный набор имеют одну и ту же метку, а обучающий набор не содержит меток опорного набора и проверочного набора. В наборе поддержки есть K помеченных данных и C различных категорий, которые называются C-way K-shot. В процессе обучения выберите набор образцов/запросов, соответствующий набору поддержки/набору тестов из набора для обучения. Конкретный метод будет подробно объяснен в стратегии обучения позже. Реляционная сеть состоит из модели встраивания и реляционной модели. Основная идея реляционной сети состоит в том, чтобы сначала извлечь карты функций изображений в наборе поддержки и наборе тестов через модель встраивания, а затем сшить измерения, представляющие количество каналов в картах функций, чтобы получить новую карта характеристик. Затем новая карта объектов отправляется в реляционную модель для работы, чтобы получить оценку отношения, которая представляет сходство между двумя изображениями. На следующем рисунке показана структура сети и процесс приема 1 образца в случае 5-канального 1-го выстрела. Изображения в 5 наборах образцов и изображения в наборе запросов будут извлечены и соединены отдельно через модель встраивания для получения 5 новых карт функций, а затем отправлены в сеть отношений для расчета оценки отношения и, наконец, один - Вектор выстрелов с наибольшим количеством очков, представляющих соответствующую категорию.
Функция потерь, используемая для обучения, также относительно проста: в качестве функции потерь используется среднеквадратическая ошибка. В формуле ri,j представляют сходство между изображениями i и j. yi и yj представляют истинную метку изображения.
Воспроизведение сети отношений на основе летающих лопастей
Для определения структуры модели реляционной сети см.:GitHub.com/Tencent и хорошо/Боюсь…Здесь я поделюсь техническими подробностями восстановления с разработчиками.
1. Создайте сеть реляционных сетей.
Модель состоит как из модели внедрения, так и из реляционной модели, обе из которых в основном состоят из модуля [CONV + BN + RELU], поэтому сначала определите класс базовой сети и реализуйте метод conv_bn_layer, код выглядит следующим образом:
class BaseNet:
def conv_bn_layer(self,
input,
num_filters,
filter_size,
stride=1,
groups=1,
padding=0,
act=None,
name=None,
data_format='NCHW'):
n = filter_size * filter_size * num_filters
conv = fluid.layers.conv2d(
input=input,
num_filters=num_filters,
filter_size=filter_size,
stride=stride,
padding=padding,
groups=groups,
act=None,
param_attr=ParamAttr(name=name + "_weights", initializer=fluid.initializer.Normal(0,math.sqrt(2. / n))),
bias_attr=ParamAttr(name=name + "_bias",
initializer=fluid.initializer.Constant(0.0)),
name=name + '.conv2d.output.1',
data_format=data_format)
bn_name = "bn_" + name
return fluid.layers.batch_norm(
input=conv,
act=act,
momentum=1,
name=bn_name + '.output.1',
param_attr=ParamAttr(name=bn_name + '_scale',
initializer=fluid.initializer.Constant(1)),
bias_attr=ParamAttr(bn_name + '_offset',
initializer=fluid.initializer.Constant(0)),
moving_mean_name=bn_name + '_mean',
moving_variance_name=bn_name + '_variance',
data_layout=data_format)
Paddle поддерживает два режима определения сети: статический график и динамический график. Здесь я выбираю статический график. Приведенный выше код определяет наиболее часто встречающийся слой conv_bn в сверточной нейронной сети, но следует отметить, что импульс слоя batch_norm установлен на 1. Достигаемый эффект заключается в том, что глобальное среднее значение и дисперсия не регистрируются. Значения конкретных параметров следующие:
- ввод: передать тензорный объект для свертки
- num_filter: количество ядер свертки (количество каналов выходного результата свертки)
- filter_size: размер ядра свертки
- шаг: сверточный шаг
- groups: количество групп сгруппированных сверток
- padding: размер заполнения, здесь установлено значение 0, что означает отсутствие заполнения после свертки.
- act: функция активации после слоя BN, если нет, то функция активации не используется
- name: имя объекта в графе операций
Затем мы определяем часть модели встраивания реляционной сети.
class EmbeddingNet(BaseNet):
def net(self,input):
conv = self.conv_bn_layer(
input=input,
num_filters=64,
filter_size=3,
padding=0,
act='relu',
name='embed_conv1')
conv = fluid.layers.pool2d(
input=conv,
pool_size=2,
pool_stride=2,
pool_type='max')
conv = self.conv_bn_layer(
input=conv,
num_filters=64,
filter_size=3,
padding=0,
act='relu',
name='embed_conv2')
conv = fluid.layers.pool2d(
input=conv,
pool_size=2,
pool_stride=2,
pool_type='max')
conv = self.conv_bn_layer(
input=conv,
num_filters=64,
filter_size=3,
padding=1,
act='relu',
name='embed_conv3')
conv = self.conv_bn_layer(
input=conv,
num_filters=64,
filter_size=3,
padding=1,
act='relu',
name='embed_conv4')
return conv
Сначала создайте класс EmbeddingNet, который наследует класс BaseNet, который наследует метод conv_bn_layer. Метод net определен в EmbeddingNet, а его входной параметр представляет собой тензор входного изображения.Этот метод используется для создания статической карты сети. Входные данные сначала проходят через модуль [Conv+BN+relu] для получения карты объектов embed_conv1, а затем выполняют операцию максимального объединения. Роль объединения заключается в уменьшении карты признаков при сохранении важных признаков, а последующие операции свертки и объединения одинаковы. Наконец, форма карты объектов, выводимая embed_conv4, имеет вид [-1, 64, 19, 19], всего 4 измерения, первое измерение представляет размер_пакета, поскольку размер_пакета не определен при создании статической сети, поэтому используйте -1 для указать, что это может быть произвольное значение. Второе измерение представляет количество каналов карты объектов.После модели встраивания количество каналов карты объектов равно 64. Наконец, 3-е и 4-е измерения представляют собой ширину и высоту карты объектов, которая здесь составляет 19x19. Часть кода реляционной модели выглядит следующим образом:
class RelationNet(BaseNet):
def net(self, input, hidden_size):
conv = self.conv_bn_layer(
input=input,
num_filters=64,
filter_size=3,
padding=0,
act='relu',
name='rn_conv1')
conv = fluid.layers.pool2d(
input=conv,
pool_size=2,
pool_stride=2,
pool_type='max')
conv = self.conv_bn_layer(
input=conv,
num_filters=64,
filter_size=3,
padding=0,
act='relu',
name='rn_conv2')
conv = fluid.layers.pool2d(
input=conv,
pool_size=2,
pool_stride=2,
pool_type='max')
fc = fluid.layers.fc(conv,size=hidden_size,act='relu',
param_attr=ParamAttr(name='fc1_weights',
initializer=fluid.initializer.Normal(0,0.01)),
bias_attr=ParamAttr(name='fc1_bias',
initializer=fluid.initializer.Constant(1)),
)
fc = fluid.layers.fc(fc, size=1,act='sigmoid',
param_attr=ParamAttr(name='fc2_weights',
initializer=fluid.initializer.Normal(0,0.01)),
bias_attr=ParamAttr(name='fc2_bias',
initializer=fluid.initializer.Constant(1)),
)
return fc
Создайте класс RelationNet, который также наследуется от класса BaseNet и наследует метод conv_bn_layer. В сетевом методе первые несколько слоев модели аналогичны модели встраивания с использованием модуля [Conv+BN+Relu] для извлечения признаков, а в конце два слоя полносвязных слоев используются для сопоставления собственных значений. в скалярную оценку отношения, представляющую сходство двух изображений.
В процессе обучения изображения в наборе образцов и изображения в наборе запросов получают карту признаков с формой [-1, 64, 19, 19] после прохождения модели встраивания, которую необходимо склеить. перед отправкой в реляционную модель Этот код немного сложен, поэтому я объясню его в разделах ниже.
sample_image = fluid.layers.data('sample_image', shape=[3, 84, 84], dtype='float32')
query_image = fluid.layers.data('query_image', shape=[3, 84, 84], dtype='float32')
sample_query_image = fluid.layers.concat([sample_image, query_image], axis=0)
sample_query_feature = embed_model.net(sample_query_image)
Эта часть кода предназначена для объединения тензоров образца изображения и изображения запроса на широте batch_size для получения тензора sample_query_image и отправки их в модель внедрения для извлечения функций для получения sample_query_feature.
sample_batch_size = fluid.layers.shape(sample_image)[0]
query_batch_size = fluid.layers.shape(query_image)[0]
Эта часть кода принимает размерность 0 тензора изображения как batch_size.
sample_feature = fluid.layers.slice(
sample_query_feature,
axes=[0],
starts=[0],
ends=[sample_batch_size])
if k_shot > 1:
# few_shot
sample_feature = fluid.layers.reshape(sample_feature, shape=[c_way, k_shot, 64, 19, 19])
sample_feature = fluid.layers.reduce_sum(sample_feature, dim=1)
query_feature = fluid.layers.slice(
sample_query_feature,
axes=[0],
starts=[sample_batch_size],
ends=[sample_batch_size + query_batch_size])
Поскольку предыдущие изображения объединены, после функции также необходимо выполнить срез по измерению 0, соответствующему размеру партии sample_query_feature, чтобы получить соответственно sample_feature и query_feature. Здесь, если K-выстрел больше 1, вам нужно изменить форму sample_feature, затем просуммировать тензоры K-выстрелов в 1-м измерении, соответствующем K-выстрелу, и удалить измерение, тогда форма sample_feature станет [C- способ , 64, 19, 19]. В это время значение sample_batch_size должно быть C-way.
sample_feature_ext = fluid.layers.unsqueeze(sample_feature, axes=0)
query_shape = fluid.layers.concat(
[query_batch_size, fluid.layers.assign(np.array([1, 1, 1,1]).astype('int32'))])
sample_feature_ext = fluid.layers.expand(sample_feature_ext, query_shape)
Поскольку каждый элемент изображения в наборе примеров должен быть объединен с элементами изображения типа C, здесь добавляется новое измерение с помощью разжатия. В соответствии с требованиями к параметрам расширенного интерфейса здесь создается новый тензор query_shape для повторения тензора sample_feature query_batch_size раз для получения тензора формы [query_batch_size, sample_batch_size, 64, 19, 19].
query_feature_ext = fluid.layers.unsqueeze(query_feature, axes=0)
if k_shot > 1:
sample_batch_size = sample_batch_size / float(k_shot)
sample_shape = fluid.layers.concat(
[sample_batch_size, fluid.layers.assign(np.array([1, 1, 1, 1]).astype('int32'))])
query_feature_ext = fluid.layers.expand(query_feature_ext, sample_shape)
Как и в приведенной выше операции, функции набора запросов также должны добавить новое измерение, которое необходимо скопировать раз больше sample_batch_size. Стоит отметить, что если k-shot больше 1, так как ранее была выполнена операция reduce_mean, новый sample_batch_size получается путем деления sample_batch_size на k-shot. Наконец, путем копирования получается тензор [sample_batch_size, query_batch_size, 64, 19, 19].
query_feature_ext = fluid.layers.transpose(query_feature_ext, [1, 0, 2, 3, 4])
relation_pairs = fluid.layers.concat([sample_feature_ext, query_feature_ext], axis=2)
relation_pairs = fluid.layers.reshape(relation_pairs, shape=[-1, 128, 19, 19])
Наконец, транспонируйте метод транспонирования, чтобы сделать форму sample_feature_ext и query_feature_ext согласованной, и, наконец, объедините и измените форму двух функций, чтобы получить тензорные отношения_пар с формой [query_batch_size x sample_batch_size, 128, 19, 19].
relation = RN_model.net(relation_pairs, hidden_size=8)
relation = fluid.layers.reshape(relation, shape=[-1, c_way])
Наконец, ранее объединенные признаки отправляются в модуль реляционной модели.Сначала будет получен вектор длины query_batch_size x sample_batch_size, а затем форма будет изменена для получения тензора [query_batch_size, sample_batch_size] (sample_batch_size на самом деле равно C-way), а вектор длины sample_batch_size равен Горячая форма представляет категорию каждого изображения запроса.
Код функции потерь выглядит следующим образом:
one_hot_label = fluid.layers.one_hot(query_label, depth=c_way)
loss = fluid.layers.square_error_cost(relation, one_hot_label)
loss = fluid.layers.reduce_mean(loss)
Сначала преобразуйте метку query_label изображения запроса в горячую форму, а ранее полученное отношение также в горячую форму, а затем вычислите MSE отношения и one_hot_label, чтобы получить функцию потерь. 2. Стратегия обучения В задаче FSL, если для обучения используется только опорный набор, вывод и предсказание тестового набора также могут быть выполнены, но из-за относительно небольшого количества выборок в опорном наборе производительность классификатора обычно не хорошо. Поэтому тренировочный набор обычно используется для обучения, чтобы классификатор имел лучшую производительность. Существует эффективный метод, называемый обучением на основе эпизодов. Этапы реализации обучения на основе эпизодов следующие:
- Обучение должно проходить через N эпизодов в цикле, и каждый эпизод будет случайным образом выбирать K данных из категорий C в обучающем наборе, чтобы сформировать набор данных выборочного набора. C и K соответствуют C-пути K-снимку в наборе поддержки, всего с образцами C x K.
- Затем случайным образом выберите несколько образцов из оставшихся образцов в категориях C в качестве набора запросов для обучения.
Для 5-этапного однократного обучения размер_пакета выборки равен 5, а размер_пакета набора запросов равен 15. Для 5-этапного 5-кратного обучения размер_пакета выборочного набора равен 25 (5 изображений на категорию), а размер_пакета набора запросов равен 10. Для обученного оптимизатора была выбрана оптимизация Адама, а скорость обучения была установлена равной 0,001. Для увеличения данных метод AutoAugment используется для изображений набора образцов и набора запросов, когда данные считываются, чтобы увеличить разнообразие данных.
3. Эффект воспроизведения модели Набор данных для проверки использует только minImageNet, использованный в эксперименте в статье, всего 100 категорий и 600 изображений в каждой категории. 100 классификаций разделены на три набора данных обучения/валидации/тестирования с номерами 64, 16 и 20 соответственно. В статье упоминается, что точность модели на тестовом наборе данных minImageNet следующая:
Relation Net достигает точности около 50,44 и 65,32 в 5-стороннем 1-м выстреле и 5-стороннем 5-кратном выстреле соответственно.
Также используйте Relation Net, реализованную на основе летающего весла в тестовом наборе данных minImageNet.
5-сторонняя точность 1 выстрела:
5-сторонняя точность 5 выстрелов:
В соответствии с точностью в статье модель воспроизводится.
Кодовый адрес:GitHub.com/Tencent и хорошо/Боюсь…