From 13030f75fce87f682bb767a3bc26fa97c215c7f9 Mon Sep 17 00:00:00 2001 From: kouzhenzhong Date: Mon, 18 May 2020 20:30:13 +0800 Subject: [PATCH] lineage: decouple train/eval lineage with summary_writer --- .../collection/model/model_lineage.py | 74 +++++++++++-------- mindinsight/lineagemgr/common/utils.py | 35 ++++++++- .../lineagemgr/common/validator/validate.py | 29 +++++++- .../lineagemgr/summary/_summary_adapter.py | 24 ++++++ .../lineagemgr/summary/summary_record.py | 20 +++-- .../collection/model/test_model_lineage.py | 53 +++++++++---- tests/st/func/lineagemgr/conftest.py | 13 ++++ .../collection/model/test_model_lineage.py | 8 ++ .../lineagemgr/summary/test_summary_record.py | 4 +- .../mindspore/train/summary/summary_record.py | 9 ++- 10 files changed, 209 insertions(+), 60 deletions(-) diff --git a/mindinsight/lineagemgr/collection/model/model_lineage.py b/mindinsight/lineagemgr/collection/model/model_lineage.py index 6d7291d..eeb5b89 100644 --- a/mindinsight/lineagemgr/collection/model/model_lineage.py +++ b/mindinsight/lineagemgr/collection/model/model_lineage.py @@ -29,7 +29,7 @@ from mindinsight.lineagemgr.common.exceptions.error_code import LineageErrors, L from mindinsight.lineagemgr.common.exceptions.exceptions import LineageParamRunContextError, \ LineageGetModelFileError, LineageLogError from mindinsight.lineagemgr.common.log import logger as log -from mindinsight.lineagemgr.common.utils import try_except +from mindinsight.lineagemgr.common.utils import try_except, make_directory from mindinsight.lineagemgr.common.validator.model_parameter import RunContextArgs, \ EvalParameter from mindinsight.lineagemgr.collection.model.base import Metadata @@ -50,9 +50,12 @@ class TrainLineage(Callback): Collect lineage of a training job. Args: - summary_record (SummaryRecord): SummaryRecord is used to record - the summary value, and summary_record is an instance of SummaryRecord, - see mindspore.train.summary.SummaryRecord. + summary_record (Union[SummaryRecord, str]): The `SummaryRecord` object which + is used to record the summary value(see mindspore.train.summary.SummaryRecord), + or a log dir(as a `str`) to be passed to `LineageSummary` to create + a lineage summary recorder. It should be noted that instead of making + use of summary_record to record lineage info directly, we obtain + log dir from it then create a new summary file to write lineage info. raise_exception (bool): Whether to raise exception when error occurs in TrainLineage. If True, raise exception. If False, catch exception and continue. Default: False. @@ -74,18 +77,25 @@ class TrainLineage(Callback): >>> lineagemgr = TrainLineage(summary_record=summary_writer) >>> model.train(epoch_num, dataset, callbacks=[model_ckpt, summary_callback, lineagemgr]) """ - def __init__(self, summary_record, raise_exception=False, user_defined_info=None): + def __init__(self, + summary_record, + raise_exception=False, + user_defined_info=None): super(TrainLineage, self).__init__() try: validate_raise_exception(raise_exception) self.raise_exception = raise_exception - validate_summary_record(summary_record) - self.summary_record = summary_record + if isinstance(summary_record, str): + # make directory if not exist + self.lineage_log_dir = make_directory(summary_record) + else: + validate_summary_record(summary_record) + summary_log_path = summary_record.full_file_name + validate_file_path(summary_log_path) + self.lineage_log_dir = os.path.dirname(summary_log_path) - summary_log_path = summary_record.full_file_name - validate_file_path(summary_log_path) - self.lineage_log_path = summary_log_path + '_lineage' + self.lineage_summary = LineageSummary(self.lineage_log_dir) self.initial_learning_rate = None @@ -113,8 +123,7 @@ class TrainLineage(Callback): log.info('Initialize training lineage collection...') if self.user_defined_info: - lineage_summary = LineageSummary(summary_log_path=self.lineage_log_path) - lineage_summary.record_user_defined_info(self.user_defined_info) + self.lineage_summary.record_user_defined_info(self.user_defined_info) if not isinstance(run_context, RunContext): error_msg = f'Invalid TrainLineage run_context.' @@ -147,8 +156,7 @@ class TrainLineage(Callback): dataset_graph_dict = json.loads(dataset_graph_json_str) log.info('Logging dataset graph...') try: - lineage_summary = LineageSummary(self.lineage_log_path) - lineage_summary.record_dataset_graph(dataset_graph=dataset_graph_dict) + self.lineage_summary.record_dataset_graph(dataset_graph=dataset_graph_dict) except Exception as error: error_msg = f'Dataset graph log error in TrainLineage begin: {error}' log.error(error_msg) @@ -210,8 +218,7 @@ class TrainLineage(Callback): log.info('Logging lineage information...') try: - lineage_summary = LineageSummary(self.lineage_log_path) - lineage_summary.record_train_lineage(train_lineage) + self.lineage_summary.record_train_lineage(train_lineage) except IOError as error: error_msg = f'End error in TrainLineage: {error}' log.error(error_msg) @@ -228,10 +235,12 @@ class EvalLineage(Callback): """ Collect lineage of an evaluation job. - Args: - summary_record (SummaryRecord): SummaryRecord is used to record - the summary value, and summary_record is an instance of SummaryRecord, - see mindspore.train.summary.SummaryRecord. + summary_record (Union[SummaryRecord, str]): The `SummaryRecord` object which + is used to record the summary value(see mindspore.train.summary.SummaryRecord), + or a log dir(as a `str`) to be passed to `LineageSummary` to create + a lineage summary recorder. It should be noted that instead of making + use of summary_record to record lineage info directly, we obtain + log dir from it then create a new summary file to write lineage info. raise_exception (bool): Whether to raise exception when error occurs in EvalLineage. If True, raise exception. If False, catch exception and continue. Default: False. @@ -253,18 +262,25 @@ class EvalLineage(Callback): >>> lineagemgr = EvalLineage(summary_record=summary_writer) >>> model.eval(epoch_num, dataset, callbacks=[model_ckpt, summary_callback, lineagemgr]) """ - def __init__(self, summary_record, raise_exception=False, user_defined_info=None): + def __init__(self, + summary_record, + raise_exception=False, + user_defined_info=None): super(EvalLineage, self).__init__() try: validate_raise_exception(raise_exception) self.raise_exception = raise_exception - validate_summary_record(summary_record) - self.summary_record = summary_record + if isinstance(summary_record, str): + # make directory if not exist + self.lineage_log_dir = make_directory(summary_record) + else: + validate_summary_record(summary_record) + summary_log_path = summary_record.full_file_name + validate_file_path(summary_log_path) + self.lineage_log_dir = os.path.dirname(summary_log_path) - summary_log_path = summary_record.full_file_name - validate_file_path(summary_log_path) - self.lineage_log_path = summary_log_path + '_lineage' + self.lineage_summary = LineageSummary(self.lineage_log_dir) self.user_defined_info = user_defined_info if user_defined_info: @@ -289,8 +305,7 @@ class EvalLineage(Callback): LineageLogError: If recording lineage information fails. """ if self.user_defined_info: - lineage_summary = LineageSummary(summary_log_path=self.lineage_log_path) - lineage_summary.record_user_defined_info(self.user_defined_info) + self.lineage_summary.record_user_defined_info(self.user_defined_info) if not isinstance(run_context, RunContext): error_msg = f'Invalid EvalLineage run_context.' @@ -312,8 +327,7 @@ class EvalLineage(Callback): log.info('Logging evaluation job lineage...') try: - lineage_summary = LineageSummary(self.lineage_log_path) - lineage_summary.record_evaluation_lineage(eval_lineage) + self.lineage_summary.record_evaluation_lineage(eval_lineage) except IOError as error: error_msg = f'End error in EvalLineage: {error}' log.error(error_msg) diff --git a/mindinsight/lineagemgr/common/utils.py b/mindinsight/lineagemgr/common/utils.py index dd5285a..030fd87 100644 --- a/mindinsight/lineagemgr/common/utils.py +++ b/mindinsight/lineagemgr/common/utils.py @@ -13,14 +13,15 @@ # limitations under the License. # ============================================================================ """Lineage utils.""" -from functools import wraps +import os import re +from functools import wraps from mindinsight.datavisual.data_transform.summary_watcher import SummaryWatcher -from mindinsight.lineagemgr.common.log import logger as log from mindinsight.lineagemgr.common.exceptions.exceptions import LineageParamRunContextError, \ - LineageGetModelFileError, LineageLogError, LineageParamValueError, LineageDirNotExistError, \ - LineageParamSummaryPathError + LineageGetModelFileError, LineageLogError, LineageParamValueError, LineageParamTypeError, \ + LineageDirNotExistError, LineageParamSummaryPathError +from mindinsight.lineagemgr.common.log import logger as log from mindinsight.lineagemgr.common.validator.validate import validate_path from mindinsight.utils.exceptions import MindInsightException @@ -76,3 +77,29 @@ def get_timestamp(filename): """Get timestamp from filename.""" timestamp = int(re.search(SummaryWatcher().SUMMARY_FILENAME_REGEX, filename)[1]) return timestamp + + +def make_directory(path): + """Make directory.""" + real_path = None + if path is None or not isinstance(path, str) or not path.strip(): + log.error("Invalid input path: %r.", path) + raise LineageParamTypeError("Invalid path type") + + # convert relative path to abs path + path = os.path.realpath(path) + log.debug("The abs path is %r", path) + + # check path exist and its write permissions] + if os.path.exists(path): + real_path = path + else: + # All exceptions need to be caught because create directory maybe have some limit(permissions) + log.debug("The directory(%s) doesn't exist, will create it", path) + try: + os.makedirs(path, exist_ok=True) + real_path = path + except PermissionError as e: + log.error("No write permission on the directory(%r), error = %r", path, e) + raise LineageParamTypeError("No write permission on the directory.") + return real_path diff --git a/mindinsight/lineagemgr/common/validator/validate.py b/mindinsight/lineagemgr/common/validator/validate.py index 735aa22..2125de2 100644 --- a/mindinsight/lineagemgr/common/validator/validate.py +++ b/mindinsight/lineagemgr/common/validator/validate.py @@ -14,7 +14,7 @@ # ============================================================================ """Validate the parameters.""" import os - +import re from marshmallow import ValidationError from mindinsight.lineagemgr.common.exceptions.error_code import LineageErrors, LineageErrorMsg @@ -31,6 +31,9 @@ try: except (ImportError, ModuleNotFoundError): log.warning('MindSpore Not Found!') +# Named string regular expression +_name_re = r"^\w+[0-9a-zA-Z\_\.]*$" + TRAIN_RUN_CONTEXT_ERROR_MAPPING = { 'optimizer': LineageErrors.PARAM_OPTIMIZER_ERROR, 'loss_fn': LineageErrors.PARAM_LOSS_FN_ERROR, @@ -511,3 +514,27 @@ def validate_added_info(added_info: dict): raise LineageParamValueError("'remark' must be str.") # length of remark should be in [0, 128]. validate_range("length of remark", len(value), min_value=0, max_value=128) + + +def validate_str_by_regular(target, reg=None, flag=re.ASCII): + """ + Validate string by given regular. + + Args: + target: target string. + reg: pattern. + flag: pattern mode. + + Raises: + LineageParamValueError, if string not match given pattern. + + Returns: + bool, if target matches pattern, return True. + + """ + if reg is None: + reg = _name_re + if re.match(reg, target, flag) is None: + raise LineageParamValueError("'{}' is illegal, it should be match " + "regular'{}' by flags'{}'".format(target, reg, flag)) + return True diff --git a/mindinsight/lineagemgr/summary/_summary_adapter.py b/mindinsight/lineagemgr/summary/_summary_adapter.py index c5adb1e..06a0612 100644 --- a/mindinsight/lineagemgr/summary/_summary_adapter.py +++ b/mindinsight/lineagemgr/summary/_summary_adapter.py @@ -13,12 +13,18 @@ # limitations under the License. # ============================================================================ """The converter between proto format event of lineage and dict.""" +import socket import time from mindinsight.datavisual.proto_files.mindinsight_lineage_pb2 import LineageEvent from mindinsight.lineagemgr.common.exceptions.exceptions import LineageParamTypeError from mindinsight.lineagemgr.common.log import logger as log +# Set the Event mark +EVENT_FILE_NAME_MARK = "out.events." +# Set lineage file mark +LINEAGE_FILE_NAME_MARK = "_lineage" + def package_dataset_graph(graph): """ @@ -345,3 +351,21 @@ def _package_user_defined_info(user_defined_dict, user_defined_message): error_msg = f"Invalid value type in user defined info. The {value}'s type" \ f"'{type(value).__name__}' is not supported. It should be float, int or str." log.error(error_msg) + + +def get_lineage_file_name(): + """ + Get lineage file name. + + Lineage filename format is: + EVENT_FILE_NAME_MARK + "summary." + time(seconds) + "." + Hostname + lineage_suffix. + + Returns: + str, the name of event log file. + """ + + time_second = str(int(time.time())) + hostname = socket.gethostname() + file_name = f'{EVENT_FILE_NAME_MARK}summary.{time_second}.{hostname}{LINEAGE_FILE_NAME_MARK}' + + return file_name diff --git a/mindinsight/lineagemgr/summary/summary_record.py b/mindinsight/lineagemgr/summary/summary_record.py index 0a53fb6..047c550 100644 --- a/mindinsight/lineagemgr/summary/summary_record.py +++ b/mindinsight/lineagemgr/summary/summary_record.py @@ -13,11 +13,13 @@ # limitations under the License. # ============================================================================ """Record message to summary log.""" +import os import time from mindinsight.datavisual.proto_files.mindinsight_lineage_pb2 import LineageEvent +from mindinsight.lineagemgr.common.validator.validate import validate_file_path from mindinsight.lineagemgr.summary.event_writer import EventWriter -from ._summary_adapter import package_dataset_graph, package_user_defined_info +from ._summary_adapter import package_dataset_graph, package_user_defined_info, get_lineage_file_name class LineageSummary: @@ -26,20 +28,24 @@ class LineageSummary: Recording train lineage and evaluation lineage to summary log. Args: - summary_log_path (str): Summary log path. + lineage_log_dir (str): lineage log dir. override (bool): If override the summary log exist. Raises: - IOError: Write to summary log failed or file_path is a dir. + IOError: Write to summary log failed. Examples: - >>> summary_log_path = "./test.log" >>> train_lineage = {"train_network": "ResNet"} - >>> lineage_summary = LineageSummary(summary_log_path=summary_log_path) + >>> lineage_summary = LineageSummary(lineage_log_dir="./") >>> lineage_summary.record_train_lineage(train_lineage) """ - def __init__(self, summary_log_path=None, override=False): - self.event_writer = EventWriter(summary_log_path, override) + def __init__(self, + lineage_log_dir=None, + override=False): + lineage_log_name = get_lineage_file_name() + self.lineage_log_path = os.path.join(lineage_log_dir, lineage_log_name) + validate_file_path(self.lineage_log_path) + self.event_writer = EventWriter(self.lineage_log_path, override) @staticmethod def package_train_message(run_context_args): diff --git a/tests/st/func/lineagemgr/collection/model/test_model_lineage.py b/tests/st/func/lineagemgr/collection/model/test_model_lineage.py index 00d98be..ab31da7 100644 --- a/tests/st/func/lineagemgr/collection/model/test_model_lineage.py +++ b/tests/st/func/lineagemgr/collection/model/test_model_lineage.py @@ -73,6 +73,7 @@ class TestModelLineage(TestCase): ] cls.run_context['list_callback'] = _ListCallback(callback) + @pytest.mark.scene_train(2) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -84,9 +85,10 @@ class TestModelLineage(TestCase): train_callback = TrainLineage(self.summary_record, True) train_callback.begin(RunContext(self.run_context)) assert train_callback.initial_learning_rate == 0.12 - lineage_log_path = self.summary_record.full_file_name + '_lineage' + lineage_log_path = train_callback.lineage_summary.lineage_log_path assert os.path.isfile(lineage_log_path) is True + @pytest.mark.scene_train(2) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -103,9 +105,28 @@ class TestModelLineage(TestCase): ) train_callback.begin(RunContext(self.run_context)) assert train_callback.initial_learning_rate == 0.12 - lineage_log_path = self.summary_record.full_file_name + '_lineage' + lineage_log_path = train_callback.lineage_summary.lineage_log_path assert os.path.isfile(lineage_log_path) is True + @pytest.mark.scene_train(2) + @pytest.mark.level0 + @pytest.mark.platform_arm_ascend_training + @pytest.mark.platform_x86_gpu_training + @pytest.mark.platform_x86_ascend_training + @pytest.mark.platform_x86_cpu + @pytest.mark.env_single + def test_train_lineage_with_log_dir(self): + """Test TrainLineage with log_dir.""" + summary_dir = os.path.join(BASE_SUMMARY_DIR, 'log_dir') + train_callback = TrainLineage(summary_record=summary_dir) + train_callback.begin(RunContext(self.run_context)) + assert summary_dir == train_callback.lineage_log_dir + lineage_log_path = train_callback.lineage_summary.lineage_log_path + assert os.path.isfile(lineage_log_path) is True + if os.path.exists(summary_dir): + shutil.rmtree(summary_dir) + + @pytest.mark.scene_train(2) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -127,6 +148,7 @@ class TestModelLineage(TestCase): res = get_summary_lineage(SUMMARY_DIR) assert res.get('hyper_parameters', {}).get('epoch') == 14 + @pytest.mark.scene_eval(3) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -142,6 +164,7 @@ class TestModelLineage(TestCase): eval_run_context['step_num'] = 32 eval_callback.end(RunContext(eval_run_context)) + @pytest.mark.scene_eval(3) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -168,6 +191,7 @@ class TestModelLineage(TestCase): assert res == expect_res shutil.rmtree(summary_dir) + @pytest.mark.scene_train(2) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -177,31 +201,30 @@ class TestModelLineage(TestCase): @mock.patch('os.path.getsize') def test_multiple_trains(self, *args): """ - Callback TrainLineage and EvalLineage for mutltiple times. + Callback TrainLineage and EvalLineage for multiple times. Write TrainLineage and EvalLineage in different files under same directory. EvalLineage log file end with '_lineage'. """ args[0].return_value = 10 for i in range(2): - summary_record = SummaryRecord(SUMMARY_DIR_2, - create_time=int(time.time()) + i) - eval_record = SummaryRecord(SUMMARY_DIR_2, - file_prefix='events.eval.', - create_time=int(time.time() + 10) + i, - file_suffix='.MS_lineage') + summary_record = SummaryRecord(SUMMARY_DIR_2, create_time=int(time.time())) + eval_record = SummaryRecord(SUMMARY_DIR_2, create_time=int(time.time()) + 1) train_callback = TrainLineage(summary_record, True) train_callback.begin(RunContext(self.run_context)) train_callback.end(RunContext(self.run_context)) + time.sleep(1) eval_callback = EvalLineage(eval_record, True) eval_run_context = self.run_context eval_run_context['metrics'] = {'accuracy': 0.78 + i + 1} eval_run_context['valid_dataset'] = self.run_context['train_dataset'] eval_run_context['step_num'] = 32 eval_callback.end(RunContext(eval_run_context)) + time.sleep(1) file_num = os.listdir(SUMMARY_DIR_2) assert len(file_num) == 8 + @pytest.mark.scene_train(2) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -234,6 +257,7 @@ class TestModelLineage(TestCase): assert res.get('algorithm', {}).get('network') == 'ResNet' assert res.get('hyper_parameters', {}).get('optimizer') == 'Momentum' + @pytest.mark.scene_exception(1) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -246,7 +270,6 @@ class TestModelLineage(TestCase): full_file_name = summary_record.full_file_name assert os.path.isfile(full_file_name) is True assert os.path.isfile(full_file_name + "_lineage") is False - train_callback = TrainLineage(summary_record, True) eval_callback = EvalLineage(summary_record, False) with self.assertRaises(LineageParamRunContextError): @@ -256,6 +279,7 @@ class TestModelLineage(TestCase): assert len(file_num) == 1 assert os.path.isfile(full_file_name + "_lineage") is False + @pytest.mark.scene_exception(1) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -276,6 +300,7 @@ class TestModelLineage(TestCase): assert len(file_num) == 1 assert os.path.isfile(full_file_name + "_lineage") is False + @pytest.mark.scene_exception(1) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -300,6 +325,7 @@ class TestModelLineage(TestCase): assert os.path.isfile(full_file_name) is True assert os.path.getsize(full_file_name) == 0 + @pytest.mark.scene_exception(1) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -317,7 +343,7 @@ class TestModelLineage(TestCase): summary_record = SummaryRecord(SUMMARY_DIR_3) train_callback = TrainLineage(summary_record, True) train_callback.begin(RunContext(self.run_context)) - full_file_name = summary_record.full_file_name + "_lineage" + full_file_name = train_callback.lineage_summary.lineage_log_path file_size1 = os.path.getsize(full_file_name) train_callback.end(RunContext(self.run_context)) file_size2 = os.path.getsize(full_file_name) @@ -327,6 +353,7 @@ class TestModelLineage(TestCase): file_size3 = os.path.getsize(full_file_name) assert file_size3 == file_size2 + @pytest.mark.scene_exception(1) @pytest.mark.level0 @pytest.mark.platform_arm_ascend_training @pytest.mark.platform_x86_gpu_training @@ -338,7 +365,7 @@ class TestModelLineage(TestCase): summary_dir = os.path.join(BASE_SUMMARY_DIR, 'run4') if os.path.exists(summary_dir): shutil.rmtree(summary_dir) - summary_record = SummaryRecord(summary_dir, file_suffix='_MS_lineage') + summary_record = SummaryRecord(summary_dir, file_suffix='_MS_lineage_none') full_file_name = summary_record.full_file_name - assert full_file_name.endswith('_lineage') + assert full_file_name.endswith('_lineage_none') assert os.path.isfile(full_file_name) diff --git a/tests/st/func/lineagemgr/conftest.py b/tests/st/func/lineagemgr/conftest.py index 89ed7b6..f225f0a 100644 --- a/tests/st/func/lineagemgr/conftest.py +++ b/tests/st/func/lineagemgr/conftest.py @@ -53,6 +53,19 @@ def pytest_collection_modifyitems(items): if module_item is not None: module_item.append(item) ordered_items = split_items.get(COLLECTION_MODULE) + item_scenes = [] + for item in ordered_items: + scenes = [ + marker for marker in item.own_markers + if marker.name.startswith('scene') + ] + if scenes: + scene_mark = scenes[0].args[0] + else: + scene_mark = 0 + item_scenes.append((item, scene_mark)) + sorted_item_scenes = sorted(item_scenes, key=lambda x: x[1]) + ordered_items = [item_scene[0] for item_scene in sorted_item_scenes] ordered_items.extend(split_items.get(API_MODULE)) items[:] = ordered_items diff --git a/tests/ut/lineagemgr/collection/model/test_model_lineage.py b/tests/ut/lineagemgr/collection/model/test_model_lineage.py index df36770..e6857f7 100644 --- a/tests/ut/lineagemgr/collection/model/test_model_lineage.py +++ b/tests/ut/lineagemgr/collection/model/test_model_lineage.py @@ -205,6 +205,7 @@ class TestModelLineage(TestCase): self.my_eval_module(self.my_summary_record(self.summary_log_path), raise_exception=2) self.assertTrue('Invalid value for raise_exception.' in str(context.exception)) + @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.make_directory') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.' 'AnalyzeObject.analyze_dataset') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.validate_summary_record') @@ -216,20 +217,24 @@ class TestModelLineage(TestCase): args[1].return_value = True args[2].return_value = True args[3].return_value = None + args[4].return_value = '/path/to/lineage/log/dir' args[0].return_value = None eval_lineage = self.my_eval_module(self.my_summary_record(self.summary_log_path)) eval_lineage.end(self.my_run_context(self.run_context)) args[0].assert_called() + @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.make_directory') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.validate_summary_record') def test_eval_end_except_run_context(self, *args): """Test EvalLineage.end method when run_context is invalid..""" args[0].return_value = True + args[1].return_value = '/path/to/lineage/log/dir' eval_lineage = self.my_eval_module(self.my_summary_record(self.summary_log_path), True) with self.assertRaises(Exception) as context: eval_lineage.end(self.run_context) self.assertTrue('Invalid EvalLineage run_context.' in str(context.exception)) + @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.make_directory') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.' 'AnalyzeObject.analyze_dataset') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.validate_summary_record') @@ -242,11 +247,13 @@ class TestModelLineage(TestCase): args[1].return_value = True args[2].return_value = True args[3].return_value = None + args[4].return_value = '/path/to/lineage/log/dir' eval_lineage = self.my_eval_module(self.my_summary_record(self.summary_log_path), True) with self.assertRaises(LineageLogError) as context: eval_lineage.end(self.my_run_context(self.run_context)) self.assertTrue('End error in EvalLineage' in str(context.exception)) + @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.make_directory') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.' 'AnalyzeObject.analyze_dataset') @mock.patch('mindinsight.lineagemgr.collection.model.model_lineage.validate_summary_record') @@ -259,6 +266,7 @@ class TestModelLineage(TestCase): args[1].return_value = True args[2].return_value = True args[3].return_value = None + args[4].return_value = '/path/to/lineage/log/dir' eval_lineage = self.my_eval_module(self.my_summary_record(self.summary_log_path), True) with self.assertRaises(LineageLogError) as context: eval_lineage.end(self.my_run_context(self.run_context)) diff --git a/tests/ut/lineagemgr/summary/test_summary_record.py b/tests/ut/lineagemgr/summary/test_summary_record.py index 15b5f69..1e2f3de 100644 --- a/tests/ut/lineagemgr/summary/test_summary_record.py +++ b/tests/ut/lineagemgr/summary/test_summary_record.py @@ -64,7 +64,7 @@ class TestSummaryRecord(TestCase): def test_record_train_lineage(self, write_file): """Test record_train_lineage.""" write_file.return_value = True - lineage_summray = LineageSummary(summary_log_path="test.log") + lineage_summray = LineageSummary(lineage_log_dir="test.log") lineage_summray.record_train_lineage(self.run_context_args) def test_package_evaluation_message(self): @@ -76,5 +76,5 @@ class TestSummaryRecord(TestCase): def test_record_eval_lineage(self, write_file): """Test record_eval_lineage.""" write_file.return_value = True - lineage_summray = LineageSummary(summary_log_path="test.log") + lineage_summray = LineageSummary(lineage_log_dir="test.log") lineage_summray.record_evaluation_lineage(self.eval_args) diff --git a/tests/utils/mindspore/train/summary/summary_record.py b/tests/utils/mindspore/train/summary/summary_record.py index 4bf0f3d..a1cf556 100644 --- a/tests/utils/mindspore/train/summary/summary_record.py +++ b/tests/utils/mindspore/train/summary/summary_record.py @@ -15,6 +15,7 @@ """MindSpore Mock Interface""" import os import time +import socket class SummaryRecord: @@ -22,13 +23,15 @@ class SummaryRecord: def __init__(self, log_dir: str, - file_prefix: str = "events.", - file_suffix: str = ".MS", + file_prefix: str = "events", + file_suffix: str = "_MS", create_time=int(time.time())): self.log_dir = log_dir self.prefix = file_prefix self.suffix = file_suffix - file_name = file_prefix + 'summary.' + str(create_time) + file_suffix + hostname = socket.gethostname() + file_name = f'{file_prefix}.out.events.summary.{str(create_time)}.{hostname}{file_suffix}' + self.full_file_name = os.path.join(log_dir, file_name) permissions = os.R_OK | os.W_OK | os.X_OK mode = permissions << 6 -- GitLab