Skip to content

HParams: Create hparams effects to trigger data to be fetched from the hparams plugin #6540

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

Merged
merged 5 commits into from
Aug 14, 2023

Conversation

rileyajones
Copy link
Contributor

@rileyajones rileyajones commented Aug 10, 2023

Motivation for features / changes

This is a natural continuation of the work done in #6535

I added a new effects file which fires a newly created action whenever the runs table is shown, a navigation occurs, or the user reloads the data.

The data loading is then filtered and throttled by the existence of experiment ids.

Finally the raw response from the hparams_data_source is written to the redux state. In a future PR I will add a series of selectors to remap and inject that data into the runs metadata.

Alternate designs / implementations considered (or N/A)

I've opted to include the effects and data source in the hparams module but hide the functionality behind the feature flag. This should make it easier to develop changes downstream from this pr. In the future I will gate the existing behavior behind the inverse of this flag and that should allow us to test the full flow without needing to remove the old code (I have tested removing the old code).

The reducer change could have been split out from this but it's quite small and I thought including it made it easier to see the entire write path.

Because I added two new attributes to the hparams redux state there are a few changes to test utilities that are not strictly necessary but are useful to have.

@rileyajones rileyajones marked this pull request as ready for review August 10, 2023 22:45
@bmd3k bmd3k self-requested a review August 11, 2023 14:19
@@ -43,6 +45,8 @@ export const HPARAMS_FEATURE_KEY = 'hparams';

export interface HparamsState {
specs: ExperimentToHparams;
currentSpecs: HparamAndMetricSpec;
Copy link
Contributor

Choose a reason for hiding this comment

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

Could you elaborate a bit on what the final data model is going to look like? Introduction of "currentSpecs" and "sessionGroups" isn't clearly going in the direction that I hoped this would. It could just be a naming issue, though.

Ultimately I think the data model should look something like:

export interface HparamsState {
  listSpecs: Record<string, HparamAndMetricSpec> ;
  listSessionGroups: Record<string, SessionGroup[]>;
  listFilters: Record<string, Filters>;
  dashboardSpecs: HparamAndMetricSpec;
  dashboardSessionGroups: SessionGroup[];
  dashboardFilters: Filters;
}

Notably, there is no notion of a single "current" spec since (1) there is also no notion of a "previous" spec and (2) you could have multiple active lists at the same time - multiple in the experiment list and one in the dashboard.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I do think this is a naming issue. I agree that dashboardSpecs seems like a better name as it helps clarify the usease. I chose ccurrentSpecs to indicate that it's value would change as the experiment ids changed, but in hindsight that is implicit with redux properties.

) {}

private readonly runTableShown$: Observable<string[]> = this.actions$.pipe(
ofType(runsActions.runTableShown),
Copy link
Contributor

Choose a reason for hiding this comment

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

If I understand correctly, runTableShown is fired when any run table is shown - either in experiment list or in dashboard, right?

If so, then loading any runs table ultimately dispatches an instance of hparamsFetchSessionGroupsSucceeded which populates the same state over and over - overwriting whatever was there before. The action doesn't clarify which run table you've loaded data for - is it one of the tables in the experiment list or is it the table in the dashboard?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm unsure how we can differentiate between them. This does remind me that I had intended to ensure the events are only dispatched on the dashboard routes. How would you feel about that solution?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you could encode the information in the action that triggers the logic. For example:

  1. have two different actions runTableShownInExperimentList and runTableShownInDashboard
  2. or make it a property of the runTableShown action. Maybe an enum of type RunTableLocation.

On the other hand, using route information for this seems ok. But just to confirm: Do you intend that this logic will also handle the run tables in the experiment list? And, if so, do you plan to somehow differentiate the two cases when you dispatch the action after retrieving the data - perhaps add a property to hparamsFetchSessionGroupsSucceeded (again maybe an enum type RunTableLocation).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

At the moment I do not intend for this to be active on the experiment list at all. Once this portion of the code is stable I plan to do a refactor of the data fetching logic on the experiment list though and at that point I may try to merge these. If that happens I will probably add an enum to the runTableShown action payload.

@rileyajones rileyajones requested a review from bmd3k August 11, 2023 17:57
filter(
([, getEnableHparamsInTimeSeries]) => getEnableHparamsInTimeSeries
),
throttleTime(10),
Copy link
Contributor

Choose a reason for hiding this comment

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

Is the reason for this because when we navigate to timeseries we also trigger runTableShown? So we are just avoiding a duplicate call?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, that's exactly it.

@@ -43,6 +45,8 @@ export const HPARAMS_FEATURE_KEY = 'hparams';

export interface HparamsState {
specs: ExperimentToHparams;
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: To avoid confusion I think this should be name experimentListSpecs or something like that.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree but I'd like to refactor the experiment list portion of the state in a separate PR once the dashboard flow is fully checked in. I think this new flow is better and I am hopeful that we can remove a lot of the old code.

@@ -19,3 +19,9 @@ limitations under the License.
export type DeepReadonly<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};

export type DeepPartial<T> = T extends object
Copy link
Contributor

Choose a reason for hiding this comment

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

useful

Copy link
Contributor

Choose a reason for hiding this comment

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

I'm surprised to discover that you can branch type definitions based on conditions on the type parameters . Kind of neat.

@bmd3k
Copy link
Contributor

bmd3k commented Aug 14, 2023

A minor error in the description:

I added a new actions file which fires whenever the runs table is shown, a navigation occurs, or the user reloads the data.

actions file => effects file

@@ -19,3 +19,9 @@ limitations under the License.
export type DeepReadonly<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};

export type DeepPartial<T> = T extends object
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm surprised to discover that you can branch type definitions based on conditions on the type parameters . Kind of neat.

) {}

private readonly runTableShown$: Observable<string[]> = this.actions$.pipe(
ofType(runsActions.runTableShown),
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you could encode the information in the action that triggers the logic. For example:

  1. have two different actions runTableShownInExperimentList and runTableShownInDashboard
  2. or make it a property of the runTableShown action. Maybe an enum of type RunTableLocation.

On the other hand, using route information for this seems ok. But just to confirm: Do you intend that this logic will also handle the run tables in the experiment list? And, if so, do you plan to somehow differentiate the two cases when you dispatch the action after retrieving the data - perhaps add a property to hparamsFetchSessionGroupsSucceeded (again maybe an enum type RunTableLocation).

@@ -50,3 +54,11 @@ export const hparamsMetricFilterChanged = createAction(
includeUndefined: boolean;
}>()
);

export const hparamsFetchSessionGroupsSucceeded = createAction(
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you have plans to introduce the other actions we typically also have for data source fetches?

hparamsFetchSessionGroupsRequested
hparamsFetchSessionGroupsFailed

(I'd ok - in fact, I prefer - if these come in a different PR. I just want to make sure they are on your radar).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I'll make sure these get added soon. I wanted to get the MVP out as soon as possible to unblock James.

routeKind: RouteKind.EXPERIMENT,
params: {},
});
store.overrideSelector(selectors.getExperimentIdsFromRoute, ['exp1']);
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we rename to perhaps 'expFromRoute' to make it a bit clearer where the navigated, reload, and manualReload tests are getting this from?

@rileyajones rileyajones merged commit d4df603 into tensorflow:master Aug 14, 2023
rileyajones added a commit that referenced this pull request Aug 21, 2023
…ects (#6544)

## Motivation for features / changes
This is a continuation of #6540
Now that data is being retrieved from the hparams plugin and written to
the store I am adding a pair of selectors to retrieve it and inject it
into the the data retrieved from `getRuns` and `getRunsForExperimentId`.

The logic used to translate `SessionGroups` to `Record<RunId/Group,
Value>` is very similar to that being used by the old code in
`runs_data_source`. I could imagine this being refactored to retrieve
the run/group relationships from another part of the store in the future
in order to better integrate with our plans to stop relying on the
metrics portion of the hparams payload.

## Note For Reviewer(s)
A large majority of the lines changed in this PR are indent changes
resulting from changing the method used to mock the state during tests.

I have opted not to add additional test to the runs or common selectors
(though I did have to fix 16) as the intention is for this to be a drop
in replacement with no new features added. The number of test failures
which I had to fix left me feeling confident of the existing test
coverage.
yatbear pushed a commit to yatbear/tensorboard that referenced this pull request Aug 25, 2023
…e hparams plugin (tensorflow#6540)

## Motivation for features / changes
This is a natural continuation of the work done in tensorflow#6535

I added a new effects file which fires a newly created action whenever
the runs table is shown, a navigation occurs, or the user reloads the
data.

The data loading is then filtered and throttled by the existence of
experiment ids.

Finally the raw response from the `hparams_data_source` is written to
the redux state. In a future PR I will add a series of selectors to
remap and inject that data into the runs metadata.

## Alternate designs / implementations considered (or N/A)
I've opted to include the effects and data source in the hparams module
but hide the functionality behind the feature flag. This should make it
easier to develop changes downstream from this pr. In the future I will
gate the existing behavior behind the inverse of this flag and that
should allow us to test the full flow without needing to remove the old
code (I have tested removing the old code).

The reducer change could have been split out from this but it's quite
small and I thought including it made it easier to see the entire write
path.

Because I added two new attributes to the hparams redux state there are
a few changes to test utilities that are not strictly necessary but are
useful to have.
yatbear pushed a commit to yatbear/tensorboard that referenced this pull request Aug 25, 2023
…ects (tensorflow#6544)

## Motivation for features / changes
This is a continuation of tensorflow#6540
Now that data is being retrieved from the hparams plugin and written to
the store I am adding a pair of selectors to retrieve it and inject it
into the the data retrieved from `getRuns` and `getRunsForExperimentId`.

The logic used to translate `SessionGroups` to `Record<RunId/Group,
Value>` is very similar to that being used by the old code in
`runs_data_source`. I could imagine this being refactored to retrieve
the run/group relationships from another part of the store in the future
in order to better integrate with our plans to stop relying on the
metrics portion of the hparams payload.

## Note For Reviewer(s)
A large majority of the lines changed in this PR are indent changes
resulting from changing the method used to mock the state during tests.

I have opted not to add additional test to the runs or common selectors
(though I did have to fix 16) as the intention is for this to be a drop
in replacement with no new features added. The number of test failures
which I had to fix left me feeling confident of the existing test
coverage.
rileyajones added a commit that referenced this pull request Aug 30, 2023
## Motivation for features / changes
Now that we are fetching the hparams data using the newly created
hparams_effects (#6540) we no longer need to fetch them using the old
method.

Note that the experiment list SHOULD still use the old method.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants