5 полезных и just for fun DIY-проектов на базе Raspberry Pi лета 2022 года

Привет, Хабр! Проектов на базе Raspberry Pi столько, что при всем желании подсчитать их не получится. Тут и профессиональные, и для дома, и для развлечений и just for fun. Сегодня поговорим о нескольких интересных DIY-проектах лета этого года. Если вы пока еще не приобрели «малинку» — самое время это сделать и попробовать повторить какой-то из указанных в подборке. Ну или сделать что-то свое, а потом рассказать об этом на Хабре. Ну а пока — поехали!

Дверной замок с распознаванием лица

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

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

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

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

«Малинка» работает с добавлением Servo PWM Pi HAT, плюс установлена, конечно, камера, магнитный замок, светодиод и MCP3008 Analog to Digital Converter (ADC). Для размещение дополнительных компонентов автор проекта разработал кастомную материнскую плату, которую затем заказал в Китае. Корпус для всего этого дела распечатан на 3D-принтере.

Если нужны подробности, то вот страничка проекта.

Цифровой ассистент на базе «малинки» и Sony TV-511 из 70-х

Большой плюс современных электронных устройств в том, что их можно использовать для разработки новых проектов на базе старых устройств. Иногда и очень старых, как в случае проекта, о котором идет речь. Это цифровой ассистент, который делает примерно то же, что Google Nest, но только вместо современного экрана используется винтажный телевизор Sony TV-511 из 70-х. Его автор проекта приобрел на eBay и нашел вот такое применение. Круто, правда?

Ассистент показывает погоду, слушает и выполняет голосовые команды, а также проигрывает видео с YouTube по запросу пользователя. Программная основа ассистента — проект Jarvis на базе Python.

Видео показывается благодаря переходнику HDMI to UHF. Адаптер подключается к ТВ через антенный вход. На данный момент проект еще дорабатывается, но основные функции работают. Вот тред, созданный автором на Reddit.

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

Печатаем консольные команды на термобумаге для чеков

Небольшой just for fun проект на базе Raspberry Pi Zero 2 W. Когда пользователь вводит команды в консоли, то модуль, о котором идет речь, распечатывает все это на термобумаге. Используется обычная бумага для чеков, ничего дефицитного.

Автор явно из СНГ, поскольку его имя Arseny, а ник — kotofey_magnus на Reddit. Он рассказал, что это его первый проект на базе «малинки». Все начиналось, как шутка, а закончилось — как полезный проект для ряда пользователей.

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

Эмуляция 6502 процессора и запуск Loderunner

«Малинка» может эмулировать самые разные устройства и отдельные элементы. Например, процессор 6502. Это восьмиразрядный микропроцессор, разработанный компанией MOS Technology в 1975 году. Разработчик использовал для теста игру Loderunner из 1983 года. Запустилась она без всяких проблем.

К «малинке», которая эмулирует винтажный ПК, можно подключать не менее винтажные аксессуары, включая джойстик от Atari или обычную PS2 клавиатуру. Вывод видео осуществляется через VGA-порт.

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

Ромбоикосододекаэдр из дерева с Raspberry Pi с двумя дисплеями


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

Mw33212 объясняет, что корпус создан из грецкого ореха, клена и индийского палисандра толщиной 10 мм. Форма известна как J83, одно из «тел Джонсона», которое по существу представляет собой серию выпуклых многогранников и описывается как трехуменьшенный ромбоикосододекаэдр. Как бы вы ни назвали эту форму, выглядит это все очень круто, скрывая элементы конструкции внутри.

В этом случае Mw33212 использует Raspberry Pi 4 для эмуляции Nintendo 64. Вы можете легко заменить Pi 4 на что-то вроде 3B+ или даже Zero, в зависимости от того, что есть под рукой. В дополнение к Pi девайс также оснащен четырьмя динамиками для вывода звука, несколькими управляющими платами для экранов, парой вентиляторов для охлаждения и, конечно, 3,4-дюймовыми круглыми ЖК-панелями с разрешением 800 x 800 пикселей.

Что касается программного эмулятора, то используется привычные уже многим RetroPie или Lakka.

Ну а на сегодня все, не переключайтесь!


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

Необычные проекты интернета вещей. Пёс-охранник на Raspberry Pi и умная видеоняня

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

Пёс-охранник на Raspberry Pi

К сожалению, не все животные боятся видеокамер. Здесь на помощь приходит «виртуальная собака» с колонками.

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

Пара колонок подключена Raspberry Pi. Одна колонка направлена на входную дверь, а вторая — на заднюю, откуда тоже может исходить угроза. Громкость лая динамически изменяется между динамиками, словно собака бегает по дому от одной двери ко второй и заливается лаем.

Автор изобретения Таннер Коллин (Tanner Collin) установил в доме такую «собаку» перед отъездом в отпуск. Вот одна из колонок:

Технически виртуальная собака работает следующим образом:

  1. Камеры наблюдения транслируют RTSP-поток в программу Blue Iris NVR, которая крутится на отдельной коробочке под Windows.
  2. Когда Blue Iris обнаруживает объект в определённой области, то отправляет MQTT-сообщение в канал iot/cameras брокера Mosquitto, запущенного на медиасервере.
  3. На Raspberry Pi работает скрипт, который прослушивает iot/cameras с помощью модуля asyncio-mqtt. Он получает JSON-сообщение вида {"serial": "SE-N-ZoneB"} и декодирует его. Если название камеры соответствует указанному в скрипте, то запускается на воспроизведение соответствующий аудиофайл с помощью Pygame.

Код скрипта:

import os, sys import logging logging.basicConfig(stream=sys.stdout, format='[%(asctime)s] %(levelname)s %(module)s/%(funcName)s - %(message)s', level=logging.DEBUG if os.environ.get('DEBUG') else logging.INFO)  import time import json  import asyncio from asyncio_mqtt import Client import pygame  import secrets  COOLDOWN = time.time()  CAMERAS = { 'NE-W-ZoneB': { 'name': 'Front Door', 'sound': 'barkLR.ogg', }, 'SE-N-ZoneB': { 'name': 'Side Door', 'sound': 'barkRL.ogg', }, 'B-E-ZoneB': { 'name': 'Back Door', 'sound': 'barkLR.ogg', }, }  async def play_sound(filename): pygame.mixer.music.load(filename) pygame.mixer.music.play()  logging.info('Playing sound %s', filename)  while pygame.mixer.music.get_busy(): #pygame.time.Clock().tick(10) await asyncio.sleep(0.1)   async def barkbark(sound): global COOLDOWN if time.time() - COOLDOWN < 15.0: logging.info('Cooldown skipping.') return COOLDOWN = time.time()  await asyncio.sleep(0.1)  await play_sound(sound)  logging.info('Done barking.')  async def process_mqtt(message): text = message.payload.decode() topic = message.topic logging.info('MQTT topic: %s, message: %s', topic, text)  if not topic.startswith('iot/cameras'): logging.info('Invalid topic, returning') return  try: data = json.loads(text) except json.JSONDecodeError: logging.info('Invalid json, returning') return  serial = str(data.get('serial', ''))  if serial not in CAMERAS: logging.info('Invalid serial, returning') return  camera = CAMERAS[serial]  logging.info('Barking %s...', camera['name'])  await barkbark(camera['sound'])   async def fetch_mqtt(): await asyncio.sleep(3) async with Client('192.168.0.100') as client: async with client.filtered_messages('iot/cameras') as messages: await client.subscribe('#') async for message in messages: loop = asyncio.get_event_loop() loop.create_task(process_mqtt(message))   if __name__ == '__main__': logging.info('') logging.info('==========================') logging.info('Booting up...')  pygame.init() pygame.mixer.pre_init(buffer=4096) pygame.mixer.init(buffer=4096)  loop = asyncio.get_event_loop() loop.run_until_complete(fetch_mqtt())

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

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

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

В любом случае, дополнительная безопасность никогда не помешает.

Умная радионяня

Ещё один интересный проект интернета вещей — умная радионяня The Hungry Baby Alarm с системой искусственного интеллекта. Программа машинного зрения интерпретирует движения младенца в коляске, оценивая степень его голода (и приближение плача).

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

По видеозаписи можно понять, как работает система. К сожалению, разработчик Калеб Олсон (Caleb Olson) не выложил код, а только показал его фрагменты и упомянул некоторые модули, которые использует для распознавания движений в реальном времени (как MediaPipe Face Mesh).

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



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

Методы использования роя БПЛА для размещения базовых станций 5G

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

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

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

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

  4. Проблема обеспечения сверхвысокой надежности. Помимо описанных выше задач при разработке и внедрении технологий 5G необходимо не забывать и об обеспечении надежности сети. Считается, что для некоторых сервисов, например, при управлении через сеть роботами или для работы беспилотного транспорта, требуется надежность/доступность сети «шесть девяток», то есть отправленный пакет данных должен дойти до адресата с вероятностью 99,9999% .

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

В рамках работы над 5G, этот вопрос решается добавлением технологий связи для крайне высоких частот (длина волны 1-10 мм, частоты 30-300 ГГц). Этот частотный диапазон не использовался активно в радиосвязи по причине высокого затухания в атмосфере, однако имеет ряд преимуществ:

  1. обилие незанятых частот, что дает возможность передавать данные со скоростью от 10 Гбит/с, причем в обе стороны (в соответствии с теоремой Шеннона-Хартли полоса пропускания радиоканала прямо пропорциональна доступной этому каналу полосе частот в Гц)

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

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

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

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

Одним из способов решения проблемы плотного расположения базовых станций 5G является размещение их на беспилотных летательных аппаратах (БПЛА).

Как будет организована непрерывная работа БПЛА?

Работа БПЛА в рассматриваемых сценариях будет координироваться через пункт управления, уникальный для конкретной зоны действия. Таким образом, будет единое место, где БПЛА могут храниться в качестве резервных копий и где они могут обслуживаться и подзаряжать аккумуляторы. Заметим, что хранение резервных копий вблизи гарантирует непрерывность обслуживания в случае ЧС, а способность БС обрабатывать передачи обслуживания позволит выполнять «горячую» замену дронов, когда они нуждаются в обслуживании.

Выбор частот для передачи данных

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

Сценарии применения дронов

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

Итак, рассмотрим сценарии использования дронов для размещения БС.

1) С одной стороны, они могут быть развернуты как летающие БС для обеспечения доступа по воздуху к наземному пользовательскому оборудованию. Здесь мы используем в зависимости от направления передачи двунаправленные каналы миллиметроволнового диапазона, состоящие из линий связи A2G и G2A, и передачу на основе неортогонального множественного доступа. Здесь возможны два варианта:

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

— в другом варианте используется метод множественного доступа с пространственным разделением SDMA, что актуально в миллиметровом диапазоне частот. Летающая БС оснащена адаптивной антенной и каждый наземный пользователь оснащен антенной. Каждый сформированный узкий миллиметровый луч A2G от летающей БС соответствует только одной группе пользователей, а количество лучей равно количеству приемопередатчиков летающей БС. Преимущество: отличные показатели с точки зрения достижимой скорости передачи данных по восходящей линии связи и многопользовательской емкости.

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

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

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

3) Сценарий с использованием VR. В этом сценарии БПЛА сначала собирают содержимое VR в видимом формате и формате 360*, которое запрашивают пользователи VR, а затем отправляют собранное содержимое в БС с поддержкой кэширования через беспроводные каналы линий связи A2G. Между тем, БС могут напрямую передавать кэшируемое содержимое пользователям. Здесь используется концепция машинного обучения ELSM. Преимущества: надежность и возможность записывать большое количество информации.

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

  • потери мощности сигнала, когда БПЛА проходит между двумя антеннами в свободном пространстве

  • атмосферное затухание в миллиметровом диапазоне, которое вызывают атмосферные газы и дождь

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

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

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

Существует ещё ряд нерешённых проблем маршрутизации между БПЛА и проблем управления роем БПЛА для решения конкретных задач.

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

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


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

#1 Нейронные сети для начинающих. Решение задачи классификации Ирисов Фишера


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

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

О чём будем говорить:

  • Нейронные сети. Что это такое и какие они бывают?
  • Виды нейронных сетей и конструкция нейронных сетей.
  • Где они применяются?
  • Перцептрон.
  • Классификация. Что это такое и почему это важно?
  • Функции активации (ФА).
  • Зачем они нужны?
  • Виды ФА.
  • Как обучить нейронную сеть?
  • Цели и задачи обучения.
  • Обучение с учителем и без.
  • Понятие ошибки.
  • Задача минимизации ошибки.
  • Градиентный спуск.
  • Как вычислить градиент?
  • Пресловутые «Ирисы Фишера».
  • Постановка задачи.
  • Softmax()+ Relu()
  • Ура! Пишем код (Наконец-то).

Что такое нейронные сети?

image

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

image

▍ Виды нейронных сетей:

image

Есть десятки видов нейросетей, которые отличаются архитектурой, особенностями функционирования и сферами применения. При этом чаще других встречаются сети трёх видов.
Нейронные сети прямого распространения (Feed forward neural networks, FFNN). Прямолинейный вид нейросетей, при котором соседние узлы слоя не связаны, а передача информации осуществляется напрямую от входного слоя к выходному. FFNN имеют малую функциональность, поэтому часто используются в комбинации с сетями других видов.

Свёрточные нейронные сети (Convolutional neural network, CNN). Состоят из слоёв пяти типов:

  • входного,
  • свёртывающего,
  • объединяющего,
  • подключённого,
  • выходного.

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

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

Рекуррентные нейронные сети (Recurrent neural network, RNN). Используют направленную последовательность связи между узлами. В RNN результат вычислений на каждом этапе используется в качестве исходных данных для следующего. Благодаря этому, рекуррентные нейронные сети могут обрабатывать серии событий во времени или последовательности для получения результата вычислений.

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

▍ Типы задач, которые решают нейронные сети

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

  • Классификация. Для распознавания лиц, эмоций, типов объектов: например, квадратов, кругов, треугольников. Также для распознавания образов, то есть выбора конкретного объекта из предложенного множества: например, выбор квадрата среди треугольников.
  • Регрессия. Для определения возраста по фотографии, составления прогноза биржевых курсов, оценки стоимости имущества и других задач, требующих получения в результате обработки конкретного числа.
  • Прогнозирования временных рядов. Для составления долгосрочных прогнозов на основе динамического временного ряда значений. Например, нейросети применяются для предсказания цен, физических явлений, объёма потребления и других показателей. По сути, даже работу автопилота Tesla можно отнести к процессу прогнозирования временных рядов.
  • Кластеризация. Для изучения и сортировки большого объёма неразмеченных данных в условиях, когда неизвестно количество классов на выходе, то есть для объединения данных по признакам. Например, кластеризация применяется для выявления классов картинок и сегментации клиентов.
  • Генерация. Для автоматизированного создания контента или его трансформации. Генерация с помощью нейросетей применяется для создания уникальных текстов, аудиофайлов, видео, раскрашивания чёрно-белых фильмов и даже изменения окружающей среды на фото.

Как выглядит простая нейронная сеть?

image

image

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

  • Экономика и бизнес.
  • Медицина и здравоохранение.
  • Авионика.
  • Связь.
  • Интернет.
  • Автоматизация производства.
  • Политологические и социологические исследования.
  • Безопасность, охранные системы.
  • Ввод и обработка информации.
  • Геологоразведка.
  • Компьютерные и настольные игры.
  • И т.д.

Теперь разберём подробнее самую простую модель искусственного нейрона — перцептрон:

Согласно общему определению перцептро́н или персептрон — математическая или компьютерная модель восприятия информации мозгом, предложенная Фрэнком Розенблаттом в 1958 году и впервые реализованная в виде электронной машины «Марк-1» в 1960 году. Перцептрон стал одной из первых моделей нейросетей, а «Марк-1» — первым в мире нейрокомпьютером.

Вы уже могли видеть подобные иллюстрации на просторах интернета:

image

Но что же это всё означает?

Давайте по порядку:

Х1, Х2, Х3, …, Хn — входные классы, данные, которые мы подаём на вход нашей сети. Т.е. здесь у нас идут те данные, которые пришли к нам от клиента или же от нашего сервиса, который каким-то образом собирает/парсит данные , далее эти данные умножаются на случайные веса (стандартное обозначение W1, …, Wn) и суммируются с так называемым нейроном смещения или bias нейрон в «Сумматоре» (из названия следует, что данные, Хn * Wn , суммируются друг с другом). Далее результат Σ(Хn * Wn * b) подаётся в функцию активации, о которой поговорим далее.

Данные метаморфозы проиллюстрированы на следующем слайде:

image

▍ Задача классификации

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

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

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

image

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

image

Но а что на это скажет компьютер?

Для него это лишь набор пикселей/байтов, который ему ни о чём не говорит. По-простому — это 0 и 1. Подробнее про это, можете почитать здесь.

Для того, чтобы компьютер понял, что происходит внутри предложенных ему данных, мы должны «объяснить» ему всё и дать какой-то алгоритм, т.е. написать программу.

▍ Функции активации — ФА

Но это будет не просто программа, помимо базового кода, нам необходимо ввести так называемую математическую модель или же функцию активации, что же это такое?
Функция активации определяет выходное значение нейрона в зависимости от результата взвешенной суммы входов и порогового значения. Пример: 𝒚=𝒇(𝒕).

Давайте рассмотрим некоторые распространённые ФА:

image

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

Функция А = активирована, если Y > граница, иначе нет.

Другой способ: A = 1, если Y > граница, иначе А = 0.

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

Функция принимает значение 1 (активирована), когда Y > 0 (граница), и значение 0 (не активирована) в противном случае.

image

Пользуясь определением, становится понятно, что ReLu возвращает значение х, если х положительно, и 0 в противном случае.

ReLu нелинейна по своей природе, а комбинация ReLu также нелинейна! (На самом деле, такая функция является хорошим аппроксиматором, так как любая функция может быть аппроксимирована комбинацией ReLu). Это означает, что мы можем стэкать слои. Область допустимых значений ReLu — [ 0,inf ].

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

image

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

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

Сигмоида действительно выглядит подходящей функцией для задач классификации. Она стремится привести значения к одной из сторон кривой (например, к верхнему при х=2 и нижнему при х=-2). Такое поведение позволяет находить чёткие границы при предсказании.
Другое преимущество сигмоиды над линейной функцией заключается в следующем. В первом случае имеем фиксированный диапазон значений функции — [0,1], тогда как линейная функция изменяется в пределах (-inf, inf). Такое свойство сигмоиды очень полезно, так как не приводит к ошибкам в случае больших значений активации.

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

Как же обучить нейронную сеть?

Теперь перейдём к другим немаловажным терминам.
Что нам понадобится:

  1. Данные для обучения
  2. Функция потерь
  3. Понятие «градиентного спуска»

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

Ошибка нейронной сети — отличие между предсказанным значением и правильным.

Ошибка нейронной сети — отличие между предсказанным значением и правильным.

Самая простая функция потерь — Евклидово Расстояние или функция MSE:

$ 𝑬=𝟏/𝑵 ∑(𝒚_𝒊−𝒛_𝒊 ) $


yi – правильный результат.
zi – предсказанный результат.

Задача минимизации ошибки:

Используем метод оптимизации:

$𝑾^∗=𝒂𝒓𝒈𝒎𝒊𝒏( 𝑬(𝑾) )$


𝒂𝒓𝒈𝒎𝒊𝒏(𝒕) — функция, возвращающая элемент вектора, где достигается минимум.
𝒂𝒓𝒈𝒎𝒂𝒙(𝒕) — функция, возвращающая элемент вектора, где достигается максимум.

Градиентный спуск — метод нахождения локального минимума или максимума функции при помощи движения вдоль градиента.

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

$𝒅𝑬/𝒅𝑾={ 𝒅𝑬/(𝒅𝑾_𝟏 ),𝒅𝑬/(𝒅𝑾_𝟐 ),𝒅𝑬/(𝒅𝑾_𝟑 ),…,𝒅𝑬/(𝒅𝑾_𝒏 ) }$

Пресловутые «Ирисы Фишера»

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

Здесь хотелось бы сделать небольшое отступление и рассказать подробнее про саму задачу «Ирисов Фишера» зачем и почему она здесь.

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

image

Вот так распределяются данные в датасете:

image

Ирисы Фишера состоят из данных о 150 экземплярах ириса, по 50 экземпляров из трёх видов:

  • Ирис щетинистый (Iris setosa).
  • Ирис виргинский (Iris virginica).
  • Ирис разноцветный (Iris versicolor).

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

  • Длина чашелистника (sepal length).
  • Ширина чашелистника (sepal width).
  • Длина лепестка (petal length).
  • Ширина лепестка (petal width).

image

Конструкция нейронной сети:

На входе у нас есть 4 класса(характеристики) — Х, также нам понадобится всего один внутренний слой — Н, в нём будет 10 нейронов (выбирается методом подбора), далее на выходе мы имеем 3 класса, которые зависят от характеристики цветов — Z. Получается вот такая конструкция сети:

image

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

image

Ура-а-а-а! Наконец-то код!

Нам потребуется:

  • Язык программирования Python.
  • Базовая библиотека языка Python, для работы с линейными данными, NumPy.
  • Базовая библиотека языка Python, для «рандомизации» значений, random.

Для начала нам необходимо импортировать библиотеки numpy и random:

import numpy as np import random as rd

Теперь пропишем некоторые гиперпараметры:

INPUT_DIM = 4    #кол-во входных нейронов OUT_PUT = 3    #кол-во выходных нейронов H_DIM = 10     #кол-во нейронов в скрытом слое 

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

x = np.random.randn(INPUT_DIM) w1 = np.random.randn(INPUT_DIM, H_DIM) b1 = np.random.randn(H_DIM) w2 = np.random.randn(H_DIM, OUT_DIM) b2 = np.random.randn(OUT_DIM) 

Расписываем вложенный слой — наше математическое обоснование:

t1 = x @ w1 + b1 h1 = relu(t1)

Точно также сделаем и для остальных.

Теперь обернём наш код в функцию:

def predict(x):     t1 = x @ W1 + b1     h1 = relu(t1)     t2 = h1 @ W2 + b2     z = softmax(t2)     print('z =', z)     return z 

Оформим функцию relu():

def relu(t):     print('relu:', np.maximum(t, 0))     return np.maximum(t, 0) 

Теперь добавим softmax():

def softmax(t):     out = np.exp(t)     print('softmax:', out / np.sum(out))     return out / np.sum(out) 

Добавим вызов функции predict(), также class_names — имена выходных классов и вывод результатов предсказания:

probs = predict(x) pred_class = np.argmax(probs) class_names = ['Setosa', 'Versicolor', 'Virginica'] print('Predicted:', class_names[pred_class]) 

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

import numpy as np import random as rd  INPUT_DIM = 4 OUT_DIM = 3 H_DIM = 10  x = [] for i in range(4):     x.append(float(input())) print(x)  # Рандомно вводим значения гиперпараметров: x = np.random.randn(INPUT_DIM) w1 = np.random.randn(INPUT_DIM, H_DIM) b1 = np.random.randn(H_DIM) w2 = np.random.randn(H_DIM, OUT_DIM) b2 = np.random.randn(OUT_DIM)  def relu(t):     print('relu:1', np.maximum(t, 0))     return np.maximum(t, 0)  def softmax(t):     out = np.exp(t)     print('softmax:', out / np.sum(out))     return out / np.sum(out)  def predict(x):     t1 = x @ w1 + b1     h1 = relu(t1)     t2 = h1 @ w2 + b2     z = softmax(t2)     print('z =1', z)     return z  tl = x @ w1 + b1 hl = relu(tl)  probs = predict(x) pred_class = np.argmax(probs) class_names = ['Setosa', 'Versicolor', 'Virginica'] print('Predicted:', class_names[pred_class])

Вот теперь добавим полученные после обучения веса и входные данные:

w1 = np.array([[ 0.33462099,  0.10068401,  0.20557238, -0.19043767,  0.40249301, -0.00925352,  0.00628916,  0.74784975,  0.25069956, -0.09290041 ], [ 0.41689589,  0.93211640, -0.32300143, -0.13845456,  0.58598293, -0.29140373, -0.28473491,  0.48021000, -0.32318306, -0.34146461 ], [-0.21927019, -0.76135162, -0.11721704,  0.92123373,  0.19501658,  0.00904006,  1.03040632, -0.66867859, -0.01571104, -0.08372566 ], [-0.67791724,  0.07044558, -0.40981071,  0.62098450, -0.33009159, -0.47352435,  0.09687051, -0.68724299,  0.43823402, -0.26574543 ]]) b1 = np.array([-0.34133575, -0.24401602, -0.06262318, -0.30410971, -0.37097632,  0.02670964, -0.51851308,  0.54665141,  0.20777536, -0.29905165 ]) w2 = np.array([[ 0.41186367,  0.15406952, -0.47391773 ], [ 0.79701137, -0.64672799, -0.06339983 ], [-0.20137522, -0.07088810,  0.00212071 ], [-0.58743081, -0.17363843,  0.93769169 ], [ 0.33262125,  0.18999841, -0.14977653 ], [ 0.04450406,  0.26168097,  0.10104333 ], [-0.74384144,  0.33092591,  0.65464737 ], [ 0.45764631,  0.48877246, -1.16928700 ], [-0.16020630, -0.12369116,  0.14171301 ], [ 0.26099978,  0.12834471,  0.20866959 ]]) b2 = np.array([-0.16286677,  0.06680119, -0.03563594 ]) 

Опять же для любителей всего кода в одном месте:

import numpy as np import random as rd  INPUT_DIM = 4 OUT_DIM = 3 H_DIM = 10  x = []  # Входные тестовые данные вводятся в следующем формате: "7.9 3.1 7.5 1.8" # Длина чашелистника: 7.9 # Ширина чашелистника: 3.1 # Длина лепестка: 7.5 # Ширина лепестка: 1.8  for i in range(4):     x.append(float(input())) print(x)  w1 = np.array([[ 0.33462099,  0.10068401,  0.20557238, -0.19043767,  0.40249301, -0.00925352,  0.00628916,  0.74784975,  0.25069956, -0.09290041 ], [ 0.41689589,  0.93211640, -0.32300143, -0.13845456,  0.58598293, -0.29140373, -0.28473491,  0.48021000, -0.32318306, -0.34146461 ], [-0.21927019, -0.76135162, -0.11721704,  0.92123373,  0.19501658,  0.00904006,  1.03040632, -0.66867859, -0.01571104, -0.08372566 ], [-0.67791724,  0.07044558, -0.40981071,  0.62098450, -0.33009159, -0.47352435,  0.09687051, -0.68724299,  0.43823402, -0.26574543 ]]) b1 = np.array([-0.34133575, -0.24401602, -0.06262318, -0.30410971, -0.37097632,  0.02670964, -0.51851308,  0.54665141,  0.20777536, -0.29905165 ]) w2 = np.array([[ 0.41186367,  0.15406952, -0.47391773 ], [ 0.79701137, -0.64672799, -0.06339983 ], [-0.20137522, -0.07088810,  0.00212071 ], [-0.58743081, -0.17363843,  0.93769169 ], [ 0.33262125,  0.18999841, -0.14977653 ], [ 0.04450406,  0.26168097,  0.10104333 ], [-0.74384144,  0.33092591,  0.65464737 ], [ 0.45764631,  0.48877246, -1.16928700 ], [-0.16020630, -0.12369116,  0.14171301 ], [ 0.26099978,  0.12834471,  0.20866959 ]]) b2 = np.array([-0.16286677,  0.06680119, -0.03563594 ])  # x = np.random.randn(INPUT_DIM) # w1 = np.random.randn(INPUT_DIM, H_DIM) # b1 = np.random.randn(H_DIM) # w2 = np.random.randn(H_DIM, OUT_DIM) # b2 = np.random.randn(OUT_DIM)  def relu(t):     print('relu:1', np.maximum(t, 0))     return np.maximum(t, 0)  def softmax(t):     out = np.exp(t)     print('softmax:', out / np.sum(out))     return out / np.sum(out)  def predict(x):     t1 = x @ w1 + b1     h1 = relu(t1)     t2 = h1 @ w2 + b2     z = softmax(t2)     print('z =1', z)     return z  tl = x @ w1 + b1 hl = relu(tl)  probs = predict(x) pred_class = np.argmax(probs) class_names = ['Setosa', 'Versicolor', 'Virginica'] print('Predicted:', class_names[pred_class])

И в итоге мы получим нужное нам предсказание

image

Полноценный код можно также посмотреть в моём github-репозитории по ссылке.

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

А какие примеры классификации и интересные задачи из направления DataSciense вы знаете? Пишите свой вариант в комментариях!


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

Как мы ведём документацию рядом с кодом

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

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

Кратко о том, как ведём документацию

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

Проектная документация у нас делится по слоям: на фронт, миддл и бэк. И в зависимости от слоя мы ведём её в разных местах.

Миддл. Рядом с кодом лежит документация на миддл-слой или слой микросервисов. В качестве системы контроля версий используем Bitbucket. Для разработки документов используем язык текстовой разметки AsciiDoc в связке с PlantUML, который позволяет создавать диаграммы из текста.

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

Бэкенд. Под бэкендом я, в первую очередь, понимаю нашу АБС Equation (примечание: Equation — комплексная, многовалютная и многоязычная система для банков). Исторически, документация на неё, — это спецификации в MS Word и MS Excel, размещаемые в базах Lotus Notes. Со временем их мигрировали в Confluence.

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

Итого. Документацию на миддл ведём рядом с кодом, на фронт и бэк — в Confluence.

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

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

Подробнее о том, как ведём документацию на миддл-слое

Процесс ведения документации на миддл выглядит так:

  • Есть проект в Bitbucket. В проекте находятся репозитории с исходным кодом микросервисов.

  • Файлы с исходниками распределены по папкам. Одна из папок предназначена для файлов документации на микросервисы.

  • Члены команды разработки выгружают репозитории с исходным кодом и документацией себе на локальные машины при помощи git. 

  • Вносят изменения и отправляют их на сервер Bitbucket на ревью.

  • После успешного ревью изменения мержим в master-ветку.

  • Система CI/CD узнаёт об изменениях в master, выгружает исходники и прогоняет их по преднастроенному pipeline. Конкретную систему не указываю — на моей памяти их было несколько: сначала использовали Jenkins, затем пилотировали GoCD, потом переключились на Bamboo. Сейчас переходим на собственное решение, под капотом которого крутится тот же Jenkins.

  • Получившиеся сборки кода и документации размещаются в Artifactory. Документация представлена в виде HTML-файлов.

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

Для описания сервиса можно использовать следующую структуру файлов:

  • index.adoc — корневая спецификация: содержит общее описание сервиса и ссылки на его методы.

index.adoc
index.adoc
  • getReport — папка с файлами: описывает метод getReport.

  • getReport/getReport.adoc — спецификация метода getReport.

getReport/getReport.adoc
getReport/getReport.adoc
  • getReport/getReport.puml — файл с описанием диаграммы: отражает логику  работы метода getReport.

getReport/getReport.puml
getReport/getReport.puml

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

Результат можно увидеть в интерфейсе IntelliJ IDEA с установленными плагинами AsciiDoc и PlantUML Integration. Также документацию можно собрать локально.

Примечание. Для сборки в учебных целях можно использовать движок Asciidoctor с расширением Asciidoctor PlantUml. В качестве PlantUML Server задействуем https://www.plantuml.com.

Пример команды сборки:

PLANTUML_URL="https://www.plantuml.com/plantuml"   \ PLANTUML_ENCODING="deflate"                        \ asciidoctor -r asciidoctor-plantuml index.adoc getReport/getReport.adoc

В результате её выполнения будут созданы два файла — index.html

index.html
index.html

и getReport/getReport.html.

getReport/getReport.html
getReport/getReport.html

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

Основная проблема хранения бинарников рядом с кодом — их размер. 

Нужно найти альтернативный способ хранения данных файлов. Здесь может помочь Git LFS. В качестве хранилища для исходников документации оставляем Bitbucket, а изображения с примерами пользовательского интерфейса будем складывать в Artifactory в репозиторий GitLfs.

На примере документации для фронта покажу, как помогает Git LFS.

Как ведём документацию на фронт?

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

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

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

  • Члены команды разработки выгружают репозитории с исходным кодом и ссылками на файлы документации себе на локальные машины при помощи git. Если нужны сами файлы документации по ссылкам — с помощью Git LFS. 

  • После внесения изменений бинарники с примерами пользовательского интерфейса уходят на хранение в Artifactory, а исходный код со ссылками на них — на сервер Bitbucket на ревью. 

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

  • После успешного ревью, как и раньше, изменения мержим в master-ветку.

  • Система CI/CD должна будет в процессе сборки научиться получать бинарники из Artifactory. В остальном pipeline останется без изменений.

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

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

  • index.adoc — файл с текстовым описанием пользовательского интерфейса;

index.adoc
index.adoc
  • images — папка со скриншотами;

  • images/index.png — скриншот пользовательского интерфейса, в котором отображается отчёт.

Источник: https://vc.ru/alfabank/94450-115-fz-prostymi-slovami-pochemu-banki-blokiruyut-karty-i-internet-bank-i-chto-delat-esli-eto-proizoshlo
Источник: https://vc.ru/alfabank/94450-115-fz-prostymi-slovami-pochemu-banki-blokiruyut-karty-i-internet-bank-i-chto-delat-esli-eto-proizoshlo

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

Так выглядит index.html после сборки.

index.html
index.html

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

Итог

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

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


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