Пример #1
0
    def translate_space(space):
        """
        Translates an openAI space into an RLGraph Space object.

        Args:
            space (gym.spaces.Space): The openAI Space to be translated.

        Returns:
            Space: The translated Rlgraph Space.
        """
        if isinstance(space, gym.spaces.Discrete):
            if space.n == 2:
                return BoolBox()
            else:
                return IntBox(space.n)
        elif isinstance(space, gym.spaces.MultiBinary):
            return BoolBox(shape=(space.n, ))
        elif isinstance(space, gym.spaces.MultiDiscrete):
            return IntBox(low=np.zeros((space.nvec.ndim, ),
                                       dtype_("uint8", "np")),
                          high=space.nvec)
        elif isinstance(space, gym.spaces.Box):
            return FloatBox(low=space.low, high=space.high)
        elif isinstance(space, gym.spaces.Tuple):
            return Tuple(
                *[OpenAIGymEnv.translate_space(s) for s in space.spaces])
        elif isinstance(space, gym.spaces.Dict):
            return Dict({
                k: OpenAIGymEnv.translate_space(v)
                for k, v in space.spaces.items()
            })
        else:
            raise RLGraphError(
                "Unknown openAI gym Space class for state_space!")
Пример #2
0
    def __init__(self, low=None, high=None, shape=None, dtype="int32", **kwargs):
        """
        Three kinds of valid input:
            IntBox(6)  # only high is given -> low assumed to be 0 (0D scalar).
            IntBox(0, 2) # low and high are given as scalars and shape is assumed to be 0D scalar.
            IntBox(-1, 1, (3,4)) # low and high are scalars, and shape is provided.
            IntBox(np.array([-1,-2]), np.array([2,4])) # low and high are arrays of the same shape (no shape given!)
        NOTE: The `high` value for IntBoxes is excluded. Valid values thus are from the interval: [low,high[
        """
        if low is None:
            assert high is None, "ERROR: If `low` is None, `high` must be None as well!"
            low = -LARGE_INTEGER
            high = LARGE_INTEGER
        # support calls like (IntBox(5) -> low=0, high=5)
        elif high is None:
            high = low
            low = 0

        dtype = dtype_(dtype, "np")
        assert dtype in [np.int16, np.int32, np.int64, np.uint8], \
            "ERROR: IntBox does not allow dtype '{}'!".format(dtype)

        super(IntBox, self).__init__(low=low, high=high, shape=shape, dtype=dtype, **kwargs)

        self.num_categories = None if self.global_bounds is False else self.global_bounds[1]
Пример #3
0
    def create_variables(self, input_spaces, action_space=None):
        # Overwrite parent's method as we don't need a custom registry.
        if self.record_space is None:
            self.record_space = input_spaces["records"]

        # Make sure all input-records have a batch rank and determine the shapes and dtypes.
        shapes = []
        dtypes = []
        names = []
        for key, value in self.record_space.flatten().items():
            # TODO: what if single items come in without a time-rank? Then this check here will fail.
            # We are expecting single items. The incoming batch-rank is actually a time-rank: Add the batch rank.
            sanity_check_space(
                value,
                must_have_batch_rank=self.only_insert_single_records is False)
            shape = value.get_shape(with_time_rank=value.has_time_rank)
            shapes.append(shape)
            dtypes.append(dtype_(value.dtype))
            names.append(key)

        # Construct the wrapped FIFOQueue object.
        if get_backend() == "tf":
            if self.reuse_variable_scope:
                shared_name = self.reuse_variable_scope + ("/" + self.scope if
                                                           self.scope else "")
            else:
                shared_name = self.global_scope

            self.queue = tf.FIFOQueue(capacity=self.capacity,
                                      dtypes=dtypes,
                                      shapes=shapes,
                                      names=names,
                                      shared_name=shared_name)
Пример #4
0
    def _graph_fn_apply(self, text_inputs):
        """
        Args:
            text_inputs (SingleDataOp): The Text input to generate a hash bucket for.

        Returns:
            tuple:
                - SingleDataOp: The hash lookup table (int64) that can be used as input to embedding-lookups.
                - SingleDataOp: The length (number of words) of the longest string in the `text_input` batch.
        """
        if get_backend() == "tf":
            # Split the input string.
            split_text_inputs = tf.string_split(source=text_inputs, delimiter=self.delimiter)
            # Build a tensor of n rows (number of items in text_inputs) words with
            dense = tf.sparse_tensor_to_dense(sp_input=split_text_inputs, default_value="")

            length = tf.reduce_sum(input_tensor=tf.to_int32(x=tf.not_equal(x=dense, y="")), axis=-1)
            if self.hash_function == "fast":
                hash_bucket = tf.string_to_hash_bucket_fast(input=dense, num_buckets=self.num_hash_buckets)
            else:
                hash_bucket = tf.string_to_hash_bucket_strong(input=dense,
                                                              num_buckets=self.num_hash_buckets,
                                                              key=self.hash_keys)

            # Int64 is tf's default for `string_to_hash_bucket` operation: Can leave as is.
            if self.dtype != "int64":
                hash_bucket = tf.cast(x=hash_bucket, dtype=dtype_(self.dtype))

            # Hash-bucket output is always batch-major.
            hash_bucket._batch_rank = 0
            hash_bucket._time_rank = 1

            return hash_bucket, length
Пример #5
0
    def __init__(self,
                 low=None,
                 high=None,
                 shape=None,
                 dtype="float32",
                 **kwargs):
        if low is None:
            assert high is None, "ERROR: If `low` is None, `high` must be None as well!"
            low = float("-inf")
            high = float("inf")
            self.unbounded = True
        else:
            self.unbounded = False
            # support calls like (FloatBox(1.0) -> low=0.0, high=1.0)
            if high is None:
                high = low
                low = 0.0

        dtype = dtype_(dtype, "np")
        assert dtype in [
            np.float16, np.float32, np.float64
        ], "ERROR: FloatBox does not allow dtype '{}'!".format(dtype)

        super(FloatBox, self).__init__(low=low,
                                       high=high,
                                       shape=shape,
                                       dtype=dtype,
                                       **kwargs)
Пример #6
0
    def create_variables(self, input_spaces, action_space=None):
        # Store the original structure for later recovery.
        dtypes = list()
        shapes = list()
        idx = 0
        while True:
            key = "inputs[{}]".format(idx)
            if key not in input_spaces:
                break
            flat_keys = list()
            for flat_key, flat_space in input_spaces[key].flatten().items():
                dtypes.append(dtype_(flat_space.dtype))
                shapes.append(
                    flat_space.get_shape(with_batch_rank=True,
                                         with_time_rank=True))
                flat_keys.append(flat_key)
            self.flat_keys.append(flat_keys)
            idx += 1

        if get_backend() == "tf":
            self.area = tf.contrib.staging.StagingArea(dtypes, shapes)
Пример #7
0
    def _read_records(self, indices):
        """
        Obtains record values for the provided indices.

        Args:
            indices ndarray: Indices to read. Assumed to be not contiguous.

        Returns:
             dict: Record value dict.
        """
        records = {}
        for name in self.record_space_flat.keys():
            records[name] = []

        if self.size > 0:
            for index in indices:
                record = self.memory_values[index]
                for name in self.record_space_flat.keys():
                    records[name].append(record[name])

        else:
            # TODO figure out how to do default handling in pytorch builds.
            # Fill with default vals for build.
            for name in self.record_space_flat.keys():
                if get_backend() == "pytorch":
                    records[name] = torch.zeros(
                        self.record_space_flat[name].shape,
                        dtype=dtype_(self.record_space_flat[name].dtype,
                                     "pytorch"))
                else:
                    records[name] = np.zeros(
                        self.record_space_flat[name].shape)

        # Convert if necessary: list of tensors fails at space inference otherwise.
        if get_backend() == "pytorch":
            for name in self.record_space_flat.keys():
                records[name] = torch.squeeze(torch.stack(records[name]))

        return records
Пример #8
0
    def _graph_fn_call(self, inputs):
        """
        Gray-scales images of arbitrary rank.
        Normally, the images' rank is 3 (width/height/colors), but can also be: batch/width/height/colors, or any other.
        However, the last rank must be of size: len(self.weights).

        Args:
            inputs (tensor): Single image or a batch of images to be gray-scaled (last rank=n colors, where
                n=len(self.weights)).

        Returns:
            DataOp: The op for processing the images.
        """
        # The reshaped weights used for the grayscale operation.
        if isinstance(inputs, list):
            inputs = np.asarray(inputs)
        images_shape = get_shape(inputs)
        assert images_shape[-1] == self.last_rank,\
            "ERROR: Given image's shape ({}) does not match number of weights (last rank must be {})!".\
            format(images_shape, self.last_rank)
        if self.backend == "python" or get_backend() == "python":
            if inputs.ndim == 4:
                grayscaled = []
                for i in range_(len(inputs)):
                    scaled = cv2.cvtColor(inputs[i], cv2.COLOR_RGB2GRAY)
                    grayscaled.append(scaled)
                scaled_images = np.asarray(grayscaled)

                # Keep last dim.
                if self.keep_rank:
                    scaled_images = scaled_images[:, :, :, np.newaxis]
            else:
                # Sample by sample.
                scaled_images = cv2.cvtColor(inputs, cv2.COLOR_RGB2GRAY)

            return scaled_images
        elif get_backend() == "pytorch":
            if len(inputs.shape) == 4:
                grayscaled = []
                for i in range_(len(inputs)):
                    scaled = cv2.cvtColor(inputs[i].numpy(),
                                          cv2.COLOR_RGB2GRAY)
                    grayscaled.append(scaled)
                scaled_images = np.asarray(grayscaled)
                # Keep last dim.
                if self.keep_rank:
                    scaled_images = scaled_images[:, :, :, np.newaxis]
            else:
                # Sample by sample.
                scaled_images = cv2.cvtColor(inputs.numpy(),
                                             cv2.COLOR_RGB2GRAY)
            return torch.tensor(scaled_images)
        elif get_backend() == "tf":
            weights_reshaped = np.reshape(
                self.weights,
                newshape=tuple([1] *
                               (get_rank(inputs) - 1)) + (self.last_rank, ))

            # Do we need to convert?
            # The dangerous thing is that multiplying an int tensor (image) with float weights results in an all
            # 0 tensor).
            if "int" in str(dtype_(inputs.dtype)):
                weighted = weights_reshaped * tf.cast(inputs,
                                                      dtype=dtype_("float"))
            else:
                weighted = weights_reshaped * inputs

            reduced = tf.reduce_sum(weighted, axis=-1, keepdims=self.keep_rank)

            # Cast back to original dtype.
            if "int" in str(dtype_(inputs.dtype)):
                reduced = tf.cast(reduced, dtype=inputs.dtype)

            return reduced