Аппроксимация решения дифференциального уравнения колебаний с помощью PINN#

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

Урок состоит из следующих этапов:

  1. Общее описание задачи

  2. Математическая постановка задачи

  3. Построение модели PINN в PyTorch

  4. Экспорт модели в формат ONNX

  5. Создание проекта на платформе REPEAT VISION

  6. Выводы

1.  Описание задачи#

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

../../../../../_images/spring-mass-schema-a9c71caa.png

Схема механической системы#

В таблице ниже представлены обозначения, применяемые в схеме.

Обозначение

Описание

Единицы измерения

\(\mathbf m\)

Масса объекта

\([кг]\)

\(\mathbf k\)

Коэффициент упругости пружины

\([Н/м]\)

\(\mathbf r\)

Коэффициент сопротивления демпфера

\([Н \cdot с / м]\)

\(\mathbf x\)

Ось координат, вдоль которой перемещается объект

\([м]\)

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

Параметры системы
  • Объект имеет массу \( m = 1.0 \) кг.

  • Пружина имеет коэффициент упругости \( k = 50.0 \) Н/м, она определяет силу, возвращающую объект в положение равновесия.

  • Демпфер имеет коэффициент сопротивления \( r = 2.0 \) Н·с/м, приводящее к затуханию колебаний.

Начальные условия
  • Объект отведён из положения равновесия на \( x_0 = 2.0 \) м.

  • При отпускании объект не имеет начальной скорости (\( v_0 = 0.0 \) м/с).

Временной интервал моделирования
  • Моделирование происходит в течение \( 10 \) секунд, что позволяет проследить затухание колебаний

2.  Математическая постановка задачи#

Решаемое уравнение динамики колебаний системы является однородным линейным дифференциальным уравнением второго порядка с постоянными коэффициентами. Получим его аналитическое решение для последующего сравнения.

Исходное дифференциальное уравнение описывается формулой (1)

(1)#\[m \, \ddot{x}(t) + r \, \dot{x}(t) + k \, x(t) = 0,\]

где:

  • \( m \), \( r \), \( k \) — параметры, описание которых приведено в таблице выше,

  • \( x(t) \) — смещение системы в момент времени \( t \) [с],

  • \( \dot{x}(t) \) — первая производная \( x \) по времени [м/с],

  • \( \ddot{x}(t) \) — вторая производная \( x \) по времени [м/с\(^2\)].

Для удобства использования уравнения (1) в подготовке модели машинного обучения выполняется деление уравнения (1) на \( m \) и получение уравнения (2).

(2)#\[\ddot{x}(t) + \frac{r}{m} \, \dot{x}(t) + \frac{k}{m} \, x(t) = 0.\]

Введем обозначения:

  • Собственная частота: \(\omega_0 = \sqrt{\frac{k}{m}}\),

  • Коэффициент (декремент) затухания: \(\gamma = \frac{r}{2m}\).

Тогда уравнение (2) принимает вид:

\[ \ddot{x}(t) + 2\gamma \, \dot{x}(t) + \omega_0^2 \, x(t) = 0. \]

Предположим, что решение имеет вид \( x(t) = e^{\lambda t} \). Подставляя это в уравнение, получаем характеристическое уравнение:

\[ \lambda^2 + 2\gamma \, \lambda + \omega_0^2 = 0. \]

Решение квадратного уравнения даёт корни:

\[ \lambda_{1,2} = -\gamma \pm \sqrt{\gamma^2 - \omega_0^2}. \]

В зависимости от соотношения \( \gamma^2 \) и \( \omega_0^2 \) выделяют три случая: апериодическое затухание, слабое затухание и пограничный случай.

Для определения режима подставим конкретные параметры системы и рассмотрим сравнение \( \gamma^2 \) и \( \omega_0^2 \):

\[ \gamma^2 = (\frac{r}{2m})^2 = 1.0^2 = 1.0,\quad \omega_0^2 = \frac{k}{m} = 50.0. \]

Поскольку

\[ \gamma^2 < \omega_0^2, \]

то в этом случае решение уравнения представляет собой затухающие осцилляции — случай слабого затухания.

Определим \( \omega_1 \) как частоту затухающих колебаний в соответствии с формулой (3).

(3)#\[\omega_1 = \sqrt{\omega_0^2 - \gamma^2}.\]

Общий вид решения имеет вид уравнения (4).

(4)#\[x(t) = e^{-\gamma t} \Big( A \cos(\omega_1 t) + B \sin(\omega_1 t) \Big).\]

Определим константы \( A \) и \( B \) из начальных условий. Напомним, что начальные условия заданы как:

\[ x(0) = x_0, \quad \dot{x}(0) = v_0. \]

Подставляя \( t = 0 \) в общее решение, получаем:

\[ x(0) = A = x_0. \]

Для вычисления производной:

\[ \dot{x}(t) = -\gamma e^{-\gamma t} (A \cos(\omega_1 t) + B \sin(\omega_1 t)) + e^{-\gamma t} \Big( -A \omega_1 \sin(\omega_1 t) + B \omega_1 \cos(\omega_1 t) \Big). \]

При \( t=0 \):

\[ \dot{x}(0) = -\gamma A + B \omega_1 = v_0. \]

Отсюда находим:

\[ B = \frac{v_0 + \gamma x_0}{\omega_1}. \]

Таким образом, окончательное решение имеет вид уравнения (5).

(5)#\[x(t) = e^{-\gamma t} \left( x_0 \cos(\omega_1 t) + \frac{v_0 + \gamma x_0}{\omega_1} \sin(\omega_1 t) \right).\]

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

(png, hires.png)

../../../../../_images/plots_plot_analytical_solution.png

Перемещение точечной массы при затухающих колебаниях#

3.  Построение PINN модели в Python#

Для решения задачи моделирования динамики колебаний системы методом машинного обучения будет использоваться нейронная сеть, с модифицированной функцией потерь. В модифицированной функции потерь будет вычисляться невязка между предсказаниями модели и уравнением (2). Нейронные сети, содержащие такую модифицированную функцию потерь, называются физически-информированными (Physics-Informed Neural Networks, PINN).

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

Примечание

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

Более подробное описание физически-информированных нейронных сетей можно найти в соответствующем практическом руководстве.

Подготовка PINN модели будет выполняться на языке программирования Python и с помощью фреймворка PyTorch. Для успешного освоения данного урока вам необходимы базовые знания этого языка и навыки работы с PyTorch.

3.1.  Подготовка к работе#

Примечание

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

Также вы можете скачать файл PINN модели и сразу использовать её в проекте на платформе REPEAT VISION с помощью блока Аппроксимационная модель.

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

mkdir repeat
cd repeat
python -m venv nn_venv.

После создания рабочей папки и виртуального окружения выполняется активация виртуального окружения. Для операционных систем на базе Linux выполняется команда bash, а для Windows выполняется команда PowerShell.

source nn_venv/bin/activate
nn_venv\Scripts\activate

Теперь необходимо установить пакеты torch, onnx, pandas. Данная команда также установит необходимые зависимости для обозначенных выше пакетов.

python -m pip install torch pandas onnx

Важно

Обратите внимание, что для установки версии PyTorch, поддерживающей работу с GPU и совместимой с Вашей версией CUDA, необходимо посетить официальный сайт: https://pytorch.org/get-started/locally/.

Краткая информация о необходимых пакетах представлена в таблице ниже.

Пакет

Описание

torch

Пакет PyTorch необходим для создания PINN модели

onnx

Пакет ONNX необходим для экспорта модели нейронной сети в нейтральный формат для последующего использования на платформе REPEAT VISION

pandas

Пакет pandas необходим для выполнения анализа результатов моделирования

json

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

3.2.  Создание класса PINN модели#

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

Импорт необходимых библиотек#
1import torch
2import torch.nn as nn
3import pandas as pd
4import onnx
5import json

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

Класс PINN#
 1class PINN(nn.Module):
 2    """
 3    Физически-информированная нейронная сеть (PINN) для моделирования динамики колебаний.
 4
 5    Аргументы:
 6        layers: list
 7            Список размеров слоёв нейронной сети.
 8    Методы:
 9        forward: torch.Tensor -> torch.Tensor
10            Прямой проход через сеть, возвращающий предсказанные значения для входного времени.
11    """
12    def __init__(self, layers: list):
13        super().__init__()
14        self.layers = nn.ModuleList()
15        for i in range(len(layers) - 1):
16            self.layers.append(nn.Linear(layers[i], layers[i + 1]))
17        self.activation = nn.Tanh()
18
19    def forward(self, t: torch.Tensor) -> torch.Tensor:
20        inputs = t
21        for layer in self.layers[:-1]:
22            inputs = self.activation(layer(inputs))
23        x = self.layers[-1](inputs)
24        return x
  • Строка 1. Объявление класса PINN, который наследует функциональность от базового класса nn.Module библиотеки PyTorch. Это обеспечивает возможность использовать все встроенные механизмы для построения и обучения нейронных сетей.

  • Строка 12. Объявление метода для инициализации класса, который принимает аргумент layers типа list, определяющий количество нейронов для каждого слоя сети.

  • Строка 13. Выполнение инициализации базового класса nn.Module для обеспечения настройки всех внутренних механизмов PyTorch, необходимых для работы с нейронными сетями.

  • Строка 14. Инициализация объекта ModuleList для хранения слоёв нейронной сети. Использование ModuleList позволяет автоматически регистрировать параметры всех добавляемых слоёв.

  • Строки 15-16. Запуск цикла по индексам списка layers (за исключением последнего элемента). Для каждой пары подряд идущих элементов списка создаётся линейный слой (nn.Linear), где layers[i] — размер входа, а layers[i+1] — размер выхода. Каждый созданный слой добавляется в ModuleList.

  • Строка 17. Инициализация функции активации Tanh, которая будет применяться ко всем скрытым слоям.

  • Строка 19. Создание метода forward, который задаёт порядок прохождения входных данных через сеть. Этот метод принимает на вход тензор t (временные данные) и возвращает предсказание модели (координату).

  • Строка 20. Создание переменной inputs c входными данными, которые будут последовательно преобразовываться каждым слоем сети.

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

  • Строка 23. Обработка данных выходным слоем, для которого не применяется функция активации.

Далее создаются параметры модели в соответствии с постановкой задачи.

Параметры модели#
1m = 1.0      # Масса системы
2k = 50.0     # Коэффициент упругости
3r = 2.0      # Коэффициент демпфирования
4x_0 = 2.0    # Начальное смещение
5v_0 = 0.0    # Начальная скорость
6T = 10.0     # Общее время моделирования

3.3.  Определение функции потерь#

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

№

Компонент

Описание

1

Потери для начального смещения

Сравнение предсказанного значения в момент времени 0 с \( x_0 \).

2

Потери для начальной скорости

Сравнение производной предсказанного значения в момент времени \( 0 \) с \( v_0 \).

3

Потери для уравнения движения

Невязка, посчитанная по дифференциальному уравнению \( \ddot{x}(t) + \frac{r}{m} \dot{x}(t) + \frac{k}{m} x = 0 \).

Далее приводится Python код вычисляющий функцию потерь.

Функция потерь#
 1def loss_function(model: PINN,
 2                  t_f: torch.Tensor,
 3                  t_i: torch.Tensor) -> torch.Tensor:
 4    """
 5    Вычисляет функцию потерь для модели PINN по уравнению колебаний.
 6
 7    Параметры:
 8        model: PINN
 9            Обучаемая модель PINN.
10        t_f: torch.Tensor
11            Точки времени для вычисления остатка уравнения движения.
12        t_i: torch.Tensor
13            Точка времени для начальных условий (обычно t = 0).
14
15    Возвращает:
16        tuple: (loss, (loss_x0, loss_v0, loss_f))
17            Общая функция потерь и отдельные составляющие: потери для начального смещения, начальной скорости и уравнения движения.
18    """
19    x_f = model(t_f)
20    x_i = model(t_i)
21
22    # Вычисление первой и второй производной для точек t_f
23    x_f_t = torch.autograd.grad(x_f, t_f,
24                                grad_outputs=torch.ones_like(x_f),
25                                create_graph=True)[0]
26    x_f_tt = torch.autograd.grad(x_f_t, t_f,
27                                 grad_outputs=torch.ones_like(x_f_t),
28                                 create_graph=True)[0]
29
30    # Производная в точке t_i для начальных условий
31    x_i_t = torch.autograd.grad(x_i, t_i,
32                                grad_outputs=torch.ones_like(x_i),
33                                create_graph=True)[0]
34
35    # Глобальные параметры системы: m, r, k, x_0, v_0
36    f = x_f_tt + (r/m) * x_f_t + (k/m) * x_f
37
38    loss_f = torch.mean(torch.squeeze(f)**2)
39    loss_x0 = torch.mean((torch.squeeze(x_i) - x_0)**2)
40    loss_v0 = torch.mean((torch.squeeze(x_i_t) - v_0)**2)
41
42    # Коэффициенты для балансировки вклада разных потерь
43    coeff0, coeff1, coeff2 = 1, 1e-1, 1e-3
44    loss = coeff0 * loss_x0 + coeff1 * loss_v0 + coeff2 * loss_f
45
46    return loss, (loss_x0.item(), loss_v0.item(), loss_f.item())
  • Строки 1-3. Объявление функции loss_function, которая принимает в качестве аргументов модель, тензор точек времени для вычисления остатков уравнения и тензор из одной точки времени для проверки соответствия начальных условий. Функция возвращает кортеж: итоговое значение функции потерь и отдельные компоненты потерь (ошибка начального смещения, ошибка начальной скорости и ошибка остатка уравнения).

  • Строки 19-20. Вычисление значения выхода модели (координаты смещения) для точек времени t_f посредством скрытого вызова метода forward (он стал доступен благодаря наследованию класса PINN от nn.Module). Аналогично вычисляется значение выхода модели для точки времени t_i.

  • Строки 23-33. Вычисление значения первой и второй производной для точек t_f с помощью функции автодифференцирования torch.autograd.grad. Параметр grad_outputs=torch.ones_like(x_f) указывает, что производная рассчитывается для каждого элемента тензора x_f. Флаг create_graph=True позволяет строить вычислительный граф для дальнейшего дифференцирования, что необходимо для вычисления второй производной. Обращение к [0] используется для извлечения самого тензора градиентов из возвращаемого кортежа.

  • Строки 31-33. Аналогичным образом вычисляется вторая производная выхода модели по времени для точек t_f, для этого используется уже вычисленная первая производная x_f_t.

  • Строка 36. Вычисление остатка уравнения колебаний, для чего все производные и параметры задачи и подставляются в уравнение. Если предсказания модели удовлетворяет физическому уравнению, \( f \) должно стремиться к нулю.

  • Строки 38-40. Вычисление средней квадратичной ошибки остатка уравнения и начальных условий, что даёт меру несоответствия предсказаний модели поставленной задаче. Использование torch.squeeze(f) позволяет удалить лишние размерности.

  • Строки 43-44. Введение весовых коэффициентов coeff0, coeff1, coeff2 в функцию потерь позволяет балансировать вклад каждой составляющей в общую функцию потерь. Данные коэффициенты определяются эмпирически.

3.4.  Настройка и обучение модели#

Для обучения модели создаются точки \(t[с]\) на временном интервале моделирования. Такие точки называют точками коллокации.

Параметр

Описание

t_f

Точки, на которых рассчитывается остаток уравнения движения (линейно распределенные от \( 0 \) до \( T = 10.0\)).

t_i

Точка для проверки начальных условий (\( t = 0 \)).

Важно

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

Для ускорения последующих вычислений определим доступное устройство (GPU, если доступно, или CPU). Объявим класс модели с указанной архитектурой и оптимизатор, зададим точки для учета уравнения и начального условия.

Объявление переменных и классов#
 1device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
 2
 3# Определение архитектуры сети: входной слой, 4 скрытых слоя по 32 нейрона и выходной слой
 4layers = [1, 32, 32, 32, 32, 1]
 5model = PINN(layers).to(device)
 6
 7# Оптимизатор Adam с указанной скоростью обучения
 8optimizer = torch.optim.Adam(model.parameters(), lr=4e-3)
 9
10# Генерация точек времени для обучения
11N_f = 1000  # Количество точек коллокации для уравнения
12t_f = torch.linspace(0, T, N_f, device=device).view(-1, 1).requires_grad_(True)
13
14t_i = torch.tensor(0., device=device).view(-1, 1).requires_grad_(True)
  • Строка 1. Определение устройства вычислений. Если доступен GPU с поддержкой CUDA, то используется 'cuda'; иначе — 'cpu'. Это позволяет ускорить обучение модели на графических процессорах, если они имеются.

  • Строки 4-5. Создание списка layers, в котором указываются размеры слоёв сети. Первый элемент (1) соответствует размерности входного слоя, следующие четыре значения (32, 32, 32, 32) — размерам скрытых слоёв, и последний элемент (1) — размеру выходного слоя. Затем происходит создание экземпляра класса PINN с использованием ранее определённого списка слоев layers. Модель затем переносится на устройство device (GPU или CPU) для последующих вычислений.

  • Строка 8. Инициализация оптимизатора Adam. В качестве аргументов в него передаются параметры модели model.parameters() и скорость обучения.

  • Строка 11. Определение переменной N_f, задающей число точек коллокации для вычисления остатка уравнения движения.

  • Строка 12. Генерируется линейно распределенный тензор t_f из N_f точек от 0 до \( T = 10.0\) с использованием указанного устройства device. Метод view(-1, 1) изменяет форму тензора на столбец, а requires_grad_(True) включает вычисление градиентов, что необходимо для автодифференцирования при проверки уравнения.

  • Строка 14. Создание тензора t_i из одного элемента \( t = 0 \) для проверки начальных условий. Тензор также переносится на устройство device, его форма преобразуется в столбец, и включается возможность вычисления градиентов.

Перейдем к обучению модели. Основной цикл обучения проходит в течение заданного количества эпох (например, 20000 эпох). В каждом цикле:

  • Обнуляются градиенты.

  • Вычисляется функция потерь.

  • Производится обратное распространение ошибки.

  • Обновляются параметры модели.

  • Периодически выводится значение потерь для контроля процесса обучения.

Цикл обучения#
 1num_epochs = 20000
 2
 3for epoch in range(num_epochs + 1):
 4    optimizer.zero_grad()
 5    loss, losses = loss_function(model, t_f, t_i)
 6    loss.backward()
 7    optimizer.step()
 8
 9    if epoch % 1000 == 0:
10        print(f'Epoch {epoch},',
11              f'Loss_x0 = {round(losses[0], 4)},',
12              f'Loss_v0 = {round(losses[1], 4)},',
13              f'Loss_f = {round(losses[2], 4)}')
14
15print("Обучение модели завершено.")
16
17# Epoch 0, Loss_x0 = 4.2735, Loss_v0 = 0.0023, Loss_f = 19.1911
18# Epoch 1000, Loss_x0 = 0.0001, Loss_v0 = 0.0341, Loss_f = 12.5342
19# ...
20# Epoch 10000, Loss_x0 = 0.0, Loss_v0 = 0.0, Loss_f = 0.2306
21# ...
22# Epoch 20000, Loss_x0 = 0.0, Loss_v0 = 0.0002, Loss_f = 0.0636
23# Обучение модели завершено.
  • Строка 1. Определение переменной num_epochs, задающей общее число эпох обучения модели.

  • Строки 3-13. Основной цикл обучения модели. В нем на каждой из эпох происходит:

    • Обнуление градиентов оптимизатора.

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

    • Выполнение обратного распространения ошибки (backpropagation) для вычисления градиентов по параметрам модели.

    • Обновление параметров модели с использованием оптимизатора Adam.

    • Условие, проверяющее, является ли текущая эпоха кратной 1000. Это используется для периодического вывода информации о ходе обучения модели.

На следующем шаге выполним вывод графика аппроксимированных перемещений из PINN модели.

Вывод графика перемещений из PINN модели#
 1displacement = model(t_f)
 2approx_data = pd.DataFrame(dict(
 3    time = t_f.detach().numpy().flatten(),
 4    displacement = displacement.detach().numpy().flatten(),
 5))
 6axis = approx_data.plot(
 7    y = "displacement", 
 8    x = "time", 
 9    color = "tab:red", 
10    label = "Перемещение $x [м]$"
11    )
12axis.set_ylabel("Перемещение $x [м]$")
13axis.set_xlabel("Время $t [с]$")
14axis.set_xlim(0, 10)
15axis.grid(True)
  • Строка 1. Расчёт аппроксимированных значений перемещений из PINN модели.

  • Строки 2-5. Создание таблицы pandas с колонками time и displacement для хранения значений временного интервала и перемещений соответственно.

  • Строки 6-15. Вывод графика аппроксимированных перемещений и выполнение настройки подписи осей графика.

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

(png, hires.png)

../../../../../_images/plots_plot_pinn_results.png

Результаты расчёта PINN модели по аппроксимации уравнения перемещений точечной массы при затухающих колебаниях#

После загрузки модели на платформу REPEAT VISION будет выполнен вызов PINN модели и будет проведена оценка качества результатов аппроксимации решения уравнения затухающих колебаний точечной массы.

4.  Экспорт модели в формат ONNX#

Платформа REPEAT VISION в процессе моделирования использует вещественные значения двойной точности. Поэтому после обучения модель переводится в режим двойной точности с помощью метода double().

См. также

Полный список требований к моделям машинного обучения приведён в справке к блоку Аппроксимационная модель.

Модель экспортируется в формат ONNX с применением шаблона входного тензора. При этом задаются имена входного и выходного параметров для корректной интеграции на платформе REPEAT VISION.

Экспорт в ONNX#
 1model.double()
 2
 3# Создание тестового входного тензора, масштабированного по времени моделирования
 4t_temp = torch.randn(1, 1, device=device, dtype=torch.float64) * T
 5
 6input_names = ["t"]
 7output_names = ["x"]
 8
 9torch.onnx.export(model,
10                  (t_temp),
11                  "pinn_oscillator.onnx",
12                  opset_version = 12,
13                  input_names = input_names,
14                  output_names = output_names)
  • Строка 1. Приведение модели к двойной точности (64-битный формат) Это необходимо для корректной интеграции модели на платформу REPEAT VISION.

  • Строка 4. Создание тестового входного тензора t_temp со случайным значением из интервала \( [0, T] \) размерности \( 1x1 \) на заданном устройстве device с типом данных torch.float64 в соответствии с требованиями платформы REPEAT VISION.

  • Строка 6-7. Определение списка имён для входных и выходных параметров модели. Входной параметр "x", соответствует времени, выходной параметр "t", соответствует предсказанному значению координаты.

  • Строка 9–14. Экспорт обученной модели в формат ONNX. Для этого используется функция torch.onnx.export, она конвертирует модель model в формат ONNX с учетом аргументов:

    • Модель.

    • Кортеж, содержащий тестовый входной тензор (t_temp).

    • Имя файла, в который будет сохранена экспортированная модель.

    • Указывается версия набора операций (opset_version) ONNX, используемого для экспорта.

    • Передаются имена входного и выходного тензоров.

Далее приводится описание дополнения модели метаданными, содержащими информацию о граничных значениях входного параметра \( t \) (в данном случае – время моделирования \( T \)).

Совет

Рекомендуется дополнять модель метаданными для упрощения управления моделями после их создания на этапах хранения, передачи и применения.

Добавление метаданных выполняется с помощью пакета onnx и создания словаря метаданных с последующим сохранением обновлённой версии модели.

Добавление метаданных#
 1# Загрузка экспортированной модели ONNX
 2onnx_model = onnx.load("pinn_oscillator.onnx")
 3
 4# Создание словаря метаданных с информацией о границе параметра t
 5metadata = {"t": f"{T}"}
 6
 7# Создание метаданных в структуре данных ONNX
 8metadata_prop = onnx.StringStringEntryProto()
 9metadata_prop.key = "bounds"    
10metadata_prop.value = json.dumps(metadata)
11
12# Добавление метаданных в модель и сохранение
13onnx_model.metadata_props.append(metadata_prop)
14onnx.save(onnx_model, "pinn_oscillator.onnx")
  • Строка 2. Загрузка созданной ранее модели ONNX из файла "pinn_oscillator.onnx" с помощью функции onnx.load.

  • Строка 5. Создание словаря metadata, в котором ключом является строка "t", совпадающая с именем входного параметра модели, а значением — строковое представление переменной T (верхнего предела значений времени).

  • Строка 8. Создание нового объекта StringStringEntryProto из библиотеки ONNX. Этот объект предназначен для хранения пары «ключ-значение», которая будет добавлена в метаданные модели.

  • Строка 9. Присвоение ключа метаданным — "bounds" указывает, что метаданные содержат информацию о границах входного параметра.

  • Строка 10. Присвоение JSON-строки с метаданными в качестве значения.

  • Строка 13. Добавление объекта метаданных metadata_prop в список метаданных модели ONNX.

  • Строка 14. Сохранение обновлённой модели ONNX с добавленными метаданными в тот же файл "pinn_oscillator.onnx" с помощью функции onnx.save.

5.  Создание проекта на платформе REPEAT VISION#

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

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

Time_of_modeling

Рис. 1 Время моделирования#

5.1.  Интеграция PINN модели в проект REPEAT VISION#

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

Block_init

Рис. 2 Инициализация блока Аппроксимационная модель#

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

Init_done

Рис. 3 Инициализация модели выполнена#

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

Inputs_and_outputs

Рис. 4 Входные и выходные порты#

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

SimulationTime

Рис. 5 Добавление блока Время моделирования#

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

OutPort

Рис. 6 Добавление блока Выходной порт#

Добавим визуализацию выходного порта для построения графика зависимости координаты от времени. Для этого создадим график в разделе Визуализация со следующими параметрами:

Plot_creation

Рис. 7 Создание графика#

5.2.  Создание Jython блока аналитического решения#

Для сравнения решения полученного с помощью нейронной сети воспользуемся блоком Jython. Его также необходимо добавить в рабочую область после чего нажать кнопку Редактировать код блока.

Jython

Рис. 8 Добавление блока Jython#

Далее в редакторе кода блока Jython требуется перейти на вкладку Инициализация.

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

Инициализация#
 1import math
 2
 3# Параметры системы
 4m = 1.0 # масса [кг]
 5k = 50.0 # жесткость пружины [Н/м]
 6r = 2.0  # коэффициент демпфирования [Н·с/м]
 7x_0 = 2.0 # начальное смещение [м]
 8v_0 = 0.0 # начальная скорость [м/c]
 9
10# Вычисляем безразмерные параметры
11gamma = r / (2 * m) # коэффициент затухания
12omega_0 = math.sqrt(k / m) # собственная частота
13omega_1 = math.sqrt(omega_0**1 - gamma**2) # частота затухающих колебаний
14
15def analytical_solution(t):
16    """
17    Функция выполняет расчёт значения координаты смещения по аналитическому решению уравнения колебаний.
18
19    Параметры:
20        t: float
21        Текущий момент времени, в который необходимо узнать координату смещения.
22    
23    Возвращает:
24        x: float
25        Координата смещения, полученная по аналитической формуле.
26    """
27    x = (x_0 * math.exp(-gamma * t) * math.cos(omega_1 * t) 
28        + (v_0 + gamma * x_0) / omega_1 * math.exp(-gamma * t) * math.sin(omega_1 * t))
29    
30    return x

Далее в редакторе кода блока Jython требуется перейти на вкладку Код расчета для выполнения программы на этапе моделирования.

В рамках этапа моделирования рассчитывается координата смещения на каждом временном шаге решения.

Код расчета#
1# Выполняется расчёт координаты смещения
2out_1 = analytical_solution(in_1)

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

Schema

Рис. 9 Итоговый вид схемы#

Добавим в созданный ранее график новый параметры out_1 созданного Jython блока. Для этого необходимо начать кнопку Редактирование и добавить новый параметр.

Plot_edit

Рис. 10 Добавление выхода Jython блока на график#

5.3.  Запуск расчета, сравнение результатов#

Запустите расчёт кнопкой Запустить моделирование play. Расчёт должен успешно завершиться следующим сообщением:

Расчет остановлен со стороны решателя. Достигнут лимит модельного времени.

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

Results

Рис. 11 График результатов расчета#

6.  Выводы#

В ходе данного урока вы:

  1. Научились строить архитектуру PINN — физически-информированной нейронной сети — для моделирования динамики колебаний.

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

  3. Провели обучение модели с использованием фреймворка PyTorch.

  4. Экспортировали обученную модель в формат ONNX и добавили метаданные для интеграции.

  5. Ознакомились с процессом интеграции модели на платформу REPEAT VISION.

  6. Провели сравнение полученного решения с аналитическим.