wandb 0.19.0rc1__py3-none-win_amd64.whl → 0.19.1rc1__py3-none-win_amd64.whl
Sign up to get free protection for your applications and to get access to all the features.
- wandb/__init__.py +1 -1
- wandb/__init__.pyi +211 -209
- wandb/apis/attrs.py +15 -4
- wandb/apis/public/api.py +8 -4
- wandb/apis/public/files.py +65 -12
- wandb/apis/public/runs.py +52 -7
- wandb/apis/public/sweeps.py +1 -1
- wandb/bin/gpu_stats.exe +0 -0
- wandb/bin/wandb-core +0 -0
- wandb/cli/cli.py +2 -1
- wandb/env.py +1 -1
- wandb/errors/term.py +60 -1
- wandb/integration/keras/callbacks/tables_builder.py +3 -1
- wandb/integration/kfp/kfp_patch.py +25 -15
- wandb/integration/lightning/fabric/logger.py +3 -1
- wandb/integration/tensorboard/monkeypatch.py +3 -2
- wandb/jupyter.py +4 -5
- wandb/plot/bar.py +5 -6
- wandb/plot/histogram.py +1 -1
- wandb/plot/line_series.py +3 -3
- wandb/plot/pr_curve.py +7 -3
- wandb/plot/scatter.py +2 -1
- wandb/proto/v3/wandb_settings_pb2.py +25 -15
- wandb/proto/v4/wandb_settings_pb2.py +17 -15
- wandb/proto/v5/wandb_settings_pb2.py +17 -15
- wandb/sdk/artifacts/_validators.py +1 -3
- wandb/sdk/artifacts/artifact_manifest_entry.py +1 -1
- wandb/sdk/data_types/helper_types/bounding_boxes_2d.py +12 -2
- wandb/sdk/data_types/helper_types/image_mask.py +8 -2
- wandb/sdk/data_types/histogram.py +3 -3
- wandb/sdk/data_types/image.py +3 -1
- wandb/sdk/interface/interface.py +34 -5
- wandb/sdk/interface/interface_sock.py +2 -2
- wandb/sdk/internal/file_stream.py +4 -1
- wandb/sdk/internal/sender.py +4 -1
- wandb/sdk/internal/settings_static.py +17 -4
- wandb/sdk/launch/utils.py +1 -0
- wandb/sdk/lib/ipython.py +5 -27
- wandb/sdk/lib/printer.py +33 -20
- wandb/sdk/lib/sparkline.py +1 -2
- wandb/sdk/wandb_config.py +2 -2
- wandb/sdk/wandb_init.py +236 -243
- wandb/sdk/wandb_run.py +172 -231
- wandb/sdk/wandb_settings.py +103 -14
- {wandb-0.19.0rc1.dist-info → wandb-0.19.1rc1.dist-info}/METADATA +1 -1
- {wandb-0.19.0rc1.dist-info → wandb-0.19.1rc1.dist-info}/RECORD +49 -49
- {wandb-0.19.0rc1.dist-info → wandb-0.19.1rc1.dist-info}/WHEEL +0 -0
- {wandb-0.19.0rc1.dist-info → wandb-0.19.1rc1.dist-info}/entry_points.txt +0 -0
- {wandb-0.19.0rc1.dist-info → wandb-0.19.1rc1.dist-info}/licenses/LICENSE +0 -0
wandb/sdk/wandb_run.py
CHANGED
@@ -19,7 +19,6 @@ from collections.abc import Mapping
|
|
19
19
|
from dataclasses import dataclass, field
|
20
20
|
from datetime import datetime, timedelta, timezone
|
21
21
|
from enum import IntEnum
|
22
|
-
from functools import reduce
|
23
22
|
from types import TracebackType
|
24
23
|
from typing import TYPE_CHECKING, Any, Callable, Literal, NamedTuple, Sequence, TextIO
|
25
24
|
|
@@ -83,9 +82,7 @@ from .lib import (
|
|
83
82
|
telemetry,
|
84
83
|
)
|
85
84
|
from .lib.exit_hooks import ExitHooks
|
86
|
-
from .lib.gitlib import GitRepo
|
87
85
|
from .lib.mailbox import MailboxError, MailboxHandle, MailboxProbe, MailboxProgress
|
88
|
-
from .lib.proto_util import message_to_dict
|
89
86
|
from .wandb_alerts import AlertLevel
|
90
87
|
from .wandb_settings import Settings
|
91
88
|
from .wandb_setup import _WandbSetup
|
@@ -520,17 +517,7 @@ class Run:
|
|
520
517
|
_telemetry_obj_flushed: bytes
|
521
518
|
|
522
519
|
_teardown_hooks: list[TeardownHook]
|
523
|
-
_tags: tuple[Any, ...] | None
|
524
520
|
|
525
|
-
_entity: str | None
|
526
|
-
_project: str | None
|
527
|
-
_group: str | None
|
528
|
-
_job_type: str | None
|
529
|
-
_name: str | None
|
530
|
-
_notes: str | None
|
531
|
-
_sweep_id: str | None
|
532
|
-
|
533
|
-
_run_obj: RunRecord | None
|
534
521
|
_backend: wandb.sdk.backend.backend.Backend | None
|
535
522
|
_internal_run_interface: wandb.sdk.interface.interface_queue.InterfaceQueue | None
|
536
523
|
_wl: _WandbSetup | None
|
@@ -567,6 +554,8 @@ class Run:
|
|
567
554
|
_is_finished: bool
|
568
555
|
_settings: Settings
|
569
556
|
|
557
|
+
_forked: bool
|
558
|
+
|
570
559
|
_launch_artifacts: dict[str, Any] | None
|
571
560
|
_printer: printer.Printer
|
572
561
|
|
@@ -605,16 +594,15 @@ class Run:
|
|
605
594
|
self._config._set_callback(self._config_callback)
|
606
595
|
self._config._set_artifact_callback(self._config_artifact_callback)
|
607
596
|
self._config._set_settings(self._settings)
|
608
|
-
|
609
|
-
self._internal_run_interface = None
|
597
|
+
|
610
598
|
# todo: perhaps this should be a property that is a noop on a finished run
|
611
599
|
self.summary = wandb_summary.Summary(
|
612
600
|
self._summary_get_current_summary_callback,
|
613
601
|
)
|
614
602
|
self.summary._set_update_callback(self._summary_update_callback)
|
615
|
-
self._step = 0
|
616
|
-
self._torch_history: wandb_torch.TorchHistory | None = None # type: ignore
|
617
603
|
|
604
|
+
self._step = 0
|
605
|
+
self._starting_step = 0
|
618
606
|
# todo: eventually would be nice to make this configurable using self._settings._start_time
|
619
607
|
# need to test (jhr): if you set start time to 2 days ago and run a test for 15 minutes,
|
620
608
|
# does the total time get calculated right (not as 2 days and 15 minutes)?
|
@@ -623,36 +611,27 @@ class Run:
|
|
623
611
|
_datatypes_set_callback(self._datatypes_callback)
|
624
612
|
|
625
613
|
self._printer = printer.new_printer()
|
626
|
-
self._wl = None
|
627
614
|
|
628
|
-
self.
|
629
|
-
|
630
|
-
self.
|
631
|
-
self.
|
632
|
-
self.
|
633
|
-
self._starting_step = 0
|
634
|
-
self._name = None
|
635
|
-
self._notes = None
|
636
|
-
self._tags = None
|
637
|
-
self._remote_url = None
|
638
|
-
self._commit = None
|
639
|
-
self._sweep_id = None
|
615
|
+
self._torch_history: wandb_torch.TorchHistory | None = None # type: ignore
|
616
|
+
|
617
|
+
self._backend = None
|
618
|
+
self._internal_run_interface = None
|
619
|
+
self._wl = None
|
640
620
|
|
641
621
|
self._hooks = None
|
642
622
|
self._teardown_hooks = []
|
623
|
+
|
624
|
+
self._output_writer = None
|
643
625
|
self._out_redir = None
|
644
626
|
self._err_redir = None
|
645
627
|
self._stdout_slave_fd = None
|
646
628
|
self._stderr_slave_fd = None
|
629
|
+
|
647
630
|
self._exit_code = None
|
648
631
|
self._exit_result = None
|
649
632
|
|
650
|
-
self._output_writer = None
|
651
633
|
self._used_artifact_slots: dict[str, str] = {}
|
652
634
|
|
653
|
-
# Returned from backend request_run(), set from wandb_init?
|
654
|
-
self._run_obj = None
|
655
|
-
|
656
635
|
# Created when the run "starts".
|
657
636
|
self._run_status_checker = None
|
658
637
|
|
@@ -670,9 +649,6 @@ class Run:
|
|
670
649
|
|
671
650
|
self._atexit_cleanup_called = False
|
672
651
|
|
673
|
-
# Pull info from settings
|
674
|
-
self._init_from_settings(self._settings)
|
675
|
-
|
676
652
|
# Initial scope setup for sentry.
|
677
653
|
# This might get updated when the actual run comes back.
|
678
654
|
wandb._sentry.configure_scope(
|
@@ -737,7 +713,7 @@ class Run:
|
|
737
713
|
self._is_finished = False
|
738
714
|
|
739
715
|
self._attach_pid = os.getpid()
|
740
|
-
|
716
|
+
self._forked = False
|
741
717
|
# for now, use runid as attach id, this could/should be versioned in the future
|
742
718
|
if not self._settings.x_disable_service:
|
743
719
|
self._attach_id = self._settings.run_id
|
@@ -813,71 +789,6 @@ class Run:
|
|
813
789
|
raise Exception(f"Attribute {attr} is not supported on Run object.")
|
814
790
|
super().__setattr__(attr, value)
|
815
791
|
|
816
|
-
def _update_settings(self, settings: Settings) -> None:
|
817
|
-
self._settings = settings
|
818
|
-
self._init_from_settings(settings)
|
819
|
-
|
820
|
-
def _init_from_settings(self, settings: Settings) -> None:
|
821
|
-
if settings.entity is not None:
|
822
|
-
self._entity = settings.entity
|
823
|
-
if settings.project is not None:
|
824
|
-
self._project = settings.project
|
825
|
-
if settings.run_group is not None:
|
826
|
-
self._group = settings.run_group
|
827
|
-
if settings.run_job_type is not None:
|
828
|
-
self._job_type = settings.run_job_type
|
829
|
-
if settings.run_name is not None:
|
830
|
-
self._name = settings.run_name
|
831
|
-
if settings.run_notes is not None:
|
832
|
-
self._notes = settings.run_notes
|
833
|
-
if settings.run_tags is not None:
|
834
|
-
self._tags = settings.run_tags
|
835
|
-
if settings.sweep_id is not None:
|
836
|
-
self._sweep_id = settings.sweep_id
|
837
|
-
|
838
|
-
def _make_proto_run(self, run: RunRecord) -> None:
|
839
|
-
"""Populate protocol buffer RunData for interface/interface."""
|
840
|
-
if self._entity is not None:
|
841
|
-
run.entity = self._entity
|
842
|
-
if self._project is not None:
|
843
|
-
run.project = self._project
|
844
|
-
if self._group is not None:
|
845
|
-
run.run_group = self._group
|
846
|
-
if self._job_type is not None:
|
847
|
-
run.job_type = self._job_type
|
848
|
-
if self._run_id is not None:
|
849
|
-
run.run_id = self._run_id
|
850
|
-
if self._name is not None:
|
851
|
-
run.display_name = self._name
|
852
|
-
if self._notes is not None:
|
853
|
-
run.notes = self._notes
|
854
|
-
if self._tags is not None:
|
855
|
-
for tag in self._tags:
|
856
|
-
run.tags.append(tag)
|
857
|
-
if self._start_time is not None:
|
858
|
-
run.start_time.FromMicroseconds(int(self._start_time * 1e6))
|
859
|
-
if self._remote_url is not None:
|
860
|
-
run.git.remote_url = self._remote_url
|
861
|
-
if self._commit is not None:
|
862
|
-
run.git.commit = self._commit
|
863
|
-
if self._sweep_id is not None:
|
864
|
-
run.sweep_id = self._sweep_id
|
865
|
-
# Note: run.config is set in interface/interface:_make_run()
|
866
|
-
|
867
|
-
def _populate_git_info(self) -> None:
|
868
|
-
# Use user provided git info if available otherwise resolve it from the environment
|
869
|
-
try:
|
870
|
-
repo = GitRepo(
|
871
|
-
root=self._settings.git_root,
|
872
|
-
remote=self._settings.git_remote,
|
873
|
-
remote_url=self._settings.git_remote_url,
|
874
|
-
commit=self._settings.git_commit,
|
875
|
-
lazy=False,
|
876
|
-
)
|
877
|
-
self._remote_url, self._commit = repo.remote_url, repo.last_commit
|
878
|
-
except Exception:
|
879
|
-
wandb.termwarn("Cannot find valid git repo associated with this directory.")
|
880
|
-
|
881
792
|
def __deepcopy__(self, memo: dict[int, Any]) -> Run:
|
882
793
|
return self
|
883
794
|
|
@@ -948,18 +859,16 @@ class Run:
|
|
948
859
|
Display names are not guaranteed to be unique and may be descriptive.
|
949
860
|
By default, they are randomly generated.
|
950
861
|
"""
|
951
|
-
if self.
|
952
|
-
return self.
|
953
|
-
|
954
|
-
return None
|
955
|
-
return self._run_obj.display_name
|
862
|
+
if self._settings.run_name:
|
863
|
+
return self._settings.run_name
|
864
|
+
return None
|
956
865
|
|
957
866
|
@name.setter
|
958
867
|
@_run_decorator._noop_on_finish()
|
959
868
|
def name(self, name: str) -> None:
|
960
869
|
with telemetry.context(run=self) as tel:
|
961
870
|
tel.feature.set_run_name = True
|
962
|
-
self.
|
871
|
+
self._settings.run_name = name
|
963
872
|
if self._backend and self._backend.interface:
|
964
873
|
self._backend.interface.publish_run(self)
|
965
874
|
|
@@ -971,16 +880,12 @@ class Run:
|
|
971
880
|
Notes can be a multiline string and can also use markdown and latex equations
|
972
881
|
inside `$$`, like `$x + 3$`.
|
973
882
|
"""
|
974
|
-
|
975
|
-
return self._notes
|
976
|
-
if not self._run_obj:
|
977
|
-
return None
|
978
|
-
return self._run_obj.notes
|
883
|
+
return self._settings.run_notes
|
979
884
|
|
980
885
|
@notes.setter
|
981
886
|
@_run_decorator._noop_on_finish()
|
982
887
|
def notes(self, notes: str) -> None:
|
983
|
-
self.
|
888
|
+
self._settings.run_notes = notes
|
984
889
|
if self._backend and self._backend.interface:
|
985
890
|
self._backend.interface.publish_run(self)
|
986
891
|
|
@@ -988,18 +893,14 @@ class Run:
|
|
988
893
|
@_run_decorator._attach
|
989
894
|
def tags(self) -> tuple | None:
|
990
895
|
"""Tags associated with the run, if there are any."""
|
991
|
-
|
992
|
-
return self._tags
|
993
|
-
if self._run_obj:
|
994
|
-
return tuple(self._run_obj.tags)
|
995
|
-
return None
|
896
|
+
return self._settings.run_tags or ()
|
996
897
|
|
997
898
|
@tags.setter
|
998
899
|
@_run_decorator._noop_on_finish()
|
999
900
|
def tags(self, tags: Sequence) -> None:
|
1000
901
|
with telemetry.context(run=self) as tel:
|
1001
902
|
tel.feature.set_run_tags = True
|
1002
|
-
self.
|
903
|
+
self._settings.run_tags = tuple(tags)
|
1003
904
|
if self._backend and self._backend.interface:
|
1004
905
|
self._backend.interface.publish_run(self)
|
1005
906
|
|
@@ -1008,22 +909,25 @@ class Run:
|
|
1008
909
|
def id(self) -> str:
|
1009
910
|
"""Identifier for this run."""
|
1010
911
|
if TYPE_CHECKING:
|
1011
|
-
assert self.
|
1012
|
-
return self.
|
912
|
+
assert self._settings.run_id is not None
|
913
|
+
return self._settings.run_id
|
1013
914
|
|
1014
915
|
@property
|
1015
916
|
@_run_decorator._attach
|
1016
917
|
def sweep_id(self) -> str | None:
|
1017
918
|
"""ID of the sweep associated with the run, if there is one."""
|
1018
|
-
|
1019
|
-
return None
|
1020
|
-
return self._run_obj.sweep_id or None
|
919
|
+
return self._settings.sweep_id
|
1021
920
|
|
1022
921
|
def _get_path(self) -> str:
|
1023
|
-
|
1024
|
-
e
|
1025
|
-
|
1026
|
-
|
922
|
+
return "/".join(
|
923
|
+
e
|
924
|
+
for e in [
|
925
|
+
self._settings.entity,
|
926
|
+
self._settings.project,
|
927
|
+
self._settings.run_id,
|
928
|
+
]
|
929
|
+
if e is not None
|
930
|
+
)
|
1027
931
|
|
1028
932
|
@property
|
1029
933
|
@_run_decorator._attach
|
@@ -1035,33 +939,23 @@ class Run:
|
|
1035
939
|
"""
|
1036
940
|
return self._get_path()
|
1037
941
|
|
1038
|
-
def _get_start_time(self) -> float:
|
1039
|
-
return (
|
1040
|
-
self._start_time
|
1041
|
-
if not self._run_obj
|
1042
|
-
else (self._run_obj.start_time.ToMicroseconds() / 1e6)
|
1043
|
-
)
|
1044
|
-
|
1045
942
|
@property
|
1046
943
|
@_run_decorator._attach
|
1047
944
|
def start_time(self) -> float:
|
1048
945
|
"""Unix timestamp (in seconds) of when the run started."""
|
1049
|
-
return self.
|
1050
|
-
|
1051
|
-
def _get_starting_step(self) -> int:
|
1052
|
-
return self._starting_step if not self._run_obj else self._run_obj.starting_step
|
946
|
+
return self._start_time
|
1053
947
|
|
1054
948
|
@property
|
1055
949
|
@_run_decorator._attach
|
1056
950
|
def starting_step(self) -> int:
|
1057
951
|
"""The first step of the run."""
|
1058
|
-
return self.
|
952
|
+
return self._starting_step
|
1059
953
|
|
1060
954
|
@property
|
1061
955
|
@_run_decorator._attach
|
1062
956
|
def resumed(self) -> bool:
|
1063
957
|
"""True if the run was resumed, False otherwise."""
|
1064
|
-
return self.
|
958
|
+
return self._settings.resumed
|
1065
959
|
|
1066
960
|
@property
|
1067
961
|
@_run_decorator._attach
|
@@ -1072,10 +966,6 @@ class Run:
|
|
1072
966
|
"""
|
1073
967
|
return self._step
|
1074
968
|
|
1075
|
-
def project_name(self) -> str:
|
1076
|
-
# TODO: deprecate this in favor of project
|
1077
|
-
return self._run_obj.project if self._run_obj else ""
|
1078
|
-
|
1079
969
|
@property
|
1080
970
|
@_run_decorator._attach
|
1081
971
|
def mode(self) -> str:
|
@@ -1100,9 +990,6 @@ class Run:
|
|
1100
990
|
def disabled(self) -> bool:
|
1101
991
|
return self._settings._noop
|
1102
992
|
|
1103
|
-
def _get_group(self) -> str:
|
1104
|
-
return self._run_obj.run_group if self._run_obj else ""
|
1105
|
-
|
1106
993
|
@property
|
1107
994
|
@_run_decorator._attach
|
1108
995
|
def group(self) -> str:
|
@@ -1115,12 +1002,16 @@ class Run:
|
|
1115
1002
|
If you are doing cross-validation you should give all the cross-validation
|
1116
1003
|
folds the same group.
|
1117
1004
|
"""
|
1118
|
-
return self.
|
1005
|
+
return self._settings.run_group or ""
|
1119
1006
|
|
1120
1007
|
@property
|
1121
1008
|
@_run_decorator._attach
|
1122
1009
|
def job_type(self) -> str:
|
1123
|
-
return self.
|
1010
|
+
return self._settings.run_job_type or ""
|
1011
|
+
|
1012
|
+
def project_name(self) -> str:
|
1013
|
+
# TODO: deprecate this in favor of project
|
1014
|
+
return self._settings.project or ""
|
1124
1015
|
|
1125
1016
|
@property
|
1126
1017
|
@_run_decorator._attach
|
@@ -1167,7 +1058,9 @@ class Run:
|
|
1167
1058
|
run.log_code(
|
1168
1059
|
"../",
|
1169
1060
|
include_fn=lambda path: path.endswith(".py") or path.endswith(".ipynb"),
|
1170
|
-
exclude_fn=lambda path, root: os.path.relpath(path, root).startswith(
|
1061
|
+
exclude_fn=lambda path, root: os.path.relpath(path, root).startswith(
|
1062
|
+
"cache/"
|
1063
|
+
),
|
1171
1064
|
)
|
1172
1065
|
```
|
1173
1066
|
|
@@ -1184,9 +1077,11 @@ class Run:
|
|
1184
1077
|
notebook_name = self.settings.x_jupyter_name
|
1185
1078
|
else:
|
1186
1079
|
notebook_name = self.settings.x_jupyter_path
|
1187
|
-
name_string = f"{self.
|
1080
|
+
name_string = f"{self._settings.project}-{notebook_name}"
|
1188
1081
|
else:
|
1189
|
-
name_string =
|
1082
|
+
name_string = (
|
1083
|
+
f"{self._settings.project}-{self._settings.program_relpath}"
|
1084
|
+
)
|
1190
1085
|
name = wandb.util.make_artifact_name_safe(f"source-{name_string}")
|
1191
1086
|
art = wandb.Artifact(name, "code")
|
1192
1087
|
files_added = False
|
@@ -1211,16 +1106,6 @@ class Run:
|
|
1211
1106
|
|
1212
1107
|
return self._log_artifact(art)
|
1213
1108
|
|
1214
|
-
def get_url(self) -> str | None:
|
1215
|
-
"""Return the url for the W&B run, if there is one.
|
1216
|
-
|
1217
|
-
Offline runs will not have a url.
|
1218
|
-
"""
|
1219
|
-
if self._settings._offline:
|
1220
|
-
wandb.termwarn("URL not available in offline run")
|
1221
|
-
return None
|
1222
|
-
return self._settings.run_url
|
1223
|
-
|
1224
1109
|
def get_project_url(self) -> str | None:
|
1225
1110
|
"""Return the url for the W&B project associated with the run, if there is one.
|
1226
1111
|
|
@@ -1238,6 +1123,16 @@ class Run:
|
|
1238
1123
|
return None
|
1239
1124
|
return self._settings.sweep_url
|
1240
1125
|
|
1126
|
+
def get_url(self) -> str | None:
|
1127
|
+
"""Return the url for the W&B run, if there is one.
|
1128
|
+
|
1129
|
+
Offline runs will not have a url.
|
1130
|
+
"""
|
1131
|
+
if self._settings._offline:
|
1132
|
+
wandb.termwarn("URL not available in offline run")
|
1133
|
+
return None
|
1134
|
+
return self._settings.run_url
|
1135
|
+
|
1241
1136
|
@property
|
1242
1137
|
@_run_decorator._attach
|
1243
1138
|
def url(self) -> str | None:
|
@@ -1251,7 +1146,7 @@ class Run:
|
|
1251
1146
|
|
1252
1147
|
Entity can be a username or the name of a team or organization.
|
1253
1148
|
"""
|
1254
|
-
return self.
|
1149
|
+
return self._settings.entity or ""
|
1255
1150
|
|
1256
1151
|
def _label_internal(
|
1257
1152
|
self,
|
@@ -1342,10 +1237,19 @@ class Run:
|
|
1342
1237
|
@_run_decorator._attach
|
1343
1238
|
def display(self, height: int = 420, hidden: bool = False) -> bool:
|
1344
1239
|
"""Display this run in jupyter."""
|
1345
|
-
if self._settings.
|
1346
|
-
|
1240
|
+
if self._settings.silent:
|
1241
|
+
return False
|
1242
|
+
|
1243
|
+
if not ipython.in_jupyter():
|
1244
|
+
return False
|
1245
|
+
|
1246
|
+
try:
|
1247
|
+
from IPython import display
|
1248
|
+
|
1249
|
+
display.display(display.HTML(self.to_html(height, hidden)))
|
1347
1250
|
return True
|
1348
|
-
|
1251
|
+
|
1252
|
+
except ImportError:
|
1349
1253
|
wandb.termwarn(".display() only works in jupyter environments")
|
1350
1254
|
return False
|
1351
1255
|
|
@@ -1548,13 +1452,13 @@ class Run:
|
|
1548
1452
|
def _set_teardown_hooks(self, hooks: list[TeardownHook]) -> None:
|
1549
1453
|
self._teardown_hooks = hooks
|
1550
1454
|
|
1551
|
-
def _set_run_obj(self, run_obj: RunRecord) -> None:
|
1552
|
-
|
1553
|
-
|
1554
|
-
|
1455
|
+
def _set_run_obj(self, run_obj: RunRecord) -> None: # noqa: C901
|
1456
|
+
if run_obj.starting_step:
|
1457
|
+
self._starting_step = run_obj.starting_step
|
1458
|
+
self._step = run_obj.starting_step
|
1555
1459
|
|
1556
|
-
|
1557
|
-
|
1460
|
+
if run_obj.start_time:
|
1461
|
+
self._start_time = run_obj.start_time.ToMicroseconds() / 1e6
|
1558
1462
|
|
1559
1463
|
# Grab the config from resuming
|
1560
1464
|
if run_obj.config:
|
@@ -1571,40 +1475,61 @@ class Run:
|
|
1571
1475
|
summary_dict[orig.key] = json.loads(orig.value_json)
|
1572
1476
|
if summary_dict:
|
1573
1477
|
self.summary.update(summary_dict)
|
1574
|
-
self._step = self._get_starting_step()
|
1575
1478
|
|
1576
1479
|
# update settings from run_obj
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
|
1583
|
-
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1597
|
-
|
1598
|
-
|
1599
|
-
if
|
1600
|
-
|
1601
|
-
|
1480
|
+
if run_obj.run_id:
|
1481
|
+
self._settings.run_id = run_obj.run_id
|
1482
|
+
if run_obj.entity:
|
1483
|
+
self._settings.entity = run_obj.entity
|
1484
|
+
if run_obj.project:
|
1485
|
+
self._settings.project = run_obj.project
|
1486
|
+
if run_obj.run_group:
|
1487
|
+
self._settings.run_group = run_obj.run_group
|
1488
|
+
if run_obj.job_type:
|
1489
|
+
self._settings.run_job_type = run_obj.job_type
|
1490
|
+
if run_obj.display_name:
|
1491
|
+
self._settings.run_name = run_obj.display_name
|
1492
|
+
if run_obj.notes:
|
1493
|
+
self._settings.run_notes = run_obj.notes
|
1494
|
+
if run_obj.tags:
|
1495
|
+
self._settings.run_tags = run_obj.tags
|
1496
|
+
if run_obj.sweep_id:
|
1497
|
+
self._settings.sweep_id = run_obj.sweep_id
|
1498
|
+
if run_obj.host:
|
1499
|
+
self._settings.host = run_obj.host
|
1500
|
+
if run_obj.resumed:
|
1501
|
+
self._settings.resumed = run_obj.resumed
|
1502
|
+
if run_obj.git:
|
1503
|
+
if run_obj.git.remote_url:
|
1504
|
+
self._settings.git_remote_url = run_obj.git.remote_url
|
1505
|
+
if run_obj.git.commit:
|
1506
|
+
self._settings.git_commit = run_obj.git.commit
|
1507
|
+
|
1508
|
+
if run_obj.forked:
|
1509
|
+
self._forked = run_obj.forked
|
1602
1510
|
|
1603
1511
|
wandb._sentry.configure_scope(
|
1604
1512
|
process_context="user",
|
1605
1513
|
tags=dict(self._settings),
|
1606
1514
|
)
|
1607
1515
|
|
1516
|
+
def _populate_git_info(self) -> None:
|
1517
|
+
from .lib.gitlib import GitRepo
|
1518
|
+
|
1519
|
+
# Use user provided git info if available otherwise resolve it from the environment
|
1520
|
+
try:
|
1521
|
+
repo = GitRepo(
|
1522
|
+
root=self._settings.git_root,
|
1523
|
+
remote=self._settings.git_remote,
|
1524
|
+
remote_url=self._settings.git_remote_url,
|
1525
|
+
commit=self._settings.git_commit,
|
1526
|
+
lazy=False,
|
1527
|
+
)
|
1528
|
+
self._settings.git_remote_url = repo.remote_url
|
1529
|
+
self._settings.git_commit = repo.last_commit
|
1530
|
+
except Exception:
|
1531
|
+
wandb.termwarn("Cannot find valid git repo associated with this directory.")
|
1532
|
+
|
1608
1533
|
def _add_singleton(
|
1609
1534
|
self, data_type: str, key: str, value: dict[int | str, str]
|
1610
1535
|
) -> None:
|
@@ -1715,12 +1640,14 @@ class Run:
|
|
1715
1640
|
the following results in two sections named "train" and "validate":
|
1716
1641
|
|
1717
1642
|
```
|
1718
|
-
run.log(
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1643
|
+
run.log(
|
1644
|
+
{
|
1645
|
+
"train/accuracy": 0.9,
|
1646
|
+
"train/loss": 30,
|
1647
|
+
"validate/accuracy": 0.8,
|
1648
|
+
"validate/loss": 20,
|
1649
|
+
}
|
1650
|
+
)
|
1724
1651
|
```
|
1725
1652
|
|
1726
1653
|
Only one level of nesting is supported; `run.log({"a/b/c": 1})`
|
@@ -1846,7 +1773,9 @@ class Run:
|
|
1846
1773
|
run = wandb.init()
|
1847
1774
|
examples = []
|
1848
1775
|
for i in range(3):
|
1849
|
-
pixels = np.random.randint(
|
1776
|
+
pixels = np.random.randint(
|
1777
|
+
low=0, high=256, size=(100, 100, 3), dtype=np.uint8
|
1778
|
+
)
|
1850
1779
|
pil_image = PILImage.fromarray(pixels, mode="RGB")
|
1851
1780
|
image = wandb.Image(pil_image, caption=f"random field {i}")
|
1852
1781
|
examples.append(image)
|
@@ -1861,7 +1790,9 @@ class Run:
|
|
1861
1790
|
|
1862
1791
|
run = wandb.init()
|
1863
1792
|
# axes are (time, channel, height, width)
|
1864
|
-
frames = np.random.randint(
|
1793
|
+
frames = np.random.randint(
|
1794
|
+
low=0, high=256, size=(10, 3, 100, 100), dtype=np.uint8
|
1795
|
+
)
|
1865
1796
|
run.log({"video": wandb.Video(frames, fps=4)})
|
1866
1797
|
```
|
1867
1798
|
|
@@ -2203,8 +2134,8 @@ class Run:
|
|
2203
2134
|
#
|
2204
2135
|
# TODO: Why not do this in _atexit_cleanup()?
|
2205
2136
|
service = self._wl and self._wl.service
|
2206
|
-
if service and self.
|
2207
|
-
service.inform_finish(run_id=self.
|
2137
|
+
if service and self._settings.run_id:
|
2138
|
+
service.inform_finish(run_id=self._settings.run_id)
|
2208
2139
|
|
2209
2140
|
finally:
|
2210
2141
|
module.unset_globals()
|
@@ -2517,12 +2448,12 @@ class Run:
|
|
2517
2448
|
|
2518
2449
|
import_telemetry_set = telemetry.list_telemetry_imports()
|
2519
2450
|
import_hook_fn = functools.partial(_telemetry_import_hook, self)
|
2520
|
-
if not self.
|
2451
|
+
if not self._settings.run_id:
|
2521
2452
|
return
|
2522
2453
|
for module_name in import_telemetry_set:
|
2523
2454
|
register_post_import_hook(
|
2524
2455
|
import_hook_fn,
|
2525
|
-
self.
|
2456
|
+
self._settings.run_id,
|
2526
2457
|
module_name,
|
2527
2458
|
)
|
2528
2459
|
|
@@ -2534,7 +2465,10 @@ class Run:
|
|
2534
2465
|
self._telemetry_obj_active = True
|
2535
2466
|
self._telemetry_flush()
|
2536
2467
|
|
2537
|
-
|
2468
|
+
try:
|
2469
|
+
self._detect_and_apply_job_inputs()
|
2470
|
+
except Exception as e:
|
2471
|
+
logger.error("Problem applying launch job inputs", exc_info=e)
|
2538
2472
|
|
2539
2473
|
# object is about to be returned to the user, don't let them modify it
|
2540
2474
|
self._freeze()
|
@@ -2715,8 +2649,8 @@ class Run:
|
|
2715
2649
|
if self._run_status_checker:
|
2716
2650
|
self._run_status_checker.join()
|
2717
2651
|
|
2718
|
-
if self.
|
2719
|
-
self._unregister_telemetry_import_hooks(self.
|
2652
|
+
if self._settings.run_id:
|
2653
|
+
self._unregister_telemetry_import_hooks(self._settings.run_id)
|
2720
2654
|
|
2721
2655
|
@staticmethod
|
2722
2656
|
def _unregister_telemetry_import_hooks(run_id: str) -> None:
|
@@ -3051,10 +2985,14 @@ class Run:
|
|
3051
2985
|
"""
|
3052
2986
|
if self._settings._offline:
|
3053
2987
|
raise TypeError("Cannot use artifact when in offline mode.")
|
3054
|
-
|
3055
|
-
|
3056
|
-
|
3057
|
-
|
2988
|
+
|
2989
|
+
api = internal.Api(
|
2990
|
+
default_settings={
|
2991
|
+
"entity": self._settings.entity,
|
2992
|
+
"project": self._settings.project,
|
2993
|
+
}
|
2994
|
+
)
|
2995
|
+
api.set_current_run_id(self._settings.run_id)
|
3058
2996
|
|
3059
2997
|
if isinstance(artifact_or_name, str):
|
3060
2998
|
if self._launch_artifact_mapping:
|
@@ -3085,8 +3023,8 @@ class Run:
|
|
3085
3023
|
self._used_artifact_slots[use_as] = artifact.id
|
3086
3024
|
api.use_artifact(
|
3087
3025
|
artifact.id,
|
3088
|
-
entity_name=
|
3089
|
-
project_name=
|
3026
|
+
entity_name=self._settings.entity,
|
3027
|
+
project_name=self._settings.project,
|
3090
3028
|
use_as=use_as or artifact_or_name,
|
3091
3029
|
)
|
3092
3030
|
else:
|
@@ -3211,12 +3149,12 @@ class Run:
|
|
3211
3149
|
Returns:
|
3212
3150
|
An `Artifact` object.
|
3213
3151
|
"""
|
3214
|
-
if self.
|
3152
|
+
if self._settings.run_group is None and distributed_id is None:
|
3215
3153
|
raise TypeError(
|
3216
3154
|
"Cannot upsert artifact unless run is in a group or distributed_id is provided"
|
3217
3155
|
)
|
3218
3156
|
if distributed_id is None:
|
3219
|
-
distributed_id = self.
|
3157
|
+
distributed_id = self._settings.run_group or ""
|
3220
3158
|
return self._log_artifact(
|
3221
3159
|
artifact_or_path,
|
3222
3160
|
name=name,
|
@@ -3264,12 +3202,12 @@ class Run:
|
|
3264
3202
|
Returns:
|
3265
3203
|
An `Artifact` object.
|
3266
3204
|
"""
|
3267
|
-
if self.
|
3205
|
+
if self._settings.run_group is None and distributed_id is None:
|
3268
3206
|
raise TypeError(
|
3269
3207
|
"Cannot finish artifact unless run is in a group or distributed_id is provided"
|
3270
3208
|
)
|
3271
3209
|
if distributed_id is None:
|
3272
|
-
distributed_id = self.
|
3210
|
+
distributed_id = self._settings.run_group or ""
|
3273
3211
|
|
3274
3212
|
return self._log_artifact(
|
3275
3213
|
artifact_or_path,
|
@@ -3349,10 +3287,10 @@ class Run:
|
|
3349
3287
|
return artifact
|
3350
3288
|
|
3351
3289
|
def _public_api(self, overrides: dict[str, str] | None = None) -> PublicApi:
|
3352
|
-
overrides = {"run": self.
|
3353
|
-
if not
|
3354
|
-
overrides["entity"] = self.
|
3355
|
-
overrides["project"] = self.
|
3290
|
+
overrides = {"run": self._settings.run_id} # type: ignore
|
3291
|
+
if not self._settings._offline:
|
3292
|
+
overrides["entity"] = self._settings.entity or ""
|
3293
|
+
overrides["project"] = self._settings.project or ""
|
3356
3294
|
return public.Api(overrides)
|
3357
3295
|
|
3358
3296
|
# TODO(jhr): annotate this
|
@@ -3395,7 +3333,10 @@ class Run:
|
|
3395
3333
|
aliases: list[str] | None = None,
|
3396
3334
|
) -> tuple[Artifact, list[str]]:
|
3397
3335
|
if isinstance(artifact_or_path, (str, os.PathLike)):
|
3398
|
-
name =
|
3336
|
+
name = (
|
3337
|
+
name
|
3338
|
+
or f"run-{self._settings.run_id}-{os.path.basename(artifact_or_path)}"
|
3339
|
+
)
|
3399
3340
|
artifact = wandb.Artifact(name, type or "unspecified")
|
3400
3341
|
if os.path.isfile(artifact_or_path):
|
3401
3342
|
artifact.add_file(str(artifact_or_path))
|