提交 bfd1c841 编写于 作者: X xiayifan

add tensor feature

上级 88ea0553
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
"d3": "5.9.7", "d3": "5.9.7",
"d3-graphviz": "3.0.4", "d3-graphviz": "3.0.4",
"element-ui": "2.11.1", "element-ui": "2.11.1",
"jquery": "3.5.0",
"slickgrid": "2.4.22",
"vue": "2.6.11", "vue": "2.6.11",
"vue-i18n": "8.15.0", "vue-i18n": "8.15.0",
"vue-router": "3.1.3", "vue-router": "3.1.3",
......
<!--
Copyright 2020 Huawei Technologies Co., Ltd.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.
-->
<template>
<div class="cl-slickgrid-container">
<div class="data-show-container">
<div v-show="incorrectData"
class="error-msg-container">
{{$t('components.gridIncorrectDataError')}}
</div>
<div v-show="!fullData.length && updated && !incorrectData"
class="error-msg-container">
{{$t('components.gridTableNoData')}}
</div>
<div :id="itemId"
v-show="!!fullData.length && !incorrectData"
class="grid-item"></div>
</div>
<div class="operate-container"
v-if="showOperate && fullData.length">
<div class="filter-container"
@keyup.enter="filterChange">
<div v-for="(item, itemIndex) in filterArr"
:key="itemIndex">
<el-input class="filter-input"
:class="item.showError ? 'error-border' : ''"
v-model="item.model"></el-input>
<span class="input-behind"
v-if="itemIndex === filterArr.length - 1">{{$t('symbols.slashes')}}</span>
<span class="input-behind"
v-else>{{$t('symbols.point')}}</span>
</div>
<el-button class="filter-check"
size="mini"
v-if="!!filterArr.length"
@click="filterChange">
<i class="el-icon-check"></i></el-button>
<span class="filter-incorrect-text"
v-if="!filterCorrect">{{$t('components.inCorrectInput')}}</span>
</div>
<div class="accuracy-container">
{{$t('components.gridAccuracy')}}<el-select v-model="accuracy"
class="select-item"
@change="accuracyChange">
<el-option v-for="item in accuracyArr"
:key="item.label"
:label="item.label"
:value="item.value"></el-option>
</el-select>
<div class="full-screen-icon"
:title="$t('scalar.fullScreen')"
@click="toggleFullScreen"
:class="fullScreen ? 'active-color' : ''">
<span><i class="el-icon-full-screen"></i></span>
</div>
</div>
</div>
</div>
</template>
<script>
import 'slickgrid/css/smoothness/jquery-ui-1.11.3.custom.css';
import 'slickgrid/slick.grid.css';
import 'slickgrid/lib/jquery-3.1.0';
import 'slickgrid/lib/jquery-ui-1.9.2';
import 'slickgrid/lib/jquery.event.drag-2.3.0.js';
import 'slickgrid/slick.core.js';
import 'slickgrid/slick.dataview.js';
import 'slickgrid/slick.grid.js';
export default {
props: {
// Table data
fullData: {
type: Array,
default() {
return [];
},
},
// Display operation Bar
showOperate: {
type: Boolean,
default: true,
},
// Display full screen
fullScreen: {
type: Boolean,
default: false,
},
},
data() {
return {
itemId: '', // Dom id
gridObj: null, // slickgrid object
columnsData: [], // Column information
filterArr: [], // Dimension selection array
formateData: [], // formatted data
formateArr: [], // formatted Array
statistics: {}, // Object contain maximun and minimun
accuracy: 5, // accuracy value
incorrectData: false, // Wheather the dimension is correctly selected
updated: false, // Updated
scrollTop: false, // Wheather scroll to the top
filterCorrect: true, // Wheather the dimension input is correct
// Accuray options
accuracyArr: [
{label: 0, value: 0},
{label: 1, value: 1},
{label: 2, value: 2},
{label: 3, value: 3},
{label: 4, value: 4},
{label: 5, value: 5},
],
// Table configuration items
optionObj: {
enableCellNavigation: true,
frozenColumn: 0,
frozenRow: 0,
},
};
},
computed: {},
watch: {},
mounted() {
this.init();
},
methods: {
/**
* Initialize
*/
init() {
this.itemId =
`${new Date().getTime()}` + `${this.$store.state.componentsCount}`;
this.$store.commit('componentsNum');
},
/**
* Initialize dimension selection
* @param {Array} dimension Dimension array
* @param {String} filterStr Dimension String
*/
initializeFilterArr(dimension, filterStr) {
if (!filterStr) {
this.filterArr = [];
return;
}
const tempFilterArr = filterStr.slice(1, filterStr.length - 1).split(',');
const tempArr = [];
for (let i = 0; i < tempFilterArr.length; i++) {
tempArr.push({
model: tempFilterArr[i],
max: dimension[i] - 1,
showError: false,
});
}
this.filterArr = tempArr;
},
/**
* Initialize column information
*/
formateColumnsData() {
this.columnsData = [
{
id: -1,
name: ' ',
field: -1,
width: 100,
headerCssClass: 'headerStyle',
},
];
const columnSample = this.formateData[0];
if (columnSample) {
columnSample.forEach((num, numIndex) => {
const order = numIndex;
this.columnsData.push({
id: order,
name: order,
field: order,
width: 100,
headerCssClass: 'headerStyle',
formatter: this.formateValueColor,
});
});
} else {
this.columnsData = [];
}
},
/**
* Setting the Background color of data
* @param {Number} row
* @param {Number} cell
* @param {String} value,
* @param {Object} columnDef
* @param {Object} dataContext
* @return {String}
*/
formateValueColor(row, cell, value, columnDef, dataContext) {
if (
!cell ||
!value ||
isNaN(value) ||
value === Infinity ||
value === -Infinity
) {
return value;
} else if (value < 0) {
return `<span class="table-item-span" style="background:rgba(94, 124, 224, ${value /
this.statistics.min})">${value}</span>`;
} else {
return `<span class="table-item-span" style="background:rgba(246, 111, 106, ${value /
this.statistics.max})">${value}</span>`;
}
},
/**
* Convetring raw data into table data
*/
formateGridArray() {
if (this.fullData instanceof Array) {
if (this.fullData.length) {
if (this.fullData[0] instanceof Array) {
this.formateData = this.fullData;
} else {
this.formateData = [this.fullData];
}
} else {
this.formateData = [[]];
this.columnsData = [];
}
} else {
this.formateData = [[this.fullData]];
}
const tempArr = [];
this.formateData.forEach((outerData, outerIndex) => {
const tempData = {
'-1': outerIndex,
};
outerData.forEach((innerData, innerIndex) => {
const innerOrder = innerIndex;
if (isNaN(innerData)) {
tempData[innerOrder] = innerData;
} else {
tempData[innerOrder] = innerData.toFixed(this.accuracy);
}
});
tempArr.push(tempData);
});
this.formateArr = tempArr;
},
/**
* Update the table
*/
updateGrid() {
this.$nextTick(() => {
if (!this.gridObj) {
this.gridObj = new Slick.Grid(
`#${this.itemId}`,
this.formateArr,
this.columnsData,
this.optionObj,
);
}
this.gridObj.setData(this.formateArr, this.scrollTop);
this.scrollTop = false;
this.gridObj.setColumns(this.columnsData);
this.gridObj.render();
});
},
/**
* accuracy changed
* @param {Number} value The value after changed
*/
accuracyChange(value) {
this.formateGridArray();
this.updateGrid();
},
/**
* Dimension selection changed
*/
filterChange() {
// 校验检索条件
let filterCorrect = true;
let incorrectData = false;
let limitCount = 2;
const tempArr = [];
this.filterArr.forEach((filter) => {
const value = filter.model.trim();
tempArr.push(value);
if (!isNaN(value)) {
if (value < -(filter.max + 1) || value > filter.max || value === '') {
filter.showError = true;
filterCorrect = false;
} else {
filter.showError = false;
}
} else if (value === ':') {
filter.showError = false;
if (!limitCount) {
incorrectData = true;
} else {
limitCount--;
}
} else {
filter.showError = true;
filterCorrect = false;
}
});
this.filterCorrect = filterCorrect;
if (incorrectData && filterCorrect) {
this.incorrectData = true;
return;
} else {
this.incorrectData = false;
}
if (filterCorrect) {
this.$emit('martixFilterChange', tempArr);
}
},
/**
* Updating Table Data
* @param {Boolean} newDataFlag Wheather data is updated
* @param {Array} dimension Array of dimension
* @param {Object} statistics Object contains maximun and minimun
* @param {String} filterStr String of dimension selection
*/
updateGridData(newDataFlag, dimension, statistics, filterStr) {
this.updated = true;
this.$nextTick(() => {
if (!this.fullData || !this.fullData.length) {
return;
}
if (newDataFlag) {
this.initializeFilterArr(dimension, filterStr);
this.scrollTop = true;
}
if (newDataFlag || this.statistics.max === undefined) {
this.statistics = statistics;
}
this.formateGridArray();
this.formateColumnsData();
this.updateGrid();
});
},
/**
* Update the view Size
*/
resizeView() {
if (this.gridObj) {
this.$nextTick(() => {
this.gridObj.resizeCanvas();
this.gridObj.render();
});
}
},
/**
* Expand/Collapse in full screen
*/
toggleFullScreen() {
this.$emit('toggleFullScreen');
},
},
destroyed() {},
};
</script>
<style lang="scss">
.cl-slickgrid-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.data-show-container {
width: 100%;
flex: 1;
.grid-item {
width: 100%;
height: 100%;
}
.error-msg-container {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
}
.info-show-container {
width: 100%;
}
.operate-container {
width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
z-index: 99;
flex-wrap: wrap;
.full-screen-icon {
float: right;
margin-left: 15px;
height: 100%;
line-height: 34px;
cursor: pointer;
:hover {
color: #3e98c5;
}
}
.active-color {
color: #3e98c5;
}
.filter-container {
float: left;
flex-wrap: wrap;
display: flex;
.error-border {
input {
border-color: red;
}
}
.filter-input {
width: 50px;
text-align: center;
}
.input-behind {
padding: 0 5px;
}
.filter-incorrect-text {
margin-left: 10px;
line-height: 32px;
color: red;
}
}
.accuracy-container {
float: right;
.select-item {
width: 60px;
}
}
}
}
.slick-cell,
.slick-headerrow-column,
.slick-footerrow-column {
padding: 0;
border-top: none;
border-left: none;
text-align: center;
}
.grid-canvas-left .slick-cell {
height: 54px;
}
.slick-viewport-left {
overflow: hidden !important;
}
.slick-viewport-left .slick-row {
background-color: white !important;
::-webkit-scrollbar {
width: 0px;
}
}
.ui-widget-content {
background: none;
}
.headerStyle {
vertical-align: middle;
text-align: center;
}
.filter-check {
font-size: 18px;
color: #00a5a7;
cursor: pointer;
}
.table-item-span {
display: block;
width: 100%;
height: 100%;
text-align: center;
}
</style>
...@@ -40,6 +40,7 @@ limitations under the License. ...@@ -40,6 +40,7 @@ limitations under the License.
v-if="this.$route.path.indexOf('/scalar') > 0 v-if="this.$route.path.indexOf('/scalar') > 0
|| this.$route.path.indexOf('/image') > 0 || this.$route.path.indexOf('/image') > 0
|| this.$route.path.indexOf('/histogram') > 0 || this.$route.path.indexOf('/histogram') > 0
|| this.$route.path.indexOf('/tensor') > 0
|| this.$route.path.indexOf('/training-dashboard') > 0 || this.$route.path.indexOf('/training-dashboard') > 0
|| !this.$route.path.indexOf('/compare-plate')"> || !this.$route.path.indexOf('/compare-plate')">
<!-- automatic refresh switch --> <!-- automatic refresh switch -->
......
<!--
Copyright 2020 Huawei Technologies Co., Ltd.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.
-->
<template>
<div class="cl-histogram-container">
<div class="data-show-container">
<div :id="itemId"
v-show="!!fullData.length"
class="data-item"></div>
</div>
</div>
</template>
<script>
import echarts from 'echarts';
import CommonProperty from '../common/common-property';
import {format, precisionRound} from 'd3';
const d3 = {format, precisionRound};
export default {
props: {
// histogram data
fullData: {
type: Array,
default() {
return [];
},
},
// view name
viewName: {
type: Number,
default: 1,
},
// axis name
axisName: {
type: Number,
default: 0,
},
// Display full screen
fullScreen: {
type: Boolean,
default: false,
},
},
data() {
return {
itemId: '', // Dom id
oriData: {}, // Original data
charOption: {}, // Chart configuration
charObj: null, // chart Object
updated: false, // Updated
zrDrawElement: {hoverDots: []},
zr: null,
chartTipFlag: false, // Wheather to display tips of the histogram
};
},
computed: {},
watch: {},
mounted() {
this.init();
},
methods: {
/**
* Initialize
*/
init() {
this.itemId =
`${new Date().getTime()}` + `${this.$store.state.componentsCount}`;
this.$store.commit('componentsNum');
},
/**
* Update the view Size
*/
resizeView() {
if (this.charObj) {
this.charObj.resize();
}
},
/**
* Convert to chart data
*/
formatDataToChar() {
const chartData = this.fullData;
const seriesData = [];
let maxX = -Infinity;
let minX = Infinity;
let maxZ = -Infinity;
let minZ = Infinity;
const gridData = [];
if (chartData && chartData.length) {
chartData.forEach((histogram) => {
const seriesItem = [];
gridData.push(histogram.step);
histogram.items.forEach((bucket) => {
if (this.viewName === 0) {
seriesItem.push([bucket[2], bucket[3]]);
} else if (this.viewName === 1) {
seriesItem.push(bucket[2], histogram.step, bucket[3]);
}
maxX = Math.max(maxX, bucket[2]);
minX = Math.min(minX, bucket[2]);
minZ = Math.min(minZ, bucket[3]);
maxZ = Math.max(maxZ, bucket[3]);
});
seriesData.push(seriesItem);
});
}
this.oriData = {
seriesData,
maxX,
minX,
maxZ,
minZ,
gridData,
};
},
/**
* update sample data
*/
updateSampleData() {
this.charOption = this.formatCharOption();
if (!this.charObj) {
const chartItem = document.getElementById(this.itemId);
if (!chartItem) {
return;
}
this.charObj = echarts.init(chartItem, null);
}
this.removeTooltip();
this.charObj.setOption(this.charOption, true);
},
/**
* Binding interaction event
*/
sampleEventBind() {
if (!this.zr) {
this.zr = this.charObj.getZr();
this.zr.off('mouseout', 'mousemove');
this.zr.on('mouseout', (e) => {
this.removeTooltip();
this.chartTipFlag = false;
this.$emit('chartTipFlagChange', this.chartTipFlag);
});
this.zr.on('mousemove', (e) => {
this.removeTooltip();
this.mousemoveEvent(e);
});
}
},
/**
* Formate chart option
* @return {Object} chatr option
*/
formatCharOption() {
const colorMin = '#346E69';
const colorMax = '#EBFFFD';
const oriData = this.oriData;
const colorArr = this.getGrientColor(
colorMin,
colorMax,
oriData.seriesData.length,
);
const fullScreenFun = this.toggleFullScreen;
const axisName = this.axisName;
const option = {
grid: {
left: 24,
top: 60,
right: 50,
bottom: 60,
},
xAxis: {
max: oriData.maxX,
min: oriData.minX,
axisLine: {onZero: false},
axisLabel: {
fontSize: '11',
formatter: function(value) {
if (value.toString().length >= 6) {
return value.toExponential(3);
} else {
return Math.round(value * 1000) / 1000;
}
},
},
splitLine: {show: false},
},
yAxis: {
position: 'right',
axisLine: {onZero: false, show: false},
splitLine: {show: true},
axisTick: {show: false},
boundaryGap: false,
axisLabel: {
fontSize: '11',
},
},
toolbox: {
top: 20,
right: 20,
emphasis: {
iconStyle: {
textPosition: 'top',
},
},
// toolbox
feature: {
// fullScreen
myToolFullScreen: {
show: true,
title: this.$t('histogram.fullScreen'),
iconStyle: {
borderColor: this.fullScreen ? '#3E98C5' : '#6D7278',
},
icon: CommonProperty.fullScreenIcon,
onclick() {
fullScreenFun();
},
},
},
},
};
if (this.viewName === 1) {
const seriesData = [];
oriData.seriesData.forEach((item, dataIndex) => {
const dataItem = {
name: item[1],
value: item,
itemStyle: {
color: colorArr[dataIndex],
},
};
seriesData.push(dataItem);
});
option.series = [
{
type: 'custom',
dimensions: ['x', 'y'],
renderItem: (params, api) => {
const points = this.makePolyPoints(
params.dataIndex,
api.coord,
params.coordSys.y - 10,
);
return {
type: 'polyline',
silent: true,
shape: {
points,
},
style: api.style({
stroke: '#bbb',
lineWidth: 1,
}),
};
},
data: seriesData,
},
];
option.yAxis.data = oriData.gridData;
option.yAxis.type = 'category';
option.grid.top = 126;
if (axisName === 2 && this.fullScreen) {
option.grid.right = 140;
}
option.yAxis.inverse = true;
const that = this;
option.yAxis.axisLabel.formatter = function(value) {
return that.yAxisFormatter(value);
};
} else if (this.viewName === 0) {
option.color = colorArr;
option.series = [];
oriData.seriesData.forEach((k) => {
option.series.push({
type: 'line',
symbol: 'none',
lineStyle: {
width: 1,
},
data: k.slice(1, -1),
});
});
}
return option;
},
/**
* Expand/Collapse in full screen
*/
toggleFullScreen() {
this.removeTooltip();
if (!this.fullScreen) {
if (this.axisName === 2) {
// this.charObj.setOption({grid: {right: 140}});
this.charOption.grid.right = 140;
}
this.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor =
'#3E98C5';
} else {
// this.charObj.setOption({grid: {right: 40}});
this.charOption.grid.right = 40;
this.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor =
'#6D7278';
}
this.charObj.setOption(this.charOption);
this.$emit('toggleFullScreen');
},
/**
* remove tooltip
*/
removeTooltip() {
if (this.zr) {
if (this.zrDrawElement.hoverDots) {
this.zrDrawElement.hoverDots.forEach((dot) => this.zr.remove(dot));
}
if (this.zrDrawElement.hoverLine) {
this.zr.remove(this.zrDrawElement.hoverLine);
}
if (this.zrDrawElement.tooltip) {
this.zr.remove(this.zrDrawElement.tooltip);
}
if (this.zrDrawElement.tooltipY) {
this.zr.remove(this.zrDrawElement.tooltipY);
}
if (this.zrDrawElement.tooltipX) {
this.zr.remove(this.zrDrawElement.tooltipX);
}
}
},
/**
* Calculate polygon points
* @param {Number} dataIndex
* @param {Object} getCoord
* @param {Number} yValueMapHeight
* @return {Array} Array of ploygon points
*/
makePolyPoints(dataIndex, getCoord, yValueMapHeight) {
const points = [];
const rawData = this.oriData.seriesData;
const maxZ = this.oriData.maxZ;
const minZ = this.oriData.minZ;
for (let i = 0; i < rawData[dataIndex].length; ) {
const x = this.getValue(rawData, dataIndex, i++);
const y = this.getValue(rawData, dataIndex, i++);
const z = this.getValue(rawData, dataIndex, i++);
const pt = getCoord([x, y]);
// linear map in z axis
if (maxZ !== minZ) {
pt[1] -= ((z - minZ) / (maxZ - minZ)) * yValueMapHeight;
}
points.push(pt);
}
return points;
},
/**
* get convert point
* @param {Array} pt value
* @return {Array}
*/
getCoord(pt) {
return this.charObj.convertToPixel('grid', pt);
},
/**
* Formate Y coordinate display
* @param {Number} value
* @return {Object}
*/
yAxisFormatter(value) {
let data = '';
const filter = this.fullData.filter((k) => k.step === value);
if (filter.length) {
if (this.axisName === 2) {
data = this.fullScreen
? this.dealrelativeTime(
new Date(filter[0].wall_time * 1000).toString(),
)
: [];
} else if (this.axisName === 1) {
data = `${(filter[0].relative_time / 3600).toFixed(3)}h`;
} else {
data = filter[0].step;
}
}
return data;
},
/**
* Formate time display
* @param {Onject} time
* @return {String} Formatted time
*/
dealrelativeTime(time) {
const arr = time.split(' ');
const str = arr[0] + ' ' + arr[1] + ' ' + arr[2] + ',' + ' ' + arr[4];
return str;
},
/**
* Mouse move event
* @param {Object} e Original event
*/
mousemoveEvent(e) {
const unit = 's';
const nearestIndex = this.findNearestValue([e.offsetX, e.offsetY]);
if (
nearestIndex &&
nearestIndex.yIndex !== null &&
nearestIndex.binIndex !== null
) {
const {binIndex, yIndex} = nearestIndex;
const chartData = this.fullData;
const hoveredItem = chartData[yIndex];
const p = Math.max(0, d3.precisionRound(0.01, 1.01) - 1);
const yValueFormat = d3.format(`.${p}e`);
const gridRect = this.charObj
.getModel()
.getComponent('grid', 0)
.coordinateSystem.getRect();
const gridRectY = gridRect.y - 10;
let linePoints = [];
if (!hoveredItem || !hoveredItem.items[binIndex]) {
return;
}
if (!this.chartTipFlag) {
this.chartTipFlag = true;
this.$emit('chartTipFlagChange', this.chartTipFlag);
}
if (this.viewName === 1 && yIndex !== null) {
linePoints = this.makePolyPoints(yIndex, this.getCoord, gridRectY);
} else if (this.viewName === 0 && hoveredItem.items) {
hoveredItem.items.forEach((item) => {
linePoints.push(this.getCoord([item[2], item[3]]));
});
}
this.zrDrawElement.hoverLine = new echarts.graphic.Polyline({
silent: true,
shape: {
points: linePoints.slice(1, -1),
},
z: 999,
});
this.zr.add(this.zrDrawElement.hoverLine);
this.zrDrawElement.tooltip = new echarts.graphic.Text({});
let itemX;
const x = hoveredItem.items[binIndex][2];
let z = 0;
chartData.forEach((dataItem, index) => {
const y = dataItem.step;
const pt = this.getCoord([x, y]);
if (index === yIndex) {
z = hoveredItem.items[binIndex][3];
} else {
const items = dataItem.items;
for (let k = 1; k < items.length - 1; k++) {
const nextX = items[k + 1][2];
const nextZ = items[k + 1][3];
if (items[k][2] === x) {
z = items[k][3];
break;
} else if (items[k][2] < x && nextX > x) {
const proportionX = (x - items[k][2]) / (nextX - items[k][2]);
z = (nextZ - items[k][3]) * proportionX + items[k][3];
break;
}
}
}
itemX = pt[0];
const circleOption = {
z: 1000,
};
if (this.viewName === 1) {
pt[1] -=
((z - this.oriData.minZ) /
(this.oriData.maxZ - this.oriData.minZ)) *
gridRectY;
circleOption.shape = {
cx: itemX,
cy: pt[1],
r: 1.5,
};
} else {
circleOption.shape = {
cx: 0,
cy: 0,
r: 1.5,
};
circleOption.position = this.charObj.convertToPixel('grid', [x, z]);
}
const dot = new echarts.graphic.Circle(circleOption);
this.zr.add(dot);
this.zrDrawElement.hoverDots.push(dot);
});
this.zrDrawElement.tooltip = new echarts.graphic.Text({});
let htmlStr = '';
const hoveredAxis = hoveredItem.items[binIndex][3];
htmlStr = `<td>${
hoveredAxis.toString().length >= 6
? yValueFormat(hoveredAxis)
: hoveredAxis
}</td><td style="text-align:center;">${hoveredItem.step}</td><td>${(
hoveredItem.relative_time / 1000
).toFixed(3)}${unit}</td><td>${this.dealrelativeTime(
new Date(hoveredItem.wall_time * 1000).toString(),
)}</td>`;
const dom = document.querySelector('#tipTr');
dom.innerHTML = htmlStr;
const chartElement = document.getElementById(this.itemId);
if (chartElement) {
if (!this.fullScreen) {
const chartWidth =
chartElement.parentNode.parentNode.parentNode.parentNode
.clientWidth;
const chartHeight =
chartElement.parentNode.parentNode.parentNode.parentNode
.clientHeight;
const left =
chartElement.parentNode.parentNode.parentNode.parentNode
.offsetLeft;
const top =
chartElement.parentNode.parentNode.parentNode.parentNode
.offsetTop;
const echartTip = document.querySelector('#echartTip');
echartTip.style.top = `${top + chartHeight - 60}px`;
if (left > echartTip.clientWidth) {
echartTip.style.left = `${left - echartTip.clientWidth}px`;
} else {
echartTip.style.left = `${left + chartWidth}px`;
}
} else {
const width = document.querySelector('#echartTip').clientWidth;
const height = document.querySelector('#echartTip').clientHeight;
const screenWidth = document.body.scrollWidth;
const screenHeight = document.body.scrollHeight;
const scrollTop = document.querySelector('.cl-show-data-content')
.scrollTop;
const offsetTop = document.querySelector('.cl-show-data-content')
.offsetTop;
if (
height + e.event.y + 20 > screenHeight &&
screenHeight > height
) {
document.querySelector('#echartTip').style.top = `${e.event.y +
scrollTop -
height -
20 -
offsetTop}px`;
} else {
document.querySelector('#echartTip').style.top = `${e.event.y +
scrollTop +
20 -
offsetTop}px`;
}
if (width + e.event.x + 50 > screenWidth && screenWidth > width) {
document.querySelector('#echartTip').style.left = `${e.event.x -
width -
20}px`;
} else {
document.querySelector('#echartTip').style.left = `${e.event.x +
20}px`;
}
}
}
this.zrDrawElement.tooltipX = new echarts.graphic.Text({
position: [itemX, gridRect.y + gridRect.height],
style: {
text:
x.toString().length >= 6
? x.toExponential(3)
: Math.round(x * 1000) / 1000,
textFill: '#fff',
textAlign: 'center',
fontSize: 12,
textBackgroundColor: '#333',
textBorderWidth: 2,
textPadding: [5, 7],
rich: {},
},
z: 2000,
});
this.zr.add(this.zrDrawElement.tooltipX);
if (this.viewName === 1 && linePoints && linePoints.length) {
let text = '';
if (yIndex !== null) {
text = this.yAxisFormatter(hoveredItem.step);
}
this.zrDrawElement.tooltipY = new echarts.graphic.Text({
position: [
gridRect.x + gridRect.width,
linePoints[linePoints.length - 1][1],
],
style: {
text: text,
textFill: '#fff',
textVerticalAlign: 'middle',
fontSize: 12,
textBackgroundColor: '#333',
textBorderWidth: 2,
textPadding: [5, 7],
rich: {},
},
z: 2000,
});
this.zr.add(this.zrDrawElement.tooltipY);
}
}
},
/**
* find nearest value
* @param {Array} eventPoint value
* @return {Object}
*/
findNearestValue(eventPoint) {
if (!eventPoint || !eventPoint.length || !this.charObj || !this.oriData) {
return;
}
const value = this.charObj.convertFromPixel('grid', eventPoint);
if (!value || !value.length) {
return;
}
let binIndex = null;
let yIndex = null;
let nearestX = Infinity;
let nearestY = -Infinity;
let nearestYData = Infinity;
const gridRect = this.charObj
.getModel()
.getComponent('grid', 0)
.coordinateSystem.getRect();
const gridRectY = gridRect.y - 10;
const x = value[0];
this.fullData.forEach((dataItem, i) => {
let distY;
let yAxis;
for (let k = 0; k < dataItem.items.length - 1; k++) {
const item = dataItem.items[k];
const itemNext = dataItem.items[k + 1];
const nextX = itemNext[2];
const nextZ = itemNext[3];
if (item.length >= 4) {
if (item[2] < x && nextX >= x) {
const proportionX = (x - item[2]) / (nextX - item[2]);
yAxis = (nextZ - item[3]) * proportionX + item[3];
distY = Math.abs(value[1] - yAxis);
break;
}
}
}
if (this.viewName === 0 && distY < nearestYData) {
nearestYData = distY;
yIndex = i;
} else if (this.viewName === 1) {
const pt = this.getCoord([x, dataItem.step]);
const ptStep = pt[1];
pt[1] -=
((yAxis - this.oriData.minZ) /
(this.oriData.maxZ - this.oriData.minZ)) *
gridRectY;
if (
eventPoint[1] > pt[1] &&
eventPoint[1] < ptStep &&
ptStep > nearestY
) {
nearestY = ptStep;
yIndex = i;
}
}
});
if (yIndex === null && this.viewName === 1) {
this.fullData.forEach((item, index) => {
if (index > value[1]) {
yIndex = yIndex === null ? index : Math.min(yIndex, index);
}
});
}
if (yIndex !== null) {
const yData = this.fullData[yIndex].items;
yData.forEach((ele, index) => {
const distX = Math.abs(ele[2] - value[0]);
if (distX < nearestX) {
nearestX = distX;
binIndex = index;
}
});
binIndex =
binIndex === 0
? 1
: binIndex === yData.length - 1
? yData.length - 2
: binIndex;
}
return {
binIndex,
yIndex,
};
},
/**
* Calculate gradient color
* @param {String} startColor
* @param {String} endColor
* @param {Number} step
* @return {Array} Array of gradient color
*/
getGrientColor(startColor, endColor, step) {
const startRgb = this.formatColor(startColor);
const endRgb = this.formatColor(endColor);
const gapRgbR = (endRgb[0] - startRgb[0]) / step;
const gapRgbG = (endRgb[1] - startRgb[1]) / step;
const gapRgbB = (endRgb[2] - startRgb[2]) / step;
const colorResult = [];
for (let i = 0; i < step; i++) {
const sR = parseInt(gapRgbR * i + startRgb[0]);
const sG = parseInt(gapRgbG * i + startRgb[1]);
const sB = parseInt(gapRgbB * i + startRgb[2]);
const hex = this.formatColorToHex(`rgb(${sR},${sG},${sB})`);
colorResult.push(hex);
}
return colorResult;
},
/**
* Converts a color string to recognizable format
* @param {String} str Color string
* @return {String}
*/
formatColor(str) {
if (!str) {
return;
}
const colorReg = /^([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
let colorStr = str.toLowerCase().slice(1);
if (colorReg.test(colorStr)) {
let colorStrNew = '';
if (colorStr.length === 3) {
for (let i = 0; i < 3; i++) {
colorStrNew += colorStrNew
.slice(i, i + 1)
.concat(colorStrNew.slice(i, i + 1));
}
colorStr = colorStrNew;
}
const colorFormat = [];
for (let i = 0; i < 6; i += 2) {
colorFormat.push(parseInt(`0x${colorStr.slice(i, i + 2)}`));
}
return colorFormat;
} else {
return colorStr;
}
},
/**
* Converts rgb color string to hex
* @param {String} rgb Rgb color
* @return {String} Hex color
*/
formatColorToHex(rgb) {
const regRgb = /^(rgb|RGB)/g;
if (regRgb.test(rgb)) {
const colorSplit = rgb.replace(/(?:(|)|rgb|RGB)*/g, '').split(',');
let hexStr = '';
for (let i = 0; i < colorSplit.length; i++) {
let hexItem = Number(colorSplit[i]).toString(16);
hexItem = hexItem < 10 ? `0${hexItem}` : hexItem;
if (hexItem === '0') {
hexItem += hexItem;
}
hexStr += hexItem;
}
if (hexStr.length !== 6) {
hexStr = rgb;
}
return hexStr;
}
},
/**
* Get value
* @param {Object} seriesData
* @param {Number} dataIndex
* @param {Number} i
* @return {Number}
*/
getValue(seriesData, dataIndex, i) {
return seriesData[dataIndex][i];
},
/**
* Unbing event
*/
clearZrData() {
if (this.zr) {
this.removeTooltip();
this.zr.off('mouseout', 'mousemove');
this.zr = null;
}
},
/**
* Update histogram data
*/
updateHistogramData() {
this.$nextTick(() => {
this.formatDataToChar();
this.updateSampleData();
this.sampleEventBind();
});
},
},
destroyed() {
this.clearZrData();
},
};
</script>
<style lang="scss">
.cl-histogram-container {
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
.data-show-container {
width: 100%;
flex: 1;
.data-item {
width: 100%;
height: 100%;
}
}
}
</style>
...@@ -21,7 +21,9 @@ ...@@ -21,7 +21,9 @@
}, },
"symbols": { "symbols": {
"leftbracket": "(", "leftbracket": "(",
"rightbracket": ")" "rightbracket": ")",
"point": "·",
"slashes": "/"
}, },
"header": { "header": {
"refreshData": "刷新数据", "refreshData": "刷新数据",
...@@ -166,6 +168,14 @@ ...@@ -166,6 +168,14 @@
"dataMap": { "dataMap": {
"titleText": "数据图" "titleText": "数据图"
}, },
"tensors": {
"titleText": "张量",
"dimension": "形状:",
"tensorType": "数据类型:",
"viewTypeTitle": "视图",
"chartViewType": "表格",
"histogramViewType": "直方图"
},
"graph": { "graph": {
"titleText": "计算图", "titleText": "计算图",
"downloadPic": "下载", "downloadPic": "下载",
...@@ -381,7 +391,11 @@ ...@@ -381,7 +391,11 @@
"selectAll": "全选", "selectAll": "全选",
"tagFilterPlaceHolder": "请输入需要的标签(支持正则表达式)", "tagFilterPlaceHolder": "请输入需要的标签(支持正则表达式)",
"open": "展开", "open": "展开",
"close": "折叠" "close": "折叠",
"gridIncorrectDataError": "当前只支持最多二维数组的展示",
"gridAccuracy": "保留小数位",
"inCorrectInput": "无效输入",
"gridTableNoData": "表格无数据"
}, },
"error": { "error": {
"50540000": "系统错误", "50540000": "系统错误",
......
...@@ -22,7 +22,9 @@ import ElementUI from 'element-ui'; ...@@ -22,7 +22,9 @@ import ElementUI from 'element-ui';
import './assets/css/element.css'; import './assets/css/element.css';
import './assets/css/reset.scss'; import './assets/css/reset.scss';
import i18n from './i18n'; import i18n from './i18n';
import $ from 'jquery';
window.$ = window.jQuery = $;
Vue.use(ElementUI); Vue.use(ElementUI);
Vue.prototype.$bus = new Vue(); Vue.prototype.$bus = new Vue();
......
...@@ -54,6 +54,10 @@ export default new Router({ ...@@ -54,6 +54,10 @@ export default new Router({
path: '/train-manage/histogram', path: '/train-manage/histogram',
component: () => import('./views/train-manage/histogram.vue'), component: () => import('./views/train-manage/histogram.vue'),
}, },
{
path: '/train-manage/tensor',
component: () => import('./views/train-manage/tensor.vue'),
},
{ {
path: '/train-manage/graph', path: '/train-manage/graph',
component: () => import('./views/train-manage/graph.vue'), component: () => import('./views/train-manage/graph.vue'),
......
...@@ -66,6 +66,18 @@ export default { ...@@ -66,6 +66,18 @@ export default {
}); });
}, },
// query tensors sample
getTensorsSample(params) {
return axios({
method: 'get',
url: 'v1/mindinsight/datavisual/tensors',
params: params,
headers: {
ignoreError: true,
},
});
},
// query graph data // query graph data
queryGraphData(params) { queryGraphData(params) {
return axios({ return axios({
......
...@@ -33,6 +33,7 @@ export default new Vuex.Store({ ...@@ -33,6 +33,7 @@ export default new Vuex.Store({
// multiSelevtGroup component count // multiSelevtGroup component count
multiSelectedGroupCount: 0, multiSelectedGroupCount: 0,
tableId: 0, tableId: 0,
componentsCount: 0,
}, },
mutations: { mutations: {
// set cancelTokenArr // set cancelTokenArr
...@@ -76,6 +77,9 @@ export default new Vuex.Store({ ...@@ -76,6 +77,9 @@ export default new Vuex.Store({
increaseTableId(state) { increaseTableId(state) {
state.tableId++; state.tableId++;
}, },
componentsNum(state) {
state.componentsCount++;
},
}, },
actions: {}, actions: {},
}); });
...@@ -90,7 +90,8 @@ limitations under the License. ...@@ -90,7 +90,8 @@ limitations under the License.
<div class="chars-container"> <div class="chars-container">
<div class="char-item-content" <div class="char-item-content"
:id="sampleItem.domId"></div> :id="sampleItem.domId"></div>
<div class="tag-title">{{sampleItem.tagName}}</div> <div class="tag-title"
:title="sampleItem.tagName">{{sampleItem.tagName}}</div>
</div> </div>
</div> </div>
</div> </div>
...@@ -1325,16 +1326,17 @@ export default { ...@@ -1325,16 +1326,17 @@ export default {
sampleObject.fullScreen = !sampleObject.fullScreen; sampleObject.fullScreen = !sampleObject.fullScreen;
if (sampleObject.fullScreen) { if (sampleObject.fullScreen) {
if (this.curAxisName === 2) { if (this.curAxisName === 2) {
sampleObject.charObj.setOption({grid: {right: 140}}); sampleObject.charOption.grid.right = 140;
} }
sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor =
'#3E98C5'; '#3E98C5';
} else { } else {
sampleObject.charObj.setOption({grid: {right: 40}}); sampleObject.charOption.grid.right = 40;
sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = sampleObject.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor =
'#6D7278'; '#6D7278';
} }
setTimeout(() => { setTimeout(() => {
sampleObject.charObj.setOption(sampleObject.charOption);
sampleObject.charObj.resize(); sampleObject.charObj.resize();
document.getElementById(sampleObject.domId).scrollIntoView(); document.getElementById(sampleObject.domId).scrollIntoView();
}, 0); }, 0);
......
<!--
Copyright 2020 Huawei Technologies Co., Ltd.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.
-->
<template>
<div class="cl-tensor-manage">
<div class="tensor-bk">
<!-- Title area -->
<div class="cl-title cl-tensor-title">
<div class="cl-title-left">{{$t('tensors.titleText')}}</div>
<div class="cl-title-right">
<div class="cl-close-btn"
@click="jumpToTrainDashboard">
<img src="@/assets/images/close-page.png" />
</div>
</div>
</div>
<!-- List item operation area -->
<div class="cl-tensor-operate-content">
<multiselectGroupComponents ref="multiselectGroupComponents"
:checkListArr="tagList"
@selectedChange="tagSelectedChanged"></multiselectGroupComponents>
</div>
<!-- Area for selecting a view type -->
<div class="cl-tensor-view-type-select-content">
<div class="view-title">{{$t('tensors.viewTypeTitle')}}</div>
<el-radio-group v-model="curDataType"
fill="#00A5A7"
text-color="#FFFFFF"
size="small"
@change="dataTypeChange">
<el-radio-button :label="0">{{$t('tensors.chartViewType')}}</el-radio-button>
<el-radio-button :label="1">{{$t('tensors.histogramViewType')}}</el-radio-button>
</el-radio-group>
<div class="view-title"
v-if="!!curDataType">{{$t('histogram.viewType')}}
</div>
<el-radio-group v-model="curViewName"
v-if="!!curDataType"
fill="#00A5A7"
text-color="#FFFFFF"
size="small"
@change="viewTypeChange">
<el-radio-button :label="0">{{$t('histogram.overlay')}}</el-radio-button>
<el-radio-button :label="1">{{$t('histogram.offset')}}</el-radio-button>
</el-radio-group>
<div class="view-title"
v-if="!!curViewName && !!curDataType">
{{$t('histogram.xAxisTitle')}}
</div>
<el-radio-group v-model="curAxisName"
fill="#00A5A7"
text-color="#FFFFFF"
size="small"
v-if="!!curDataType && !!curViewName"
:disabled="curViewName === 0"
@change="timeTypeChange">
<el-radio-button :label="0">{{$t('histogram.step')}}</el-radio-button>
<el-radio-button :label="1">{{$t('histogram.relativeTime')}}</el-radio-button>
<el-radio-button :label="2">{{$t('histogram.absoluteTime')}}</el-radio-button>
</el-radio-group>
</div>
<!-- Content display area -->
<div class="cl-show-data-content">
<!-- No data -->
<div class="image-noData"
v-if="initOver && !originDataArr.length">
<div>
<img :src="require('@/assets/images/nodata.png')" />
</div>
<div class="noData-text">{{$t('public.noData')}}</div>
</div>
<!-- Data -->
<div class="data-content"
v-if="!!originDataArr.length">
<div id="echartTip"
v-show="chartTipFlag">
<table class="char-tip-table borderspacing3">
<tr>
<td>{{$t('histogram.centerValue')}}</td>
<td>{{$t('histogram.step')}}</td>
<td>{{$t('histogram.relativeTime')}}</td>
<td>{{$t('histogram.absoluteTime')}}</td>
</tr>
<tr id="tipTr"></tr>
</table>
</div>
<div class="sample-content"
v-for="sampleItem in originDataArr"
:key="sampleItem.domId"
:class="sampleItem.fullScreen ? 'char-full-screen' : ''"
v-show="sampleItem.show">
<div class="chars-container">
<!-- components -->
<gridTableComponents v-if="!curDataType"
:ref="sampleItem.ref"
:fullScreen="sampleItem.fullScreen"
@martixFilterChange="filterChange($event, sampleItem)"
@toggleFullScreen="toggleFullScreen(sampleItem)"
:fullData="sampleItem.curData"></gridTableComponents>
<histogramUntil v-else
:ref="sampleItem.ref"
:fullScreen="sampleItem.fullScreen"
@chartTipFlagChange="chartTipFlagChange"
@toggleFullScreen="toggleFullScreen(sampleItem)"
:viewName="curViewName"
:axisName="curAxisName"
:fullData="sampleItem.curData"></histogramUntil>
</div>
<!-- Information display area -->
<div class="sample-data-show"
v-if="!curDataType">
<div class="tensor-demension"
:title="sampleItem.curDims">
{{$t('tensors.dimension')}}
<span>{{sampleItem.curDims}}</span>
</div>
<div class="tensor-type"
:title="sampleItem.curDataType">
{{$t('tensors.tensorType')}} {{sampleItem.curDataType}}
</div>
<!-- Current step information -->
<div class="sample-operate-info select-disable">
<span class="step-info"
:title="sampleItem.curStep">{{$t('images.step')}}{{sampleItem.curStep}}</span>
<span class="time-info"
:title="sampleItem.curTime">{{sampleItem.curTime}}</span>
</div>
<el-slider class="step-slider"
v-model="sampleItem.sliderValue"
:step="1"
:max="sampleItem.totalStepNum"
@input="sliderChange(sampleItem.sliderValue, sampleItem)"
:show-tooltip="false"
:disabled="sampleItem.totalStepNum === 0">
</el-slider>
</div>
<div class="tag-title"
:title="sampleItem.tagName">{{sampleItem.tagName}}
</div>
</div>
</div>
</div>
<!-- Page number area -->
<div class="pagination-content"
v-if="originDataArr.length">
<el-pagination @current-change="currentPageChange"
:current-page="pageIndex + 1"
:page-sizes="pageSizes"
:page-size="pageNum"
layout="total, prev, pager, next, jumper"
:total="curFilterSamples.length">
</el-pagination>
</div>
</div>
</div>
</template>
<script>
import multiselectGroupComponents from '../../components/multiselectGroup.vue';
import gridTableComponents from '../../components/gridTableSimple';
import histogramUntil from '../../components/histogramUnit';
import RequestService from '../../services/request-service';
export default {
data() {
return {
tagList: [], // Tag list.
trainingJobId: this.$route.query.train_id, // ID of the current training job.
originDataArr: [], // List of all data.
initOver: false, // Indicates whether the initialization is complete.
curFullTagDic: {}, // Dictionary that contains all the current tags.
multiSelectedTagNames: {}, // Dictionary for storing the name of the selected tags.
curFilterSamples: [], // List of data that meet the current filter criteria.
curPageArr: [], // Data list on the current page.
pageIndex: 0, // Current page number.
pageSizes: [6], // The number of records on each page is optional.
pageNum: 6, // Number of records on each page.
isReloading: false, // Manually refresh.
autoUpdateTimer: null, // Automatic refresh timer.
dataTypeChangeTimer: null, // View switching timer
viewNameChangeTimer: null, // ViewName switching timer
axisNameChangeTimer: null, // Vertical axis switching timer
curDataType: 0, // current data type
curViewName: 1, // current histogram view type
curAxisName: 0, // current histogran axis type
chartTipFlag: false, // Wheather to display tips of the histogram
};
},
computed: {
/**
* Global refresh switch
* @return {Boolean}
*/
isReload() {
return this.$store.state.isReload;
},
/**
* Automatic refresh switch
* @return {Boolean}
*/
isTimeReload() {
return this.$store.state.isTimeReload;
},
/**
* Automatic refresh value
* @return {Boolean}
*/
timeReloadValue() {
return this.$store.state.timeReloadValue;
},
},
components: {
multiselectGroupComponents,
gridTableComponents,
histogramUntil,
},
watch: {
/**
* Global refresh switch listener
* @param {Boolean} newVal Value after change
* @param {Boolean} oldVal Value before change
*/
isReload(newVal, oldVal) {
if (newVal) {
this.isReloading = true;
// Automatic refresh and retiming
if (this.isTimeReload) {
this.autoUpdateSamples();
}
this.updateAllData(false);
}
},
/**
* Automatic refresh switch listener
* @param {Boolean} newVal Value after change
* @param {Boolean} oldVal Value before change
*/
isTimeReload(newVal, oldVal) {
if (newVal) {
// Enable automatic refresh
this.autoUpdateSamples();
} else {
// Disable automatic refresh
this.stopUpdateSamples();
}
},
/**
* The refresh time is changed
*/
timeReloadValue() {
this.autoUpdateSamples();
},
},
destroyed() {
window.removeEventListener('resize', this.resizeCallback);
// Disable the automatic refresh function
if (this.autoUpdateTimer) {
clearInterval(this.autoUpdateTimer);
this.autoUpdateTimer = null;
}
// Stop refreshing
if (this.isReloading) {
this.$store.commit('setIsReload', false);
this.isReloading = false;
}
// Cancel the delay
this.originDataArr.forEach((sampleItem) => {
if (sampleItem.sliderChangeTimer) {
clearTimeout(sampleItem.sliderChangeTimer);
sampleItem.sliderChangeTimer = null;
}
});
if (this.charResizeTimer) {
clearTimeout(this.charResizeTimer);
this.charResizeTimer = null;
}
if (this.dataTypeChangeTimer) {
clearTimeout(this.dataTypeChangeTimer);
this.dataTypeChangeTimer = null;
}
if (this.viewNameChangeTimer) {
this.clearTimeout(this.viewNameChangeTimer);
this.viewNameChangeTimer = null;
}
if (this.axisNameChangeTimer) {
this.clearTimeout(this.axisNameChangeTimer);
this.axisNameChangeTimer = null;
}
},
mounted() {
this.init();
window.addEventListener('resize', this.resizeCallback, false);
},
methods: {
/**
* Callback after the window size is changed
*/
resizeCallback() {
if (this.charResizeTimer) {
clearTimeout(this.charResizeTimer);
this.charResizeTimer = null;
}
this.charResizeTimer = setTimeout(() => {
this.curPageArr.forEach((sampleItem) => {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].resizeView();
}
});
}, 500);
},
/**
* Initialize
*/
init() {
this.getOriginData();
if (this.isTimeReload) {
this.autoUpdateSamples();
}
},
/**
* jump back to train dashboard
*/
jumpToTrainDashboard() {
this.$router.push({
path: '/train-manage/training-dashboard',
query: {
id: this.trainingJobId,
},
});
},
/**
* Obtains original data.
*/
getOriginData() {
const params = {
plugin_name: 'tensor',
train_id: this.trainingJobId,
};
RequestService.getSingleTrainJob(params)
.then((res) => {
if (
!res ||
!res.data ||
!res.data.train_jobs ||
!res.data.train_jobs.length
) {
this.initOver = true;
return;
}
const data = res.data.train_jobs[0];
if (!data.tags) {
return;
}
const tagList = [];
const dataList = [];
data.tags.forEach((tagName, tagIndex) => {
if (!this.curFullTagDic[tagName]) {
this.curFullTagDic[tagName] = true;
tagList.push({
label: tagName,
checked: true,
show: true,
});
dataList.push({
tagName: tagName,
summaryName: this.trainingJobId,
show: false,
sliderValue: 0,
newDataFlag: true,
totalStepNum: 0,
curStep: '',
curTime: '',
curDims: '',
curDataType: '',
fullScreen: false,
ref: tagName,
sliderChangeTimer: null,
curData: [],
formateData: [],
fullData: [],
filterStr: '',
curMartixShowSliderValue: 0,
});
}
});
this.tagList = tagList;
this.originDataArr = dataList;
this.$nextTick(() => {
this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic();
this.initOver = true;
this.updateTagInPage();
});
}, this.requestErrorCallback)
.catch((e) => {
this.initOver = true;
this.$message.error(this.$t('public.dataError'));
});
},
/**
* Table dimension change callback
* @param {Array} data Dimension array after change
* @param {Object} sampleItem The object that is being operated
*/
filterChange(data, sampleItem) {
sampleItem.filterStr = `[${data.toString()}]`;
this.freshtMartixData(sampleItem);
},
/**
* The selected label is changed.
* @param {Object} selectedItemDict Dictionary containing the selected tags
*/
tagSelectedChanged(selectedItemDict) {
if (!selectedItemDict) {
return;
}
this.multiSelectedTagNames = selectedItemDict;
// Reset to the first page
this.pageIndex = 0;
this.updateTagInPage();
},
/**
* Page number change event
* @param {Number} pageIndex Changed page number
*/
currentPageChange(pageIndex) {
this.pageIndex = pageIndex - 1;
// Load the data on the current page
this.getCurPageDataArr();
},
/**
* Obtains data on the current page
* @param {Boolean} noPageDataNumChange No new data is added or deleted
*/
getCurPageDataArr(noPageDataNumChange) {
// Clear the previous page
if (!noPageDataNumChange) {
this.curPageArr.forEach((sampleItem) => {
sampleItem.show = false;
if (this.curDataType === 1 && this.curViewName === 1) {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem.clearZrData();
}
}
});
}
// This interface is used to obtain the current page group and hide the current page group.
const startIndex = this.pageIndex * this.pageNum;
const endIndex = startIndex + this.pageNum;
const curPageArr = [];
for (let i = startIndex; i < endIndex; i++) {
const sampleItem = this.curFilterSamples[i];
if (sampleItem) {
sampleItem.show = true;
curPageArr.push(sampleItem);
}
}
this.curPageArr = curPageArr;
// Update the data information on the current page
this.freshCurPageData();
},
/**
* Refresh the data on the current page
*/
freshCurPageData() {
this.curPageArr.forEach((sampleItem, index) => {
if (!sampleItem || !sampleItem.tagName) {
return;
}
const dataType = this.curDataType;
if (dataType) {
this.getHistogramData(sampleItem);
} else {
this.getMartixData(sampleItem);
}
});
},
/**
* Initialize the current dimension selection
* @param {Array} array Array containing the current number of dimensions
* @return {Object} Current dimension selection
*/
initFilterStr(array) {
if (!array) {
return [];
}
const countLinit = array.length - 2;
const tempArr = [];
for (let i = 0; i < array.length; i++) {
tempArr.push(i >= countLinit ? ':' : '0');
}
return `[${tempArr.toString()}]`;
},
/**
* Obtains histogram data
* @param {Object} sampleItem The object that is being operated
*/
getHistogramData(sampleItem) {
const params = {
train_id: this.trainingJobId,
tag: sampleItem.tagName,
detail: 'histogram',
};
RequestService.getTensorsSample(params).then((res) => {
if (!res || !res.data || !this.curDataType) {
return;
}
if (!res.data.tensors || !res.data.tensors.length) {
return;
}
const resData = JSON.parse(JSON.stringify(res.data.tensors[0]));
sampleItem.summaryName = resData.train_id;
// sampleItem.fullData = resData;
sampleItem.curData = this.formHistogramOriData(resData);
this.$nextTick(() => {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].updateHistogramData();
}
});
});
},
/**
* Obtain table data
* @param {Object} sampleItem The object that is being operated
*/
getMartixData(sampleItem) {
const params = {
train_id: this.trainingJobId,
tag: sampleItem.tagName,
detail: 'stats',
};
RequestService.getTensorsSample(params).then(
(res) => {
if (!res || !res.data || this.curDataType) {
return;
}
if (!res.data.tensors.length) {
return;
}
const resData = JSON.parse(JSON.stringify(res.data.tensors[0]));
sampleItem.summaryName = resData.train_id;
if (!resData.values.length) {
sampleItem.fullData = [];
sampleItem.formateData = [];
sampleItem.curData = [];
sampleItem.curTime = '';
sampleItem.curDims = '';
sampleItem.curDataType = '';
sampleItem.curStep = '';
sampleItem.sliderValue = 0;
sampleItem.totalStepNum = 0;
this.clearMartixData();
return;
}
const oldTotalStepNum = sampleItem.totalStepNum;
sampleItem.totalStepNum = resData.values.length - 1;
if (sampleItem.sliderValue === oldTotalStepNum) {
sampleItem.sliderValue = sampleItem.totalStepNum;
}
if (sampleItem.sliderValue > sampleItem.totalStepNum) {
sampleItem.sliderValue = sampleItem.totalStepNum;
}
sampleItem.fullData = resData.values;
sampleItem.formateData = sampleItem.fullData[sampleItem.sliderValue];
const oldStep = sampleItem.curStep;
sampleItem.curStep = sampleItem.formateData.step;
if (!sampleItem.filterStr) {
sampleItem.filterStr = this.initFilterStr(
sampleItem.formateData.value.dims,
);
sampleItem.newDataFlag = true;
}
if (sampleItem.curStep !== oldStep) {
sampleItem.newDataFlag = true;
}
sampleItem.curTime = this.dealrelativeTime(
new Date(sampleItem.formateData.wall_time * 1000).toString(),
);
sampleItem.curDataType = sampleItem.formateData.value.data_type;
sampleItem.curDims = JSON.stringify(
sampleItem.formateData.value.dims,
);
this.freshtMartixData(sampleItem);
},
() => {
sampleItem.fullData = [];
sampleItem.formateData = [];
sampleItem.curData = [];
sampleItem.curTime = '';
sampleItem.curDims = '';
sampleItem.curDataType = '';
sampleItem.curStep = '';
sampleItem.sliderValue = 0;
sampleItem.totalStepNum = 0;
this.clearMartixData(sampleItem);
},
);
},
/**
* Refresh table display
* @param {Object} sampleItem The object that is being operated
*/
freshtMartixData(sampleItem) {
const params = {
train_id: this.trainingJobId,
tag: sampleItem.tagName,
detail: 'data',
step: sampleItem.curStep,
dims: sampleItem.filterStr,
};
sampleItem.curMartixShowSliderValue = sampleItem.sliderValue;
RequestService.getTensorsSample(params).then(
(res) => {
if (!res || !res.data || this.curDataType) {
return;
}
if (!res.data.tensors.length) {
return;
}
const resData = res.data.tensors[0];
const curStepData = resData.values[0];
let statistics = {};
if (curStepData) {
sampleItem.curData =
curStepData.value.data instanceof Array
? curStepData.value.data
: [curStepData.value.data];
statistics = curStepData.value.statistics;
} else {
sampleItem.curData = [[]];
}
let elementItem = null;
this.$nextTick(() => {
elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].updateGridData(
sampleItem.newDataFlag,
curStepData.value.dims,
statistics,
sampleItem.filterStr,
);
}
sampleItem.newDataFlag = false;
});
},
() => {
this.clearMartixData(sampleItem);
},
);
},
/**
* Clear table display
* @param {Object} sampleItem The object that is being operated
*/
clearMartixData(sampleItem) {
sampleItem.curData = [];
sampleItem.newDataFlag = true;
let elementItem = null;
this.$nextTick(() => {
elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].updateGridData();
}
});
},
/**
* The dataType display type is changed
*/
dataTypeChange() {
if (this.dataTypeChangeTimer) {
clearTimeout(this.dataTypeChangeTimer);
this.dataTypeChangeTimer = null;
}
this.dataTypeChangeTimer = setTimeout(() => {
this.freshCurPageData();
}, 500);
},
/**
* The time display type is changed
* @param {Number} val Current mode
*/
timeTypeChange(val) {
if (this.axisNameChangeTimer) {
clearTimeout(this.axisNameChangeTimer);
this.axisNameChangeTimer = null;
}
this.axisNameChangeTimer = setTimeout(() => {
this.curPageArr.forEach((sampleItem) => {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].updateHistogramData();
}
});
}, 500);
},
/**
* The view display type is changed
* @param {Number} val Current mode
*/
viewTypeChange(val) {
if (this.viewNameChangeTimer) {
clearTimeout(this.viewNameChangeTimer);
this.viewNameChangeTimer = null;
}
this.viewNameChangeTimer = setTimeout(() => {
this.curPageArr.forEach((sampleItem) => {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].updateHistogramData();
}
});
}, 200);
},
/**
* Formate absolute time
* @param {String} time time string
* @return {String} str Formatted time
*/
dealrelativeTime(time) {
const arr = time.split(' ');
const str = `${arr[0]} ${arr[1]} ${arr[2]}, ${arr[4]}`;
return str;
},
/**
* Update the data list based on the filtered tags
* @param {Boolean} noPageDataNumChange No new data is added or deleted
*/
updateTagInPage(noPageDataNumChange) {
const curFilterSamples = [];
// Obtains data subscript that meets the tag filtering conditions
this.originDataArr.forEach((sampleItem) => {
if (this.multiSelectedTagNames[sampleItem.tagName]) {
curFilterSamples.push(sampleItem);
}
});
this.curFilterSamples = curFilterSamples;
// Obtains data on the current page
this.getCurPageDataArr(noPageDataNumChange);
},
/**
* Clear data
*/
clearAllData() {
if (this.curDataType === 1 && this.curViewName === 1) {
this.originDataArr.forEach((sampleItem) => {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].clearZrData();
}
});
}
this.tagList = [];
this.originDataArr = [];
this.curFullTagDic = {};
this.multiSelectedTagNames = {};
this.curFilterSamples = [];
this.pageIndex = 0;
this.curPageArr = [];
this.$nextTick(() => {
this.$refs.multiselectGroupComponents.updateSelectedDic();
});
},
/**
* error
* @param {Object} error error object
*/
requestErrorCallback(error) {
if (!this.initOver) {
this.initOver = true;
}
if (this.isReloading) {
this.$store.commit('setIsReload', false);
this.isReloading = false;
}
if (error.response && error.response.data) {
this.clearAllData();
} else {
if (
!(error.code === 'ECONNABORTED' && /^timeout/.test(error.message))
) {
// Clear data
this.clearAllData();
}
}
},
/**
* Enable automatic refresh
*/
autoUpdateSamples() {
if (this.autoUpdateTimer) {
clearInterval(this.autoUpdateTimer);
this.autoUpdateTimer = null;
}
this.autoUpdateTimer = setInterval(() => {
this.$store.commit('clearToken');
this.updateAllData(true);
}, this.timeReloadValue * 1000);
},
/**
* Disable automatic refresh
*/
stopUpdateSamples() {
if (this.autoUpdateTimer) {
clearInterval(this.autoUpdateTimer);
this.autoUpdateTimer = null;
}
},
/**
* Update all data.
* @param {Boolean} ignoreError whether ignore error tip.
*/
updateAllData(ignoreError) {
const params = {
plugin_name: 'tensor',
train_id: this.trainingJobId,
};
RequestService.getSingleTrainJob(params, ignoreError)
.then((res) => {
if (this.isReloading) {
this.$store.commit('setIsReload', false);
this.isReloading = false;
}
// Fault tolerance processing
if (
!res ||
!res.data ||
!res.data.train_jobs ||
!res.data.train_jobs.length ||
!res.data.train_jobs[0].tags
) {
this.clearAllData();
return;
}
const data = res.data.train_jobs[0];
// Remove data that does not exist.
const dataRemoveFlag = this.removeNoneExistentData(data);
// Add new data.
const dataAddFlag = this.checkNewDataAndComplete(data);
this.$nextTick(() => {
this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic();
this.updateTagInPage(!dataAddFlag && !dataRemoveFlag);
});
}, this.requestErrorCallback)
.catch((e) => {
this.$message.error(this.$t('public.dataError'));
});
},
/**
* Delete the data that does not exist
* @param {Object} oriData Raw data with tags
* @return {Boolean} Indicates whether data is removed.
*/
removeNoneExistentData(oriData) {
if (!oriData || !oriData.tags) {
return false;
}
const newTagDictionaries = {};
let dataRemoveFlag = false;
// Obtains the current tag list
oriData.tags.forEach((tagName) => {
newTagDictionaries[tagName] = true;
});
// Delete data that do not exist in the operation bar
const oldTagListLength = this.tagList.length;
for (let i = oldTagListLength - 1; i >= 0; i--) {
if (!newTagDictionaries[this.tagList[i].label]) {
dataRemoveFlag = true;
delete this.curFullTagDic[this.tagList[i].label];
this.tagList.splice(i, 1);
}
}
// Delete the data corresponding to the tag that does not exist.
const oldSampleLength = this.originDataArr.length;
for (let i = oldSampleLength - 1; i >= 0; i--) {
if (!newTagDictionaries[this.originDataArr[i].tagName]) {
dataRemoveFlag = true;
this.originDataArr.splice(i, 1);
}
}
return dataRemoveFlag;
},
/**
* Check and add new data
* @param {Object} oriData Raw data with tags
* @return {Boolean} Check whether new data is added
*/
checkNewDataAndComplete(oriData) {
if (!oriData || !oriData.tags) {
return false;
}
let dataAddFlag = false;
oriData.tags.forEach((tagName) => {
if (!this.curFullTagDic[tagName]) {
this.tagList.push({
label: tagName,
checked: true,
show: false,
});
this.originDataArr.push({
tagName: tagName,
summaryName: this.trainingJobId,
show: false,
sliderValue: 0,
newDataFlag: true,
totalStepNum: 0,
curStep: '',
curTime: '',
curDims: '',
curDataType: '',
fullScreen: false,
ref: tagName,
sliderChangeTimer: null,
curData: [],
formateData: [],
fullData: [],
filterStr: '',
curMartixShowSliderValue: 0,
});
this.curFullTagDic[tagName] = true;
dataAddFlag = true;
}
});
return dataAddFlag;
},
/**
* Expand/Collapse in Full Screen
* @param {Object} sampleItem The object that is being operated
*/
toggleFullScreen(sampleItem) {
if (!sampleItem) {
return;
}
sampleItem.fullScreen = !sampleItem.fullScreen;
this.$nextTick(() => {
const elementItem = this.$refs[sampleItem.ref];
if (elementItem) {
elementItem[0].resizeView();
elementItem[0].$el.scrollIntoView();
}
});
},
/**
* Callback after the step slider changes
* @param {Number} sliderValue changed slider value
* @param {Object} sampleItem The object that is being operated
*/
sliderChange(sliderValue, sampleItem) {
if (sampleItem.sliderChangeTimer) {
clearTimeout(sampleItem.sliderChangeTimer);
sampleItem.sliderChangeTimer = null;
}
if (sampleItem.curMartixShowSliderValue === sliderValue) {
return;
}
if (!sampleItem.fullData || !sampleItem.fullData[sliderValue]) {
return;
}
sampleItem.newDataFlag = true;
sampleItem.formateData = sampleItem.fullData[sliderValue];
sampleItem.curStep = sampleItem.formateData.step;
sampleItem.curTime = this.dealrelativeTime(
new Date(sampleItem.formateData.wall_time * 1000).toString(),
);
sampleItem.curDataType = sampleItem.formateData.value.data_type;
sampleItem.curDims = JSON.stringify(sampleItem.formateData.value.dims);
sampleItem.sliderChangeTimer = setTimeout(() => {
this.freshtMartixData(sampleItem);
}, 500);
},
/**
* Converts the original data formate to a histogram-recognizable formate
* @param {Object} resData Original data
* @return {Object} Formatted data
*/
formHistogramOriData(resData) {
const formateData = [];
const histogramArr = resData.values || [];
const wallTimeInit = histogramArr.length ? histogramArr[0].wall_time : 0;
histogramArr.forEach((histogram, index) => {
const step = histogram.step.toString();
const chartItem = {
wall_time: histogram.wall_time,
relative_time: histogram.wall_time - wallTimeInit,
step: step,
items: [],
};
const chartArr = [];
histogram.value.histogram_buckets.forEach((bucket) => {
const xData = bucket[0] + bucket[1] / 2;
const filter = chartArr.filter((k) => k[0] === xData);
if (!filter.length) {
chartArr.push([
histogram.wall_time,
step,
xData,
Math.floor(bucket[2]),
]);
}
});
chartArr.sort((a, b) => a[0] - b[0]);
if (chartArr.length) {
const minItem = chartArr[0][2];
const maxItem = chartArr[chartArr.length - 1][2];
const chartAll = [
[histogram.wall_time, step, minItem, 0],
].concat(chartArr, [[histogram.wall_time, step, maxItem, 0]]);
chartItem.items = chartAll;
formateData.push(chartItem);
}
});
return formateData;
},
/**
* Histogram display/hidden change of tip
* @param {Boolean} value Show tip
*/
chartTipFlagChange(value) {
this.chartTipFlag = value;
},
},
};
</script>
<style lang="scss">
.cl-tensor-manage {
height: 100%;
.tensor-bk {
height: 100%;
background-color: #fff;
display: flex;
flex-direction: column;
.cl-tensor-title {
height: 56px;
line-height: 56px;
.cl-close-btn {
width: 20px;
height: 20px;
vertical-align: -3px;
cursor: pointer;
display: inline-block;
}
}
.cl-tensor-operate-content {
width: 100%;
padding: 8px 32px 22px 32px;
background: #ffffff;
}
.cl-tensor-view-type-select-content {
background: #ffffff;
padding: 0 32px 21px 32px;
height: 58px;
display: flex;
align-items: center;
border-bottom: 2px solid #e6ebf5;
.view-title {
font-size: 14px;
line-height: 14px;
vertical-align: middle;
margin-right: 16px;
flex-shrink: 0;
}
.el-radio-group {
margin-right: 64px;
flex-shrink: 0;
}
}
.cl-show-data-content {
background: #ffffff;
padding: 0 23px;
flex: 1;
overflow: auto;
.data-content {
display: flex;
height: 100%;
width: 100%;
flex-wrap: wrap;
min-height: 400px;
position: relative;
.sample-content {
width: 33.3%;
height: 600px;
display: flex;
flex-direction: column;
flex-shrink: 0;
background-color: #fff;
position: relative;
padding: 32px 9px 0 9px;
}
.char-full-screen {
width: 100%;
height: 600px;
}
.chars-container {
flex: 1;
padding: 10px 15px 0 15px;
position: relative;
background: #f0f3fa;
overflow-x: hidden;
}
.sample-data-show {
padding: 32px 16px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
background-color: #f0f3fa;
margin-top: 1px;
.tensor-demension,
.tensor-type {
font-size: 14px;
line-height: 20px;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
span {
color: #00a5a7;
}
}
.sample-operate-info {
width: 100%;
min-height: 24px;
vertical-align: middle;
line-height: 20px;
margin-top: 24px;
color: #000000;
position: relative;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
span {
max-width: 100%;
text-overflow: ellipsis;
white-space: nowrap;
overflow: hidden;
}
.step-info {
left: 0;
font-size: 14px;
}
.time-info {
right: 0;
float: right;
font-size: 14px;
}
}
.step-slider {
margin-top: 10px;
}
}
.tag-title {
margin-top: 10px;
width: 100%;
font-size: 16px;
font-weight: 600;
text-align: center;
}
}
}
.pagination-content {
padding: 24px 32px;
text-align: right;
}
// No data available.
.image-noData {
// Set the width and white on the right.
width: 100%;
height: 450px;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
}
.content {
position: relative;
}
#echart {
width: 500px;
height: 500px;
border: 1px solid black;
position: relative;
}
#echartTip {
position: absolute;
padding: 5px;
z-index: 9999;
font-size: 14px;
font-family: 'Microsoft YaHei';
background-color: rgba(50, 50, 50, 0.7);
border: 0;
border-radius: 4px;
color: #fff;
}
.char-tip-table td {
padding-left: 5px;
padding-right: 5px;
text-overflow: ellipsis;
white-space: nowrap;
max-width: 150px;
overflow: hidden;
}
.borderspacing3 {
border-spacing: 3px;
}
}
</style>
...@@ -146,12 +146,28 @@ limitations under the License. ...@@ -146,12 +146,28 @@ limitations under the License.
</div> </div>
</div> </div>
</div> </div>
<div class="cl-dashboard-con-up no-data-hover"> <div class="cl-dashboard-con-up"
<div class="coming-soon-content"> :class="!!tensorTag && !wrongPlugin ? '' : 'no-data-hover'"
<div class="coming-soon-container"> @click="viewMoreTensors">
<img :src="require('@/assets/images/coming-soon.png')" /> <div class="cl-dashboard-title">{{$t("tensors.titleText")}}</div>
<p class='coming-soon-text'> <div class="cl-module">
{{$t("public.stayTuned")}} <div class="tensor-char-container"
v-show="!!tensorTag && !wrongPlugin">
<div id="tensor-chart-container">
<gridTableComponents ref="tensorChart"
:showOperate="false"
:fullData="tensorData"></gridTableComponents>
</div>
<div class="tag-text"
:title="tensorTag">{{tensorTag}}</div>
</div>
<div class="no-data-img"
key="no-chart-data"
v-show="!tensorTag || wrongPlugin">
<img :src="require('@/assets/images/nodata.png')"
alt="" />
<p class='no-data-text'>
{{$t("public.noData")}}
</p> </p>
</div> </div>
</div> </div>
...@@ -168,6 +184,7 @@ import {select, selectAll, format, precisionRound} from 'd3'; ...@@ -168,6 +184,7 @@ import {select, selectAll, format, precisionRound} from 'd3';
import 'd3-graphviz'; import 'd3-graphviz';
const d3 = {select, selectAll, format, precisionRound}; const d3 = {select, selectAll, format, precisionRound};
import echarts from 'echarts'; import echarts from 'echarts';
import gridTableComponents from '../../components/gridTableSimple';
export default { export default {
data() { data() {
return { return {
...@@ -201,6 +218,8 @@ export default { ...@@ -201,6 +218,8 @@ export default {
reloadStopTime: 1000, reloadStopTime: 1000,
wrongPlugin: false, wrongPlugin: false,
fileTag: '', fileTag: '',
tensorData: [],
tensorTag: '',
}; };
}, },
computed: { computed: {
...@@ -218,6 +237,9 @@ export default { ...@@ -218,6 +237,9 @@ export default {
return this.$store.state.timeReloadValue; return this.$store.state.timeReloadValue;
}, },
}, },
components: {
gridTableComponents,
},
watch: { watch: {
isReload(newVal) { isReload(newVal) {
if (newVal) { if (newVal) {
...@@ -282,6 +304,10 @@ export default { ...@@ -282,6 +304,10 @@ export default {
if (this.histogramObj) { if (this.histogramObj) {
this.histogramObj.resize(); this.histogramObj.resize();
} }
const elementItem = this.$refs.tensorChart;
if (elementItem) {
elementItem.resizeView();
}
}, 500); }, 500);
}, },
...@@ -330,6 +356,7 @@ export default { ...@@ -330,6 +356,7 @@ export default {
const imageTags = data.image || []; const imageTags = data.image || [];
const scalarTags = data.scalar || []; const scalarTags = data.scalar || [];
const graphIds = data.graph || []; const graphIds = data.graph || [];
const tensorTags = data.tensor || [];
if (graphIds.length) { if (graphIds.length) {
this.fileTag = graphIds[0]; this.fileTag = graphIds[0];
} }
...@@ -337,6 +364,7 @@ export default { ...@@ -337,6 +364,7 @@ export default {
this.getHistogramTag(histogramTags); this.getHistogramTag(histogramTags);
this.dealImageData(imageTags); this.dealImageData(imageTags);
this.getScalarList(scalarTags); this.getScalarList(scalarTags);
this.dealTensorData(tensorTags);
if (!this.firstFloorNodes.length && graphIds.length) { if (!this.firstFloorNodes.length && graphIds.length) {
this.queryGraphData(); this.queryGraphData();
} }
...@@ -383,6 +411,20 @@ export default { ...@@ -383,6 +411,20 @@ export default {
}, },
}); });
}, },
/**
* Viewing more tensors information
*/
viewMoreTensors() {
if (!this.tensorTag) {
return;
}
this.$router.push({
path: '/train-manage/tensor',
query: {
train_id: this.trainingJobId,
},
});
},
/** /**
* Go to data. * Go to data.
*/ */
...@@ -785,6 +827,117 @@ export default { ...@@ -785,6 +827,117 @@ export default {
this.originImageDataArr = dataList; this.originImageDataArr = dataList;
this.getSampleRandomly(); this.getSampleRandomly();
}, },
dealTensorData(tags) {
if (tags.length) {
this.tensorTag = tags[0];
} else {
this.tensorTag = '';
}
if (this.tensorTag) {
this.getTensorGridData();
}
},
getTensorGridData() {
const params = {
train_id: this.trainingJobId,
tag: this.tensorTag,
detail: 'stats',
};
RequestService.getTensorsSample(params).then(
(res) => {
if (!res || !res.data) {
return;
}
if (!res.data.tensors.length) {
return;
}
const resData = JSON.parse(JSON.stringify(res.data.tensors[0]));
if (!resData.values.length) {
this.tensorData = [];
this.$nextTick(() => {
const elementItem = this.$refs.tensorChart;
if (elementItem) {
elementItem.updateGridData();
}
});
return;
}
const data = resData.values[resData.values.length - 1];
const filterStr = this.initFilterStr(data.value.dims);
this.freshtMartixData(data.step, filterStr);
},
() => {
this.tensorData = [];
this.$nextTick(() => {
const elementItem = this.$refs.tensorChart;
if (elementItem) {
elementItem.updateGridData();
}
});
},
);
},
initFilterStr(array) {
if (!array) {
return [];
}
const countLinit = array.length - 2;
const tempArr = [];
for (let i = 0; i < array.length; i++) {
tempArr.push(i >= countLinit ? ':' : '0');
}
return `[${tempArr.toString()}]`;
},
freshtMartixData(step, filterStr) {
const params = {
train_id: this.trainingJobId,
tag: this.tensorTag,
detail: 'data',
step: step,
dims: filterStr,
};
RequestService.getTensorsSample(params).then(
(res) => {
if (!res || !res.data) {
return;
}
if (!res.data.tensors.length) {
return;
}
const resData = res.data.tensors[0];
const curStepData = resData.values[0];
let statistics = {};
if (curStepData) {
this.tensorData =
curStepData.value.data instanceof Array
? curStepData.value.data
: [curStepData.value.data];
statistics = curStepData.value.statistics;
} else {
this.tensorData = [[]];
}
this.$nextTick(() => {
const elementItem = this.$refs.tensorChart;
if (elementItem) {
elementItem.updateGridData(
true,
curStepData.value.dims,
statistics,
);
}
});
},
() => {
this.tensorData = [];
this.$nextTick(() => {
const elementItem = this.$refs.tensorChart;
if (elementItem) {
elementItem.updateGridData();
}
});
},
);
},
getHistogramTag(tagList) { getHistogramTag(tagList) {
if (!tagList) { if (!tagList) {
return; return;
...@@ -1889,20 +2042,6 @@ export default { ...@@ -1889,20 +2042,6 @@ export default {
} }
} }
.coming-soon-content {
width: 100%;
height: 100%;
text-align: center;
.coming-soon-container {
position: relative;
top: calc(50% - 88px);
.coming-soon-text {
color: #000000;
font-size: 16px;
}
}
}
.no-data-hover { .no-data-hover {
cursor: not-allowed; cursor: not-allowed;
} }
...@@ -1928,13 +2067,15 @@ export default { ...@@ -1928,13 +2067,15 @@ export default {
cursor: pointer; cursor: pointer;
} }
} }
#distribution-chart { #distribution-chart,
#tensor-chart-container {
height: calc(100% - 19px); height: calc(100% - 19px);
canvas { canvas {
cursor: pointer; cursor: pointer;
} }
} }
.histogram-char-container { .histogram-char-container,
.tensor-char-container {
height: 100%; height: 100%;
width: 100%; width: 100%;
cursor: pointer; cursor: pointer;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册