Модель машинного обучения максимальных напряжений в отводе газопровода-шлейфа, возникающих при эрозионном износе#

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

В процессе чтения руководства вы узнаете:

  1. Где и зачем нужен газопровод-шлейф?

  2. Цель и задачи моделирования процесса эксплуатации газопроводов-шлейфов;

  3. Основные шаги создания модели машинного обучения (ML модель) с помощью Python для оценки процесса эрозии;

  4. Как использовать ML модель с газодинамической моделью газопровода-шлейфа на платформе REPEAT VISION.

1.  Общая информация о газопроводах-шлейфах#

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

../../../_images/gas_pipeline_with_annotations.png

Газопровод-шлейф на кусте двух газовых скважин.#

Газопровод-шлейф (№1 на рисунке выше) в процессе эксплуатации подвержен следующим воздействиям:

  1. Внутренняя поверхность газопровода нагружена давлением и температурой газа;

  2. Наружная поверхность газопровода нагружена переменной температурой внешней среды.

1.1.  Проблема эрозионного износа газопровода-шлейфа#

Процесс эксплуатации газовой скважины (№2 на рисунке выше) может сопровождаться выносом воды, содержащей механические примеси, что вызывает эрозионный износ внутренней поверхности газопровода-шлейфа.

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

Также эрозионный износ может носить циклический характер с периодическим выносом воды и механических примесей.

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

Наиболее уязвимым элементом газопровода-шлейфа является первый отвод, если считать от фонтанной арматуры газовой скважины (№2 на рисунке выше).

1.2.  Способы снижения риска#

Для снижения риска инцидентов и аварий вследствие эрозионного износа газопровода-шлейфа требуется решение комплексной задачи, включающей:

  1. Применение физико-математического моделирования процесса эксплуатации трубопроводной системы и его системы управления;

  2. Применение автоматизированных средств диагностики технического состояния элементов газопровода;

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

2.  Средства диагностики технического состояния газопроводов-шлейфов#

Автоматизированные средства диагностики технического состояния элементов газопровода-шлейфа, необходимые для контроля эрозионного процесса включают следующие системы:

  1. Системы контроля расхода;

  2. Датчики температуры внешней среды и системы контроля давления и температуры газа;

  3. Интрузивные датчики измерения эрозии и акустические системы контроля песка;

  4. Системы точечной и распределённой толщинометрии.

3.  Цель и задачи моделирования процесса эксплуатации газопроводов-шлейфов#

Цель. Повышение производственной эффективности компании и предупреждение аварий промысловых объектов.

Задачи моделирования:

  1. Расчёт параметров прочности на основании актуальных данных диагностики технического состояния газопроводов-шлейфов;

  2. Расчёт параметров системы сбора на соответствие техническому проекту разработки месторождения;

  3. Обеспечение максимальной добычи газа в пиковый сезонный период (зима, спрос) и минимальной добычи (лето);

  4. Обеспечение оптимальных параметров работы системы сбора при незапланированном отключении скважин или при режимах работы скважин, не соответствующих проектным;

  5. Определение параметров системы сбора при изменении входных параметров системы подготовки газа и конденсата.

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

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

Выполнить оценку напряжённо-деформированного состояния (НДС) отвода на основании исходных данных и граничных условий.

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

  1. Исходные данные и граничные условия:

    1. Минимальная толщина стенки,

    2. Давление газа,

    3. Температура газа,

    4. Температура окружающей среды,

  2. Результат расчёта НДС: Максимальные напряжения по Мизесу.

Расчётные случаи основаны на технологическом регламенте конкретного месторождения:

  1. Давление газа изменяется в диапазоне: от 8.5 до 6.0 \([МПа]\),

  2. Температура газа изменяется в диапазоне: от 7 до 20 \([^{\circ}C]\),

  3. Температура окружающей среды изменяется в диапазоне: от -55 до 40 \([^{\circ}C]\),

  4. Расчётные случаи включают минимальные толщины стенки отвода от 6.45 до 4.9 \([мм]\).

Результатом расчёта статической прочности одного из расчётных случаев является распределение напряжений по Мизесу, приведённое на рисунке ниже.

../../../_images/stress_results.ru.png

Пример распределений напряжений по Мизесу в отводе.#

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

5.  Подготовка таблицы расчётных случаев#

Расчёт статической прочности отвода выполняется в программном комплексе, реализующего метод конечных элементов (МКЭ).

5.1.  Модель статической прочности#

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

Линейные участки трубопроводов газопровода-шлейфа и опорные конструкции моделировались в балочном приближении.

Отводы и тройниковые соединения моделировались с помощью объёмных КЭ.

5.2.  Основные этапы подготовки данных#

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

Подсказка

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

Основные этапы процесса параметрических исследований приведены на рисунке ниже.

../../../_images/param_study_proc.ru.png

Процесс подготовки данных на основе моделирования статической прочности отвода.#

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

6.  Построение модели нейронной сети#

Примечание

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

Дополнительно вам понадобятся данные для обучения модели и (не обязательно) данные для визуализации одного результата расчёта.

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

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

Важно

Обратите внимание, что для установки версии PyTorch, поддерживающей работу с GPU и совместимой с Вашей версией CUDA, необходимо посетить официальный сайт.

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

  • NumPy и Pandas — работа с массивами, линейная алгебра и обработка табличных данных соответственно.

  • Matplotlib, Seaborn — визуализация статических графиков для отслеживания качества работы модели.

  • Plotly — интерактивные графики, для наглядного представления объекта исследования.

  • scikit-learn — подсчет метрик и разбиение данных.

Перед началом подготовки ML модели необходимо установить Python, а также требуется установить пакеты для работы с данными и создания ML модели. Для этого необходимо выполнить в командной строке вашего компьютера следующие команды и продолжить работу в Jupyter ноутбуке.

mkdir ml_branch_stress
cd ml_branch_stress
python -m venv repeat_ml.
source repeat_ml/bin/activate
python -m pip install numpy pandas scikit-learn onnx onnxscript 
python -m pip install seaborn matplotlib plotly 
python -m pip install jupyterlab tqdm ipywidgets netron
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu

jupyter lab
mkdir ml_branch_stress
cd ml_branch_stress
python -m venv repeat_ml.
repeat_ml\Scripts\Activate.ps1
python -m pip install numpy pandas scikit-learn onnx onnxscript 
python -m pip install seaborn matplotlib plotly 
python -m pip install jupyterlab tqdm ipywidgets netron
python -m pip install torch --index-url https://download.pytorch.org/whl/cpu

jupyter lab

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

Импорт библиотек#
 1import numpy as np
 2import pandas as pd
 3
 4import seaborn as sns
 5import matplotlib.pyplot as plt
 6import plotly.graph_objects as go
 7
 8import torch
 9import torch.nn as nn
10import torch.optim as optim
11from torch.utils.data import Dataset, DataLoader
12
13from sklearn.model_selection import train_test_split
14from sklearn.metrics import (mean_squared_error, 
15                             mean_absolute_error,
16                             mean_absolute_percentage_error,
17                             r2_score)
18
19from tqdm.notebook import tqdm
20from typing import Tuple, List, Dict, Union

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

Воспроизводимость и устройство#
1SEED = 42
2torch.manual_seed(SEED)
3np.random.seed(SEED)
4
5device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
6print(device)

6.1.  Исследование данных#

Для наглядного отображения распределения напряжений в отводе визуализируем трехмерное распределение точек используя интерактивную 3D-визуализация с помощью Plotly.

Визуализация напряжений#
 1def branch_plot(df: pd.DataFrame) -> go.Figure:
 2    """
 3    Создает 3D визуализацию распределения напряжений.
 4    
 5    Параметры:
 6        df: pd.DataFrame
 7            DataFrame с данными о координатах и напряжениях
 8    Возвращает:
 9        go.Figure: Объект графика Plotly
10    """
11    marker_config = dict(
12        size=3,
13        color=df['Stress'],
14        colorscale='Jet',
15        opacity=0.8,
16        colorbar=dict(title="Напряжение (МПа)")
17    )
18    hover_template = (
19        '<b>Узел</b>: %{customdata}<br>'
20        '<b>X</b>: %{x:.2f} мм<br>'
21        '<b>Y</b>: %{y:.2f} мм<br>'
22        '<b>Z</b>: %{z:.2f} мм<br>'
23        '<b>Напряжение</b>: %{marker.color:.2f} МПа'
24    )
25    fig = go.Figure(
26        data=[
27            go.Scatter3d(
28                x=df['X'],
29                y=df['Y'],
30                z=df['Z'],
31                mode='markers',
32                marker=marker_config,
33                hovertemplate=hover_template,
34                customdata=df['Node']
35            )
36        ]
37    )
38    scene_config = dict(
39        xaxis_title='X (мм)',
40        yaxis_title='Y (мм)',
41        zaxis_title='Z (мм)',
42        aspectmode='data',
43        camera=dict(
44            eye=dict(x=0, y=0, z=2.5),
45            center=dict(x=0, y=0, z=0),
46            up=dict(x=0, y=1, z=0)
47        )
48    )
49    margin_config = dict(l=0, r=0, b=0, t=30)
50    fig.update_layout(
51        title='Распределение напряжений',
52        scene=scene_config,
53        margin=margin_config
54    )
55
56    return fig

В результате, для произвольно выбранного файла с результатами численного эксперимента, будет построен набор точек, цвет которых будет отображать величину напряжения, а в качестве осей будут использованы привычные \( X, Y, Z \). Проведем построение визуализации выполнением следующего кода:

Построение визуализации напряжений#
1df = pd.read_csv('stress_branch.csv')
2fig = branch_plot(df)
3fig.show()
Stress_distribution

Распределение напряжений в отводе.#

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

Итогова таблица для постановки задачи регрессии имеет следующие параметры:

  • Входные параметры (признаки):

    • Давление (pressure), меняется в диапазоне: 6.0 - 8.5 \([МПа]\).

    • Температура газа (gas_temperature), меняется в диапазоне: 7.0 - 20.0 \([^{\circ}C]\).

    • Температура окружающей среды (ambient_temperature), меняется в диапазоне: -55.0 - 40.0 \([^{\circ}C]\).

    • Минимальная толщина стенки (wall_thickness_min), меняется в диапазоне: 4.90 - 6.45 \([мм]\).

  • Целевая переменная:

    • Максимальное напряжение по Мизесу в конструкции (stress_max), меняется в диапазоне: 45.31 - 140.40 \([МПа]\).

Распределение данных для обучения#
1df = pd.read_csv('branch_data.csv')
2df.describe()

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

Отображение данных для обучения#
1features = ['pressure', 'gas_temp', 'ambient_temp', 'wall_thickness']
2target = 'stress_max'
3
4df[features + [target]].head()

6.2.  Подготовка данных#

Для эффективной работы с данными в PyTorch используется специальный класс StressDataset, который наследуется от torch.utils.data.Dataset. Родительский класс является абстрактным и требует реализации двух основных методов: __len__() и __getitem__(). В итоге, этот класс выполняет несколько важных функций:

  1. Инкапсулирует логику загрузки и предобработки данных. В данном случае - преобразует данные в torch.Tensor и переносит их на необходимое устройство.

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

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

  4. Упрощает интеграцию с DataLoader для разбиения на батчи и перемешивания данных.

Определение класса StressDataset#
 1class StressDataset(Dataset):
 2    """
 3    Класс датасета для обучения модели.
 4    """
 5    def __init__(
 6        self,
 7        X: np.ndarray,
 8        y: np.ndarray,
 9        device: torch.device = torch.device('cpu')
10    ) -> None:
11        """
12        Инициализация набора данных.
13
14        Параметры:
15            X: np.ndarray
16                Массив входных признаков
17            y: np.ndarray
18                Массив целевых значений
19            device: torch.device
20                Устройство для вычислений
21        """
22        super().__init__()
23        self.device = device
24        self.X = X
25        self.y = torch.FloatTensor(y, device=self.device).reshape(-1, 1)
26    
27    def __len__(self) -> int:
28        """
29        Методы получения количества элементов.
30        
31        Возвращает:
32            int: Количество элементов
33        """
34        return len(self.X)
35    
36    def __getitem__(self, idx: int) -> Tuple[Tuple[torch.Tensor, ...], torch.Tensor]:
37        """
38        Возвращает пару (признаки, целевое значение) для заданного индекса.
39        
40        Параметры:
41            idx: int
42                Индекс образца
43            
44        Возвращает:
45            Tuple[Tuple[torch.Tensor, ...], torch.Tensor]: 
46                Кортеж из кортежа признаков и целевого значения
47        """
48        return (
49            tuple(torch.Tensor([feature], device=self.device) 
50                  for feature in self.X[idx]),
51            self.y[idx]
52        )

Важно

Важно отметить, что каждый признак возвращается отдельным тензором, что важно для экспорта в ONNX и интеграции с REPEAT VISION.

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

Подготовка данных для обучения и тестирования#
 1X = df[features].values
 2y = df[target].values
 3
 4X_train, X_test, y_train, y_test = train_test_split(
 5    X, y,
 6    test_size=0.2,
 7    random_state=42
 8)
 9
10train_dataset = StressDataset(X_train, y_train, device)
11test_dataset = StressDataset(X_test, y_test, device)
12
13batch_size = 64
14train_loader = DataLoader(
15    train_dataset, 
16    batch_size=batch_size, 
17    shuffle=True
18)
19test_loader = DataLoader(
20    test_dataset, 
21    batch_size=batch_size, 
22    shuffle=False
23)

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

  • Строки 1-2. Отделение численных значений признаков и целевой переменной.

  • Строки 4-8. Разбиение на обучающую и тестовую выборки.

  • Строка 10-11. Создание экземпляров класса StressDataset для обучения и тесторвания

  • Строка 13-23. Создание экземпляров класса DataLoader для эффективной загрузки данных батчами.

6.3.  Архитектура нейронной сети#

В задаче заданы 4 входных признака: давление (pressure), температура газа (gas_temp), температура окружающей среды (ambient_temp) и толщина стенки (wall_thickness). Все они склеиваются в один вектор размера 4. Выходом же является одно численное значение (предсказанное максимальное напряжение), то есть задача является примером задачи регрессии:

\[ f: \mathbb{R}^4 \rightarrow \mathbb{R} \]

где:

\[ f(p, t_g, t_a, w) = \sigma_{max} \]

где:

\(p\) - давление;

\(t_g\) - температура газа;

\(t_a\) - температура окружающей среды;

\(w\) - толщина стенки;

\(\sigma_{max}\) - максимальное напряжение.

Для табличных данных могут быть применены различные модели, от классического машинного обучения до глубоких нейронных сетей. В данном случае используется MLP (Multi Layer Perceptron) модель.

  • Архитектура модели представляет собой трехслойный MLP с фиксированной глубиной, где размер скрытых слоев настраивается при инициализации. Такая структура обеспечивает достаточную емкость для аппроксимации нелинейных зависимостей в данных.

Матричное представление трехслойной MLP модели с 4 входными каналами, 1 выходным и скрытым состоянием \( h \):

\[\begin{split} \begin{align*} h_1 &= \text{ReLU}(\text{LayerNorm}(W_1 x + b_1)) \\ h_2 &= \text{ReLU}(\text{LayerNorm}(W_2 h_1 + b_2)) \\ h_3 &= \text{ReLU}(\text{LayerNorm}(W_3 h_2 + b_3)) \\ y &= W_4 h_3 + b_4 \end{align*} \end{split}\]

где:

  • \(x \in \mathbb{R}^4\) - входной вектор признаков

  • \(W_1 \in \mathbb{R}^{h \times 4}, b_1 \in \mathbb{R}^{h}\) - веса и смещения первого слоя

  • \(W_2 \in \mathbb{R}^{h \times h}, b_2 \in \mathbb{R}^{h}\) - веса и смещения второго слоя

  • \(W_3 \in \mathbb{R}^{h \times h}, b_3 \in \mathbb{R}^{h}\) - веса и смещения третьего слоя

  • \(W_4 \in \mathbb{R}^{1 \times h}, b_4 \in \mathbb{R}\) - веса и смещения выходного слоя

  • \(y \in \mathbb{R}\) - выходное значение (предсказанное напряжение)

В модели применено несколько идей:

  • Для стабилизации обучения модель использует предварительно вычисленные статистики (mean и std) из тренировочного набора данных. Нормализация входных признаков в методе forward позволяет привести каждый пример к единому распределению, не требуя отдельного нормализатора, что осложнило бы импорт в REPEAT VISION.

  • В качестве регуляризации применяется комбинация Dropout, L2-регуляризации (weight decay) и ранней остановкой (early stopping). Функция активации ReLU выбрана на основе анализа данных, хотя альтернативно можно использовать и более сглаженные варианты. Для инициализации весов используется метод Кайминга, который стабилизирует дисперсию выходов слоев и предотвращает проблемы с градиентами. Смещения инициализируются нулями, так как они быстро обучаются сами.

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

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

Определение класса StressNet#
  1class StressNet(nn.Module):
  2    """
  3    Нейронная сеть.
  4    """
  5    def __init__(
  6        self,
  7        input_size: int = 4,
  8        hidden_size: int = 32,
  9        mean: torch.Tensor = torch.zeros(4),
 10        std: torch.Tensor = torch.ones(4),
 11        dropout_rate: float = 0.2
 12    ) -> None:
 13        """
 14        Инициализация модели.
 15        
 16        Параметры:
 17            input_size: int
 18                Размер входного слоя
 19            hidden_size: int
 20                Размер скрытых слоев
 21            mean: torch.Tensor
 22                Средние значения для нормализации
 23            std: torch.Tensor
 24                Стандартные отклонения для нормализации
 25            dropout_rate: float
 26                Вероятность отключения нейронов
 27        """
 28        super().__init__()
 29        
 30        self.fc1 = nn.Linear(input_size, hidden_size)
 31        self.norm1 = nn.LayerNorm(hidden_size)
 32        self.fc2 = nn.Linear(hidden_size, hidden_size)
 33        self.norm2 = nn.LayerNorm(hidden_size)
 34        self.fc3 = nn.Linear(hidden_size, hidden_size)
 35        self.norm3 = nn.LayerNorm(hidden_size)
 36        self.out = nn.Linear(hidden_size, 1)
 37
 38        self.act = nn.ReLU()
 39        self.dropout = nn.Dropout(dropout_rate)
 40
 41        self.mean = mean
 42        self.std = std
 43
 44        self.apply(self._init_weights)
 45
 46    def _init_weights(self, module: nn.Module) -> None:
 47        """
 48        Инициализация весов слоев.
 49        
 50        Параметры:
 51            module: nn.Module
 52                Модуль для инициализации весов
 53        """
 54        if isinstance(module, nn.Linear):
 55            nn.init.kaiming_uniform_(
 56                module.weight,
 57                nonlinearity='relu'
 58            )
 59            nn.init.zeros_(module.bias)
 60
 61    def forward(
 62        self,
 63        pressure: torch.Tensor,
 64        gas_temp: torch.Tensor,
 65        ambient_temp: torch.Tensor,
 66        wall_thickness: torch.Tensor
 67    ) -> torch.Tensor:
 68        """
 69        Прямой проход через сеть.
 70        
 71        Параметры:
 72            pressure: torch.Tensor
 73                Давление
 74            gas_temp: torch.Tensor
 75                Температура газа
 76            ambient_temp: torch.Tensor
 77                Температура окружения
 78            wall_thickness: torch.Tensor
 79                Толщина стенки
 80            
 81        Возвращает:
 82            torch.Tensor: Предсказанное значение максимального напряжения
 83        """
 84        batch_size = pressure.shape[0]
 85        
 86        x = torch.cat([
 87            pressure.view(batch_size, -1),
 88            gas_temp.view(batch_size, -1),
 89            ambient_temp.view(batch_size, -1),
 90            wall_thickness.view(batch_size, -1)
 91        ], dim=1)
 92
 93        x = (x - self.mean) / self.std
 94
 95        x = self.fc1(x)
 96        x = self.norm1(x)
 97        x = self.act(x)
 98        x = self.dropout(x)
 99
100        x = self.fc2(x)
101        x = self.norm2(x)
102        x = self.act(x)
103        x = self.dropout(x)
104
105        x = self.fc3(x)
106        x = self.norm3(x)
107        x = self.act(x)
108        x = self.dropout(x)
109
110        return self.out(x)
  • Строки 30-39. Объявление трех слоев с LayerNorm и Dropout для регуляризации.

  • Строки 41-42. Поскольку входные данные нормализуются внутри модели, mean и std передаются в конструктор.

  • Строки 44. Применяется начальная инициализация весов (строки 46-59).

  • Строки 61-110. Основной метод, forward, принимает необходимые входные параметры, объединяет их в один тензор и затем пропускает его через все слои в необходимом порядке.

После определения архитектуры модели, необходимо инициализировать саму модель и настроить оптимизатор и критерий (функцию потерь).

В данном случае используется следующая конфигурация:

  • Размер скрытого слоя (hidden_size) установлен на 512 нейронов

  • Коэффициент прореживания (dropout_rate) равен 0.2

  • Для нормализации входных данных используются статистики из обучающего набора

  • В качестве функции потерь выбрано среднеквадратичное отклонение (MSE)

  • Оптимизатор AdamW с коэффициентом обучения 5e-4 и L2-регуляризацией 1e-4

Объявление задачи и общая постановка задачи#
 1hidden_size = 512
 2dropout_rate = 0.2
 3
 4stats = pd.DataFrame(df[features])
 5mean = torch.tensor(stats.mean().values, dtype=torch.float32)
 6std = torch.tensor(stats.std().values,  dtype=torch.float32)
 7
 8model = StressNet(
 9    input_size=len(features),
10    mean=mean,
11    std=std,
12    hidden_size=hidden_size,
13    dropout_rate=dropout_rate 
14)
15
16criterion = nn.MSELoss()
17optimizer = optim.AdamW(model.parameters(), lr=5e-4, weight_decay=1e-4)

6.4.  Обучение модели#

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

  • Подготовка:

    • Перенос модели на указанное устройство.

    • Инициализация списков для отслеживания потерь.

    • Настройка ранней остановки (early stopping).

  • Цикл обучения:

    • Обучение на тренировочных данных.

    • Валидация на проверочных данных.

    • Отслеживание лучшей модели.

    • Проверка условий ранней остановки.

  • Мониторинг:

    • Отслеживание значения функции потерь.

    • Сохранение лучшей модели.

    • Вывод прогресса обучения.

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

Определение функции train_model#
 1def train_model(
 2    model: nn.Module,
 3    train_loader: DataLoader,
 4    val_loader: DataLoader,
 5    criterion: nn.Module,
 6    optimizer: optim.Optimizer,
 7    epochs: int,
 8    device: torch.device = torch.device('cpu'),
 9    patience: int = 20
10) -> Tuple[nn.Module, List[float], List[float]]:
11    """
12    Обучает модель нейронной сети.
13    
14    Параметры:
15        model: nn.Module
16            Модель нейронной сети для обучения
17        train_loader: DataLoader
18            Загрузчик данных для обучающей выборки
19        val_loader: DataLoader
20            Загрузчик данных для валидационной выборки
21        criterion: nn.Module
22            Функция потерь
23        optimizer: optim.Optimizer
24            Оптимизатор для обновления весов
25        epochs: int
26            Количество эпох обучения
27        device: torch.device
28            Устройство для вычислений (CPU/GPU)
29        patience: int
30            Количество проведенных эпох без улучшения, достаточное для ранней остановки обучения
31        
32    Возвращает:
33        Tuple[nn.Module, List[float], List[float]]: Обученная модель, 
34            список потерь на обучающей выборке, список потерь на валидационной выборке
35    """
36    model.to(device)
37    
38    train_losses = []
39    val_losses = []
40    
41    best_val_loss = float('inf')
42    no_improvement = 0
43    best_model_state = None
44    
45    for epoch in tqdm(range(epochs), desc='Training'):
46        model.train()
47        train_loss = 0.0
48        
49        for inputs, targets in train_loader:
50            optimizer.zero_grad()
51            
52            outputs = model(*inputs)
53            loss = criterion(outputs, targets)
54            
55            loss.backward()
56            optimizer.step()
57            
58            train_loss += loss.item() * targets.size(0)
59            
60        train_loss = train_loss / len(train_loader.dataset)
61        train_losses.append(train_loss)
62        
63        model.eval()
64        val_loss = 0.0
65        
66        with torch.no_grad():
67            for inputs, targets in val_loader:
68                outputs = model(*inputs)
69                loss = criterion(outputs, targets)
70                
71                val_loss += loss.item() * targets.size(0)
72                
73        val_loss = val_loss / len(val_loader.dataset)
74        val_losses.append(val_loss)
75        
76        if epoch % 10 == 0:
77            print(
78                f'Epoch {epoch+1}/{epochs}, '
79                f'Train Loss: {train_loss:.6f}, '
80                f'Val Loss: {val_loss:.6f}'
81            )
82        
83        if val_loss < best_val_loss:
84            best_val_loss = val_loss
85            no_improvement = 0
86            best_model_state = model.state_dict().copy()
87        else:
88            no_improvement += 1
89            if no_improvement >= patience:
90                print(f'Early stopping at epoch {epoch+1}')
91                model.load_state_dict(best_model_state)
92                break
93    
94    return model, train_losses, val_losses
  • Строки 49-58. Основной цикл обучения с вычислением потерь на тренировочном наборе данных.

  • Строки 66-71. Валидация модели и вычисление потерь на валидационном наборе.

  • Строки 83-92. Логика ранней остановки и сохранения лучшей модели.

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

Вызов функции train_model#
 1model, train_losses, val_losses = train_model(
 2    model=model,
 3    train_loader=train_loader,
 4    val_loader=test_loader,
 5    criterion=criterion,
 6    optimizer=optimizer,
 7    epochs=500,
 8    device=device,
 9    patience=10
10)

6.5.  Оценка модели#

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

  1. Подготовка модели:

    • Переводит модель в режим оценки (model.eval()).

    • Отключает вычисление градиентов для оптимизации памяти.

  2. Обработка данных:

    • Проходит по всем батчам в DataLoader.

    • Получает предсказания модели.

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

  3. Расчет метрик:

    • MSE (Mean Squared Error) - средняя квадратичная ошибка.

    • RMSE (Root Mean Squared Error) - корень из средней квадратичной ошибки.

    • MAPE (Mean Absolute Percentage Error) - средняя абсолютная процентная ошибка.

    • MAE (Mean Absolute Error) - средняя абсолютная ошибка.

    • R² (R-squared) - коэффициент детерминации.

Определение функции evaluate_model#
 1def evaluate_model(
 2    model: nn.Module,
 3    data_loader: DataLoader,
 4    criterion: nn.Module,
 5    device: torch.device = torch.device('cpu')
 6) -> Dict[str, Union[float, np.ndarray]]:
 7    """
 8    Оценивает производительность модели на заданном наборе данных.
 9    
10    Параметры:
11        model: nn.Module
12            Модель PyTorch для оценки
13        data_loader: DataLoader
14            DataLoader с данными для оценки
15        criterion: nn.Module
16            Функция потерь
17        device: torch.device
18            Устройство для вычислений
19        
20    Возвращает:
21        Dict[str, Union[float, np.ndarray]]: Словарь с метриками оценки
22        и результатами предсказаний
23    """
24    model.to(device)
25    model.eval()
26    
27    all_targets = []
28    all_predictions = []
29    total_loss = 0.0
30    
31    with torch.no_grad():
32        for inputs, targets in data_loader:
33            outputs = model(*inputs)
34            loss = criterion(outputs, targets)
35            total_loss += loss.item() * targets.size(0)
36            
37            all_targets.extend(targets.cpu().numpy())
38            all_predictions.extend(outputs.cpu().numpy())
39    
40    all_targets = np.array(all_targets).flatten()
41    all_predictions = np.array(all_predictions).flatten()
42    
43    mse = mean_squared_error(all_targets, all_predictions)
44    rmse = np.sqrt(mse)
45    mape = mean_absolute_percentage_error(all_targets, all_predictions)
46    mae = mean_absolute_error(all_targets, all_predictions)
47    r2 = r2_score(all_targets, all_predictions)
48    
49    avg_loss = total_loss / len(data_loader.dataset)
50    
51    return {
52        'loss': avg_loss,
53        'mse': mse,
54        'rmse': rmse,
55        'mape': mape,
56        'mae': mae,
57        'r2': r2,
58        'targets': all_targets,
59        'predictions': all_predictions
60    }

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

Для получения всех метрик достаточно выполнить следующий код:

Вызов функции evaluate_model#
1test_results = evaluate_model(model, test_loader, criterion, device)
2
3print("Test metrics:")
4print(f"MSE: {test_results['loss']:.3f}")
5print(f"RMSE: {test_results['rmse']:.3f}")
6print(f"MAPE: {test_results['mape']*100:.3f}%")
7print(f"MAE: {test_results['mae']:.3f}")
8print(f"R^2: {test_results['r2']:.3f}")

Этот код выведет результаты тестирования модели.

Метрика

Значение

Интерпретация

MSE

5.281

Среднеквадратичная ошибка

RMSE

2.298

Корень из среднеквадратичной ошибки

MAPE

1.066%

Средняя абсолютная процентная ошибка

MAE

0.814

Средняя абсолютная ошибка

R²

0.987

Коэффициент детерминации

6.6.  Визуализация результатов#

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

Определение функции visualize_results#
 1def visualize_results(
 2    train_losses: List[float],
 3    val_losses: List[float],
 4    test_results: Dict[str, np.ndarray]
 5) -> None:
 6    """
 7    Визуализирует результаты обучения модели.
 8    
 9    Параметры:
10        train_losses: List[float]
11            Список значений функции потерь на обучающей выборке
12        val_losses: List[float]
13            Список значений функции потерь на валидационной выборке
14        test_results: Dict[str, np.ndarray]
15            Словарь с результатами тестирования модели
16    """
17    _, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 4))
18    
19    ax1.plot(train_losses, label='Train Loss')
20    ax1.plot(val_losses, label='Val Loss')
21    ax1.set_xlabel('Epoch')
22    ax1.set_ylabel('Loss')
23    ax1.legend()
24    ax1.grid(True)
25    
26    errors: np.ndarray = test_results['predictions'] - test_results['targets']
27    sns.histplot(errors, bins=30)
28    ax2.set_xlabel('Error')
29    ax2.set_ylabel('Frequency')
30    ax2.grid(True)
31    
32    plt.tight_layout()
33    plt.show()

Вызовем эту функцию.

Вызов функции visualize_results#
1visualize_results(train_losses, val_losses, test_results)

В результате имеем два графика:

  • Первый — динамика функции потерь на обучении и валидации.

  • Второй — гистограмма распределения ошибок предсказания.

LossAndErrors

Графики изменения значения функции потерь и распределения ошибок.#

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

Функция export_to_onnx предназначена для экспорта обученной PyTorch модели в формат ONNX. Функция учитывает необходимости перевода в режим double и учитывает имена входных и выходных параметров.

Определение функции export_to_onnx#
 1def export_to_onnx(
 2    model: nn.Module,
 3    features: List[str],
 4    target: str,
 5    output_path: str = "stress_model.onnx"
 6) -> None:
 7    """
 8    Экспортирует PyTorch модель в формат ONNX.
 9    
10    Args:
11        model: nn.Module
12            PyTorch модель для экспорта
13        features: List[str]
14            Список имен входных признаков
15        target: str
16            Имя целевой переменной
17        output_path: str
18            Путь для сохранения ONNX модели
19    """
20    model.eval()
21    model.double()
22    
23    dummy_inputs: Dict[str, torch.Tensor] = {
24        feature: torch.zeros(1, 1, dtype=torch.float64)
25        for feature in features
26    }
27    
28    torch.onnx.export(
29        model,
30        dummy_inputs,
31        output_path,
32        input_names=features,
33        output_names=[target],
34        opset_version=12,
35        dynamo = False
36        )
37    
38    print(f"Model exported to {output_path}.")

Для конфертации обученной ранее модели необходимо передать ее в объявленную ранее модель и имена признаков и целевой переменной для корректного отображения в REPEAT VISION.

Вызов функции export_to_onnx#
1export_to_onnx(model, features, target)

На следующем этапе сохранённая модель будет импортирована на платформу REPEAT VISION в проект газопровода-шлейфа для выполнения междисциплинарного моделирования.

7.  Проект газопровода-шлейфа на платформе REPEAT VISION#

На рисунке ниже приведён проект на платформе REPEAT VISION для моделирования газопровода-шлейфа с помощью блоков библиотек Пневматика, Автоматика и Внешние модели. Данная модель газопровода-шлейфа позволяет:

  1. Выполнять расчёт параметров системы сбора на соответствие техническому проекту разработки месторождения;

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

../../../_images/repeat_project.ru.png

Проект газопровода-шлейфа на платформе REPEAT VISION.#

В рамках единого проекта на основании актуальных данных диагностики технического состояния газопровода-шлейфа также выполняется расчёт напряжений по Мизесу отвода с помощью блока №12 Аппроксимационная модель и импортированной в данный блок модели машинного обучения.

Проект, изображённый выше позволяет:

  1. Выполнять расчётные эксперимены на модели машинного обучения,

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

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

7.1.  Результаты расчётных экспериментов#

Динамика уменьшения толщины стенки отвода приведена на рисунке ниже.

../../../_images/branch_wall_thicks.ru.png

Динамика уменьшения минимальной толщины стенки отвода.#

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

../../../_images/approx_stress.ru.png

Динамика увеличения максимальных напряжений по Мизесу в отводе.#

8.  Выводы#

Интеграция моделей машинного обучения на платформу REPEAT VISION:

  1. Расширяет набор решаемых задач в системном моделировании и в создании цифровых двойников комплексных систем;

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

  3. По сравнению с прямой интеграцией с внешним инженерным ПО: устраняет риск возникновения ошибок из-за проблем сходимости расчёта МКЭ (МКО) модели, значительно повышает скорость расчёта структурного проекта.