Fast.ai-Tutorial о том, как приготовить традиционную еду

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

Однако, поскольку методы глубокого обучения очень эффективны и существует множество возможных вариантов использования, я попытался включить некоторые моменты, которые я узнал из курса fast.ai Джереми Ховарда и Рэйчел Томас. Я спросил себя: как машинное обучение может помочь мне лучше понимать повседневные вещи вокруг меня? Могу ли я раскрыть традиции, сделав их видимыми - по крайней мере, для меня? На мой взгляд, ключ к традициям лежит во многих вещах, которые нас окружают каждый день. В этом примере я хотел использовать алгоритмы классификации изображений, чтобы поделиться знаниями о прошлых временах.

Я переехал во Франкфурт почти десять лет назад. Сначала я был очень не знаком с едой и напитками, предлагаемыми во Франкфурте, Hessestub. В этих старинных ресторанах много яблочного вина в оригинальных гессенских кувшинах, так называемых «бембель». Люди часто сидят вместе за большими столами на деревянных скамейках, в ресторанах многолюдно, обычно шумно и шумно. Итак, вы придерживаетесь яблочного вина и заказываете очень оригинальные и тяжелые блюда, которые, вероятно, подает очень быстрый, но не очень приятный хозяин (иногда я думаю, что они ненавидят быть милыми - это делает все это еще более интересным для посетителей) . Если вы просите «оригинальное региональное блюдо Гессен», хозяин просто качает головой, потому что все, что они подают, является региональным, и он или она понятия не имеют, что вы имеете в виду, говоря о своем запросе.

Если вам посчастливилось посетить Франкфурт или Гессен в целом, я хотел бы дать вам несколько советов: попробуйте зеленый соус («grüne Soße»). Гессенцы иногда подают его с мясом (например, шницелем), но часто вместе с ним подают только картофель. Всем это нравится. Вот так выглядит зеленый соус, если вы берете его с собой на пикник:

Зеленый соус Франкфуртер состоит из семи трав: петрушки, чеснока, кервеля, огуречника, щавеля, кресс-салата и салата.

Если только вы не обладаете сверхспособностями и не можете убедить поваров (и немецких бабушек) изменить традиционные рецепты: забудьте добавить или изменить одну из этих трав. Это традиция. Травы - это суть дела: поэтому, чтобы приготовить зеленый соус, мы должны уметь идентифицировать и собирать эти семь трав! Все травы, необходимые для нашего зеленого соуса, можно найти недалеко от Франкфурта, они растут на полях и в лесах недалеко от города. Я уже рассказывал вам о немецких бабушках и дедушках: по сей день некоторые пожилые люди точно знают, где найти травы для зеленого соуса. Если вы хотите узнать, где они растут, вы можете принять участие в региональных курсах, особенно летом. Эксперт покажет вам секретные места, которые могут найти только те, кто побывал там раньше. Но я не хочу ждать: моя цель - создать маленького помощника для меня и моих друзей, чтобы определить травы, необходимые для приготовления зеленого соуса. Давай сделаем это!

Глубокое обучение - это мой выбор, мои искусственные дедушка и бабушка, которые ведут меня к сокровищам дикой природы.

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

Среда, в которой мы будем работать, - это блокнот jupyter. Fastai - это библиотека (библиотека = набор инструментов / частей кода), расположенная поверх Pytorch - очень мощной библиотеки машинного обучения, работающей с кодом Python. Если вы никогда не слышали об одной из этих вещей: Python - это язык, на котором мы пишем наш код, Pytorch и fastai - это инструменты, которые мы используем, а блокнот jupyter помогает нам организовать наш код. Для получения дополнительной информации о настройке посетите сайт fastai.

Запускаем наш блокнот jupyter и вводим:

from fastai import *
from fastai.vision import *

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

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

Шаг 1. Получение набора данных

Поэтому мы открываем браузер Chrome, заходим в поиск изображений Google и вводим: например, 'петрушка'. Затем получаем большое количество изображений петрушки и прокручиваем вниз. Затем мы нажимаем Shift + Control + j, чтобы открыть консоль Javascript нашего браузера. Набираем:

urls = Array.from(document.querySelectorAll('.rg_di .rg_meta')).map(el=>JSON.parse(el.textContent).ou);
window.open('data:text/csv;charset=utf-8,' + escape(urls.join('\n')));

Когда мы нажимаем Enter, мы загружаем файл со всеми URL-адресами google-Images петрушки. Мы сохраняем его в «parsley.txt» и продолжаем использовать остальные шесть трав. Здорово! Подготовлены ссылки на набор данных. Мы помещаем все текстовые файлы в папку с именем «seven_herbs» и убеждаемся, что она находится в папке данных в нашем домашнем каталоге (иначе fastai не найдет его).

Шаг 2. Загрузка файлов изображений

Затем мы загружаем данные прямо на сервер, над которым мы работаем. Fastai необходимо знать путь, по которому лежит наш набор данных. В некоторых средах этот шаг может немного отличаться - например, если вы работаете в ядрах kaggle. Если вы боретесь, вы можете посетить мое стартовое ядро ​​на kaggle.

path = Path('data/seven_herbs')

После этого мы устанавливаем названия наших трав как классы.

classes = ['borage', 'chervil', 'chives', 'garden_cress', 'parsley', 'salad_burnet', 'sorrel']

Эти следующие шаги кажутся немного сложными, на самом деле они очень просты. Он просто берет текстовые файлы и делает две вещи: он создает и называет папку для каждого класса (также известный как трава), а затем заполняет эту папку изображениями, определенными в текстовом файле с одинаковым именем. (В стартовом наборе kaggle вам не нужно выполнять эти шаги, потому что я уже прикрепил набор данных к ядру.)

for x in range(0,7):
    dest = path/(classes[x])
    dest.mkdir(parents=True, exist_ok=True)
    download_images(path/(classes[x]+str('.txt')), dest, max_pics=200)

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

for c in classes:
    print(c)
    verify_images(path/c, delete=True, max_workers=8)

Шаг 3. Создание ImageDataBunch

Теперь все становится серьезно. Мы начинаем обработку наших данных с создания объекта ImageDataBunch. Таким образом, мы можем манипулировать данными и обучать нашу модель позже. Np.random.seed (13) определяет, какие изображения случайным образом выбираются из наших обучающих данных. (Нам нужна эта строка кода только в том случае, если мы хотим снова обучить модель таким же образом.) Наш ImageDataBunch создается путем передачи пути к папке с данными наших фотографий в ней. Мы определяем набор проверки, который представляет 20% данных, и определяем размер для наших изображений.

np.random.seed(13)
data = (ImageList.from_folder(path)
        .split_by_rand_pct(0.2)
        .label_from_folder()
        .transform(tfms, size=128)
        .databunch())

Затем нам также нужно назначить наши классы для ImageDataBunch.

data.classes

Если мы введем следующий код, появится ImageDataBunch, и мы сможем взглянуть на наши данные.

data.show_batch(rows=3, figsize=(7,8))

Шаг 4. Обучение модели

Да начнется обучение! Сначала мы загружаем Vision.learner, модуль, который содержит cnn_learner: представьте, что это предварительно обученная нейронная сеть, обученная на большом наборе данных изображений. Затем мы используем «трансферное обучение» в качестве метода - мы показываем наш набор данных cnn_learner, чтобы он узнал особенности семи трав.

from fastai.vision.learner import create_cnn,models
from fastai.vision import error_rate

Наконец: давайте создадим нашу модель - наше математическое представление корреляции между надписью и изображениями.

learn = create_cnn(data, models.resnet34, metrics=error_rate)

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

learn.fit_one_cycle(4)
learn.save('green-sauce-stage-1')

После этого процесса мы получаем результат, который показывает коэффициент ошибок 0,33, что означает, что в 33% случаев модель все равно будет испорчена. Мы хотим подробнее узнать, что это означает:

learn.unfreeze()
learn.lr_find()
learn.recorder.plot()

Этот график показывает нам скорость обучения и потери нашей обученной модели. Для дальнейшего объяснения, пожалуйста, посмотрите «например, здесь". Короче говоря, функция потерь показывает нам, насколько хорошо мы справляемся с нашей моделью. Для каждого прогноза график показывает нам абсолютную разницу между прогнозом, который делает наша модель, и фактической меткой, содержащейся на фотографии. (Помните: все наши обучающие данные помечены). Как правило, мы всегда стараемся найти на участке путь под уклон. Если мы посмотрим на части от 1e-5 до 1e-3, кажется, что модель там все еще улучшается. Вскоре после 1e-3 градиент снова растет очень быстро, что означает, что частота ошибок также снова увеличивается. Мы можем улучшить нашу модель, обучив ее дальше.

learn.fit_one_cycle(2, max_lr=slice(1e-5,1e-3))
learn.save('green-sauce-stage-2')

Шаг 4. Интерпретация результатов

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

interp= ClassificationInterpretation.from_learner(learn)
interp.plot_confusion_matrix()

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

interp.most_confused()

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

  • Улучшение нашего набора данных путем удаления изображений, которые появились при поиске изображений, но не совсем соответствуют нашему предполагаемому результату (например, виджет FileDeleter библиотеки fastai).
  • Сделайте нашу модель еще лучше, обучая больше / с большим количеством данных / с другими данными
  • Разработайте лучший набор для проверки. Подробнее здесь

А сейчас оставим все как есть и объявим: мы готовы! Мы построили нашу нейронную сеть. Вы можете подумать: «Хорошо, но как мне сфотографировать траву и показать ее моей обученной сети?»

Шаг 5. Создание веб-сайта

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

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

learn.load('green-sauce-stage-2')
learn.export(file = Path("/kaggle/working/export.pkl"))

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

Чтобы использовать Render, нам нужно загрузить проект, который мы хотим отобразить, в github. Если вы не знаете github: в основном это место, где люди делятся кодом. В github замечательно то, что вы найдете множество хороших проектов, которые можно использовать в качестве отправной точки для своих собственных проектов.
В данном случае мы используем репозиторий анурагов как основу и делаем на его основе свое. Если вы нажмете fork в репозитории Anurags, вы найдете его репозиторий в своей учетной записи github. Затем вы можете изменить его (переименовать, ввести свой код) и зафиксировать изменения (не беспокойтесь - это изменит только вашу ветку - другими словами: вашу версию репозитория). Если вы хотите узнать подробно, как работает github, настоятельно рекомендую прочитать руководство по github.

Итак, после разветвления репозитория anurags вы можете переименовать его в «зеленый соус», и нам нужно сделать две важные вещи, чтобы этот код заработал:

  • Нам нужно отредактировать файл server.py (green -auce / app / server.py), чтобы наше приложение нашло прямую ссылку для загрузки нашей модели. Мы также модифицируем раздел классов и вводим названия (также известные как классы) наших семи трав. Затем мы нажимаем «зафиксировать изменения».
export_file_url = 'https://YOUR-DIRECT-DOWNLOAD-LINK'
export_file_name = 'export.pkl' 
classes = ['borage', 'chervil', 'chives', 'garden_cress', 'parsley', 'salat_burnet', 'sorrel']
  • Мы модифицируем index.html (зеленый-соус / app / view / index.html). Мы можем изменить заголовок нашей веб-страницы, изменив текст между скобками div (например, ‹div class = 'title'› этот текст ‹/div›), и мы можем написать небольшой текст описания. между скобками ‹p›. Мы также "фиксируем" изменения

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

На панели инструментов рендеринга мы нажимаем на значок новый веб-сервис. Там набираем github-адрес наших репозиториев. Вы можете найти мой репозиторий на github для этой статьи на https://github.com/piaoyapia/Seven-Herbs. Если вы хотите отобразить собственное приложение, оставьте раскрывающееся меню среды на Docker. Вот и все. Об остальном позаботится Render!

Шаг 6. Тестирование веб-сайта

Наконец-то мы закончили и можем протестировать наш сайт! Если вы последовали за мной, у вас, вероятно, уже есть собственная версия. В противном случае просто испытайте мою.

Я загрузил фотографию, на которой я держу петрушку. Затем я нажал «проанализировать». Результат не такой впечатляющий визуально, но, по крайней мере, он правильный: сеть распознает травы как петрушку. Ага! 🎉

Миссия выполнена - у нас есть модель по поиску трав. Теоретически мы могли бы пойти на поля Франкфурта и различить семь разных трав, которые там растут. Как вы, возможно, заметили, у нас нет класса, вызываемого, когда ни одна из этих трав не встречается в перед нашей линзой. Это означает, что даже если мы сфотографируем симпатичного котенка, наша нейронная сеть увидит одну из семи трав на картинке. В заключение, я не рекомендую - и не несу ответственности за любой ущерб - использовать этот веб-сайт в реальной жизни. Скорее, этот проект предназначен как стимул для поиска способов использования концепций машинного обучения, которые могут рассказать нам что-то о мире, в котором мы живем, и о чем мы не думаем в повседневной жизни. Поиск трав для зеленого соуса - это, конечно, не мировая проблема, но за этим стоит культура. Если вы прочитали эту статью до этого момента, возможно, вы узнали что-то не только о машинном обучении, но и о старинном немецком рецепте. Давайте объединим старые знания и машинное обучение в будущих проектах - даже в более важных областях, чем только культура питания!