Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions nemo_curator/backends/experimental/ray_data/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,10 @@ def process_dataset(self, dataset: Dataset, ignore_head_node: bool = False) -> D
Returns:
Dataset: Processed Ray Data dataset
"""
# TODO: Support nvdecs / nvencs
if self.stage.resources.gpus <= 0 and (self.stage.resources.nvdecs > 0 or self.stage.resources.nvencs > 0):
msg = "Ray Data does not support nvdecs / nvencs. Please use gpus instead."
raise ValueError(msg)

is_actor_stage_ = self.stage.ray_stage_spec().get(RayStageSpecKeys.IS_ACTOR_STAGE, is_actor_stage(self.stage))

Expand Down
9 changes: 6 additions & 3 deletions nemo_curator/backends/xenna/adapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@
# limitations under the License.

from cosmos_xenna.pipelines import v1 as pipelines_v1
from cosmos_xenna.pipelines.private.resources import NodeInfo as XennaNodeInfo
from cosmos_xenna.pipelines.private.resources import Resources as XennaResources
from cosmos_xenna.pipelines.private.resources import WorkerMetadata as XennaWorkerMetadata
from cosmos_xenna.ray_utils.resources import NodeInfo as XennaNodeInfo
from cosmos_xenna.ray_utils.resources import Resources as XennaResources
from cosmos_xenna.ray_utils.resources import WorkerMetadata as XennaWorkerMetadata
from loguru import logger

from nemo_curator.backends.base import BaseStageAdapter, NodeInfo, WorkerMetadata
Expand Down Expand Up @@ -44,6 +44,9 @@ def required_resources(self) -> XennaResources:
return XennaResources(
cpus=self.processing_stage.resources.cpus,
gpus=self.processing_stage.resources.gpus,
nvdecs=self.processing_stage.resources.nvdecs,
nvencs=self.processing_stage.resources.nvencs,
entire_gpu=self.processing_stage.resources.entire_gpu,
)

@property
Expand Down
6 changes: 5 additions & 1 deletion nemo_curator/pipeline/pipeline.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ def __repr__(self) -> str:
stage_info = ", ".join([f"{s.name}({s.__class__.__name__})" for s in self.stages])
return f"Pipeline(name='{self.name}', stages=[{stage_info}])"

def describe(self) -> str:
def describe(self) -> str: # noqa: C901
"""Get a detailed description of the pipeline stages and their requirements."""
lines = [
f"Pipeline: {self.name}",
Expand All @@ -148,6 +148,10 @@ def describe(self) -> str:
lines.append(f" Resources: {stage.resources.cpus} CPUs")
if stage.resources.requires_gpu:
lines.append(f" GPU Memory: {stage.resources.gpu_memory_gb} GB ({stage.resources.gpus} GPUs)")
if stage.resources.nvdecs > 0:
lines.append(f" NVDEC: {stage.resources.nvdecs}")
if stage.resources.nvencs > 0:
lines.append(f" NVENC: {stage.resources.nvencs}")

lines.append(f" Batch size: {stage.batch_size}")

Expand Down
9 changes: 5 additions & 4 deletions nemo_curator/stages/resources.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,17 @@ class Resources:
Attributes:
cpus: Number of CPU cores required
gpu_memory_gb: GPU memory required in GB (Only for single-GPU stages)
entire_gpu: Whether to allocate entire GPU regardless of memory
nvdecs: Number of NVDEC units required
nvencs: Number of NVENC units required
entire_gpu: Whether to allocate entire GPU regardless of memory (This also gives you nvdecs and nvencs of that GPU)
gpus: Number of GPUs required (Only for multi-GPU stages)
"""

# TODO : Revisit this gpu_memory_gb, gpus, entire_gpu too many variables for gpu
cpus: float = 1.0
gpu_memory_gb: float = 0.0
nvdecs: int = 0
nvencs: int = 0
entire_gpu: bool = False
gpus: float = 0.0

Expand All @@ -66,9 +70,6 @@ def __post_init__(self):
error_message += "Please use gpus for multi-GPU stages."
raise ValueError(error_message)

if self.entire_gpu:
self.gpus = 1.0

@property
def requires_gpu(self) -> bool:
"""Check if this stage requires GPU resources."""
Expand Down
10 changes: 8 additions & 2 deletions nemo_curator/stages/video/clipping/clip_extraction_stages.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,13 @@
from dataclasses import dataclass
from typing import Any

from cosmos_xenna.ray_utils.resources import _get_local_gpu_info, _make_gpu_resources_from_gpu_name
from loguru import logger

from nemo_curator.backends.base import WorkerMetadata
from nemo_curator.backends.experimental.utils import RayStageSpecKeys
from nemo_curator.stages.base import ProcessingStage
from nemo_curator.stages.resources import Resources
from nemo_curator.stages.resources import Resources, _get_gpu_memory_gb
from nemo_curator.tasks.video import Clip, Video, VideoTask
from nemo_curator.utils import grouping
from nemo_curator.utils.operation_utils import make_pipeline_temporary_dir
Expand Down Expand Up @@ -78,7 +79,12 @@ def __post_init__(self) -> None:
if self.encoder == "h264_nvenc" or self.use_hwaccel:
if self.nb_streams_per_gpu > 0:
# Assume that we have same type of GPUs
self.resources = Resources(gpus=1.0 / self.nb_streams_per_gpu)
gpu_info = _get_local_gpu_info()[0]
nvencs = _make_gpu_resources_from_gpu_name(gpu_info.name).num_nvencs
Comment on lines +82 to +83

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Accessing [0] assumes at least one GPU is available. This will raise an IndexError if no GPUs are detected. Should this handle the case where no GPUs are available or add validation?

gpu_memory_gb = _get_gpu_memory_gb()
self.resources = Resources(
nvencs=nvencs // self.nb_streams_per_gpu, gpu_memory_gb=gpu_memory_gb // self.nb_streams_per_gpu
)
Comment on lines +86 to +87

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

logic: Integer division by nb_streams_per_gpu could result in zero resources if the divisor is larger than the dividend. What should happen when nb_streams_per_gpu exceeds available nvencs or gpu_memory_gb?

else:
self.resources = Resources(gpus=1)
else:
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ classifiers = [
dependencies = [
"absl-py>=2.0.0,<3.0.0",
"comment_parser",
"cosmos-xenna==0.1.8",
"cosmos-xenna==0.1.2",
"fsspec",
"hydra-core",
"jieba==0.42.1",
Expand Down
29 changes: 7 additions & 22 deletions tests/stages/video/clipping/test_clip_transcoding_stage.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ def __init__(self, index: int, name: str):
self.name = name


# Mock GPU resources class to simulate GPU resources
class MockGpuResources:
def __init__(self, num_nvencs: int = 3, num_nvdecs: int = 3):
self.num_nvencs = num_nvencs
self.num_nvdecs = num_nvdecs

Comment on lines +37 to +42

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

style: MockGpuResources class is defined but never used in any test. Either add tests for the new nvenc-based resource allocation in ClipTranscodingStage.__post_init__ that use this mock, or remove the dead code.


class TestClipTranscodingStage:
"""Test cases for ClipTranscodingStage."""

Expand Down Expand Up @@ -273,28 +280,6 @@ def test_add_hwaccel_options_disabled(self) -> None:
# Should not add any hwaccel options
assert "-hwaccel" not in command

def test_add_hwaccel_options_enabled(self) -> None:
"""Test hardware acceleration options when enabled."""
command = []
stage = ClipTranscodingStage(use_hwaccel=True, encoder="h264_nvenc", nb_streams_per_gpu=1)

stage._add_hwaccel_options(command)

assert "-hwaccel" in command
assert "-hwaccel_output_format" in command
assert stage.resources.gpus == 1.0

def test_add_hwaccel_options_enabled_multiple_streams(self) -> None:
"""Test hardware acceleration options when enabled."""
command = []
stage = ClipTranscodingStage(use_hwaccel=True, encoder="h264_nvenc", nb_streams_per_gpu=4)

stage._add_hwaccel_options(command)

assert "-hwaccel" in command
assert "-hwaccel_output_format" in command
assert stage.resources.gpus == 0.25

def test_add_input_options(self) -> None:
"""Test adding input options to FFmpeg command."""
command = []
Expand Down
Loading
Loading