wandb 0.21.0__py3-none-win_amd64.whl → 0.21.1__py3-none-win_amd64.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 +526 -360
- wandb/apis/public/artifacts.py +204 -8
- 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/registries_search.py +7 -15
- wandb/apis/public/reports.py +83 -5
- 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/beta/workflows.py +66 -30
- wandb/bin/gpu_stats.exe +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +80 -1
- 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/errors.py +13 -0
- wandb/integration/metaflow/metaflow.py +205 -190
- wandb/integration/openai/fine_tuning.py +1 -2
- wandb/jupyter.py +5 -5
- wandb/plot/custom_chart.py +30 -7
- wandb/proto/v3/wandb_internal_pb2.py +280 -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/_internal_artifact.py +19 -8
- wandb/sdk/artifacts/_validators.py +8 -0
- wandb/sdk/artifacts/artifact.py +106 -75
- 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/internal/internal_api.py +6 -0
- wandb/sdk/internal/job_builder.py +6 -0
- 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 +3 -1
- 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 +328 -1
- wandb/sdk/launch/sweeps/scheduler.py +2 -3
- wandb/sdk/lib/asyncio_compat.py +3 -0
- wandb/sdk/lib/deprecate.py +1 -7
- wandb/sdk/lib/disabled.py +1 -1
- wandb/sdk/lib/hashutil.py +14 -1
- wandb/sdk/lib/module.py +7 -13
- wandb/sdk/lib/progress.py +0 -19
- wandb/sdk/lib/sock_client.py +0 -4
- wandb/sdk/wandb_init.py +66 -91
- wandb/sdk/wandb_login.py +18 -14
- wandb/sdk/wandb_metric.py +2 -0
- wandb/sdk/wandb_run.py +406 -414
- wandb/sdk/wandb_settings.py +130 -2
- wandb/sdk/wandb_setup.py +28 -28
- wandb/sdk/wandb_sweep.py +14 -13
- wandb/sdk/wandb_watch.py +4 -6
- wandb/sync/sync.py +10 -0
- wandb/util.py +57 -0
- wandb/wandb_run.py +1 -2
- {wandb-0.21.0.dist-info → wandb-0.21.1.dist-info}/METADATA +1 -1
- {wandb-0.21.0.dist-info → wandb-0.21.1.dist-info}/RECORD +95 -95
- wandb/vendor/pynvml/__init__.py +0 -0
- wandb/vendor/pynvml/pynvml.py +0 -4779
- {wandb-0.21.0.dist-info → wandb-0.21.1.dist-info}/WHEEL +0 -0
- {wandb-0.21.0.dist-info → wandb-0.21.1.dist-info}/entry_points.txt +0 -0
- {wandb-0.21.0.dist-info → wandb-0.21.1.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_settings.py
CHANGED
@@ -162,7 +162,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
162
162
|
This class manages configuration settings for the W&B SDK,
|
163
163
|
ensuring type safety and validation of all settings. Settings are accessible
|
164
164
|
as attributes and can be initialized programmatically, through environment
|
165
|
-
variables (WANDB_ prefix), and
|
165
|
+
variables (`WANDB_ prefix`), and with configuration files.
|
166
166
|
|
167
167
|
The settings are organized into three categories:
|
168
168
|
1. Public settings: Core configuration options that users can safely modify to customize
|
@@ -230,7 +230,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
230
230
|
"""The type of console capture to be applied.
|
231
231
|
|
232
232
|
Possible values are:
|
233
|
-
|
233
|
+
"auto" - Automatically selects the console capture method based on the
|
234
234
|
system environment and settings.
|
235
235
|
|
236
236
|
"off" - Disables console capture.
|
@@ -955,6 +955,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
955
955
|
|
956
956
|
@model_validator(mode="after")
|
957
957
|
def validate_mutual_exclusion_of_branching_args(self) -> Self:
|
958
|
+
"""Check if `fork_from`, `resume`, and `resume_from` are mutually exclusive.
|
959
|
+
|
960
|
+
<!-- lazydoc-ignore: internal -->
|
961
|
+
"""
|
958
962
|
if (
|
959
963
|
sum(
|
960
964
|
o is not None
|
@@ -1002,6 +1006,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1002
1006
|
@field_validator("api_key", mode="after")
|
1003
1007
|
@classmethod
|
1004
1008
|
def validate_api_key(cls, value):
|
1009
|
+
"""Validate the API key.
|
1010
|
+
|
1011
|
+
<!-- lazydoc-ignore: internal -->
|
1012
|
+
"""
|
1005
1013
|
if value is not None and (len(value) > len(value.strip())):
|
1006
1014
|
raise UsageError("API key cannot start or end with whitespace")
|
1007
1015
|
return value
|
@@ -1009,6 +1017,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1009
1017
|
@field_validator("base_url", mode="after")
|
1010
1018
|
@classmethod
|
1011
1019
|
def validate_base_url(cls, value):
|
1020
|
+
"""Validate the base URL.
|
1021
|
+
|
1022
|
+
<!-- lazydoc-ignore: internal -->
|
1023
|
+
"""
|
1012
1024
|
validate_url(value)
|
1013
1025
|
# wandb.ai-specific checks
|
1014
1026
|
if re.match(r".*wandb\.ai[^\.]*$", value) and "api." not in value:
|
@@ -1023,6 +1035,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1023
1035
|
@field_validator("code_dir", mode="before")
|
1024
1036
|
@classmethod
|
1025
1037
|
def validate_code_dir(cls, value):
|
1038
|
+
"""Validate the code directory.
|
1039
|
+
|
1040
|
+
<!-- lazydoc-ignore: internal -->
|
1041
|
+
"""
|
1026
1042
|
# TODO: add native support for pathlib.Path
|
1027
1043
|
if isinstance(value, pathlib.Path):
|
1028
1044
|
return str(value)
|
@@ -1031,6 +1047,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1031
1047
|
@field_validator("console", mode="after")
|
1032
1048
|
@classmethod
|
1033
1049
|
def validate_console(cls, value, values):
|
1050
|
+
"""Validate the console capture method.
|
1051
|
+
|
1052
|
+
<!-- lazydoc-ignore: internal -->
|
1053
|
+
"""
|
1034
1054
|
if value != "auto":
|
1035
1055
|
return value
|
1036
1056
|
|
@@ -1039,6 +1059,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1039
1059
|
@field_validator("x_executable", mode="before")
|
1040
1060
|
@classmethod
|
1041
1061
|
def validate_x_executable(cls, value):
|
1062
|
+
"""Validate the Python executable path.
|
1063
|
+
|
1064
|
+
<!-- lazydoc-ignore: internal -->
|
1065
|
+
"""
|
1042
1066
|
# TODO: add native support for pathlib.Path
|
1043
1067
|
if isinstance(value, pathlib.Path):
|
1044
1068
|
return str(value)
|
@@ -1054,6 +1078,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1054
1078
|
@field_validator("x_file_stream_max_line_bytes", mode="after")
|
1055
1079
|
@classmethod
|
1056
1080
|
def validate_file_stream_max_line_bytes(cls, value):
|
1081
|
+
"""Validate the maximum line length for filestream JSONL files.
|
1082
|
+
|
1083
|
+
<!-- lazydoc-ignore: internal -->
|
1084
|
+
"""
|
1057
1085
|
if value is not None and value < 1:
|
1058
1086
|
raise ValueError("File stream max line bytes must be greater than 0")
|
1059
1087
|
return value
|
@@ -1061,6 +1089,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1061
1089
|
@field_validator("x_files_dir", mode="before")
|
1062
1090
|
@classmethod
|
1063
1091
|
def validate_x_files_dir(cls, value):
|
1092
|
+
"""Validate the files directory.
|
1093
|
+
|
1094
|
+
<!-- lazydoc-ignore: internal -->
|
1095
|
+
"""
|
1064
1096
|
# TODO: add native support for pathlib.Path
|
1065
1097
|
if isinstance(value, pathlib.Path):
|
1066
1098
|
return str(value)
|
@@ -1069,6 +1101,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1069
1101
|
@field_validator("fork_from", mode="before")
|
1070
1102
|
@classmethod
|
1071
1103
|
def validate_fork_from(cls, value, values) -> Optional[RunMoment]:
|
1104
|
+
"""Validate the fork_from field.
|
1105
|
+
|
1106
|
+
<!-- lazydoc-ignore: internal -->
|
1107
|
+
"""
|
1072
1108
|
run_moment = cls._runmoment_preprocessor(value)
|
1073
1109
|
|
1074
1110
|
if hasattr(values, "data"):
|
@@ -1093,6 +1129,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1093
1129
|
@field_validator("http_proxy", mode="after")
|
1094
1130
|
@classmethod
|
1095
1131
|
def validate_http_proxy(cls, value):
|
1132
|
+
"""Validate the HTTP proxy.
|
1133
|
+
|
1134
|
+
<!-- lazydoc-ignore: internal -->
|
1135
|
+
"""
|
1096
1136
|
if value is None:
|
1097
1137
|
return None
|
1098
1138
|
validate_url(value)
|
@@ -1101,6 +1141,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1101
1141
|
@field_validator("https_proxy", mode="after")
|
1102
1142
|
@classmethod
|
1103
1143
|
def validate_https_proxy(cls, value):
|
1144
|
+
"""Validate the HTTPS proxy.
|
1145
|
+
|
1146
|
+
<!-- lazydoc-ignore: internal -->
|
1147
|
+
"""
|
1104
1148
|
if value is None:
|
1105
1149
|
return None
|
1106
1150
|
validate_url(value)
|
@@ -1109,11 +1153,19 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1109
1153
|
@field_validator("ignore_globs", mode="after")
|
1110
1154
|
@classmethod
|
1111
1155
|
def validate_ignore_globs(cls, value):
|
1156
|
+
"""Validate the ignore globs.
|
1157
|
+
|
1158
|
+
<!-- lazydoc-ignore: internal -->
|
1159
|
+
"""
|
1112
1160
|
return tuple(value) if not isinstance(value, tuple) else value
|
1113
1161
|
|
1114
1162
|
@field_validator("program", mode="before")
|
1115
1163
|
@classmethod
|
1116
1164
|
def validate_program(cls, value):
|
1165
|
+
"""Validate the program path.
|
1166
|
+
|
1167
|
+
<!-- lazydoc-ignore: internal -->
|
1168
|
+
"""
|
1117
1169
|
# TODO: add native support for pathlib.Path
|
1118
1170
|
if isinstance(value, pathlib.Path):
|
1119
1171
|
return str(value)
|
@@ -1122,6 +1174,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1122
1174
|
@field_validator("program_abspath", mode="before")
|
1123
1175
|
@classmethod
|
1124
1176
|
def validate_program_abspath(cls, value):
|
1177
|
+
"""Validate the absolute program path.
|
1178
|
+
|
1179
|
+
<!-- lazydoc-ignore: internal -->
|
1180
|
+
"""
|
1125
1181
|
# TODO: add native support for pathlib.Path
|
1126
1182
|
if isinstance(value, pathlib.Path):
|
1127
1183
|
return str(value)
|
@@ -1130,6 +1186,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1130
1186
|
@field_validator("program_relpath", mode="before")
|
1131
1187
|
@classmethod
|
1132
1188
|
def validate_program_relpath(cls, value):
|
1189
|
+
"""Validate the relative program path.
|
1190
|
+
|
1191
|
+
<!-- lazydoc-ignore: internal -->
|
1192
|
+
"""
|
1133
1193
|
# TODO: add native support for pathlib.Path
|
1134
1194
|
if isinstance(value, pathlib.Path):
|
1135
1195
|
return str(value)
|
@@ -1138,6 +1198,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1138
1198
|
@field_validator("project", mode="after")
|
1139
1199
|
@classmethod
|
1140
1200
|
def validate_project(cls, value, values):
|
1201
|
+
"""Validate the project name.
|
1202
|
+
|
1203
|
+
<!-- lazydoc-ignore: internal -->
|
1204
|
+
"""
|
1141
1205
|
if value is None:
|
1142
1206
|
return None
|
1143
1207
|
invalid_chars_list = list("/\\#?%:")
|
@@ -1155,6 +1219,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1155
1219
|
@field_validator("resume", mode="before")
|
1156
1220
|
@classmethod
|
1157
1221
|
def validate_resume(cls, value):
|
1222
|
+
"""Validate the resume behavior.
|
1223
|
+
|
1224
|
+
<!-- lazydoc-ignore: internal -->
|
1225
|
+
"""
|
1158
1226
|
if value is False:
|
1159
1227
|
return None
|
1160
1228
|
if value is True:
|
@@ -1164,6 +1232,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1164
1232
|
@field_validator("resume_from", mode="before")
|
1165
1233
|
@classmethod
|
1166
1234
|
def validate_resume_from(cls, value, values) -> Optional[RunMoment]:
|
1235
|
+
"""Validate the resume_from field.
|
1236
|
+
|
1237
|
+
<!-- lazydoc-ignore: internal -->
|
1238
|
+
"""
|
1167
1239
|
run_moment = cls._runmoment_preprocessor(value)
|
1168
1240
|
|
1169
1241
|
if hasattr(values, "data"):
|
@@ -1186,6 +1258,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1186
1258
|
@field_validator("root_dir", mode="before")
|
1187
1259
|
@classmethod
|
1188
1260
|
def validate_root_dir(cls, value):
|
1261
|
+
"""Validate the root directory.
|
1262
|
+
|
1263
|
+
<!-- lazydoc-ignore: internal -->
|
1264
|
+
"""
|
1189
1265
|
# TODO: add native support for pathlib.Path
|
1190
1266
|
if isinstance(value, pathlib.Path):
|
1191
1267
|
return str(value)
|
@@ -1194,6 +1270,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1194
1270
|
@field_validator("run_id", mode="after")
|
1195
1271
|
@classmethod
|
1196
1272
|
def validate_run_id(cls, value, values):
|
1273
|
+
"""Validate the run ID.
|
1274
|
+
|
1275
|
+
<!-- lazydoc-ignore: internal -->
|
1276
|
+
"""
|
1197
1277
|
if value is None:
|
1198
1278
|
return None
|
1199
1279
|
|
@@ -1213,6 +1293,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1213
1293
|
@field_validator("settings_system", mode="after")
|
1214
1294
|
@classmethod
|
1215
1295
|
def validate_settings_system(cls, value):
|
1296
|
+
"""Validate the system settings file path.
|
1297
|
+
|
1298
|
+
<!-- lazydoc-ignore: internal -->
|
1299
|
+
"""
|
1216
1300
|
if value is None:
|
1217
1301
|
return None
|
1218
1302
|
elif isinstance(value, pathlib.Path):
|
@@ -1223,6 +1307,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1223
1307
|
@field_validator("x_service_wait", mode="after")
|
1224
1308
|
@classmethod
|
1225
1309
|
def validate_service_wait(cls, value):
|
1310
|
+
"""Validate the service wait time.
|
1311
|
+
|
1312
|
+
<!-- lazydoc-ignore: internal -->
|
1313
|
+
"""
|
1226
1314
|
if value < 0:
|
1227
1315
|
raise UsageError("Service wait time cannot be negative")
|
1228
1316
|
return value
|
@@ -1230,6 +1318,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1230
1318
|
@field_validator("start_method", mode="after")
|
1231
1319
|
@classmethod
|
1232
1320
|
def validate_start_method(cls, value):
|
1321
|
+
"""Validate the start method for subprocesses.
|
1322
|
+
|
1323
|
+
<!-- lazydoc-ignore: internal -->
|
1324
|
+
"""
|
1233
1325
|
if value is None:
|
1234
1326
|
return value
|
1235
1327
|
wandb.termwarn(
|
@@ -1248,6 +1340,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1248
1340
|
@field_validator("x_stats_gpu_device_ids", mode="before")
|
1249
1341
|
@classmethod
|
1250
1342
|
def validate_x_stats_gpu_device_ids(cls, value):
|
1343
|
+
"""Validate the GPU device IDs.
|
1344
|
+
|
1345
|
+
<!-- lazydoc-ignore: internal -->
|
1346
|
+
"""
|
1251
1347
|
if isinstance(value, str):
|
1252
1348
|
return json.loads(value)
|
1253
1349
|
return value
|
@@ -1255,6 +1351,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1255
1351
|
@field_validator("x_stats_neuron_monitor_config_path", mode="before")
|
1256
1352
|
@classmethod
|
1257
1353
|
def validate_x_stats_neuron_monitor_config_path(cls, value):
|
1354
|
+
"""Validate the path to the neuron-monitor config file.
|
1355
|
+
|
1356
|
+
<!-- lazydoc-ignore: internal -->
|
1357
|
+
"""
|
1258
1358
|
# TODO: add native support for pathlib.Path
|
1259
1359
|
if isinstance(value, pathlib.Path):
|
1260
1360
|
return str(value)
|
@@ -1263,6 +1363,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1263
1363
|
@field_validator("x_stats_open_metrics_endpoints", mode="before")
|
1264
1364
|
@classmethod
|
1265
1365
|
def validate_stats_open_metrics_endpoints(cls, value):
|
1366
|
+
"""Validate the OpenMetrics endpoints.
|
1367
|
+
|
1368
|
+
<!-- lazydoc-ignore: internal -->
|
1369
|
+
"""
|
1266
1370
|
if isinstance(value, str):
|
1267
1371
|
return json.loads(value)
|
1268
1372
|
return value
|
@@ -1270,6 +1374,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1270
1374
|
@field_validator("x_stats_open_metrics_filters", mode="before")
|
1271
1375
|
@classmethod
|
1272
1376
|
def validate_stats_open_metrics_filters(cls, value):
|
1377
|
+
"""Validate the OpenMetrics filters.
|
1378
|
+
|
1379
|
+
<!-- lazydoc-ignore: internal -->
|
1380
|
+
"""
|
1273
1381
|
if isinstance(value, str):
|
1274
1382
|
return json.loads(value)
|
1275
1383
|
return value
|
@@ -1277,6 +1385,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1277
1385
|
@field_validator("x_stats_open_metrics_http_headers", mode="before")
|
1278
1386
|
@classmethod
|
1279
1387
|
def validate_stats_open_metrics_http_headers(cls, value):
|
1388
|
+
"""Validate the OpenMetrics HTTP headers.
|
1389
|
+
|
1390
|
+
<!-- lazydoc-ignore: internal -->
|
1391
|
+
"""
|
1280
1392
|
if isinstance(value, str):
|
1281
1393
|
return json.loads(value)
|
1282
1394
|
return value
|
@@ -1284,6 +1396,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1284
1396
|
@field_validator("x_stats_sampling_interval", mode="after")
|
1285
1397
|
@classmethod
|
1286
1398
|
def validate_stats_sampling_interval(cls, value):
|
1399
|
+
"""Validate the stats sampling interval.
|
1400
|
+
|
1401
|
+
<!-- lazydoc-ignore: internal -->
|
1402
|
+
"""
|
1287
1403
|
if value < 0.1:
|
1288
1404
|
raise UsageError("Stats sampling interval cannot be less than 0.1 seconds")
|
1289
1405
|
return value
|
@@ -1291,6 +1407,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1291
1407
|
@field_validator("sweep_id", mode="after")
|
1292
1408
|
@classmethod
|
1293
1409
|
def validate_sweep_id(cls, value):
|
1410
|
+
"""Validate the sweep ID.
|
1411
|
+
|
1412
|
+
<!-- lazydoc-ignore: internal -->
|
1413
|
+
"""
|
1294
1414
|
if value is None:
|
1295
1415
|
return None
|
1296
1416
|
if len(value) == 0:
|
@@ -1304,6 +1424,10 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1304
1424
|
@field_validator("sweep_param_path", mode="before")
|
1305
1425
|
@classmethod
|
1306
1426
|
def validate_sweep_param_path(cls, value):
|
1427
|
+
"""Validate the sweep parameter path.
|
1428
|
+
|
1429
|
+
<!-- lazydoc-ignore: internal -->
|
1430
|
+
"""
|
1307
1431
|
# TODO: add native support for pathlib.Path
|
1308
1432
|
if isinstance(value, pathlib.Path):
|
1309
1433
|
return str(value)
|
@@ -1503,6 +1627,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1503
1627
|
@computed_field # type: ignore[prop-decorator]
|
1504
1628
|
@property
|
1505
1629
|
def run_mode(self) -> Literal["run", "offline-run"]:
|
1630
|
+
"""The mode of the run. Can be either "run" or "offline-run"."""
|
1506
1631
|
return "run" if not self._offline else "offline-run"
|
1507
1632
|
|
1508
1633
|
@computed_field # type: ignore[prop-decorator]
|
@@ -1538,6 +1663,7 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1538
1663
|
@computed_field # type: ignore[prop-decorator]
|
1539
1664
|
@property
|
1540
1665
|
def sync_dir(self) -> str:
|
1666
|
+
"""The directory for storing the run's files."""
|
1541
1667
|
return _path_convert(
|
1542
1668
|
self.wandb_dir,
|
1543
1669
|
f"{self.run_mode}-{self.timespec}-{self.run_id}",
|
@@ -1552,11 +1678,13 @@ class Settings(BaseModel, validate_assignment=True):
|
|
1552
1678
|
@computed_field # type: ignore[prop-decorator]
|
1553
1679
|
@property
|
1554
1680
|
def sync_symlink_latest(self) -> str:
|
1681
|
+
"""Path to the symlink to the most recent run's transaction log file."""
|
1555
1682
|
return _path_convert(self.wandb_dir, "latest-run")
|
1556
1683
|
|
1557
1684
|
@computed_field # type: ignore[prop-decorator]
|
1558
1685
|
@property
|
1559
1686
|
def timespec(self) -> str:
|
1687
|
+
"""The time specification for the run."""
|
1560
1688
|
return self._start_datetime
|
1561
1689
|
|
1562
1690
|
@computed_field # type: ignore[prop-decorator]
|
wandb/sdk/wandb_setup.py
CHANGED
@@ -419,49 +419,49 @@ def setup(settings: Settings | None = None) -> _WandbSetup:
|
|
419
419
|
overridden by subsequent `wandb.init()` calls.
|
420
420
|
|
421
421
|
Example:
|
422
|
-
|
423
|
-
|
422
|
+
```python
|
423
|
+
import multiprocessing
|
424
424
|
|
425
|
-
|
425
|
+
import wandb
|
426
426
|
|
427
427
|
|
428
|
-
|
429
|
-
|
430
|
-
|
431
|
-
|
428
|
+
def run_experiment(params):
|
429
|
+
with wandb.init(config=params):
|
430
|
+
# Run experiment
|
431
|
+
pass
|
432
432
|
|
433
433
|
|
434
|
-
|
435
|
-
|
436
|
-
|
434
|
+
if __name__ == "__main__":
|
435
|
+
# Start backend and set global config
|
436
|
+
wandb.setup(settings={"project": "my_project"})
|
437
437
|
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
|
442
|
-
|
438
|
+
# Define experiment parameters
|
439
|
+
experiment_params = [
|
440
|
+
{"learning_rate": 0.01, "epochs": 10},
|
441
|
+
{"learning_rate": 0.001, "epochs": 20},
|
442
|
+
]
|
443
443
|
|
444
|
-
|
445
|
-
|
446
|
-
|
447
|
-
|
448
|
-
|
449
|
-
|
444
|
+
# Start multiple processes, each running a separate experiment
|
445
|
+
processes = []
|
446
|
+
for params in experiment_params:
|
447
|
+
p = multiprocessing.Process(target=run_experiment, args=(params,))
|
448
|
+
p.start()
|
449
|
+
processes.append(p)
|
450
450
|
|
451
|
-
|
452
|
-
|
453
|
-
|
451
|
+
# Wait for all processes to complete
|
452
|
+
for p in processes:
|
453
|
+
p.join()
|
454
454
|
|
455
|
-
|
456
|
-
|
457
|
-
|
455
|
+
# Optional: Explicitly shut down the backend
|
456
|
+
wandb.teardown()
|
457
|
+
```
|
458
458
|
"""
|
459
459
|
return _setup(settings=settings)
|
460
460
|
|
461
461
|
|
462
462
|
@wb_logging.log_to_all_runs()
|
463
463
|
def teardown(exit_code: int | None = None) -> None:
|
464
|
-
"""Waits for
|
464
|
+
"""Waits for W&B to finish and frees resources.
|
465
465
|
|
466
466
|
Completes any runs that were not explicitly finished
|
467
467
|
using `run.finish()` and waits for all data to be uploaded.
|
wandb/sdk/wandb_sweep.py
CHANGED
@@ -45,11 +45,12 @@ def sweep(
|
|
45
45
|
Make note the unique identifier, `sweep_id`, that is returned.
|
46
46
|
At a later step provide the `sweep_id` to a sweep agent.
|
47
47
|
|
48
|
+
See [Sweep configuration structure](https://docs.wandb.ai/guides/sweeps/define-sweep-configuration)
|
49
|
+
for information on how to define your sweep.
|
50
|
+
|
48
51
|
Args:
|
49
52
|
sweep: The configuration of a hyperparameter search.
|
50
|
-
(or configuration generator).
|
51
|
-
[Sweep configuration structure](https://docs.wandb.ai/guides/sweeps/define-sweep-configuration)
|
52
|
-
for information on how to define your sweep.
|
53
|
+
(or configuration generator).
|
53
54
|
If you provide a callable, ensure that the callable does
|
54
55
|
not take arguments and that it returns a dictionary that
|
55
56
|
conforms to the W&B sweep config spec.
|
@@ -64,7 +65,7 @@ def sweep(
|
|
64
65
|
prior_runs: The run IDs of existing runs to add to this sweep.
|
65
66
|
|
66
67
|
Returns:
|
67
|
-
|
68
|
+
str: A unique identifier for the sweep.
|
68
69
|
"""
|
69
70
|
if callable(sweep):
|
70
71
|
sweep = sweep()
|
@@ -99,16 +100,16 @@ def controller(
|
|
99
100
|
) -> "_WandbController":
|
100
101
|
"""Public sweep controller constructor.
|
101
102
|
|
102
|
-
|
103
|
-
|
104
|
-
|
103
|
+
Examples:
|
104
|
+
```python
|
105
|
+
import wandb
|
105
106
|
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
107
|
+
tuner = wandb.controller(...)
|
108
|
+
print(tuner.sweep_config)
|
109
|
+
print(tuner.sweep_id)
|
110
|
+
tuner.configure_search(...)
|
111
|
+
tuner.configure_stopping(...)
|
112
|
+
```
|
112
113
|
|
113
114
|
"""
|
114
115
|
from ..wandb_controller import _WandbController
|
wandb/sdk/wandb_watch.py
CHANGED
@@ -17,15 +17,13 @@ from .lib import telemetry
|
|
17
17
|
if TYPE_CHECKING:
|
18
18
|
import torch # type: ignore [import-not-found]
|
19
19
|
|
20
|
-
from wandb.sdk.wandb_run import Run
|
21
|
-
|
22
20
|
logger = logging.getLogger("wandb")
|
23
21
|
|
24
22
|
_global_watch_idx = 0
|
25
23
|
|
26
24
|
|
27
25
|
def _watch(
|
28
|
-
run: Run,
|
26
|
+
run: wandb.Run,
|
29
27
|
models: torch.nn.Module | Sequence[torch.nn.Module],
|
30
28
|
criterion: torch.F | None = None,
|
31
29
|
log: Literal["gradients", "parameters", "all"] | None = "gradients",
|
@@ -39,7 +37,7 @@ def _watch(
|
|
39
37
|
extended to support arbitrary machine learning models in the future.
|
40
38
|
|
41
39
|
Args:
|
42
|
-
run (wandb.
|
40
|
+
run (wandb.Run): The run object to log to.
|
43
41
|
models (Union[torch.nn.Module, Sequence[torch.nn.Module]]):
|
44
42
|
A single model or a sequence of models to be monitored.
|
45
43
|
criterion (Optional[torch.F]):
|
@@ -122,12 +120,12 @@ def _watch(
|
|
122
120
|
|
123
121
|
|
124
122
|
def _unwatch(
|
125
|
-
run: Run, models: torch.nn.Module | Sequence[torch.nn.Module] | None = None
|
123
|
+
run: wandb.Run, models: torch.nn.Module | Sequence[torch.nn.Module] | None = None
|
126
124
|
) -> None:
|
127
125
|
"""Remove pytorch model topology, gradient and parameter hooks.
|
128
126
|
|
129
127
|
Args:
|
130
|
-
run (wandb.
|
128
|
+
run (wandb.Run):
|
131
129
|
The run object to log to.
|
132
130
|
models (torch.nn.Module | Sequence[torch.nn.Module]):
|
133
131
|
Optional list of pytorch models that have had watch called on them
|
wandb/sync/sync.py
CHANGED
@@ -54,6 +54,7 @@ class SyncThread(threading.Thread):
|
|
54
54
|
log_path=None,
|
55
55
|
append=None,
|
56
56
|
skip_console=None,
|
57
|
+
replace_tags=None,
|
57
58
|
):
|
58
59
|
threading.Thread.__init__(self)
|
59
60
|
# mark this process as internal
|
@@ -71,6 +72,7 @@ class SyncThread(threading.Thread):
|
|
71
72
|
self._log_path = log_path
|
72
73
|
self._append = append
|
73
74
|
self._skip_console = skip_console
|
75
|
+
self._replace_tags = replace_tags or {}
|
74
76
|
|
75
77
|
self._tmp_dir = tempfile.TemporaryDirectory()
|
76
78
|
atexit.register(self._tmp_dir.cleanup)
|
@@ -94,6 +96,11 @@ class SyncThread(threading.Thread):
|
|
94
96
|
pb.run.entity = self._entity
|
95
97
|
if self._job_type:
|
96
98
|
pb.run.job_type = self._job_type
|
99
|
+
# Replace tags if specified
|
100
|
+
if self._replace_tags:
|
101
|
+
new_tags = [self._replace_tags.get(tag, tag) for tag in pb.run.tags]
|
102
|
+
pb.run.ClearField("tags")
|
103
|
+
pb.run.tags.extend(new_tags)
|
97
104
|
pb.control.req_resp = True
|
98
105
|
elif record_type in ("output", "output_raw") and self._skip_console:
|
99
106
|
return pb, exit_pb, True
|
@@ -338,6 +345,7 @@ class SyncManager:
|
|
338
345
|
log_path=None,
|
339
346
|
append=None,
|
340
347
|
skip_console=None,
|
348
|
+
replace_tags=None,
|
341
349
|
):
|
342
350
|
self._sync_list = []
|
343
351
|
self._thread = None
|
@@ -353,6 +361,7 @@ class SyncManager:
|
|
353
361
|
self._log_path = log_path
|
354
362
|
self._append = append
|
355
363
|
self._skip_console = skip_console
|
364
|
+
self._replace_tags = replace_tags or {}
|
356
365
|
|
357
366
|
def status(self):
|
358
367
|
pass
|
@@ -376,6 +385,7 @@ class SyncManager:
|
|
376
385
|
log_path=self._log_path,
|
377
386
|
append=self._append,
|
378
387
|
skip_console=self._skip_console,
|
388
|
+
replace_tags=self._replace_tags,
|
379
389
|
)
|
380
390
|
self._thread.start()
|
381
391
|
|
wandb/util.py
CHANGED
@@ -341,6 +341,63 @@ def get_local_path_or_none(path_or_uri: str) -> Optional[str]:
|
|
341
341
|
return None
|
342
342
|
|
343
343
|
|
344
|
+
def check_windows_valid_filename(path: Union[int, str]) -> bool:
|
345
|
+
r"""Verify that the given path does not contain any invalid characters for a Windows filename.
|
346
|
+
|
347
|
+
Windows filenames cannot contain the following characters:
|
348
|
+
< > : " \ / | ? *
|
349
|
+
|
350
|
+
For more details, refer to the official documentation:
|
351
|
+
https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
|
352
|
+
|
353
|
+
Args:
|
354
|
+
path: The file path to check, which can be either an integer or a string.
|
355
|
+
|
356
|
+
Returns:
|
357
|
+
bool: True if the path does not contain any invalid characters, False otherwise.
|
358
|
+
"""
|
359
|
+
return not bool(re.search(r'[<>:"\\?*]', path)) # type: ignore
|
360
|
+
|
361
|
+
|
362
|
+
def make_file_path_upload_safe(path: str) -> str:
|
363
|
+
r"""Makes the provide path safe for file upload.
|
364
|
+
|
365
|
+
The filename is made safe by:
|
366
|
+
1. Removing any leading slashes to prevent writing to absolute paths
|
367
|
+
2. Replacing '.' and '..' with underscores to prevent directory traversal attacks
|
368
|
+
|
369
|
+
Raises:
|
370
|
+
ValueError: If running on Windows and the key contains invalid filename characters
|
371
|
+
(\, :, *, ?, ", <, >, |)
|
372
|
+
"""
|
373
|
+
sys_platform = platform.system()
|
374
|
+
if sys_platform == "Windows" and not check_windows_valid_filename(path):
|
375
|
+
raise ValueError(
|
376
|
+
f"Path {path} is invalid. Please remove invalid filename characters"
|
377
|
+
r' (\, :, *, ?, ", <, >, |)'
|
378
|
+
)
|
379
|
+
|
380
|
+
# On Windows, convert forward slashes to backslashes.
|
381
|
+
# This ensures that the key is a valid filename on Windows.
|
382
|
+
if sys_platform == "Windows":
|
383
|
+
path = str(path).replace("/", os.sep)
|
384
|
+
|
385
|
+
# Avoid writing to absolute paths by striping any leading slashes.
|
386
|
+
# The key has already been validated for windows operating systems in util.check_windows_valid_filename
|
387
|
+
# This ensures the key does not contain invalid characters for windows, such as '\' or ':'.
|
388
|
+
# So we can check only for '/' in the key.
|
389
|
+
path = path.lstrip(os.sep)
|
390
|
+
|
391
|
+
# Avoid directory traversal by replacing dots with underscores.
|
392
|
+
paths = path.split(os.sep)
|
393
|
+
safe_paths = [
|
394
|
+
p.replace(".", "_") if p in (os.curdir, os.pardir) else p for p in paths
|
395
|
+
]
|
396
|
+
|
397
|
+
# Recombine the key into a relative path.
|
398
|
+
return os.sep.join(safe_paths)
|
399
|
+
|
400
|
+
|
344
401
|
def make_tarfile(
|
345
402
|
output_filename: str,
|
346
403
|
source_dir: str,
|
wandb/wandb_run.py
CHANGED