Example #1
0
    def __call__(self, inp: to.Tensor) -> to.Tensor:
        """
        Evaluate the features and normalize them.

        .. note::
            Only processing of 1-dim input (e.g., no images)! The input can be batched along the first dimension.

        :param inp: input i.e. observations in the RL setting
        :return: 1-dim vector of all feature values given the observations
        """
        if inp.ndimension() > 2:
            raise pyrado.ShapeErr(
                msg='RBF class can only handle 1-dim or 2-dim input!')
        inp = atleast_2D(
            inp
        )  # first dim is the batch size, the second dim it the actual input dimension
        inp = inp.reshape(inp.shape[0], 1,
                          inp.shape[1]).repeat(1, self.centers.shape[0],
                                               1)  # reshape explicitly

        exp_sq_dist = to.exp(-self.scale * to.pow(inp - self.centers, 2))

        feat_val = to.empty(inp.shape[0], self.num_feat)
        for i, sample in enumerate(exp_sq_dist):
            if self._state_wise_norm:
                # Normalize the features such that the activation for every state dimension sums up to one
                feat_val[i, :] = normalize(sample, axis=0,
                                           order=1).t().reshape(-1, )
            else:
                # Turn the features into a vector and normalize over all of them
                feat_val[i, :] = normalize(sample.t().reshape(-1, ),
                                           axis=-1,
                                           order=1)
        return feat_val
Example #2
0
    def _normalize_and_reshape(self, inp: to.Tensor) -> to.Tensor:
        """
        Normalize (depending on `state_wise_norm`) and reshape the input.

        :param inp: input tensor of exponentiated squared distances
        :return: feature value
        """
        if self._state_wise_norm:
            # Normalize the features such that the activation for every state dimension sums up to one
            return normalize(inp, axis=0, order=1).t().reshape(-1)
        else:
            # Turn the features into a vector and normalize over all of them
            return normalize(inp.t().reshape(-1), axis=-1, order=1)
Example #3
0
def test_normalize(dtype, axis):
    for _ in range(10):
        x = to.rand(5, 3) if dtype == 'torch' else np.random.rand(5, 3)
        x_norm = normalize(x, axis=axis, order=1)
        if isinstance(x_norm, to.Tensor):
            x_norm = x_norm.numpy()  # for easier checking with pytest.approx
        assert np.sum(x_norm, axis=axis) == pytest.approx(1.)
Example #4
0
def cosine_similarity(x: to.Tensor, y: to.Tensor) -> to.Tensor:
    r"""
    Compute the cosine similarity between two tensors $D_cos(x,y) = \frac{x^T y}{|x| \cdot |y|}$.

    :param x: input tensor
    :param y: input tensor
    :return: cosine similarity value
    """
    if not isinstance(x, to.Tensor):
        raise pyrado.TypeErr(given=x, expected_type=to.Tensor)
    if not isinstance(y, to.Tensor):
        raise pyrado.TypeErr(given=y, expected_type=to.Tensor)

    x_normed = normalize(x, order=2)
    y_normed = x_normed if y is x else normalize(y, order=2)
    return x_normed.dot(y_normed)
Example #5
0
    def derivative(self, inp: to.Tensor) -> to.Tensor:
        """
        Compute the derivative of the features w.r.t. the inputs.

        .. note::
            Only processing of 1-dim input (e.g., no images)! The input can be batched along the first dimension.

        :param inp: input i.e. observations in the RL setting
        :return: value of all features derivatives given the observations
        """

        if inp.ndimension() > 2:
            raise pyrado.ShapeErr(
                msg="RBF class can only handle 1-dim or 2-dim input!")
        inp = to.atleast_2d(
            inp
        )  # first dim is the batch size, the second dim it the actual input dimension
        inp = inp.reshape(inp.shape[0], 1,
                          inp.shape[1]).repeat(1, self.centers.shape[0],
                                               1)  # reshape explicitly

        exp_sq_dist = to.exp(-self.scale * to.pow(inp - self.centers, 2))
        exp_sq_dist_d = -2 * self.scale * (inp - self.centers)

        feat_val = to.empty(inp.shape[0], self.num_feat)
        feat_val_dot = to.empty(inp.shape[0], self.num_feat)

        for i, (sample, sample_d) in enumerate(zip(exp_sq_dist,
                                                   exp_sq_dist_d)):
            if self._state_wise_norm:
                # Normalize the features such that the activation for every state dimension sums up to one
                feat_val[i, :] = normalize(sample, axis=0, order=1).reshape(-1)
            else:
                # Turn the features into a vector and normalize over all of them
                feat_val[i, :] = normalize(
                    sample.t().reshape(-1),
                    axis=-1,
                    order=1,
                )

            feat_val_dot[
                i, :] = sample_d.reshape(-1) * feat_val[i, :] - feat_val[
                    i, :] * sum(sample_d.reshape(-1) * feat_val[i, :])

        return feat_val_dot