wandb 0.21.0__py3-none-win32.whl → 0.21.2__py3-none-win32.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.
- wandb/__init__.py +16 -14
- wandb/__init__.pyi +427 -450
- wandb/agents/pyagent.py +41 -12
- wandb/analytics/sentry.py +7 -2
- wandb/apis/importers/mlflow.py +1 -1
- wandb/apis/public/__init__.py +1 -1
- wandb/apis/public/api.py +525 -360
- wandb/apis/public/artifacts.py +207 -13
- wandb/apis/public/automations.py +19 -3
- wandb/apis/public/files.py +172 -33
- wandb/apis/public/history.py +67 -15
- wandb/apis/public/integrations.py +25 -2
- wandb/apis/public/jobs.py +90 -2
- wandb/apis/public/projects.py +130 -79
- wandb/apis/public/query_generator.py +11 -1
- wandb/apis/public/registries/_utils.py +14 -16
- wandb/apis/public/registries/registries_search.py +183 -304
- wandb/apis/public/reports.py +96 -15
- wandb/apis/public/runs.py +299 -105
- wandb/apis/public/sweeps.py +222 -22
- wandb/apis/public/teams.py +41 -4
- wandb/apis/public/users.py +45 -4
- wandb/automations/_generated/delete_automation.py +1 -3
- wandb/automations/_generated/enums.py +13 -11
- wandb/beta/workflows.py +66 -30
- wandb/bin/gpu_stats.exe +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +127 -3
- wandb/env.py +8 -0
- wandb/errors/errors.py +4 -1
- wandb/integration/lightning/fabric/logger.py +3 -4
- wandb/integration/metaflow/__init__.py +6 -0
- wandb/integration/metaflow/data_pandas.py +74 -0
- wandb/integration/metaflow/data_pytorch.py +75 -0
- wandb/integration/metaflow/data_sklearn.py +76 -0
- wandb/integration/metaflow/errors.py +13 -0
- wandb/integration/metaflow/metaflow.py +167 -223
- wandb/integration/openai/fine_tuning.py +1 -2
- wandb/integration/weave/__init__.py +6 -0
- wandb/integration/weave/interface.py +49 -0
- wandb/integration/weave/weave.py +63 -0
- wandb/jupyter.py +5 -5
- wandb/plot/custom_chart.py +30 -7
- wandb/proto/v3/wandb_internal_pb2.py +281 -280
- wandb/proto/v3/wandb_telemetry_pb2.py +4 -4
- wandb/proto/v4/wandb_internal_pb2.py +280 -280
- wandb/proto/v4/wandb_telemetry_pb2.py +4 -4
- wandb/proto/v5/wandb_internal_pb2.py +280 -280
- wandb/proto/v5/wandb_telemetry_pb2.py +4 -4
- wandb/proto/v6/wandb_internal_pb2.py +280 -280
- wandb/proto/v6/wandb_telemetry_pb2.py +4 -4
- wandb/proto/wandb_deprecated.py +6 -0
- wandb/sdk/artifacts/_factories.py +17 -0
- wandb/sdk/artifacts/_generated/__init__.py +221 -13
- wandb/sdk/artifacts/_generated/artifact_by_id.py +17 -0
- wandb/sdk/artifacts/_generated/artifact_by_name.py +22 -0
- wandb/sdk/artifacts/_generated/artifact_collection_membership_file_urls.py +43 -0
- wandb/sdk/artifacts/_generated/artifact_created_by.py +47 -0
- wandb/sdk/artifacts/_generated/artifact_file_urls.py +22 -0
- wandb/sdk/artifacts/_generated/artifact_type.py +31 -0
- wandb/sdk/artifacts/_generated/artifact_used_by.py +43 -0
- wandb/sdk/artifacts/_generated/artifact_via_membership_by_name.py +26 -0
- wandb/sdk/artifacts/_generated/delete_artifact.py +28 -0
- wandb/sdk/artifacts/_generated/enums.py +5 -0
- wandb/sdk/artifacts/_generated/fetch_artifact_manifest.py +38 -0
- wandb/sdk/artifacts/_generated/fetch_registries.py +32 -0
- wandb/sdk/artifacts/_generated/fragments.py +279 -41
- wandb/sdk/artifacts/_generated/link_artifact.py +6 -0
- wandb/sdk/artifacts/_generated/operations.py +654 -51
- wandb/sdk/artifacts/_generated/registry_collections.py +34 -0
- wandb/sdk/artifacts/_generated/registry_versions.py +34 -0
- wandb/sdk/artifacts/_generated/unlink_artifact.py +25 -0
- wandb/sdk/artifacts/_graphql_fragments.py +3 -86
- wandb/sdk/artifacts/_internal_artifact.py +19 -8
- wandb/sdk/artifacts/_validators.py +14 -4
- wandb/sdk/artifacts/artifact.py +512 -618
- wandb/sdk/artifacts/artifact_file_cache.py +10 -6
- wandb/sdk/artifacts/artifact_manifest.py +10 -9
- wandb/sdk/artifacts/artifact_manifest_entry.py +9 -10
- wandb/sdk/artifacts/artifact_manifests/artifact_manifest_v1.py +5 -3
- wandb/sdk/artifacts/storage_handlers/http_handler.py +1 -1
- wandb/sdk/artifacts/storage_handlers/s3_handler.py +1 -1
- wandb/sdk/artifacts/storage_policies/wandb_storage_policy.py +1 -1
- wandb/sdk/data_types/audio.py +38 -10
- wandb/sdk/data_types/base_types/media.py +6 -56
- wandb/sdk/data_types/graph.py +48 -14
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +1 -3
- wandb/sdk/data_types/helper_types/image_mask.py +1 -3
- wandb/sdk/data_types/histogram.py +34 -21
- wandb/sdk/data_types/html.py +35 -12
- wandb/sdk/data_types/image.py +104 -68
- wandb/sdk/data_types/molecule.py +32 -19
- wandb/sdk/data_types/object_3d.py +36 -17
- wandb/sdk/data_types/plotly.py +18 -5
- wandb/sdk/data_types/saved_model.py +4 -6
- wandb/sdk/data_types/table.py +59 -30
- wandb/sdk/data_types/video.py +53 -26
- wandb/sdk/integration_utils/auto_logging.py +2 -2
- wandb/sdk/interface/interface_queue.py +1 -4
- wandb/sdk/interface/interface_shared.py +26 -37
- wandb/sdk/interface/interface_sock.py +24 -14
- wandb/sdk/internal/internal_api.py +6 -0
- wandb/sdk/internal/job_builder.py +6 -0
- wandb/sdk/internal/settings_static.py +2 -3
- wandb/sdk/launch/agent/agent.py +8 -1
- wandb/sdk/launch/agent/run_queue_item_file_saver.py +2 -2
- wandb/sdk/launch/create_job.py +15 -2
- wandb/sdk/launch/inputs/internal.py +3 -4
- wandb/sdk/launch/inputs/schema.py +1 -0
- wandb/sdk/launch/runner/kubernetes_monitor.py +1 -0
- wandb/sdk/launch/runner/kubernetes_runner.py +323 -1
- wandb/sdk/launch/sweeps/scheduler.py +2 -3
- wandb/sdk/lib/asyncio_compat.py +19 -16
- wandb/sdk/lib/asyncio_manager.py +252 -0
- wandb/sdk/lib/deprecate.py +1 -7
- wandb/sdk/lib/disabled.py +1 -1
- wandb/sdk/lib/hashutil.py +27 -5
- wandb/sdk/lib/module.py +7 -13
- wandb/sdk/lib/printer.py +2 -2
- wandb/sdk/lib/printer_asyncio.py +3 -1
- wandb/sdk/lib/progress.py +0 -19
- wandb/sdk/lib/retry.py +185 -78
- wandb/sdk/lib/service/service_client.py +106 -0
- wandb/sdk/lib/service/service_connection.py +20 -26
- wandb/sdk/lib/service/service_token.py +30 -13
- wandb/sdk/mailbox/mailbox.py +13 -5
- wandb/sdk/mailbox/mailbox_handle.py +22 -13
- wandb/sdk/mailbox/response_handle.py +42 -106
- wandb/sdk/mailbox/wait_with_progress.py +7 -42
- wandb/sdk/wandb_init.py +77 -116
- wandb/sdk/wandb_login.py +19 -15
- wandb/sdk/wandb_metric.py +2 -0
- wandb/sdk/wandb_run.py +497 -469
- wandb/sdk/wandb_settings.py +145 -4
- wandb/sdk/wandb_setup.py +204 -124
- wandb/sdk/wandb_sweep.py +14 -13
- wandb/sdk/wandb_watch.py +4 -6
- wandb/sync/sync.py +10 -0
- wandb/util.py +58 -1
- wandb/wandb_run.py +1 -2
- {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/METADATA +1 -1
- {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/RECORD +145 -129
- wandb/sdk/interface/interface_relay.py +0 -38
- wandb/sdk/interface/router.py +0 -89
- wandb/sdk/interface/router_queue.py +0 -43
- wandb/sdk/interface/router_relay.py +0 -50
- wandb/sdk/interface/router_sock.py +0 -32
- wandb/sdk/lib/sock_client.py +0 -236
- wandb/vendor/pynvml/__init__.py +0 -0
- wandb/vendor/pynvml/pynvml.py +0 -4779
- {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/WHEEL +0 -0
- {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/entry_points.txt +0 -0
- {wandb-0.21.0.dist-info → wandb-0.21.2.dist-info}/licenses/LICENSE +0 -0
wandb/apis/public/runs.py
CHANGED
@@ -1,20 +1,45 @@
|
|
1
|
-
"""Public API
|
1
|
+
"""W&B Public API for Runs.
|
2
|
+
|
3
|
+
This module provides classes for interacting with W&B runs and their associated
|
4
|
+
data.
|
5
|
+
|
6
|
+
Example:
|
7
|
+
```python
|
8
|
+
from wandb.apis.public import Api
|
9
|
+
|
10
|
+
# Get runs matching filters
|
11
|
+
runs = Api().runs(
|
12
|
+
path="entity/project", filters={"state": "finished", "config.batch_size": 32}
|
13
|
+
)
|
14
|
+
|
15
|
+
# Access run data
|
16
|
+
for run in runs:
|
17
|
+
print(f"Run: {run.name}")
|
18
|
+
print(f"Config: {run.config}")
|
19
|
+
print(f"Metrics: {run.summary}")
|
20
|
+
|
21
|
+
# Get history with pandas
|
22
|
+
history_df = run.history(keys=["loss", "accuracy"], pandas=True)
|
23
|
+
|
24
|
+
# Work with artifacts
|
25
|
+
for artifact in run.logged_artifacts():
|
26
|
+
print(f"Artifact: {artifact.name}")
|
27
|
+
```
|
28
|
+
|
29
|
+
Note:
|
30
|
+
This module is part of the W&B Public API and provides read/write access
|
31
|
+
to run data. For logging new runs, use the wandb.init() function from
|
32
|
+
the main wandb package.
|
33
|
+
"""
|
34
|
+
|
35
|
+
from __future__ import annotations
|
2
36
|
|
3
37
|
import json
|
4
38
|
import os
|
5
39
|
import tempfile
|
6
40
|
import time
|
7
41
|
import urllib
|
8
|
-
from typing import
|
9
|
-
TYPE_CHECKING,
|
10
|
-
Any,
|
11
|
-
Collection,
|
12
|
-
Dict,
|
13
|
-
List,
|
14
|
-
Literal,
|
15
|
-
Mapping,
|
16
|
-
Optional,
|
17
|
-
)
|
42
|
+
from typing import TYPE_CHECKING, Any, Collection, Literal, Mapping
|
18
43
|
|
19
44
|
from wandb_gql import gql
|
20
45
|
|
@@ -85,22 +110,101 @@ def _server_provides_internal_id_for_project(client) -> bool:
|
|
85
110
|
]
|
86
111
|
|
87
112
|
|
88
|
-
|
89
|
-
|
113
|
+
@normalize_exceptions
|
114
|
+
def _convert_to_dict(value: Any) -> dict[str, Any]:
|
115
|
+
"""Converts a value to a dictionary.
|
90
116
|
|
91
|
-
|
117
|
+
If the value is already a dictionary, the value is returned unchanged.
|
118
|
+
If the value is a string, bytes, or bytearray, it is parsed as JSON.
|
119
|
+
For any other type, a TypeError is raised.
|
120
|
+
"""
|
121
|
+
if value is None:
|
122
|
+
return {}
|
123
|
+
|
124
|
+
if isinstance(value, dict):
|
125
|
+
return value
|
126
|
+
|
127
|
+
if isinstance(value, (str, bytes, bytearray)):
|
128
|
+
try:
|
129
|
+
return json.loads(value)
|
130
|
+
except json.decoder.JSONDecodeError:
|
131
|
+
# ignore invalid utf-8 or control characters
|
132
|
+
return json.loads(value, strict=False)
|
133
|
+
|
134
|
+
raise TypeError(f"Unable to convert {value} to a dict")
|
135
|
+
|
136
|
+
|
137
|
+
class Runs(SizedPaginator["Run"]):
|
138
|
+
"""A lazy iterator of `Run` objects associated with a project and optional filter.
|
139
|
+
|
140
|
+
Runs are retrieved in pages from the W&B server as needed.
|
141
|
+
|
142
|
+
This is generally used indirectly using the `Api.runs` namespace.
|
143
|
+
|
144
|
+
Args:
|
145
|
+
client: (`wandb.apis.public.RetryingClient`) The API client to use
|
146
|
+
for requests.
|
147
|
+
entity: (str) The entity (username or team) that owns the project.
|
148
|
+
project: (str) The name of the project to fetch runs from.
|
149
|
+
filters: (Optional[Dict[str, Any]]) A dictionary of filters to apply
|
150
|
+
to the runs query.
|
151
|
+
order: (str) Order can be `created_at`, `heartbeat_at`, `config.*.value`, or `summary_metrics.*`.
|
152
|
+
If you prepend order with a + order is ascending (default).
|
153
|
+
If you prepend order with a - order is descending.
|
154
|
+
The default order is run.created_at from oldest to newest.
|
155
|
+
per_page: (int) The number of runs to fetch per request (default is 50).
|
156
|
+
include_sweeps: (bool) Whether to include sweep information in the
|
157
|
+
runs. Defaults to True.
|
158
|
+
|
159
|
+
Examples:
|
160
|
+
```python
|
161
|
+
from wandb.apis.public.runs import Runs
|
162
|
+
from wandb.apis.public import Api
|
163
|
+
|
164
|
+
# Get all runs from a project that satisfy the filters
|
165
|
+
filters = {"state": "finished", "config.optimizer": "adam"}
|
166
|
+
|
167
|
+
runs = Api().runs(
|
168
|
+
client=api.client,
|
169
|
+
entity="entity",
|
170
|
+
project="project_name",
|
171
|
+
filters=filters,
|
172
|
+
)
|
173
|
+
|
174
|
+
# Iterate over runs and print details
|
175
|
+
for run in runs:
|
176
|
+
print(f"Run name: {run.name}")
|
177
|
+
print(f"Run ID: {run.id}")
|
178
|
+
print(f"Run URL: {run.url}")
|
179
|
+
print(f"Run state: {run.state}")
|
180
|
+
print(f"Run config: {run.config}")
|
181
|
+
print(f"Run summary: {run.summary}")
|
182
|
+
print(f"Run history (samples=5): {run.history(samples=5)}")
|
183
|
+
print("----------")
|
184
|
+
|
185
|
+
# Get histories for all runs with specific metrics
|
186
|
+
histories_df = runs.histories(
|
187
|
+
samples=100, # Number of samples per run
|
188
|
+
keys=["loss", "accuracy"], # Metrics to fetch
|
189
|
+
x_axis="_step", # X-axis metric
|
190
|
+
format="pandas", # Return as pandas DataFrame
|
191
|
+
)
|
192
|
+
```
|
92
193
|
"""
|
93
194
|
|
94
195
|
def __init__(
|
95
196
|
self,
|
96
|
-
client:
|
197
|
+
client: RetryingClient,
|
97
198
|
entity: str,
|
98
199
|
project: str,
|
99
|
-
filters:
|
100
|
-
order:
|
200
|
+
filters: dict[str, Any] | None = None,
|
201
|
+
order: str = "+created_at",
|
101
202
|
per_page: int = 50,
|
102
203
|
include_sweeps: bool = True,
|
103
204
|
):
|
205
|
+
if not order:
|
206
|
+
order = "+created_at"
|
207
|
+
|
104
208
|
self.QUERY = gql(
|
105
209
|
f"""#graphql
|
106
210
|
query Runs($project: String!, $entity: String!, $cursor: String, $perPage: Int = 50, $order: String, $filters: JSONString) {{
|
@@ -144,25 +248,43 @@ class Runs(SizedPaginator["Run"]):
|
|
144
248
|
|
145
249
|
@property
|
146
250
|
def _length(self):
|
251
|
+
"""Returns the total number of runs.
|
252
|
+
|
253
|
+
<!-- lazydoc-ignore: internal -->
|
254
|
+
"""
|
147
255
|
if not self.last_response:
|
148
256
|
self._load_page()
|
149
257
|
return self.last_response["project"]["runCount"]
|
150
258
|
|
151
259
|
@property
|
152
|
-
def more(self):
|
260
|
+
def more(self) -> bool:
|
261
|
+
"""Returns whether there are more runs to fetch.
|
262
|
+
|
263
|
+
<!-- lazydoc-ignore: internal -->
|
264
|
+
"""
|
153
265
|
if self.last_response:
|
154
|
-
return
|
266
|
+
return bool(
|
267
|
+
self.last_response["project"]["runs"]["pageInfo"]["hasNextPage"]
|
268
|
+
)
|
155
269
|
else:
|
156
270
|
return True
|
157
271
|
|
158
272
|
@property
|
159
273
|
def cursor(self):
|
274
|
+
"""Returns the cursor position for pagination of runs results.
|
275
|
+
|
276
|
+
<!-- lazydoc-ignore: internal -->
|
277
|
+
"""
|
160
278
|
if self.last_response:
|
161
279
|
return self.last_response["project"]["runs"]["edges"][-1]["cursor"]
|
162
280
|
else:
|
163
281
|
return None
|
164
282
|
|
165
283
|
def convert_objects(self):
|
284
|
+
"""Converts GraphQL edges to Runs objects.
|
285
|
+
|
286
|
+
<!-- lazydoc-ignore: internal -->
|
287
|
+
"""
|
166
288
|
objs = []
|
167
289
|
if self.last_response is None or self.last_response.get("project") is None:
|
168
290
|
raise ValueError("Could not find project {}".format(self.project))
|
@@ -200,7 +322,7 @@ class Runs(SizedPaginator["Run"]):
|
|
200
322
|
def histories(
|
201
323
|
self,
|
202
324
|
samples: int = 500,
|
203
|
-
keys:
|
325
|
+
keys: list[str] | None = None,
|
204
326
|
x_axis: str = "_step",
|
205
327
|
format: Literal["default", "pandas", "polars"] = "default",
|
206
328
|
stream: Literal["default", "system"] = "default",
|
@@ -208,15 +330,19 @@ class Runs(SizedPaginator["Run"]):
|
|
208
330
|
"""Return sampled history metrics for all runs that fit the filters conditions.
|
209
331
|
|
210
332
|
Args:
|
211
|
-
samples
|
212
|
-
keys
|
213
|
-
x_axis
|
214
|
-
format
|
215
|
-
|
333
|
+
samples: The number of samples to return per run
|
334
|
+
keys: Only return metrics for specific keys
|
335
|
+
x_axis: Use this metric as the xAxis defaults to _step
|
336
|
+
format: Format to return data in, options are "default", "pandas",
|
337
|
+
"polars"
|
338
|
+
stream: "default" for metrics, "system" for machine metrics
|
216
339
|
Returns:
|
217
|
-
pandas.DataFrame: If format="pandas"
|
218
|
-
|
219
|
-
|
340
|
+
pandas.DataFrame: If `format="pandas"`, returns a `pandas.DataFrame`
|
341
|
+
of history metrics.
|
342
|
+
polars.DataFrame: If `format="polars"`, returns a `polars.DataFrame`
|
343
|
+
of history metrics.
|
344
|
+
list of dicts: If `format="default"`, returns a list of dicts
|
345
|
+
containing history metrics with a `run_id` key.
|
220
346
|
"""
|
221
347
|
if format not in ("default", "pandas", "polars"):
|
222
348
|
raise ValueError(
|
@@ -300,6 +426,14 @@ class Runs(SizedPaginator["Run"]):
|
|
300
426
|
class Run(Attrs):
|
301
427
|
"""A single run associated with an entity and project.
|
302
428
|
|
429
|
+
Args:
|
430
|
+
client: The W&B API client.
|
431
|
+
entity: The entity associated with the run.
|
432
|
+
project: The project associated with the run.
|
433
|
+
run_id: The unique identifier for the run.
|
434
|
+
attrs: The attributes of the run.
|
435
|
+
include_sweeps: Whether to include sweeps in the run.
|
436
|
+
|
303
437
|
Attributes:
|
304
438
|
tags ([str]): a list of tags associated with the run
|
305
439
|
url (str): the url of this run
|
@@ -325,11 +459,11 @@ class Run(Attrs):
|
|
325
459
|
|
326
460
|
def __init__(
|
327
461
|
self,
|
328
|
-
client:
|
462
|
+
client: RetryingClient,
|
329
463
|
entity: str,
|
330
464
|
project: str,
|
331
465
|
run_id: str,
|
332
|
-
attrs:
|
466
|
+
attrs: Mapping | None = None,
|
333
467
|
include_sweeps: bool = True,
|
334
468
|
):
|
335
469
|
"""Initialize a Run object.
|
@@ -353,27 +487,32 @@ class Run(Attrs):
|
|
353
487
|
except OSError:
|
354
488
|
pass
|
355
489
|
self._summary = None
|
356
|
-
self._metadata:
|
490
|
+
self._metadata: dict[str, Any] | None = None
|
357
491
|
self._state = _attrs.get("state", "not found")
|
358
|
-
self.server_provides_internal_id_field:
|
492
|
+
self.server_provides_internal_id_field: bool | None = None
|
493
|
+
self._is_loaded: bool = False
|
359
494
|
|
360
495
|
self.load(force=not _attrs)
|
361
496
|
|
362
497
|
@property
|
363
498
|
def state(self):
|
499
|
+
"""The state of the run. Can be one of: Finished, Failed, Crashed, or Running."""
|
364
500
|
return self._state
|
365
501
|
|
366
502
|
@property
|
367
503
|
def entity(self):
|
504
|
+
"""The entity associated with the run."""
|
368
505
|
return self._entity
|
369
506
|
|
370
507
|
@property
|
371
508
|
def username(self):
|
509
|
+
"""This API is deprecated. Use `entity` instead."""
|
372
510
|
wandb.termwarn("Run.username is deprecated. Please use Run.entity instead.")
|
373
511
|
return self._entity
|
374
512
|
|
375
513
|
@property
|
376
514
|
def storage_id(self):
|
515
|
+
"""The unique storage identifier for the run."""
|
377
516
|
# For compatibility with wandb.Run, which has storage IDs
|
378
517
|
# in self.storage_id and names in self.id.
|
379
518
|
|
@@ -381,33 +520,38 @@ class Run(Attrs):
|
|
381
520
|
|
382
521
|
@property
|
383
522
|
def id(self):
|
523
|
+
"""The unique identifier for the run."""
|
384
524
|
return self._attrs.get("name")
|
385
525
|
|
386
526
|
@id.setter
|
387
527
|
def id(self, new_id):
|
528
|
+
"""Set the unique identifier for the run."""
|
388
529
|
attrs = self._attrs
|
389
530
|
attrs["name"] = new_id
|
390
531
|
return new_id
|
391
532
|
|
392
533
|
@property
|
393
534
|
def name(self):
|
535
|
+
"""The name of the run."""
|
394
536
|
return self._attrs.get("displayName")
|
395
537
|
|
396
538
|
@name.setter
|
397
539
|
def name(self, new_name):
|
540
|
+
"""Set the name of the run."""
|
398
541
|
self._attrs["displayName"] = new_name
|
399
542
|
return new_name
|
400
543
|
|
401
544
|
@classmethod
|
402
545
|
def create(
|
403
546
|
cls,
|
404
|
-
api,
|
405
|
-
run_id=None,
|
406
|
-
project=None,
|
407
|
-
entity=None,
|
547
|
+
api: public.Api,
|
548
|
+
run_id: str | None = None,
|
549
|
+
project: str | None = None,
|
550
|
+
entity: str | None = None,
|
408
551
|
state: Literal["running", "pending"] = "running",
|
409
552
|
):
|
410
553
|
"""Create a run for the given project."""
|
554
|
+
api._sentry.message("Invoking Run.create", level="info")
|
411
555
|
run_id = run_id or runid.generate_id()
|
412
556
|
project = project or api.settings.get("project") or "uncategorized"
|
413
557
|
mutation = gql(
|
@@ -454,6 +598,7 @@ class Run(Attrs):
|
|
454
598
|
|
455
599
|
def load(self, force=False):
|
456
600
|
if force or not self._attrs:
|
601
|
+
self._is_loaded = False
|
457
602
|
query = gql(f"""#graphql
|
458
603
|
query Run($project: String!, $entity: String!, $name: String!) {{
|
459
604
|
project(name: $project, entityName: $entity) {{
|
@@ -474,7 +619,6 @@ class Run(Attrs):
|
|
474
619
|
):
|
475
620
|
raise ValueError("Could not find run {}".format(self))
|
476
621
|
self._attrs = response["project"]["run"]
|
477
|
-
self._state = self._attrs["state"]
|
478
622
|
|
479
623
|
if self._include_sweeps and self.sweep_name and not self.sweep:
|
480
624
|
# There may be a lot of runs. Don't bother pulling them all
|
@@ -487,32 +631,31 @@ class Run(Attrs):
|
|
487
631
|
withRuns=False,
|
488
632
|
)
|
489
633
|
|
634
|
+
if not self._is_loaded:
|
635
|
+
self._load_from_attrs()
|
636
|
+
self._is_loaded = True
|
637
|
+
|
638
|
+
return self._attrs
|
639
|
+
|
640
|
+
def _load_from_attrs(self):
|
641
|
+
self._state = self._attrs.get("state", None)
|
642
|
+
self._attrs["config"] = _convert_to_dict(self._attrs.get("config"))
|
643
|
+
self._attrs["summaryMetrics"] = _convert_to_dict(
|
644
|
+
self._attrs.get("summaryMetrics")
|
645
|
+
)
|
646
|
+
self._attrs["systemMetrics"] = _convert_to_dict(
|
647
|
+
self._attrs.get("systemMetrics")
|
648
|
+
)
|
649
|
+
|
490
650
|
if "projectId" in self._attrs:
|
491
651
|
self._project_internal_id = int(self._attrs["projectId"])
|
492
652
|
else:
|
493
653
|
self._project_internal_id = None
|
494
654
|
|
495
|
-
try:
|
496
|
-
self._attrs["summaryMetrics"] = (
|
497
|
-
json.loads(self._attrs["summaryMetrics"])
|
498
|
-
if self._attrs.get("summaryMetrics")
|
499
|
-
else {}
|
500
|
-
)
|
501
|
-
except json.decoder.JSONDecodeError:
|
502
|
-
# ignore invalid utf-8 or control characters
|
503
|
-
self._attrs["summaryMetrics"] = json.loads(
|
504
|
-
self._attrs["summaryMetrics"],
|
505
|
-
strict=False,
|
506
|
-
)
|
507
|
-
self._attrs["systemMetrics"] = (
|
508
|
-
json.loads(self._attrs["systemMetrics"])
|
509
|
-
if self._attrs.get("systemMetrics")
|
510
|
-
else {}
|
511
|
-
)
|
512
655
|
if self._attrs.get("user"):
|
513
656
|
self.user = public.User(self.client, self._attrs["user"])
|
514
657
|
config_user, config_raw = {}, {}
|
515
|
-
for key, value in
|
658
|
+
for key, value in self._attrs.get("config").items():
|
516
659
|
config = config_raw if key in WANDB_INTERNAL_KEYS else config_user
|
517
660
|
if isinstance(value, dict) and "value" in value:
|
518
661
|
config[key] = value["value"]
|
@@ -521,10 +664,10 @@ class Run(Attrs):
|
|
521
664
|
config_raw.update(config_user)
|
522
665
|
self._attrs["config"] = config_user
|
523
666
|
self._attrs["rawconfig"] = config_raw
|
524
|
-
return self._attrs
|
525
667
|
|
526
668
|
@normalize_exceptions
|
527
669
|
def wait_until_finished(self):
|
670
|
+
"""Check the state of the run until it is finished."""
|
528
671
|
query = gql(
|
529
672
|
"""
|
530
673
|
query RunState($project: String!, $entity: String!, $name: String!) {
|
@@ -575,7 +718,12 @@ class Run(Attrs):
|
|
575
718
|
|
576
719
|
@normalize_exceptions
|
577
720
|
def delete(self, delete_artifacts=False):
|
578
|
-
"""Delete the given run from the wandb backend.
|
721
|
+
"""Delete the given run from the wandb backend.
|
722
|
+
|
723
|
+
Args:
|
724
|
+
delete_artifacts (bool, optional): Whether to delete the artifacts
|
725
|
+
associated with the run.
|
726
|
+
"""
|
579
727
|
mutation = gql(
|
580
728
|
"""
|
581
729
|
mutation DeleteRun(
|
@@ -604,10 +752,15 @@ class Run(Attrs):
|
|
604
752
|
)
|
605
753
|
|
606
754
|
def save(self):
|
755
|
+
"""Persist changes to the run object to the W&B backend."""
|
607
756
|
self.update()
|
608
757
|
|
609
758
|
@property
|
610
759
|
def json_config(self):
|
760
|
+
"""Return the run config as a JSON string.
|
761
|
+
|
762
|
+
<!-- lazydoc-ignore: internal -->
|
763
|
+
"""
|
611
764
|
config = {}
|
612
765
|
if "_wandb" in self.rawconfig:
|
613
766
|
config["_wandb"] = {"value": self.rawconfig["_wandb"], "desc": None}
|
@@ -653,17 +806,35 @@ class Run(Attrs):
|
|
653
806
|
return [json.loads(line) for line in response["project"]["run"][node]]
|
654
807
|
|
655
808
|
@normalize_exceptions
|
656
|
-
def files(
|
657
|
-
|
809
|
+
def files(
|
810
|
+
self,
|
811
|
+
names: list[str] | None = None,
|
812
|
+
pattern: str | None = None,
|
813
|
+
per_page: int = 50,
|
814
|
+
):
|
815
|
+
"""Returns a `Files` object for all files in the run which match the given criteria.
|
816
|
+
|
817
|
+
You can specify a list of exact file names to match, or a pattern to match against.
|
818
|
+
If both are provided, the pattern will be ignored.
|
658
819
|
|
659
820
|
Args:
|
660
821
|
names (list): names of the requested files, if empty returns all files
|
822
|
+
pattern (str, optional): Pattern to match when returning files from W&B.
|
823
|
+
This pattern uses mySQL's LIKE syntax,
|
824
|
+
so matching all files that end with .json would be "%.json".
|
825
|
+
If both names and pattern are provided, a ValueError will be raised.
|
661
826
|
per_page (int): number of results per page.
|
662
827
|
|
663
828
|
Returns:
|
664
829
|
A `Files` object, which is an iterator over `File` objects.
|
665
830
|
"""
|
666
|
-
return public.Files(
|
831
|
+
return public.Files(
|
832
|
+
self.client,
|
833
|
+
self,
|
834
|
+
names or [],
|
835
|
+
pattern=pattern,
|
836
|
+
per_page=per_page,
|
837
|
+
)
|
667
838
|
|
668
839
|
@normalize_exceptions
|
669
840
|
def file(self, name):
|
@@ -679,16 +850,17 @@ class Run(Attrs):
|
|
679
850
|
|
680
851
|
@normalize_exceptions
|
681
852
|
def upload_file(self, path, root="."):
|
682
|
-
"""Upload a file.
|
853
|
+
"""Upload a local file to W&B, associating it with this run.
|
683
854
|
|
684
855
|
Args:
|
685
|
-
path (str):
|
686
|
-
root (str):
|
687
|
-
|
856
|
+
path (str): Path to the file to upload. Can be absolute or relative.
|
857
|
+
root (str): The root path to save the file relative to. For example,
|
858
|
+
if you want to have the file saved in the run as "my_dir/file.txt"
|
688
859
|
and you're currently in "my_dir" you would set root to "../".
|
860
|
+
Defaults to current directory (".").
|
689
861
|
|
690
862
|
Returns:
|
691
|
-
A `File`
|
863
|
+
A `File` object representing the uploaded file.
|
692
864
|
"""
|
693
865
|
api = InternalApi(
|
694
866
|
default_settings={"entity": self.entity, "project": self.project},
|
@@ -697,8 +869,9 @@ class Run(Attrs):
|
|
697
869
|
api.set_current_run_id(self.id)
|
698
870
|
root = os.path.abspath(root)
|
699
871
|
name = os.path.relpath(path, root)
|
872
|
+
upload_path = util.make_file_path_upload_safe(name)
|
700
873
|
with open(os.path.join(root, name), "rb") as f:
|
701
|
-
api.push({LogicalPath(
|
874
|
+
api.push({LogicalPath(upload_path): f})
|
702
875
|
return public.Files(self.client, self, [name])[0]
|
703
876
|
|
704
877
|
@normalize_exceptions
|
@@ -747,15 +920,6 @@ class Run(Attrs):
|
|
747
920
|
def scan_history(self, keys=None, page_size=1000, min_step=None, max_step=None):
|
748
921
|
"""Returns an iterable collection of all history records for a run.
|
749
922
|
|
750
|
-
Example:
|
751
|
-
Export all the loss values for an example run
|
752
|
-
|
753
|
-
```python
|
754
|
-
run = api.run("l2k2/examples-numpy-boston/i0wt6xua")
|
755
|
-
history = run.scan_history(keys=["Loss"])
|
756
|
-
losses = [row["Loss"] for row in history]
|
757
|
-
```
|
758
|
-
|
759
923
|
Args:
|
760
924
|
keys ([str], optional): only fetch these keys, and only fetch rows that have all of keys defined.
|
761
925
|
page_size (int, optional): size of pages to fetch from the api.
|
@@ -764,6 +928,15 @@ class Run(Attrs):
|
|
764
928
|
|
765
929
|
Returns:
|
766
930
|
An iterable collection over history records (dict).
|
931
|
+
|
932
|
+
Example:
|
933
|
+
Export all the loss values for an example run
|
934
|
+
|
935
|
+
```python
|
936
|
+
run = api.run("entity/project-name/run-id")
|
937
|
+
history = run.scan_history(keys=["Loss"])
|
938
|
+
losses = [row["Loss"] for row in history]
|
939
|
+
```
|
767
940
|
"""
|
768
941
|
if keys is not None and not isinstance(keys, list):
|
769
942
|
wandb.termerror("keys must be specified in a list")
|
@@ -813,23 +986,27 @@ class Run(Attrs):
|
|
813
986
|
An iterable collection of all Artifact objects logged as outputs during this run.
|
814
987
|
|
815
988
|
Example:
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
989
|
+
```python
|
990
|
+
import wandb
|
991
|
+
import tempfile
|
992
|
+
|
993
|
+
with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".txt") as tmp:
|
994
|
+
tmp.write("This is a test artifact")
|
995
|
+
tmp_path = tmp.name
|
996
|
+
run = wandb.init(project="artifact-example")
|
997
|
+
artifact = wandb.Artifact("test_artifact", type="dataset")
|
998
|
+
artifact.add_file(tmp_path)
|
999
|
+
run.log_artifact(artifact)
|
1000
|
+
run.finish()
|
1001
|
+
|
1002
|
+
api = wandb.Api()
|
1003
|
+
|
1004
|
+
finished_run = api.run(f"{run.entity}/{run.project}/{run.id}")
|
1005
|
+
|
1006
|
+
for logged_artifact in finished_run.logged_artifacts():
|
1007
|
+
print(logged_artifact.name)
|
1008
|
+
```
|
1009
|
+
|
833
1010
|
"""
|
834
1011
|
return public.RunArtifacts(self.client, self, mode="logged", per_page=per_page)
|
835
1012
|
|
@@ -848,15 +1025,19 @@ class Run(Attrs):
|
|
848
1025
|
An iterable collection of Artifact objects explicitly used as inputs in this run.
|
849
1026
|
|
850
1027
|
Example:
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
1028
|
+
```python
|
1029
|
+
import wandb
|
1030
|
+
|
1031
|
+
run = wandb.init(project="artifact-example")
|
1032
|
+
run.use_artifact("test_artifact:latest")
|
1033
|
+
run.finish()
|
1034
|
+
|
1035
|
+
api = wandb.Api()
|
1036
|
+
finished_run = api.run(f"{run.entity}/{run.project}/{run.id}")
|
1037
|
+
for used_artifact in finished_run.used_artifacts():
|
1038
|
+
print(used_artifact.name)
|
1039
|
+
test_artifact
|
1040
|
+
```
|
860
1041
|
"""
|
861
1042
|
return public.RunArtifacts(self.client, self, mode="used", per_page=per_page)
|
862
1043
|
|
@@ -874,7 +1055,7 @@ class Run(Attrs):
|
|
874
1055
|
feature's artifact swapping functionality.
|
875
1056
|
|
876
1057
|
Returns:
|
877
|
-
|
1058
|
+
An `Artifact` object.
|
878
1059
|
"""
|
879
1060
|
api = InternalApi(
|
880
1061
|
default_settings={"entity": self.entity, "project": self.project},
|
@@ -901,9 +1082,9 @@ class Run(Attrs):
|
|
901
1082
|
@normalize_exceptions
|
902
1083
|
def log_artifact(
|
903
1084
|
self,
|
904
|
-
artifact:
|
905
|
-
aliases:
|
906
|
-
tags:
|
1085
|
+
artifact: wandb.Artifact,
|
1086
|
+
aliases: Collection[str] | None = None,
|
1087
|
+
tags: Collection[str] | None = None,
|
907
1088
|
):
|
908
1089
|
"""Declare an artifact as output of a run.
|
909
1090
|
|
@@ -947,6 +1128,7 @@ class Run(Attrs):
|
|
947
1128
|
|
948
1129
|
@property
|
949
1130
|
def summary(self):
|
1131
|
+
"""A mutable dict-like property that holds summary values associated with the run."""
|
950
1132
|
if self._summary is None:
|
951
1133
|
from wandb.old.summary import HTTPSummary
|
952
1134
|
|
@@ -956,6 +1138,7 @@ class Run(Attrs):
|
|
956
1138
|
|
957
1139
|
@property
|
958
1140
|
def path(self):
|
1141
|
+
"""The path of the run. The path is a list containing the entity, project, and run_id."""
|
959
1142
|
return [
|
960
1143
|
urllib.parse.quote_plus(str(self.entity)),
|
961
1144
|
urllib.parse.quote_plus(str(self.project)),
|
@@ -964,12 +1147,22 @@ class Run(Attrs):
|
|
964
1147
|
|
965
1148
|
@property
|
966
1149
|
def url(self):
|
1150
|
+
"""The URL of the run.
|
1151
|
+
|
1152
|
+
The run URL is generated from the entity, project, and run_id. For
|
1153
|
+
SaaS users, it takes the form of `https://wandb.ai/entity/project/run_id`.
|
1154
|
+
"""
|
967
1155
|
path = self.path
|
968
1156
|
path.insert(2, "runs")
|
969
1157
|
return self.client.app_url + "/".join(path)
|
970
1158
|
|
971
1159
|
@property
|
972
1160
|
def metadata(self):
|
1161
|
+
"""Metadata about the run from wandb-metadata.json.
|
1162
|
+
|
1163
|
+
Metadata includes the run's description, tags, start time, memory
|
1164
|
+
usage and more.
|
1165
|
+
"""
|
973
1166
|
if self._metadata is None:
|
974
1167
|
try:
|
975
1168
|
f = self.file("wandb-metadata.json")
|
@@ -985,6 +1178,7 @@ class Run(Attrs):
|
|
985
1178
|
|
986
1179
|
@property
|
987
1180
|
def lastHistoryStep(self): # noqa: N802
|
1181
|
+
"""Returns the last step logged in the run's history."""
|
988
1182
|
query = gql(
|
989
1183
|
"""
|
990
1184
|
query RunHistoryKeys($project: String!, $entity: String!, $name: String!) {
|