Структурные модели самоподобных сетей
Исходный код

Модели PyTorch

regnets.modular преобразует готовую топологию в обучаемую сеть. regnets.kernels предоставляет готовые описания ядер и интерфейс Kernel. Модули топологии используют только стандартную библиотеку Python и не зависят от вычислительной части.

Использование #

Установка PyTorch #

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

bash
python -m pip install 'regnets[torch]'

В клонированном репозитории выполните uv sync --extra torch; команды вычислительных примеров запускайте через uv run --extra torch python .... При отсутствии PyTorch импорт regnets.modular или regnets.kernels выдаёт ImportError с этой командой установки. Остальные ошибки загрузки PyTorch сохраняются без подмены. Топология и её визуализация доступны при базовой установке regnets.

Создание сети #

python
import torch
from torch import nn

from regnets.kernels import Dense
from regnets.modular import Layer, ModularNet
from regnets.topology.lib import cooley_tukey

net = ModularNet(
    topology=cooley_tukey((2,) * 8),
    layers=Layer(kernel=Dense(activation=nn.SiLU)),
    device="cpu",
)
x = torch.randn(4, 256, device="cpu")
y = net(x)
assert y.shape == x.shape

Одно неизменяемое описание Layer распространяется на все слои; параметры каждого слоя создаются независимо и сразу видны оптимизатору. p и g принадлежат топологии и задают числа входных и выходных контактов каждого модуля. Если g пропущено при создании топологии, используется g=p. Числа контактов всей сети доступны как net.n_inputs и net.n_outputs.

shared=True задаёт общие параметры между позициями модулей одного слоя. shared=False задаёт независимые параметры каждой позиции. Это относится также к параметрам нормировки и обучаемой остаточной проекции. Разные слои имеют независимые параметры при любом режиме.

Векторы на контактах и разные слои #

  • Layer(..., in_size=None), по умолчанию: скалярные контакты, форма [..., N].
  • Layer(..., in_size=k): векторы на входных контактах слоя. Даже in_size=1 требует явного последнего измерения длины 1: [..., N, 1].
  • out_size задаёт длину вектора на выходных контактах слоя. Если его пропустить, выходной размер равен входному. Размеры должны быть положительными целыми числами.

Размер выходного вектора слоя должен совпадать с входным размером следующего слоя. При построении сети проверяются все такие пары, включая размеры, полученные по умолчанию. Сеть использует либо скалярные контакты во всех слоях, либо векторные; смешивать эти режимы нельзя. Входная и выходная формы всей сети определяются первым in_size и последним out_size соответственно. Указание out_size для скалярного входа не поддерживается.

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

python
from regnets.kernels import MLP
from regnets.modular import Residual
from regnets.topology.lib import good

net = ModularNet(
    good((2, 3, 2), g=(3, 2, 1)),
    layers=[
        Layer(Dense(activation=nn.SiLU), in_size=8),
        Layer(MLP(hidden=(32, 16)), shared=False,
              residual=Residual(project=True), in_size=8, out_size=4),
        Layer(Dense(bias=False), in_size=4, out_size=2),
    ],
    device="cpu",
)
assert net(torch.randn(4, 12, 8)).shape == (4, 6, 2)

Одно описание Layer можно повторить на всех слоях, если оно сохраняет размер вектора. Для переходов между размерами задайте совместимые описания слоёв, как в примере. Для двойственной сети передайте topology.dual(): она преобразует слова и размерности контактов. Порядок описаний слоёв и их фактические входные и выходные размеры векторов при необходимости измените отдельно: сеть не преобразует вычислительные ядра автоматически.

Прежний параметр ModularNet(size=...) удалён: постоянный размер переносится в Layer(in_size=...), а последовательность размеров — в in_size и out_size соответствующих слоёв.

Параметры Layer(p=..., g=...) удалены: задайте числа контактов в Topology или стандартном генераторе и передайте эту топологию в ModularNet.

Блоки ядра #

Все описания создают пакетный nn.Module при конструировании сети. Параметры не создаются и не собираются заново в forward.

Блок Поведение
Dense() Линейное преобразование со смещением; выход выводится из слоя
Dense(64, bias=False, activation=nn.SiLU) Явные 64 локальных выходных признака
MLP(hidden=(64, 32)) Скрытые размеры 64 и 32, вход и выход выводятся из слоя
Sequential(...) Последовательная композиция описаний блоков
RMSNorm(eps=1e-6, affine=True) Нормировка локального среднеквадратичного значения
LayerNorm(eps=1e-5, affine=True, bias=True) Нормировка локального среднего и дисперсии
Dropout(0.1) Независимые маски признаков при обучении, отключён в eval()
Identity() Тождественное преобразование локальных признаков
GatedMLP(hidden=64) Совмещённая проекция в две ветви, SiLU-управление и выходная проекция

У Dense по умолчанию нет активации. У MLP активация nn.SiLU следует после скрытых преобразований; output_activation=None оставляет последнее преобразование линейным. hidden принимает число или последовательность. Активация задаётся фабрикой без аргументов, например nn.GELU или lambda: nn.LeakyReLU(0.1). Обучаемую активацию оформляйте отдельным Kernel.

python
from regnets.kernels import Dropout, RMSNorm, Sequential

kernel = Sequential(
    RMSNorm(),
    MLP(hidden=(64, 32), activation=nn.SiLU),
    Dropout(0.1),
)
net = ModularNet(cooley_tukey((2,) * 8), Layer(kernel=kernel, shared=False,
                                       residual=True, in_size=32), device="cpu")

Нормировка охватывает объединённый локальный вектор входов ядра. Позиции модулей и объекты пакета в статистике не смешиваются. В Sequential нормировка, Dropout и Identity сохраняют текущую ширину; Dense(64) явно устанавливает её, а Dense() и MLP используют выходную ширину окружающего слоя. Проверяется итоговое число признаков. Композиции могут быть вложенными.

Остаточная ветвь #

residual=True обходит одно вычислительное ядро слоя и требует p == g и одинаковых размеров вектора на входе и выходе. Residual(project=True) добавляет обучаемую локальную линейную проекцию без смещения; она позволяет менять обе размерности.

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

Методы и атрибуты ModularNet #

Обращение Назначение
net(x) Выполнить расчёт для входного тензора
net.n_inputs, net.n_outputs Узнать число входных и выходных контактов
net.positions Узнать число модулей каждого слоя
net.parameters() Получить параметры для оптимизатора
net.train(), net.eval() Выбрать режим обучения или применения
net.to(...), net.double() Изменить устройство или тип параметров
net.state_dict() Получить состояние модели
net.load_state_dict(state) Загрузить совместимое состояние
net.get_extra_state() Получить описание конфигурации

Состояние и расширение #

python
optimizer = torch.optim.SGD(net.parameters(), lr=0.01)
loss = net(torch.randn(2, 256, 32)).square().mean()
loss.backward()
optimizer.step()
torch.save(net.state_dict(), "weights.pt")
# Вновь создайте net с той же конфигурацией перед загрузкой.
net.load_state_dict(torch.load("weights.pt", map_location="cpu", weights_only=True))

state_dict сохраняет параметры и конфигурацию в _extra_state. Получить копию конфигурации можно также через net.get_extra_state(). В ней два раздела:

  • topology содержит тот же словарь JSON версии 1, что и save_topology. Конструктор получает Topology, поэтому сохраняется его текущее состояние с пустым именем и dual: false; исходные имя и флаг TopologySpec теряются при передаче только её поля topology.
  • layers содержит описание каждого слоя: kernel, shared, residual, in_size и out_size. Размеры приведены к фактическим: если out_size не задан, он равен in_size; скалярным контактам соответствуют None. Остаточная ветвь записана как none, identity или project. kernel содержит типы и текстовые описания построенных модулей для проверки весов.

Несовместимая конфигурация вызывает RuntimeError. Производные индексы не сохраняются: они восстанавливаются конструктором. to(...), double(), train() и eval() работают стандартным образом. Конфигурацию конструкции и код собственного ядра хранит вызывающая программа; словарь весов не создаёт модель автоматически.

Собственное описание наследует regnets.kernels.Kernel и реализует build(shape: KernelShape) -> nn.Module. shape содержит in_features, out_features, positions, shared, device и dtype. Результат работает с [...,positions,in_features] и возвращает [...,positions,out_features], сохраняя независимость позиций и пакета. Автор создаёт зарегистрированные параметры согласно shared до первого вычисления. Сеть проверяет форму результата; произвольный nn.Module не векторизуется автоматически.

Полные сигнатуры приведены ниже: ModularNet и Layer, Kernel и готовые ядра.

regnets.modular #

Справочник публичного API Regnets 0.3.1. Сигнатуры, поля и описания получены из исходников при сборке. Имена в <factory: …> обозначают фабрики значений dataclass.

Для импорта этого модуля нужен PyTorch.

ModularNet наследует torch.nn.Module. Вход — вещественный тензор с net.n_inputs контактами. Несовместимые формы и описания отклоняются с ValueError, конфигурация весов — с RuntimeError. Создание и настройка модели.

Residual #

Исходный код

python
Residual(project: bool = False)

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

Поля #

Имя Тип По умолчанию
project bool False

Layer #

Исходный код

python
Layer(kernel: Kernel = <factory: Dense>, shared: bool = True, residual: bool | Residual = False, *, in_size: int | None = None, out_size: int | None = None)

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

Параметры

  • kernel: Неизменяемое описание, по которому создаётся векторизованное ядро.
  • shared: Использовать общие параметры для позиций внутри слоя.
  • residual: Обойти слой, сохранив его порядок сгруппированных контактов.
  • in_size: Размер вектора входного контакта или None для скалярных контактов.
  • out_size: Размер вектора выходного контакта или размер входа, если не задан.

Поля #

Имя Тип По умолчанию
kernel Kernel <factory: Dense>
shared bool True
residual bool | Residual False
in_size (только по имени) int | None None
out_size (только по имени) int | None None

ModularNet #

Исходный код

python
ModularNet(topology: Topology, layers: Layer | Sequence[Layer], *, device: torch.device | str | None=None, dtype: torch.dtype | None=None)

Применить компактную топологию с упакованными ядрами и остаточными связями.

Остаточные связи необязательны.

Параметры

  • topology: Соединения, не зависящие от PyTorch.
  • layers: Одно описание, повторяемое с новыми параметрами, или n описаний. Размеры соседних контактов и скалярный или векторный режим должны совпадать.
  • device: Начальное устройство для параметров и индексов.
  • dtype: Начальный тип параметров.

ModularNet.p #

python
p: tuple[int, ...]

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

Исходный код

ModularNet.g #

python
g: tuple[int, ...]

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

Исходный код

ModularNet.get_extra_state #

python
get_extra_state() -> dict

Сохранить метаданные соединений и построения вместе с зарегистрированными параметрами.

Исходный код

ModularNet.set_extra_state #

python
set_extra_state(state: dict) -> None

Запретить загрузку весов при другой конфигурации соединений или ядер.

Исходный код

ModularNet.forward #

python
forward(x: Tensor) -> Tensor

Сохранить начальные размерности пакета и применить все n+1 перестановок.

Исходный код

ModularNet.extra_repr #

python
extra_repr() -> str

Вернуть текстовое описание размеров и режима сети.

Исходный код

regnets.kernels #

Справочник публичного API Regnets 0.3.1. Сигнатуры, поля и описания получены из исходников при сборке. Имена в <factory: …> обозначают фабрики значений dataclass.

Для импорта этого модуля нужен PyTorch.

Неизменяемые описания ядер создают модули через build(shape). Вход имеет форму [..., positions, in_features], выход — [..., positions, out_features]. shared определяет общность параметров внутри слоя. Композиция блоков и собственное ядро.

Kernel #

Исходный код

python
Kernel()

Описать операцию над [..., positions, features] с сохранением позиций.

Подклассы создают новые экземпляры nn.Module с параметрами согласно shape.shared. Они могут смешивать локальные признаки, но не элементы пакета и не позиции.

Kernel.output_features #

python
output_features(in_features: int, default: int) -> int

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

Исходный код

Kernel.build #

python
build(shape: KernelShape) -> nn.Module

Создать все регистрируемые параметры до создания оптимизатора.

Исходный код

KernelShape #

Исходный код

python
KernelShape(in_features: int, out_features: int, positions: int, shared: bool, device: torch.device | str | None = None, dtype: torch.dtype | None = None)

Размерности и правила работы с параметрами для метода build ядра.

Поля #

Имя Тип По умолчанию
in_features int Обязательно
out_features int Обязательно
positions int Обязательно
shared bool Обязательно
device torch.device | str | None None
dtype torch.dtype | None None

Dense #

Исходный код

python
Dense(out_features: int | None = None, bias: bool = True, activation: Activation = None)

Описать аффинное преобразование с необязательной выходной активацией.

Параметры

  • out_features: Явная локальная размерность или размерность выхода слоя.
  • bias: Добавить обучаемое смещение.
  • activation: Фабрика активации без состояния, например nn.SiLU.

Поля #

Имя Тип По умолчанию
out_features int | None None
bias bool True
activation Activation None

Dense.output_features #

python
output_features(in_features: int, default: int) -> int

Определить промежуточную ширину выхода при включении блока в Sequential.

Исходный код

Dense.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

MLP #

Исходный код

python
MLP(hidden: int | Sequence[int] = (64,), activation: Activation = nn.SiLU, output_activation: Activation = None, bias: bool = True)

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

Поля #

Имя Тип По умолчанию
hidden int | Sequence[int] (64,)
activation Activation nn.SiLU
output_activation Activation None
bias bool True

MLP.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

Sequential #

Исходный код

python
Sequential(*blocks: Kernel)

Объединить блоки; блоки без изменения размерности сохраняют прежнюю локальную размерность.

Поля #

Имя Тип По умолчанию
blocks tuple[Kernel, ...] Обязательно

Sequential.output_features #

python
output_features(in_features: int, default: int) -> int

Определить промежуточную ширину выхода при включении блока в Sequential.

Исходный код

Sequential.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

Identity #

Исходный код

python
Identity()

Сохранить локальные признаки без использования параметров.

Identity.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

Dropout #

Исходный код

python
Dropout(p: float = 0.1)

Исключать отдельные локальные признаки при обучении с независимыми масками.

Поля #

Имя Тип По умолчанию
p float 0.1

Dropout.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

LayerNorm #

Исходный код

python
LayerNorm(eps: float = 1e-05, affine: bool = True, bias: bool = True)

Нормализовать весь локальный вектор признаков, не смешивая позиции и элементы пакета.

Поля #

Имя Тип По умолчанию
eps float 1e-05
affine bool True
bias bool True

LayerNorm.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

RMSNorm #

Исходный код

python
RMSNorm(eps: float = 1e-06, affine: bool = True)

Нормализовать локальную среднеквадратичную величину с необязательным обучаемым масштабом.

Поля #

Имя Тип По умолчанию
eps float 1e-06
affine bool True

RMSNorm.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

GatedMLP #

Исходный код

python
GatedMLP(hidden: int = 64, activation: Activation = nn.SiLU, bias: bool = True)

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

Поля #

Имя Тип По умолчанию
hidden int 64
activation Activation nn.SiLU
bias bool True

GatedMLP.build #

python
build(shape: KernelShape) -> nn.Module

Создать новый модуль с зарегистрированными параметрами согласно KernelShape.

Исходный код

Исходники раздела: docs/modular-nn.md