Инженерные системы можно либо собирать, либо выращивать, но в любом случае в них есть ошибки. Ошибки быстро распространяются по системным связям: ошибка в какой-то части системы приводит всю систему к неработоспособности, если система слишком цельная. Корабль без переборок тонет. Каждая связь внутри системы имеет свою цену. Когда каждая связь имеет цену, эволюция "изобретает" модульность -- системы начинают собираться или расти крупными частями, которые более-менее автономны и соединяются друг с другом через оговорённые интерфейсы, минимизирующие связи в системе. Не было бы цены, не было бы и модулей (
http://arxiv.org/abs/1207.2743). Меньше связность -- можно делать более радикальные изменения в частях системы, не рискуя развалить всю систему в целом (
http://www.pnas.org/content/108/22/9008.full). Если связей много, то одно лечим, а другое калечим при любом изменении.
Каждая система представляет собой единство модуля и компоненты, так как конструкторский-сборочный аспект представляется модулем с его интерфейсами, а вот логический-функциональный аспект представляется компонентами/функциональными элементами. Функция, конечно, это зачем система-модуль может использоваться в надсистеме (использующей системе). Конечно, несколько модулей как элементов конструкции вполне могут внутри системы использоваться для поддержки какой-то одной функции, но на уровне целой системы, которая выходит из рук инженера в проекте обычно функция и конструкция совпадают, модуль и компонента совпадают. Уровнем выше всё, конечно, уже будет по-другому: система станет подсистемой и основное назначение будет проигнорировано. Но реальность, конструкцию, не проигнорируешь: она останется. Микроскоп, использованный в надсистеме в качестве молотка, продолжает конструктивно быть микроскопом. Согласование требуемого набора функций (компонент, чаще всего это функциональные диаграммы и принципиальные схемы) и набора модулей с их интерфейсами -- это и есть суть архитектурной работы. Ключевую часть этой работы часто называют "модульный синтез". Работа инженера прежде всего синтетична, поэтому я не люблю акцента на "анализ" -- он выполняется обычно ровно в той мере, в какой нужно подыскать материал для синтеза, без понимания того, каков будет синтез, анализ невозможен.
Есть множество методологий архитектурного/модульного синтеза, см. обзор в первой главе книги М.Левина «Технология поддержки решений для модульных систем»:
http://www.mslevin.iitp.ru/Levin-bk-Nov2013-071.pdf). У всех них один «недостаток»: хорошему инженеру эти методы помогают, плохому инженеру они помочь не могут. В России из этих методов наиболее известен ТРИЗ
(
http://ru.wikibooks.org/wiki/%D0%9E%D1%81%D0%BD%D0%BE%D0%B2%D1%8B_%D0%A2%D0%A0%D0%98%D0%97, можно начинать знакомиться с ним с проглядывания трёх текстов: АРИЗ-85В
http://altshuller.ru/triz/ariz85v.asp, типовых приёмов разрешения противоречий
http://www.altshuller.ru/triz/technique1.asp и стандартных решений изобретательских задач
http://www.altshuller.ru/triz/standards.asp). DSM (design structure matrix,
http://www.dsmweb.org/) чаще всего используется как метод разбиения системы на модули. ТРИЗ в его современном варианте ТРИЗ++ и DSM практикуются во многих центрах разработки. Но есть огромное число методов, практикующихся в рамках одного-двух университетских или промышленных исследовательских центров/лабораторий (реже - неисследовательских центров разработки).
Для понимания модульности критичны понятия компонуемости (composability) и композициональности (сompositionality), например их особо оговаривают в CPS PWG Cyber-Physical Systems (CPS) Framework
https://pages.nist.gov/cpspwg/ для киберфизических систем. Увы, поздно подбирать русскоязычные переводы этих слов, электронные переводчики их знают. Можно только запомнить мнемонику, что
-- компонуемость (composability) -- это про возможность сложить целую систему из частей-подсистем. Модульный аспект сборки, компоновки, создания холархии: интерфейсы воткнутся друг во друга, целая система, собранная из подсистем, заработает. Обратите внимание, что "выращиваемые" системы не компонуемы! Их не соберёшь из частей, и хотя в них тоже присутствует холархия, нельзя сказать, что на неё как-то существенно можно влиять, отдельные модули не взаимозаменяемы путём подключения к известному интерфейсу, требуются разные "врастания".
-- композициональность (compositionality) требует некоторого "композиторства" -- речь идёт о свойстве собранного из частей целого обходиться без неожиданной эмерджентности типа отрицательных побочных эффектов. Система композициональна по какому-то свойству, когда её это свойство напрямую трассируется к свойству отдельных модулей. Это хитрое антисистемное понятие, потому как целая композициональная система в отношении какого-то свойства не больше суммы своих частей, а равна сумме своих частей! Композициональная система имеет какое-то свойство, если её модули имеют это свойство, поэтому для композициональной системы простая сборка её из обладающих каким-то свойством модулей будет означать доказательство того, что вся система обладает этим свойством. Если модули системы критичны к работе во времени и требуется их синхронизация, то создать систему, синхронно работающую "в силу конструкции", обычно нельзя. Так что свойства с плохой композициональностью обычно попадают в список интересов стейкхолдеров отдельными пунктами и в проектах им уделяется много внимания.
Поскольку системы создаются из гетерогенных элементов, то компонуемость эксплуатирует полезную эмерджентность (нужная функция появляется в результате взаимодействия элементов), а композициональность наоборот, указывает на отсутствие вредной эмерджентности.
Вот картинка, которая иллюстрирует чисто механическое понимание модульности:
Дальше мы потихоньку будем отходить от механистического представления о модульности.
Проблема модульности описаний стоит так же остро: каждое описание в конечном итоге отражает какую-то систему (целевую, подсистему, использующую систему, систему в операционном окружении, обеспечивающую). Хотелось бы вносить какие-то изменения в описания, которые имели бы локальное влияние -- чтобы не приходилось потом пересобирать всё описание или переделывать определяемую этим описанием всю систему полностью. А если связь между описанием и производимой (генерируемой, выращиваемой, изготавливаемой -- это неважно) конечной конструкцией неизвестна, то отладка (исправление ошибок проектирования/конструирования) становится невозможна. Трудность тут в том, что описания в инженерии модельны -- они отражают какие-то формальные стороны системы, игнорируя ненужные детали. И эти формализмы моделирования тоже имеют и свои описания -- всегда присутствует этажерка уровней абстракции (каждое view имеет свой viewpoint, эти viewpoint тоже написаны с использованием каких-то языков, и типичный случай -- это три-четыре уровня "описания описаний", абстрагирования).
В моделировании (и особо -- в имитационном моделировании, см., например,
https://en.wikipedia.org/wiki/Composability) в локальных (формально-символических) представлениях модульность обсуждается как набор самых разных идей:
-- гранулярности (проблема "разрешающей способности" описания -- какие особенности модульной конструкции могут быть описаны). Именно тут обычно обсуждается: строить из кирпичиков или строить крупнопанельно.
-- масштабируемости (на сколько уровней "вверх" модули могут состоять друг из друга, чтобы систему можно было как-то отлаживать, ремонтировать, модернизировать при её росте). Особо я тут рекомендую лекцию Алана Кея Programming and Scaling,
http://www.tele-task.de/archive/video/flash/14029/, транскрипт
http://limist.com/coding/talk-notes-programming-and-scaling-alan-kay-2011.html-- платформенности, сама идея "платформы" опирается на идею "развязанности", независимости, наличия компактного минимального интерфейса платформы и строящейся на её основе системы. Сюда же и стеки платформ (например, интеллект-стек:
http://ailev.livejournal.com/1222210.html).
-- проблемы типа expression problem (независимое, т.е. без перекомпиляции всего пополнение структур данных и алгоритмов, которые эти данные обрабатывают -- какие средства в языках описаний aka языках программирования позволяют эту проблему решать --
https://en.wikipedia.org/wiki/Expression_problem, например, Julia для этого использует multiple dispatch -- пункт 1 в
http://ailev.livejournal.com/1218155.html-- модульность онтологий (вернее, онтологических описаний -- это ведь тоже модели, описания мира) рассматривается как важнейшее их свойство: сейчас приходят к выводу, что отдельные модули (наборы аксиом, микротеории) среднего уровня (предметных областей, middle ontologies) являются главным артефактом онтологической работы, хотя традиционно акценты ставились на upper ontology и definitional ontology. Вот только вчера на совете попечителей Ontolog Forum обсуждалось, что в стандартизации upper ontology (стандартизироваться будет форма, не содержание) особое внимание нужно уделить средствам обеспечения модульности. Ну, и "онтики", которые потом обычно мэппятся к upper ontology, это тоже модули -- их ведь нужно несколько, чтобы отразить какой-то интересующий фрагмент мира.
Коннекционистские описания, коннекционистские (нейронные сети, векторные представления) модели нужно при этом выделить из числа всех моделей -- они себя по принципу ведут себя в плане модульности по-другому. Их модульность (компонуемость и композициональность) крайне мала, эти модели "обучают" ("выращивают"), а не "собирают". И тут возможны два подхода:
а) смириться, и работать в таких представлениях. Куски знания невозможно передать, можно только заставить обучаемую модель пройти путь научения, так что не стоит и пытаться изобрести "таблетку знания". Опыт, опыт, опыт -- вот и вся передача знания. Знание не локально. В какой-то мере это соответствует "восточной цивилизационной модели", где делается упор на холистичность, гештальтность восприятия и понимания (см. обсуждение в
http://ailev.livejournal.com/1293882.html и отчасти в
http://ailev.livejournal.com/1281819.html). Обратим внимание: холистичность тут выступает не системным свойством в западном его понимании (система состоит из частей, но не будем терять целое из виду), а просто указанием на "связанность всего со всем", отсутствия заботы о компонуемости и композициональности.
б) засучить рукава и добавлять другие виды моделей (в локальных представлениях, символьные), чтобы внести компонуемость и композициональность по максимуму -- это западная цивилизационная модель. Если нельзя сделать "таблетку знаний" с чётким интерфейсом, то можно хотя бы сделать полуфабрикат, который чуть-чуть "довыращивается", или сделать тренажёрчик, или ещё что-нибудь сделать инженерное. Конечно, это не устранит холистичность, эмерджентность, не преодолеет наличие невыразимого дао (т.е. невыразимых в локальных символических представлениях каких-то коннекционистских распределённых представлений) -- мысль изречённая, сиречь смоделированная, сиречь сжатая -- ложь, то есть теряет что-то по сравнению с изначальной формой коннекционистского выученного "опыта". Но как минимум, это позволит в разы и разы ускорить обучение, ускорить передачу опыта путём прохождения тренинга. Я наметил этот тренд в своём докладе
http://www.slideshare.net/ailev/ss-59952353 (видео, увы, не получилось записать) и потом
Le Bouttou поставил эту задачу добиваться модульности (до тонких различений между composability и compositionality в инженерии машинного обучения не дошли, обходятся пока одним из этих двух взятых наугад слов, подразумевая просто "модульность") в
http://leon.bottou.org/slides/2challenges/2challenges.pdf, где выделил два проблемных типа модуля:
-- Models as modules: problematic due to weak contracts (models behave differently on different input data). Входные данные «не проверишь» при подаче модулю-модели, у него нет «спецификации» ожидаемых входных данных, интерфейс недоопределён.
-- Learning algorithms as modules: problematic due to output depends on the training data which itself depends on every other module. Нейросеть-алгоритм не специфицируешь, ибо без обучающих данных (и последовательности обучения - curriculum learning) это ещё не модель.
Тут нужно ещё заметить, что у обучающихся систем в любой момент времени отклик не предопределённый -- они ведь меняются в ходе постоянного дообучения! Поэтому их, например, нельзя сертифицировать: после малейшего дообучения они уже будут изменены, и сертификация формально к ним не будет подходить. Это означает, что обычные инженерные испытания, после которых можно быть уверенными в результате, к таким системам не подходят -- обучающиеся системы больше в этом плане похожи на людей, и вся критика "экзаменов" как аналога сертификации (способа определения надёжности выполнения системой машинного обучения её функций) полностью переходит в инженерию от педагогики.
По линии обеспечения модульности систем машинного обучения (то есть перехода от искусства выращивания систем машинного обучения методов проб и ошибок к какой-то инженерии, хоть и не на базе строго научных решений -- вычислимых на основе формальных моделей, но на базе каких-то более-менее строгих эвристик) в настоящее время делается очень много -- но прежде всего выделяются уровни платформы интеллект-стека (когда проблемы с модульностью возникают только в части моделей самих сетей и алгоритмов машинного обучения на одном уровне и общей когнитивной архитектуры другого уровня), вот формулировки его примерно годичной давности:
http://ailev.livejournal.com/1210678.html с выделением каких-то платформенных уровней и известными интерфейсами, вот свежий обзор происходящего с аппаратной частью:
http://ailev.livejournal.com/1293810.html (и там, конечно, для любых чипов предусматриваются средства их комплексирования в большие вычислительные структуры -- гарантируется компонуемость супервычислителей из этих чипов).
Общая задача повышения функциональности идёт под флагом transfer learning (как знание из одной ситуации обучения передать в другую -- по возможности передав какой-то артефакт). Иногда это обсуждается и как multitask learning (как одну и ту же архитектуру учить самым разным задачам). В любом случае, это требует выделения каких-то частей нейронной сетки -- скажем, при transfer learning можно взять обученную с нуля нейронную сеть, отрезать от неё пару верхних уровней, заморозить веса этой сети, нарастить её новыми верхними уровнями и доучить на новых данных. Понятно, что сохраняемый обученный на первой задачей кусок -- это вполне себе "модуль", хотя и очень неклассический (как это и обсуждал Le Boutou). Вся онтологичность-статичность модуляризации, обсуждение того, что именно из мира отмоделировано какой частью сетки размывается, и разговор уходит в эпистемологию -- ответ на онтологический вопрос "что учили", а эпистемологический "как учили". То есть приходится разбираться с модульностью процедур, ведущих к цели, где интерфейсы -- это последовательность выполнения этих процедур и логистика передачи целевой выращиваемой/обучающейся системы в разные среды. Это типа как конвейер на кондитерской фабрике, где невозможно ответить на вопрос "из чего собрали тортик", ибо это не сборочный конвейер, а что-то типа химзавода с реакторами и трубами -- что-то из чего-то замешивают (и хоть это и похоже на операцию сборки, результат совсем не похож -- частей в сборке не видно, нет интерфейсов), заквашивают (то же самое: нет интерфейсов, нельзя разобрать), запекают (всё меняется, но даже не добавляют новых частей!), и инженеры тут не конструкторы, а технологи. Модульность тут есть главным образом у обеспечивающей системы, но нас-то интересует модульность целевой! Напомню: нас интересует, чтобы при ошибке, например, в дрожжах, весь тортик системно не испортился, а только связанная с дрожжами часть. Борьба-то за это!
Далее борьба за компонуемость и композициональность идёт в рамках архитектуры самой нейронной сети: типы слоёв, типы нейронов, их элементов (передаточных функций). Само представление такой сетки из типовых элементов -- это уже огромный прогресс! Для описания этой архитектуры сегодня обычно используется DataFlow язык (отсюда и название TensorFlow у самого популярного фреймворка), но есть и более гибкие варианты (см. MXNet). Наличие формального языка позволяет легко собирать сетки-полуфабрикаты (необученные!) из элементов так, чтобы получившийся сложный и запутанный результат был полностью дифференцируемым (differentiable), что гарантирует его последующую обучаемость -- на полностью дифференцируемых коннекционистских структурах может работать backpropagation. Конечно, можно создавать новые типы модулей, новые комбинации организации таких слоёв из них, таких предложений множество (типа массовой замены пару лет назад сигмоиды на tanh, а tanh на ReLU, или совсем свежего использования двумерной PixelNet для картинок как идеи для создания одномерной WaveNet для конволюционной обработки звука
https://deepmind.com/blog/wavenet-generative-model-raw-audio/).
Борьба за автономию модулей в супермодуле обучаемой нейронной сетки идёт и тут. Например, совсем недавно предложили способ автономизации слоёв нейронной сетки, чтобы не нужно было дожидаться в глубокой структуре, пока до слоя добежит волна коррекции весов -- теперь вычисления во всех слоях можно распарралеливать, чего раньше делать было нельзя:
https://deepmind.com/blog/decoupled-neural-networks-using-synthetic-gradients/. Обратите внимание на название этой работы: Decoupled Neural Interfaces Using Synthetic Gradients. Ключевое слово, указывающее на разговор о модулях -- это "интерфейс", а указывающее на поднятие модульности (обеспечение компонуемости и композициональности) -- тут это decoupled.
Ещё одни интересный ход -- это поиск возможных модулей внутри выученной нейросети. Ключевое слово тут -- "ансамблевость", внутри сети меняется даже терминология: тут не "сборки" и "модули-подмодули", тут "ансамбли", и основной ход -- это показ, что математически какая-то сеть работает как ансамбль более простых моделей. Вот только несколько ссылок, показывающих тренд на разборку в этом направлении:
-- обзор residual neural networks:
https://blog.init.ai/residual-neural-networks-are-an-exciting-area-of-deep-learning-research-acf14f4912e9#.k2bkvbvoc-- Residual Networks are Exponential Ensembles of Relatively Shallow Networks (обнаружение "нейроонтик", островков-клочков абстракции)
https://arxiv.org/abs/1605.06431-- Wide Residual Networks (успешная попытка уменьшить число уровней абстракции-слоёв сети за счёт более богатых представлений на каждом уровне -- т.е. сделать сеть более широкой, чем глубокой. Это довольно контринтуитивно, ибо выразительные широкие сети обычно проблемны в части трудоёмкости вычислений и это компенсируют как раз увеличением глубины. Но оказалось, что такой ход не универсален):
http://arxiv.org/abs/1605.07146-- FractalNet: Ultra-Deep Neural Networks without Residuals (идея регуляризации архитектуры сверхглубоких сетей на основе самопохожести фрагментов этой архитектуры -- если продолжить эту аналогию с онтологическими разработками, то это шаг к фрактальным foundational ontology):
http://arxiv.org/abs/1605.07648 Использование заранее выученных word embeddings даже как инициализаций в рамках transfer learning это тоже важный ход на модульность, и помним возражения от Nando de Freitas про ограниченную полезность онтологической "статики" в мире эпистемологической и прагматической динамике обучающихся архитектур --
http://ailev.livejournal.com/1240509.html.
Хорошо описанные наборы данных для обучения (часто и лежащие в сети), это ведь тоже модули, хотя в данном случае это больше похоже на модули обеспечивающей, а не целевой системы (учебные наборы данных это "станки для обучения"), тем не менее.
Нет никаких сомнений, что тема модульности в инженерии машинного обучения будет только развиваться. На закуску -- свеженькое видео от Nando de Freitas с его взглядом на модульность (у него используется термин compositionality), это хорошо иллюстрирует, насколько по-разному обсуждают модульность в иженерии обучаемых систем по сравнению с традиционной "конструкторской" сборочной инженерией -- Learning to learn and compositionality with deep recurrent neural networks">Learning to learn and compositionality with deep recurrent neural networks (
https://youtu.be/x1kf4Zojtb0):
Click to view
Так что при переходе ко всё более и более обучаемым киберфизическим системам тот самый CPS Framework
https://pages.nist.gov/cpspwg/ придётся править -- и эта правка не должна быть для нас неожиданной.