| @@ -1,3 +1,3 @@ | |||||
| [submodule "third_party/securec"] | [submodule "third_party/securec"] | ||||
| path = third_party/securec | path = third_party/securec | ||||
| url = https://gitee.com/openeuler/bounds_checking_function.git | |||||
| url = https://gitee.com/openeuler/libboundscheck.git | |||||
| @@ -68,6 +68,11 @@ training process, such as loss value and accuracy rate of each iteration. | |||||
| Two scalar curves can be combined and displayed in one chart. | Two scalar curves can be combined and displayed in one chart. | ||||
| ### Parameter distribution | |||||
| The GUI of MindInsight displays the distribution change tendency of a tensor such as weight | |||||
| or gradient during the entire training process. | |||||
| ### Image visualization | ### Image visualization | ||||
| The GUI of MindInsight displays both original images and enhanced images during the entire | The GUI of MindInsight displays both original images and enhanced images during the entire | ||||
| @@ -1,5 +1,28 @@ | |||||
| ## MindInsight | ## MindInsight | ||||
| # Release 0.2.0-alpha | |||||
| ## Major Features and Improvements | |||||
| * Parameter distribution graph (Histogram). | |||||
| Now you can use [`HistogramSummary`](https://www.mindspore.cn/api/zh-CN/master/api/python/mindspore/mindspore.ops.operations.html#mindspore.ops.operations.HistogramSummary) and MindInsight to record and visualize distribution info of tensors. See our [tutorial](https://www.mindspore.cn/tutorial/zh-CN/master/advanced_use/visualization_tutorials.html) for details. | |||||
| * Lineage support Custom information | |||||
| * GPU support | |||||
| * Model and dataset tracking linkage support | |||||
| ## Bugfixes | |||||
| * Reduce cyclomatic complexity of `list_summary_directories` ([!11](https://gitee.com/mindspore/mindinsight/pulls/11)). | |||||
| * Fix unsafe functions and duplication files and redundant codes ([!14](https://gitee.com/mindspore/mindinsight/pulls/14)). | |||||
| * Fix sha256 checksum missing bug ([!24](https://gitee.com/mindspore/mindinsight/pulls/24)). | |||||
| * Fix graph bug when node name is empty ([!34](https://gitee.com/mindspore/mindinsight/pulls/34)). | |||||
| * Fix start/stop command exit-code incorrect ([!44](https://gitee.com/mindspore/mindinsight/pulls/44)). | |||||
| ## Thanks to our Contributors | |||||
| Thanks goes to these wonderful people: | |||||
| Ye Huang, Weifeng Huang, Zhenzhong Kou, Pengting Luo, Hongzhang Li, Yongxiong Liang, Gongchang Ou, Hui Pan, Luyu Qiu, Junyan Qin, Kai Wen, Weining Wang, Yifan Xia, Yunshu Zhang, Ting Zhao | |||||
| Contributions of any kind are welcome! | |||||
| # Release 0.1.0-alpha | # Release 0.1.0-alpha | ||||
| * Training process observation | * Training process observation | ||||
| @@ -23,13 +23,13 @@ from mindinsight.conf import settings | |||||
| # Type of the tensor event from external component | # Type of the tensor event from external component | ||||
| _Tensor = collections.namedtuple('_Tensor', ['wall_time', 'step', 'value']) | |||||
| _Tensor = collections.namedtuple('_Tensor', ['wall_time', 'step', 'value', 'filename']) | |||||
| TensorEvent = collections.namedtuple( | TensorEvent = collections.namedtuple( | ||||
| 'TensorEvent', ['wall_time', 'step', 'tag', 'plugin_name', 'value']) | |||||
| 'TensorEvent', ['wall_time', 'step', 'tag', 'plugin_name', 'value', 'filename']) | |||||
| # config for `EventsData` | # config for `EventsData` | ||||
| _DEFAULT_STEP_SIZES_PER_TAG = settings.DEFAULT_STEP_SIZES_PER_TAG | _DEFAULT_STEP_SIZES_PER_TAG = settings.DEFAULT_STEP_SIZES_PER_TAG | ||||
| _MAX_DELETED_TAGS_SIZE = settings.MAX_TAG_SIZE_PER_EVENTS_DATA * 100 | |||||
| CONFIG = { | CONFIG = { | ||||
| 'max_total_tag_sizes': settings.MAX_TAG_SIZE_PER_EVENTS_DATA, | 'max_total_tag_sizes': settings.MAX_TAG_SIZE_PER_EVENTS_DATA, | ||||
| 'max_tag_sizes_per_plugin': | 'max_tag_sizes_per_plugin': | ||||
| @@ -60,6 +60,7 @@ class EventsData: | |||||
| self._max_step_sizes_per_tag = self._config['max_step_sizes_per_tag'] | self._max_step_sizes_per_tag = self._config['max_step_sizes_per_tag'] | ||||
| self._tags = list() | self._tags = list() | ||||
| self._deleted_tags = set() | |||||
| self._reservoir_by_tag = {} | self._reservoir_by_tag = {} | ||||
| self._reservoir_mutex_lock = threading.Lock() | self._reservoir_mutex_lock = threading.Lock() | ||||
| @@ -82,6 +83,8 @@ class EventsData: | |||||
| if tag not in set(self._tags): | if tag not in set(self._tags): | ||||
| deleted_tag = self._check_tag_out_of_spec(plugin_name) | deleted_tag = self._check_tag_out_of_spec(plugin_name) | ||||
| if deleted_tag is not None: | if deleted_tag is not None: | ||||
| if tag in self._deleted_tags: | |||||
| return | |||||
| self.delete_tensor_event(deleted_tag) | self.delete_tensor_event(deleted_tag) | ||||
| self._tags.append(tag) | self._tags.append(tag) | ||||
| @@ -99,10 +102,11 @@ class EventsData: | |||||
| tensor = _Tensor(wall_time=tensor_event.wall_time, | tensor = _Tensor(wall_time=tensor_event.wall_time, | ||||
| step=tensor_event.step, | step=tensor_event.step, | ||||
| value=tensor_event.value) | |||||
| value=tensor_event.value, | |||||
| filename=tensor_event.filename) | |||||
| if self._is_out_of_order_step(tensor_event.step, tensor_event.tag): | if self._is_out_of_order_step(tensor_event.step, tensor_event.tag): | ||||
| self.purge_reservoir_data(tensor_event.step, self._reservoir_by_tag[tag]) | |||||
| self.purge_reservoir_data(tensor_event.filename, tensor_event.step, self._reservoir_by_tag[tag]) | |||||
| self._reservoir_by_tag[tag].add_sample(tensor) | self._reservoir_by_tag[tag].add_sample(tensor) | ||||
| @@ -113,6 +117,8 @@ class EventsData: | |||||
| Args: | Args: | ||||
| tag (str): The tag name. | tag (str): The tag name. | ||||
| """ | """ | ||||
| if len(self._deleted_tags) < _MAX_DELETED_TAGS_SIZE: | |||||
| self._deleted_tags.add(tag) | |||||
| self._tags.remove(tag) | self._tags.remove(tag) | ||||
| for plugin_name, lock in self._tags_by_plugin_mutex_lock.items(): | for plugin_name, lock in self._tags_by_plugin_mutex_lock.items(): | ||||
| with lock: | with lock: | ||||
| @@ -176,7 +182,7 @@ class EventsData: | |||||
| return False | return False | ||||
| @staticmethod | @staticmethod | ||||
| def purge_reservoir_data(start_step, tensor_reservoir): | |||||
| def purge_reservoir_data(filename, start_step, tensor_reservoir): | |||||
| """ | """ | ||||
| Purge all tensor event that are out-of-order step after the given start step. | Purge all tensor event that are out-of-order step after the given start step. | ||||
| @@ -188,7 +194,8 @@ class EventsData: | |||||
| Returns: | Returns: | ||||
| int, the number of items removed. | int, the number of items removed. | ||||
| """ | """ | ||||
| cnt_out_of_order = tensor_reservoir.remove_sample(lambda x: x.step < start_step) | |||||
| cnt_out_of_order = tensor_reservoir.remove_sample( | |||||
| lambda x: x.step < start_step or (x.step > start_step and x.filename == filename)) | |||||
| return cnt_out_of_order | return cnt_out_of_order | ||||
| @@ -72,6 +72,10 @@ class Bucket: | |||||
| class HistogramContainer: | class HistogramContainer: | ||||
| # Max quantity of original buckets. | |||||
| MAX_ORIGINAL_BUCKETS_COUNT = 90 | |||||
| """ | """ | ||||
| Histogram data container. | Histogram data container. | ||||
| @@ -114,6 +118,11 @@ class HistogramContainer: | |||||
| """Gets original proto message.""" | """Gets original proto message.""" | ||||
| return self._msg | return self._msg | ||||
| @property | |||||
| def original_buckets_count(self): | |||||
| """Gets original buckets quantity.""" | |||||
| return len(self._original_buckets) | |||||
| def set_visual_range(self, max_val: float, min_val: float, bins: int) -> None: | def set_visual_range(self, max_val: float, min_val: float, bins: int) -> None: | ||||
| """ | """ | ||||
| Sets visual range for later re-sampling. | Sets visual range for later re-sampling. | ||||
| @@ -223,7 +223,8 @@ class MSDataLoader: | |||||
| step=event.step, | step=event.step, | ||||
| tag=tag, | tag=tag, | ||||
| plugin_name=PluginNameEnum.SCALAR.value, | plugin_name=PluginNameEnum.SCALAR.value, | ||||
| value=value.scalar_value) | |||||
| value=value.scalar_value, | |||||
| filename=self._latest_summary_filename) | |||||
| self._events_data.add_tensor_event(tensor_event) | self._events_data.add_tensor_event(tensor_event) | ||||
| if value.HasField('image'): | if value.HasField('image'): | ||||
| @@ -232,18 +233,25 @@ class MSDataLoader: | |||||
| step=event.step, | step=event.step, | ||||
| tag=tag, | tag=tag, | ||||
| plugin_name=PluginNameEnum.IMAGE.value, | plugin_name=PluginNameEnum.IMAGE.value, | ||||
| value=value.image) | |||||
| value=value.image, | |||||
| filename=self._latest_summary_filename) | |||||
| self._events_data.add_tensor_event(tensor_event) | self._events_data.add_tensor_event(tensor_event) | ||||
| if value.HasField('histogram'): | if value.HasField('histogram'): | ||||
| histogram_msg = HistogramContainer(value.histogram) | histogram_msg = HistogramContainer(value.histogram) | ||||
| tag = '{}/{}'.format(value.tag, PluginNameEnum.HISTOGRAM.value) | |||||
| tensor_event = TensorEvent(wall_time=event.wall_time, | |||||
| step=event.step, | |||||
| tag=tag, | |||||
| plugin_name=PluginNameEnum.HISTOGRAM.value, | |||||
| value=histogram_msg) | |||||
| self._events_data.add_tensor_event(tensor_event) | |||||
| # Drop steps if original_buckets_count exceeds HistogramContainer.MAX_ORIGINAL_BUCKETS_COUNT | |||||
| # to avoid time-consuming re-sample process. | |||||
| if histogram_msg.original_buckets_count > HistogramContainer.MAX_ORIGINAL_BUCKETS_COUNT: | |||||
| logger.warning('original_buckets_count exceeds HistogramContainer.MAX_ORIGINAL_BUCKETS_COUNT') | |||||
| else: | |||||
| tag = '{}/{}'.format(value.tag, PluginNameEnum.HISTOGRAM.value) | |||||
| tensor_event = TensorEvent(wall_time=event.wall_time, | |||||
| step=event.step, | |||||
| tag=tag, | |||||
| plugin_name=PluginNameEnum.HISTOGRAM.value, | |||||
| value=histogram_msg, | |||||
| filename=self._latest_summary_filename) | |||||
| self._events_data.add_tensor_event(tensor_event) | |||||
| if event.HasField('graph_def'): | if event.HasField('graph_def'): | ||||
| graph_proto = event.graph_def | graph_proto = event.graph_def | ||||
| @@ -253,7 +261,8 @@ class MSDataLoader: | |||||
| step=event.step, | step=event.step, | ||||
| tag=self._latest_summary_filename, | tag=self._latest_summary_filename, | ||||
| plugin_name=PluginNameEnum.GRAPH.value, | plugin_name=PluginNameEnum.GRAPH.value, | ||||
| value=graph) | |||||
| value=graph, | |||||
| filename=self._latest_summary_filename) | |||||
| try: | try: | ||||
| graph_tags = self._events_data.list_tags_by_plugin(PluginNameEnum.GRAPH.value) | graph_tags = self._events_data.list_tags_by_plugin(PluginNameEnum.GRAPH.value) | ||||
| @@ -436,7 +445,8 @@ class _PbParser: | |||||
| step=0, | step=0, | ||||
| tag=filename, | tag=filename, | ||||
| plugin_name=PluginNameEnum.GRAPH.value, | plugin_name=PluginNameEnum.GRAPH.value, | ||||
| value=graph) | |||||
| value=graph, | |||||
| filename=filename) | |||||
| logger.info("Build graph success, file path: %s.", file_path) | logger.info("Build graph success, file path: %s.", file_path) | ||||
| return tensor_event | return tensor_event | ||||
| @@ -23,6 +23,24 @@ from mindinsight.utils.exceptions import ParamValueError | |||||
| from mindinsight.datavisual.utils.utils import calc_histogram_bins | from mindinsight.datavisual.utils.utils import calc_histogram_bins | ||||
| def binary_search(samples, target): | |||||
| """Binary search target in samples.""" | |||||
| left = 0 | |||||
| right = len(samples) - 1 | |||||
| while left <= right: | |||||
| mid = (left + right) // 2 | |||||
| if target < samples[mid].step: | |||||
| right = mid - 1 | |||||
| elif target > samples[mid].step: | |||||
| left = mid + 1 | |||||
| else: | |||||
| return mid | |||||
| # if right is -1, it is less than the first one. | |||||
| # if list is [1, 2, 4], target is 3, right will be 1, so wo will insert by 2. | |||||
| return right + 1 | |||||
| class Reservoir: | class Reservoir: | ||||
| """ | """ | ||||
| A container based on Reservoir Sampling algorithm. | A container based on Reservoir Sampling algorithm. | ||||
| @@ -68,18 +86,28 @@ class Reservoir: | |||||
| """ | """ | ||||
| with self._mutex: | with self._mutex: | ||||
| if len(self._samples) < self._samples_max_size or self._samples_max_size == 0: | if len(self._samples) < self._samples_max_size or self._samples_max_size == 0: | ||||
| self._samples.append(sample) | |||||
| self._add_sample(sample) | |||||
| else: | else: | ||||
| # Use the Reservoir Sampling algorithm to replace the old sample. | # Use the Reservoir Sampling algorithm to replace the old sample. | ||||
| rand_int = self._sample_selector.randint( | |||||
| 0, self._sample_counter) | |||||
| rand_int = self._sample_selector.randint(0, self._sample_counter) | |||||
| if rand_int < self._samples_max_size: | if rand_int < self._samples_max_size: | ||||
| self._samples.pop(rand_int) | self._samples.pop(rand_int) | ||||
| self._samples.append(sample) | |||||
| else: | else: | ||||
| self._samples[-1] = sample | |||||
| self._samples = self._samples[:-1] | |||||
| self._add_sample(sample) | |||||
| self._sample_counter += 1 | self._sample_counter += 1 | ||||
| def _add_sample(self, sample): | |||||
| """Search the index and add sample.""" | |||||
| if not self._samples or sample.step > self._samples[-1].step: | |||||
| self._samples.append(sample) | |||||
| return | |||||
| index = binary_search(self._samples, sample.step) | |||||
| if index == len(self._samples): | |||||
| self._samples.append(sample) | |||||
| else: | |||||
| self._samples.insert(index, sample) | |||||
| def remove_sample(self, filter_fun): | def remove_sample(self, filter_fun): | ||||
| """ | """ | ||||
| Remove the samples from Reservoir that do not meet the filter criteria. | Remove the samples from Reservoir that do not meet the filter criteria. | ||||
| @@ -288,8 +288,8 @@ class Querier: | |||||
| try: | try: | ||||
| cmp_result = (value1 > value2) - (value1 < value2) | cmp_result = (value1 > value2) - (value1 < value2) | ||||
| except TypeError: | except TypeError: | ||||
| type1 = str(type(value1)) | |||||
| type2 = str(type(value2)) | |||||
| type1 = type(value1).__name__ | |||||
| type2 = type(value2).__name__ | |||||
| cmp_result = (type1 > type2) - (type1 < type2) | cmp_result = (type1 > type2) - (type1 < type2) | ||||
| return cmp_result | return cmp_result | ||||
| @@ -314,19 +314,7 @@ class Querier: | |||||
| offset_results = self._handle_limit_and_offset(condition, results) | offset_results = self._handle_limit_and_offset(condition, results) | ||||
| customized = dict() | |||||
| for offset_result in offset_results: | |||||
| for obj_name in ["metric", "user_defined"]: | |||||
| obj = getattr(offset_result, obj_name) | |||||
| require = bool(obj_name == "metric") | |||||
| if obj and isinstance(obj, dict): | |||||
| for key, value in obj.items(): | |||||
| label = f'{obj_name}/{key}' | |||||
| customized[label] = dict() | |||||
| customized[label]["label"] = label | |||||
| # user defined info is not displayed by default | |||||
| customized[label]["required"] = require | |||||
| customized[label]["type"] = type(value).__name__ | |||||
| customized = self._organize_customized(offset_results) | |||||
| lineage_types = condition.get(ConditionParam.LINEAGE_TYPE.value) | lineage_types = condition.get(ConditionParam.LINEAGE_TYPE.value) | ||||
| lineage_types = self._get_lineage_types(lineage_types) | lineage_types = self._get_lineage_types(lineage_types) | ||||
| @@ -348,6 +336,41 @@ class Querier: | |||||
| return lineage_info | return lineage_info | ||||
| def _organize_customized(self, offset_results): | |||||
| """Organize customized.""" | |||||
| customized = dict() | |||||
| for offset_result in offset_results: | |||||
| for obj_name in ["metric", "user_defined"]: | |||||
| self._organize_customized_item(customized, offset_result, obj_name) | |||||
| # If types contain numbers and string, it will be "mixed". | |||||
| # If types contain "int" and "float", it will be "float". | |||||
| for key, value in customized.items(): | |||||
| types = value["type"] | |||||
| if len(types) == 1: | |||||
| customized[key]["type"] = list(types)[0] | |||||
| elif types.issubset(["int", "float"]): | |||||
| customized[key]["type"] = "float" | |||||
| else: | |||||
| customized[key]["type"] = "mixed" | |||||
| return customized | |||||
| def _organize_customized_item(self, customized, offset_result, obj_name): | |||||
| """Organize customized item.""" | |||||
| obj = getattr(offset_result, obj_name) | |||||
| require = bool(obj_name == "metric") | |||||
| if obj and isinstance(obj, dict): | |||||
| for key, value in obj.items(): | |||||
| label = f'{obj_name}/{key}' | |||||
| current_type = type(value).__name__ | |||||
| if customized.get(label) is None: | |||||
| customized[label] = dict() | |||||
| customized[label]["label"] = label | |||||
| # user defined info is not displayed by default | |||||
| customized[label]["required"] = require | |||||
| customized[label]["type"] = set() | |||||
| customized[label]["type"].add(current_type) | |||||
| def _get_lineage_types(self, lineage_type_param): | def _get_lineage_types(self, lineage_type_param): | ||||
| """ | """ | ||||
| Get lineage types. | Get lineage types. | ||||
| @@ -70,13 +70,13 @@ def _package_current_dataset(operation, message): | |||||
| message (Operation): Operation proto message. | message (Operation): Operation proto message. | ||||
| """ | """ | ||||
| for key, value in operation.items(): | for key, value in operation.items(): | ||||
| if key == "operations": | |||||
| if value and key == "operations": | |||||
| for operator in value: | for operator in value: | ||||
| _package_enhancement_operation( | _package_enhancement_operation( | ||||
| operator, | operator, | ||||
| message.operations.add() | message.operations.add() | ||||
| ) | ) | ||||
| elif key == "sampler": | |||||
| elif value and key == "sampler": | |||||
| _package_enhancement_operation( | _package_enhancement_operation( | ||||
| value, | value, | ||||
| message.sampler | message.sampler | ||||
| @@ -93,7 +93,6 @@ def _package_enhancement_operation(operation, message): | |||||
| operation (dict): Enhancement operation. | operation (dict): Enhancement operation. | ||||
| message (Operation): Enhancement operation proto message. | message (Operation): Enhancement operation proto message. | ||||
| """ | """ | ||||
| for key, value in operation.items(): | for key, value in operation.items(): | ||||
| if isinstance(value, list): | if isinstance(value, list): | ||||
| if all(isinstance(ele, int) for ele in value): | if all(isinstance(ele, int) for ele in value): | ||||
| @@ -21,7 +21,7 @@ limitations under the License. | |||||
| <meta charset="utf-8" /> | <meta charset="utf-8" /> | ||||
| <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | <meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||||
| <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | <meta name="viewport" content="width=device-width,initial-scale=1.0" /> | ||||
| <link rel="icon" href="<%= BASE_URL %>/static/img/favicon.ico" /> | |||||
| <link rel="icon" href="<%= BASE_URL %>/static/img/favicon.png" /> | |||||
| <title>MindInsight</title> | <title>MindInsight</title> | ||||
| <style> | <style> | ||||
| .errorInfo { | .errorInfo { | ||||
| @@ -96,4 +96,14 @@ export default { | |||||
| '.edge.highlighted path {stroke: red;}.edge.highlighted polygon {' + | '.edge.highlighted path {stroke: red;}.edge.highlighted polygon {' + | ||||
| 'stroke: red;fill: red;}' + | 'stroke: red;fill: red;}' + | ||||
| '.edge.highlighted marker path {fill: red;}</style>', | '.edge.highlighted marker path {fill: red;}</style>', | ||||
| dataMapDownloadStyle: '<style> #graph0 > polygon { fill: transparent; }' + | |||||
| '.node, .cluster { cursor: pointer; }' + | |||||
| '.selected { polygon, ellipse { stroke: red !important; stroke-width: 2px; } }' + | |||||
| '.CreatDataset > polygon, .Operator > ellipse { stroke: #58a4e0; fill: #d1ebff; }' + | |||||
| '.cluster > polygon { fill: #c1f5d5; stroke: #56b077; }' + | |||||
| '.RepeatDataset > polygon { stroke: #fdca5a; fill: #fff2d4; }' + | |||||
| '.ShuffleDataset > polygon { stroke: #f79666; fill: #fed78e; }' + | |||||
| '.BatchDataset > polygon { stroke: #fa8e5a; fill: #ffcfb8; }' + | |||||
| '.edge { path { stroke: rgb(167, 167, 167); }' + | |||||
| 'polygon { fill: rgb(167, 167, 167); stroke: rgb(167, 167, 167); } }</style>', | |||||
| }; | }; | ||||
| @@ -99,6 +99,7 @@ export default { | |||||
| multiSelectedItemNames: {}, // Dictionary for storing the name of the selected tags. | multiSelectedItemNames: {}, // Dictionary for storing the name of the selected tags. | ||||
| operateSelectAll: true, // Indicates whether to select all tags. | operateSelectAll: true, // Indicates whether to select all tags. | ||||
| perSelectItemMarginBottom: 1, // Outer margin of the bottom of each selection box. | perSelectItemMarginBottom: 1, // Outer margin of the bottom of each selection box. | ||||
| searching: false, | |||||
| }; | }; | ||||
| }, | }, | ||||
| computed: {}, | computed: {}, | ||||
| @@ -156,11 +157,13 @@ export default { | |||||
| * Tag Filter | * Tag Filter | ||||
| */ | */ | ||||
| listFilter() { | listFilter() { | ||||
| this.searching = true; | |||||
| if (this.searchInputTimer) { | if (this.searchInputTimer) { | ||||
| clearTimeout(this.searchInputTimer); | clearTimeout(this.searchInputTimer); | ||||
| this.searchInputTimer = null; | this.searchInputTimer = null; | ||||
| } | } | ||||
| this.searchInputTimer = setTimeout(() => { | this.searchInputTimer = setTimeout(() => { | ||||
| this.searching = false; | |||||
| let reg; | let reg; | ||||
| try { | try { | ||||
| reg = new RegExp(this.searchInput); | reg = new RegExp(this.searchInput); | ||||
| @@ -234,6 +237,9 @@ export default { | |||||
| * @return {Object} Dictionary containing selected tags | * @return {Object} Dictionary containing selected tags | ||||
| */ | */ | ||||
| updateSelectedDic() { | updateSelectedDic() { | ||||
| if (this.searching) { | |||||
| return this.multiSelectedItemNames; | |||||
| } | |||||
| let reg; | let reg; | ||||
| try { | try { | ||||
| reg = new RegExp(this.searchInput); | reg = new RegExp(this.searchInput); | ||||
| @@ -45,19 +45,20 @@ | |||||
| "learningRate": "学习率", | "learningRate": "学习率", | ||||
| "modelSize": "模型大小", | "modelSize": "模型大小", | ||||
| "dataProcess": "数据处理", | "dataProcess": "数据处理", | ||||
| "noDataFound":"暂无满足筛选条件的数据", | |||||
| "noDataTips":"请点击“显示全量数据”按钮查看全量数据", | |||||
| "noDataFound": "暂无满足筛选条件的数据", | |||||
| "noDataTips": "请点击“显示全量数据”按钮查看全量数据", | |||||
| "userDefined": "自定义数据", | "userDefined": "自定义数据", | ||||
| "metric": "度量指标", | "metric": "度量指标", | ||||
| "deviceNum": "device数目" | |||||
| "deviceNum": "device数目", | |||||
| "mixedItemMessage": "该参数含有多种类型数据,无法筛选展示" | |||||
| }, | }, | ||||
| "dataTraceback": { | "dataTraceback": { | ||||
| "details": "详情", | "details": "详情", | ||||
| "key": "KEY", | "key": "KEY", | ||||
| "value": "VALUE", | "value": "VALUE", | ||||
| "dataTraceTips": "该数据涉及合并操作", | "dataTraceTips": "该数据涉及合并操作", | ||||
| "noDataFound":"暂无满足筛选条件的数据", | |||||
| "noDataTips":"请点击“显示全量数据”按钮查看全量数据" | |||||
| "noDataFound": "暂无满足筛选条件的数据", | |||||
| "noDataTips": "请点击“显示全量数据”按钮查看全量数据" | |||||
| }, | }, | ||||
| "trainingDashboard": { | "trainingDashboard": { | ||||
| "trainingDashboardTitle": "训练看板", | "trainingDashboardTitle": "训练看板", | ||||
| @@ -66,7 +67,8 @@ | |||||
| "trainingScalar": "训练标量信息", | "trainingScalar": "训练标量信息", | ||||
| "samplingData": "数据抽样", | "samplingData": "数据抽样", | ||||
| "imagesampleSwitch": "切换标签", | "imagesampleSwitch": "切换标签", | ||||
| "invalidId": "无效的训练作业" | |||||
| "invalidId": "无效的训练作业", | |||||
| "summaryDirPath": "summary路径:" | |||||
| }, | }, | ||||
| "scalar": { | "scalar": { | ||||
| "titleText": "标量", | "titleText": "标量", | ||||
| @@ -120,6 +122,7 @@ | |||||
| "graph": { | "graph": { | ||||
| "titleText": "计算图", | "titleText": "计算图", | ||||
| "downloadPic": "下载", | "downloadPic": "下载", | ||||
| "fitScreen": "适应屏幕", | |||||
| "nodeInfo": "节点信息", | "nodeInfo": "节点信息", | ||||
| "legend": "图例", | "legend": "图例", | ||||
| "nameSpace": "命名空间", | "nameSpace": "命名空间", | ||||
| @@ -46,6 +46,12 @@ limitations under the License. | |||||
| <div :title="$t('graph.fullScreen')" | <div :title="$t('graph.fullScreen')" | ||||
| class="full-screen-button" | class="full-screen-button" | ||||
| @click="fullScreen = !fullScreen"></div> | @click="fullScreen = !fullScreen"></div> | ||||
| <div :title="$t('graph.fitScreen')" | |||||
| class="fit-screen" | |||||
| @click="fit()"></div> | |||||
| <div :title="$t('graph.downloadPic')" | |||||
| class="download-button" | |||||
| @click="downLoadSVG"></div> | |||||
| </div> | </div> | ||||
| <!-- Right column --> | <!-- Right column --> | ||||
| <div id="sidebar" | <div id="sidebar" | ||||
| @@ -138,6 +144,7 @@ limitations under the License. | |||||
| <script> | <script> | ||||
| import RequestService from '../../services/request-service'; | import RequestService from '../../services/request-service'; | ||||
| import CommonProperty from '@/common/common-property.js'; | |||||
| import {select, selectAll, zoom} from 'd3'; | import {select, selectAll, zoom} from 'd3'; | ||||
| import 'd3-graphviz'; | import 'd3-graphviz'; | ||||
| const d3 = {select, selectAll, zoom}; | const d3 = {select, selectAll, zoom}; | ||||
| @@ -340,6 +347,7 @@ export default { | |||||
| * Initialization method executed after the graph rendering is complete | * Initialization method executed after the graph rendering is complete | ||||
| */ | */ | ||||
| startApp() { | startApp() { | ||||
| this.initZooming(); | |||||
| const nodes = d3.selectAll('g.node, g.cluster'); | const nodes = d3.selectAll('g.node, g.cluster'); | ||||
| nodes.on('click', (target, index, nodesList) => { | nodes.on('click', (target, index, nodesList) => { | ||||
| this.selectNodeInfo(target); | this.selectNodeInfo(target); | ||||
| @@ -347,9 +355,109 @@ export default { | |||||
| nodes.classed('selected', false); | nodes.classed('selected', false); | ||||
| d3.select(`g[id="${selectedNode.id}"]`).classed('selected', true); | d3.select(`g[id="${selectedNode.id}"]`).classed('selected', true); | ||||
| }); | }); | ||||
| d3.select('svg').on('dblclick.zoom', null); | |||||
| }, | }, | ||||
| /** | |||||
| * Initializing the Zoom Function of a Graph | |||||
| */ | |||||
| initZooming() { | |||||
| const graphDom = document.querySelector('#graph0'); | |||||
| const graphBox = graphDom.getBBox(); | |||||
| const padding = 4; | |||||
| const pointer = { | |||||
| start: { | |||||
| x: 0, | |||||
| y: 0, | |||||
| }, | |||||
| end: { | |||||
| x: 0, | |||||
| y: 0, | |||||
| }, | |||||
| }; | |||||
| const zoom = d3 | |||||
| .zoom() | |||||
| .on('start', (target) => { | |||||
| pointer.start.x = event.x; | |||||
| pointer.start.y = event.y; | |||||
| }) | |||||
| .on('zoom', (target) => { | |||||
| const transformData = this.getTransformData(graphDom); | |||||
| let tempStr = ''; | |||||
| let change = {}; | |||||
| let scale = transformData.scale[0]; | |||||
| const graphRect = graphDom.getBoundingClientRect(); | |||||
| const mapping = { | |||||
| width: graphBox.width / graphRect.width, | |||||
| height: graphBox.height / graphRect.height, | |||||
| }; | |||||
| if (event.type === 'mousemove') { | |||||
| pointer.end.x = event.x; | |||||
| pointer.end.y = event.y; | |||||
| change = { | |||||
| x: (pointer.end.x - pointer.start.x) * mapping.width * scale, | |||||
| y: (pointer.end.y - pointer.start.y) * mapping.height * scale, | |||||
| }; | |||||
| pointer.start.x = pointer.end.x; | |||||
| pointer.start.y = pointer.end.y; | |||||
| } else if (event.type === 'wheel') { | |||||
| const wheelDelta = event.wheelDelta; | |||||
| const rate = Math.abs(wheelDelta / 100); | |||||
| scale = | |||||
| wheelDelta > 0 | |||||
| ? transformData.scale[0] * rate | |||||
| : transformData.scale[0] / rate; | |||||
| scale = Math.max(this.scaleRange[0], scale); | |||||
| scale = Math.min(this.scaleRange[1], scale); | |||||
| change = { | |||||
| x: | |||||
| (graphRect.x + padding / mapping.width - event.x) * | |||||
| mapping.width * | |||||
| (scale - transformData.scale[0]), | |||||
| y: | |||||
| (graphRect.bottom - padding / mapping.height - event.y) * | |||||
| mapping.height * | |||||
| (scale - transformData.scale[0]), | |||||
| }; | |||||
| } | |||||
| tempStr = `translate(${transformData.translate[0] + | |||||
| change.x},${transformData.translate[1] + | |||||
| change.y}) scale(${scale})`; | |||||
| graphDom.setAttribute('transform', tempStr); | |||||
| }); | |||||
| const svg = d3.select('svg'); | |||||
| svg.on('.zoom', null); | |||||
| svg.call(zoom); | |||||
| svg.on('dblclick.zoom', null); | |||||
| }, | |||||
| /** | |||||
| * Obtains the transform data of a node. | |||||
| * @param {Object} node Node dom data | |||||
| * @return {Object} transform data of a node | |||||
| */ | |||||
| getTransformData(node) { | |||||
| if (!node) { | |||||
| return []; | |||||
| } | |||||
| const transformData = node.getAttribute('transform'); | |||||
| const attrObj = {}; | |||||
| if (transformData) { | |||||
| const lists = transformData.trim().split(' '); | |||||
| lists.forEach((item) => { | |||||
| const index1 = item.indexOf('('); | |||||
| const index2 = item.indexOf(')'); | |||||
| const name = item.substring(0, index1); | |||||
| const params = item | |||||
| .substring(index1 + 1, index2) | |||||
| .split(',') | |||||
| .map((i) => { | |||||
| return parseFloat(i) || 0; | |||||
| }); | |||||
| attrObj[name] = params; | |||||
| }); | |||||
| } | |||||
| return attrObj; | |||||
| }, | |||||
| /** | /** | ||||
| * Process the selected node information. | * Process the selected node information. | ||||
| * @param {Object} target Selected Object | * @param {Object} target Selected Object | ||||
| @@ -397,6 +505,36 @@ export default { | |||||
| }); | }); | ||||
| } | } | ||||
| }, | }, | ||||
| /** | |||||
| * Adapt to the screen | |||||
| */ | |||||
| fit() { | |||||
| const graphDom = document.getElementById('graph0'); | |||||
| const box = graphDom.getBBox(); | |||||
| const str = `translate(${-box.x},${-box.y}) scale(1)`; | |||||
| graphDom.setAttribute('transform', str); | |||||
| }, | |||||
| /** | |||||
| * Download svg | |||||
| */ | |||||
| downLoadSVG() { | |||||
| const svgXml = document.querySelector('#graph #graph0').innerHTML; | |||||
| const bbox = document.getElementById('graph0').getBBox(); | |||||
| const viewBoxSize = `${bbox.x} ${bbox.y} ${bbox.width} ${bbox.height}`; | |||||
| const encodeStr = | |||||
| `<svg xmlns="http://www.w3.org/2000/svg" ` + | |||||
| `xmlns:xlink="http://www.w3.org/1999/xlink" ` + | |||||
| `width="${bbox.width}" height="${bbox.height}" ` + | |||||
| `viewBox="${viewBoxSize}">${CommonProperty.dataMapDownloadStyle}<g>${svgXml}</g></svg>`; | |||||
| // Write the svg stream encoded by base64 to the image object. | |||||
| const src = `data:image/svg+xml;base64, | |||||
| ${window.btoa(unescape(encodeURIComponent(encodeStr)))}`; | |||||
| const a = document.createElement('a'); | |||||
| a.href = src; // Export the information in the canvas as image data. | |||||
| a.download = 'dataMap'; // Set the download name. | |||||
| a.click(); // Click to trigger download. | |||||
| }, | |||||
| /** | /** | ||||
| * Collapse on the right | * Collapse on the right | ||||
| */ | */ | ||||
| @@ -515,6 +653,30 @@ export default { | |||||
| display: inline-block; | display: inline-block; | ||||
| background-image: url('../../assets/images/full-screen.png'); | background-image: url('../../assets/images/full-screen.png'); | ||||
| } | } | ||||
| .fit-screen { | |||||
| position: absolute; | |||||
| width: 16px; | |||||
| height: 14px; | |||||
| right: 32px; | |||||
| top: 10px; | |||||
| z-index: 999; | |||||
| cursor: pointer; | |||||
| display: inline-block; | |||||
| background-image: url('../../assets/images/fit.png'); | |||||
| } | |||||
| .download-button { | |||||
| position: absolute; | |||||
| width: 16px; | |||||
| height: 14px; | |||||
| right: 54px; | |||||
| top: 10px; | |||||
| z-index: 999; | |||||
| cursor: pointer; | |||||
| display: inline-block; | |||||
| background-image: url('../../assets/images/download.png'); | |||||
| background-size: 14px 14px; | |||||
| background-repeat: no-repeat; | |||||
| } | |||||
| } | } | ||||
| } | } | ||||
| .cl-data-map.full-screen { | .cl-data-map.full-screen { | ||||
| @@ -509,6 +509,7 @@ export default { | |||||
| }); | }); | ||||
| // The summaryList value could not be saved in the destroy state. | // The summaryList value could not be saved in the destroy state. | ||||
| this.dataCheckedSummary = []; | this.dataCheckedSummary = []; | ||||
| this.tableFilter.summary_dir = {in: summaryList}; | |||||
| this.$store.commit('setSummaryDirList', summaryList); | this.$store.commit('setSummaryDirList', summaryList); | ||||
| if (!tempList.length) { | if (!tempList.length) { | ||||
| this.summaryDirList = []; | this.summaryDirList = []; | ||||
| @@ -967,6 +968,7 @@ export default { | |||||
| sorted_name: data.prop, | sorted_name: data.prop, | ||||
| sorted_type: data.order, | sorted_type: data.order, | ||||
| }; | }; | ||||
| this.pagination.currentPage = 1; | |||||
| params.body = Object.assign({}, tempParam, this.tableFilter); | params.body = Object.assign({}, tempParam, this.tableFilter); | ||||
| this.queryLineagesData(params); | this.queryLineagesData(params); | ||||
| }, | }, | ||||
| @@ -1010,6 +1010,10 @@ export default { | |||||
| source = node.name; | source = node.name; | ||||
| for (let i = 0; i < Math.min(5, keys.length); i++) { | for (let i = 0; i < Math.min(5, keys.length); i++) { | ||||
| target = keys[i]; | target = keys[i]; | ||||
| isConst = !!( | |||||
| this.allGraphData[keys[i]] && | |||||
| this.allGraphData[keys[i]].type === 'Const' | |||||
| ); | |||||
| const nodeStr = isConst | const nodeStr = isConst | ||||
| ? `shape="circle";width="0.14";height="0.14";fixedsize=true;` + | ? `shape="circle";width="0.14";height="0.14";fixedsize=true;` + | ||||
| `label="${target.split('/').pop()}\n\n\n";` | `label="${target.split('/').pop()}\n\n\n";` | ||||
| @@ -138,6 +138,8 @@ export default { | |||||
| zrDrawElement: {hoverDots: []}, | zrDrawElement: {hoverDots: []}, | ||||
| chartTipFlag: false, | chartTipFlag: false, | ||||
| charResizeTimer: null, | charResizeTimer: null, | ||||
| changeAxisTimer: null, | |||||
| changeViewTimer: null, | |||||
| }; | }; | ||||
| }, | }, | ||||
| computed: { | computed: { | ||||
| @@ -220,6 +222,14 @@ export default { | |||||
| this.$store.commit('setIsReload', false); | this.$store.commit('setIsReload', false); | ||||
| this.isReloading = false; | this.isReloading = false; | ||||
| } | } | ||||
| if (this.changeAxisTimer) { | |||||
| clearTimeout(this.changeAxisTimer); | |||||
| this.changeAxisTimer = null; | |||||
| } | |||||
| if (this.changeViewTimer) { | |||||
| clearTimeout(this.changeViewTimer); | |||||
| this.changeViewTimer = null; | |||||
| } | |||||
| }, | }, | ||||
| mounted() { | mounted() { | ||||
| this.init(); | this.init(); | ||||
| @@ -394,19 +404,31 @@ export default { | |||||
| * @param {Number} val Current mode | * @param {Number} val Current mode | ||||
| */ | */ | ||||
| timeTypeChange(val) { | timeTypeChange(val) { | ||||
| this.curPageArr.forEach((item) => { | |||||
| this.updateSampleData(item); | |||||
| }); | |||||
| if (this.changeAxisTimer) { | |||||
| clearTimeout(this.changeAxisTimer); | |||||
| this.changeAxisTimer = null; | |||||
| } | |||||
| this.changeAxisTimer = setTimeout(() => { | |||||
| this.curPageArr.forEach((item) => { | |||||
| this.updateSampleData(item); | |||||
| }); | |||||
| }, 500); | |||||
| }, | }, | ||||
| /** | /** | ||||
| * The view display type is changed | * The view display type is changed | ||||
| * @param {Number} val Current mode | * @param {Number} val Current mode | ||||
| */ | */ | ||||
| viewTypeChange(val) { | viewTypeChange(val) { | ||||
| this.curPageArr.forEach((item) => { | |||||
| this.formatDataToChar(item); | |||||
| this.updateSampleData(item); | |||||
| }); | |||||
| if (this.changeViewTimer) { | |||||
| clearTimeout(this.changeViewTimer); | |||||
| this.changeViewTimer = null; | |||||
| } | |||||
| this.changeViewTimer = setTimeout(() => { | |||||
| this.curPageArr.forEach((item) => { | |||||
| this.formatDataToChar(item); | |||||
| this.updateSampleData(item); | |||||
| }); | |||||
| }, 200); | |||||
| }, | }, | ||||
| /** | /** | ||||
| * Update the data list based on the filtered tags | * Update the data list based on the filtered tags | ||||
| @@ -743,7 +765,7 @@ export default { | |||||
| }</td><td style="text-align:center;">${hoveredItem.step}</td><td>${( | }</td><td style="text-align:center;">${hoveredItem.step}</td><td>${( | ||||
| hoveredItem.relative_time / 1000 | hoveredItem.relative_time / 1000 | ||||
| ).toFixed(3)}${unit}</td><td>${this.dealrelativeTime( | ).toFixed(3)}${unit}</td><td>${this.dealrelativeTime( | ||||
| new Date(hoveredItem.wall_time).toString(), | |||||
| new Date(hoveredItem.wall_time * 1000).toString(), | |||||
| )}</td>`; | )}</td>`; | ||||
| const dom = document.querySelector('#tipTr'); | const dom = document.querySelector('#tipTr'); | ||||
| dom.innerHTML = htmlStr; | dom.innerHTML = htmlStr; | ||||
| @@ -996,7 +1018,9 @@ export default { | |||||
| const z = this.getValue(rawData, dataIndex, i++); | const z = this.getValue(rawData, dataIndex, i++); | ||||
| const pt = getCoord([x, y], sampleObject); | const pt = getCoord([x, y], sampleObject); | ||||
| // linear map in z axis | // linear map in z axis | ||||
| pt[1] -= ((z - minZ) / (maxZ - minZ)) * yValueMapHeight; | |||||
| if (maxZ !== minZ) { | |||||
| pt[1] -= ((z - minZ) / (maxZ - minZ)) * yValueMapHeight; | |||||
| } | |||||
| points.push(pt); | points.push(pt); | ||||
| } | } | ||||
| return points; | return points; | ||||
| @@ -1216,7 +1240,7 @@ export default { | |||||
| if (filter.length) { | if (filter.length) { | ||||
| if (this.curAxisName === 2) { | if (this.curAxisName === 2) { | ||||
| data = sampleObject.fullScreen | data = sampleObject.fullScreen | ||||
| ? this.dealrelativeTime(new Date(filter[0].wall_time).toString()) | |||||
| ? this.dealrelativeTime(new Date(filter[0].wall_time * 1000).toString()) | |||||
| : []; | : []; | ||||
| } else if (this.curAxisName === 1) { | } else if (this.curAxisName === 1) { | ||||
| data = `${(filter[0].relative_time / 3600).toFixed(3)}h`; | data = `${(filter[0].relative_time / 3600).toFixed(3)}h`; | ||||
| @@ -151,6 +151,7 @@ export default { | |||||
| 'batch_size', | 'batch_size', | ||||
| 'device_num', | 'device_num', | ||||
| ], // All keys whose values are int | ], // All keys whose values are int | ||||
| keysOfMixed: [], | |||||
| echart: { | echart: { | ||||
| chart: null, | chart: null, | ||||
| allData: [], | allData: [], | ||||
| @@ -166,10 +167,7 @@ export default { | |||||
| }, | }, | ||||
| chartFilter: {}, // chart filter condition | chartFilter: {}, // chart filter condition | ||||
| tableFilter: {lineage_type: {in: ['model']}}, // table filter condition | tableFilter: {lineage_type: {in: ['model']}}, // table filter condition | ||||
| sortInfo: { | |||||
| sorted_name: 'summary_dir', | |||||
| sorted_type: null, | |||||
| }, | |||||
| sortInfo: {}, | |||||
| showTable: false, | showTable: false, | ||||
| noData: false, | noData: false, | ||||
| haveCustomizedParams: false, | haveCustomizedParams: false, | ||||
| @@ -281,6 +279,7 @@ export default { | |||||
| selectAll: false, // Whether to select all columns | selectAll: false, // Whether to select all columns | ||||
| indeterminate: false, | indeterminate: false, | ||||
| }; | }; | ||||
| this.keysOfMixed = []; | |||||
| this.queryLineagesData(true); | this.queryLineagesData(true); | ||||
| }, | }, | ||||
| /** | /** | ||||
| @@ -324,10 +323,15 @@ export default { | |||||
| tempParam.limit = this.pagination.pageSize; | tempParam.limit = this.pagination.pageSize; | ||||
| tempParam.offset = this.pagination.currentPage - 1; | tempParam.offset = this.pagination.currentPage - 1; | ||||
| params.body = Object.assign(params.body, this.chartFilter); | |||||
| params.body = Object.assign( | |||||
| params.body, | |||||
| this.chartFilter, | |||||
| tempParam, | |||||
| this.tableFilter, | |||||
| ); | |||||
| } else { | |||||
| params.body = Object.assign(params.body, this.tableFilter); | |||||
| } | } | ||||
| params.body = Object.assign(params.body, tempParam, this.tableFilter); | |||||
| RequestService.queryLineagesData(params) | RequestService.queryLineagesData(params) | ||||
| .then( | .then( | ||||
| (res) => { | (res) => { | ||||
| @@ -344,6 +348,10 @@ export default { | |||||
| this.keysOfIntValue.push(i); | this.keysOfIntValue.push(i); | ||||
| } else if (customized[i].type === 'str') { | } else if (customized[i].type === 'str') { | ||||
| this.keysOfStringValue.push(i); | this.keysOfStringValue.push(i); | ||||
| } else if (customized[i].type === 'mixed') { | |||||
| // list of type mixed | |||||
| this.keysOfMixed.push(i); | |||||
| this.keysOfStringValue.push(i); | |||||
| } | } | ||||
| if (i.startsWith(this.replaceStr.userDefined)) { | if (i.startsWith(this.replaceStr.userDefined)) { | ||||
| customized[i].label = customized[i].label.replace( | customized[i].label = customized[i].label.replace( | ||||
| @@ -568,7 +576,16 @@ export default { | |||||
| }; | }; | ||||
| chartAxis.forEach((key) => { | chartAxis.forEach((key) => { | ||||
| item.value.push(i[key]); | |||||
| if ( | |||||
| (i[key] || i[key] == 0) && | |||||
| this.keysOfMixed && | |||||
| this.keysOfMixed.length && | |||||
| this.keysOfMixed.includes(key) | |||||
| ) { | |||||
| item.value.push(i[key].toString()); | |||||
| } else { | |||||
| item.value.push(i[key]); | |||||
| } | |||||
| }); | }); | ||||
| data.push(item); | data.push(item); | ||||
| }); | }); | ||||
| @@ -581,7 +598,7 @@ export default { | |||||
| const values = {}; | const values = {}; | ||||
| this.echart.showData.forEach((i) => { | this.echart.showData.forEach((i) => { | ||||
| if (i[key] || i[key] === 0) { | if (i[key] || i[key] === 0) { | ||||
| values[i[key]] = i[key]; | |||||
| values[i[key].toString()] = i[key].toString(); | |||||
| } | } | ||||
| }); | }); | ||||
| obj.type = 'category'; | obj.type = 'category'; | ||||
| @@ -693,6 +710,15 @@ export default { | |||||
| // select use api | // select use api | ||||
| this.echart.chart.on('axisareaselected', (params) => { | this.echart.chart.on('axisareaselected', (params) => { | ||||
| const key = params.parallelAxisId; | const key = params.parallelAxisId; | ||||
| if ( | |||||
| this.keysOfMixed && | |||||
| this.keysOfMixed.length && | |||||
| this.keysOfMixed.includes(key) | |||||
| ) { | |||||
| this.$message.error(this.$t('modelTraceback.mixedItemMessage')); | |||||
| this.initChart(); | |||||
| return; | |||||
| } | |||||
| const list = this.$store.state.selectedBarList || []; | const list = this.$store.state.selectedBarList || []; | ||||
| const selectedAxisId = params.parallelAxisId; | const selectedAxisId = params.parallelAxisId; | ||||
| if (list.length) { | if (list.length) { | ||||
| @@ -741,6 +767,12 @@ export default { | |||||
| {}, | {}, | ||||
| this.chartFilter, | this.chartFilter, | ||||
| this.tableFilter, | this.tableFilter, | ||||
| ); | |||||
| const tableParams = {}; | |||||
| tableParams.body = Object.assign( | |||||
| {}, | |||||
| this.chartFilter, | |||||
| this.tableFilter, | |||||
| this.sortInfo, | this.sortInfo, | ||||
| ); | ); | ||||
| RequestService.queryLineagesData(filterParams) | RequestService.queryLineagesData(filterParams) | ||||
| @@ -752,20 +784,47 @@ export default { | |||||
| res.data.object && | res.data.object && | ||||
| res.data.object.length | res.data.object.length | ||||
| ) { | ) { | ||||
| let customized = {}; | |||||
| customized = JSON.parse(JSON.stringify(res.data.customized)); | |||||
| const customizedKeys = Object.keys(customized); | |||||
| if (customizedKeys.length) { | |||||
| this.keysOfStringValue = [ | |||||
| 'summary_dir', | |||||
| 'network', | |||||
| 'optimizer', | |||||
| 'loss_function', | |||||
| 'train_dataset_path', | |||||
| 'test_dataset_path', | |||||
| 'dataset_mark', | |||||
| ]; | |||||
| this.keysOfIntValue = [ | |||||
| 'train_dataset_count', | |||||
| 'test_dataset_count', | |||||
| 'epoch', | |||||
| 'batch_size', | |||||
| 'device_num', | |||||
| ]; | |||||
| this.keysOfMixed = []; | |||||
| customizedKeys.forEach((i) => { | |||||
| if (customized[i].type === 'int') { | |||||
| this.keysOfIntValue.push(i); | |||||
| } else if (customized[i].type === 'str') { | |||||
| this.keysOfStringValue.push(i); | |||||
| } else if (customized[i].type === 'mixed') { | |||||
| // list of type mixed | |||||
| this.keysOfMixed.push(i); | |||||
| this.keysOfStringValue.push(i); | |||||
| } | |||||
| }); | |||||
| } | |||||
| const list = this.setDataOfModel(res.data.object); | const list = this.setDataOfModel(res.data.object); | ||||
| const summaryDirList = list.map((i) => i.summary_dir); | const summaryDirList = list.map((i) => i.summary_dir); | ||||
| this.$store.commit('setSummaryDirList', summaryDirList); | this.$store.commit('setSummaryDirList', summaryDirList); | ||||
| this.echart.showData = this.echart.brushData = list; | this.echart.showData = this.echart.brushData = list; | ||||
| this.initChart(); | this.initChart(); | ||||
| this.table.data = this.echart.brushData.slice( | |||||
| 0, | |||||
| this.pagination.pageSize, | |||||
| ); | |||||
| this.pagination.currentPage = 1; | |||||
| this.pagination.total = this.echart.brushData.length; | |||||
| this.$refs.table.clearSelection(); | |||||
| this.getTableList(tableParams); | |||||
| } else { | } else { | ||||
| this.summaryDirList = []; | this.summaryDirList = []; | ||||
| this.$store.commit('setSummaryDirList', []); | this.$store.commit('setSummaryDirList', []); | ||||
| @@ -779,6 +838,26 @@ export default { | |||||
| } | } | ||||
| }); | }); | ||||
| }, | }, | ||||
| /** | |||||
| * Get table data | |||||
| * @param {Object} tableParams | |||||
| */ | |||||
| getTableList(tableParams) { | |||||
| RequestService.queryLineagesData(tableParams) | |||||
| .then( | |||||
| (res) => { | |||||
| if (res && res.data && res.data.object && res.data.object.length) { | |||||
| const list = this.setDataOfModel(res.data.object); | |||||
| this.table.data = list.slice(0, this.pagination.pageSize); | |||||
| this.pagination.currentPage = 1; | |||||
| this.pagination.total = this.echart.brushData.length; | |||||
| this.$refs.table.clearSelection(); | |||||
| } | |||||
| }, | |||||
| (error) => {}, | |||||
| ) | |||||
| .catch(() => {}); | |||||
| }, | |||||
| /** | /** | ||||
| * Resetting the Eechart | * Resetting the Eechart | ||||
| */ | */ | ||||
| @@ -790,6 +869,7 @@ export default { | |||||
| this.showTable = false; | this.showTable = false; | ||||
| this.chartFilter = {}; | this.chartFilter = {}; | ||||
| this.tableFilter.summary_dir = undefined; | this.tableFilter.summary_dir = undefined; | ||||
| this.sortInfo = {}; | |||||
| this.pagination.currentPage = 1; | this.pagination.currentPage = 1; | ||||
| this.echart.allData = []; | this.echart.allData = []; | ||||
| if (this.echart.chart) { | if (this.echart.chart) { | ||||
| @@ -34,10 +34,9 @@ limitations under the License. | |||||
| <!--operation area --> | <!--operation area --> | ||||
| <div class="cl-eval-operate-content" | <div class="cl-eval-operate-content" | ||||
| v-show="!compare"> | v-show="!compare"> | ||||
| <multiselectGroupComponents ref="multiselectGroupComponents" | |||||
| :checkListArr="tagOperateList" | |||||
| @selectedChange="tagSelectedChanged" | |||||
| ></multiselectGroupComponents> | |||||
| <multiselectGroupComponents ref="multiselectGroupComponents" | |||||
| :checkListArr="tagOperateList" | |||||
| @selectedChange="tagSelectedChanged"></multiselectGroupComponents> | |||||
| </div> | </div> | ||||
| <!-- Slider --> | <!-- Slider --> | ||||
| <div class="cl-eval-slider-operate-content" | <div class="cl-eval-slider-operate-content" | ||||
| @@ -56,14 +55,12 @@ limitations under the License. | |||||
| <el-slider v-model="smoothValue" | <el-slider v-model="smoothValue" | ||||
| :step="0.01" | :step="0.01" | ||||
| :max="0.99" | :max="0.99" | ||||
| @input="updataInputValue" | |||||
| ></el-slider> | |||||
| <el-input v-model="smoothValueNumber" | |||||
| class="w60" | |||||
| @input="smoothValueChange" | |||||
| @blur="smoothValueBlur" | |||||
| ></el-input> | |||||
| @input="updataInputValue"></el-slider> | |||||
| <el-input v-model="smoothValueNumber" | |||||
| class="w60" | |||||
| @input="smoothValueChange" | |||||
| @blur="smoothValueBlur"></el-input> | |||||
| </div> | </div> | ||||
| <!-- Content display --> | <!-- Content display --> | ||||
| <div class="cl-eval-show-data-content" | <div class="cl-eval-show-data-content" | ||||
| @@ -247,6 +244,10 @@ export default { | |||||
| clearInterval(this.autoUpdateTimer); | clearInterval(this.autoUpdateTimer); | ||||
| this.autoUpdateTimer = null; | this.autoUpdateTimer = null; | ||||
| } | } | ||||
| if (this.axisBenchChangeTimer) { | |||||
| clearTimeout(this.axisBenchChangeTimer); | |||||
| this.axisBenchChangeTimer = null; | |||||
| } | |||||
| }, | }, | ||||
| mounted() { | mounted() { | ||||
| // Adding a Listener | // Adding a Listener | ||||
| @@ -290,7 +291,7 @@ export default { | |||||
| const runNmeColor = CommonProperty.commonColorArr[0]; | const runNmeColor = CommonProperty.commonColorArr[0]; | ||||
| data.tags.forEach((tagObj) => { | data.tags.forEach((tagObj) => { | ||||
| if (!this.oriDataDictionaries[tagObj]) { | if (!this.oriDataDictionaries[tagObj]) { | ||||
| this.oriDataDictionaries[tagObj]=true; | |||||
| this.oriDataDictionaries[tagObj] = true; | |||||
| // Add the tag list | // Add the tag list | ||||
| tempTagList.push({ | tempTagList.push({ | ||||
| label: tagObj, | label: tagObj, | ||||
| @@ -337,7 +338,7 @@ export default { | |||||
| this.initOver = true; | this.initOver = true; | ||||
| this.$nextTick(() => { | this.$nextTick(() => { | ||||
| this.multiSelectedTagNames=this.$refs.multiselectGroupComponents.updateSelectedDic(); | |||||
| this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic(); | |||||
| // Obtains data on the current page | // Obtains data on the current page | ||||
| this.updateTagInPage(); | this.updateTagInPage(); | ||||
| @@ -365,10 +366,10 @@ export default { | |||||
| const curPageArr = []; | const curPageArr = []; | ||||
| for (let i = startIndex; i < endIndex; i++) { | for (let i = startIndex; i < endIndex; i++) { | ||||
| const sampleItem=this.curFilterSamples[i]; | |||||
| const sampleItem = this.curFilterSamples[i]; | |||||
| if (sampleItem) { | if (sampleItem) { | ||||
| sampleItem.updateFlag=true; | |||||
| sampleItem.show=true; | |||||
| sampleItem.updateFlag = true; | |||||
| sampleItem.show = true; | |||||
| curPageArr.push(sampleItem); | curPageArr.push(sampleItem); | ||||
| } | } | ||||
| } | } | ||||
| @@ -381,110 +382,110 @@ export default { | |||||
| * Load the data on the current page | * Load the data on the current page | ||||
| */ | */ | ||||
| updateCurPageSamples() { | updateCurPageSamples() { | ||||
| this.curPageArr.forEach((sampleObject)=>{ | |||||
| const sampleIndex=sampleObject.sampleIndex; | |||||
| this.curPageArr.forEach((sampleObject) => { | |||||
| const sampleIndex = sampleObject.sampleIndex; | |||||
| if (!sampleObject) { | if (!sampleObject) { | ||||
| return; | return; | ||||
| } | } | ||||
| sampleObject.updateFlag = true; | sampleObject.updateFlag = true; | ||||
| const params = { | const params = { | ||||
| train_id: this.trainingJobId, | train_id: this.trainingJobId, | ||||
| tag: sampleObject.tagName, | tag: sampleObject.tagName, | ||||
| }; | }; | ||||
| RequestService.getScalarsSample(params).then((res)=>{ | |||||
| // error | |||||
| if (!res || !res.data || !res.data.metadatas) { | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.clear(); | |||||
| } | |||||
| return; | |||||
| } | |||||
| let hasInvalidData = false; | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.showLoading(); | |||||
| } | |||||
| RequestService.getScalarsSample(params) | |||||
| .then((res) => { | |||||
| // error | |||||
| if (!res || !res.data || !res.data.metadatas) { | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.clear(); | |||||
| } | |||||
| return; | |||||
| } | |||||
| let hasInvalidData = false; | |||||
| const resData = res.data; | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.showLoading(); | |||||
| } | |||||
| const tempObject = { | |||||
| valueData: { | |||||
| stepData: [], | |||||
| absData: [], | |||||
| relativeData: [], | |||||
| }, | |||||
| logData: { | |||||
| stepData: [], | |||||
| absData: [], | |||||
| relativeData: [], | |||||
| }, | |||||
| }; | |||||
| let relativeTimeBench = 0; | |||||
| if (resData.metadatas.length) { | |||||
| relativeTimeBench = resData.metadatas[0].wall_time; | |||||
| } | |||||
| const resData = res.data; | |||||
| const tempObject = { | |||||
| valueData: { | |||||
| stepData: [], | |||||
| absData: [], | |||||
| relativeData: [], | |||||
| }, | |||||
| logData: { | |||||
| stepData: [], | |||||
| absData: [], | |||||
| relativeData: [], | |||||
| }, | |||||
| }; | |||||
| let relativeTimeBench = 0; | |||||
| if (resData.metadatas.length) { | |||||
| relativeTimeBench = resData.metadatas[0].wall_time; | |||||
| } | |||||
| // Initializing Chart Data | |||||
| resData.metadatas.forEach((metaData) => { | |||||
| if (metaData.value === null && !hasInvalidData) { | |||||
| hasInvalidData = true; | |||||
| } | |||||
| tempObject.valueData.stepData.push([ | |||||
| metaData.step, | |||||
| metaData.value, | |||||
| ]); | |||||
| tempObject.valueData.absData.push([ | |||||
| metaData.wall_time, | |||||
| metaData.value, | |||||
| ]); | |||||
| tempObject.valueData.relativeData.push([ | |||||
| metaData.wall_time - relativeTimeBench, | |||||
| metaData.value, | |||||
| ]); | |||||
| const logValue = metaData.value >= 0 ? metaData.value : ''; | |||||
| tempObject.logData.stepData.push([metaData.step, logValue]); | |||||
| tempObject.logData.absData.push([metaData.wall_time, logValue]); | |||||
| tempObject.logData.relativeData.push([ | |||||
| metaData.wall_time - relativeTimeBench, | |||||
| logValue, | |||||
| ]); | |||||
| }); | |||||
| // Initializing Chart Data | |||||
| resData.metadatas.forEach((metaData) => { | |||||
| if (metaData.value === null && !hasInvalidData) { | |||||
| hasInvalidData = true; | |||||
| } | |||||
| tempObject.valueData.stepData.push([ | |||||
| metaData.step, | |||||
| metaData.value, | |||||
| ]); | |||||
| tempObject.valueData.absData.push([ | |||||
| metaData.wall_time, | |||||
| metaData.value, | |||||
| ]); | |||||
| tempObject.valueData.relativeData.push([ | |||||
| metaData.wall_time - relativeTimeBench, | |||||
| metaData.value, | |||||
| ]); | |||||
| const logValue = metaData.value >= 0 ? metaData.value : ''; | |||||
| tempObject.logData.stepData.push([metaData.step, logValue]); | |||||
| tempObject.logData.absData.push([metaData.wall_time, logValue]); | |||||
| tempObject.logData.relativeData.push([ | |||||
| metaData.wall_time - relativeTimeBench, | |||||
| logValue, | |||||
| ]); | |||||
| }); | |||||
| sampleObject.charData.oriData[0] = tempObject; | |||||
| sampleObject.charData.oriData[0] = tempObject; | |||||
| if (hasInvalidData) { | |||||
| this.$set(sampleObject, 'invalidData', true); | |||||
| } | |||||
| sampleObject.charData.charOption = this.formateCharOption( | |||||
| sampleIndex, | |||||
| ); | |||||
| if (hasInvalidData) { | |||||
| this.$set(sampleObject, 'invalidData', true); | |||||
| } | |||||
| sampleObject.charData.charOption = this.formateCharOption( | |||||
| sampleIndex, | |||||
| ); | |||||
| this.$forceUpdate(); | |||||
| this.$forceUpdate(); | |||||
| this.$nextTick(() => { | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.hideLoading(); | |||||
| } | |||||
| this.$nextTick(() => { | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.hideLoading(); | |||||
| } | |||||
| // Draw chart | |||||
| if (!this.compare) { | |||||
| this.updateOrCreateChar(sampleIndex); | |||||
| } else { | |||||
| this.abort = true; | |||||
| } | |||||
| }); | |||||
| }).catch((e)=>{ | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.clear(); | |||||
| } | |||||
| }); | |||||
| // Draw chart | |||||
| if (!this.compare) { | |||||
| this.updateOrCreateChar(sampleIndex); | |||||
| } else { | |||||
| this.abort = true; | |||||
| } | |||||
| }); | |||||
| }) | |||||
| .catch((e) => { | |||||
| if (sampleObject.charObj) { | |||||
| sampleObject.charObj.clear(); | |||||
| } | |||||
| }); | |||||
| }); | }); | ||||
| }, | }, | ||||
| /** | /** | ||||
| * Formatting Chart Data | * Formatting Chart Data | ||||
| * @param {Number} sampleIndex Chart subscript | * @param {Number} sampleIndex Chart subscript | ||||
| @@ -499,7 +500,7 @@ export default { | |||||
| let returnFlag = false; | let returnFlag = false; | ||||
| const seriesData = []; | const seriesData = []; | ||||
| const oriData = sampleObject.charData.oriData; | const oriData = sampleObject.charData.oriData; | ||||
| const runName=sampleObject.runNames; | |||||
| const runName = sampleObject.runNames; | |||||
| const curBackName = runName + this.backendString; | const curBackName = runName + this.backendString; | ||||
| const dataObj = { | const dataObj = { | ||||
| name: runName, | name: runName, | ||||
| @@ -645,7 +646,7 @@ export default { | |||||
| }, | }, | ||||
| grid: { | grid: { | ||||
| left: 80, | left: 80, | ||||
| right: 10, | |||||
| right: sampleObject.fullScreen ? 80 : 10, | |||||
| }, | }, | ||||
| animation: true, | animation: true, | ||||
| dataZoom: [ | dataZoom: [ | ||||
| @@ -886,9 +887,11 @@ export default { | |||||
| if (sampleObject.fullScreen) { | if (sampleObject.fullScreen) { | ||||
| sampleObject.charData.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | sampleObject.charData.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | ||||
| '#3E98C5'; | '#3E98C5'; | ||||
| sampleObject.charData.charOption.grid.right = 80; | |||||
| } else { | } else { | ||||
| sampleObject.charData.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | sampleObject.charData.charOption.toolbox.feature.myToolFullScreen.iconStyle.borderColor = | ||||
| '#6D7278'; | '#6D7278'; | ||||
| sampleObject.charData.charOption.grid.right = 10; | |||||
| } | } | ||||
| sampleObject.updateFlag = true; | sampleObject.updateFlag = true; | ||||
| @@ -901,14 +904,13 @@ export default { | |||||
| }, 0); | }, 0); | ||||
| }, | }, | ||||
| /** | /** | ||||
| * Update Chart by tag | * Update Chart by tag | ||||
| * @param {Boolean} noPageDataNumChange No new data is added or deleted | * @param {Boolean} noPageDataNumChange No new data is added or deleted | ||||
| */ | */ | ||||
| updateTagInPage(noPageDataNumChange) { | updateTagInPage(noPageDataNumChange) { | ||||
| const curFilterSamples=[]; | |||||
| const curFilterSamples = []; | |||||
| // Obtains the chart subscript | // Obtains the chart subscript | ||||
| this.originDataArr.forEach((sampleItem) => { | this.originDataArr.forEach((sampleItem) => { | ||||
| if (this.multiSelectedTagNames[sampleItem.tagName]) { | if (this.multiSelectedTagNames[sampleItem.tagName]) { | ||||
| @@ -1012,13 +1014,12 @@ export default { | |||||
| if (!selectedItemDict) { | if (!selectedItemDict) { | ||||
| return; | return; | ||||
| } | } | ||||
| this.multiSelectedTagNames=selectedItemDict; | |||||
| this.multiSelectedTagNames = selectedItemDict; | |||||
| // Reset to the first page | // Reset to the first page | ||||
| this.pageIndex=0; | |||||
| this.pageIndex = 0; | |||||
| this.updateTagInPage(); | this.updateTagInPage(); | ||||
| }, | }, | ||||
| /** | /** | ||||
| *window resize | *window resize | ||||
| */ | */ | ||||
| @@ -1050,7 +1051,7 @@ export default { | |||||
| this.tagOperateList = []; | this.tagOperateList = []; | ||||
| this.pageIndex = 0; | this.pageIndex = 0; | ||||
| this.originDataArr = []; | this.originDataArr = []; | ||||
| this.oriDataDictionaries={}; | |||||
| this.oriDataDictionaries = {}; | |||||
| this.curPageArr = []; | this.curPageArr = []; | ||||
| this.tagPropsList = []; | this.tagPropsList = []; | ||||
| this.propsList = []; | this.propsList = []; | ||||
| @@ -1090,10 +1091,10 @@ export default { | |||||
| if (!oriData) { | if (!oriData) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| const newTagDictionaries={}; // Index of the tag in the new data | |||||
| const newTagDictionaries = {}; // Index of the tag in the new data | |||||
| let dataRemoveFlag = false; | let dataRemoveFlag = false; | ||||
| oriData.tags.forEach((tagName) => { | oriData.tags.forEach((tagName) => { | ||||
| newTagDictionaries[tagName]=true; | |||||
| newTagDictionaries[tagName] = true; | |||||
| }); | }); | ||||
| // Delete the tag that does not exist | // Delete the tag that does not exist | ||||
| const oldTagListLength = this.tagOperateList.length; | const oldTagListLength = this.tagOperateList.length; | ||||
| @@ -1132,7 +1133,7 @@ export default { | |||||
| const runColor = CommonProperty.commonColorArr[0]; | const runColor = CommonProperty.commonColorArr[0]; | ||||
| oriData.tags.forEach((tagObj) => { | oriData.tags.forEach((tagObj) => { | ||||
| if (!this.oriDataDictionaries[tagObj]) { | if (!this.oriDataDictionaries[tagObj]) { | ||||
| this.oriDataDictionaries[tagObj]=true; | |||||
| this.oriDataDictionaries[tagObj] = true; | |||||
| this.tagOperateList.push({ | this.tagOperateList.push({ | ||||
| label: tagObj, | label: tagObj, | ||||
| checked: true, | checked: true, | ||||
| @@ -1198,7 +1199,7 @@ export default { | |||||
| const tagAddFlag = this.checkNewDataAndComplete(data); | const tagAddFlag = this.checkNewDataAndComplete(data); | ||||
| this.$nextTick(() => { | this.$nextTick(() => { | ||||
| this.multiSelectedTagNames=this.$refs.multiselectGroupComponents.updateSelectedDic(); | |||||
| this.multiSelectedTagNames = this.$refs.multiselectGroupComponents.updateSelectedDic(); | |||||
| this.updateTagInPage(!tagRemoveFlag && !tagAddFlag); | this.updateTagInPage(!tagRemoveFlag && !tagAddFlag); | ||||
| this.resizeCallback(); | this.resizeCallback(); | ||||
| @@ -1209,7 +1210,7 @@ export default { | |||||
| // Initial chart data | // Initial chart data | ||||
| data.tags.forEach((tagObj) => { | data.tags.forEach((tagObj) => { | ||||
| // Check whether the tag with the same name exists | |||||
| // Check whether the tag with the same name exists | |||||
| tempTagList.push({ | tempTagList.push({ | ||||
| label: tagObj, | label: tagObj, | ||||
| checked: true, | checked: true, | ||||
| @@ -1266,7 +1267,7 @@ export default { | |||||
| if (this.firstNum === 0) { | if (this.firstNum === 0) { | ||||
| return; | return; | ||||
| } | } | ||||
| this.smoothValueNumber=Number(val); | |||||
| this.smoothValueNumber = Number(val); | |||||
| if (this.smoothSliderValueTimer) { | if (this.smoothSliderValueTimer) { | ||||
| clearTimeout(this.smoothSliderValueTimer); | clearTimeout(this.smoothSliderValueTimer); | ||||
| this.smoothSliderValueTimer = null; | this.smoothSliderValueTimer = null; | ||||
| @@ -1279,26 +1280,26 @@ export default { | |||||
| smoothValueChange(val) { | smoothValueChange(val) { | ||||
| if (!isNaN(val)) { | if (!isNaN(val)) { | ||||
| if (Number(val)===0) { | |||||
| this.smoothValue=0; | |||||
| if (Number(val) === 0) { | |||||
| this.smoothValue = 0; | |||||
| } | } | ||||
| if (Number(val)<0) { | |||||
| this.smoothValue=0; | |||||
| this.smoothValueNumber=0; | |||||
| if (Number(val) < 0) { | |||||
| this.smoothValue = 0; | |||||
| this.smoothValueNumber = 0; | |||||
| } | } | ||||
| if (Number(val)>0) { | |||||
| if (Number(val)>0.99) { | |||||
| this.smoothValue=0.99; | |||||
| this.smoothValueNumber=0.99; | |||||
| if (Number(val) > 0) { | |||||
| if (Number(val) > 0.99) { | |||||
| this.smoothValue = 0.99; | |||||
| this.smoothValueNumber = 0.99; | |||||
| } else { | } else { | ||||
| this.smoothValue=Number(val); | |||||
| this.smoothValue = Number(val); | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| }, | }, | ||||
| smoothValueBlur() { | smoothValueBlur() { | ||||
| this.smoothValueNumber=this.smoothValue; | |||||
| this.smoothValueNumber = this.smoothValue; | |||||
| }, | }, | ||||
| /** | /** | ||||
| @@ -21,6 +21,12 @@ limitations under the License. | |||||
| <div class="cl-dashboard-top-title"> | <div class="cl-dashboard-top-title"> | ||||
| {{$t('trainingDashboard.trainingDashboardTitle')}} | {{$t('trainingDashboard.trainingDashboardTitle')}} | ||||
| </div> | </div> | ||||
| <div class="path-message"> | |||||
| <span>{{$t('symbols.leftbracket')}}</span> | |||||
| <span>{{$t('trainingDashboard.summaryDirPath')}}</span> | |||||
| <span>{{summaryPath}}</span> | |||||
| <span>{{$t('symbols.rightbracket')}}</span> | |||||
| </div> | |||||
| </div> | </div> | ||||
| <div class="cl-dashboard-center"> | <div class="cl-dashboard-center"> | ||||
| <div class="cl-dashboard-con-up" | <div class="cl-dashboard-con-up" | ||||
| @@ -166,6 +172,7 @@ export default { | |||||
| return { | return { | ||||
| // training job id | // training job id | ||||
| trainingJobId: '', | trainingJobId: '', | ||||
| summaryPath: '', | |||||
| defColorCount: CommonProperty.commonColorArr.length, // default color | defColorCount: CommonProperty.commonColorArr.length, // default color | ||||
| colorNum: 0, | colorNum: 0, | ||||
| charObj: null, | charObj: null, | ||||
| @@ -284,6 +291,7 @@ export default { | |||||
| init() { | init() { | ||||
| if (this.$route.query && this.$route.query.id) { | if (this.$route.query && this.$route.query.id) { | ||||
| this.trainingJobId = this.$route.query.id; | this.trainingJobId = this.$route.query.id; | ||||
| this.summaryPath = decodeURIComponent(this.trainingJobId); | |||||
| } else { | } else { | ||||
| this.trainingJobId = ''; | this.trainingJobId = ''; | ||||
| this.$message.error(this.$t('trainingDashboard.invalidId')); | this.$message.error(this.$t('trainingDashboard.invalidId')); | ||||
| @@ -1720,6 +1728,12 @@ export default { | |||||
| height: 56px; | height: 56px; | ||||
| vertical-align: middle; | vertical-align: middle; | ||||
| background: #ffffff; | background: #ffffff; | ||||
| .path-message { | |||||
| display: inline-block; | |||||
| line-height: 20px; | |||||
| padding: 18px 16px; | |||||
| font-weight: bold; | |||||
| } | |||||
| .cl-dashboard-top-title { | .cl-dashboard-top-title { | ||||
| float: left; | float: left; | ||||
| color: #000000; | color: #000000; | ||||
| @@ -36,9 +36,9 @@ class MockReservoir: | |||||
| def __init__(self, size): | def __init__(self, size): | ||||
| self.size = size | self.size = size | ||||
| self._samples = [ | self._samples = [ | ||||
| _Tensor('wall_time1', 1, 'value1'), | |||||
| _Tensor('wall_time2', 2, 'value2'), | |||||
| _Tensor('wall_time3', 3, 'value3') | |||||
| _Tensor('wall_time1', 1, 'value1', 'filename1'), | |||||
| _Tensor('wall_time2', 2, 'value2', 'filename2'), | |||||
| _Tensor('wall_time3', 3, 'value3', 'filename3') | |||||
| ] | ] | ||||
| def samples(self): | def samples(self): | ||||
| @@ -107,7 +107,8 @@ class TestEventsData: | |||||
| """Test add_tensor_event success.""" | """Test add_tensor_event success.""" | ||||
| ev_data = self.get_ev_data() | ev_data = self.get_ev_data() | ||||
| t_event = TensorEvent(wall_time=1, step=4, tag='new_tag', plugin_name='plugin_name1', value='value1') | |||||
| t_event = TensorEvent(wall_time=1, step=4, tag='new_tag', | |||||
| plugin_name='plugin_name1', value='value1', filename='filename') | |||||
| ev_data.add_tensor_event(t_event) | ev_data.add_tensor_event(t_event) | ||||
| assert 'tag0' not in ev_data._tags | assert 'tag0' not in ev_data._tags | ||||
| @@ -116,4 +117,54 @@ class TestEventsData: | |||||
| assert 'tag0' not in ev_data._reservoir_by_tag | assert 'tag0' not in ev_data._reservoir_by_tag | ||||
| assert 'new_tag' in ev_data._tags_by_plugin['plugin_name1'] | assert 'new_tag' in ev_data._tags_by_plugin['plugin_name1'] | ||||
| assert ev_data._reservoir_by_tag['new_tag'].samples()[-1] == _Tensor(t_event.wall_time, t_event.step, | assert ev_data._reservoir_by_tag['new_tag'].samples()[-1] == _Tensor(t_event.wall_time, t_event.step, | ||||
| t_event.value) | |||||
| t_event.value, 'filename') | |||||
| def test_add_tensor_event_out_of_order(self): | |||||
| """Test add_tensor_event success for out_of_order summaries.""" | |||||
| wall_time = 1 | |||||
| value = '1' | |||||
| tag = 'tag' | |||||
| plugin_name = 'scalar' | |||||
| file1 = 'file1' | |||||
| ev_data = EventsData() | |||||
| steps = [i for i in range(2, 10)] | |||||
| for step in steps: | |||||
| t_event = TensorEvent(wall_time=1, step=step, tag=tag, | |||||
| plugin_name=plugin_name, value=value, filename=file1) | |||||
| ev_data.add_tensor_event(t_event) | |||||
| t_event = TensorEvent(wall_time=1, step=1, tag=tag, | |||||
| plugin_name=plugin_name, value=value, filename=file1) | |||||
| ev_data.add_tensor_event(t_event) | |||||
| # Current steps should be: [1, 2, 3, 4, 5, 6, 7, 8, 9] | |||||
| assert len(ev_data._reservoir_by_tag[tag].samples()) == len(steps) + 1 | |||||
| file2 = 'file2' | |||||
| new_steps_1 = [5, 10] | |||||
| for step in new_steps_1: | |||||
| t_event = TensorEvent(wall_time=1, step=step, tag=tag, | |||||
| plugin_name=plugin_name, value=value, filename=file2) | |||||
| ev_data.add_tensor_event(t_event) | |||||
| assert ev_data._reservoir_by_tag[tag].samples()[-1] == _Tensor(wall_time, step, value, file2) | |||||
| # Current steps should be: [1, 2, 3, 4, 5, 10] | |||||
| steps = [1, 2, 3, 4, 5, 10] | |||||
| samples = ev_data._reservoir_by_tag[tag].samples() | |||||
| for step, sample in zip(steps, samples): | |||||
| filename = file1 if sample.step < 5 else file2 | |||||
| assert sample == _Tensor(wall_time, step, value, filename) | |||||
| new_steps_2 = [7, 11, 3] | |||||
| for step in new_steps_2: | |||||
| t_event = TensorEvent(wall_time=1, step=step, tag=tag, | |||||
| plugin_name=plugin_name, value=value, filename=file2) | |||||
| ev_data.add_tensor_event(t_event) | |||||
| # Current steps should be: [1, 2, 3, 5, 7, 10, 11], file2: [3, 5, 7, 10, 11] | |||||
| steps = [1, 2, 3, 5, 7, 10, 11] | |||||
| new_steps_2.extend(new_steps_1) | |||||
| samples = ev_data._reservoir_by_tag[tag].samples() | |||||
| for step, sample in zip(steps, samples): | |||||
| filename = file2 if sample.step in new_steps_2 else file1 | |||||
| assert sample == _Tensor(wall_time, step, value, filename) | |||||
| @@ -27,10 +27,14 @@ class TestHistogramReservoir: | |||||
| sample1.value.count = 1 | sample1.value.count = 1 | ||||
| sample1.value.max = 102 | sample1.value.max = 102 | ||||
| sample1.value.min = 101 | sample1.value.min = 101 | ||||
| sample1.step = 2 | |||||
| sample1.filename = 'filename' | |||||
| sample2 = mock.MagicMock() | sample2 = mock.MagicMock() | ||||
| sample2.value.count = 2 | sample2.value.count = 2 | ||||
| sample2.value.max = 102 | sample2.value.max = 102 | ||||
| sample2.value.min = 101 | sample2.value.min = 101 | ||||
| sample2.step = 1 | |||||
| sample2.filename = 'filename' | |||||
| my_reservoir.add_sample(sample1) | my_reservoir.add_sample(sample1) | ||||
| my_reservoir.add_sample(sample2) | my_reservoir.add_sample(sample2) | ||||
| samples = my_reservoir.samples() | samples = my_reservoir.samples() | ||||
| @@ -216,9 +216,8 @@ class TestImagesProcessor: | |||||
| """ | """ | ||||
| Test removing sample in reservoir. | Test removing sample in reservoir. | ||||
| If step list is [1, 3, 5, 7, 9, 2, 3, 4, 15], | |||||
| and then [3, 5, 7, 9] will be deleted. | |||||
| Results will be [1, 2, 3, 4, 15]. | |||||
| If step list is [1, 3, 5, 7, 9, 2, 3, 4, 15] in one summary, | |||||
| Results will be [1, 2, 3, 4, 5, 7, 9, 15]. | |||||
| """ | """ | ||||
| test_tag_name = self._complete_tag_name | test_tag_name = self._complete_tag_name | ||||
| @@ -237,5 +236,4 @@ class TestImagesProcessor: | |||||
| except ImageNotExistError: | except ImageNotExistError: | ||||
| not_found_step_list.append(test_step) | not_found_step_list.append(test_step) | ||||
| assert current_step_list == [1, 2, 3, 4, 15] | |||||
| assert not_found_step_list == [5, 7, 9] | |||||
| assert current_step_list == [1, 2, 3, 4, 5, 7, 9, 15] | |||||
| @@ -204,6 +204,12 @@ CUSTOMIZED_1 = { | |||||
| 'metric/mse': {'label': 'metric/mse', 'required': True, 'type': 'float'} | 'metric/mse': {'label': 'metric/mse', 'required': True, 'type': 'float'} | ||||
| } | } | ||||
| CUSTOMIZED_2 = { | |||||
| 'metric/accuracy': {'label': 'metric/accuracy', 'required': True, 'type': 'mixed'}, | |||||
| 'metric/mae': {'label': 'metric/mae', 'required': True, 'type': 'float'}, | |||||
| 'metric/mse': {'label': 'metric/mse', 'required': True, 'type': 'float'} | |||||
| } | |||||
| METRIC_1 = { | METRIC_1 = { | ||||
| 'accuracy': 1.0000002, | 'accuracy': 1.0000002, | ||||
| 'mae': 2.00000002, | 'mae': 2.00000002, | ||||
| @@ -463,7 +463,7 @@ class TestQuerier(TestCase): | |||||
| def test_filter_summary_lineage_success_4(self): | def test_filter_summary_lineage_success_4(self): | ||||
| """Test the success of filter_summary_lineage.""" | """Test the success of filter_summary_lineage.""" | ||||
| expected_result = { | expected_result = { | ||||
| 'customized': event_data.CUSTOMIZED_0, | |||||
| 'customized': event_data.CUSTOMIZED_2, | |||||
| 'object': [ | 'object': [ | ||||
| LINEAGE_FILTRATION_0, | LINEAGE_FILTRATION_0, | ||||
| LINEAGE_FILTRATION_1, | LINEAGE_FILTRATION_1, | ||||
| @@ -500,7 +500,7 @@ class TestQuerier(TestCase): | |||||
| 'sorted_type': 'ascending' | 'sorted_type': 'ascending' | ||||
| } | } | ||||
| expected_result = { | expected_result = { | ||||
| 'customized': event_data.CUSTOMIZED_0, | |||||
| 'customized': event_data.CUSTOMIZED_2, | |||||
| 'object': [ | 'object': [ | ||||
| LINEAGE_FILTRATION_0, | LINEAGE_FILTRATION_0, | ||||
| LINEAGE_FILTRATION_5, | LINEAGE_FILTRATION_5, | ||||
| @@ -522,7 +522,7 @@ class TestQuerier(TestCase): | |||||
| 'sorted_type': 'descending' | 'sorted_type': 'descending' | ||||
| } | } | ||||
| expected_result = { | expected_result = { | ||||
| 'customized': event_data.CUSTOMIZED_1, | |||||
| 'customized': event_data.CUSTOMIZED_2, | |||||
| 'object': [ | 'object': [ | ||||
| LINEAGE_FILTRATION_6, | LINEAGE_FILTRATION_6, | ||||
| LINEAGE_FILTRATION_4, | LINEAGE_FILTRATION_4, | ||||