- PVSM.RU - https://www.pvsm.ru -
В данной статье вы познакомитесь c применением deep learning на практике. Будет использован фреймворк Caffe [1] на датасете SVHN [2].
Deep Learning. Этот buzz word уже давно звенит в ушах, но попробовать его на практике никак не удавалось. Подвернулся удобный случай это исправить! На новогодние праздники был назначен контест на kaggle [3] по распознаванию номеров домов в рамках курса по анализу изображений.
Была дана часть известной выборки SVHN [2], состоящей из 73257 изображений в обучающей и 26032 в тестовой (неразмеченной) выборках. Всего 10 классов для каждой цифры. Изображение имеет размер 32x32 в цветовом пространстве RGB. Как показывает бенчмарк [4], методы на основе deep learning показывают точность выше чем у человека — 1.92% против 2% ошибки!
У меня был опыт работы с алгоритмами машинного обучения на основе SVM и Naive Bayes. Применять уже известные методы скучно, поэтому решил использовать что-нибудь из deep learning, а именно сверточную нейронную сеть [5].
Для работы с глубокими нейросетями существует много разных библиотек и фреймворков. Мои критерии были такими:
По ним отлично подошел Caffe:
К тому же Caffe очень быстрый, т.к. использует GPU (хотя можно обойтись и CPU).
Изначально я поставил Caffe на свой ноутбук с помощью docker [10] и запускал его в режиме CPU. Обучение нейросети проходило очень медленно, но сравнивать было не с чем и казалось, что это нормально.
Затем наткнулся на 25$ купон амазона [13] и решил попробовать на AWS g2.2xlarge [14] с NVIDIA GPU и поддержкой CUDA. Там развернул Caffe с помощью Chef [9]. В итоге получилось в 41 раз быстрее — на CPU 100 итераций проходило за 290 сек, на GPU c CUDA за 7 cек!
Если в алгоритмах машинного обучения необходимо было формировать хороший вектор признаков, чтобы получить приемлемое качество, то в сверточных нейросетях этого делать не нужно. Главное — придумать хорошую архитектуру сети.
Введем следующие обозначения:
Для задачи классификации изображений основной является следующая архитектура НС:
input -> conv -> pool -> conv -> pool -> fully-conn -> fully-conn -> output
Количество (conv -> pool) слоев может быть разным, но обычно не меньше 2х. Количество fully-conn не меньше 1го.
В рамках данного контеста было перепробовано несколько архитектур. Наибольшую точность я получил со следующей:
input -> conv -> pool -> conv -> pool -> conv -> pool -> fully-conn -> fully-conn -> output
Caffe конфигурируется с помощью Protobuf файлов. Имплементация архитектуры для контеста находится здесь [18]. Рассмотрим ключевые моменты конфигурации каждого слоя.
name: "WinnyNet-F"
layers {
name: "svhn-rgb"
type: IMAGE_DATA
top: "data"
top: "label"
image_data_param {
source: "/home/deploy/opt/SVHN/train-rgb-b.txt"
batch_size: 128
shuffle: true
}
transform_param {
mean_file: "/home/deploy/opt/SVHN/svhn/winny_net5/mean.binaryproto"
}
include: { phase: TRAIN }
}
layers {
name: "svhn-rgb"
type: IMAGE_DATA
top: "data"
top: "label"
image_data_param {
source: "/home/deploy/opt/SVHN/test-rgb-b.txt"
batch_size: 120
}
transform_param {
mean_file: "/home/deploy/opt/SVHN/svhn/winny_net5/mean.binaryproto"
}
include: { phase: TEST }
}
...
Первые 2 слоя (для обучающей и тестовой фазы) имеют type: IMAGE_DATA, т.е. сеть на вход принимает изображения. Изображения перечисляются в текстовом файле [19], где 1 колонка — путь к изображению, 2 колонка — класс. Путь к текстовому файлу указывается в атрибуте image_data_param.
Кроме изображений, можно подавать на вход данные из HDF5 [20], LevelDB и lmbd. Последние 2 варианта особенно актуальны, если критична скорость работы. Таким образом Caffe может работать с любыми данными, а не только изображениями. Проще всего работать с IMAGE_DATA, поэтому он и был выбран для контеста.
Также входные слои могут включать атрибут transform_param. В нем указываются трансформации, которым надо подвергнуть входные данные. Обычно, перед подачей изображений на нейросеть, их нормализуют или проводят более хитрые операции, например Local Contrast Normalization [21]. В данном случае был указан mean_file — вычитание «среднего» изображения [22] из входного.
В Caffe используется batch gradient descent [23]. Входной слой содержит параметр batch_size. За одну итерацию на вход нейросети поступает batch_size элементов выборки.
...
layers {
bottom: "data"
top: "conv1/5x5_s1"
name: "conv1/5x5_s1"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
convolution_param {
num_output: 64
kernel_size: 5
stride: 1
pad: 2
weight_filler {
type: "xavier"
std: 0.0001
}
}
}
layers {
bottom: "conv1/5x5_s1"
top: "conv1/5x5_s1"
name: "conv1/relu_5x5"
type: RELU
}
layers {
bottom: "conv1/5x5_s1"
top: "pool1/3x3_s2"
name: "pool1/3x3_s2"
type: POOLING
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
bottom: "pool1/3x3_s2"
top: "conv2/5x5_s1"
name: "conv2/5x5_s1"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
convolution_param {
num_output: 64
kernel_size: 5
stride: 1
pad: 2
weight_filler {
type: "xavier"
std: 0.01
}
}
}
layers {
bottom: "conv2/5x5_s1"
top: "conv2/5x5_s1"
name: "conv2/relu_5x5"
type: RELU
}
layers {
bottom: "conv2/5x5_s1"
top: "pool2/3x3_s2"
name: "pool2/3x3_s2"
type: POOLING
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
bottom: "pool2/3x3_s2"
top: "conv3/5x5_s1"
name: "conv3/5x5_s1"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
convolution_param {
num_output: 128
kernel_size: 5
stride: 1
pad: 2
weight_filler {
type: "xavier"
std: 0.01
}
}
}
layers {
bottom: "conv3/5x5_s1"
top: "conv3/5x5_s1"
name: "conv3/relu_5x5"
type: RELU
}
layers {
bottom: "conv3/5x5_s1"
top: "pool3/3x3_s2"
name: "pool3/3x3_s2"
type: POOLING
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
...
3м является слой свертки с type: CONVOLUTION. Далее идет указание функции активации c type: RELU. 4м слоем является слой подвыборки с type: POOL. Далее 2 раза идет повторение conv, pool слоев, но с другими параметрами.
Подбор параметров для этих слоев является эмпирическим.
...
layers {
bottom: "pool3/3x3_s2"
top: "ip1/3072"
name: "ip1/3072"
type: INNER_PRODUCT
blobs_lr: 1
blobs_lr: 2
inner_product_param {
num_output: 3072
weight_filler {
type: "gaussian"
std: 0.001
}
bias_filler {
type: "constant"
}
}
}
layers {
bottom: "ip1/3072"
top: "ip1/3072"
name: "ip1/relu_5x5"
type: RELU
}
layers {
bottom: "ip1/3072"
top: "ip2/2048"
name: "ip2/2048"
type: INNER_PRODUCT
blobs_lr: 1
blobs_lr: 2
inner_product_param {
num_output: 2048
weight_filler {
type: "xavier"
std: 0.001
}
bias_filler {
type: "constant"
}
}
}
layers {
bottom: "ip2/2048"
top: "ip2/2048"
name: "ip2/relu_5x5"
type: RELU
}
layers {
bottom: "ip2/2048"
top: "ip3/10"
name: "ip3/10"
type: INNER_PRODUCT
blobs_lr: 1
blobs_lr: 2
inner_product_param {
num_output: 10
weight_filler {
type: "xavier"
std: 0.1
}
}
}
layers {
name: "accuracy"
type: ACCURACY
bottom: "ip3/10"
bottom: "label"
top: "accuracy"
include: { phase: TEST }
}
layers {
name: "loss"
type: SOFTMAX_LOSS
bottom: "ip3/10"
bottom: "label"
top: "loss"
}
Полносвязный слой имеет type: INNER_PRODUCT. Выходной слой соединяется со слоем функцией потерь (type: SOFTMAX_LOSS) и слоем точности (type: ACCURACY). Слой точности срабатывает только в тестовой фазе и показывает процент верно классифицированных изображений в валидационной выборке.
Важным является указание атрибута weight_filler. Если он будет большим, то функция потерь (loss) может на начальных итерациях возвращать NaN. В таком случае надо уменьшить параметр std у атрибута weight_filler.
net: "/home/deploy/opt/SVHN/svhn/winny-f/winny_f_svhn.prototxt"
test_iter: 1
test_interval: 700
base_lr: 0.01
momentum: 0.9
weight_decay: 0.004
lr_policy: "inv"
gamma: 0.0001
power: 0.75
solver_type: NESTEROV
display: 100
max_iter: 77000
snapshot: 700
snapshot_prefix: "/mnt/home/deploy/opt/SVHN/svhn/snapshots/winny_net/winny-F"
solver_mode: GPU
Для получения хорошо обученной нейронной сети нужно задать параметры обучения. В Caffe параметры обучения устанавливаются через конфигурационный protobuf файл. Конфигурационный файл для данного контеста находится здесь [24]. Параметров много [25], рассмотрим некоторые из них подробнее:
Чтобы запустить обучение НС, нужно выполнить команду caffe train с указанием конфигурационного файла [24], где заданы параметры обучения:
> caffe train --solver=/home/deploy/winny-f/winny_f_svhn_solver.prototxt
.......................
I0109 18:12:17.035543 12864 solver.cpp:160] Solving WinnyNet-F
I0109 18:12:17.035578 12864 solver.cpp:247] Iteration 0, Testing net (#0)
I0109 18:12:17.077910 12864 solver.cpp:298] Test net output #0: accuracy = 0.0666667
I0109 18:12:17.077997 12864 solver.cpp:298] Test net output #1: loss = 2.3027 (* 1 = 2.3027 loss)
I0109 18:12:17.107712 12864 solver.cpp:191] Iteration 0, loss = 2.30359
I0109 18:12:17.107795 12864 solver.cpp:206] Train net output #0: loss = 2.30359 (* 1 = 2.30359 loss)
I0109 18:12:17.107817 12864 solver.cpp:516] Iteration 0, lr = 0.01
.......................
I0109 18:13:17.960325 12864 solver.cpp:247] Iteration 700, Testing net (#0)
I0109 18:13:18.045385 12864 solver.cpp:298] Test net output #0: accuracy = 0.841667
I0109 18:13:18.045462 12864 solver.cpp:298] Test net output #1: loss = 0.675567 (* 1 = 0.675567 loss)
I0109 18:13:18.072872 12864 solver.cpp:191] Iteration 700, loss = 0.383181
I0109 18:13:18.072949 12864 solver.cpp:206] Train net output #0: loss = 0.383181 (* 1 = 0.383181 loss)
.......................
I0109 20:08:50.567730 26450 solver.cpp:247] Iteration 77000, Testing net (#0)
I0109 20:08:50.610496 26450 solver.cpp:298] Test net output #0: accuracy = 0.916667
I0109 20:08:50.610571 26450 solver.cpp:298] Test net output #1: loss = 0.734139 (* 1 = 0.734139 loss)
I0109 20:08:50.640389 26450 solver.cpp:191] Iteration 77000, loss = 0.0050708
I0109 20:08:50.640470 26450 solver.cpp:206] Train net output #0: loss = 0.0050708 (* 1 = 0.0050708 loss)
I0109 20:08:50.640494 26450 solver.cpp:516] Iteration 77000, lr = 0.00197406
.......................
I0109 20:52:32.236827 30453 solver.cpp:247] Iteration 103600, Testing net (#0)
I0109 20:52:32.263108 30453 solver.cpp:298] Test net output #0: accuracy = 0.883333
I0109 20:52:32.263183 30453 solver.cpp:298] Test net output #1: loss = 0.901031 (* 1 = 0.901031 loss)
I0109 20:52:32.290550 30453 solver.cpp:191] Iteration 103600, loss = 0.00463345
I0109 20:52:32.290627 30453 solver.cpp:206] Train net output #0: loss = 0.00463345 (* 1 = 0.00463345 loss)
I0109 20:52:32.290644 30453 solver.cpp:516] Iteration 103600, lr = 0.00161609
Одна эпоха — это (73257-120)/128 ~= 571 итерация. Чуть больше чем за 1 эпоху, на 700 итерации, точность сети на валидационной выборке 84%. На 134 эпохе точность уже 91%. На 181 эпохе — 88%. Возможно, если обучать сеть больше эпох, например 1000, точность стабилизируется и будет выше. В данном контесте обучение было остановлено на 181 эпохе.
В Caffe можно возобновлять обучение сети из snapshot добавляя параметр --snapshot:
> caffe train --solver=/home/deploy/winny-f/winny_f_svhn_solver.prototxt
--snapshot=winny_net/winny-F_snapshot_77000.solverstate
Для тестирования НС, необходимо создать deploy конфигурацию архитектуры сети [26]. В ней, в отличие от предыдущей конфигурации, отсутствует слой точности и упрощен входной слой.
Тестовая выборка, состоящая из 26032 изображений, идет без разметки. Поэтому, чтобы оценить точность на тестовой выборке контеста, нужно написать немного кода [27]. Caffe имеет интерфейсы для Питона и Матлаба [28].
Для тестирования сетей из разных эпох в Caffe есть снапшоты. Сеть 134 эпохи показала точность (Private Score в kaggle) 88.7%, а сеть 181 эпохи — 87.6%.
Судя по магистерской диссертации [29], точность реализованной архитектуры может достигать 96%.
Как можно попробовать повысить полученную точность 88.7%?
Реализованная сверточная нейронная сеть показала точность 88.9%. Это не лучший результат, но для первого блина неплохо. Есть потенциал для увеличения точности до 96%.
Благодаря фреймворку Caffe погружение в deep learning не вызывает больших трудностей. Достаточно создать пару конфигурационных файлов и одной командой запустить процесс обучения. Конечно, также нужны базовые познания в теории искусственных нейронных сетей. Эту и другую информацию для быстрого старта я постарался дать в этой статье.
Автор: lytr
Источник [32]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/obrabotka-izobrazhenij/80924
Ссылки в тексте:
[1] Caffe: http://caffe.berkeleyvision.org/
[2] SVHN: http://ufldl.stanford.edu/housenumbers/
[3] контест на kaggle: https://inclass.kaggle.com/c/svhn-mipt2
[4] бенчмарк: http://rodrigob.github.io/are_we_there_yet/build/classification_datasets_results.html#5356484e
[5] сверточную нейронную сеть: https://ru.wikipedia.org/wiki/%D0%A1%D0%B2%D1%91%D1%80%D1%82%D0%BE%D1%87%D0%BD%D0%B0%D1%8F_%D0%BD%D0%B5%D0%B9%D1%80%D0%BE%D0%BD%D0%BD%D0%B0%D1%8F_%D1%81%D0%B5%D1%82%D1%8C
[6] Caffe Summer Bootcamp: http://courses.cs.tau.ac.il/Caffe_workshop/Bootcamp/
[7] основания нейронных сетей: https://sites.google.com/site/deeplearningcvpr2014/
[8] про Caffe: https://docs.google.com/presentation/d/1UeKXVgRvvxg9OUdh_UiC5G71UMscNPlvArsWER41PsU/edit#slide=id.p
[9] chef-кукбук: https://github.com/robomakery/caffe-cookbook
[10] docker-образы: https://registry.hub.docker.com/u/tleyden5iwx/caffe-cpu-master/
[11] гитхабе: https://github.com/BVLC/caffe/
[12] гугл-группе: https://groups.google.com/forum/#!forum/caffe-users
[13] 25$ купон амазона: http://habrahabr.ru/post/243757/
[14] g2.2xlarge: http://aws.amazon.com/ru/ec2/instance-types/
[15] 1: http://ufldl.stanford.edu/tutorial/supervised/FeatureExtractionUsingConvolution/
[16] 2: http://ufldl.stanford.edu/tutorial/supervised/Pooling/
[17] 3: http://ufldl.stanford.edu/tutorial/supervised/MultiLayerNeuralNetworks/
[18] здесь: https://gist.github.com/sld/6ecd597d455b62ef5d36#file-train-test
[19] текстовом файле: https://gist.github.com/sld/5cb766398471c63903f3#file-train-rgb-b-txt
[20] HDF5: http://ru.wikipedia.org/wiki/Hierarchical_Data_Format
[21] Local Contrast Normalization: http://www.frontiersincomputervision.com/slides/FCV_Learn_LeCun.pdf
[22] «среднего» изображения: https://gist.github.com/sld/5cb766398471c63903f3#file-mean_image-py
[23] batch gradient descent: http://en.wikipedia.org/wiki/Stochastic_gradient_descent#Iterative_method
[24] здесь: https://gist.github.com/sld/6ecd597d455b62ef5d36#file-solver
[25] много: http://caffe.berkeleyvision.org/tutorial/solver.html
[26] deploy конфигурацию архитектуры сети: https://gist.github.com/sld/6ecd597d455b62ef5d36#file-deploy
[27] немного кода: https://gist.github.com/sld/5cb766398471c63903f3#file-net-py
[28] интерфейсы для Питона и Матлаба: http://caffe.berkeleyvision.org/tutorial/interfaces.html
[29] магистерской диссертации: http://www.cs.toronto.edu/%7Enitish/msc_thesis.pdf
[30] deep learning в facial keypoints detection: http://danielnouri.org/notes/2014/12/17/using-convolutional-neural-nets-to-detect-facial-keypoints-tutorial/#second-model-convolutions
[31] потребуется обучать сеть еще больше эпох, чем 1000: http://danielnouri.org/notes/2014/12/17/using-convolutional-neural-nets-to-detect-facial-keypoints-tutorial/#dropout
[32] Источник: http://habrahabr.ru/post/249089/
Нажмите здесь для печати.