synapse-sdk 1.0.0a11__py3-none-any.whl → 2026.1.1b2__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of synapse-sdk might be problematic. Click here for more details.
- synapse_sdk/__init__.py +24 -0
- synapse_sdk/cli/__init__.py +9 -8
- synapse_sdk/cli/agent/__init__.py +25 -0
- synapse_sdk/cli/agent/config.py +104 -0
- synapse_sdk/cli/agent/select.py +197 -0
- synapse_sdk/cli/auth.py +104 -0
- synapse_sdk/cli/main.py +1025 -0
- synapse_sdk/cli/plugin/__init__.py +58 -0
- synapse_sdk/cli/plugin/create.py +566 -0
- synapse_sdk/cli/plugin/job.py +196 -0
- synapse_sdk/cli/plugin/publish.py +322 -0
- synapse_sdk/cli/plugin/run.py +131 -0
- synapse_sdk/cli/plugin/test.py +200 -0
- synapse_sdk/clients/README.md +239 -0
- synapse_sdk/clients/__init__.py +5 -0
- synapse_sdk/clients/_template.py +266 -0
- synapse_sdk/clients/agent/__init__.py +84 -29
- synapse_sdk/clients/agent/async_ray.py +289 -0
- synapse_sdk/clients/agent/container.py +83 -0
- synapse_sdk/clients/agent/plugin.py +101 -0
- synapse_sdk/clients/agent/ray.py +296 -39
- synapse_sdk/clients/backend/__init__.py +152 -12
- synapse_sdk/clients/backend/annotation.py +164 -22
- synapse_sdk/clients/backend/core.py +101 -0
- synapse_sdk/clients/backend/data_collection.py +292 -0
- synapse_sdk/clients/backend/hitl.py +87 -0
- synapse_sdk/clients/backend/integration.py +374 -46
- synapse_sdk/clients/backend/ml.py +134 -22
- synapse_sdk/clients/backend/models.py +247 -0
- synapse_sdk/clients/base.py +538 -59
- synapse_sdk/clients/exceptions.py +35 -7
- synapse_sdk/clients/pipeline/__init__.py +5 -0
- synapse_sdk/clients/pipeline/client.py +636 -0
- synapse_sdk/clients/protocols.py +178 -0
- synapse_sdk/clients/utils.py +86 -8
- synapse_sdk/clients/validation.py +58 -0
- synapse_sdk/enums.py +76 -0
- synapse_sdk/exceptions.py +168 -0
- synapse_sdk/integrations/__init__.py +74 -0
- synapse_sdk/integrations/_base.py +119 -0
- synapse_sdk/integrations/_context.py +53 -0
- synapse_sdk/integrations/ultralytics/__init__.py +78 -0
- synapse_sdk/integrations/ultralytics/_callbacks.py +126 -0
- synapse_sdk/integrations/ultralytics/_patches.py +124 -0
- synapse_sdk/loggers.py +476 -95
- synapse_sdk/mcp/MCP.md +69 -0
- synapse_sdk/mcp/__init__.py +48 -0
- synapse_sdk/mcp/__main__.py +6 -0
- synapse_sdk/mcp/config.py +349 -0
- synapse_sdk/mcp/prompts/__init__.py +4 -0
- synapse_sdk/mcp/resources/__init__.py +4 -0
- synapse_sdk/mcp/server.py +1352 -0
- synapse_sdk/mcp/tools/__init__.py +6 -0
- synapse_sdk/plugins/__init__.py +133 -9
- synapse_sdk/plugins/action.py +229 -0
- synapse_sdk/plugins/actions/__init__.py +82 -0
- synapse_sdk/plugins/actions/dataset/__init__.py +37 -0
- synapse_sdk/plugins/actions/dataset/action.py +471 -0
- synapse_sdk/plugins/actions/export/__init__.py +55 -0
- synapse_sdk/plugins/actions/export/action.py +183 -0
- synapse_sdk/plugins/actions/export/context.py +59 -0
- synapse_sdk/plugins/actions/inference/__init__.py +84 -0
- synapse_sdk/plugins/actions/inference/action.py +285 -0
- synapse_sdk/plugins/actions/inference/context.py +81 -0
- synapse_sdk/plugins/actions/inference/deployment.py +322 -0
- synapse_sdk/plugins/actions/inference/serve.py +252 -0
- synapse_sdk/plugins/actions/train/__init__.py +54 -0
- synapse_sdk/plugins/actions/train/action.py +326 -0
- synapse_sdk/plugins/actions/train/context.py +57 -0
- synapse_sdk/plugins/actions/upload/__init__.py +49 -0
- synapse_sdk/plugins/actions/upload/action.py +165 -0
- synapse_sdk/plugins/actions/upload/context.py +61 -0
- synapse_sdk/plugins/config.py +98 -0
- synapse_sdk/plugins/context/__init__.py +109 -0
- synapse_sdk/plugins/context/env.py +113 -0
- synapse_sdk/plugins/datasets/__init__.py +113 -0
- synapse_sdk/plugins/datasets/converters/__init__.py +76 -0
- synapse_sdk/plugins/datasets/converters/base.py +347 -0
- synapse_sdk/plugins/datasets/converters/yolo/__init__.py +9 -0
- synapse_sdk/plugins/datasets/converters/yolo/from_dm.py +468 -0
- synapse_sdk/plugins/datasets/converters/yolo/to_dm.py +381 -0
- synapse_sdk/plugins/datasets/formats/__init__.py +82 -0
- synapse_sdk/plugins/datasets/formats/dm.py +351 -0
- synapse_sdk/plugins/datasets/formats/yolo.py +240 -0
- synapse_sdk/plugins/decorators.py +83 -0
- synapse_sdk/plugins/discovery.py +790 -0
- synapse_sdk/plugins/docs/ACTION_DEV_GUIDE.md +933 -0
- synapse_sdk/plugins/docs/ARCHITECTURE.md +1225 -0
- synapse_sdk/plugins/docs/LOGGING_SYSTEM.md +683 -0
- synapse_sdk/plugins/docs/OVERVIEW.md +531 -0
- synapse_sdk/plugins/docs/PIPELINE_GUIDE.md +145 -0
- synapse_sdk/plugins/docs/README.md +513 -0
- synapse_sdk/plugins/docs/STEP.md +656 -0
- synapse_sdk/plugins/enums.py +70 -10
- synapse_sdk/plugins/errors.py +92 -0
- synapse_sdk/plugins/executors/__init__.py +43 -0
- synapse_sdk/plugins/executors/local.py +99 -0
- synapse_sdk/plugins/executors/ray/__init__.py +18 -0
- synapse_sdk/plugins/executors/ray/base.py +282 -0
- synapse_sdk/plugins/executors/ray/job.py +298 -0
- synapse_sdk/plugins/executors/ray/jobs_api.py +511 -0
- synapse_sdk/plugins/executors/ray/packaging.py +137 -0
- synapse_sdk/plugins/executors/ray/pipeline.py +792 -0
- synapse_sdk/plugins/executors/ray/task.py +257 -0
- synapse_sdk/plugins/models/__init__.py +26 -0
- synapse_sdk/plugins/models/logger.py +173 -0
- synapse_sdk/plugins/models/pipeline.py +25 -0
- synapse_sdk/plugins/pipelines/__init__.py +81 -0
- synapse_sdk/plugins/pipelines/action_pipeline.py +417 -0
- synapse_sdk/plugins/pipelines/context.py +107 -0
- synapse_sdk/plugins/pipelines/display.py +311 -0
- synapse_sdk/plugins/runner.py +114 -0
- synapse_sdk/plugins/schemas/__init__.py +19 -0
- synapse_sdk/plugins/schemas/results.py +152 -0
- synapse_sdk/plugins/steps/__init__.py +63 -0
- synapse_sdk/plugins/steps/base.py +128 -0
- synapse_sdk/plugins/steps/context.py +90 -0
- synapse_sdk/plugins/steps/orchestrator.py +128 -0
- synapse_sdk/plugins/steps/registry.py +103 -0
- synapse_sdk/plugins/steps/utils/__init__.py +20 -0
- synapse_sdk/plugins/steps/utils/logging.py +85 -0
- synapse_sdk/plugins/steps/utils/timing.py +71 -0
- synapse_sdk/plugins/steps/utils/validation.py +68 -0
- synapse_sdk/plugins/templates/__init__.py +50 -0
- synapse_sdk/plugins/templates/base/.gitignore.j2 +26 -0
- synapse_sdk/plugins/templates/base/.synapseignore.j2 +11 -0
- synapse_sdk/plugins/templates/base/README.md.j2 +26 -0
- synapse_sdk/plugins/templates/base/plugin/__init__.py.j2 +1 -0
- synapse_sdk/plugins/templates/base/pyproject.toml.j2 +14 -0
- synapse_sdk/plugins/templates/base/requirements.txt.j2 +1 -0
- synapse_sdk/plugins/templates/custom/plugin/main.py.j2 +18 -0
- synapse_sdk/plugins/templates/data_validation/plugin/validate.py.j2 +32 -0
- synapse_sdk/plugins/templates/export/plugin/export.py.j2 +36 -0
- synapse_sdk/plugins/templates/neural_net/plugin/inference.py.j2 +36 -0
- synapse_sdk/plugins/templates/neural_net/plugin/train.py.j2 +33 -0
- synapse_sdk/plugins/templates/post_annotation/plugin/post_annotate.py.j2 +32 -0
- synapse_sdk/plugins/templates/pre_annotation/plugin/pre_annotate.py.j2 +32 -0
- synapse_sdk/plugins/templates/smart_tool/plugin/auto_label.py.j2 +44 -0
- synapse_sdk/plugins/templates/upload/plugin/upload.py.j2 +35 -0
- synapse_sdk/plugins/testing/__init__.py +25 -0
- synapse_sdk/plugins/testing/sample_actions.py +98 -0
- synapse_sdk/plugins/types.py +206 -0
- synapse_sdk/plugins/upload.py +595 -64
- synapse_sdk/plugins/utils.py +325 -37
- synapse_sdk/shared/__init__.py +25 -0
- synapse_sdk/utils/__init__.py +1 -0
- synapse_sdk/utils/auth.py +74 -0
- synapse_sdk/utils/file/__init__.py +58 -0
- synapse_sdk/utils/file/archive.py +449 -0
- synapse_sdk/utils/file/checksum.py +167 -0
- synapse_sdk/utils/file/download.py +286 -0
- synapse_sdk/utils/file/io.py +129 -0
- synapse_sdk/utils/file/requirements.py +36 -0
- synapse_sdk/utils/network.py +168 -0
- synapse_sdk/utils/storage/__init__.py +238 -0
- synapse_sdk/utils/storage/config.py +188 -0
- synapse_sdk/utils/storage/errors.py +52 -0
- synapse_sdk/utils/storage/providers/__init__.py +13 -0
- synapse_sdk/utils/storage/providers/base.py +76 -0
- synapse_sdk/utils/storage/providers/gcs.py +168 -0
- synapse_sdk/utils/storage/providers/http.py +250 -0
- synapse_sdk/utils/storage/providers/local.py +126 -0
- synapse_sdk/utils/storage/providers/s3.py +177 -0
- synapse_sdk/utils/storage/providers/sftp.py +208 -0
- synapse_sdk/utils/storage/registry.py +125 -0
- synapse_sdk/utils/websocket.py +99 -0
- synapse_sdk-2026.1.1b2.dist-info/METADATA +715 -0
- synapse_sdk-2026.1.1b2.dist-info/RECORD +172 -0
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/WHEEL +1 -1
- synapse_sdk-2026.1.1b2.dist-info/licenses/LICENSE +201 -0
- locale/en/LC_MESSAGES/messages.mo +0 -0
- locale/en/LC_MESSAGES/messages.po +0 -39
- locale/ko/LC_MESSAGES/messages.mo +0 -0
- locale/ko/LC_MESSAGES/messages.po +0 -34
- synapse_sdk/cli/create_plugin.py +0 -10
- synapse_sdk/clients/agent/core.py +0 -7
- synapse_sdk/clients/agent/service.py +0 -15
- synapse_sdk/clients/backend/dataset.py +0 -51
- synapse_sdk/clients/ray/__init__.py +0 -6
- synapse_sdk/clients/ray/core.py +0 -22
- synapse_sdk/clients/ray/serve.py +0 -20
- synapse_sdk/i18n.py +0 -35
- synapse_sdk/plugins/categories/__init__.py +0 -0
- synapse_sdk/plugins/categories/base.py +0 -235
- synapse_sdk/plugins/categories/data_validation/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/actions/validation.py +0 -10
- synapse_sdk/plugins/categories/data_validation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/data_validation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/data_validation/templates/plugin/validation.py +0 -5
- synapse_sdk/plugins/categories/decorators.py +0 -13
- synapse_sdk/plugins/categories/export/__init__.py +0 -0
- synapse_sdk/plugins/categories/export/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/export/actions/export.py +0 -10
- synapse_sdk/plugins/categories/import/__init__.py +0 -0
- synapse_sdk/plugins/categories/import/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/import/actions/import.py +0 -10
- synapse_sdk/plugins/categories/neural_net/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/actions/deployment.py +0 -45
- synapse_sdk/plugins/categories/neural_net/actions/inference.py +0 -18
- synapse_sdk/plugins/categories/neural_net/actions/test.py +0 -10
- synapse_sdk/plugins/categories/neural_net/actions/train.py +0 -143
- synapse_sdk/plugins/categories/neural_net/templates/config.yaml +0 -12
- synapse_sdk/plugins/categories/neural_net/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/neural_net/templates/plugin/inference.py +0 -4
- synapse_sdk/plugins/categories/neural_net/templates/plugin/test.py +0 -2
- synapse_sdk/plugins/categories/neural_net/templates/plugin/train.py +0 -14
- synapse_sdk/plugins/categories/post_annotation/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/actions/post_annotation.py +0 -10
- synapse_sdk/plugins/categories/post_annotation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/post_annotation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/post_annotation/templates/plugin/post_annotation.py +0 -3
- synapse_sdk/plugins/categories/pre_annotation/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/actions/pre_annotation.py +0 -10
- synapse_sdk/plugins/categories/pre_annotation/templates/config.yaml +0 -3
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/pre_annotation/templates/plugin/pre_annotation.py +0 -3
- synapse_sdk/plugins/categories/registry.py +0 -16
- synapse_sdk/plugins/categories/smart_tool/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/actions/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/actions/auto_label.py +0 -37
- synapse_sdk/plugins/categories/smart_tool/templates/config.yaml +0 -7
- synapse_sdk/plugins/categories/smart_tool/templates/plugin/__init__.py +0 -0
- synapse_sdk/plugins/categories/smart_tool/templates/plugin/auto_label.py +0 -11
- synapse_sdk/plugins/categories/templates.py +0 -32
- synapse_sdk/plugins/cli/__init__.py +0 -21
- synapse_sdk/plugins/cli/publish.py +0 -37
- synapse_sdk/plugins/cli/run.py +0 -67
- synapse_sdk/plugins/exceptions.py +0 -22
- synapse_sdk/plugins/models.py +0 -121
- synapse_sdk/plugins/templates/cookiecutter.json +0 -11
- synapse_sdk/plugins/templates/hooks/post_gen_project.py +0 -3
- synapse_sdk/plugins/templates/hooks/pre_prompt.py +0 -21
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.env.dist +0 -24
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.gitignore +0 -27
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/.pre-commit-config.yaml +0 -7
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/README.md +0 -5
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/config.yaml +0 -6
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/main.py +0 -4
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/plugin/__init__.py +0 -0
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/pyproject.toml +0 -13
- synapse_sdk/plugins/templates/synapse-{{cookiecutter.plugin_code}}-plugin/requirements.txt +0 -1
- synapse_sdk/shared/enums.py +0 -8
- synapse_sdk/utils/debug.py +0 -5
- synapse_sdk/utils/file.py +0 -87
- synapse_sdk/utils/module_loading.py +0 -29
- synapse_sdk/utils/pydantic/__init__.py +0 -0
- synapse_sdk/utils/pydantic/config.py +0 -4
- synapse_sdk/utils/pydantic/errors.py +0 -33
- synapse_sdk/utils/pydantic/validators.py +0 -7
- synapse_sdk/utils/storage.py +0 -91
- synapse_sdk/utils/string.py +0 -11
- synapse_sdk-1.0.0a11.dist-info/LICENSE +0 -21
- synapse_sdk-1.0.0a11.dist-info/METADATA +0 -43
- synapse_sdk-1.0.0a11.dist-info/RECORD +0 -111
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/entry_points.txt +0 -0
- {synapse_sdk-1.0.0a11.dist-info → synapse_sdk-2026.1.1b2.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
"""Base integration infrastructure for autolog."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from abc import ABC, abstractmethod
|
|
6
|
+
from typing import TYPE_CHECKING, Callable
|
|
7
|
+
|
|
8
|
+
if TYPE_CHECKING:
|
|
9
|
+
from synapse_sdk.plugins.action import BaseAction
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class BaseIntegration(ABC):
|
|
13
|
+
"""Base class for framework integrations.
|
|
14
|
+
|
|
15
|
+
Subclasses implement framework-specific autologging by patching
|
|
16
|
+
the framework's training methods to automatically log metrics,
|
|
17
|
+
progress, and artifacts.
|
|
18
|
+
|
|
19
|
+
Example:
|
|
20
|
+
>>> @register_integration('my_framework')
|
|
21
|
+
... class MyFrameworkIntegration(BaseIntegration):
|
|
22
|
+
... name = 'my_framework'
|
|
23
|
+
...
|
|
24
|
+
... def enable(self, action):
|
|
25
|
+
... # Patch framework methods
|
|
26
|
+
... ...
|
|
27
|
+
...
|
|
28
|
+
... def disable(self):
|
|
29
|
+
... # Restore original methods
|
|
30
|
+
... ...
|
|
31
|
+
...
|
|
32
|
+
... def is_available(self):
|
|
33
|
+
... try:
|
|
34
|
+
... import my_framework
|
|
35
|
+
... return True
|
|
36
|
+
... except ImportError:
|
|
37
|
+
... return False
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
name: str
|
|
41
|
+
|
|
42
|
+
@abstractmethod
|
|
43
|
+
def enable(self, action: BaseAction) -> None:
|
|
44
|
+
"""Enable autologging for this framework.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
action: The current action instance to log to.
|
|
48
|
+
"""
|
|
49
|
+
...
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def disable(self) -> None:
|
|
53
|
+
"""Disable autologging and restore original behavior."""
|
|
54
|
+
...
|
|
55
|
+
|
|
56
|
+
@abstractmethod
|
|
57
|
+
def is_available(self) -> bool:
|
|
58
|
+
"""Check if the framework is installed.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
True if framework is available, False otherwise.
|
|
62
|
+
"""
|
|
63
|
+
...
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
# Registry of available integrations
|
|
67
|
+
_integrations: dict[str, type[BaseIntegration]] = {}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def register_integration(name: str) -> Callable[[type[BaseIntegration]], type[BaseIntegration]]:
|
|
71
|
+
"""Decorator to register an integration.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
name: Integration name (e.g., 'ultralytics').
|
|
75
|
+
|
|
76
|
+
Returns:
|
|
77
|
+
Decorator function.
|
|
78
|
+
|
|
79
|
+
Example:
|
|
80
|
+
>>> @register_integration('ultralytics')
|
|
81
|
+
... class UltralyticsIntegration(BaseIntegration):
|
|
82
|
+
... ...
|
|
83
|
+
"""
|
|
84
|
+
|
|
85
|
+
def decorator(cls: type[BaseIntegration]) -> type[BaseIntegration]:
|
|
86
|
+
_integrations[name] = cls
|
|
87
|
+
return cls
|
|
88
|
+
|
|
89
|
+
return decorator
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def get_integration(name: str) -> BaseIntegration:
|
|
93
|
+
"""Get integration instance by name.
|
|
94
|
+
|
|
95
|
+
Args:
|
|
96
|
+
name: Integration name (e.g., 'ultralytics').
|
|
97
|
+
|
|
98
|
+
Returns:
|
|
99
|
+
BaseIntegration instance.
|
|
100
|
+
|
|
101
|
+
Raises:
|
|
102
|
+
ValueError: If integration is not registered.
|
|
103
|
+
"""
|
|
104
|
+
if name not in _integrations:
|
|
105
|
+
available = list(_integrations.keys()) or ['none']
|
|
106
|
+
raise ValueError(f"Unknown integration: '{name}'. Available: {available}")
|
|
107
|
+
return _integrations[name]()
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def list_integrations() -> list[str]:
|
|
111
|
+
"""List all registered integration names.
|
|
112
|
+
|
|
113
|
+
Returns:
|
|
114
|
+
List of integration names.
|
|
115
|
+
"""
|
|
116
|
+
return list(_integrations.keys())
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
__all__ = ['BaseIntegration', 'register_integration', 'get_integration', 'list_integrations']
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""Context management for autolog integrations."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from contextvars import ContextVar
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from typing import TYPE_CHECKING, Any
|
|
8
|
+
|
|
9
|
+
if TYPE_CHECKING:
|
|
10
|
+
from synapse_sdk.plugins.action import BaseAction
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
@dataclass
|
|
14
|
+
class AutologContext:
|
|
15
|
+
"""Holds action context for autolog callbacks.
|
|
16
|
+
|
|
17
|
+
Attributes:
|
|
18
|
+
action: The current BaseAction instance.
|
|
19
|
+
total_epochs: Total epochs (auto-detected from train() kwargs).
|
|
20
|
+
extra: Additional framework-specific data.
|
|
21
|
+
"""
|
|
22
|
+
|
|
23
|
+
action: BaseAction[Any]
|
|
24
|
+
total_epochs: int | None = None
|
|
25
|
+
extra: dict[str, Any] = field(default_factory=dict)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
# Thread/async safe context storage
|
|
29
|
+
_autolog_context: ContextVar[AutologContext | None] = ContextVar(
|
|
30
|
+
'synapse_autolog_context',
|
|
31
|
+
default=None,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def get_autolog_context() -> AutologContext | None:
|
|
36
|
+
"""Get current autolog context.
|
|
37
|
+
|
|
38
|
+
Returns:
|
|
39
|
+
AutologContext if autolog is active, None otherwise.
|
|
40
|
+
"""
|
|
41
|
+
return _autolog_context.get()
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def set_autolog_context(ctx: AutologContext | None) -> None:
|
|
45
|
+
"""Set autolog context.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
ctx: AutologContext to set, or None to clear.
|
|
49
|
+
"""
|
|
50
|
+
_autolog_context.set(ctx)
|
|
51
|
+
|
|
52
|
+
|
|
53
|
+
__all__ = ['AutologContext', 'get_autolog_context', 'set_autolog_context']
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""Ultralytics YOLO autolog integration."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import TYPE_CHECKING
|
|
6
|
+
|
|
7
|
+
from synapse_sdk.integrations._base import BaseIntegration, register_integration
|
|
8
|
+
from synapse_sdk.integrations._context import AutologContext, set_autolog_context
|
|
9
|
+
|
|
10
|
+
if TYPE_CHECKING:
|
|
11
|
+
from synapse_sdk.plugins.action import BaseAction
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
@register_integration('ultralytics')
|
|
15
|
+
class UltralyticsIntegration(BaseIntegration):
|
|
16
|
+
"""Ultralytics YOLO autologging integration.
|
|
17
|
+
|
|
18
|
+
Automatically logs training progress, metrics, and artifacts
|
|
19
|
+
when using Ultralytics YOLO models.
|
|
20
|
+
|
|
21
|
+
Logged metrics:
|
|
22
|
+
- train: box_loss, cls_loss, dfl_loss (per epoch)
|
|
23
|
+
- validation: mAP50, mAP50_95 (per epoch)
|
|
24
|
+
|
|
25
|
+
Logged artifacts:
|
|
26
|
+
- validation_samples: Validation batch prediction images
|
|
27
|
+
- model_weights: best.pt weights file
|
|
28
|
+
- training_results: results.csv file
|
|
29
|
+
|
|
30
|
+
Example:
|
|
31
|
+
>>> class TrainAction(BaseTrainAction[TrainParams]):
|
|
32
|
+
... def execute(self):
|
|
33
|
+
... self.autolog('ultralytics')
|
|
34
|
+
... model = YOLO('yolov8n.pt')
|
|
35
|
+
... model.train(data='coco.yaml', epochs=100)
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
name = 'ultralytics'
|
|
39
|
+
|
|
40
|
+
def is_available(self) -> bool:
|
|
41
|
+
"""Check if ultralytics is installed."""
|
|
42
|
+
try:
|
|
43
|
+
import ultralytics # noqa: F401
|
|
44
|
+
|
|
45
|
+
return True
|
|
46
|
+
except ImportError:
|
|
47
|
+
return False
|
|
48
|
+
|
|
49
|
+
def enable(self, action: BaseAction) -> None:
|
|
50
|
+
"""Enable autologging for Ultralytics.
|
|
51
|
+
|
|
52
|
+
Args:
|
|
53
|
+
action: The action instance to log to.
|
|
54
|
+
|
|
55
|
+
Raises:
|
|
56
|
+
ImportError: If ultralytics is not installed.
|
|
57
|
+
"""
|
|
58
|
+
if not self.is_available():
|
|
59
|
+
raise ImportError('ultralytics is not installed. Install with: pip install ultralytics')
|
|
60
|
+
|
|
61
|
+
# Set context for callbacks
|
|
62
|
+
set_autolog_context(AutologContext(action=action))
|
|
63
|
+
|
|
64
|
+
# Apply patches (idempotent)
|
|
65
|
+
from synapse_sdk.integrations.ultralytics._patches import patch_yolo
|
|
66
|
+
|
|
67
|
+
patch_yolo()
|
|
68
|
+
|
|
69
|
+
def disable(self) -> None:
|
|
70
|
+
"""Disable autologging for Ultralytics.
|
|
71
|
+
|
|
72
|
+
Clears the context but keeps patches in place for efficiency.
|
|
73
|
+
Callbacks check context before logging.
|
|
74
|
+
"""
|
|
75
|
+
set_autolog_context(None)
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
__all__ = ['UltralyticsIntegration']
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Ultralytics YOLO callback implementations for autolog."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from synapse_sdk.integrations._context import get_autolog_context
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def on_train_epoch_end(trainer: Any) -> None:
|
|
12
|
+
"""Log training metrics at end of each epoch.
|
|
13
|
+
|
|
14
|
+
Logs:
|
|
15
|
+
- Progress: epoch/total_epochs
|
|
16
|
+
- Metrics: box_loss, cls_loss, dfl_loss (category='train')
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
trainer: Ultralytics trainer instance.
|
|
20
|
+
"""
|
|
21
|
+
ctx = get_autolog_context()
|
|
22
|
+
if ctx is None:
|
|
23
|
+
return
|
|
24
|
+
|
|
25
|
+
action = ctx.action
|
|
26
|
+
epoch = trainer.epoch + 1
|
|
27
|
+
total_epochs = ctx.total_epochs or getattr(trainer, 'epochs', 100)
|
|
28
|
+
|
|
29
|
+
# Update progress
|
|
30
|
+
action.set_progress(epoch, total_epochs, 'train')
|
|
31
|
+
|
|
32
|
+
# Log loss metrics
|
|
33
|
+
if hasattr(trainer, 'loss_items') and trainer.loss_items is not None:
|
|
34
|
+
loss_items = trainer.loss_items
|
|
35
|
+
if hasattr(loss_items, 'cpu'):
|
|
36
|
+
loss_items = loss_items.cpu().numpy()
|
|
37
|
+
|
|
38
|
+
action.set_metrics(
|
|
39
|
+
{
|
|
40
|
+
'epoch': epoch,
|
|
41
|
+
'box_loss': float(loss_items[0]),
|
|
42
|
+
'cls_loss': float(loss_items[1]),
|
|
43
|
+
'dfl_loss': float(loss_items[2]),
|
|
44
|
+
},
|
|
45
|
+
category='train',
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def on_fit_epoch_end(trainer: Any) -> None:
|
|
50
|
+
"""Log validation metrics after validation pass.
|
|
51
|
+
|
|
52
|
+
Logs:
|
|
53
|
+
- Metrics: mAP50, mAP50_95 (category='validation')
|
|
54
|
+
- Files: validation batch prediction images
|
|
55
|
+
|
|
56
|
+
Args:
|
|
57
|
+
trainer: Ultralytics trainer instance.
|
|
58
|
+
"""
|
|
59
|
+
ctx = get_autolog_context()
|
|
60
|
+
if ctx is None:
|
|
61
|
+
return
|
|
62
|
+
|
|
63
|
+
action = ctx.action
|
|
64
|
+
epoch = trainer.epoch + 1
|
|
65
|
+
metrics = trainer.metrics
|
|
66
|
+
|
|
67
|
+
if metrics:
|
|
68
|
+
action.set_metrics(
|
|
69
|
+
{
|
|
70
|
+
'epoch': epoch,
|
|
71
|
+
'mAP50': metrics.get('metrics/mAP50(B)', 0),
|
|
72
|
+
'mAP50_95': metrics.get('metrics/mAP50-95(B)', 0),
|
|
73
|
+
},
|
|
74
|
+
category='validation',
|
|
75
|
+
)
|
|
76
|
+
|
|
77
|
+
# Log validation sample images
|
|
78
|
+
save_dir = Path(trainer.save_dir)
|
|
79
|
+
for i in range(3):
|
|
80
|
+
img_path = save_dir / f'val_batch{i}_pred.jpg'
|
|
81
|
+
if img_path.exists():
|
|
82
|
+
action.log(
|
|
83
|
+
'validation_samples',
|
|
84
|
+
{'group': epoch, 'index': i},
|
|
85
|
+
file=str(img_path),
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
# Ray Tune integration
|
|
89
|
+
is_tune = action.ctx.env.get_bool('IS_TUNE', default=False)
|
|
90
|
+
if is_tune and metrics:
|
|
91
|
+
try:
|
|
92
|
+
from ray import tune
|
|
93
|
+
|
|
94
|
+
tune.report(**metrics)
|
|
95
|
+
except ImportError:
|
|
96
|
+
pass
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def on_train_end(trainer: Any) -> None:
|
|
100
|
+
"""Log final artifacts when training completes.
|
|
101
|
+
|
|
102
|
+
Logs:
|
|
103
|
+
- Files: best.pt weights, results.csv
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
trainer: Ultralytics trainer instance.
|
|
107
|
+
"""
|
|
108
|
+
ctx = get_autolog_context()
|
|
109
|
+
if ctx is None:
|
|
110
|
+
return
|
|
111
|
+
|
|
112
|
+
action = ctx.action
|
|
113
|
+
save_dir = Path(trainer.save_dir)
|
|
114
|
+
|
|
115
|
+
# Log final model weights
|
|
116
|
+
best_pt = save_dir / 'weights' / 'best.pt'
|
|
117
|
+
if best_pt.exists():
|
|
118
|
+
action.log('model_weights', {'type': 'best'}, file=str(best_pt))
|
|
119
|
+
|
|
120
|
+
# Log training results CSV
|
|
121
|
+
results_csv = save_dir / 'results.csv'
|
|
122
|
+
if results_csv.exists():
|
|
123
|
+
action.log('training_results', {}, file=str(results_csv))
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
__all__ = ['on_train_epoch_end', 'on_fit_epoch_end', 'on_train_end']
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"""Monkey patches for Ultralytics YOLO autolog."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import functools
|
|
6
|
+
from typing import Any
|
|
7
|
+
|
|
8
|
+
from synapse_sdk.integrations._context import get_autolog_context
|
|
9
|
+
from synapse_sdk.integrations.ultralytics._callbacks import (
|
|
10
|
+
on_fit_epoch_end,
|
|
11
|
+
on_train_end,
|
|
12
|
+
on_train_epoch_end,
|
|
13
|
+
)
|
|
14
|
+
|
|
15
|
+
# Store original methods to avoid re-patching
|
|
16
|
+
_original_yolo_init: Any = None
|
|
17
|
+
_original_yolo_train: Any = None
|
|
18
|
+
_patched = False
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def patch_yolo() -> None:
|
|
22
|
+
"""Apply all YOLO patches.
|
|
23
|
+
|
|
24
|
+
Patches:
|
|
25
|
+
- YOLO.__init__: Auto-attach callbacks when model is created
|
|
26
|
+
- YOLO.train: Capture epochs from kwargs
|
|
27
|
+
|
|
28
|
+
This function is idempotent - calling it multiple times has no effect.
|
|
29
|
+
"""
|
|
30
|
+
global _patched
|
|
31
|
+
if _patched:
|
|
32
|
+
return
|
|
33
|
+
|
|
34
|
+
_patch_yolo_init()
|
|
35
|
+
_patch_yolo_train()
|
|
36
|
+
_patched = True
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def _patch_yolo_init() -> None:
|
|
40
|
+
"""Patch YOLO.__init__ to auto-attach callbacks."""
|
|
41
|
+
global _original_yolo_init
|
|
42
|
+
|
|
43
|
+
from ultralytics import YOLO
|
|
44
|
+
|
|
45
|
+
if _original_yolo_init is not None:
|
|
46
|
+
return # Already patched
|
|
47
|
+
|
|
48
|
+
_original_yolo_init = YOLO.__init__
|
|
49
|
+
|
|
50
|
+
@functools.wraps(_original_yolo_init)
|
|
51
|
+
def patched_init(self: Any, *args: Any, **kwargs: Any) -> None:
|
|
52
|
+
result = _original_yolo_init(self, *args, **kwargs)
|
|
53
|
+
|
|
54
|
+
# Check if autolog is active
|
|
55
|
+
ctx = get_autolog_context()
|
|
56
|
+
if ctx is not None:
|
|
57
|
+
# Attach Synapse callbacks
|
|
58
|
+
self.add_callback('on_train_epoch_end', on_train_epoch_end)
|
|
59
|
+
self.add_callback('on_fit_epoch_end', on_fit_epoch_end)
|
|
60
|
+
self.add_callback('on_train_end', on_train_end)
|
|
61
|
+
|
|
62
|
+
return result
|
|
63
|
+
|
|
64
|
+
YOLO.__init__ = patched_init
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
def _patch_yolo_train() -> None:
|
|
68
|
+
"""Patch YOLO.train to capture epochs from kwargs."""
|
|
69
|
+
global _original_yolo_train
|
|
70
|
+
|
|
71
|
+
from ultralytics import YOLO
|
|
72
|
+
|
|
73
|
+
if _original_yolo_train is not None:
|
|
74
|
+
return # Already patched
|
|
75
|
+
|
|
76
|
+
_original_yolo_train = YOLO.train
|
|
77
|
+
|
|
78
|
+
@functools.wraps(_original_yolo_train)
|
|
79
|
+
def patched_train(self: Any, *args: Any, **kwargs: Any) -> Any:
|
|
80
|
+
ctx = get_autolog_context()
|
|
81
|
+
if ctx is not None:
|
|
82
|
+
# Auto-detect epochs from train() kwargs
|
|
83
|
+
epochs = kwargs.get('epochs')
|
|
84
|
+
if epochs is None:
|
|
85
|
+
# Check data config for epochs
|
|
86
|
+
data = kwargs.get('data')
|
|
87
|
+
if isinstance(data, dict):
|
|
88
|
+
epochs = data.get('epochs')
|
|
89
|
+
|
|
90
|
+
# Fall back to ultralytics default
|
|
91
|
+
if epochs is None:
|
|
92
|
+
epochs = 100
|
|
93
|
+
|
|
94
|
+
ctx.total_epochs = epochs
|
|
95
|
+
|
|
96
|
+
return _original_yolo_train(self, *args, **kwargs)
|
|
97
|
+
|
|
98
|
+
YOLO.train = patched_train
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def unpatch_yolo() -> None:
|
|
102
|
+
"""Restore original YOLO methods.
|
|
103
|
+
|
|
104
|
+
Used for testing or cleanup.
|
|
105
|
+
"""
|
|
106
|
+
global _original_yolo_init, _original_yolo_train, _patched
|
|
107
|
+
|
|
108
|
+
if not _patched:
|
|
109
|
+
return
|
|
110
|
+
|
|
111
|
+
from ultralytics import YOLO
|
|
112
|
+
|
|
113
|
+
if _original_yolo_init is not None:
|
|
114
|
+
YOLO.__init__ = _original_yolo_init
|
|
115
|
+
_original_yolo_init = None
|
|
116
|
+
|
|
117
|
+
if _original_yolo_train is not None:
|
|
118
|
+
YOLO.train = _original_yolo_train
|
|
119
|
+
_original_yolo_train = None
|
|
120
|
+
|
|
121
|
+
_patched = False
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
__all__ = ['patch_yolo', 'unpatch_yolo']
|