Source code for cursus.steps.configs.config_xgboost_model_step

from pydantic import Field, model_validator, field_validator
from typing import List, Optional, Dict
from datetime import datetime

from ...core.base.config_base import BasePipelineConfig


[docs] class XGBoostModelStepConfig(BasePipelineConfig): """Configuration specific to the SageMaker XGBoost Model creation (for inference).""" # Renamed from inference_instance_type for consistency with builder instance_type: str = Field( default="ml.m5.large", description="Instance type for inference endpoint/transform job.", ) # Renamed from inference_entry_point for consistency with builder entry_point: str = Field( default="inference.py", description="Entry point script for inference." ) framework_version: str = Field( default="1.5-1", # Updated default to XGBoost version description="XGBoost framework version", ) # source_dir is inherited from BasePipelineConfig # Python version for the SageMaker XGBoost container py_version: str = Field( default="py3", description="Python version for the SageMaker XGBoost container." ) # Accelerator type for inference accelerator_type: Optional[str] = Field( default=None, description="Accelerator type for inference endpoint." ) # Model name model_name: Optional[str] = Field( default=None, description="Name for the SageMaker model." ) # Tags for the model tags: Optional[List[Dict[str, str]]] = Field( default=None, description="Tags for the model." ) # Endpoint / Container specific settings initial_instance_count: int = Field( default=1, ge=1, description="Initial instance count for endpoint (used by EndpointConfig).", ) container_startup_health_check_timeout: int = Field( default=300, ge=60, description="Container startup health check timeout (seconds).", ) container_memory_limit: int = Field( default=6144, ge=1024, description="Container memory limit (MB)." ) data_download_timeout: int = Field( default=900, ge=60, description="Model data download timeout (seconds)." ) inference_memory_limit: int = Field( default=6144, ge=1024, description="Inference memory limit (MB)." ) max_concurrent_invocations: int = Field( default=10, ge=1, description="Max concurrent invocations per instance." ) max_payload_size: int = Field( default=6, ge=1, le=100, description="Max payload size (MB) for inference." ) model_config = BasePipelineConfig.model_config
[docs] @model_validator(mode="after") def validate_configuration(self) -> "XGBoostModelStepConfig": """Validate the complete configuration""" self._validate_memory_constraints() self._validate_timeouts() self._validate_entry_point() self._validate_framework_version() return self
def _validate_memory_constraints(self) -> None: """Validate memory-related constraints""" if self.inference_memory_limit > self.container_memory_limit: raise ValueError( f"Inference memory limit ({self.inference_memory_limit}MB) cannot exceed " f"container memory limit ({self.container_memory_limit}MB)" ) def _validate_timeouts(self) -> None: """Validate timeout-related configurations""" if self.container_startup_health_check_timeout > self.data_download_timeout: raise ValueError( "Container startup health check timeout should not exceed data download timeout" ) def _validate_entry_point(self) -> None: """Validate entry point configuration (without file existence checks)""" # Removed file existence validation to improve configuration portability # File validation should happen at execution time in builders, not at config creation time # Only validate that source_dir is provided if entry_point is a relative path if self.entry_point and not self.entry_point.startswith("s3://"): if not self.source_dir: raise ValueError( "source_dir must be provided when entry_point is a relative path" ) def _validate_framework_version(self) -> None: """Validate XGBoost framework version""" valid_versions = [ "1.5-1", "1.3-1", "1.2-2", "1.2-1", ] # Add more versions as needed if self.framework_version not in valid_versions: raise ValueError( f"Invalid XGBoost framework version: {self.framework_version}. " f"Must be one of {valid_versions}" )
[docs] @field_validator("inference_memory_limit") @classmethod def validate_memory_limits(cls, v: int, info) -> int: container_memory_limit = info.data.get("container_memory_limit") if container_memory_limit and v > container_memory_limit: raise ValueError( "Inference memory limit cannot exceed container memory limit" ) return v
@field_validator("instance_type") @classmethod def _validate_sagemaker_inference_instance_type(cls, v: str) -> str: if not v.startswith("ml."): raise ValueError( f"Invalid inference instance type: {v}. Must start with 'ml.'" ) return v
[docs] def get_model_name(self) -> str: """Generate a unique model name if not provided""" if self.model_name: return self.model_name timestamp = datetime.now().strftime("%Y%m%d-%H%M%S") return f"xgb-{self.pipeline_name}-model-{timestamp}"
[docs] def get_endpoint_config_name(self) -> str: """Generate endpoint configuration name""" return f"{self.get_model_name()}-config"
[docs] def get_endpoint_name(self) -> str: """Generate endpoint name""" return f"xgb-{self.pipeline_name}-endpoint"