Проєктуємо нейронні мережі за допомогою об’єктно-орієнтованого підходу
Я в IT з 2011, починав як тестувальник, а потім пройшов шлях Java, Data Engineer і зараз розвиваюсь в напрямку Machine Learning. Ще в університеті, на четвертому курсі, в
Психолог Дональд Олдінг Хебб зробив першу теоретичну спробу описати алгоритм навчання на основі природних нейронних мереж у
Можна з упевненістю сказати, що багато базових алгоритмів штучних нейронних мереж є недеталізованими моделями природних нейронних мереж та/або їх частин.
Формалізація проблеми
Відповідно до попереднього розділу здається логічним мати деякий фреймворк для побудови моделі природних нейронних мереж довільної деталізації. Після початкового рівня дослідження нейробіології та порівняння з поточними алгоритмами штучних нейронних мереж, я сформував твердження:
- Нейрони можуть обробляти два класи сигналів: біохімічні та біоелектричні. Відмінності у швидкості поширення біоелектричного та біохімічного сигналу значні.
- Різні сигнали мають різний час поширення.
- Набір рецепторів нейрону визначає сигнали, які він може обробляти, та його структуру. Набір рецепторів у різних типів нейронів різний.
- Пізнавальні процеси пов’язані з часом.
Фреймворк повинен мати можливість:
- Визначати різні типи сигналів.
- Визначати нейрон, здатний обробляти кілька типів сигналів з різною логікою обробки для кожного типу сигналу.
- Визначати різні типи нейронів.
- Визначати відносні швидкості обробки для двох класів сигналів.
- Визначати відносну швидкість обробки для кожного типу сигналу.
Ці вимоги були використані для реалізації Jneopallium.
Процес моделювання природної нейронної мережі
Архітектура високого рівня
Це вже моя друга стаття про моделювання натуральних нейронних мереж. Першу написав ще в процесі розробки фреймворку.
Jneopallium — це набір інтерфейсів і реалізацій, які відокремлюють логіку обробки нейронної мережі від фактичних типів нейронів і сигналів. Так же колекції відокремлюють логіку зберігання від фактичних типів об’єктів, які вона зберігає, за допомогою генериків. Я вибрав Java для реалізації, оскільки ця мова підходить для інтерфейсів і загального використання, а ще забезпечує певну безпеку типів. Весь код Jneopallium, розміщений у сховищах github.com/rakovpublic/jneopallium і gitlab.com/rakovpublic/jneopallium, поширюється за ліцензією BSD 3 — Clause License.
Щоб побудувати модель, користувач повинен визначити типи сигналів, типи нейронів, джерела вхідних даних і класи вихідних агрегаторів. Потім описати структуру нейронної мережі, вказати технічну інформацію у файлі конфігурації та запустити Jneopallium із вказаним шляхом до визначеного користувачем коду jar, структури нейронної мережі та файлу конфігурації.
Ще одна причина, чому я вибрав Java для реалізації — є можливість завантажувати визначений користувачем код під час виконання. Jneopallium може працювати в трьох режимах: локальному, кластерному HTTP і кластерному gRPC. gRPC дозволяє запускати Jneopallium на FPGA.
Для цієї статті я розділив процес моделювання на три частини: визначення функціональної логіки, визначення структурної логіки та визначення логіки IO. Наступні три підрозділи описують процес моделювання.
Визначення функціональної логіки
Процес моделювання починається з визначення сигналу. Користувач повинен визначити всі сигнали в системі та ваговий об’єкт, який буде використовуватися для навчання.
Наступний крок — визначення інтерфейсів нейронів. Кожен механізм обробки повинен мати окремий нейронний інтерфейс, який розширює базовий інтерфейс INeuron.
Третій крок — реалізація сигнального процесора. Сигнальні процесори повинні реалізовувати інтерфейс ISignalProcessor, параметризований сигналом і інтерфейсом нейрону, який має відповідні механізми для обробки. Тоді користувач повинен реалізувати нейрони, розширивши Neuron.class і реалізувавши інтерфейс або інтерфейси, визначені на другому кроці. Множинне наслідування через реалізацію інтерфейсу дозволяє користувачеві реалізувати нейрони з кількома механізмами обробки, які можуть обробляти різні типи сигналів. Крім того, нейрон має поля Axon.class і Dendrites.class. Dendrites інкапсулюють вхідні адреси (ім’я джерела введення або ідентифікатор рівня та ідентифікатор нейрона), типи сигналів і ваги. Ці ваги застосовуються до вхідних сигналів і повинні використовуватися в процесі навчання. Вихідні адреси інкапсуляції аксонів (ідентифікатор рівня та ідентифікатор нейрона), тип і вага сигналу. Ці ваги застосовуються до вихідних сигналів і також повинні використовуватися в процесі навчання.
Щоб показати приклад процесу моделювання, я визначив чотири сигнали та три нейрони в окремій тестовій гілці github.com/...finitions/functionallogic. IntSignal.class представляє сигнал, описаний за допомогою цілого значення. DoubleSignal.class представляє сигнал, описаний double-значенням. Класи IntProcessor і DoubleProcessor описують логіку обробки цих сигналів. Інтерфейси NeuronIntField і NeuronWithDoubleField описують нейрони з внутрішньою структурою, яка дозволяє обробляти IntSignal і DoubleSignal відповідно. NeuronC і NeuronB — це реалізації нейронів, які обробляють лише один тип сигналу. Нейрон A — це нейрон, який може обробляти обидва сигнали, тобто має два рецептори. Приклад:
public class NeuronA extends Neuron implements IResultNeuron<TestResultSignal>,NeuronIntField, NeuronWithDoubleField { public Integer intField; public Double doubleField; public NeuronA() { super(); intField =0; doubleField=0d; currentNeuronClass = NeuronA.class; resultClasses.add(ASignal.class); } public NeuronA(Long neuronId, ISignalChain processingChain, Long run) { super(neuronId, processingChain, run); currentNeuronClass = NeuronA.class; intField =0; doubleField=0d; resultClasses.add(ASignal.class); } @Override public Integer getIntField() { return intField; } @Override public void setIntField(Integer field) { this.intField = field; } @Override public Double getDoubleField() { return doubleField; } @Override public void setDoubleField(Double value) { this.doubleField = value; } @Override public void activate() { super.activate(); Double d = doubleField%intField; if(d>=1){ result.add( new ASignal(d.intValue(), getLayer().getId(), getId(), 1, «a signal», false, this.currentNeuronClass.getName(), false, true, ASignal.class.getName())); intField = 0; doubleField = 0.0; } isProcessed=true; } @JsonIgnore @Override public TestResultSignal getFinalResult() { String res = result.toString(); TestResultSignal resultSignal = new TestResultSignal(res, this.getLayer().getId(), this.getId(), 1, «„, false, this.getClass().getCanonicalName(), false, false, “»); return resultSignal; } }
Визначення структурної логіки
Після визначення всіх частин функціональної моделі, користувач повинен визначити структуру нейронної мережі. Я рекомендую використовувати статистичний підхід, тобто знайти ймовірність появи кожного нейрона на кожному шарі. Це дозволяє моделювати горизонтальну структуру. Щоб визначити, який порядок нейронів на шарах може бути, користувач повинен реалізувати інтерфейс NeighboringRules. Ця функція дозволяє моделювати структуру вертикального нейронної мережі.
Приклади моделювання структури розміщено тут.
Моделювання конструкції виконано за допомогою NeuronNetStructureGenerator. Для цього потрібна хешкарта з розмірами шарів, хешкарта зі статистичними властивостями для кожного типу нейрона, список NeighboringRules і клас, який реалізує IConnectionGenerator. IConnectionGenerator описує, як пов’язані нейрони.
Визначення логіки введення/виведення
Логіка введення/виведення описує джерела введення та призначення виводу. Нейронна мережа може мати кілька джерел введення. Щоб визначити джерело введення, користувач повинен реалізувати інтерфейс IInitInput. Кожен вхідний сигнал має стандартну частоту обробки, яка показує, як часто сигнали від джерела введення будуть поширюватися до нейронів. Частоту обробки можна змінити за допомогою відправки сигналу в Cycle Neuron (докладніше про це в наступному розділі). Спосіб поширення вхідних сигналів до нейронів слід описати за допомогою реалізації інтерфейсу InputInitStrategy.
Кожне джерело введення може мати окрему InputInitStrategy. Якщо вхід є виходом іншої нейронної мережі, сигнали можуть надсилатися до цієї нейронної мережі. У цьому випадку для джерела введення має бути реалізований інтерфейс INeuronNetInput. Ця функція може бути корисною для створення модульних моделей, щоб спростити навчання.
Щоб визначити призначення виводу, користувач повинен реалізувати інтерфейс IOutputAggregator. Приклад визначення логіки введення/виведення розміщено в цьому пакеті.
Частота обробки сигналів
Частота обробки сигналу визначається двома циклами обробки. Швидкий цикл обробляє кожну ітерацію обробки, а повільний цикл — один раз за n ітерацій швидкого циклу. Значення n визначається в Cycle Neuron і може бути змінено за допомогою надсилання сигналу до рівня з ідентифікатором — 2147483648 та нейрону з ідентифікатором 0. Кожен тип сигналу та джерело вхідного сигналу мають ProcessingFrequency, який описується полем loop та полем epoch. Сигнал із циклом ProcessingFrequency 1 оброблятиметься щоразу під час обробки швидкого циклу, зі значенням 2 — один раз у 2 обробки, зі значенням 3 — один раз у 3 обробки тощо.
Епоха ProcessingFrequency використовує ту саму логіку, але для повільного циклу. Ось тут код описує всі можливі сигнали Cycle Neuron і логіку обробки.
Масштабування
Розмір шару можна змінити за допомогою надсилання сигналу LayerManipulatingNeuron. Він розташований на кожному шарі з ідентифікатором — 9 223 372 036 854 775 808 і може створювати та видаляти нейрони. Тут ви можете знайти список логіки сигналу та обробки.
Додаткові можливості
Існує можливість визначити будь-яку кількість дискримінаторів для нейронних мереж. Їх можна використовувати для реалізації GAN. Крім того, користувач може зберігати та витягувати параметри в шарах.
Конфігураційні файли
Приклади конфігураційних файлів можна знайти тут.
Застосування
Моделі, побудовані за допомогою jneopallium, можуть бути використані для робототехніки. Вихід і вхід визначаються користувачем, щоб він міг безпосередньо комунікувати з контролерами. Я очікую, що загальний ШІ можна реалізувати за допомогою такого підходу.
Також такі моделі можна використовувати для управління компанією в середовищах з різним рівнем волатильності сигналів та метрик.
Їх можна використовувати для моделювання природної нейронної мережі, особливо коли потрібно моделювати контрольну структуру та структуру з різними відхиленнями.
Також можна використовувати для автономного керування місією, коли затримка з’єднання є високою і є високі умови та невизначеність проходження місії.
Монетизація
Jneopallium має кілька сценаріїв монетизації. Перший — це створення моделей для різних продуктів. Іншим способом монетизації є надання послуг хостингу так само, як це роблять хмарні провайдери для Spark. Третій спосіб — оптимізація FPGA під модель.
Конкуренти
Найближчими конкурентами Jneopallium є NEURON Simulator і CoreNeuron. Вони дозволяють будувати високодетальні моделі природних нейронних мереж. Основна відмінність полягає в тому, що Jneopallium дозволяє користувачам вибирати рівень деталізації. Основна мета Jneopallium — бути мостом між нейробіологією та інформатикою. Основна мета NEURON Simulator і CoreNeuron — створити точну копію природної нейронної мережі.
Висновок
Уже існують рішення для детального моделювання, але немає рішень, які були б містком між дуже детальним описом натуральних нейронних мереж і чимось прикладним, що могло б використовуватись на практиці. Саме цю нішу намагається зайняти Jneopallium.
Дякую за увагу.
77 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів