def get_image_features(self, task, batched_lmap_speed_thresh=None):
        if batched_lmap_speed_thresh is None:
            batched_lmap_speed_thresh = self.batched_lmap_speed_thresh
        images = task.images
        try:
            rval, _images, cdict = self.image_features[images]
            # -- currently it is true that all tasks should be indexing into
            # -- the same set of images. Later when this is not the case,
            # -- delete this over-strict check.
            assert _images is images
        except KeyError:
            feature_lmap = self.get_image_features_lmap(task.images,
                    batched_lmap_speed_thresh)

            rval = cache_memmap(
                feature_lmap,
                self.memmap_name + '_image_features_' + task.name,
                del_atexit=self.memmap_del_atexit)

            foobar.append_ndarray_signature(rval[0],
                'get_image_features features 0', task.name)
            foobar.append_ndarray_signature(rval[100],
                'get_image_features features 100', task.name)

            cdict = {}
            self.image_features[images] = rval, images, cdict
        return rval, cdict
Exemple #2
0
def alloc_random_uniform_filterbank(n_filters, height, width,
        channels, dtype, rseed, normalize=True):
    """
    Generate the same weights as are generated by pythor3
    """
    if height != width:
        raise ValueError('filters must be square')
    if channels is None:
        filter_shape = [n_filters, height, width]
    else:
        filter_shape = [n_filters, height, width, channels]

    rng = np.random.RandomState(rseed)
    foobar.append_randomstate('alloc_random_uniform_filterbank', rng)
    fb_data = rng.uniform(size=filter_shape)

    # normalize each filter in the bank if needed
    if normalize:
        # TODO: vectorize these computations, do all at once.
        for fidx, filt in enumerate(fb_data):
            # normalization here means zero-mean, unit-L2norm
            filt -= filt.mean()
            filt_norm = np.sqrt((filt * filt).sum())
            assert filt_norm != 0
            filt /= filt_norm
            fb_data[fidx] = filt

    foobar.append_ndarray_signature(fb_data, 'alloc_random_uniform_filterbank')
    return fb_data.astype(dtype)
def fb_whitened_projections(patches, pwfX, n_filters, rseed, dtype):
    """
    pwfX is the output of patch_whitening_filterbank_X with reshape=False

    M, and fb will be reshaped to match elements of patches
    """
    M, P, patches_cn = pwfX
    if patches_cn.ndim != 2:
        raise TypeError('wrong shape for pwfX args, should be flattened',
                        patches_cn.shape)
    rng = np.random.RandomState(rseed)
    foobar.append_randomstate('fb_whitened_projections', rng)

    D = rng.randn(n_filters, patches_cn.shape[1])
    D = D / (np.sqrt((D**2).sum(axis=1))[:, None] + 1e-20)
    fb = dot_f32(D, P)
    fb.shape = (n_filters, ) + patches.shape[1:]
    M.shape = patches.shape[1:]
    M = M.astype(dtype)
    fb = fb.astype(dtype)
    if fb.size == 0:
        raise ValueError('filterbank had size 0')
    foobar.append_ndarray_signature(M, 'fb_whitened_projections M')
    foobar.append_ndarray_signature(fb, 'fb_whitened_projections fb')
    return M, fb
def alloc_random_uniform_filterbank(n_filters,
                                    height,
                                    width,
                                    channels,
                                    dtype,
                                    rseed,
                                    normalize=True):
    """
    Generate the same weights as are generated by pythor3
    """
    if height != width:
        raise ValueError('filters must be square')
    if channels is None:
        filter_shape = [n_filters, height, width]
    else:
        filter_shape = [n_filters, height, width, channels]

    rng = np.random.RandomState(rseed)
    foobar.append_randomstate('alloc_random_uniform_filterbank', rng)
    fb_data = rng.uniform(size=filter_shape)

    # normalize each filter in the bank if needed
    if normalize:
        # TODO: vectorize these computations, do all at once.
        for fidx, filt in enumerate(fb_data):
            # normalization here means zero-mean, unit-L2norm
            filt -= filt.mean()
            filt_norm = np.sqrt((filt * filt).sum())
            assert filt_norm != 0
            filt /= filt_norm
            fb_data[fidx] = filt

    foobar.append_ndarray_signature(fb_data, 'alloc_random_uniform_filterbank')
    return fb_data.astype(dtype)
    def get_image_features(self, task, batched_lmap_speed_thresh=None):
        if batched_lmap_speed_thresh is None:
            batched_lmap_speed_thresh = self.batched_lmap_speed_thresh
        images = task.images
        try:
            rval, _images, cdict = self.image_features[images]
            # -- currently it is true that all tasks should be indexing into
            # -- the same set of images. Later when this is not the case,
            # -- delete this over-strict check.
            assert _images is images
        except KeyError:
            feature_lmap = self.get_image_features_lmap(
                task.images, batched_lmap_speed_thresh)

            rval = cache_memmap(feature_lmap,
                                self.memmap_name + '_image_features_' +
                                task.name,
                                del_atexit=self.memmap_del_atexit)

            foobar.append_ndarray_signature(rval[0],
                                            'get_image_features features 0',
                                            task.name)
            foobar.append_ndarray_signature(rval[100],
                                            'get_image_features features 100',
                                            task.name)

            cdict = {}
            self.image_features[images] = rval, images, cdict
        return rval, cdict
Exemple #6
0
def fb_whitened_projections(patches, pwfX, n_filters, rseed, dtype):
    """
    pwfX is the output of patch_whitening_filterbank_X with reshape=False

    M, and fb will be reshaped to match elements of patches
    """
    M, P, patches_cn = pwfX
    if patches_cn.ndim != 2:
        raise TypeError('wrong shape for pwfX args, should be flattened',
                patches_cn.shape)
    rng = np.random.RandomState(rseed)
    foobar.append_randomstate('fb_whitened_projections', rng)

    D = rng.randn(n_filters, patches_cn.shape[1])
    D = D / (np.sqrt((D ** 2).sum(axis=1))[:, None] + 1e-20)
    fb = dot_f32(D, P)
    fb.shape = (n_filters,) + patches.shape[1:]
    M.shape = patches.shape[1:]
    M = M.astype(dtype)
    fb = fb.astype(dtype)
    if fb.size == 0:
        raise ValueError('filterbank had size 0')
    foobar.append_ndarray_signature(M, 'fb_whitened_projections M')
    foobar.append_ndarray_signature(fb, 'fb_whitened_projections fb')
    return M, fb
    def load_ensemble_grams(self, norm_sample, ens, sample1, sample2):
        trial_attachments = self.ctrl.trials.trial_attachments

        # -- load the gram matrices saved by each ensemble member
        for trial in self.history:
            trial_norm_key = self.norm_key(norm_sample, tid=trial['tid'])
            info('Loading grams from document %i' % trial['tid'])
            debug(' .. saved_grams: %s' %
                    str(trial['result']['grams'][trial_norm_key]))
            for (s1, s2) in trial['result']['grams'][trial_norm_key]:
                if set([sample1, sample2]) == set([s1, s2]):
                    if not ens.has_gram(trial_norm_key, s1, s2):
                        att_key = 'gram_%s_%s_%s.pkl' % (trial_norm_key, s1, s2)
                        info('retrieving gram_data %i:%s'
                             % (trial['tid'], att_key))
                        try:
                            gram_data = cached_gram_load(trial['tid'], att_key)
                        except IOError:
                            gram_data = trial_attachments(trial)[att_key]
                            cached_gram_save(trial['tid'], att_key, gram_data)
                        info('retrieved %i bytes' % len(gram_data))
                        gram = loads_gram(gram_data)
                        if s1 == sample1:
                            ens.add_gram(trial_norm_key, sample1, sample2, gram)
                        else:
                            ens.add_gram(trial_norm_key, sample1, sample2,
                                    gram.T)
                        foobar.append_ndarray_signature(
                            gram,
                            'load gram', trial_norm_key, sample1, sample2)
            info('Loading grams done')
Exemple #8
0
def unsup_images(data_view, trn, N):
    """
    Return a block of 
    """
    if trn == 'DevTrain':
        # -- extract training images, and put them into channel-major format
        imgs = larray.reindex(data_view.image_pixels,
                data_view.dev_train['lpathidx'][0, :N])[:]
        imgs = np.asarray(imgs)
        assert 'int' in str(imgs.dtype)
        foobar.append_ndarray_signature(imgs, 'unsup_images')
        foobar.append_trace('unsup_images N', N)
        return imgs.transpose(0, 3, 1, 2).copy()
    else:
        raise NotImplementedError()
Exemple #9
0
def patch_whitening_filterbank_X(patches, o_ndim, gamma,
        remove_mean, beta, hard_beta,
        ):
    """
    patches - Image patches (can be uint8 pixels or floats)
    o_ndim - 2 to get matrix outputs, 4 to get image-stack outputs
    gamma - non-negative real to boost low-principle components

    remove_mean - see contrast_normalize
    beta - see contrast_normalize
    hard_beta - see contrast_normalize

    Returns: M, P, X
        M - mean of contrast-normalized patches
        P - whitening matrix / filterbank for contrast-normalized patches
        X - contrast-normalized patches

    """
    # Algorithm from Coates' sc_vq_demo.m

    # -- patches -> column vectors
    X = patches.reshape(len(patches), -1).astype('float64')

    X = contrast_normalize(X,
            remove_mean=remove_mean,
            beta=beta,
            hard_beta=hard_beta)

    # -- ZCA whitening (with low-pass)
    logger.debug('patch_whitening_filterbank_X starting ZCA')
    M, _std = mean_and_std(X)
    Xm = X - M
    assert Xm.shape == X.shape
    logger.info('patch_whitening_filterbank_X starting ZCA: dot %s' %
            str(Xm.shape))
    C = dot_f64(Xm.T, Xm) / (Xm.shape[0] - 1)
    logger.debug('patch_whitening_filterbank_X starting ZCA: eigh')
    D, V = np.linalg.eigh(C)
    logger.debug(
        'patch_whitening_filterbank_X starting ZCA: dot %s' % str(V.shape))
    P = dot_f32(np.sqrt(1.0 / (D + gamma)) * V, V.T)

    # -- return to image space
    if o_ndim == 4:
        M = M.reshape(patches.shape[1:])
        P = P.reshape((P.shape[0],) + patches.shape[1:])
        X = X.reshape((len(X),) + patches.shape[1:])
    elif o_ndim == 2:
        pass
    else:
        raise ValueError('o_ndim not in (2, 4)', o_ndim)

    logger.debug('patch_whitening_filterbank_X -> done')

    foobar.append_ndarray_signature(M, 'patch_whitening_filterbank_X M')
    foobar.append_ndarray_signature(P, 'patch_whitening_filterbank_X P')
    foobar.append_ndarray_signature(X, 'patch_whitening_filterbank_X X')
    dtype = patches.dtype
    return M.astype(dtype), P.astype(dtype), X.astype(dtype)
def contrast_normalize(patches, remove_mean, beta, hard_beta):
    X = patches
    if X.ndim != 2:
        raise TypeError('contrast_normalize requires flat patches')
    if remove_mean:
        xm = X.mean(1)
    else:
        xm = X[:, 0] * 0
    Xc = X - xm[:, None]
    if 0:
        # -- for some reason the following sometimes uses gigs of RAM
        l2 = (Xc * Xc).sum(axis=1)
    else:
        l2 = np.zeros_like(Xc[:, 0])
        for i in xrange(Xc.shape[1]):
            l2 += Xc[:, i]**2
    if hard_beta:
        div2 = np.maximum(l2, beta)
    else:
        div2 = l2 + beta
    Xc /= np.sqrt(div2[:, None])
    foobar.append_ndarray_signature(Xc, 'contrast_normalize')
    return Xc
def fb_whitened_patches(patches, pwfX, n_filters, rseed, dtype):
    """
    pwfX is the output of patch_whitening_filterbank_X with reshape=False

    M, and fb will be reshaped to match elements of patches

    """
    M, P, patches_cn = pwfX
    rng = np.random.RandomState(rseed)
    foobar.append_randomstate('fb_whitened_patches', rng)
    d_elems = rng.randint(len(patches_cn), size=n_filters)
    D = dot_f64(patches_cn[d_elems] - M, P)
    D = D / (np.sqrt((D**2).sum(axis=1))[:, None] + 1e-20)
    fb = dot_f32(D, P)
    fb.shape = (n_filters, ) + patches.shape[1:]
    M.shape = patches.shape[1:]
    M = M.astype(dtype)
    fb = fb.astype(dtype)
    if fb.size == 0:
        raise ValueError('filterbank had size 0')
    foobar.append_ndarray_signature(M, 'fb_whitened_patches M')
    foobar.append_ndarray_signature(fb, 'fb_whitened_patches fb')
    return M, fb
Exemple #12
0
def fb_whitened_patches(patches, pwfX, n_filters, rseed, dtype):
    """
    pwfX is the output of patch_whitening_filterbank_X with reshape=False

    M, and fb will be reshaped to match elements of patches

    """
    M, P, patches_cn = pwfX
    rng = np.random.RandomState(rseed)
    foobar.append_randomstate('fb_whitened_patches', rng)
    d_elems = rng.randint(len(patches_cn), size=n_filters)
    D = dot_f64(patches_cn[d_elems] - M, P)
    D = D / (np.sqrt((D ** 2).sum(axis=1))[:, None] + 1e-20)
    fb = dot_f32(D, P)
    fb.shape = (n_filters,) + patches.shape[1:]
    M.shape = patches.shape[1:]
    M = M.astype(dtype)
    fb = fb.astype(dtype)
    if fb.size == 0:
        raise ValueError('filterbank had size 0')
    foobar.append_ndarray_signature(M, 'fb_whitened_patches M')
    foobar.append_ndarray_signature(fb, 'fb_whitened_patches fb')
    return M, fb
Exemple #13
0
def contrast_normalize(patches, remove_mean, beta, hard_beta):
    X = patches
    if X.ndim != 2:
        raise TypeError('contrast_normalize requires flat patches')
    if remove_mean:
        xm = X.mean(1)
    else:
        xm = X[:,0] * 0
    Xc = X - xm[:, None]
    if 0:
        # -- for some reason the following sometimes uses gigs of RAM
        l2 = (Xc * Xc).sum(axis=1)
    else:
        l2 = np.zeros_like(Xc[:, 0])
        for i in xrange(Xc.shape[1]):
            l2 += Xc[:, i] ** 2
    if hard_beta:
        div2 = np.maximum(l2, beta)
    else:
        div2 = l2 + beta
    Xc /= np.sqrt(div2[:, None])
    foobar.append_ndarray_signature(Xc, 'contrast_normalize')
    return Xc
Exemple #14
0
def random_patches(images, N, R, C, rng, channel_major=False, memlimit=None):
    """Return a stack of N image patches (channel major version)"""

    def N_with_memlimit():
        if memlimit is not None:
            # -- memlimit in bytes
            sizelimit = memlimit / images.dtype.itemsize
            return min(N, sizelimit // (R * C * iF))
        else:
            return N

    if channel_major:
        n_imgs, iF, iR, iC = images.shape
        N = N_with_memlimit()
        rval = np.empty((N, iF, R, C), dtype=images.dtype)
    else:
        n_imgs, iR, iC, iF = images.shape
        N = N_with_memlimit()
        rval = np.empty((N, R, C, iF), dtype=images.dtype)

    foobar.append_trace('random_patches dims', *rval.shape)
    foobar.append_randomstate('random_patches rng', rng)

    srcs = rng.randint(n_imgs, size=N)

    if R > iR or C > iC:
        raise InvalidDescription('cannot extract patches', (R, C))
    roffsets = rng.randint(iR - R + 1, size=N)
    coffsets = rng.randint(iC - C + 1, size=N)
    # TODO: this can be done with one advanced index right?
    for rv_i, src_i, ro, co in zip(rval, srcs, roffsets, coffsets):
        if channel_major:
            rv_i[:] = images[src_i, :, ro: ro + R, co : co + C]
        else:
            rv_i[:] = images[src_i, ro: ro + R, co : co + C]
    foobar.append_ndarray_signature(rval, 'random_patches rval')
    return rval
def random_patches(images, N, R, C, rng, channel_major=False, memlimit=None):
    """Return a stack of N image patches (channel major version)"""
    def N_with_memlimit():
        if memlimit is not None:
            # -- memlimit in bytes
            sizelimit = memlimit / images.dtype.itemsize
            return min(N, sizelimit // (R * C * iF))
        else:
            return N

    if channel_major:
        n_imgs, iF, iR, iC = images.shape
        N = N_with_memlimit()
        rval = np.empty((N, iF, R, C), dtype=images.dtype)
    else:
        n_imgs, iR, iC, iF = images.shape
        N = N_with_memlimit()
        rval = np.empty((N, R, C, iF), dtype=images.dtype)

    foobar.append_trace('random_patches dims', *rval.shape)
    foobar.append_randomstate('random_patches rng', rng)

    srcs = rng.randint(n_imgs, size=N)

    if R > iR or C > iC:
        raise InvalidDescription('cannot extract patches', (R, C))
    roffsets = rng.randint(iR - R + 1, size=N)
    coffsets = rng.randint(iC - C + 1, size=N)
    # TODO: this can be done with one advanced index right?
    for rv_i, src_i, ro, co in zip(rval, srcs, roffsets, coffsets):
        if channel_major:
            rv_i[:] = images[src_i, :, ro:ro + R, co:co + C]
        else:
            rv_i[:] = images[src_i, ro:ro + R, co:co + C]
    foobar.append_ndarray_signature(rval, 'random_patches rval')
    return rval
    def normalized_image_match_features(self, task, svm_dct, role,
            batched_lmap_speed_thresh=None):
        assert role in ('train', 'test')
        if batched_lmap_speed_thresh is None:
            batched_lmap_speed_thresh = self.batched_lmap_speed_thresh
        image_features, cdict = self.get_image_features(task,
                batched_lmap_speed_thresh=batched_lmap_speed_thresh)
        del cdict # -- no longer used (waste of memory)
        pipeline = self.pipeline
        info('Indexing into image_features of shape %s' %
                str(image_features.shape))

        comps = [getattr(comparisons, cc)
                for cc in self.comparison_names]
        n_features = np.prod(image_features.shape[1:])
        n_trn = len(task.lidx)

        x_trn_shp = (n_trn, len(comps), n_features)
        info('Allocating training ndarray of shape %s' % str(x_trn_shp))
        x_trn = np.empty(x_trn_shp, dtype='float32')

        # -- pre-compute all of the image_features we will need
        all_l_features = reindex(image_features, task.lidx)[:]
        all_r_features = reindex(image_features, task.ridx)[:]

        all_l_features = all_l_features.reshape(len(all_l_features), -1)
        all_r_features = all_r_features.reshape(len(all_r_features), -1)

        foobar.append_ndarray_signature(all_l_features,
            'normalized_image_match l_features', task.name)
        foobar.append_ndarray_signature(all_r_features,
            'normalized_image_match r_features', task.name)

        if role == 'train':
            if np.allclose(all_l_features.var(axis=0), 0.0):
                raise ValueError(
                    'Homogeneous features (non-finite features)')

            xmean_l, xstd_l = mean_and_std(all_l_features,
                    remove_std0=pipeline['remove_std0'])
            xmean_r, xstd_r = mean_and_std(all_r_features,
                    remove_std0=pipeline['remove_std0'])
            xmean = (xmean_l + xmean_r) / 2.0
            # -- this is an ad-hoc way of blending the variances.
            xstd = np.sqrt(np.maximum(xstd_l, xstd_r) ** 2
                           + pipeline['varthresh'])

            foobar.append_ndarray_signature(
                xmean, 'normalized_image_match xmean', task.name)
            foobar.append_ndarray_signature(
                xstd, 'normalized_image_match xstd', task.name)


            svm_dct['xmean'] = xmean
            svm_dct['xstd'] = xstd
        else:
            xmean = svm_dct['xmean']
            xstd = svm_dct['xstd']

        info('Computing comparison features')

        # -- now compute the "comparison functions" into x_trn
        for jj, (lfeat, rfeat) in enumerate(
                zip(all_l_features, all_r_features)):
            lfeat_z = (lfeat - xmean) / xstd
            rfeat_z = (rfeat - xmean) / xstd
            for ci, comp in enumerate(comps):
                x_trn[jj, ci, :] = comp(lfeat_z, rfeat_z)

        if pipeline['divrowl2']:
            info('Dividing by feature norms')
            # -- now normalize by average feature norm because some
            #    comparison functions come out smaller than others
            if role == 'train':
                svm_dct['divrowl2_avg_nrm'] = {}
                for ci, cname in enumerate(self.comparison_names):
                    avg_nrm = average_row_l2norm(x_trn[:, ci, :]) + 1e-7
                    svm_dct['divrowl2_avg_nrm'][cname] = avg_nrm

            avg_nrm_vec = [svm_dct['divrowl2_avg_nrm'][cname]
                           for cname in self.comparison_names]
            x_trn /= np.asarray(avg_nrm_vec)[None, :, None]
            foobar.append_trace('get_normlized_features avg_nrm', avg_nrm_vec)

        # -- collapse comparison and feature dimensions
        x_trn.shape = (x_trn.shape[0], x_trn.shape[1] * x_trn.shape[2])

        foobar.append_ndarray_signature(
            x_trn, 'normalized_image_match x_trn', task.name)
        info('normalized_image_match_features complete')
        return x_trn
    def train_image_match_indexed(self, task, valid=None):

        pipeline = self.pipeline

        info('training svm on %s' % task.name)
        ens = EnsembleSVC(task.name)

        norm_task = task.name
        norm_key = self.norm_key(norm_task)
        svm_dct = {
                'ens': ens,
                'norm_key': norm_key,
                'norm_task': task.name,
                'task_name': task.name,
                }

        ens.add_member(norm_key)
        ens.add_sample(task.name, task.y)
        x_trn = self.normalized_image_match_features(task, svm_dct,
                role='train')
        ens.add_features(norm_key, task.name, x_trn)

        foobar.append_ndarray_signature(x_trn,
            'train_image x_trn', norm_key, task.name)

        info('computing gram: %s / %s / %s' % (
            norm_key, task.name, task.name))
        ens.compute_gram(norm_key, task.name, task.name, dtype='float32')

        foobar.append_ndarray_signature(
            ens._grams[(norm_key, task.name, task.name)],
            'train_image train_gram', norm_key, task.name)

        if valid is not None:
            info('cross-validating svm on %s' % valid.name)
            x_val = self.normalized_image_match_features(valid, svm_dct,
                    role='test',
                    # -- assume that slow features were caught earlier
                    batched_lmap_speed_thresh={'seconds': 30, 'elements': 1},
                    )
            foobar.append_ndarray_signature(
                x_val,
                'train_image x_val', norm_key, valid.name, task.name)

            ens.add_sample(valid.name, valid.y)
            ens.add_features(norm_key, valid.name, x_val)

            info('computing gram: %s / %s / %s' % (
                norm_key, valid.name, task.name))
            ens.compute_gram(norm_key, valid.name, task.name, dtype='float32')
            foobar.append_ndarray_signature(
                ens._grams[(norm_key, valid.name, task.name)],
                'train_image valid_gram', norm_key, valid.name, task.name)

            # -- re-fit the model using best weights on train + valid sets
            info('computing gram: %s / %s / %s' % (
                norm_key, valid.name, valid.name))
            ens.compute_gram(norm_key, valid.name, valid.name, dtype='float32')

            train_valid = '%s_%s' % (task.name, valid.name)
            ens.add_compound_sample(train_valid, [task.name, valid.name])


        def load_history():
            info('loading history')
            self.load_ensemble_history(
                fields=['result.weights','result.grams'])
            self.load_ensemble_weights(norm_task, task.name, ens)
            self.load_ensemble_grams(norm_task, ens, task.name, task.name)
            if valid is not None:
                self.load_ensemble_grams(norm_task, ens, valid.name, task.name)
                self.load_ensemble_grams(norm_task, ens, valid.name, valid.name)


        def train_main():
            ens.train_sample = task.name

            t0 = time.time()
            if valid is None:
                svm_dct['l2_reg'] = pipeline['l2_reg']
                ens.fit_svm(svm_dct['l2_reg'])
                svm_dct['train_error'] = ens.error_rate(task.name)
                svm_dct['loss'] = svm_dct['train_error']
            else:

                #scales = {m: 3.0 for m in ens._weights}
                scales = dict([(m, 3.0) for m in ens._weights])
                scales[norm_key] = 100.0

                info('fit_weights_crossvalid(%s, %i)' % (
                    valid.name, self.svm_crossvalid_max_evals))
                ens.fit_weights_crossvalid(valid.name,
                        max_evals=self.svm_crossvalid_max_evals,
                        scales=scales)

                foobar.append_trace('xvalid weights', sorted(ens._weights.items()))

                svm_dct['task_error'] = ens.error_rate(task.name)
                foobar.append_trace('task_error', svm_dct['task_error'])

                svm_dct['valid_name'] = valid.name
                svm_dct['valid_error'] = ens.error_rate(valid.name)
                info('valid_error %f' % svm_dct['valid_error'])
                foobar.append_trace('valid_error', svm_dct['valid_error'])

                svm_dct['l2_reg'] = None  # -- use default when retraining

                # -- re-fit the model using best weights on train + valid sets
                ens.train_sample = train_valid
                ens.fit_svm()

            fit_time = time.time() - t0
            svm_dct['fit_time'] = fit_time


        info('training with just the current features...')
        train_main()
        svm_dct['task_error_no_ensemble'] = svm_dct['task_error']
        svm_dct['valid_error_no_ensemble'] = svm_dct['valid_error']

        load_history()
        if self.history:
            info('training the full ensemble...')
            train_main()

        try:
            print_summary = ens.print_summary
        except AttributeError:
            print_summary = lambda : None

        print_summary()

        dct = self._results['train_image_match_indexed']
        dct.setdefault(norm_key, {})
        if task.name in dct[norm_key]:
            warn('Overwriting train_image_match_indexed result: %s'
                 % task.name)
        dct[norm_key][task.name] = svm_dct

        return svm_dct
    def normalized_image_match_features(self,
                                        task,
                                        svm_dct,
                                        role,
                                        batched_lmap_speed_thresh=None):
        assert role in ('train', 'test')
        if batched_lmap_speed_thresh is None:
            batched_lmap_speed_thresh = self.batched_lmap_speed_thresh
        image_features, cdict = self.get_image_features(
            task, batched_lmap_speed_thresh=batched_lmap_speed_thresh)
        del cdict  # -- no longer used (waste of memory)
        pipeline = self.pipeline
        info('Indexing into image_features of shape %s' %
             str(image_features.shape))

        comps = [getattr(comparisons, cc) for cc in self.comparison_names]
        n_features = np.prod(image_features.shape[1:])
        n_trn = len(task.lidx)

        x_trn_shp = (n_trn, len(comps), n_features)
        info('Allocating training ndarray of shape %s' % str(x_trn_shp))
        x_trn = np.empty(x_trn_shp, dtype='float32')

        # -- pre-compute all of the image_features we will need
        all_l_features = reindex(image_features, task.lidx)[:]
        all_r_features = reindex(image_features, task.ridx)[:]

        all_l_features = all_l_features.reshape(len(all_l_features), -1)
        all_r_features = all_r_features.reshape(len(all_r_features), -1)

        foobar.append_ndarray_signature(all_l_features,
                                        'normalized_image_match l_features',
                                        task.name)
        foobar.append_ndarray_signature(all_r_features,
                                        'normalized_image_match r_features',
                                        task.name)

        if role == 'train':
            if np.allclose(all_l_features.var(axis=0), 0.0):
                raise ValueError('Homogeneous features (non-finite features)')

            xmean_l, xstd_l = mean_and_std(all_l_features,
                                           remove_std0=pipeline['remove_std0'])
            xmean_r, xstd_r = mean_and_std(all_r_features,
                                           remove_std0=pipeline['remove_std0'])
            xmean = (xmean_l + xmean_r) / 2.0
            # -- this is an ad-hoc way of blending the variances.
            xstd = np.sqrt(
                np.maximum(xstd_l, xstd_r)**2 + pipeline['varthresh'])

            foobar.append_ndarray_signature(xmean,
                                            'normalized_image_match xmean',
                                            task.name)
            foobar.append_ndarray_signature(xstd,
                                            'normalized_image_match xstd',
                                            task.name)

            svm_dct['xmean'] = xmean
            svm_dct['xstd'] = xstd
        else:
            xmean = svm_dct['xmean']
            xstd = svm_dct['xstd']

        info('Computing comparison features')

        # -- now compute the "comparison functions" into x_trn
        for jj, (lfeat, rfeat) in enumerate(zip(all_l_features,
                                                all_r_features)):
            lfeat_z = (lfeat - xmean) / xstd
            rfeat_z = (rfeat - xmean) / xstd
            for ci, comp in enumerate(comps):
                x_trn[jj, ci, :] = comp(lfeat_z, rfeat_z)

        if pipeline['divrowl2']:
            info('Dividing by feature norms')
            # -- now normalize by average feature norm because some
            #    comparison functions come out smaller than others
            if role == 'train':
                svm_dct['divrowl2_avg_nrm'] = {}
                for ci, cname in enumerate(self.comparison_names):
                    avg_nrm = average_row_l2norm(x_trn[:, ci, :]) + 1e-7
                    svm_dct['divrowl2_avg_nrm'][cname] = avg_nrm

            avg_nrm_vec = [
                svm_dct['divrowl2_avg_nrm'][cname]
                for cname in self.comparison_names
            ]
            x_trn /= np.asarray(avg_nrm_vec)[None, :, None]
            foobar.append_trace('get_normlized_features avg_nrm', avg_nrm_vec)

        # -- collapse comparison and feature dimensions
        x_trn.shape = (x_trn.shape[0], x_trn.shape[1] * x_trn.shape[2])

        foobar.append_ndarray_signature(x_trn, 'normalized_image_match x_trn',
                                        task.name)
        info('normalized_image_match_features complete')
        return x_trn
def patch_whitening_filterbank_X(
    patches,
    o_ndim,
    gamma,
    remove_mean,
    beta,
    hard_beta,
):
    """
    patches - Image patches (can be uint8 pixels or floats)
    o_ndim - 2 to get matrix outputs, 4 to get image-stack outputs
    gamma - non-negative real to boost low-principle components

    remove_mean - see contrast_normalize
    beta - see contrast_normalize
    hard_beta - see contrast_normalize

    Returns: M, P, X
        M - mean of contrast-normalized patches
        P - whitening matrix / filterbank for contrast-normalized patches
        X - contrast-normalized patches

    """
    # Algorithm from Coates' sc_vq_demo.m

    # -- patches -> column vectors
    X = patches.reshape(len(patches), -1).astype('float64')

    X = contrast_normalize(X,
                           remove_mean=remove_mean,
                           beta=beta,
                           hard_beta=hard_beta)

    # -- ZCA whitening (with low-pass)
    logger.debug('patch_whitening_filterbank_X starting ZCA')
    M, _std = mean_and_std(X)
    Xm = X - M
    assert Xm.shape == X.shape
    logger.info('patch_whitening_filterbank_X starting ZCA: dot %s' %
                str(Xm.shape))
    C = dot_f64(Xm.T, Xm) / (Xm.shape[0] - 1)
    logger.debug('patch_whitening_filterbank_X starting ZCA: eigh')
    D, V = np.linalg.eigh(C)
    logger.debug('patch_whitening_filterbank_X starting ZCA: dot %s' %
                 str(V.shape))
    P = dot_f32(np.sqrt(1.0 / (D + gamma)) * V, V.T)

    # -- return to image space
    if o_ndim == 4:
        M = M.reshape(patches.shape[1:])
        P = P.reshape((P.shape[0], ) + patches.shape[1:])
        X = X.reshape((len(X), ) + patches.shape[1:])
    elif o_ndim == 2:
        pass
    else:
        raise ValueError('o_ndim not in (2, 4)', o_ndim)

    logger.debug('patch_whitening_filterbank_X -> done')

    foobar.append_ndarray_signature(M, 'patch_whitening_filterbank_X M')
    foobar.append_ndarray_signature(P, 'patch_whitening_filterbank_X P')
    foobar.append_ndarray_signature(X, 'patch_whitening_filterbank_X X')
    dtype = patches.dtype
    return M.astype(dtype), P.astype(dtype), X.astype(dtype)