def generalized_outer_product(mat):
    if len(mat.shape) == 1:
        return np.outer(mat, mat)
    elif len(mat.shape) == 2:
        return np.einsum('ij,ik->ijk', mat, mat)
    else:
        raise ArithmeticError
 def predictions(weights, inputs):
     """weights is shape (num_weight_samples x num_weights)
        inputs  is shape (num_datapoints x D)"""
     inputs = np.expand_dims(inputs, 0)
     for W, b in unpack_layers(weights):
         outputs = np.einsum('mnd,mdo->mno', inputs, W) + b
         inputs = nonlinearity(outputs)
     return outputs