Exemple #1
0
def backup_splits():
    """
    Save the data splits used during training to the timestamped dir.
    """
    src = paths.get_splits_dir()
    dst = paths.get_ts_splits_dir()
    copy_tree(src, dst)
Exemple #2
0
def save_embeddings_txt(filepaths, labels, name):
    # Remove prepath
    new_paths = []
    embed_dir = paths.get_embeddings_dir()
    for fpath in filepaths:
        tmp_path = os.path.relpath(fpath, start=embed_dir)
        new_paths.append(tmp_path)
    new_paths = np.array(new_paths)

    np.savetxt(os.path.join(paths.get_ts_splits_dir(), name),
               np.array([new_paths, labels]).T,
               delimiter=' ',
               fmt='%s')
def train_fn(TIMESTAMP, CONF):

    paths.timestamp = TIMESTAMP
    paths.CONF = CONF

    utils.create_dir_tree()
    utils.backup_splits()

    # Load the training data
    X_train, y_train = load_data_splits(splits_dir=paths.get_ts_splits_dir(),
                                        dataset_dir=paths.get_dataset_dir(),
                                        split_name='train')

    # Load the validation data
    if (CONF['training']['use_validation']) and ('val.txt' in os.listdir(
            paths.get_ts_splits_dir())):
        X_val, y_val = load_data_splits(splits_dir=paths.get_ts_splits_dir(),
                                        dataset_dir=paths.get_dataset_dir(),
                                        split_name='val')
    else:
        print('No validation data.')
        X_val, y_val = None, None
        CONF['training']['use_validation'] = False

    # Load the class names
    class_names = load_class_names(splits_dir=paths.get_ts_splits_dir())

    # Update the configuration
    CONF['training']['batch_size'] = min(CONF['training']['batch_size'],
                                         len(X_train))

    if CONF['model']['num_classes'] is None:
        CONF['model']['num_classes'] = len(class_names)

    assert CONF['model']['num_classes'] >= np.amax(
        y_train
    ), "Your train.txt file has more categories than those defined in classes.txt"
    if CONF['training']['use_validation']:
        assert CONF['model']['num_classes'] >= np.amax(
            y_val
        ), "Your val.txt file has more categories than those defined in classes.txt"

    # # Transform the training data to scipy-compatible 16-bit
    # print('Transforming inputs to 16-bits ...')
    # for p in tqdm(X_train):
    #     file_to_PCM_16bits(p)
    # if CONF['training']['use_validation']:
    #     for p in tqdm(X_val):
    #         file_to_PCM_16bits(p)

    # Empty embeddings dir if needed
    print('Generating embeddings ...')
    embed_dir = paths.get_embeddings_dir()
    if CONF['training']['recompute_embeddings']:
        for f in os.listdir(embed_dir):
            os.remove(os.path.join(embed_dir, f))

    # Generate embeddings
    model_wrap = ModelWrapper()
    X_train = generate_embeddings(
        model_wrap=model_wrap,
        file_list=X_train,
        overwrite=CONF['training']['recompute_embeddings'])
    if CONF['training']['use_validation']:
        X_val = generate_embeddings(
            model_wrap=model_wrap,
            file_list=X_val,
            overwrite=CONF['training']['recompute_embeddings'])
        if len(X_train) + len(X_val) != len(
                set(X_train.tolist() + X_val.tolist())):
            raise Exception(
                'File names are repeated between training and validation')

    #Create data generator for train and val sets
    train_gen = data_sequence(X_train,
                              y_train,
                              batch_size=CONF['training']['batch_size'],
                              num_classes=CONF['model']['num_classes'])
    train_steps = int(np.ceil(len(X_train) / CONF['training']['batch_size']))

    if CONF['training']['use_validation']:
        val_gen = data_sequence(X_val,
                                y_val,
                                batch_size=CONF['training']['batch_size'],
                                num_classes=CONF['model']['num_classes'])
        val_steps = int(np.ceil(len(X_val) / CONF['training']['batch_size']))
    else:
        val_gen = None
        val_steps = None

    # Launch the training
    t0 = time.time()

    # Create the model and compile it
    model, base_model = model_utils.create_model(
        CONF, base_model=model_wrap.classify_model)

    # Get a list of the top layer variables that should not be applied a lr_multiplier
    base_vars = [var.name for var in base_model.trainable_variables]
    all_vars = [var.name for var in model.trainable_variables]
    top_vars = set(all_vars) - set(base_vars)
    top_vars = list(top_vars)

    # Set trainable layers
    if CONF['training']['mode'] == 'fast':
        for layer in base_model.layers:
            layer.trainable = False

    model.compile(optimizer=customAdam(lr=CONF['training']['initial_lr'],
                                       amsgrad=True,
                                       lr_mult=0.1,
                                       excluded_vars=top_vars),
                  loss='categorical_crossentropy',
                  metrics=['accuracy'])

    history = model.fit_generator(generator=train_gen,
                                  steps_per_epoch=train_steps,
                                  epochs=CONF['training']['epochs'],
                                  class_weight=None,
                                  validation_data=val_gen,
                                  validation_steps=val_steps,
                                  callbacks=utils.get_callbacks(CONF),
                                  verbose=1,
                                  max_queue_size=5,
                                  workers=4,
                                  use_multiprocessing=True,
                                  initial_epoch=0)

    # Saving everything
    print('Saving data to {} folder.'.format(paths.get_timestamped_dir()))
    print('Saving training stats ...')
    stats = {
        'epoch': history.epoch,
        'training time (s)': round(time.time() - t0, 2),
        'timestamp': TIMESTAMP
    }
    stats.update(history.history)
    stats_dir = paths.get_stats_dir()
    with open(os.path.join(stats_dir, 'stats.json'), 'w') as outfile:
        json.dump(stats, outfile, sort_keys=True, indent=4)

    print('Saving the configuration ...')
    model_utils.save_conf(CONF)

    print('Saving the model to h5...')
    fpath = os.path.join(paths.get_checkpoints_dir(), 'final_model.h5')
    model.save(fpath)

    # print('Saving the model to protobuf...')
    # fpath = os.path.join(paths.get_checkpoints_dir(), 'final_model.proto')
    # model_utils.save_to_pb(model, fpath)

    print('Finished')
def load_inference_model(timestamp=None, ckpt_name=None):
    """
    Load a model for prediction.

    Parameters
    ----------
    * timestamp: str
        Name of the timestamp to use. The default is the last timestamp in `./models`.
    * ckpt_name: str
        Name of the checkpoint to use. The default is the last checkpoint in `./models/[timestamp]/ckpts`.
    """
    global loaded_ts, loaded_ckpt
    global model_wrapper, conf, class_names, class_info

    # Set the timestamp
    timestamp_list = next(os.walk(paths.get_models_dir()))[1]
    timestamp_list = sorted(timestamp_list)
    timestamp_list.remove('common')  # common files do not count as full model
    if not timestamp_list:
        raise Exception(
            "You have no models in your `./models` folder to be used for inference. "
            "Therefore the API can only be used for training.")
    elif timestamp is None:
        timestamp = timestamp_list[-1]
    elif timestamp not in timestamp_list:
        raise ValueError(
            "Invalid timestamp name: {}. Available timestamp names are: {}".
            format(timestamp, timestamp_list))
    paths.timestamp = timestamp
    print('Using TIMESTAMP={}'.format(timestamp))

    # Set the checkpoint model to use to make the prediction
    ckpt_list = os.listdir(paths.get_checkpoints_dir())
    ckpt_list = sorted([name for name in ckpt_list if name.endswith('.h5')])
    if not ckpt_list:
        raise Exception(
            "You have no checkpoints in your `./models/{}/ckpts` folder to be used for inference. "
            .format(timestamp) +
            "Therefore the API can only be used for training.")
    elif ckpt_name is None:
        ckpt_name = ckpt_list[-1]
    elif ckpt_name not in ckpt_list:
        raise ValueError(
            "Invalid checkpoint name: {}. Available checkpoint names are: {}".
            format(ckpt_name, ckpt_list))
    print('Using CKPT_NAME={}'.format(ckpt_name))

    # Clear the previous loaded model
    K.clear_session()

    # Load the class names and info
    splits_dir = paths.get_ts_splits_dir()
    class_names = load_class_names(splits_dir=splits_dir)
    class_info = None
    if 'info.txt' in os.listdir(splits_dir):
        class_info = load_class_info(splits_dir=splits_dir)
        if len(class_info) != len(class_names):
            warnings.warn(
                """The 'classes.txt' file has a different length than the 'info.txt' file.
            If a class has no information whatsoever you should leave that classes row empty or put a '-' symbol.
            The API will run with no info until this is solved.""")
            class_info = None
    if class_info is None:
        class_info = ['' for _ in range(len(class_names))]

    # Load training configuration
    conf_path = os.path.join(paths.get_conf_dir(), 'conf.json')
    with open(conf_path) as f:
        conf = json.load(f)
        update_with_saved_conf(conf)

    # Load the model
    model_wrapper = ModelWrapper(
        classifier_model=os.path.join(paths.get_checkpoints_dir(), ckpt_name))

    # Set the model as loaded
    loaded_ts = timestamp
    loaded_ckpt = ckpt_name