Repository navigation
Conversation
1725779 to
38b75f5
Compare
Installing sagemaker-serve (or the umbrella sagemaker, which depends on it) pulled torch, and on Linux the ~2.9 GB CUDA/cuDNN/NCCL closure, even for API-only use. sagemaker-core already declared torch an extra; sagemaker-serve declared it required, so serve users paid regardless. The import-time blocker was DEFAULT_SERIALIZERS_BY_FRAMEWORK in serve/constants.py, which instantiated TorchTensorSerializer() at module scope, running `from torch import Tensor` on any `import sagemaker.serve`. Changes: - Store serializer/deserializer classes (not instances) in DEFAULT_SERIALIZERS_BY_FRAMEWORK; instantiate on lookup. Removes the import-time torch dependency. - Move torch>=2.0.0 to a `torch` extra in sagemaker-serve, matching sagemaker-core. Add a `torch` extra to the umbrella sagemaker package (sagemaker-serve[torch]) so `pip install sagemaker[torch]` works. - Duck-type the tensor check in TorchTensorSerializer: serialization only needs the object's own detach()/numpy(), so it no longer imports torch at all and works whenever the caller holds a tensor. - Make the in-process model server's torch import lazy with a CPU fallback, so importing it no longer requires torch. - Fix the error messages that told serve users to install the wrong package: TorchTensorDeserializer, the Triton translator, and the ONNX export path now name sagemaker-serve[torch]. - Update and add tests asserting the whole surface imports and serializes without torch, and that the paths that genuinely construct torch objects (deserializer, Triton translator) still raise a clear error naming the extra. Fixes aws#5531 Breaking change: users who installed plain sagemaker-serve and relied on a torch code path (deserializing to tensor/pt, or ONNX/Triton export of a PyTorch model) must now install sagemaker-serve[torch]. Both paths inherently require a torch object the caller supplies, so torch is already present in practice; a GitHub-wide search found no external callers of these paths that do not already import torch. --- X-AI-Prompt: address the reviewer concern on whether making torch optional breaks existing customers; find ways to reduce the torch dependency and update pyproject and docs; consolidate all changes in the goelakash93 fork for a possible major version bump. X-AI-Tool: Claude Code
38b75f5 to
299438e
Compare
The reviewer aborted on every fork PR with "Actor does not have write permissions to the repository" (e.g. run 31217496013 on #6166), so it only ever ran for collaborators. claude-code-action checks that the PR author has write access before doing anything. That default protects its normal @claude usage, where a read-only user's comment becomes the prompt. It does not apply here: pull_request_target always runs the base-branch copy of this workflow, so the prompt is fixed by maintainers and a fork cannot supply it. Set allowed_non_write_users so the review actually runs, and harden the prompt-injection surface it exposes (untrusted diff/PR text entering context): - deny Read on /proc, /sys, ~/.aws, the Actions _temp dir and .git/config so an injected instruction cannot use the review comment as a secret-exfiltration channel - instruct the model to treat all contributor-authored content as data, never as instructions, and to report attempted injection Fork PRs continue to require maintainer approval via the manual-approval environment, Bash/Write/Edit remain unavailable, and the assumed role is still limited to bedrock:InvokeModel on a single inference profile.
aws#6512 made the sagemaker-serve serving backends extras, but four gaps kept torch from being genuinely optional (aws#5531). All four were diagnosed first in aws#6166. Selecting the PyTorch default serializer still required torch. ``TorchTensorSerializer.__init__`` imported torch, so the lazy registry only deferred the failure to ``_fetch_serializer_and_deserializer_for_framework``. A client deploying a prebuilt PyTorch container detects the framework from the image URI and never touches a tensor, so it hit an ImportError for a dependency it had no use for. The type check now consults ``sys.modules``: a torch.Tensor cannot exist unless torch has already been imported, so the check stays exact without triggering an import. ``torch_tensor`` becomes a property, keeping the attribute and its ImportError for callers that want the type itself. Membership tests built the pair they were asking about. The registry inherited ``Mapping.__contains__``, which answers by calling ``__getitem__`` - defeating the laziness and raising a backend's ImportError out of an ``in`` test rather than returning True. ``TorchTensorTranslator`` raised a bare ModuleNotFoundError, leaving the caller to guess which extra to install. ``pip install sagemaker[torch]`` did not work. The top-level package now passes sagemaker-serve's backend extras through. ``all`` is unchanged, so no existing install starts pulling torch. Co-authored-by: goelakash <goelakash93@gmail.com>
|
Thanks for this @goelakash, and apologies for how long it sat. Doing a proper deep dive on it now — here's where things landed. Your diagnosis was right, and it was the correct read of the problem: While this PR was waiting, #6512 landed (Oct 21) and independently fixed the same root cause with a wider scope — it also made So rather than ask you to resolve conflicts into a change that would mostly be reverted, I've opened #6531 to carry forward the parts of this PR that #6512 did not cover, with you credited as co-author on the commit:
One change I made to your approach on (1): instead of the structural check type(data).__module__.split(".")[0] == "torch" and callable(getattr(data, "detach", None)) ...#6531 uses Closing this in favor of #6531. Thank you for the diagnosis, the measurements (1.45 GB → 536 MB is what made the case concrete), and for your patience with the delay. |
#6512 made the sagemaker-serve serving backends extras, but four gaps kept torch from being genuinely optional (#5531). All four were diagnosed first in #6166. Selecting the PyTorch default serializer still required torch. ``TorchTensorSerializer.__init__`` imported torch, so the lazy registry only deferred the failure to ``_fetch_serializer_and_deserializer_for_framework``. A client deploying a prebuilt PyTorch container detects the framework from the image URI and never touches a tensor, so it hit an ImportError for a dependency it had no use for. The type check now consults ``sys.modules``: a torch.Tensor cannot exist unless torch has already been imported, so the check stays exact without triggering an import. ``torch_tensor`` becomes a property, keeping the attribute and its ImportError for callers that want the type itself. Membership tests built the pair they were asking about. The registry inherited ``Mapping.__contains__``, which answers by calling ``__getitem__`` - defeating the laziness and raising a backend's ImportError out of an ``in`` test rather than returning True. ``TorchTensorTranslator`` raised a bare ModuleNotFoundError, leaving the caller to guess which extra to install. ``pip install sagemaker[torch]`` did not work. The top-level package now passes sagemaker-serve's backend extras through. ``all`` is unchanged, so no existing install starts pulling torch. Co-authored-by: Mohamed Zeidan <zeidmo@amazon.com> Co-authored-by: goelakash <goelakash93@gmail.com>
Fixes #5531
sagemaker-serveliststorch>=2.0.0as a required dependency, so any install ofsagemaker,sagemaker-serve, orsagemaker-mlopspulls torch (and on Linux, the CUDA/cuDNN/NCCL stack) even for API-only use.sagemaker-corealready treats torch as an extra.The blocker was
DEFAULT_SERIALIZERS_BY_FRAMEWORKinserve/constants.py, which instantiatedTorchTensorSerializer()at module scope. That runsfrom torch import Tensoron anyimport sagemaker.serve. Every other torch reference in the package is already lazy.Changes
DEFAULT_SERIALIZERS_BY_FRAMEWORK; instantiate at lookup in_fetch_serializer_and_deserializer_for_framework.torch>=2.0.0to atorchextra, matchingsagemaker-core.tests/unit/test_optional_torch_dependency.py, mirroring the existingsagemaker-coresubprocess pattern.Installing with the
torchextra is unchanged.TorchTensorSerializer()still raises the sameImportErrorif torch is missing when actually used.Testing
tests/unitin a venv with and without torch: no new failures vs.master(53 pre-existing failures in both).masterand pass with this change.from sagemaker.serve import ModelBuilderandimport sagemaker.mlopsboth succeed.