-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
HParams: Create hparams effects to trigger data to be fetched from th…
…e hparams plugin (#6540) ## 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.
- Loading branch information
1 parent
4669e6d
commit d4df603
Showing
13 changed files
with
597 additions
and
97 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
/* Copyright 2023 The TensorFlow Authors. All Rights Reserved. | ||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
http://www.apache.org/licenses/LICENSE-2.0 | ||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
==============================================================================*/ | ||
import {Injectable} from '@angular/core'; | ||
import {Actions, createEffect, ofType} from '@ngrx/effects'; | ||
import {Store} from '@ngrx/store'; | ||
import {Observable, of, throwError, merge} from 'rxjs'; | ||
import { | ||
catchError, | ||
filter, | ||
map, | ||
switchMap, | ||
withLatestFrom, | ||
throttleTime, | ||
combineLatestWith, | ||
} from 'rxjs/operators'; | ||
|
||
import {navigated} from '../../app_routing/actions'; | ||
import { | ||
getActiveRoute, | ||
getExperimentIdsFromRoute, | ||
} from '../../app_routing/store/app_routing_selectors'; | ||
import {State} from '../../app_state'; | ||
import * as coreActions from '../../core/actions'; | ||
import * as runsActions from '../../runs/actions/runs_actions'; | ||
import {HttpErrorResponse} from '../../webapp_data_source/tb_http_client'; | ||
|
||
import * as hparamsActions from './hparams_actions'; | ||
import {HparamsDataSource} from './hparams_data_source'; | ||
import {HparamAndMetricSpec, SessionGroup} from '../types'; | ||
import {getEnableHparamsInTimeSeries} from '../../feature_flag/store/feature_flag_selectors'; | ||
import {RouteKind} from '../../app_routing/types'; | ||
|
||
/** | ||
* Effects for fetching the hparams data from the backend. | ||
*/ | ||
@Injectable() | ||
export class HparamsEffects { | ||
constructor( | ||
private readonly actions$: Actions, | ||
private readonly store: Store<State>, | ||
private readonly dataSource: HparamsDataSource | ||
) {} | ||
|
||
private readonly runTableShown$: Observable<string[]> = this.actions$.pipe( | ||
ofType(runsActions.runTableShown), | ||
map(({experimentIds}) => experimentIds) | ||
); | ||
|
||
private readonly loadHparamsOnNavigationOrReload$: Observable<string[]> = | ||
this.actions$.pipe( | ||
ofType(navigated, coreActions.reload, coreActions.manualReload), | ||
withLatestFrom(this.store.select(getExperimentIdsFromRoute)), | ||
filter(([, experimentIds]) => Boolean(experimentIds)), | ||
map(([, experimentIds]) => experimentIds as string[]) | ||
); | ||
|
||
/** @export */ | ||
loadHparamsData$ = createEffect(() => { | ||
return merge( | ||
this.runTableShown$, | ||
this.loadHparamsOnNavigationOrReload$ | ||
).pipe( | ||
combineLatestWith( | ||
this.store.select(getEnableHparamsInTimeSeries), | ||
this.store.select(getActiveRoute) | ||
), | ||
filter( | ||
([, getEnableHparamsInTimeSeries]) => getEnableHparamsInTimeSeries | ||
), | ||
filter( | ||
([, , activeRoute]) => | ||
activeRoute?.routeKind === RouteKind.EXPERIMENT || | ||
activeRoute?.routeKind === RouteKind.COMPARE_EXPERIMENT | ||
), | ||
throttleTime(10), | ||
switchMap(([experimentIds]) => | ||
this.loadHparamsForExperiments(experimentIds) | ||
), | ||
map((resp) => hparamsActions.hparamsFetchSessionGroupsSucceeded(resp)) | ||
); | ||
}); | ||
|
||
private loadHparamsForExperiments(experimentIds: string[]): Observable<{ | ||
hparamsAndMetricsSpecs: HparamAndMetricSpec; | ||
sessionGroups: SessionGroup[]; | ||
}> { | ||
return this.dataSource.fetchExperimentInfo(experimentIds).pipe( | ||
switchMap((hparamsAndMetricsSpecs) => { | ||
return this.dataSource | ||
.fetchSessionGroups(experimentIds, hparamsAndMetricsSpecs) | ||
.pipe( | ||
catchError((error) => { | ||
// HParam plugin return 400 when there are no hparams | ||
// for an experiment. | ||
if (error instanceof HttpErrorResponse && error.status === 400) { | ||
return of([] as SessionGroup[]); | ||
} | ||
return throwError(() => error); | ||
}), | ||
map((sessionGroups) => ({hparamsAndMetricsSpecs, sessionGroups})) | ||
); | ||
}) | ||
); | ||
} | ||
} |
Oops, something went wrong.