Skip to content
This repository has been archived by the owner on Sep 18, 2024. It is now read-only.

Fix bugs in NAS UI (deferred from previous releases) #2552

Merged
merged 5 commits into from
Jun 28, 2020
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/nasui/assets/darts/graph.json

Large diffs are not rendered by default.

471 changes: 471 additions & 0 deletions src/nasui/assets/darts/log

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/nasui/assets/naive/graph.json

Large diffs are not rendered by default.

404 changes: 404 additions & 0 deletions src/nasui/assets/naive/log

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions src/nasui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
"start": "react-scripts start",
"build": "react-scripts build",
"eject": "react-scripts eject",
"test": "react-scripts test",
"backend": "node server.js"
},
"eslintConfig": {
Expand Down
25 changes: 16 additions & 9 deletions src/nasui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import Backdrop from '@material-ui/core/Backdrop';
import Tooltip from '@material-ui/core/Tooltip';
import Chart from './Chart';
import { Graph } from './graphUtils';

Expand Down Expand Up @@ -272,15 +273,21 @@ class App extends React.Component<AppProps, AppState> {
<Typography variant='h6' className={classes.title}>
NNI NAS Board
</Typography>
<IconButton color='inherit' onClick={handleLayoutStateChanged(true)}>
<ShuffleIcon />
</IconButton>
<IconButton color='inherit' onClick={this.refresh}>
<RefreshIcon />
</IconButton>
<IconButton color='inherit' onClick={handleSettingsDialogToggle(true)}>
<SettingsIcon />
</IconButton>
<Tooltip title="Re-layout graph">
<IconButton color='inherit' onClick={handleLayoutStateChanged(true)}>
<ShuffleIcon />
</IconButton>
</Tooltip>
<Tooltip title="Refresh">
<IconButton color='inherit' onClick={this.refresh}>
<RefreshIcon />
</IconButton>
</Tooltip>
<Tooltip title="Settings">
<IconButton color='inherit' onClick={handleSettingsDialogToggle(true)}>
<SettingsIcon />
</IconButton>
</Tooltip>
</Toolbar>
</AppBar>
<AppBar position='fixed' color='default' className={classes.bottomAppBar}>
Expand Down
10 changes: 7 additions & 3 deletions src/nasui/src/Chart.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ export default class Chart extends React.Component<ChartProps> {
expandSet: Set<string> = new Set<string>();
elemWeight: Map<string, number> = new Map<string, number>();
graphEl: any[] = [];
private firstUpdate = true;

componentDidMount() {
this.cyInstance = cytoscape({
Expand Down Expand Up @@ -149,7 +150,8 @@ export default class Chart extends React.Component<ChartProps> {
}
} else {
// re-calculate collapse
this.renderGraph(true);
this.renderGraph(true, this.firstUpdate);
this.firstUpdate = false;
}
}

Expand Down Expand Up @@ -245,7 +247,7 @@ export default class Chart extends React.Component<ChartProps> {
setTimeout(_render, 100);
}

private renderGraph(graphChanged: boolean) {
private renderGraph(graphChanged: boolean, fit: boolean = false) {
const { graph } = this.props;
if (graph === undefined)
return;
Expand All @@ -269,7 +271,9 @@ export default class Chart extends React.Component<ChartProps> {
this.cyInstance!.json({
elements: graphEl
});
layout.fit = false;
if (!fit) {
layout.fit = false;
}
eles.layout(layout).run();
}
} else {
Expand Down
26 changes: 26 additions & 0 deletions src/nasui/src/graphUtils.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Graph } from './graphUtils';
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggest to move all unit test stuff into test directory like nnimanager.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Here is the reference.

Jest will look for test files with any of the following popular naming conventions:

  • Files with .js suffix in __tests__ folders.
  • Files with .test.js suffix.
  • Files with .spec.js suffix.
    The .test.js / .spec.js files (or the tests folders) can be located at any depth under the src top level folder.

We recommend to put the test files (or tests folders) next to the code they are testing so that relative imports appear shorter. For example, if App.test.js and App.js are in the same folder, the test only needs to import App from './App' instead of a long relative path. Collocation also helps find tests more quickly in larger projects.

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'll move them to __tests__ folder. I checked nni manager conversion (test folder) and jest doesn't recognize them automatically.

Copy link
Contributor

Choose a reason for hiding this comment

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

OK.

Copy link
Contributor

Choose a reason for hiding this comment

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

btw, nnimanager is using mocha for test, what is the reason that nasui select jest instead of mocha?

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 used the default settings provided by react-scripts.

import * as fs from 'fs';

describe('Graph utils test', () => {
it('Graph constructor darts', () => {
const graph = new Graph(JSON.parse(fs.readFileSync('assets/darts/graph.json').toString()), true);
const activation = JSON.parse(fs.readFileSync('assets/darts/log').toString().split('\n')[0]);
expect(graph.nodes.length).toEqual(1842);
expect(graph.edges.length).toEqual(927);
const weights = graph.weightFromMutables(activation);
expect(weights.get('["CNN/ModuleList[cells]/Cell[1]/ModuleList[mutable_ops]/Node[0]/InputChoice[input_switch]/input.228",' +
'"CNN/ModuleList[cells]/Cell[1]/ModuleList[mutable_ops]/Node[1]/ModuleList[ops]/' +
'LayerChoice[2]/PoolBN[maxpool]/MaxPool2d[pool]/input.229"]')).toBeCloseTo(0.125, 3);
});

it('Graph constructor naive', () => {
const graph = new Graph(JSON.parse(fs.readFileSync('assets/naive/graph.json').toString()), true);
expect(graph.nodes.length).toEqual(51);
expect(graph.edges.length).toEqual(37);
expect(graph.mutableEdges.get('LayerChoice1')![0].length).toEqual(5);
expect(graph.mutableEdges.get('LayerChoice1')![1].length).toEqual(5);
expect(graph.mutableEdges.get('LayerChoice2')![0].length).toEqual(5);
expect(graph.mutableEdges.get('LayerChoice2')![1].length).toEqual(5);
expect(graph.mutableEdges.get('InputChoice3')![0].length).toEqual(4);
});
});
24 changes: 20 additions & 4 deletions src/nasui/src/graphUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export class NodeTs {
isParent(): boolean {
return this.children.length > 0;
}

toString(): string {
return `Node(id=${this.id})`;
}
};

export class Edge {
Expand All @@ -59,6 +63,10 @@ export class Edge {
this.target = target;
this.id = JSON.stringify([this.source.id, this.target.id]);
}

toString(): string {
return `Edge(${this.source} -> ${this.target})`;
}
};

interface NodeSummary {
Expand All @@ -76,12 +84,12 @@ export class Graph {
nodes: NodeTs[];
edges: Edge[];
defaultExpandSet: Set<string>;
mutableEdges: Map<string, Edge[][]>;
private id2idx: Map<string, number>;
private edgeId2idx: Map<string, number>;
private forwardGraph: Map<string, string[]>;
private backwardGraph: Map<string, string[]>;
private node2edge: Map<string, Edge[]>;
private mutableEdges: Map<string, Edge[][]>;

private build() {
this.id2idx.clear();
Expand Down Expand Up @@ -359,17 +367,25 @@ export class Graph {
weightFromMutables(mutable: any): Map<string, number> {
const elemWeight = new Map<string, number>();
Object.entries(mutable).forEach(entry => {
const elemWeightPartial = new Map<string, number>();
const key = entry[0];
const weights = entry[1] as number[];
this.mutableEdges.get(key)!.forEach((edges: any, i: number) => {
edges.forEach((edge: any) => {
if (elemWeight.has(edge.id)) {
elemWeight.set(edge.id, elemWeight.get(edge.id)! + weights[i]);
if (elemWeightPartial.has(edge.id)) {
elemWeightPartial.set(edge.id, elemWeightPartial.get(edge.id)! + weights[i]);
} else {
elemWeight.set(edge.id, weights[i]);
elemWeightPartial.set(edge.id, weights[i]);
}
})
});
elemWeightPartial.forEach((v, k) => {
if (elemWeight.has(k)) {
elemWeight.set(k, Math.min(elemWeight.get(k)!, v));
} else {
elemWeight.set(k, v);
}
});
});
this.nodes.forEach(node => {
const edges = this.connectedEdges(node.id);
Expand Down
6 changes: 6 additions & 0 deletions test/scripts/unittest.sh
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,9 @@ cd ${CWD}/../src/nni_manager
echo ""
echo "===========================Testing: nni_manager==========================="
npm run test

# -------------For NASUI unittest-------------
cd ${CWD}/../src/nasui
echo ""
echo "===========================Testing: nasui==========================="
CI=true npm test