From 292eb694ba4ba50c3060ceea3a329c3d2296785d Mon Sep 17 00:00:00 2001 From: yousan Date: Thu, 15 Jan 2026 17:20:32 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=E3=83=86=E3=83=B3=E3=82=BD=E3=83=AB?= =?UTF-8?q?=E3=83=A1=E3=83=A2=E3=83=AA=E3=83=AA=E3=83=BC=E3=82=AF=E3=82=92?= =?UTF-8?q?=E4=BF=AE=E6=AD=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PeekOutput()で取得したテンソルをDisposeせずに放置していた問題を修正。 ## 修正内容 ### LLMRunner.cs - kvCache テンソル: 初回forward passで取得したKVキャッシュを即座にDispose - newKvCache テンソル: 自己回帰ループ内で毎回取得するKVキャッシュをDispose ### FlowRunner.cs - velocity テンソル: Euler ODEソルバーの各ステップで取得する速度場テンソルをDispose ## 原因 Unity AI Interface (Sentis) の `Worker.PeekOutput()` は内部バッファへの参照を返すが、 データをCPU側にコピー後、明示的にDisposeしないとメモリリークが発生する。 これにより `Found unreferenced, but undisposed CPUTensorData` 警告が出ていた。 Co-Authored-By: Claude Opus 4.5 --- .../Runtime/Inference/FlowRunner.cs | 12 ++++++--- .../uCosyVoice/Runtime/Inference/LLMRunner.cs | 26 ++++++++++++------- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/Assets/uCosyVoice/Runtime/Inference/FlowRunner.cs b/Assets/uCosyVoice/Runtime/Inference/FlowRunner.cs index b0c2038..1eef58d 100644 --- a/Assets/uCosyVoice/Runtime/Inference/FlowRunner.cs +++ b/Assets/uCosyVoice/Runtime/Inference/FlowRunner.cs @@ -189,11 +189,15 @@ public Tensor ProcessWithPrompt( _estimatorWorker.SetInput("cond", condsBatch); _estimatorWorker.Schedule(); - var velocity = _estimatorWorker.PeekOutput() as Tensor; - velocity.ReadbackAndClone(); + // Must dispose velocity tensor after copying data + float[] vData; + using (var velocity = _estimatorWorker.PeekOutput() as Tensor) + { + velocity.ReadbackAndClone(); + vData = velocity.DownloadToArray(); + } - // Download velocity and update x on CPU - var vData = velocity.DownloadToArray(); + // Download x and update on CPU var xData = xBatch.DownloadToArray(); // Euler step: x = x + dt * v diff --git a/Assets/uCosyVoice/Runtime/Inference/LLMRunner.cs b/Assets/uCosyVoice/Runtime/Inference/LLMRunner.cs index 8ae6ca1..de6a502 100644 --- a/Assets/uCosyVoice/Runtime/Inference/LLMRunner.cs +++ b/Assets/uCosyVoice/Runtime/Inference/LLMRunner.cs @@ -165,11 +165,15 @@ public Tensor GenerateWithPrompt( var hiddenStates = _backboneInitialWorker.PeekOutput("hidden_states") as Tensor; hiddenStates.ReadbackAndClone(); - // Get KV cache - var kvCache = _backboneInitialWorker.PeekOutput("past_key_values") as Tensor; - kvCache.ReadbackAndClone(); - var kvCacheData = kvCache.DownloadToArray(); - var kvCacheShape = kvCache.shape; + // Get KV cache (must dispose after copying data) + float[] kvCacheData; + TensorShape kvCacheShape; + using (var kvCache = _backboneInitialWorker.PeekOutput("past_key_values") as Tensor) + { + kvCache.ReadbackAndClone(); + kvCacheData = kvCache.DownloadToArray(); + kvCacheShape = kvCache.shape; + } lmInput.Dispose(); @@ -215,11 +219,13 @@ public Tensor GenerateWithPrompt( var newHiddenStates = _backboneDecodeWorker.PeekOutput("hidden_states") as Tensor; newHiddenStates.ReadbackAndClone(); - // Update KV cache (decode model outputs "new_past_key_values") - var newKvCache = _backboneDecodeWorker.PeekOutput("new_past_key_values") as Tensor; - newKvCache.ReadbackAndClone(); - kvCacheData = newKvCache.DownloadToArray(); - kvCacheShape = newKvCache.shape; + // Update KV cache (decode model outputs "new_past_key_values") - must dispose after copying data + using (var newKvCache = _backboneDecodeWorker.PeekOutput("new_past_key_values") as Tensor) + { + newKvCache.ReadbackAndClone(); + kvCacheData = newKvCache.DownloadToArray(); + kvCacheShape = newKvCache.shape; + } // Get logits logits = GetLogits(newHiddenStates);