Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow for logging to Studio when not inside a repo #646

Merged
merged 46 commits into from
Feb 15, 2024
Merged

Allow for logging to Studio when not inside a repo #646

merged 46 commits into from
Feb 15, 2024

Conversation

dberenbaum
Copy link
Contributor

@dberenbaum dberenbaum commented Jul 31, 2023

Partially addresses #638. This does not solve how to copy metrics back to the repo or make the experience completely smooth everywhere, but the goal for this PR is to achieve parity with other trackers where a token and project are all that's needed.

This allows for posting to Studio if the following environment variables are set:

  • DVC_STUDIO_TOKEN
  • DVC_STUDIO_REPO_URL
  • DVC_EXP_BASELINE_REV
  • DVC_EXP_NAME

TODO:

@codecov-commenter
Copy link

codecov-commenter commented Jul 31, 2023

Codecov Report

Attention: 2 lines in your changes are missing coverage. Please review.

Comparison is base (aba8807) 95.55% compared to head (5003104) 95.51%.

Files Patch % Lines
src/dvclive/studio.py 87.50% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #646      +/-   ##
==========================================
- Coverage   95.55%   95.51%   -0.05%     
==========================================
  Files          55       55              
  Lines        3532     3542      +10     
  Branches      314      317       +3     
==========================================
+ Hits         3375     3383       +8     
- Misses        110      111       +1     
- Partials       47       48       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@dberenbaum
Copy link
Contributor Author

Need to look into windows tests not passing. Somehow dvclive expects to pass posix paths even on windows, but not sure where that conversion happens.

@daavoo
Copy link
Contributor

daavoo commented Aug 1, 2023

Somehow dvclive expects to pass posix paths even on windows, but not sure where that conversion happens.

This is because Studio expected the paths in POSIX format.
There was a bug where live metrics sent from Windows were not being shown in Studio.

It was added here:

def _rel_path(path, dvc_root_path):
absolute_path = Path(path).resolve()
return str(absolute_path.relative_to(dvc_root_path).as_posix())

@dberenbaum
Copy link
Contributor Author

Need to look into windows tests not passing. Somehow dvclive expects to pass posix paths even on windows, but not sure where that conversion happens.

The cause was because the conversion only happens within a repo, which brought up that we need to decide where paths should be relative to if there is no repo root. I went with cwd for now.

@daavoo
Copy link
Contributor

daavoo commented Aug 4, 2023

Need to look into windows tests not passing. Somehow dvclive expects to pass posix paths even on windows, but not sure where that conversion happens.

The cause was because the conversion only happens within a repo, which brought up that we need to decide where paths should be relative to if there is no repo root. I went with cwd for now.

I see. Probably no need to do with cwd (not even sure if it might be potentially problematic)

The posix and relpath operations should be decoupled but I mixed them in a single function (they were actually 2 separate bugfixes one for windows other for monorepo in Studio).
I assume that in norepo scenario we don't really need relpath operation because the default values are already as expected but we do need posix

src/dvclive/dvc.py Outdated Show resolved Hide resolved
@dberenbaum
Copy link
Contributor Author

  • Make DVC_EXP_BASELINE_REV and/or DVC_EXP_NAME optional

This depends on:

@dberenbaum
Copy link
Contributor Author

I see. Probably no need to do with cwd (not even sure if it might be potentially problematic)

Updated to remove that.

@dberenbaum
Copy link
Contributor Author

@shcheklein
Copy link
Member

@dberenbaum do you have a sense on what is the mid-term plan for this? If we are not attached to Git - what is the benefit of using the DVC ecosystem? (sorry, I know it's a non-trivial question, definitely not a blocker of this PR or effort). Data management? something else?

Is there a way to clone the repo in those system under the hood / seamlessly for end-users?

Do we want to cover scenarios like when people don't use Git at all - they don't have a repo at all even? (we pretty much then become two products - Git based and separately MlFlow/W&B, right?

@dberenbaum
Copy link
Contributor Author

Do we want to cover scenarios like when people don't use Git at all - they don't have a repo at all even? (we pretty much then become two products - Git based and separately MlFlow/W&B, right?

It's not in my plans at this point. This is mainly to cover scenarios where you have a project in a repo but want to run an experiment in an environment where it's painful/impossible to have a full copy of the Git repo. In my experience, it's not uncommon to have a notebook that gets checked into Git but that runs independently in databricks, colab, etc. It's also helpful for the SageMaker scenario where you can kick off a job on a remote machine, but that machine only has access to a single .py file, so this way you can at least see metrics populated in Studio.

@shcheklein
Copy link
Member

Okay, I see. What is the plan of connecting it back? Those experiments will stay "studio"-only, is it correct?

And why can't we try to do a git clone? any specific obstacles for that?

@dberenbaum dberenbaum mentioned this pull request Aug 5, 2023
@daavoo daavoo added the A: studio Area: Studio integration label Aug 14, 2023
@shcheklein
Copy link
Member

@mattseddon i think you should be aware by this change as well (baseline is optional)

@dberenbaum
Copy link
Contributor Author

dberenbaum commented Feb 7, 2024

@mattseddon i think you should be aware by this change as well (baseline is optional)

In the end, baseline is still required to be sent to dvc-studio-client in this PR and defaults to "0" * 40. It seems this is an accepted convention for a null ref (see https://stackoverflow.com/questions/18977462/git-sha1-0000000000000000000000000000000000000000-all-zeroes-is-this-normal).

src/dvclive/live.py Outdated Show resolved Hide resolved
@@ -131,9 +132,14 @@ def _update_entries(old, new, key):
def get_exp_name(name, scm, baseline_rev) -> str:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated get_exp_name to always be able to return an experiment name instead of only when inside a repo.

Comment on lines +161 to +167
scm = self._dvc_repo.scm if self._dvc_repo else None
if isinstance(scm, NoSCM):
scm = None
if scm:
self._baseline_rev = scm.get_rev()
self._exp_name = get_exp_name(self._exp_name, scm, self._baseline_rev)
logger.info(f"Logging to experiment '{self._exp_name}'")
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Once we have tried to find a repo, we can generate all exp info we need instead of scattering it throughout the code

src/dvclive/studio.py Outdated Show resolved Hide resolved
src/dvclive/utils.py Outdated Show resolved Hide resolved
Comment on lines +32 to +33
assert live._baseline_rev is not None
assert live._exp_name is not None
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These now get set always

@@ -60,31 +57,6 @@ def test_exp_save_skip_on_env_vars(tmp_dir, monkeypatch, mocker):
assert live._inside_dvc_pipeline


def test_exp_save_run_on_dvc_repro(tmp_dir, mocker):
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test was actually outdated and not working. It conflicts with test_dvc_repro below, so I consolidated the meaningful assertions into that test.

monkeypatch.setenv(DVC_EXP_BASELINE_REV, "foo")
monkeypatch.setenv(DVC_EXP_NAME, "bar")
monkeypatch.setenv(DVC_ROOT, tmp_dir)

mocker.patch("dvclive.live.get_dvc_repo", return_value=None)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed

@@ -166,7 +138,7 @@ def test_errors_on_git_add_are_catched(tmp_dir, mocked_dvc_repo, monkeypatch):
mocked_dvc_repo.scm.untracked_files.return_value = ["dvclive/metrics.json"]
mocked_dvc_repo.scm.add.side_effect = DvcException("foo")

with Live(dvcyaml=False) as live:
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed

Comment on lines +182 to +184
assert live._baseline_rev is not None
assert live._exp_name is not None
assert not live._studio_events_to_skip
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consolidated from the deleted test_exp_save_run_on_dvc_repro above. On repro, everything will still work except actually saving an exp ref.

def test_post_to_studio_requires_exp(tmp_dir, mocked_dvc_repo, mocked_studio_post):
assert Live(save_dvc_exp=False)._studio_events_to_skip == {"start", "data", "done"}
assert not Live()._studio_events_to_skip
def test_post_to_studio_without_exp(tmp_dir, mocked_dvc_repo, mocked_studio_post):
assert not Live(save_dvc_exp=False)._studio_events_to_skip
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Live updates to Studio will happen regardless of save_dvc_exp value.

@@ -571,7 +558,8 @@ def make_report(self):

@catch_and_warn(DvcException, logger)
def make_dvcyaml(self):
make_dvcyaml(self)
if self.dvc_file:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what is the case for this?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean when can it be None?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is the only (?) unresolved question? Approved, since it doesn't look anything major ...

good stuff, Dave. thanks!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, missed this one. Good catch. Maybe this came from an earlier iteration. I dropped this condition in the latest commit.

@dberenbaum dberenbaum merged commit 35ce2f3 into main Feb 15, 2024
14 checks passed
@dberenbaum dberenbaum deleted the no-git branch February 15, 2024 17:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A: studio Area: Studio integration
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

6 participants