DeepSDFStruct 1.7.2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- DeepSDFStruct/SDF.py +1734 -0
- DeepSDFStruct/__init__.py +66 -0
- DeepSDFStruct/deep_sdf/__init__.py +69 -0
- DeepSDFStruct/deep_sdf/create_screenshots_from_plyfiles.py +65 -0
- DeepSDFStruct/deep_sdf/data.py +258 -0
- DeepSDFStruct/deep_sdf/metrics/__init__.py +14 -0
- DeepSDFStruct/deep_sdf/metrics/mesh_to_analytical.py +24 -0
- DeepSDFStruct/deep_sdf/models.py +197 -0
- DeepSDFStruct/deep_sdf/networks/__init__.py +8 -0
- DeepSDFStruct/deep_sdf/networks/analytic_round_cross.py +105 -0
- DeepSDFStruct/deep_sdf/networks/deep_sdf_decoder.py +155 -0
- DeepSDFStruct/deep_sdf/networks/hierarchical_deep_sdf_decoder.py +139 -0
- DeepSDFStruct/deep_sdf/networks/hierarchical_positional_sdf_decoder.py +190 -0
- DeepSDFStruct/deep_sdf/networks/resnet_positional_sdf_decoder.py +108 -0
- DeepSDFStruct/deep_sdf/nn_utils.py +70 -0
- DeepSDFStruct/deep_sdf/plotting.py +143 -0
- DeepSDFStruct/deep_sdf/reconstruction.py +165 -0
- DeepSDFStruct/deep_sdf/training.py +840 -0
- DeepSDFStruct/deep_sdf/workspace.py +363 -0
- DeepSDFStruct/design_of_experiments.py +235 -0
- DeepSDFStruct/flexicubes/__init__.py +15 -0
- DeepSDFStruct/flexicubes/flexicubes.py +1005 -0
- DeepSDFStruct/flexicubes/tables.py +2338 -0
- DeepSDFStruct/flexisquares/__init__.py +15 -0
- DeepSDFStruct/flexisquares/flexisquares.py +967 -0
- DeepSDFStruct/flexisquares/tables.py +63 -0
- DeepSDFStruct/lattice_structure.py +254 -0
- DeepSDFStruct/local_shapes.py +226 -0
- DeepSDFStruct/mesh.py +1184 -0
- DeepSDFStruct/optimization.py +357 -0
- DeepSDFStruct/parametrization.py +215 -0
- DeepSDFStruct/pretrained_models.py +128 -0
- DeepSDFStruct/sampling.py +670 -0
- DeepSDFStruct/sdf_operations.py +990 -0
- DeepSDFStruct/sdf_primitives.py +1416 -0
- DeepSDFStruct/splinepy_unitcells/__init__.py +35 -0
- DeepSDFStruct/splinepy_unitcells/chi_3D.py +1617 -0
- DeepSDFStruct/splinepy_unitcells/cross_lattice.py +165 -0
- DeepSDFStruct/splinepy_unitcells/double_lattice_extruded.py +298 -0
- DeepSDFStruct/splinepy_unitcells/snappy_3d.py +544 -0
- DeepSDFStruct/torch_spline.py +446 -0
- DeepSDFStruct/trained_models/analytic_round_cross/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/analytic_round_cross/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/analytic_round_cross/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/analytic_round_cross/specs.json +45 -0
- DeepSDFStruct/trained_models/chi_and_cross/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/Logs.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/chi_and_cross/specs.json +76 -0
- DeepSDFStruct/trained_models/primitives/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives/specs.json +46 -0
- DeepSDFStruct/trained_models/primitives_2d/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives_2d/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives_2d/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/primitives_2d/specs.json +46 -0
- DeepSDFStruct/trained_models/round_cross/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/Logs.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/round_cross/specs.json +45 -0
- DeepSDFStruct/trained_models/test_experiment/LatentCodes/latent_code_data_map.json +106 -0
- DeepSDFStruct/trained_models/test_experiment/specs.json +45 -0
- DeepSDFStruct/trained_models/test_experiment/training_summary.json +10 -0
- DeepSDFStruct/trained_models/test_experiment_hierarchical/LatentCodes/latent_code_data_map.json +106 -0
- DeepSDFStruct/trained_models/test_experiment_hierarchical/specs.json +45 -0
- DeepSDFStruct/trained_models/test_experiment_hierarchical/training_summary.json +10 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/LatentCodes/latent_code_data_map.json +5006 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/LatentCodes/latest.pth +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/Logs.png +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/ModelParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/OptimizerParameters/latest.pth +0 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/specs.json +83 -0
- DeepSDFStruct/trained_models/test_experiment_homogenization/training_summary.json +10 -0
- DeepSDFStruct/utils.py +96 -0
- DeepSDFStruct/visualization/latent_viewer.py +211 -0
- DeepSDFStruct/visualization/latent_viewer_cli.py +8 -0
- benchmarks/generate_sdf_showcase.py +622 -0
- benchmarks/sdf_from_mesh_benchmark.py +52 -0
- benchmarks/sdf_from_mesh_comparison.md +33 -0
- benchmarks/sdf_showcase/operations/boolean/difference_sphere_box.png +0 -0
- benchmarks/sdf_showcase/operations/boolean/union_sphere_box.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/circular_array_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/dilate_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/mirror_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/repeat_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/revolve_circle.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/shell_sphere.png +0 -0
- benchmarks/sdf_showcase/operations/transformations/twist_torus.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/circle.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/equilateral_triangle.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/hexagon.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/polygon_pentagon.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/rectangle.png +0 -0
- benchmarks/sdf_showcase/primitives/2D/rounded_rectangle.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/box.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/capped_cone.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/capped_cylinder.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/capsule.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/cone.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/corner_spheres.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/cross_ms.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/cylinder.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/dodecahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/ellipsoid.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/icosahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/octahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/pyramid.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/rounded_box.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/rounded_cone.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/rounded_cylinder.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/sphere.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/tetrahedron.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/torus.png +0 -0
- benchmarks/sdf_showcase/primitives/3D/wireframe_box.png +0 -0
- deepsdfstruct-1.7.2.dist-info/METADATA +44 -0
- deepsdfstruct-1.7.2.dist-info/RECORD +165 -0
- deepsdfstruct-1.7.2.dist-info/WHEEL +5 -0
- deepsdfstruct-1.7.2.dist-info/licenses/LICENSE +208 -0
- deepsdfstruct-1.7.2.dist-info/licenses/NOTICE +67 -0
- deepsdfstruct-1.7.2.dist-info/scm_file_list.json +178 -0
- deepsdfstruct-1.7.2.dist-info/scm_version.json +8 -0
- deepsdfstruct-1.7.2.dist-info/top_level.txt +4 -0
- docs/Makefile +20 -0
- docs/api_reference.rst +6 -0
- docs/conf.py +60 -0
- docs/index.rst +136 -0
- docs/make.bat +35 -0
- docs/qr_code_github.png +0 -0
- docs/qr_code_paper.png +0 -0
- docs/readme_images/example_output_01.png +0 -0
- docs/readme_images/example_output_02.png +0 -0
- docs/readme_images/example_output_03.png +0 -0
- docs/readme_images/example_output_04.png +0 -0
- tests/data/chairs/1005.obj +282 -0
- tests/data/chairs/1024.obj +222 -0
- tests/data/chairs/README.md +1 -0
- tests/data/circular_balls_test_case.stl +0 -0
- tests/data/cone.stl +1794 -0
- tests/data/example_disconnectd_mesh.inp +1784 -0
- tests/data/example_line_mesh.vtk +0 -0
- tests/data/stanford_bunny.stl +0 -0
- tests/data/sweep_test_case.stl +0 -0
- tests/test_DOE.py +49 -0
- tests/test_elongate_sdf.py +195 -0
- tests/test_flexisquares.py +187 -0
- tests/test_generate_dataset.py +76 -0
- tests/test_lattice_evaluation.py +137 -0
- tests/test_mesh_export.py +137 -0
- tests/test_mesh_functions.py +49 -0
- tests/test_networks.py +71 -0
- tests/test_pretrained_models.py +40 -0
- tests/test_reconstruction.py +101 -0
- tests/test_sdf_from_mesh.py +52 -0
- tests/test_sdf_functions.py +117 -0
- tests/test_sdf_primitives.py +668 -0
- tests/test_sdf_trimesh_comparison.py +482 -0
- tests/test_splinepy_unitcells.py +64 -0
- tests/test_structural_optimization.py +178 -0
- tests/test_torch_spline.py +216 -0
- tests/test_train_model.py +110 -0
- tests/test_training_data_ids.py +41 -0
- tests/tmp_outputs/temp_file.txt +0 -0
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Description": "This experiment is intented for testing purposes only.",
|
|
3
|
+
"NetworkArch": "deep_sdf_decoder",
|
|
4
|
+
"TrainSplit": "splits/splines_v2_small.json",
|
|
5
|
+
"TestSplit": "splits/splines_v2_small.json",
|
|
6
|
+
"ReconstructionSplit": "",
|
|
7
|
+
"NetworkSpecs": {
|
|
8
|
+
"dims": [
|
|
9
|
+
32,
|
|
10
|
+
32,
|
|
11
|
+
32,
|
|
12
|
+
32,
|
|
13
|
+
32,
|
|
14
|
+
32
|
|
15
|
+
],
|
|
16
|
+
"dropout": [
|
|
17
|
+
0,
|
|
18
|
+
1,
|
|
19
|
+
2,
|
|
20
|
+
3,
|
|
21
|
+
4,
|
|
22
|
+
5,
|
|
23
|
+
6,
|
|
24
|
+
7
|
|
25
|
+
],
|
|
26
|
+
"dropout_prob": 0.2,
|
|
27
|
+
"norm_layers": [
|
|
28
|
+
0,
|
|
29
|
+
1,
|
|
30
|
+
2,
|
|
31
|
+
3,
|
|
32
|
+
4,
|
|
33
|
+
5,
|
|
34
|
+
6,
|
|
35
|
+
7
|
|
36
|
+
],
|
|
37
|
+
"latent_in": [
|
|
38
|
+
2
|
|
39
|
+
],
|
|
40
|
+
"xyz_in_all": false,
|
|
41
|
+
"use_tanh": false,
|
|
42
|
+
"latent_dropout": false,
|
|
43
|
+
"weight_norm": true,
|
|
44
|
+
"geom_dimension": 3,
|
|
45
|
+
"homogen_predictor_dims": [
|
|
46
|
+
64,
|
|
47
|
+
64,
|
|
48
|
+
64,
|
|
49
|
+
64,
|
|
50
|
+
9
|
|
51
|
+
]
|
|
52
|
+
},
|
|
53
|
+
"CodeLength": 10,
|
|
54
|
+
"NumEpochs": 5,
|
|
55
|
+
"LogFrequency": 5,
|
|
56
|
+
"SnapshotFrequency": 100,
|
|
57
|
+
"AdditionalSnapshots": [
|
|
58
|
+
1,
|
|
59
|
+
5
|
|
60
|
+
],
|
|
61
|
+
"LearningRateSchedule": [
|
|
62
|
+
{
|
|
63
|
+
"Type": "Step",
|
|
64
|
+
"Initial": 0.0005,
|
|
65
|
+
"Interval": 500,
|
|
66
|
+
"Factor": 0.5
|
|
67
|
+
},
|
|
68
|
+
{
|
|
69
|
+
"Type": "Step",
|
|
70
|
+
"Initial": 0.001,
|
|
71
|
+
"Interval": 500,
|
|
72
|
+
"Factor": 0.5
|
|
73
|
+
}
|
|
74
|
+
],
|
|
75
|
+
"SamplesPerScene": 4,
|
|
76
|
+
"ScenesPerBatch": 2,
|
|
77
|
+
"DataLoaderThreads": 1,
|
|
78
|
+
"ClampingDistance": 0.1,
|
|
79
|
+
"CodeRegularization": true,
|
|
80
|
+
"AddHomogenization": true,
|
|
81
|
+
"CodeRegularizationLambda": 1e-4,
|
|
82
|
+
"CodeBound": 1.0
|
|
83
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
{
|
|
2
|
+
"loss": 9775.975620117188,
|
|
3
|
+
"num_epochs": 5,
|
|
4
|
+
"timestamp": "2026-05-21 17:39:48",
|
|
5
|
+
"host_name": "neptune",
|
|
6
|
+
"device": "cpu",
|
|
7
|
+
"training_duration": "0:00:28",
|
|
8
|
+
"data_dir": "/storage/mkofler/dissertation/data/",
|
|
9
|
+
"version": "1.7.1.dev40+g989384bd4.d20260330"
|
|
10
|
+
}
|
DeepSDFStruct/utils.py
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Utility Functions
|
|
3
|
+
=================
|
|
4
|
+
|
|
5
|
+
This module provides general utility functions used throughout DeepSDFStruct,
|
|
6
|
+
including logging configuration and color scheme definitions.
|
|
7
|
+
|
|
8
|
+
Functions
|
|
9
|
+
---------
|
|
10
|
+
configure_logging
|
|
11
|
+
Set up logging for the DeepSDFStruct package with customizable
|
|
12
|
+
output format and destinations.
|
|
13
|
+
|
|
14
|
+
Constants
|
|
15
|
+
---------
|
|
16
|
+
_TUWIEN_COLOR_SCHEME
|
|
17
|
+
TU Wien corporate color scheme for consistent visualization styling.
|
|
18
|
+
"""
|
|
19
|
+
|
|
20
|
+
import logging
|
|
21
|
+
import DeepSDFStruct
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def configure_logging(level=logging.INFO, logfile=None):
|
|
25
|
+
"""Configure logging for the DeepSDFStruct package.
|
|
26
|
+
|
|
27
|
+
Sets up a logger with a standard format and optional file output.
|
|
28
|
+
This is called automatically when DeepSDFStruct is imported.
|
|
29
|
+
|
|
30
|
+
Parameters
|
|
31
|
+
----------
|
|
32
|
+
level : int, default logging.INFO
|
|
33
|
+
Logging level (e.g., logging.DEBUG, logging.INFO, logging.WARNING).
|
|
34
|
+
logfile : str, optional
|
|
35
|
+
Path to log file. If provided, logs are written to both console
|
|
36
|
+
and file. If None, logs only to console.
|
|
37
|
+
|
|
38
|
+
Examples
|
|
39
|
+
--------
|
|
40
|
+
>>> from DeepSDFStruct.utils import configure_logging
|
|
41
|
+
>>> import logging
|
|
42
|
+
>>>
|
|
43
|
+
>>> # Set debug level and log to file
|
|
44
|
+
>>> configure_logging(level=logging.DEBUG, logfile='deepsdf.log')
|
|
45
|
+
|
|
46
|
+
Notes
|
|
47
|
+
-----
|
|
48
|
+
The log format is: "HH:MM:SS message"
|
|
49
|
+
All log messages are prefixed with a timestamp for easy debugging.
|
|
50
|
+
"""
|
|
51
|
+
logger = logging.getLogger(DeepSDFStruct.__name__)
|
|
52
|
+
logger.setLevel(level)
|
|
53
|
+
formatter = logging.Formatter("%(asctime)s %(message)s", datefmt="%H:%M:%S")
|
|
54
|
+
if not logger.hasHandlers():
|
|
55
|
+
logger_handler = logging.StreamHandler()
|
|
56
|
+
logger_handler.setFormatter(formatter)
|
|
57
|
+
logger.addHandler(logger_handler)
|
|
58
|
+
|
|
59
|
+
if logfile is not None:
|
|
60
|
+
file_logger_handler = logging.FileHandler(logfile)
|
|
61
|
+
file_logger_handler.setFormatter(formatter)
|
|
62
|
+
logger.addHandler(file_logger_handler)
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
#: TU Wien corporate color scheme
|
|
66
|
+
#:
|
|
67
|
+
#: Dictionary mapping color names to RGB tuples (0-255 range).
|
|
68
|
+
#: Includes primary colors (blue, black, white) and secondary colors
|
|
69
|
+
#: (green, magenta, yellow, grey) with multiple shades of each.
|
|
70
|
+
#:
|
|
71
|
+
#: Useful for creating plots and visualizations with consistent branding.
|
|
72
|
+
_TUWIEN_COLOR_SCHEME = {
|
|
73
|
+
"blue": (0, 102, 153),
|
|
74
|
+
"black": (0, 0, 0),
|
|
75
|
+
"white": (255, 255, 255),
|
|
76
|
+
"blue_1": (84, 133, 171),
|
|
77
|
+
"blue_2": (114, 173, 213),
|
|
78
|
+
"blue_3": (166, 213, 236),
|
|
79
|
+
"blue_4": (223, 242, 253),
|
|
80
|
+
"grey": (100, 99, 99),
|
|
81
|
+
"grey_1": (157, 157, 156),
|
|
82
|
+
"grey_2": (208, 208, 208),
|
|
83
|
+
"grey_3": (237, 237, 237),
|
|
84
|
+
"green": (0, 126, 113),
|
|
85
|
+
"green_1": (106, 170, 165),
|
|
86
|
+
"green_2": (162, 198, 194),
|
|
87
|
+
"green_3": (233, 241, 240),
|
|
88
|
+
"magenta": (186, 70, 130),
|
|
89
|
+
"magenta_1": (205, 129, 168),
|
|
90
|
+
"magenta_2": (223, 175, 202),
|
|
91
|
+
"magenta_3": (245, 229, 239),
|
|
92
|
+
"yellow": (225, 137, 34),
|
|
93
|
+
"yellow_1": (238, 180, 115),
|
|
94
|
+
"yellow_2": (245, 208, 168),
|
|
95
|
+
"yellow_3": (153, 239, 225),
|
|
96
|
+
}
|
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import torch
|
|
2
|
+
import streamlit as st
|
|
3
|
+
import os
|
|
4
|
+
import io
|
|
5
|
+
import meshio
|
|
6
|
+
import numpy as np
|
|
7
|
+
import matplotlib.pyplot as plt
|
|
8
|
+
from sklearn.manifold import TSNE
|
|
9
|
+
from sklearn.cluster import KMeans
|
|
10
|
+
from streamlit_stl import stl_from_text
|
|
11
|
+
|
|
12
|
+
import random
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
from DeepSDFStruct.pretrained_models import get_model, PRETRAINED_MODELS_DIR
|
|
16
|
+
from DeepSDFStruct.SDF import SDFfromDeepSDF
|
|
17
|
+
from DeepSDFStruct.mesh import create_3D_mesh
|
|
18
|
+
|
|
19
|
+
from mlflow import MlflowClient
|
|
20
|
+
from mlflow.entities import Experiment
|
|
21
|
+
|
|
22
|
+
client = MlflowClient(tracking_uri="sqlite:///mlruns.db")
|
|
23
|
+
|
|
24
|
+
all_exp = client.search_experiments()
|
|
25
|
+
experiments = {exp.name: exp for exp in all_exp}
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def get_runs_from_experiment(experiment: Experiment):
|
|
29
|
+
runs = client.search_runs(experiment_ids=[experiment.experiment_id])
|
|
30
|
+
return runs
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
st.set_page_config(page_title="Cluster Shape Explorer", layout="wide")
|
|
34
|
+
|
|
35
|
+
# -------------------------------------------------------------------------
|
|
36
|
+
# Sidebar: Model Selector
|
|
37
|
+
# -------------------------------------------------------------------------
|
|
38
|
+
|
|
39
|
+
available_dirs = ["Pretrained Models"] + list(experiments.keys())
|
|
40
|
+
|
|
41
|
+
model_dir = st.sidebar.selectbox("Select experiment", available_dirs, 0)
|
|
42
|
+
|
|
43
|
+
available_models = {}
|
|
44
|
+
|
|
45
|
+
if model_dir == "Pretrained Models":
|
|
46
|
+
# Local folder models
|
|
47
|
+
for name in os.listdir(PRETRAINED_MODELS_DIR):
|
|
48
|
+
path = os.path.join(PRETRAINED_MODELS_DIR, name)
|
|
49
|
+
if os.path.isdir(path):
|
|
50
|
+
available_models[name] = path
|
|
51
|
+
|
|
52
|
+
else:
|
|
53
|
+
# MLflow experiment (runs)
|
|
54
|
+
ml_exp = experiments[model_dir]
|
|
55
|
+
runs = client.search_runs(experiment_ids=[ml_exp.experiment_id])
|
|
56
|
+
|
|
57
|
+
for run in runs:
|
|
58
|
+
run_name = run.data.tags.get("mlflow.runName", run.info.run_id)
|
|
59
|
+
available_models[run_name] = run.info.artifact_uri
|
|
60
|
+
model_name = st.sidebar.selectbox("Select a model", available_models)
|
|
61
|
+
|
|
62
|
+
local_path = available_models[model_name]
|
|
63
|
+
epoch_dir = os.path.join(local_path, "ModelParameters")
|
|
64
|
+
|
|
65
|
+
available_epochs = [
|
|
66
|
+
file[:-4]
|
|
67
|
+
for file in os.listdir(epoch_dir)
|
|
68
|
+
if file.endswith(".pth") or file.endswith(".pt")
|
|
69
|
+
]
|
|
70
|
+
|
|
71
|
+
if "cluster_index" not in st.session_state.keys():
|
|
72
|
+
st.session_state.cluster_index = 0
|
|
73
|
+
|
|
74
|
+
epoch = st.sidebar.selectbox(
|
|
75
|
+
"Select epoch", available_epochs, len(available_epochs) - 1
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
# -------------------------------------------------------------------------
|
|
80
|
+
# Load model once
|
|
81
|
+
# -------------------------------------------------------------------------
|
|
82
|
+
@st.cache_resource
|
|
83
|
+
def load_model(model_name: str, epoch: str):
|
|
84
|
+
"""
|
|
85
|
+
model_dir: 'deepsdf_experiments' or mlflow experiment name
|
|
86
|
+
model_name: run-name or folder-name
|
|
87
|
+
epoch: checkpoint epoch
|
|
88
|
+
"""
|
|
89
|
+
model_path = available_models[model_name]
|
|
90
|
+
model = get_model(model_path, checkpoint=epoch)
|
|
91
|
+
sdf = SDFfromDeepSDF(model)
|
|
92
|
+
return model, sdf
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
model, sdf = load_model(model_name, epoch)
|
|
96
|
+
latent_vectors = model._trained_latent_vectors.detach().cpu().numpy()
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
# -------------------------------------------------------------------------
|
|
100
|
+
# Cluster computation (TSNE + KMeans)
|
|
101
|
+
# -------------------------------------------------------------------------
|
|
102
|
+
@st.cache_resource
|
|
103
|
+
def compute_clusters(latent_vectors, n_clusters=10, perplexity=3):
|
|
104
|
+
X_embedded = TSNE(
|
|
105
|
+
n_components=2, learning_rate="auto", init="random", perplexity=perplexity
|
|
106
|
+
).fit_transform(latent_vectors)
|
|
107
|
+
kmeans = KMeans(n_clusters=n_clusters, random_state=0).fit(X_embedded)
|
|
108
|
+
return kmeans.labels_, X_embedded
|
|
109
|
+
|
|
110
|
+
|
|
111
|
+
n_clusters = st.sidebar.slider(
|
|
112
|
+
"Number of clusters", min_value=2, max_value=20, value=10
|
|
113
|
+
)
|
|
114
|
+
labels, X_embedded = compute_clusters(latent_vectors, n_clusters=n_clusters)
|
|
115
|
+
|
|
116
|
+
# -------------------------------------------------------------------------
|
|
117
|
+
# Sidebar: Cluster selector
|
|
118
|
+
# -------------------------------------------------------------------------
|
|
119
|
+
|
|
120
|
+
# -------------------------------------------------------------------------
|
|
121
|
+
# Navigation buttons (main window)
|
|
122
|
+
# -------------------------------------------------------------------------
|
|
123
|
+
col1, col2, col3 = st.columns([1, 2, 1])
|
|
124
|
+
with col1:
|
|
125
|
+
if st.button("Prev"):
|
|
126
|
+
st.session_state.cluster_index = max(0, st.session_state.cluster_index - 1)
|
|
127
|
+
with col3:
|
|
128
|
+
if st.button("Next"):
|
|
129
|
+
st.session_state.cluster_index = min(
|
|
130
|
+
n_clusters - 1, st.session_state.cluster_index + 1
|
|
131
|
+
)
|
|
132
|
+
with col2:
|
|
133
|
+
st.text(f"Cluster {st.session_state.cluster_index+1}/{n_clusters}")
|
|
134
|
+
|
|
135
|
+
indices_in_cluster = np.argwhere(labels == st.session_state.cluster_index).flatten()
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
# -------------------------------------------------------------------------
|
|
139
|
+
# STL generation function
|
|
140
|
+
# -------------------------------------------------------------------------
|
|
141
|
+
def generate_stl(lat_vec, color_rgb):
|
|
142
|
+
lat_vec_torch = torch.tensor(lat_vec, dtype=torch.float32, device=model.device)
|
|
143
|
+
sdf.set_latent_vec(lat_vec_torch)
|
|
144
|
+
with torch.inference_mode():
|
|
145
|
+
surf_mesh, _ = create_3D_mesh(
|
|
146
|
+
sdf, 100, differentiate=False, mesh_type="surface", device=model.device
|
|
147
|
+
)
|
|
148
|
+
surf_mesh_gus = surf_mesh.to_gus()
|
|
149
|
+
surf_mesh_gus.show_options["c"] = color_rgb # apply color
|
|
150
|
+
mesh = meshio.Mesh(
|
|
151
|
+
points=surf_mesh_gus.vertices, cells=[("triangle", surf_mesh_gus.faces)]
|
|
152
|
+
)
|
|
153
|
+
output = io.StringIO()
|
|
154
|
+
meshio.write(output, mesh, file_format="stl", binary=False)
|
|
155
|
+
return output
|
|
156
|
+
|
|
157
|
+
|
|
158
|
+
# -------------------------------------------------------------------------
|
|
159
|
+
# Display selected geometry
|
|
160
|
+
# -------------------------------------------------------------------------
|
|
161
|
+
def rgb_to_hex(rgb):
|
|
162
|
+
"""Convert an RGB list [R,G,B] to hex string."""
|
|
163
|
+
return "#{:02x}{:02x}{:02x}".format(*rgb)
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
indices = [random.choice(list(indices_in_cluster)) for i in range(4)]
|
|
167
|
+
n_select = min(5, len(indices_in_cluster))
|
|
168
|
+
|
|
169
|
+
indices = random.sample(list(indices_in_cluster), n_select)
|
|
170
|
+
columns_row1 = st.columns(3)
|
|
171
|
+
columns_row2 = st.columns(3)
|
|
172
|
+
|
|
173
|
+
fig, ax = plt.subplots(figsize=(6, 6))
|
|
174
|
+
scatter = ax.scatter(
|
|
175
|
+
X_embedded[:, 0], X_embedded[:, 1], c=labels, cmap="tab10", alpha=0.6
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
# Map cluster id to color
|
|
179
|
+
cmap = plt.get_cmap("tab10")
|
|
180
|
+
cluster_color = [int(255 * c) for c in cmap(st.session_state.cluster_index)[:3]]
|
|
181
|
+
|
|
182
|
+
ax.scatter(
|
|
183
|
+
X_embedded[indices, 0],
|
|
184
|
+
X_embedded[indices, 1],
|
|
185
|
+
edgecolors="k",
|
|
186
|
+
facecolor=cmap(st.session_state.cluster_index),
|
|
187
|
+
s=120,
|
|
188
|
+
linewidths=2,
|
|
189
|
+
)
|
|
190
|
+
plt.colorbar(scatter, ax=ax, label="Cluster")
|
|
191
|
+
columns_row1[0].pyplot(fig)
|
|
192
|
+
|
|
193
|
+
for selected_idx, column in zip(indices, columns_row1[1:] + columns_row2):
|
|
194
|
+
lat_vec = latent_vectors[selected_idx]
|
|
195
|
+
|
|
196
|
+
# st.subheader(
|
|
197
|
+
# f"Latent vector index: {selected_idx} (Cluster {st.session_state.cluster_index})"
|
|
198
|
+
# )
|
|
199
|
+
stl_io = generate_stl(lat_vec, cluster_color)
|
|
200
|
+
with column:
|
|
201
|
+
stl_from_text(
|
|
202
|
+
text=stl_io.getvalue(),
|
|
203
|
+
color=rgb_to_hex(cluster_color),
|
|
204
|
+
material="material",
|
|
205
|
+
auto_rotate=True,
|
|
206
|
+
opacity=1,
|
|
207
|
+
shininess=10,
|
|
208
|
+
cam_v_angle=60,
|
|
209
|
+
cam_h_angle=-90,
|
|
210
|
+
height=500,
|
|
211
|
+
)
|