示例#1
0
 def _check_args(self):
     """ Perfunctory argument checks and modification.
     """
     args = self.args
     # Check scp and labels
     common.CHK_GE(len(args.valid_scp), 1)
     common.CHK_EQ(len(args.valid_labels) % len(args.valid_scp), 0)
     labels_per_valid_scp = len(args.valid_labels) / len(args.valid_scp)
     common.CHK_EQ(len(args.train_labels), labels_per_valid_scp)
     # Check task
     if len(args.task) == 1:
         args.task = args.task * len(args.train_labels)
     common.CHK_EQ(len(args.task), len(args.train_labels))
     for task in args.task:
         common.CHK_VALS(task, TASKS)
     if args.num_classes is not None:
         common.CHK_EQ(len(args.task), len(args.num_classes))
     if args.task_weights is None:
         args.task_weights = [1.0] * len(args.task)
     common.CHK_EQ(len(args.task), len(args.task_weights))
     # Check others
     for layer_type in args.layer_type:
         common.CHK_VALS(layer_type, LAYERS.keys())
     common.CHK_VALS(args.optimizer, OPTIMIZERS.keys())
     common.CHK_VALS(args.lrate, LRATES.keys())
示例#2
0
def copy_dnn(from_dnn, to_dnn):
    """ Copy weights from from_dnn to to_dnn. The number of layers must match.
    """
    common.CHK_EQ(len(from_dnn.layers), len(to_dnn.layers))
    for i in range(len(from_dnn.layers)):
        to_dnn.layers[i].W.set_value(from_dnn.layers[i].W.get_value())
        to_dnn.layers[i].b.set_value(from_dnn.layers[i].b.get_value())
    return to_dnn
示例#3
0
 def accum(self, y_true, y_pred):
     classes = preds_to_classes(y_pred)
     common.CHK_EQ(len(y_true), len(classes))
     for corr, pred in zip(y_true, classes):
         if corr not in self.total:
             self.total[corr] = 0.0
             self.correct[corr] = 0.0
         self.total[corr] += 1
         self.correct[corr] += int(corr == pred)
示例#4
0
 def _check_args(self):
     """ Perfunctory argument checks.
     """
     args = self.args
     common.CHK_GE(len(args.valid_scp), 1)
     common.CHK_EQ(len(args.valid_scp), len(args.valid_labels))
     common.CHK_VALS(args.task, TASKS)
     for layer_type in args.layer_type:
         common.CHK_VALS(layer_type, LAYERS.keys())
     common.CHK_VALS(args.optimizer, OPTIMIZERS.keys())
     common.CHK_VALS(args.lrate, LRATES.keys())
示例#5
0
def __extract(extract_fn, ark_out, dataset, x, utt_names, utt_frames):
    # Set data
    feats = dataset.get_data_by_utt_names(utt_names)
    common.CHK_EQ(len(feats), np.sum(utt_frames))
    x[:len(feats)] = feats
    # Get big feature matrix
    ext_feats = extract_fn(x[:len(feats)])
    # Write to ark for each utterance
    start = 0
    for utt, frames in zip(utt_names, utt_frames):
        end = start + frames
        ark_out.write_kaldi_mat(utt, ext_feats[start:end])
        start = end
示例#6
0
def __nnet_fwd(output_fn, dataset, x, shared_x, utt_names, utt_frames,
               log_priors):
    # Set data
    feats = dataset.get_data_by_utt_names(utt_names)
    common.CHK_EQ(len(feats), np.sum(utt_frames))
    x[:len(feats)] = feats
    shared_x.set_value(x[:len(feats)], borrow=True)
    # Process each utterance
    start = 0
    for utt, frames in zip(utt_names, utt_frames):
        end = start + frames
        log_probs = np.log(output_fn(start, end))
        if log_priors is not None:
            log_probs -= log_priors
        print_matrix(utt, log_probs)
        start = end
示例#7
0
def comp_UARs(corr_lbls, pred_lbls):
    """ Compute recall rate for each class. Return (recall_rates, classes).
    """
    common.CHK_EQ(len(pred_lbls), len(corr_lbls))
    correct = {}
    count = {}
    for pred, corr in zip(pred_lbls, corr_lbls):
        if corr not in count:
            count[corr] = 0.0
            correct[corr] = 0.0
        count[corr] += 1
        correct[corr] += 1 if pred == corr else 0
    recall_rates = []
    classes = []
    for c in count.keys():
        recall_rates.append(correct[c] / count[c])
        classes.append(c)
    return (recall_rates, classes)
示例#8
0
文件: io.py 项目: ducle90/chai_share
def ali_with_length_read(ali_fname, ordered=True, expand=False):
    """
    Read a Kaldi alignment with length file. Returns a dictionary.
        If `expand` is False, each value is a list of 2-element tuples
        containing the token ID and length in frames.
        If `expand` is True, each value is an expanded list of labels.
    """
    ret = OrderedDict() if ordered else {}
    with open(ali_fname, 'r') as f:
        for line in f:
            ary = line.strip().replace(';', '').split()
            common.CHK_EQ(len(ary) % 2, 1)
            if ary[0] in ret:
                log('WARNING: duplicate key {}'.format(ary[0]))
            ret[ary[0]] = []
            for i in range(1, len(ary), 2):
                if expand:
                    ret[ary[0]].extend([ary[i]] * int(ary[i + 1]))
                else:
                    ret[ary[0]].append((ary[i], int(ary[i + 1])))
    return ret
示例#9
0
    def __init__(self, data_gens, buf_cls, shuffle_gens=True, **kwargs):
        """
        :type buf_cls: class
        :param buf_cls: Class to use for buffered dataset

        :type data_gens: list of chaipy.data.incremental.DataGenerator
        :param data_gens: For generating individual datasets

        :type shuffle_gens: bool
        :param shuffle_gens: Shuffle generator list after each iteration

        :type kwargs: dict
        :param kwargs: Keyword arguments used to initialize `buf_cls`
        """
        common.CHK_EQ(type(data_gens), list)
        common.CHK_GE(len(data_gens), 1)
        self.__buf_dataset = None
        self._data_gens = data_gens
        self._buf_cls = buf_cls
        self._shuffle_gens = shuffle_gens
        self._kwargs = kwargs
        self.reset()
示例#10
0
def AUC(corr_lbls, pred_scores, positive_lbl):
    """ Compute AUC (Area Under the Curve) """
    common.CHK_EQ(len(pred_scores), len(corr_lbls))
    fpr, tpr, _ = metrics.roc_curve(corr_lbls, pred_scores,
                                    pos_label=positive_lbl)
    return metrics.auc(fpr, tpr)
示例#11
0
def train_mtrnn_v2(model,
                   buf_train,
                   buf_valids,
                   lrate,
                   validate_on=0,
                   ntasks=None,
                   optimizer=None,
                   task_weights=None,
                   primary_task=0,
                   save_dir=None,
                   pre_validate=False,
                   restore=False,
                   loss='sparse_categorical_crossentropy',
                   metrics=['acc'],
                   validate_metrics=None,
                   stateful=False):
    """
    Train multi-task RNN given a training and multiple validation sets.

    :type model: Keras model
    :param model: The model to train

    :type buf_train: chaipy.data.temporal.BufferedUttData
    :param buf_train: The dataset to train on (multi-label)

    :type buf_valids: list of chaipy.data.temporal.BufferedUttData
    :param buf_valids: The datasets to validate on (multi-label)

    :type lrate: utils.learn_rates.LearningRate
    :param lrate: Object to control learning rate decay

    :type validate_on: int
    :param validate_on: (optional) Which validation set to use for learning
        rate schedule. By default, use the first validation set.

    :type ntasks: int
    :param ntasks: (optional) Number of tasks. If not set, determine automatically.

    :type optimizer: keras.optimizers.Optimizer
    :param optimizer: (optional) Optimizer to use. If not set, use Adam.

    :type task_weights: list
    :param task_weights: (optional) Task weights. If not set, use 1.0 everywhere.

    :type primary_task: int
    :param primary_task: (optional) Validate on this task. If set to -1, use
        the average metric across all tasks.

    :type save_dir: str
    :param save_dir: (optional) If not None, save the most recent intermediate
        model to this directory. We only keep the most recent model in this
        directory, except for the final model since we expect the caller of
        this function to save it manually. The caller is responsible for the
        creation and deletion of this directory. The code does not create and
        delete the directory automatically.

    :type pre_validate: bool
    :param pre_validate: (optional) If True, do one validation iteration
        before training the model and use this value to bootstrap lrate.

    :type restore: bool
    :param restore: (optional) If True, restore parameters of the previous model
        if new validation error is higher than the lowest error thus far. This
        strategy is suitable for less stable learning.

    :type loss: str or keras loss function or list
    :param loss: (optional) Loss function(s) for training. Use list to apply
        different loss functions to different tasks. Accepted types are:
            * str: must be a key in `chaipy.common.metrics.OBJECTIVE_FUNCTIONS`
                   or one recognized by keras.
            * function: a symbolic function with signature `fn(y_true, y_pred)`

    :type metrics: list of str
    :param metrics: (optional) Metrics to report when showing training progress.
        Must use the exact Keras name defined by the metric function! For
        example, use 'mean_squared_error' instead of 'mse'; use 'acc' instead
        of 'accuracy'. If multiple metrics are specified, the first metric is
        used to log training errors.

    :type validate_metrics: list of str or function
    :param validate_metrics: (optional) Which metrics to use for validation.
        If unspecified, use training metrics. If multiple metrics are specified,
        the first metric is used for actual validation. Valid string metrics are
        'acc' or those defined in `chaipy.common.metrics.VALIDATION_METRICS`.
        Functions must have the signature `fn(y_true, y_pred)`. If different
        tasks need different validation metrics, use a dict that maps from
        task ID to a list of validation metrics.

    :type validate_metrics: list
    :param validate_metrics: (optional) Which metrics to use for validation.
        If unspecified, use training metrics. If multiple metrics are specified,
        the first metric is used for actual validation. By default, the same
        metrics are applied to all tasks. If different tasks need different
        validation metrics, use a dict that maps from task ID to a list of
        validation metrics. Accepted types are:
            * str: must be a key in `chaipy.common.metrics.VALIDATION_METRICS`
            * function: must have the signature `fn(y_true, y_pred)`
            * class: must be a subclass of `chaipy.common.metrics.AbstractMetric`

    :type stateful: bool
    :param stateful: (optional) Network is stateful.

    :rtype: tuple
    :return: (training errors, [validation errors])
    """
    common.CHK_EQ(type(buf_valids), list)
    if optimizer is None:
        optimizer = adam(lr=lrate.get_rate())
    if type(loss) == list:
        loss = [init_loss(l) for l in loss]
    else:
        loss = init_loss(loss)
    if validate_metrics is None:
        validate_metrics = metrics
    io.log('... finetuning the model')
    train_errs, valid_errs = [], []
    for _ in range(len(buf_valids)):
        valid_errs.append([])
    prev_weights = None
    # Do one premptive validation iteration if necessary
    if pre_validate:
        train_errs.append(-1)
        for i in range(len(buf_valids)):
            all_valid_errs = validate_mtrnn(model,
                                            buf_valids[i],
                                            ntasks=ntasks,
                                            metrics=validate_metrics,
                                            stateful=stateful)
            io.log('** Pre-validate: all validation errors ({}) {}'.format(
                i, all_valid_errs))
            valid_errs[i].append(__get_metric(all_valid_errs, primary_task))
            io.log('** Pre-validate: validation error ({}) {}'.format(
                i, valid_errs[i][-1]))
        lrate.lowest_error = valid_errs[validate_on][-1]
        if restore:
            prev_weights = [l.get_weights() for l in model.layers]
    # Start training
    model.compile(optimizer=optimizer,
                  loss=loss,
                  loss_weights=task_weights,
                  metrics=metrics)
    while lrate.get_rate() != 0:
        model.optimizer.lr.set_value(lrate.get_rate())
        io.log('*** Optimizer state: {}'.format(model.optimizer.get_config()))
        # One epoch of training
        all_train_errs = _train_mt(model,
                                   buf_train,
                                   ntasks=ntasks,
                                   metrics=metrics,
                                   stateful=stateful,
                                   loss=loss)
        io.log('** Epoch {}, lrate {}, all training errors {}'.format(
            lrate.epoch, lrate.get_rate(), all_train_errs))
        train_errs.append(__get_metric(all_train_errs, primary_task))
        io.log('** Epoch {}, lrate {}, training error {}'.format(
            lrate.epoch, lrate.get_rate(), train_errs[-1]))
        for i in range(len(buf_valids)):
            all_valid_errs = validate_mtrnn(model,
                                            buf_valids[i],
                                            ntasks=ntasks,
                                            metrics=validate_metrics,
                                            stateful=stateful)
            io.log(
                '** Epoch {}, lrate {}, all validation errors ({}) {}'.format(
                    lrate.epoch, lrate.get_rate(), i, all_valid_errs))
            valid_errs[i].append(__get_metric(all_valid_errs, primary_task))
            io.log('** Epoch {}, lrate {}, validation error ({}) {}'.format(
                lrate.epoch, lrate.get_rate(), i, valid_errs[i][-1]))
        prev_error = lrate.lowest_error
        lrate.get_next_rate(current_error=valid_errs[validate_on][-1])
        io.log('**** Updated lrate: {}'.format(lrate.get_rate()))
        # Restore model weights if necessary
        if restore:
            if valid_errs[validate_on][-1] < prev_error:
                prev_weights = [l.get_weights() for l in model.layers]
            elif prev_weights is None:
                io.log(
                    '**WARN** error increased but no prev_weights to restore!')
            elif lrate.epoch <= lrate.min_epoch_decay_start:
                io.log(
                    '** Only {} training epoch, need at least {} to restore **'
                    .format(lrate.epoch - 1, lrate.min_epoch_decay_start))
            else:
                io.log('** Restoring params of previous best model **')
                for l, lw in zip(model.layers, prev_weights):
                    l.set_weights(lw)
                idx = numpy.argmin(valid_errs[validate_on])
                io.log(
                    '** Restored: train err = {}, valid errs = {} **'.format(
                        train_errs[idx],
                        [valid_errs[i][idx] for i in range(len(buf_valids))]))
        # Save intermediate model
        if save_dir is not None:
            curr_epoch = lrate.epoch - 1
            prev_epoch = curr_epoch - 1
            curr_fname = os.path.join(save_dir, '{}'.format(curr_epoch))
            prev_fname = os.path.join(save_dir, '{}'.format(prev_epoch))
            if lrate.get_rate() != 0:
                io.json_save('{}.json'.format(curr_fname), model.to_json())
                model.save_weights('{}.weights'.format(curr_fname))
            for suffix in ['json', 'weights']:
                if os.path.exists('{}.{}'.format(prev_fname, suffix)):
                    os.remove('{}.{}'.format(prev_fname, suffix))
    # If restoring, make sure the final err is also the best err
    if restore and valid_errs[validate_on][-1] != numpy.min(
            valid_errs[validate_on]):
        idx = numpy.argmin(valid_errs[validate_on])
        train_errs.append(train_errs[idx])
        for i in range(len(buf_valids)):
            valid_errs[i].append(valid_errs[i][idx])
    return (train_errs, valid_errs)