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

Описание ниже основано на использовании глубокого обучения для задачи классификации изображений и Caffe в качестве основы. Я не пробовал фреймворк Caffe2, но он может работать так же.

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

Теперь мы также можем утверждать, что —

  1. Многие проблемы классификации изображений могут быть решены путем предоставления большого количества «структурированных» данных и охвата всех случаев.
  2. Идите глубже со своими слоями свертки. (Ну:/Если вас устраивает большой размер модели и большой объем аннотированных данных.)

Как мы видим из приведенных выше пунктов, есть очевидные причины, по которым они никогда не могут быть достигнуты. Итак, после некоторого момента нам нужно сосредоточиться на особенностях того, что изучает сеть. В этом блоге мы попытаемся ответить на вопрос «Как это сделать?».

Важно! Используйте Caffe, если вы не используете :P

  1. Загрузите модель.
  2. Преобразуйте свой FC (полностью подключенные слои в сверточные слои).
  3. Просмотрите результат, запустив сеть.

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

Говорить дешево, покажи мне код ~ Линус

  1. Загрузите «CaffeNet».
import caffe
import numpy as np
import matplotlib.pyplot as plt
caffe.set_mode_gpu()
net = caffe.Net('../models/bvlc_reference_caffenet/deploy.prototxt', '../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel',caffe.TEST)

2. См. полносвязные слои.

params = ['fc6', 'fc7', 'fc8']
fc_params ={pr: 
(
net.params[pr][0].data, 
net.params[pr][1].data
)
for pr in params
}

for fc in params:
    print '{} weights are {} dimensional and biases are {} dimensional'.format(fc, fc_params[fc][0].shape, fc_params[fc[1].shape)

3. См. слои свертки.

net_full_conv caffe.Net('net_surgery/bvlc_caffenet_full_conv.prototxt', '../models/bvlc_reference_caffenet/bvlc_reference_caffenet.caffemodel',caffe.TEST)
params_full_conv = ['fc6-conv', 'fc7-conv', 'fc8-conv']
conv_params = 
{
pr: (
net_full_conv.params[pr][0].data, 
net_full_conv.params[pr][1].data
) 
for pr in params_full_conv}

for conv in params_full_conv:
    print '{} weights are {} dimensional and biases are {} dimensional'.format(conv, conv_params[conv][0].shape, conv_params[conv][1].shape)

4. Преобразование.

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

for pr, pr_conv in zip(params, params_full_conv):
    conv_params[pr_conv][0].flat = fc_params[pr][0].flat
    conv_params[pr_conv][1][...] = fc_params[pr][1]
net_full_conv.save('net_surgery/bvlc_caffenet_full_conv.caffemodel')

5. Визуализируйте

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

Пример: ВХОД 451x451, ВЫХОД 8x8

import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

im = caffe.io.load_image('images/cat.jpg')
transformer = caffe.io.Transformer({'data': net_full_conv.blobs['data'].data.shape})
transformer.set_mean('data', np.load('../python/caffe/imagenet/ilsvrc_2012_mean.npy').mean(1).
mean(1))

transformer.set_transpose('data', (2,0,1))
transformer.set_channel_swap('data', (2,1,0))
transformer.set_raw_scale('data', 255.0)

out = net_full_conv.forward_all(
data=np.asarray([transformer.preprocess('data', im)])
)
print out['prob'][0].argmax(axis=0)
plt.subplot(1, 2, 1)
plt.imshow(transformer.deprocess('data', net_full_conv.blobs['data'].data[0]))
plt.subplot(1, 2, 2)
plt.imshow(out['prob'][0,281])