You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tensor.vue 42 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233
  1. <!--
  2. Copyright 2020 Huawei Technologies Co., Ltd.All Rights Reserved.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. -->
  13. <template>
  14. <div class="cl-tensor-manage">
  15. <div class="tensor-bk">
  16. <!-- Title area -->
  17. <div class="cl-title cl-tensor-title">
  18. <div class="cl-title-left">{{$t('tensors.titleText')}}
  19. <div class="path-message">
  20. <span>{{$t('symbols.leftbracket')}}</span>
  21. <span>{{$t('trainingDashboard.summaryDirPath')}}</span>
  22. <span>{{summaryPath}}</span>
  23. <span>{{$t('symbols.rightbracket')}}</span>
  24. </div>
  25. </div>
  26. <div class="cl-title-right">
  27. <div class="cl-close-btn"
  28. @click="jumpToTrainDashboard">
  29. <img src="@/assets/images/close-page.png" />
  30. </div>
  31. </div>
  32. </div>
  33. <!-- List item operation area -->
  34. <div class="cl-tensor-operate-content">
  35. <multiselectGroupComponents ref="multiselectGroupComponents"
  36. :checkListArr="tagList"
  37. @selectedChange="tagSelectedChanged"></multiselectGroupComponents>
  38. </div>
  39. <!-- Area for selecting a view type -->
  40. <div class="cl-tensor-view-type-select-content">
  41. <div class="view-title">{{$t('tensors.viewTypeTitle')}}</div>
  42. <el-radio-group v-model="curDataType"
  43. fill="#00A5A7"
  44. text-color="#FFFFFF"
  45. size="small"
  46. @change="dataTypeChange">
  47. <el-radio-button :label="0">{{$t('tensors.chartViewType')}}</el-radio-button>
  48. <el-radio-button :label="1">{{$t('tensors.histogramViewType')}}</el-radio-button>
  49. </el-radio-group>
  50. <div class="view-title"
  51. v-if="!!curDataType">{{$t('histogram.viewType')}}
  52. </div>
  53. <el-radio-group v-model="curViewName"
  54. v-if="!!curDataType"
  55. fill="#00A5A7"
  56. text-color="#FFFFFF"
  57. size="small"
  58. @change="viewTypeChange">
  59. <el-radio-button :label="0">{{$t('histogram.overlay')}}</el-radio-button>
  60. <el-radio-button :label="1">{{$t('histogram.offset')}}</el-radio-button>
  61. </el-radio-group>
  62. <div class="view-title"
  63. v-if="!!curViewName && !!curDataType">
  64. {{$t('histogram.xAxisTitle')}}
  65. </div>
  66. <el-radio-group v-model="curAxisName"
  67. fill="#00A5A7"
  68. text-color="#FFFFFF"
  69. size="small"
  70. v-if="!!curDataType && !!curViewName"
  71. :disabled="curViewName === 0"
  72. @change="timeTypeChange">
  73. <el-radio-button :label="0">{{$t('histogram.step')}}</el-radio-button>
  74. <el-radio-button :label="1">{{$t('histogram.relativeTime')}}</el-radio-button>
  75. <el-radio-button :label="2">{{$t('histogram.absoluteTime')}}</el-radio-button>
  76. </el-radio-group>
  77. </div>
  78. <!-- Content display area -->
  79. <div class="cl-show-data-content">
  80. <!-- No data -->
  81. <div class="image-noData"
  82. v-if="!originDataArr.length">
  83. <div>
  84. <img :src="require('@/assets/images/nodata.png')" />
  85. </div>
  86. <div v-if="initOver"
  87. class="noData-text">{{$t('public.noData')}}</div>
  88. <div v-else
  89. class="noData-text">{{$t("public.dataLoading")}}</div>
  90. </div>
  91. <!-- Data -->
  92. <div class="data-content"
  93. v-if="!!originDataArr.length">
  94. <div id="echartTip"
  95. v-show="chartTipFlag">
  96. <table class="char-tip-table borderspacing3">
  97. <tr>
  98. <td>{{$t('histogram.centerValue')}}</td>
  99. <td>{{$t('histogram.step')}}</td>
  100. <td>{{$t('histogram.relativeTime')}}</td>
  101. <td>{{$t('histogram.absoluteTime')}}</td>
  102. </tr>
  103. <tr id="tipTr"></tr>
  104. </table>
  105. </div>
  106. <div class="sample-content"
  107. v-for="sampleItem in originDataArr"
  108. :key="sampleItem.ref"
  109. :class="sampleItem.fullScreen ? 'char-full-screen' : ''"
  110. v-show="sampleItem.show">
  111. <div class="chars-container">
  112. <!-- Components -->
  113. <gridTableComponents v-if="!curDataType"
  114. :ref="sampleItem.ref"
  115. :fullScreen="sampleItem.fullScreen"
  116. @martixFilterChange="filterChange($event, sampleItem)"
  117. @toggleFullScreen="toggleFullScreen(sampleItem)"
  118. :columnLimitNum="columnLimitNum"
  119. :fullData="sampleItem.curData"></gridTableComponents>
  120. <histogramUntil v-else
  121. :ref="sampleItem.ref"
  122. :fullScreen="sampleItem.fullScreen"
  123. @chartTipFlagChange="chartTipFlagChange"
  124. @toggleFullScreen="toggleFullScreen(sampleItem)"
  125. :viewName="curViewName"
  126. :axisName="curAxisName"
  127. :fullData="sampleItem.curData"></histogramUntil>
  128. <div class="loading-cover"
  129. v-if="sampleItem.showLoading">
  130. <i class="el-icon-loading"></i></div>
  131. </div>
  132. <!-- Information display area -->
  133. <div class="sample-data-show"
  134. v-if="!curDataType">
  135. <div class="tensor-demension"
  136. :title="sampleItem.curDims">
  137. {{$t('tensors.dimension')}}
  138. <span>{{sampleItem.curDims}}</span>
  139. </div>
  140. <div class="tensor-type"
  141. :title="sampleItem.curDataType">
  142. {{$t('tensors.tensorType')}} {{sampleItem.curDataType}}
  143. </div>
  144. <!-- Current step information -->
  145. <div class="sample-operate-info select-disable">
  146. <span class="step-info"
  147. :title="sampleItem.curStep">{{$t('images.step')}}{{sampleItem.curStep}}</span>
  148. <span class="time-info"
  149. :title="sampleItem.curTime">{{sampleItem.curTime}}</span>
  150. </div>
  151. <el-slider class="step-slider"
  152. v-model="sampleItem.sliderValue"
  153. :step="1"
  154. :max="sampleItem.totalStepNum"
  155. @input="sliderChange(sampleItem.sliderValue, sampleItem)"
  156. :show-tooltip="false"
  157. :disabled="sampleItem.totalStepNum === 0">
  158. </el-slider>
  159. </div>
  160. <div class="tag-title"
  161. :title="sampleItem.tagName">{{sampleItem.tagName}}
  162. </div>
  163. </div>
  164. </div>
  165. </div>
  166. <!-- Page number area -->
  167. <div class="pagination-content"
  168. v-if="originDataArr.length">
  169. <el-pagination @current-change="currentPageChange"
  170. :current-page="pageIndex + 1"
  171. :page-sizes="pageSizes"
  172. :page-size="pageNum"
  173. layout="total, prev, pager, next, jumper"
  174. :total="curFilterSamples.length">
  175. </el-pagination>
  176. </div>
  177. </div>
  178. </div>
  179. </template>
  180. <script>
  181. import multiselectGroupComponents from '../../components/multiselect-group.vue';
  182. import gridTableComponents from '../../components/grid-table-simple';
  183. import histogramUntil from '../../components/histogram-unit';
  184. import RequestService from '../../services/request-service';
  185. import autoUpdate from '../../mixins/auto-update.vue';
  186. export default {
  187. mixins: [autoUpdate],
  188. data() {
  189. return {
  190. tagList: [], // Tag list.
  191. trainingJobId: this.$route.query.train_id, // ID of the current training job.
  192. summaryPath: this.$route.query.summaryPath,
  193. originDataArr: [], // List of all data.
  194. initOver: false, // Indicates whether the initialization is complete.
  195. curFullTagDic: {}, // Dictionary that contains all the current tags.
  196. multiSelectedTagNames: {}, // Dictionary for storing the name of the selected tags.
  197. curFilterSamples: [], // List of data that meet the current filter criteria.
  198. curPageArr: [], // Data list on the current page.
  199. pageIndex: 0, // Current page number.
  200. pageSizes: [6], // The number of records on each page is optional.
  201. pageNum: 6, // Number of records on each page.
  202. dataTypeChangeTimer: null, // View switching timer
  203. viewNameChangeTimer: null, // ViewName switching timer
  204. axisNameChangeTimer: null, // Vertical axis switching timer
  205. curDataType: 0, // Current data type
  206. curViewName: 1, // Current histogram view type
  207. curAxisName: 0, // Current histogran axis type
  208. chartTipFlag: false, // Whether to display tips of the histogram
  209. columnLimitNum: 1000, // Maximum number of columns is 1000
  210. };
  211. },
  212. computed: {},
  213. components: {
  214. multiselectGroupComponents,
  215. gridTableComponents,
  216. histogramUntil,
  217. },
  218. watch: {},
  219. destroyed() {
  220. window.removeEventListener('resize', this.resizeCallback);
  221. // Cancel the delay
  222. this.originDataArr.forEach((sampleItem) => {
  223. if (sampleItem.sliderChangeTimer) {
  224. clearTimeout(sampleItem.sliderChangeTimer);
  225. sampleItem.sliderChangeTimer = null;
  226. }
  227. });
  228. if (this.charResizeTimer) {
  229. clearTimeout(this.charResizeTimer);
  230. this.charResizeTimer = null;
  231. }
  232. if (this.dataTypeChangeTimer) {
  233. clearTimeout(this.dataTypeChangeTimer);
  234. this.dataTypeChangeTimer = null;
  235. }
  236. if (this.viewNameChangeTimer) {
  237. clearTimeout(this.viewNameChangeTimer);
  238. this.viewNameChangeTimer = null;
  239. }
  240. if (this.axisNameChangeTimer) {
  241. clearTimeout(this.axisNameChangeTimer);
  242. this.axisNameChangeTimer = null;
  243. }
  244. },
  245. mounted() {
  246. this.init();
  247. window.addEventListener('resize', this.resizeCallback, false);
  248. },
  249. methods: {
  250. /**
  251. * Callback after the window size is changed
  252. */
  253. resizeCallback() {
  254. if (this.charResizeTimer) {
  255. clearTimeout(this.charResizeTimer);
  256. this.charResizeTimer = null;
  257. }
  258. this.charResizeTimer = setTimeout(() => {
  259. this.curPageArr.forEach((sampleItem) => {
  260. const elementItem = this.$refs[sampleItem.ref];
  261. if (elementItem) {
  262. elementItem[0].resizeView();
  263. }
  264. });
  265. }, 500);
  266. },
  267. /**
  268. * Initialize
  269. */
  270. init() {
  271. this.getOriginData();
  272. if (this.isTimeReload) {
  273. this.autoUpdateSamples();
  274. }
  275. },
  276. /**
  277. * Jump back to train dashboard
  278. */
  279. jumpToTrainDashboard() {
  280. this.$router.push({
  281. path: '/train-manage/training-dashboard',
  282. query: {
  283. id: this.trainingJobId,
  284. },
  285. });
  286. },
  287. /**
  288. * Obtains original data.
  289. */
  290. getOriginData() {
  291. const params = {
  292. plugin_name: 'tensor',
  293. train_id: this.trainingJobId,
  294. };
  295. RequestService.getSingleTrainJob(params)
  296. .then((res) => {
  297. if (
  298. !res ||
  299. !res.data ||
  300. !res.data.train_jobs ||
  301. !res.data.train_jobs.length
  302. ) {
  303. this.initOver = true;
  304. return;
  305. }
  306. const data = res.data.train_jobs[0];
  307. if (!data.tags) {
  308. return;
  309. }
  310. const tagList = [];
  311. const dataList = [];
  312. data.tags.forEach((tagName, tagIndex) => {
  313. if (!this.curFullTagDic[tagName]) {
  314. this.curFullTagDic[tagName] = true;
  315. tagList.push({
  316. label: tagName,
  317. checked: true,
  318. show: true,
  319. });
  320. dataList.push({
  321. tagName: tagName,
  322. summaryName: this.trainingJobId,
  323. show: false,
  324. showLoading: false,
  325. sliderValue: 0,
  326. newDataFlag: true,
  327. totalStepNum: 0,
  328. curStep: '',
  329. curTime: '',
  330. curDims: '',
  331. curDataType: '',
  332. fullScreen: false,
  333. ref: tagName,
  334. sliderChangeTimer: null,
  335. curData: [],
  336. formateData: [],
  337. fullData: [],
  338. filterStr: '',
  339. curMartixShowSliderValue: 0,
  340. });
  341. }
  342. });
  343. if (dataList.length === 1) {
  344. dataList[0].fullScreen = true;
  345. }
  346. this.tagList = tagList;
  347. this.originDataArr = dataList;
  348. this.$nextTick(() => {
  349. this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic();
  350. this.initOver = true;
  351. this.updateTagInPage();
  352. });
  353. }, this.requestErrorCallback)
  354. .catch((e) => {
  355. this.initOver = true;
  356. this.$message.error(this.$t('public.dataError'));
  357. });
  358. },
  359. /**
  360. * Table dimension change callback
  361. * @param {Array} data Dimension array after change
  362. * @param {Object} sampleItem The object that is being operated
  363. */
  364. filterChange(data, sampleItem) {
  365. sampleItem.showLoading = true;
  366. sampleItem.filterStr = `[${data.toString()}]`;
  367. sampleItem.newDataFlag = true;
  368. this.freshtMartixData(sampleItem);
  369. },
  370. /**
  371. * The selected label is changed.
  372. * @param {Object} selectedItemDict Dictionary containing the selected tags
  373. */
  374. tagSelectedChanged(selectedItemDict) {
  375. if (!selectedItemDict) {
  376. return;
  377. }
  378. this.multiSelectedTagNames = selectedItemDict;
  379. // Reset to the first page
  380. this.pageIndex = 0;
  381. this.updateTagInPage();
  382. },
  383. /**
  384. * Page number change event
  385. * @param {Number} pageIndex Changed page number
  386. */
  387. currentPageChange(pageIndex) {
  388. this.pageIndex = pageIndex - 1;
  389. // Load the data on the current page
  390. this.getCurPageDataArr();
  391. },
  392. /**
  393. * Obtains data on the current page
  394. * @param {Boolean} noPageDataNumChange No new data is added or deleted
  395. */
  396. getCurPageDataArr(noPageDataNumChange) {
  397. // Clear the previous page
  398. if (!noPageDataNumChange) {
  399. this.curPageArr.forEach((sampleItem) => {
  400. sampleItem.show = false;
  401. if (this.curDataType === 1 && this.curViewName === 1) {
  402. const elementItem = this.$refs[sampleItem.ref];
  403. if (elementItem) {
  404. elementItem[0].clearZrData();
  405. }
  406. }
  407. });
  408. }
  409. // This interface is used to obtain the current page group and hide the current page group.
  410. const startIndex = this.pageIndex * this.pageNum;
  411. const endIndex = startIndex + this.pageNum;
  412. const curPageArr = [];
  413. for (let i = startIndex; i < endIndex; i++) {
  414. const sampleItem = this.curFilterSamples[i];
  415. if (sampleItem) {
  416. sampleItem.show = true;
  417. curPageArr.push(sampleItem);
  418. }
  419. }
  420. this.curPageArr = curPageArr;
  421. // Update the data information on the current page
  422. this.freshCurPageData();
  423. },
  424. /**
  425. * Refresh the data on the current page
  426. * @param {Boolean} isFromTypeChange
  427. */
  428. freshCurPageData(isFromTypeChange) {
  429. this.curPageArr.forEach((sampleItem, index) => {
  430. if (!sampleItem || !sampleItem.tagName) {
  431. return;
  432. }
  433. const dataType = this.curDataType;
  434. if (dataType) {
  435. this.getHistogramData(sampleItem);
  436. } else {
  437. sampleItem.newDataFlag = !!isFromTypeChange || sampleItem.newDataFlag;
  438. this.getMartixData(sampleItem);
  439. }
  440. });
  441. },
  442. /**
  443. * Initialize the current dimension selection
  444. * @param {Array} array Array containing the current number of dimensions
  445. * @return {Object} Current dimension selection
  446. */
  447. initFilterStr(array) {
  448. if (!array) {
  449. return [];
  450. }
  451. const countLinit = array.length - 2;
  452. const tempArr = [];
  453. for (let i = 0; i < array.length; i++) {
  454. tempArr.push(i >= countLinit ? ':' : '0');
  455. }
  456. if (tempArr.length) {
  457. const lastIndex = tempArr.length - 1;
  458. const lastFilter = tempArr[lastIndex];
  459. if (lastFilter && array[lastIndex] > this.columnLimitNum) {
  460. tempArr[lastIndex] = `0:${this.columnLimitNum}`;
  461. }
  462. }
  463. return `[${tempArr.toString()}]`;
  464. },
  465. /**
  466. * Obtains histogram data
  467. * @param {Object} sampleItem The object that is being operated
  468. */
  469. getHistogramData(sampleItem) {
  470. const params = {
  471. train_id: this.trainingJobId,
  472. tag: sampleItem.tagName,
  473. detail: 'histogram',
  474. };
  475. RequestService.getTensorsSample(params).then(
  476. (res) => {
  477. sampleItem.showLoading = false;
  478. if (!res || !res.data || !this.curDataType) {
  479. return;
  480. }
  481. if (!res.data.tensors || !res.data.tensors.length) {
  482. return;
  483. }
  484. const resData = JSON.parse(JSON.stringify(res.data.tensors[0]));
  485. sampleItem.summaryName = resData.train_id;
  486. // sampleItem.fullData = resData;
  487. sampleItem.curData = this.formHistogramOriData(resData);
  488. this.$nextTick(() => {
  489. const elementItem = this.$refs[sampleItem.ref];
  490. if (elementItem) {
  491. elementItem[0].updateHistogramData();
  492. }
  493. });
  494. },
  495. (e) => {
  496. this.freshDataErrorCallback(e, sampleItem, false);
  497. },
  498. );
  499. },
  500. /**
  501. * Obtain table data
  502. * @param {Object} sampleItem The object that is being operated
  503. */
  504. getMartixData(sampleItem) {
  505. const params = {
  506. train_id: this.trainingJobId,
  507. tag: sampleItem.tagName,
  508. detail: 'stats',
  509. };
  510. RequestService.getTensorsSample(params).then(
  511. (res) => {
  512. if (!res || !res.data || this.curDataType) {
  513. sampleItem.showLoading = false;
  514. return;
  515. }
  516. if (!res.data.tensors.length) {
  517. sampleItem.showLoading = false;
  518. return;
  519. }
  520. const resData = JSON.parse(JSON.stringify(res.data.tensors[0]));
  521. sampleItem.summaryName = resData.train_id;
  522. if (!resData.values.length) {
  523. sampleItem.fullData = [];
  524. sampleItem.formateData = [];
  525. sampleItem.curData = [];
  526. sampleItem.curTime = '';
  527. sampleItem.curDims = '';
  528. sampleItem.curDataType = '';
  529. sampleItem.curStep = '';
  530. sampleItem.sliderValue = 0;
  531. sampleItem.totalStepNum = 0;
  532. this.clearMartixData(sampleItem);
  533. sampleItem.showLoading = false;
  534. return;
  535. }
  536. const oldTotalStepNum = sampleItem.totalStepNum;
  537. sampleItem.totalStepNum = resData.values.length - 1;
  538. if (sampleItem.sliderValue === oldTotalStepNum) {
  539. sampleItem.sliderValue = sampleItem.totalStepNum;
  540. }
  541. if (sampleItem.sliderValue > sampleItem.totalStepNum) {
  542. sampleItem.sliderValue = sampleItem.totalStepNum;
  543. }
  544. sampleItem.fullData = resData.values;
  545. sampleItem.formateData = sampleItem.fullData[sampleItem.sliderValue];
  546. const oldStep = sampleItem.curStep;
  547. sampleItem.curStep = sampleItem.formateData.step;
  548. if (!sampleItem.filterStr) {
  549. sampleItem.filterStr = this.initFilterStr(
  550. sampleItem.formateData.value.dims,
  551. );
  552. sampleItem.newDataFlag = true;
  553. }
  554. if (sampleItem.curStep !== oldStep) {
  555. sampleItem.newDataFlag = true;
  556. }
  557. sampleItem.curTime = this.dealrelativeTime(
  558. new Date(sampleItem.formateData.wall_time * 1000).toString(),
  559. );
  560. sampleItem.curDataType = sampleItem.formateData.value.data_type;
  561. sampleItem.curDims = JSON.stringify(
  562. sampleItem.formateData.value.dims,
  563. );
  564. this.freshtMartixData(sampleItem);
  565. },
  566. () => {
  567. sampleItem.fullData = [];
  568. sampleItem.formateData = [];
  569. sampleItem.curData = [];
  570. sampleItem.curTime = '';
  571. sampleItem.curDims = '';
  572. sampleItem.curDataType = '';
  573. sampleItem.curStep = '';
  574. sampleItem.sliderValue = 0;
  575. sampleItem.totalStepNum = 0;
  576. this.clearMartixData(sampleItem);
  577. sampleItem.showLoading = false;
  578. },
  579. );
  580. },
  581. /**
  582. * Refresh table display
  583. * @param {Object} sampleItem The object that is being operated
  584. */
  585. freshtMartixData(sampleItem) {
  586. const params = {
  587. train_id: this.trainingJobId,
  588. tag: sampleItem.tagName,
  589. detail: 'data',
  590. step: sampleItem.curStep,
  591. dims: encodeURIComponent(sampleItem.filterStr),
  592. };
  593. sampleItem.curMartixShowSliderValue = sampleItem.sliderValue;
  594. RequestService.getTensorsSample(params).then(
  595. (res) => {
  596. sampleItem.showLoading = false;
  597. if (!res || !res.data || this.curDataType) {
  598. return;
  599. }
  600. if (!res.data.tensors.length) {
  601. return;
  602. }
  603. const resData = res.data.tensors[0];
  604. const curStepData = resData.values[0];
  605. let statistics = {};
  606. if (curStepData) {
  607. sampleItem.curData =
  608. curStepData.value.data instanceof Array
  609. ? curStepData.value.data
  610. : [curStepData.value.data];
  611. statistics = curStepData.value.statistics;
  612. } else {
  613. sampleItem.curData = [[]];
  614. }
  615. let elementItem = null;
  616. this.$nextTick(() => {
  617. elementItem = this.$refs[sampleItem.ref];
  618. if (elementItem) {
  619. elementItem[0].updateGridData(
  620. sampleItem.newDataFlag,
  621. curStepData.value.dims,
  622. statistics,
  623. sampleItem.filterStr,
  624. );
  625. }
  626. sampleItem.newDataFlag = false;
  627. });
  628. },
  629. (e) => {
  630. this.freshDataErrorCallback(e, sampleItem, true);
  631. },
  632. );
  633. },
  634. /**
  635. * callback of fresh data
  636. * @param {Object} errorData The error object
  637. * @param {Object} sampleItem The object that is being operated
  638. * @param {Boolean} isMartix Martix data
  639. */
  640. freshDataErrorCallback(errorData, sampleItem, isMartix) {
  641. let showLimitError = false;
  642. let errorMsg = '';
  643. if (
  644. errorData.response &&
  645. errorData.response.data &&
  646. errorData.response.data.error_code &&
  647. (errorData.response.data.error_code.toString() === '50545013' ||
  648. errorData.response.data.error_code.toString() === '50545014' ||
  649. errorData.response.data.error_code.toString() === '50545016')
  650. ) {
  651. showLimitError = true;
  652. errorMsg = this.$t('error')[errorData.response.data.error_code];
  653. }
  654. if (isMartix) {
  655. this.clearMartixData(sampleItem, showLimitError, errorMsg);
  656. } else {
  657. this.$nextTick(() => {
  658. const elementItem = this.$refs[sampleItem.ref];
  659. if (elementItem) {
  660. elementItem[0].showRequestErrorMessage(errorMsg);
  661. }
  662. });
  663. }
  664. sampleItem.showLoading = false;
  665. },
  666. /**
  667. * Clear table display
  668. * @param {Object} sampleItem The object that is being operated
  669. * @param {Boolean} showLimitError Display request error message
  670. * @param {String} errorMsg Error message
  671. */
  672. clearMartixData(sampleItem, showLimitError, errorMsg) {
  673. sampleItem.curData = [];
  674. sampleItem.newDataFlag = true;
  675. let elementItem = null;
  676. this.$nextTick(() => {
  677. elementItem = this.$refs[sampleItem.ref];
  678. if (elementItem) {
  679. if (showLimitError) {
  680. elementItem[0].showRequestErrorMessage(
  681. errorMsg,
  682. sampleItem.formateData.value.dims,
  683. sampleItem.filterStr,
  684. );
  685. } else {
  686. elementItem[0].updateGridData();
  687. }
  688. }
  689. });
  690. },
  691. /**
  692. * The dataType display type is changed
  693. */
  694. dataTypeChange() {
  695. if (this.dataTypeChangeTimer) {
  696. clearTimeout(this.dataTypeChangeTimer);
  697. this.dataTypeChangeTimer = null;
  698. }
  699. this.dataTypeChangeTimer = setTimeout(() => {
  700. this.freshCurPageData(true);
  701. }, 500);
  702. },
  703. /**
  704. * The time display type is changed
  705. * @param {Number} val Current mode
  706. */
  707. timeTypeChange(val) {
  708. if (this.axisNameChangeTimer) {
  709. clearTimeout(this.axisNameChangeTimer);
  710. this.axisNameChangeTimer = null;
  711. }
  712. this.axisNameChangeTimer = setTimeout(() => {
  713. this.curPageArr.forEach((sampleItem) => {
  714. const elementItem = this.$refs[sampleItem.ref];
  715. if (elementItem) {
  716. elementItem[0].updateHistogramData();
  717. }
  718. });
  719. }, 500);
  720. },
  721. /**
  722. * The view display type is changed
  723. * @param {Number} val Current mode
  724. */
  725. viewTypeChange(val) {
  726. if (this.viewNameChangeTimer) {
  727. clearTimeout(this.viewNameChangeTimer);
  728. this.viewNameChangeTimer = null;
  729. }
  730. this.viewNameChangeTimer = setTimeout(() => {
  731. this.curPageArr.forEach((sampleItem) => {
  732. const elementItem = this.$refs[sampleItem.ref];
  733. if (elementItem) {
  734. elementItem[0].updateHistogramData();
  735. }
  736. });
  737. }, 200);
  738. },
  739. /**
  740. * Format absolute time
  741. * @param {String} time Time string
  742. * @return {String} String Formatted time
  743. */
  744. dealrelativeTime(time) {
  745. const arr = time.split(' ');
  746. const str = `${arr[0]} ${arr[1]} ${arr[2]}, ${arr[4]}`;
  747. return str;
  748. },
  749. /**
  750. * Update the data list based on the filtered tags
  751. * @param {Boolean} noPageDataNumChange No new data is added or deleted
  752. */
  753. updateTagInPage(noPageDataNumChange) {
  754. const curFilterSamples = [];
  755. // Obtains data subscript that meets the tag filtering conditions
  756. this.originDataArr.forEach((sampleItem) => {
  757. if (this.multiSelectedTagNames[sampleItem.tagName]) {
  758. curFilterSamples.push(sampleItem);
  759. }
  760. });
  761. this.curFilterSamples = curFilterSamples;
  762. // Obtains data on the current page
  763. this.getCurPageDataArr(noPageDataNumChange);
  764. },
  765. /**
  766. * Clear data
  767. */
  768. clearAllData() {
  769. if (this.curDataType === 1 && this.curViewName === 1) {
  770. this.originDataArr.forEach((sampleItem) => {
  771. const elementItem = this.$refs[sampleItem.ref];
  772. if (elementItem) {
  773. elementItem[0].clearZrData();
  774. }
  775. });
  776. }
  777. this.tagList = [];
  778. this.originDataArr = [];
  779. this.curFullTagDic = {};
  780. this.multiSelectedTagNames = {};
  781. this.curFilterSamples = [];
  782. this.pageIndex = 0;
  783. this.curPageArr = [];
  784. this.$nextTick(() => {
  785. this.$refs.multiselectGroupComponents.updateSelectedDic();
  786. });
  787. },
  788. /**
  789. * error
  790. * @param {Object} error error object
  791. */
  792. requestErrorCallback(error) {
  793. if (!this.initOver) {
  794. this.initOver = true;
  795. }
  796. if (this.isReloading) {
  797. this.$store.commit('setIsReload', false);
  798. this.isReloading = false;
  799. }
  800. if (error.response && error.response.data) {
  801. this.clearAllData();
  802. } else {
  803. if (
  804. !(error.code === 'ECONNABORTED' && /^timeout/.test(error.message))
  805. ) {
  806. // Clear data
  807. this.clearAllData();
  808. }
  809. }
  810. },
  811. /**
  812. * Update all data.
  813. * @param {Boolean} ignoreError Whether ignore error tip.
  814. */
  815. updateAllData(ignoreError) {
  816. const params = {
  817. plugin_name: 'tensor',
  818. train_id: this.trainingJobId,
  819. };
  820. RequestService.getSingleTrainJob(params, ignoreError)
  821. .then((res) => {
  822. if (this.isReloading) {
  823. this.$store.commit('setIsReload', false);
  824. this.isReloading = false;
  825. }
  826. // Fault tolerance processing
  827. if (
  828. !res ||
  829. !res.data ||
  830. !res.data.train_jobs ||
  831. !res.data.train_jobs.length ||
  832. !res.data.train_jobs[0].tags
  833. ) {
  834. this.clearAllData();
  835. return;
  836. }
  837. const data = res.data.train_jobs[0];
  838. // Remove data that does not exist.
  839. const dataRemoveFlag = this.removeNoneExistentData(data);
  840. // Add new data.
  841. const dataAddFlag = this.checkNewDataAndComplete(data);
  842. this.$nextTick(() => {
  843. this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic();
  844. this.updateTagInPage(!dataAddFlag && !dataRemoveFlag);
  845. });
  846. }, this.requestErrorCallback)
  847. .catch((e) => {
  848. this.$message.error(this.$t('public.dataError'));
  849. });
  850. },
  851. /**
  852. * Delete the data that does not exist
  853. * @param {Object} oriData Raw data with tags
  854. * @return {Boolean} Indicates whether data is removed.
  855. */
  856. removeNoneExistentData(oriData) {
  857. if (!oriData || !oriData.tags) {
  858. return false;
  859. }
  860. const newTagDictionaries = {};
  861. let dataRemoveFlag = false;
  862. // Obtains the current tag list
  863. oriData.tags.forEach((tagName) => {
  864. newTagDictionaries[tagName] = true;
  865. });
  866. // Delete data that do not exist in the operation bar
  867. const oldTagListLength = this.tagList.length;
  868. for (let i = oldTagListLength - 1; i >= 0; i--) {
  869. if (!newTagDictionaries[this.tagList[i].label]) {
  870. dataRemoveFlag = true;
  871. delete this.curFullTagDic[this.tagList[i].label];
  872. this.tagList.splice(i, 1);
  873. }
  874. }
  875. // Delete the data corresponding to the tag that does not exist.
  876. const oldSampleLength = this.originDataArr.length;
  877. for (let i = oldSampleLength - 1; i >= 0; i--) {
  878. if (!newTagDictionaries[this.originDataArr[i].tagName]) {
  879. dataRemoveFlag = true;
  880. this.originDataArr.splice(i, 1);
  881. }
  882. }
  883. return dataRemoveFlag;
  884. },
  885. /**
  886. * Check and add new data
  887. * @param {Object} oriData Raw data with tags
  888. * @return {Boolean} Check whether new data is added
  889. */
  890. checkNewDataAndComplete(oriData) {
  891. if (!oriData || !oriData.tags) {
  892. return false;
  893. }
  894. let dataAddFlag = false;
  895. oriData.tags.forEach((tagName) => {
  896. if (!this.curFullTagDic[tagName]) {
  897. this.tagList.push({
  898. label: tagName,
  899. checked: true,
  900. show: false,
  901. });
  902. this.originDataArr.push({
  903. tagName: tagName,
  904. summaryName: this.trainingJobId,
  905. show: false,
  906. showLoading: false,
  907. sliderValue: 0,
  908. newDataFlag: true,
  909. totalStepNum: 0,
  910. curStep: '',
  911. curTime: '',
  912. curDims: '',
  913. curDataType: '',
  914. fullScreen: false,
  915. ref: tagName,
  916. sliderChangeTimer: null,
  917. curData: [],
  918. formateData: [],
  919. fullData: [],
  920. filterStr: '',
  921. curMartixShowSliderValue: 0,
  922. });
  923. this.curFullTagDic[tagName] = true;
  924. dataAddFlag = true;
  925. }
  926. });
  927. return dataAddFlag;
  928. },
  929. /**
  930. * Expand/Collapse in full Screen
  931. * @param {Object} sampleItem The object that is being operated
  932. */
  933. toggleFullScreen(sampleItem) {
  934. if (!sampleItem) {
  935. return;
  936. }
  937. sampleItem.fullScreen = !sampleItem.fullScreen;
  938. this.$nextTick(() => {
  939. const elementItem = this.$refs[sampleItem.ref];
  940. if (elementItem) {
  941. elementItem[0].resizeView();
  942. elementItem[0].$el.scrollIntoView();
  943. }
  944. });
  945. },
  946. /**
  947. * Callback after the step slider changes
  948. * @param {Number} sliderValue Changed slider value
  949. * @param {Object} sampleItem The object that is being operated
  950. */
  951. sliderChange(sliderValue, sampleItem) {
  952. if (sampleItem.sliderChangeTimer) {
  953. clearTimeout(sampleItem.sliderChangeTimer);
  954. sampleItem.sliderChangeTimer = null;
  955. }
  956. if (!sampleItem.fullData || !sampleItem.fullData[sliderValue]) {
  957. return;
  958. }
  959. sampleItem.newDataFlag = true;
  960. sampleItem.formateData = sampleItem.fullData[sliderValue];
  961. sampleItem.curStep = sampleItem.formateData.step;
  962. sampleItem.curTime = this.dealrelativeTime(
  963. new Date(sampleItem.formateData.wall_time * 1000).toString(),
  964. );
  965. sampleItem.curDataType = sampleItem.formateData.value.data_type;
  966. sampleItem.curDims = JSON.stringify(sampleItem.formateData.value.dims);
  967. if (sampleItem.curMartixShowSliderValue === sliderValue) {
  968. return;
  969. }
  970. sampleItem.sliderChangeTimer = setTimeout(() => {
  971. sampleItem.showLoading = true;
  972. this.freshtMartixData(sampleItem);
  973. }, 500);
  974. },
  975. /**
  976. * Converts the original data format to a histogram-recognizable format
  977. * @param {Object} resData Original data
  978. * @return {Object} Formatted data
  979. */
  980. formHistogramOriData(resData) {
  981. const formateData = [];
  982. const histogramArr = resData.values || [];
  983. const wallTimeInit = histogramArr.length ? histogramArr[0].wall_time : 0;
  984. histogramArr.forEach((histogram, index) => {
  985. const step = histogram.step.toString();
  986. const chartItem = {
  987. wall_time: histogram.wall_time,
  988. relative_time: histogram.wall_time - wallTimeInit,
  989. step: step,
  990. items: [],
  991. };
  992. const chartArr = [];
  993. histogram.value.histogram_buckets.forEach((bucket) => {
  994. const xData = bucket[0] + bucket[1] / 2;
  995. const filter = chartArr.filter((k) => k[0] === xData);
  996. if (!filter.length) {
  997. chartArr.push([
  998. histogram.wall_time,
  999. step,
  1000. xData,
  1001. Math.floor(bucket[2]),
  1002. ]);
  1003. }
  1004. });
  1005. chartArr.sort((a, b) => a[0] - b[0]);
  1006. if (chartArr.length) {
  1007. const minItem = chartArr[0][2];
  1008. const maxItem = chartArr[chartArr.length - 1][2];
  1009. const chartAll = [
  1010. [histogram.wall_time, step, minItem, 0],
  1011. ].concat(chartArr, [[histogram.wall_time, step, maxItem, 0]]);
  1012. chartItem.items = chartAll;
  1013. formateData.push(chartItem);
  1014. }
  1015. });
  1016. return formateData;
  1017. },
  1018. /**
  1019. * Histogram display/hidden change of tip
  1020. * @param {Boolean} value Show tip
  1021. */
  1022. chartTipFlagChange(value) {
  1023. this.chartTipFlag = value;
  1024. },
  1025. },
  1026. };
  1027. </script>
  1028. <style>
  1029. .cl-tensor-manage {
  1030. height: 100%;
  1031. }
  1032. .cl-tensor-manage .tensor-bk {
  1033. height: 100%;
  1034. background-color: #fff;
  1035. display: flex;
  1036. flex-direction: column;
  1037. }
  1038. .cl-tensor-manage .tensor-bk .cl-tensor-title {
  1039. height: 56px;
  1040. line-height: 56px;
  1041. }
  1042. .cl-tensor-manage .tensor-bk .cl-tensor-title .path-message {
  1043. display: inline-block;
  1044. line-height: 20px;
  1045. padding: 0px 4px 15px 4px;
  1046. font-weight: bold;
  1047. vertical-align: bottom;
  1048. }
  1049. .cl-tensor-manage .tensor-bk .cl-tensor-title .cl-close-btn {
  1050. width: 20px;
  1051. height: 20px;
  1052. vertical-align: -3px;
  1053. cursor: pointer;
  1054. display: inline-block;
  1055. }
  1056. .cl-tensor-manage .tensor-bk .cl-tensor-operate-content {
  1057. width: 100%;
  1058. padding: 8px 32px 22px 32px;
  1059. background: #ffffff;
  1060. }
  1061. .cl-tensor-manage .tensor-bk .cl-tensor-view-type-select-content {
  1062. background: #ffffff;
  1063. padding: 0 32px 21px 32px;
  1064. height: 58px;
  1065. display: flex;
  1066. align-items: center;
  1067. border-bottom: 2px solid #e6ebf5;
  1068. }
  1069. .cl-tensor-manage .tensor-bk .cl-tensor-view-type-select-content .view-title {
  1070. font-size: 14px;
  1071. line-height: 14px;
  1072. vertical-align: middle;
  1073. margin-right: 16px;
  1074. flex-shrink: 0;
  1075. }
  1076. .cl-tensor-manage .tensor-bk .cl-tensor-view-type-select-content .el-radio-group {
  1077. margin-right: 64px;
  1078. flex-shrink: 0;
  1079. }
  1080. .cl-tensor-manage .tensor-bk .cl-show-data-content {
  1081. background: #ffffff;
  1082. padding: 0 23px;
  1083. flex: 1;
  1084. overflow: auto;
  1085. }
  1086. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content {
  1087. display: flex;
  1088. height: 100%;
  1089. width: 100%;
  1090. flex-wrap: wrap;
  1091. min-height: 400px;
  1092. position: relative;
  1093. }
  1094. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-content {
  1095. width: 33.3%;
  1096. height: 600px;
  1097. display: flex;
  1098. flex-direction: column;
  1099. flex-shrink: 0;
  1100. background-color: #fff;
  1101. position: relative;
  1102. padding: 32px 9px 0 9px;
  1103. }
  1104. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .char-full-screen {
  1105. width: 100%;
  1106. height: 600px;
  1107. }
  1108. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .chars-container {
  1109. flex: 1;
  1110. padding: 10px 15px 0 15px;
  1111. position: relative;
  1112. background: #f0f3fa;
  1113. overflow-x: hidden;
  1114. }
  1115. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .chars-container .loading-cover {
  1116. width: 100%;
  1117. height: 100%;
  1118. z-index: 9;
  1119. position: absolute;
  1120. top: 0;
  1121. left: 0;
  1122. display: flex;
  1123. background: white;
  1124. opacity: 0.5;
  1125. align-items: center;
  1126. justify-content: center;
  1127. }
  1128. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show {
  1129. padding: 32px 16px;
  1130. text-overflow: ellipsis;
  1131. white-space: nowrap;
  1132. overflow: hidden;
  1133. background-color: #f0f3fa;
  1134. margin-top: 1px;
  1135. }
  1136. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .tensor-demension,
  1137. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .tensor-type {
  1138. font-size: 14px;
  1139. line-height: 20px;
  1140. text-overflow: ellipsis;
  1141. white-space: nowrap;
  1142. overflow: hidden;
  1143. }
  1144. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .tensor-demension span,
  1145. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .tensor-type span {
  1146. color: #00a5a7;
  1147. }
  1148. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .sample-operate-info {
  1149. width: 100%;
  1150. min-height: 24px;
  1151. vertical-align: middle;
  1152. line-height: 20px;
  1153. margin-top: 24px;
  1154. color: #000000;
  1155. position: relative;
  1156. text-overflow: ellipsis;
  1157. white-space: nowrap;
  1158. overflow: hidden;
  1159. }
  1160. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .sample-operate-info span {
  1161. max-width: 100%;
  1162. text-overflow: ellipsis;
  1163. white-space: nowrap;
  1164. overflow: hidden;
  1165. }
  1166. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .sample-operate-info .step-info {
  1167. left: 0;
  1168. font-size: 14px;
  1169. }
  1170. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .sample-operate-info .time-info {
  1171. right: 0;
  1172. float: right;
  1173. font-size: 14px;
  1174. }
  1175. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .sample-data-show .step-slider {
  1176. margin-top: 10px;
  1177. }
  1178. .cl-tensor-manage .tensor-bk .cl-show-data-content .data-content .tag-title {
  1179. margin-top: 10px;
  1180. width: 100%;
  1181. font-size: 16px;
  1182. font-weight: 600;
  1183. text-align: center;
  1184. }
  1185. .cl-tensor-manage .tensor-bk .pagination-content {
  1186. padding: 24px 32px;
  1187. text-align: right;
  1188. }
  1189. .cl-tensor-manage .tensor-bk .image-noData {
  1190. width: 100%;
  1191. height: 100%;
  1192. display: flex;
  1193. justify-content: center;
  1194. align-items: center;
  1195. flex-direction: column;
  1196. }
  1197. .cl-tensor-manage .content {
  1198. position: relative;
  1199. }
  1200. .cl-tensor-manage #echart {
  1201. width: 500px;
  1202. height: 500px;
  1203. border: 1px solid black;
  1204. position: relative;
  1205. }
  1206. .cl-tensor-manage #echartTip {
  1207. position: absolute;
  1208. padding: 5px;
  1209. z-index: 9999;
  1210. font-size: 14px;
  1211. font-family: "Microsoft YaHei";
  1212. background-color: rgba(50, 50, 50, 0.7);
  1213. border: 0;
  1214. border-radius: 4px;
  1215. color: #fff;
  1216. }
  1217. .cl-tensor-manage .char-tip-table td {
  1218. padding-left: 5px;
  1219. padding-right: 5px;
  1220. text-overflow: ellipsis;
  1221. white-space: nowrap;
  1222. max-width: 150px;
  1223. overflow: hidden;
  1224. }
  1225. .cl-tensor-manage .borderspacing3 {
  1226. border-spacing: 3px;
  1227. }
  1228. </style>