0,2
рейтинг
16 июня 2014 в 13:31

Разработка → Про котиков, собак, машинное обучение и deep learning из песочницы

image
«В 1997 году Deep Blue обыграл в шахматы Каспарова.
В 2011 Watson обставил чемпионов Jeopardy.
Сможет ли ваш алгоритм в 2013 году отличить Бобика от Пушистика?»


Эта картинка и предисловие — из челленджа на Kaggle, который проходил осенью прошлого года. Забегая вперед, на последний вопрос вполне можно ответить «да» — десятка лидеров справилась с заданием на 98.8%, что на удивление впечатляет.

И все-таки — откуда вообще берется такая постановка вопроса? Почему задачи на классификацию, которые легко решает четырехлетний ребенок, долгое время были (и до сих пор остаются) не по зубам программам? Почему распознавать предметы окружающего мира сложнее, чем играть в шахматы? Что такое deep learning и почему в публикациях о нем с пугающим постоянством фигурируют котики? Давайте поговорим об этом.

Что вообще значит «распознать»?


Предположим, что у нас есть две категории и много-много картинок, которые нужно разложить в две соответствующие категориям стопки. По какому принципу мы будем это делать? Замечательный ответ на этот вопрос состоит в том, что никто точно не знает, но общепринятый подход такой: мы будем искать в картинках какие-то «интересные» нам куски данных, которые будут встречаться только у одной из категорий. Такие куски данных называются features, а сам подход — feature detection. Существуют достаточно уверенные доводы в пользу того, что как-то так работает и биологический мозг — первым делом, конечно, знаменитый эксперимент Хьюбела и Визеля на клетках кошачьей (опять) зрительной коры.
О терминах
В отечественной литературе про машинному обучению вместо feature пишут «признак», что, по-моему, звучит как-то размыто. Здесь я буду говорить «фича», да простится мне это издевательство над русским языком.


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



Допустим, мы хотим сделать гугл-кар, который мог бы отличать правые повороты от левых и соответствующим образом поворачивать руль. Правило для обнаружения хорошей фичи можно придумать почти на пальцах: отрезаем верхнюю половину картинки, выделяем участок определенного оттенка (асфальт), прикладываем к нему слева какую-нибудь логарифмическую кривую. Если весь асфальт поместился под кривой — то у нас поворот направо, иначе — налево. Можно набрать себе несколько кривых на случай поворотов разной кривизны — и, конечно, разный набор оттенков асфальта, включающий в себя сухое и мокрое состояние. Правда, на грунтовых дорогах наша фича окажется бесполезной.



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

Картинка из курса Джоффри Хинтона «Neural networks for machine learning»
Кстати, обратите внимание на цифры 7 и 9 — у них отсутствует нижняя часть. Дело в том, что у семерки и девятки она одинаковая, и полезной информации для распознания не несет — поэтому нейросеть, которая вырабатывала эти фичи, проигнорировала этот элемент. Обычно для получения таких фич-фильтров мы как раз и пользуемся обычными однослойными нейронными сетями или чем-то похожим.


Ок, ближе к теме. Как насчет такого?



Различий между этими двумя картинками очень много — глаза разбегаются. Уровень яркости, цвета, или вот например забавное совпадение — у левой картинки белый цвет преобладает в левой части, а у правой — в правой. Но нам нужно выбрать не любые, а именно те, которые однозначно будут определять кошек или собак. То есть, например, следующие две картинки должны распознаться как принадлежащие одной категории:



Если долго и внимательно смотреть на них и пытаться понять, что между ними общего, то в голову приходит разве что форма ушей — они более-менее одинаковые, только справа наклонены. Но это тоже совпадение — можно легко себе представить (и найти примеры из того же набора данных) фотографию, на которой кот смотрит не в ту сторону, наклоняет голову или вообще запечатлен сзади. Остальное — все разное. Масштаб, цвет и длина шерсти, глаз, поза, фон… Вообще ничего общего — и тем не менее, небольшое устройство в вашей голове способно с высочайшей точностью и безошибочно отнести эти две картинки к одной категории, а две те, что повыше — к разным. Не знаю, как вас, а меня иногда восхищает, что такой могущественный девайс находится совсем рядом у каждого из нас, только руку протянуть — и тем не менее, мы до сих пор не можем понять, как он работает.

Пятиминутка оптимизма (и теории)


Ладно. А все-таки, если попробовать задать наивный вопрос — чем кошки визуально отличаются от собак? Мы можем с легкостью начать список — размер, пушистость, усы, форма лап, наличие характерных поз, которые они могут принимать… Или, например, у кошек нет бровей. Проблема в том, что все эти отличительные признаки выражены не на языке пикселей. Мы не можем заложить их в алгоритм, пока предварительно не объяснили ему, что такое эти самые брови и где они должны находиться — или что такое лапы и откуда они растут. Более того, мы, в общем-то, делаем все эти алгоритмы распознавания для того, чтобы понимать, что перед нами кошка — существо, к которому применимы понятия «усы», «лапы» и «хвост» — а до этого мы даже не можем с достаточной уверенностью сказать, где на фотографии заканчиваются обои или диван, и начинается кошка. Круг замкнулся.

Но некоторый вывод отсюда сделать все-таки можно. Когда мы формулировали фичи в предыдущих примерах, мы исходили из возможной изменчивости объекта. Поворот дороги может быть только влево или вправо — других вариантов нет (кроме проезда прямо, конечно, но там и делать ничего не надо), плюс стандарты дорожного строительства гарантируют нам, что поворот будет достаточно плавным, а не под прямым углом. Поэтому мы конструируем свою фичу так, чтобы она допускала различную кривизну поворота, определенный набор оттенков дорожного покрытия, и на этом возможная изменчивость заканчивается. Следующий пример: цифра «1» может быть написана разным почерком, и все варианты будут отличаться друг от друга — но в ней обязательно должна присутствовать прямая вертикальная (или наклонная) черта, иначе она перестанет быть единицей. Когда мы подготавливаем свою фичу-фильтр, мы оставляем классификатору пространство для изменчивости — и если взглянуть на картинку под спойлером снова, можно увидеть, что активная часть фильтра для единицы представляет собой толстую полосу, которая позволяет нарисовать черту с разным наклоном и с допустимым острым углом в верхней части.

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

Это «пока непонятно» длилось довольно долго — большую часть истории машинного обучения. Но вдруг в какой-то момент люди поняли об окружающем мире одну увлекательную идею. Звучит она примерно так:
Все вещи состоят из других, маленьких и более элементарных вещей.

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


(почему-то не нашел хорошей информативной картинки, поэтому эта вырезана из выступления Эндрю Ына (основатель Coursera) про deep learning

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

1. Уже упоминавшиеся Хьюбел и Визель в своем эксперименте в 1959 году обнаружили в зрительной коре мозга клетки, реагирующие на определенные символы на экране — и кроме этого обнаружили существование других клеток «уровнем выше», которые, в свою очередь, реагируют на определенные устойчивые сочетания сигналов от клеток первого уровня. На основании этого они предположили существование целой иерархии аналогичных клеток-детекторов.
прекрасный отрывок видео из эксперимента
… где демонстрируется, как они почти случайно обнаружили нужную фичу, которая заставляла нейрон реагировать — сдвинув чуть дальше обычного образец так, что край стекла попал в камеру. Чувствительным людям смотреть осторожно, в наличии издевательства над животными.

2. Где-то в районе двухтысячных в среде специалистов машинного обучения появляется сам термин deep learning — применительно к нейронным сетям, у которых не один слой нейронов, а много — и которые, таким образом, могут обучаться нескольким уровням фич. Подобная архитектура имеет вполне строго обоснованные преимущества — чем больше уровней в сети, тем более сложные функции она может выражать. Немедленно возникает проблема с тем, как обучать такие сети — повсеместно использовавшийся раньше алгоритм обратного распространения ошибки (backpropagation) плохо работает с большим количеством слоев. Появляется несколько разных моделей для этих целей — автоэнкодеры, ограниченные машины Больцмана и т.д.
3. Джефф Хокинс в своей книге «Об интеллекте» в 2004 году пишет, что иерархический подход рулит и за ним будущее. Он уже слегка опоздал к началу бала, но не могу о нем не упомянуть — в книге эта мысль выводится из совершенно повседневных вещей и простым языком, человеком, который был достаточно далек от машинного обучения и вообще говорил, что все эти ваши нейронные сети — плохая идея. Почитайте книгу, она очень вдохновляет.

Немного о кодах


Итак, у нас есть гипотеза. Вместо того, чтобы запихивать в обучающий алгоритм 1024x768 равноправных пикселей и смотреть, как он медленно задыхается от нехватки памяти и неспособности понять, какие пиксели важны для распознавания, мы хотим извлечь из картинки некоторую иерархическую структуру, которая будет состоять из разных уровней. На первом уровне мы предполагаем увидеть какие-то самые базовые, структурно простые элементы картинки — ее строительные кирпичи: границы, штрихи, отрезки. Повыше — устойчивые комбинации фич первого уровня (например, углы), еще выше — фичи, скомпонованные из предыдущих (геометрические фигуры, и т.д.). Собственно, вопрос — откуда взять такую структуру для отдельной картинки?

Давайте в качестве отвлеченного вопроса немного поговорим о кодах.

Когда мы хотим представить объект из реального мира в компьютере, мы пользуемся каким-то набором правил, чтобы перевести этот объект, по кусочкам, в цифровой вид. Букве, например, ставится в сопоставление байт (в ASCII), а картинка разбивается на много маленьких пикселей, и каждый из них выражается набором чисел, которые передают яркость и цветовую информацию. Моделей представления цвета много, и хотя, вообще говоря, не все равно, какую использовать для обучения — для простоты пока представим себе черно-белый мир, где один пиксель представляется числом от 0 до 1, выражающим его яркость — от черного до белого.



Что не так с этим представлением? Каждый пиксель здесь — независим, передает только небольшую часть информации о итоговой картинке. Это, с одной стороны, приятно и выгодно, когда нам нужно куда-то сохранить картинку или передать по сети, потому что она занимает меньше места, с другой — неудобно для распознавания. В нашем случае мы видим здесь наклонный штрих (немного с изгибом) в нижней части изображения — отсюда сложно догадаться, но это деталь контура носа с фотографии лица. Так вот, в данном случае нам важны те пиксели, которые составляют этот штрих, важна граница между черным и белым — а едва уловимая игра света в оттенках светло-серого в верхней части квадратика совершенно не важна, и не стоит даже тратить на нее вычислительные ресурсы. Но в этом представлении нам приходится иметь дело со всеми пикселями сразу — каждый из них ничем не лучше другого.
Давайте теперь представим себе другой код. Разложим этот квадратик на линейную сумму других таких же квадратиков, каждый из которых умножен на коэффициент. Можно себе представить, как мы берем много пластин темного стекла с разной прозрачностью, и на каждой пластине нарисованы различные штрихи — вертикальные, горизонтальные, разные. Мы кладем эти пластины стопкой друг на друга, и настраиваем прозрачность так, чтобы получить нечто похожее на наш рисунок — не идеальное, но достаточное для целей распознавания.



Наш новый код состоит из функциональных элементов — каждый из них теперь говорит что-то о присутствии в исходном квадратике какого-то отдельного осмысленного компонента. Видим коэффициент 0.01 у компонента с вертикальным штрихом — и понимаем, что в образце мало «вертикальности» (зато много «косого штриха» — см. первый коэффициент). Если мы независимым образом выберем компоненты этого нового кода, его словарь, то можно ожидать, что ненулевых коэффициентов будет немного — такой код называется разреженным (sparse).
Полезные свойства такого представления можно увидеть на примере одного из приложений под названием denoising autoencoder. Если взять изображение, разбить его на небольшие квадраты размером, допустим, 10x10, и для каждого кусочка подобрать соответствующий код — то мы можем с впечатляющей эффективностью затем очищать это изображение от случайного шума и искажений, переводя зашумленное изображение в код и восстанавливая обратно (пример можно найти, например, здесь). Это показывает, что код нечувствителен к случайному шуму, и сохраняет те части изображения, которые нужны нам для восприятия объекта — благодаря чему мы считаем, что шума после восстановления стало «меньше».

Обратной стороной такого подхода оказывается то, что новый код тяжеловесней — в зависимости от количества компонентов, бывший квадратик 10x10 пикселей может утяжелиться в значительно большей степени. Чтобы оценить масштаб — есть свидетельства того, что зрительная кора головного мозга человека кодирует 14x14 пикселей (размерность 196) с помощью примерно 100000 нейронов.

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

Пятиминутка практики


Воспользуемся пакетом scikit-learn — библиотекой для машинного обучения к SciPy (Python). И конкретно, классом (сюрприз) MiniBatchDictionaryLearning. MiniBatch — потому что алгоритм будет не над всем датасетом сразу, а поочередно над небольшими, случайно выбранными пачками данных. Процесс прост и занимает десять строчек кода:

from sklearn.decomposition import MiniBatchDictionaryLearning
from sklearn.feature_extraction.image import extract_patches_2d
from sklearn import preprocessing
from scipy.misc import lena

lena = lena() / 256.0  # тестовое изображение
data = extract_patches_2d(lena, (10, 10), max_patches=1000)  # извлекаем тысячу кусочков 10x10 - обучающую выборку
data = preprocessing.scale(data.reshape(data.shape[0], -1))  # rescaling - сдвигаем значения симметрично нуля, и чтобы стандартное отклонение равнялось 1
learning = MiniBatchDictionaryLearning(n_components=49)
features = learning.fit(data).components_


Если нарисовать то, что лежит в features, получится примерно следующее:
Вывод через pylab
import pylab as pl

for i, feature in enumerate(features):
    pl.subplot(7, 7, i + 1)
    pl.imshow(feature.reshape(10, 10),
              cmap=pl.cm.gray_r, interpolation='nearest')
    pl.xticks(())
    pl.yticks(())

pl.show()




Тут можно ненадолго остановиться и вспомнить, зачем мы все это изначально делали. Мы хотели получить набор достаточно независимых друг от друга «строительных кирпичиков», из которых складывается изображенный объект. Чтобы этого добиться, мы нарезали много-много маленьких квадратных кусочков, прогнали их через алгоритм, и получили, что все эти квадратные кусочки можно с достаточной степенью достоверности для распознавания представить в виде композиции вот таких компонентов. Поскольку на уровне 10x10 пикселей (хотя, конечно, зависит от разрешения картинки) мы сталкиваемся только с краями и границами, то их же и получаем в результате, все — с необходимостью разные.
Это закодированное представление мы можем использовать в качестве детектора. Чтобы понять, является ли случайно выбранный кусок картинки краем или границей, мы берем его и просим scikit подобрать эквивалентный код, вот так:

patch = lena[0:10, 0:10]
code = learning.transform(patch)


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

Но мы хотим двигаться дальше. Для этого понадобится еще несколько преобразований.
Итак, любой фрагмент размера 10x10 теперь можно выразить последовательностью из 49 чисел, каждое из которых будет означать коэффициент прозрачности для соответствующего компонента на картинке выше. А теперь возьмем эти 49 чисел и запишем в форме квадратной матрицы 7x7 — и нарисуем то, что получилось.
А получилось следующее (два примера для наглядности):



Слева — фрагмент оригинального изображения. Справа — его кодированное представление, где каждый пиксель — уровень присутствия в коде соответствующего компонента (чем светлее, тем сильнее). Можно заметить, что на первом фрагменте (верхнем) нет четко выраженного штриха, и его код выглядит смешением всего подряд в слабой бледно-серой интенсивности, а на втором четко присутствует один компонент — а остальные все равны нулю.

Теперь, чтобы обучить второй уровень иерархии, возьмем из оригинальной картинки фрагмент побольше (так, чтобы в него помещалось несколько маленьких — скажем, 30x30), разрежем его на маленькие фрагменты и представим каждый из них в кодированом варианте. Потом состыкуем обратно вместе, и на таких данных обучим еще один DictionaryLearning. Логика простая — если наша первоначальная идея правильна, то находящиеся рядом края и границы должны тоже складываться в устойчивые и повторяющиеся сочетания.



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

многовато картинок как-то

Тут, правда, размер фрагмента выбран побольше — 25x25 вместо 10x10. Одна из неприятных особенностей этого подхода — необходимость самому настраивать размер «минимальной смысловой единицы».


Некоторые трудности возникают с тем, чтобы нарисовать полученный «словарь», потому что второй уровень обучается на коде первого, и компоненты его будут выглядеть как пестрое крошево точек с рисунка выше. Для этого нам нужно сделать еще один шаг вниз — снова разбить эти компоненты на части, и «раскодировать» их при помощи первого уровня, но здесь этот процесс детально рассматривать не будем.

А дальше уровни наращиваются до тех пор, пока это необходимо, по совершенно такому же принципу. Вот, например, третий. И тут мы уже видим что-то интересное:


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

И что — все, мы победили?


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

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


Наш подход страдает из-за того же, за что мы раскритиковали обычные feed-forward нейронные сети. DictionaryLearning в процессе обучения пытается искать некоторые общие места, структурные компоненты выбранных фрагментов картинки. В случае с лицами у нас все получилось, потому что они более-менее похожи друг на друга — вытянутые овальные формы с некоторым количеством отклонений (а несколько уровней иерархии дает нам больше свободы в этом отношении). В случае с котиками — уже не получается, потому что во всем датасете с трудом можно отыскать два похожих силуэта. Алгоритм не находит ничего общего между картинками в тестовой выборке — исключая первые уровни, где мы все еще имеем дело со штрихами и границами. Фэйл. Опять тупик. Потрачено.

Идеи на будущее


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

Идея номер два вытекает из первой, и озвучивалась уже многими, в том числе упомянутым Джеффом Хокинсом — попытаться извлечь пользу из времени. В конце концов, разнообразие форм и поз, которое мы наблюдаем у одного объекта, мы видим во времени — и можем, для начала, группировать последовательно поступающие картинки, считая, что на них изображен один и тот же кот, просто каждый раз в несколько новой позе. А это значит, что нам, как минимум, придется кардинально сменить обучающую выборку, и вооружиться роликами с ютуба, найденными по запросу «kitty wakes up». Но об этом — в следующей серии.

Посмотреть на код


… можно на гитхабе. Запуск через python train.py myimage.jpg (можно также указать папку с картинками), плюс дополнительные параметры настройки — количество уровней, размер фрагментов и т.д. Требует scipy, scikit-learn и matplotlib.

Полезные ссылки и что еще можно вводного почитать про deep learning



  • A Primer on Deep Learning — информативный пост с историей вопроса, кратким введением и гораздо более красивыми картинками.
  • UFLDL Tutorial — туториал от уже упоминавшегося Andrew Ng из Стэнфорда — to get your hands dirty. Здесь буквально все, чтобы познакомиться с тем, как это работает — введение, математика процесса, параллели с feed-forward сетями, иллюстрированые примеры и упражнения в Matlab/Octave.
  • Бесплатная онлайновая книга Neural Networks and Deep Learning — к сожалению, еще не закончена. В достаточно популярном виде описывает основы, начиная с перцептронов, моделей нейронов и т.д.
  • Джоффри Хинтон рассказывает про новые поколений нейронных сетей
  • Последний talk с Хокинсом, где он вкратце излагает примерно то же, что в своей книге, но больше конкретики. О том, что должен уметь интеллектуальный алгоритм, что известные свойства человеческого мозга говорят нам про это, чем нас не устраивают нейронные сети, и чем полезен sparse coding.
Артем Хуршудов @rocknrollnerd
карма
196,0
рейтинг 0,2
Machine learning wannabe
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Реклама

Самое читаемое Разработка

Комментарии (48)

  • +10
    Вы ведь продолжите писать? И очень интересная тема, и котики! Perfect match!
    • +7
      Спасибо, постараюсь) В следующей серии будет про время.
  • +2
    Спасибо за статью, познавательно.
    Насчет выводов. Лично У меня есть идея, что при анализе реального мира мозг ориентируется на трехмерное представление объектов. То есть он хранит в памяти именно трехмерные образы, умея проводить их матчинг с текущим двумерным зрительным представлением. Потому что не хватит никакой памяти на хранение всех возможных ракурсов для сравнения, в отличие от грубой трехмерной модели объекта (вероятно, так же основанной на фичах) + карт текстур для закраски.

    Создание же эталонных трехмерных образов идет с помощью фотограмметрии на движущихся объектах. Т.е. да, с помощью «ютуба».

    Использует ли кто-нибудь данный подход в машинном обучении?
    • 0
      Совершенно логичная мысль) На этот счет есть фраза, кажется, того же Джоффри Хинтона (первоисточник уже не нашел), про то, что «Computer vision is inverse computer graphics». То есть если в трехмерной графике у нас есть модель, которая поворачивается и демонстрируется на экране разными сторонами, то для компьютерного зрения тоже должна существовать какая-то трехмерная модель абстрактного котика, куда будут «укладываться» все проекции, которые мы видим.

      По поводу прикладного использования — навскидку, можно почитать статью про transforming autoencoders. Идея там такая — вместе с картинкой для обучения кладем в алгоритм еще и информацию о том, где она находится, а на выходе заставляем алгоритм эту информацию предсказывать — так, чтобы он, увидев распознанный объект, мог сделать предположение о том, какой стороной он повернут.
    • 0
      Несколько лет назад на хабре высказывалась эта идея в комментариях к подобной статье. Интересно, через какое время она снова возникнет и когда появится реализация?
    • 0
      Трехмерную картинку мира нужно еще вначале реконструировать по зрительным образам, а эта задача чрезвычайно сложна. Человек распознает порядка 10 различных признаков глубины, причем «хардварных» из них только два (бинокулярное зрение / конвергенция и аккомодация), а все остальное основано на чистой обработке 2D — прямом распознавании в совершенно плоской картинке различных признаков глубины. В числе прочих признаков достоверно известно что в некоторых ситуациях человек реконструирует 3D по опыту знакомых ему трехмерных объектов. Т.е. он ВНАЧАЛЕ распознает по плоскому изображению знакомый ему объект и ПОТОМ это создает у него иллюзию определенных размеров, положения и глубины объекта.
      • 0
        Разве нельзя сделать точно такое же кодирование, как в статье, только не массивом двумерных штрихов, а набором трехмерных линий, углов, срезов?
        • 0
          Можно. Если уже есть трехмерная картинка, то её в принципе можно кодировать подобным образом. Очень сложно (поскольку воксельных данных на многие порядки больше чем пиксельных), но в принципе можно. Проблема в том что трехмерной картинки у человека изначально нет, а есть только два плоских изображения на которые он может влиять парой способов.
  • +5
    Спасибо большое, большая часть статьи написано простым и понятным языком, так что можно дать почитать совсем не программисту, и он поймёт.
    Было бы здорово увидеть больше статей в такой же манере.
    • +5
      Спасибо, надеюсь, что их будет. Мне иногда кажется, что большая часть материалов по этой теме страдает какой-то демонстративной научностью — много математики, тумана, непонятно, что эти нейросети вообще умеют, и где там AI уже.
    • 0
      Кстати, хорошее замечание про простой русский язык. Читал несколько статей в последнее время на эту же тему и тихонько понимал, что надо идти работать грузчиком. Здесь же вам большой плюс, если бы мог) В этой статье все ясно и понятно.
  • +3
    Статья читается отлично, даже есть элемент юмора ->
    поэтому эта вырезана из выступления Эндрю Ына (основатель Coursera) про deep learning

    Такой вариант русифицирования его фамилии я ещё не встречал :)
    • 0
      Вот вы будете смеяться, но он так в русской википедии назван) Я не знаток транслитерации корейского, но:
      1) на форуме курса Machine learning как-то был вопрос, как правильно читать эту фамилию, и присутствующие носители языка сказали, что мол, носовое «н», как в слове England.
      2) один Ким Чен с такой фамилией в медиа уже присутствует. Хотя на самом деле последний слог в его фамилии — «ун» ( Kim Jong Un в латинице). В общем, темная вещь этот хангыль)
  • +5
    Спасибо за хорошее видео по биологическим экспериментам с кошками!

    По поводу самой статьи — честно говоря, ожидал большего.

    1. Из прочтения названия и начала статьи возникло ощущение, что нам расскажут, как сделать метод распознавания кошек от собак средствами Deep Learning с качеством 98% на хорошей выборке (Kaggle). Этого не произошло, и это главное разочарование.

    2. Обучение алгоритма происходит в этих строках

    «learning = MiniBatchDictionaryLearning(n_components=49)
    features = learning.fit(data).components_»

    Что конкретно здесь происходит? Каким способом идет подстройка модели к словарю? Про это можно и нужно рассказать.

    3. Алгоритм сопоставления визуальных слов и векторов признаков (features) на их основе имеет примерно такое же отношение к Deep Learning, как колесо и трактор. У трактора есть колесо, но совершенно необязательно, что любой механизм с колесом — это трактор. То, что картинку можно представить как суперпозицию других картинок, которые формируют базис — это очень старая вообще идея, возникшая задолго до Deep Learning. Это и eigenfaces и эпитомы и много что еще.

    4. Вообще, главная «фишка» глубокого обучения состоит в том, что эти самые «визуальные слова» или «признаки» получаются автоматически во время процедуры «предобучения» (pre-training). То есть, визуальные слова-признаки — это не какие попало нарезанные куски одной картинки, а картинки, которые сгенерировались в итоге предобучения без учителя, суть которого — восстанавливать исходные изображения для задачи «бутылочное горлышко» с помощью алгоритмов RBM, Stacked Autoencoders или других алгоритмов.
    • +4
      Еще раз перечитал, более внимательно — хочу извиниться перед автором и забрать назад свое раздражение по поводу «неглубокости» алгоритма, извините за каламбур. Действительно, это имеет отношение к Deep Learning поскольку а) здесь используются автоенкодеры для поиска информативных частей картинки, которые используются как признаки и б) вручную формируется иерархичность, глубина иерархии определяется размером визуальных слов-признаков.
    • +2
      Спасибо за подробный отзыв) Конечно, это условно-обзорный пост, который оставляет за занавеской много деталей — в том числе то, что происходит под капотом DictionaryLearning, и чем всякие там orthogonal matching pursuit отличается от lasso-lars. Очевидно, писался он скорее для людей не в теме) Про Kaggle немного света пролить могу: например, победитель челленджа — некто Pierre Sermanet из группы Яна ЛеКуна, использовавший свою штуку под названием OverFeat, которая позиционируется как natural feature extractor и использует сверточные сети (куда без них).

      Про третий пункт — это да, было такое лирическое отступление. Вся эта идея dictionary learning была взята совершенно из сторонней темы и других источников — просто так уж вышло, что мы можем приспособить ее для обучения признакам, из которых потом будем составлять иерархию (вот тут уже появляется глубокость). Вместо этого мы могли использовать какую-нибудь RBM с тем же успехом. Наверное, стоило об этом уточнить подробнее — потому что про линейное кодирование картинки можно много увлекательного рассказать самого по себе.
      • +1
        Да уж, без сверточных сетей действительно никуда. Спасибо за статью и ссылки. Да, она написана для новичков — и поэтому за деревьями не всегда сразу видно лес (а он есть). Вообще, критиковать всегда намного легче, чем писать ))

        Желаю успехов!
  • +2
    Ого! Хабр как всегда в тему. Недели две назад задумался над тем, что устал пользоваться готовыми нейронными сетями без их понимания и хочу несколько сам запрогать-потестировать. И сейчас упёрся именно в свёрточные сети. Не понимаю я механизм обучения свёрточного слоя. Как я понимаю, у вас тут выделение главных компонент достаточно близко к нему реализовано? Кстати да, чем в целом тот подход что тут у вас приведён отличается от свёрточных сетей?

    На счёт кошечек и собачек. Лично мне кажется, что подход опирающийся на такие типы фичерсов для этой задачки слабо применим. Лучше пробовать выделять характерные текстуры, цвета (или их отношения) и градиенты. Это может быть более репрезентативным признаком.
    • +1
      Да, прочитав прошлый вопрос, хотел поправить свой вопрос. «выделением главных компонент» я назвал вот этот кусок

      learning = MiniBatchDictionaryLearning(n_components=49)
      features = learning.fit(data).components_

      Может я неправильно его смысл понял. Если так, то поясните что там происходит тогда.
      • 0
        Я вас понял, да) Про сверточные сети, к сожалению, вообще ничего не знаю и не могу сориентировать. Про «выделение компонент» — здесь мы решаем задачу разложения матрицы на линейную сумму составляющих, и решаться она, на самом деле, может кучей разных способов:

        — PCA, который вы упомянули — вполне подходит
        — автоэнкодеры, машины Больцмана, прочая традиционная атрибутика из области unsupervised feature learning
        — … внезапно, даже K-means

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

        Иногда к компонентам еще выставляют какие-то требования — например, что они должны быть разреженными, или топографически ориентированными (примерно вот так, то есть соседи каждого компонента по линейной сумме очень на него похожи с небольшим отклонением в какую-то сторону).

        А вот когда вы эти компоненты получили — насколько я очень смутно понимаю, потом уже в ход идет сверточность. Допустим, знаем, что где-то на изображении 800x600 спрятано лицо размера 160x160. Чтобы понять, где именно, возьмем наш лицо-компонент и начнем проходиться им по всей картинке с шагом в один пиксель, постоянно проверяя, не найдется ли хорошего совпадения — это, собственно, и есть свертка. Результат прохода добавим себе в выборку для следующего этапа обучения, и когда таких наберется прилично — будем учиться искать среди фильтрованных картинок те, где свертка дала хороший результат (то есть в процессе прохода мы-таки наткнулись на лицо). Это, справедливости ради, очень туманное представление, которое у меня где-то есть про сверточные сети, и очень возможно, что я неправ)
  • 0
    Такое впечатление, что весь каскад работает только на дивергенцию признаков, на первом слое находятся элементарные признаки, на следующем, — определённые сочетания элементов первого уровня в пространстве, и так далее. Надо как-то обеспечить конвергенцию, иначе — комбинаторный взрыв. Есть же инварианты, например, угол поворота «фичи», масштабирование, параллельный перенос. Сейчас, кажется, лица предварительно центруют перед запуском в ИНС, но рано или поздно сетевые алгоритмы должны вобрать в себя эту функцию. Чтобы на верхнем уровне было не
    >>несколько наиболее встречающихся расположений — фронтальное, пол-оборота направо и налево, плюс разные цвета кожи
    а разная высота лба, форма рта, разрез глаз (ну и цвет кожи тоже).
    • +1
      Тут, между прочим, могут найтись интересные грабли, потому что вообще говоря, фичи с разным масштабом и углом поворота — «не invariant, а equivariant» (Хинтон лидирует по объемам цитирования в этом посте и комментах)). То есть мы-то, конечно, понимаем, что кошка, перевернутая вверх ногами — та же самая кошка, что и не перевернутая, но у нас при этом появляется дополнительная информация о том, что она все-таки перевернутая. И вообще говоря, мы не должны распознавать их как одно и то же. Косвенным подтверждением того, что наш с вами мозг не всегда с легкостью вращает и масштабирует увиденное, может быть mental rotation — тот факт, что мы не можем читать текст вверх ногами, не делая неких осознанных усилий по переворачиванию букв.
      В качестве многообещающего подхода на этот счет я там выше приводил ссылку на transforming autoencoders — к сожалению, маловато демонстративных данных пока, но то что есть, выглядит круто. Если доберусь до следующего поста по теме, обязательно напишу про это.
      • 0
        Про перевёрнутый текст не соглашусь, по-моему, он читается настолько же просто (по крайней мере, русский). Усилия иногда приходится прикладывать, чтобы восстанавливать правильный порядок слов (при быстром чтении они начинают переставляться), но буквы узнаются (и складываются в слова) сразу, как картинки. Почти так же легко читается и зеркальный текст. С английским текстом и формулами хуже — для их перевёрнутого варианта действительно приходится соображать.
        • 0
          А не пробовали засекать количество слов в минуту обычным и перевернутым способом? В принципе, конечно, в таком восприятии нет ничего невозможного — немного практики по чтению таких текстов, и перевернутая буква становится такой же распознаваемой картинкой, чем обычная. Но зеркальный текст, например, я читаю очень медленно — перевернутый еще куда ни шло)
          • 0
            Попробовал. Перевёрнутый примерно вдвое медленнее — на отрывок в 120 слов ушло 39 секунд против 17. На зеркальный вариант — около 100 секунд.
            Но я не думаю, что мозг переворачивает или отражает все буквы. Скорее, там идёт runtime расшифровка закодированного текста — попытка угадать, какой крючок какой букве соответствует. Проблемы возникают на редких и необычных для русского языка словах, там действительно приходится отражать буквы в голове.
          • 0
            с бувками еще ничего, а вот узнавать перевернутые лица мозг практически не способен, можете на друзьях проверить. Но опять же, здесь во многом вопрос набора обучающих данных — с перевернутыми буквами мозг сталкивается регулярно, а с лицами практически никогда. получается, «вращение» не работает в мозге автоматически, а надстраивается следующим слоем?
            • 0
              с бувками еще ничего, а вот узнавать перевернутые лица мозг практически не способен, можете на друзьях проверить.

              ??? Вполне узнаю, хотя, наверное, медленнее.
              Что касается «автоматичности», то реализация механизма неизвестна, можно строить предположения, например о том, что механизм не запрограммирован генетически, а приобретается при обучении. То, что распознавание перевернутого лица занимает больше времени, возможно, действительно указывает на то что основной прямой путь от первичной зрительной коры к области лиц с этой задачей сам не справляется, и требует либо нескольких проходов, либо задействует другие пути и поля, «надстраивается следующим слоем», можно и так сказать, наверное.
      • 0
        Совершенно верно, находя инвариант, мы попутно извлекаем признак (угол поворота кошки). Непонятно, как сети находить инварианты. Возможно, наблюдая за движущимися объектами.
  • 0
    98,8% — это очень круто!
    С таким качеством распознавания скоро уже идей для капч не останется :)
    • 0
      Согласен, впечатляет) Причем если скачать датасет и посмотреть на примеры, впечатляет еще сильнее — там полно картинок типа «фигура человека во весь рост и маленький, еле заметный котик на руках». Примеры в посте как раз оттуда, но не самые показательные.
      А про капчи — идею с собачками всегда можно развить чуть дальше)
      image

      Вот на этой картинке, между прочим, с треском ломается вся логика про много уровней фич — тут даже контура нет! Победители челленджа, наверное, пользовались какими-то другими подходами — интересно, что у них бы получилось здесь.
    • 0
      Это очень хороший признак того что соревнование было проведено ошибочно.
      Я почитал сейчас правила и похоже что там элементарно нет разделения на обучающую и тестовую выборки
      • +1
        нет разделения на обучающую и тестовую выборки


        Гм, там как раз про это чётко написано:
        «The training archive contains 25,000 images of dogs and cats. Train your algorithm on these files and predict the labels for test1.zip (1 = dog, 0 = cat).»
        Судя по размеру файла, тестовая выборка примерно в два раза меньше обучающей.

        А ещё ниже написано про возможные пути реального читерства, и как организаторы с этим борются :)
        • 0
          Спасибо, ясно. Но поскольку тестовая выборка общедоступна и классификация гоняется на компьютерах участников, то ничего не мешало обучить алгоритм и на этой выборке.
          Предложенный механизм борьбы в виде релиза новой тестовой выборки перед концом соревнований заведомо нерабочий — эта новая выборка все равно вначале поступает участникам, которые имеют возможность вначале дообучить свои классификаторы, добиться подгонкой хороших результатов и лишь после этого опубликовать результат на новой выборке.
          Для исключения читерства необходимо было бы забрать у участников их алгоритмы и скормить этим алгоритмам заранее неизвестную выборку.
          Этого, как я понимаю, сделано не было.
          • 0
            Как Вы обучать без ответов собрались?
            • 0
              Обучающая выборка должна быть доступна, я про то что тестовая выборка должна от неё отличаться и быть неизвестна
              • 0
                Ну так, так и есть, тестовая выборка отличается от обучающей, и ответы для неё неизвестны. Как Вы обучать на тесте-то собрались?
                • 0
                  А, понял о чем Вы. Ответы для тестовой выборки может (в пределах тысячи картинок) сделать и человек. Собственно как Вы результат теста проверять-то будете :)?
                  • 0
                    Так проверять-то система будет, а не человек, посылающий решение.

                    Картинок в тесте там 12.5к — многовато для человека.
                    • 0
                      Для автоматической проверки вначале человек должен вначале вручную составить разметку.
                      Хотя 12.5к картинок — это уже прилично, работы по разметке на день
                      • 0
                        Да, и на странице соревнования описано, что они могут сделать для противостояния этому. У них там 3 миллиона картинок — могут тест и на 200к выдать.
      • 0
        www.kaggle.com/c/dogs-vs-cats/data — собственно, вот тут test и train)
        • 0
          ОК, разделение формально есть, но оно не защищено адекватным образом от читерства (см. выше)
          Авторы даже не позаботились расписать подробно какие меры ими были предприняты в ходе борьбы с читерством.
  • 0
    Это не в сторону ImageNet рассуждения? (http://image-net.org/challenges/LSVRC/2014/)
  • +1
    Общее замечание: недавно была опубликована прекрасная статья которая хорошо критиковала именно тот подход который Вы здесь изложили :).

    Эта картинка и предисловие — из челленджа на Kaggle, который проходил осенью прошлого года. Забегая вперед, на последний вопрос вполне можно ответить «да» — десятка лидеров справилась с заданием на 98.8%, что на удивление впечатляет.


    Насколько я могу судить по условиям конкурса, там от алгоритма требовалось всего лишь разделить изображения в фиксированном наборе. Прямо до такой степени что авторам пришлось аж специально оговаривать что запрещено встраивать в алгоритм простую распознавалку знакомых изображения и комплект ручной разметки для тестового набора :D. Для капчи может это и разумный подход (там набор все ж таки ограничен), но о распознавании с точностью 98.8% реальных изображений речь здесь не идет даже близко.

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


    Элементарная линейная алгебра подсказывает что любое линейное разложение квадратика 10x10 на независимые компоненты требует не более 10x10 коэффициентов. Больше коэффициентом можно сделать либо нелинейным разложением либо добавляя коэффициенты которые не независимы (однозначно вычисляются из ранее заданных коэффициентов).
    • +1
      Эта статья по первой ссылке подняла неслабый хайп, да) Тоже хотел что-нибудь про нее написать, но остерегся, потому что не читал оригинал — а переложения и комментарии какие-то слишком панические — например, по вашей первой ссылке, когда я ее читал, мне показалось, что та же проблема может быть вызвана обычным оверфиттингом, и бегать с криками «спасите, нейронные сети не работают» как-то рано.

      Про разложение — спасибо за замечание, надо было отдельно оговорить, что нас интересует именно overcomplete basis.
  • 0
    но о распознавании с точностью 98.8% реальных изображений речь здесь не идет даже близко


    Судя по вот этому обсуждению, можно вполне реально честно получить на конкурсных данных точность под 97%, никуда не подглядывая и ничего вручную не размечая.
  • +1
    Есть просьба-вопрос от новичка в теме:
    Как я видел, словарь строится на определенном наборе изображений, заданных все-таки в пикселях. Допустим, в обучающем наборе с лицами будут присутствовать одновременно портреты крупным планом и в полный рост. Правильно ли я понимаю, что даже при хорошем результате в словаре мы получим отдельно лица крупным планом и отдельно генерализации человеческих фигур? Где почитать о том, как в данном случае решается проблема масштаба определяемого элемента на исходном изображении?
    • +1
      Так и есть, да. Насчет масштаба и прочих пространственных трансформаций мне наиболее многообещающей кажется идея с transforming autoencoder (уже выше мелькала ссылка). Смысл в том, что в параметры картинки вкладывается не только ее пиксельное содержимое, но и информация о, допустим, масштабе, с которым глаза/камера смотрит на объект. На выходе ваша модель должна, аналогично, предсказывать масштаб, с которым изображен объект, который, по его мнению, он нашел.

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

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