Пример #1
0
    def model(self, x, w):
        # feature transformation - switch for dealing
        # with feature transforms that either do or do
        # not have internal parameters
        f = 0
        if len(self.sig.parameters) == 2:
            if np.shape(w)[1] == 1:
                f = self.feature_transforms(x, w)
            else:
                f = self.feature_transforms(x, w[0])
        else:
            f = self.feature_transforms(x)

        # tack a 1 onto the top of each input point all at once
        o = np.ones((1, np.shape(f)[1]))
        f = np.vstack((o, f))

        # compute linear combination and return
        # switch for dealing with feature transforms that either
        # do or do not have internal parameters
        a = 0
        if np.ndim(w) == 2:
            a = np.dot(f.T, w)
        elif np.ndim(w) == 3:
            a = np.dot(f.T, w[1])
        return a
Пример #2
0
 def sum_to_match_shape(sum_this, to_match_this):
     sum_this = np.sum(
         sum_this,
         axis=tuple(range(0,
                          np.ndim(sum_this) - np.ndim(to_match_this))))
     for axis, size in enumerate(np.shape(to_match_this)):
         if size == 1:
             sum_this = np.sum(sum_this, axis=axis, keepdims=True)
     return sum_this
Пример #3
0
 def repeat_to_match_shape(g, A, axis=None):
     gout = np.empty_like(A)
     if np.ndim(gout) == 0:
         gout = g
     else:
         gout = np.ones_like(A) * g
     return gout
Пример #4
0
    def compare_smoother_grads(lds):
        init_params, pair_params, node_params = lds

        symmetrize = make_unop(
            lambda x: (x + x.T) / 2. if np.ndim(x) == 2 else x, tuple)

        messages, _ = natural_filter_forward_general(*lds)
        dotter = randn_like(natural_smoother_general(messages, *lds))

        def py_fun(messages):
            result = natural_smoother_general(messages, *lds)
            assert shape(result) == shape(dotter)
            return contract(dotter, result)

        dense_messages, _ = _natural_filter_forward_general(
            init_params, pair_params, node_params)

        def cy_fun(messages):
            result = _natural_smoother_general(messages, pair_params)
            result = result[0][:3], result[1], result[2]
            assert shape(result) == shape(dotter)
            return contract(dotter, result)

        result_py = py_fun(messages)
        result_cy = cy_fun(dense_messages)
        assert np.isclose(result_py, result_cy)

        g_py = grad(py_fun)(messages)
        g_cy = unpack_dense_messages(grad(cy_fun)(dense_messages))

        assert allclose(g_py, g_cy)
Пример #5
0
def visual_comparison(x, weights):
    '''
    Visually compare the results of several runs of PCA applied to two dimensional input and 
    two principal components
    '''
    # do weights
    weights = np.array(weights)
    num_runs = np.ndim(weights)

    # plot data
    fig = plt.figure(figsize=(10, 4))
    gs = gridspec.GridSpec(1, num_runs)
    for run in range(num_runs):
        # create subplot
        ax = plt.subplot(gs[run], aspect='equal')
        w_best = weights[run]

        # scatter data
        ax.scatter(x[0, :], x[1, :], c='k')

        # plot pc 1
        vector_draw(w_best[:, 0], ax, color='red', zorder=1)
        vector_draw(w_best[:, 1], ax, color='red', zorder=1)

        # plot vertical / horizontal axes
        ax.axhline(linewidth=0.5, color='k', zorder=0)
        ax.axvline(linewidth=0.5, color='k', zorder=0)
        ax.set_title('run ' + str(run + 1), fontsize=16)
        ax.set_xlabel(r'$x_1$', fontsize=16)
        ax.set_ylabel(r'$x_2$', fontsize=16, rotation=0, labelpad=10)
Пример #6
0
def test_hessian_tensor_product():
    fun = lambda a: np.sum(np.sin(a))
    a = npr.randn(5, 4, 3)
    V = npr.randn(5, 4, 3)
    H = hessian(fun)(a)
    check_equivalent(np.tensordot(H, V, axes=np.ndim(V)),
                     hessian_tensor_product(fun)(a, V))
Пример #7
0
def test_tensor_jacobian_product():
    fun = lambda a: np.roll(np.sin(a), 1)
    a = npr.randn(5, 4, 3)
    V = npr.randn(5, 4)
    J = jacobian(fun)(a)
    check_equivalent(np.tensordot(V, J, axes=np.ndim(V)),
                     tensor_jacobian_product(fun)(a, V))
Пример #8
0
    def setUp(self):
        self.m = m = 100
        self.n = n = 50
        self.man = Sphere(m, n)

        # For automatic testing of ehess2rhess
        self.proj = lambda x, u: u - np.tensordot(x, u, np.ndim(u)) * x
Пример #9
0
    def compare_smoother_grads(lds):
        init_params, pair_params, node_params = lds

        symmetrize = make_unop(lambda x: (x + x.T)/2. if np.ndim(x) == 2 else x, tuple)

        messages, _ = natural_filter_forward_general(*lds)
        dotter = randn_like(natural_smoother_general(messages, *lds))

        def py_fun(messages):
            result = natural_smoother_general(messages, *lds)
            assert shape(result) == shape(dotter)
            return contract(dotter, result)

        dense_messages, _ = _natural_filter_forward_general(
            init_params, pair_params, node_params)
        def cy_fun(messages):
            result = _natural_smoother_general(messages, pair_params)
            result = result[0][:3], result[1], result[2]
            assert shape(result) == shape(dotter)
            return contract(dotter, result)

        result_py = py_fun(messages)
        result_cy = cy_fun(dense_messages)
        assert np.isclose(result_py, result_cy)

        g_py = grad(py_fun)(messages)
        g_cy = unpack_dense_messages(grad(cy_fun)(dense_messages))

        assert allclose(g_py, g_cy)
Пример #10
0
def _compose_einsums(formula, args1, args2, parent_formula, parent_args):
    parent_formula = debroadcast_formula(
        parent_formula, *[np.ndim(arg) for arg in parent_args])
    parent_in_formulas, parent_out_formula = split_einsum_formula(
        parent_formula)

    parent_ndim = len(parent_out_formula)
    arg_ndims = ([np.ndim(arg) for arg in args1] + [parent_ndim] +
                 [np.ndim(arg) for arg in args2])
    formula = debroadcast_formula(formula, *arg_ndims)
    in_formulas, out_formula = split_einsum_formula(formula)

    i = len(args1)
    if len(parent_out_formula) != len(in_formulas[i]):
        raise ValueError('Input formula {} and parent formula {} have'
                         ' inconsistent numbers of indexes, broadcasting'
                         'problem?'.format(in_formulas[i], parent_out_formula))

    subs_map = collections.defaultdict(iter(_einsum_range).next)

    # splice out the old input formula
    old_in_formula = in_formulas[i]
    in_formulas = in_formulas[:i] + in_formulas[i + 1:]

    # canonicalize input and output formulas (optional, for cleanliness)
    in_formulas = [
        ''.join(subs_map[idx] for idx in subs) for subs in in_formulas
    ]
    out_formula = ''.join(subs_map[idx] for idx in out_formula)

    # identify parent output indices with corresponding input indices
    subs_map.update((pidx + '_parent', subs_map[idx])
                    for pidx, idx in zip(parent_out_formula, old_in_formula))

    # update the parent input formulas
    parent_in_formulas = [
        ''.join(subs_map[idx + '_parent'] for idx in subs)
        for subs in parent_in_formulas
    ]

    # splice the formula lists and arguments
    new_in_formulas = in_formulas[:i] + parent_in_formulas + in_formulas[i:]
    new_args = args1 + parent_args + args2

    new_formula = _reconstitute_einsum_formula(new_in_formulas, out_formula)
    return np.einsum(new_formula, *new_args)
Пример #11
0
def _dot_vjp_0(ans, sparse, dense):
    if max(anp.ndim(sparse), anp.ndim(dense)) > 2:
        raise NotImplementedError("Current dot vjps only support ndim <= 2.")

    if anp.ndim(sparse) == 0:
        return lambda g: anp.sum(dense * g)
    if anp.ndim(sparse) == 1 and anp.ndim(dense) == 1:
        return lambda g: g * dense
    if anp.ndim(sparse) == 2 and anp.ndim(dense) == 1:
        return lambda g: g[:, None] * dense
    if anp.ndim(sparse) == 1 and anp.ndim(dense) == 2:
        print('  4th case')
        return lambda g: anp.dot(dense, g)
    return lambda g: dot(dense.T, g)
Пример #12
0
    def draw_weight_path(self, ax, w_hist, **kwargs):
        # make colors for plot
        colorspec = self.make_colorspec(w_hist)

        arrows = True
        if 'arrows' in kwargs:
            arrows = kwargs['arrows']

        ### plot function decrease plot in right panel
        for j in range(len(w_hist)):
            w_val = w_hist[j]

            # plot each weight set as a point
            ax.scatter(w_val[0],
                       w_val[1],
                       s=80,
                       c=colorspec[j],
                       edgecolor='k',
                       linewidth=2 * math.sqrt((1 / (float(j) + 1))),
                       zorder=3)

            # plot connector between points for visualization purposes
            if j > 0:
                pt1 = w_hist[j - 1]
                pt2 = w_hist[j]

                # produce scalar for arrow head length
                pt_length = np.linalg.norm(pt1 - pt2)
                head_length = 0.1
                alpha = (head_length - 0.35) / pt_length + 1

                # if points are different draw error
                if np.linalg.norm(pt1 - pt2) > head_length and arrows == True:
                    if np.ndim(pt1) > 1:
                        pt1 = pt1.flatten()
                        pt2 = pt2.flatten()

                    ax.arrow(pt1[0],
                             pt1[1], (pt2[0] - pt1[0]) * alpha,
                             (pt2[1] - pt1[1]) * alpha,
                             head_width=0.1,
                             head_length=head_length,
                             fc='k',
                             ec='k',
                             linewidth=4,
                             zorder=2,
                             length_includes_head=True)
                    ax.arrow(pt1[0],
                             pt1[1], (pt2[0] - pt1[0]) * alpha,
                             (pt2[1] - pt1[1]) * alpha,
                             head_width=0.1,
                             head_length=head_length,
                             fc='w',
                             ec='w',
                             linewidth=0.25,
                             zorder=2,
                             length_includes_head=True)
Пример #13
0
    def setUp(self):
        self.m = m = 100
        self.n = n = 50
        self.manifold = Sphere(m, n)

        # For automatic testing of euclidean_to_riemannian_hessian
        self.projection = lambda x, u: u - np.tensordot(x, u, np.ndim(u)) * x

        super().setUp()
Пример #14
0
def broadcast(gvs, vs, result, broadcast_idx=0):
    while anp.ndim(result) < len(vs.shape):
        result = anp.expand_dims(result, 0)
    for axis, size in enumerate(anp.shape(result)):
        if size == 1:
            result = anp.repeat(result, vs.shape[axis], axis=axis)
    if vs.iscomplex and not gvs.iscomplex:
        result = result + 0j
    return result
Пример #15
0
def maybe_einsum(formula, *args):
    formula = debroadcast_formula(formula, *[np.ndim(arg) for arg in args])

    if any(_is_constant_zero(arg) for arg in args):
        return _zeros_like_einsum(formula, args, ())
    if len(args) == 1:
        input_formulas, output_formula = split_einsum_formula(formula)
        if input_formulas[0] == output_formula:
            return args[0]
    return constant_folding_einsum(formula, *args)
Пример #16
0
def label_meanfield(label_global, gaussian_globals, gaussian_stats):
    partial_contract = lambda a, b: \
        sum(np.tensordot(x, y, axes=np.ndim(y)) for x, y, in zip(a, b))

    gaussian_local_natparams = map(niw.expectedstats, gaussian_globals)
    node_params = np.array([
        partial_contract(gaussian_stats, natparam) for natparam in gaussian_local_natparams]).T

    local_natparam = dirichlet.expectedstats(label_global) + node_params
    stats = normalize(np.exp(local_natparam  - logsumexp(local_natparam, axis=1, keepdims=True)))
    vlb = np.sum(logsumexp(local_natparam, axis=1)) - contract(stats, node_params)

    return local_natparam, stats, vlb
Пример #17
0
def argmin_vjp(ans, x):
    """
    This should return the jacobian-vector product
    it should calculate d_ans/dx because the vector contains dloss/dans
    then we get with dloss/dans * dans/dx = dloss/dx which we're actually interested in
    """
    g = elementwise_grad(O2, 1)
    dg_dy = elementwise_grad(g, 1)(x, initial_y)
    dg_dx = elementwise_grad(g, 0)(x, initial_y)
    if np.ndim(dg_dy) == 0:  # we have just simple scalar function so we just have to divide instead of inverse
        return lambda v: v * (1. / dg_dy) * dg_dx

    return lambda v: v * np.matmul(np.linalg.inv(dg_dy), dg_dx)
Пример #18
0
def svd_solve(U, s, V, b, s_tol=1e-15):
    """
    Solve the system :math:`A X = b` for :math:`X` where :math:`A` is a
    positive semi-definite matrix using the singular value decomposition.
    This truncates the SVD so only dimensions corresponding to non-negative and
    sufficiently large singular values are used.
    Parameters
    ----------
    U: numpy.ndarray
        The :code:`U` factor of :code:`U, s, V = svd(A)` positive
        semi-definite matrix.
    s: numpy.ndarray
        The :code:`s` factor of :code:`U, s, V = svd(A)` positive
        semi-definite matrix.
    V: numpy.ndarray
        The :code:`V` factor of :code:`U, s, V = svd(A)` positive
        semi-definite matrix.
    b: numpy.ndarray
        An array or matrix
    s_tol: float
        Cutoff for small singular values. Singular values smaller than
        :code:`s_tol` are clamped to :code:`s_tol`.
    Returns
    -------
    X: numpy.ndarray
        The result of :math:`X = A^-1 b`
    okind: numpy.ndarray
        The indices of :code:`s` that are kept in the factorisation
    """

    # Test shapes for efficient computations
    n = U.shape[0]
    assert (b.shape[0] == n)
    m = b.shape[1] if np.ndim(b) > 1 else 1

    # Auto clamp SVD based on threshold
    sclamp = np.maximum(s, s_tol)

    # Inversion factors
    ss = 1. / np.sqrt(sclamp)
    U2 = U * ss[np.newaxis, :]
    V2 = ss[:, np.newaxis] * V

    if m < n:
        # Few queries
        X = U2.dot(V2.dot(b))  # O(n^2 (2m))
    else:
        X = U2.dot(V2).dot(b)  # O(n^2 (m + n))

    return X
    def draw_weight_path(self, ax, w_hist, **kwargs):
        # make colors for plot
        colorspec = self.make_colorspec(w_hist)

        arrows = True
        if 'arrows' in kwargs:
            arrows = kwargs['arrows']

        ### plot function decrease plot in right panel
        for j in range(len(w_hist)):
            w_val = w_hist[j]

            # plot each weight set as a point
            ax.scatter(w_val[0],
                       w_val[1],
                       s=80,
                       color=colorspec[j],
                       edgecolor=self.edgecolor,
                       linewidth=2 * math.sqrt((1 / (float(j) + 1))),
                       zorder=3)

            # plot connector between points for visualization purposes
            if j > 0:
                pt1 = w_hist[j - 1]
                pt2 = w_hist[j]

                # produce scalar for arrow head length
                pt_length = np.linalg.norm(pt1 - pt2)
                head_length = 0.1
                alpha = (head_length - 0.35) / pt_length + 1

                # if points are different draw error
                if np.linalg.norm(pt1 - pt2) > head_length and arrows == True:
                    if np.ndim(pt1) > 1:
                        pt1 = pt1.flatten()
                        pt2 = pt2.flatten()

                    # draw color connectors for visualization
                    w_old = pt1
                    w_new = pt2
                    ax.plot([w_old[0], w_new[0]], [w_old[1], w_new[1]],
                            color=colorspec[j],
                            linewidth=2,
                            alpha=1,
                            zorder=2)  # plot approx
                    ax.plot([w_old[0], w_new[0]], [w_old[1], w_new[1]],
                            color='k',
                            linewidth=3,
                            alpha=1,
                            zorder=1)  # plot approx
Пример #20
0
def get_arhmm_local_nodeparams(lds_global_natparam, lds_expected_stats):
    init_stats, pair_stats = lds_expected_stats[:2]
    all_init_params, all_pair_params = get_all_lds_local_natparams(lds_global_natparam)

    dense_init_params = map(np.stack, zip(*all_init_params))
    dense_pair_params = map(np.stack, zip(*all_pair_params))

    partial_contract = lambda a: lambda b: contract(a, b)
    init_node_potential = np.array(map(partial_contract(init_stats), all_init_params))

    partial_contract = lambda a: lambda b: \
        sum(np.tensordot(x, y, axes=np.ndim(y)) for x, y in zip(a,b))
    remaining_node_potentials = np.vstack(map(partial_contract(pair_stats), all_pair_params)).T

    node_potentials = np.vstack((init_node_potential, remaining_node_potentials))

    return node_potentials
Пример #21
0
    def __init__(self, func, initialX, interval=[-1e15, 1e15], ftol=1e-6, maxIters=1e3, maxItersLS=200):
        self.costFunc   = func
        self.gradFunc   = grad(self.evaluate)
        self.hessFunc   = hessian(self.evaluate)
        self.maxIters   = int(maxIters)
        self.maxItersLS = maxItersLS
        self.interval   = interval
        self.fevals     = 0
        self.ftol       = ftol
        self.x_is_matrix= False

        if np.ndim(initialX) > 1:
            self.x_is_matrix = True
            initialX = np.squeeze(initialX)

        self.xLen = np.shape(initialX)[0]
        self.direction  = np.zeros((maxIters, self.xLen))
        self.x          = np.zeros((maxIters, self.xLen))
        self.x[0] = initialX
Пример #22
0
    def compute(self, theta):
        # Not exactly the same as the equation of Gauss-Newton update
        # d = lstsq(J, r), not the stardard update d = inv (J^T * J) * J * r
        # however, it works better than implementing the equation malually

        r = self.flattened_residual(theta)
        J = self.jacobian(theta)

        check_non_nan(r)
        check_non_nan(J)
        assert(np.ndim(r) == 1)

        # residuals can be a multi-dimensonal array so flatten them
        J = J.reshape(r.shape[0], theta.shape[0])

        # TODO add weighted Gauss-Newton as an option
        # weights = self.robustifier.weights(r)
        delta, error, _, _ = np.linalg.lstsq(J, r, rcond=None)
        return delta
Пример #23
0
    def __init__(self,
                 func,
                 initialX,
                 interval=[-1e15, 1e15],
                 ftol=1e-6,
                 maxIters=1e3,
                 maxItersLS=200):
        self.costFunc = func
        self.gradFunc = grad(self.evaluate)
        self.hessFunc = hessian(self.evaluate)
        self.maxIters = int(maxIters)
        self.maxItersLS = maxItersLS
        self.interval = interval
        self.fevals = 0
        self.ftol = ftol

        self.x_is_matrix = False

        if np.ndim(initialX) > 1:
            self.x_is_matrix = True
            initialX = np.squeeze(initialX)

        self.xLen = np.shape(initialX)[0]
        self.direction = np.zeros((maxIters, self.xLen))
        self.x = np.zeros((maxIters, self.xLen))
        self.x[0] = initialX

        self.gradient = np.zeros((self.maxIters, self.xLen))
        self.S = np.zeros((self.maxIters, self.xLen, self.xLen))

        self.epsilon1 = self.ftol
        self.k = 0
        self.m = 0
        self.rho = 0.1
        self.sigma = 0.7
        self.tau = 0.1
        self.chi = 0.75
        self.m_hat = 600
        self.epsilon2 = 1e-10

        self.S[0] = np.eye(self.xLen)
Пример #24
0
def test_hessian_tensor_product():
    fun = lambda a: np.sum(np.sin(a))
    a = npr.randn(5, 4, 3)
    V = npr.randn(5, 4, 3)
    H = hessian(fun)(a)
    check_equivalent(np.tensordot(H, V, axes=np.ndim(V)), hessian_vector_product(fun)(a, V))
Пример #25
0
 def vector_dot_fun(*args, **kwargs):
     args, vector = args[:-1], args[-1]
     return np.tensordot(vector, fun(*args, **kwargs), axes=np.ndim(vector))
Пример #26
0
 def vector_dot_grad(*args, **kwargs):
     args, vector = args[:-1], args[-1]
     return np.tensordot(fun_grad(*args, **kwargs), vector, np.ndim(vector))
Пример #27
0
def generalized_outer_product(x):
    if np.ndim(x) == 1:
        return np.outer(x, x)
    return np.matmul(x, np.swapaxes(x, -1, -2))
Пример #28
0
 def T(X): return np.swapaxes(X, -1, -2) if np.ndim(X) > 1 else X
 def symmetrize(X): return 0.5 * (X + T(X))
Пример #29
0
 def vector_dot_fun(*args, **kwargs):
     args, vector = args[:-1], args[-1]
     return np.tensordot(vector, fun(*args, **kwargs), axes=np.ndim(vector))
Пример #30
0
 def vector_dot_grad(*args, **kwargs):
     args, vector = args[:-1], args[-1]
     return np.tensordot(fun_grad(*args, **kwargs), vector, np.ndim(vector))
Пример #31
0
 def T(X):
     return anp.swapaxes(X, -1, -2) if anp.ndim(X) > 1 else X
Пример #32
0
        assert shape(a) == shape(b)
        return binop(a, b)
    return wrapped
make_binop = (lambda make_binop: lambda *args:
              add_binop_size_check(make_binop(*args)))(make_binop)

add      = make_binop(operator.add,     tuple)
sub      = make_binop(operator.sub,     tuple)
mul      = make_binop(operator.mul,     tuple)
div      = make_binop(operator.truediv, tuple)
allclose = make_binop(np.allclose,      all)
contract = make_binop(inner,            sum)

shape      = make_unop(np.shape, tuple)
unbox      = make_unop(getval,   tuple)
sqrt       = make_unop(np.sqrt,  tuple)
square     = make_unop(lambda a: a**2, tuple)
randn_like = make_unop(lambda a: npr.normal(size=np.shape(a)), tuple)
zeros_like = make_unop(lambda a: np.zeros(np.shape(a)), tuple)
flatten    = make_unop(lambda a: np.ravel(a), np.concatenate)

scale      = make_scalar_op(operator.mul, tuple)
add_scalar = make_scalar_op(operator.add, tuple)

norm = lambda x: np.sqrt(contract(x, x))
rand_dir_like = lambda x: scale(1./norm(x), randn_like(x))

isobjarray = lambda x: isinstance(x, np.ndarray) and x.dtype == np.object
tuplify = Y(lambda f: lambda a: a if not istuple(a) and not isobjarray(a) else tuple(map(f, a)))
depth = Y(lambda f: lambda a: np.ndim(a) if not istuple(a) else 1+(min(map(f, a)) if len(a) else 1))
Пример #33
0
def generalized_outer_product(x):
    if np.ndim(x) == 1:
        return np.outer(x, x)
    return np.matmul(x, np.swapaxes(x, -1, -2))
Пример #34
0
def _dot_vjp_1(ans, sparse, dense):
    if anp.ndim(sparse) != 2 or anp.ndim(dense) > 2:
        raise NotImplementedError(
            "Current dot vjps only support sparse matrices with ndim == 2.")
    return lambda g: dot(sparse.T, g)
Пример #35
0
make_binop = (lambda make_binop: lambda *args: add_binop_size_check(
    make_binop(*args)))(make_binop)

add = make_binop(operator.add, tuple)
sub = make_binop(operator.sub, tuple)
mul = make_binop(operator.mul, tuple)
div = make_binop(operator.truediv, tuple)
allclose = make_binop(np.allclose, all)
contract = make_binop(inner, sum)

shape = make_unop(np.shape, tuple)
unbox = make_unop(getval, tuple)
sqrt = make_unop(np.sqrt, tuple)
square = make_unop(lambda a: a**2, tuple)
randn_like = make_unop(lambda a: npr.normal(size=np.shape(a)), tuple)
zeros_like = make_unop(lambda a: np.zeros(np.shape(a)), tuple)
flatten = make_unop(lambda a: np.ravel(a), np.concatenate)

scale = make_scalar_op(operator.mul, tuple)
add_scalar = make_scalar_op(operator.add, tuple)

norm = lambda x: np.sqrt(contract(x, x))
rand_dir_like = lambda x: scale(1. / norm(x), randn_like(x))

isobjarray = lambda x: isinstance(x, np.ndarray) and x.dtype == np.object
tuplify = Y(lambda f: lambda a: a
            if not istuple(a) and not isobjarray(a) else tuple(map(f, a)))
depth = Y(lambda f: lambda a: np.ndim(a)
          if not istuple(a) else 1 + (min(map(f, a)) if len(a) else 1))
Пример #36
0
 def T(X): return np.swapaxes(X, -1, -2) if np.ndim(X) > 1 else X
 def symmetrize(X): return 0.5 * (X + T(X))
Пример #37
0
def test_tensor_jacobian_product():
    fun = lambda a: np.roll(np.sin(a), 1)
    a = npr.randn(5, 4, 3)
    V = npr.randn(5, 4)
    J = jacobian(fun)(a)
    check_equivalent(np.tensordot(V, J, axes=np.ndim(V)), vector_jacobian_product(fun)(a, V))
Пример #38
0
def show_encode_decode(x, cost_history, weight_history, **kwargs):
    '''
    Examine the results of linear or nonlinear PCA / autoencoder to two-dimensional input.
    Four panels are shown: 
    - original data (top left panel)
    - data projected onto lower dimensional curve (top right panel)
    - lower dimensional curve (lower left panel)
    - vector field illustrating how points in space are projected onto lower dimensional curve (lower right panel)
    
    Inputs: 
    - x: data
    - encoder: encoding function from autoencoder
    - decoder: decoding function from autoencoder
    - cost_history/weight_history: from run of gradient descent minimizing PCA least squares
    
    Optinal inputs:
    - show_pc: show pcs?   Only useful really for linear case.
    - scale: for vector field / quiver plot, adjusts the length of arrows in vector field
    '''
    # user-adjustable args
    encoder = lambda a, b: np.dot(b.T, a)
    decoder = lambda a, b: np.dot(b, a)
    if 'encoder' in kwargs:
        encoder = kwargs['encoder']
    if 'decoder' in kwargs:
        decoder = kwargs['decoder']
    projmap = False
    if 'projmap' in kwargs:
        projmap = kwargs['projmap']
    show_pc = False
    if 'show_pc' in kwargs:
        show_pc = kwargs['show_pc']
    scale = 14
    if 'scale' in kwargs:
        scale = kwargs['scale']
    encode_label = ''
    if 'encode_label' in kwargs:
        encode_label = kwargs['encode_label']

    # pluck out best weights
    ind = np.argmin(cost_history)
    w_best = weight_history[ind]
    num_params = 0
    if type(w_best) == list:
        num_params = len(w_best)
    else:
        num_params = np.ndim(w_best) - 1

    ###### figure 1 - original data, encoded data, decoded data ######
    fig = plt.figure(figsize=(10, 4))
    gs = gridspec.GridSpec(1, 3)
    ax1 = plt.subplot(gs[0], aspect='equal')
    ax2 = plt.subplot(gs[1], aspect='equal')
    ax3 = plt.subplot(gs[2], aspect='equal')

    # scatter original data with pc
    ax1.scatter(x[0, :], x[1, :], c='k', s=60, linewidth=0.75, edgecolor='w')

    if show_pc == True:
        for pc in range(np.shape(w_best)[1]):
            ax1.arrow(0,
                      0,
                      w_best[0, pc],
                      w_best[1, pc],
                      head_width=0.25,
                      head_length=0.5,
                      fc='k',
                      ec='k',
                      linewidth=4)
            ax1.arrow(0,
                      0,
                      w_best[0, pc],
                      w_best[1, pc],
                      head_width=0.25,
                      head_length=0.5,
                      fc='r',
                      ec='r',
                      linewidth=3)

    ### plot encoded and decoded data ###
    v = 0
    p = 0
    if num_params == 2:
        # create encoded vectors
        v = encoder(x, w_best[0])

        # decode onto basis
        p = decoder(v, w_best[1])
    else:
        # create encoded vectors
        v = encoder(x, w_best)

        # decode onto basis
        p = decoder(v, w_best)

    # plot decoded data
    z = np.zeros((1, np.size(v)))
    ax2.scatter(v, z, c='k', s=60, linewidth=0.75, edgecolor='w')

    # plot decoded data
    ax3.scatter(p[0, :], p[1, :], c='k', s=60, linewidth=0.75, edgecolor='r')

    # clean up panels
    xmin1 = np.min(x[0, :])
    xmax1 = np.max(x[0, :])
    xmin2 = np.min(x[1, :])
    xmax2 = np.max(x[1, :])
    xgap1 = (xmax1 - xmin1) * 0.2
    xgap2 = (xmax2 - xmin2) * 0.2
    xmin1 -= xgap1
    xmax1 += xgap1
    xmin2 -= xgap2
    xmax2 += xgap2

    for ax in [ax1, ax2, ax3]:
        if ax == ax1 or ax == ax3:
            ax.set_xlim([xmin1, xmax1])
            ax.set_ylim([xmin2, xmax2])
            ax.set_xlabel(r'$x_1$', fontsize=16)
            ax.set_ylabel(r'$x_2$', fontsize=16, rotation=0, labelpad=10)
            ax.axvline(linewidth=0.5, color='k', zorder=0)
        else:
            ax.set_ylim([-1, 1])
            if len(encode_label) > 0:
                ax.set_xlabel(encode_label, fontsize=16)
        ax.axhline(linewidth=0.5, color='k', zorder=0)

    ax1.set_title('original data', fontsize=18)
    ax2.set_title('encoded data', fontsize=18)
    ax3.set_title('decoded data', fontsize=18)

    # plot learned manifold
    a = np.linspace(xmin1, xmax1, 200)
    b = np.linspace(xmin2, xmax2, 200)
    s, t = np.meshgrid(a, b)
    s.shape = (1, len(a)**2)
    t.shape = (1, len(b)**2)
    z = np.vstack((s, t))

    v = 0
    p = 0
    if num_params == 2:
        # create encoded vectors
        v = encoder(z, w_best[0])

        # decode onto basis
        p = decoder(v, w_best[1])
    else:
        # create encoded vectors
        v = encoder(z, w_best)

        # decode onto basis
        p = decoder(v, w_best)

    ax3.scatter(p[0, :],
                p[1, :],
                c='k',
                s=1.5,
                edgecolor='r',
                linewidth=1,
                zorder=0)

    # set whitespace
    #fgs.update(wspace=0.01, hspace=0.5) # set the spacing between axes.

    ##### bottom panels - plot subspace and quiver plot of projections ####
    if projmap == True:
        fig = plt.figure(figsize=(10, 4))
        gs = gridspec.GridSpec(1, 1)
        ax1 = plt.subplot(gs[0], aspect='equal')
        ax1.scatter(p[0, :], p[1, :], c='r', s=9.5)
        ax1.scatter(p[0, :], p[1, :], c='k', s=1.5)

        ### create quiver plot of how data is projected ###
        new_scale = 0.75
        a = np.linspace(xmin1 - xgap1 * new_scale, xmax1 + xgap1 * new_scale,
                        20)
        b = np.linspace(xmin2 - xgap2 * new_scale, xmax2 + xgap2 * new_scale,
                        20)
        s, t = np.meshgrid(a, b)
        s.shape = (1, len(a)**2)
        t.shape = (1, len(b)**2)
        z = np.vstack((s, t))

        v = 0
        p = 0
        if num_params == 2:
            # create encoded vectors
            v = encoder(z, w_best[0])

            # decode onto basis
            p = decoder(v, w_best[1])
        else:
            # create encoded vectors
            v = encoder(z, w_best)

            # decode onto basis
            p = decoder(v, w_best)

        # get directions
        d = []
        for i in range(p.shape[1]):
            dr = (p[:, i] - z[:, i])[:, np.newaxis]
            d.append(dr)
        d = 2 * np.array(d)
        d = d[:, :, 0].T
        M = np.hypot(d[0, :], d[1, :])
        ax1.quiver(z[0, :],
                   z[1, :],
                   d[0, :],
                   d[1, :],
                   M,
                   alpha=0.5,
                   width=0.01,
                   scale=scale,
                   cmap='autumn')
        ax1.quiver(z[0, :],
                   z[1, :],
                   d[0, :],
                   d[1, :],
                   edgecolor='k',
                   linewidth=0.25,
                   facecolor='None',
                   width=0.01,
                   scale=scale)

        #### clean up and label panels ####
        for ax in [ax1]:
            ax.set_xlim([xmin1 - xgap1 * new_scale, xmax1 + xgap1 * new_scale])
            ax.set_ylim([xmin2 - xgap2 * new_scale, xmax2 + xgap1 * new_scale])
            ax.set_xlabel(r'$x_1$', fontsize=16)
            ax.set_ylabel(r'$x_2$', fontsize=16, rotation=0, labelpad=10)

        ax1.set_title('projection map', fontsize=18)

        # set whitespace
        gs.update(wspace=0.01, hspace=0.5)  # set the spacing between axes.