-
Notifications
You must be signed in to change notification settings - Fork 37
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
live: Add log_image
and log_plot
.
#189
Conversation
Codecov Report
@@ Coverage Diff @@
## main #189 +/- ##
==========================================
- Coverage 92.81% 91.83% -0.98%
==========================================
Files 18 19 +1
Lines 487 588 +101
==========================================
+ Hits 452 540 +88
- Misses 35 48 +13
Continue to review full report at Codecov.
|
The integration looks alright. One question that I have is whether we want to promote logging confusion matrix as image file. While we do support images on DVC side, I am not sure we should promote that.
|
I think I implemented it as an image mainly for saving users from having to set custom plot properties (i.e. However, the other functions save the data in "DVC plots format", requiring custom plot properties as well, so it would be consistent. |
Well, maybe it's another reason to reconsider iterative/dvc#6944 - maybe we should discuss somehow providing config for each image which would define how to plot it? |
Agree with @pared about the confusion matrix and plots in general. Seems better to save the data and work on making it easier to specify plots properties. For the other plots, it seems awkward to have to call them in dvclive and configure them in dvc. Also, I'm not sure how much value there is in these functions that lightly wrap existing sklearn functions. Seems more useful to do one or both of:
What do you think? |
Revisiting this.
I don't fully get
About the value of these light wraps, I don't really know. My view is that there are many stages between this light wraps and automagic logging "a la mlflow". I would say that a good intermediate would be However, it seems that it's up to user taste and there is no real need to don't support any stage. Automagic methods are going to be using something similar to (if not exactly) these light wraps so, why not expose all different levels of granularity? We could start with this low level integration and incrementally add magic |
04ba8a0
to
c511533
Compare
4ead8a4
to
5845af9
Compare
I'm still unsure about this. My hesitations are:
Another option is to add support solely via docs (once #203 is merged), similar to https://dvc.org/doc/dvclive/ml-frameworks/tensorflow. How much value do you think the current PR adds, and how much added value do you see in further integration? |
I would not say it's arbitrary. It's not complete, for sure, but includes 3 out of the 6 visualizations supported in scikit-learn (https://scikit-learn.org/stable/visualizations.html). I would support any scikit-learn visualization that can be seamlessly integrated with It's a similar selection to the integrations in https://docs.wandb.ai/guides/integrations/scikit . The difference is that some of those plots types are not directly integrable with
Indeed, but it's a common limitation for any logger that doesn't perform the "magic" patching. This is addressable on docs, similar to the existing barebones PyTorch and TensorFlow guides.
With Potentially, after #203, this could be extended to include
I don't / haven't really use scikit-learn beyond toy projects, so I have a lack of context on what it's valuable in real scenarios π I see immediate value to be used in https://github.com/iterative/example-get-started to reduce code and promote I don't see how different these functions are from the basic usage of Added value in further integration should move towards "magic" patching and/or Given that the inputs are arrays of |
Thanks for the explanation. That makes sense. Why can't calibration curves and partial dependence plots also be supported in DVC? They are all linear unless I'm missing something.
I think this is where we had different ideas for sklearn integration. I thought we would first need to capture the scalar metrics before worrying about plots. I guess you are thinking that the plots are harder for the user to log, and they can easily log scalar metrics already? Still, it would be nice to automatically capture all of the relevant scalar metrics (in addition to plots) if there is some higher-level integration.
Are you suggesting that these could be generic functions rather than specific to |
You are right, calibration curves can be supported. And also partial dependence, but only in "average" mode.
I agree, after #203 , a higher level
We can start documenting as part of sklearn integration but I can see the plots being useful for basically any other framework that supports some classification task (so, pretty much, all). |
8fdd0f8
to
a6aab0f
Compare
Should these be logged inside the dvclive dir? |
Ultimately, I think the workflow for this should depend on #82 and #203. Right now, it's impossible to log from within a
Do you think it's worth merging as is and then modifying it after? I think it will require breaking changes to address those issues. |
I mention it because this PR seems like a specific application of #82. Similar to #166, it seems that we will need to decide on the canonical workflow and directory structure for this type of data in both non-step and step-based workflows. So, we can try to decide that now, or we can merge knowing we will need to break it later. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved all the logic to Live.log
and made plots
a new "data type".
So the idea is that Live.log
can log any of the 3 supported data types: scalars, images, and plots.
- Scalar
live.log("accuracy", 0.9)
- Image
img = np.ones((500, 500, 3), np.uint8)
live.log("image.png", img)
- Plot
live.log("roc_curve.json", (y_true, y_score, "roc"))
live.log("cm.json", (y_true, y_pred, "confusion_matrix"))
The internals make sense for me and the no step / step logic is resolved equally for images and plots.
However, I'm not sure how intuitive the API for plots is.
It could be a matter of documentation or it could be better to have explicitly separated methods for each data type log_metric
, log_image
, log_plot
.
I kind of prefer separate methods.
6f9b868
to
2ac8394
Compare
I think that separate methods make sense too, as the distinction in use will be seen at first sight. I am not sure we should rename |
Nice! I agree with @pared that it seems best to have separate methods but leave |
Returning to this, yes, I think it should be possible to see how the ROC curve changes at each step, for example. Right now, saving the data works, but it's almost impossible to configure |
The initial scope for this kind of plot was for non-step. Properly supporting multi-step curves would require a new template would be required on DVC side using |
Okay, let's discuss separately in #82 or elsewhere the per-step scenario. Why support logging at each step then in this PR? Should an error be thrown if using |
No strong reason, it just reuses the logic already present for images.
Will do |
Decouple data type logging into separated methods. Use subfolders for each data type. Raise NotImplementedError in `log_plot` when using steps.
Sorry for the confusion over step/no-step scenarios. Limiting to no-step makes sense. |
def log_image(self, name: str, val): | ||
if not Image.could_log(val): | ||
raise InvalidDataTypeError(name, type(val)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe val
should be renamed. val
made sense for scalars (log()
) but image_data
or something more descriptive would be better here IMO.
def log_plot(self, name, labels, predictions, **kwargs): | ||
val = (labels, predictions) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here. plot_data
?
if name in self._images: | ||
data = self._images[name] | ||
else: | ||
data = Image(name, self.dir) | ||
self._images[name] = data |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As for name
, should it be filename
or out
instead? Again for clarity
if name in self._plots: | ||
data = self._plots[name] | ||
elif name in PLOTS and PLOTS[name].could_log(val): | ||
data = PLOTS[name](name, self.dir) | ||
self._plots[name] = data | ||
else: | ||
raise InvalidPlotTypeError(name) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same. filename
? plot_fname
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or I guess (plot_)type
would be most accurate here.
β I have followed the Contributing to DVCLive guide.
π If this PR requires documentation updates, I have created a separate PR (or issue, at least) in dvc.org and linked it here.
Adds new
plots
data type.Refactor each data type to separated methods:
Live.log
-> Saves todvclive.dir
/scalars
Live.log_image
-> Saves todvclive.dir
/images
Live.log_plot
-> Saves todvclive.dir
/plots
Supported
plot_type
(first argument):calibration
confusion_matrix
det
precission_recall
roc
Full example:
dvc plots show