Files
wehub-resource-sync ba4be087d5
Create PR to main with cherry-pick from release / cherry-pick (push) Failing after 0s
CICD NeMo / pre-flight (push) Failing after 0s
CICD NeMo / configure (push) Has been skipped
Build, validate, and release Neural Modules / pre-flight (push) Failing after 1s
CICD NeMo / code-linting (push) Has been skipped
Build, validate, and release Neural Modules / release (push) Has been skipped
Build, validate, and release Neural Modules / release-summary (push) Has been cancelled
CICD NeMo / cicd-test-container-build (push) Has been cancelled
CICD NeMo / cicd-import-tests (push) Has been cancelled
CICD NeMo / L0_Setup_Test_Data_And_Models (push) Has been cancelled
CICD NeMo / cicd-main-unit-tests (push) Has been cancelled
CICD NeMo / cicd-main-speech (push) Has been cancelled
CICD NeMo / Nemo_CICD_Test (push) Has been cancelled
CICD NeMo / Coverage (e2e) (push) Has been cancelled
CICD NeMo / Coverage (unit-test) (push) Has been cancelled
CodeQL / Analyze (python) (push) Has been cancelled
CICD NeMo / cicd-wait-in-queue (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 13:28:58 +08:00

161 lines
5.2 KiB
Python

# Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import torch
from omegaconf import DictConfig
from nemo.collections.asr.inference.streaming.framing.request import FeatureBuffer
from nemo.collections.asr.inference.utils.constants import LOG_MEL_ZERO
class FeatureBufferer:
"""
Feature bufferer class
It buffers the feature chunks and maintains the buffer.
"""
def __init__(
self,
sample_rate: int,
buffer_size_in_secs: float,
preprocessor_cfg: DictConfig,
device: torch.device,
fill_value: float = LOG_MEL_ZERO,
):
"""
Args:
sample_rate (int): sample rate
buffer_size_in_secs (float): buffer size in seconds
preprocessor_cfg (DictConfig): preprocessor config
device (torch.device): device
fill_value (float): value to fill the feature buffer with
"""
self.sample_rate = sample_rate
self.buffer_size_in_secs = buffer_size_in_secs
self.device = device
if hasattr(preprocessor_cfg, 'log') and preprocessor_cfg.log:
self.ZERO_LEVEL_SPEC_DB_VAL = LOG_MEL_ZERO
else:
self.ZERO_LEVEL_SPEC_DB_VAL = fill_value
self.n_feat = preprocessor_cfg.features
self.feature_buffer_len = int(buffer_size_in_secs / preprocessor_cfg.window_stride)
self.feature_buffer = torch.full(
[self.n_feat, self.feature_buffer_len],
self.ZERO_LEVEL_SPEC_DB_VAL,
dtype=torch.float32,
device=self.device,
)
def reset(self) -> None:
"""
Reset the buffer to zero
"""
self.feature_buffer.fill_(self.ZERO_LEVEL_SPEC_DB_VAL)
def update(self, fbuffer: FeatureBuffer) -> None:
"""
Replace feature buffer with new data
Args:
fbuffer (FeatureBuffer): feature buffer to update
"""
# Resize if needed (optional)
if fbuffer.size != self.feature_buffer.shape[1]:
self.feature_buffer = torch.full(
[self.n_feat, fbuffer.size],
self.ZERO_LEVEL_SPEC_DB_VAL,
dtype=torch.float32,
device=self.device,
)
self.feature_buffer.copy_(fbuffer.features)
def get_feature_buffer(self) -> torch.Tensor:
"""
Get the current feature buffer
Returns:
torch.Tensor: current state of the feature buffer
"""
return self.feature_buffer.clone()
class BatchedFeatureBufferer:
"""
Batched feature bufferer class
It buffers the feature chunks from multiple streams and maintains the buffers.
"""
def __init__(
self,
sample_rate: int,
buffer_size_in_secs: float,
preprocessor_cfg: DictConfig,
device: torch.device,
):
"""
Args:
sample_rate (int): sample rate
buffer_size_in_secs (float): buffer size in seconds
preprocessor_cfg (DictConfig): preprocessor config
device (torch.device): device
"""
self.sample_rate = sample_rate
self.buffer_size_in_secs = buffer_size_in_secs
self.preprocessor_cfg = preprocessor_cfg
self.device = device
self.bufferers = {}
def reset(self) -> None:
"""Reset bufferers"""
self.bufferers = {}
def rm_bufferer(self, stream_id: int) -> None:
"""
Remove bufferer for the given stream id
Args:
stream_id (int): stream id
"""
self.bufferers.pop(stream_id, None)
def update(self, fbuffers: list[FeatureBuffer]) -> list[torch.Tensor]:
"""
Update the feature bufferers with the new feature buffers.
Feature buffers can come from different streams (audios), so we need to maintain a bufferer for each stream.
Args:
fbuffers (list[FeatureBuffer]): list of feature buffers
Returns:
list[torch.Tensor]: list of feature buffers, one per input frame
"""
result_buffers = []
for fbuffer in fbuffers:
bufferer = self.bufferers.get(fbuffer.stream_id, None)
if bufferer is None:
bufferer = FeatureBufferer(
self.sample_rate,
self.buffer_size_in_secs,
self.preprocessor_cfg,
self.device,
)
self.bufferers[fbuffer.stream_id] = bufferer
bufferer.update(fbuffer)
result_buffers.append(bufferer.get_feature_buffer())
if fbuffer.is_last:
self.rm_bufferer(fbuffer.stream_id)
return result_buffers