Португалия. Лучшие пляжи и тысяча стартапов в год

Всем привет

Вот так выглядит место, где проводится WebSummit:

Parque das Nações
Parque das Nações

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

Для тех кому надо по-быстрому, субъективно:

Плюсы:

  • Климат
  • Люди и их отношение к вам, как к эмигранту
  • Еда
  • IT компании на любой вкус и цвет
  • Пляжи
  • Большинство вменяемо говорит на английском
  • Документы получить не так и сложно
  • Безопасность
  • 5 лет и у вас гражданство
  • Медицина и её стоимость (относительно Европы и США)
  • Можете открыть компанию за пол часа и не платить налоги первый год

Минусы:

  • Низкие зарплаты
  • Все медленно (получение документов, подключение интернета…)
  • IT компании пока не знают как работать c эмигрантами (не знают как оформить документы и т.д.)
  • Высокие налоги (НДС — 23%. При доходе в 30 тыс в год — 34.6% уйдет государству, автомобили на 30-40% дороже, чем в России)
  • Население консервативное. Что-то новое продвинуть тяжеловато, но это меняется
  • Бюрократия страшная, но это меняется
  • Найти работу вашей жене\девушке\мужу\парню не в IT будет достаточно тяжело, потому что рынок вакансий не очень-то разнообразный.
  • Цены на недвижимость — космос, в том числе и на аренду.
  • Слишком толерантное население(об этом далее)

Начнем-с…

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

Я приехал в Португалию по учебной визе в Университет Алгарве (Universidade de Algarve).
Алгарве — это регион на юге Португалии, где много туристов, пляжей, отелей и т.д.
Университет сам по себе довольно неплох и находится в живописном месте и выглядит вот так:

Universidade de Algarve

Стоимость обучения на направлении informatics engineering была около 1500 евро в год, что по меркам Европы всего ничего. Качество обучения конкретно на на этом направлении и в то время — от «очень хорошо» до «так себе». Очень хорошо, потому что некоторые профессоры были действующими сотрудниками компаний, знающими современные штуки, плюс были очень интересными, живыми и давали много практики. Так себе, потому что не все профессоры говорили на английском (по 2 предметам обучение было в виде: возьмите лекции на английском, прочитайте и в конце года будет тест) и организация обучения иностранцев оставляло желать лучшего (ответственная за наш курс только называлась ответственной, но на деле добиться чего-то от неё было тяжеловато). Учебная виза дает возможность работать, если дополнить её разрешением на работу, главное чтобы работа не мешала вашей учебе. Учеба для магистров, в основном, вечерняя, и за пару месяцев я нашел работу в маленькой компании, занимающейся установкой телевидения и интернета для отелей и частных вилл. Получить документы было не так легко, но если работодатель сделает свою часть, то все должно пройти без особых приключений. В Алгарве есть несколько компаний, которые занимаются разработкой, но зарплаты низкие, около 900-1000 евро чистыми для Java мидла. Я жил примерно год в Фару — это город в Алгарве. Там очень красивые пляжи, уютные города, пальмы, ощущения курорта, очень приятные и приветливые люди. Проблема только в том, что зимой жизнь замирает и делать становится нечего, совсем нечего. Все закрыто или закрывается в 6 вечера. Кроме одного торгового центра. Транспорт ходит по выходным раз в 3 часа. В общем зимой там можно сойти с ума от нечего делать, особенно если у вас нет машины, чтобы поехать куда-то. После года все это мне надоело. К тому моменту я закончил курсы программирования по Java и начал искать работу в Лиссабоне.

Лиссабон

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

Коротко о жилищной проблеме в Лиссабоне

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

Центр Лиссабона

Как видите, тут не то чтобы сильно развернешься со строительством отелей.
Выход нашли следующий: если вы богатый китаец, бразилец или вообще кто угодно с деньгами, вы можете приехать в Португалию, купить полу-разрушенный дворец\дом\здание в центре за больше, чем пол миллиона евро и получить Золотую визу, которая как гражданство, только голосовать нельзя. Все эти ребята начали скупать недвижимость в центре Лиссабона, восстанавливать и делать хостелы, мини-отели или апартаменты для туристов. Большое количество желающих на покупку подобной недвижимости, приезжающих в Португалию, понимали, что можно заработать и просто на квартирах, даже если они не в самом центре. А затем, оправившись после кризиса 2008го, куча европейцев, понимая, что дорожающая недвижимость с возможностью её сдачи — это отличный актив, стали приезжать в Португалию и скупать жилье, которое сколько-нибудь близко к туристическим местам. Весь этот бурный спрос на недвижимость, а также то, что большинство строительных компаний во время кризиса разорилось, так ничего и не построив, привело к вакууму на рынке недвижимости и ценам, выше, чем в более развитых государствах Европы. И вот, квартира, которая сдавалась 3 года назад за 600 евро в месяц, сейчас будет стоить вам минимум 950 евро и это будет явно не то, что вы ожидаете получить за эту сумму. Не говоря уже о покупке, когда за чахлую двушку (по-нашему трешку) в неплохом районе просят 300 тыс евро. Правительству на это побоку, ведь они отчасти этого и добивались, так что цены вряд ли пойдут вниз. Люди со средней зарплатой в Лиссабоне в 1000 после налогов, конечно не в восторге, но терпят и живут в пригороде.
В общем, три года назад, посмотрев много вариантов и пожив сначала в комнате, потом в плохом районе со всеми вытекающими прелестями в виде полиции под окнами, иногда скорой и т.п., я таки нашел квартиру близко к центру, не так далеко от метро и в неплохом районе. Но мне повезло.

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

Теперь, собственно, об IT

IT в Португалии растет как на дрожжах. То есть около тысячи новых стартапов в год, некоторые из которых довольно успешно работают как в Португалии, так и по миру. Также, каждый год в Португалию приходят большие компании, вроде Сименса, Нокиа (кто не знает, Нокиа — это не только и не столько китайские мобильники, сколько телекоммуникации, 5G и т.д.), Эрикссон, KPMG, Accenture и тд. и тп. Сейчас заговорили об Амазон и Гугл, но пока непонятно когда. Каждой такой компании, которая нанимает много и сразу, дают хорошие налоговые преференции на 5 лет, а там как договоришься. Местные айтишники имеют хорошее образование (в Португалии вообще образование хорошее. Кстати, все же знают, что Гари Поттера списали с португальских студентов Коимбры?). В последнее время, начали создавать свои хабы для разработки здесь и игроки поменьше, вроде Мерседеса, BMW и тд. В общем, найдется компания в любой сфере, которая вам может нравится.

Но весь этот ажиотаж не просто так. Несмотря на хорошее образование, португальцы не спешат просить большие зарплаты, так что мидл с окладом в 1200 евро чистыми в Лиссабоне — довольно частое явление.
О налогах и зарплатах.
Также, в Португалии довольно высокие налоги, при доходе в 30 тыс в год — 34.6% уйдет государству. При увеличении суммы, процент налога будет непристойно повышаться. Повышаться он будет не только для вас, но и для работодателя, который платит соцстрах и и другие налоги за каждого работника. При чем повышаться будет еще непристойнее. Но хитрые бухгалтеры есть не только в России, поэтому схема обхода налога есть и тут. Сейчас в Лиссабоне около 200 консалтинговых компаний. По сути, это даже не консалтинговая компания, это такая прокладка между вами и компанией в которой вы работаете. Большая компания не будет мухлевать с налогами, потому что это сложно для большой компании, а вот маленькая «прокладка» — пожалуйста. Выглядит это так: вы идете на собеседование в компанию X, которая потом вам говорит, что контракт у вас будет с компанией Y, которая в свою очередь получает деньги за вас от компании X как за оказание услуги. А вам платят низкую базовую сумму плюс бонусы, компенсации за «путешествия» и тд. Все это позволяет всем оставаться счастливыми и не платить высокие налоги, за исключением простого люда, которому пенсии и компенсации по безработице платят с той самой базовой суммы. Но кого это интересует? Главное что здесь и сейчас вы получаете больше денег, а они платят меньше налогов, так что все счастливы.

А сколько собственно платят?

Сложный вопрос, но примерные суммы такие. 1-2 года опыта и хорошие знания в Java — это 1200 евро чистыми(получаете 14 раз в год), 2-4 года опыта 1300-1700 евро чистыми (тоже 14 раз в год), 4 и больше лет опыта 1700 — 2500 евро. Больше пока не встречал. В определенный момент люди идут на менеджеров внутри компании или куда еще…

Что с понаехавшими?

Обычно, когда надо привезти иностранца, то везут бразильцев или граждан ЕС, которым проще с документами помочь… А вот остальным надо пройти 3 круга бюрократического ада местной системы, с чем компании не хотят связываться. Местные компании плохо умеют работать с иммигрантами, но становится лучше и приглашают работать из третьих стран тоже. Как и везде, работодателю надо доказать, что вы незаменимы, получить для вас стопку документов, что очень медленно и тд, поэтому заморачиваться с неопытными скорее всего не будут.
Также, проблема может возникнуть у вашей семьи, если таковая имеется. Проблема с работой. Если ваша вторая половинка представитель профессии не IT и не сферы обслуживания, то найти работу будет проблематично. Вообще, с разнообразием тут беда. 20% вакансий — это IT, менеджеры и HR для IT. 60% — это сфера туризма, кафе, рестораны, отели и вот это вот всё. Остальные — единичные вакансии бухгалтеров, инженеров, экономистов, финансистов, учителей и т.д.

Транспорт

Транспорт в Португалии — это и боль и радость. С одной стороны, вы можете доехать куда надо. Даже отдаленные пляжи и туристические объекты обслуживаются общественным транспортом. В пригороды Лиссабоны ходят автобусы, поезда, электрички и речной транспорт. Всё это по утрам, в следствии с упомянутыми проблемами с недвижимостью, конечно-же, переполнено. И опаздывает. С опозданиями на работе уже никто не парится, а самая частая отмазка — застрял в пробке на мосту, долго ждал автобус и все в таком духе. При этом, если вы хотите приехать на своем автомобили в город, то надо трижды подумать где оставить свой автомобиль. Мест для автомобилей нет и цены кусаются (до 20 евро в день, в зависимости от зоны). Парковку на паркинге компании обычно разыгрывают в лотерею между работниками. Менеджеры получают автоматически.

Медицина в Португалии

Тут сказать можно много всего, но основное вот что: государственная — медленно и бесплатно. Очереди к врачам тянутся на недели, с операциями все еще хуже. Частная — быстро и не очень дорого, если со страховкой. В 99% случаев страховку вам сделает компания. в 60% случаев сделает вашей семье тоже. В остальных случаях Вы можете купить её для себя и/или своей семье у страховой, с которой сотрудничает компания, в которой вы работаете. (20-30 евро в месяц, если у партнерской, 30-60, если у какой-либо другой). Эти цены включают стоматологию. Обычно, консультация со страховкой в частной клинике стоит 15-20 евро. Анализ крови и подобное — 3-5-10 евро.

Жизнь в целом

Португальцы очень хорошо относятся к нормальным эмигрантам. То есть если вы не хамите, не кидаете мусор и не бухаете под окнами, то вам будут помогать, советовать что как делать и тд. Португальцы могут быть очень медленными. Подключить интернет — неделя-две. Постоять в очереди в магазине пол-часа, пока кто-то обсуждает с кассиршей рождение внучки — запросто. Но при этом, многие сервисы вынесены онлайн, что позволяет вам делать многие вещи удобно и быстро. Например, можете оформить контракты на коммунальные, подать декларацию о доходах, оформить страховку, зарегистрировать свою компанию и тд. Подавляющее большинство хорошо говорит на английском. Фильмы не дублируются, меню делают на англ в том числе и тд. Погода хорошая, дожди и серое небо вы будете видеть дней 20-30 в году. Почти все эти дни сконцентрированы в месяце апреле. В большинстве квартир и домов отопления нет. Ночью температура в столице может опуститься до +6. Поэтому обогреватель и теплое одеяло на зиму — необходимость. Днем зимой температура колеблется от 14 до 18 градусов. Солнечно. Летом может быть как прохладно и хорошо(+25), так и слегка жарковато(+44). Жарковато бывает редко, 5-6 дней за лето. Пляжи в полу-часе езды от Лиссабона. Широкие и не очень забиты людьми даже в выходные.

Costa de Caparica

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

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

Очередь на замену прав в 7 утра

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

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

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

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

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


ссылка на оригинал статьи https://habr.com/ru/post/460551/

Опыт моделеварения от команды Computer Vision Mail.ru

Меня зовут Эдуард Тянтов, я руковожу командой Computer Vision в Mail.ru Group. За несколько лет существования наша команда решила десятки задач компьютерного зрения, и сегодня расскажу вам о том, какие методики мы используем для успешного создания моделей машинного обучения, которые работают на широком спектре задач. Поделюсь трюками, которые могут ускорить получение модели на всех этапах: постановка задачи, подготовка данных, обучение и развертывание в продакшен.

Computer Vision в Mail.ru

Начну с того, что такое Computer Vision в Mail.ru, и какими проектами мы занимаемся. Мы предоставляем решения в наши продукты, такие как Почта, Облако Mail.ru (приложение для хранения фото и видео), Vision (B2B-решения на основе компьютерного зрения) и другие. Приведу несколько примеров.

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

Для Почты мы делали OCR — распознавание текста с картинки. О нем я сегодня чуть подробнее расскажу.

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

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

Начнем с критически важной части любой задачи — ее постановки. Практически любая ML-разработка занимает минимум месяц (это в лучшем случае, когда вы знаете, что надо делать), а в большинстве случаев несколько месяцев. Если неверно или неточно поставить задачу, то велик шанс в конце работы услышать от продакт-менеджера что-то в духе: «Все неправильно. Это не годится. Я хотел другое». Чтобы этого не произошло, нужно предпринимать некие шаги. В чем особенность продуктов на основе ML? В отличие от задачи на разработку сайта, задачу в машинном обучении нельзя формализовать одним только текстом. Более того, как правило, неподготовленному человеку кажется, что и все и так очевидно, и просто требуется сделать все «красиво». А уж какие там мелкие детали, постановщик задачи, может быть, даже не знает, никогда о них не думал и не подумает, пока не увидит финальный продукт и скажет: «Что же вы наделали?»

Проблемы

Давайте на примере поймем, какие могут быть проблемы. Допустим, перед вами стоит задача распознавания лиц. Вы ее получаете, радуетесь и звоните маме: «Ура, интересная задача!» Но можно ли прямо срываться и начинать делать? Если так поступить, то в конце вас могут ожидать сюрпризы:

  • Бывают разные национальности. Например, в датасете не было азиатов или еще кого-то. Ваша модель, соответственно, совсем не умеет их распознавать, а продукту это оказалось надо. Или наоборот, вы потратили лишние три месяца на доработку, а в продукте будут только европеоиды, и делать это было необязательно.
  • Бывают дети. Для таких бездетных отцов, как я, все дети на одно лицо. Я абсолютно солидарен с моделью, когда она всех детей отправляет в один кластер — реально ж непонятно, чем отличаются большинство детей! 😉 Но у людей, у которых есть дети, совершенно другое мнение. Обычно они еще и твои руководители. Или бывают еще забавные ошибки распознавания, когда голова ребенка успешно сравнивается с локтем или головой лысого мужика (true story).
  • Что делать с рисованными персонажами, вообще непонятно. Надо их распознавать или нет?

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

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

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

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

Данные

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

А «старые» (классические) алгоритмы с какого-то момента уже не могут улучшиться.

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

Давайте подробнее на примере того же самого распознавания лиц. Допустим, мы скачали «ВКонтакте» аватарки пользователей. К примеру, у нас есть профиль пользователя с 4 аватарками. Мы детектируем лица, которые есть на всех 4 изображениях, и прогоняем через модель распознавания лиц. Так мы получаем эмбеддинги лиц, с помощью которых можно их «склеивать» похожие лица в группы (кластеризовать). Дальше мы выбираем самый большой кластер, предполагая, что аватарки пользователя в основном содержат именно его лицо. Соответственно, все остальные лица (являющиеся шумом) мы таким образом можем вычистить. После этого мы можем снова повторить цикл: на прочищенных данных обучить модель и с ее помощью прочистить данные. Повторять можно несколько раз.

Практически всегда для подобной кластеризации мы используем алгоритмы CLink. Это иерархический алгоритм кластеризации, в котором очень удобно задавать пороговое значение для «склейки» похожих объектов (это как раз то, что требуется для прочистки). CLink генерирует сферические кластеры. Это важно, так как мы часто учим метрическое пространство этих эмбеддингов. Алгоритм имеет сложность О(n2), что, в принципе, ок.

Иногда данные настолько тяжело достать или разметить, что не остается ничего, как только начать их генерировать. Генеративный подход позволяет производить огромное количество данных. Но для этого надо что-то программировать. Самый простой пример — это OCR, распознавание текста на изображениях. Разметка текста для этой задачи дико дорогая и шумная: нужно каждую строчку и каждое слово выделить, подписать текст и так далее. Даже сотню страниц текста асессоры (люди, занимающиеся разметкой) будут размечать крайне долго, а для обучения нужно гораздо больше. Очевидно, что можно каким-то образом сгенерировать текст и как-то его «пошевелить», чтобы модель на нем училась.

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

Иногда нам нужны какие-то объекты реального мира. Например, товары на полках магазинов. Одна их этих картинок автоматически сгенерирована. Как вы думаете, левая или правая?

На самом деле, обе сгенерированы. Если не присматриваться к мелким деталям, то отличия от реальности не заметить. Делаем мы это с помощью Blender (аналог 3dmax).

Основное важное преимущество — это то, что он open source. У него есть отличный Python API, который позволяет прямо в коде размещать объекты, конфигурировать и рандомизировать процесс и в итоге получить разнообразный датасет.

Для рендеринга используется ray tracing. Это достаточно затратная процедура, но она выдает результат с отличным качеством. Самый главный вопрос: где брать модели для объектов? Как правило, их надо покупать. Но если вы бедный студент и хотите с чем-то поэкспериментировать, всегда есть торренты. Понятно, что для продакшена нужно закупать или заказывать у кого-то отрисованные модели.

На этом про данные всё. Перейдем к обучению.

Metric learning

Цель Metric learning — обучить сеть таким образом, чтобы она похожие объекты переводила в похожие регионы в метрическом пространстве embedding. Приведу снова пример с достопримечательностями, который необычен тем, что в сущности это задача классификации, но на десятки тысяч классов. Казалось бы, зачем здесь metric learning, который, как правило, уместен в задачах типа face recognition? Давайте попробуем разобраться.

Если использовать стандартные лоссы при обучении задачи классификации, например Softmax, то классы в метрическом пространстве хорошо разделятся, но в embedding пространстве точки разных классов могут находится близко друг к другу…

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

Center loss программируется буквально в 10 строчек на Python, работает очень быстро, а что самое главное — улучшает качество классификации, т.к. компактность приводит к лучшей обобщающей способности.

Angular Softmax

Мы пробовали множество разных методов metric learning, и пришли к выводу, что Angular Softmax приводит к самым лучшим результатам. Среди research-сообщества он также считается state of the art.

Давайте разберем его на примере face recognition. Вот у нас есть два человека. Если воспользоваться стандартным Softmax, то будет проведена разделяющая плоскость между ними — на основе двух векторов весов. Если сделать норму эмбеддингов 1, то точки лягут на окружность, т.е. на сферу в n-мерном случае (картинка справа).

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

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

Есть несколько вариантов Angular Softmax. Все они играются с тем, умножать на m этот угол или прибавлять, или умножать и прибавлять. State-of-the-art — ArcFace.

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

Разберем на примере Джека Николсона. Прогоняем его фотографию через сетку в процессе обучения. Получаем эмбеддинг, прогоняем через линейный слой для классификации и получаем на выходе скоры, которые отражают степень принадлежности к классу. В данном случае у фотографии Николсона скор 20, самый большой. Далее по формуле из ArcFace мы снижаем скор с 20 до 13 (делается только для groundtruth класса), усложнив таск для нейросети. Дальше мы делаем все, как обычно: Softmax + Cross Entropy.

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

Transfer learning

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

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

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

Мы набрали данных для этой задачи на основе по похожести картинок и кликов пользователей и получили 200к классов. После обучения с ArсFace мы получили следующий результат.

На картинке выше мы видим, что для запрашиваемого пеликана, в выдачу попали еще и воробьи. Т.е. embedding получился семантически верный — это птица, но расово неверный. Самое обидное, что изначальная модель, с которой мы дообучались, знала эти классы и прекрасно их различала. Здесь мы видим эффект, который свойственен всем нейросетям, под названием catastrophic forgetting. То есть сеть при дообучении забывает предыдущий таск, иногда даже полностью. Это как раз то, что мешает в данной задаче достичь лучшего качества.

Knowledge distillation

Лечится это с помощью техники под названием knowledge distillation, когда одна сеть учит другую и “передает ей свои знания”. Как это выглядит (полный пайплайн обучения на картинке ниже).

У нас уже знакомый пайплайн классификации с Arcface. Вспомним, что у нас есть сеть, с которой мы претрейнились. Мы ее заморозили и просто вычисляем ее эмбеддинги на всех фотографиях, на которых мы учим нашу сеть, и получаем скоры классов OpenImages: пеликаны, воробьи, машины, люди и т.д… От исходной обучаемой нейросети отпочковываемся, и учим еще один эмбеддинг под классы OpenImages, который выдает аналогичные скоры. С помощью BCE мы заставляем сеть выдавать похожее распределение этих скоров. Таким образом, с одной стороны мы учим новый таск (в верхней части картинки), но и заставляем сеть не забывать ее корни (в нижней части) — помнить о тех классах, которые она раньше знала. Если правильно сбалансировать градиенты в условной пропорции 50/50, то это позволит оставить всех пеликанов в топе и выкинуть оттуда всех воробьев.

Когда мы это применили, мы получили целый процент в mAP. Это достаточно много.

Модель mAP
Arcface 92,8
+ Knowledge distil 93,8 (+1 %)

Так что если ваша сеть забывает предыдущий таск, то лечите с помощью knowledge distillation — это отлично работает.

Дополнительные головы

Базовая идея очень простая. Снова на примере Face Recognition. У нас в датасете есть набор персон. Но также часто в датасетах есть прочие характеристики лица. Например, сколько лет, какой цвет глаз и т.д. Все это можно добавлять как еще один доп. сигнал: учить отдельные головы на предсказание этих данных. Таким образом, у нас сеть получает больше разнообразного сигнала, и может, как следствие, лучше выучить основной таск.

Еще один пример: детект очередей.

Часто в датасетах с людьми помимо туловища есть отдельная разметка положения головы, что, очевидно, можно использовать. Поэтому мы добавили в сеть к предсказанию bounding box’а человека еще и предсказание bounding box’а головы, и получили прирост в 0,5% к точности (mAP), что прилично. А главное — бесплатно с точки зрения производительности, т.к. на продакшне дополнительная голова «отключается».

OCR

Более сложный и интересный кейс — это OCR, уже упомянутый выше. Стандартный пайплайн такой.

Пусть имеется постер с пингвином, на нем написан текст. С помощью модели детектирования мы выделяем этот текст. Дальше мы этот текст подаем на вход модели распознавания, которая выдает распознанный текст. Допустим, наша сеть ошибается и вместо «i» в слове penguins предсказывает «l». Это на самом деле очень распространенная проблема в OCR, когда сеть путает похожие символы. Вопрос в том, как этого избежать — pengulns перевести в penguins? Когда человек смотрит на этот пример, ему очевидно, что это ошибка, т.к. у него есть знания о структуре языка. Поэтому следует встроить в модель знания о распределении символов и слов в языке.

Мы для этого использовали штуку под названием BPE (byte-pair encoding). Это алгоритм сжатия, который вообще был изобретен еще в 90-х не для машинного обучения, но сейчас он очень популярен и используется в deep learning. Смысл алгоритма в том, что часто встречающиеся подпоследовательности в тексте заменяются на новые символы. Допустим, у нас есть строка «aaabdaaabac», и мы хотим получить для нее BPE. Мы находим, что пара символов «аа» — самая частая в нашем слове. Мы заменяем ее на новый символ «Z», получаем строку «ZabdZabac». Повторяем итерацию: видим, что ab — самая частая подпоследовательность, заменяем ее на «Y», получаем строку «ZYdZYac». Теперь «ZY» — самая частая подпоследовательность, ее мы заменяем на «X», получаем «XdXac». Таким образом, мы кодируем некие статистические зависимости в распределении текста. Если мы встречаем слово, в котором очень «странные» (редкие для обучающего корпуса) подпоследовательности, значит, это слово подозрительное.

aaabdaaabac
ZabdZabac Z=aa
ZYdZYac Y=ab
XdXac X=ZY

Как это всё встраивается в распознавание.

Мы выделили слово «penguin», отправили его в сверточную нейросеть, которая выдала пространственный эмбеддинг (вектор фиксированной длины, например 512). В этом векторе закодирована пространственная информация о символах. Далее мы используем рекуррентную сеть (UPD: на самом деле, мы уже используем модель Transformer), она выдает некие скрытые состояния (зеленые столбики), в каждом из которых зашито распределение вероятностей — какой по мнению модели символ изображен на конкретной позиции. Дальше с помощью CTC-Loss мы раскручиваем эти состояния и получаем наше предсказание для всего слова, но с ошибкой: L на месте i.

Теперь интеграция BPE в пайплайн. Мы хотим уйти от предсказания отдельных символов к словам, поэтому мы делаем ответвление от состояний, в которых зашита информация о символах, и натравливаем на них еще одну рекуррентную сеть; она и предсказывает BPE. В случае с описанной выше ошибкой получается 3 BPE: «peng», «ul», «ns». Это значительно отличается от правильной последовательности для слова penguins, то есть «pen», «gu», «ins». Если посмотреть на это с точки зрения обучения модели, то при посимвольном предсказании сеть ошиблась только в одной букве из восьми (ошибка 12,5 %); а в терминах BPE она ошиблась в 100%, неверно предсказав все 3 BPE. Это гораздо бóльший сигнал для сети, что что-то пошло не так, и надо исправить свое поведение. Когда мы это внедрили, то смогли исправить ошибки подобного рода и уменьшили Word Error Rate на 0,25% — это много. Эта дополнительная голова при инференсе убирается, выполнив свою роль при обучении.

FP16

Последнее, что я хотел сказать про обучение, — это FP16. Так исторически сложилось, что сети обучались на GPU в единичной точности, то есть FP32. Но это избыточно, в особенности для инференса, где хватает и половинной точности (FP16) без потери качества. Однако при обучении это не так.

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

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

Если обучать, используя технику mixed precision, то результат получается практически идентичный FP32. Mixed precision реализует два трюка.

Первый: мы просто умножаем loss на константу, например, 128. Таким образом, мы скейлим все градиенты, и перемещаем их значения от нуля в сторону рабочего рейнджа FP16. Второй: мы храним мастер-версию весов FP32, которая используется только для обновления, а в операциях вычисления forward и backward pass сетей используется только FP16.

Мы используем Pytorch для обучения сетей. NVIDIA сделала для него специальную сборку с так называемым APEX, который реализует описанную выше логику. У него есть два режима. Первый — Automatic mixed precision. По коду ниже можно убедиться на сколько просто его использовать.

В код обучения добавляется буквально две строчки, которые оборачивают loss и процедуру инициализации модели и оптимизаторов. Что делает AMP? Он monkey patch’ит все функции. Что конкретно происходит? Например, он видит, что есть функция свертки, а она получает профит от FP16. Тогда он ее заменяет на свою, которая сначала делает cast к FP16, а потом уже выполняет операцию свертки. Так AMP делает для всех функций, которые могут использоваться в сети. Для каких-то не делает, т.к. не будет ускорения. Для большинства задач этот метод подойдет.

Второй вариант: FP16 optimizer для любителей полного контроля. Подходит в случае, если вы хотите сами задавать какие слои будут в FP16, а какие в FP32. Но в нем есть ряд ограничений и сложностей. Он не заводится с полпинка (по крайней мере нам пришлось попотеть, чтобы его завести). Также FP_optimizer работает только с Adam, да и то только с тем Adam, который есть в APEX (да, у них свой Adam в репозитории, который имеет совершенно другой интерфейс, чем пайторчевый).

Мы провели сравнение при обучении на картах Tesla T4.

На Inference у нас ожидаемое ускорение в два раза. При обучении мы видим, что фреймворк Apex дает 20 % ускорения относительно просто FP16. В итоге мы получаем тренировку, которая в два раза быстрее и потребляет в 2 раза меньше памяти, а качество обучения никак не страдает. Халява.

Inference

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

Есть 3 варианта, как его это делать (и все из них мы использовали(-ем).

  • ONNX -> Caffe2
  • ONNX -> TensorRT
  • И с недавнего времени Pytorch C++

Давайте разберем каждый из них.

ONNX и Caffe2

1,5 года назад появился ONNX. Это специальный фреймворк для конвертации моделей между различными фреймворками. А Caffe2 — фреймворк, смежный с Pytorch, оба разрабатывают в Facebook. Исторически Pytorch развивается гораздо быстрее, чем Caffe2. Caffe2 отстает по фичам от Pytorch, поэтому не каждую модель, которую вы обучили в Pytorch, можно конвертнуть в Caffe2. Часто приходится переучивать с другими слоями. К примеру, в Caffe2 нет такой стандартной операции как upsampling с nearest neighbor interpolation. В итоге мы пришли к тому, что под каждую модель завели специальный docker image, в котором мы прибиваем версии фреймворков гвоздями во избежания расхождений при их будущих обновлений, чтобы когда в очередной раз обновится какая-нибудь из версий, мы не тратили время на их совместимость. Все это не очень удобно и удлиняет процесс деплоя.

Tensor RT

Есть еще Tensor RT, фреймворк от NVIDIA, который оптимизирует архитектуру сети для ускорения инференса. Мы произвели свои замеры (на карте Tesla T4).

Если посмотреть на графики, то можно увидеть, что переход от FP32 к FP16 дает 2x ускорение на Pytorch, а TensorRT при этом дает аж 4x. Очень существенная разница. Мы это тестировали на Tesla T4, у которой есть тензорные ядра, которые как раз очень хорошо утилизируют вычисления FP16, что очевидно отличное используется в TensorRT. Поэтому, если есть высоконагруженная модель, работающая на десятках видеокартах, то есть все мотиваторы попробовать Tensor RT.

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

Pytorch C++

И последнее — Pytorch C++. Полгода назад разработчики Pytorch осознали всю боль людей, которые используют их фреймворк, и выпустили TorchScript tutorial, который позволяет трейсить и сериализовать Python модель в статический граф без лишних телодвижений (JIT). Она вышла в декабре 2018, мы сразу же начали ей пользоваться, сразу же словили несколько багов производительности и ждали несколько месяцев фикса от Чинталы. Но сейчас это достаточно стабильная технология, и мы ее активно используем для всех моделей. Единственное, не хватает документации, которая активно дополняется. Конечно, всегда можно посмотреть по *.h-файлам, но людям, не знающим плюсы, это тяжело. Но зато там действительно идентичная работа с Python. В C++ запускается от-jit’енный код на минимальном интерпретаторе Python’а, что практически гарантирует идентичность С++ с Python.

Выводы

  • Постановка задачи — это суперважно. С продакт-менеджерами общаться нужно обязательно на данных. Перед тем, как начать делать задачу, желательно иметь готовый тестсет, на котором замеряем финальные метрики перед стадией внедрения.
  • Сами данные мы чистим с помощью кластеризации. Получаем модель на исходных данных, чистим данные с помощью кластеризации CLink и повторяем процесс до сходимости.
  • Metric learning: помогает даже классификации. State-of-the-art — ArcFace, который легко интегрировать в процесс обучения.
  • Если вы делаете transfer learning с предобученной сети, то, чтобы сеть не забывала старый таск, используйте knowledge distillation.
  • Также полезно использовать несколько голов сети, которые будут утилизировать разные сигналы из данных, для улучшения основного таска.
  • Для FP16 надо использовать сборки Apex от NVIDIA, Pytorch.
  • И на инференсе удобно использовать Pytorch C++.


ссылка на оригинал статьи https://habr.com/ru/company/mailru/blog/460307/

Древности: Psion 5MX и жизнь на пенсии

Почти десять лет назад я написал один из первых своих постов на Хабр про карманный компьютер Psion 5MX. Уже тогда этот клавиатурный КПК был хоть и приятным, но напрочь устаревшим устройством, и настроение статьи было соответствующее: жалко, но пора отправлять девайс на пенсию. 15 июня 2019 года исполнилось двадцать лет со дня анонса этой модели. Более совместимым с современными компьютерами и интернетом этот КПК не стал, но изменилось мое отношение к старым железкам.

Теперь я стараюсь приставлять их к делу. Я записываю сборники на кассетах (используя, впрочем, весь арсенал современных средств обработки звука), поддерживаю работу собственной BBS, пишу тексты на умеренно древней пишущей машинке с WiFi. Psion 5MX, без сомнений, мое любимое винтажное устройство, поэтому его уж точно стоит достать с полки и попробовать изобразить на нем что-то этакое. Сегодня — рассказ о загробной жизни Psion 5MX.

Дневник коллекционера старых железок я веду в Телеграмме. В ближайших планах — исследование второго в списке любимых устройств — смартфона Nokia N900. И немного магнитофонных технологий из прошлого.

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

Анбоксинг

Подробные характеристики и общие впечатления от Psion 5MX есть в моей старой публикации, поэтому повторяться не буду. Psion Series 5 появились в 1997 году, и представляли собой серьезный апгрейд по сравнению с весьма успешной третьей серией клавиатурных КПК Psion: помощнее процессор (18 мегагерц в Series 5 или 36 мегагерц в 5MX), больше памяти (8 или 16-32 мегабайта), поддержка карт Compact Flash вместо проприетарного стандарта. Новая 32-битная операционная система EPOC32, которая впоследствии стала фундаментом платформы Symbian. Но в этом устройстве важны не спецификации, а плотная интеграция софта и железа. Почти как у Apple в смартфонах времен Стива Джобса. Система и пользовательские приложения настолько хорошо оптимизированы под железо, что до сих пор при использовании 5MX нет ощущения работы со старым и медленным устройством. Экран у 5MX сенсорный, но пользоваться им для навигации не обязательно, все продублировано на клавиатуре. С точки зрения пользовательского экспириенса это идеальное устройство, на уровне современных мощных смартфонов, но при этом выдающее тебе только ту информацию, которую ты просил. Никаких уведомлений о том, что ваше фото полайкали три человека.

За десять лет к моему оригинальному Psion 5MX, который успешно работает по сей день, добавились еще три. Не уверен точно, зачем я их покупал, видимо в приступах острой ностальгии по ушедшим временам. Неважно, зато теперь в моих музейных запасниках есть новое устройство, в том виде, в котором с 1999 по 2001 годы его можно было купить в магазине.

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

Из нестандартных аксессуаров для Psion 5MX в моей коллекции есть адаптер для PCMCIA-модема, очень странное устройство на четырех батарейках. В отличие от Philips Velo 1, встроенного модема в 5MX нет. Реально необходимые для Psion аксессуары — это блок питания и чехол.

Экспериментально было установлено, что 5MX поддерживает карты памяти объемом до 2 гигабайт, и именно такая сейчас установлена в моем устройстве. Это предел возможностей используемой файловой системы FAT. Такой объем Псиону совершенно ни к чему: ни музыку слушать, ни фильмы смотреть на нем не получится. Достаточно 32-64 мегабайта для программ и бэкапа. Сейчас правда проще купить большую флешку, и она скорее всего в этом старом устройстве заработает.

Восстановление

С современной точки зрения главным недостатком Psion 5MX является даже не ограниченная производительность: со всеми своими задачами он хорошо справляется. Экран устройства далек от идеала: на солнце или в темноте он читается нормально, в сумерках будут проблемы. Сложная конструкция устройства обеспечивает расположение дисплея под углом, но наклон не регулируется. Читать книги с вертикальной ориентацией экрана можно, но для этого лучше подходит миниатюрный Palm. Клавиши туговаты и, как и в любых устройствах с маленьким экраном (до сих пор!), в раскладку не помещаются некоторые русские буквы. С точки зрения коллекционера главное слабое место устройства — шлейф между материнской платой и дисплеем (ломается, экран начинает полосить).

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

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

Штатная программа для синхронизации КПК и резервного копирования неплохо работала на Windows 7, но под 64-битной Windows 10 уже не запускается. Для установки программ она, впрочем, и не требуется, в отличие от КПК на базе Palm OS. Достаточно перекинуть на флешку установочные файлы и запустить их уже на самом устройстве. Для других устройств я обычно использую подходящий винтажный ноутбук, но в этом случае у меня есть другой план.

Для начала давайте освоимся в штатном интерфейсе Psion. Кнопки по краям экрана — сенсорные, они отвечают за запуск определенных программ и доступ к настройкам. В любой момент доступно изменение размера шрифтов, отправка файлов через инфракрасный порт и копирование-вставка (также работает со стандартными комбинациями клавиш Ctrl-C/Ctrl-V). Кнопка System открывает по сути простой файловый менеджер, со стандартными опциями работы с файлами и программами. Справа над часами расположены кнопки контекстного меню, уникальные для каждого приложения. В System это «Панель управления»:

Там же расположены кнопки доступа к недавно открытым документам, создания папки или файла. Это четырехкнопочное меню позже переехало без изменений в смартфоны на базе Symbian Series 80.

Сенсорные кнопки под экраном запускают вшитые приложения, а все остальные программы доступны в меню Extras. Если программ много, есть утилиты для разбивки этого меню на отдельные папки, по аналогии с подобными «улучшайзерами» для Palm OS и Windows Mobile.

Первое что нужно сделать на пустом устройстве — установить русификатор. На одном устройстве у меня стоит русификатор Эльбрус, в свое время — коммерческий продукт компании Макцентр. Защита от копирования там реализована путем привязки конкретного дистрибутива к серийному номеру устройства. Хотя эта компания выложила практически все свои разработки двадцатилетней давности в свободный доступ, официальной бесплатной версии Эльбруса кажется до сих пор не существует (только для КПК Diamond Mako, также работающего на EPOC32). Поэтому для других Псионов я использую бесплатный русификатор CyrLat. Его преимущество в том, что он работает не только на американских и британских Psion, но и на устройствах выпущенных для других стран (системный язык на 5MX намертво вшит в ПЗУ, и не меняется, единственное исключение — редкая модель 5MX Pro c 32 мегабайтами RAM).

Если вы собираетесь использовать Psion 5MX в качестве пишущей машинки и оффлайнового органайзера, вам больше ничего не нужно. Встроенный текстовый процессор сохраняет документы в собственном формате, но есть возможность сохранения в текстовом виде прямо на карту Compact Flash. Импорт текстовых файлов также возможен, но при сохранении на компьютере надо менять кодировку на cp1251. «Эльбрус» выводит индикатор раскладки на экран, а переключение возможно привычными кнопками Ctrl+Shift. Большая часть этого текста без всяких проблем была набрана на Psion. Удобно ли это? Смотря с чем сравнивать. Если с сенсорным экраном телефона, то удобно. Если с ноутбуком, то не очень. Зато ни один девайс, даже современный, даже не менее компактный, не обеспечит вам 20-25 часов автономной работы от одного комплекта батареек. Встроенный редактор умеет считать количество слов в документе. Для подсчета символов требуется отдельная утилита.

Браузера в стандартной комплектации Psion 5MX нет, только электронная почта и терминал. Есть, на выбор, браузер от разработчика устройства, с нехитрым названием Web. Его можно установить с комплектного CD, и он бесплатный, но совсем уж старый (разработка закончена в 1999 году). Есть платная версия браузера Opera — она современнее (2001 год), но в с пробным периодом на 30 дней. Но это сейчас любой относительно старый девайс хочется сразу подключить к сети. В начале двухтысячных это было не обязательно, и, откровенно говоря, сеть на Psion я использовал довольно редко. К интернету я этот КПК обязательно подключу, но сегодня статья будет строго про оффлайн.

Привычный для меня твик системы — небольшая утилита nSwitcher, выводящая по требованию список открытых приложений поверх любого окна (на скриншоте вверху) и позволяющая переключаться между приложениями комбинацией Ctrl-Space. Разработчик утилиты — команда Neuon. Они в свое время создали много полезных программ для EPOC32 и ранних смартфонов на Symbian, и бесплатных и коммерческих. Они все (платные — с серийниками) выложены на старом сайте компании.

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

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

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

Кстати о диктофоне. У Psion Series 5 есть встроенный микрофон и динамик, а также кнопки, позволяющие начать запись, не открывая устройство. Поддерживаются базовые возможности редактирования. Программа eNoteM дублирует возможности встроенного диктофона и позволяет сжимать звук в формат MP3 с битрейтом 8 или 16 килобит в секунду. Чуть выше я написал, что музыку на Psion 5MX слушать нельзя, но это не совсем так. Можно, например, с утилитой EPOC MP3 Player, но с ограничением по битрейту (не более 64 килобит в секунду).

Загробная жизнь

Большинство ресурсов, таких как сайты разработчиков и сайт самого прозводителя Psion 5MX, больше не существуют. За редкими исключениями, вроде архива програм Neuon или российского сайта MyPsion.ru. Большое спасибо тем, кто поддерживает его работоспособность, хранит архив программ и полезных статей, помогающих обойти немногочисленные «сложные» моменты при использовании этого КПК. Большинство ссылок на программы в этом посте ведут туда.

Если вы хотите и дальше использовать Psion 5MX в качестве устройства для работы с данными и текстом, то это конечно будет странный выбор, но мой опыт показывает — все возможно. Как минимум в том, что касается работы с текстами, заметками, и даже календарем и задачами. Еще два способа применения такого старого устройства — персональный учет расходов и, например, трат на автомобиль. Для коллекционера будут интересны и исторические программы с какими-то данными. Мой любимый пример — расписание авиарейсов по всему миру, по состоянию на 1999 год.

Десять лет назад мне казался невозможным выпуск устройства в корпусе Psion 5MX, но с новым железом. Тем не менее, это произошло. В 2017 году был выпущен КПК Gemini (на хабре есть пост с впечатлениями), и вот-вот будет выпущено устройство второго поколения, известное как Cosmo Communicator. Их разрабатывает британская компания, а за конструкцию отвечает Мартин Риддифорд, дизайнер оригинального Series 5. Это достаточно мощные Android-устройства, с клавиатурой, которая почти полностью идентична клавиатуре 5MX, со всеми ее достоинствами и недостатками.

И это очень круто, и я уже почти решился на покупку, но передумал. Мне точно не нужно носить с собой два смартфона, а использовать только Gemini или только Cosmo будет неудобно. Как говорил Стив Джобс, главная проблема устройств с клавиатурой в том, что эта клавиатура присутствует всегда, независимо от того, нужна она вам прямо сейчас или нет. В Cosmo пытаются решить этот вопрос при помощи небольшого внешнего экрана, чтобы для ответа на звонок и других базовых действий не требовалось открывать устройство. Если рассматривать клавиатурный КПК как дополнительное устройство, то оригинальный Psion лично мне интереснее. На момент публикации статьи Cosmo все еще можно заказать на странице Indiegogo. Массовое производство задерживается уже на месяц, но судя по регулярным обновлениям, коммуникатор приедет к заказчикам уже скоро.

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


ссылка на оригинал статьи https://habr.com/ru/company/kaspersky/blog/460547/

Как разработать ещё один платформер с помощью Unity. Ещё один туториал, ч.2

В продолжении первой статьи (https://habr.com/ru/post/458846/), продолжаю разрабатывать платформер на основе статьи Паттерны дизайна уровней для 2D-игр (https://habr.com/ru/post/456152/ )

После выпуска первой статьи, однозначно было решено, что кнопочное управление, которое в ней описывалось — совершенно не удобно. Поэтому, Управление в игре было переделано на джойстик. Далее, к сожалению игра не прошла модерацию в плеймаркете. В прошедшую пятницу мне пришло уведомление о том, что проект отклонён по причине сбора метаданных. К слову сказать, мой первый платформер «Рыцарь Кадавар» так же в первый раз был отклонён, по причине якобы запроса на разрешение управления звонками и просмотра смс (что было полнейшей глупостью со стороны их бота. Игра не требовала никаких разрешений). Google тогда потребовал от меня письменное уведомление о том, зачем мне это нужно. Но, всё закончилось тем, что я исправил пару ошибок, которые заметил и отправил игру на повторную модерацию. Она была успешно добавлена в плеймаркет. Сейчас, я планирую сделать точно так же и с этой игрой.

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

Сцена

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

Бонус


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

Реализуем 2 вида бонусов для Лукаса:

  • Аптечка, которая будет выпадать при уничтожении монстров
  • Сундуки с мечами, которые Лукас сможет метать во врагов

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

Затем, модифицируем скрипт Enemy.cs:

Заголовок спойлера

/* Определяем, выпадет ли бонус для игрока при смерти монстра*/ 	[SerializeField] 	private GameObject bonusPref; // Префаб бонуса 	[SerializeField] 	private Transform instBonus; // Откуда будет вылетать бонус 	[SerializeField] 	private int isBonus; // Реализуем с помощью рандома, будет ли выдан бонус 	/* Конец определения бонусов*/  public void ifDie() 	{ 		if (Damage(0) <= 0) 		{ 			isBonus = Random.Range(0,3); 			if (isBonus == 0) 			{ 				Instantiate(bonusPref, instBonus.position, instBonus.rotation); 			} 			Destroy(this.gameObject); 		} 	}

Вызываем функцию с возвращаемым типом Damage(0) и проверяем, возвращает ли Health 0. Если да, что вызываем генератор случайных чисел. Если генератор останавливается на выборе цифры 0, то выбрасываем игроку бонус и уничтожаем монстра.

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

Заголовок спойлера

public void OnTriggerEnter2D(Collider2D collision)     { 		switch (collision.gameObject.tag)         {             case "Player":             { 				HeroScript.Health = 100; 				Destroy(this.gameObject); 			} 			break; 		} 	}

Посмотреть превью ролик

Далее, реализовываем бонус выпадения мечей. Его можно реализовать по тому же принципу, как в первой части реализовывалось выпадение брёвен. Интересная часть будет заключаться в том, что когда Лукас подберёт мечи, их необходимо будет бросать только в зоне видимости противников, а не то тогда, когда Лукас собирает брёвна. Ведь в том виде, в котором сейчас реализована кнопка Атаки\сбора предметов сделала бы именно так. Мечи выбрасывались в любой ситуации. Для этого модифицируем код скрипта атаки\сбора:

Заголовок спойлера

 /* Определяем поля для метания меча */     [SerializeField] 	private GameObject swordPref; // Префаб хранения меча 	[SerializeField] 	private Transform instSword; // Откуда выпускать префаб меча 	[SerializeField] 	private float swordSpeed; // Скорость полёта мечей 	private float attackInBoxX, attackInBoxY; // Для отрисовки куба /* Конец определения полей для метания мечей */  // ED значит EnemyDamage Collider2D[] ED = Physics2D.OverlapBoxAll(Hero.position, new Vector2(attackInBoxX, attackInBoxY), 12, lEnemy); 			{ 				if (ED.Length > 0) 				{ 					if (InventoryOnHero.swordCount  == 0) 					{ 						Debug.Log("Нечем стрелять"); 					} 				 					if (InventoryOnHero.swordCount > 0) 					{ 						instantiateSword(); 						InventoryOnHero.swordCount = InventoryOnHero.swordCount - 1; 					 					} 					else 					{ 						for (int i = 0; i < ED.Length; i++) 						{ 							ED[i].GetComponent<Enemy>().Damage(1); 						} 					} 				} 			}

Что означают данные строчки кода? Сперва, мы определяем массив коллайдеров и проверяем всё, что попало в наш куб

Collider2D[] ED = Physics2D.OverlapBoxAll(Hero.position, new Vector2(attackInBoxX, attackInBoxY), lEnemy);

Обратите внимание в передаваемые параметры, они сильно отличаются от тех, что используются для OvelapCircleAll. Ключевые параметры —

Vector2(attackInBoxX, attackInBoxY)

Затем выполняется условие, если массив коллайдеров больше 0, то мы проверяем инвентарь на наличие мечей. Если количество мечей равно 0, то ничего не делаем и выполняем метод

ED[i].GetComponent<Enemy>().Damage(1);

как если бы это был обычный удар. Если больше 0, то выпускаем меч и уменьшаем количество мечей на 1.

Далее, реализация метода instantiateSword();

Заголовок спойлера

 private void instantiateSword()     { 		GameObject newArrow = Instantiate(swordPref) as GameObject; 		newArrow.transform.position = instSword.transform.position; 		Rigidbody2D rb = newArrow.GetComponent<Rigidbody2D>(); 		if (GameObject.Find("Hero").GetComponent<HeroScript>().localScale.x > 0) 		{ 			rb.velocity = new Vector3(swordSpeed, 0, 0); 		} 		else 		{ 			rb.velocity = new Vector3(-swordSpeed, 0, 0); 			newArrow.transform.Rotate(0,0,-180); 		} 	}

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

(GameObject.Find("Hero").GetComponent<HeroScript>().localScale.x > 0)

Если Лукас смотрит налево, то

rb.velocity = new Vector3(-swordSpeed, 0, 0); newArrow.transform.Rotate(0,0,-180);

меч летит налево и так же вращаем его на 180 градусов.
Посмотреть превью ролик

Выполнив данное действие, мы автоматически закрыли ещё 1 паттерн:

Объект


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

Хотя, вероятнее всего, данный паттерн был реализован раньше, когда был запрограммирован первый монстр.

В итоге, на данный момент осталось не реализовано 3 паттерна:

  • Недостижимая область
  • Механика
  • Босс

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

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

Босс! Так же останется вишенкой на торте. Я хочу сделать его максимально самостоятельным и с возможностью менять своё обличье.

Ссылка на мою витрину приложений в Google Play

Ссылка на Лукаса Джонса на sourceforge.net

Чувствуйте себя свободным и пишите комментарии на хабре или мне на почту worldofonehero@gmail.com.
Благодарю за прочтение, удачи.


ссылка на оригинал статьи https://habr.com/ru/post/460561/

Безумный конвертер GIF’ок в анимированные стикеры для Telegram

Вместо тысячи слов…

xZibit тоже рад, ведь здесь GIF вставлены в стикеры, чтобы быть вставлеными в GIF для КДПВ!

А теперь о подробностях реализации.

Всё началось с дискуссии в чатике Telegram-разработчиков о грядущей фиче:

Bohdan Horbeshko, [04.07.19 20:21] Мда, а бот наверняка будет принимать только gif, и потом конвертить... | Vitaly, [04.07.19 20:22] с гифа в джейсон? я бы посмотрел :))) | Bohdan Horbeshko, [04.07.19 20:22] А почему нет? Вон PlayCanvas'овский редактор модельки в JSON конвертит. | Vitaly, [04.07.19 20:23] а гиф как? попиксельно экспортировать? :) | Bohdan Horbeshko, [04.07.19 20:24] Конечно, мир IT и не такие извращения видал, стерпит.

Мужик сказал — мужик сделал! Первый прототип на Pillow и svgwrite, разбирающий GIF’ку на пиксели и преобразующий их в векторные квадратики с предпросмотром в SVG, был написан за один выходной.

Веселье началось дальше…

JSON — открытый формат, говорили они…

Доселе с форматами в Telegram то и дело хитрили. Сделали поддержку GIF-анимаций — на самом деле они конвертируются в MP4-видео. Сделали поддержку стикеров — выгружаются они в PNG, но преобразуются в WebP. В этот раз всё честнее: что на входе, то и на выходе.

Для анимированных стикеров в Telegram используется не GIF, не видео, и даже не какой-нибудь устоявшийся формат векторной графики типа SVG или — упаси Ктулху! — Flash. В нём задействован новомодный формат, вышедший из-под крыла Airbnb — Lottie. Доселе он имел некоторую известность в среде мобильных разработчиков, но благодаря Telegram, возможно, обретёт бо́льшую популярность.

По сути своей, файлы Lottie являются сериализованными в JSON проектами Adobe After Effects, по максимуму реализующими все возможности этой программы. С отображением, увы, всё не так радужно. Хотя готовых «официальных» реализаций библиотеки для рендеринга Lottie и много, как раз под покрываемые Telegram платформы: Android, iOS, Qt и Web — лишь часть из возможностей формата реализована во всех из них. В Telegram пошли ещё дальше и ограничили перечень поддерживаемых возможностей, а также «придумали» свой формат, который отличается от обычного Lottie всего лишь упаковкой в GZip и параметром "tgs": 1. Кажется, я знаю, где сейчас работает Денис Попов! 🙂

И если с документацией на библиотеки для разных платформ всё довольно неплохо, то найти хоть какое-то описание устройства формата, увы, не удалось — только JSON-схему в исходниках lottie-web. Пришлось попутно ковыряться в существующих анимациях, дабы понять общие концепции формата. Также обнаружились расхождения реальных файлов со схемой: в частности, в слоях типа 4, согласно схеме, вложенные объекты хранятся в свойстве "it" — однако в реальных файлах ключ называется "shapes", а "it" не работает.

Выясненные нюансы формата:

  • Файл состоит из слоёв. В отличие от GIF, здесь у каждого слоя может быть произвольное время начала и конца отображения. К слою можно (точнее, нужно) применять различные трансформации: масштабирование, повороты, изменение прозрачности и т.д. Слои могут быть даже трёхмерными (запрещено для Telegram).
  • Слой состоит из «фигур» (shapes). Типов у них много, некоторе нельзя использовать в Telegram. На практике, чтобы слой отобразился, он должен включать три фигуры: контур (в готовых анимациях это обычно тип "sh" — кривые Безье; конвертер пока использует только тип "rc" — прямоугольники), заливка (тип "fl") и трансформация (тип "tr").
  • Можно даже включать растровые элементы, создавать текстовые слои, устанавливать взаимосвязи параметров слоёв и фигур через выражения. Вся эта вкуснотища также запрещена в Telegram.

Отсюда прямо следует первая проблема: избыточность. Хотя в JSON-схему недавно добавлены значения по умолчанию для параметров трансформаций — в библиотеках они не реализованы. Так что задавать их в явном виде всё равно нужно.

Казалось бы, это и не проблема вовсе? Даже простенький GZip неплохо справляется со сжатием вопиюще повторяющихся данных, и 1 МБ сырого JSON магическим образом превращается в пару десятков килобайт, которые спокойно пролезают в заявленное ограничение в 64 кБ. Не тут-то было!

Загружаю я, значит, пухленькую анимацию, которая спокойно отображается lottie-web, в Telegram — и тут вместо условно красивого пиксель-арта на меня смотрит статическое размазанное вот это:

Что такое?! А оказалось, на разжатые данные тоже есть явно не указанное ограничение в 1 МБ. Представитель команды Telegram оперативно подтвердил его и сообщил о грядущем поднятии лимита до 2 МБ.

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

Прозрачность — это важно

Pillow, наряду с OpenCV, можно назвать индустриальным стандартом для обработки изображений в Python. Мало того, он неплохо заточен и под особенности GIF: поддерживает индексированные цвета, даёт доступ к палитре. Поддерживает преобразование пиксельной карты в NumPy-массив, что важно для продуктивной обработки. Даже статистику по цветам собирает! Но обнаружились и минусы:

  1. Не нашлось задокументированного способа получить индекс прозрачного цвета. Пришлось в качестве временного решения подразумевать, что прозрачный цвет — самый распространённый, но в реальных GIF’ках это не всегда так.
  2. То же самое с задержкой между кадрами: Pillow отдаёт только сами кадры как последовательность изображений, без информации о задержках.
  3. Иногда некорректно накладываются частичные кадры.

Посему пришлось искать замену. В качестве неё выступил модуль gif2numpy. Он «заточен» под особенности GIF и предоставляет доступ ко всем техническим свойствам как изображения, так и отдельных кадров, в том числе GCE. Таким образом, проблему считывания задержек он решает.

Прозрачность, как оказалось, gif2numpy не поддерживает вообще: цвета сразу преобразуются в три канала с разрядностью в байт, без учёта разрядности и сохранения индексов цветов. Благо, модуль состоит из одного файла, так что не составило труда включить его в проект и доработать, зарезервировав под прозрачность цвет #FE00FE.

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

Сожми меня сильнее

Квадратики — это хорошо, но с такими ограничениями нужно проявить больше фантазии, иначе в Telegram не «пролезают» даже миниатюрные GIF’ки.

Первым в ход пошло нечто похоже на RLE: соседние по горизонтали квадратики одного цвета объединяются в один прямоугольник.

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

Планы по развитию

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

  • Распознавать одноцветные области любого размера. Можно разбивать их на набор прямоугольников, для чего есть неплохой алгоритм. Также целесообразно преобразовывать их в контур, но это омрачается необходимостью указывать все точки кривых Безье в Lottie — прямоугольниками в некоторых случаях может быть выгоднее.
  • Распознавать движение. Техника, опять-таки, издревле применяющаяся в видеокодеках. Если один и тот же контур не меняет форму от кадра к кадру, но лишь координаты — стоит вместо дублирования на нескольких слоях поместить его на один слой с трансформацией.
  • Распознавать «накрытие» одних областей другими. Пример:
    ......
    .O..O.
    ......
    .OOOO.
    ......

    На прямоугольник одного цвета накладываются пиксели другого цвета. Вместо того, чтобы разбивать этот прямоугольник на кучу мелких, или пребразовывать в контур сложной формы — можно просто наложить их поверх целого прямоугольника.
  • Векторизация кривых и эллипсов, распознавание градиентов. Это испортит пиксельный шарм, зато на порядки улучшит сжимаемость некоторых GIF’ок. Градиенты есть даже в допотопных «колобках», я гарантирую это! :D
  • Сжатие с потерями. В первую очередь — устранение дизеринга, да и в излишне сглаженных картинках не помешает цвета поумерить. С этим наверняка справится вышеупомянутый gifsicle.

Ссылки

  • Исходники. Местами страшные.
  • Канал, на котором я выкладываю паки успешно сконвертированных GIF’ок.


ссылка на оригинал статьи https://habr.com/ru/post/460411/