feat: Implement unified memory management for ONNX model inference

- Introduced a new memory management policy for ONNX Runtime to release temporary GPU memory after inference completion.
- Established a shared inference entry point for all ONNX models, differentiating between long-lived sessions and temporary memory arenas.
- Updated CUDA sessions to utilize a shrinkable memory arena, reclaiming GPU memory post-inference.
- Ensured consistent memory release semantics across BEN2, DA3, MoGe-2, and Upscale models while reusing existing sessions.
- Added lifecycle tests to validate temporary memory release and session reuse.
- Modified model adapters to integrate the new memory management features, ensuring backward compatibility with existing inference behavior.
- Enhanced unit tests to cover new memory release scenarios and verify correct behavior across different execution providers.
This commit is contained in:
2026-09-01 13:22:35 +08:00
parent 4d4b892d64
commit 2ff7b04f56
24 changed files with 767 additions and 32 deletions

View File

@@ -2,6 +2,7 @@ import sys
import unittest
from pathlib import Path
from types import SimpleNamespace
from unittest.mock import patch
import numpy as np
from PIL import Image
@@ -20,6 +21,9 @@ import onnx_upscale
class FakeSession:
def get_providers(self):
return ["CPUExecutionProvider"]
def get_inputs(self):
return [SimpleNamespace(name="input")]
@@ -121,6 +125,40 @@ class UpscaleOnnxTest(unittest.TestCase):
self.assertEqual(session.calls, 6)
self.assertEqual(session.feeds["input"].shape, (1, 3, 256, 256))
def test_only_final_tile_releases_memory(self):
releases = []
session = FakeSession()
def run(model, output_names, feeds, *, release_memory):
releases.append(release_memory)
return model.run(output_names, feeds)
with patch.object(onnx_upscale, "run_session", side_effect=run):
result = onnx_upscale.infer(
session,
Image.new("RGB", (449, 225), (1, 2, 3)),
)
self.assertEqual(result.size, (1796, 900))
self.assertEqual(releases, [False, False, False, False, False, True])
def test_non_final_image_does_not_release_its_final_tile(self):
releases = []
session = FakeSession()
def run(model, output_names, feeds, *, release_memory):
releases.append(release_memory)
return model.run(output_names, feeds)
with patch.object(onnx_upscale, "run_session", side_effect=run):
onnx_upscale.infer(
session,
Image.new("RGB", (449, 225), (1, 2, 3)),
release_memory=False,
)
self.assertEqual(releases, [False] * 6)
def test_provider_unicode_error_is_presented_as_resource_error(self):
class InvalidProviderSession(FakeSession):
def run(self, _output_names, _feeds):