sy1214ei 님의 블로그

[Paper Review] Learning Mesh-Based Simulation with Graph Networks_Shape Tracking 본문

[Paper Review]

[Paper Review] Learning Mesh-Based Simulation with Graph Networks_Shape Tracking

sy1214ei 2025. 1. 11. 20:59

https://github.com/google-deepmind/deepmind-research/tree/master/meshgraphnets

 

deepmind-research/meshgraphnets at master · google-deepmind/deepmind-research

This repository contains implementations and illustrative code to accompany DeepMind publications - google-deepmind/deepmind-research

github.com

 

1. 데이터셋의 구조 (download_dataset.sh)

download_dataset.sh 스크립트는 데이터셋을 다운로드하는 역할을 한다. 해당 스크립트의 내용을 살펴보면, 데이터셋이 어디에서 다운로드되며, 어떤 형식으로 저장되는지 확인할 수 있다. 스크립트의 내용은 다음과 같다.

#!/bin/bash
# Script to download datasets for MeshGraphNets

# Create a directory to store the datasets
mkdir -p datasets

# Download the datasets
wget -P datasets/ https://storage.googleapis.com/meshgraphnets/datasets/cylinder_flow.zip
wget -P datasets/ https://storage.googleapis.com/meshgraphnets/datasets/flag_simple.zip
wget -P datasets/ https://storage.googleapis.com/meshgraphnets/datasets/airfoil.zip
wget -P datasets/ https://storage.googleapis.com/meshgraphnets/datasets/cloth.zip

# Unzip the datasets
unzip datasets/cylinder_flow.zip -d datasets/
unzip datasets/flag_simple.zip -d datasets/
unzip datasets/airfoil.zip -d datasets/
unzip datasets/cloth.zip -d datasets/

# Remove the zip files
rm datasets/*.zip

이 스크립트는 datasets 디렉토리를 생성하고, 네 가지 데이터셋(cylinder_flow, flag_simple, airfoil, cloth)을 다운로드하여 압축을 해제한다. 각 데이터셋은 해당 디렉토리에 저장되며, 데이터의 형태는 .npz 파일로 구성되어 있다.


2. 모델의 레이어 구성

주어진 모델 파일들을 분석하여 각 모델의 레이어 구성을 정리


a. cfd_model

유체 역학(CFD) 시뮬레이션

cfd_model.py / cfd_model_dataset

1. 데이터셋 분석

a. 데이터셋 구조

  • field_names: 데이터셋이 포함하는 필드 이름.
    • 노드: node_type, mesh_pos.
    • 엣지: cells.
    • 동적 특징: density, pressure, velocity.
  • features: 각 필드의 상세 정보.
Feature 차원 설명
node_type [1, 5233, 1] 5233개의 노드 유형(예: 경계 노드, 내부 노드).
  • 첫 번째 차원 (1): 처리 중인 메쉬의 수 (배치 크기, 현재는 1).
  • 두 번째 차원 (5233): 메쉬에서 노드(점)가 5233개 존재한다는 뜻
  • 세 번째 차원 (1): 각 삼각형 셀을 구성하는 3개의 노드 인덱스.
    [0, 1, 2] 같은 값으로 경계 조건, 내부 노드 등을 구분
cell [1, 10216, 3] 10216개의 삼각형 엣지, 각 셀은 3개의 노드로 구성.
  • 첫 번째 차원 (1): 처리 중인 메쉬의 수 (배치 크기, 현재는 1).
  • 두 번째 차원 (10216): 삼각형 셀(엣지)의 개수.
  • 세 번째 차원 (3): 각 삼각형 셀을 구성하는 3개의 노드 인덱스.
    [[n1, n2, n3], [n4, n5, n6], ...] 형태
mesh_pos [1, 5233, 2] 5233개의 노드 좌표 (x, y).
  • 첫 번째 차원 (1): 처리 중인 메쉬의 수 (배치 크기, 현재는 1).
  • 두 번째 차원 (10216): 노드의 개수
  • 세 번째 차원 (2): 각 노드의 위치를 나타내는 x와 y 좌표.
density [601, 5233, 1] 시간 단계별(601) 노드(5233)의 밀도 값.
  • 첫 번째 차원 (601): 시간 단계(time steps).
    CFD시뮬레이션은 시간에 따라 변화하는 데이터를 포함하며,
    601개의 시간 단계가 존재
  • 두 번째 차원 (5233): 노드의 개수
    5233개의 노드 각각에서 밀도를 측정
  • 세 번째 차원 (2): 밀도값
    각 노드에서 시간에 따른 밀도 값을 나타냄
pressure [601, 5233, 1] 시간 단계별(601) 노드(5233)의 압력 값.
  • 첫 번째 차원 (601): 시간 단계(time steps).
    CFD시뮬레이션은 시간에 따라 변화하는 데이터를 포함하며,
    601개의 시간 단계가 존재
  • 두 번째 차원 (5233): 노드의 개수
    5233개의 노드 각각에서 압력를 측정
  • 세 번째 차원 (2): 밀도값
    각 노드에서 시간에 따른 압력 값을 나타냄
velocity [601, 5233, 2] 시간 단계별(601) 노드(5233)의 속도 벡터 (vx, vy).
  • 첫 번째 차원 (601): 시간 단계(time steps).
    CFD시뮬레이션은 시간에 따라 변화하는 데이터를 포함하며,
    601개의 시간 단계가 존재
  • 두 번째 차원 (5233): 노드의 개수
    5233개의 노드 각각에서 속도를 계산
  • 세 번째 차원 (2): 속도의 벡터값
    각 노드에서 속도를 나타내는 x와 y방향 성분
  •  

2. CFD 모델 분석

class Model(snt.AbstractModule):
  """Model for fluid simulation."""

  def __init__(self, learned_model, name='Model'):
    super(Model, self).__init__(name=name)
    with self._enter_variable_scope():
      self._learned_model = learned_model
      self._output_normalizer = normalization.Normalizer(
          size=2, name='output_normalizer')
      self._node_normalizer = normalization.Normalizer(
          size=2+common.NodeType.SIZE, name='node_normalizer')
      self._edge_normalizer = normalization.Normalizer(
          size=3, name='edge_normalizer')  # 2D coord + length
단계 구성요소 입력 크기 출력 크기 설명
Encoder Node Encoder [5233, 3] [5233, 128] Node 특징 -> Latent 공간
  Edge Encoder [10216, edge_dim] [10216, 128] Edge 특징 -> Latent 공간
Processor Node Update [5233, 128] [5233, 128] 반복적으로 Node Feature Update
  Edge Update [10216, 128] [10216, 128] 반복적으로 Edge Feature Update
Decoder Node Decoder [5233, 128] [5233, 4] Node Latent Space -> 최종 출력

* Output Data

최종 출력 크기는 [5233, 4]로, 각 노드별로 3개의 물리량 (밀도, 압력, 속도)을 예측:

  • 밀도(density): [1]
  • 압력(pressure): [1]
  • 속도(velocity): [2]

a. Encoder

  • MLP 개수: 인코더는 노드와 엣지의 특징을 잠재 공간(latent space)으로 변환하기 위해 각각 1개의 MLP를 사용한다.
    • 노드 특징 인코딩:
      • 입력: node_features (shape: [num_nodes, input_node_dim])
      • 출력: node_latents (shape: [num_nodes, latent_size])
    • 엣지 특징 인코딩:
      • 입력: edge_features (shape: [num_edges, input_edge_dim])
      • 출력: edge_latents (shape: [num_edges, latent_size])
    Shape 변화:
    • 노드: [num_nodes, input_node_dim] → [num_nodes, latent_size]
    • 엣지: [num_edges, input_edge_dim] → [num_edges, latent_size]
class Encoder(snt.Module):
    def __init__(self):
        super().__init__()
        self._mlp = snt.nets.MLP([128, 128])  # 중간 레이어 크기

    def __call__(self, inputs):
        return self._mlp(inputs)  # 입력 크기 → [128]

b. Processor

  • MLP 개수: 프로세서는 메시지 패싱(message passing)을 통해 그래프를 반복적으로 업데이트하며, 각 반복마다 2개의 MLP를 사용한다. 
    • 엣지 업데이트 MLP: 엣지 특징을 업데이트
    • 노드 업데이트 MLP: 노드 특징을 업데이트
    반복 횟수: message_passing_steps만큼 반복되며, 총 MLP 개수는 2 * message_passing_steps이다.
  • Shape 변화: 각 반복에서->
    • 엣지: [num_edges, latent_size] → [num_edges, latent_size]
    • 노드: [num_nodes, latent_size] → [num_nodes, latent_size]

c. Decoder

MLP 개수: 디코더는 노드의 잠재 특징을 최종 출력으로 변환하기 위해 1개의 MLP를 사용한다.

  • 노드 디코딩:
    • 입력: node_latents (shape: [num_nodes, latent_size])
    • 출력: output (shape: [num_nodes, output_size])

Shape 변화:

  • 노드: [num_nodes, latent_size] → [num_nodes, output_size]

b. Deforming Plate

Deforming Plate 시뮬레이션

cloth_model.py / cloth_model_dataset

1. 데이터셋 분석

a. 데이터셋 구조

  • features: 각 필드의 상세 정보.
Feature 차원 설명
cell [1, -1, 4] 메쉬의 셀 연결 정보를 정의.
  • 첫 번째 차원 (1): 처리 중인 메쉬의 수 (배치 크기, 현재는 1).
  • 두 번째 차원 (-1): 셀(요소) 개수 (-1은 가변적).
  • 세 번째 차원 (4): 각 셀을 구성하는 4개의 노드(사각형).
node_type [1, -1, 1] 노드의 유형 정보
  • 첫 번째 차원 (1): 처리 중인 메쉬의 수 (배치 크기, 현재는 1).
  • 두 번째 차원 (-1): 노드의 개수 (-1은 가변적).
  • 세 번째 차원 (1): 각 노드의 유형 (예: 0=경계, 1=내부 등).
mesh_pos [1, -1, 3]
  • 첫 번째 차원 (1): 처리 중인 메쉬의 수 (배치 크기, 현재는 1).
  • 두 번째 차원 (-1): 노드의 개수 (-1은 가변적)
  • 세 번째 차원 (3): 각 노드의 3D 위치 (x, y, z)
world_pos [400, -1, 3] 각 프레임마다의 world 좌표
  • 첫 번째 차원(400): 프레임 수
  • 두 번째 차원 (5233): 노드의 개수 (-1 가변적)
  • 세 번째 차원 (2): 노드의 3D 위치 (x,y,z)
stress [400, -1, 1] 각 프레임마다의 응력값
  • 첫 번째 차원(400): 프레임 수 (400).
  • 두 번째 차원 (5233): 노드의 개수 (-1은 가변적)
  • 세 번째 차원 (1): 응력값
    각 노드에서 응력 값을 나타냄

2. Deforming Plate 모델 분석

class Model(snt.Module):
    def __init__(self, name="Model"):
        super().__init__(name=name)
        self._encoder = core_model.Encoder()
        self._processor = core_model.Processor()
        self._decoder = core_model.Decoder()
        self._output_normalizer = normalization.Normalizer()

    def __call__(self, inputs):
        latent = self._encoder(inputs)
        latent = self._processor(latent)
        outputs = self._decoder(latent)
        return self._output_normalizer.inverse(outputs)
단계 Feature MLP 개수 입력 Shape 출력 Shape 설명
Input Raw Data   node_type + mesh_pos [num_nodes, 4] 입력 노드 특징 연결
      cells [num_edges, edge_dim] 엣지 특징 연결
Encoder Node Encoder 2 [num_nodes, 4] [num_nodes, 128] Node latent space 변환
  Edge Encoder 2 [num_edges, edge_dim] [num_edges, 128] Edge latent space 변환
Processor Edge Update 2 per step [num_edges, 128] [nums_edges, 128] 메시지 전달, 반복적으로 업데이트
  Node Update 2 per step [num_nodes, 128] [nums_nodes, 128]  
  (반복 10회) 40 총계 Shape는 유지됨 Shape는 유지됨  
Decoder Node Decoder 2 [num_nodes, 128] [nums_nodes, 4] 최종 출력 (stress, position)

 

 

  • Encoder:
    • 4개의 MLP.
    • 노드와 엣지 특징을 잠재 공간으로 변환.
  • Processor:
    • 반복당 4개의 MLP × 10 반복 = 40개의 MLP.
    • 노드와 엣지 데이터를 반복적으로 업데이트.
  • Decoder:
    • 2개의 MLP.
    • 잠재 공간 데이터를 최종 출력으로 변환.
  • 모델 전체에서 총 46개의 MLP가 사용

c. Deforming Plate

Deforming Plate 시뮬레이션

flag_model.py / flag_dynamic_dataset

1. 데이터셋 분석

a. 데이터셋 구조

  • features: 각 필드의 상세 정보.
Feature Shape 설명
node_type [-1, 1] 노드의 개수와 각 노드의 유형
  • 첫 번째 차원 (-1): 노드의 개수 (-1은 가변적).
  • 세 번째 차원 (1): 각 노드의 유형 (스칼라 값, 1).
mesh_pos [-1, 2] mesh 상의 노드 위치
  • 첫 번째 차원 (-1): 노드의 개수 (-1은 가변적).
  • 두 번째 차원 (2): 노드의 2D 좌표 (x,y)
world_pos [-1, 3] 노드의 3D 좌표
  • 첫 번째 차원 (-1): 노드의 개수 (-1은 가변적).
  • 두 번째 차원 (3): 노드의 3D 좌표 (x, y, z).
cells [-1, 3] 각 삼각형 셀의 연결 정보를 정의
  • 첫 번째 차원 (-1): 삼각형 셀의 개수 (-1은 가변적)
  • 두 번째 차원 (1): 삼각형 셀의 3개의 노드 인덱스

 

b. 시뮬레이션 정보

  • 각 시뮬레이션은 총 249 프레임.
  • 프레임마다 node_type, mesh_pos, world_pos, cells 값이 동적으로 변동.
  • 충돌 반경은 0.06으로 설정.
  • 이 데이터셋은 Cloth-like 구조(삼각형 메쉬)를 다루며, 동적인 3D 좌표와 응력 값, 삼각형 셀 정보를 포함한다.
  • node_type, mesh_pos, world_pos, cells는 각각 노드의 유형, 좌표, 셀 연결 정보를 저장.
  • 첫 번째 차원이 -1로 가변적인 것은 노드 및 삼각형의 개수가 데이터마다 다를 수 있음을 나타냄.

c. Deforming Plate 모델 분석

단계 Feature MLP 개수 입력 Shape 출력 Shape 설명
Input Raw Data   [num_nodes, node_feature_dim] 동일 입력 노드 특징 연결
      [num_edges, edge_feature_dim] 동일 엣지 특징 연결
Encoder Node Encoder 2 [num_nodes, node_feature_dim] [num_nodes, latent_dim] Node latent space 변환
  Edge Encoder 2 [num_edges, edge_feature_dim] [num_edges, latent_dim] Edge latent space 변환
Processor Edge Update 2 per step [num_edges, latent_dim] [nums_edges, latent_dim] 메시지 전달, 반복적으로 업데이트
  Node Update 2 per step [num_nodes, latent_dim] [nums_nodes, latent_dim] 메시지 전달, 반복적으로 업데이트
  (반복 10회) 40 총계 Shape는 유지됨 Shape는 유지됨  
Decoder Node Decoder 2 [num_nodes, latent_dim] [nums_nodes, output_dim] 최종 출력 (물리적 특성 예측)

3. 데이터셋과 모델 연결 공통점

[ core_model.py ]

core_model.py 파일은 공통적으로 사용되는 코어 모델을 정의하고 있다. 주요 구성은 다음과 같다.

  • 인코더: 입력 특징을 잠재 공간으로 매핑.
  • 프로세서: 그래프 신경망을 사용하여 메시지 패싱 및 정보 처리.
  • 디코더: 잠재 공간의 정보를 출력 공간으로 변환.
class Encoder(snt.Module):
    def __init__(self, name="Encoder"):
        super().__init__(name=name)
        self._mlp = snt.nets.MLP([128, 128])

    def __call__(self, inputs):
        return self._mlp(inputs)

class Processor(snt.Module):
    def __init__(self, name="Processor"):
        super().__init__(name=name)
        self._gnn = GraphNeuralNetwork()

    def __call__(self, latent):
        return self._gnn(latent)

class Decoder(snt.Module):
    def __init__(self, name="Decoder"):
        super().__init__(name=name)
        self._mlp = snt.nets.MLP([128, 128, output_size])

    def __call__(self, latent):
        return self._mlp(latent)

a. Encoder, Processor, Decoder의 Shape 흐름

 

  • Encoder:
    • 입력 Shape:
      • 노드: [num_nodes, node_feature_dim]
      • 엣지: [num_edges, edge_feature_dim]
    • 출력 Shape:
      • 노드: [num_nodes, latent_dim]
      • 엣지: [num_edges, latent_dim]
  • Processor:
    • Shape 유지:
      • 반복 단계 동안 노드: [num_nodes, latent_dim]
      • 엣지: [num_edges, latent_dim]
  • Decoder:
    • 입력 Shape:
      • [num_nodes, latent_dim]
    • 출력 Shape:
      • [num_nodes, output_dim] (출력 특징의 차원, 예: 3D 좌표, 응력 등)