-
Notifications
You must be signed in to change notification settings - Fork 1.7k
[DebuggerV2] Display detailed tensor debug-values in graph- and eager-execution components #3541
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
Changes from all commits
Commits
Show all changes
30 commits
Select commit
Hold shift + click to select a range
6150f26
[DebuggerV2] Flesh out graph execution data display
caisq d7dd9c5
Flesh out scrolling effect; Improve CSS
caisq 4b31ddb
Add unit tests for selectors
caisq 20daabf
Add unit tests for reducers
caisq 5eb5e10
Adjust CSS
caisq d1ef4ab
Add unit tests for effect
caisq 4df718f
Add container tests
caisq 964c20c
Fix loading spinner css
caisq 9e37e35
Revert extraneous change
caisq ab58b65
Tweak some comments
caisq 8893db2
[DebuggerV2] Add tensor-debug info to GraphExecutionComponent
caisq 1d7b8d2
Merge branch 'master' into dbg2-graph-exec-1c
caisq a6d5e56
WIP: Add debug_tensor_value.ts
caisq 14613da
Add logic and tests for FULL_TENSOR and FULL_HEALTH; doc string
caisq 64282ad
Add undefined filling for shape
caisq 02c8e32
Refactoring into DebugTensorValueComponent
caisq df83903
Refactor DebugTensorValueComponent into separate folder
caisq 3820d93
Adjust breakdown component CSS
caisq ccbc314
Add DebugTensorShapeComponent
caisq 1e90a8e
Add DebugTensorHasInfOrNaNComponent
caisq 4f2bcdc
Switch ExecutionDataComponent to using DebugTensorValueCompoennt
caisq 7f71cbb
Adding unit tests for debug-tensor-value components
caisq 606f80f
Add more unit tests for debug-tensor-value components
caisq c4ab22c
Add more unit tests
caisq 0dc3281
Fix typos
caisq 8634808
Fix more typos
caisq 0873c95
Address Stephan's comments
caisq a67a8f5
Address 2nd round of comments
caisq b33d934
Remove cruft
caisq b6ce533
Add missing BUILD dependency
caisq File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
379 changes: 24 additions & 355 deletions
379
tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/debugger_container_test.ts
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains hidden or 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
213 changes: 213 additions & 0 deletions
213
tensorboard/plugins/debugger_v2/tf_debugger_v2_plugin/store/debug_tensor_value.ts
This file contains hidden or 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,213 @@ | ||
| /* Copyright 2020 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 {DTYPE_ENUM_TO_NAME} from '../tf_dtypes'; | ||
| import {DebugTensorValue, TensorDebugMode} from './debugger_types'; | ||
|
|
||
| export interface RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode; | ||
| array: null | number[]; | ||
| } | ||
|
|
||
| export interface RawDebugTensorValueNoTensor extends RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode.NO_TENSOR; | ||
| array: null; | ||
| } | ||
|
|
||
| export interface RawDebugTensorValueCurtHealth extends RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode.CURT_HEALTH; | ||
| array: [ | ||
| number, // Tensor ID. | ||
| number // 0-1 indicator for the presence of inf/nan. | ||
| ]; | ||
| } | ||
|
|
||
| export interface RawDebugTensorValueConciseHealth extends RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode.CURT_HEALTH; | ||
| array: [ | ||
| number, // Tensor ID. | ||
| number, // Element count (size). | ||
| number, // -inf count. | ||
| number, // +inf count. | ||
| number // nan count. | ||
| ]; | ||
| } | ||
|
|
||
| export interface RawDebugTensorValueShape extends RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode.SHAPE; | ||
| array: [ | ||
| number, // Tensor ID. | ||
| number, // DType enum value. | ||
| number, // Rank. | ||
| number, // Size. | ||
| number, // Shape truncated at head to a maximum length of 6. | ||
| number, | ||
| number, | ||
| number, | ||
| number, | ||
| number | ||
| ]; | ||
| } | ||
|
|
||
| export interface RawDebugTensorValueFullHealth extends RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode.FULL_HEALTH; | ||
| array: [ | ||
| number, // Tensor ID. | ||
| number, // Device ID. | ||
| number, // DType enum value. | ||
| number, // Rank. | ||
| number, // Size. | ||
| number, // -inf count. | ||
| number, // +inf count. | ||
| number, // nan count. | ||
| number, // -finite count. | ||
| number, // zero count. | ||
| number // +finite count. | ||
| ]; | ||
| } | ||
|
|
||
| export interface RawDebugTensorValueFullTensor extends RawDebugTensorValue { | ||
| tensorDebugMode: TensorDebugMode.FULL_HEALTH; | ||
| array: null; | ||
| } | ||
|
|
||
| /** | ||
| * Parse a number array that represents debugging summary of an instrumented | ||
| * tensor value. | ||
| * | ||
| * @param tensorDebugMode and the array of number that represents various | ||
| * aspect of the instrumented tensor. The semantics of the numbers are | ||
| * determined by `tensorDebugMode`. | ||
| * @returns A DebugTensorValue object with the same information as | ||
| * carried by `array`, but represented in a more explicit fashion. | ||
| * For numbers that represent breakdown of numeric values by type | ||
| * (e.g., counts of -inf, +inf and nan), the corresponding fields | ||
| * in the returned object will be defined only if the count is non-zero. | ||
| */ | ||
| export function parseDebugTensorValue( | ||
| raw: RawDebugTensorValue | ||
| ): DebugTensorValue { | ||
| const {tensorDebugMode, array} = raw; | ||
| switch (tensorDebugMode) { | ||
| case TensorDebugMode.NO_TENSOR: { | ||
| if (array !== null) { | ||
| throw new Error( | ||
| 'Unexpectedly received non-null debug-tensor-value array ' + | ||
| 'under NO_TENSOR mode' | ||
| ); | ||
| } | ||
| return {}; | ||
| } | ||
| case TensorDebugMode.CURT_HEALTH: { | ||
| if (array === null || array.length !== 2) { | ||
| throw new Error( | ||
| `Under CURT_HEALTH mode, expected debug-tensor-value array ` + | ||
| `to have length 2, but got ${JSON.stringify(array)}` | ||
| ); | ||
| } | ||
| return { | ||
| hasInfOrNaN: Boolean(array[1]), | ||
| }; | ||
| } | ||
| case TensorDebugMode.CONCISE_HEALTH: { | ||
| if (array === null || array.length !== 5) { | ||
| throw new Error( | ||
| `Under CONCISE_HEALTH mode, expected debug-tensor-value array ` + | ||
| `to have length 5, but got ${JSON.stringify(array)}` | ||
| ); | ||
| } | ||
| const value: DebugTensorValue = { | ||
| size: array[1], | ||
| }; | ||
| if (array[2] > 0) { | ||
| value.numNegativeInfs = array[2]; | ||
| } | ||
| if (array[3] > 0) { | ||
| value.numPositiveInfs = array[3]; | ||
| } | ||
| if (array[4] > 0) { | ||
| value.numNaNs = array[4]; | ||
| } | ||
| return value; | ||
| } | ||
| case TensorDebugMode.SHAPE: { | ||
| if (array === null || array.length !== 10) { | ||
| throw new Error( | ||
| `Under SHAPE mode, expected debug-tensor-value array ` + | ||
| `to have length 10, but got ${JSON.stringify(array)}` | ||
| ); | ||
| } | ||
| const rank = array[2]; | ||
| let shape: number[] = array.slice(4, Math.min(4 + rank, array.length)); | ||
| if (shape.length < rank) { | ||
| // The SHAPE mode truncates the shape at head. | ||
| shape = new Array<number>(rank - shape.length).concat(shape); | ||
| } | ||
| return { | ||
| dtype: DTYPE_ENUM_TO_NAME[array[1]], | ||
| rank, | ||
| size: array[3], | ||
| shape, | ||
| }; | ||
| } | ||
| case TensorDebugMode.FULL_HEALTH: { | ||
| if (array === null || array.length !== 11) { | ||
| throw new Error( | ||
| `Under FULL_HEALTH mode, expected debug-tensor-value array ` + | ||
| `to have length 11, but got ${JSON.stringify(array)}` | ||
| ); | ||
| } | ||
| const rank = array[3]; | ||
| const value: DebugTensorValue = { | ||
| dtype: DTYPE_ENUM_TO_NAME[array[2]], | ||
| rank, | ||
| size: array[4], | ||
| }; | ||
| if (array[5] > 0) { | ||
| value.numNegativeInfs = array[5]; | ||
| } | ||
| if (array[6] > 0) { | ||
| value.numPositiveInfs = array[6]; | ||
| } | ||
| if (array[7] > 0) { | ||
| value.numNaNs = array[7]; | ||
| } | ||
| if (array[8] > 0) { | ||
| value.numNegativeFinites = array[8]; | ||
| } | ||
| if (array[9] > 0) { | ||
| value.numZeros = array[9]; | ||
| } | ||
| if (array[10] > 0) { | ||
| value.numPositiveFinites = array[10]; | ||
| } | ||
| return value; | ||
| } | ||
| case TensorDebugMode.FULL_TENSOR: { | ||
| // Under FULL_TENSOR mode, the full tensor value is supplied via | ||
| // separate means. No summary values are provided for the tensor value. | ||
| if (array !== null) { | ||
| throw new Error( | ||
| 'Unexpectedly received non-null debug-tensor-value array ' + | ||
| 'under FULL_TENSOR mode' | ||
| ); | ||
| } | ||
| return {}; | ||
| } | ||
| default: { | ||
| throw new Error(`Unrecognized tensorDebugMode: ${tensorDebugMode}`); | ||
| } | ||
| } | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back 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.
high level question: I find this rather tedious. What happens if we just have hard dependency on jspb or OSS equivalent?
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.
This is a little tedious. But this is the only place where this logic needs to exist in tensorboard. The background is that for efficiency, DebugNumericsSummaryV2 ops return a fixed-size 1D tensor for all instrumented tensors. The advantages of this format is that
As such, the 1D vector must have a contract in what each number means (given the TensorDebugMode). This function here knows and carries out this contract.
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.
I am not too convinced about the performance argument. Protobuf, sure, may not be as efficient at representing such values as what you did here but it surely is closer to this than, say, JSON (jspb encodes values as array of arrays; it does not transfer binaries).
I am still okay with this because jspb dependency (closure version) on FE is quite not pleasant.
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.
Ack.