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

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

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

Цель в том, чтобы добиться еще более эффективных вычислений и за счет разреженности достичь улучшений в энергоэффективности. Ранние реализации, такие как Loihi от Intel и TrueNorth от IBM, продемонстрировали на порядки более низкое энергопотребление для определенных классов задач.

Последовательность входных сигналов и сом модели «Интегрировать и сработать» в идеализированном нейроне импульсной сети

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

Изображение автора, сгенерированное кодом ниже

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

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

В отличие от традиционных фреймворков глубокого обучения, которые оперируют плотными матричными вычислениями, NEST имитирует дискретную, событийно-управляемую активность биологических нейронов. Ядро NEST написано на C++ и компилируется; для взаимодействия с ним мы обычно используем PyNEST — интерфейс Python, разработанный в рамках проекта Human Brain Project и инициативы eBrain. 

В этом контексте визуализация становится ключевым элементом. Далее я расскажу, как создать динамический визуализатор для сложных архитектур импульсных нейронных сетей. Знаковой работой, сфокусированной на этой цели, является широко известный Neucube Николы Касабова. Я переработал этот подход, используя возможности PyNEST и простые методы визуализации на Python.

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

DynamicSpikingNNVisualizer

Помимо нейромоделирования на основе ИИ, ключевым элементом является система визуализации результатов. Есть класс на Python, который создает анимированные представления активности сети в реальном времени. Вот основной класс после необходимых импортируемых библиотек:

import nest
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation, PillowWriter
from matplotlib.patches import Circle
from mpl_toolkits.mplot3d import Axes3D
from collections import defaultdict, deque

class DynamicSpikingNNVisualizer:
    """
    Динамический визуализатор в реальном времени для импульсных нейронных сетей PyNEST.
    Отображает спайки по мере их возникновения с визуальными эффектами и распространением.
    """
    
    def __init__(self, figsize=(18, 10)):
        """Инициализация визуализатора с настройкой изображения."""
        self.fig = plt.figure(figsize=figsize)
        self.spike_data = defaultdict(list)
        self.neuron_positions = {}
        self.connections = []
        self.neuron_types = {}
        self.weights = {}
        
        # Для динамической визуализации 
        self.spike_decay_time = 50.0  # мс - длительность свечения спайка
        self.propagation_speed = 0.5  # Визуализация скорости распространения спайка

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

  • spike_data: записывает моменты срабатывания каждого нейрона;
  • neuron_positions: 3D-координаты каждого нейрона;
  • connections: связи между нейронами;
  • neuron_types: классификация нейронов (возбуждающие, тормозные, входные).

Настройка нейронной сети

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

def example_dynamic_simulation():
    """Пример моделирования с динамической визуализацией процесса."""
    
    nest.ResetKernel()
    nest.SetKernelStatus({"resolution": 0.1})
    
    # Создание сети 
    n_excitatory = 80
    n_inhibitory = 20
    
    excitatory = nest.Create("iaf_psc_alpha", n_excitatory)
    inhibitory = nest.Create("iaf_psc_alpha", n_inhibitory)

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

  • Синие точки → возбуждающие нейроны,
  • Красные точки → тормозные нейроны.

Шаблон связности: нейронная архитектура, вдохновленная мозгом

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

# Связи
nest.Connect(poisson, excitatory, syn_spec={"weight": 50.0})
nest.Connect(excitatory, excitatory, 
             conn_spec={"rule": "pairwise_bernoulli", "p": 0.1},
             syn_spec={"weight": nest.random.uniform(10.0, 50.0)})
nest.Connect(inhibitory, excitatory, 
             conn_spec={"rule": "pairwise_bernoulli", "p": 0.3},
             syn_spec={"weight": -80.0})

Данная структура связей включает:

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

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

Фиксация и визуализация динамики спайков

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

def get_neuron_activity(self, gid, current_time, decay_time):
    """
    Вычисление уровня активности нейронов на основе последних спайков.
    Возвращает значения между 0 и 1. 
    """
    if gid not in self.spike_data or not self.spike_data[gid]:
        return 0.0
    
    activity = 0.0
    for spike_time in self.spike_data[gid]:
        time_diff = current_time - spike_time
        if 0 <= time_diff <= decay_time:
            # Экспоненциальное затухание
            activity = max(activity, np.exp(-time_diff / (decay_time / 3)))
    
    return min(activity, 1.0)

Наконец, можем создать комплексную визуализацию:

# Инициализация изображения с несколькими областями построения
self.fig.clear()
gs = self.fig.add_gridspec(2, 2, height_ratios=[2, 1], hspace=0.3, wspace=0.3)
# Главное 3D-представление сети
ax_3d = self.fig.add_subplot(gs[0, :], projection='3d')
# Растровый график
ax_raster = self.fig.add_subplot(gs[1, 0])
# Счетчик активности
ax_activity = self.fig.add_subplot(gs[1, 1])

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

На растровом графике каждый спайк отображается точкой, где идентификатор нейрона показан на оси Y, а время — на оси X.

Активности популяции отображает колебания и динамику на уровне нейронной популяции, отслеживая общую частоту спайков в сети с течением времени. 

def get_active_connections(self, current_time, window=5.0):
    """Получение соединений, отображающих распространение спайков."""
    active_conns = []
    
    for src, tgt in self.connections:
        if src not in self.spike_data:
            continue
            
        for spike_time in self.spike_data[src]:
            time_diff = current_time - spike_time
            if 0 <= time_diff <= window:
                progress = time_diff / window
                active_conns.append((src, tgt, progress))
    
    return active_conns

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

Вот полный код.

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

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

Читайте также:

Читайте нас в Telegram, VK и Дзен


Перевод статьи Dr. Alessandro Crimi: Visualizing Large-Scale Spiking Neural Networks

Предыдущая статьяC++: полное руководство по бинарной сортировке