def _compute_svm_params(img_feats, prim_labels, expressions, exp_idx):
    # setup svm
    exp_lst = expressions[exp_idx]
    _logger.info("{}/{} - Training svm  ...".format(exp_idx, len(expressions)))
    exp_tree = dbac_expression.list2exp_parse(exp_lst)
    var_dic = {p: prim_labels[:, int(p)] for p in dbac_expression.get_vars(exp_tree)}
    exp_labels = dbac_expression.eval_exp(exp_tree, var_dic)
    svm_object = sklearn_svm.LinearSVC(C=1e-5, class_weight={1: 2.0, 0: 1.0}, verbose=0, penalty='l2',
                                       loss='hinge', dual=True)
    svm_object.fit(img_feats, exp_labels)
    train_acc = svm_object.score(img_feats, exp_labels)
    _logger.info("{}/{} - Finalized svm. Positives {}, Negatives {}, Accuracy {}."
                 .format(exp_idx, len(expressions), np.sum(exp_labels), np.sum(np.logical_not(exp_labels)), train_acc))
    svm_params = np.hstack((svm_object.intercept_.ravel(), svm_object.coef_.ravel()))
    return svm_params
예제 #2
0
def _compute_statistics(db_name,
                        db_path,
                        split_file,
                        comb_file=None,
                        plot=False):
    # Read data
    logger.info("Loading dataset and split...")
    dataset = dbac_data.IDataset.factory(db_name, db_path)
    dataset.load_split(split_file, comb_file)

    # extract information
    train_labels = dataset.labels[dataset.images_split ==
                                  dbac_data.DB_IMAGE_SPLITS.index('train')]
    val_labels = dataset.labels[dataset.images_split ==
                                dbac_data.DB_IMAGE_SPLITS.index('val')]
    test_labels = dataset.labels[dataset.images_split ==
                                 dbac_data.DB_IMAGE_SPLITS.index('test')]
    logger.info("Number of images (train, val, test): {}, {}, {}".format(
        len(train_labels), len(val_labels), len(test_labels)))

    train_exps = dataset.expressions[dataset.expressions_split ==
                                     dbac_data.DB_EXP_SPLITS.index('train')]
    test_exps = dataset.expressions[dataset.expressions_split ==
                                    dbac_data.DB_EXP_SPLITS.index('test')]
    logger.info("Number of expressions (train, test): {}, {}".format(
        len(train_exps), len(test_exps)))

    valid_prims = np.where(dataset.valid_primitives)[0]
    logger.info("Number of primitives: {}".format(len(valid_prims)))

    if comb_file:
        train_combs = dataset.combinations[dataset.combinations_split ==
                                           dbac_data.DB_COMB_SPLITS.index(
                                               'train')]
        test_combs = dataset.combinations[dataset.combinations_split ==
                                          dbac_data.DB_COMB_SPLITS.index(
                                              'test')]
        logger.info("Number of combinations (train, test): {}, {}".format(
            len(train_combs), len(test_combs)))
    else:
        train_combs, test_combs = None, None

    # compute detailed statistics
    info_exp, info_prim, info_comb = [], [], []
    prim_box, exp_box, comb_box = [], [], []
    for labels, combs, exps, prims in zip(
        [train_labels, val_labels, test_labels],
        [train_combs, train_combs, test_combs],
        [train_exps, train_exps, test_exps], [valid_prims] * 3):
        count_prim = np.zeros(len(prims))
        for p, prim in enumerate(prims):
            count_prim[p] = np.sum(labels[:, prim])
        mean, std, min, max = np.mean(count_prim), np.std(count_prim), np.min(
            count_prim), np.max(count_prim)
        info_prim.append((mean, std, min, max))
        prim_box.append(count_prim)

        count_exp = np.zeros(len(exps))
        for e, exp in enumerate(exps):
            op, v_a, v_b = exp[0], labels[:, int(
                exp[1])], labels[:,
                                 int(exp[2])] if exp[2] is not None else None
            count_exp[e] = np.sum(dbac_expression.eval_op(op, v_a, v_b))
        mean, std, min, max = np.mean(count_exp), np.std(count_exp), np.min(
            count_exp), np.max(count_exp)
        info_exp.append((mean, std, min, max))
        exp_box.append(count_exp)

        if comb_file:
            count_comb = np.zeros(len(combs))
            for c, comb in enumerate(combs):
                comb_tree = dbac_expression.list2exp_parse(comb)
                var_dic = {
                    p: labels[:, int(p)]
                    for p in dbac_expression.get_vars(comb_tree)
                }
                count_comb[c] = dbac_expression.eval_exp(comb_tree,
                                                         var_dic).sum()
            mean, std, min, max = np.mean(count_comb), np.std(
                count_comb), np.min(count_comb), np.max(count_comb)
            info_comb.append((mean, std, min, max))
            comb_box.append(count_comb)

    logger.info(
        "Primitives sample density (mean, std, min, max) train, val, test: {}".
        format(info_prim))
    logger.info(
        "Expression sample density (mean, std, min, max) train, val, test: {}".
        format(info_exp))
    logger.info(
        "Compositions sample density (mean, std, min, max) train, val, test: {}"
        .format(info_comb))
    if plot:
        import matplotlib.pyplot as plt
        f, (ax1, ax2, ax3) = plt.subplots(1, 3)
        ax1.boxplot(prim_box, labels=['Train', 'Val', 'Test'], showmeans=True)
        ax1.set_title('Primitives', fontsize=16)
        ax1.set_ylabel('# Positive Images', fontsize=12)
        ax1.tick_params(axis='x', labelsize=12)
        ax2.boxplot(exp_box, labels=['Train', 'Val', 'Test'], showmeans=True)
        ax2.set_title('Expressions', fontsize=16)
        ax2.tick_params(axis='x', labelsize=12)
        if comb_file:
            ax3.boxplot(comb_box,
                        labels=['Train', 'Val', 'Test'],
                        showmeans=True)
            ax3.set_title('Compositions', fontsize=16)
            ax3.tick_params(axis='x', labelsize=12)
        f.tight_layout()
        plt.show()
예제 #3
0
def _compute_combs(db_name,
                   db_path,
                   split_file,
                   complexity,
                   output_file,
                   form='D',
                   allow_not=False,
                   min_pos_comb=[100, 10, 10],
                   qtd_combs=[3e3, 1e3, 1e3]):
    # load data
    logger.info("Loading dataset and split...")
    db = dbac_data.IDataset.factory(db_name, db_path)
    db.load_split(split_file)
    train_labels = db.labels[db.images_split ==
                             dbac_data.DB_IMAGE_SPLITS.index('train')]
    train_exps = db.expressions[db.expressions_split ==
                                dbac_data.DB_EXP_SPLITS.index('train')]
    val_labels = db.labels[db.images_split == dbac_data.DB_IMAGE_SPLITS.index(
        'val')]
    test_labels = db.labels[db.images_split == dbac_data.DB_IMAGE_SPLITS.index(
        'test')]
    test_exps = db.expressions[db.expressions_split ==
                               dbac_data.DB_EXP_SPLITS.index('test')]
    # compute combinations
    comb_dict = {}
    train_combs, test_combs = [], []
    data_iter = zip(['train', 'test'], [train_combs, test_combs], min_pos_comb,
                    qtd_combs, [train_exps, test_exps],
                    [train_labels, test_labels])
    for name, combs, min_pos, qtd, exps, labels in data_iter:
        logger.info("Computing combinations for {}".format(name))
        for idx, exp in enumerate(
                dbac_expression.exp_comb_gen(exps,
                                             complexity,
                                             form=form,
                                             allow_not=allow_not)):
            # compute expression positive samples
            var_dic = {
                p: labels[:, int(p)]
                for p in dbac_expression.get_vars(exp)
            }
            exp_labels = dbac_expression.eval_exp(exp, var_dic)
            num_pos = exp_labels.sum()
            num_neg = np.logical_not(exp_labels).sum()
            # filter out expressions with few samples
            if num_pos > min_pos and num_neg > min_pos and not any(
                [dbac_expression.exp_tree_eq(exp, comb) for comb in combs]):
                if name == 'train':
                    var_dic = {
                        p: val_labels[:, int(p)]
                        for p in dbac_expression.get_vars(exp)
                    }
                    exp_labels = dbac_expression.eval_exp(exp, var_dic)
                    num_pos = exp_labels.sum()
                    num_neg = np.logical_not(exp_labels).sum()
                    if num_pos <= min_pos_comb[1] or num_neg <= min_pos_comb[1]:
                        continue
                combs.append(copy.deepcopy(exp))
                # maximum number of combinations sampled
            if len(combs) > qtd:
                break
            if (idx + 1) % 100 == 0:
                logger.info('{} - Collected {} from {} expressions'.format(
                    name, len(combs), (idx + 1)))
        comb_dict["{}_combs".format(name)] = [
            dbac_expression.exp2list_parse(comb) for comb in combs[:qtd]
        ]

    # save to json file
    with open(output_file, "w") as outfile:
        json.dump(comb_dict, outfile, indent=4, sort_keys=True)
    logger.info("Combination saved to {}.".format(output_file))
    return comb_dict
    def learning(self, images_path, labels, expressions, **kwargs):

        # training parameters
        batch_size, num_epochs = int(kwargs.get('batch_size', 32)), int(kwargs.get('num_epochs', 1e3))
        snap_int, snap_dir, log_dir = int(kwargs.get('snap_int', 250)), kwargs.get('snap_dir', None), kwargs.get(
            'log_dir', None)
        init_weights = kwargs.get('init_weights', None)
        snapshot = kwargs.get('snapshot', None)
        learning_rate = float(kwargs.get('learning_rate', 1e-5))
        alphas = [float(p) for p in kwargs.get('alphas', '10.0 1.0 0.1 1.0').split()]
        _logger.info("Training parameters: batch_size={}, num_epochs={}, snap_int={}, snap_dir={}, log_dir={}, "
                     "learning_rate={}, alphas={}, learn_feats={}, init_weights={}, norm_in={}, norm_out={},"
                     " snapshot={}, demorgan_reg={}".format(batch_size, num_epochs, snap_int, snap_dir, log_dir, learning_rate, alphas,
                                                            self.learn_feats, init_weights, self.norm_in, self.norm_out,
                                                            snapshot, self.demorgan_reg))

        # setup training network
        with self.graph.as_default() as graph:
            # Loss
            reg_loss = tf.reduce_mean(tf.losses.get_regularization_loss())
            norm_loss = tf.reduce_mean(0.5 * tf.pow(tf.norm(self.output_tn, axis=-1), 2.0))
            cls_loss = tf.losses.hinge_loss(self._ground_truth_ph, self.scores_tn, reduction=tf.losses.Reduction.MEAN)
            loss_tn = alphas[0] * norm_loss + alphas[1] * cls_loss + alphas[2] * reg_loss
            if self.demorgan_reg:
                dem_loss = tf.reduce_mean(0.5 * tf.pow(tf.norm(self.output_tn - self.dm_output_tn, axis=-1), 2.0))
                loss_tn = loss_tn + (alphas[3] * dem_loss)
                dem_loss_val, dem_loss_up, dem_loss_reset = _create_reset_metric(
                    tf.metrics.mean, 'epoch_dem_loss', values=dem_loss)
                tf.summary.scalar('dem_loss', dem_loss_val)

            pred = tf.greater(self.scores_tn, 0.0)
            # Metrics
            reg_loss_val, reg_loss_up, reg_loss_reset = _create_reset_metric(
                tf.metrics.mean, 'epoch_reg_loss', values=reg_loss)
            tf.summary.scalar('reg_loss', reg_loss_val)
            cls_loss_val, cls_loss_up, cls_loss_reset = _create_reset_metric(
                tf.metrics.mean, 'epoch_cls_loss', values=cls_loss)
            tf.summary.scalar('cls_loss', cls_loss_val)
            norm_loss_val, norm_loss_up, norm_loss_reset = _create_reset_metric(
                tf.metrics.mean, 'epoch_norm_loss', values=norm_loss)
            tf.summary.scalar('norm_loss', norm_loss_val)
            loss_val, loss_up, loss_reset = _create_reset_metric(
                tf.metrics.mean, 'epoch_loss', values=loss_tn)
            tf.summary.scalar('total_loss', loss_val)
            prec_val, prec_up, prec_reset = _create_reset_metric(
                tf.metrics.precision, 'epoch_prec', predictions=pred, labels=self._ground_truth_ph)
            tf.summary.scalar('Precision', prec_val)
            rec_val, rec_up, rec_reset = _create_reset_metric(
                tf.metrics.recall, 'epoch_rec', predictions=pred, labels=self._ground_truth_ph)
            tf.summary.scalar('Recall', rec_val)
            tf.summary.scalar('Fscore', (2 * prec_val * rec_val) / (prec_val + rec_val + 1e-6))
            summ_ops = tf.summary.merge_all()
            summ_writer = tf.summary.FileWriter(log_dir) if log_dir else None
            metrics_ops_reset = [reg_loss_reset, cls_loss_reset, norm_loss_reset, loss_reset, prec_reset, rec_reset]
            metrics_ops_update = [reg_loss_up, cls_loss_up, norm_loss_up, loss_up, prec_up, rec_up]
            if self.demorgan_reg:
                metrics_ops_reset += [dem_loss_reset]
                metrics_ops_update += [dem_loss_up]
            # Optimizer
            global_step_tn = tf.train.get_or_create_global_step(graph)
            optimizer = tf.train.AdamOptimizer(learning_rate)
            train_op = optimizer.minimize(loss_tn, global_step=global_step_tn, colocate_gradients_with_ops=True)
            init = tf.global_variables_initializer()
            tf_snap_tr = tf.train.Saver(max_to_keep=1)

        # Decompose expressions and compute labels
        _logger.info("Decomposing expressions...")
        valid_exps, pos_img_ites, neg_img_ites, exp_labels = [], [], [], []
        for exp_lst in expressions:
            for exp_term in dbac_expression.get_terms(dbac_expression.list2exp_parse(exp_lst)):
                term_lst = dbac_expression.exp2list_parse(exp_term)
                var_dic = {p: labels[:, int(p)] for p in dbac_expression.get_vars(exp_term)}
                term_labels = dbac_expression.eval_exp(exp_term, var_dic)
                if (term_lst not in valid_exps) and (exp_term.name != dbac_expression.OPS[0]) \
                        and (term_labels.sum() > 0) and (np.logical_not(term_labels).sum() > 0):
                    valid_exps.append(term_lst)
                    exp_labels.append(term_labels)
                    pos_img_ites.append(CycleIterator(list(np.where(term_labels)[0])))
                    neg_img_ites.append(CycleIterator(list(np.where(np.logical_not(term_labels))[0])))
        expressions = valid_exps
        exp_ite = CycleIterator(np.arange(len(expressions)).tolist())
        exp_labels = np.vstack(exp_labels).astype(np.float32)
        _logger.info("Total of expressions decomposed: {}".format(len(expressions)))

        # Initialization
        _logger.info("Initializing model...")
        self.tf_session.run(init)
        if self.init_vgg is not None:
            _logger.info("Loading features pre-trained weights")
            self.init_vgg(self.tf_session)
        if init_weights:
            _logger.info("Loading model pre-trained weights")
            self.load(init_weights)
        init_epoch = 0
        if snapshot:
            _logger.info("Loading from training snapshot")
            tf_snap_tr.restore(self.tf_session, snapshot)
            init_epoch = int((self.tf_session.run(global_step_tn) * batch_size) / len(expressions))

        # training loop
        _logger.info("Training...")
        for epoch in range(init_epoch, num_epochs):
            self.tf_session.run(metrics_ops_reset)
            for b in range(int(np.ceil(len(expressions) / batch_size))):
                # batch sampling
                b_exp_ids = [next(exp_ite) for _ in range(batch_size)]
                b_img_ids = [next(pos_img_ites[exp_id]) for _ in range(5) for exp_id in b_exp_ids]
                b_img_ids += [next(neg_img_ites[exp_id]) for _ in range(5) for exp_id in b_exp_ids]

                # compute image features
                if self.learn_feats:
                    b_img_feats = images_path[b_img_ids]
                else:
                    b_img_feats = self.feat_ext.compute(images_path[b_img_ids])

                # compute operations
                b_prims_rpr, b_op_switch = [], []
                for exp_id in b_exp_ids:
                    exp_tree = dbac_expression.list2exp_parse(expressions[exp_id])
                    b_op_switch.append({'NOT': 0, 'AND': 1, 'OR': 2}[exp_tree.name])
                    operand_a, operand_b = exp_tree.children if np.random.rand() > 0.5 else exp_tree.children[::-1]
                    b_prims_rpr.append(dbac_expression.exp2list_parse(operand_a))
                    b_prims_rpr.append(dbac_expression.exp2list_parse(operand_b))
                b_op_switch = np.array(b_op_switch)
                b_prims_rpr = self.inference(b_prims_rpr).reshape((len(b_exp_ids), 2 * self.dim))

                # compute labels
                b_exp_labels = exp_labels[b_exp_ids, :]
                b_exp_labels = b_exp_labels[:, b_img_ids]

                # run model
                self.tf_session.run(
                    [train_op, loss_tn] + metrics_ops_update,
                    feed_dict={self.is_training_ph: True,
                               self._images_ph: b_img_feats,
                               self._prims_rpr_ph: b_prims_rpr,
                               self._switch_ph: b_op_switch,
                               self._ground_truth_ph: b_exp_labels})

            if (epoch + 1) % 2 == 0:
                loss, prec, rec, summary = self.tf_session.run([loss_val, prec_val, rec_val, summ_ops])
                _logger.info("Epoch {}: Loss={:.4f}, Prec={:.2f}, Rec={:.2f}, Fsc={:.2f}"
                             .format((epoch + 1), loss, prec, rec, (2 * prec * rec) / (prec + rec + 1e-6)))
                if summ_writer:
                    summ_writer.add_summary(summary, global_step=epoch + 1)

            if snap_dir and (epoch + 1) % snap_int == 0:
                snap_file = os.path.join(snap_dir, 'nba_mlp_snap_E{}.npz'.format((epoch + 1)))
                self.save(snap_file)
                tf_snap_tr.save(self.tf_session, os.path.join(snap_dir, 'train.chk'), latest_filename='checkpoint.TRAIN')
                _logger.info("Model epoch {} snapshoted to {}".format(epoch + 1, snap_file))
def _test(db_name, db_dir, db_split_file, db_comb_file, primitives_file, model_name, model_file, output_dir, kwargs_str=None):
    # processing kwargs
    kwargs_dic = dbac_util.get_kwargs_dic(kwargs_str)
    logger.info("Kwargs dictionary: {}".format(kwargs_dic))

    # read dataset and partitions
    logger.info("Reading dataset and split")
    db = dbac_data.IDataset.factory(db_name, db_dir)
    db.load_split(db_split_file, db_comb_file)
    train_imgs_path = db.images_path[db.images_split == dbac_data.DB_IMAGE_SPLITS.index('train')]
    train_labels = db.labels[db.images_split == dbac_data.DB_IMAGE_SPLITS.index('train')]
    val_imgs_path = db.images_path[db.images_split == dbac_data.DB_IMAGE_SPLITS.index('val')]
    val_labels = db.labels[db.images_split == dbac_data.DB_IMAGE_SPLITS.index('val')]
    test_imgs_path = db.images_path[db.images_split == dbac_data.DB_IMAGE_SPLITS.index('test')]
    test_labels = db.labels[db.images_split == dbac_data.DB_IMAGE_SPLITS.index('test')]

    if db_comb_file:
        logger.info("Loading compositions...")
        train_exps = db.combinations[db.combinations_split == dbac_data.DB_COMB_SPLITS.index('train')]
        test_exps = db.combinations[db.combinations_split == dbac_data.DB_COMB_SPLITS.index('test')]
    else:
        logger.info("Loading single expressions...")
        train_exps = db.expressions[db.expressions_split == dbac_data.DB_EXP_SPLITS.index('train')]
        test_exps = db.expressions[db.expressions_split == dbac_data.DB_EXP_SPLITS.index('test')]

    # Set up feature extractor
    logger.info("Configuring Features Extractor")
    feat_extractor = dbac_feature_ext.IFeatureExtractor.factory(dbac_feature_ext.FEAT_TYPE[1], **kwargs_dic)
    feat_extractor.load()

    # set up primitive collection
    logger.info("Configuring Primitive Collection")
    prim_collection = dbac_primitives.IPrimitiveCollection.factory(dbac_primitives.PRIMITIVE_TYPES[0], **kwargs_dic)
    prim_collection.load(primitives_file)

    # setup model
    logger.info("Configuring Model")
    model = dbac_model.IModel.factory(model_name, feat_extractor, prim_collection, **kwargs_dic, is_train=False)
    model.load(model_file)

    # test model
    logger.info("Testing on seen expressions on training images...")
    train_scores = model.score(train_imgs_path, train_exps, **kwargs_dic)
    logger.info("Testing on seen expressions on validation images...")
    val_scores = model.score(val_imgs_path, train_exps, **kwargs_dic)
    logger.info("Testing on unseen expressions on test images...")
    test_scores = model.score(test_imgs_path, test_exps, **kwargs_dic)

    # save results
    logger.info("Computing results.")
    report_dic = dict()
    results_iter = zip(['train', 'val', 'test'], [train_exps, train_exps, test_exps],
                       [train_labels, val_labels, test_labels], [train_scores, val_scores, test_scores],
                       [train_imgs_path, val_imgs_path, test_imgs_path])
    for key, exps, labels, scores, images in results_iter:
        # compute ground truth labels
        ground_truth = np.zeros_like(scores)
        for idx, exp_lst in enumerate(exps):
            exp_tree = dbac_expression.list2exp_parse(exp_lst)
            var_dic = {p: labels[:, int(p)] for p in dbac_expression.get_vars(exp_tree)}
            ground_truth[idx] = dbac_expression.eval_exp(exp_tree, var_dic)
        # fill report dictionary
        report_dic['_'.join([key, 'exps'])] = exps
        report_dic['_'.join([key, 'imgs'])] = images
        report_dic['_'.join([key, 'gt'])] = ground_truth
        report_dic['_'.join([key, 'pred'])] = scores
    result_file = os.path.join(output_dir, 'results.npy')
    np.save(result_file, report_dic)
    logger.info("Results file saved to {}.".format(result_file))