validators.py 5.37 KB
Newer Older
chicm-ms's avatar
chicm-ms committed
1
2
3
4
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT license.

import os.path as osp
Yan Ni's avatar
Yan Ni committed
5
6
from os import remove
import subprocess
chicm-ms's avatar
chicm-ms committed
7
8
import json
import requests
J-shang's avatar
J-shang committed
9
from nni.experiment import Experiment
10
from nni.tools.nnictl.updater import load_imported_data
11
from utils import METRICS_URL, GET_IMPORTED_DATA_URL
chicm-ms's avatar
chicm-ms committed
12
13
14
15
16
17


class ITValidator:
    def __call__(self, rest_endpoint, experiment_dir, nni_source_dir, **kwargs):
        pass

Yan Ni's avatar
Yan Ni committed
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class ExportValidator(ITValidator):
    def __call__(self, rest_endpoint, experiment_dir, nni_source_dir, **kwargs):
        exp_id = osp.split(experiment_dir)[-1]
        proc1 = subprocess.run(["nnictl", "experiment", "export", exp_id, "-t", "csv", "-f", "report.csv"])
        assert proc1.returncode == 0, '`nnictl experiment export -t csv` failed with code %d' % proc1.returncode
        with open("report.csv", 'r') as f:
            print('Exported CSV file: \n')
            print(''.join(f.readlines()))
            print('\n\n')
        remove('report.csv')

        proc2 = subprocess.run(["nnictl", "experiment", "export", exp_id, "-t", "json", "-f", "report.json"])
        assert proc2.returncode == 0, '`nnictl experiment export -t json` failed with code %d' % proc2.returncode
        with open("report.json", 'r') as f:
            print('Exported JSON file: \n')
            print('\n'.join(f.readlines()))
            print('\n\n')
        remove('report.json')
chicm-ms's avatar
chicm-ms committed
36

37
38
39
40
41
42
43
44
class ImportValidator(ITValidator):
    def __call__(self, rest_endpoint, experiment_dir, nni_source_dir, **kwargs):
        exp_id = osp.split(experiment_dir)[-1]
        import_data_file_path = kwargs.get('import_data_file_path')
        proc = subprocess.run(['nnictl', 'experiment', 'import', exp_id, '-f', import_data_file_path])
        assert proc.returncode == 0, \
            '`nnictl experiment import {0} -f {1}` failed with code {2}'.format(exp_id, import_data_file_path, proc.returncode)
        imported_data = requests.get(GET_IMPORTED_DATA_URL).json()
45
        origin_data = load_imported_data(import_data_file_path).replace(' ', '')
46
47
        assert origin_data in imported_data

chicm-ms's avatar
chicm-ms committed
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class MetricsValidator(ITValidator):
    def __call__(self, rest_endpoint, experiment_dir, nni_source_dir, **kwargs):
        self.check_metrics(nni_source_dir, **kwargs)

    def check_metrics(self, nni_source_dir, **kwargs):
        expected_result_file = kwargs.get('expected_result_file', 'expected_metrics.json')
        with open(osp.join(nni_source_dir, 'test', 'config', 'metrics_test', expected_result_file), 'r') as f:
            expected_metrics = json.load(f)
        print('expected metrics:', expected_metrics)
        metrics = requests.get(METRICS_URL).json()
        print('RAW METRICS:', json.dumps(metrics, indent=4))
        intermediate_result, final_result = self.get_metric_results(metrics)

        assert intermediate_result and final_result
        for trialjob_id in intermediate_result:
            trial_final_result = final_result[trialjob_id]
            trial_intermediate_result = intermediate_result[trialjob_id]
            print('intermediate result:', trial_intermediate_result)
            print('final result:', trial_final_result)
            assert len(trial_final_result) == 1, 'there should be 1 final result'
            assert trial_final_result[0] == expected_metrics['final_result']
            # encode dict/number into json string to compare them in set
chicm-ms's avatar
chicm-ms committed
70
71
            assert set([json.dumps(x, sort_keys=True) for x in trial_intermediate_result]) \
                == set([json.dumps(x, sort_keys=True) for x in expected_metrics['intermediate_result']])
chicm-ms's avatar
chicm-ms committed
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

    def get_metric_results(self, metrics):
        intermediate_result = {}
        final_result = {}
        for metric in metrics:
            # metrics value are encoded by NNI SDK as json string,
            # here we decode the value by json.loads twice
            metric_value = json.loads(json.loads(metric['data']))
            if metric['type'] == 'PERIODICAL':
                if metric['trialJobId'] in intermediate_result:
                    intermediate_result[metric['trialJobId']].append(metric_value)
                else:
                    intermediate_result[metric['trialJobId']] = [metric_value]
            elif metric['type'] == 'FINAL':
                if metric['trialJobId'] in final_result:
                    final_result[metric['trialJobId']].append(metric_value)
                else:
                    final_result[metric['trialJobId']] = [metric_value]
        return intermediate_result, final_result

class NnicliValidator(ITValidator):
    def __call__(self, rest_endpoint, experiment_dir, nni_source_dir, **kwargs):
        print(rest_endpoint)
Junwei Sun's avatar
Junwei Sun committed
95
        exp = Experiment()
96
        exp.connect(int(rest_endpoint.split(':')[-1]))
Junwei Sun's avatar
Junwei Sun committed
97
98
99
        print(exp.get_job_statistics())
        print(exp.get_experiment_status())
        print(exp.list_trial_jobs())
100
101
102
103
104
105
106
107
108
109
110
111
112
113

class FileExistValidator(ITValidator):
    def __call__(self, rest_endpoint, experiment_dir, nni_source_dir, **kwargs):
        print(rest_endpoint)
        exp_id = osp.split(experiment_dir)[-1]
        rootpath = kwargs.get('rootpath')
        
        metrics = requests.get(METRICS_URL).json()
        for metric in metrics:
            trial_id = metric['trialJobId']
            checkpath = osp.join(rootpath, 'nni', exp_id, 'trials', trial_id, 'nnioutput', 'checkingfile.txt')
            print('Checking shared storage log exists on trial ',trial_id)
            assert osp.exists(checkpath)