autoforge 1.9.3__tar.gz → 1.9.4__tar.gz
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.
- {autoforge-1.9.3 → autoforge-1.9.4}/PKG-INFO +1 -1
- {autoforge-1.9.3 → autoforge-1.9.4}/pyproject.toml +1 -1
- {autoforge-1.9.3 → autoforge-1.9.4}/src/AutoForge.egg-info/PKG-INFO +1 -1
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/PruningHelper.py +145 -83
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/filamentcolors_library.py +2 -1
- {autoforge-1.9.3 → autoforge-1.9.4}/README.md +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/setup.cfg +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/AutoForge.egg-info/SOURCES.txt +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/AutoForge.egg-info/dependency_links.txt +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/AutoForge.egg-info/entry_points.txt +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/AutoForge.egg-info/requires.txt +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/AutoForge.egg-info/top_level.txt +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/AmpUtils.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/CAdamW.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/FilamentHelper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/Heightmaps/ChristofidesHeightMap.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/Heightmaps/DepthEstimateHeightMap.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/Heightmaps/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/ImageHelper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/OptimizerHelper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/OtherHelper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/OutputHelper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Init_comparer/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Init_comparer/auto_forge_init_check.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Init_comparer/plot_results.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Loss/LossFunctions.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Loss/PerceptionLoss.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Loss/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Misc/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Misc/color_fit_all.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Modules/Optimizer.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Modules/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/__init__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/__main__.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/auto_forge.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/priority_mask_editor.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_amp_autocast_probe.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_cadamw.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_christofides_height_map.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_christofides_heightmap.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_depth_adjusted_height_map.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_depth_estimate_height_map.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_end_to_end_optimizer.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_filament_and_output.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_filament_helper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_flatforge.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_heightmap_init.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_image_helper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_loss_functions.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_optimizer_helper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_optimizer_module.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_optimizer_smoke.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_output_helper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_output_helper_extended.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_perception_and_pruning.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_property_based.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_pruning_helper.py +0 -0
- {autoforge-1.9.3 → autoforge-1.9.4}/tests/test_remove_height_spikes.py +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "AutoForge"
|
|
7
|
-
version="1.9.
|
|
7
|
+
version="1.9.4"
|
|
8
8
|
description = "AutoForge is a Python tool for generating 3D printed layered models from an input image."
|
|
9
9
|
authors = [{ name = "Hendric Voss", email = "hvoss@techfak.uni-bielefeld.de" }]
|
|
10
10
|
readme = "README.md"
|
|
@@ -10,6 +10,7 @@ import numpy as np
|
|
|
10
10
|
from autoforge.Helper.OptimizerHelper import composite_image_disc
|
|
11
11
|
from autoforge.Loss.LossFunctions import compute_loss
|
|
12
12
|
from autoforge.Modules.Optimizer import FilamentOptimizer
|
|
13
|
+
from collections import deque
|
|
13
14
|
|
|
14
15
|
# One global lock that serialises every call that needs GPU / VRAM
|
|
15
16
|
_gpu_lock = threading.Lock()
|
|
@@ -46,22 +47,15 @@ def _chunked(iterable, chunk_size):
|
|
|
46
47
|
def prune_num_colors(
|
|
47
48
|
optimizer: FilamentOptimizer,
|
|
48
49
|
max_colors_allowed: int,
|
|
49
|
-
tau_for_comp: float,
|
|
50
|
-
perception_loss_module: torch.nn.Module,
|
|
51
|
-
n_jobs: int | None = -1,
|
|
50
|
+
tau_for_comp: float,
|
|
51
|
+
perception_loss_module: torch.nn.Module,
|
|
52
|
+
n_jobs: int | None = -1,
|
|
52
53
|
*,
|
|
53
|
-
fast: bool = True,
|
|
54
|
-
chunking_percent=0.05,
|
|
55
|
-
allowed_loss_increase_percent=0.00,
|
|
54
|
+
fast: bool = True,
|
|
55
|
+
chunking_percent=0.05,
|
|
56
|
+
allowed_loss_increase_percent=0.00,
|
|
56
57
|
) -> torch.Tensor:
|
|
57
|
-
"""Iteratively merge materials until the number of distinct colors is
|
|
58
|
-
<= max_colors_allowed or until merging would worsen the loss.
|
|
59
58
|
|
|
60
|
-
When *fast* is True we only look at 10 percent of the candidate merges at a
|
|
61
|
-
time. If none of those improve the objective we look at the next 10 percent
|
|
62
|
-
and so on. In the worst case we still examine every merge, in the best case
|
|
63
|
-
we stop after the first improving chunk, saving work.
|
|
64
|
-
"""
|
|
65
59
|
num_materials = optimizer.material_colors.shape[0]
|
|
66
60
|
disc_global, _ = optimizer.get_discretized_solution(best=True)
|
|
67
61
|
|
|
@@ -70,28 +64,41 @@ def prune_num_colors(
|
|
|
70
64
|
) -> tuple[float, torch.Tensor]:
|
|
71
65
|
dg_test = merge_color(dg_base, c_from, c_to)
|
|
72
66
|
logits_for_disc = disc_to_logits(dg_test, num_materials, big_pos=1e5)
|
|
67
|
+
|
|
73
68
|
with _gpu_lock, torch.no_grad():
|
|
74
69
|
out_im = optimizer.get_best_discretized_image(
|
|
75
70
|
custom_global_logits=logits_for_disc
|
|
76
71
|
)
|
|
77
72
|
loss = compute_loss(comp=out_im, target=optimizer.target)
|
|
73
|
+
|
|
78
74
|
return loss, dg_test
|
|
79
75
|
|
|
80
76
|
def get_image_loss(dg_test: torch.Tensor) -> float:
|
|
81
77
|
logits_for_disc = disc_to_logits(dg_test, num_materials, big_pos=1e5)
|
|
78
|
+
|
|
82
79
|
with _gpu_lock, torch.no_grad():
|
|
83
80
|
out_im = optimizer.get_best_discretized_image(
|
|
84
81
|
custom_global_logits=logits_for_disc
|
|
85
82
|
)
|
|
86
83
|
loss = compute_loss(comp=out_im, target=optimizer.target)
|
|
84
|
+
|
|
87
85
|
return loss
|
|
88
86
|
|
|
89
87
|
best_dg = disc_global.clone()
|
|
90
88
|
best_loss = get_image_loss(best_dg)
|
|
91
89
|
|
|
90
|
+
distinct_mats = torch.unique(best_dg)
|
|
91
|
+
|
|
92
|
+
print(f"PRUNING: Color - initial loss={best_loss:.4f}, initial colors={len(distinct_mats)}")
|
|
93
|
+
|
|
92
94
|
tbar = tqdm(total=100, leave=False)
|
|
95
|
+
|
|
93
96
|
while True:
|
|
94
97
|
distinct_mats = torch.unique(best_dg)
|
|
98
|
+
|
|
99
|
+
if len(distinct_mats) <= 1:
|
|
100
|
+
break
|
|
101
|
+
|
|
95
102
|
merge_pairs = [
|
|
96
103
|
(c_from.item(), c_to.item())
|
|
97
104
|
for c_from in distinct_mats
|
|
@@ -110,69 +117,80 @@ def prune_num_colors(
|
|
|
110
117
|
if fast:
|
|
111
118
|
random.shuffle(merge_pairs)
|
|
112
119
|
chunk_size = max(1, math.ceil(len(merge_pairs) * chunking_percent))
|
|
120
|
+
|
|
113
121
|
improved = False
|
|
114
|
-
|
|
115
|
-
|
|
122
|
+
best_candidate = None
|
|
123
|
+
best_candidate_loss = float("inf")
|
|
124
|
+
|
|
116
125
|
for chunk in _chunked(merge_pairs, chunk_size):
|
|
117
126
|
cand_results = Parallel(
|
|
118
127
|
n_jobs=n_jobs, backend="threading", prefer="threads"
|
|
119
128
|
)(delayed(score_color)(best_dg, *pair) for pair in chunk)
|
|
129
|
+
|
|
120
130
|
merge_loss, merge_dg = min(cand_results, key=lambda x: x[0])
|
|
131
|
+
|
|
121
132
|
if merge_loss < best_loss * (1 + allowed_loss_increase_percent):
|
|
122
|
-
best_dg
|
|
133
|
+
best_dg = merge_dg
|
|
134
|
+
best_loss = merge_loss
|
|
123
135
|
improved = True
|
|
124
|
-
break
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
c_loss = merge_loss
|
|
130
|
-
if c_cand is not None:
|
|
131
|
-
best_dg, best_loss = c_cand
|
|
132
|
-
distinct_mats = torch.unique(best_dg)
|
|
133
|
-
optimizer.best_params["global_logits"] = disc_to_logits(
|
|
134
|
-
best_dg, num_materials=num_materials, big_pos=1e5
|
|
135
|
-
)
|
|
136
|
-
tbar.set_description(
|
|
137
|
-
f"Colors {len(distinct_mats)} | Loss {best_loss:.4f} | Merge pairs {len(merge_pairs)}"
|
|
138
|
-
)
|
|
139
|
-
improved = True
|
|
136
|
+
break
|
|
137
|
+
|
|
138
|
+
if merge_loss < best_candidate_loss:
|
|
139
|
+
best_candidate = merge_dg
|
|
140
|
+
best_candidate_loss = merge_loss
|
|
140
141
|
|
|
141
142
|
if not improved:
|
|
142
|
-
|
|
143
|
+
if len(distinct_mats) > max_colors_allowed and best_candidate is not None:
|
|
144
|
+
best_dg = best_candidate
|
|
145
|
+
best_loss = best_candidate_loss
|
|
146
|
+
else:
|
|
147
|
+
break
|
|
148
|
+
|
|
143
149
|
else:
|
|
144
150
|
cand_results = Parallel(
|
|
145
151
|
n_jobs=n_jobs, backend="threading", prefer="threads"
|
|
146
152
|
)(delayed(score_color)(best_dg, *pair) for pair in merge_pairs)
|
|
153
|
+
|
|
147
154
|
merge_loss, merge_dg = min(cand_results, key=lambda x: x[0])
|
|
155
|
+
|
|
148
156
|
if merge_loss < best_loss or len(distinct_mats) > max_colors_allowed:
|
|
149
|
-
best_dg
|
|
157
|
+
best_dg = merge_dg
|
|
158
|
+
best_loss = merge_loss
|
|
150
159
|
else:
|
|
151
160
|
break
|
|
152
161
|
|
|
153
162
|
tbar.close()
|
|
163
|
+
|
|
154
164
|
optimizer.best_params["global_logits"] = disc_to_logits(
|
|
155
165
|
best_dg, num_materials=num_materials, big_pos=1e5
|
|
156
166
|
)
|
|
167
|
+
|
|
168
|
+
final_colors = torch.unique(best_dg)
|
|
169
|
+
|
|
170
|
+
assert len(final_colors) <= max_colors_allowed, (
|
|
171
|
+
f"Color pruning failed: {len(final_colors)} > {max_colors_allowed}"
|
|
172
|
+
)
|
|
173
|
+
|
|
174
|
+
print(f"PRUNING: Color - final loss={best_loss:.4f}, final colors={len(final_colors)}")
|
|
175
|
+
|
|
157
176
|
return best_dg
|
|
158
177
|
|
|
159
178
|
|
|
160
179
|
def prune_num_swaps(
|
|
161
180
|
optimizer: FilamentOptimizer,
|
|
162
181
|
max_swaps_allowed: int,
|
|
163
|
-
tau_for_comp: float,
|
|
164
|
-
perception_loss_module: torch.nn.Module,
|
|
165
|
-
n_jobs: int | None = -1,
|
|
182
|
+
tau_for_comp: float,
|
|
183
|
+
perception_loss_module: torch.nn.Module,
|
|
184
|
+
n_jobs: int | None = -1,
|
|
166
185
|
*,
|
|
167
|
-
fast: bool = True,
|
|
168
|
-
chunking_percent=0.05,
|
|
169
|
-
allowed_loss_increase_percent=0.000,
|
|
186
|
+
fast: bool = True,
|
|
187
|
+
chunking_percent=0.05,
|
|
188
|
+
allowed_loss_increase_percent=0.000,
|
|
170
189
|
) -> torch.Tensor:
|
|
171
|
-
"""Reduce the number of color boundaries until it is
|
|
172
|
-
|
|
173
|
-
loss. The *fast* parameter activates the same 10 percent chunk search logic
|
|
174
|
-
used in *prune_num_colors*.
|
|
190
|
+
"""Reduce the number of color boundaries until it is <= max_swaps_allowed.
|
|
191
|
+
If necessary, merges are forced even when they worsen the loss.
|
|
175
192
|
"""
|
|
193
|
+
|
|
176
194
|
num_materials = optimizer.material_colors.shape[0]
|
|
177
195
|
disc_global, _ = optimizer.get_discretized_solution(best=True)
|
|
178
196
|
|
|
@@ -198,10 +216,17 @@ def prune_num_swaps(
|
|
|
198
216
|
best_dg = disc_global.clone()
|
|
199
217
|
best_loss = get_image_loss(best_dg)
|
|
200
218
|
|
|
219
|
+
bands = find_color_bands(best_dg)
|
|
220
|
+
num_swaps = len(bands) - 1
|
|
221
|
+
|
|
222
|
+
print(f"PRUNING: Swap - initial loss={best_loss:.4f}, initial swaps={num_swaps:d}")
|
|
223
|
+
|
|
201
224
|
tbar = tqdm(total=100, leave=False)
|
|
225
|
+
|
|
202
226
|
while True:
|
|
203
227
|
bands = find_color_bands(best_dg)
|
|
204
228
|
num_swaps = len(bands) - 1
|
|
229
|
+
|
|
205
230
|
if num_swaps == 0:
|
|
206
231
|
break
|
|
207
232
|
|
|
@@ -223,38 +248,45 @@ def prune_num_swaps(
|
|
|
223
248
|
if fast:
|
|
224
249
|
random.shuffle(merge_specs)
|
|
225
250
|
chunk_size = max(1, math.ceil(len(merge_specs) * chunking_percent))
|
|
251
|
+
|
|
226
252
|
improved = False
|
|
227
|
-
|
|
228
|
-
|
|
253
|
+
best_candidate = None
|
|
254
|
+
best_candidate_loss = float("inf")
|
|
255
|
+
|
|
229
256
|
for chunk in _chunked(merge_specs, chunk_size):
|
|
257
|
+
|
|
230
258
|
cand_results = Parallel(
|
|
231
259
|
n_jobs=n_jobs, backend="threading", prefer="threads"
|
|
232
260
|
)(
|
|
233
261
|
delayed(score_swap)(best_dg, band_a, band_b, direction)
|
|
234
262
|
for band_a, band_b, direction in chunk
|
|
235
263
|
)
|
|
264
|
+
|
|
236
265
|
merge_loss, merge_dg = min(cand_results, key=lambda x: x[0])
|
|
266
|
+
|
|
267
|
+
# Accept merge if loss increase is allowed
|
|
237
268
|
if merge_loss < best_loss * (1 + allowed_loss_increase_percent):
|
|
238
269
|
best_dg, best_loss = merge_dg, merge_loss
|
|
239
270
|
improved = True
|
|
240
271
|
break
|
|
241
|
-
else:
|
|
242
|
-
if num_swaps > max_swaps_allowed and merge_loss < c_loss:
|
|
243
|
-
c_cand = (merge_dg, merge_loss)
|
|
244
|
-
c_loss = merge_loss
|
|
245
|
-
if c_cand is not None:
|
|
246
|
-
best_dg, best_loss = c_cand
|
|
247
|
-
num_swaps = len(find_color_bands(best_dg)) - 1
|
|
248
|
-
optimizer.best_params["global_logits"] = disc_to_logits(
|
|
249
|
-
best_dg, num_materials=num_materials, big_pos=1e5
|
|
250
|
-
)
|
|
251
|
-
tbar.set_description(
|
|
252
|
-
f"Swaps {num_swaps} | Loss {best_loss:.4f} | Merge swaps {len(merge_specs)}"
|
|
253
|
-
)
|
|
254
|
-
improved = True
|
|
255
272
|
|
|
273
|
+
# Track best candidate for forced merge
|
|
274
|
+
if merge_loss < best_candidate_loss:
|
|
275
|
+
best_candidate = (merge_dg, merge_loss)
|
|
276
|
+
best_candidate_loss = merge_loss
|
|
277
|
+
|
|
278
|
+
bands = find_color_bands(best_dg)
|
|
279
|
+
num_swaps = len(bands) - 1
|
|
280
|
+
|
|
281
|
+
# If no acceptable merge but we still exceed swap budget,
|
|
282
|
+
# force the best candidate.
|
|
256
283
|
if not improved:
|
|
257
|
-
|
|
284
|
+
if num_swaps > max_swaps_allowed and best_candidate is not None:
|
|
285
|
+
best_dg, best_loss = best_candidate
|
|
286
|
+
improved = True
|
|
287
|
+
else:
|
|
288
|
+
break
|
|
289
|
+
|
|
258
290
|
else:
|
|
259
291
|
cand_results = Parallel(
|
|
260
292
|
n_jobs=n_jobs, backend="threading", prefer="threads"
|
|
@@ -262,16 +294,28 @@ def prune_num_swaps(
|
|
|
262
294
|
delayed(score_swap)(best_dg, band_a, band_b, direction)
|
|
263
295
|
for band_a, band_b, direction in merge_specs
|
|
264
296
|
)
|
|
297
|
+
|
|
265
298
|
merge_loss, merge_dg = min(cand_results, key=lambda x: x[0])
|
|
299
|
+
|
|
266
300
|
if merge_loss < best_loss or num_swaps > max_swaps_allowed:
|
|
267
301
|
best_dg, best_loss = merge_dg, merge_loss
|
|
268
302
|
else:
|
|
269
303
|
break
|
|
270
304
|
|
|
305
|
+
print(f"PRUNING: Swap - final loss={best_loss:.4f}, final swaps={len(find_color_bands(best_dg)) - 1:d}")
|
|
306
|
+
|
|
271
307
|
tbar.close()
|
|
308
|
+
|
|
272
309
|
optimizer.best_params["global_logits"] = disc_to_logits(
|
|
273
310
|
best_dg, num_materials=num_materials, big_pos=1e5
|
|
274
311
|
)
|
|
312
|
+
|
|
313
|
+
# safety check
|
|
314
|
+
final_swaps = len(find_color_bands(best_dg)) - 1
|
|
315
|
+
assert final_swaps <= max_swaps_allowed, (
|
|
316
|
+
f"Swap pruning failed: {final_swaps} swaps > {max_swaps_allowed}"
|
|
317
|
+
)
|
|
318
|
+
|
|
275
319
|
return best_dg
|
|
276
320
|
|
|
277
321
|
|
|
@@ -417,6 +461,8 @@ def prune_redundant_layers(
|
|
|
417
461
|
# Baseline loss with current best parameters
|
|
418
462
|
best_loss = get_initial_loss(current_max_layers, optimizer)
|
|
419
463
|
|
|
464
|
+
print(f"PRUNING: Layer - initial loss={best_loss:.4f}, initial layer={current_max_layers:d}")
|
|
465
|
+
|
|
420
466
|
tbar = tqdm(
|
|
421
467
|
desc=f"Layer pruning | Loss {best_loss:.4f}",
|
|
422
468
|
total=max(current_max_layers - 1, 0),
|
|
@@ -550,6 +596,8 @@ def prune_redundant_layers(
|
|
|
550
596
|
else:
|
|
551
597
|
break
|
|
552
598
|
|
|
599
|
+
print(f"PRUNING: Layers - final loss={best_loss:.4f}, final layers={current_max_layers:d}")
|
|
600
|
+
|
|
553
601
|
tbar.close()
|
|
554
602
|
return optimizer.best_params, best_loss, current_max_layers
|
|
555
603
|
|
|
@@ -807,6 +855,7 @@ def optimise_swap_positions(
|
|
|
807
855
|
|
|
808
856
|
best_dg, _ = optimizer.get_discretized_solution(best=True)
|
|
809
857
|
best_loss = disc_loss(best_dg)
|
|
858
|
+
print(f"PRUNING: Swap position - initial loss={best_loss:.4f}")
|
|
810
859
|
|
|
811
860
|
outer_tbar = tqdm(desc="Optimising swap positions", total=100, leave=False)
|
|
812
861
|
improved = True
|
|
@@ -857,13 +906,14 @@ def optimise_swap_positions(
|
|
|
857
906
|
outer_tbar.set_description(
|
|
858
907
|
f"Swap {swap_idx} moved {old_pos}->{new_pos} | Loss {best_loss:.4f}"
|
|
859
908
|
)
|
|
860
|
-
print(
|
|
861
|
-
|
|
862
|
-
)
|
|
909
|
+
# print(
|
|
910
|
+
# f"Swap {swap_idx} moved {old_pos}->{new_pos} | Loss {best_loss:.4f}"
|
|
911
|
+
# )
|
|
863
912
|
improved = True
|
|
864
913
|
break
|
|
865
914
|
|
|
866
915
|
outer_tbar.close()
|
|
916
|
+
print(f"PRUNING: Swap position - final loss={best_loss:.4f}")
|
|
867
917
|
return best_dg
|
|
868
918
|
|
|
869
919
|
|
|
@@ -937,26 +987,38 @@ def remove_height_spikes(
|
|
|
937
987
|
|
|
938
988
|
out = dh_np.copy()
|
|
939
989
|
spikes = 0
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
990
|
+
queue = deque((y, x) for y in range(1, H - 1) for x in range(1, W - 1))
|
|
991
|
+
total_num = len(queue)
|
|
992
|
+
max_iters = (H - 2) * (W - 2) * 10 # safety cap
|
|
993
|
+
iters = 0
|
|
994
|
+
tbar = tqdm(total=total_num, desc="Removing height spikes", leave=False)
|
|
995
|
+
while queue and iters < max_iters:
|
|
996
|
+
tbar.update(1)
|
|
997
|
+
y, x = queue.popleft()
|
|
998
|
+
iters += 1
|
|
999
|
+
window = out[y - 1: y + 2, x - 1: x + 2]
|
|
1000
|
+
replacement, is_spike, _ = _median_without_outliers(
|
|
1001
|
+
window, threshold_layers, max_outliers
|
|
1002
|
+
)
|
|
1003
|
+
center_val = out[y, x]
|
|
1004
|
+
if (
|
|
1005
|
+
not is_spike
|
|
1006
|
+
or center_val < replacement + threshold_layers
|
|
1007
|
+
or replacement == center_val
|
|
1008
|
+
):
|
|
1009
|
+
continue
|
|
1010
|
+
out[y, x] = replacement
|
|
1011
|
+
spikes += 1
|
|
1012
|
+
for ny in range(y - 1, y + 2):
|
|
1013
|
+
if ny <= 0 or ny >= H - 1:
|
|
956
1014
|
continue
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
1015
|
+
for nx in range(x - 1, x + 2):
|
|
1016
|
+
if nx <= 0 or nx >= W - 1:
|
|
1017
|
+
continue
|
|
1018
|
+
queue.append((ny, nx))
|
|
1019
|
+
total_num += 1
|
|
1020
|
+
tbar.total = total_num
|
|
1021
|
+
tbar.close()
|
|
960
1022
|
|
|
961
1023
|
if spikes == 0:
|
|
962
1024
|
return disc_height, 0
|
|
@@ -2,7 +2,7 @@ import json
|
|
|
2
2
|
import os
|
|
3
3
|
import time
|
|
4
4
|
import traceback
|
|
5
|
-
|
|
5
|
+
import time
|
|
6
6
|
import requests
|
|
7
7
|
from tqdm import tqdm
|
|
8
8
|
|
|
@@ -89,6 +89,7 @@ def download_all_pages(url):
|
|
|
89
89
|
all_results.extend(data.get("results", []))
|
|
90
90
|
url = data.get("next")
|
|
91
91
|
tbar.update(1)
|
|
92
|
+
time.sleep(5)
|
|
92
93
|
return all_results
|
|
93
94
|
|
|
94
95
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/Heightmaps/ChristofidesHeightMap.py
RENAMED
|
File without changes
|
{autoforge-1.9.3 → autoforge-1.9.4}/src/autoforge/Helper/Heightmaps/DepthEstimateHeightMap.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|