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

Hackathon

Serverless шагает по планете. Сравним SberCloud и AWS

14.12.2020 10:07:17 | Автор: admin

image


Мне с друзьями довелось поучаствовать в хакатоне
SberCloud.Advanced Hacking и пощупать облачные сервисы Сбера. На моем текущем месте работы я каждый день работаю с Serverless стеком от AWS (CloudFront + Lambda Edge + S3 + Lambda + Step Functions + Aurora PostgreSQL Serverless + DynamoDB + Cognito). Так что мне есть с чем сравнить. Если заинтересовались, то добро пожаловать под кат.


Недавно Сбер выкатил в публичный доступ свою облачную платформу SberCloud. К сожалению, сейчас, чтобы ей воспользоваться, нужно быть юридическим лицом. Представители Сбера говорят, что, возможно, доступ для физических лиц появится в следующем году. Но тем не менее, в рамках хакатона, я смог посмотреть, что там внутри, как обычный смертный. Что я там увидел? Огромное количество сервисов прям, как у AWS, на любой вкус https://sbercloud.ru/ru/products.


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


Я хотел собрать приложение аналогичное такому в AWS.
AWS Serverless Application


Вот что получилось на стеке SberCloud.
SberCloud Serverless Application


Я быстренько создал лямбду FunctionGraph.
FunctionGraph. 1
FunctionGraph. 2


Прикрутил к ней API Gateway. Настроил HTTP/HTTPS trigger.
API Gateway


Кстати, читать логи лямбды оказалось намного удобнее чем в AWS. Всё в одном месте. Ненужно прыгать по вкладкам и искать нужный Log Stream.
FunctionGraph Logs


К сожалению, настоящей Serverless базы данных у SberCloud не нашлось. Пришлось взять сервис с фиксированной платой.
RDS Postgres


Настроил Environment variables от PostgreSQL пользователя у лямбды FunctionGraph.
Environment variables


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


import { Client } from 'pg'export const escapeId = (str: string): string => `"${String(str).replace(/(["])/gi, '$1$1')}"`export const escapeStr = (str: string): string => `'${String(str).replace(/(['])/gi, '$1$1')}'`export const executeStatement = async <T extends Record<string, any>>(  sql: string): Promise<Array<T>> => {  const client = new Client()  await client.connect()  try {    const res = await client.query(sql)    return res.rows  } finally {    await client.end()  }}

Настроил Object Storage Service.
Object Storage Service. 1
Object Storage Service. 2


Некое SDK для работы с SberCloud имеется, но чего-то полезного мне там найти не удалось.
SberCloud SDK


Для загрузки картинок из браузера в Object Storage Service через подписанный URL код пришлось писать самому. Не самое приятное занятие угадывать сигнатуры и считать хеши руками.


async (req: Request, res: Response) => {  validateUserHandler(req, res)  const { authToken } = context  const { userId } = req.params  const uploadId = uuidV4()  const body = Buffer.from(    JSON.stringify({      auth: {        identity: {          methods: ['token'],          token: {            id: authToken,            'duration-seconds': '900',          },        },      },    }),    'utf8'  )  const options = {    hostname: 'iam.ru-moscow-1.hc.sbercloud.ru',    port: 443,    path: '/v3.0/OS-CREDENTIAL/securitytokens',    method: 'POST',    headers: {      'Content-Type': 'application/json; charset=utf8',      'Content-Length': body.length,    },  }  const credentialBuffer: Buffer = await new Promise((resolve, reject) => {    const req = https.request(options, (res) => {      res.on('data', (data) => {        resolve(data)      })      res.on('error', (error) => {        reject(error)      })    })    req.write(body)    req.end()  })  const {    credential,  }: {    credential: { securitytoken: string; secret: string }  } = JSON.parse(credentialBuffer.toString('utf8'))  const { securitytoken, secret } = credential  const stringToSign = Buffer.from(    JSON.stringify({      expiration: '2020-12-31T12:00:00.000Z',      conditions: [        { 'x-obs-acl': 'public-read' },        { 'x-obs-security-token': securitytoken },        { bucket: 'anti-cube-images' },        ['starts-with', '$key', `${userId}/`],      ],    }),    'utf8'  ).toString('base64')  const hmac = crypto.createHmac('sha1', secret)  hmac.update(stringToSign)  const signature = hmac.digest('base64')  res.json({    uploadId,    signature,  })}

В целом SberCloud мне понравился. Очень достойно. Не ожидал увидеть международный уровень облачных сервисов на российском рынке. Желаю Сберу обзавестись настоящей Serverless базой данных с платой только за использование. Лучше смотреть в этом плане в сторону CosmosDB от Azure или опенсорсного TiDB на своих серверах. У AWS сделано не особо грамотно, не копируйте у них.


Дополнительно про SberCloud можно посмотреть на YouTube:



Документация: https://docs.sbercloud.ru/


На хакатоне мы с ребятами делали изоморфное приложение на React+Redux. Презентация нашего проекта: https://docs.google.com/presentation/d/1LNjg2xfFHljTuH6ke_lkF6o1m9HTfemWcxW0w1OOssc/edit?usp=sharing


Подробнее..

Тривиальная и неправильная облачная компиляция

28.01.2021 00:21:03 | Автор: admin


Введение


Данная статья не история успеха, а скорее руководство как не надо делать. Весной 2020 для поддержания спортивного тонуса участвовал в студенческом хакатоне (спойлер: заняли 2-е место). Удивительно, но задача из полуфинала оказалась более интересной и сложной чем финальная. Как вы поняли, о ней и своём решении расскажу под катом.


Задача


Данный кейс был предложен Deutsche Bank в направлении WEB-разработка.
Необходимо было разработать онлайн-редактор для проекта Алгосимулятор тестового стенда для проверки работы алгоритмов электронной торговли на языке Java. Каждый алгоритм реализуется в виде наследника класса AbstractTradingAlgorythm.


AbstractTradingAlgorythm.java
public abstract class AbstractTradingAlgorithm {    abstract void handleTicker(Ticker ticker) throws Exception;    public void receiveTick(String tick) throws Exception {        handleTicker(Ticker.parse(tick));    }    static class Ticker {        String pair;        double price;       static Ticker parse(String tick) {           Ticker ticker = new Ticker();           String[] tickerSplit = tick.split(",");           ticker.pair = tickerSplit[0];           ticker.price = Double.valueOf(tickerSplit[1]);           return ticker;       }    }}

Сам же редактор во время работы говорит тебе три вещи:


  1. Наследуешь ли ты правильный класс
  2. Будут ли ошибки на этапе компиляции
  3. Успешен ли тестовый прогон алгоритма. В данном случае подразумевается, что "В результате вызова new <ClassName>().receiveTick(RUBHGD,100.1) отсутствуют runtime exceptions".


Ну окей, скелет веб-сервиса через spring накидать дело на 5-10 минут. Пункт 1 работа для регулярных выражений, поэтому даже думать об этом сейчас не буду. Для пункта 2 можно конечно написать синтаксический анализатор, но зачем, когда это уже сделали за меня. Может и пункт 3 получится сделать, использовав наработки по пункту 2. В общем, дело за малым, уместить в один метод, ну например, компиляцию исходного кода программы на Java, переданного в контроллер строкой.


Решение


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



у каждого свой путь.


Естественно, Java окружение устанавливать и настраивать всё же придётся. Правда компилировать и исполнять код мы будем не в терминале, а, как бы это ни звучало, в коде. Начиная с 6 версии, в Java SE присутствует пакет javax.tools, добавленный в стандартный API для компиляции исходного кода Java.
Теперь привычные понятия такие, как файлы с исходным кодом, параметры компилятора, каталоги с выходными файлами, сообщения компилятора, превратились в абстракции, используемые при работе с интерфейсом JavaCompiler, через реализации которого ведётся основная работа с задачами компиляции. Подробней о нём можно прочитать в официальной документации. Главное, что оттуда сейчас перейдёт моментально в текст статьи, это класс JavaSourceFromString. Дело в том, что, по умолчанию, исходный код загружается из файловой системы. В нашем же случае исходный код будет приходить строкой извне.


JavaSourceFromString.java
import javax.tools.SimpleJavaFileObject;import java.net.URI;public class JavaSourceFromString extends SimpleJavaFileObject {    final String code;    public JavaSourceFromString(String name, String code) {        super(URI.create("string:///" + name.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);        this.code = code;    }    @Override    public CharSequence getCharContent(boolean ignoreEncodingErrors) {        return code;    }}

Далее, в принципе уже ничего сложного нет. Получаем строку, имя класса и преобразуем их в объект JavaFileObject. Этот объект передаём в компилятор, компилируем и собираем вывод, который и возвращаем на клиент.
Сделаем класс Validator, в котором инкапсулируем процесс компиляции и тестового прогона некоторого исходника.


public class Validator {    private JavaSourceFromString sourceObject;    public Validator(String className, String source) {        sourceObject = new JavaSourceFromString(className, source);    }}

Далее добавим компиляцию.


public class Validator {    ...    public List<Diagnostic<? extends JavaFileObject>> compile() {        // получаем компилятор, установленный в системе        var compiler = ToolProvider.getSystemJavaCompiler();        // компилируем        var compilationUnits = Collections.singletonList(sourceObject);        var diagnostics = new DiagnosticCollector<JavaFileObject>();        compiler.getTask(null, null, diagnostics, null, null, compilationUnits).call();        // возворащаем диагностику        return diagnostics.getDiagnostics();    }}

Пользоваться этим можно как-то так.


public void MyMethod() {        var className = "TradeAlgo";        var sourceString = "public class TradeAlgo extends AbstractTradingAlgorithm{\n" +                "@Override\n" +                "    void handleTicker(Ticker ticker) throws Exception {\n" +                "       System.out.println(\"TradeAlgo::handleTicker\");\n" +                "    }\n" +                "}\n";        var validator = new Validator(className, sourceString);        for (var message : validator.compile()) {            System.out.println(message);        }    }

При этом, если компиляция прошла успешно, то возвращённый методом compile список будет пуст. Что интересно? А вот что.

На приведённом изображении вы можете видеть директорию проекта после завершения выполнения программы, во время выполнения которой была осуществлена компиляция. Красным прямоугольником обведены .class файлы, сгенерированные компилятором. Куда их девать, и как это чистить, не знаю жду в комментариях. Но что это значит? Что скомпилированные классы присоединяются в runtime, и там их можно использовать. А значит, следующий пункт задачи решается тривиально с помощью средств рефлексии.
Создадим вспомогательный POJO для хранения результата прогона.


TestResult.java
public class TestResult {    private boolean success;    private String comment;    public TestResult(boolean success, String comment) {        this.success = success;        this.comment = comment;    }    public boolean success() {        return success;    }    public String getComment() {        return comment;    }}

Теперь модифицируем класс Validator с учётом новых обстоятельств.


public class Validator {    ...    private String className;    private boolean compiled = false;    public Validator(String className, String source) {        this.className = className;        ...    }    ...    public TestResult testRun(String arg) {        var result = new TestResult(false, "Failed to compile");        if (compiled) {            try {                // загружаем класс                var classLoader = URLClassLoader.newInstance(new URL[]{new File("").toURI().toURL()});                var c = Class.forName(className, true, classLoader);                // создаём объект класса                var constructor = c.getConstructor();                var instance = constructor.newInstance();                // выполняем целевой метод                c.getDeclaredMethod("receiveTick", String.class).invoke(instance, arg);                result = new TestResult(true, "Success");            } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException | RuntimeException | MalformedURLException | InstantiationException e) {                var sw = new StringWriter();                e.printStackTrace(new PrintWriter(sw));                result = new TestResult(false, sw.toString());            }        }        return result;    }}

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


public void MyMethod() {        ...        var result = validator.testRun("RUBHGD,100.1");        System.out.println(result.success() + " " + result.getComment());    }

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


Какие проблемы?


  1. Ещё раз напомню про кучу .class файлов.


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


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



Поэтому делать в точности как я не надо)


P.S. Ссылка на гитхаб с исходным кодом из статьи.

Подробнее..

Как собрать датасет за неделю опыт студентов магистратуры Наука о данных

24.12.2020 14:22:40 | Автор: admin
Привет, Хабр! Сегодня хотим представить вам некоммерческий открытый датасет, собранный командой студентов магистратуры Наука о данных НИТУ МИСиС и Zavtra.Online (подразделении SkillFactory по работе с вузами) в рамках первого учебного Дататона. Мероприятие проходило как один из форматов командной практики. Данная работа заняла первое место из 18 команд.

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

TLTR: Ближе к концу статьи вы найдёте информативные графики, карты и ссылки.




Немного про сам Дататон


Программа магистратуры Наука о данных НИТУ МИСиС и Zavtra.Online рассчитана на два года т.е четыре семестра и раз в семестр для студентов будет проводиться хакатон, делая обучение больше ориентированным на решение практических задач. Первый хакатон был посвящен сбору датасета, поэтому и назвали его соответственно Дататон.

Всего в Дататоне приняло участие 90 студентов. Перед ними поставили задачу собрать датасет, который может использоваться в продукте, основанном на Data Science.

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

Оценивать команды позвали менторов практикующих специалистов по Data Science высокого уровня из таких компаний как: Align Technology, Intellivision, Wrike, Мерлин АИ, Лаборатория Касперского, Auriga, Huawei, SkillFactory.

Начало работы над датасетом


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

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

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


Источник: stroi.mos.ru

Какие проблемы решает датасет?


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

  • Я хочу открыть новую торговую точку по адресу X, сколько прямых конкурентов будет вокруг?
  • В окрестностях какого из строящихся ТПУ будут самые благоприятные условия для развития торговой точки?
  • В каких условиях сейчас работают мои непосредственные конкуренты?
  • Будет ли моя торговая точка входить в зону охвата уже существующего или строящегося ТПУ?
  • Мои клиенты используют автомобили, где лучше разместиться, чтобы им было удобнее посещать мой магазин?

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

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

1. Описание источников


1.1 Источники


В датасете были использованы следующие данные с сайта Портал открытых данных правительства города Москвы:


Другие источники:


1.2 Структура датасета


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

  • Информация о ближайшем ТПУ.
  • Информация о районе размещения.
  • График работы и транспортная доступность.
  • Данные о стоимости коммерческой недвижимости в районе.
  • Данные о зоне охвата и размере объекта.

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

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


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

1.3 Качество данных и проблемы при их сборе


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

  • Сведения по статусу и срокам сдачи отдельных ТПУ можно считать устаревшими.
  • Обнаружилась путаница в единичных случаях указаниях широты и долготы, из-за чего некоторые объекты убегали в другие страны.
  • Данные о пассажиропотоке опубликованы с неточностями в форматировании, отдельные записи явно сильно завышены. Яркий пример данные по пассажиропотоку на станции Авиамоторная. Цифра в 400 000 пассажиров в сутки кажется явно завышенной, впрочем, как и в ряде других случаев. Беглый поиск показал, что реальная цифра может быть в разы меньше. Исправить такие артефакты крайне сложно.
  • Данные о ценах на коммерческую недвижимость пришлось собирать в ручном режиме.


Пример спорных данных

2. Обработка данных


2.1 Данные об объектах


После предварительной оценки имеющихся в распоряжении первичных данных (а это были данные об объектах торговли, услуг и ТПУ на территории Москвы) мы поняли, что ключевым элементом нашего датасета будут уникальные объекты торговли и услуг, которые мы объединили в единый центральный датасет. Всего мы получили более 78 000 записей, для которых помимо уникального ID и названия имеются сведения о:

  • Времени работы.
  • Типе объекта.
  • Принадлежности к сетевым объектам.
  • Адресе и координатах расположения.
  • Административной принадлежности.

2.2 Данные об административном делении


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

  • Использование специальных символов для сносок.
  • Необходимость приведения всех данных к общим единицам измерения.

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

2.3 Данные о зонах охвата


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

2.4 Данные о ТПУ


В имеющемся датасете под ТПУ подразумевается любой транспортный объект, которых на территории Москвы более 250. Поэтому нам пришлось объединять их в комплексы, исходя из названий и расстояний между ними. Сведения об объектах включают в себя такие данные, как:

  • Административные данные и географическое расположение.
  • Типы транспорта.
  • Год сдачи и статус объекта (от проекта до завершения).
  • Ближашая станция.

В теории они легко объединяются в кластеры, но на практике обнаружился ТПУ Планерная, который рушил всю систему. Одна станция находится в районе метро Речной вокзал, а вторая за Химками. Расстояние между ними составляет около 6 км, и очевидно, что учитывать их как единый комплекс при расчёте транспортной доступности нельзя. Подобные отклонения вносят шум в данные и вынуждают создавать сложные алгоритмы обработки.

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

2.5 Данные о стоимости аренды и покупки коммерческой недвижимости


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

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

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

2.6 Данные о пассажиропотоке на станциях метро


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

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

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

2.7 Новые признаки и данные


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

  • Параметры ближайшего ТПУ.
  • Расстояние до ТПУ.
  • Радиус охвата объекта.
  • Входит ли ТПУ в зону охвата?
  • К какому классу относится объект?


Небольшой кусок датасета с бинарными признаками

2.8 Итоговый датасет


В результате объединения мы получили датасет размерностью 44 столбца и 78086 строк. В формате Pandas он занимает около 25,9+ MB. Если разбить столбцы на тематические сегменты, то в нём содержатся данные о:

  • Объекте.
  • Близлежащем ТПУ и его составе.
  • Районе объекта.
  • Стоимости покупки и аренды площадей.

2.9 Корреляционная матрица




Что можно сказать по полученной корреляционной матрице?

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

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

3. Немного визуализаций


3.1 Датасет на карте Москвы


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

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

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


Пример отображения районов по плотности размещения объектов


Транспортная схема Москвы: здесь отображаются только ТПУ


Пример отображения с объектами в данной выборке всего 10000 объектов из более чем 78 000


Пример отображения объектов по выделенному адресу описание сформировано в виде HTML-кода

3.2 (Не)много графиков


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

Вот, например, 20 крупнейших торговых сетей Москвы:



А если посмотреть, какие типы объектов самые популярные?



По типам услуг всё не так интересно, зато понятно, сколько всего объектов каждого типа есть в городе.



Теперь чуть более интересные цифры количество объектов при ТПУ.



Руки чешутся посмотреть на самый верхний ТПУ Профсоюзная. Почему бы и да? На этом скриншоте размещаются больше 2000 объектов, для которых этот ТПУ ближайший.



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



Раз уж мы решили строить топы, почему бы не узнать адрес, по которому располагается большее число объектов? Легко!



Найти его не так уж сложно. Список впечатляет:



И напоследок немного более сложной экономической статистики. Что если поделить все ТПУ на группы от проектируемых до уже сданных в эксплуатацию? Какое стандартное отклонение (сигма), в рублях, за аренду торговых площадей или, скажем, при приобретении отдельно стоящих зданий будет в этих группах?



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

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

4. Заключение


4.1 Варианты применения


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

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

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

4.2 Целевая аудитория


Датасет может быть интересен:

  • Девелоперам,
  • Инвесторам,
  • Бизнесу (торговля и услуги),
  • Риэлторам и консультантам,
  • Частным исследователям и урбанистам.

4.3 Достоинства и недостатки


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

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

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

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

  • Преобразования некоторых данных к бинарному представлению 1/0.
  • Приведения всех отсутствующих данных к единой форме NaN.
  • Создания служебных колонок, описывающих длину вложенных словарей.
  • Разбиения столбцов на логические секции и с детальными именами.
  • Опоры на источники. Все данные могут быть получены путём непосредственного доступа к первоисточнику.
  • Упрощения визуализации. Она организована удобными функциями, которые принимают на вход много служебных параметров и сводят отображение нужных данных к паре строк кода.

4.4 Вместо резюме


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

GitHub и сайт датасета.

Узнать больше про магистратуру можно на сайте data.misis.ru и в Telegram канале.

Участники команды Data SkyScrapers


Артем Филиппенко Тимлид / Программирование / Автор статьи
Юлия Компаниец Программирование / Алгоритмизация / Визуализация
Егор Петров Программирование / Парсинг / Поддержка репозитория
Вячеслав Кандыбин Парсинг / Поиск источников
Ильдар Габитов Координация / Анализ
Сергей Гильдт Помощь в составлении статьи

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



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



Подробнее..

Нужно больше датасетов. Музыка, IT-скилы и котики

11.02.2021 18:04:31 | Автор: admin

Привет, Хабр! Совсем недавно мы писали про открытый датасет, собранный командой студентов магистратуры Наука о данных НИТУ МИСиС и Zavtra.Online (подразделение SkillFactory по работе с университетами) в рамках первого учебного Дататона. А сегодня представим вам целых 3 датасета от команд, которые также вышли в финал.

Все они разные: кто-то исследовал музыкальный рынок, кто-то рынок труда IT-специалистов, а кто-то и вовсе домашних кошек. Каждый из этих проектов актуален в своей сфере и может быть использован для того, чтобы что-то усовершенствовать в привычном ходе работы. Датасет с котиками, например, поможет судьям на выставках. Датасеты, которые необходимо было собрать студентам, должны были представлять собой MVP (таблица, json или структура каталогов), данные должны быть очищены и проанализированы. Посмотрим же, что у них получилось.



Датасет 1: Скользим по музыкальным волнам с Data Surfers


Состав команды:

  • Плотников Кирилл project manager, разработка, документация.
  • Тарасов Дмитрий разработка, сбор данных, документация.
  • Шадрин Ярослав разработка, сбор данных.
  • Мерзликин Артём product manager, презентация.
  • Колесниченко Ксения предварительный анализ данных.

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

Spotify музыкальная платформа, пришедшая в Россию не так давно, но уже активно захватывающая популярность на рынке. Кроме того, с точки зрения анализа данных, Spotify предоставляет очень удобное API с возможностью запроса большого количества данных, в том числе их собственных метрик, например таких, как danceability показатель от 0 до 1, описывающий, насколько трек подходит для танцев.

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

Сбор данных об артистах


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

Описание полей таблицы
artist имя артиста или название группы;
musicbrainz_id уникальный идентификатор артиста в музыкальной базе данных Musicbrainz;
spotify_id уникальный идентификатор артиста в стриминговом сервисе Spotify, если он там представлен;
type тип исполнителя, может принимать значения Person, Group, Other, Orchestra, Choir или Character;
followers количество подписчиков артиста на Spotify;
genres музыкальные жанры артиста;
popularity индекс популярности артиста на Spotify от 0 до 100, который рассчитывается на основе популярности всех треков артиста.


Пример записи

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

  1. Постранично парсить раздел Artists на странице с информацией о России.
  2. Достать данные через API.
    Документация MusicBrainz API
    Документация MusicBrainz API Search
    Пример запроса GET на musicbrainz.org

В ходе работы выяснилось, что API MusicBrainz не совсем корректно отвечает на запрос с параметром Area:Russia, скрывая от нас тех исполнителей, у кого в поле Area указано, например, Izhevsk или Moskva. Поэтому данные с MusicBrainz были взяты парсером непосредственно с сайта. Ниже пример страницы, откуда парсились данные.


Полученные данные об артистах из Musicbrainz.

Остальные поля получаем в результате GET запросов к эндпоинту.При отправке запроса в значении параметра q указываем имя артиста, а в значении параметра type указываем artist.

Сбор данных о популярных треках


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

Описание полей таблицы
artist имя артиста или название группы;
artist_spotify_id уникальный идентификатор артиста в стриминговом сервисе Spotify (по нему можно будет джойнить таблицы, так как это spotify_id из таблицы с артистами);
name название трека;
spotify_id уникальный идентификатор трека в стриминговом сервисе Spotify;
duration_ms длительность трека в миллисекундах;
explicit содержит ли текст трека нецензурные выражения, может принимать значения true или false;
popularity индекс популярности трека на Spotify *;
album_type тип альбома, может принимать значения album, single или compilation;
album_name название альбома;
album_spotify_id уникальный идентификатор альбома в стриминговом сервисе Spotify;
release_date дата выхода альбома;
album_popularity индекс популярности альбома на Spotify.

Особенности аудио
key предполагаемая общая тональность трека, целые числа накладываются на нотацию звуковысотных классов, 0 = C, 1 = C/D, 2 = D и т.д.;
mode указывает модальность трека, мажор 1, минор 0;
time_signature предполагаемый общий тактовый размер композиции;
acousticness мера достоверности от 0,0 до 1,0 того, является ли трек акустическим;
danceability описывает, насколько трек подходит для танцев от 0,0 до 1,0;
energy представляет собой перцептивную меру интенсивности и активности от 0,0 до 1,0;
instrumentalness определяет, содержит ли трек вокал, принимает значения от 0,0 до 1.0;
liveness определяет присутствие аудитории при записи, принимает значения от 0,0 до 1,0;
loudness общая громкость трека в децибелах, типичный диапазон значений от -60 до 0 дБ;
speechiness определяет наличие произнесённых слов в треке, принимает значения от 0,0 до 1,0;
valence описывает музыкальную позитивность, передаваемую треком, принимает значения от 0,0 до 1,0;
tempo предполагаемый общий темп трека в ударах в минуту.

Подробно о каждом параметре можно прочитать здесь.


Пример записи

Поля name, spotify_id, duration_ms, explicit, popularity, album_type, album_name, album_spotify_id, release_date получаем с помощью GET запроса на https://api.spotify.com/v1//v1/artists/{id}/top-tracks , указывая в качестве значения параметра id Spotify ID артиста, который мы получили ранее, а в значении параметра market указываем RU. Документация.

Поле album_popularity можно получить, сделав GET запрос на https://api.spotify.com/v1/albums/{id}, указав album_spotify_id, полученный ранее, в качестве значения для параметра id. Документация.

В результате получаем данные о лучших треках артистов из Spotify. Теперь задача получить особенности аудио. Сделать это можно двумя способами:

  1. Для получения данных об одном треке нужно сделать GET-запрос на https://api.spotify.com/v1/audio-features/{id}, указав его Spotify ID как значение параметра id. Документация.
  2. Чтобы получить данные о нескольких треках сразу, следует отправить GET запрос на https://api.spotify.com/v1/audio-features, передавая Spotify ID этих треков через запятую как значение для параметра ids. Документация.

Все скрипты находятся в репозитории по этой ссылке.

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



Итоги


В результате у нас получилось собрать данные по 14363 артистам и 44473 трекам. Объединив данные из MusicBrainz и Spotify, мы получили наиболее полный на текущий момент набор данных о всех российских музыкальных исполнителях, представленных на платформе Spotify.

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

Датасет 2: Исследуем рынок вакансий и выявляем ключевые навыки с Ежу понятно


Состав команды:

  • Пшеничный Андрей сбор и обработка данных, написание аналитической записки о датасете.
  • Кондратёнок Павел Product Manager, сбор данных и описание его процесса, GitHub.
  • Щербакова Светлана сбор и обработка данных.
  • Евсеева Оксана подготовка итоговой презентации проекта.
  • Елфимова Анна Project Manager.

Для своего датасета мы выбрали идею сбора данных о вакансиях в России из сферы IT и Телеком с сайта hh.ru за октябрь 2020 года.

Сбор данных о скилах


Самым важным показателем для всех категорий пользователей являются ключевые навыки. Однако при их анализе у нас возникли трудности: эйчары при заполнении данных о вакансии выбирают ключевые навыки из списка, а также могут вносить их вручную, а следовательно, в наш датасет попало большое количество дублирующих навыков и некорректных навыков (например, мы столкнулись с названием ключевого навыка 0,4 Кb). Есть ещё одна трудность, которая доставила проблем при анализе получившегося датасета, только около половины вакансий содержат данные о заработной плате, но мы можем использовать средние показатели о заработной плате с другого ресурса (например, с ресурсов Мой круг или Хабр.Карьера).

Начали с получения данных и их глубинного анализа. Далее мы произвели выборку данных, то есть отобрали признаки (features или, иначе, предикторы) и объекты с учетом их релевантности для целей Data Mining, качества и технических ограничений (объема и типа).

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


Наиболее часто встречающиеся ключевые навыки в вакансиях из сферы IT, Телеком

Данные получили с сайта hh.ru с помощью их API. Код для выгрузки данных можно найти тут. Вручную выбрали признаки, которые нам необходимы для датасета. Структуру и тип собираемых данных можно увидеть в описании документации к датасету.

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


Образец собранных данных

Итоги


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

Датасет 3: Наслаждаемся многообразием котиков с Команда AA


Состав команды:

  • Евгений Иванов разработка веб-скрапера.
  • Сергей Гурылёв product manager, описание процесса разработки, GitHub.
  • Юлия Черганова подготовка презентации проекта, анализ данных.
  • Елена Терещенко подготовка данных, анализ данных.
  • Юрий Котеленко project manager, документация, презентация проекта.

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

Сбор данных о котиках


Изначально для сбора данных мы выбрали сайт catfishes.ru, он обладает всеми нужными нам преимуществами: это свободный источник с простой структурой HTML и качественными изображениями. Несмотря на преимущества этого сайта, он имел существенный недостаток малое количество фотографий в целом (около 500 по всем породам) и малое количество изображений каждой породы. Поэтому мы выбрали другой сайт lapkins.ru.




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

Для сбора изображений с сайта нами был написан веб-скрапер. Сайт содержит страницу lapkins.ru/cat со списком всех пород. Сделав парсинг этой страницы, мы получили названия всех пород и ссылки на страницу каждой породы. Итеративно пройдя в цикле по каждой из пород, мы получили все изображения и сложили их в соответствующие папки. Код скрапера был реализован на Python с использованием следующих библиотек:

  • urllib: функции для работы с URL;
  • html: функции для обработки XML и HTML;
  • Shutil: функции высокого уровня для обработки файлов, групп файлов и папок;
  • OS: функции для работы с операционной системой.

Для работы с тегами мы использовали XPath.



Каталог Cats_lapkins содержит папки, названия которых соответствуют названиям пород кошек. Репозиторий содержит 64 каталога для каждой породы. Всего в датасете содержатся 2600 изображений. Все изображения представлены в формате .jpg. Формат названия файлов: например Абиссинская кошка 2.jpg, вначале идёт название породы, затем число порядковый номер образца.



Итоги


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

Послесловие


По итогам дататона наши студенты получили первый кейс в своё портфолио дата-сайентиста и обратную связь по работе от менторов из таких компаний, как Huawei, Лаборатория Касперского, Align Technology, Auriga, Intellivision, Wrike, Мерлин АИ. Дататон был полезен ещё и тем, что прокачал сразу и профильные хард- и софт-скилы, которые понадобятся будущим дата-сайентистам, когда они будут работать уже в реальных командах. Также это хорошая возможность для взаимного обмена знаниями, так как у каждого студента разный бэкграунд и, соответственно, свой взгляд на задачу и её возможное решение. Можно с уверенностью сказать, что без подобных практических работ, похожих на какие-то уже существующие бизнес-задачи, подготовка специалистов в современном мире просто немыслима.

Узнать больше про нашу магистратуру можно на сайте data.misis.ru и в Telegram канале.

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



image



Подробнее..

Starline Hackathon 2020

25.11.2020 14:11:26 | Автор: admin

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

Если вы не знаете что такое ROS советую к изучению ресурсVoltbto.com, вот напримерстатья по работе с сервисами в ROS.

В конце марта 2020 года компания Starline во второй раз в своей истории провелахакатон.

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

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

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

  1. StarlineHackathon

  2. COEXHackathon

  3. РобофестAutonet 18+

  4. UpGreatЗимний город+ очень крутаястатья на vc.ru

  5. Робокросстык-1,тык-2

  6. РобофинистРТК Экстремал Pro (информация естьздесь)

  7. КрокКонкурс летающих роботов[больше не проводит]

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

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

Я@urpylkaс моим другом Артуром@goldarteрешили участвовать вдвоём (в предыдущий раз я занял третье место, а он первое).

Дано

Каждой команде был выделен робот Turtlebot E2 следующего содержания:

  1. Платформа Kobuki

  2. RGBD-камера Orbbec Astra

  3. Rplidar A2

  4. Компьютер Intel NUC [BOXNUC7I7BNH]

  5. Дополнительная камера Logitech HD Pro C920

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

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

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

В городе имелись препятствия (про расположение которых мы не знали заранее):

  1. Светофоры

  2. Знаки Стоп

  3. Блоки Дорожные работы

  4. Другие участники движения в виде статичных моделей машин

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

Задание и решение

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

Мы разделили решение на несколько частей и занялись ими по отдельности:

  1. Стейт машина для управления роботом

  2. Определение дорожной разметки и способ не пересекать сплошную

  3. Машинное зрение для распознавания знаков Стоп и светофоров

  4. Ориентация и перемещение робота по городу с использованием алгоритмов, доступных в ROS

В начале решения задач по техническому зрению, мы изначально понимали какие есть алгоритмы и как они работают. Хорошей кодовой базой и документацией к ней являютсямануалы для TurtleBot3 на robotis.com, плюс в их репозитории с соревнованийautorace:turtlebot3autorace,https://github.com/ROBOTIS-GIT/turtlebot3autorace2020. В этих репозиториях есть хорошие примеры:

State Machine

Идея решения изначально была следующая: Делаем стэйт-машину с двумя состояниями:GOTO_0,GOTO_1. Они являются состояниями следования в точки0и1на карте соотвественно.

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

По завершению (достижению точки) состояния циклично меняются. Так достигается то, что робот ездит кругами.

В состоянияхGOTO_0,GOTO_1стэйт-машины проверяется, не был ли замечен красный свет светофора или знак Стоп. Если таковые были замечены, делаем остановку до окончания красного света или на одну секунду в случае знака.

Также впоследствии были добавлены состоянияINITиIDLE. ВINITмы включаем платформу, инициализируем объекты вспомогательных классов и переходим в состояниеIDLE. Также перейти в состояниеIDLEможно изGOTO_0иGOTO_1. В качестве фреймворка для state-machine было реализованособстсвенное решение, построенное на базестэйт-машины Karn Saheb. В реализацию классаStateMachineдобавлено полеSтипа пустого классаObjectStorage. Это позволяет организовать удобную работу с одними данными из разных состояний черезsetattr(Class, Attr, Value)и через его сокращенный вариантClass.Attr = Value.

Детекция разметки

В начале думали использовать, что вродеlane-detection:

  1. github/awesome-lane-detection

  2. github поиск lane-detection

  3. hackster.io curved-lane-detection

Также завели конфигурированиеbirdviewс помощьюdynamic_reconfigure.

Затем посмотрели в сторону использования нейронных сетей для детектирования попутной полосы цветомcolor-segmentation. Нам понравилось решениеdheera/ros-semantic-segmentation. По размеченной цветом картинке можно высчитать координаты области и передавать эти данные в локальный планировщик.

На тему семантической сегментации изображений естьстатьяна хабре.

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

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

Затем нам нужно было как-то правильно выбирать полосу и не ехать по встречке. Мы решили динамически наносить на глобальную карту препятствия, таким образом, что если робот въезжает в радиусR1центра некоторого перекрестка, то во всех запрещенных встречных направлениях перекрестка строятся препятствия, до тех пор пока робот не отдалится от центра данного перекрестка на радиусR2.

Распознание объектов

В рамках ограниченного времени хакатона, было решено заранее поискать готовые инструменты для выделения нужных объектов на изображении. Одним из инструментов оказался ROS пакетfind_object_2d: он позволяет на лету сконфигурировать детектор фич и дескриптор для классификации объектов по заранее имеющимся картинкам, а также предоставляет список определённых объектов и их координат с матрицами гомографии в топик/objectsиobjectsStamped. Помимо выделения объектов нужно было, например, правильно распознать цвет светофора, поэтому помимо готовых решений пришлось применять решения из библиотекиopencv. Итоговым решением задачи по определению знака стоп и цвета светофора стала нодаdetect_objects_node.py. Кстати вотнеплохой кодиз проекта по управлению машинойCarND-Capstoneв котором мы черпнули много полезного.

Распознавание знака стоп

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

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

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

Для настройки некоторых параметров детектора был применён механизм динамической конфигурации параметровdynamic_reconfigure, который позволяет на лету (что особенно актуально в условиях ограниченного времени) подобрать нужные параметры через инструментrqt. Например вот так мы настраивали распознание красного света светофора:

Распознавание светофора и его цвета

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

Рабочий алгоритм по выделению цвета светофора выглядел следующим образом: вначале на изображении выделяются области определённой насыщенности в цветовом пространстве HSV, затем среди этих областей производится поиск областей, наиболее похожих на круг (методом Hough Circles) с определёнными границами по размеру. Если такие области есть - мы определили, что находимся у светофора с определённым цветом.

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

Особенным моментом стало то, что мы не могли использовать видимое изображение с камеры Astra в виду очень узкого угла обзора. А также не особо подходила камераLogitech HD Pro C920также из-за достаточно узкого угла обзора установленная камера внутри робота не позволяет увидеть знак с другого края дороги нужна более широкоугольная камера. Мы же более-менее решили эту проблему с выносом камеры за пределы робота.

Navigation Stack

Приведу схему ROS Navigation Stack (информация взята изпрезентации PhD PaulEdouard Sarlin) для общего понимания процессов.

  • Map prior: что заранее известно о окружающей среде

  • Kinect: камера глубины, возвращающая облако точек

  • Odometry: позиция робота в лабиринте

  • Map updater: обрабатывает данные для создания и обновления внутренней карты окружающей среды

  • Global planner: вычисляет маршрут от начальной точки в цель, используюя карту

  • Local planner: выполняет и корректирует с учетом обстановки процесс перемещения робота по построенному маршруту

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

Полезным к изучению будетмануалпо настройке Navigation Stack на роботе. И туда же очень хорошаястатьяпо настройке ROS Navigation Stack.

Также вышелновый пакетrobot_navigation, как замена старому.

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

Вместо стандартного локального планировщика мы решили использоватьteb_local_planner (github), который написали ребята изTU Dortmund University. Несколько ссылочек c примерами:

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

В планировщиках обычно используются простые по назначению слои:

  • obstacle_layer динамические препятствия (примернастройки Obstacle inflation in costmap2d)

  • inflation_layer утолщение препятствий

  • static_layer статичная карта

Каждый слой должен быть определнного типа:

  • costmap_2d::StaticLayer препятствия, построенные на базе заданной статической карты

  • costmap_2d::ObstacleLayer препятствия добавляемые с помощью топика типаLaserScanилиPointCloud

  • costmap_2d::InflationLayer добавляет вcostmapлинию некоторого радиуса и определнной плотности вокруг препятствий

  • costmap_2d::VoxelLayer добавление 3D объектов

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

Подробнее проcostmap_2dвы можете прочитать в официальной документацииздесь. Там вы можете найти примеры конфигураций (1,2,3), описание простых типов (staticmap,obstacles), описаниеflatиlayered.

Также я нашел решениеSr4l/virtualobstacles, которое представляло из себя Costmap Plugin для добавления слоев типаcostmap_2d::MovingObjects. У проекта была не очень хорошая документация, поэтому я написалLars Kistnerи он дополнил репу и прислал еще дополнительные инструкции и интересноевидео, где он это использует. Однако я не успел завести это решение и решил использовать что-то более топорное. В дальнейшем наверное правильнее будет использовать его решение.

Для построения препятствий на карте я написалреализациюрисования линий с помощью простейшегоалгоритма Брезенхэма.

Для динамического слияния (наложения) карт я написалMaps Merger.

Итого у нас получилось пять карт:

  1. /maps/map_amcl чистая карта, полученная с помощью алгоритмаgmapping(подробнее о построении картыздесь)

  2. /maps/map_mb/maps/map_amcl+ нарисованные сплошные линии (передавалась в глобальный планировщик)

  3. /maps/crossroads карта с динамически наносимыми на неё перекрестками

  4. /maps/start_wall карта с динамически наносимыми на неё стенками у точки старта

  5. /maps/map_merged- карта динамически строящаяся из/maps/map_mb,/maps/crossroads,/maps/start_wall(передавалась в локальный планировщик)

Статические карты поднимаются с помощью стандартнойутилитыmap_serverвходящей в стекnavigation.

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

rostopic pub /move_base_simple/goal geometry_msgs/PoseStamped '{header: {stamp: now, frame_id: "map"}, pose: {position: {x: 0.674, y: 0.119, z: 0.0}, orientation: {w: 1.0}}}'# PS Координаты и фреймы должны быть ваши (выбраны исходя из используемых карт)

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

Другие интересные источники по теме

Определение препятствий

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

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

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

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

Итог

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

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

У нас же была очень круто проведененная неделя в Питере в компании специалистов и друзей. Мы очень благодарны компанииStarline, в частности: Алексею Хованскому, Николаю Дема, Александру Никифорову, Кириллу Гореву, Веденину Даниилу и Маркеловой Виктории.

Бонусом укажу пару-тройку ссылочек на ресурсы ребят и компанию ораганизавторов:

  • developer.starline.ru открытое API некоторых продуктов Starline.

  • Портал РобоФинист, кстати его основным разработчик является всего один человек Кирилл Горев. А еще на этомпорталевы можете найти больше фоточек с этого замечательного мероприятия.

  • YouTube канал Николая Дема. Коля крутой робототехник и на его ютубчике периодически появляются интересные видосы.

На этом всё, спасибо большое за прочтение!

Подробнее..

Категории

Последние комментарии

  • Имя: Макс
    24.08.2022 | 11:28
    Я разраб в IT компании, работаю на арбитражную команду. Мы работаем с приламы и сайтами, при работе замечаются постоянные баны и лаги. Пацаны посоветовали сервис по анализу исходного кода,https://app Подробнее..
  • Имя: 9055410337
    20.08.2022 | 17:41
    поможем пишите в телеграм Подробнее..
  • Имя: sabbat
    17.08.2022 | 20:42
    Охренеть.. это просто шикарная статья, феноменально круто. Большое спасибо за разбор! Надеюсь как-нибудь с тобой связаться для обсуждений чего-либо) Подробнее..
  • Имя: Мария
    09.08.2022 | 14:44
    Добрый день. Если обладаете такой информацией, то подскажите, пожалуйста, где можно найти много-много материала по Yggdrasil и его уязвимостях для написания диплома? Благодарю. Подробнее..
© 2006-2024, personeltest.ru