VGG16 — сверточная сеть для выделения признаков изображений

23 ноября 2018
vgg16 нейронная сеть

VGG16 — сверточная сеть для выделения признаков изображений

VGG16 — модель сверточной нейронной сети, предложенная K. Simonyan и A. Zisserman из Оксфордского университета в статье “Very Deep Convolutional Networks for Large-Scale Image Recognition”. Модель достигает точности 92.7% —…

VGG16 — модель сверточной нейронной сети, предложенная K. Simonyan и A. Zisserman из Оксфордского университета в статье “Very Deep Convolutional Networks for Large-Scale Image Recognition”. Модель достигает точности 92.7% — топ-5, при тестировании на ImageNet в задаче распознавания объектов на изображении. Этот датасет состоит из более чем 14 миллионов изображений, принадлежащих к 1000 классам.

VGG16 — одна из самых знаменитых моделей, отправленных на соревнование ILSVRC-2014. Она является улучшенной версией AlexNet, в которой заменены большие фильтры (размера 11 и 5 в первом и втором сверточном слое, соответственно) на несколько фильтров размера 3х3, следующих один за другим. Сеть VGG16 обучалась на протяжении нескольких недель при использовании видеокарт NVIDIA TITAN BLACK.

слои vgg16

Датасет

ImageNet — набор данных, состоящий из более чем 15 миллионов размеченных высококачественных изображений, разделенных на 22000 категорий. Изображения были взяты из интернета и размечены вручную людьми-разметчиками с помощью краудсорсинговой площадки Mechanical Turk от Amazon.

В 2010 году, как часть Pascal Visual Object Challenge, началось ежегодное соревнование — ImageNet Large-Scale Visual Recognition Challenge (ILSVRC). В ILSVRC используется подвыборка из ImageNet размером 1000 изображений в каждой из 1000 категорий. Таким образом, тренировочный сет состоял из примерно 1.2 миллионов изображений, проверочный — 50000 изображений, тестовый — 150000 изображений. Так как ImageNet состоит из изображений разного размера, то их необходимо было привести к единому размеру 256х256. Если изображение представляет из себя прямоугольник, то оно масштабируется и из него вырезается центральная часть размером 256х256.

Архитектура

Архитектура VGG16 представлена на рисунке ниже.

Архитектура нейросети vgg16

На вход слоя conv1 подаются RGB изображения размера 224х224. Далее изображения проходят через стек сверточных слоев, в которых используются фильтры с очень маленьким рецептивным полем размера 3х3 (который является наименьшим размером для получения представления о том,где находится право/лево, верх/низ, центр).

В одной из конфигураций используется сверточный фильтр размера 1х1, который может быть представлен как линейная трансформация входных каналов (с последующей нелинейностью). Сверточный шаг фиксируется на значении 1 пиксель. Пространственное дополнение (padding) входа сверточного слоя выбирается таким образом, чтобы пространственное разрешение сохранялось после свертки, то есть дополнение равно 1 для 3х3 сверточных слоев. Пространственный пулинг осуществляется при помощи пяти max-pooling слоев, которые следуют за одним из сверточных слоев (не все сверточные слои имеют последующие max-pooling). Операция max-pooling выполняется на окне размера 2х2 пикселей с шагом 2.

После стека сверточных слоев (который имеет разную глубину в разных архитектурах) идут три полносвязных слоя: первые два имеют по 4096 каналов, третий — 1000 каналов (так как в соревновании ILSVRC требуется классифицировать объекты по 1000 категориям; следовательно, классу соответствует один канал). Последним идет soft-max слой. Конфигурация полносвязных слоев одна и та же во всех нейросетях.

Все скрытые слои снабжены ReLU. Отметим также, что сети (за исключением одной) не содержат слоя нормализации (Local Response Normalisation), так как нормализация не улучшает результата на датасете ILSVRC, а ведет к увеличению потребления памяти и времени исполнения кода.

Конфигурация

Конфигурации сверточных сетей представлены на рисунке 2. Каждая сеть соответствует своему имени (A-E). Все конфигурации имеют общую конструкцию, представленную в архитектуре, и различаются только глубиной: от 11 слоев с весами в сети A (8 сверточных и 3 полносвязных слоя) до 19 (16 сверточных и 3 полносвязных слоя). Ширина сверточных слоев (количество каналов) относительно небольшая: от 64 в первом слое до 512 в последнем с увеличением количества каналов в 2 раза после каждого max-pooling слоя.

vgg16
Рисунок 2

Реализация

К сожалению, сеть VGG имеет два серьезных недостатка:

  1. Очень медленная скорость обучения.
  2. Сама архитектура сети весит слишком много (появляются проблемы с диском и пропускной способностью)

Из-за глубины и количества полносвязных узлов, VGG16 весит более 533 МБ. Это делает процесс развертывания VGG утомительной задачей. Хотя VGG16 и используется для решения многих проблем классификации при помощи нейронных сетей, меньшие архитектуры более предпочтительны (SqueezeNet, GoogLeNet и другие). Несмотря на недостатки, данная архитектура является отличным строительным блоком для обучения, так как её легко реализовать.

[Pytorch]

[Tensorflow]

[Keras]

Результаты

VGG16 существенно превосходит в производительности прошлые поколения моделей в соревнованиях ILSVRC-2012 and ILSVRC-2013. Достигнутый VGG16 результат сопоставим с победителем соревнования по классификации (GoogLeNet с ошибкой 6.7%) в 2014 году и значительно опережает результат Clarifai победителя ILSVRC-2013, который показал ошибку 11.2% с внешними тренировочными данными и 11.7% без них. Что касается одной сети, архитектура VGG16 достигает наилучшего результата (7.0% ошибки на тесте), опережаю одну сеть GoogLeNet на 0.9%.

Было показано, что глубина представления положительно влияет на точность классификации, и state-of-the-art результат на соревновательном датасете ImageNet может быть достигнут с помощью обычной сверточной нейронной сети с значительно большей глубиной.

Реализация Transfer learning с библиотекой Keras

22 ноября 2018
transfer-learning-keras

Реализация Transfer learning с библиотекой Keras

Для большинства задач компьютерного зрения не существует больших датасетов (около 50 000 изображений). Даже при экстремальных стратегиях аугментации данных трудно добиться высокой точности. Обучение таких сетей с миллионами параметров обычно…

Для большинства задач компьютерного зрения не существует больших датасетов (около 50 000 изображений). Даже при экстремальных стратегиях аугментации данных трудно добиться высокой точности. Обучение таких сетей с миллионами параметров обычно имеет тенденцию перегружать модель. В этом случае Transfer learning готов прийти на помощь.

Inception-V3 Google Research

Что такое Transfer learning?

Transfer Learning (TL) — одно из направлений исследований в машинном обучении, которое изучает возможность применения знаний, полученных при решении одной задачи, к другой.

Зачем нужен Trasfer learning?

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

Как может помочь Trasfer learning?

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

transfer learning
Inception V3 Google Research

Простая реализация с помощью Keras


Помня, что свойства СonvNet являются более примитивными на первых слоях и усложняются с каждым последующим слоем, рассмотрим четыре типичных сценария.

1. Новый датасет небольшой и аналогичен исходному датасету

Если мы пытаемся обучить всю сеть сразу, возникает проблема перегрузки модели. Поскольку данные аналогичны исходным, мы ожидаем, что свойства более высокого уровня в ConvNet также будут иметь отношение к этому датасету. Следовательно, лучшей стратегией может быть обучение линейного классификатора по кодам CNN.

Таким образом, давайте отбросим все слои VGG19 и обучим только классификатор:

for layer in model.layers:
   layer.trainable = False
#Now we will be training only the classifiers (FC layers)

2. Новый датасет большой и аналогичен исходному

Так как у нас есть больше данных, есть большая уверенность в том, что мы не перегрузим модель, если попробуем выполнить точную настройку всей сети сразу:

for layer in model.layers:
   layer.trainable = True
#The default is already set to True. I have mentioned it here to make things clear.

Если вы хотите отбросить несколько первых слоев, формирующих самые примитивные свойства, это можно сделать с помощью следующего кода:

for layer in model.layers[:5]:
   layer.trainable = False.
# Here I am freezing the first 5 layers

3. Новый датасет небольшой и сильно отличается от исходного

Так как датасет небольшой, можно экспортировать свойства из более ранних слоев и обучить классификатор поверх них. Для этого требуются некоторые знания h5py:

Этот код должен помочь. Он будет извлекать свойства «block2_pool». Обычно это не очень полезно, поскольку слой имеет 64х64х128 свойств и обучение классификатора поверх них может и не помочь. Можно добавить несколько полносвязных слоев и обучить нейронную сеть поверх них. Это нужно делать в следующем порядке:

  1. Добавьте несколько FC слоев и выходной слой.
  2. Задайте весовые коэффициенты для более ранних слоев и отбросьте их.
  3. Обучите сеть.

4. Новый датасет большой и сильно отличается от исходного

Поскольку датасет большой, можно создать свою собственную сеть или использовать существующие. В этом случае надо действовать следующим образом.

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

FaceNet — пример простой системы распознавания лиц с открытым кодом Github

16 ноября 2018

FaceNet — пример простой системы распознавания лиц с открытым кодом Github

Распознавание лица — последний тренд в авторизации пользователя. Apple использует Face ID, OnePlus — технологию Face Unlock. Baidu использует распознавание лица вместо ID-карт для обеспечения доступа в офис, а при…

Распознавание лица — последний тренд в авторизации пользователя. Apple использует Face ID, OnePlus — технологию Face Unlock. Baidu использует распознавание лица вместо ID-карт для обеспечения доступа в офис, а при повторном пересечении границы в ОАЭ вам нужно только посмотреть в камеру.

В статье разбираемся, как сделать простейшую сеть распознавания лиц самостоятельно с помощью FaceNet.

Ссылка на Гитхаб, кому нужен только код

Немного о FaceNet

FaceNet — нейронная сеть, которая учится преобразовывать изображения лица в компактное евклидово пространство, где дистанция соответствует мере схожести лиц. Проще говоря, чем более похожи лица, тем они ближе.

Триплет потерь

FaceNet использует особую функцию потерь называемую TripletLoss. Она минимизирует дистанцию между якорем и изображениями, которые содержат похожую внешность, и максимизирует дистанцую между разными.

  • f(a) это энкодинг якоря
  • f(p) это энкодинг похожих лиц (positive)
  • f(n) это энкодинг непохожих лиц (negative)
  • Альфа — это константа, которая позволяет быть уверенным, что сеть не будет пытаться оптимизировать напрямую f(a) — f(p) = f(a) — f(n) = 0
  • […]+ экиввалентено max(0, sum)

Сиамские сети

FaceNet — сиамская сеть. Сиамская сеть — тип архитектуры нейросети, который обучается диффиренцированию входных данных. То есть, позволяет научиться понимать какие изображения похожи, а какие нет.

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

В FaceNet это делается путем вычисления расстояния между двумя выходами.

Реализация

Переходим к практике.

В реализации мы будем использовать Keras и Tensorflow. Кроме того, мы используем два файла утилиты из репозитория deeplayning.ai, чтобы абстрагироваться от взаимодействий с сетью FaceNet.

  • fr_utils.py содержит функции для подачи изображений в сеть и получения кодирования изображений;
  • inception_blocks_v2.py содержит функции для подготовки и компиляции сети FaceNet.

Компиляция сети FaceNet

Первое, что нам нужно сделать, это собрать сеть FaceNet для нашей системы распознавания лиц.

import os
import glob
import numpy as np
import cv2
import tensorflow as tf
from fr_utils import *
from inception_blocks_v2 import *
from keras import backend as K
K.set_image_data_format('channels_first')
FRmodel = faceRecoModel(input_shape=(3, 96, 96))
def triplet_loss(y_true, y_pred, alpha = 0.3):
    anchor, positive, negative = y_pred[0], y_pred[1], y_pred[2]

    pos_dist = tf.reduce_sum(tf.square(tf.subtract(anchor,
               positive)), axis=-1)
    neg_dist = tf.reduce_sum(tf.square(tf.subtract(anchor, 
               negative)), axis=-1)
    basic_loss = tf.add(tf.subtract(pos_dist, neg_dist), alpha)
    loss = tf.reduce_sum(tf.maximum(basic_loss, 0.0))
   
    return loss
FRmodel.compile(optimizer = 'adam', loss = triplet_loss, metrics = ['accuracy'])
load_weights_from_FaceNet(FRmodel)

Мы начнем инициализпцию нашей сети со входа размерности (3, 96, 96). Это означает, что картинка передается в виде трех каналов RGB и размерности 96×96 пикселей.

Теперь давайте определим Triplet Loss функцию. Функция в сниппете кода выше удовлетворяет уравнению Triplet Loss, которое мы определили в предыдущей секции.

Если вы не знакомы с фреймворком TensorFlow, ознакомьтесь с документацией.

Сразу после того, как мы определили функцию потерь, мы можем скомпилировать нашу систему распознавания лиц с помощью Keras. Мы будем использовать Adam optimizer для минимизации потерь, подсчитанных с помощью функции Triplet Loss.

Подготовка базы данных

Теперь когда мы скомпилировали FaceNet, нужно подготовить базу данных личностей, которых сеть будет распознавать. Мы будем использовать все изображения, которые лежат в директории images.

Замечание: мы будем использовать по одному изображения на человека в нашей реализации.  FaceNet достаточно мощна, чтобы распознать человека по одной фотографии.

def prepare_database():
    database = {}
    for file in glob.glob("images/*"):
        identity = os.path.splitext(os.path.basename(file))[0]
        database[identity] = img_path_to_encoding(file, FRmodel)
    return database

Для каждого изображения мы преобразуем данные изображения в 128 float чисел. Этим занимается функция img_path_to_encoding. Функция принимает на вход путь до изображения и «скармливает» изображение нашей распознающей сети, после чего возвращают результаты работы сети.

Как только мы получили закодированное изображения в базе данных, сеть наконец готова приступить к распознаванию!

Распознавание лиц

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

def who_is_it(image, database, model):
    encoding = img_to_encoding(image, model)
    
    min_dist = 100
    identity = None
    
    # Loop over the database dictionary's names and encodings.
    for (name, db_enc) in database.items():
        dist = np.linalg.norm(db_enc - encoding)
        print('distance for %s is %s' %(name, dist))
        if dist < min_dist:
            min_dist = dist
            identity = name
    
    if min_dist > 0.52:
        return None
    else:
        return identity

Загружаем новое изображение в функцию img_to_encoding. Функция обрабатывает изображения, используя FaceNet и возвращает закодированное изображение. Теперь мы можем сделать предположение о наиболее вероятной личности этого человека.

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

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

 if min_dist > 0.52: 
     return None 
 else:
     return identity

Магическое число 0.52 получено методом проб и ошибок. Для вас это число может отличатся, в зависимости от реализации и данных. Попробуйте настроить самостоятельно.

На GitHub есть демо работы полученной сети, с входом от простой вебкамеры.

Заключение

Теперь вы знаете, как работают технологии распознавания лиц и можете сделать собственную упрощенную сеть распознавания, используя предварительно подготовленную версию алгоритма FaceNet на python.


Интересные статьи:

Как создать нейронную сеть c библиотекой Keras на Python: пример

9 октября 2018
keras нейронаня сеть на python

Как создать нейронную сеть c библиотекой Keras на Python: пример

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

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

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

Обратите внимание, что мы не будем вдаваться в подробности Keras и глубокого обучения. Этот пост предназначен для того, чтобы предоставить схему нейронной сети в Keras и познакомить с ее реализацией.

Содержание:

  • Что такое Keras?
  • Что такое анализ настроений?
  • Датасет IMDB
  • Импорт зависимостей и получение данных
  • Изучение данных
  • Подготовка данных
  • Создание и обучение модели

Что такое Keras?

Keras — это библиотека для Python с открытым исходным кодом, которая позволяет легко создавать нейронные сети. Библиотека совместима с TensorFlow, Microsoft Cognitive Toolkit, Theano и MXNet. Tensorflow и Theano являются наиболее часто используемыми численными платформами на Python для разработки алгоритмов глубокого обучения, но они довольно сложны в использовании.

deep learning frameworks
Оценка популярности фреймворков машинного обучения по 7 категориям

Читайте: TensorFlow туториал. Часть 1: тензоры и векторы

Keras, наоборот, предоставляет простой и удобный способ создания моделей глубокого обучения. Ее создатель, François Chollet, разработал ее для того, чтобы максимально ускорить и упростить процесс создания нейронных сетей. Он сосредоточил свое внимание на расширяемости, модульности, минимализме и поддержке Python. Keras можно использовать с GPU и CPU; она поддерживает как Python 2, так и Python 3. Keras компании Google внесла большой вклад в коммерциализацию глубокого обучения и искусственного интеллекта, поскольку она содержит cовременные алгоритмы глубокого обучения, которые ранее были не только недоступными, но и непригодными для использования.

Что такое анализ настроений (сентимент-анализ)?

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

keras нейронная сеть анализ настроений
Пример шкалы анализа настроений

Спектр настроений обычно подразделяется на положительные, отрицательные и нейтральные категории. С использованием анализа настроений можно, например, прогнозировать мнение клиентов и их отношение к продукту на основе написанных ими обзоров. Поэтому анализ настроений широко применяется к обзорам, опросам, текстам и многому другому.

Датасет IMDb

imdb reviews sentiment
Рецензии на сайте IMDb

Датасет IMDb состоит из 50 000 обзоров фильмов от пользователей, помеченных как положительные (1) и отрицательные (0).

  • Рецензии предварительно обрабатываются, и каждая из них кодируется последовательностью индексов слов в виде целых чисел.
  • Слова в обзорах индексируются по их общей частоте появления в датасете. Например, целое число «2» кодирует второе наиболее частое используемое слово.
  • 50 000 обзоров разделены на два набора: 25 000 для обучения и 25 000 для тестирования.

Датасет был создан исследователями Стэнфордского университета и представлен в статье 2011 года, в котором достигнутая точность предсказаний была равна 88,89%. Датасет также использовался в рамках конкурса сообщества Keggle «Bag of Words Meets Bags of Popcorn» в 2011 году.

Импорт зависимостей и получение данных

Начнем с импорта необходимых зависимостей для предварительной обработки данных и построения модели.

%matplotlib inline
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
from keras.utils import to_categorical
from keras import models
from keras import layers

Загрузим датесет IMDb, который уже встроен в Keras. Поскольку мы не хотим иметь данные обучения и тестирования в пропорции 50/50, мы сразу же объединим эти данные после загрузки для последующего разделения в пропорции 80/20:

from keras.datasets import imdb
(training_data, training_targets), (testing_data, testing_targets) = imdb.load_data(num_words=10000)
data = np.concatenate((training_data, testing_data), axis=0)
targets = np.concatenate((training_targets, testing_targets), axis=0)

Изучение данных

Изучим наш датасет:

print("Categories:", np.unique(targets))
print("Number of unique words:", len(np.unique(np.hstack(data))))
Categories: [0 1]
Number of unique words: 9998
length = [len(i) for i in data]
print("Average Review length:", np.mean(length))
print("Standard Deviation:", round(np.std(length)))
Average Review length: 234.75892
Standard Deviation: 173.0

Можно видеть, что все данные относятся к двум категориям: 0 или 1, что представляет собой настроение обзора. Весь датасет содержит 9998 уникальных слов, средний размер обзора составляет 234 слова со стандартным отклонением 173.

Рассмотрим простой способ обучения:

print("Label:", targets[0])
Label: 1
print(data[0])
[1, 14, 22, 16, 43, 530, 973, 1622, 1385, 65, 458, 4468, 66, 3941, 4, 173, 36, 256, 5, 25, 100, 43, 838, 112, 50, 670, 2, 9, 35, 480, 284, 5, 150, 4, 172, 112, 167, 2, 336, 385, 39, 4, 172, 4536, 1111, 17, 546, 38, 13, 447, 4, 192, 50, 16, 6, 147, 2025, 19, 14, 22, 4, 1920, 4613, 469, 4, 22, 71, 87, 12, 16, 43, 530, 38, 76, 15, 13, 1247, 4, 22, 17, 515, 17, 12, 16, 626, 18, 2, 5, 62, 386, 12, 8, 316, 8, 106, 5, 4, 2223, 5244, 16, 480, 66, 3785, 33, 4, 130, 12, 16, 38, 619, 5, 25, 124, 51, 36, 135, 48, 25, 1415, 33, 6, 22, 12, 215, 28, 77, 52, 5, 14, 407, 16, 82, 2, 8, 4, 107, 117, 5952, 15, 256, 4, 2, 7, 3766, 5, 723, 36, 71, 43, 530, 476, 26, 400, 317, 46, 7, 4, 2, 1029, 13, 104, 88, 4, 381, 15, 297, 98, 32, 2071, 56, 26, 141, 6, 194, 7486, 18, 4, 226, 22, 21, 134, 476, 26, 480, 5, 144, 30, 5535, 18, 51, 36, 28, 224, 92, 25, 104, 4, 226, 65, 16, 38, 1334, 88, 12, 16, 283, 5, 16, 4472, 113, 103, 32, 15, 16, 5345, 19, 178, 32]

Здесь вы видите первый обзор из датасета, который помечен как положительный (1). Нижеследующий код производит обратное преобразование индексов в слова, чтобы мы могли их прочесть. В нем каждое неизвестное слово заменяется на «#». Это делается с помощью функции get_word_index ().

index = imdb.get_word_index()
reverse_index = dict([(value, key) for (key, value) in index.items()]) 
decoded = " ".join( [reverse_index.get(i - 3, "#") for i in data[0]] )
print(decoded) 

# this film was just brilliant casting location scenery story direction everyone's really suited the part they played and you could just imagine being there robert # is an amazing actor and now the same being director # father came from the same scottish island as myself so i loved the fact there was a real connection with this film the witty remarks throughout the film were great it was just brilliant so much that i bought the film as soon as it was released for # and would recommend it to everyone to watch and the fly fishing was amazing really cried at the end it was so sad and you know what they say if you cry at a film it must have been good and this definitely was also # to the two little boy's that played the # of norman and paul they were just brilliant children are often left out of the # list i think because the stars that play them all grown up are such a big profile for the whole film but these children are amazing and should be praised for what they have done don't you think the whole story was so lovely because it was true and was someone's life after all that was shared with us all

Подготовка данных

Пришло время подготовить данные. Нужно векторизовать каждый обзор и заполнить его нулями, чтобы вектор содержал ровно 10 000 чисел. Это означает, что каждый обзор, который короче 10 000 слов, мы заполняем нулями. Это делается потому, что самый большой обзор имеет почти такой же размер, а каждый элемент входных данных нашей нейронной сети должен иметь одинаковый размер. Также нужно выполнить преобразование переменных в тип float.

def vectorize(sequences, dimension = 10000):
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
results[i, sequence] = 1
return results
 
data = vectorize(data)
targets = np.array(targets).astype("float32")

Разделим датасет на обучающий и тестировочный наборы. Обучающий набор будет состоять из 40 000 обзоров, тестировочный — из 10 000.

test_x = data[:10000]
test_y = targets[:10000]
train_x = data[10000:]
train_y = targets[10000:]

Создание и обучение модели

Теперь можно создать простую нейронную сеть. Начнем с определения типа модели, которую мы хотим создать. В Keras доступны два типа моделей: последовательные и с функциональным API.

Затем нужно добавить входные, скрытые и выходные слои. Для предотвращения переобучения будем использовать между ними исключение («dropout»). Обратите внимание, что вы всегда должны использовать коэффициент исключения в диапазоне от 20% до 50%. На каждом слое используется функция «dense» для полного соединения слоев друг с другом. В скрытых слоях будем используем функцию активации «relu», потому это практически всегда приводит к удовлетворительным результатам. Не бойтесь экспериментировать с другими функциями активации. На выходном слое используем сигмоидную функцию, которая выполняет перенормировку значений в диапазоне от 0 до 1. Обратите внимание, что мы устанавливаем размер входных элементов датасета равным 10 000, потому что наши обзоры имеют размер до 10 000 целых чисел. Входной слой принимает элементы с размером 10 000, а выдает — с размером 50.

Наконец, пусть Keras выведет краткое описание модели, которую мы только что создали.

# Input - Layer
model.add(layers.Dense(50, activation = "relu", input_shape=(10000, )))
# Hidden - Layers
model.add(layers.Dropout(0.3, noise_shape=None, seed=None))
model.add(layers.Dense(50, activation = "relu")
model.add(layers.Dropout(0.2, noise_shape=None, seed=None))
model.add(layers.Dense(50, activation = "relu"))
# Output- Layer
model.add(layers.Dense(1, activation = "sigmoid"))model.summary()
model.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 50)                500050    
_________________________________________________________________
dropout_1 (Dropout)          (None, 50)                0         
_________________________________________________________________
dense_2 (Dense)              (None, 50)                2550      
_________________________________________________________________
dropout_2 (Dropout)          (None, 50)                0         
_________________________________________________________________
dense_3 (Dense)              (None, 50)                2550      
_________________________________________________________________
dense_4 (Dense)              (None, 1)                 51        
=================================================================
Total params: 505,201
Trainable params: 505,201
Non-trainable params: 0
_________________________________________________________________

Теперь нужно скомпилировать нашу модель, то есть, по существу, настроить ее для обучения. Будем использовать оптимизатор «adam». Оптимизатор — это алгоритм, который изменяет веса и смещения во время обучения. В качестве функции потерь используем бинарную кросс-энтропию (так как мы работаем с бинарной классификацией), в качестве метрики оценки — точность.

model.compile(
 optimizer = "adam",
 loss = "binary_crossentropy",
 metrics = ["accuracy"]
)

Теперь можно обучить нашу модель. Мы будем делать это с размером партии 500 и только двумя эпохами, поскольку я выяснил, что модель начинает переобучаться, если тренировать ее дольше. Размер партии определяет количество элементов, которые будут распространяться по сети, а эпоха — это один проход всех элементов датасета. Обычно больший размер партии приводит к более быстрому обучению, но не всегда — к быстрой сходимости. Меньший размер партии обучает медленнее, но может быстрее сходиться. Выбор того или иного варианта определенно зависит от типа решаемой задачи, и лучше попробовать каждый из них. Если вы новичок в этом вопросе, я бы посоветовал вам сначала использовать размер партии 32, что является своего рода стандартом.

results = model.fit(
 train_x, train_y,
 epochs= 2,
 batch_size = 500,
 validation_data = (test_x, test_y)
)

Train on 40000 samples, validate on 10000 samples
Epoch 1/2
40000/40000 [==============================] - 5s 129us/step - loss: 0.4051 - acc: 0.8212 - val_loss: 0.2635 - val_acc: 0.8945
Epoch 2/2
40000/40000 [==============================] - 4s 90us/step - loss: 0.2122 - acc: 0.9190 - val_loss: 0.2598 - val_acc: 0.8950

Проведем оценку работы модели:

print(np.mean(results.history["val_acc"]))
0.894750000536

Отлично! Наша простая модель уже побила рекорд точности в статье 2011 года, упомянутой в начале поста. Смело экспериментируйте с параметрами сети и количеством слоев.

Полный код модели приведен ниже:

import numpy as np
from keras.utils import to_categorical
from keras import models
from keras import layers
from keras.datasets import imdb
(training_data, training_targets), (testing_data, testing_targets) = imdb.load_data(num_words=10000)
data = np.concatenate((training_data, testing_data), axis=0)
targets = np.concatenate((training_targets, testing_targets), axis=0)
def vectorize(sequences, dimension = 10000):
 results = np.zeros((len(sequences), dimension))
 for i, sequence in enumerate(sequences):
  results[i, sequence] = 1
 return results
 
data = vectorize(data)
targets = np.array(targets).astype("float32")
test_x = data[:10000]
test_y = targets[:10000]
train_x = data[10000:]
train_y = targets[10000:]
model = models.Sequential()
# Input - Layer
model.add(layers.Dense(50, activation = "relu", input_shape=(10000, )))
# Hidden - Layers
model.add(layers.Dropout(0.3, noise_shape=None, seed=None))
model.add(layers.Dense(50, activation = "relu"))
model.add(layers.Dropout(0.2, noise_shape=None, seed=None))
model.add(layers.Dense(50, activation = "relu"))
# Output- Layer
model.add(layers.Dense(1, activation = "sigmoid"))
model.summary()
# compiling the model
model.compile(
 optimizer = "adam",
 loss = "binary_crossentropy",
 metrics = ["accuracy"]
)
results = model.fit(
 train_x, train_y,
 epochs= 2,
 batch_size = 500,
 validation_data = (test_x, test_y)
)
print("Test-Accuracy:", np.mean(results.history["val_acc"]))

Итоги

Вы узнали, что такое анализ настроений и почему Keras является одной из наиболее популярных библиотек глубокого обучения.

Мы создали простую нейронную сеть с шестью слоями, которая может вычислять настроение авторов кинорецензий с точностью 89%. Теперь вы можете использовать эту модель для анализа бинарных настроений в других источниках, но для этого вам придется сделать их размер равным 10 000 или изменить параметры входного слоя.

Эту модель (с небольшими изменениями) можно применить и для решения других задач машинного обучения.


Интересные статьи:

Обучение с подкреплением на Python с библиотекой Keras

14 августа 2018
Обучение с подкреплением Python Keras

Обучение с подкреплением на Python с библиотекой Keras

Статья о том, как научить машинку участвовать в гонке, а персонажей — избегать файерболов. При этом агент способен научиться играть в игру в своем собственном «воображении. В статье — пример обучения…

Статья о том, как научить машинку участвовать в гонке, а персонажей — избегать файерболов. При этом агент способен научиться играть в игру в своем собственном «воображении. В статье — пример обучения с подкреплением (reinforcement learning) на Python с библиотекой Keras. Автор статьи — Давид Фостер.

Эта работа стоит внимания по трем причинам:

  1. Она сочетает в себе несколько методов глубокого обучения и обучения с подкреплением для достижения удивительных результатов  — получен первый известный «агент» для популярной виртуальной среды обучения с подкреплением «Автомобильные гонки»;
  2. Она написана в доступном стиле, и является отличным учебным ресурсом для всех, кто интересуется передовым AI;
  3. Вы можете самостоятельно запрограммировать решение!

Другие полезные статьи по теме:

Шаг 1: Постановка задачи

Мы собираемся построить алгоритм обучения с подкреплением (создать «агента»), который бы хорошо справлялся с вождением автомобиля на виртуальном 2D-треке. Эта среда («Автомобильные гонки») доступна через OpenAI Gym.

На каждом временном шаге алгоритм получает наблюдаемые данные трека (64×64-пиксельное цветное изображение автомобиля и ближайшего окружения, «наблюдение»), и ему необходимо вернуть набор предпринятых действий: направление рулевого управления (от -1 до 1), ускорение (от 0 до 1) и торможение (от 0 до 1). Это действие затем передается в среду, которая возвращает следующие данные трека, и цикл повторяется.

Трек разбит на N фрагментов. За посещение каждого из них агент получает 1000/N баллов, каждый потраченный временной промежуток отнимает 0,1 балла. Например, если агент проходит трек целиком за 732 кадра, вознаграждение составляет 1000 — 0,1 * 732 = 926,8 балла.

Python Keras

Выше представлен пример агента, который выбирает действие [0, 1, 0] для первых 200 временных шагов, а затем случайное… не самая лучшая стратегия вождения.

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

Шаг 2: Решение

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

Решение состоит из трех отдельных частей, которые обучаются отдельно:

Вариационный автоэнкодер (VAE)

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

Это именно то, чему обучается VAE —  сжимать входное изображение 64x64x3 (RGB) в 32-мерный скрытый вектор z, удовлетворяющий нормальному распределению.

Такое представление визуального окружения полезно, т.к. гораздо меньше по размеру, и агент может обучаться эффективнее.

Рекуррентная нейронная сеть с сетью смеси распределений на выходе (Recurrent Neural Network with Mixture Density Network output, MDN-RNN)

Reinforcement learning

Если в принятии решений вы обходитесь без компонента MDN-RNN, ваше вождение может выглядеть примерно так. Когда вы едете на машине, каждое последующее наблюдение не является для вас полной неожиданностью. Вы знаете, что если в данный момент окружение предполагает поворот налево на дороге, и вы поворачиваете колеса влево, вы ожидаете, что следующий кадр покажет, что вы все еще на одной линии с дорогой.

Подобное «мышление наперед» суть работы RNN, сети долгой краткосрочной памяти (LSTM) с 256 скрытыми значениями. Вектор скрытых состояний обозначим за h.

Подобно VAE, RNN пытается зафиксировать внутреннее «понимание» текущего состояния автомобиля в своем окружении, но на этот раз с целью предсказать, как будет выглядеть последующий z на основе предыдущего z и совершённого действия.

Выходной слой MDN просто учитывает тот факт, что следующий z может быть фактически выведен из любого из нескольких нормальных распределений.

MDN для генерации почерка
MDN для генерации почерка

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

Аналогично, в статье «Модели мира» следующее наблюдаемое скрытое состояние может быть составлено из любого из пяти гауссовских распределений.

Контроллер

До этого момента мы ничего не говорили о выборе действия. Эта ответственность лежит на Контроллере.

Контроллер — это обычная полносвязная нейронная сеть, где вход представляет собой конкатенацию z (текущее скрытое состояние от VAE, длина 32) и h (скрытое состояние RNN, длина 256). 3 выходных нейрона соответствуют трем действиям, их значения масштабируются для попадания в соответствующие диапазоны.

Диалог

Чтобы понять разные роли трех компонентов и то, как они работают вместе, можно представить себе своеобразный диалог между ними:

Model
Схема архитектуры Моделей мира (источник: https://arxiv.org/pdf/1803.10122.pdf)

VAE: (смотрит последнее наблюдение размера 64 * 64 * 3) “Это выглядит как прямая дорога, с легким левым поворотом, приближающимся к машине, движущейся вдоль дороги”.

RNN: “Из того, что мне описал VAE (вектор z) и того факта, что Контроллер решил ускориться на последнем шаге, я обновлю свое скрытое состояние (h), чтобы предсказание следующего наблюдения все еще была прямая дорога, но с чуть более сильным левым поворотом”.

Контроллер: “На основании описания из VAE (z) и текущего скрытого состояния из RNN (h) моя нейронная сеть выводит следующее действие как [0.34, 0.8, 0]”.

Затем это действие передается в окружение, которая возвращает новое наблюдение, и цикл повторяется снова.

Теперь мы рассмотрим, как настроить среду, которая позволяет вам обучать собственную версию агента для автогонок.

Пора писать код!

Шаг 3. Настройка среды

Если у вас компьютер с высокой производительностью, вы можете запускать решение локально, но я бы рекомендовал использовать Google Cloud Compute для доступа к мощным машинам.

Описанное ниже было проверено на Linux (Ubuntu 16.04); если вы используете Mac или Windows, измените соответствующие команды установки пакетов.

Склонируйте репозиторий

В командной строке, перейдите в папку, в которую вы хотите сохранить репозиторий, и введите следующее:

git clone https://github.com/AppliedDataSciencePartners/WorldModels.git

Репозиторий адаптирован из весьма полезной библиотеки estool, разработанной Дэвидом Ха, первым автором статьи «Модели мира».

Для обучения нейронной сети данная реализация использует Keras над Tensorflow, хотя в оригинальной статье авторы использовали чистый Tensorflow.

Настройте виртуальную среду

Создайте себе виртуальную среду (virtual environment) для Python 3 (я использую virutalenv и virtualenvwrapper):

sudo apt-get install python-pip
sudo pip install virtualenv
sudo pip install virtualenvwrapper
export WORKON_HOME = ~/.virtualenvs
source /usr/local/bin/virtualenvwrapper.sh
mkvirtualenv --python=/usr/bin/python3 worldmodels

Установите пакеты

sudo apt-get install cmake swig python3-dev zlib1g-dev python-opengl mpich xvfb xserver-xephyr vnc4server

Установите requirements.txt

cd WorldModels
pip install -r requirements.txt

Эта команда устанавливает больше, чем нужно для примера с гонками. Зато если вы захотите протестировать другие окружения от Open AI, для которых требуются дополнительные пакеты, у вас будет все необходимое.

Шаг 4: Создание случайных «трасс»

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

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

Чтобы сгенерировать случайные трассы, выполните следующую команду из командной строки:

python 01_generate_data.py car_racing --total_episodes 2000 --start_batch 0 --time_steps 300

или же если запускаете на сервере без дисплея:

xvfb-run -a -s "-screen 0 1400x900x24" python 01_generate_data.py car_racing --total_episodes 2000 --start_batch 0 --time_steps 300

Это приведет к выпуску 2000 новых примеров трасс (сохраняются в десяти пакетах (batch) размера 200), начиная с номера 0. Каждая трасса будет иметь максимум 300 временных шагов.

Два набора файлов сохраняются в ./data, (* — номер батча)

obs_data_*.npy (сохраняет изображения 64 * 64 * 3 в виде массивов numpy)

action_data_*.npy (хранит три измерения действий)

Шаг 5: Обучение VAE

Для обучения VAE требуется только obs_data_*.npy. Убедитесь, что вы выполнили шаг 4, и эти файлы существуют в папке ./data.

В командной строке выполните:

python 02_train_vae.py --start_batch 0 --max_batch 9 --new_model

Эта команда обучит новый VAE на каждом пакете от 0 до 9.

Веса модели будут сохранены в ./vae/weights.h5. Флаг --new_model сообщает скрипту, что модель нужно строить с нуля.

Если в этой папке есть файл weights.h5 уже существует, а флаг --new_model при запуске не указан, скрипт загрузит веса из этого файла и продолжит тренировать существующую модель. Таким образом, можно итеративно обучать VAE партиями, а не за один раз.

Спецификация архитектуры VAE в файле ./vae/arch.py.

Шаг 6: Создание данных RNN

Теперь, когда у нас есть подготовленный VAE, с его помощью можно создать обучающий набор для RNN.

RNN принимает кодированное изображение z из VAE и вектор команд управления a в качестве входных данных, в качестве выхода — вектор z на один временной шаг вперед.

Сгенерировать эти данные можно, выполнив:

python 03_generate_rnn_data.py --start_batch 0 --max_batch 9

Это потребует наличия файлов obs_data_*.npy и action_data_*.npy из батчей от 0 до 9, и сконвертирует их в правильный формат, необходимый для обучения RNN.

Два набора файлов будут записаны в ./data, (* — номер батча):

rnn_input_*.npy (сохраняет сконкатенированные векторы [z a])

rnn_output_*.npy (сохраняет следующий по времени вектор z)

Шаг 7: Обучение рекуррентной нейросети

Для обучения RNN требуется только rnn_input_*.npy и rnn_output_*.npy. Убедитесь, что вы успешно выполнили шаг 6, и файлы находятся в папке ./data.

В командной строке выполните:

python 04_train_rnn.py --start_batch 0 --max_batch 9 --new_model

Это запустит процессы обучения новых RNN для каждого пакета данных от 0 до 9.

Веса модели будут сохранены в ./rnn/weights.h5. Флаг --new_model сообщает скрипту, что модель нужно подготавливать с нуля.

Аналогично VAE, если в этой папке weights.h5 существуют, а флаг --new_model не указан, скрипт загрузит веса из этого файла и продолжит тренировку существующей модели. Аналогично это позволяет итеративно обучать RNN партиями.

Спецификация архитектуры RNN находится в файле ./rnn/arch.py.

Шаг 8: Обучение контроллера

Теперь забавная часть! До сих пор мы просто применяли Deep Learning для создания VAE, который способен «сжимать» изображения большого размера вплоть до низкоразмерного пространства, и обучения RNN, предсказывающего, как со временем будет изменяться скрытый вектор. Это было возможно, потому что мы смогли создать обучающие наборы данных, используя данные случайных карт.

Для обучения контроллера мы будем применять особую форму обучения с подкреплением. В ней используется эволюционный алгоритм, известный под названием CMA-ES (Covariance Matrix Adaptation — Evolution Strategy).

Так как вход представляет собой вектор размерности 288 (= 32 + 256), а выход — вектор размерности 3, то для тренировки мы имеем 288 * 3 + 1 (смещение) = 867 параметров.

Machine learning Python Keras

CMA-ES работает, сначала создавая несколько случайно инициализированных копий 867 параметров («популяцию»). Затем он тестирует каждого члена популяции на трассе и записывает его средний балл. По принципу естественного отбора, наборам весов, которые получают самые высокие баллы, разрешено «воспроизводиться» и порождать следующее поколение.

Чтобы запустить этот процесс на вашем компьютере, выполните следующую команду с соответствующими значениями для аргументов:

python 05_train_controller.py car_racing --num_worker 16 --num_worker_trial 2 --num_episode 4 --max_length 1000 --eval_steps 25

или на сервере без дисплея:

xvfb-run -s "-screen 0 1400x900x24" python 05_train_controller.py car_racing --num_worker 16 --num_worker_trial 2 --num_episode 4 --max_length 1000 --eval_steps 25

--num_worker 16 : установите это значение не большим, чем количество доступных ядер

--num_work_trial 2 : количество представителей популяции, которое будет тестировать каждый поток (num_worker * num_work_trial дает общий размер популяции для каждого поколения)

--num_episode 4 : количество тестовых запусков каждого члена популяции (таким образом, оценка будет средним по баллам за это количество эпизодов)

--max_length 1000 : максимальное количество временных шагов в эпизоде

--eval_steps 25 : количество поколений до выбора наилучшего набора весов, через 100 эпизодов

--init_opt ./controller/car_racing.cma.4.32.es.pk По умолчанию контроллер запускается с нуля каждый раз при его запуске и сохраняет текущее состояние процесса в файле pickle в каталоге controller. Этот аргумент позволяет продолжить обучение с последней точки сохранения, указав ее в соответствующем файле.

После каждого поколения текущее состояние алгоритма и лучший набор весов будут выводиться в папку ./controller.

Шаг 9: Визуализация работы агента

На момент написания статьи мне удалось подготовить агента для достижения среднего балла ~833,13 после 200 поколений обучения. Запуски проводились в Google Cloud под Ubuntu 16.04, 18 vCPU, 67,5 ГБ оперативной памяти с шагами и параметрами, приведенными в этом уроке.

Авторам статьи удалось достичь среднего балла ~906, после 2000 поколений обучения, который считается самым высоким показателем в этой виртуальной среде на сегодняшний день. Были использованы несколько более высокие настройки (например, 10 000 эпизодов учебных данных, 64 размер популяции, 64-ядерная машина, 16 эпизодов за испытание и т. д.).

Чтобы визуализировать текущее состояние вашего контроллера, запустите:

python model.py car_racing --filename ./controller/car_racing.cma.4.32.best.json --render_mode --record_video

--filename : путь к json-файлу весов, который вы хотите подключить к контроллеру

--render_mode : отображение среды на экране

--record_video : выводит файлы mp4 в папку ./video, показывая каждый эпизод

--final_mode : выполняет 100 эпизодов в тестовом режиме контроллера и выводит средний балл.

Пример работы

Reinforcement learning result

Шаг 10: Обучение «в воображении»

Уже увиденнные нами вещи довольно круты, но следующая часть статьи просто потрясает мозг, и, полагаю, может серьезно повлиять на развитие ИИ.

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

Агент действительно способен научиться играть в игру в своем собственном «воображении», построенном VAE/RNN, а не внутри самой окружающей среды.

Единственное обязательное дополнение состоит в том, что RNN обучается также прогнозировать вероятность быть убитым на следующем шаге. Таким образом, комбинация VAE/RNN может быть обернута как самостоятельная среда и использоваться для обучения Контроллера. Это и есть  концепция «Моделей мира».

Мы могли бы описать обучение с воображением следующим образом:

  1. Первоначальные данные обучения агента представляют собой не что иное, как случайное взаимодействие с реальной средой. Благодаря этому он создает скрытое понимание того, как мир «работает» — его естественные признаки, физика и то, как собственные действия агента влияют на состояние мира.
  2. Затем он может использовать это понимание, чтобы установить оптимальную стратегию для поставленной задачи, не проверяя при этом ее в реальном мире. Эта проверка не требуется потому, что агент может использовать свою собственную внутреннюю, скрытую модель окружающей среды как «игровую площадку» для того, чтобы попытаться разобраться в том, что происходит.

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

Сравнение GPU для машинного обучения: Amazon, Google, IBM

25 июня 2018
GPU для машинного обучения

Сравнение GPU для машинного обучения: Amazon, Google, IBM

Результаты тестов популярных GPU для машинного обучения: Amazon AWS, Google Cloud Engine, Hetzner, Leader GPU, IBM, Paperspace. Тестируемые GPU платформы  В этот тест включены: Amazon Web Services AWS EC2, Google Cloud Engine…

Результаты тестов популярных GPU для машинного обучения: Amazon AWS, Google Cloud Engine, Hetzner, Leader GPU, IBM, Paperspace.

Тестируемые GPU платформы 

В этот тест включены: Amazon Web Services AWS EC2, Google Cloud Engine GCE, IBM Softlayer, Hetzner, Paperspace and LeaderGPU.

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

Я хотел бы поблагодарить провайдеров GPU для машинного обучения за любезное предоставление нам тестовых кредитов и отличную поддержку в течение всего моего тестирования. Каждая платформа имеет свои собственные плюсы и минусы, а рынок GPUaaS — очень интересное и оживленное пространство.

Отмечу что, единственный крупный провайдер, который не отвечал, на самом деле у нас не было ответа даже по официальным каналам поддержки, был Microsoft Azure. Сделайте свои собственные выводы.

Мы рассмотрим два типа графических процессоров на основе цен инстансов на каждой платформе — «low-end» и «high-end» (см. Таблицу 1). Цель состоит в том, чтобы показать, стоят ли дорогие инстансы своих денег.

Настройка Benchmark для машинного обучения

Постановка задачи

В RARE Technologies, мы часто занимаемся проблемами обработки естественного языка (NLP), поэтому я остановился на задаче классификации настроений для бенчмарка. Двунаправленная сеть долгой краткосрочной памяти (LSTM) обучается выполнять двоичную категоризацию твитов. Выбор алгоритма не очень важен; моим единственным истинным требованием для этого бенчмарка является то, что он должен загружать GPU. Чтобы обеспечить максимальное использование графического процессора, я воспользовался быстрой реализацией LSTM Keras (v2.1.3), поддерживаемой CuDNN — слоем CuDNNLSM.

Набор данных

В качестве набора данных мы взяли Twitter Sentiment Analysis Dataset, содержащий 1 578 627 классифицированных твитов, каждая строка помечена 1 для положительной тональности и 0 для отрицательной тональности. Модель обучается в течение 4 эпох на 90% перемешанных данных, а оставшиеся удерживаемые 10% используются для оценки модели.

Docker

В целях воспроизводимости я создал Nvidia Docker image, который содержит все зависимости и данные, необходимые для повторного запуска этого бенчмарка . Dockerfile и весь необходимый код можно найти в этом архиве Github.

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

Результаты

GPU для машинного обучения
Таблица 1: сводка результатов тестов GPU для машинного обучения

* Это multiple GPU инстансы, в которых модели прошли обучение на всех графических процессорах с использованием функции multi_gpu_model, которая позже была признана не оптимальной при использовании нескольких графических процессоров.

** Это multiple GPU инстансы, в которых модели прошли обучение с использованием только одного из своих графических процессоров из-за вышеуказанных причин.

+ Hetzner предоставляет выделенные серверы ежемесячно. Цифры здесь отражают почасовые пропорциональные затраты.

Простота заказа, настройки и удобство пользования

Я прокомментировал опыт использования AWS, Softlayer и GCE в моем предыдущем сообщении. Заказать инстанс на LeaderGPU и Paperspace было проще простого без каких-либо сложных настроек. Время предоставления ресурсов для Paperspace и LeaderGPU было порядка пары минут, по сравнению с AWS или GCE, которые предоставили в течение нескольких секунд.

LeaderGPU, Amazon и Paperspace предлагают в свободном доступе Deep Learning Machine Images, которые идут в комплекте с предустановленными драйверами Nvidia вместе со средой разработки Python, и Nvidia-Docker необходим полностью для немедленного начала экспериментов. Для облегчения жизни, особенно для начинающих пользователей, которые просто хотят экспериментировать с моделями машинного обучения, я настроил все с нуля (за исключением LeaderGPU) по старым правилам, чтобы оценить легкость настройки экземпляра по индивидуальным потребностям. В этом процессе я столкнулся с несколькими проблемами, присущими всем платформам, такими как несовместимость драйвера NVIDIA с установленной версией gcc или использование GPU, достигающее 100% после установки драйвера без каких-либо доказательств текущего процесса. Неожиданно, запуск моего Docker на low-end инстансе Paperspace (P6000) привел к ошибке. Эта проблема была вызвана тем, что Tensorflow on Docker строился из источника с оптимизацией ЦП (MSSE, MAVX, MFMA), который Paperspace инстанс не поддерживал. Запуск Docker без этих оптимизаций исправил ошибку.

Что касается стабильности, я не сталкивался с какой-либо проблемой с любой из платформ.

Стоимость

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

Рисунок 1: Стоимость обучения двунаправленной LSTM по задаче классификации настроений в twitter (~ 1,5 миллиона твитов, 4 эпохи) на разных аппаратных платформах GPU
Рисунок 1: Стоимость обучения двунаправленной LSTM по задаче классификации настроений в twitter (~ 1,5 миллиона твитов, 4 эпохи) на разных аппаратных платформах GPU

Между AWS и GCE, похоже, происходит изменение тенденции при переходе с графических процессоров с низким уровнем производительности к высокому уровню. GCE значительно дешевле, чем AWS в классе графических процессоров с низким уровнем, и он немного дороже, чем AWS в классе графических процессоров с высокой производительностью. Это говорит о том, что дорогостоящие графические процессоры AWS могут стоить дополнительных затрат.

IBM Softlayer и LeaderGPU кажутся дорогими, в основном из-за недостаточного использования инстансов с несколькими GPU. Benchmark был выполнен с использованием фреймворка Keras, реализация которого на нескольких GPU была неожиданно неэффективной, иногда хуже, чем работа одного графического процессора на том же компьютере. Но ни одна из этих платформ не предлагает single GPU инстанс. Бенчмарк проводимый на Softlayer использовал все доступные графические процессоры, использующие multi_gpu_model, тогда как на LeaderGPU использовался только один из доступных графических процессоров. Это привело к значительным дополнительным расходам для недостаточно используемых ресурсов. Кроме того, LeaderGPU предоставляет более мощные графические процессоры, GTX 1080 Ti & Tesla V100, по тем же ценам за минуту, что и GTX 1080 и Tesla P100 соответственно. Запуск на этих серверах определенно снизил бы общие затраты. Принимая во внимание все это, стоимость low-end LeaderGPU вполне разумна. Имейте это в виду, особенно если вы планируете использовать не Keras фреймворк, который лучше использует несколько графических процессоров.

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

Замечание по подготовке обучающих мульти-графических моделей с использованием Keras

Огромному количеству людей в академических кругах и промышленности очень удобно использовать высокоуровневые API, такие как Keras для моделей глубокого обучения. Благодаря одной из наиболее приемлемых и активно разработанных систем глубокого обучения пользователи ожидают ускорения при переключении на многопроцессорную модель без какой-либо дополнительной обработки. Но это, конечно, не так, как видно из графика ниже. Ускорение довольно непредсказуемо. На графике видно, что на сервере «dual GTX 1080» скорость обучения выше, в то время как обучение с multi-GPU заняло больше времени, по сравнению с обучением на single-GPU на сервере «Dual P100». Такое же мнение отражено в других статьях и вопросах на Gidhub , с которыми я столкнулся, исследуя стоимостью.

Рисунок 2: Время обучения, проведенное с помощью multi-GPU и обучения с single-GPU на идентичных машинах с использованием Keras
Рисунок 2: Время обучения, проведенное с помощью multi-GPU и обучения с single-GPU на идентичных машинах с использованием Keras

Точность модели

Для проверки работоспособности мы проверили окончательную точность модели в конце обучения. Как видно из таблицы 1, существенных различий не было, что подтверждает, что базовое оборудование / платформа не влияет на качество обучения и что бенчмарк был правильно настроен.

Стоимость

Цены на графические процессоры часто меняются, но на данный момент AWS предоставляет графические процессоры K80, начиная с $0,9 в час, которые выставляются с шагом в одну секунду, тогда как более мощные и эффективные графические процессоры Tesla V100 стоят от $3,06 в час. Дополнительные услуги, такие как передача данных, Elastic IP адреса и оптимизированные инстансы EBS, предоставляются за дополнительную плату. GCE — экономичная альтернатива, которая предоставляет Tesla K80 и P100 по запросу, начиная с $0,45 в час и $1,46 в час. Они тарифицируются с шагом в одну секунду и предлагают значительные льготы через скидки на их использование.

Paperspace конкурирует с GCE в низкой ценовой категории со ставками для выделенных графических процессоров, начиная с Quadro M4000 по цене $0,4 в час до Tesla V100 по цене $2,3 в час. Помимо обычных почасовых сборов, они также взимают ежемесячную абонентскую плату в размере $5, включающая в себя хранение и обслуживание. Paperspace предоставляет дополнительные услуги за дополнительную плату. Hetzner предлагает только один выделенный сервер с GTX 1080 ежемесячно с дополнительной одноразовой настройкой.

IBM Softlayer — одна из немногих платформ на рынке, которая предоставляет bare metal GPU сервера на ежемесячной и ежечасной основе. IBM Softlayer предлагает 3 GPU сервера с Tesla M60s & K80s, начиная с $2,8 в час. Эти серверы имеют статическую конфигурацию, что означает, что их возможности настройки ограничены по сравнению с другими облачными провайдерами. Стоимость Softlayer с почасовыми надбавками будет финансово невыгодно и может оказаться более дорогостоящим для краткосрочных задач.

LeaderGPU, относительно новый участник на рынке, предоставляет выделенные серверы с широким спектром графических процессоров (P100, V100, GTX 1080, GTX 1080Ti). Пользователи могут воспользоваться ежемесячной, ежечасной или ежеминутной оплатой, которая рассчитывается по секундам. Серверы имеют от 2 до 8 графических процессоров, со стоимостью от 0,02 € до 0,08 € в минуту.

Спотовые/вытесняемые инстансы

Некоторые из платформ предоставляют значительные скидки (50% -90%) на их запасную вычислительную мощность (AWS spot instances and GCE’s preemptive instances), хотя скидки могут неожиданно закончиться или вновь появиться. Это приводит к крайне непредсказуемому времени обучения, так как нет никакой гарантии, когда инстанс снова появится. Это нормально для приложений, которые могут обрабатывать такие завершения, но многие задачи, например, time-bound projects будут плохо выполняться в таком случае, особенно если вы считаете потраченное рабочее время. Выполнение задач на Spot/Preemptive Instances требует дополнительного кода для корректного завершения и повторного запуска инстансов. (проверка / сохранение данных на постоянный диск и т.д.).

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

Поэтому, вы можете сэкономить деньги с помощью spot/preemptive инстансов, если вы будете осторожны. Что касается меня, то я не стал включать их в этот бенчмарк из-за этих осложнений.

Результаты тестов

  • Paperspace на один шаг вперед в отношении производительности и стоимости. Это особенно верно для разовых или нечастых пользователей, которые просто хотят экспериментировать с методами глубокого обучения (аналогичный вывод в другом бенчмарке).
  • Выделенные серверы (например, предоставляемые LeaderGPU) и bare metal servers, например, Hetzner подходят для пользователей, которые рассматривают долговременную работу этих ресурсов. Обратите внимание, что ваша задача прилично загружает CPU / GPU, чтобы действительно выиграть в цен
  • Новые игроки, такие как Paperspace и LeaderGPU, не должны быть списаны со счетов, поскольку они могут помочь сократить основную часть затрат. Предприятия могут быть против смены провайдеров из-за связанных инерционных и коммутационных расходов, но эти небольшие платформы, безусловно, стоит рассмотреть.
  • AWS и GCE могут быть потрясающими вариантами для тех, кто ищет объединение со своими другими сервисами (Amazon Rekognition, Google Cloud AI).
  • Если Вы не планируете выполнять задачу, выполнение которой займет несколько дней, лучше всего выбрать lower-end single-GPU инстанс с одним графическим процессором (см. также здесь).
  • Higher-End GPUs значительно быстрее, но на самом деле имеют плохую окупаемость. Вы должны выбрать их только тогда, когда короткое время обучения является приоритетней, чем затраты на оборудование.

Перевод статьи Шива Манне Machine learning mega-benchmark: GPU providers.

Как создать собственную нейронную сеть с нуля на языке Python

25 июня 2018
нейронная сеть на python

Как создать собственную нейронную сеть с нуля на языке Python

Джеймс Лой, Технологический университет штата Джорджия. Руководство для новичков, после которого вы сможете создать собственную нейронную сеть на Python. Мотивация: ориентируясь на личный опыт в изучении глубокого обучения, я решил создать…

Джеймс Лой, Технологический университет штата Джорджия. Руководство для новичков, после которого вы сможете создать собственную нейронную сеть на Python.

Мотивация: ориентируясь на личный опыт в изучении глубокого обучения, я решил создать нейронную сеть с нуля без сложной учебной библиотеки, такой как, например, TensorFlow. Я считаю, что для начинающего Data Scientist-а важно понимание внутренней структуры нейронной сети.

Эта статья содержит то, что я усвоил, и, надеюсь, она будет полезна и для вас! Другие полезные статьи по теме:

Что такое нейронная сеть?

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

Нейронные сети состоят из следующих компонентов:

  • входной слой, x
  • произвольное количество скрытых слоев
  • выходной слой, ŷ
  • набор весов и смещений между каждым слоем и b
  • выбор функции активации для каждого скрытого слоя σ; в этой работе мы будем использовать функцию активации Sigmoid

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

   нейронная сеть на python

Создание класса Neural Network на Python выглядит просто:

Обучение нейронной сети

Выход ŷ простой двухслойной нейронной сети:

обучение нейронной сети на питон

В приведенном выше уравнении, веса W и смещения b являются единственными переменными, которые влияют на выход ŷ.

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

Каждая итерация обучающего процесса состоит из следующих шагов

  • вычисление прогнозируемого выхода ŷ, называемого прямым распространением
  • обновление весов и смещений, называемых обратным распространением

Последовательный график ниже иллюстрирует процесс:

backpropagation

Прямое распространение

Как мы видели на графике выше, прямое распространение — это просто несложное вычисление, а для базовой 2-слойной нейронной сети вывод нейронной сети дается формулой:

обучение нейронной сети на питон

Давайте добавим функцию прямого распространения в наш код на Python-е, чтобы сделать это. Заметим, что для простоты, мы предположили, что смещения равны 0.

Однако нужен способ оценить «добротность» наших прогнозов, то есть насколько далеки наши прогнозы). Функция потери как раз позволяет нам сделать это.

Функция потери

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

функция потери

Сумма квадратов ошибок — это среднее значение разницы между каждым прогнозируемым и фактическим значением.

Цель обучения — найти набор весов и смещений, который минимизирует функцию потери.

Обратное распространение

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

Чтобы узнать подходящую сумму для корректировки весов и смещений, нам нужно знать производную функции потери по отношению к весам и смещениям.

Напомним из анализа, что производная функции — это тангенс угла наклона функции.

градиентный спуск

Если у нас есть производная, то мы можем просто обновить веса и смещения, увеличив/уменьшив их (см. диаграмму выше). Это называется градиентным спуском.

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

chain rule python neural network

Фух! Это было громоздко, но позволило получить то, что нам нужно — производную (наклон) функции потерь по отношению к весам. Теперь мы можем соответствующим образом регулировать веса.

Добавим функцию backpropagation (обратного распространения) в наш код на Python-е:

Проверка работы нейросети

Теперь, когда у нас есть наш полный код на Python-е для выполнения прямого и обратного распространения, давайте рассмотрим нашу нейронную сеть на примере и посмотрим, как это работает.

Идеальный набор весов нейросети
Идеальный набор весов

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

Давайте тренируем нейронную сеть на 1500 итераций и посмотрим, что произойдет. Рассматривая график потерь на итерации ниже, мы можем ясно видеть, что потеря монотонно уменьшается до минимума. Это согласуется с алгоритмом спуска градиента, о котором мы говорили ранее.

ошибка нейронной сети

Посмотрим на окончательное предсказание (вывод) из нейронной сети после 1500 итераций.

предсказание

Мы сделали это! Наш алгоритм прямого и обратного распространения показал успешную работу нейронной сети, а предсказания сходятся на истинных значениях.

Заметим, что есть небольшая разница между предсказаниями и фактическими значениями. Это желательно, поскольку предотвращает переобучение и позволяет нейронной сети лучше обобщать невидимые данные.

Финальные размышления

Я многому научился в процессе написания с нуля своей собственной нейронной сети. Хотя библиотеки глубинного обучения, такие как TensorFlow и Keras, допускают создание глубоких сетей без полного понимания внутренней работы нейронной сети, я нахожу, что начинающим Data Scientist-ам полезно получить более глубокое их понимание.

Я инвестировал много своего личного времени в данную работу, и я надеюсь, что она будет полезной для вас!

Обзор Tensorflow.JS: машинное обучение на JavaScript

25 июня 2018
Tensorflow Javascript

Обзор Tensorflow.JS: машинное обучение на JavaScript

Разработчики Google представили TensorFlow.JS — библиотеку с открытым исходным кодом, которую можно использовать для определения, обучения и запуска моделей машинного обучения полностью в браузере, используя Javascript и высокоуровневое API. Если вы Javascript-разработчик, который…

Разработчики Google представили TensorFlow.JS — библиотеку с открытым исходным кодом, которую можно использовать для определения, обучения и запуска моделей машинного обучения полностью в браузере, используя Javascript и высокоуровневое API.

Если вы Javascript-разработчик, который новичок в машинном обучении, TensorFlow.js — отличный способ начать обучение.

Если вы ML-инженер и новичок в Javascript, то читайте дальше, чтобы узнать больше о новых возможностях in-browser ML.

Представляем краткий обзор TensorFlow.js, и ресурсов, которые можно использовать, чтобы его опробовать.

In-Browser ML

Запуск программ машинного обучения полностью на стороне клиента в браузере открывает новые возможности, такие как интерактивное ML! Если вы посмотрите трансляцию c TensorFlow Developer Summit, то в течение выступления о TensorFlow.js вы найдете демо-версию, где @dsmilkov и @nsthorat обучают модель управления игрой PAC-MAN с помощью компьютерного зрения и веб-камеры прямо в браузере. Вы также можете попробовать сделать это самостоятельно, перейдя по ссылке ниже — и найти нужное в папке examples.

Превратите свою веб-камеру в пульт управления для PAC-MAN с помощью нейронной сети
Превратите свою веб-камеру в пульт управления для PAC-MAN с помощью нейронной сети

Если вы хотите попробовать другую игру, то оцените Emoji Scavenger Hunt— на этот раз из браузера на вашем мобильном телефоне.

Emoji Scavenger Hunt — интересный пример приложения, построенного с использованием TensorFlow.js. Попробуйте его с телефона
Emoji Scavenger Hunt — интересный пример приложения, построенного с использованием TensorFlow.js. Попробуйте его с телефона

ML работа в браузере означает, что с точки зрения пользователя, нет необходимости устанавливать какие-либо библиотеки или драйвера. Просто откройте веб-страницу, и ваша программа готова к запуску. Кроме того, всё готово к работе с ускорением на GPU. TensorFlow.js автоматически поддерживает WebGL и незаметно ускоряет ваш код, когда GPU доступен. Пользователи также могут открыть веб-страницу с мобильного устройства, и в этом случае ваша модель может воспользоваться данными с датчиков, например, от гироскопа или акселерометра. Наконец, все данные остаются на стороне клиенте, делая TensorFlow.js пригодным для вывода с низкой задержкой, а также для приложений, сохраняющих конфиденциальность.

Что можно делать с TensorFlow.js?

Если вы разрабатываете, используя TensorFlow.js, вот три рабочих процесса, которые вы можете рассматривать.

  1. Можно импортировать существующую предварительно подготовленную модель. Если у вас есть существующая модель на TensorFlow или Keras, которую вы ранее обучали в оффлайн режиме, то вы можете преобразовать её в TensorFlow.js формат, и загрузить в браузер.
  2. Можно повторно обучить импортированную модель. Как и в приведенной выше demo Pac-Man, вы можете использовать transfer learning для дополнения существующей модели, обученной в offline режиме, используя небольшое количество данных, собранных в браузере, используя метод, называемый Image Retraining. Это один из способов быстрой подготовки точной модели с использованием лишь небольшого количества данных.
  3. Создать модель прямо в браузере. Вы можете использовать TensorFlow.js для создания, обучения и запуска моделей полностью в браузере с использованием Javascript и высокоуровневого API. Если вы знакомы с Keras, то это API должно показаться знакомым.

Давайте посмотрим код

Если хотите сразу начать работу, можно отправиться к примерам или обучалкам. Они показывают, как экспортировать модель на Python для вывода в браузере, а также как определять и обучать модели полностью на Javascript. В качестве быстрого предварительного просмотра, ниже приведён фрагмент кода, который определяет нейронную сеть для классификации цветов, так же, как в руководстве по началу работы на TensorFlow.org. Здесь мы определим модель, используя стек слоев.

API, которое мы используем здесь, поддерживает все слои Keras, находящиеся в каталоге примеров (включая Dense, CNN, LSTM и так далее). Затем мы можем обучить нашу модель, используя тот же API, совместимое с Keras, при помощи вызова метода:

Теперь модель готова к использованию:

TensorFlow.js также включает в себя низкоуровневый API (ранее deeplearn.js) и поддержку Eager execution. Вы можете узнать об этом больше, посмотрев выступление на TensorFlow Developer Summit.

Обзор API TensorFlow.js. TensorFlow.js работает на WebGL и предоставляет высокоуровневый API для создания моделей и низкоуровневый API для работы с линейной алгебры и алгеброическим дифференциированием (automatic differentation). TensorFlow.js поддерживает импорт моделей Tensorflow SavedModels и Keras
Обзор API TensorFlow.js. TensorFlow.js работает на WebGL и предоставляет высокоуровневый API для создания моделей и низкоуровневый API для работы с линейной алгебры и алгеброическим дифференциированием (automatic differentation). TensorFlow.js поддерживает импорт моделей Tensorflow SavedModels и Keras

Как TensorFlow.js относятся к deeplearn.js?

Хороший вопрос! TensorFlow.JS, экосистема инструментов JavaScript для машинного обучения, является преемником deeplearn.js, который теперь называется TensorFlow.js Core. TensorFlow.js также включает в себя API, который является библиотекой более высокого уровня для построения моделей машинного обучения, которая использует ядро (core), а также инструменты для автоматического переноса моделей TensorFlow SavedModels и Keras hdf5. Для получения ответов на похожие вопросы, ознакомьтесь с FAQ.

Пример задачи взлома капчи за 15 минут с помощью машинного обучения

24 мая 2018
really simple captcha

Пример задачи взлома капчи за 15 минут с помощью машинного обучения

А именно самого используемого в мире плагина для WordPress Really Simple Captcha. Капча (CAPTCHA) — надоедливая картинка с текстом, который надо ввести, чтобы попасть на сайт. Капчу придумали чтобы роботы не могли автоматически…

А именно самого используемого в мире плагина для WordPress Really Simple Captcha.

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

Я прочел отличную книгу: Deep Learning for Computer Vision with Python, которую написал Adrian Rosebrock. В этой книге Адриан описывает способ, которым он взломал капчу на сайте E-ZPass New York используя машинное обучение:

account login form

У Адриана не было доступа к исходному коду, генерирующему капчу. Чтобы обучить модель, ему пришлось скачать тысячи картинок и вручную разметить все надписи.

Но предположим, что мы хотим взламывать капчу, к исходному коду которой у нас есть доступ.

Я зашел на WordPress.org Plugin Registry и ввел в поиске “captcha”. Первый результат назывался “Really Simple CAPTCHA” и установлен более миллиона раз.

really simple captcha

И самое крутое — он с открытыми исходниками! Раз у нас есть алгоритм, генерирующий картинку, его, должно быть, не сложно взломать. Чтобы было сложнее, ограничим себе время. Можно ли уложиться в 15 минут? Давайте попробуем!

Важное замечание: Это ни в коем случае не критика плагина “Really Simple CAPTCHA” или его автора. Сам автор указал, что плагин более не является надежным и рекомендует использовать что-нибудь другое. Это просто небольшой интересный челлендж. Если вы один из того миллиона пользователей, установивших его, то возможно вам стоит сменить данный плагин на что-нибудь другое 🙂

Челлендж

Для начала посмотрим на изображения, создаваемые Really Simple CAPTCHA. На демке видим это:

demo

Итак, капча состоит из четырех букв. Убедимся в этом, посмотрев исходники:

	public function __construct() {
		/* Characters available in images */
		$this->chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';

		/* Length of a word in an image */
		$this->char_length = 4;

		/* Array of fonts. Randomly picked up per character */
		$this->fonts = array(
			dirname( __FILE__ ) . '/gentium/GenBkBasR.ttf',
			dirname( __FILE__ ) . '/gentium/GenBkBasI.ttf',
			dirname( __FILE__ ) . '/gentium/GenBkBasBI.ttf',
			dirname( __FILE__ ) . '/gentium/GenBkBasB.ttf',
		);

Да, действительно капча создается случайным образом из четырех букв или цифр с разными шрифтами. Символы “O”, “0”, “I”, “1” не используются, чтобы пользователь не путался. Остается 32 символа, которые нужно распознать. Не проблема!

Прошло: 2 минуты

Наш набор инструментов

Перед тем, как решать задачу, перечислим инструменты, которыми мы будем пользоваться:

Python 3

Python — простой и мощный язык программирования с отличными библиотеками для машинного обучения и машинного зрения.

OpenCV

Популярная библиотека для обработки изображений с поддержкой алгоритмов машинного зрения. Мы будем использовать ее для предварительной обработки капчи. OpenCV написана на C++, но все ее функции вызываются из питона, чем мы и будем пользоваться.

Keras

Фреймворк для машинного обучения, написанный на питоне. С его помощью легко строить, обучать и использовать нейронные сети. Требует минимального количества кода.

TensorFlow

Гугловская библиотека для машинного обучения. Мы будем пользоваться только Keras, но сам Keras в качестве бэкенда использует TensorFlow, поэтому его тоже придется установить.

Итак, обратно к задаче!

Создаем датасет

Чтобы собрать любую модель машинного обучения, требуются обучающие данные. Нам понадобятся данные, выглядящие следующим образом:

input-output

Так как у нас есть исходный код плагина, создающего капчу, мы можем его использовать, чтобы нагенерировать 10,000 изображений, и для каждого будет известна расшифровка.

Пару минут повозившись с кодом и добавив в него простой цикл ‘for’, я получил папку с обучающими данными — 10,000 PNG файлов, в названии которых указан правильный ответ:

CAPTCHA

В этом и только в этом месте я не дам вам рабочий пример кода. Мы делаем это в образовательных целях, и мне не хочется, чтобы вы заспамили реальные сайты, работающие на WordPress. Вместо этого, я дам ссылку на 10,000 изображений, сделанных мной, чтобы вы могли повторить мой результат.

Прошло: 5 минут

Упрощаем задачу

Теперь, когда есть обучающие данные, мы могли бы их использовать напрямую, обучив по ним нейросеть:

Deep CNN

С достаточным количеством данных, этот подход мог бы даже сработать. Но можно сделать задачу гораздо проще. Чем проще задача, тем меньше нам понадобится обучающих данных и вычислительных ресурсов, чтобы ее решить. У нас ведь всего лишь 15 минут!

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

Training CNN

У меня нет времени разрезать каждую из 10,000 картинок в фотошопе. Это бы заняло несколько дней, а у меня осталось всего 10 минут. И нельзя просто автоматически разделить все картинки на 4 одинаковых куска. Потому что алгоритм задает символам случайное горизонтальное положение:

random captcha

Символы сдвинуты случайным образом, чтобы изображение было сложнее разделить.

К счастью, это всё же можно автоматизировать. При обработке изображений часто приходится находить связные области из пикселей одного цвета. Границы таких областей называют контурами. В OpenCV есть встроенная функция findContours(), которую мы используем, чтобы найти связные области.

Итак, начнем с изображения капчи:

captcha image

Преобразуем изображение в бинарное (это называется thresholding), чтобы было легче найти связные области:

thresholding

Далее, используем функцию findContours(), чтобы выделить связные группы пикселей, состоящие из одного цвета:

findContours

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

Погодите-ка! Тут есть проблемка! Буквы в капче иногда накладываются друг на друга:

problem
И наш алгоритм отмечает их как одну:
problem 2

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

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

problem solving

Мы разделим пополам все прямоугольники, ширина которых сильно превышает высоту, и будем считать их за две буквы. Способ слегка “химический”, но с этими капчами работает.

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

Вот так выглядит моя папка с буквой “W” после того, как я запустил свой алгоритм:

captcha W

Некоторые буквы “W”, вытащенные из наших 10,000 изображений. У меня всего получилось 1,147 разных “W”.

Прошло: 10 минут…

Создаем и обучаем нейросеть

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

Будем использовать простую сверточную нейросеть с двумя сверточными (convolutional) слоями и двумя полносвязными (dense):

CNN Layers
Задать архитектуру нейросети используя Keras можно всего в несколько строк:
# Build the neural network!
model = Sequential()

# First convolutional layer with max pooling
model.add(Conv2D(20, (5, 5), padding="same", input_shape=(20, 20, 1), activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Second convolutional layer with max pooling
model.add(Conv2D(50, (5, 5), padding="same", activation="relu"))
model.add(MaxPooling2D(pool_size=(2, 2), strides=(2, 2)))

# Hidden layer with 500 nodes
model.add(Flatten())
model.add(Dense(500, activation="relu"))

# Output layer with 32 nodes (one for each possible letter/number we predict)
model.add(Dense(32, activation="softmax"))

# Ask Keras to build the TensorFlow model behind the scenes
model.compile(loss="categorical_crossentropy", optimizer="adam", metrics=["accuracy"])

Теперь можно обучать нейросеть!

# Train the neural network
model.fit(X_train, Y_train, validation_data=(X_test, Y_test), batch_size=32, epochs=10, verbose=1)

После 10 прогонов по всему обучающему набору, мы достигаем точности почти в 100%. В начале мы ставили задачу автоматически распознавать любую капчу. И мы это сделали!

Прошло: 15 минут (фух!)

Используем обученную модель для расшифровки капчи

Теперь, когда нейросеть обучена, ее можно использовать для взлома капчи:

  1. Взять изображение капчи с сайта, который использует этот плагин.
  2. Разбить картинку на четыре части, на каждой из которых по одному символу.
  3. Прогнать каждую часть через нейросеть.
  4. Использовать выданные нейросетью буквы, чтобы решить капчу.
  5. PROFIT!

Вот так выглядит расшифровка реальной капчи:

real captcha

А в командной строке вот так:

command

Попробовать самому!

Если хотите попробовать сами, то возьмите код здесь. Он включает 10,000 картинок и код для каждого шага в этой статье. Инструкция к запуску в файле README.md.

Но если хочется вникнуть и понять, что делает каждая строчка кода, советую купить книгу Deep Learning for Computer Vision with Python. Она содержит более детальное объяснение и кучу разобранных примеров. Это единственная книга из тех что я видел, в которой объясняется и как это работает, и как это использовать, чтобы решать реальные и сложные задачи. Рекомендую!

Перевел Руслан Байназаров, оригинал — Adam Geitgey