Esempio n. 1
0
 def __init__(self):
     self.name = os.getenv('PROJECT_NAME') or self.DEFAULT_PROJECT_NAME
     self.path = os.getenv('PROJECT_PATH') or self.DEFAULT_PROJECT_PATH
     self.description = ''
     self.tf_enabled = TFSummaryAdapter.exists()
     self.repo = AimRepo(repo_full_path=self.REPO_PATH,
                         mode=AimRepo.READING_MODE)
Esempio n. 2
0
def init():
    """
    Initializes new repository in the current working directory:
     - Creates .aim directory
     - Adds .aim/config.json file with initial configuration
    """
    repo = AimRepo(os.getcwd())
    re_init = False

    # Check whether repo already exists
    if repo.exists():
        re_init = click.confirm('Aim repository is already initialized. ' +
                                'Do you want to re-initialize it?')
        if not re_init:
            return
        # Clear old repo
        repo.rm()

    # Init repo
    new_repo = AimRepo(os.getcwd())
    if new_repo.init():
        if re_init:
            click.echo(
                'Re-initialized empty Aim repository at {}'.format(new_repo))
        else:
            click.echo(('Initialized a new ' +
                        'Aim repository at {}').format(new_repo))
Esempio n. 3
0
    def _save_record(repo: AimRepo,
                     artifact: Artifact,
                     record: Record,
                     dir_path: str = None):
        if record.binary_type is Artifact.IMAGE:
            # Get image name and abs path
            img_name_time = math.floor(time.time() * 1000)
            img_name_random = random_str(10)
            img_name = '{time}__{random}.jpg'.format(time=img_name_time,
                                                     random=img_name_random)
            res = repo.store_image(img_name, record.cat)

            # Save image at specified path
            artifact.save_blobs(res['path'], res['abs_path'])
        elif record.binary_type == Artifact.MODEL:
            # Get model name, directory and zip archive paths
            file_res = repo.store_model_file(record.name, record.cat)

            # Save model at specified path
            model_save_res = artifact.save_blobs(file_res)

            res = repo.store_model(record.name, record.data['model_name'],
                                   record.data['epoch'], record.data['meta'],
                                   model_save_res, record.cat)

            # Archive model directory
            archive_dir(res['zip_path'], res['dir_path'])
        elif record.binary_type == Artifact.PROTOBUF:
            writer_type = RecordWriter.AIMRECORDS_WRITER
            write_mode = 'w' if record.is_singular else 'a'
            writer = RecordWriter.get_writer(writer_type, repo.records_storage)
            writer.write(artifact.get_inst_unique_name(), write_mode,
                         record.content, record.context)
            res = repo.store_artifact(record.name, record.cat, record.data,
                                      writer_type, record.binary_type,
                                      record.context)
        else:
            if record.binary_type == Artifact.JSON:
                writer = RecordWriter.JSON_WRITER
            else:
                writer = RecordWriter.JSON_LOG_WRITER
            file_name = '{}.log'.format(record.name)
            res = repo.store_file(file_name, record.name, record.cat,
                                  record.data, dir_path)
            write_mode = 'w' if record.is_singular else 'a'
            writer = RecordWriter.get_writer(writer)
            writer.write(res['abs_path'], write_mode, record.content)

        return res
Esempio n. 4
0
def select_runs(expression: Optional[str] = None,
                repo_path: Optional[str] = None):
    if repo_path is not None:
        repo = AimRepo(repo_full_path=repo_path)
    else:
        repo = AimRepo.get_working_repo(mode=AimRepo.READING_MODE)

    if not repo:
        return None

    if expression and 'run.archived' not in expression:
        default_expression = 'run.archived is not True'
    else:
        default_expression = None

    return repo.select_runs(expression, default_expression)
Esempio n. 5
0
    def _parse_env_vars(self, env_vars):
        env_vars = env_vars or ''
        env_vars_arr = env_vars.split(' ')
        filtered_env_vars = []

        automated = False
        automated_branch = None
        automated_commit = None
        for e in env_vars_arr:
            if AIM_AUTOMATED_EXEC_ENV_VAR in e:
                automated = True
            elif AIM_BRANCH_ENV_VAR in e:
                _, _, automated_branch = e.rpartition('=')
            else:
                filtered_env_vars.append(e)

        if automated:
            if not automated_branch:
                automated_branch = AIM_DEFAULT_BRANCH_NAME
            automated_commit = AimRepo.generate_commit_hash()

            filtered_env_vars.append('{}={}'.format(AIM_BRANCH_ENV_VAR,
                                                    automated_branch))
            filtered_env_vars.append('{}={}'.format(AIM_COMMIT_ENV_VAR,
                                                    automated_commit))
            filtered_env_vars.append('{}={}'.format(AIM_PROCESS_ENV_VAR,
                                                    self.process_uuid))
            filtered_env_vars.append('{}=1'.format(AIM_AUTOMATED_EXEC_ENV_VAR))

        return {
            'env_vars': ' '.join(filtered_env_vars),
            'automated': automated,
            'automated_branch': automated_branch,
            'automated_commit': automated_commit,
        }
Esempio n. 6
0
def down(repo_inst, repo):
    check_docker_dependency()

    repo_path = clean_repo_path(repo)
    if repo_path:
        repo_inst = AimRepo(repo_path)
    if repo_inst is None or not repo_inst.exists():
        repo_init_alert()
        return

    # Kill all identical running containers
    cont = AimContainer(repo_inst)

    if cont.get_container() is not None:
        click.echo('Shutting down Aim UI at `{}`'.format(repo_inst.path))
        cont.kill()
        click.echo('Done')
    else:
        click.echo('No running Aim UI at `{}`'.format(repo_inst.path))
Esempio n. 7
0
def de_entry_point(ctx):
    repo = ctx.obj or AimRepo.get_working_repo()
    if repo is None:
        repo_init_alert()
        exit()

    ctx.obj = repo

    if not AimContainer.is_docker_installed():
        docker_requirement_alert()
        exit()
Esempio n. 8
0
def select_metrics(search_statement: str, repo_path: Optional[str] = None):
    if repo_path is not None:
        repo = AimRepo(repo_full_path=repo_path)
    else:
        repo = AimRepo.get_working_repo(mode=AimRepo.READING_MODE)

    if not repo:
        return None

    parser = Statement()
    parsed_stmt = parser.parse(search_statement.strip())
    statement_select = parsed_stmt.node['select']
    statement_expr = parsed_stmt.node['expression']

    if 'run.archived' not in search_statement:
        default_expression = 'run.archived is not True'
    else:
        default_expression = None

    return repo.select_metrics(statement_select, statement_expr,
                               default_expression)
Esempio n. 9
0
class Project:
    DEFAULT_PROJECT_NAME = 'Project'
    DEFAULT_PROJECT_PATH = '/project'
    REPO_PATH = '/store'

    def __init__(self):
        self.name = os.getenv('PROJECT_NAME') or self.DEFAULT_PROJECT_NAME
        self.path = os.getenv('PROJECT_PATH') or self.DEFAULT_PROJECT_PATH
        self.description = ''
        self.tf_enabled = TFSummaryAdapter.exists()
        self.repo = AimRepo(repo_full_path=self.REPO_PATH,
                            mode=AimRepo.READING_MODE)

    def exists(self):
        return self.repo and self.repo.exists()
Esempio n. 10
0
def init():
    repo = AimRepo(os.getcwd())
    re_init = False

    # Check whether repo already exists
    if repo.exists():
        re_init = click.confirm('Aim repository is already initialized. ' +
                                'Do you want to re-initialize it?')
        if not re_init:
            return
        # Clear old repo
        repo.rm()

    # Init repo
    new_repo = AimRepo(os.getcwd())
    if new_repo.init():
        if re_init:
            click.echo(
                'Re-initialized empty Aim repository in {}'.format(new_repo))
        else:
            click.echo(('Initialized empty ' +
                        'Aim repository in {}').format(new_repo))
Esempio n. 11
0
    def save(self, repo: AimRepo, artifact: Artifact) -> bool:
        """
        Stores serialized instance into .aim repo
        """
        item = artifact.serialize()
        res = None

        if isinstance(item, Record):
            res = ArtifactWriter._save_record(repo, artifact, item)
        elif isinstance(item, RecordCollection):
            dir_path, dir_rel_path = repo.store_dir(item.name, item.cat,
                                                    item.data)
            res = []
            for record in item.records:
                # Store dir files
                res.append(
                    ArtifactWriter._save_record(repo, artifact, record,
                                                dir_rel_path))

        # Save dict
        return res
Esempio n. 12
0
    def get_repo(path: Optional[str] = None,
                 experiment_name: Optional[str] = None) -> AimRepo:
        # Auto commit
        if os.getenv(AIM_AUTOMATED_EXEC_ENV_VAR):
            # Get Aim environment variables
            branch_name = os.getenv(AIM_BRANCH_ENV_VAR)
            commit_hash = os.getenv(AIM_COMMIT_ENV_VAR)
        else:
            commit_hash = AimRepo.generate_commit_hash()
            if experiment_name is not None:
                branch_name = experiment_name
            else:
                # FIXME: Get active experiment name from given repo
                #  if path is specified. Currently active experiment name of
                #  the highest repo in the hierarchy will be returned.
                branch_name = AimRepo.get_active_branch_if_exists() \
                              or AIM_DEFAULT_BRANCH_NAME

        if path is not None:
            repo = AimRepo(path)
            if not repo.exists():
                if not repo.init():
                    raise ValueError('can not create repo `{}`'.format(path))
            repo = AimRepo(path, branch_name, commit_hash)
        else:
            if AimRepo.get_working_repo() is None:
                path = os.getcwd()
                repo = AimRepo(path)
                if not repo.init():
                    raise ValueError('can not create repo `{}`'.format(path))
                repo = AimRepo(path, branch_name, commit_hash)
            else:
                repo = AimRepo.get_working_repo(branch_name, commit_hash)

        return repo
Esempio n. 13
0
def cli_entry_point(ctx, verbose):
    if verbose:
        click.echo('Verbose mode is on')

    # Init repo instance
    ctx.obj = AimRepo.get_working_repo()
Esempio n. 14
0
def up(repo_inst, dev, host, port, version, repo, tf_logs, detach):
    check_docker_dependency()

    repo_path = clean_repo_path(repo)
    if repo_path:
        repo_inst = AimRepo(repo_path)
    if repo_inst is None or not repo_inst.exists():
        repo_init_alert()
        return

    # Dev param
    # 0 => pull and run official image of container
    # 1 => run production build from local environment
    # 2 => run in development mode
    cont = AimContainer(repo_inst, dev=bool(dev))

    if tf_logs:
        cont.mount_volume(tf_logs, AIM_TF_LOGS_PATH)

    click.echo(
        click.style('Running Aim UI on repo `{}`'.format(repo_inst),
                    fg='yellow'))

    # Check if image exist
    if dev == 0 and not cont.image_exist(version):
        click.echo('Pulling Aim UI docker image, please wait...')
        if not cont.pull(version):
            docker_image_pull_fail_alert()
            return
        else:
            click.echo('Successfully pulled Aim UI image')

    if cont.get_container(running_only=True):
        kill = click.confirm('Aim UI is already running. ' +
                             'Do you want to restart it?')
        if not kill:
            return

    # Kill all identical running containers
    cont.kill()

    # if dev < 2
    # cont.bind(port + 1, AIM_CONTAINER_CMD_PORT)
    cont_id = cont.up(port, host, version)
    if not cont_id:
        click.echo('Failed to run Aim UI. Please try again.')
        return

    # cont_cmd = AimContainerCommandManager((port + 1) if dev < 2
    #                                       else AIM_CONTAINER_CMD_PORT)
    # cont_cmd.listen()

    # Kill container after keyboard interruption
    def graceful_shutdown():
        # cont_cmd.kill()

        click.echo('')
        click.echo('Shutting down...')
        try:
            cont.kill()
        except Exception:
            pass
        click.echo('Done')
        sys.exit(0)

    # Add keyboard signal interruption listener
    # signal.signal(signal.SIGINT, graceful_shutdown)
    # signal.pause()

    try:
        sleep(4)
        click.echo('Open http://{}:{}'.format(host, port))

        if not detach:
            click.echo('Press Ctrl+C to exit')
            while True:
                if cont.get_container() is not None:
                    sleep(0.3)
                else:
                    click.echo('Exited')
                    return
    except KeyboardInterrupt:
        graceful_shutdown()
        sys.exit(0)
Esempio n. 15
0
def up(repo_inst, dev, host, port, version, repo, tf_logs, detach):
    check_docker_dependency()

    repo_path = clean_repo_path(repo)
    if repo_path:
        repo_inst = AimRepo(repo_path)
    if repo_inst is None or not repo_inst.exists():
        repo_init_alert()
        return

    # Dev param
    # 0 => pull and run official image of container
    # 1 => run production build from local environment
    # 2 => run in development mode
    cont = AimContainer(repo_inst, dev=bool(dev))

    if tf_logs:
        cont.mount_volume(tf_logs, AIM_TF_LOGS_PATH)

    if os.getenv(AIM_CONTAINER_TELEMETRY_FLAG) is not None \
            and os.getenv(AIM_CONTAINER_TELEMETRY_FLAG) == '0':
        cont.turn_telemetry_off()
    else:
        cont.turn_telemetry_on()
        alert_msg = 'Aim UI collects anonymous usage analytics.'
        opt_out_msg = 'Read how to opt-out here: '
        opt_out_url = 'https://github.com/aimhubio/aim#anonymized-telemetry'
        line_width = max(len(opt_out_msg), len(alert_msg)) + 16
        click.echo('┌{}┐'.format('-' * (line_width - 2)))
        click.echo('{}{}{}'.format(' ' * ((line_width - len(alert_msg)) // 2),
                                   alert_msg,
                                   ' ' * ((line_width - len(alert_msg)) // 2)))
        click.echo('{}{}{}'.format(
            ' ' * ((line_width - len(opt_out_msg)) // 2), opt_out_msg,
            ' ' * ((line_width - len(opt_out_msg)) // 2)))
        click.echo('{}{}{}'.format(
            ' ' * ((line_width - len(opt_out_url)) // 2), opt_out_url,
            ' ' * ((line_width - len(opt_out_url)) // 2)))
        click.echo('└{}┘'.format('-' * (line_width - 2)))

    click.echo(
        click.style('Running Aim UI on repo `{}`'.format(repo_inst),
                    fg='yellow'))

    # Check if image exist
    if dev == 0 and not cont.image_exist(version):
        click.echo('Pulling Aim UI docker image, please wait...')
        if not cont.pull(version):
            docker_image_pull_fail_alert()
            return
        else:
            click.echo('Successfully pulled Aim UI image')

    if cont.get_container(running_only=True):
        kill = click.confirm('Aim UI is already running. ' +
                             'Do you want to restart it?')
        if not kill:
            return

    # Kill all identical running containers
    cont.kill()

    # if dev < 2
    # cont.bind(port + 1, AIM_CONTAINER_CMD_PORT)
    cont_id = cont.up(port, host, version)
    if not cont_id:
        click.echo('Failed to run Aim UI. Please try again.')
        return

    # cont_cmd = AimContainerCommandManager((port + 1) if dev < 2
    #                                       else AIM_CONTAINER_CMD_PORT)
    # cont_cmd.listen()

    # Kill container after keyboard interruption
    def graceful_shutdown():
        # cont_cmd.kill()

        click.echo('')
        click.echo('Shutting down...')
        try:
            cont.kill()
        except Exception:
            pass
        click.echo('Done')
        sys.exit(0)

    # Add keyboard signal interruption listener
    # signal.signal(signal.SIGINT, graceful_shutdown)
    # signal.pause()

    try:
        sleep(4)
        click.echo('Open http://{}:{}'.format(host, port))

        if not detach:
            click.echo('Press Ctrl+C to exit')
            while True:
                if cont.get_container() is not None:
                    sleep(0.3)
                else:
                    click.echo('Exited')
                    return
    except KeyboardInterrupt:
        graceful_shutdown()
        sys.exit(0)
Esempio n. 16
0
class Project:
    DEFAULT_PROJECT_NAME = 'Project'
    DEFAULT_PROJECT_PATH = '/project'
    REPO_PATH = '/store'

    def __init__(self):
        self.name = os.getenv('PROJECT_NAME') or self.DEFAULT_PROJECT_NAME
        self.path = os.getenv('PROJECT_PATH') or self.DEFAULT_PROJECT_PATH
        self.description = ''
        self.tf_enabled = TFSummaryAdapter.exists()
        self.repo = AimRepo(repo_full_path=self.REPO_PATH,
                            mode=AimRepo.READING_MODE)

    def exists(self):
        return self.repo and self.repo.exists()

    def get_run_config(self, experiment_name, run_hash):
        config_file_path = os.path.join(self.repo.path,
                                        experiment_name,
                                        run_hash)
        config_file_path = os.path.join(config_file_path,
                                        AIM_COMMIT_CONFIG_FILE_NAME)

        if not os.path.isfile(config_file_path):
            return None

        with open(config_file_path, 'r+') as config_file:
            try:
                configs = json.loads(config_file.read())
            except:
                configs = None

        return configs

    def get_modified_runs(self, last_modified=0):
        updated_runs = {}

        if not self.repo:
            return updated_runs

        experiments = self.repo.list_branches()
        for experiment in experiments:
            runs = self.repo.list_branch_commits(experiment)
            for run in runs:
                run_path = os.path.join(self.repo.path, experiment, run)
                run_config_path = os.path.join(run_path,
                                               AIM_COMMIT_CONFIG_FILE_NAME)

                if not os.path.exists(run_config_path):
                    continue

                run_config_path = Path(run_config_path)
                if not run_config_path or not run_config_path.exists():
                    continue

                run_stats = run_config_path.stat()
                if not run_stats:
                    continue

                modified_time = run_config_path.stat().st_mtime

                if not modified_time or modified_time > last_modified:
                    updated_runs.setdefault(experiment, [])
                    updated_runs[experiment].append((run, modified_time))

        return updated_runs
Esempio n. 17
0
def commit(repo, message, code):
    if repo is None:
        click.echo('Repository does not exist')
        return

    commit_hash = AimRepo.generate_commit_hash()
    message = message.strip() or int(time.time())

    # Check if there is anything to commit
    if repo.is_index_empty():
        click.echo('Nothing to commit')
        return

    branch_name = branch_hash = None
    if code:
        try:
            from aim.version_control.factory import Factory
        except Exception:
            click.echo('Git executable not found')
            return

        vc = Factory.create(Factory.GIT)

        # Check if version control repo exists
        if vc is None or vc.get_repo() is None:
            click.echo('No git repository (or any parent up to mount ' +
                       'point /) found. Initialize git repository ' +
                       'by running `git init`')
            return

        # Check untracked files
        if len(vc.get_untracked_files()):
            click.echo('You have untracked files, please add them to the ' +
                       'index before committing your changes by running ' +
                       '`git add -A`')
            return

        # Check if HEAD exists
        if not vc.get_head_hash():
            click.echo('Needed a single revision. ' +
                       'You do not have the git initial commit yet')
            return

        # Commit changes to a new created branch and return branch name
        branch_name, branch_hash = vc.commit_changes_to_branch(
            message, commit_hash)

        # Get the latest branch
        latest_branch = repo.get_latest_vc_branch() or {}
        latest_branch = latest_branch.get('branch')
        if latest_branch is None:
            latest_branch = vc.get_head_hash()

        # Get diff between current commit and latest commit(or HEAD)
        diff = vc.get_diff_text(latest_branch, branch_name)
        repo.save_diff(diff)

    # Commit
    commit_res = repo.commit(commit_hash, message, branch_name, branch_hash)

    click.echo(
        click.style('[{b}/{c} commit]'.format(b=commit_res['branch'],
                                              c=commit_res['commit']),
                    fg='yellow'))
    click.echo(message)
Esempio n. 18
0
    def test_run_archivation(self):
        """
        Test aim repo can be removed correctly.
        """
        prefix = os.getcwd() + '/'
        with tempfile.TemporaryDirectory(prefix=prefix) as tmp_dir_path:
            AimRepo(tmp_dir_path).init()

            experiment = 'test'
            run_hash = AimRepo.generate_commit_hash()
            repo = AimRepo(tmp_dir_path, experiment, run_hash)
            repo.commit_init()
            repo.commit_finish()

            self.assertFalse(repo.is_archived(experiment, run_hash))

            repo.archive(experiment, run_hash)
            self.assertTrue(repo.is_archived(experiment, run_hash))

            repo.unarchive(experiment, run_hash)
            self.assertFalse(repo.is_archived(experiment, run_hash))