Первая версия от 5 марта 2017 г.
Несколько месяцев назад я начал экспериментировать с различными инструментами глубокого обучения. Что касается производительности, я был очень впечатлен Керасом. Под производительностью я подразумеваю, что я редко трачу много времени на ошибку.
Этот пост показывает, как легко перенести модель в Keras.
Я буду использовать модель VGG-Face в качестве примера. Модель объяснена в этой статье (Deep Face Recognition, Visual Geometry Group), а подогнанные веса доступны как MatConvNet здесь.
Вкратце, модель VGG-Face - это та же архитектура NeuralNet, что и модель VGG16, используемая для идентификации 1000 классов объектов в конкурсе ImageNet. Название VGG16 просто указывает, что модель произошла из Группы визуальной геометрии и что это 16 обучаемых слоев. Основное различие между моделями VGG16-ImageNet и VGG-Face - это набор калиброванных весов, поскольку обучающие наборы были разными.
Полный код доступен в этой папке GitHub.
Архитектура модели
Архитектура модели (см. Стр. 6, таблица 3) представляет собой линейную последовательность преобразований слоев следующих типов:
- Активации Convolution + ReLU
- MaxPooling
- softmax
Поскольку в последовательности есть повторяющийся образец слоев, мы факторизуем его как функцию строительного блока:
# building block of the VGG model : def convblock(cdim, nb, bits=3): L = [] for k in range(1,bits+1): convname = 'conv'+str(nb)+'_'+str(k) L.append( Convolution2D(cdim, 3, 3, border_mode='same', activation='relu', name=convname) ) L.append( MaxPooling2D((2, 2), strides=(2, 2)) ) return L
Мы называем слой свертки модели, чтобы мы могли легко получить к нему доступ при загрузке весов.
Инициализация модели
from keras.models import Sequential mdl = Sequential() # Trick : # dummy-permutation = identity to specify input shape # index starts at 1 as 0 is the sample dimension mdl.add( Permute((1,2,3), input_shape=(3,224,224)) )
Модель тела
for l in convblock(64, 1, bits=2): mdl.add(l) for l in convblock(128, 2, bits=2): mdl.add(l) for l in convblock(256, 3, bits=3): mdl.add(l) for l in convblock(512, 4, bits=3): mdl.add(l) for l in convblock(512, 5, bits=3): mdl.add(l)
Модель головы
mdl.add( Convolution2D(4096, 7, 7, activation='relu', name='fc6') ) mdl.add( Convolution2D(4096, 1, 1, activation='relu', name='fc7') ) mdl.add( Convolution2D(2622, 1, 1, name='fc8') ) mdl.add( Flatten() ) mdl.add( Activation('softmax') )
Кормление модельных гирь
После того, как модель построена, мы можем установить веса слоев на значения, обученные на более крупном наборе данных. Обучение модели с нуля действительно представляет собой сложность в глубоком обучении. В идеале мы можем найти веса для Keras напрямую, но часто это не так. Для модели VGG веса, которые я нашел, взяты из реализации MatConvNet, то есть в формате файла Matlab.
К счастью, функция scipy.io.loadmat позволяет загрузить такой файл в Python.
from scipy.io import loadmat data = loadmat('vgg_face_matconvnet/data/vgg_face.mat', matlab_compatible=False, struct_as_record=False) net = data['net'][0,0] l = net.layers description = net.classes[0,0].description
Извлечение данных Matlab в правильном формате немного утомительно, но весь смысл работы с записной книжкой Jupyter заключается в том, что мы можем взаимодействовать с данными. После 15 минут работы с массивами я нашел следующий рецепт преобразования веса, в котором основная уловка состоит в том, чтобы «перевернуть» ось, соответствующую окнам ядра свертки:
prmt = (3,2,0,1) l_weights = matlab_layer.weights[0,0] f_l_weights = l_weights.transpose(prmt) f_l_weights = np.flip(f_l_weights, 2) # reverse axis ordering f_l_weights = np.flip(f_l_weights, 3) # reverse axis ordering l_bias = matlab_layer.weights[0,1] keras_layer.set_weights([f_l_weights, l_bias[:,0]])
Использование модели
После того, как модель будет полностью определена (архитектура и значение веса), мы можем использовать ее для идентификации лиц с помощью метода прогноз.
Поскольку веса VGG были обучены на квадратных / центрированных изображениях лиц, мы тестируем их на изображении, которое было вручную обрезано:
imarr = np.array(cropped_image).astype(np.float32) # move color dimension on first axis : imarr = imarr.transpose((2,0,1)) # turn image into a 1-element batch : imarr = np.expand_dims(imarr, axis=0) # prediction probability vector : out = model.predict(imarr) # most probable item : best_index = np.argmax(out, axis=1)[0]
В этом случае модель правильно определяет index = 2 (метка «Aamir_Khan») как наиболее вероятный с 99%.
Найдите лица на больших изображениях с помощью OpenCV
Чтобы быть полезным, инструмент идентификации лиц должен иметь возможность работать с изображениями любого измерения, содержащими несколько объектов: людей, улиц, автомобилей и т. Д.
Поскольку модель VGG-Face была оптимизирована для центрированных лиц, мы добавим этап предварительной обработки, который извлекает лица из изображений. Хотя эту задачу можно выполнить с помощью NeuralNets (например, эта статья), здесь мы используем реализацию классификатора Cascade из библиотеки OpenCV (Быстрое обнаружение объектов с использованием усиленного каскада простых функций, П. Виола и М. Джонс).
Помимо предварительной обработки изображений, классификатор OpenCV Cascade является очень удобным инструментом, если вы хотите создать набор данных лиц; вам просто нужно объединить веб-парсер с классификатором, чтобы создать набор данных о лицах! Этот набор данных, скорее всего, будет немаркированным, но неконтролируемое и полу-контролируемое обучение также весьма полезно.
Загрузка каскад-классификатора
import cv2 cascade_file_src = "haarcascade_frontalface_default.xml" faceCascade = cv2.CascadeClassifier(cascade_file_src)
Использование каскадного классификатора
# load image on gray scale : image = cv2.imread(imagePath) gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # detect faces in the image : faces = faceCascade.detectMultiScale(gray, 1.2, 5) # draw rectangles around the faces : for (x, y, w, h) in faces: cv2.rectangle(image, (x, y), (x+w, y+h), (0, 255, 0), 2) plt.imshow(image)
# crop image and scale to 224x224 : crpim = im.crop(box).resize((224,224)) plt.imshow(np.asarray(crpim))
Обобщение модели на «всех»
Чтобы иметь дело с лицами людей, которые не были частью обучающей выборки модели (2622 знаменитости), мы можем получить сокращенную модель из обученной модели VGG. Это легко сделать с помощью функционального API Keras: мы указываем вход и выход.
В нашем случае мы можем с уверенностью предположить, что признаков, закодированных в модельных весах, чтобы различать 2622 знаменитостей, достаточно, чтобы точно описать «любое» лицо.
Мы строим модель из вероятностных входов Softmax, то есть «логитов».
Векторная модель лица
from keras.models import Model # output the 2nd last layer : featuremodel = Model( input = facemodel.layers[0].input, output = facemodel.layers[-2].output )
Косинусное сходство
from scipy.spatial.distance import cosine as dcos fvec1 = featuremodel.predict(imarr1)[0,:] fvec2 = featuremodel.predict(imarr2)[0,:] dcos_1_2 = dcos(fvec1, fvec2)
1 последнее слово
Если вам понравилось читать эту статью, вы можете улучшить ее видимость с помощью маленькой зеленой кнопки в виде сердечка ниже. Спасибо!