-Поиск по дневнику

Поиск сообщений в rss_rss_hh_new

 -Подписка по e-mail

 

 -Статистика

Статистика LiveInternet.ru: показано количество хитов и посетителей
Создан: 17.03.2011
Записей:
Комментариев:
Написано: 51

Habrahabr/New








Добавить любой RSS - источник (включая журнал LiveJournal) в свою ленту друзей вы можете на странице синдикации.

Исходная информация - http://habrahabr.ru/rss/new/.
Данный дневник сформирован из открытого RSS-источника по адресу http://feeds.feedburner.com/xtmb/hh-new-full, и дополняется в соответствии с дополнением данного источника. Он может не соответствовать содержимому оригинальной страницы. Трансляция создана автоматически по запросу читателей этой RSS ленты.
По всем вопросам о работе данного сервиса обращаться со страницы контактной информации.

[Обновить трансляцию]

В сеть утекли исходные коды операционной системы Windows 10 [маленькая часть]

Суббота, 24 Июня 2017 г. 02:53 + в цитатник
UPD Выяснилось, что theregister все сильно преувеличил.

image

По информации портала theregister.co.uk недавно произошла массивная утечка приватных билдов ОС Windows 10 и фрагментов ее исходных кодов.

Массив из 32 терабайтов данных (в архивированном виде — 8 терабайт), состоящий из официальных и приватных образов, закрытой технической документации и исходных текстов, оказался загруженным на ресурс betaarchive.com

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

По сообщениям людей, успевших ознакомиться с материалами внушительного архива, утекшие исходные коды в нем относятся к Microsoft's Shared Source Kit. Этот набор включает в себя исходники базовых драйверов Windows 10, стеков Wi-Fi,USB и PnP, драйверов систем хранения и ARM-версии ядра OneCore.

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

image

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

По мнению Криса Уильямса, редактора theregister, Internet ждет новая волна эксплоитов и вирусов, использующих ранее неизвестные уязвимости в коде новейших версий Windows.

Источник утечки и обстоятельства произошедшего пока не ясны. Представители компании Microsoft на момент публикации никак не про комментировали ситуацию.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331534/


Метки:  

Грех администратора или восстановление данных из стучащего HDD Western Digital WD5000AAKX

Пятница, 23 Июня 2017 г. 23:30 + в цитатник
В одной маленькой софтверной компании хранение данных было организовано следующим образом: сервер, в котором обыкновенные SATA накопители средствами linux (mdamd) организованы в несколько массивов RAID 1, каждый из которых являлся хранилищем для одного из направлений разработки. Данный вариант при минимальных затратах относительно надежен, если за ним подобающим образом присматривать. Но системный администратор решил, что нет нужды регулярно проверять состояние массивов, и занимался иными делами. В июне 2017, получив жалобы о невозможности прочитать данные от пользователей одного из массивов, обнаружил, что собственно массива уже давно нет, и что на один из накопителей запись прекратилась в августе 2015, а второй с актуальными данными при попытке монтирования подвешивает ОС. Резервная копия за пределы сервера последний раз была сделана в ноябре 2016 года.


рис. 1

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

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

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

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

Проводим стандартные диагностические мероприятия: визуальный осмотр, проверка цепей питания на печатной плате, сопротивления обмоток двигателя. Не обнаружив ничего крамольного, подключаем к порту PC3000 и подаем питание. Слышен нормальный звук раскрутки вала, прохождения калибровочного теста. По регистрам накопитель демонстрирует готовность к обмену данными. На запрос паспорта получаем от жесткого диска корректный ответ со всеми данными. Проверяем читабельность модулей микропрограммы и оцениваем их контрольные суммы. При анализе relo-list обнаруживаем, что он не пустой, что свидетельствует о том, что микропрограмма накопителя обнаружила некоторые проблемы на поверхности. Просматривая атрибуты SMART, замечаем, что 197 атрибут (текущее количество нестабильных секторов) весьма далек от нулевого значения, что подтверждает наличие проблем. Модифицируем в ОЗУ накопителя настройки: отключаем процедуры переназначения и добавления дефектов в relo-list, очищаем сам relo-list, запрещаем обновление журналов SMART. После такой модификации накопитель не будет выполнять процедуры оффлайн сканирования и обновлять журналы SMART. На этом этапе производим оценку качества чтения каждой из головок в зонах разной плотности записи. Тест подтверждает пригодность оригинального БМГ для вычитывания данных. Читаем 0 сектор.


рис. 2

Обнаруживаем, что в нем содержатся записи для трех разделов.

По смещению 0x00000800 (2048) секторов располагается первый раздел Linux RAID (0xFD), размер раздела 0x00064000 (409 600) секторов.

По смещению 0x00064800 (411 648) секторов располагается второй раздел Linux RAID (0xFD), размер раздела 0x39DC8000 (970 752 000) секторов.

По смещению 0x39E2C800 (971 163 648) секторов располагается третий раздел linux swap (0x82), размер раздела 0x00400000 (4 194 304) секторов.

Анализ содержимого суперблоков первых двух разделов показывает, что они состояли в массивах RAID 1 и в каждом массиве содержит по одному разделу c Ext4. Выполнив попытку чтения метаданных файловой системы на большом разделе, обнаруживаем, что имеются затруднения в чтении.

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

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

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

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

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

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

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

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

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

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

В условиях ламинарного бокса было произведено вскрытие накопителя. Повреждения БМГ были заметны визуально и даже не требовали снятия для осмотра под микроскопом. Но фотофиксация была сделана.


рис. 3

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

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


рис. 4

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

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

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


рис. 5

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


рис. 6

Запрашиваем паспорт накопителя и получаем пустышку, что свидетельствует о том, что накопитель не смог загрузить из служебной зоны все модули, которые необходимы для старта. Анализируем версию кода в ПЗУ накопителя и подбираем подходящий оверлей из нашей базы данных микропрограмм скопированных из накопителей. После загрузки его в память накопителя получили возможность полноценно читать и анализировать содержимое служебной зоны. По результатам проверки целостности служебной зоны нечитабельными оказались 0x11 (основной оверлей), 0x31 – транслятор, 0x32 – relo-list, 0x33 – P-list, 0x34 – G-list, 0x43 – адаптивные параметры, а также модули, ответственные за работу SMART.

Производим посекторную вычитку наиболее критичных модулей. P-list прочитался с небольшим количеством дефектов, расположение которых достаточно далеко от начала модуля. Аналогичная картина с модулем адаптивных параметров. Модули транслятора, G-list, relo-list оказались нечитабельными на 100%. Подобные повреждения модулей случаются при работе накопителя с не совсем исправными головками при попытке переписать модуль микропрограммой накопителя.

Для восстановления модуля транслятора записываем все необходимое, полученное из служебной зоны пациента, в накопитель-донор, в том числе и реконструированные 0x33 и 0x43. Выполнив пересчет транслятора с учетом P-list получим оригинальный 0x31 модуль за счет работы самой микропрограммы накопителя. Информация о скрытых дефектах в модуле 0x34 безвозвратно потеряна, поэтому создадим модуль пустышку без записей. Аналогичное действие выполним и с модулем 0x32.

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

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

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


рис. 7

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

Изменим чтение с UDMA режима на PIO для лучшего контроля процесса чтения и провизведем вычитку метаданных файловой системы (Ext4) второго раздела. Завершив этут операцию на 99,99% перейдем к чтению мини зон с коротким таймаутом и прыжком 10 000 секторов в случае нестабильности. Данная мера позволила нам дочитать более 85% от непрочитанного объема.

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

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

В процессе проведения работ Заказчику пересылались отчеты о поврежденных файлах после каждой деградации донорского БМГ и согласовывалось использование каждого дополнительного донора. При использовании третьего динамика чтения была малозаметной, по этой причине было принято решение о прекращении дальнейших попыток получить оставшиеся данные из дефектных зон. Удалось получить более 95% всех файлов (и более 99,5% согласно основному техническому заданию). Данный результат удовлетворил Заказчика.

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

Предыдущая публикация: Неглубокое погружение или восстановление данных с жесткого диска после затопления офиса
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331512/


Security Week 25: В *NIX реанимировали древнюю уязвимость, WannaCry оказался не доделан, ЦРУ прослушивает наши роутеры

Пятница, 23 Июня 2017 г. 21:40 + в цитатник
Земля, 2005 год. По всей планете происходят загадочные события: Nokia выводит на рынок планшет на Linux, в глубокой тайне идет разработка игры с участниками группы Metallica в главных ролях, Джобс объявил о переходе Маков на платформу Intel.

Тем временем на конференции CancSecWest Гаэль Делалло из Beijaflore представил фундаментальный доклад об уязвимостях системы управления памятью в разнообразных NIX-ах, и проиллюстрировал свои находки эксплойтами для Apache. Все запатчились. Прошло несколько лет.

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

2016 год. Гуглевский Project Zero разродился исследованием эксплуатации уязвимостей стека ядра под Ubuntu. Оберайде передает в комментах привет. Убунта запатчилась.

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

Эксплойты стека юзермода основаны на простом вопросе – если динамическая область (heap) и стек будут расти навстречу друг другу, то что будет, когда они встретятся? Однако не надо думать, что ядра никсов разрабатывают дураки! Они, конечно же, подумали о таком развитии событий (ну, к нашему времени точно уже додумались). И во всех современных юниксоподобных операционках стек юзермода огорожен специальной страницей памяти, попытка доступа к которой вызывает исключение или завершение процесса.

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

Принцип эксплуатации этого бородатого бага основан на увеличении объема стека без записи в него. Это делается по-разному в разных ОС, например, с помощью рекурсивного вызова процедуры, или многомегабайтными аргументами командной строки. Указатель стека перемещается на его начало (нижний адрес), стек резко наращивается, и – хоп, – указатель стека оказывается уже за сторожевой страницей. Доступа к самой сторожевой странице не происходит, ошибки нет. Получается, что область стека перекрывается с динамической областью.



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

Qualys испытали эту методику лишь локально, но теоретически подобный трюк можно провернуть удаленно, ну или, как минимум, это будет полезно троянцам для повышения собственных привилегий. Исследователи видят два пути исправления этой уязвимости: фантастический и реалистический. Фантастический заключается в раздувании сторожевой страницы как минимум до 1 Мб, а лучше больше. А реалистический – это всего-то перекомпилировать весь код пространства пользователя с опцией -fsatack-check в GCC, после чего указатель стека уже не сможет перепрыгивать сторожевую страницу без записи в нее. А в FreeBSD еще стоит хотя бы включить эту самую сторожевую страницу – по умолчанию она там не задействуется.

Исследователь предположил преждевременные роды WannaCry

Роковой для многих троянец WannaCry то ли сделан кривыми руками, то ли вырвался на волю до того, как его доделали. Такую любопытную теорию высказал Джейк Вильямс из Rendition InfoSec, после глубокого анализа новостей кода EternalBlue и WannaCry. По его мнению, создатели рансомвары допустили несколько «ошеломляющих ошибок».

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

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

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

С гипотезой, что вонакрай – детище криворуких «скрипт-киддис», не вяжется ряд признаков, указывающих на северокорейское происхождение этой эпидемии. Группа Lazarus, которую подозревают в связи с WannaCry, не давала повода обвинить ее в непрофессионализме. Поэтому Вильямс предложил другое объяснение. По его мнению, недоделанный WannaCry попросту случайно вырвался из тестовой среды и дальше пошел распространяться неконтролируемо.

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

ЦРУ годами следит за нашими роутерами

На Wikileaks опубликованы подробности программы ЦРУ по мониторингу трафика, проходящего через роутеры D-Link, Linksys, 3Com и Panet Tec. Поэтично названная Cherry Blossom, программа включает в себя создание особых прошивок, которые прошиваются на роутеры удаленно. Прошивка выглядит как настоящая, но только выдирает из трафика и передает на свой сервер имейл-адреса, имена, встречающиеся в чатах, MAC-адреса, номера VoIP. А в случае необходимости может даже перенаправлять трафик «куда надо».



Единственным более-менее сложным этапом операции выглядит внедрение прошивки на ничего не подозревающий роутер. Однако, что получается у Mirai, точно по плечу детищу ЦРУ – для роутеров агентство разработало эксплойты Tomato и Surfside. Работают они не везде, и для прочих случаев в документации рекомендовано внедрять прошивку оперативным путем. То есть внедриться в компанию-поставщика и втихаря прошить все роутеры на складе. Романтика шпионской работы, как она есть. Все-таки жив в ЦРУ дух старой школы!

Древности


«Justice»

Очень опасен, поражает COM-файлы при обращении к ним функциями DOS 43h, 4Bh, 3Dh, 56h. Записывается в конец файлов и изменяет 5 байт их начала (NOP; NOP; JMP Loc_Virus). COMMAND.COM заражается по алгоритму вируса «Lehigh». Периодически направляет записываемую на диск информацию в сектор с другим номером. Содержит текст «AND JUSTICE FOR ALL». Перехватывает int 13h и int 21h.

Цитата по книге «Компьютерные вирусы в MS-DOS» Евгения Касперского. 1992 год. Страницa 72.

Disclaimer: Данная колонка отражает лишь частное мнение ее автора. Оно может совпадать с позицией компании «Лаборатория Касперского», а может и не совпадать. Тут уж как повезет.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331524/


Метки:  

Результаты внедрения Zextras для SaaS провайдера

Пятница, 23 Июня 2017 г. 19:39 + в цитатник
В этой статье мы хотим рассказать о примере реального внедрения Zimbra Open Source Edition и Zextras Suite для европейского провайдера SaaS услуг, который специализируется на предоставлении услуг государственным, образовательным и медицинским учреждениям. Они предоставляют собственные облачные решения и обслуживают больше 21000 почтовых ящиков для более чем 200 различных доменов. Для модернизации ИТ инфраструктуры, желая предоставлять конечному пользователю высокотехнологичные и безопасные продукты, обеспечить надежную мобильную синхронизацию, управлять хранением файлов и предоставлять мультиаренду, было решено внедрить Zimbra Open Source Edition и полный комплект зимлетов Zextras Suite.

image



Zimbra Open Source Edition — надежный почтовый сервер с высокопроизводительными функциями PIM/collaboration.

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

Внедрение Zimbra и Zextras проходило в несколько этапов:
  • формирование плана модернизации (резервная копия данных, новая конфигурация хранения);
  • установка программного обеспечения;
  • создание backup storage, new life storage configuration.


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

Дизайн Инфраструктуры: Платформа


Для улучшения производительности партнер установил мультисервер Zimbra Collaboration из 15 серверов. Все они размещены в Amazon's EC2:

Mailbox
  • 1 Mailboxd + Master LDAP
  • 4 Mailboxd


Proxy
  • 2 Proxy + LDAP Replica + MTA (специализированный)


MTA
  • 3 Inbound MTA + AS/AV
  • 4 Outbound MTA
  • 1 Outbound MTA (“на домене” для пакетной отправки)
image

Использование Storage


Благодаря сжатию и дедупликации Zextras Backup и Zextras Powerstore, возможна экстремальная оптимизация томов. Общая «пользовательская» квота maiboxes составляла 15.5TB, в то время как фактический общий размер основных объемов составляет 1.8 TB, а фактический общий размер вторичных составляет 9 TB. Это означает сохранение 30% дискового пространства. Вторичные объемы содержат электронные письма, которые хранятся более 90 дней, и сохранены как данные по блокам Amazon S3 с огромной экономией затрат на хранение. Backup занимает в общей сложности 9TB, с сохранением 32 дня после удаления (сохранение нелинейного роста – так в этом конкретном случае его можно было увеличить до 90 дней, даже не удваивая резервный размер).

Дизайн инфраструктуры: Storage


Данные хранятся на дисках Amazon EBS. Amazon EBS позволяет создавать тома хранилища и подключать их к инстансам Amazon EC2. После подключения томов на них можно создавать файловую систему, запускать базы данных или использовать любым другим образом. Тома Amazon EBS расположены в конкретных зонах доступности, внутри которых они автоматически реплицируются, чтобы защитить информацию от сбоя отдельных элементов оборудования. Все типы томов EBS обладают одинаково надежными возможностями создания снимков состояния и обеспечивают доступность на уровне 99,999 %.

Управляется storage через Zimbra Store и Zextras Powerstore, которые обеспечивают и разделение на уровни хранения, и совместимость EC2 блоков Amazon EC2. Модуль Zextras Powerstore позволяет управлять несколькими томами и HSM-политиками через Zimlet управления Zextras, полностью интегрированный в Панель управления Zimbra, что дает эффективное управление хранением.

  • Первичный объем на локальных драйверах (GP2 General Purpouse SSD — Amazon EBS)
  • Вторичный объем на блоках Amazon S3
  • Backup на локальных драйверах (GP2 General Purpouse SSD – Amazon EBS)
  • Компрессия: Первичная: НЕТ| Вторичная: Auto | Backup: Да
  • Дедупликация: Первичная: Периодическая| Вторичная: Auto | Backup: Да



Детальная информация по использованию Storage:

Mailbox 1
Итоговая квота: 4.3 TB
Первичный объем: 367 GB
Backup: 2.7TB (~38% compression)

Mailbox 2
  • Итоговая квота: 4.1 TB
  • Первичный объем: 371 GB
  • Backup: 2.5TB (~40% компрессии)

Mailbox 3
  • Итоговая квота: 4.4TB
  • Первичный объем: 268GB
  • Backup: 2.4TB (~46% компрессия)

Mailbox 4
  • Итоговая квота: 1.9 TB
  • Первичный объем: 349 GB
  • Backup: 1.1TB (~43% компрессии)

Mailbox5
  • Итоговая квота: 775 GB
  • Первичный объем: 419 GB
  • Backup: 379GB (~52% компрессии)


Итоговая квота: 15.5 TB
Итоговый первичный объем: 1.8 TB
Итоговый размер S3 блок: 9 TB
Итоговый размер backup volumes: 9 TB


Клиенты SaaS провайдера также часто требуют, чтобы их IT-специалисты имели права для настройки их домена. Это было реализовано при помощи административного делегирования зимлета Zextras Admin. Этот же модуль позволяет определять пределы для домена на основании контракта с партнером и легко просматривать действия делегированных администраторов в рамках европейского законодательства.

Итого


Затраты SaaS провайдера уменьшились на порядок. Zimbra Open Source Edition + Zextras Suite уменьшили занимаемое место на серверах компании. У пользователей появилась возможность использовать мультиаренду программного обеспечения.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331522/


Метки:  

Как держать 20 тысяч VPN клиентов на серверах за $5

Пятница, 23 Июня 2017 г. 19:21 + в цитатник

Метки:  

CocoaHeads Russia. Прямая трансляция

Пятница, 23 Июня 2017 г. 18:12 + в цитатник
image

Привет, хабраюзеры!

Сегодня (23 июня 2017) в офисе Туту.ру пройдет очередной митап iOS разработчиков. Мы организуем прямую трансляцию митапа. Если вы не смогли к нам попасть, то у вас есть шанс увидеть все online.

Программа


  • 19:10 Открытие
  • 19:15 Анимация как средство самовыражения.
    Александр Зимин
  • 20:00 Перерыв
  • 20:25 Team Lead. Структурирование мыслей.
    Николай Ашанин
  • 21:00 Перерыв
  • 21:15 Викторина
  • 21:35 Реактивный VIPER.
    Дмитрий Котенко
  • 22:00 Автепати (трансляция в личные соцсеточки)


Ссылка на трансляцию


Будет доступна за 5 минут до открытия
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331520/


Метки:  

Борьба со спамом на хостинге. Настройка EFA Project Free Spam/antivirus filter

Пятница, 23 Июня 2017 г. 18:00 + в цитатник

image


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


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


Спам не любят. Спам оставляет «чёрное пятно» на лице провайдера, когда его IP адреса вносят в блеклисты, от чего страдают все клиенты. Удалить IP из блеклистов — особый разговор. Но это одна сторона медали. Если вернуть репутацию IP адресу можно, то вернуть репутацию компании и доверие — намного сложнее.


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


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


Популярные opensource-решения против спама


Rspamd


Он подходит для систем различного масштаба. Умеет интегрироваться в различные MTA (в документации описаны Exim, Postfix, Sendmail и Haraka) или работать в режиме SMTP-прокси.


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


В Rspamd поддерживается расширение при помощи плагинов.


Apache SpamAssassin


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


Легко интегрируется практически с любым почтовым сервисом. В SA доступны популярные технологии, которые подключаются как плагины: DNSBL, SPF, DKIM, URIBL, SURBL, PSBL, Razor, RelayCountry, автоматическое ведение белого списка (AWL) и другие.


Установка в общем не сложна. После установки SpamAssassin требует тонкой настройки параметров и обучения на спам-письмах.


ASSP


Платформно-зависимый SMTP-прокси-сервер, принимающий сообщения до MTA и анализирующий его на спам.


Поддерживаются все популярные технологии: белые и серые списки, байесовский фильтр, DNSBL, DNSWL, URIBL, SPF, DKIM, SRS, проверка на вирусы (с ClamAV), блокировка или замена вложений и многое другое. Обнаруживается кодированный MIME-спам и картинки (при помощи Tesseract). Возможности расширяются при помощи модулей.


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


MailScanner


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


MailScanner легко интегрируется с любым МТА, в поставке есть готовые конфигурационные файлы. Помимо собственных наработок, он может использовать сторонние решения. Для проверки на спам может использоваться SpamAssassin.


EFA-project


Есть еще один Open Source проект — «eFa-project» — Email Filter Appliance. EFA изначально разработан как виртуальное устройство для работы на Vmware или HyperV. Программа использует готовые пакеты MailScanner, Postfix, SpamAssasin (весь список ниже) для остановки спама и вирусов и они уже установлены и настроены для правильной работы в vm. Это значит, что костыли не нужны — все работает «из коробки».


В EFA входят такие компоненты:


В качестве MTA (mail transfer agent) выступает Postfix — надежный, быстрый, проверенный годами;
Ядро спам фильтра — MailScanner — плечом к плечу с антивирусом принимают на себя весь удар;
Спам фильтр — SpamAssassin — определяет письма-спам. В основу включено множество оценочных систем, MTA и наборы регулярных выражений;
ClamAV — антивирус, который работает с MailScanner;
MailWatch — удобный веб-интерфейс для работы с MailScanner и другими приложениями;
Фильтр контента — DCC — определяет массовую рассылку через отправку хеш-сумм тела писем на специальный сервер, который в свою очередь предоставляет ответ в виде числа полученных хешей. Если число превышает порог score=6, письмо считается спамом;
Pyzor и Razor — помогают SpamAssassin точнее распознавать спам, используя сети по обнаружению спама;
Для grey-листинга используется SQLgrey — служба политики postfix, позволяющая снизить количество спама, которое может быть принято получателями;
Для распознавания изображений используется модуль ImageCeberus — определяет порно изображения и т.д.
Мы выбрали EFA, поскольку проект включает в себя все лучшие характеристики вышеперечисленных. К тому же наши администраторы уже имели некоторый опыт работы с ним, поэтому выбор остановили именно на EFA. Приступим к описанию установки.


Установка и последующая настройка EFA


Устанавливать решили на VPS с чистой CentOS 6.8 x64, который выступает в качестве relay-сервера. Первым делом, необходимо обновить все системные утилиты и компоненты до последних версий, которые доступны в репозиториях. Для этого используем команду:


yum -y update

Затем устанавливаем утилиты wget и screen, если они не были установлены:


yum -y install wget screen

После чего, скачаем скрипт, который выполнит установку EFA:


wget https://raw.githubusercontent.com/E-F-A/v3/master/build/prepare-build-without-ks.bash

Даем скрипту права на исполнение:


chmod +x ./prepare-build-without-ks.bash

Запускаем screen:


screen

И запускаем скрипт:


./prepare-build-without-ks.bash

Теперь можно свернуть наш скрин используя комбинацию Ctrl + A + D.


После установки нужно заново войти на сервер через ssh, используя данные для первого входа. Это нужно для запуска скрипта инициализации и первичной настройки EFA.


После входа, система предлагает ответить на несколько вопросов, чтобы настроить EFA.


Список вопросов выглядит следующим образом:


Функция Свойство
Hostname Указывается хостнейм машины
Domainname Домен, к которому относится машина. В сумме с хостнеймом, получится полный FQDN сервера
Adminemail Ящик администратора, который будет получать письма от самой системы (доступные обновления, различные отчеты и т.д.)
Postmasteremail Ящик человека, который будет получать письма, которые имеют отношение к MTA
IP address IP адрес машины
Netmask Маска
Default Gateway Шлюз
Primary DNS Первичный DNS сервер
Secondary DNS Вторичный DNS сервер
Local User Логин локального администратора. Используется для входа в систему и в веб-интерфейс MailWatch
Local User Password Пароль
Root Password Пароль для пользователя root
VMware tools Будет отображаться только, если установка происходит на виртуальную машину под управлением VMware. Она необходима для установки инструментов по работе с VMware
UTC Time Если Ваша машина находится в часовом поясе UTC, необходимо выбрать Yes
Timezone Тут можно выбрать другой часовой пояс, отличный от UTC
Keyboard Layout Раскладка клавиатуры, которая будет использоваться в системе
IANA Code Тут указывается код страны, в которой находится машина. Это необходимо для того, чтобы определить, с каких зеркал в будущем будут скачиваться обновления
Your mailserver Индивидуальный параметр. Используется в случае если EFA работает и на приём писем
Your organization name Название организации. Используется для заголовков в письмах
Auto Updates Задается политика автообновлений. По умолчанию установлено disabled. В этом случае, автообновлений не будет, но на емейл админа будут приходить уведомления о доступных обновлениях

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


image


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


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


  • Перезагрузка / выключение системы;
  • Изменение сетевых параметров;
  • Настройка MailScanner;
  • Включение / выключение grey-листинг;
  • Включение / отключение автообновления;
  • Настройка системы как исходящего relay-сервера;
  • Изменение ящика Adminemail;
  • Добавление / удаление почтовых доменов;
  • Изменение настроек фильтров спама;
  • Восстановление mysql базу, в случае повреждения из-за аварийного завершения работы.

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


Ручная настройка EFA


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


Первым делом в файле main.cf настроек postfix добавили mynetworks, с которых принимались соединения по SMTP. Затем прописали ограничения по helo запросам, отправителям, получателям, и указали пути к картам с политиками ACCEPT или REJECT при соблюдении определенных условий. Также, inet_protocols был изменен на ipv4, чтобы исключить соединения по ipv6.


Затем изменили политику Spam Actions на Store в конфигурационном файле /etc/MailScanner/MailScanner.conf. Это значит, что если письмо будет определено как спам, оно уйдет в карантин. Это помогает дополнительно обучать SpamAssassin.


После таких настроек мы столкнулись с первой проблемой. На нас обрушились тысячи писем от адресатов you@example.com, fail2ban@example.com, root@localhost.localdomain и т.д. Получатели были схожие. Также получили письма, отправленные MAILER-DAEMON, то есть фактически без отправителя.


В итоге получили забитую очередь без возможности найти среди «красного полотна» нормальные, письма не-спам. Решили делать REJECT подобных писем, используя стандартный функционал Postfix карт: helo_access, recipient_access, sender_access. Теперь вредные адресаты и подобные стали успешно REJECT’иться. А те письма, которые отправлялись MAILER-DAEMON отфильтровываются по helo запросам.


Когда очередь вычистили, а наши нервы успокоились, начали настраивать SpamAssassin.


Обучение SpamAssassin


Обучение SpamAssassin делается на письмах, которые уже попали в спам. Делать это можно двумя способами.


Через веб-интерфейс


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


Score Matching Rule Description
-0.02 AWL Adjusted score from AWL reputation of From: address
0.80 BAYES_50 Bayes spam probability is 40 to 60%
0.90 DKIM_ADSP_NXDOMAIN No valid author signature and domain not in DNS
0.00 HTML_MESSAGE HTML included in message
1.00 KAM_LAZY_DOMAIN_SECURITY Sending domain does not have any anti-forgery methods
0.00 NO_DNS_FOR_FROM Envelope sender has no MX or A DNS records
0.79 RDNS_NONE Delivered to internal network by a host with no rDNS
2.00 TO_NO_BRKTS_HTML_IMG To: lacks brackets and HTML and one image
0.00 WEIRD_PORT Uses non-standard port number for HTTP

Открыв письмо, можно поставить галку в чекбоксе «SA Learn» и выбрать одно из нескольких действий:


  • As Ham — пометить письмо как чистое (тренировка алгоритма Байеса);
  • As Spam — пометить письмо как спам (тренировка алгоритма Байеса);
  • Forget — пропустить письмо;
  • As Spam+Report — пометить письмо как спам и отправить информацию о нём в сети по обнаружению спама (razor + pyzor);
  • As Ham+Revoke — пометить письмо как чистое и отправить информацию о нём в сети по обнаружению спама (razor + pyzor).

Через консоль


Делается это просто. Команда выглядит следующим образом:


sa-learn --ham /20170224/spam/0DC5B48D4.A739D

В этой команде письмо с ID: 0DC5B48D4.A739D, которое находится в архиве спам писем за определенную дату /20170224/spam/, помечается как чистое (не спам) bash--ham.


Бытует мнение, что достаточно обучать SpamAssassin только для эффективной фильтрации почты. Мы решили тренировать SpamAssassin, скармливая ему абсолютно все письма, как чистые, так и спам. В дополнение, мы нашли базу спам-писем и отдали SA на растерзание.


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


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




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


P.S.: Эта статья не является панацеей. Мы просто решили поделиться с вами одним из наших методов борьбы со спамом.


Всем добра и may the ham be with you! :)

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331498/


Метки:  

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

Пятница, 23 Июня 2017 г. 17:10 + в цитатник
Несмотря на всеобщий хайп вокруг машинного обучения и нейронных сетей, несомненно, сейчас на них действительно стоит обратить особое внимание. Почему? Вот ключевые причины:

  1. Железо стало гораздо быстрее и можно легко обсчитывать модели на GPU
  2. Появилась куча неплохих бесплатных фреймворков для нейросетей
  3. Одурманенные предыдущим хайпом, компании стали собирать бигдату — теперь есть на чем тренироваться!
  4. Нейронки в некоторых областях приблизились к человеку, а в некоторых — уже превзошли в решении ряда задач (где тут лопаты продают, надо срочно бункер рыть)

Но управлять этим, по прежнему, сложно: много математики, высшей и беспощадной. И либо ты из физмата, либо сиди и решай 2-3 тысячи задачек в течении двух-трех лет, чтобы понимать, о чем идет речь. Разобраться по дороге на собеседование в электричке, полистав книжку «Программирование на PHP/JavaScript за 3 дня» — не получится, ну никак, и списать никто не даст (даже за ящик водки).


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

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

Красота теории и практика


Даже в такой, казалось бы, интуитивно понятной и прикладной до уровня «АК-47» области, как обработка реляционных данных, крупная и очень известная компания IBM в свое время замучилась и, по сути, «выдавила» старика Кодда, знаменитого создателя «языка для базок», для прогулок на все четыре стороны. Что же произошло? Кодд утверждал, что SQL, распространяемый IBM — это зло, он не строг и не полон и не соответствует строгой и красивой теории :-) Тем не менее, мы же все пользуемся SQL до сих пор и… ничего, живые.

Примерно то же происходит сейчас и с машинным обучением. С одной стороны еженедельно или, даже, чаще, выходят окрыляющие научные публикации на тему внезапной победы ГироДраконов (имеющих в физиологических шариках — гироскопы) над ГиперКашалотами в Тьюринг-пространствах в созвездии Маленького Принца, массово появляются бесплатные прототипы на github и в дистрибутивах нейронных фреймворков, которые понимают смысл вопроса на 5% лучше предыдущих прототипов — но, по сути, продолжая ни черта не понимать суть. Одновременно с этим, путем сильнейшего группового насилия над нейросетью и самой идеей обучения с подкреплением в пространствах огромной размерности — она вдруг начинает обыигрывать Atari в двумерные игры и про победу нейросетей над чемпионами в Go, наверно, все давно знают уже. А с другой, бизнес начинает осознавать, что область еще очень сырая, находится в фазе бурного роста и прикладных, эффективно решающих задачи людей кейсов еще очень мало — хотя они, безусловно, есть и просто поражают. К сожалению, гораздо больше академических игрушек: нейронки старят лица, генерят порно (не гуглите, потеряете потенцию на сутки) и создают глючную верстку по дизайну веб-страниц.


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

А реальный, потрясающий успех в некоторых сферах, таких как, например, распознавание образов, достигнут ценой обучения огромных сверточных сетей из сотен слоев — что могут себе позволить, пожалуй, только гиганты индустрии: Google, Microsoft… Аналогично дело обстоит и с машинным переводом: вам нужны большие, очень большие, объемы данных и большие вычислительные мощности.

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

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


Вы думаете, что развернуть Hadoop без помощи понимающих системных администраторов — просто? Пойдите лучше и похрюкайте вместе с этим стадом :)

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

Поэтому рассчитывать на то, что вы займетесь deeplearning «на коленке» и что-то из этого полезного получится и быстро — не стоит (ударение на букву «о»). Нужно и знать немало и работать в «поте лица своего».

Бизнес-кейсы алгоритмов ML — в сухом остатке


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

  1. Классификация чего угодно на несколько классов (спам/не спам, купит/не купит, уволится/не уволится)
  2. Персонализация: какой товар/услугу человек купит, уже купив другие?
  3. Регрессия чего угодно в циферку: определяем цену квартиры по ее параметрам, цену автомобиля, потенциальный доход клиента по его характеристикам
  4. Кластеризация чего угодно в несколько групп
  5. Обогащение бизнесовых датасетов или предобучение с помощью GAN
  6. Перевод одной последовательности в другую: Next Best Offer, циклы лояльности клиента и др.


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

Бизнес-менеджерам, тем временем, ничего не остается делать, как с утра до вечера кидать в разработчиков учебниками математики со словами: «ну найдите же прикладное применение этим алгоритмам, for-fan — не предлагать!» и нанимать экспертов, понимающих научные публикации и способные, хотя бы на python, писать адекватный код.

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


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

Выбор алгоритма, почему нейронки


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

  1. За счет факторизации слоев и нелинейности, они способны аппроксимировать гораздо более сложные паттерны меньшим числом слоев, чем плоско-широкие модели
  2. Нейросети, при достаточном числе обучающих примеров, лучше работают с новыми данными «by design» (генерализация лучше)
  3. Нейросети могут работать лучше классических моделей и даже лучше моделей, которые предварительно парсят тексты и вычленяют из них смысловые отношения между словами и предложениями.
  4. Если использовать регуляризацию, похожую на действие алкоголя в мозге человека (dropout), то нейросети адекватно сходятся и не сильно страдают от переобучения

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

Обучается нейросеть часа полтора (без GPU, а на нем гораздо быстрее) и использует для обучения датасет ~ 100к привязок вопросов к категориям.

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

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

  1. код на PHP
  2. верстку
  3. мат-перемат-сленг
  4. описание проблемы, задачи, идеи
  5. ссылки на файлы внутри продукта

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

Вот как это работает изнутри:


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


В голове у этого астродроида не очень мощная нейросеть — но он, тем не менее, иногда ошибаясь, приносит много пользы на протяжении 6 частей (или уже 7) киносаги

Планы на будущее


Сейчас мы экспериментируем на Keras с другими архитектурами текстовых классификаторов:

— на базе рекуррентной сети
— на базе сверточной сети
— на базе bag-of-words

Лучше всего работает многослойный классификатор, на вход которого подаются one-hot вектора символов (из небольшого словаря символов корпуса), затем проходит несколько слоев 1D-свертки c global-max/average pooling и на выходе стоит обычная feed-forward слой с softmax. Подобный классификатор обучить сквозным способом так и не получилось, и даже batch normalization не помог (надо было меньше на девушек заглядываться и слушать преподавателя) — но удалось таки хорошенько ее обучить путем последовательного обучения слоя за слоем. Видимо, когда мы придумаем, как вместо тензоров на java эффективно использовать тензоры на Keras/python/Tensorflow на production — мы обязательно выкатим эту архитектуру на бой и еще больше обрадуем наших менеджеров и клиентов.

Так работает не всем понятная 1D-свертка. Можно сказать, что создаются kernels (сверточные ядра), определяющие 1-2-3-n цепочки символов, «аля» мульти-nrgams модель. В нашем случае лучше всего работает 1D-свертка с окном 9.

В завершении поста, дорогие друзья, желаю вам не тушевать перед ML и нейронками, смело брать их и использовать, строить и обучать модели и уверен, вы сами увидите, как AI эффективно работает, как помогает снять с людей рутину и увеличить качество ваших сервисов. Всем удачи и хорошего и, главное, быстрого схождения нейросетей! Целую нежно.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331304/


Метки:  

[Из песочницы] Symfony 4: структура приложения

Пятница, 23 Июня 2017 г. 16:52 + в цитатник
Данный пост написан на основе публикации Фабьена Потенсье.

В свое время в Symfony 3 появились каталоги bin/, src/, var/, что по-моему мнению очень удобно и понятно. Мы все привыкли работать с такими каталогами. В свою очередь, Symfony 4 движется в этом же направлении и предлагает обновленную структуру каталогов приложения.

tests/ для тестов


Все тесты теперь будут располагаться непосредственно в каталоге tests/. Ранее в каталоге tests/ всегда присутствовали каталоги с именами бандлов вашего приложения в которых находились тесты. В Symfony 4, приложения не будут (или не обязательно должны) реализовывать код в каком либо бандле. Это позволит определить собственное пространство имен тестов для автозагрузки:

{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    },
    "autoload-dev": {
        "psr-4": {
            "App\\Tests\\": "tests/"
        }
    }
}


templates/ для шаблонов


При установке шаблонизатора Twig, теперь будет создаваться каталог templates/ в корне приложения, где и будут размещаться все шаблоны. Мне очень нравится эта идея, потому что каталог Resources, который содержал в себе до этого и публичные файлы (css, js и т.п.) и шаблоны, вносил некоторый дискомфорт. Возможно, что каталог будет называться tpl/, это еще пока окончательно не известно. В целом, перемещение шаблонов из каталога src/ делает приложение более структурированным. Теперь в src/ лежит только код. Класс Kernel, который ранее располагался в папке app/, так же перемещен в src/ где ему и место.

etc/ для конфигураций


Каталог etc/ заменит существовавший ранее app/config. Параметры окружения, которые ранее определялись в файле parameters.yml, теперь конфигурируются с помощью переменных окружения операционной системы. По умолчанию в каталоге etc/ вы обнаружите пустой файл container.yaml (yaml — это не опечатка, в Symfony 4 конфигурационные файлы в формате YAML, теперь имеют расширение yaml, вместо yml)в котором как и прежде можете определять конфигурацию контейнера. Так же там будет файл routing.yaml. В данных файлах вы будете определять только собственные настройки. Компоненты, установленные с помощью Composer, будут хранить свои настройки в отдельных файлах для каждого окружения.

Конфигурацию как и прежде можно будет задавать в трех форматах: YAML, XML, PHP. Помимо конфигурационных файлов, в каталоге etc/ появится bundles.php, который будет представлен массивом бандлов, активных в вашей системе.

//bundles.php

https://habrahabr.ru/post/331516/


Метки:  

[Перевод] Как мы собрали 1500 звезд на Гитхабе, соединив проверенную временем технологию и новый интерфейс

Пятница, 23 Июня 2017 г. 16:25 + в цитатник


Недавно мы выпустили инструмент с открытым исходным кодом GraphQL Voyager. Удивительно, но он попал на первую страницу новостей Hacker News и GitHub, и в первые несколько дней получил 1000+ звезд. Сейчас у него уже более 1600 звезд.*


Людям понравился гладкий интерфейс, интерактивные функции и анимация. Мы использовали TypeScript, React, Redux, webpack и даже PostCSS, но это НЕ еще одна статья об этом. Давайте заглянем под капот...


Наша предыстория


Все началось несколько месяцев назад. Мой друг и я (мы называем себя APIs.guru) искали идею для проекта вокруг GraphQL (язык запросов для API, разработанных Facebook). После некоторых исследований нам попался на глаза один интересный инструмент — GraphQL Visualizer.


Вот что мы получили на выходе из GraphQL Visualizer:



Нам захотелось в него добавить:


  • Цвета (черно-белое выглядело слишком скучно)
  • Возможность масштабирования
  • Интерактивные функции, такие как выбор вершин и ребер

Но, посмотрев исходный код, мы обнаружили фатальный недостаток этой штуки: там использовался Graphviz — инструмент, разработанный десятки лет назад, написанный на обычном C и скомпилированный в нечитабельный JavaScript с использованием Emscripten.


Выглядит даже хуже, чем то, что вылазит обычно из Uglify.js:



Как мы можем использовать что-то из 2000-го года? Мы же хипстеры, в конце концов! ReactJS, D3, webpack, TypeScript, PostCSS — вот с чем мы работаем! Не с инструментами, написанными на старомодном C .


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


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

И это мы даже не отобразили на этом графике все детали! Что за мешанина!


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


Оказалось, что в cytoscape.js нельзя сделать так, чтобы ребра не пересекались с вершинами графа. Мы перепробовали все варианты. Мы гуглили. Мы задавали вопросы на StackOverflow. Мы даже побеспокоили нескольких знакомых гуру SVG. Безуспешно :(


От безысходности я даже попытался хакнуть cytoscape.js, чтобы добиться читабельного результата. Ещё немного изучив этот вопрос, я вынужден был сдаться: видимо, визуализация графов — это и в самом деле rocket science (даже для магистра по прикладной математике).


Мы были побеждены...


И тогда нас осенило. А что, если мы возьмём результат работы Graphviz (это ведь просто SVG) и причешем его при помощи CSS и JS?


И это сработало



Намного лучше! И код написан меньше, чем за день .


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



Да, мы написали несколько сотен строк уродливых манипуляций с DOM. Да, мы упаковали весь этот бардак НЕ в виде чистого компонента React / Redux. И да, код Graphviz настолько большой, что мы выделили его в отдельный файл размером 2 МБ. Но это работает, и всем пофигу. Что подтверждается 1600 звездами на GitHub.


Апдейт: с момента представления статьи времени нашу разработку взяли на вооружение компании в этой области (например, Graphcool, Neo4j), и её показали на GraphQL Europe, так что уже не только 1600 звезд подтверждают это :)


Уроки выучены


«Если я видел дальше других, то потому, что стоял на плечах гигантов». — Исаак Ньютон

Не судите код по его возрасту. Особенно, если он был написан такими технологическими гигантами, как AT&T Labs (где родилась ОС Unix и языки C и C++).


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


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


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


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


«Эмм… ты обещал мне рассказать, как получить много звезд»


Упс… Ладно. И правда. Я хотел сделать заголовок достаточно запоминающимся.


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


  • Попытайтесь использовать название своей технологии в имени проекта (например, graphql-что-то, react-что-то и т.д.). Тогда ваш проект будет иметь более высокий ранг в результатах поиска GitHub для этих технологий.
  • Ваш README-файл должен привлекать внимание. Мы положили гифку в шапке нашего README, чтобы люди могли сразу понять, о чем идет речь в нашем проекте. Если это консольное приложение — добавьте гифку с консолью (вот замечательный пример).
  • Больше свистелок и перделок: добавьте значки, добавьте красивый логотип, добавьте эмодзи
  • Соберите демо-версию, если это возможно, и добавьте её в ссылку в строке с описанием репозитория:


  • Повторяю, сделайте демку! И не забудьте добавить ссылку с неё обратно на GitHub (мы используем GitHub Corners).
  • Прежде чем постить свой проект в HackerNews / Reddit / и т.д., получите начальное число звезд (5-10), разместив его на менее популярных ресурсах или поделившись им со своими друзьями. Люди с меньшей вероятностью нажимают «звезду» на проектах с нулевым числом звезд.
  • Попытайтесь получить 30-40 звезд в первый день. Тогда, вас, скорее всего, зафичерят в GitHub trending для вашего языка программирования, а это еще один источник трафика.
  • Сделайте что-нибудь полезное.

Есть еще несколько статей о том, как продвигать проекты с открытым исходным кодом: здесь, здесь и здесь.




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


* Примечание переводчика: спустя неделю после оригинальной публикации у проекта уже 2000+ звезд.
** Заглавная картинка, как и в исходном посте, взята с сайта www.k3projektwheels.com.

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331514/


Метки:  

ECS (Elastic Cloud Storage) - облачная платформа хранения Dell EMC

Пятница, 23 Июня 2017 г. 16:05 + в цитатник
Объемы неструктурированных данных растут в геометрической прогрессии, и не похоже, чтобы этот процесс замедлялся. Некоторым организациям пока удается управлять ими с помощью традиционной инфраструктуры хранения, но она дорого обходится и не поддерживает масштабирование в соответствии с ростом объема данных.

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


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

Что такое ECS?


Сперва нужно отметить, что ECS - не публичный Cloud Storage, когда пользователь не знает, где хранятся его данные. Напротив, Dell EMC (Elastic Cloud Storage) — физический массив хранения (хотя есть и версия в виде ПО), и клиент сам выбирает, где его разместить. А облачным хранилищем ECS называется, поскольку систему можно использовать именно с такой целью.  

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

Заказчики могут приобрести ECS как готовую программно-аппаратную систему (решение Dell EMC ECS Appliance) или в виде программного продукта (ПО ECS): он устанавливается на серверы заказчика и типовые диски, сертифицированные Dell EMC. В состав ECS входит модуль хранения неструктурированных данных, который поддерживает сервисы управления объектами и HDFS, а также поддержка файловых сервисов.

Технически эта система представляет собой:

  • сервер Intel x86 с подключенными к нему полками JBOD (до 60 дисков на сервер),
  • сетевые адаптеры 10GbE для подключения узлов.

Конфигурация системы включает 4/8 узлов. Емкость решения достигает 3840 Tбайт на стойку.
 
ECS - объектная система хранения данных третьего поколения. Она позволяет:

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

Преимущества объектного хранилища:

  • Доступ к объектам предоставляется по специализированным протоколам. В отличие от блочных или файловых, они работают поверх HTTP и основаны на REST: S3, Swift, Atmos.
  • Ориентированность на хранение неструктурированной информации (любые файлы, которые являются статическим или динамическим контентом на стороне клиента).
  • Каждый объект обладает уникальным адресом.
  • Глобальное пространство имен объектов: любой объект доступен в любой момент из любого сегмента инфраструктуры.

Чем удобна ECS?


  1. Экономичность. ECS - многофункциональная платформа, которая предполагает множество сценариев использования и защищает инвестиции в инфраструктуру хранения Dell EMC. Она упрощает управление, повышает гибкость, а главное — снижает затраты. С точки зрения масштабирования, ECS - одно из самых экономически эффективных решений на рынке. Согласно исследованию Enterprise Strategy Group (ESG), хранить файлы в ECS минимум на 60% выгоднее по сравнению с другими облачными сервисами.

  2. Интеграция с существующей средой хранения. ECS «расширяет» облако до основного хранилища и позволяет освободить инфраструктуру хранения при помощи решений Dell EMC для облачных вычислений (CloudPools, CloudBoost, CloudArray и т. д.). Заказчики могут выводить неактивные данные из первичного хранилища (Isilon, VMAX Series, VPLEX, VNX Series, Vx Series, Data Domain, Data Protection Suite и т. д.) в облако, перемещая их на ECS. Такая консолидация ресурсов позволяет не покупать дополнительные и более дорогие платформы и заметно повышает эффективность имеющейся среды хранения.

  3. Оперативный и повсеместный доступ к данным. Объектная платформа ECS способна радикально улучшить время отклика и повысить скорость доступа к данным по сравнению с традиционной NAS. Данные защищаются при помощи кодирования и распределяются по всем узлам системы, обеспечивая мгновенный доступ для чтения/записи из любого места. При этом доступна самая последняя копия данных, что упрощает разработку приложений. Поддержка геокэширования также делает доступ более оперативным благодаря интеллектуальному системному распознаванию шаблонов операций: оно минимизирует трафик глобальной сети и улучшает латентность.

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

  5. Пользователю доступны все плюсы программно-определяемой СХД. Платформа ECS полностью использует программно-определяемую архитектуру, что позволяет независимо масштабировать вычислительные ресурсы и ресурсы хранения. Все данные в ECS контейнеризированы; нет аппаратной зависимости, необходимости перекодировать или перенастраивать приложения, поскольку ECS обеспечивает поддержку нескольких протоколов. Это позволяет разработчикам гораздо быстрее внедрять инновации и выводить свои приложения на рынок.

Цифровая трансформация — это просто


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


ECS совместима с HDFS, OpenStack Swift и Amazon S3, а также с API Centera и Atmos. По выбору заказчика ее можно развертывать как полностью интегрированное решение, которое масштабируется до 3,8 Пбайт на стойку, или как программное решение для хранения данных на сертифицированном оборудовании. Кроме того, ECS доступна по подписке с платой за использование. Благодаря этому система завоевывает популярность у корпоративных клиентов и поставщиков услуг.


Производитель позиционирует ECS для случаев, когда требуется:

  • распределенная архитектура,
  • глобальное пространство имен (все центры данных с узлами active/active, геозащитой, многопротокольным доступом и поиском по метаданным).

Сценарии использования ECS


Платформа ECS применяется как:

  1. Глобальный репозиторий контента. Это сравнительно простое в реализации решение обеспечивает глобальный доступ к файлам и защиту данных корпоративного уровня.
  2. Масштабная реализация аналитики больших данных. Система обеспечивает глобальную аналитику данных из географически распределенных архивов. Это экономичное высокоплотное решение хранения для Hadoop.
  3. Современная платформа для приложений. ECS поддерживает множество API и протоколов, а ее архитектура active/active оптимизирована для хранения данных и доступа к ним.
  4. Система холодного архивирования неактивных данных. Позволяет создавать архивы, готовые к поддержке будущих приложений, а также оптимизирует существующие среды хранения.
  5. Развертывание платформы управления для Интернета вещей (IoT). Архитектура IoT эффективна для работы с большим объемом неструктурированных данных. А на недавнем форуме Dell EMC World 2017 было объявлено, что теперь в ECS возможна потоковая передача данных IoT.


Вот несколько вариантов использования ECS вместе с другими системами хранения Dell EMC:

Пример 1. Комбинация ECS с Dell EMC Cloud Array. Файловые службы и хранилища для удаленных офисов без развертывания массива хранения на удаленной площадке.


Пример 2. Комбинация ECS с Isilon (облачные пулы). Isilon (горизонтально-масштабируемая NAS) с автоматическим перемещением файлов на недорогое хранилище по заданным правилам.


Пример 3. Классическое архивирование. ECS используется в качестве архива.
 
Пример 4. Комбинация с Dell EMC Cloud Boost. Долгосрочное хранение данных.


Пример 5. Разработка с использованием объектного хранилища. Мобильные приложения стали настолько развитыми, что их сложно связать с известными протоколами хранения данных (FC, NAS) без «шлюза» - например, веб-сервера. Благодаря ECS мобильные приложения получают прямой доступ к хранилищу при помощи HTTP/HTTPS и могут получать или сохранять нужные объекты.

Платформа ECS была выпущена в июне 2015 года. Сейчас ею пользуются более 250 клиентов, и у многих из них емкости инсталляций превышают петабайт. ECS поддерживает объекты, NFS и распределенную файловую систему Hadoop (HDFS), что позволяет ей хранить миллиарды файлов для облачных приложений.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331506/


Метки:  

13 вопросов, чтобы узнать, готовы ли вы нанимать команду мобильной разработки

Пятница, 23 Июня 2017 г. 15:53 + в цитатник
Если вы решили создать мобильное приложение, определились с его целью и находитесь в поисках команды, способной реализовать ваш продукт, не забудьте подготовить ответы, на вопросы, описанные ниже. Скорее всего, ваш подрядчик их задаст или предложит обсудить по ним решения.

image

Вопросы:

  1. Вы хотите приложение на одной платформе или на двух/трех сразу? (IOS/Android/Windows). Нужно иметь ввиду, что разработка на Android, как правило, займет больше времени и больше ресурсов (приблизительно на 20%), так как на Android больше различных расширений экрана и различных версий ОС, использующихся на текущий момент. Если бюджет ограничен, то что бы вы хотели выпустить в первую очередь?
  2. Вы планируете, что ваше приложение будут запускать на iPad или планшетах или часах? Если да, то это также увеличит время на разработку и тестирование.
  3. Как вы думаете, какое количество пользователей будет у приложения в ближайший год/три/5 лет?
  4. Что вы планируете делать для того, чтобы количество пользователей росло? Какие маркетинговые стратегии/шаги? Возможно видео ролик, промосайт, страницы в социальных сетях? Кто будет обрабатывать данные потоки информации от этих сервисов? (Примечание. Для публикации в Appstore обаятелен либо промо сайт приложения, либо страница в социальной сети, например, FB)
  5. Ваше приложение должно работать без интернета?
  6. Планируете ли вы монетизировать ваше приложение? Делать его платным, зарабатывать на рекламе внутри, делать платную и бесплатную версию, продавать внутри приложения что-либо?
  7. Планируете ли вы заниматься заполнением контента (текст, картинки, звуки…) самостоятельно или доверите этот вопрос профессионалам?
  8. Планируете ли вы включить в команду разработки также специалиста по тестированию, который сможет полноценно проверить работу продукта? (полное тестирование, стрессовое тестирование, нагрузочное тестирование…)?
  9. Планируете ли вы проверить, насколько сработает идея и улучшить свой продукт с помощью фокус-группы из вашей целевой аудитории?
  10. Планируете ли вы подключить аналитику в приложение, чтобы изучать поведение пользователей, собирать показатели? Планируете ли вы привлекать маркетолога для обработки данных по этой аналитике?
  11. Ваше приложение будет на нескольких языках, в разных странах? Если да, планируете ли вы сами осуществлять перевод контента в приложении и в маркете или вам нужна будет помощь?
  12. Помните ли вы, что для публикации приложения вам необходимо будет завести аккаунты (например, Google, Apple)? Если ваше приложение будет использовать серверную часть, то нужно будет приобрести и настроить хостинг, вам нужна будет помощь в этом вопросе?
  13. Как вы хотите взаимодействовать с командой исполнителей? Какую отчетность получать? Хотите ли следить за прогрессом в режиме реального времени (Например, используя Agile Boards) или просто участвовать в демонстрациях раз в 2-3 недели?

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

P.S. Буду рада услышать рекомендации от разработчиков и проектных команд, как можно еще расширить этот список!
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331510/


Автоэнкодеры в Keras, Часть 2: Manifold learning и скрытые (latent) переменные

Пятница, 23 Июня 2017 г. 14:40 + в цитатник

Содержание


  • Часть 1: Введение
  • Часть 2: Manifold learning и скрытые (latent) переменные
  • Часть 3: Вариационные автоэнкодеры (VAE)
  • Часть 4: Conditional VAE
  • Часть 5: GAN (Generative Adversarial Networks) и tensorflow
  • Часть 6: VAE + GAN




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

Manifold learning


Изображения цифр mnist (на которых примеры в прошлой части) — это элементы 28*28=784-мерного пространства, как и вообще любое монохромное изображение 28 на 28.

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

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

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

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

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

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

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

Код и визуализация
# Импорт необходимых библиотек
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline
import seaborn as sns

# Создание датасета
x1 = np.linspace(-2.2, 2.2, 1000)
fx = np.sin(x1)
dots = np.vstack([x1, fx]).T
noise = 0.06 * np.random.randn(*dots.shape)
dots += noise

# Цветные точки для отдельной визуализации позже
from itertools import cycle
size = 25
colors = ["r", "g", "c", "y", "m"]
idxs = range(0, x1.shape[0], x1.shape[0]//size)
vx1 = x1[idxs]
vdots = dots[idxs]

# Визуализация
plt.figure(figsize=(12, 10))
plt.xlim([-2.5, 2.5])
plt.scatter(dots[:, 0], dots[:, 1])
plt.plot(x1, fx,  color="red", linewidth=4)
plt.grid(False)



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

Линейный сжимающий автоэнкодер


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

Такой автоэнкодер ищет аффинное (линейное со сдвигом) подпространство в пространстве объектов, которое описывает наибольшую вариацию в объектах, тоже самое делает и PCA (метод главных компонент) и оба они находят одно и тоже подпространство

from keras.layers import Input, Dense
from keras.models import Model
from keras.optimizers import Adam

def linear_ae():
    input_dots = Input((2,))
    code = Dense(1, activation='linear')(input_dots)
    out  = Dense(2, activation='linear')(code)

    ae = Model(input_dots, out)
    return ae

ae = linear_ae()
ae.compile(Adam(0.01), 'mse')

ae.fit(dots, dots, epochs=15, batch_size=30, verbose=0)


# Применение линейного автоэнкодера
pdots = ae.predict(dots, batch_size=30)
vpdots = pdots[idxs]

# Применение PCA
from sklearn.decomposition import PCA
pca = PCA(1)
pdots_pca = pca.inverse_transform(pca.fit_transform(dots))

Визуализация
# Визуализация
plt.figure(figsize=(12, 10))
plt.xlim([-2.5, 2.5])
plt.scatter(dots[:, 0], dots[:, 1], zorder=1)
plt.plot(x1, fx,  color="red", linewidth=4, zorder=10)
plt.plot(pdots[:,0], pdots[:,1], color='white', linewidth=12, zorder=3)
plt.plot(pdots_pca[:,0], pdots_pca[:,1], color='orange', linewidth=4, zorder=4)
plt.scatter(vpdots[:,0], vpdots[:,1], color=colors*5, marker='*', s=150, zorder=5)
plt.scatter(vdots[:,0], vdots[:,1], color=colors*5, s=150, zorder=6)
plt.grid(False)



На картинке выше:

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

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

Глубокий автоэнкодер


У глубокого автоэнкодера больше число слоев и самое главное — нелинейная функция активации между ними (в нашем случае ELU — Exponential Linear Unit).

def deep_ae():
    input_dots = Input((2,))
    x = Dense(64, activation='elu')(input_dots)
    x = Dense(64, activation='elu')(x)
    code = Dense(1, activation='linear')(x)
    x = Dense(64, activation='elu')(code)
    x = Dense(64, activation='elu')(x)
    out = Dense(2, activation='linear')(x)

    ae = Model(input_dots, out)
    return ae

dae = deep_ae()
dae.compile(Adam(0.003), 'mse')

dae.fit(dots, dots, epochs=200, batch_size=30, verbose=0)
pdots_d = dae.predict(dots, batch_size=30)
vpdots_d = pdots_d[idxs]

Визуализация
# Визуализация
plt.figure(figsize=(12, 10))
plt.xlim([-2.5, 2.5])
plt.scatter(dots[:, 0], dots[:, 1], zorder=1)
plt.plot(x1, fx,  color="red", linewidth=4, zorder=10)
plt.plot(pdots_d[:,0], pdots_d[:,1], color='white', linewidth=12, zorder=3)
plt.plot(pdots_pca[:,0], pdots_pca[:,1], color='orange', linewidth=4, zorder=4)
plt.scatter(vpdots_d[:,0], vpdots_d[:,1], color=colors*5, marker='*', s=150, zorder=5)
plt.scatter(vdots[:,0], vdots[:,1], color=colors*5, s=150, zorder=6)
plt.grid(False)




У такого автоэнкодера практически идеально получилось построить определяющее многообразие: белая кривая почти совпадает с красной.

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

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

Вернемся к датасету рукописных цифр из предыдущей части.

Сначала двигаемся по прямой в пространстве цифр от одной 8-ки к другой:

Код
from keras.layers import Conv2D, MaxPooling2D, UpSampling2D
from keras.datasets import mnist

(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test  = x_test .astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test  = np.reshape(x_test,  (len(x_test),  28, 28, 1))

# Сверточный автоэнкодер
def create_deep_conv_ae():
    input_img = Input(shape=(28, 28, 1))

    x = Conv2D(128, (7, 7), activation='relu', padding='same')(input_img)
    x = MaxPooling2D((2, 2), padding='same')(x)
    x = Conv2D(32, (2, 2), activation='relu', padding='same')(x)
    x = MaxPooling2D((2, 2), padding='same')(x)
    encoded = Conv2D(1, (7, 7), activation='relu', padding='same')(x)

    # На этом моменте представление  (7, 7, 1) т.е. 49-размерное

    input_encoded = Input(shape=(7, 7, 1))
    x = Conv2D(32, (7, 7), activation='relu', padding='same')(input_encoded)
    x = UpSampling2D((2, 2))(x)
    x = Conv2D(128, (2, 2), activation='relu', padding='same')(x)
    x = UpSampling2D((2, 2))(x)
    decoded = Conv2D(1, (7, 7), activation='sigmoid', padding='same')(x)

    # Модели
    encoder = Model(input_img, encoded, name="encoder")
    decoder = Model(input_encoded, decoded, name="decoder")
    autoencoder = Model(input_img, decoder(encoder(input_img)), name="autoencoder")
    return encoder, decoder, autoencoder

c_encoder, c_decoder, c_autoencoder = create_deep_conv_ae()
c_autoencoder.compile(optimizer='adam', loss='binary_crossentropy')
c_autoencoder.fit(x_train, x_train,
                epochs=50,
                batch_size=256,
                shuffle=True,
                validation_data=(x_test, x_test))

def plot_digits(*args):
    args = [x.squeeze() for x in args]
    n = min([x.shape[0] for x in args])
    
    plt.figure(figsize=(2*n, 2*len(args)))
    for j in range(n):
        for i in range(len(args)):
            ax = plt.subplot(len(args), n, i*n + j + 1)
            plt.imshow(args[i][j])
            plt.gray()
            ax.get_xaxis().set_visible(False)
            ax.get_yaxis().set_visible(False)

    plt.show()

# Гомотопия по прямой между объектами или между кодами
def plot_homotopy(frm, to, n=10, decoder=None):
    z = np.zeros(([n] + list(frm.shape)))
    for i, t in enumerate(np.linspace(0., 1., n)):
        z[i] = frm * (1-t) + to * t
    if decoder:
        plot_digits(decoder.predict(z, batch_size=n))
    else:
        plot_digits(z)


# Гомотопия между первыми двумя восьмерками
frm, to = x_test[y_test == 8][1:3]
plot_homotopy(frm, to)



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

codes = c_encoder.predict(x_test[y_test == 8][1:3])
plot_homotopy(codes[0], codes[1], n=10, decoder=c_decoder)


Промежуточные цифры — вполне себе хорошие восьмерки.

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

Переобучение автоэнкодера


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

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

Код
dae = deep_ae()
dae.compile(Adam(0.0003), 'mse')
x_train_oft = np.vstack([dots[idxs]]*4000)


dae.fit(x_train_oft, x_train_oft, epochs=200, batch_size=15, verbose=1)


pdots_d = dae.predict(dots, batch_size=30)
vpdots_d = pdots_d[idxs]

plt.figure(figsize=(12, 10))
plt.xlim([-2.5, 2.5])
plt.scatter(dots[:, 0], dots[:, 1], zorder=1)
plt.plot(x1, fx, color="red", linewidth=4, zorder=10)
plt.plot(pdots_d[:,0], pdots_d[:,1], color='white', linewidth=6, zorder=3)
plt.plot(pdots_pca[:,0], pdots_pca[:,1], color='orange', linewidth=4, zorder=4)
plt.scatter(vpdots_d[:,0], vpdots_d[:,1], color=colors*5, marker='*', s=150, zorder=5)
plt.scatter(vdots[:,0], vdots[:,1], color=colors*5, s=150, zorder=6)
plt.grid(False)




Видно, что белая кривая прошла через каждую точку данных и слабо похожа на определяющую данные красную кривую: на лицо типичное переобучение.

Скрытые переменные


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

  • желаемой цифры,
  • толщины штриха,
  • наклона цифры,
  • аккуратности,
  • и т.д.

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

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

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

Для определенности введем некоторые обозначения на примере цифр:

  • X — случайная величина картинки 28х28,
  • Z — случайная величина скрытых факторов, определяющих цифру на картинке,
  • p(X) — вероятностное распределение изображений цифр на картинках, т.е. вероятность конкретного изображения цифры в принципе быть нарисованным (если картинка не похожа на цифру, то эта вероятность крайне мала),
  • p(Z) — вероятностное распределение скрытых факторов, например, распределение толщины штриха,
  • p(Z|X) — распределение вероятности скрытых факторов при заданной картинке (к одной и той же картинке могут привести различное сочетание скрытых переменных и шума),
  • p(X|Z) — распределение вероятности картинок при заданных скрытых факторах, одни и те же факторы могут привести к разным картинкам (один и тот же человек в одних и тех же условиях не рисует абсолютно одинаковые цифры),
  • p(X,Z) — совместное распределение X и Z, наиболее полное понимание данных, необходимое для генерации новых объектов.

p(X,Z) = p(X|Z) p(Z)

p(X|Z) нам приближает декодер, но p(Z) на данный момент мы пока еще не понимаем.

Посмотрим, как распределены скрытые переменные в обычном автоэнкодере:

Код
from keras.layers import Flatten, Reshape
from keras.regularizers import L1L2

def create_deep_sparse_ae(lambda_l1):
    # Размерность кодированного представления
    encoding_dim = 16

    # Энкодер
    input_img = Input(shape=(28, 28, 1))
    flat_img = Flatten()(input_img)
    x = Dense(encoding_dim*4, activation='relu')(flat_img)
    x = Dense(encoding_dim*3, activation='relu')(x)
    x = Dense(encoding_dim*2, activation='relu')(x)
    encoded = Dense(encoding_dim, activation='linear', activity_regularizer=L1L2(lambda_l1, 0))(x)
    
    # Декодер
    input_encoded = Input(shape=(encoding_dim,))
    x = Dense(encoding_dim*2, activation='relu')(input_encoded)
    x = Dense(encoding_dim*3, activation='relu')(x)
    x = Dense(encoding_dim*4, activation='relu')(x)
    flat_decoded = Dense(28*28, activation='sigmoid')(x)
    decoded = Reshape((28, 28, 1))(flat_decoded)
    
    # Модели
    encoder = Model(input_img, encoded, name="encoder")
    decoder = Model(input_encoded, decoded, name="decoder")
    autoencoder = Model(input_img, decoder(encoder(input_img)), name="autoencoder")
    return encoder, decoder, autoencoder

encoder, decoder, autoencoder = create_deep_sparse_ae(0.)
autoencoder.compile(optimizer=Adam(0.0003), loss='binary_crossentropy')

autoencoder.fit(x_train, x_train,
                      epochs=100,
                      batch_size=64,
                      shuffle=True,
                      validation_data=(x_test, x_test))

n = 10
imgs = x_test[:n]
decoded_imgs = autoencoder.predict(imgs, batch_size=n)

plot_digits(imgs, decoded_imgs)


Вот так выглядят восстановленные этим энкодером изображения:

Изображения


Совместное распределение скрытых переменных P(Z_1, Z_3)

codes = encoder.predict(x_test)
sns.jointplot(codes[:,1], codes[:,3])



Видно, что совместное распределение P(Z_1,Z_3) имеет сложную форму; Z_1 и Z_3 зависимы друг от друга.

Есть ли какой-то способ контролировать распределения скрытых переменных P(Z)?

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

Регуляризатор вынуждает автоэнкодер искать скрытые переменные, которые распределены по нужным законам, получится ли у него — другой вопрос. Однако это никак не заставляет делать их независимыми, т.е. P(Z_i) \neq P(Z_i|Z_j).

Посмотрим на совместное распределение скрытых параметров в разреженом автоэнкодере.

Код и визуализация
s_encoder, s_decoder, s_autoencoder = create_deep_sparse_ae(0.00001)
s_autoencoder.compile(optimizer=Adam(0.0003), loss='binary_crossentropy')

s_autoencoder.fit(x_train, x_train, epochs=200, batch_size=256, shuffle=True, 
                          validation_data=(x_test, x_test))

imgs = x_test[:n]
decoded_imgs = s_autoencoder.predict(imgs, batch_size=n)
plot_digits(imgs, decoded_imgs)



codes = s_encoder.predict(x_test)
snt.jointplot(codes[:,1], codes[:,3])



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

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

Полезные ссылки и литература


Этот пост основан на главе про автоэнкодеры (в частности подглавы Learning maifolds with autoencoders) в Deep Learning Book.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331500/


Метки:  

Автоэнкодеры в Keras, Часть 1: Введение

Пятница, 23 Июня 2017 г. 14:38 + в цитатник

Автоэнкодеры в Keras


Часть 1: Введение


Содержание



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

Автоэнкодеры


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



Кому интересно, добро пожаловать под кат


Автоэнкодеры состоят из двух частей: энкодера g и декодера f. Энкодер переводит входной сигнал в его представление (код): h = g(x), а декодер восстанавливает сигнал по его коду: x=f(h).

Автоэнкодер, изменяя f и g, стремится выучить тождественную функцию x = f(g(x)), минимизируя какой-то функционал ошибки.

L(x, f(g(x))).

При этом семейства функций энкодера g и декодера f как-то ограничены, чтобы автоэнкодер был вынужден отбирать наиболее важные свойства сигнала.

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

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

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

Keras


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

Модели keras легко сохранять/загружать, у них простой, но в тоже время глубоко настраиваемый процесс обучения; модели свободно встраиваются в tensorflow/theano код (как операции над тензорами).

В качестве данных будем использовать датасет рукописных цифр MNIST

Загрузим его:

from keras.datasets import mnist
import numpy as np

(x_train, y_train), (x_test, y_test) = mnist.load_data()

x_train = x_train.astype('float32') / 255.
x_test  = x_test .astype('float32') / 255.
x_train = np.reshape(x_train, (len(x_train), 28, 28, 1))
x_test  = np.reshape(x_test,  (len(x_test),  28, 28, 1))

Сжимающий автоэнкодер


Для начала создадим наиболее простой (сжимающий, undercomplete) автоэнкодер с кодом малой размерности из двух полносвязных слоев: енкодера и декодера.

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

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

from keras.layers import Input, Dense, Flatten, Reshape
from keras.models import Model

def create_dense_ae():
    # Размерность кодированного представления
    encoding_dim = 49

    # Энкодер
    # Входной плейсхолдер
    input_img = Input(shape=(28, 28, 1)) # 28, 28, 1 - размерности строк, столбцов, фильтров одной картинки, без батч-размерности
    # Вспомогательный слой решейпинга
    flat_img = Flatten()(input_img)
    # Кодированное полносвязным слоем представление
    encoded = Dense(encoding_dim, activation='relu')(flat_img)
    
    # Декодер
    # Раскодированное другим полносвязным слоем изображение
    input_encoded = Input(shape=(encoding_dim,))
    flat_decoded = Dense(28*28, activation='sigmoid')(input_encoded)
    decoded = Reshape((28, 28, 1))(flat_decoded)

    # Модели, в конструктор первым аргументом передаются входные слои, а вторым выходные слои
    # Другие модели можно так же использовать как и слои
    encoder = Model(input_img, encoded, name="encoder")
    decoder = Model(input_encoded, decoded, name="decoder")
    autoencoder = Model(input_img, decoder(encoder(input_img)), name="autoencoder")
    return encoder, decoder, autoencoder

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

encoder, decoder, autoencoder = create_dense_ae()
autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

Посмотрим на число параметров

autoencoder.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_1 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
encoder (Model)              (None, 49)                38465     
_________________________________________________________________
decoder (Model)              (None, 28, 28, 1)         39200     
=================================================================
Total params: 77,665.0
Trainable params: 77,665.0
Non-trainable params: 0.0
_________________________________________________________________

Обучим теперь наш автоэнкодер

autoencoder.fit(x_train, x_train,
                epochs=50,
                batch_size=256,
                shuffle=True,
                validation_data=(x_test, x_test))

Epoch 46/50
60000/60000 [==============================] - 3s - loss: 0.0785 - val_loss: 0.0777
Epoch 47/50
60000/60000 [==============================] - 2s - loss: 0.0784 - val_loss: 0.0777
Epoch 48/50
60000/60000 [==============================] - 3s - loss: 0.0784 - val_loss: 0.0777
Epoch 49/50
60000/60000 [==============================] - 2s - loss: 0.0784 - val_loss: 0.0777
Epoch 50/50
60000/60000 [==============================] - 3s - loss: 0.0784 - val_loss: 0.0777

Функция отрисовки цифр

%matplotlib inline
import seaborn as sns
import matplotlib.pyplot as plt

def plot_digits(*args):
    args = [x.squeeze() for x in args]
    n = min([x.shape[0] for x in args])
    
    plt.figure(figsize=(2*n, 2*len(args)))
    for j in range(n):
        for i in range(len(args)):
            ax = plt.subplot(len(args), n, i*n + j + 1)
            plt.imshow(args[i][j])
            plt.gray()
            ax.get_xaxis().set_visible(False)
            ax.get_yaxis().set_visible(False)

    plt.show()

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

n = 10

imgs = x_test[:n]
encoded_imgs = encoder.predict(imgs, batch_size=n)
encoded_imgs[0]

array([  6.64665604,   7.53528595,   3.81508064,   4.66803837,
         1.50886345,   5.41063929,   9.28293324,  10.79530716,
         0.39599913,   4.20529413,   6.53982353,   5.64758158,
         5.25313473,   1.37336707,   9.37590599,   6.00672245,
         4.39552879,   5.39900637,   4.11449528,   7.490417  ,
        10.89267063,   7.74325705,  13.35806847,   3.59005809,
         9.75185394,   2.87570286,   3.64097357,   7.86691713,
         5.93383646,   5.52847338,   3.45317888,   1.88125253,
         7.471385  ,   7.29820824,  10.02830505,  10.5430584 ,
         3.2561543 ,   8.24713707,   2.2687614 ,   6.60069561,
         7.58116722,   4.48140812,   6.13670635,   2.9162209 ,
         8.05503941,  10.78182602,   4.26916027,   5.17175484,   6.18108797], dtype=float32)

Декодируем эти коды и сравним с оригиналами

decoded_imgs = decoder.predict(encoded_imgs, batch_size=n)

plot_digits(imgs, decoded_imgs)



Глубокий автоэнкодер


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

def create_deep_dense_ae():
    # Размерность кодированного представления
    encoding_dim = 49

    # Энкодер
    input_img = Input(shape=(28, 28, 1))
    flat_img = Flatten()(input_img)
    x = Dense(encoding_dim*3, activation='relu')(flat_img)
    x = Dense(encoding_dim*2, activation='relu')(x)
    encoded = Dense(encoding_dim, activation='linear')(x)
    
    # Декодер
    input_encoded = Input(shape=(encoding_dim,))
    x = Dense(encoding_dim*2, activation='relu')(input_encoded)
    x = Dense(encoding_dim*3, activation='relu')(x)
    flat_decoded = Dense(28*28, activation='sigmoid')(x)
    decoded = Reshape((28, 28, 1))(flat_decoded)
    
    # Модели
    encoder = Model(input_img, encoded, name="encoder")
    decoder = Model(input_encoded, decoded, name="decoder")
    autoencoder = Model(input_img, decoder(encoder(input_img)), name="autoencoder")
    return encoder, decoder, autoencoder

d_encoder, d_decoder, d_autoencoder = create_deep_dense_ae()
d_autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

Посмотрим на summary нашей модели

d_autoencoder.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_3 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
encoder (Model)              (None, 49)                134750    
_________________________________________________________________
decoder (Model)              (None, 28, 28, 1)         135485    
=================================================================
Total params: 270,235.0
Trainable params: 270,235.0
Non-trainable params: 0.0

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

d_autoencoder.fit(x_train, x_train,
                  epochs=100,
                  batch_size=256,
                  shuffle=True,
                  validation_data=(x_test, x_test))

Epoch 96/100
60000/60000 [==============================] - 3s - loss: 0.0722 - val_loss: 0.0724
Epoch 97/100
60000/60000 [==============================] - 3s - loss: 0.0722 - val_loss: 0.0719
Epoch 98/100
60000/60000 [==============================] - 3s - loss: 0.0721 - val_loss: 0.0722
Epoch 99/100
60000/60000 [==============================] - 3s - loss: 0.0721 - val_loss: 0.0720
Epoch 100/100
60000/60000 [==============================] - 3s - loss: 0.0721 - val_loss: 0.0720

n = 10

imgs = x_test[:n]
encoded_imgs = d_encoder.predict(imgs, batch_size=n)
encoded_imgs[0]

decoded_imgs = d_decoder.predict(encoded_imgs, batch_size=n)

plot_digits(imgs, decoded_imgs)



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

Сверточный автоэнкодер


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

from keras.layers import Conv2D, MaxPooling2D, UpSampling2D

def create_deep_conv_ae():
    input_img = Input(shape=(28, 28, 1))

    x = Conv2D(128, (7, 7), activation='relu', padding='same')(input_img)
    x = MaxPooling2D((2, 2), padding='same')(x)
    x = Conv2D(32, (2, 2), activation='relu', padding='same')(x)
    x = MaxPooling2D((2, 2), padding='same')(x)
    encoded = Conv2D(1, (7, 7), activation='relu', padding='same')(x)

    # На этом моменте представление  (7, 7, 1) т.е. 49-размерное

    input_encoded = Input(shape=(7, 7, 1))
    x = Conv2D(32, (7, 7), activation='relu', padding='same')(input_encoded)
    x = UpSampling2D((2, 2))(x)
    x = Conv2D(128, (2, 2), activation='relu', padding='same')(x)
    x = UpSampling2D((2, 2))(x)
    decoded = Conv2D(1, (7, 7), activation='sigmoid', padding='same')(x)

    # Модели
    encoder = Model(input_img, encoded, name="encoder")
    decoder = Model(input_encoded, decoded, name="decoder")
    autoencoder = Model(input_img, decoder(encoder(input_img)), name="autoencoder")
    return encoder, decoder, autoencoder

c_encoder, c_decoder, c_autoencoder = create_deep_conv_ae()
c_autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

c_autoencoder.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
input_5 (InputLayer)         (None, 28, 28, 1)         0         
_________________________________________________________________
encoder (Model)              (None, 7, 7, 1)           24385     
_________________________________________________________________
decoder (Model)              (None, 28, 28, 1)         24385     
=================================================================
Total params: 48,770.0
Trainable params: 48,770.0
Non-trainable params: 0.0

c_autoencoder.fit(x_train, x_train,
                epochs=64,
                batch_size=256,
                shuffle=True,
                validation_data=(x_test, x_test))

Epoch 60/64
60000/60000 [==============================] - 24s - loss: 0.0698 - val_loss: 0.0695
Epoch 61/64
60000/60000 [==============================] - 24s - loss: 0.0699 - val_loss: 0.0705
Epoch 62/64
60000/60000 [==============================] - 24s - loss: 0.0699 - val_loss: 0.0694
Epoch 63/64
60000/60000 [==============================] - 24s - loss: 0.0698 - val_loss: 0.0691
Epoch 64/64
60000/60000 [==============================] - 24s - loss: 0.0697 - val_loss: 0.0693

n = 10

imgs = x_test[:n]
encoded_imgs = c_encoder.predict(imgs, batch_size=n)
decoded_imgs = c_decoder.predict(encoded_imgs, batch_size=n)

plot_digits(imgs, decoded_imgs)



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

Denoising автоэнкодер


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

L(x, f(g(\hat x))),

где \hat x — зашумленные данные.

В Keras можно оборачивать произвольные операции из нижележащего фреймворка в Lambda слой. Обращаться к операциям из tensorflow или theano можно через модуль backend.

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

import keras.backend as K
from keras.layers import Lambda

batch_size = 16

def create_denoising_model(autoencoder):
    def add_noise(x):
        noise_factor = 0.5
        x = x + K.random_normal(x.get_shape(), 0.5, noise_factor)
        x = K.clip(x, 0., 1.)
        return x

    input_img  = Input(batch_shape=(batch_size, 28, 28, 1))
    noised_img = Lambda(add_noise)(input_img)

    noiser = Model(input_img, noised_img, name="noiser")
    denoiser_model = Model(input_img, autoencoder(noiser(input_img)), name="denoiser")
    return noiser, denoiser_model


noiser, denoiser_model = create_denoising_model(autoencoder)
denoiser_model.compile(optimizer='adam', loss='binary_crossentropy')

denoiser_model.fit(x_train, x_train,
                   epochs=200,
                   batch_size=batch_size,
                   shuffle=True,
                   validation_data=(x_test, x_test))

n = 10

imgs = x_test[:batch_size]
noised_imgs = noiser.predict(imgs, batch_size=batch_size)
encoded_imgs = encoder.predict(noised_imgs[:n],  batch_size=n)
decoded_imgs = decoder.predict(encoded_imgs[:n], batch_size=n)

plot_digits(imgs[:n], noised_imgs, decoded_imgs)



Цифры на зашумленных изображениях с трудом проглядываются, однако denoising autoencoder неплохо убрал шум и цифры стали вполне читаемыми.

Разреженный (Sparse) автоэнкодер


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

L(x, f(g(x))) + \Omega(h),

где h = g(x) — код,

\Omega(h) — обычный регуляризатор (например L1):

\Omega(h) = \lambda * |h|

Разреженный автоэнкодер не обязательно сужается к центру. Его код может иметь и большую размерность, чем входной сигнал. Обучаясь приближать тождественную функцию x = f(g(x)), он учится в коде выделять полезные свойства сигнала. Из-за регуляризатора даже расширяющийся к центру разреженный автоэнкодер не может выучить тождественную функцию напрямую.

from keras.regularizers import L1L2

def create_sparse_ae():
    encoding_dim = 16
    lambda_l1 = 0.00001
    
    # Энкодер
    input_img = Input(shape=(28, 28, 1))
    flat_img = Flatten()(input_img)
    x = Dense(encoding_dim*3, activation='relu')(flat_img)
    x = Dense(encoding_dim*2, activation='relu')(x)
    encoded = Dense(encoding_dim, activation='linear', activity_regularizer=L1L2(lambda_l1))(x)
    
    # Декодер
    input_encoded = Input(shape=(encoding_dim,))
    x = Dense(encoding_dim*2, activation='relu')(input_encoded)
    x = Dense(encoding_dim*3, activation='relu')(x)
    flat_decoded = Dense(28*28, activation='sigmoid')(x)
    decoded = Reshape((28, 28, 1))(flat_decoded)
    
    # Модели
    encoder = Model(input_img, encoded, name="encoder")
    decoder = Model(input_encoded, decoded, name="decoder")
    autoencoder = Model(input_img, decoder(encoder(input_img)), name="autoencoder")
    return encoder, decoder, autoencoder

s_encoder, s_decoder, s_autoencoder = create_sparse_ae()
s_autoencoder.compile(optimizer='adam', loss='binary_crossentropy')

s_autoencoder.fit(x_train, x_train,
                epochs=400,
                batch_size=256,
                shuffle=True,
                validation_data=(x_test, x_test))

Взглянем на коды

n = 10

imgs = x_test[:n]
encoded_imgs = s_encoder.predict(imgs, batch_size=n)
encoded_imgs[1]

array([  7.13531828,  -0.61532277,  -5.95510817,  12.0058918 ,
        -1.29253936,  -8.56000137,  -7.48944521,  -0.05415952,
        -2.81205249,  -8.4289856 ,  -0.67815018, -11.19531345,
        -3.4353714 ,   3.18580866,  -0.21041733,   4.13229799], dtype=float32)

decoded_imgs = s_decoder.predict(encoded_imgs, batch_size=n)

plot_digits(imgs, decoded_imgs)



Посмотрим, можно ли как-то интерпретировать размерности в кодах.
Возьмем среднее из всех кодов, а потом по очереди каждую размерность в усредненном коде заменим на максимальное ее значение.

imgs = x_test
encoded_imgs = s_encoder.predict(imgs, batch_size=16)
codes = np.vstack([encoded_imgs.mean(axis=0)]*10)
np.fill_diagonal(codes, encoded_imgs.max(axis=0))

decoded_features = s_decoder.predict(codes, batch_size=16)
plot_digits(decoded_features)



Какие-то черты проглядываются, но ничего толкового тут не видно.

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

Можно ли из кодов генерировать объекты по собственному желанию?

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

Полезные ссылки и литература


Этот пост основан на собственной интерпретации первой части поста создателя Keras Francois Chollet про автоэнкодеры в Keras.

А также главы про автоэнкодеры в Deep Learning Book.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331382/


Метки:  

[Перевод] Вехи истории шифрования и борьбы с ним

Пятница, 23 Июня 2017 г. 13:40 + в цитатник
Шифрование — это тема, вокруг которой в последние годы постоянно кипят страсти. Производители устройств и программ встраивают в свои изделия системы защиты. Эти системы, с одной стороны, помогают обычным людям и организациям, с другой же — ими же пользуются и нарушители закона. Последнее ведёт к обеспокоенности спецслужб, которым, в идеале, хотелось бы, чтобы у них были ключи ко всем зашифрованным данным. Перед вами — рассказ о десяти событиях из истории шифрования и борьбы с ним.



1979. All Writs Act



В 1789-м году был принят закон США «О всех исковых заявлениях и постановлениях судов» (All Writs Act). Он дал судам широкие полномочия на выдачу предписаний по практически любым вопросам. Именно на этот закон полагался суд в Калифорнии, требуя, чтобы компания Apple создала программу, которая поможет ФБР взломать Iphone 5C, который принадлежал Сайеду Фаруку — одному из террористов из Сан-Бернардино. Главный вопрос тут в том, действительно ли закон, принятый две сотни лет назад, позволяет суду обязать компанию создать нечто, ещё не существующее, для помощи в расследовании.

1993. Микросхема Clipper



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

1994. CALEA



В 1994-м году в США был принят закон «О помощи и содействии провайдеров телекоммуникационных услуг правоохранительным органам» (Communications Assistance for Law Enforcement Act, CALEA). Он обязывал телефонные компании содействовать спецслужбам в прослушивании телефонных разговоров. В 2005-м закон был расширен, его действие распространилось и на интернет-трафик, обязывая интернет-провайдеров помогать правоохранителям перехватывать трафик пользователей. Оба вида наблюдения требуют распоряжения суда. В конфликте Apple и ФБР, о котором мы уже говорили, этот закон не применялся, так как он не распространяется на данные, которые хранятся в смартфонах.

1996. SSL 3.0



В 1996-м вышел SSL 3.0. Это ПО породило сегодняшнюю систему защиты данных при передаче их через Интернет. Но не все данные, которые путешествуют по Интернету, зашифрованы. Работа по исправлению этой ситуации идёт уже много лет и приносит определённые результаты. Например, по прогнозам канадской сетевой компании Sandvine, более 70% процентов мирового интернет-трафика к концу 2016-го года будет зашифровано.

2001. USA PATRIOT Act



В 2001-м году в США принят закон «О сплочении и укреплении Америки путём обеспечения надлежащими средствами, требуемыми для пресечения и воспрепятствования терроризму» (Uniting and Strengthening America by Providing Appropriate Tools Required to Intercept and Obstruct Terrorism Act, USA PATRIOT Act). Появился он после теракта 11 сентября 2001-го года. Закон чрезвычайно расширяет полномочия спецслужб. Особо стоит отметить то, что дебаты по поводу шифрования проложили дорогу к созданию федерального Суда по наблюдению в целях разведки (Foreign Intelligence Surveillance Court, FISC), который, работая в режиме закрытых заседаний, может выдавать ордера на выполнение следственных действий.

2009. Операция «Aurora»



В 2009-м году состоялась атака на интернет-компании, исходящая из Китая, известная, как Операция «Aurora». В частности, была атакована компания Google, удару подверглись Gmail-аккаунты активистов в области прав человека. В целом, произошедшее затронуло более 20 компаний. Это привело к началу резкого охлаждения отношений между Google и Китаем. Поисковый гигант прекратил цензурирование результатов поиска в Китае и перевёл свои офисы из континентальной части Китая в Гонконг. Сейчас сервисы Google в Китае сильно ограничены.

2010. BlackBerry в Саудовской Аравии



В 2010-м компания Research in Motion позволила правительству Саудовской Аравии получить доступ к данным пользователей BlackBerry. К соглашению привела угроза блокировки сервисов BlackBerry в стране. Похожая ситуация характерна и для других стран, где RIM ставили перед выбором — не вести деятельность, или пойти навстречу спецслужбам. В результате всех этих событий репутация RIM, как создателя устройств и сервисов, обеспечивающих надёжную защиту данных, была подпорчена.

2013. Разоблачения Сноудена



В 2013-м бывший работник компании-подрядчика АНБ Эдвард Сноуден показал масштабы слежки США за другими странами и за собственными гражданами. Центром разоблачения оказалось сотрудничество со спецслужбами семи крупнейших технологических компаний. Они предоставляли АНБ данные, которые агентство исследовало с помощью комплекса PRISM. Газета «Нью-Йорк Таймс» назвала эти компании: Google, Microsoft, Yahoo, Facebook, Apple, AOL и PalTalk, заявив, что эти они подтвердили выполнение запросов на получение пользовательских данных по ордерам FISA. Всё это привело к усилиям, направленным на то, чтобы ограничить доступ компаний к данным пользователей. В частности, по этому направлению пошла и Apple.

2014. Приложения для обмена зашифрованными сообщениями



2014-й год заметен ростом приложений для обмена сообщениями со сквозным шифрованием. Среди них — Signal, Telegram, WhatsApp, Line, Cyber Dust и Apple iMessaging. Все эти программы предоставляют возможность обмена сообщениями, которые зашифровываются и расшифровываются только на устройствах пользователей. В результате никто, кроме этих пользователей, не может свободно читать их сообщения. Без применения технологии сквозного шифрования незащищённые сообщения оказываются на серверах сервис-провайдеров. Это означает, что компании вроде Facebook могут просматривать сообщения пользователей и передавать их спецслужбам.

2014. Шифрование данных по умолчанию



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

Итоги


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

Уважаемые читатели! Как вы относитесь к шифрованию данных? Шифруетесь? ;)
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331496/


Метки:  

Расставляем точки над микросервисами. Секция Avito на РИТ++ 2017 (Видео)

Пятница, 23 Июня 2017 г. 13:05 + в цитатник
Вот и подоспели материалы с фестиваля РИТ++ 2017. Мы выступили там с докладами по темам machine learning, front-end и mobile разработки и провели отдельный тематический блок, посвященный микросервисам. Под катом – видеозаписи выступлений на этой секции наших докладчиков и коллег из других компаний. Обязательно загляните, чтобы узнать о подходах к работе с микросервисами и интересных приемах, которые реально использовать для решения ваших задач.



Микросервисная архитектура: проблемы и решения


Тему микросервисов на мероприятии открыл Сергей Орлов в главном зале РИТ++. Это был разговор о проблемах, задачах и решениях микросервисной архитектуры, на которую переходят многие современные веб-проекты. Но при этом классические задачи предстают в новом свете. К разработке, эксплуатации, тестированию предъявляются качественно новые требования. Обо всем этом (и, конечно, о подходах к решению проблем) рассказывается в видео.




Преимущества и недостатки микросервисной архитектуры в HeadHunter


Хотите распилить монолит на микросервисы? Учитывайте, что эти изменения затронут всю компанию. Скорее всего, возникнут проблемы с разработкой, деплоем, эксплуатацией и так далее. Иногда они могут даже свести на нет преимущества от использования микросервисов. В своем докладе Антон Иванов из HeadHunter взвешивает преимущества и недостатки при вертикальном и горизонтальном делении на микросервисы.




События, события и ещё раз события


Для сбора событий мы в Avito разработали систему Event Stream Processing. К ней предъявлялись высокие требования. Это хорошая пропускная способность, отказоустойчивость, масштабируемость. Из доклада Антона Сухова вы узнаете, почему для решения наших задач мы предпочли NSQ, а не fluent, как решать проблемы сбора событий, которые неизбежно возникают при переходе от монолита к микросервисам, а также как заложить базу для того, чтобы новые события добавлялись в полностью автоматизированном режиме. Если вы решите, что хотите реализовать подобную систему, то посмотрите наш небольшой чек-лист по требованиям к ней и к вашей инфраструктуре в конце видео.




Мониторинг в микросервисной архитектуре


В этом видео Владимир Колобаев рассказывает о системе мониторинга в Avito. Ключевые слова: мониторинг как сервис (разработчики сами могут отправлять метрики, создавать дашборды, триггеры и нотификации для своих проектов), SLA > 99,99%, низкий порог вхождения. Футуристический прогноз: мониторинг в каждый дом, детектор аномалий, метаданные. И да, машина времени в докладе тоже есть.




Legacy в коробочке. Dev-среда на базе Kubernetes


Новые микросервисы появляются, но монолит никуда не исчезает. Мы в Avito разрабатываем и деплоим сервисы с помощью связки Docker и Kubernetes. Зачастую интегрировать монолит с сервисами довольно проблематично. А что, если его тоже завернуть в Docker+Kubernetes и применять те же практики, что и для микросервисов? В докладе Ильи Сауленко – ответы на вопросы о том, как уместить legacy-приложение вместе с базами и sphinxsearch в изолированной коробочке, сократить различия между окружениями и не забыть про Developer Experience. Будет полезно командам, планирующим или переживающим распил монолита и всем, кому приходится работать со сторонними legacy-системами.




Управление секретами в кластере Kubernetes при помощи Hashicorp Vault


В следующем докладе Сергей Носков рассказал об управлении секретами в кластере Kubernetes при помощи Hashicorp Vault. В видео приведен краткий обзор решения, рассмотрены случаи автоматического и безопасного управления секретами с помощью Puppet + Hiera. Особое внимание уделено встроенным секретам Kubernetes, проблемам управления ими и недостаткам существующих решений для получения секретов из Vault. Рассказано, как мы устранили эти недостатки с помощью простого самописного решения.




От сырых данных до отчета. Архитектурные подходы в проекте «Автотека»


С помощью нашего нового сервиса «Автотека» можно проверить историю автомобиля по VIN-номеру. В этом видео Николай Балакирев рассказывает об архитектурных подходах Avito, которые были реализованы в проекте. Почему мы стали использовать микросервисы для этой задачи? И что же мы сделали для того, чтобы потребитель получал нужную и актуальную информацию менее, чем за секунду? О построении сервиса, который может за это время посетить более 10 сторонних API, извлечь заранее собранные данные, проверить источники со статичной информацией, и, наконец, произвести слияние по определенному набору правил, смотрите в докладе.




Микросервисы для Machine Learning


У нас было 30 миллионов активных объявлений, 20 миллионов активных пользователей, 1,2 миллиарда событий и команда, которая реализует практическое машинное обучение. Что дальше? Смотрите видео, в котором Дмитрий Ходаков рассказывает две истории: о том, как традиционные микросервисы можно использовать для системы раздачи контента на рекомендациях и применения моделей в реальном времени, и о том, как мы распилили монолит пайплайна нашей рекомендательной системы на микросервисы. Click to play!




Микросервисы в продакшн. Kubernetes


И конечно, на РИТ++ не обошлось без практических занятий. Наши коллеги из Openprovider Елена Граховац и Игорь Должиков провели для всех желающих мастер-класс «Микросервисы в продакшн». Он состоял из двух частей.

Часть I:


— некоторые вопросы разработки микросервисов;
— написание сервисов на Go.

Часть II:


— подготовка инфраструктуры;
— релиз сервисов в Kubernetes с использованием CI/CD.
Мастер-класс доступен в следующем видео, а вот ссылка на репозитории с его материалами.




Это все материалы с секции о микросервисах на РИТ++. Задавайте вопросы, если такие возникнут.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331418/


[recovery mode] NTT Com заявили о создании первой в мире полностью программно-определяемой сети

Пятница, 23 Июня 2017 г. 12:46 + в цитатник
Поставщик услуг связи NTT Communications Corp объявил о том, что запускает самую большую в мире программно-определяемую сеть (SDN), которая охватит более 190 стран. По словам представителей компании, SD-WAN Service Portfolio — это «первая стопроцентная SDN в мире», которая позволит предоставлять высокопроизводительные SD-WAN-сервисы для компаний самых разных размеров.

/ Flickr / Dennis van Zuijlekom / CC

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

NTT Com заявляют, что построили свою SD-WAN-платформу на базе локально-распределённой архитектуры, покрывающей более 75 облачных центров. Эта архитектура была оптимизирована для работы с сетью и сервисами безопасности. При этом в ней используется технология, которую компания приобрела вместе с SDN-стартапом Virtela в 2014 году.

«Цифровые трансфигурации сегодня происходят в каждой корпорации, в корне меняя бизнес-модели, — говорит Сюити Сасакура (Shuichi Sasakura), старший вице-президент NTT Com. — Глобальный сервис NTT SD-WAN Service Portfolio — это end-to-end решение, предоставляющее организациям доступ к гибкой и масштабируемой сети, полностью удовлетворяющей их специфическим требованиям. Это позволяет компаниям быть более конкурентными в условиях цифровой экономики».

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

NTT SD-WAN Service Portfolio (источник)

Другой особенностью SD-WAN Service Portfolio является увеличенная гибкость подключений. Платформа поддерживает все типы, включая локальные ISP, интернет, MPLS, LTE и беспроводные подключения. Пользователи получают возможность комбинировать их согласно требованиям компаний. Другие полезные преимущества — это безопасные интернет-шлюзы, фильтрация URL и сервисы предотвращения вторжений.

Стю Миниман (Stu Miniman), главный аналитик из сообщества консультантов Wikibon, отметил, что телекоммуникационные компании много лет пытались закрепиться в облачной сфере, однако им это плохо удавалось. По его мнению, доставка сервисов с помощью SD-WAN подходит для них гораздо больше.

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

О компании NTT Com

NTT Com — это международное ответвление крупнейшей японской телекоммуникационной компании Nippon Telegraph and Telephone Group (NTT Group). Компания оказывает консалтинговые услуги, а также занимается проектированием, обеспечением информационной безопасности и реализацией облачных сервисов. В России подразделение NTT Com Russia поддерживает расширение бизнеса глобальных компаний, предоставляя им универсальные телеком-решения.

P.S. Предлагаем вашему вниманию еще несколько постов по теме из нашего блога VAS Experts:

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/330996/


Метки:  

[Перевод] Рассмотрим Kotlin повнимательнее

Пятница, 23 Июня 2017 г. 12:44 + в цитатник

image


https://trends.google.com/trends/explore?q=%2Fm%2F0_lcrx4


Выше приведён скриншот Google Trends, когда я искал по слову «kotlin». Внезапный всплеск — это когда Google объявила, что Kotlin становится главным языком в Android. Произошло это на конференции Google I/O несколько недель назад. На сегодняшний день вы либо уже использовали этот язык раньше, либо заинтересовались им, потому что все вокруг вдруг начали о нём говорить.


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


Когда я впервые использовал Kotlin после пяти лет работы на Java, некоторые вещи казались мне настоящим волшебством.


«Погодите, что? Я могут просто писать data class, чтобы избежать шаблонного кода?»
«Стоп, так если я пишу apply, то мне уже не нужно определять объект каждый раз, когда я хочу вызвать метод применительно к нему?»


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


Этому и посвящена статья. Мне было очень интересно узнать, как компилятор Kotlin преобразует конкретные конструкции, чтобы они стали взаимосовместимы с Java. Для своих исследований я выбрал четыре наиболее востребованных метода из стандартной библиотеки Kotlin:


  1. apply
  2. with
  3. let
  4. run

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


Apply


/**
 * Вызывает определённую функцию [block] со значением `this` в качестве своего получателя и возвращает значение `this`.
 */
@kotlin.internal.InlineOnly
public inline fun  T.apply(block: T.() -> Unit): T { block(); return this }

apply проста: это функция-расширение, которая выполняет параметр block применительно к экземпляру расширенного типа (extended type) (он называется «получатель») и возвращает самого получателя.


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


val layout = LayoutStyle().apply { orientation = VERTICAL }


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


Но как это работает? Давайте рассмотрим короткий пример.


enum class Orientation {
  VERTICAL, HORIZONTAL
}

class LayoutStyle {
  var orientation = HORIZONTAL
}

fun main(vararg args: Array) {
  val layout = LayoutStyle().apply { orientation = VERTICAL }
}

Благодаря инструменту IntelliJ IDEA «Show Kotlin bytecode» (Tools > Kotlin > Show Kotlin Bytecode) мы можем посмотреть, как компилятор преобразует наш код в JVM-байткод:


NEW kotlindeepdive/LayoutStyle
DUP
INVOKESPECIAL kotlindeepdive/LayoutStyle. ()V
ASTORE 2
ALOAD 2
ASTORE 3
ALOAD 3
GETSTATIC kotlindeepdive/Orientation.VERTICAL : Lkotlindeepdive/Orientation;
INVOKEVIRTUAL kotlindeepdive/LayoutStyle.setOrientation (Lkotlindeepdive/Orientation;)V
ALOAD 2
ASTORE 1

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


Разберём по пунктам:


  1. Создаётся новый экземпляр LayoutStyle и дублируется в стек.
  2. Вызывается конструктор с нулевыми параметрами.
  3. Выполняются операции store/load (об этом — ниже).
  4. В стек передаётся значение Orientation.VERTICAL.
  5. Вызывается setOrientation, который поднимает из стека объект и значение.

Здесь отметим пару вещей. Во-первых, не задействовано никакой магии, всё происходит так, как ожидается: применительно к созданному нами экземпляру LayoutStyle вызывается метод setOrientation. Кроме того, нигде не видно функции apply, потому что компилятор инлайнит её.


Более того, байткод почти идентичен тому, который генерируется при использовании одного лишь Java! Судите сами:


// Java

enum Orientation {
    VERTICAL, HORIZONTAL;
}

public class LayoutStyle {
    private Orientation orientation = HORIZONTAL;

    public Orientation getOrientation() {
        return orientation;
    }

    public void setOrientation(Orientation orientation) {
        this.orientation = orientation;
    }

    public static void main(String[] args) {
        LayoutStyle layout = new LayoutStyle();
        layout.setOrientation(VERTICAL);
    }
}

// Bytecode

NEW kotlindeepdive/LayoutStyle
DUP
ASTORE 1
ALOAD 1
GETSTATIC kotlindeepdive/Orientation.VERTICAL : kotlindeepdive/Orientation;
INVOKEVIRTUAL kotlindeepdive/LayoutStyle.setOrientation (kotlindeepdive/Orientation;)V

Совет: вы могли заметить большое количество операций ASTORE/ALOAD. Они вставлены компилятором Kotlin, так что отладчик работает и для лямбд! Об этом мы поговорим в последнем разделе статьи.


With


/**
 * Вызывает определённую функцию [block] с данным [receiver] в качестве своего получателя и возвращает результат.
 */
@kotlin.internal.InlineOnly
public inline fun  with(receiver: T, block: T.() -> R): R = receiver.block()

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


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


val layout = with(contextWrapper) { 
  // `this` is the contextWrapper
  LayoutStyle(context, attrs).apply { orientation = VERTICAL }
}

Здесь можно опустить префикс contextWrapper. для context и attrs, потому что contextWrapper — получатель функции with. Но даже в этом случае способы применения вовсе не так очевидны по сравнению с apply, эта функция может оказаться полезна при определённых условиях.


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


enum class Orientation {
  VERTICAL, HORIZONTAL
}

class LayoutStyle {
  var orientation = HORIZONTAL
}

object SharedState {
  val previousOrientation = VERTICAL
}

fun main() {
  val layout = with(SharedState) {
    LayoutStyle().apply { orientation = previousOrientation }
  }
}

Получатель with — синглтон SharedState, он содержит параметр ориентации (orientation parameter), который мы хотим задать для нашего макета. Внутри функции block создаём экземпляр LayoutStyle, и благодаря apply мы можем просто задать ориентацию, считав её из SharedState.


Посмотрим снова на сгенерированный байткод:


GETSTATIC kotlindeepdive/SharedState.INSTANCE : Lkotlindeepdive/SharedState;
ASTORE 1
ALOAD 1
ASTORE 2
NEW kotlindeepdive/LayoutStyle
DUP
INVOKESPECIAL kotlindeepdive/LayoutStyle. ()V
ASTORE 3
ALOAD 3
ASTORE 4
ALOAD 4
ALOAD 2
INVOKEVIRTUAL kotlindeepdive/SharedState.getPreviousOrientation ()Lkotlindeepdive/Orientation;
INVOKEVIRTUAL kotlindeepdive/LayoutStyle.setOrientation (Lkotlindeepdive/Orientation;)V
ALOAD 3
ASTORE 0
RETURN

Ничего особенного. Извлечён синглтон, реализованный в виде статичного поля в классе SharedState; экземпляр LayoutStyle создаётся так же, как и раньше, вызывается конструктор, ещё одно обращение для получения значения previousOrientation внутри SharedState и последнее обращение для присвоения значения экземпляру LayoutStyle.


Совет: при использовании «Show Kotlin Bytecode» можно нажать «Decompile» и посмотреть Java-представление байткода, созданного для компилятора Kotlin. Спойлер: оно будет именно таким, как вы ожидаете!


Let


/**
 * Вызывает заданную функцию [block] со значением `this` в качестве аргумента и возвращает результат.
 */
@kotlin.internal.InlineOnly
public inline fun  T.let(block: (T) -> R): R = block(this)

let очень полезен при работе с объектами, которые могут принимать значение null. Вместо того чтобы создавать бесконечные цепочки выражений if-else, можно просто скомбинировать оператор ? (называется «оператор безопасного вызова») с let: в результате вы получите лямбду, у которой аргумент it является не-nullable-версией исходного объекта.


val layout = LayoutStyle()
SharedState.previousOrientation?.let { layout.orientation = it }

Рассмотрим пример целиком:


enum class Orientation {
  VERTICAL, HORIZONTAL
}

class LayoutStyle {
  var orientation = HORIZONTAL
}

object SharedState {
  val previousOrientation: Orientation? = VERTICAL
}

fun main() {
  val layout = LayoutStyle()
  // layout.orientation = SharedState.previousOrientation -- this would NOT work!
  SharedState.previousOrientation?.let { layout.orientation = it }
}

Теперь previousOrientation может быть null. Если мы попробуем напрямую присвоить его нашему макету, то компилятор возмутится, потому что nullable-тип нельзя присваивать не-nullable-типу. Конечно, можно написать выражение if, но это приведёт к двойной ссылке на выражение SharedState.previousOrientation. А если воспользоваться let, то получим не-nullable-ссылку на тот же самый параметр, которую можно безопасно присвоить нашему макету.
С точки зрения байткода всё очень просто:


NEW kotlindeepdive/let/LayoutStyle
DUP
INVOKESPECIAL kotlindeepdive/let/LayoutStyle. ()V
GETSTATIC kotlindeepdive/let/SharedState.INSTANCE : Lkotlindeepdive/let/SharedState;
INVOKEVIRTUAL kotlindeepdive/let/SharedState.getPreviousOrientation ()Lkotlindeepdive/let/Orientation;
DUP
IFNULL L2
ASTORE 1
ALOAD 1
ASTORE 2
ALOAD 0
ALOAD 2
INVOKEVIRTUAL kotlindeepdive/let/LayoutStyle.setOrientation (Lkotlindeepdive/let/Orientation;)V
GOTO L9
L2
 POP
L9
 RETURN

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


Run


Есть две версии run: первая — простая функция, вторая — функция-расширение обобщённого типа (generic type). Поскольку первая всего лишь вызывает функцию block, которая передаётся как параметр, мы будем анализировать вторую.


/**
 * Вызывает определённую функцию [block] со значением `this` в качестве получателя и возвращает результат.
 */
@kotlin.internal.InlineOnly
public inline fun  T.run(block: T.() -> R): R = block()

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


В этом примере подчёркивается тот факт, что run возвращает результат функции block, в данном случае это присваивание (Unit):


enum class Orientation {
    VERTICAL, HORIZONTAL
}

class LayoutStyle {
    var orientation = HORIZONTAL
}

object SharedState {
    val previousOrientation = VERTICAL
}

fun main() {
    val layout = LayoutStyle()
    layout.run { orientation = SharedState.previousOrientation } // returns Unit
}

Эквивалентный байткод:


NEW kotlindeepdive/LayoutStyle
DUP
INVOKESPECIAL kotlindeepdive/LayoutStyle. ()V
ASTORE 0
ALOAD 0
ASTORE 1
ALOAD 1
ASTORE 2
ALOAD 2
GETSTATIC kotlindeepdive/SharedState.INSTANCE : Lkotlindeepdive/SharedState;
INVOKEVIRTUAL kotlindeepdive/SharedState.getPreviousOrientation ()Lkotlindeepdive/Orientation;
INVOKEVIRTUAL kotlindeepdive/LayoutStyle.setOrientation (Lkotlindeepdive/Orientation;)V
RETURN

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




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


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


image


Приложение: дополнительные операции store/load


Я ещё кое-что не мог до конца понять при сравнении «Java-байткода» и «Kotlin-байткода». Как я уже говорил, в Kotlin, в отличие от Java, были дополнительные операции astore/aload. Я знал, что это как-то связано с лямбдами, но мог разобраться, зачем они нужны.


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


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


Для этого может подойти ProGuard, инструмент всем известный и всеми «любимый». Он работает на уровне байткода и, помимо запутывания и урезания, также выполняет оптимизационные проходы, чтобы сделать байткод компактнее. Я написал одинаковый кусок кода на Java и Kotlin, применил к обеим версиям ProGuard с одним набором правил и сравнил результаты. Вот что обнаружилось.


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


-dontobfuscate
-dontshrink
-verbose
-keep,allowoptimization class kotlindeepdive.apply.LayoutStyle
-optimizationpasses 2
-keep,allowoptimization class kotlindeepdive.LayoutStyleJ

Исходный код


Java:


package kotlindeepdive

enum OrientationJ {
    VERTICAL, HORIZONTAL;
}

class LayoutStyleJ {
    private OrientationJ orientation = HORIZONTAL;

    public OrientationJ getOrientation() {
        return orientation;
    }

    public LayoutStyleJ() {
        if (System.currentTimeMillis() < 1) { main(); }
    }

    public void setOrientation(OrientationJ orientation) {
        this.orientation = orientation;
    }

    public OrientationJ main() {
        LayoutStyleJ layout = new LayoutStyleJ();
        layout.setOrientation(VERTICAL);
        return layout.orientation;
    }
}

Kotlin:


package kotlindeepdive.apply

enum class Orientation {
  VERTICAL, HORIZONTAL
}

class LayoutStyle {
  var orientation = Orientation.HORIZONTAL

  init {
    if (System.currentTimeMillis() < 1) { main() }
  }

  fun main() {
    val layout = LayoutStyle().apply { orientation = Orientation.VERTICAL }
    layout.orientation
  }
}

Байткод


Java:


 sgotti@Sebastianos-MBP ~/Desktop/proguard5.3.3/lib/PD/kotlindeepdive > javap -c LayoutStyleJ.class
Compiled from "SimpleJ.java"
final class kotlindeepdive.LayoutStyleJ {
  public kotlindeepdive.LayoutStyleJ();
    Code:
       0: aload_0
       1: invokespecial #8                  // Method java/lang/Object."":()V
       4: aload_0
       5: getstatic     #6                  // Field kotlindeepdive/OrientationJ.HORIZONTAL$5c1d747f:I
       8: putfield      #5                  // Field orientation$5c1d747f:I
      11: invokestatic  #9                  // Method java/lang/System.currentTimeMillis:()J
      14: lconst_1
      15: lcmp
      16: ifge          34
      19: new           #3                  // class kotlindeepdive/LayoutStyleJ
      22: dup
      23: invokespecial #10                 // Method "":()V
      26: getstatic     #7                  // Field kotlindeepdive/OrientationJ.VERTICAL$5c1d747f:I
      29: pop
      30: iconst_1
      31: putfield      #5                  // Field orientation$5c1d747f:I
      34: return
}

Kotlin:


 sgotti@Sebastianos-MBP ~/Desktop/proguard5.3.3/lib/PD/kotlindeepdive > javap -c apply/LayoutStyle.class
Compiled from "Apply.kt"
public final class kotlindeepdive.apply.LayoutStyle {
  public kotlindeepdive.apply.LayoutStyle();
    Code:
       0: aload_0
       1: invokespecial #13                 // Method java/lang/Object."":()V
       4: aload_0
       5: getstatic     #11                 // Field kotlindeepdive/apply/Orientation.HORIZONTAL:Lkotlindeepdive/apply/Orientation;
       8: putfield      #10                 // Field orientation:Lkotlindeepdive/apply/Orientation;
      11: invokestatic  #14                 // Method java/lang/System.currentTimeMillis:()J
      14: lconst_1
      15: lcmp
      16: ifge          32
      19: new           #8                  // class kotlindeepdive/apply/LayoutStyle
      22: dup
      23: invokespecial #16                 // Method "":()V
      26: getstatic     #12                 // Field kotlindeepdive/apply/Orientation.VERTICAL:Lkotlindeepdive/apply/Orientation;
      29: putfield      #10                 // Field orientation:Lkotlindeepdive/apply/Orientation;
      32: return
}

Выводы после сравнения двух листингов байткода:


  1. Дополнительные операции astore/aload в «Kotlin-байткоде» исчезли, потому что ProGuard счёл их избыточными и сразу удалил (любопытно, что для этого понадобилось сделать два оптимизационных прохода, после одного они не были удалены).
  2. «Java-байткод» и «Kotlin-байткод» почти идентичны. В первом есть интересные/странные моменты при работе с enum-значением, а в Kotlin ничего подобного нет.

Заключение


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


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

Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331442/


Метки:  

[recovery mode] Как пожизненный пользователь Windows переключился на Linux по-плохому

Пятница, 23 Июня 2017 г. 12:18 + в цитатник
Позвольте мне перефразировать этот заголовок сказав таким образом: я всегда интересовался тем, как устроены вещи, а не лишь тем, что они делают. Если что-либо что-то делает, то я бы хотел знать зачем, как и могу-ли я это кастомизировать.

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

К счастью для меня и других, подобных мне, есть альтернатива. Ну, существует несколько (очень много) дистрибутивов Linux, и большинство из них интуитивно понятны и полностью пригодны для использования сразу после установки. Возможно, одним из самых известных «Windows-подобных» дистрибутивов является Ubuntu. У этого есть рабочий стол, похожий на Windows 10, и он очень «графический» и ориентирован в основном на то, что являются новыми для Linux.
Я, в свою очередь, пришёл к Debian, дистрибутив, на котором и был основан Ubuntu. Он не держит вас за ручку так крепко как другие многофункциональные дистрибутивы, но от того он и более настраиваемый. Я начал с установочного образа, найденного здесь, который вы можете скачать и использовать для создания загрузочного USB.

Это самая простая установка Debian и исключает те вещи, которые я, как предыдущий пользователь Windows, воспринимаю как должное. Помимо прочего, мне пришлось найти и установить (или, по крайней мере, настроить):

  • Менеджер окон (i3)
  • Приложение, которое позволит мне подключиться к Интернету (NetworkManager / nm-applet)
  • Программа, которая позволяет мне контролировать яркость экрана (xrandr)
  • Программа, которая обрабатывает звук, подобные программы ещё называют звуковым сервером (pulseaudio)
  • Обработчики событий, чтобы, например, говорить моему ноутбуку приостанавливать работу, когда я закрываю крышку
  • Дисплей для базовой информации о состояниях (i3bar)
  • Уведомления рабочего стола (dunst) (об этом ещё обязательно будет отдельная статья)
  • Основные программы, такие как графический файловый менеджер (PCmanFM), просмотрщик PDF (Okular) и редактор изображений (Darktable)

Если, в отличие от меня, вы предпочитаете использовать более полнофункциональную среду рабочего стола, то есть лёгкий способ: Net Install по умолчанию предоставляет стандартную систему с рабочей средой GNOME. Для Debian есть полное руководство по установке, которое шаг за шагом проведет вас через этот процесс.
Однако, делая это сложным путём («по-плохому») я многому научился. После начала работы с базовой системой я получил куда лучшее представление в отношении того, что происходит “под капотом”. Если в будущем у меня возникнет проблема с одним компонентом, у меня куда больше шансов получить представление о том, как же это исправить, поскольку я “это” сам собрал. На этом пути я набил не мало шишек, но также нашёл некоторые решения, которые работаю куда лучше, чем даже предлагаемые Net Install по-умолчанию.

Но, сперва, для мотивации, скриншот моего рабочего стола (Linux-не Linux, а я люблю, когда всё красивенько):
image
Разрешение на распространение этих ну очень красивых конфигурационных файлов были любезно предоставлены мне Vicky Lai для написания этой статьи и доступны в её GitHub, так что милости прошу.

Что вообще такое файлы конфигурации?


Если вы новичок в Linux или вовсе в программировании, то это в основном техническая версия простого и знакомого «Файл> Настройки» в программах GUI. В зависимости от приложения, которое вы настраиваете, есть несколько разных форматов и языков этих самых файлов конфигурации. К счастью, есть достаточно примеров конфигурационных файлов, доступных с помощью простого веб-поиска.

Куда же засунуть все эти файлы конфигурации?


Я нашел несколько разных путей для файлов. Ниже приведены пути работы моих конфигурационных файлов:
systemd event handlers:   /etc/systemd/logind.conf
Для URxvt:                ~/.Xdefaults
Для i3wm:                 ~/.config/i3/config 
Для i3bar:                ~/.config/i3status/config/i3status.conf
Для dunst:                ~/.config/dunst/dunstrc 
Для Compton:              ~/.config/compton.conf


Я выбрал глупое имя пользователя, как его изменить?


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

  • Dropbox
  • Anaconda and pip
  • Файловые пути, написанные полностью в файлах конфигурации

Чтобы избежать проблем, с которыми я столкнулся, измените свое имя пользователя, прежде чем настраивать все свои программ. Если для этого уже слишком поздно, просто имейте в виду, что затронуты многие программы, включая все файловые пути содержащие: /home /oldusername /…
Чтобы изменить имя пользователя через терминал, войдите в систему с правами root, а затем:
$ killall -u oldusername
$ id oldusername
>>> uid=1000(oldusername) gid=1000(oldusername) groups=1000(oldusername),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev)
# изменение логина
$ usermod -l newusername oldusername
# изменение имени группы
$ groupmod -n newusername oldusername 
# изменение директории home
$ usermod -d /home/newusername -m newusername
# добавление комментария с полным именем
$ usermod -c "New Full Name" newusername 
# проверяем что "newusername" заменил "oldusername" во всех полях
$ id newusername 
>>> uid=1000(newusername) gid=1000(newusername) groups=1000(newusername),24(cdrom),25(floppy),27(sudo),29(audio),30(dip),44(video),46(plugdev),108(netdev)

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

Как заставить NetworkManager и Dropbox запускаться автоматически?


Dropbox для Linux предположительно имеет настройку автозапуска, где вы можете ввести dropbox autostart y прямо в терминал и таким образом создать обработку события. Но я, естественно, решил что это не для меня. Вместо этого я добавил все приложения, которые я хотел бы запустить автоматически при входе в мой конфигурационный файл i3 с помощью этого синтаксиса:
# автозапуск приложений
exec --no-startup-id /usr/bin/nm-applet
exec --no-startup-id dropbox start

В выше приведённом коде exec является командой выполнения (от “execute”), --no-startup-id в основном избавляет вас от того чтобы смотреть как ваш курсор делает эту причудливую вращающуюся загрузку. И последним компонентом команды является путь к файлу программы или синтаксис для его запуска, так, как если бы вы писали в терминале.

Как настроить OpenVPN с помощью NetworkManager?


Для начала убедитесь, что вы выполнили
apt-get install network-manager-openvpn

чтобы получить плагин.
Вам понадобится файл client.ovpn. В моем случае я настроил свой собственный VPN с помощью Amazon EC2 и загрузил файл client.ovpn со своей страницы консоли OpenVPN.
Откройте client.ovpn с помощью текстового редактора, например vim (уверен ниже из-за этого появится ссылка на статью о его закрытии), и измените любые экземпляры “удалённый openvpn порт xxxx” (так как я пошёл по пути англоязычного ПО здесь и далее в скобках тот вариант который лицезрел я в оригинале “remote openvpn port xxxx”) вместо “удалённый <ваш ip-адрес> порт xxxx” (“remote port xxxx”).
Используйте nm-applet для настройки нового VPN-соединения. Если вы установили плагин OpenVPN, в раскрывающемся списке вы увидите OpenVPN. Выберите вариант “Импортировать сохраненную конфигурацию VPN”.
image
Как только вы загрузите файл client.ovpn и нажмите “Создать”, все настройки будут заполнены за вас, кроме имени пользователя и пароля. Заполняете их и всё, готово.

Как получить статус VPN в i3bar?


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

Отредактируйте путь к файлу в следующем разделе кода:
run_watch VPN {
        pidfile = "sys/class/net/yoursetting"
}

Где «yoursetting» – это один из tap/tun/tun tap в зависимости от ваших настроек VPN. Если вы не знаете, что это такое вы можете узнать в настройках конфигурации VPN в разделе VPN> Дополнительно>«Установить тип виртуального устройства» (VPN > Advanced > «Set virtual device type»).

Как вновь начать использовать клавиши Print Screen/управления подсветкой и звуком?


Я создал привязки клавиш в моем файле конфигурации i3. Самое трудная часть заключалась в выяснении того, что контролирует конкретную функцию (и в некоторых случаях, нужно было что-то установить для управления функцией).
# настройки яркости (brightness adjustment)
bindsym $mod+Shift+F6 exec xrandr --output eDP-1 --brightness 1
bindsym $mod+F6       exec xrandr --output eDP-1 --brightness 0.8
bindsym $mod+F5       exec xrandr --output eDP-1 --brightness 0.5
bindsym $mod+F7       exec xrandr --output eDP-1 --brightness 0.1

# настройки звука (volume control)
bindsym $mod+F12 exec amixer -q sset Master 3%+
bindsym $mod+F11 exec amixer -q sset Master 3%-
bindsym $mod+F10 exec amixer -q sset Master toggle

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

Я отредактировал мой файл конфигурации, но я не вижу никаких изменений. Что за дела?
При изменении некоторых конфигурация, таких как обои в i3 и dunst- уведомления, я обнаружил, что мне пришлось либо перезагрузить приложение (для i3, написать i3-msg restart в терминале), либо перезапустить весь мой сеанс (выйти из системы и вернуться в систему), чтобы увидеть изменения.

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


Я очень надеюсь данный пост был полезен и не рискует быть назван очевидным. Быть может после его прочтения кто-то будет следовать всему вышеперечисленному как инструкции, а кто-то подскажет мне на что обратить внимание и что, быть може по-незнанию, я сделал не так.
Ссылки:
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331492/


Метки:  

Марафонский раунд Яндекс.Алгоритма 2017

Пятница, 23 Июня 2017 г. 12:06 + в цитатник

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




Особенностью большинства практических задач является отсутствие точного решения — или же алгоритмы его нахождения оказываются слишком медленными. Команде и отдельному разработчику нужно сделать хороший прототип решения, который будет внедряться в окончательный алгоритм. Задачи подобного рода давно встречаются в соревнованиях TopCoder, ежегодных соревнованиях Marathon24, Deadline24, Google Hash Code и других. Конкурс длится больше стандартных алгоритмических раундов, так что участники могут в спокойной обстановке и в удобное для себя время реализовать придуманный метод.


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


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


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


Условие задачи «Разделение страны»


Cмотреть условие
Ограничение времени: Ограничение памяти: Ввод: Вывод:
2 с 256 МБ стандартный ввод стандартный вывод

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


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


Формат ввода


  • В первой строке содержится три целых числа n, m и k (3 <= n, m <= 50, 3 <= k <= 16) — размеры страны и количество источников жизни и магии.
  • В следующих k строках содержатся пары целых чисел rli, cli (0 <= rli <= n-1, 0 <= cli <= m-1) — координаты источников жизни.
  • В следующих k строках содержатся пары целых чисел rmi, cmi (0 <= rmi <=n-1, 0 <= cmi <= m-1) — координаты источников магии.
  • Гарантируется, что все источники находятся в различных клетках, а также что для указанных входных данных существует хотя бы одно разделение на области, удовлетворяющее вышеописанным условиям.

Формат вывода


Выведите n строк по m латинских букв в каждой: разбиение страны на области. Участки, содержащие одинаковые буквы, будут отнесены к одной области. В качестве символов разрешается использовать строчные и прописные английские буквы. Всего должно быть использовано в точности k различных букв. Клетки с одинаковыми буквами должны образовывать связную область. Каждая область должна содержать ровно один источник жизни и ровно один источник магии.


Система оценки


Предоставленное разбиение будет оценено по следующей системе:


  • Если разбиение некорректно (оно содержит несвязные области, либо области содержат неверное количество источников, либо не соблюдён формат вывода), ваше решение получит 0 баллов за этот тест;
  • Иначе для каждой области определим её «выпуклость» как отношение площади к квадрату периметра области, где площадь — это количество клеток, входящих в область, а периметр — количество сторон клеток, смежных с другими областями либо с границей страны (см. пример для пояснения);
  • Сумма баллов за тест — средняя «выпуклость» всех областей, умноженная на 160 000 и округлённая к ближайшему целому.

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


После окончания соревнования ваше последнее отосланное и скомпилированное решение будет проверено на полном наборе из 250 тестов (50 предварительных тестов не входят в полный набор). Среднее количество баллов по всем тестам из полного набора и будет вашим окончательным результатом.


Генерация тестов


  • 40% тестов в каждом наборе являются полностью случайными: равновероятно выбраны n, m, k, после чего на поле некоторым случайным образом распределено соответствующее количество источников жизни и магии.
  • 40% тестов в каждом наборе сгенерированы следующим образом: равновероятно выбраны n, m, k, после чего на поле некоторым случайным образом распределено k источников жизни. Рядом с каждым источником жизни некоторым случайным образом сгенерирован источник магии так, чтобы разность координат по каждой из осей не превышала d, где d — фиксированное для теста число от 1 до 4, выбранное равновероятно.
  • 20% тестов в каждом наборе сгенерированы следующим образом: равновероятно выбраны n, m, k, после чего выбрано число s такое, что 2s <= min(n, m) и k <= 4(s - 1). После этого на поле некоторым случайным образом выбраны два непересекающихся квадрата размером sxs, в одном из которых некоторым случайным образом распределены k источников жизни, а в другом k источников магии.

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


Пример


ввод вывод
4 6 3
0 0
1 3
3 0
3 5
2 4
2 2
aaabbc
aaabbc
aaabbc
cccccc

Примечания


В примере имеются три области:


  • Область ‘a’: площадь 9, периметр 3 + 3 + 3 + 3 = 12, «выпуклость» 0.0625
  • Область ‘b’: площадь 6, периметр 3 + 2 + 3 + 2 = 10, «выпуклость» 0.06
  • Область ‘c’: площадь 9, периметр 4 + 6 + 1 + 5 + 3 + 1 = 20, «выпуклость» 0.0225

Тогда средняя «выпуклость» равна 0.048(3), а количество баллов за этот тест — 7733.


Вы можете отправлять решения не чаще одного раза в 5 минут.




Константин Хадаев (Россия, 7 место по итогам раунда)

Сначала найдём какие-нибудь пути от одних источников к другим. Это стандартная задача на потоки. Некоторые участники здесь использовали min-cost max-flow, но в моём решении он не дал никакого прироста, и в последней версии я оставил алгоритм Диница.

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

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

Дальше у нас есть какая-то карта, будем её локально оптимизировать.

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

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

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

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

И про обратную связь:
Не понравилось, что с VK Cup'ом пересекается. Кстати, следующего раунда это тоже касается — он в один день с Russian code cup и Distributed code jam, я три контеста в один день точно не потяну. А задача очень приятная, да.

Eryx (Польша, 2 место по итогам раунда)

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

Версию моего решения с комментариями можно найти здесь:
https://www.mimuw.edu.pl/~erykk/yandex/solution.cpp

Я вижу, что часть финальных тестов упала (хотя с публичными тестами всё было нормально). У меня не возникло идеи использовать min-cost max-flow для построения путей. Думаю, если бы я задействовал это в качестве альтернативного подхода, то получил бы корректные ответы на указанных тестах, а возможно и улучшил бы другие результаты.
Оригинал на английском
Thanks for the great contest and the very interesting task! It was a pleasure to work on it. The only thing I did not like was a bit unclear
statement of the test case generation («some random distribution» — but what distribution?), possibly a 'official' test generator could be even included (with no seeds), with the non-trivial part «make sure that a solution exists» left for us to implement (or solve manually).

The commented version of my solution can be found at:
https://www.mimuw.edu.pl/~erykk/yandex/solution.cpp

I see that I have failed some final tests (the public tests were all okay). I did not get the idea to use min-cost-max-flow to generate paths; I think using this as an alternative approach could help me get positive scores on these few tests, and possibly improve the results on other tests.

Илья Корнаков (Швейцария, 6 место по итогам раунда)

Я уже что-то написал в http://codeforces.com/blog/entry/51858?#comment-358766

Задача понравилась, по модулю тормозов Java. Решение устроено следующим образом:
  • Сначала min-cost-max-flow ищет пути, соединяющие истоки и стоки.
  • Потом пути расширяются жадно, пока поле не будет заполнено. Жадные шаги пробуют добавлять по одной клетке, а также по отрезку столбца/строки к существующей компоненте. Целевая функция — изменение скора / (количество добавленных клеток + 10).
  • Полученное решение жадно оптимизируется, перекидывая клетки или отрезки столбцов/строк между компонентами (с той же целевой функцией).
  • Описанный процесс запускается много раз, выбирается лучшее решение. В процесс добавлен рандом: рёбра в графе для потока перемешиваются, скоры в жадности умножаются на случайное число от 1 до 1,2.

Больше всего очков принесло переписывание решения с Java на C++ (~+150). Помимо этого, жадные улучшения после того как решение сгенерировалось — видимо, полезная идея. Из нереализованного — пробовать больше изменений в жадности (например, отрезать «углы» — пары сторон) и вместо потока сделать что-нибудь, что лучше приспособлено к целевой метрике (т. к. для потока длинный горизонтальный путь — сильно лучше, чем путь по диагонали с таким же горизонтальным смещением, а с точки зрения целевой метрики — сильно хуже). Ещё была идея попробовать simulated annealing вместо жадности, но на это не осталось времени.
Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/331482/


Метки:  

Поиск сообщений в rss_rss_hh_new
Страницы: 1437 ... 1020 1019 [1018] 1017 1016 ..
.. 1 Календарь