def quadrature_scheme_softmaxnormal_gauss_hermite( normal_loc, normal_scale, quadrature_size, validate_args=False, name=None): """Use Gauss-Hermite quadrature to form quadrature on `K - 1` simplex. A `SoftmaxNormal` random variable `Y` may be generated via ``` Y = SoftmaxCentered(X), X = Normal(normal_loc, normal_scale) ``` Note: for a given `quadrature_size`, this method is generally less accurate than `quadrature_scheme_softmaxnormal_quantiles`. Args: normal_loc: `float`-like `Tensor` with shape `[b1, ..., bB, K-1]`, B>=0. The location parameter of the Normal used to construct the SoftmaxNormal. normal_scale: `float`-like `Tensor`. Broadcastable with `normal_loc`. The scale parameter of the Normal used to construct the SoftmaxNormal. quadrature_size: Python `int` scalar representing the number of quadrature points. validate_args: Python `bool`, default `False`. When `True` distribution parameters are checked for validity despite possibly degrading runtime performance. When `False` invalid inputs may silently render incorrect outputs. name: Python `str` name prefixed to Ops created by this class. Returns: grid: Shape `[b1, ..., bB, K, quadrature_size]` `Tensor` representing the convex combination of affine parameters for `K` components. `grid[..., :, n]` is the `n`-th grid point, living in the `K - 1` simplex. probs: Shape `[b1, ..., bB, K, quadrature_size]` `Tensor` representing the associated with each grid point. """ with ops.name_scope(name, "quadrature_scheme_softmaxnormal_gauss_hermite", [normal_loc, normal_scale]): normal_loc = ops.convert_to_tensor(normal_loc, name="normal_loc") dt = normal_loc.dtype.base_dtype normal_scale = ops.convert_to_tensor( normal_scale, dtype=dt, name="normal_scale") normal_scale = maybe_check_quadrature_param( normal_scale, "normal_scale", validate_args) grid, probs = np.polynomial.hermite.hermgauss(deg=quadrature_size) grid = grid.astype(dt.dtype.as_numpy_dtype) probs = probs.astype(dt.dtype.as_numpy_dtype) probs /= np.linalg.norm(probs, ord=1, keepdims=True) probs = ops.convert_to_tensor(probs, name="probs", dtype=dt) grid = softmax( -distribution_util.pad( (normal_loc[..., array_ops.newaxis] + np.sqrt(2.) * normal_scale[..., array_ops.newaxis] * grid), axis=-2, front=True), axis=-2) # shape: [B, components, deg] return grid, probs
def testPosAxisCorrectness(self): x_ = np.float32([[1., 2, 3], [4, 5, 6]]) value_ = np.float32(0.25) count_ = np.int32(2) with self.test_session() as sess: x = array_ops.placeholder_with_default( x_, shape=x_.shape if self.is_static_shape else None) value = (constant_op.constant(value_) if self.is_static_shape else array_ops.placeholder_with_default(value_, shape=None)) count = (constant_op.constant(count_) if self.is_static_shape else array_ops.placeholder_with_default(count_, shape=None)) x1_front = distribution_util.pad(x, axis=1, value=value, count=count, front=True) x1_back = distribution_util.pad(x, axis=1, count=count, back=True) x1_both = distribution_util.pad(x, axis=1, value=value, front=True, back=True) if self.is_static_shape: self.assertAllEqual([2, 5], x1_front.shape) self.assertAllEqual([2, 5], x1_back.shape) self.assertAllEqual([2, 5], x1_both.shape) [x1_front_, x1_back_, x1_both_] = sess.run([x1_front, x1_back, x1_both]) self.assertAllClose(np.float32([[value_] * 2 + [1, 2, 3], [value_] * 2 + [4, 5, 6]]), x1_front_, atol=0., rtol=1e-6) self.assertAllClose(np.float32([[1, 2, 3] + [0.] * 2, [4, 5, 6] + [0.] * 2]), x1_back_, atol=0., rtol=1e-6) self.assertAllClose(np.float32([[value_, 1, 2, 3, value_], [value_, 4, 5, 6, value_]]), x1_both_, atol=0., rtol=1e-6)
def testNegAxisCorrectness(self): x_ = np.float32([[1., 2, 3], [4, 5, 6]]) value_ = np.float32(0.25) count_ = np.int32(2) with self.test_session() as sess: x = array_ops.placeholder_with_default( x_, shape=x_.shape if self.is_static_shape else None) value = (constant_op.constant(value_) if self.is_static_shape else array_ops.placeholder_with_default(value_, shape=None)) count = (constant_op.constant(count_) if self.is_static_shape else array_ops.placeholder_with_default(count_, shape=None)) x0_front = distribution_util.pad( x, axis=-2, value=value, count=count, front=True) x0_back = distribution_util.pad( x, axis=-2, count=count, back=True) x0_both = distribution_util.pad( x, axis=-2, value=value, front=True, back=True) if self.is_static_shape: self.assertAllEqual([4, 3], x0_front.shape) self.assertAllEqual([4, 3], x0_back.shape) self.assertAllEqual([4, 3], x0_both.shape) [x0_front_, x0_back_, x0_both_] = sess.run([ x0_front, x0_back, x0_both]) self.assertAllClose( np.float32([[value_]*3, [value_]*3, [1, 2, 3], [4, 5, 6]]), x0_front_, atol=0., rtol=1e-6) self.assertAllClose( np.float32([[1, 2, 3], [4, 5, 6], [0.]*3, [0.]*3]), x0_back_, atol=0., rtol=1e-6) self.assertAllClose( np.float32([[value_]*3, [1, 2, 3], [4, 5, 6], [value_]*3]), x0_both_, atol=0., rtol=1e-6)
def _forward(self, x): # Pad the last dim with a zeros vector. We need this because it lets us # infer the scale in the inverse function. y = distribution_util.pad(x, axis=-1, back=True) # Set shape hints. if x.shape.ndims is not None: shape = x.shape[:-1].concatenate(x.shape[-1] + 1) y.shape.assert_is_compatible_with(shape) y.set_shape(shape) return nn_ops.softmax(y)
def _forward(self, x): # Pad the last dim with a zeros vector. We need this because it lets us # infer the scale in the inverse function. y = distribution_util.pad(x, axis=-1, back=True) # Set shape hints. if x.shape.ndims is not None: shape = x.shape[:-1].concatenate(x.shape[-1] + 1) y.shape.assert_is_compatible_with(shape) y.set_shape(shape) # Since we only support event_ndims in [0, 1] and we do padding, we always # reduce over the last dimension, i.e., dim=-1 (which is the default). return nn_ops.softmax(y)
def _forward(self, x): # Pad the last dim with a zeros vector. We need this because it lets us # infer the scale in the inverse function. y = array_ops.expand_dims(x, dim=-1) if self._static_event_ndims == 0 else x y = distribution_util.pad(y, axis=-1, back=True) # Set shape hints. if x.shape.ndims is not None: shape = x.shape.as_list() if self._static_event_ndims == 0: shape += [2] elif shape[-1] is not None: shape[-1] += 1 shape = tensor_shape.TensorShape(shape) y.shape.assert_is_compatible_with(shape) y.set_shape(shape) # Since we only support event_ndims in [0, 1] and we do padding, we always # reduce over the last dimension, i.e., dim=-1 (which is the default). return nn_ops.softmax(y)