Русский
Русский
English
Статистика
Реклама

Блог компании skillfactory

Кибервойна. Когда 500 Кб кода страшнее межконтинентальной ракеты

23.02.2021 18:07:11 | Автор: admin

Привет, Хабр! Мы искренне поздравляем всех хабровчан с Днём защитника Отечества! И сегодня подготовили интересный тематический материал.

Война никогда не меняется. Думаю, все узнали интро из Fallout 4. Но действительно ли это так? Ведь за последние 20 лет военная сфера изменилась настолько сильно, что практически не имеет ничего общего с масштабными конфликтами прошлого века. Сегодня мы поговорим о современных высокотехнологичных элементах военных действий так называемой кибервойне.



Уже во время холодной войны между СССР и США мировые лидеры поняли, что одна ошибка с любой стороны будет означать не просто начало войны, а практически гарантированное уничтожение всего человечества, ведь к 1967 году обе мировые державы обладали суммарным боезапасом в 40 тысяч ядерных зарядов.

Несколько раз мир буквально висел на волоске. Стоит вспомнить только ложное срабатывание советской космической системы раннего предупреждения Око, зафиксировавшей 26 сентября 1983 года запуск нескольких ракет с американской территории. Оперативный дежурный Станислав Петров, занимавший должность инженера-аналитика, который принял на командном пункте сигнал от Ока усомнился в верности данных. Будучи инженером, он справедливо считал, что компьютер может ошибаться. И его логику несложно понять. В случае начала войны американцы бы использовали весь свой арсенал, а не стали запускать пару ракет с одной базы. Петров сознательно нарушил инструкцию и сказал командиру, что произошло ложное срабатывание системы. Поступи дежурный по инструкции со стороны СССР сразу же последовал бы удар возмездия и мир бы уже не был таким, каким мы его сейчас знаем. Спасший тогда всю планету Станислав Петров получил только выговор.

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

Хакеры новые спецагенты


2010 год ознаменовал начало совершенно нового типа военных действий кибернетических.

В сентябре стало известно, что компьютерный вирус Stuxnet нанёс значительный ущерб иранской ядерной программе. Этот червь весом в 500 Кб стал причиной повреждения 1368 из 5000 центрифуг для обогащения урана и отбросил ядерную программу Ирана примерно на два года назад. Ещё раз: 500 килобайт кода на ассемблере, С и С++ частично разрушили инфраструктуру ядерной программы целой страны, которую выстраивали на протяжении десятилетия.

По уровню ущерба действие червя можно сравнить с полноценным налётом ВВС и атакой с воздуха. Но при этом нет никакого риска для живой силы атакующего и военной техники, не тратятся боеприпасы. Для атаки не нужно ничего, кроме куска кода. Уже прошло 10 лет после первого звоночка кибервойн, но до сих пор неясно, насколько серьёзный ущерб могут причинить подобные атаки. Эксперты рассматривают самые пессимистичные варианты вроде подрыва ядерных боеголовок прямо в шахтах запуска.

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

Надежной киберзащиты не существует


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

В 2013 году иранские хакеры успешно атаковали программную инфраструктуру небольшой дамбы на севере Нью-Йорка. И это было настолько неожиданно, что ФБР фактически расписалось в своей беспомощности. Представитель Бюро дал комментарий, что если бы террористы попытались перехватить контроль над плотиной Гувера, то скорее всего, им бы это удалось.



Разрушение плотины Гувера или её повреждение грозит затоплением территории свыше 360 кв. км. Пострадают пригороды Лас Вегаса и десятки небольших городов. А Калифорния, Невада и Аризона враз лишатся четверти всех энергетических мощностей. Это была бы колоссальная катастрофа, которую оценивали бы в миллиарды или даже десятки миллиардов долларов.

Для сравнения: так выглядит плотина Bowman Avenue, на которую было совершено нападение:



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

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

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

У любого режимного объекта очень сложная техническая структура. Но время от времени им тоже нужны технические апгрейды. Контролировать их производство на каждом отдельном этапе практически невозможно в создании программных частей принимают участие сотни и тысячи людей. Заразить даже партию чипов на стадии производства проще, чем может показаться. И если заражённый чип попадёт в панель управления, то его в перспективе можно использовать для кибератаки.

Проблемы международной политики


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

В мае 2019 года израильские ВВС уничтожили здание в городе Газа, в котором размещались основные компьютерные мощности Хамаса организации, признанной террористической в Израиле. Заметим, авиаудар был нанесён по вполне себе жилому кварталу.



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

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

ООН и НАТО должны были разработать международные законы ведения кибервойн еще в 2014 году. Но, по состоянию на начало 2021 года, их всё ещё нет. Потому что до сих пор неясно, насколько опасной может быть кибервойна и как вообще её можно регулировать. Есть только рекомендательные правила, которые не имеют законодательной силы.

В 2013 году эксперты НАТО подготовили документ под названием Таллинское руководство по ведению кибервойн, где в 95 пунктах расписали правила ведения военных действий с помощью киберпространства. В 2017 году их дополнили до 154 правил.

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

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

Простые граждане часто ошибочно понимают, что такое кибервойна. Говорящие головы с экранов и дезинформация в новостях это только элемент политики. Настоящая же кибервойна начнётся в тот момент, когда в одночасье пропадут мобильная связь, Интернет и начнут взрываться АЭС вместе с шахтами межконтинентальных ракет.

И здесь как раз стоит вспомнить высказывание Эйнштейна: Я не знаю, каким оружием будут сражаться в Третьей мировой войне, но в Четвёртой будут использовать камни и палки.

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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Recovery mode Кибервойна. Когда 500 Кб кода страшнее межконтинентальной ракеты

23.02.2021 20:21:55 | Автор: admin

Привет, Хабр! Мы искренне поздравляем всех хабровчан с Днём защитника Отечества! И сегодня подготовили интересный тематический материал.

Война никогда не меняется. Думаю, все узнали интро из Fallout. Но действительно ли это так? Ведь за последние 20 лет военная сфера изменилась настолько сильно, что практически не имеет ничего общего с масштабными конфликтами прошлого века. Сегодня мы поговорим о современных высокотехнологичных элементах военных действий так называемой кибервойне.



Уже во время холодной войны между СССР и США мировые лидеры поняли, что одна ошибка с любой стороны будет означать не просто начало войны, а практически гарантированное уничтожение всего человечества, ведь к 1967 году обе мировые державы обладали суммарным боезапасом в 40 тысяч ядерных зарядов.

Несколько раз мир буквально висел на волоске. Стоит вспомнить только ложное срабатывание советской космической системы раннего предупреждения Око, зафиксировавшей 26 сентября 1983 года запуск нескольких ракет с американской территории. Оперативный дежурный Станислав Петров, занимавший должность инженера-аналитика, который принял на командном пункте сигнал от Ока усомнился в верности данных. Будучи инженером, он справедливо считал, что компьютер может ошибаться. И его логику несложно понять. В случае начала войны американцы бы использовали весь свой арсенал, а не стали запускать пару ракет с одной базы. Петров сознательно нарушил инструкцию и сказал командиру, что произошло ложное срабатывание системы. Поступи дежурный по инструкции со стороны СССР сразу же последовал бы удар возмездия и никого из нас не было бы в живых. Никто, кому сейчас младше 37 лет, вообще не появился бы на свет.

Спасший тогда всю планету Станислав Петров получил только выговор. Эта история была подробно описана в книге Дэвида Хоффмана Мертвая рука одном из главных мировых произведений о холодной войне.

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

Хакеры новые спецагенты


2010 год ознаменовал начало совершенно нового типа военных действий кибернетических.

В сентябре стало известно, что компьютерный вирус Stuxnet нанёс значительный ущерб иранской ядерной программе. Этот червь весом в 500 Кб стал причиной повреждения 1368 из 5000 центрифуг для обогащения урана и отбросил ядерную программу Ирана примерно на два года назад. Ещё раз: 500 килобайт кода на ассемблере, С и С++ частично разрушили инфраструктуру ядерной программы целой страны, которую выстраивали на протяжении десятилетия.

По уровню ущерба действие червя можно сравнить с полноценным налётом ВВС и атакой с воздуха. Но при этом нет никакого риска для живой силы атакующего и военной техники, не тратятся боеприпасы. Для атаки не нужно ничего, кроме куска кода. Уже прошло 10 лет после первого звоночка кибервойн, но до сих пор неясно, насколько серьёзный ущерб могут причинить подобные атаки. Эксперты рассматривают самые пессимистичные варианты вроде подрыва ядерных боеголовок прямо в шахтах запуска.

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

Надежной киберзащиты не существует


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

В 2013 году иранские хакеры успешно атаковали программную инфраструктуру небольшой дамбы на севере Нью-Йорка. И это было настолько неожиданно, что ФБР фактически расписалось в своей беспомощности. Представитель Бюро дал комментарий, что если бы террористы попытались перехватить контроль над плотиной Гувера, то скорее всего, им бы это удалось.



Разрушение плотины Гувера или её повреждение грозит затоплением территории свыше 360 кв. км. Пострадают пригороды Лас-Вегаса и десятки небольших городов. А Калифорния, Невада и Аризона враз лишатся четверти всех энергетических мощностей. Это была бы колоссальная катастрофа, которую оценивали бы в миллиарды или даже десятки миллиардов долларов.

Для сравнения: так выглядит плотина Bowman Avenue, на которую было совершено нападение:



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

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

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

У любого режимного объекта очень сложная техническая структура. Но время от времени им тоже нужны технические апгрейды. Контролировать их производство на каждом отдельном этапе практически невозможно в создании программных частей принимают участие сотни и тысячи людей. Заразить даже партию чипов на стадии производства проще, чем может показаться. И если заражённый чип попадёт в панель управления, то его в перспективе можно использовать для кибератаки.

Проблемы международной политики


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

В мае 2019 года израильские ВВС уничтожили здание в городе Газа, в котором размещались основные компьютерные мощности Хамаса организации, признанной террористической в Израиле. Заметим, авиаудар был нанесён по вполне себе жилому кварталу.



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

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

ООН и НАТО должны были разработать международные законы ведения кибервойн еще в 2014 году. Но, по состоянию на начало 2021 года, их всё ещё нет. Потому что до сих пор неясно, насколько опасной может быть кибервойна и как вообще её можно регулировать. Есть только рекомендательные правила, которые не имеют законодательной силы.

В 2013 году эксперты НАТО подготовили документ под названием Таллинское руководство по ведению кибервойн, где в 95 пунктах расписали правила ведения военных действий с помощью киберпространства. В 2017 году их дополнили до 154 правил.

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

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

Простые граждане часто ошибочно понимают, что такое кибервойна. Говорящие головы с экранов и дезинформация в новостях это только элемент политики. Настоящая же кибервойна начнётся в тот момент, когда в одночасье пропадут мобильная связь, Интернет и начнут взрываться АЭС вместе с шахтами межконтинентальных ракет.

И здесь как раз стоит вспомнить высказывание Эйнштейна: Я не знаю, каким оружием будут сражаться в Третьей мировой войне, но в Четвёртой будут использовать камни и палки.

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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Анализ качества сна с машинным обучением, Python и SQL

12.02.2021 14:21:36 | Автор: admin

Последние примерно 2 месяца я ношу кольцо Oura, чтобы получать информацию о моём сне и о том, сколько я прошла шагов за день. Приложение считывает сон, разбитый на фазы (лёгкий, глубокий, быстрый), и даёт вам другие показатели, такие как частота сердечных сокращений, температура тела и частота дыхания. И для такого ботаника, как я, радостно было обнаружить, что у Oura есть API экспорта данных, чтобы я смогла лучше проанализировать их. Я загрузила данные в BigQuery и воспользовалась функцией CORR() (она потрясающая!), чтобы увидеть, какие показатели коррелируют с улучшением качества сна, а также визуализировала некоторые данные в Data Studio. Если у вас мало времени, переходите к разделу Заключение, чтобы прочитать о том, что я узнала.

Дисклеймер: я не врач. Как раз наоборот: я ипохондрик, которому нравится писать на Python и SQL.



Получение данных из Oura в BigQuery


Я написала скрипт на Python, чтобы получить все мои текущие данные из Oura и записать их в файл JSON с разделителями новой строки (один из форматов файлов, который принимает BigQuery). Затем скрипт загружает файл в таблицу BigQuery. Я хочу написать скрипт, который запускается каждый день и добавляет самые свежие данные в мой набор данных BigQuery, но пока достаточно единоразового экспорта. Если вы пользуетесь Oura, для запуска скрипта потребуется получить токен доступа из консоли разработчика Oura. Вот мой код, который получает данные и записывает их в локальный файл:

import requestsimport jsonsummaries = ['sleep', 'activity', 'readiness']for data_type in summaries:url = 'https://api.ouraring.com/v1/' + data_type + '?start=2019-03-21'access_token = 'your_oura_access_token'result = requests.get(url,headers={'Content-Type':'application/json','Authorization': 'Bearer {}'.format(access_token)})json_data = json.loads(result.content)with open(data_type + '.json', 'w') as jsonfile:for j in json_data[i]:json.dump(j, jsonfile)jsonfile.write('\n')

После выполнения этого скрипта у нас будет 3 файла JSON для каждого типа данных, которые предоставляет Oura: сон, активность и то, что они называют готовностью [к чему-либо; но это не бодрость; бодрость cheerfulness], то есть того, что Oura вычисляет на основе качества вашего сна и уровня активности. Затем нужно импортировать библиотеку BigQuery и указать ссылку на набор данных:

from google.cloud import bigqueryclient = bigquery.Client()dataset_ref = client.dataset('your_dataset_name')

Теперь мы можем записать каждый файл в новую таблицу BigQuery следующим образом:

with open(filename, 'rb') as sourcefile:table_ref = dataset_ref.table(data_type)job_config = bigquery.LoadJobConfig()job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSONjob_config.autodetect = Truejob = client.load_table_from_file(sourcefile,table_ref,location="US",job_config=job_config)job.result()print('Job complete', job.output_rows)

Моя таблица сна теперь в BQ. Вот скриншот данных:


Поиск корреляций


А теперь самое интересное! Я хотела выяснить, какие факторы коррелировали с общим временем сна и с его качеством (количеством быстрых и глубоких фаз сна). Функция BigQuery CORR() идеально подходит, чтобы это сделать. Она использует коэффициент корреляции Пирсона: вы передаёте функции два параметра, и она возвращает число от -1 до 1, сигнализирующее о силе корреляции. 0 корреляции между двумя значениями нет, -1 означает обратную корреляцию: когда первое значение растёт, второе падает), а 1 указывает на идеальную положительную корреляцию.

Вы никогда не увидите значений -1 или 1 в реальных данных, поэтому всё, что превышает |0,5|, сигнализирует о средней и сильной корреляции, а всё, что находится в пределах от |0,3| до |0.5|, сообщает о небольшой корреляции.

Обратите внимание, что многие из этих корреляций специфичны для меня. Моя подруга (моя ровесница) поделилась со мной своими данными Oura, и многие из её сильных корреляций отличались от моих. Каждый уникален!

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

SELECT  CORR(hr_average, rem / total)FROM  `gcp-project.bq-dataset.sleep`

Этот код вернёт значение корреляции -0,45, оно означает отрицательную среднюю корреляцию. Это имеет смысл по мере того, как у меня увеличивается частота пульса, процент быстрых фаз сна, через которые я прохожу, снижается. Но что влияет на частоту пульса в состоянии покоя? Давайте посмотрим на температуру тела. Oura предоставляет данные об отклонении температуры тела, то есть о том, насколько ваша текущая температура отличается от средней температуры:

SELECT  CORR(hr_average, temperature_trend_deviation)FROM  `gcp-project.bq-dataset.sleep`

Корреляция здесь 0,67 очень сильная. Чем выше температура моего тела, тем выше частота пульса. Но как насчёт того, что я могу контролировать напрямую, например времени, когда я ложусь спать?

SELECT  CORR(hr_average, EXTRACT(hour from bedtime_start))FROM  `gcp-project.bq-dataset.sleep`

Это соотношение составляет 0,59. Значит, как правило, чем раньше я ложусь спать, тем ниже частота пульса в состоянии покоя в течение ночи и тем больше у меня фаза быстрого сна! Быстрый сон восстанавливает ваш мозг и улучшает память, а глубокий сон помогает восстановить ваше тело. К сожалению, я не смогла найти сильной корреляции между этими факторами и процентом глубокого сна, который у меня зафиксирован. Это всё ещёе загадка для меня, хотя я читала, что полезно сократить время перед экранами до сна (по иронии судьбы я читала это на своём телефоне перед сном).

А что насчёт тренировок?


Я немного фанатик тренировок (на самом деле больше, чем немного), и, поскольку я тренируюсь почти каждый день, у меня недостаточно данных, чтобы сравнить влияние ежедневных тренировок и их отсутствия на сон. Но я обнаружила небольшую корреляцию между объёмом активности и процентом глубокого сна, который у меня был недавно. Для этого потребовался более сложный запрос JOIN для таблиц активности и сна. И мне нужно было выполнить DATE_SUB() в операторе ON из-за того, что Oura так возвращает данные:

SELECT corr(deep / total, high + medium + low) FROM (  SELECT high, medium, low, a.summary_date  FROM `gcp-project.oura.activity` activity  JOIN (SELECT deep, total, summary_date FROM `gcp-project.oura.sleep`  ) sleep  ON activity.summary_date = date_sub(sleep.summary_date, interval 1 day) )

И я получила 0,32. Значение указывает на то, что дни, когда я активнее, слегка коррелируют с ночами, когда сон глубже.

О программном обеспечении и предубеждениях


Помимо множества интересных показателей, Oura также даёт различные оценки, которые вычисляет на основе своих данных с помощью собственных алгоритмов. Каждый день вы получаете 100 баллов за свой сон, активность и готовность. Температура тела это один из показателей, которые используются, чтобы рассчитать показатели сна и готовности. Через пару недель использования приложения я заметила довольно сильную обратную корреляцию между температурой тела и этими показателями. Проблема здесь в том, что у большинства женщин температура тела немного повышается раз в месяц, и это нормальное явление для женщины. Сообщения в приложении довольно ясно показывают, что повышенная температура тела является симптомом того, что что-то не так:

Господи, я проспала 9 часов!

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

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

Визуализация данных о сне в Data Studio


Вернёмся к интересной части: визуализируем некоторые данные, чтобы лучше понять корреляции, которые я обнаружила. BigQuery отлично интегрируется с Data Studio, которой я могу воспользоваться, чтобы создать интересные графики временных рядов с наложением различных показателей. Когда я создаю новый отчёт в Data Studio, мне нужно выбрать BigQuery в качестве источника данных, а затем выбрать Custom Query:


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

SELECT start_hr_utc, temperature_deviation, rem / total as rem_pct, deep / total as deep_pct, light / total as light_pct, low + medium + high as total_activity, steps, inactive, hr_lowest, hr_average, activity.summary_dateFROM `gcp-project.oura.activity` activityJOIN (  SELECT bedtime_start, extract (hour from bedtime_start) as start_hr_utc, temperature_deviation, rem, deep, light, summary_date, hr_lowest, hr_average FROM `gcp-project.oura.sleep`) sleepON activity.summary_date = date_sub(sleep.summary_date, interval 1 day)

А вот моя диаграмма зависимости времени, когда начался отход ко сну, от процента быстрого сна:


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


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


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

Заключение


Что я узнала, кроме навязчивого анализа данных о моём здоровье? Резюмирую:

  • Повышенная температура тела обычно коррелирует с учащённым пульсом в состоянии покоя и частотой дыхания.
  • Ранний отход ко сну почти всегда улучшает фазу быстрого сна.
  • Ложиться спать в определённое время тоже хорошо.
  • Тренировки хорошо влияют на фазу глубокого сна.
  • Помните о предвзятости при создании технологий для разнообразной аудитории.
  • Конечно, люди не роботы, и я не могу ложиться спать в 9 вечера каждую ночь, но всё же считаю данные очень полезными.

Эти данные сложно использовать для машинного обучения, поскольку, даже если я соберу годовой отчет, в наборе данных будет только 365 строк. Однако я думаю, что у машинного обучения есть много возможностей для работы с данными о состоянии здоровья в целом. Хотите научиться использовать машинное обучение приходите учиться, а промокод HABR, дающий 10 % дополнительно к скидке на баннере, вам в этом поможет.



image



Подробнее..

Перевод Часы для обнаружения жестов на основе машинного обучения, ESP8266 и Arduino

15.02.2021 16:13:26 | Автор: admin

Мир, безусловно, становится лучше с каждым днем благодаря технологиям, основанным на жестах, потому что они интуитивно понятны, просты в применении и делают взаимодействие с гаджетами и вещами вокруг вас футуристическим и фантастическим! Итак, чтобы быть в тренде, мы возьмём самодельные спортивные часы, погрузимся в Machine Learning и посмотрим, сможем ли мы с его помощью определить, какой жест выполняем, и, возможно, мы сможем использовать это в последующих проектах, например, реализовать отправку e-mail взмахом руки. Далее под катом настоящее гик-порно с кучей картинок, приготовьтесь.




Шаг 1. Рассказываю!


Так как я убрал ряд изначально планировавшихся мной функций часов (таких как мониторинг пульса и микро-USB для зарядки), то решил уделить больше времени доведению до ума программной части. Я подумал о том, чтобы добавить в проект немного машинного обучения; это должно быть легко по сравнению с электроникой: я буду иметь дело с простым набором кода копипастой со StackOverflow. По крайней мере, я так думал.

Но я ошибался: реализовав обнаружение жестов на основе машинного обучения, я просто сошёл с ума. Я ненавидел всё это. Не потому, что это было сложно, просто было очень неприятно собирать данные и обучать модель.

Если вы хотите узнать больше о внедрении машинного обучения во встраиваемую систему, ознакомьтесь с двумя ссылками: TinyMLи определение жестов. Первая объясняет, как использовать TensorFlow в TinyML с Arduino, а вторая как использовать базовые алгоритмы ML на Arduino. Я много раз упоминал последнюю ссылку, потому что материал просто понять, а также это работает с микроконтроллерами с очень небольшим количеством памяти, такими как Arduino NANO и UNO.

Шаг 2. Сборка печатной платы










В этот раз сборка должна быть очень простой и быстрой благодаря печатным платам, и за это я благодарю PCBWay за спонсирование этой великолепной чёрной печатной платы для этого проекта.

Я собрал все SMD-компоненты для проекта, а затем расположил их таким образом, чтобы можно было легко, без возни получить к ним доступ. Остальное я потом просто паял!

Просто следуйте принципиальной схеме и соответствующим образом припаяйте компоненты на печатной плате. Чтобы упростить пайку, переходите от пайки небольших SMD-компонентов [резистор, конденсатор, регулятор] к более крупным компонентам со сквозными отверстиями [MPU6050, OLED]. Во время пайки я также с помощью ленты 3M закрепил батарею Lipo между платой и OLED-дисплеем.

Мне сложно найти подходящий регулятор для проектов, поэтому в своих прошлых проектах я просто использовал AMS1117: он дешёвый и его легко найти. На плате я дал два варианта, вы можете воспользоваться MCP1700 или LSD3985. В моём случае я использую LSD3985 и игнорирую MCP1700, а вы можете использовать любой вариант. Если вам нужна точная схема, посмотрите здесь.

Шаг 3. Программирование часов






Чтобы упростить программирование, я выделил немного места на печатной плате, так что вы можете просто подключить модуль FTDI, чтобы начать программировать. Для программирования платы необходимо сначала перевести esp8266 в мигающий режим, поэтому при подключении к ПК просто удерживайте кнопку, которая подключена к GPIO-0 esp12E.

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

Шаг 4. Машинное обучение? Часть 1




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

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

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

Шаг 5. Машинное обучение? Часть 2




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

Возьмём, к примеру, поиск яблока на фотографии, это очень легко сделать человеку, но довольно сложно написать алгоритм и заставить компьютер понимать все функции, которые есть у яблока; это возможно, но крайне утомительно и сложно. Вместо этого, если бы мы могли написать алгоритм, который может обучаться сам по себе, просто глядя на тысячи изображений яблок, и учиться самостоятельно, разве такое не было бы здорово? Есть ещё один положительный момент использования алгоритма машинного обучения: они могут придумать новый способ поиска яблок на фотографии, о котором мы даже не думали. Итак, ML довольно интересная область, чтобы её исследовать.

Примечание! Я не самый подходящий человек, чтобы объяснить машинное обучение и искусственный интеллект, я просто пишу то, что узнал.

Шаг 6. Классификация






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

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

Шаг 7. Сбор данных для обучения модели с датчиков







Поскольку теперь у нас есть базовое представление о машинном обучении, мы можем начать со сбора данных, которыми воспользуемся, чтобы обучить наш алгоритм ML. В руководстве, которому я следовал, сбор данных был неуклюжим: через монитор порта. Мне было бы очень сложно сделать то же самое, потому что пришлось бы носить устройство на запястье во время жеста. Чтобы решить эту проблему, я сделал сбор данных беспроводным. Я воспользовался встроенной флеш-памятью esp8266 и, чтобы было удобнее, отображал статус сбора и сохранения данных на OLED-дисплее. Если вы хотите сделать то же самое, скомпилируйте и загрузите файл Data_collection.ino на свои часы.

После того как вы загрузили код, чтобы проверить его, держите руку неподвижно, как только устройство запускается; оно сначала калибрует акселерометр и гироскоп. Как только калибровка закончится, вы можете начать сбор данных! Просто нажмите кнопку, к которой подключён GPIO-0, и устройство создаст новы признак, а затем просто двигайте руками, чтобы записать движение. Попытки сделать сбор данных беспроводным определённо того стоили! Стал намного проще сбор каждого движения (примерно 2530 раз), он не доставил проблем. Чем больше у вас будет выборок, тем лучше будет работать алгоритм.

Шаг 8. Обработка данных







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

Затем разделите текстовый файл на 3 файла CSV, используя Excel, на жест свайпа влево, жест свайпа вправо и хлопка. Мы закончили сбор данных.

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

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







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

Для обучения я использую скрипт python, который обучает модель и конвертирует её в файл C, а этот файл, в свою очередь, мы можем использовать с IDE arduino. Вы можете скачать этот файл из моего репозитория на github и открыть файл Classifier.py внутри папки Python training code. В этом коде мы прочитаем файлы csv и обучим модель изучению жестов. мы записывали раньше. Если у вас другие имена файлов, просто измените список Python, который называется fileName, чтобы он обучал модель на основе собранных вами данных.

Этот код создаст файл model.h. Он содержит обученную модель, которая определяет три зафиксированных нами жеста. Если вы хотите просто протестировать модель, вставьте файл model.h в папку Testing gesture detection и откройте файл arduino в этой папке. Затем просто скомпилируйте и загрузите код на часы.

Testing_Gesture_Detection.ino

Шаг 10. Выводы модели






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

После успешной загрузки кода выполните любой жест. Жест, который вы выполняете, должен быть указан на OLED-дисплее. В моём случае модель работала в 95 % случаев, иногда затрудняясь обнаружить свайп вправо. Возможно, данные, которые я собрал, были зашумлены, или, может быть, когда собирал данные, я делал жесты неправильно.

Как бы то ни было, для меня 95 % это хорошо, с таким распознанием можно многое сделать!

Шаг 11. Заключительные мысли






Есть так много вещей, которые вы могли бы улучшить, если хотите реализовать это для проекта более высокого уровня. Например, можно увеличить частоту дискретизации во время сбора данных, увеличить количество образцов, которые вы собираете, очистить данные после их сбора, использовать обработку сигналов, чтобы удалить шум и т. д. Но с точки зрения начинающего любителя, даже такая реализация модели машинного обучения в микроконтроллере имеет большое значение! Хотите научиться использовать машинное обучение приходите учиться, а промокод HABR, дающий 10 % дополнительно к скидке на баннере, вам в этом поможет.



image
Подробнее..

Перевод Как преобразовать текст в речь с использованием Google Tesseract и Arm NN на Raspberry Pi

17.02.2021 16:08:10 | Автор: admin

Привет, Хабр! Сегодня специально к старту нового потока курса по Maсhine Learning делимся с вами постом, автор которого создаёт устройство преобразования текста в речь. Такой механизм преобразования текста в речь (TTS) ключевой элемент систем, которые стремятся сформировать естественное взаимодействие между людьми и машинами на основе встроенных устройств. Встроенные устройства могут, например, помочь людям с нарушениями зрения читать знаки, буквы и документы. В частности, устройство может, используя оптическое распознавание символов, дать понять пользователю, что видно на изображении. Впрочем, приступим к крафту



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

Обычно такие системы начинаются с некоторого машиночитаемого текста. Что делать, если у вас нет готового источника текста для документа, браузера или приложения? Программное обеспечение для оптического распознавания символов (OCR) может преобразовывать отсканированные изображения в текст. В контексте приложения TTS это глифы отдельные символы. Программное обеспечение OCR само по себе занимается только точным извлечением цифр и букв.

Для точного обнаружения текста в реальном времени распознавания наборов глифов как произносимых слов можно обратиться к методам глубокого обучения ИИ. В этом случае для распознавания слов в тексте, захваченном при оптическом распознавании символов, можно было бы использовать рекуррентную нейронную сеть (РНС). А что, если бы это можно было сделать на встроенном устройстве, более лёгком и компактном, чем даже смартфон?

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

В этой статье я покажу, как это сделать с помощью TensorFlow, OpenCV, Festival и Raspberry Pi. Для оптического распознавания текста я буду использовать платформу машинного обучения TensorFlow вместе с предварительно обученной моделью Keras-OCR. Библиотека OpenCV будет использоваться для захвата изображений с веб-камеры. Наконец, в качестве TTS-модуля будет выступать система синтеза речи Festival. Затем всё соединим, чтобы создать приложение на Python для Raspberry Pi.

Попутно я расскажу, как работают типичные OCR-модели и как дополнительно оптимизировать решение с помощью TensorFlow Lite, набора инструментов для запуска оптимизированных моделей TensorFlow в ограниченных средах, таких как встраиваемые устройства и устройства Интернета вещей. Полный исходный код, представленный здесь, доступен на моей странице GitHub.

Начало работы


Во-первых, чтобы создать устройство и приложение для этого туториала, понадобится Raspberry Pi. Для этого примера подойдут версии 2, 3 или 4. Вы также можете использовать собственный компьютер для разработки (мы тестировали код для Python 3.7).

Необходимо установить два пакета: tensorflow (2.1.0) и keras_ocr (0.7.1). Вот несколько полезных ссылок:


OCR с помощью рекуррентных нейронных сетей


Здесь для распознавания текста на изображениях я использую пакет keras_ocr. Этот пакет основан на платформе TensorFlow и свёрточной нейронной сети, которая первоначально была опубликована в качестве примера OCR на веб-сайте Keras.

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

Рекуррентные нейронные сети (РНС) обычно состоят из слоёв долгой краткосрочной памяти (LTSM). Долгая краткосрочная память произвела революцию во многих применениях ИИ, включая распознавание речи, создание субтитров к изображениям и анализ временных рядов. OCR-модели используют РНС для создания так называемой матрицы вероятностей символов. Эта матрица определяет степень уверенности в том, что заданный символ находится в конкретной части входного изображения.

Таким образом, на последнем этапе эта матрица используется для декодирования текста на изображении. Обычно люди используют алгоритм классификации по рейтингу (Connectionist Temporal Classification, CTC). CTC стремится преобразовать матрицу в осмысленное слово или последовательность таких слов. Такое преобразование не тривиальная задача, так как в соседних частях изображения могут быть найдены одинаковые символы. Кроме того, некоторые входные части могут не содержать символов.

Хотя OCR-системы на основе РНС эффективны, пытаясь внедрить их в свои проекты, можно столкнуться с множеством проблем. В идеале необходимо выполнить обучение преобразованию, чтобы настроить модель в соответствие со своими данными. Затем модель преобразуется в формат TensorFlow Lite, чтобы оптимизировать для вывода на оконечное устройство. Такой подход оказался успешным в мобильных приложениях компьютерного зрения. Например, многие предварительно обученные сети MobileNet эффективно классифицируют изображения на мобильных устройствах и устройствах Интернета вещей.

Однако TensorFlow Lite представляет собой подмножество TensorFlow, и поэтому в настоящее время поддерживается не каждая операция. Эта несовместимость становится проблемой, когда необходимо выполнить оптическое распознавание символов, подобное тому, что включено в пакет keras-ocr на устройстве Интернета вещей. Список возможных решений предоставлен на официальном сайте TensorFlow.

В этой статье я покажу, как использовать модель TensorFlow, поскольку двунаправленные слои LSTM (используемые в keras-ocr) еще не поддерживаются в TensorFlow Lite.

Предварительно обученная OCR-модель


Для начала я написал тестовый скрипт (ocr.py), который показывает, как использовать модель нейронной сети из keras-ocr:

# Importsimport keras_ocrimport helpers # Prepare OCR recognizerrecognizer = keras_ocr.recognition.Recognizer() # Load images and their labelsdataset_folder = 'Dataset'image_file_filter = '*.jpg' images_with_labels = helpers.load_images_from_folder(dataset_folder, image_file_filter) # Perform OCR recognition on the input imagespredicted_labels = []for image_with_label in images_with_labels:predicted_labels.append(recognizer.recognize(image_with_label[0])) # Display resultsrows = 4cols = 2font_size = 14helpers.plot_results(images_with_labels, predicted_labels, rows, cols, font_size)

Этот скрипт создаёт экземпляр объекта Recognizer на основе модуля keras_ocr.recognition. Затем скрипт загружает изображения и их метки из прикреплённого набора тестовых данных (папка Dataset). Этот набор данных содержит восемь случайно выбранных изображений из набора синтетических слов (Synth90k). Затем скрипт запускает оптическое распознавание символов на каждом изображении этого набора данных, а затем отображает результаты прогнозирования.



Для загрузки изображений и их меток я использую функцию load_images_from_folder, которую я реализовал в модуле helpers. Этот метод предполагает два параметра: путь к папке с изображениями и фильтр. Здесь я предполагаю, что изображения находятся в подпапке Dataset, и я читаю все изображения в формате JPEG (с расширением имени файла .jpg).

В наборе данных Synth90k каждое имя файла изображения содержит метку изображения между символами подчёркивания. Например: 199_pulpiest_61190.jpg. Таким образом, чтобы получить метку изображения, функция load_images_from_folder разделяет имя файла по символу подчёркивания, а затем берёт первый элемент полученной коллекции строк. Также обратите внимание, что функция load_images_from_folder возвращает массив кортежей. Каждый элемент такого массива содержит изображение и соответствующую метку. По этой причине я передаю обработчику OCR только первый элемент этого кортежа.

Для распознавания я использую метод распознавания объекта Recognizer. Этот метод возвращает прогнозируемую метку, которую я сохраняю в коллекции predicted_labels.

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

Камера


После тестирования OCR-модели я реализовал класс camera. В этом классе используется библиотека OpenCV, которая была установлена вместе с модулем keras-ocr. OpenCV предоставляет собой удобный программный интерфейс для доступа к камере. В явном виде вы сначала инициализируете объект VideoCapture, а затем вызываете его метод чтения (read), чтобы получить изображение с камеры.

import cv2 as opencv class camera(object):def __init__(self):# Initialize the camera captureself.camera_capture = opencv.VideoCapture(0)def capture_frame(self, ignore_first_frame):# Get frame, ignore the first one if neededif(ignore_first_frame):self.camera_capture.read()(capture_status, current_camera_frame) = self.camera_capture.read() # Verify capture statusif(capture_status):return current_camera_frame else:# Print error to the consoleprint('Capture error')

В этом коде я создал объект VideoCapture в инициализаторе класса camera. Я передаю объекту VideoCapture значение 0, чтобы указать на камеру системы по умолчанию. Затем я сохраняю полученный объект в поле camera_capture класса camera.

Чтобы получать изображения с камеры, я реализовал метод capture_frame. У него есть дополнительный параметр, ignore_first_frame. Когда значение этого параметра равно True, я дважды вызываю метод caper_capture.read, но игнорирую результат первого вызова. Смысл этой операции заключается в том, что первый кадр, возвращаемый моей камерой, обычно пуст.

Второй вызов метода read дает статус захвата и кадр. Если сбор данных был успешным (capture_status = True), я возвращаю кадр камеры. В противном случае я печатаю строку Ошибка захвата.

Преобразование текста в речь


Последний элемент данного приложения TTS-модуль. Было решено использовать здесь систему Festival, потому что она может работать в автономном режиме. Другие возможные подходы к TTS хорошо описаны в статье Adafruit Speech Synthesis on the Raspberry Pi (Синтез речи на Raspberry Pi).
Чтобы установить Festival на Raspberry Pi, выполните следующую команду:

sudo apt-get install festival -y

Убедиться в том, что всё работает правильно, можно, введя следующую команду:

echo "Hello, Arm" | Festival tts

Ваш Raspberry Pi должен произнести: Hello, Arm.
Festival предоставляет API-интерфейс. Однако для простоты было решено взаимодействовать с Festival посредством командной строки. С этой целью модуль helpers был дополнен ещё одним методом:

def say_text(text):os.system('echo ' + text + ' | festival --tts')

Собираем всё вместе


Наконец, мы можем собрать всё вместе. Я сделал это в скрипте main.py:

import keras_ocrimport camera as camimport helpers if __name__ == "__main__":# Prepare recognizerrecognizer = keras_ocr.recognition.Recognizer() # Get image from the cameracamera = cam.camera() # Ignore the first frame, which is typically blank on my machineimage = camera.capture_frame(True) # Perform recognitionlabel = recognizer.recognize(image) # Perform TTS (speak label)helpers.say_text('The recognition result is: ' + label)

Сначала я создаю OCR-распознаватель. Затем я создаю объект Camera и считываю кадр с веб-камеры по умолчанию. Изображение передаётся распознавателю, а полученная в результате метка произносится вспомогательным TTS-модулем.

Заключение


Итак, мы создали надёжную систему, которая способна оптически распознавать символы с использованием глубокого обучения, а затем передавать результаты пользователям посредством механизма преобразования текста в речь. Мы использовали пакет keras-OCR с предварительным обучением.

В более сложном сценарии распознаванию текста может предшествовать обнаружение текста. Сначала на изображении обнаруживаются строки текста, а затем распознаётся каждая из них. Для этого потребуются только возможности пакета keras-ocr по обнаружению текста. Это было показано в данной версии реализации Keras CRNN и опубликованной модели обнаружения текста CRAFT Фаусто Моралесом.

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

Хочется завершить этот материал цитатой третьего закона Артура Кларка:

Любая достаточно развитая технология неотличима от магии.

Если следовать ему то можно спокойно сказать, что у нас в SkillFactory мы обучаем людей настоящей магии, просто она называется data science и machine learning.



image
Подробнее..

Перевод Как распознать рукописный текст с помощью ИИ на микроконтроллерах

18.02.2021 18:15:13 | Автор: admin


Распознавание рукописных цифр с помощью TensorFlow и MNIST стало довольно распространённым введением в искусственный интеллект (ИИ) и ML. MNIST это база данных, которая содержит 70 000 примеров рукописных цифр. Она широко используется как источник изображений для обучения систем обработки изображений и программного обеспечения для машинного обучения.

Хотя учебные пособия по ML с использованием TensorFlow и MNIST стали привычными, до недавнего времени они обычно демонстрировались в полнофункциональных средах обработки с архитектурой x86 и графическими процессорами класса рабочих станций. Однако сегодня можно создать полнофункциональное приложение для распознавания рукописного ввода MNIST даже на 8-разрядном микроконтроллере. Чтобы продемонстрировать это, мы собираемся создать полнофункциональное приложение для распознавания рукописного ввода MNIST, используя TensorFlow Lite для получения результатов ИИ на маломощном микроконтроллере STMicroelectronics на базе процессора ARM Cortex M7.



В этой статье предполагается, что вы знакомы с C/C++ и машинным обучением, но не волнуйтесь, если это не так. Вы всё равно можете изучить предлагаемый пример и попробовать развернуть проект на собственном устройстве дома! Подобная реализация демонстрирует возможность создания надёжных приложений на основе машинного обучения даже на автономных устройствах с батарейным питанием в самых разных сценариях для Интернета вещей и портативных устройств.



Для создания этого проекта потребуется несколько компонентов:


Код этого проекта можно найти на GitHub.

Краткий обзор


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

  1. Обучить прогнозирующую модель на основе набора данных (рукописные цифры MNIST).
  2. Преобразовать модель в формат TensorFlow Lite.
  3. Создать встроенное приложение.
  4. Создать образцы данных.
  5. Развернуть и протестировать приложение.

Чтобы ускорить и упростить этот процесс, я создал записную книжку Jupyter в Google Colab, чтобы сделать первые два шага за вас из вашего браузера, не устанавливая и не настраивая Python на вашем компьютере. Она также может служить справочным материалом для других проектов, поскольку содержит весь код, необходимый для обучения и оценки модели MNIST с помощью TensorFlow, а также для преобразования модели в целях автономного использования в TensorFlow Lite для микроконтроллеров и создания версии кода массива Си модели для простой компиляции в любую программу на C++.

Чтобы перейти к встроенному приложению на шаге 3, сначала в меню записной книжки нажмите Runtime Run All (Время выполнения > Выполнить всё), чтобы создать файл model.h. Загрузите его из списка файлов на левой стороне. Также можно загрузить предварительно созданную модель из репозитория GitHub, чтобы включить её в проект.

Чтобы выполнить эти действия локально на своём компьютере, убедитесь, что используете платформу TensorFlow версии 2.0 или более поздней и дистрибутив Anaconda для установки и использования Python. Если вы используете упомянутую ранее записную книжку Jupyter, о которой говорилось выше, вам не придётся беспокоиться об установке TensorFlow 2.0, так как эта версия входит в состав этой записной книжки.

Обучение модели TensorFlow с использованием MNIST


Keras это высокоуровневая библиотека Python для нейронных сетей, часто используемая для создания прототипов ИИ-решений. Она интегрирована с TensorFlow, а также содержит встроенный набор данных MNIST из 60 000 изображений и 10 000 тестовых образцов, доступных прямо в TensorFlow.

Чтобы прогнозировать рукописные цифры, этот набор данных использовался для обучения относительно простой модели, в которой изображение 2828 принимается в качестве входной формы и выводятся до 10 категорий результатов с помощью функции активации Softmax с одним скрытым слоем между входным и выходным слоями. Этого было достаточно для достижения точности 96,6 %, но при желании можно добавить больше скрытых слоёв или тензоров.

За более глубоким обсуждением работы с набором данных MNIST в TensorFlow я рекомендую обратиться к некоторым (из многих) замечательным учебным пособиям по TensorFlow в Интернете, таким как Not another MNIST tutorial with TensorFlow, автор О'Рейли (O'Reilly). Вы также можете обратиться к примеру синусоидальной модели TensorFlow в этой записной книжке, чтобы ознакомиться с обучением и оценкой моделей TensorFlow и преобразованием модели в формат TensorFlow Lite для микроконтроллеров.



Преобразование модели в формат TensorFlow Lite


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

В этом случае платформа TensorFlow Lite нужна, чтобы приложение занимало как можно меньше места во флеш-памяти и ОЗУ, оставаясь при этом быстрым, чтобы можно было немного понизить точность, не жертвуя слишком многим.

Чтобы ещё больше уменьшить размер, преобразователь TensorFlow Lite поддерживает дискретизацию модели, чтобы перейти в вычислениях от 32-разрядных значений с плавающей запятой к 8-разрядным целым числам, так как часто высокая точность значений с плавающей запятой не требуется. В результате также значительно уменьшается размер модели и повышается производительность.

Мне не удалось получить дискретизированную модель для правильного и согласованного использования функции Softmax. На моём устройстве STM32F7 Discovery возникает ошибка не удалось вызвать. Преобразователь TensorFlow Lite постоянно развивается, и некоторые конструкции моделей ещё не поддерживаются. Например, этот инструмент преобразует некоторые веса в значения типа int8 вместо uint8, а тип int8 не поддерживается. По крайней мере пока.

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

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

Я добавил скрипт Python в конец своей записной книжки, чтобы обработать эту часть и превратить её в файл model.h. При желании в Linux с помощью команды оболочки xxd -i созданный tflite-файл также можно преобразовать в массив Си. Загрузите этот файл из меню слева и приготовьтесь добавить его в проект встроенного приложения на следующем шаге.

import binasciidef convert_to_c_array(bytes) -> str:  hexstr = binascii.hexlify(bytes).decode("UTF-8")  hexstr = hexstr.upper()  array = ["0x" + hexstr[i:i + 2] for i in range(0, len(hexstr), 2)]  array = [array[i:i+10] for i in range(0, len(array), 10)]  return ",\n  ".join([", ".join(e) for e in array])tflite_binary = open("model.tflite", 'rb').read()ascii_bytes = convert_to_c_array(tflite_binary)c_file = "const unsigned char tf_model[] = {\n  " + ascii_bytes +   "\n};\nunsigned int tf_model_len = " + str(len(tflite_binary)) + ";"# print(c_file)open("model.h", "w").write(c_file)

Создание встроенного приложения


Теперь мы готовы взять нашу обученную модель MNIST и реализовать её на реальном маломощном микроконтроллере. Ваши конкретные действия могут зависеть от используемого набора инструментов, но с моими интегрированной средой разработки PlatformIO и устройством STM32F746G Discovery мною были предприняты следующие действия.

Сначала создан новый проект приложения с настройками для соответствующего устройства на базе ARM Cortex-M и подготовлены основные функции setup и loop. Я выбрал структуру Stm32Cube, чтобы выводить результаты на экран. Если вы используете Stm32Cube, вы можете загрузить файлы stm32_app.h и stm32_app.c из репозитория и создать файл main.cpp с функциями setup и loop, например, как здесь:

#include "stm32_app.h"void setup() {}void loop() {}



Добавьте или загрузите библиотеку TensorFlow Lite Micro. Я предварительно настроил библиотеку для интегрированной среды разработки PlateformIO, чтобы вы могли загрузить папку tfmicro отсюда в папку lib проекта и добавить её в качестве зависимости библиотеки в файл platformio.ini:

[env:disco_f746ng]platform = ststm32board = disco_f746ngframework = stm32cubelib_deps = tfmicro

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

#include "stm32_app.h"#include "tensorflow/lite/experimental/micro/kernels/all_ops_resolver.h"#include "tensorflow/lite/experimental/micro/micro_error_reporter.h"#include "tensorflow/lite/experimental/micro/micro_interpreter.h"#include "tensorflow/lite/schema/schema_generated.h"#include "tensorflow/lite/version.h"void setup() {}void loop() {}

Включите преобразованный ранее файл model.h в этот проект в папку Include и добавьте его под заголовками TensorFlow. Затем сохраните результат и выполните сборку, чтобы убедиться, что всё в порядке, ошибок нет.

#include "model.h"



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

// Globalsconst tflite::Model* model = nullptr;tflite::MicroInterpreter* interpreter = nullptr;tflite::ErrorReporter* reporter = nullptr;TfLiteTensor* input = nullptr;TfLiteTensor* output = nullptr;constexpr int kTensorArenaSize = 5000; // Just pick a big enough numberuint8_t tensor_arena[ kTensorArenaSize ] = { 0 };float* input_buffer = nullptr;

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

void setup() {  // Load Model  static tflite::MicroErrorReporter error_reporter;  reporter = &error_reporter;  reporter->Report( "Let's use AI to recognize some numbers!" );  model = tflite::GetModel( tf_model );  if( model->version() != TFLITE_SCHEMA_VERSION ) {reporter->Report(   "Model is schema version: %d\nSupported schema version is: %d",   model->version(), TFLITE_SCHEMA_VERSION );return;  }   // Set up our TF runner  static tflite::ops::micro::AllOpsResolver resolver;  static tflite::MicroInterpreter static_interpreter(  model, resolver, tensor_arena, kTensorArenaSize, reporter );  interpreter = &static_interpreter;   // Allocate memory from the tensor_arena for the model's tensors.  TfLiteStatus allocate_status = interpreter->AllocateTensors();  if( allocate_status != kTfLiteOk ) {reporter->Report( "AllocateTensors() failed" );return;  }  // Obtain pointers to the model's input and output tensors.  input = interpreter->input(0);  output = interpreter->output(0);  // Save the input buffer to put our MNIST images into  input_buffer = input->data.f;}

Подготовьте TensorFlow к выполнению на устройстве ARM Cortex-M при каждом вызове функции loop с короткой задержкой (одна секунда) между обновлениями, например, как здесь:

void loop() {  // Run our model  TfLiteStatus invoke_status = interpreter->Invoke();  if( invoke_status != kTfLiteOk ) {reporter->Report( "Invoke failed" );return;  }   float* result = output->data.f;  char resultText[ 256 ];  sprintf( resultText, "It looks like the number: %d", std::distance( result, std::max_element( result, result + 10 ) ) );  draw_text( resultText, 0xFF0000FF );  // Wait 1-sec til before running again  delay( 1000 );}

Приложение готово к работе. Оно просто ждёт, когда мы скормим ему несколько забавных тестовых изображений MNIST для обработки!

Создание образца данных MNIST для встраивания


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

Чтобы добавить эти изображения в программу независимо от внешнего хранилища, мы можем заранее преобразовать 100 изображений MNIST из формата JPEG в чёрно-белые изображения, сохранённые в виде массивов, так же как и наша модель TensorFlow. Для этого я использовал веб-инструмент с открытым исходным кодом под названием image2cpp, который выполняет большую часть этой работы за нас в одном пакете. Если вы хотите сгенерировать их самостоятельно, проанализируйте пиксели и закодируйте по восемь в каждый байт и запишите их в формате массива Си, как показано ниже.

ПРИМЕЧАНИЕ. Веб-инструмент генерирует код для интегрированной среды разработки Arduino, поэтому в коде найдите и удалите все экземпляры PROGMEM, а затем компилируйте код в среде PlatformIO.

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



// 'mnist_0_1', 28x28pxconst unsigned char mnist_1 [] PROGMEM = {  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,  0x00, 0x07, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x1f, 0x80, 0x00,  0x00, 0x3f, 0xe0, 0x00, 0x00, 0x7f, 0xf0, 0x00, 0x00, 0x7e, 0x30, 0x00, 0x00, 0xfc, 0x38, 0x00,  0x00, 0xf0, 0x1c, 0x00, 0x00, 0xe0, 0x1c, 0x00, 0x00, 0xc0, 0x1e, 0x00, 0x00, 0xc0, 0x1c, 0x00,  0x01, 0xc0, 0x3c, 0x00, 0x01, 0xc0, 0xf8, 0x00, 0x01, 0xc1, 0xf8, 0x00, 0x01, 0xcf, 0xf0, 0x00,  0x00, 0xff, 0xf0, 0x00, 0x00, 0xff, 0xc0, 0x00, 0x00, 0x7f, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};

Сохраните сгенерированные изображения в новый файл mnist.h в проекте или, чтобы сэкономить время и пропустить этот шаг, можно просто загрузить мою версию изGitHub.

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

const unsigned char* test_images[] = {  mnist_1, mnist_2, mnist_3, mnist_4, mnist_5,   mnist_6, mnist_7, mnist_8, mnist_9, mnist_10,  mnist_11, mnist_12, mnist_13, mnist_14, mnist_15,   mnist_16, mnist_17, mnist_18, mnist_19, mnist_20,  mnist_21, mnist_22, mnist_23, mnist_24, mnist_25,   mnist_26, mnist_27, mnist_28, mnist_29, mnist_30,  mnist_31, mnist_32, mnist_33, mnist_34, mnist_35,   mnist_36, mnist_37, mnist_38, mnist_39, mnist_40,  mnist_41, mnist_42, mnist_43, mnist_44, mnist_45,   mnist_46, mnist_47, mnist_48, mnist_49, mnist_50,  mnist_51, mnist_52, mnist_53, mnist_54, mnist_55,   mnist_56, mnist_57, mnist_58, mnist_59, mnist_60,  mnist_61, mnist_62, mnist_63, mnist_64, mnist_65,   mnist_66, mnist_67, mnist_68, mnist_69, mnist_70,  mnist_71, mnist_72, mnist_73, mnist_74, mnist_75,   mnist_76, mnist_77, mnist_78, mnist_79, mnist_80,  mnist_81, mnist_82, mnist_83, mnist_84, mnist_85,   mnist_86, mnist_87, mnist_88, mnist_89, mnist_90,  mnist_91, mnist_92, mnist_93, mnist_94, mnist_95,   mnist_96, mnist_97, mnist_98, mnist_99, mnist_100,};

Не забудьте включить в верхнюю часть кода заголовок нового изображения:

#include "mnist.h"

Тестирование изображений MNIST


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

void bitmap_to_float_array( float* dest, const unsigned char* bitmap ) { // Populate input_vec with the monochrome 1bpp bitmap  int pixel = 0;  for( int y = 0; y < 28; y++ ) {for( int x = 0; x < 28; x++ ) {  int B = x / 8; // the Byte # of the row  int b = x % 8; // the Bit # of the Byte  dest[ pixel ] = ( bitmap[ y * 4 + B ] >> ( 7 - b ) ) & 0x1 ? 1.0f : 0.0f;  pixel++;}  }}void draw_input_buffer() {  clear_display();  for( int y = 0; y < 28; y++ ) {for( int x = 0; x < 28; x++ ) {  draw_pixel( x + 16, y + 3, input_buffer[ y * 28 + x ] > 0 ? 0xFFFFFFFF : 0xFF000000 );}  }}

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

void loop() {  // Pick a random test image for input  const int num_test_images = ( sizeof( test_images ) / sizeof( *test_images ) );  bitmap_to_float_array( input_buffer,  test_images[ rand() % num_test_images ] );  draw_input_buffer();   // Run our model  ...}

Если всё в порядке, ваш проект будет скомпонован и развёрнут, и вы увидите, как ваш микроконтроллер распознаёт все рукописные цифры и выдаёт отличные результаты! Верите?




Что дальше?


Теперь, когда вы узнали о возможностях маломощных микроконтроллеров ARM Cortex-M, позволяющих использовать возможности глубокого обучения с помощью TensorFlow, вы готовы сделать гораздо больше! От обнаружения животных и предметов различных типов до обучения устройства понимать речь или отвечать на вопросы вы со своим устройством можете открыть новые горизонты, которые ранее считались возможными только при использовании мощных компьютеров и устройств.

На GitHub доступны несколько потрясающих примеров TensorFlow Lite для микроконтроллеров, разработанных командой TensorFlow. Ознакомьтесь с этимирекомендациями, чтобы убедиться, что вы максимально эффективно используете свой проект ИИ, работающий на устройстве Arm Cortex-M. А если хотите прокачать себя в Machine Learning, Data Science или поднять уровень уже имеющихся знаний приходите учиться, будет сложно, но интересно.



image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR:

Подробнее..

Перевод Как классифицировать мусор с помощью Raspberry Pi и машинного обучения Arm NN

18.02.2021 20:14:00 | Автор: admin


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

Производительность таких решений сильно зависит от пропускной способности сети и задержки. Кроме того, отправка данных внешнему сервису может привести к проблемам с конфиденциальностью. В этой статье демонстрируется возможность переноса ИИ из облачной среды на периферию. Чтобы продемонстрировать ML с использованием периферийных ресурсов, мы будем использовать API-интерфейсы Arm NN для классификации изображений мусора с веб-камеры, подключённой к компьютеру Raspberry Pi, который покажет результаты классификации.



Arm NN и Arm Compute Library это библиотеки с открытым исходным кодом для оптимизации машинного обучения на процессорах Arm и оконечных устройствах Интернета вещей. Рабочие вычисления машинного обучения могут выполняться целиком на оконечных устройствах, что позволяет сложному программному обеспечению с поддержкой ИИ работать практически где угодно, даже без доступа к сети.

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



Что нам нужно для создания устройства и приложения?



  • Устройство Raspberry Pi. Урок проверен на устройствах Pi 2, Pi 3 и Pi 4 модели B.
  • Карту MicroSD.
  • Модуль камеры USB или MIPI для Raspberry Pi.
  • Чтобы создать собственную библиотеку Arm NN, также потребуется хост-компьютер Linux или компьютер с установленной виртуальной средой Linux.
  • Стекло, бумагу, картон, пластик, металл или любой другой мусор, который Raspberry Pi поможет вам классифицировать.



Конфигурация устройства


Я использовал Raspberry Pi 4 модель B с четырёхъядерным процессором ARM Cortex A72, встроенной памятью объёмом 1 ГБ, картой MicroSD объёмом 8 ГБ, аппаратным ключом WiFi и USB-камерой (Microsoft HD-3000).

Перед включением устройства необходимо установить ОС Raspbian на карту MicroSD, как описано в руководстве по настройке Raspberry Pi. Чтобы облегчить установку, я использовал установщик NOOBS.

Затем я загрузил Raspberry Pi, сконфигурировал Raspbian и настроил систему удалённого доступа к рабочему столу VNC для удалённого доступа к моему компьютеру Raspberry Pi. Подробные инструкции по настройке VNC можно найти на странице VNC (Virtual Network Computing) сайта RaspberryPi.org.

После настройки оборудования я занялся программным обеспечением. Данное решение состоит из трёх компонентов:
  • camera.hpp реализует вспомогательные методы захвата изображений с веб-камеры;
  • ml.hpp содержит методы загрузки модели машинного обучения и классификации изображений мусора на основе входных данных с камеры;
  • main.cpp содержит метод main, который объединяет указанные выше компоненты. Это точка входа в приложение.

Все эти компоненты обсуждаются ниже. Всё, что вы видите здесь, было создано с помощью редактора Geany, который по умолчанию устанавливается вместе с ОС Raspbian.

Настройка камеры


Для получения изображений с веб-камеры я использовал библиотеку OpenCV с открытым исходным кодом для компьютерного зрения. Эта библиотека предоставляет удобный интерфейс для захвата и обработки изображений. Один и тот же API-интерфейс легко использовать для различных приложений и устройств, от Интернета вещей до мобильных устройств и настольных ПК.
Самый простой способ включить OpenCV в свои приложения Raspbian для Интернета вещей установить пакет libopencv-dev с помощью программы apt-get:

sudo apt-get updatesudo apt-get upgradesudo apt-get install libopencv-dev

После загрузки и установки пакетов можно приступать к захвату изображений с веб-камеры. Я начал с реализации двух методов: grabFrame и showFrame (см. camera.hpp в сопутствующем коде):

Mat grabFrame(){  // Open default camera  VideoCapture cap(0);  // If camera was open, get the frame  Mat frame;  if (cap.isOpened())  {cap >> frame;imwrite("image.jpg", frame);   }  else  {printf("No valid camera\n");  }  return frame;} void showFrame(Mat frame){  if (!frame.empty())  {imshow("Image", frame);waitKey(0);  }}

Первый метод, grabFrame, открывает веб-камеру по умолчанию (индекс 0) и захватывает один кадр. Обратите внимание, что интерфейс C++ OpenCV для представления изображений использует класс Mat, поэтому grabFrame возвращает объекты этого типа. Доступ к необработанным данным изображения можно получить, считав элемент данных класса Mat.

Второй метод, showFrame, используется для отображения захваченного изображения. С этой целью в showFrame для создания окна, в котором отображается изображение, используется метод imshow из библиотеки OpenCV. Затем вызывается метод waitKey, чтобы окно изображения отображалось до тех пор, пока пользователь не нажмёт клавишу на клавиатуре. Время ожидания было указано с помощью параметра waitKey. Здесь использовалось бесконечное время ожидания, представленное значением 0.

Для тестирования указанных выше методов я вызвал их в методе main (main.cpp):

int main(){  // Grab image  Mat frame = grabFrame();   // Display image  showFrame(frame);   return 0;}

Для создания приложения я использовал команду g++ и связал библиотеки OpenCV посредством pkg-config:

g++ main.cpp -o trashClassifier 'pkg-config --cflags --libs opencv'

После этого я запустил приложение, чтобы захватить одно изображение:



Набор данных о мусоре и обучение модели


Модель классификации TensorFlow была обучена на основе набора данных, созданного Гэри Тунгом (Gary Thung) и доступного в его репозитории Github trashnet.

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

# Building the modelmodel = Sequential()# 3 convolutional layersmodel.add(Conv2D(32, (3, 3), input_shape = (IMG_HEIGHT, IMG_WIDTH, 3)))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(64, (3, 3)))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Conv2D(64, (3, 3)))model.add(Activation("relu"))model.add(MaxPooling2D(pool_size=(2,2)))model.add(Dropout(0.25))# 2 hidden layersmodel.add(Flatten())model.add(Dense(128))model.add(Activation("relu"))model.add(Dense(128))model.add(Activation("relu"))# The output layer with 6 neurons, for 6 classesmodel.add(Dense(6))model.add(Activation("softmax"))

Модель достигла точности около 83 %. С помощью преобразователя tf.lite.TFLiteConverter мы преобразовали её в формат TensorFlow Lite trash_model.tflite.

converter = tf.lite.TFLiteConverter.from_keras_model_file('model.h5') model = converter.convert()file = open('model.tflite' , 'wb') file.write(model)

Настройка пакета средств разработки Arm NN


Следующий шаг подготовка пакета средств разработки (SDK) Arm NN. При создании библиотеки Arm NN для Raspberry Pi можно последовать учебному руководству Cross-compile Arm NN and Tensorflow for the Raspberry Pi компании Arm или выполнить автоматический сценарий из репозитория Github Tool-Solutions компании Arm для кросс-компиляции пакета средств разработки. Двоичный tar-файл Arm NN 19.08 для Raspberry Pi можно найти на GitHub.

Независимо от выбранного подхода скопируйте полученный tar-файл (armnn-dist) в Raspberry Pi. В этом случае я использую VNC для передачи файлов между моим ПК для разработки и Raspberry Pi.

Затем задайте переменную среды LD_LIBRARY_PATH. Она должна указывать на подпапку armnn/lib в armnn-dist:

export LD_LIBRARY_PATH=/home/pi/armnn-dist/armnn/lib

Здесь я предполагаю, что armnn-dist находится в папке home/pi.

Использование Arm NN для получения логических выводов на основе машинного обучения на устройстве


Загрузка меток вывода модели


Для интерпретации выходных данных модели необходимо использовать метки вывода модели. В нашем коде мы создаём строковый вектор для хранения 6 классов.

const std::vector<std::string> modelOutputLabels = {"cardboard", "glass", "metal", "paper", "plastic", "trash"};

Загрузка и предварительная обработка входного изображения


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

На входе нашей модели находится слой Conversion 2D (преобразование 2D) с идентификатором conv2d_input. Её выход слой активации функции Softmax с идентификатором activation_5/Softmax. Свойства модели извлекаются с помощью Tensorboard, инструмента визуализации, предоставленного в TensorFlow для проверки модели.

const std::string inputName = "conv2d_input";const std::string outputName = "activation_5/Softmax";const unsigned int inputTensorWidth = 256;const unsigned int inputTensorHeight = 192;const unsigned int inputTensorBatchSize = 32;const armnn::DataLayout inputTensorDataLayout = armnn::DataLayout::NHWC;

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

// Load and preprocess input imageconst std::vector<TContainer> inputDataContainers ={ PrepareImageTensor<uint8_t>("image.jpg" , inputTensorWidth, inputTensorHeight, normParams, inputTensorBatchSize, inputTensorDataLayout) } ;

Вся логика, связанная с загрузкой модели машинного обучения и выполнением прогнозов, содержится в файле ml.hpp.

Создание синтаксического анализатора и загрузка сети


Следующий шаг при работе с Armn NN создание объекта синтаксического анализатора, который будет использоваться для загрузки файла сети. В Arm NN есть синтаксические анализаторы для файлов моделей различных типов, включая TFLite, ONNX, Caffe и т. д. Синтаксические анализаторы обрабатывают создание базового графа Arm NN, поэтому вам не нужно создавать граф модели вручную.

В этом примере используется модель TFLite, поэтому мы создаём синтаксический анализатор TfLite для загрузки модели, используя указанный путь.

Наиболее важный метод в ml.hpp это loadModelAndPredict. Сначала он создаёт синтаксический анализатор модели TensorFlow:

// Import the TensorFlow model. // Note: use CreateNetworkFromBinaryFile for .tflite files.armnnTfLiteParser::ITfLiteParserPtr parser =   armnnTfLiteParser::ITfLiteParser::Create();armnn::INetworkPtr network =   parser->CreateNetworkFromBinaryFile("trash_model.tflite");

Затем вызывается метод armnnTfLiteParser::ITfLiteParser::Create, синтаксический анализатор используется для загрузки файла trash_model.tflite.

После анализа модели создаются привязки к слоям с помощью метода GetNetworkInputBindingInfo/GetNetworkOutputBindingInfo:

// Find the binding points for the input and output nodesconst size_t subgraphId = 0;armnnTfParser::BindingPointInfo inputBindingInfo = parser->GetNetworkInputBindingInfo(subgraphId, inputName);armnnTfParser::BindingPointInfo outputBindingInfo = parser->GetNetworkOutputBindingInfo(subgraphId, outputName);

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

// Output tensor size is equal to the number of model output labelsconst unsigned int outputNumElements = modelOutputLabels.size();std::vector<TContainer> outputDataContainers = { std::vector<uint8_t>(outputNumElements)};

Выбор внутренних интерфейсов, создание среды выполнения и оптимизация модели


Необходимо оптимизировать сеть и загрузить её на вычислительное устройство. Пакет средств разработки Arm NN поддерживает внутренние интерфейсы оптимизированного выполнения на центральных процессорах Arm, графических процессорах Mali и устройствах DSP. Внутренние интерфейсы идентифицируются строкой, которая должна быть уникальной для всех выходных интерфейсов. Можно указать один или несколько внутренних интерфейсов в порядке предпочтения.

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

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

Как только это сделано, LoadNetwork создаёт характерные для внутреннего интерфейса рабочие нагрузки для слоёв, а также характерную для внутреннего интерфейса фабрику рабочих нагрузок и вызывает её для создания рабочих нагрузок. Входное изображение сворачивается с тензором типа const и ограничивается входным тензором.

// Optimize the network for a specific runtime compute // device, e.g. CpuAcc, GpuAccarmnn::IRuntime::CreationOptions options;armnn::IRuntimePtr runtime = armnn::IRuntime::Create(options);armnn::IOptimizedNetworkPtr optNet = armnn::Optimize(*network,   {armnn::Compute::CpuAcc, armnn::Compute::CpuRef},     runtime->GetDeviceSpec());

Механизм логического вывода в пакете Arm NN SDK предоставляет мост между существующими платформами нейронных сетей и центральными процессорами Arm Cortex-A, графическими процессорами Arm Mali и устройствами DSP. При получении логических выводов на основе машинного обучения с помощью Arm NN SDK алгоритмы машинного обучения оптимизируются для используемого оборудования.

После оптимизации сеть загружается в среду выполнения:

// Load the optimized network onto the runtime devicearmnn::NetworkId networkIdentifier;runtime->LoadNetwork(networkIdentifier, std::move(optNet));

Затем выполните прогнозы с помощью метода EnqueueWorkload:

// Predictarmnn::Status ret = runtime->EnqueueWorkload(networkIdentifier,  armnnUtils::MakeInputTensors(inputBindings, inputDataContainers),  armnnUtils::MakeOutputTensors(outputBindings, outputDataContainers));

На последнем шаге получаем результат прогнозирования.

std::vector<uint8_t> output = boost::get<std::vector<uint8_t>>(outputDataContainers[0]);size_t labelInd = std::distance(output.begin(), std::max_element(output.begin(), output.end()));std::cout << "Prediction: ";std::cout << modelOutputLabels[labelInd] << std::endl;

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

Объединение всех компонентов и создание приложения


Наконец, я собрал все компоненты вместе в методе main (main.cpp):

#include "camera.hpp"#include "ml.hpp" int main(){  // Grab frame from the camera  grabFrame(true);   // Load ML model and predict  loadModelAndPredict();   return 0;}

Обратите внимание, что у метода grabFrame есть дополнительный параметр. Если этот параметр имеет значение true, изображение камеры преобразуется в оттенки серого с изменением размеров до 256192 пикселей в соответствии с входным форматом модели машинного обучения, а затем преобразованное изображение передаётся методу loadModelAndPredict.
Для создания приложения требуется использовать команду g++ и связать библиотеку OpenCV и пакет Arm NN SDK:

g++ main.cpp -o trashClassifier 'pkg-config --cflags --libs opencv' -I/home/pi/armnn-dist/armnn/include -I/home/pi/armnn-dist/boost/include -L/home/pi/armnn-dist/armnn/lib -larmnn -lpthread -linferenceTest -lboost_system -lboost_filesystem -lboost_program_options -larmnnTfLiteParser -lprotobuf

Опять же, я предполагаю, что пакет Arm NN SDK находится в папке home/pi/armnn-dist. Запустите приложение и сделайте снимок какого-нибудь картона.

pi@raspberrypi:~/ $ ./trashClassifierArmNN v20190800Running network...Prediction: cardboard

Если во время выполнения приложения отображается сообщение error while loading shared libraries: libarmnn.so: cannot open shared object file: No such file or directory (ошибка при загрузке общих библиотек: libarmnn.so, не удаётся открыть общий объектный файл: нет такого файла или каталога), убедитесь, что ваша переменная среды LD_LIBRARY_PATH задана правильно.

Данное приложение также можно улучшить, реализовав запуск захвата и распознавания изображений по внешнему сигналу. Для этого требуется изменить метод loadAndPredict в модуле ml.hpp и отделить загрузку модели от прогнозирования (логического вывода). А если хотите прокачать себя в Data Science, Machine Learning или поднять уровень уже имеющихся знаний приходите учиться, будет сложно, но интересно.

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Как воскресить раннюю электронную музыку с помощью Arduino?

19.02.2021 16:11:01 | Автор: admin

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

В своём проекте с помощью микроконтроллера Arduino я смоделировал три винтажных тестовых генератора; весь проект можно собрать меньше чем за 15 фунтов стерлингов [около полутора тысяч рублей]. Исполнению не хватает эстетического очарования и аналогового звука реальных вещей, но я сохранил тактильное управление руками, которого нет в программных плагинах, и по самой его сути все потроха проекта можно хакнуть, отремонтировать и обновить.



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

Компоненты:


  • Один микроконтроллер Arduino X. Я воспользовался Nano, но заработать должен любой совместимый контроллер.
  • 2 резистора 1M Ом.
  • Резистор 3.9K Ом.
  • Конденсатор X 4.7 nF.
  • Выходной аудио разъём (6,3 мм или 3,5 мм).
  • 6 линейных потенциометров 10K.
  • 3 логарифмических потенциометра 10K.
  • 2 однополюсных однонаправленных переключателя.
  • USB-кабель питания.
  • Перфорированная плата Veroboard.
  • Гнездовая колодка (необязательно).

Чтобы загрузить ПО, вам также понадобится компьютер с установленной Arduino IDE. Схема достаточно проста для ручной проводки от точки до точки с помощью недорогой перфорированной платы. AudioPhonic Workbench хорошо работает от питания USB, поэтому никакого специального источника питания не потребуется.

Шаг 1. Начинаем


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

Пионеры ранней электронной музыки в своих творениях задействовали такие устройства, как вобуляторы и кольцевые модуляторы. Вобулятор использовал один осциллятор, чтобы изменять высоту тона второго осциллятора, разновидность частотной модуляции (ЧМ). На низких частотах так получается эффект вибрато, всё более диссонирующий на высоких частотах. Кольцевой модулятор позволяет одному осциллятору изменять громкость второго, этот процесс известен как амплитудная модуляция (AM). На низких частотах так рождается эффект тремело, который, опять же, всё более диссонирует, когда увеличивается частота модуляции. Audiophonic Workbench даёт как амплитудную, так и частотную модуляцию.


Выше показана передняя панель Audiophonic Workbench. Верхний ряд регуляторов управляет высотой звука каждого генератора, а нижний ряд громкостью. Две ручки в среднем ряду управляют модуляцией. Первая контролирует то, как Oscillator 1 модулирует Oscillator 2. Поворот по часовой стрелке увеличивает амплитудную модуляцию, а поворот против часовой стрелки частотную модуляцию. Вторая ручка в среднем ряду управляет тем, как Oscallator 2 модулирует Oscillator 3. Когда эти регуляторы расположены по центру, перекрёстной модуляции нет. Последние два элемента управления это переключатели скорости осциллятора. Они позволяют генераторам 1 и 2 действовать в качестве генераторов низкой частоты (LFO), создавая эффекты вибрато и тремело, о которых я рассказывал выше.

Шаг 2. Железо



Принципиальная схема проекта показана выше. Он состоит из 8 потенциометров, соединённых с 8-ю аналоговым входами Arduino, и 2 переключателей, подключённых к контактам цифровых входов, и RC-цепи для аудиовыхода.

Чтобы выводить звук, Audiophonic Workbench использует широтно-импульсную модуляцию (ШИМ), избегая необходимости в отдельном цифро-аналоговом преобразователе. Аудиотека Mozzi поддерживает режим HIFI PWM, который здесь применяется. Режим объединяет вывод двух выходов ШИМ, чтобы звук был качественнее. Включение HIFI PWM требует дополнительных усилий перед загрузкой кода. О них я написал в шаге 4.

Шаг 3. Воскрешение пульта



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


У всех потенциометров левые ножки соединены и подключены к выходу 5В на Arduino (выход 27). Точно так же правые контакты подключены и связаны с двумя тумблерами и GND на Arduino (контакт 29). Центральные ножки каждого потенциометра подключаются к аналоговым входам Arduino через тонкие проволочные выводы.

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


Я разместил гнездо аудиовыхода на задней панели коробки, но это только моё предпочтение. Также я просверлил большое отверстие в задней части, через которое USB-кабель проходит в коробку питания Arduino. При установке платы в корпус убедитесь, что у вас достаточно места, чтобы подключить USB-кабель.

Шаг 4. Загружаем и настраиваем Mozzi


В моём проекте для реализации осцилляторов используется библиотека синтеза звука Mozzi. Чтобы скомпилировать скетч, нужно скачать Mozzi и установить её в Arduino IDE. Загрузить библиотеку можно здесь

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

Аудио у ШИМ Arduino, как правило, имеет низкое качество, но Mozzi поддерживает режим HIFI PWM существенное улучшение стандартного звука ШИМ. Для этого используются два ШИМ-контакта и требуется один дополнительный резистор. Единственное осложнение: чтобы режим заработал, нужно изменить файл mozzi_config.h в библиотеке Mozzi, чтобы это работало.

Во-первых, найдите файл (на моём Linux он находится в /home/john/Arduino/libraries/Mozzi-master. Вам нужно будет отредактировать его.

Замените код

    //#define AUDIO_MODE STANDARD    #define AUDIO_MODE STANDARD_PLUS    //#define AUDIO_MODE HIFI

вот этим кодом:

    //#define AUDIO_MODE STANDARD    //#define AUDIO_MODE STANDARD_PLUS    #define AUDIO_MODE HIFI    

Изменить нужно начало файла, строка 27.

Шаг 5. Проверяем железо



Чтобы протестировать железо, можно скачать простой скетч с моего Github.

Скетч считывает значения каждого аналогового входа один раз в секунду. Они, вместе с двумя входами переключателя, отображаются монитором порта Arduino IDE, как показано выше. После загрузки скетча попробуйте по очереди повернуть каждый потенциометр и убедитесь, что значения изменяются от 0 до 1023. Скетч также генерирует тестовый сигнал на аудиовыходе. Чтобы генерация заработала, вы должны изменить файл mozzi-config.h, как я написал в предыдущем разделе.

Шаг 6. Програмная начинка


Весь код можно скачать с GitHub по этой ссылке.

Код довольно прост, но его нелегко понять, поскольку он оптимизирован с прицелом на скорость, а не на удобство чтения. Он был написан в манере встраивания и использует целочисленную арифметику с масштабированием данных, чтобы избежать числовых переполнений. Скетч создаёт три экземпляра осциллятора Моцци, используя волновую таблицу синусоидальной волны. Главный контур управления updateControl считывает потенциометры и переключатели 128 раз в секунду и соответственно обновляет ряд глобальных переменных. Цикл обработки звука updateAudio использует эти глобальные переменные, чтобы вычислить отдельные отсчёты для каждого генератора. Затем они смешиваются и выводятся. Не стесняйтесь экспериментировать с кодом, но помните, что цикл updateAudio вызывается 32768 раз в секунду. Код в нём должен выполняться быстро. Выход обработки за допустимые пределы вызовет треск и сбои в звуке.

Шаг 7. Как оно в деле?



Audiophonic Workbench поощряет эксперименты. Элементы управления спроектированы так, чтобы, пока громкость Oscillator 3 не установлена на ноль, всегда воспроизводить какой-то звук. Хотя этот звук может стать диссонирующим, он не должен давать сбоев или сильно искажённого вывода. Несколько настроек ручек и по пространству разносится стиль sci-fi с его пульсирующими ритмами.

Простые синусоиды значительно выигрывают от дополнительных звуковых эффектов. Оригинальная работа радиофонической мастерской во многом приобретает характер благодаря интенсивному использованию реверберации и эха. Идеально подойдёт педаль multi-fx я использую старую гитарную педаль Zoom. Программные эффекты плагинов отлично подходят для записи на компьютер. Эффекты винтажного стиля, такие как имитация Tape Echo и Spring Reverb, работают хорошо: они соответствуют звучанию 1960-х. Интересные тона также можно записать в сэмплер и проиграть с помощью обычной MIDI-клавиатуры. Возможные модификации переключатели, чтобы добиваться другой формы волны, ЦАП для высококачественного аудиовывода и MIDI-интерфейс, чтобы управлять высотой звука Oscillator 3.

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод 10 полезных расширений для дата-сайентистов

23.02.2021 14:15:47 | Автор: admin

Эти расширения Jupyter Notebook облегчают жизнь дата-сайентиста


Каждый специалист по Data Science тратит большую часть своего времени на визуализацию данных, их предварительную обработку и настройку модели на основе полученных результатов. Для каждого исследователя данных именно эти моменты самая сложная часть процесса, поскольку хорошую модель можно получить при условии, что вы точно выполните все эти три шага. И вот 10 очень полезных расширений Jupyter Notebook, которые помогут вам выполнить эти шаги.



1. Qgrid


Qgrid это виджет Jupyter Notebook, который использует SlickGrid, чтобы рендерить фреймы данных pandas в Jupyter Notebook. Это позволяет исследовать ваши фреймы данных с помощью интуитивно понятных элементов управления прокруткой, сортировкой и фильтрацией, а также редактировать фреймы, дважды щёлкая ячейки.


Установка


pip install qgrid #Installing with pipconda install qgrid #Installing with conda

2. itables


ITables превращает фреймы данных и серии pandas в интерактивные таблицы данных и в ваших блокнотах, и в их HTML-представлении. ITables применяет простой Javascript, из-за чего работает только в Jupyter Notebook, но не в JupyterLab.


Установка

pip install itables

Активируйте интерактивный режим для всех серий и фреймов данных вот так:

from itables import init_notebook_modeinit_notebook_mode(all_interactive=True)import world_bank_data as wbdf = wb.get_countries()df

3. Jupyter DataTables


Специалисты Data Science и многие разработчики ежедневно работают с dataframe, чтобы интерпретировать данные для обработки. Общий рабочий процесс заключается в отображении фрейма данных, взгляде на схему данных, а затем создании нескольких графиков, чтобы проверить, как распределяются данные, получив более чёткую картину, и, возможно, в том, чтобы найти новые данные в таблице и т. д.

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

Чтобы нарисовать таблицу, jupyter-datatables использует jupyter-require.



Установка

pip install jupyter-datatables

Как пользоваться расширением?


from jupyter_datatables import init_datatables_modeinit_datatables_mode()

4. ipyvolume


ipyvolume помогает в 3d-графике на Python в Jupyter, в качестве основы используя IPython и WebGL в нём.

Сегодня Ipyvolume может:

  • Сделать множественный объёмный рендеринг.
  • Отрисовать точечные диаграммы (до ~1 миллиона глифов).
  • Отрисовать графики колчана (например, разброс, но со стрелкой в определённом направлении).
  • Поддерживает произвольные области, которые вы рисуете мышью.
  • Рендерит в стереообъём для виртуальной реальности с помощью Google Cardboard.
  • Анимирует в стиле d3, например, если координаты x или цвет точечных диаграмм изменяются.
  • Анимация или последовательности, все свойства точечной диаграммы или quiver plot (векторный график) могут быть списком массивов, которые, в свою очередь, могут представлять снапшоты и т. д.



Установка

pip install ipyvolume #Installing with pipconda install -c conda-forge ipyvolume #Installing with conda

5. bqplot


bqplot это система визуализации в 2D для Jupyter, основанная на конструкциях Grammar of Graphics.



Задачи библиотеки


  • Полноценный фреймворк для 2D визуализаций с помощью API на Python.
  • Здравое API, чтобы добавлять пользовательские взаимодействия (панорамирование, масштабирование, выделение и т. д.).

Представлены два API

  • Пользователи могут создавать настраиваемые визуализации, используя внутреннюю объектную модель, которая вдохновлена конструкциями Gramamr of Graphics (рисунок, метки, оси, шкалы), и обогащать их визуализацию нашим слоем взаимодействий.
  • Или можно воспользоваться контекстным API, подобным pyplot у Matplotlib, который обеспечивает разумный выбор по умолчанию для большинства параметров.

Установка

pip install bqplot #Installing with pipconda install -c conda-forge bqplot #Installing with conda

6. livelossplot


Не обучайте модели глубокого обучения вслепую! Смотрите на каждую эпоху вашего обучения!

livelossplot предоставляет в Jupyter Notebook график потерь в реальном времени для моделей Keras, PyTorch и других фреймворков.



Установка

pip install livelossplot

Как пользоваться расширением?


from livelossplot import PlotLossesKerasmodel.fit(X_train, Y_train,epochs=10,validation_data=(X_test, Y_test),callbacks=[PlotLossesKeras()],verbose=0)

7. TensorWatch


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


Установка

pip install tensorwatch

8. Polyaxon


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



Установка

pip install -U polyaxon

9. handcalcs


handcalcs это библиотека для автоматического рендеринга кода вычислений Python в Latex, но таким образом, чтобы имитировать формат вычисления так, как если бы они были написаны карандашом: напишите символическую формулу, сопровождённую числовыми заменами, а затем результат.



Установка

pip install handcalcs

10. jupyternotify


jupyternotify предоставляет магическое значение %%notify, которое уведомляет пользователя о завершении потенциально длительной работы ячейки с помощью push-уведомлений браузера. Примеры применения содержат модели машинного обучения, которые долго обучаются, поиск по сетке или вычисления Spark. %%notify позволяет вам перейти к другой работе и получить уведомление в момент, когда ваша ячейка завершает работу.


Установка

pip install jupyternotify


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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Компульсивная жизнь разработчиков ПО или Почему весь кодинг немного навязчивый?

25.02.2021 14:18:30 | Автор: admin

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

Иногда мне приходит в голову, что программирование в силу необходимости навязчивая идея. В наших головах так много деталей я не уверен, что можно, в принципе, программировать без навязчивости. Программирование, как пишет в Smarter Than You Think, требует внимания к деталям и способности думать обо всём как о сериях процессов. Но оно требует не просто какого-то там внимания к деталям, оно требует интенсивного внимания к деталям. Одна шальная точка с запятой может поставить на колени миллионы строк и привести к чудовищному краху. Единственная функция с неврным возвратом сломает всю вашу внимательно прописанную логику. Как такая работа может требовать чего-то кроме навязчивости до такой степени, чтобы забывать пообедать?



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

Когда я ложусь в кровать, я всё так же вижу код. Мне снится код. Функции, классы, управляющие структуры. Иногда утром я просыпаюсь с решением упрямой проблемы, которая решалась в моей голове: я программирую, даже когда сплю!

Тем, кто пишет код, это знакомо. История возникновения Facebook, сколь бы неприятной она ни была, рассказанная в постах Цукерберга и в фильме Социальная сеть, о том, как мужчина провёл ночь над проблемами в коде (понятно, что его задачей было собрать изображения девушек с сайта колледжа, чтобы унизить их, но мы не можем винить в этом PHP). Код часто пишут одержимые.

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

Я говорю, что занимаюсь кодингом. Другие люди могут выражаться иначе, говорить о программной инженерии, программировании, разработке, хакинге. Есть жаркие, но шуточные дискуссии об определениях. Лично я называю процесс скриптингом. Самый распространённый сегодня язык JavaScript, в конце концов.

Скриптинг скромное определение. Оно останавливает меня от идей выше моего положения. Код это скрипт, которому должен следовать компьютер. Он заставляет компьютер делать вещи, которые можно в теории сделать вручную. Мы можем спросить водителя Uber рядом с нами, где он, и отметить его положение на карте. Приложение Uber с помощью скрипта автоматизирует ручные операции. Даёт компьютеру набор инструкций, чтобы он следовал им, участвовал в качестве точного до буквальности исполнителя. Скрипт описывает процесс, который у человека может занимать часы, но который может быть рассчитан компьютером за миллисекунды.

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

Не могу сказать, что я отличный кодер. Помню, как в детстве был поражён, когда написал магические слова, чтобы заставить компьютер выполнять мои приказы. Я чувствовал, что обманываю. Я не читал инструкции, не изучал компьютерные науки. Не знал, что такое кривые Безье и какие алгоритмы сортировки применять. Короче говоря, я не был настоящим инженером-программистом, я был дилетантом. Да, я знал, как делаются веб-сайты, базы данных, как пользоваться командной строкой и общаться с API, но это всё для достижения другой цели. Я не был истинным разработчиком.

Мы индустрия, страдающая синдромом самозванца, отчасти потому, что мы все самозванцы. Никто не знает всего и обо всём коде. Всегда найдётся кто-то ещё более одержимый, чем ты. Думаю, мы все боимся однажды стать целью тирады Линуса Торвальдса.

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

Сегодня я управляю командами. Моя работа составление бюджетов, управление и утверждение, а не объекты, функции и инкапсуляция. Я работаю скорее с PowerPoint, чем с PowerShell. Но уметь программировать значит, уметь говорить на другом языке. Это умение останется с вами. С помощью кода становится возможным то, что не сделаешь руками.

Я часто обнаруживаю себя пишущим код, чтобы решить проблемы, код, который соединяется со старыми системами и извлекает данные. Ручная работа такого рода отняла бы недели, но скрипты делают её за минуты. Мой код уродлив и неуправляем, такого зверя следовало бы запереть в подвале, но никому и не нужно видеть его. Всё, что нужно знать людям, это то, что задача, которая потребовала бы полгода, выполнится за время, пока они обедают.

Последняя неделя ещё один пример. Нужно было сделать работу, о которой скучно даже рассказывать. Я расчехлил Sublime Text и написал код. Он не выиграет наград, его не развернуть в системе большого масштаба и Торвальдса этим кодом тоже не впечатлить.

Когда я начинаю программировать, моя команда стонет: Босс снова взялся за дело кому-то приятно, что я свой. Другие, возможно, радуются, что я понимаю раздражение, преследующее программиста день за днём.

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

Код бросает ошибки, он подвержен авариям, перестаёт работать; делает то, чего я не ожидаю, по причинам, которых я не понимаю. Если я пишу variable вместо Variable, компьютер разводит руками, не понимая, о чём я говорю ему. Хм правда, компьютер? Со всем вашим кремнием, чипами, терафлопсами, неужели вы не можете разобраться?

Истина, принятая в кругу программистов, заключается в том, что программировать по большей части значит, биться головой о стену, гуглить ошибки, смотреть на StackOverflow, пробуя самые разные решения, пока не найдёшь то, которое работает. Так создавался современный мир. Баги это ситуации, которые при тестировании не возникли.

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

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

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

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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Избегайте рекурсии в Python вспомните о замыкании

25.02.2021 16:13:17 | Автор: admin


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

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

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



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

Что такое замыкание в Python?


Прежде всего позвольте мне на простом примере продемонстрировать, что такое замыкание в Python. Посмотрите на функцию ниже:

def outer():x = 1def inner():print(f'x in outer function: {x}')return inner

Функция outer определяется с функцией inner внутри, а функция outer возвращает функцию inner; именно она возвращаемое значение outer.

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


Что делает замыкание? Поскольку оно вернуло функцию, мы, конечно, можем запустить её.


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


Следовательно, мы также можем сказать, что в замыкании Python мы определили функцию, которая определяет функции.

Доступ к внешним переменным из внутренней функции


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

def outer():x = 1def inner():print(f'x in outer function (before modifying): {x}')x += 1print(f'x in outer function (after modifying): {x}')return inner

В замыкании выше мы хотим добавить 1 к внешней переменной x во внутренней функции. Это работает неочевидным образом.


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

def outer():x = 1def inner():nonlocal xprint(f'x in outer function (before modifying): {x}')x += 1print(f'x in outer function (after modifying): {x}')return inner

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

f = outer()for i in range(5):print(f'Run {i+1}')f()print('\n')


Фибоначчи с помощью замыкания


Фибоначчи обычно используется как пример рекурсивных функций, как рекурсивный Hello, World!. Напомню, о чём речь. Последовательность Фибоначчи это ряд чисел, каждое следующее число это сумма двух чисел перед ним. Первые два числа, X и X, особенные. Это 0 и 1. Значит, X, как упоминалось выше, это сумма X и X. И так далее [сократил].

Рекурсивная функция требует, чтобы мы мыслили в обратном порядке, от текущей ситуации к предыдущей ситуации и, в конечном счёте, об условии завершения рекурсии. При помощи замыкания можно думать о проблеме более естественным образом. В коде ниже показана реализация Фибоначчи через замыкание:

def fib():x1 = 0x2 = 1def get_next_number():nonlocal x1, x2x3 = x1 + x2x1, x2 = x2, x3return x3return get_next_number

Мы знаем, что Фибоначчи начинается с двух специальных чисел X = 0 и X = 1, поэтому просто определяем их во внешней функции. Затем внутренняя функция get_next_number просто возвращает сумму двух чисел, полученных от внешней функции. Кроме того, не забудьте обновить X и X с помощью X и X. Код можно упростить:

...x3 = x1 + x2x1, x2 = x2, x3return x3

Вот так:

x0, x1 = x1, x0 + x1return x1

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

fibonacci = fib()for i in range(2, 21):num = fibonacci()print(f'The {i}th Fibonacci number is {num}')




Сравниваем производительность


А как насчёт производительности? Давайте сравним! Сначала реализуем функцию Фибоначчи рекурсивно:

def fib_recursion(n):if n == 0:return 0elif n == 1:return 1else:return fib_recursion(n-1) + fib_recursion(n-2)

Функцию можно проверить: вывести 20-е число последовательности Фибоначчи.


Теперь напишем то же самое с замыканием.

def fib_closure(n):f = fib()for i in range(2, n+1):num = f()return num



Сравниваем скорость.


2,79 мс против 2,75 мкс. Замыкание в 1000 раз быстрее рекурсии! Интуитивно понятно: причина в том, что все временные значения для каждого уровня рекурсии хранятся в памяти отдельно, тогда как замыкание каждый раз обновляет одни и те же переменные. Кроме того, существует ограничение глубины рекурсии. В случае замыкания, поскольку это в основном цикл for, никаких ограничений нет. Вот пример получения 1000-го числа Фибоначчи.


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

Как ещё применять замыкание?


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

students = {'Alice': 98,'Bob': 67,'Chris': 85,'David': 75,'Ella': 54,'Fiona': 35,'Grace': 69}

Хочется иметь несколько функций, которые помогут нам фильтровать студентов по оценкам, помещать их в разные классы. Однако со временем критерии могут измениться. В этом случае можно определить замыкание Python, вот так:

def make_student_classifier(lower_bound, upper_bound):def classify_student(exam_dict):return {k:v for (k,v) in exam_dict.items() if lower_bound <= v < upper_bound}return classify_student

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

grade_A = make_student_classifier(80, 100)grade_B = make_student_classifier(70, 80)grade_C = make_student_classifier(50, 70)grade_D = make_student_classifier(0, 50)

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


Выглядит очень аккуратно! Но имейте в виду, что в более сложных случаях всё равно нужно определять классы.

Что в итоге?


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

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

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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Как машинное обучение помогает открыть мир Древней Японии

16.02.2021 18:22:34 | Автор: admin


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


Относительно недавно были обнаружены десятки тысяч глиняных таблеток из Древнего Вавилона [1], но только несколько сотен учёных могут их перевести. Подавляющее большинство этих документов никогда не были прочитаны, даже если они были обнаружены в XIX веке. В качестве дополнительной иллюстрации задачи такого масштаба: в 1851 году в ходе экспедиции была собрана табличка из Повести о Гильгамеше, но о её значении стало известно лишь в 1872 году. Эта табличка содержит добиблейское повествование о потопе, имеющее огромное культурное значение как предвестник повествования о Ноевом ковчеге. Это глобальная проблема, но одним из наиболее ярких примеров является случай Японии.

С 800 до 1900 года нашей эры в Японии использовалась система письма под названием кудзусидзи, которую исключили из учебной программы в 1900 году, когда было реформировано начальное школьное образование. В настоящее время подавляющее большинство говорящих на японском языке не умеют читать тексты, которым более 150 лет. Объём этих текстов, состоящий из более чем трёх миллионов книг, но читаемый лишь горсткой учёных, прошедших специальное обучение, поражает. Только в одной библиотеке оцифровано 20 миллионов страниц таких документов. Общее количество (включая письма и личные дневники, но не ограничиваясь ими) оценивается более чем в миллиард документов. Учитывая, что очень немногие люди могут понять эти тексты (в основном имеющие докторскую степень по классической японской литературе и японской истории), было бы очень дорого и затратно в смысле времени финансировать учёных для перевода этих документов на современный японский язык. Это мотивировало использовать машинное обучение, чтобы разобраться в таких текстах автоматически.

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

Учитывая значение кудзусидзи для японской культуры, задачу использования компьютеров для содействия распознаванию кудзусидзи тщательно изучили в [2] посредством использования различных методов в глубоком обучении и компьютерного зрения. Однако эти модели не смогли достичь высоких показателей распознавания кудсусидзи. Это было вызвано недостаточным пониманием японской исторической литературы в сообществе оптического распознавания символов (OCR) и отсутствием стандартизированных наборов данных высокого качества.

Для решения этой проблемы Национальный институт японской литературы (NIJL) создал и выпустил набор данных кудзусидзи, курируемый Центром открытых данных в области гуманитарных наук (CODH). В настоящее время набор данных содержит более 4000 классов символов и миллион символьных изображений. До выхода этого набора данных кудзусидзи исследователи OCR пытались создавать наборы данных самостоятельно. Однако количество символов было очень ограниченным, что заставляло их модели работать плохо, когда они оценивались по всему спектру данных. NIJL-CODH решил эту проблему, предоставив большой и полный набор данных кудзусидзи для обучения и оценки модели.

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

  • Большое значение имеет учёт как локального, так и глобального контекста. В связи с тем, что некоторые символы написаны в зависимости от контекста, при классификации важно учитывать несколько символов, а не рассматривать каждый символ в отдельности.
  • Общее количество символов в словаре очень велико. В частности, набор данных NIJL-CODH содержит более 4300 символов, на самом же деле их гораздо больше. Более того, набор данных следует распределению длинный хвост, поэтому в наборе данных, содержащем 44 книги, много символов, которые появляются лишь несколько раз или даже один раз.
  • Многие символы могут быть написаны несколькими способами на основе хентайганы. Хэнтайгана это старый способ написания хираганы или японских фонетических иероглифов с такой спецификой, что сегодня многие иероглифы могут быть нанесены на один иероглиф. Для современных японских читателей принципы хэнтайганы представляются сложными для понимания.
  • Тексты кудзусидзи часто пишутся вместе с иллюстрациями и замысловатыми фонами, которые трудно чисто отделить от текста. Они распространены потому, что самой популярной системой печати в современной Японии была печать на ксилографии, которая включает в себя резьбу по целому куску дерева вместе с иллюстрациями. Поэтому макет страницы может быть сложным и художественным, и не всегда его легко представить в виде последовательности.

Техника печати по дереву с использованием чернил и кисти

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

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

Образец стиля письма Чирасигаки в документе кудзусидзи

KuroNet


KuroNet это транскрипционная модель кудзусидзи, которую я разработал совместно с моими коллегами Тарином Клануватом и Асанобу Китамото из Центра открытых данных в гуманитарных науках ROIS-DS при Национальном институте информатики в Японии. Метод KuroNet мотивирован идеей обработки всей страницы текста целиком с целью захвата как большого диапазона, так и локальных зависимостей. KuroNet передаёт изображения, содержащие целую страницу текста, через остаточную архитектуру U-Net (FusionNet) для получения представления признака. Однако общее количество классов символов в нашем наборе данных относительно велико и насчитывает более 4300. Поэтому мы обнаружили, что прогнозирование точного символа в каждой позиции было слишком дорогостоящим с вычислительной точки зрения, и в надежде решить эту проблему ввели аппроксимацию, которая изначально оценивает, содержит ли некая пространственная позиция символ. Оттуда KuroNet рассчитывает только относительно дорогой классификатор символов в позициях, которые содержат символы, в соответствии с наблюдаемой истиной. Эта методика, являющаяся примером Teacher Forcing [обучения с принуждением], помогает значительно снизить использование памяти и сократить вычисления.

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

Работа [3], в которой интерполировали небольшое количество в направлении случайных различных примеров, сохраняя при этом исходную метку. Многие книги написаны на относительно тонкой бумаге, поэтому содержание соседней страницы часто слабо просматривается через бумагу. Изображения, создаваемые Mixup, выглядят несколько похожими на изображения, где слабо просматривается содержимое соседней страницы. Таким образом, Mixup может иметь дополнительное преимущество, помогая побудить модель игнорировать соседнюю страницу.

Для получения дополнительной информации о KuroNet, пожалуйста, ознакомьтесь с нашей работой KuroNet: Pre-Modern Japanese Kuzushiji Character Recognition with Deep Learning, которая была принята на Международной конференции по анализу и распознаванию документов (ICDAR) в 2019 году. [4].

Примеры транскрипции KuroNet на страницах со значением F1 выше 0,9

KuroNet может транскрибировать целую страницу кудзусидзи со средним временем 1,2 секунды на страницу, включая конвейер постобработки, который не оптимизировался тщательно. Несмотря на то что производительность всё ещё сильно различается на разных книгах, мы обнаружили, что ксилографические печатные книги периода Эдо (XVIIXIX веков) это те книги, на которых KuroNet показывает хорошие результаты. Мы обнаружили, что модель борется с необычными размерами и редкими символами. Кроме того, мы оценили модель на контрольном наборе страниц из различных книг и обнаружили, что худшими книгами оказались словари, содержащие много необычных символов, и кулинарная книга с множеством иллюстраций и необычных макетов.

Конкурс по распознаванию кудзусидзи на Kaggle



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

В конечном счёте после трёх месяцев соревнований, в которых приняли участие 293 команды, 338 участников и 2652 заявки, победитель получил оценку F1 в 0,950 баллов. Когда мы оценивали KuroNet в тех же обстоятельствах, то обнаружили, что она получила оценку F1 0,902, с ней нейросеть оказалась бы на двенадцатом месте, что, хотя и приемлемо, намного ниже лучших решений.

Финал конкурса Распознавание кудзусидзи на Kaggle (топ-10)

Есть несколько важных уроков, которые мы извлекли из этого конкурса:

  • Некоторые существующие алгоритмы обнаружения объектов достаточно хорошо работают над этой задачей, даже когда применяются как есть, из коробки. Например, Faster R-CNN и Cascade R-CNN дали отличные результаты без модификаций или каких-либо специфических для кудзусидзи приёмов. Учитывая то, насколько распознавание со страниц с кудзусидзи отличаются от обычных задач по обнаружению объектов, было довольно удивительно, что эти нейросети справляются так хорошо.
  • В то же время другие методы без модификации работают плохо. Например, You Only Look Once (YOLO) выполнил задачу довольно плохо, несмотря на значительные усилия. Другие методики, использующие CenterNet, работали хорошо, но требовали больших усилий и специфической для домена настройки, чтобы заставить их работать.
  • Несколько ведущих подходов имели модели, которые выполняли обнаружение и классификацию совместно. Которые не использовали искусные методы включения окружающих символов в своём классификационном конвейере.
  • Лишь немногие из лучших решений использовали языковые модели или пытались трактовать символы как последовательность.

Будущие исследования


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

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

Работа [5] фокусируется именно на этой проблеме.

Ещё одна интересная открытая проблема возникает из-за того, что все предложенные методы только конвертируют документы кудзусидзи в современный японский шрифт. Это делает отдельные символы узнаваемыми, но весь текст по-прежнему довольно трудно читать. Из разговоров с носителями японского языка у меня сложилось впечатление, что обычный японец сможет читать, но это умеренно труднее, чем для современных англоговорящих людей читать Шекспира. Таким образом, захватывающей и самой открытой проблемой машинного обучения будет преобразование старого языка в лексику и грамматику современного японского. Эту проблему можно решить, так как часто устаревшее слово можно заменить более современным, но также эта проблема очень глубокая, поскольку правильно перевести поэзию и красивую прозу с её многочисленными нюансами может быть почти невозможно. Кроме того, отсутствие (или небольшой объем) чётко согласованных парных данных из классического и современного японского может мотивировать воспользоваться недавними исследованиями неконтролируемого машинного перевода с низким уровнем ресурсов.

Я считаю, что это одно из самых эффективных приложений для машинного обучения сегодня, и для достижения прогресса потребуется сотрудничество как между теми, кто имеет опыт работы с историческими документами в конкретной предметной области, так и исследователями прикладного машинного обучения, а также исследователями базовых алгоритмов ML. Это требует междисциплинарных усилий. Историки могут помочь определить наиболее важные подзадачи и интуитивно судить о том, действительно ли полезны метрики. Исследователи прикладного машинного обучения могут создавать модели для оптимизации этих показателей и выявления недостатков современных алгоритмов. Исследователи базового машинного обучения могут помочь улучшить алгоритмы. Например, наша работа по японскому языку требует более совершенных алгоритмов для Few-shot Learning, а также лучшего обобщения для меняющейся среды, и обе эти проблемы всё более широко изучаются в сообществе исследователей ML.

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

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




image
Подробнее..

Перевод Как избежать парадокса убитого дедушки или Квантовая механика решает загадки путешествия во времени

19.02.2021 14:12:20 | Автор: admin

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

Эта дилемма, известная как парадокс убитого дедушки, отражает главное возражение философов и физиков против путешествий во времени возможное нарушение причинности. В то время как само путешествие во времени остаётся в области чистой спекуляции, возможные результаты нарушения принципа причинности и то, как природа может предотвратить их, являются горячо обсуждаемыми темами, с такими известными физиками и философами, как Стивен Хокинг и Кип Торн, размышляющими о возможных решениях. Возможно ли, что многомировая интерпретация квантовой механики может спасти несчастного (и неуклюжего) путешественника во времени?



Что такое парадокс убитого дедушки, и почему он так важен?


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

Фрай, неуклюжий главный герой Футурамы Мэтта Грейнинга, имел довольно неудачную встречу со своими дедушкой и бабушкой в титулованном эпизоде Розуэлл, который хорошо кончается

Чтобы рассмотреть этот парадокс, давайте представим себе ситуацию, в которой одарённый молодой изобретатель Марти создаёт машину времени в 2018 году. Поскольку Марти никогда не видел своего деда, он решает совершить путешествие в прошлое, чтобы встретиться с ним. После тщательного исследования Марти выясняет, где именно будет находиться его дед, ещё молодой и бездетный, 23 ноября 1963 года. Он входит в свою машину и начинает путешествие в прошлое.

Набросок путешествия Марти, если мы допустим существование только одной мировой линии

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

Решение дилеммы Марти?


Физики и философы размышляли над несколькими решениями этого парадокса. Принцип самосогласованности Новикова, также известный как Закон сохранения истории Нивена, разработанный русским физиком Игорем Дмитриевичем Новиковым в конце 1970-х годов (Эволюция Вселенной (1979)), предложил использовать геодезические (аналогичные тем, которые используются для описания кривизны пространства в общей теории относительности Эйнштейна) для описания кривизны времени. Эти замкнутые временные кривые (CTCS) предотвратили бы нарушение любых причинно-связанных событий, лежащих на одной и той же кривой. Подход также предполагает, что путешествие во времени возможно только в тех областях, где эти временные кривые существуют, например в червоточинах, как предположил Кип Торн и его коллеги в статье 1988 года Червоточины, машины времени и состояние слабой энергии. События будут цикличными и самосогласованными. Это подразумевает, что путешественники во времени не смогут изменить прошлое, независимо от того, физически ли им препятствуют или они действительно не имеют возможности сделать это. Поэтому, как бы Марти ни старался, он не смог бы приземлить свою машину именно в этом месте, даже если бы намеревался убить своего деда.

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

Визуальное представление решения Эчеверрии и Клинкхаммера (Brightroundircle)

Итак, согласно теории Новикова, любые действия, предпринимаемые путешественником во времени, просто становятся частью ранее существовавшей истории, и наблюдателям запрещается видеть эти события из-за так называемого горизонта Коши.

Вернувшись в 2018 год, наш герой Марти обнаруживает, что его семейный дом исчез, как и все следы его существования. Читая о теории Новикова и пересекающихся бильярдных шарах, он проклинает бездеятельность Вселенной. Именно в этот момент он понимает, что, возможно, Вселенная не вмешивалась, поскольку для этого требовалось какое-то другое корректирующее действие. Вдохновлённый статьёй о столкновении бильярдных шаров, он мчится к своей машине времени, чтобы помешать себе и спасти собственное будущее.

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

Есть ли более экономное решение парадокса убитого дедушки, основанное на ранее существовавших аспектах физики, введённых другими теориями или дисциплинами?

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

Многомировая интерпретация квантовой механики


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

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

Электроны, выпущенные по отдельности, начинают создавать характерную интерференционную картину на экране за пределами двух щелей

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

Эверетт задал другой вопрос. Коллапсирует ли вообще волновая функция?


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

Это значит, что когда Марти вернётся в 1963 год, произойдет раскол. Он больше не в том мире, из которого пришёл, назовём его Миром 1. Вместо этого он создал новый мир. Когда он путешествует вперёд во времени, он путешествует по временной шкале этого мира. Он никогда не существовал в этом мире и, по правде говоря, не убивал своего деда. Его дед существует в целости и сохранности ещё в 1963 году в Мире 1.


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

Итак, что происходит, когда Марти возвращается в прошлое в попытке спасти свой мир? Он непреднамеренно создаёт другое состояние, Мир 3. Этот мир может походить на Мир 1 почти всеми мыслимыми способами, но, согласно применению интерпретации, он не является тем же самым из-за одного события. Столкновение двух машин времени 23 ноября 1963 года.

Если Марти снова попытается вернуться в 1963 год, чтобы исправить первоначальное вмешательство, он просто создаст другое состояние, Мир 3

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

Заключение


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

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

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

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

Оказывается, Марти было легко.

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Мы уже знаем, как построить машину времени

24.02.2021 18:11:35 | Автор: admin

Это всего лишь вопрос времени, когда мы построим то, что сможет перенести нас в далёкое будущее.

В сентябре 2015 года космонавт Геннадий Падалка в последний раз вернулся на Землю. Он только что завершил свою шестую миссию в космосе и побил рекорд общего времени, проведённого за пределами атмосферы Земли: 879 дней. И из-за этих 2,5 лет, проведённых на орбите планеты на высоких скоростях, Падалка также стал путешественником во времени, испытывая общую теорию относительности Эйнштейна в действии.

Когда г-н Падалка вернулся, он обнаружил, что Земля находится на 1/44 секунды в будущем, объясняет Дж. Ричард Готт, физик из Принстона и автор книги Time Travel in Einsteins Universe, Он буквально путешествовал в будущее. Быть на долю секунды моложе, чем если бы он остался на Земле, не является чем-то невероятным, тем не менее это дало Падалке звание нынешнего рекорда путешественника во времени, согласно Готту.

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



Ускоренный курс путешествия во времени


image

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

Пока не появился 26-летний Альберт Эйнштейн.

В 1905 году Эйнштейн раскрыл свои идеи по особой теории относительности, используя эту основу для своей теории общей теории относительности десять лет спустя. Расчёты Эйнштейна, определяющие Вселенную, ввели много вещей, а также некоторые понятия, связанные со временем. Самое главное что время эластично и зависит от скорости, замедляется или ускоряется в зависимости от того, насколько быстро движется объект или человек.

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

Без общей теории относительности Эйнштейна не будет работать GPS.

Без общей теории относительности Эйнштейна наша система GPS не будет работать, рассказывает Рон Маллет, астрофизик и автор книги Time Traveler: A Scientist's Personal Mission to Make Time Travel a Reality. Это также доказательство того, что теории Эйнштейна верны".

Но помимо этой изменчивой версии времени Эйнштейн также рассчитал скорость света. Скорость 300 000 000 метров (или 186 282 миль) в секунду Эйнштейн описывает как предел скорости и универсальную константу, независимо от того, сидит ли человек на скамейке или путешествует на ракетном корабле.

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

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

Субатомная машина времени


image


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

Возвращаясь к нашему путешествующего во времени космонавту Падалке, его 1/44-секундный прыжок в будущее настолько мизерный, потому что он перемещался со скоростью всего 17000 миль в час. Это не очень быстро, по крайней мере по сравнению со скоростью света. Но что произойдёт, если мы создадим что-то, что может двигаться гораздо быстрее, чем на геостационарной орбите? Речь идёт не о коммерческом лайнере (550600 миль в час) или ракете ХХI века, летящей к МКС (25 000 миль в час), а о том, что может приблизить к 186 282 милям в секунду.

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

Ускоритель элементарных частиц способен перемещать протоны со скоростью 99,999999 процентов от скорости света, скорости, с которой их относительное время движется примерно в 6900 раз медленнее по сравнению со временем их стационарных наблюдателей людей.

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

Готт поясняет: учитывая, что мы регулярно разгоняем частицы почти до скоростью света, концептуально для людей довольно просто путешествовать во времени в будущее. Если вы хотите посетить Землю в 3000 году, говорит Готт, всё, что вам нужно сделать, это сесть на космический корабль и полететь со скоростью в 99,995 процентов от скорости света.

Допустим, человека посадили на такой корабль и отправили на планету, которая находится на расстоянии немногим менее 500 световых лет (например, Кеплер 186f), то есть, если бы он путешествовал со скоростью 99,995 % от скорости света, нужно было бы 500 лет, чтобы добраться туда, так как корабль летит почти со скоростью света.

image


После быстрого перекуса и перерыва в ванной комнате они развернулись и направились обратно на Землю, что заняло ещё 500 лет. Таким образом, в общей сложности нужно около тысячи лет, чтобы благополучно вернуться домой. На Земле это будет 3018 год.

Однако, поскольку корабль двигался так быстро, результирующее замедление времени не могло показаться им тысячей лет с того момента, как их внутренние часы замедлились. [Их] часы будут отсчитывать 1/100 от скорости часов на Земле. Для них пройдет только 10 лет, говорит Готт. Для нас пройдёт тысячелетие, для них это будет десятилетие.

Если бы мы [на Земле] смотрели в окно, они бы завтракали очень медленно, говорит Готт, тогда как для [них] всё было бы нормально.

Но существует огромная пропасть между теоретическим и реальным. Так как же нам преодолеть огромные технологические проблемы создания машины времени?

Не столь отдалённое будущее путешествий во времени


image


Датчик Parker Solar Probe будет развивать скорость 430 000 миль в час это быстро, но далеко до скорости света.

Строительство космического корабля, путешествующего во времени, может быть лучшим местом для начала, но инженерные препятствия, по крайней мере сейчас, огромны. Во-первых, мы даже близко не приблизились к космическому кораблю, который может путешествовать со скоростью света. Самым быстрым космическим кораблем из когда-либо созданных скоро станет Parker Solar Probe, который будет запущен этим летом и будет двигаться скоростью всего 0,00067% от скорости света.

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

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

Затем есть всё, что связано с ускорением. Чтобы гарантировать, что наш гипотетический путешественник не будет уничтожен подавляющими силами перегрузки, корабль должен постепенно и неуклонно ускоряться. Хотя постоянное ускорение в 1g (подобное тому, что мы ощущаем на Земле) в течение длительного периода в конечном счёте приведёт к тому, что корабль приблизится к скорости, близкой к скорости света, оно увеличит продолжительность полёта и минимизирует то, как далеко можно уйти в будущее.

Проблема обратного движения




Но у этого теоретического портрета реального путешествия во времени есть один большой недостаток эта машина не движется вспять. В то время как Билл и Тед путешествуют в прошлое, чтобы встретить Сократа, на самом деле учёным и исследователям нужно найти способ обойти законы физики, чтобы отправиться в прошлое.

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

Технологии не за горами Мы могли бы сделать это в ближайшие 20 лет.

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

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



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

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

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

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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Перевод Почему алгоритмы так ML трудно настраивать?

20.02.2021 16:15:19 | Автор: admin


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

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



В этом посте мы надеемся изложить следующие аргументы:

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

Линейные комбинации потерь повсюду


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

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



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



Кроме того, вы можете увидеть такое множество целей в обучении с подкреплением. Мало того, что во многих средах принято просто суммировать очки, полученные за достижение частичных целей. Функции потерь обычно также представляют собой линейную комбинацию потерь. Возьмём в качестве примера потери в PPO, SAC и MPO, энтропийно регуляризованных методов с их перестраиваемым параметром .




Наконец, GAN-потери сумма между дискриминатором и потерями генератора:



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

В этой статье мы надеемся показать вам, что такой подход к объединению потерь может показаться привлекательным, но эта линейная комбинация на самом деле ненадёжна и коварна. Балансировка часто похожа на хождение по канату.

Наш маленький пример


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


Наш код в Jax будет выглядеть примерно так:

def loss():return loss_1() + loss_2()loss_derivative = grad(loss)for gradient_step in range(200):gradient = loss_derivative() =  - 0.02 * gradient

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

def loss(, ):return loss_1() + *loss_2()loss_derivative = grad(loss)for gradient_step in range(200):gradient = loss_derivative(, =0.5) =  - 0.02 * gradient

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

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


Похоже, что независимо от того, как мы точно настроим наш -параметр, мы не сможем найти хороший компромисс между нашими двумя потерями


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

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

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

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

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



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

Почему не удаётся оптимизировать градиентный спуск для вогнутых фронтов Парето?


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

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


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


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


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

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

Какие проблемы вызывают эти линейные комбинации?


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

  • Во-первых, даже если вы не вводите гиперпараметр для взвешивания между потерями, неправильно говорить, что градиентный спуск будет пытаться сбалансировать противодействующие силы. В зависимости от решений, достижимых с помощью вашей модели, она вполне может полностью игнорировать одну из потерь, чтобы сосредоточиться на другой, или, наоборот, в зависимости от того, где вы инициализировали модель.
  • Во-вторых, даже когда вводится гиперпараметр, он настраивается методом проб и ошибок. Вы запускаете полный процесс оптимизации, решаете, довольны ли вы, а затем настраиваете свой гиперпараметр. Вы повторяете этот цикл оптимизации, пока не будете довольны производительностью. Это расточительный и трудоёмкий подход, обычно включающий несколько итераций бегового градиентного спуска.
  • В-третьих, гиперпараметр не может настраиваться на все оптимумы. Независимо от того, насколько хорошо вы настраиваете гиперпараметры, вы не найдёте промежуточных решений, которые могут вас заинтересовать. Не потому, что они не существуют, а они наверняка существуют, а потому, что был выбран плохой подход для объединения этих потерь.
  • В-четвёртых, важно подчеркнуть, что для практических приложений всегда неизвестно, является ли фронт Парето выпуклым и, следовательно, можно ли настраивать эти веса потерь. Являются ли они хорошими гиперпараметрами, зависит от того, как параметризована ваша модель и как это влияет на кривую Парето. Однако визуализировать или анализировать кривую Парето для какого-либо практического применения невозможно. Визуализировать это значительно сложнее, чем нашу первоначальную задачу оптимизации. Так что, если возникнет проблема, она останется незамеченной.
  • Наконец, если вы действительно хотите использовать эти линейные веса для поиска компромиссов, вам нужно явное доказательство того, что вся кривая Парето является выпуклой для конкретной используемой модели. Поэтому использования выпуклых потерь по сравнению с выходными данными вашей модели недостаточно, чтобы избежать проблемы. Если ваше пространство параметризации велико, что всегда имеет место, если ваша оптимизация включает веса внутри нейронной сети, вы можете забыть о попытках такого доказательства. Важно подчеркнуть, что демонстрации выпуклости кривой Парето для этих потерь на основе некоторых промежуточных скрытых значений недостаточно, чтобы показать, что у вас есть настраиваемый параметр. Выпуклость действительно должна зависеть от пространства параметров и от того, как выглядит фронт Парето достижимых решений.

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


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


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

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

image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Шахматные алгоритмы, которые думают почти так же, как человек, только лучше

26.02.2021 16:11:32 | Автор: admin

Когда создавались первые вычислительные машины, их воспринимали только как дополнение к человеческому разуму. И до недавнего времени так и было. Программисты учили компьютеры играть в шахматы с 1960-х годов. И тогда победа у игрока-новичка уже считалась большим прогрессом. О серьёзных матчах даже не задумывались.

В 1980-х программа Belle достигла рейтинга Эло в 2250 пунктов, что примерно соответствует рейтингу мастера спорта. И с того времени развитие компьютерных шахмат вышло на совершенно новый уровень.

Сначала честь человечества не смог защитить Гарри Каспаров в 1996 году, а сегодня уже создана нейросеть с рейтингом около 5000 Эло, что в разы превосходит даже сильнейших игроков.

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


Как работает шахматный движок: от механического перебора вариантов до умного выбора

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

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

Общее количество уникальных партий в шахматы составляет примерно 10120, что на 1040 превышает количество атомов во Вселенной.

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

В шахматной теории у каждой фигуры есть своя ценность, которая измеряется в пешках:

  • Конь 3 пешки;

  • Слон 3 пешки;

  • Ладья 5 пешек;

  • Ферзь 9 пешек;

  • Пешка 1 пешка.

Король бесценен, потому что его потеря означает проигрыш партии.

Анализ современных машин подтверждает истинность такой оценки. Так, в зависимости от позиции на доске компьютер оценивает ферзя в 912 пешек, ладью в 56, коня и слона в 35. Короля же машина оценивает в 300 пешек. Это задаёт максимальную границу оценки.

Анализ современных машин подтверждает истинность такой оценки. Так, в зависимости от позиции на доске компьютер оценивает ферзя в 912 пешек, ладью в 56, коня и слона в 35. Короля же машина оценивает в 300 пешек. Это задаёт максимальную границу оценки.

Чтобы было более понятно, преимущество в 0,5 пешки это уже неплохо для шахматиста. В целую пешку серьёзный перевес. В 3 пешки подавляющее преимущество, которое можно практически без проблем довести до победы.

Но счётные возможности машины ограниченны. Иногда она показывает оценку в +51 или что-то вроде. Это означает, что алгоритм видит колоссальное преимущество белых в позиции и материале, но не может найти конкретный путь к мату.

Минимакс, или прямой перебор вариантов, в таком случае не работает. Даже КМС без проблем найдёт на доске мат в 3 хода в миттельшпиле, когда на доске ещё много фигур. А программе для этого нужно будет перебрать свыше 750 млн. полуходов.

Даже если программа перебирает 1 млн вариантов в секунду, чтобы найти мат в 3 хода, ей понадобится до 750 секунд, или 12,5 минут.

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

Поэтому для анализа позиции используется алгоритм под названием альфа-бета-отсечение.

Система анализирует начальные варианты ходов и сразу отсекает те из них, которые ведут к мгновенному ухудшению оценки.

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

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

В варианте кода это может быть реализовано примерно следующим образом:

function alphabeta(node, depth, , , maximizingPlayer) is    if depth = 0 or node is a terminal node then        return the heuristic value of node    if maximizingPlayer then        value :=         for each child of node do            value := max(value, alphabeta(child, depth  1, , , FALSE))             := max(, value)            if    then                break (*  cutoff *)        return value    else        value := +        for each child of node do            value := min(value, alphabeta(child, depth  1, , , TRUE))             := min(, value)            if    then                break (*  cutoff *)        return value

За код особо не ругайте.

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

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

После ответа соперника ситуация снова анализируется по тому же алгоритму. Сначала отсекаются заведомо проигрышные линии (таких порядка 95 %), а затем путём более глубокого анализа перспективных вариантов выбирается лучший из них.

Новая эра в шахматных движках: нейросеть Alpha Zero

В 2017 году компания Deep Mind объявила о создании нейросети Alpha Zero. Тестировать её решили на трёх самых популярных стратегических настольных играх: шахматы, го и сёги.

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

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

Alpha Zero не использует ничего, кроме правил. Ей просто дали стартовую позицию, объяснили, как ходят фигуры, и цель игры поставить мат сопернику. И всё.

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

В декабре 2018 года Alpha Zero во второй раз сразилась с самой последней версией движка Stockfish.

Исследователи провели 1000 партий с контролем 3 часа на партию плюс 15 секунд на ход.Alpha Zero одержала уверенную победу, выиграв в 155 партиях, сыграв вничью 839 партий и проиграв только 6.

Более того, Alpha Zero одерживала победу даже в партиях с форой по времени на обдумывание. Имея в 10 раз меньше времени, чем у противника, нейросеть всё равно победила в суммарном итоге. Только 30-кратная фора во времени смогла уравнять шансы и дать Stockfish примерно равную игру 3 часа у движка и всего лишь 6 минут у нейросети.

Alpha Zero анализирует лишь 60 000 позиций в секунду, а тестируемая версия Stockfish 60 млн. позиций. Для достижения аналогичных результатов анализа нейросети нужно в 1000 раз меньше ресурсов, чем движку.

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

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

И, что гораздо более важно, при оценке ситуации Alpha Zero учитывает стратегическую позицию.

Давайте рассмотрим на примере одной из партий.

После 20-го хода на доске творится невообразимая стратегическая борьба. Но если нейросеть шаг за шагом минимально укрепляет свою позицию, избавляясь даже от призрачных слабостей, то движок с 24-го по 29-й ход просто топчется на месте ладьёй.

Интересно, что Stockfish в упор не видит стратегических решений Alpha Zero, оценивая позицию как абсолютно ничейную. Но в результате минимальных укреплений позиции к 39-му ходу оказывается, что все фигуры белых активны, а чёрный конь и слон занимают пассивную оборонительную позицию. А после размена ферзей и ладей даже Stockfish оценивает преимущество нейросети в +2,2. Ещё несколько ходов и король черных зажат в углу доски, а конь в одиночку не способен справиться с проходной пешкой. Поэтому программа сдалась.

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

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

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

Многие теоретики считают, что благодаря шахматным компьютерам повысился и средний рейтинг топовых шахматистов. Ведь современные тренировки включают глубокую проработку компьютерных вариантов и разбора партий движками. Средний рейтинг ведущих топ-100 шахматистов в 2000 году составлял 2644 пункта Эло, а в январе 2021 года 2715. За 20 лет среднее значение увеличилось на 71 пункт.

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

Она умеет мыслить позиционно и при этом не допускает зевков и ошибок. И самое интересное в этом ситуации шахматы для Alpha Zero являются только тестировочным полигоном, где система оттачивает навыки работы. Реальные же её цели Google не раскрывает. Поэтому здесь может быть всё что угодно: от анализа изменений климатической ситуации до создания системы идеально персонифицированной рекламы. А как вы считаете, для чего создают настолько мощную нейросеть?

Создать своего гениального цифрового шахматиста или получить Level Up по навыкам и зарплате можно пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение. Узнайте подробности.

Другие профессии и курсы
Подробнее..

Перевод Как скопировать стиль Уорхола с помощью нейросети VGG-19, трансферного обучения и TensorFlow

11.02.2021 16:05:53 | Автор: admin

То что мы сделаем ещё называется Нейронный перенос стиля это метод смешивания двух изображений и создания нового изображения из изображения-контента путём копирования стиля другого изображения, которое называется изображением стиля. Созданное изображение часто называют стилизованным изображением.

В этой статье мы скопируем стиль Энди Уорхола с Мэрилин Диптихна наши фотографии. Уорхол создал диптих Монро в 1962 году, сначала раскрасив холст разными цветами, а затем разместив теперь знаменитое изображение Мэрилин поверх холста. Хотя Уорхол не является основателем поп-арта, он одна из самых влиятельных фигур в этом жанре.



Рис. 1. Мэрилин Диптих Уорхола, а на кдпв показан наш результат нейронного переноса стиля в поп-арт, которого мы добились с помощью сети VGG-19

Что касается технического аспекта туториала, вместо использования готовой сети Magenta мы используем предварительно обученную модель компьютерного зрения VGG-19 и настроим её. Таким образом, эта статья представляет собой руководство по переносному обучению, а также по компьютерному зрению. Применяя возможности трансферного обучения, мы можем достичь лучших результатов, если сможем правильно настроить модель и иметь широкий спектр дополнительных возможностей настройки.

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

Кратко расскажу о модели, которую мы будем настраивать: VGG-19.

VGG-19


VGG это свёрточная нейронная сеть с глубиной 19 слоев. Она была построена и обучена К. Симоняном и А. Зиссерманом в Оксфордском университете в 2014 году. Вся информация об этом есть в статье Very Deep Convolutional Networks for Large-Scale Image Recognition, опубликованной в 2015 году. Сеть VGG-19 обучена с использованием более одного миллиона изображений из базы данных ImageNet. Она обучалась на цветных изображениях размером 224x224 пикселей. Естественно, вы можете импортировать модель ImageNet с уже обученными весами. Эта предварительно обученная сеть может классифицировать до тысячи объектов. В этом туториале мы избавимся от верхней части, используемой для классификации, и добавим наши собственные дополнительные слои, чтобы её можно было использовать для нейронного переноса стиля. Вот официальная визуализация сети из научной работы:

Рис. 3. Иллюстрация сети VGG-19

Как я уже упоминал, чей стиль мог бы быть более культовым и более подходящим, чем стиль Энди Уорхолла для переноса в поп-арт. Мы будем использовать его культовую работу Мэрилин Диптих в качестве основы стиля и портретное фото из Unsplash в качестве основного контента:

Рис. 4. Мэрилин Диптих и выбранное для эксперимента фото

Уакзываем пути к изображениям


Используя TensorFlow, я могу написать get_files [получить файлы] с внешних URL-адресов. С помощью приведённого ниже кода я загружу изображения в свой блокнот Colab, одно для стиля, а другое для контента:


Масштабирование изображений


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


Загрузка изображений


Теперь, когда мы определяем нашу функцию img_scaler, мы можем создать функцию обёртывания для загрузки изображения из контуров изображения, которые мы установили выше, масштабировать их, чтобы ускорить обучение (с помощью вызова img_scaler()) и создть 4-мерный тензор, чтобы он подходил для VGG-19:


Теперь можно просто создать тензоры content_image и style_image, используя функции, которые мы перечислили выше:


Отображение изображения


Используя matplotlib, мы можем легко отобразить контент и изображения стиля рядом:


И вот вывод:

Рис. 5. Визуализация изображений контента и стиля

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

  • Загружаем VGG-19 с помощью API Keras ФЗШ от TensorFlow и загружаем его с весами ImageNet.
  • Создаём матричную функцию Грама для расчёта потери стиля.
  • Выбирам слои обученной модели VGG-19 для контента и стиля.
  • Создаём пользовательскую модель на основе ранее загруженной модели VGG-19 с опцией Keras Model Subclassing.
  • Настраиваем оптимизатор и функции потерь.
  • Определяем настроенный шаг обучения.
  • Запускаем написанный нами цикл обучения.

Обратите внимание на комментарии в gist

Загружаем VGG с Functional API


Поскольку в Keras размещена предварительно обученная модель VGG-19, мы можем загрузить модель из Keras Application API. Сначала создадим функцию, чтобы использовать её позже в разделе Создание подклассов. Эта функция позволяет нам создавать пользовательскую модель VGG с желаемыми слоями, по-прежнему имея доступ к атрибутам модели:


Основная модель с Model Subclassing


Вместо того чтобы сравнивать необработанные промежуточные выходные данные изображения контента и изображения стиля, мы сравним матрицы Грама двух выводов с помощью функции gram_matrix; она даёт результаты точнее:


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


Теперь, когда у нас есть выбранные слои, функция gram_matrix() для расчёта потерь и функция vgg_layers() для загрузки желаемого в VGG-19, мы можем создать нашу основную модель с опцией Keras Model Subclassing. С помощью следующих строк мы делаем preprocess_input [предварительно обрабатываем входные] данные, пропуская их через нашу пользовательскую модель VGG и gram_matrix. Cоздаём модель и называем её extractor. Модель выводит словарь, который содержит выходные значения для контента и информации стиля:


Оптимизатор и настройки потерь


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


Пользовательский шаг обучения


Теперь мы определим пользовательскую функцию train_step, в которой воспользуемся преимуществом GradientTape, который, в свою очередь, позволяет выполнять автоматическое дифференцирование для расчёта потерь. GradientTapeзаписывает операции во время прямого прохода, а затем может вычислить градиент нашей функции потерь для входного изображения уже для обратного прохода. Обратите внимание, что мы используем декоратор tf.function(), чтобы TensorFlow знал, что мы передаём функцию trainstep. Свободно экспериментируйте с total_variation_weight, чтобы получить разные результаты переноса стиля.


Настраиваемый цикл обучения


Теперь, когда всё прочитано, мы можем запустить пользовательский цикл обучения, чтобы оптимизировать веса и получить наилучшие результаты. Запустим модель на 20 эпох и 100 steps_per_epoch [шагов на эпоху]. Это даст нам красивую версию фотографии, которую мы загрузили вначале, в стиле поп-арт. Кроме того, наш цикл будет выводить стилизованную фотографию после каждой эпохи (это временно).

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


Сохраняем и отображаем стилизованное изображение


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


Вот результат:

Рис. 6. Фото истилизованная версия

Поздравляю!


Вы только что построили модель передачи нейронного стиля с помощью трансферного обучения. Очевидно, что есть возможности сделать её лучше, но если вы присмотритесь, то увидите, что наша модель скопировала стиль Уорхола, когда он стилизовал волосы Монро. Модель также позаимствовала цвет фона из диптиха Монро. Поэкспериментируйте с числами img_scale, total_variation_weight, epoch, steps_per_epoch, чтобы получить разные результаты. Вы также можете использовать другие художественные стили, чтобы получить интересные результаты. А если хотите научиться применять машинное обучение иначе приходите учиться, а промокод HABR, дающий 10% дополнительно к скидке на баннере вам в этом поможет.



image



Подробнее..

Mockito. Из чего он приготовлен и как его подавать?

12.02.2021 16:06:23 | Автор: admin

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

Чему же я удивился? Например, этому:

private static class Apple {   private String color;   public String getName() {return color;}}@Testpublic void basic() {   Apple apple = mock(Apple.class);   when(apple.getName()).thenReturn("Red");   assertEquals("Red", apple.getName()); // true}

С точки зрения написания кода, это очень красиво и понятно:

  • Мы создаём экземпляр-заглушку для класса Apple.
  • Затем мы как бы говорим, когда вызывается метод apple.getColor(), то верни Red.
  • Далее мы просто проверяем действительно ли apple.getColor() возвращает то, что мы хотим, и это работает!

Внимание! Не читайте дальше, если и дальше хотите верить в магию. Дальнейшее содержание статьи отнимет у вас и эту толику детского счастья.



Что такое Mockito?


Mockito является открытой библиотекой с лицензией MIT License.

Приведённый выше пример работы позволяет заменить логику компонента, что очень полезно при тестировании. Например, если есть какой-то компонент, который должен использовать внешний API для получения данных, то с помощью Mockito мы можем сделать заглушку без обращения к внешнему API. Ещё более важным может быть изменение возвращаемых значений, которое можно задавать сразу в логике модульного теста.

Библиотека довольно популярна и часто используется при тестировании, например, Spring Boot приложений.

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

Так и здесь. Результат для нас может вполне очевиден, но как же он реализован?

Присмотримся к коду ещё раз и акцентируем внимание на второй строке:

when(human.getName()).thenReturn("Red");

Внутри метода when по сути мы помещаем возвращаемое значение из метода getName(), а потом говорим thenReturn. Но как так получается? Как when может изменить наш метод getName, просто получив то значение, которое он возвращает?

Более того, мы знаем что поле name не инициализировано, а значит, там будет null.

За это уже можно влюбиться в неё и начать вовсю использовать.

По моему личному мнению, Mockito полезная вещь, которую стоит изучить при наличии свободного времени. Но если изучить досконально не получится тоже не страшно, то, что вы будете иметь о ней представление, уже хорошо. Тем более лучшие практики подтверждают, что если ваш код трудно тестировать, то с вашим кодом явно что-то не так. В пользу ознакомления, а не глубокого изучения, говорит и то, что в 2018 году появился такой инструмент, как TestContainers, который умеет поднимать реальную базу в Docker и реально выполнять запросы в БД/Kafka/RabbitMQ.

Егор Воронянский, Java Middle Developer в BPC Banking Technologies.
Ментор раздела backend на курсе SkillFactory Java-разработка

Учимся показывать фокусы


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

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

Нашим же приготовлением был вызов метода mock:

Apple apple = mock(Apple.class);

Отсюда мы понимаем, что наш apple это уже необычное яблоко.

И действительно, если вы попробуете передать обычный экземпляр класса в метод when, то получите ошибку.

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

@Testpublic void basic2() {   Apple apple = mock(Apple.class);   System.out.println(apple.getClass().getCanonicalName());   // org.own.ArticleExample1$Apple$MockitoMock$692964397   System.out.println(apple.getClass().getSuperclass().getCanonicalName());   // org.own.ArticleExample1.Apple   assertNotEquals(apple.getClass(), Apple.class); // true}

Итак, с кем же мы имеем дело? Кто же этот самозванец, который выдаёт себя за наше яблоко?

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

Что касается именно нашей библиотеки Mockito, то она действительно основана на проксировании. Тем не менее есть библиотеки, занимающиеся тем же, но основанные не на проксировании, а, например, на изменении байт-кода. Примером такой библиотеки может служить PowerMock с лицензией Apache-2.0 License.

Ну, и разница между библиотекой, работающей с Java API, и той, которая манипулирует байт-кодом, наверное, очевидна. Но зачастую подключение PowerMock избыточно, хотя случаев его использования довольно много.

Далее мы разберём, в чём же минусы решения через проксирование.

Proxy


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

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

Индейская пословица гласит:

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

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

ProxyExample

import java.lang.reflect.Proxy;/** * @author Arthur Kupriyanov */public class ProxyExample {interface IApple {String getColor();}private static class Apple implements IApple {private String color = "red";public String getColor() {return color;}}public static void main(String[] args) {Object proxyInstance = Proxy.newProxyInstance(ProxyExample.class.getClassLoader(),Apple.class.getInterfaces(), (proxy, method, args1) -> {System.out.println("Called getColor() method on Apple");return method.invoke(new Apple(), args1);});IApple appleProxy = (IApple) proxyInstance;System.out.println(appleProxy.getColor());}}

На выводе мы получим:

Called getColor() method on Applered

Попробуйте, например, вместо вызова method.invoke сделать return Green.

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

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

  • Мы не можем перехватывать вызовы статических, приватных и ненаследуемых (final) методов.
  • Сделать прокси из ненаследуемого класса (final).

Показываем фокус


На самом деле, имея лишь этот арсенал, можно сделать что-то наподобие Mockito.

Конечно, наш фокус будет весьма ограничен по сравнению с увиденным ранее, но основной метод фокуса будет тем же.

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

  1. Создадим прокси типа с нашим InvocationHandler с необходимой нам логикой.
  2. Создадим метод when, который вместе с thenReturn запомнит вызов метода, его аргументы и значение, которое нужно вернуть.
  3. При вызове метода из нашего прокси объекта будем проверять сохранённые значения из пункта 2. Если есть сохранение заданного метода с такими же аргументами, то вернём сохранённое значение. Если нет, то вернем null.

Исходный код можно найти в репозитории или же поиграть в онлайн-редакторе.

private static MockInvocationHandler lastMockInvocationHandler;@SuppressWarnings("unchecked")public static <T> T mock(Class<T> clazz) {   MockInvocationHandler invocationHandler = new MockInvocationHandler();   T proxy = (T) Proxy.newProxyInstance(Bourbon.class.getClassLoader(), new Class[]{clazz}, invocationHandler);   return proxy;}public static <T> When<T> when(T obj) {   return new When<>();}public static class When<T> {   public void thenReturn(T retObj) {   lastMockInvocationHandler.setRetObj(retObj);   }}private static class MockInvocationHandler implements InvocationHandler {   private Method lastMethod;   private Object[] lastArgs;   private final List<StoredData> storedData = new ArrayList<>();   private Optional<Object> searchInStoredData(Method method, Object[] args) {   for (StoredData storedData : this.storedData) {   if (storedData.getMethod().equals(method) && Arrays.deepEquals(storedData.getArgs(), args)) {   // если данные есть, то возвращаем сохраненный   return Optional.ofNullable(storedData.getRetObj());   }   }   return Optional.empty();   }   @Override   public Object invoke(Object proxy, Method method, Object[] args) {   lastMockInvocationHandler = this;   lastMethod = method;   lastArgs = args;   // проверяем в сохраненных данных   return searchInStoredData(method, args).orElse(null);   }   public void setRetObj(Object retObj) {   storedData.add(new StoredData(lastMethod, lastArgs, retObj));   }   private static class StoredData {   private final Object[] args;   private final Method method;   private final Object retObj;   private StoredData(Method method, Object[] args, Object retObj) {   this.args = args;   this.method = method;   this.retObj = retObj;   }   private Object[] getArgs() {   return args;   }   private Method getMethod() {   return method;   }   private Object getRetObj() {   return retObj;   }   }}

Этот код не претендует на какое-либо качество кода, но он вполне нагляден.

Основным классом здесь является MockInvocationHandler, в который мы вставляем всю нашу логику с поиском сохранённых значений. Все сохранённые значения мы храним в виде списка StoredData, а затем при вызове любого из методов запроксированного объекта проверяем, было ли сохранено какое-либо значение.

Те сомнения, которые не разрешает теория, разрешит тебе практика. Людвиг Файербах


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

Заключение


Mockito имеет не только конструкцию when-thenReturn, но и ещё много других не менее интересных и не уступающих по красоте конструкций. Разработчики Mockito смогли не только найти весьма любопытный способ создавать заглушки, но и выбрали правильные имена и способ подачи разработчикам. Согласитесь, что та же конструкция, которую мы рассмотрели ранее, выглядит, как единая строчка текста.

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

Для ознакомления с методами использования библиотеки уже есть довольно много других статей на разных языках, в том числе на русском. Поэтому вам осталось самое интересное: изучить внутренности самого Mockito, (хорошо, что исходники есть в репозитории на GitHub) и понять, как он хорошо интегрируется в Spring Boot для тестирования. А я пожелаю вам удачи в этом пути!



image



Подробнее..

Нужно больше датасетов. Музыка, IT-скилы и котики

11.02.2021 18:04:31 | Автор: admin

Привет, Хабр! Совсем недавно мы писали про открытый датасет, собранный командой студентов магистратуры Наука о данных НИТУ МИСиС и Zavtra.Online (подразделение SkillFactory по работе с университетами) в рамках первого учебного Дататона. А сегодня представим вам целых 3 датасета от команд, которые также вышли в финал.

Все они разные: кто-то исследовал музыкальный рынок, кто-то рынок труда IT-специалистов, а кто-то и вовсе домашних кошек. Каждый из этих проектов актуален в своей сфере и может быть использован для того, чтобы что-то усовершенствовать в привычном ходе работы. Датасет с котиками, например, поможет судьям на выставках. Датасеты, которые необходимо было собрать студентам, должны были представлять собой MVP (таблица, json или структура каталогов), данные должны быть очищены и проанализированы. Посмотрим же, что у них получилось.



Датасет 1: Скользим по музыкальным волнам с Data Surfers


Состав команды:

  • Плотников Кирилл project manager, разработка, документация.
  • Тарасов Дмитрий разработка, сбор данных, документация.
  • Шадрин Ярослав разработка, сбор данных.
  • Мерзликин Артём product manager, презентация.
  • Колесниченко Ксения предварительный анализ данных.

В рамках участия в хакатоне участниками команды было предложено несколько различных интересных идей, но мы решили остановиться на сборе данных о российских музыкальных исполнителях и их лучших треках с ресурсов Spotify и MusicBrainz.

Spotify музыкальная платформа, пришедшая в Россию не так давно, но уже активно захватывающая популярность на рынке. Кроме того, с точки зрения анализа данных, Spotify предоставляет очень удобное API с возможностью запроса большого количества данных, в том числе их собственных метрик, например таких, как danceability показатель от 0 до 1, описывающий, насколько трек подходит для танцев.

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

Сбор данных об артистах


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

Описание полей таблицы
artist имя артиста или название группы;
musicbrainz_id уникальный идентификатор артиста в музыкальной базе данных Musicbrainz;
spotify_id уникальный идентификатор артиста в стриминговом сервисе Spotify, если он там представлен;
type тип исполнителя, может принимать значения Person, Group, Other, Orchestra, Choir или Character;
followers количество подписчиков артиста на Spotify;
genres музыкальные жанры артиста;
popularity индекс популярности артиста на Spotify от 0 до 100, который рассчитывается на основе популярности всех треков артиста.


Пример записи

Поля artist, musicbrainz_id и type извлекаем из музыкальной базы данных Musicbrainz, так как там есть возможность получить список артистов, связанных с одной страной. Извлечь эти данные можно двумя способами:

  1. Постранично парсить раздел Artists на странице с информацией о России.
  2. Достать данные через API.
    Документация MusicBrainz API
    Документация MusicBrainz API Search
    Пример запроса GET на musicbrainz.org

В ходе работы выяснилось, что API MusicBrainz не совсем корректно отвечает на запрос с параметром Area:Russia, скрывая от нас тех исполнителей, у кого в поле Area указано, например, Izhevsk или Moskva. Поэтому данные с MusicBrainz были взяты парсером непосредственно с сайта. Ниже пример страницы, откуда парсились данные.


Полученные данные об артистах из Musicbrainz.

Остальные поля получаем в результате GET запросов к эндпоинту.При отправке запроса в значении параметра q указываем имя артиста, а в значении параметра type указываем artist.

Сбор данных о популярных треках


Таблица содержит 44473 записи о самых популярных треках российских артистов, представленных в таблице выше. Под спойлером описание полей таблицы.

Описание полей таблицы
artist имя артиста или название группы;
artist_spotify_id уникальный идентификатор артиста в стриминговом сервисе Spotify (по нему можно будет джойнить таблицы, так как это spotify_id из таблицы с артистами);
name название трека;
spotify_id уникальный идентификатор трека в стриминговом сервисе Spotify;
duration_ms длительность трека в миллисекундах;
explicit содержит ли текст трека нецензурные выражения, может принимать значения true или false;
popularity индекс популярности трека на Spotify *;
album_type тип альбома, может принимать значения album, single или compilation;
album_name название альбома;
album_spotify_id уникальный идентификатор альбома в стриминговом сервисе Spotify;
release_date дата выхода альбома;
album_popularity индекс популярности альбома на Spotify.

Особенности аудио
key предполагаемая общая тональность трека, целые числа накладываются на нотацию звуковысотных классов, 0 = C, 1 = C/D, 2 = D и т.д.;
mode указывает модальность трека, мажор 1, минор 0;
time_signature предполагаемый общий тактовый размер композиции;
acousticness мера достоверности от 0,0 до 1,0 того, является ли трек акустическим;
danceability описывает, насколько трек подходит для танцев от 0,0 до 1,0;
energy представляет собой перцептивную меру интенсивности и активности от 0,0 до 1,0;
instrumentalness определяет, содержит ли трек вокал, принимает значения от 0,0 до 1.0;
liveness определяет присутствие аудитории при записи, принимает значения от 0,0 до 1,0;
loudness общая громкость трека в децибелах, типичный диапазон значений от -60 до 0 дБ;
speechiness определяет наличие произнесённых слов в треке, принимает значения от 0,0 до 1,0;
valence описывает музыкальную позитивность, передаваемую треком, принимает значения от 0,0 до 1,0;
tempo предполагаемый общий темп трека в ударах в минуту.

Подробно о каждом параметре можно прочитать здесь.


Пример записи

Поля name, spotify_id, duration_ms, explicit, popularity, album_type, album_name, album_spotify_id, release_date получаем с помощью GET запроса на https://api.spotify.com/v1//v1/artists/{id}/top-tracks , указывая в качестве значения параметра id Spotify ID артиста, который мы получили ранее, а в значении параметра market указываем RU. Документация.

Поле album_popularity можно получить, сделав GET запрос на https://api.spotify.com/v1/albums/{id}, указав album_spotify_id, полученный ранее, в качестве значения для параметра id. Документация.

В результате получаем данные о лучших треках артистов из Spotify. Теперь задача получить особенности аудио. Сделать это можно двумя способами:

  1. Для получения данных об одном треке нужно сделать GET-запрос на https://api.spotify.com/v1/audio-features/{id}, указав его Spotify ID как значение параметра id. Документация.
  2. Чтобы получить данные о нескольких треках сразу, следует отправить GET запрос на https://api.spotify.com/v1/audio-features, передавая Spotify ID этих треков через запятую как значение для параметра ids. Документация.

Все скрипты находятся в репозитории по этой ссылке.

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



Итоги


В результате у нас получилось собрать данные по 14363 артистам и 44473 трекам. Объединив данные из MusicBrainz и Spotify, мы получили наиболее полный на текущий момент набор данных о всех российских музыкальных исполнителях, представленных на платформе Spotify.

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

Датасет 2: Исследуем рынок вакансий и выявляем ключевые навыки с Ежу понятно


Состав команды:

  • Пшеничный Андрей сбор и обработка данных, написание аналитической записки о датасете.
  • Кондратёнок Павел Product Manager, сбор данных и описание его процесса, GitHub.
  • Щербакова Светлана сбор и обработка данных.
  • Евсеева Оксана подготовка итоговой презентации проекта.
  • Елфимова Анна Project Manager.

Для своего датасета мы выбрали идею сбора данных о вакансиях в России из сферы IT и Телеком с сайта hh.ru за октябрь 2020 года.

Сбор данных о скилах


Самым важным показателем для всех категорий пользователей являются ключевые навыки. Однако при их анализе у нас возникли трудности: эйчары при заполнении данных о вакансии выбирают ключевые навыки из списка, а также могут вносить их вручную, а следовательно, в наш датасет попало большое количество дублирующих навыков и некорректных навыков (например, мы столкнулись с названием ключевого навыка 0,4 Кb). Есть ещё одна трудность, которая доставила проблем при анализе получившегося датасета, только около половины вакансий содержат данные о заработной плате, но мы можем использовать средние показатели о заработной плате с другого ресурса (например, с ресурсов Мой круг или Хабр.Карьера).

Начали с получения данных и их глубинного анализа. Далее мы произвели выборку данных, то есть отобрали признаки (features или, иначе, предикторы) и объекты с учетом их релевантности для целей Data Mining, качества и технических ограничений (объема и типа).

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


Наиболее часто встречающиеся ключевые навыки в вакансиях из сферы IT, Телеком

Данные получили с сайта hh.ru с помощью их API. Код для выгрузки данных можно найти тут. Вручную выбрали признаки, которые нам необходимы для датасета. Структуру и тип собираемых данных можно увидеть в описании документации к датасету.

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


Образец собранных данных

Итоги


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

Датасет 3: Наслаждаемся многообразием котиков с Команда AA


Состав команды:

  • Евгений Иванов разработка веб-скрапера.
  • Сергей Гурылёв product manager, описание процесса разработки, GitHub.
  • Юлия Черганова подготовка презентации проекта, анализ данных.
  • Елена Терещенко подготовка данных, анализ данных.
  • Юрий Котеленко project manager, документация, презентация проекта.

Датасет, посвящённый котам? Да почему бы и нет, подумали мы. Наш котосет содержит образцы изображений, на которых сфотографированы кошки различных пород.

Сбор данных о котиках


Изначально для сбора данных мы выбрали сайт catfishes.ru, он обладает всеми нужными нам преимуществами: это свободный источник с простой структурой HTML и качественными изображениями. Несмотря на преимущества этого сайта, он имел существенный недостаток малое количество фотографий в целом (около 500 по всем породам) и малое количество изображений каждой породы. Поэтому мы выбрали другой сайт lapkins.ru.




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

Для сбора изображений с сайта нами был написан веб-скрапер. Сайт содержит страницу lapkins.ru/cat со списком всех пород. Сделав парсинг этой страницы, мы получили названия всех пород и ссылки на страницу каждой породы. Итеративно пройдя в цикле по каждой из пород, мы получили все изображения и сложили их в соответствующие папки. Код скрапера был реализован на Python с использованием следующих библиотек:

  • urllib: функции для работы с URL;
  • html: функции для обработки XML и HTML;
  • Shutil: функции высокого уровня для обработки файлов, групп файлов и папок;
  • OS: функции для работы с операционной системой.

Для работы с тегами мы использовали XPath.



Каталог Cats_lapkins содержит папки, названия которых соответствуют названиям пород кошек. Репозиторий содержит 64 каталога для каждой породы. Всего в датасете содержатся 2600 изображений. Все изображения представлены в формате .jpg. Формат названия файлов: например Абиссинская кошка 2.jpg, вначале идёт название породы, затем число порядковый номер образца.



Итоги


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

Послесловие


По итогам дататона наши студенты получили первый кейс в своё портфолио дата-сайентиста и обратную связь по работе от менторов из таких компаний, как Huawei, Лаборатория Касперского, Align Technology, Auriga, Intellivision, Wrike, Мерлин АИ. Дататон был полезен ещё и тем, что прокачал сразу и профильные хард- и софт-скилы, которые понадобятся будущим дата-сайентистам, когда они будут работать уже в реальных командах. Также это хорошая возможность для взаимного обмена знаниями, так как у каждого студента разный бэкграунд и, соответственно, свой взгляд на задачу и её возможное решение. Можно с уверенностью сказать, что без подобных практических работ, похожих на какие-то уже существующие бизнес-задачи, подготовка специалистов в современном мире просто немыслима.

Узнать больше про нашу магистратуру можно на сайте data.misis.ru и в Telegram канале.

Ну, и, конечно, не магистратурой единой! Хотите узнать больше про Data Science, машинное и глубокое обучение заглядывайте к нам на соответствующие курсы, будет непросто, но увлекательно. А промокод HABR поможет в стремлении освоить новое, добавив 10 % к скидке на баннере.



image



Подробнее..

Перевод Стучимся в дверь к Тьюрингу квантовые компьютеры и машинное обучение

22.02.2021 18:08:55 | Автор: admin


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



Если это множество новых многоядерных процессоров, графических процессоров и гигантских вычислительных кластеров, размещённых в облаке, оценить критически, мы скоро поймём, что процессоры быстрее не обязательно приводят к увеличению вычислительной мощности. Конечно, скорость вычислений за последние десятилетия экспоненциально увеличилась, так же как и объём данных, которые мы можем собирать и обрабатывать. Мы можем хранить и анализировать эксабайт данных в Интернете, обучать модели глубокого обучения, такие как OpenAI GPT-3, и задействовать вычислительный интеллект, необходимый, чтобы побеждать чемпионов и гроссмейстеров сложных игр, таких как го или шахматы. Но расширили ли все эти технологические достижения существующие границы, то, что мы можем делать с помощью компьютеров в принципе, за пределами того, с чего начали? Или, проще говоря, изменили ли мы нашу традиционную модель вычислений? Современные компьютеры работают согласно принципам архитектуры фон Неймана (Ogban et al, 2007). Архитектура фон Неймана использует входы и выходы для блока обработки, который на основе набора инструкций выполняет логические функции на входах.

Архитектура фон Неймана.

Тогда как архитектуры фон Неймана и хороши в практическом решении проблем, они не описывают процесс вычислений сам по себе. Чтобы описать процесс вычислений, нужна машина Тьюринга (De Mol, 2018). Эта машина представляет собой абстрактную модель сегодняшних вычислений: она манипулирует символами на ленте согласно набору инструкций. В зависимости от текущего состояния машины лента продвигается или останавливается. Хорошо известно, что все вычисления, которые может выполнять сегодняшний компьютер, могут выполняться и машиной Тьюринга. Проницательный читатель свяжет этот факт с тезисом Чёрча Тьюринга, в котором говорится, что любое практическое вычисление может быть выполнено с помощью лямбда-исчисления, которое эквивалентно генерализованным рекурсивным функциям (Rabin, 2018). На практике, однако, скорости реальной машины Тьюринга будет недостаточно, чтобы решить реалистичную проблему приемлемого масштаба.

Схематичное изображение машины Тьюринга.

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

Однако это не означает, что всё потеряно. Как сказал однажды Мартин Лютер Кинг, мы должны принять конечное разочарование, но никогда не терять бесконечную надежду. Чтобы пробить этот потолок, требуется нечто большее, чем просто упаковывать легионы транзисторов в компьютерных микросхемах. Это требует радикального переосмысления компьютеров с самого начала, с базовой единицы бита.

Проявление квантовой реальности


В последние 120 лет мы добились, возможно, величайших достижений в истории физики. Специальная и общая теории относительности Эйнштейна изменили представления о времени, пространстве и гравитации; Дирак, Паули, Фепйнман, Шрёдингер и Планк сформулировали принципы квантовой механики и коренным образом изменили наше понимание мира бесконечно малых электронов, протонов и нейтронов.

Международная конференция Solvay 1927 года считается поворотным моментом для современной физики.

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

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

Классический бит и кубит.

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

Квантово-механическая интерлюдия


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


Дуализм частиц.

Второй принцип, который важно понимать, квантовая запутанность. Рассмотрим систему частиц, где каждая частица имеет собственную волновую функцию. Система из множества частиц определяется произведением тензора состояния пространства. Это произведение k частиц, при этом каждая частица представлена n мерным столбцовым вектором; говорят, что частица имеет размерность n. Такое представление пространства называется совокупностью состояний (assembling of states). Чтобы проиллюстрировать это, приведём нашу систему из k частиц в систему с двумя частицами, каждая из которых находится в суперпозиции двух состояний, a и b (или, для простоты, окружность и квадрат). Мы говорим, что две частицы независимы, когда знание о состоянии одной частицы не раскрывает информацию о состоянии второй частицы.

Независимые частицы.

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

Запутанные частицы.

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

На практике независимые частицы встречаются редко, так как взаимодействия между системами приводят к запутыванию из-за математической подоплёки, связывающей волновые функции с конкретными вероятностями, которая вводит корреляцию между частицами (Joos, 2009). Учитывая эти концепции, то есть квантово-волнового дуализма частиц и квантовой запутанности свежих в нашем сознании, давайте посмотрим, как квантовые компьютеры могут воспользоваться этими концепциями, чтобы что-то вычислить.

Совершенно иная модель вычислений


Подобно транзистору, представляющему 1 бит информации в классических компьютерах, ядерный спин полупроводникового материала, такого как силикон или фосфор, представляет собой кубит информации. Эти полупроводниковые атомы кремния или фосфора управляются и считываются с помощью электрического и магнитного полей (Vogel, n.d.) (Physics World, 2019).

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

На практике можно кодировать классический бит с помощью кубита, но обратное неверно, т есть невозможно закодировать кубиты информации в классическом транзисторе. Используя биты, можно кодировать n-компонентную систему, с помощью n транзисторов. Для инкапсуляции 8-битной классической системы требуется всего 8 сохранённых битов. Если бы n-компонентная система была квантовой, то для её кодирования потребовались бы комплексные числа 2 (Kopczyk, 2018). 8-кубитный квантовый компьютер требует 256 комплексных чисел. А для моделирования 64 кубитов потребуется 2=18, 446, 744, 073, 709, 551, 616 комплексных чисел на классической машине. Поэтому квантовые вычисления обеспечивают значительно большее пространство потенциальных состояний по сравнению с классическим компьютером. Поскольку кубит это гораздо больший вычислительный объект, для представления сложных вычислительных задач требуется меньшее количествокубитов. И, вне сомнения, для классического компьютера такие представления было бы чрезвычайно сложно эмулировать.

Подобно классическим логическим вентилям (например, AND, OR, XOR) сути любой операции на битах, квантовые вентили изменяют состояние кубита с помощью соответствующих логических вентилей. Тем не менее квантовые компьютеры имеют массив специальных вентилей, специфичных для операций с кубитами. Среди них вентили Хадамарда и CNOT (Djordjevic, 2012). Вентили Хадамарда могут использоваться, чтобы создать суперпозиции состояний (Qiskit/IBM, n.d.), в то время как вентили CNOT могут использоваться, чтобы запутать кубиты (Qiskit/IBM, n.d.).

Схема квантов.

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

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

Умело применяя принципы суперпозиции и запутывания, квантовый компьютер может одновременно вычислять результаты из множества кубитов (Kopczyk, 2018). Например, скажем, наше квантовое вычисление включает в себя применение преобразования или функции на множестве входов; мы можем применить эту функцию на нескольких входах и получить их результаты в тандеме. С другой стороны, одна и та же операция на классическом компьютере должна выполняться последовательно для каждого входа. или в отдельных классических схемах. Поясню: поскольку классические биты не запутаны и не находятся в суперпозиции, чтобы получить информацию, необходимы индивидуальные измерения и вычисления. В случае квантовых компьютеров запутанность и суперпозиция позволяют одновременно вычислить информацию о нескольких кубитах, за одну операцию. По сути, данная модель вычислений позволяет исследовать различные пути и выполнять математические операции в тандеме.

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

Подробный обзор квантового компьютера.

Первая ощутимая демонстрация квантового компьютера, превосходящего классический. случилась в 2019 году. Исследователи Google использовали Sycamore, квантовый компьютер с 53 кубитами, чтобы решить задачу менее чем за 200 секунд. Для решения этой же задачи существующему классическому суперкомпьютеру потребовалось бы около 10 000 лет. Результат Sycamore был официально охарактеризован как проявление квантового превосходства, наглядный пример парадигмы квантовых вычислений, показавших себя значительно более мощными, чем классические вычисления (Arute & Arya, 2019, р. 505510).

53-кубитный квантовый компьютер Google, Sycamore (Arute & Arya, 2019, р. 505510)

IBM быстро оспорил претензии Google, опубликовав работу (Pednault et al., 2019), но находка Google (квантовое превосходство с помощью программируемого сверхпроводящего процессора) считается прорывным моментом в развитии квантовых компьютеров.

Трава на том берегу не такая уж зелёная


До сих пор мы обсуждали только положительные аспекты квантовых компьютеров. Но не всё гладко с точки зрения их внедрения и разработки. Как оказалось, удерживать кубиты в состоянии суперпозиции невероятно сложно. Чтобы достичь стабильности, квантовые компьютеры должны удерживаться в рефрижераторах, которые охлаждают кубиты до температур чуть скромнее абсолютного нуля (0 K). Это означает, что квантовые компьютеры ограничены нишевыми исследовательскими областями и дорогими лабораториями, по крайней мере сегодня.

Типичная среда квантового компьютера в NISQ-era.

Кроме того, кубиты чувствительны к шумам (явление известно как декогерентность), это означает, что они теряют своё вероятностное квантовое поведение а вместе с ним и хранимую информацию в среде взаимодействующих частиц. Так происходит потому, что на квантовом уровне никакое наблюдение или взаимодействие не является достаточно щадящим, чтобы одновременно извлечь информацию из системы, но при этом сохранить её первоначальное состояние покоя. Такие взаимодействия эффективно локализуют кванты, благоприятная суперпозиция состояний исчезает (Bacciagaluppi, 2020), в этом ещё одна причина того, что мы не смогли полностью раскрыть потенциал квантовых компьютеров полностью (Kopczyk, 2018).

Вопрос связан с когерентностью.

Учитывая их ограничения, мы находимся вовремени, которое исследователи называют Noisy Intermediate-Scale Quantum (NISQ) эрой квантовых компьютеров. Нынешнее поколение квантовых компьютеров недостаточно мощное, чтобы давать приемлемые результаты. Декогерентность также угрожает эффективности квантовых алгоритмов, лишая их преимуществ ускорения. Именно поэтому алгоритм Шора, способный дестабилизировать наши существующие стандарты шифрования позволя осуществлять первичную факторизацию массивных чисел в полиномиальное время, остатся теоретическим достижением.

Самое главное, что квантовые компьютеры не лучший выбор для каждого типа вычислений. Они не будут быстрее выполнять элементарные операции с двумя числами, не будут без усилий обучать нейронные сети, и они, безусловно, не будут быстрее выполнять повседневные программы. Такие фирмы, как IBM, утверждают, что квантовые компьютеры никогда не будут господствовать над классическими компьютерами, они будут работать вместе с ними, поскольку каждый тип обладает своими уникальными сильными сторонами (Pednault & Gunnels, 2019)..

Однако есть определённые задачи, в решении которых квантовые компьютеры преуспевают, и их стоит обсудить.

Квантовое машинное обучение


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

Однако это увеличение поискового пространства становится послушным, если мы используем гибридный алгоритм квантового машинного обучения. Variational-Quantum-Eigensolver (VQE) использует как классические, так и квантовые алгоритмы для оценки наименьшего собственного значения Hamiltonian. Проще говоря, его квантовая часть, известная как анзац, за приемлемое время находит пространство всех возможных состояний частицы. Классическая часть настраивает параметры анзаца с помощью градиентного спуска, чтобы помочь ему приблизиться к оптимальному ответу. Эта комбинация показала, что квантовый компьютер может быть особенно полезен в задачах моделирования частиц такого рода.

Схематичное изображение алгоритма VQE.

За последние несколько лет также были сформулированы различные алгоритмы под эгидой квантового машинного обучения. Квантовый алгоритм, который наиболее известен в применении для традиционной кластеризации k-means оптимизирует классическую подпрограмму Ллойда для вычисления расстояний (Rebollo-Monedero & Girod, 2009) между векторами для уменьшения классической O(NkM) вычислительной сложности экспоненциально до O(Mklog(N)), где k число кластеров, M счётчик сэмплов, а N счётчик функций (Biamonte & Wittek, 2017, р. 195202).

Также исследовалась мощность квантовых компьютеров в работающих нейронных сетях. В то время как надёжная формулировка нейронной сети всё ещё находится в квантовой области (Schuld & Sinayskiy, 2014), учёные разработали различные методы представления классических нейронных сетей с квантовыми цепями. В качестве примера можно привести исследователей из ETH Zurich и IBM Q, которые сравнили размерность, оптимизируемость и обучаемость классических нейронных сетей и квантовых нейронных сетей (Abbas и др., 2020).

Квантовая нейронная сеть, исследование в статье Abbas et al., 2020

Аббас и другие учёные в своей работе использовали размерность модели для сравнения мощности различных нейронных сетей. Их результаты показали, что квантовая нейронная сеть в сочетании с хорошей картой признаков (для кодирования данных) имела более высокую эффективную размерность, чем классическая нейронная сеть. Более того, в отличие от классических нейронных сетей, которые иногда медленно обучаемы из-за сильно дегенерирующих информационных матриц Фишера, квантовая нейронная сеть выше предлагает более описательную информационную матрицу Фишера с более однородными, ненулевыми собственными значениями. Эта квантовая нейронная сеть смогла тренироваться и конвергироватиься быстрее, чем классическая нейронная сеть с Iris dataset на машине IBM в 27 кубит.

Квантовая нейронная сеть обучается лучше, чем классическая нейронная сеть (Abbas et al., 2020)

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

NP-полные задачи, поиск и моделирование методом Монте-Карло


Квантовые компьютеры также превосходно справляются с задачами оптимизации. В задачах оптимизации используется определённое эвристическое решение, чтобы найти лучшее возможное решение из когорты действительных решений. Чтобы понять, как оптимизация может работать в контексте квантовых вычислений, исследователи разработали квантовые алгоритмы для некоторых NP-полных задач. Одним из примеров является квантовый алгоритм для задачи коммивояжёра, который для большого числа городов даёт квадратичное ускорение по сравнению с классическим методом грубой силы (Srinivasan et al., 2018).

Другие алгоритмы, использующие параллелизм квантового компьютера, также показали многообещающие результаты. Алгоритм гровера на данный момент является самым быстрым квантовым алгоритмом для поиска по несортированной базе данных с N записями. На классическом компьютере эта задача потребует времени, пропорционального N, но квантовая копия демонстрирует ускорение квадратного корня из N. получая оценку сложности в O(sqrt(N)). Аналогичным образом квантовые компьютеры могут выполнять преобразования Фурье по N точка данных, инвертировать разреженные матрицы N*N, а также находить свои собственные значения и собственные векторы во времени, пропорциональном полиномиальному, за log(N). Для этих задач оптимальные известные классические алгоритмы займут время, пропорциональное N log(N), т. е. квантовый компьютер также в таких случаях демонстрирует экспоненциальную скорость (Biamonte & Wittek, 2017, р. 195202).

Финансовая индустрия также готовится к потенциальному использованию квантовых компьютеров. Задача анализа фондовых рынков и связанных с ними показателей может быть превращена в задачу оптимизации. Учитывая это, применение квантовых компьютеров прямо сейчас потенциально может укорениться в финансовой сфере. Исследование испанского банка BBVA, которое вышло в июле 2020 года, показало, что квантовые компьютеры могут улучшить кредитный скоринг, возможности спотового арбитража, а также ускорить Моделирование Монте-Карло (The Economist, 2020). Аналогично руководитель исследовательского подразделения компании JPMorgan Chase & Co. Марко Пистойя (Marco Pistoia) надеется, что квантовые компьютеры потенциально могут увеличить прибыль за счёт ускорения ценообразования на активы, нахождения лучших портфелей и усовершенствования существующих алгоритмов ML. Даже руководитель отдела квантовых исследований компании Goldman Sachs Уильям Зенг (William Zeng) смело утверждал, что квантовые компьютеры могут перевернуть банковскую и финансовую отрасли (The Economist, 2020).

Запутанное будущее


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

Возвращаясь к обсуждению машин Тьюринга, квантовая машина Тьюринга является обобщением или квантизацией классической машины Тьюринга, где головка и лента запутываются друг с другом. Формально состояния машины представляют собой квантовые состояния в Гильбертова пространства. Лента квантовой машины Тьюринга это бесконечная односторонняя лента, которая представляет собой запутанные биты. В этом контексте квантовое вычисление это унитарное преобразование, результат которого определяется квантовым измерением, которое редуцирует одностороннюю ленту в когерентной суперпозиции к классической двусторонней ленте с разделяемыми ортогональными собственными состояниями (Moschovakis, 2003).

Схематичное представление квантовой машины Тьюринга.

Сочетание этой модели вычислений с аппаратным обеспечением, демонстрирующим квантовое превосходство Google исследователи считают нарушением расширенного тезиса Church-Turing, в котором утверждается, что такая модель вычислений должна быть эффективно смоделирована традиционной машиной Тьюринга. Фактически [Bernstein & Vazirani, 1993] показали, что машины Тьюринга квантового типа по своей природе отличаются от традиционных машин Тьюринга и могут решать определённые проблемы, требующие сверхполиноминального времени на классических компьютерах.

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

Осознавая потенциал, технические фирмы, такие как IBM, Intel, Zapata, Amazon и Honeywell, вкладывают значительные средства в разработку коммерческих приложений для квантовых компьютеров. Языки, фреймворки и библиотеки для программирования на квантовых компьютерах высокого уровня, такие как Q#, Qiskit, TensorFlow Quantum и Cirq, также неуклонно набирают обороты. Эти фреймворки и их туториалы снизили порог входа в квантовые вычисления, и если популярность будет расти и дальше, то в этом десятилетии мы можем ожидать множество новых интересных разработок в области квантовых вычислений.

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

Библиография



image
Узнайте подробности, как получить Level Up по навыкам и зарплате или востребованную профессию с нуля, пройдя онлайн-курсы SkillFactory со скидкой 40% и промокодом HABR, который даст еще +10% скидки на обучение:

Подробнее..

Категории

Последние комментарии

© 2006-2021, personeltest.ru