Exemplo n.º 1
0
    def _exploration_cluster(self, exploration_random_numbers: torch.Tensor,
                             action_outputs: torch.Tensor,
                             action_rewards: torch.Tensor):
        """For all those exploring, they have a self.exploration_probability chance of a totally random cluster being picked to explore instead
         of the sequence they were going to do in _exploration_sequence. Update rewards accordingly.

         """
        cluster_exploration = (exploration_random_numbers <
                               self.cluster_exploration_prob *
                               self.exploration_probability).float()

        random_indices = torch.randint(low=0,
                                       high=self.n_cluster_centers,
                                       size=(self._flock_size, ),
                                       device=self.device)
        # one-hot representation of the actions (=clusters) we want to explore right now
        exploration_actions = id_to_one_hot(random_indices,
                                            self.n_cluster_centers,
                                            dtype=self._float_dtype)
        exploration_rewards = exploration_actions * EXPLORATION_REWARD

        # overwrite the actions for experts which are exploring by exploration actions
        weighted_sum_(tensor_a=exploration_actions,
                      weight_a=cluster_exploration,
                      tensor_b=action_outputs,
                      weight_b=1.0 - cluster_exploration,
                      output=action_outputs)

        # Do the same for the rewards
        weighted_sum_(tensor_a=exploration_rewards,
                      weight_a=cluster_exploration,
                      tensor_b=action_rewards,
                      weight_b=1.0 - cluster_exploration,
                      output=action_rewards)
Exemplo n.º 2
0
    def test_to_one_hot_in_process(self, device):
        flock_size = 2
        n_cluster_centers = 3
        float_dtype = get_float(device)
        all_indices = torch.arange(flock_size,
                                   dtype=torch.int64,
                                   device=device)
        process = SPProcessStub(all_indices,
                                do_subflocking=True,
                                n_cluster_centers=n_cluster_centers,
                                input_size=1,
                                device=device)
        closest_cluster_centers = torch.tensor([[0, 1], [2, 2], [1, 2]],
                                               dtype=torch.int64,
                                               device=device)

        result = id_to_one_hot(closest_cluster_centers,
                               process._n_cluster_centers,
                               dtype=float_dtype)
        expected_result = torch.tensor(
            [[[1, 0, 0], [0, 1, 0]], [[0, 0, 1], [0, 0, 1]],
             [[0, 1, 0], [0, 0, 1]]],
            dtype=float_dtype,
            device=device)

        assert same(expected_result, result)
Exemplo n.º 3
0
    def _exploration_sequence(self, exploring: torch.Tensor,
                              exploration_random_numbers: torch.Tensor,
                              sequence_likelihoods_active: torch.Tensor,
                              buffer: TPFlockBuffer):
        """Decide if exploring. If yes, overwrite the sequence_likelihoods by a random sequence which will get
         converted to a corresponding cluster center later. Update the rewards with a corresponding exploration reward.

           Also stores the exploration flag into the buffer."""

        # Randomly decide which experts will be exploring
        exploration_random_numbers.uniform_(0, 1.0)
        exploring.copy_(
            exploration_random_numbers < self.exploration_probability)

        buffer.exploring.store(exploring)

        random_indices = torch.randint(low=0,
                                       high=self.n_frequent_seqs,
                                       size=(self._flock_size, ),
                                       device=self.device)
        # one-hot representation of the sequences we want to explore right now
        exploration_sequences = id_to_one_hot(random_indices,
                                              self.n_frequent_seqs,
                                              dtype=self._float_dtype)

        exploration_sequences *= EXPLORATION_REWARD

        # overwrite the actions for experts which are exploring by exploration actions
        weighted_sum_(tensor_a=exploration_sequences,
                      weight_a=exploring,
                      tensor_b=sequence_likelihoods_active,
                      weight_b=1.0 - exploring,
                      output=sequence_likelihoods_active)
Exemplo n.º 4
0
    def get_landmark(self, y: float, x: float):
        """Finds a nearest landmark for a given yx position. Position expected from range [0, MAX_POSITION).

        Args:
            y: y position in range [0,MAX_POSITION)
            x: x position in range [0,MAX_POSITION)

        Returns:
            ID of the nearest landmark from [0, horizontal_segments * vertical_segments] as a scalar Tensor
            (or one-hot).
        """
        if math.isnan(y) or math.isnan(x):
            return self._handle_nan()

        sy = self.segment_sizes[0].item()
        sx = self.segment_sizes[1].item()

        y_landmark = np.floor(y / sy)
        x_landmark = np.floor(x / sx)

        res = y_landmark * self.horizontal_segments + x_landmark

        result = torch.tensor([res],
                              dtype=self._float_dtype,
                              device=self._device)
        return result, id_to_one_hot(result.long(),
                                     self.num_landmarks).squeeze(0)
Exemplo n.º 5
0
def test_id_to_one_hot(indexes, number_of_elements, dtype, expected_output,
                       device):
    float_type = get_float(device)
    indexes_tensor = torch.tensor(indexes, dtype=torch.int64, device=device)

    if dtype is None:  # test default dtype
        result = id_to_one_hot(indexes_tensor, number_of_elements)
        ground_truth = torch.tensor(expected_output,
                                    dtype=float_type,
                                    device=device)
    else:
        result = id_to_one_hot(indexes_tensor, number_of_elements, dtype=dtype)
        ground_truth = torch.tensor(expected_output,
                                    dtype=dtype,
                                    device=device)

    assert same(ground_truth, result)
Exemplo n.º 6
0
 def step(self):
     self.output_data.copy_(self.all_symbols[self._current])
     self.output_label[0] = self._current
     self.output_sequence_id[0] = self.seq.current_sequence_id
     self.output_sequence_id_one_hot.copy_(
         id_to_one_hot(self.output_sequence_id,
                       self.output_sequence_id_one_hot.shape[1]))
     self._current = next(self.seq)
Exemplo n.º 7
0
    def _forward(self, input_clusters, input_context, input_rewards, sp_mask):
        self._verify_context_and_rewards(input_context, input_rewards)

        self._every_step_computations()

        trained_forward_indices, untrained_forward_indices, common_mask = self._determine_forward_pass(
            input_clusters, sp_mask)
        # Create and run trained
        if self.trained_forward_process is not None:
            # Free memory of old process
            del self.trained_forward_process

        # TODO this causes blinking of process observers in UI. Solve it e.g. by caching the last value in observer.
        # Do not assign to self to prevent observer to fetch invalid data
        trained_process = self._trained_forward_process_factory.create(
            self, input_clusters, self.input_context, self.input_rewards,
            trained_forward_indices, self._device)
        self._run_process(trained_process)

        if trained_process is not None:
            self.trained_forward_process = trained_process

        untrained_process = self._untrained_forward_process_factory.create(
            self, input_clusters, self.input_context, self.input_rewards,
            untrained_forward_indices, self._device)
        self._run_process(untrained_process)

        # Find all TPs who are annoyed (i.e over the frustration threshold) and generate a random action for them
        # Also: activate their exploration bits in the buffer, so as to learn that this action they have currently
        # taken doesn't do anything
        annoyed = self.frustration > self.frustration_threshold
        annoyed_experts = annoyed.sum()

        action_ids = torch.randint(high=self.n_cluster_centers,
                                   size=(annoyed_experts.item(), ),
                                   dtype=torch.int64,
                                   device=self._device)
        actions = id_to_one_hot(action_ids, vector_len=self.n_cluster_centers)

        self.action_rewards[annoyed, :] = actions * EXPLORATION_REWARD
        self.action_outputs[annoyed, :] = actions

        if annoyed_experts > 0:
            annoyed_indices = annoyed.nonzero().view(-1)

            self.buffer.set_flock_indices(annoyed_indices)
            self.buffer.exploring.store(
                torch.ones((annoyed_indices.numel(), ),
                           dtype=self._float_dtype,
                           device=self._device))
            self.buffer.unset_flock_indices()

        return common_mask
Exemplo n.º 8
0
 def step(self):
     self._step += 1
     if self._step % self._next_generation != 0:
         return
     self._step = 0
     if self._random_generation_intervals:
         self._next_generation = self._random.randint(
             low=1, high=self._generate_new_every_n + 1)
     self._current_value[0] = self._random.randint(low=self._lower_bound,
                                                   high=self._upper_bound)
     self._scalar_output[0] = self._current_value[0]
     self._one_hot_output.copy_(
         id_to_one_hot(self._current_value, self._upper_bound).squeeze())
Exemplo n.º 9
0
def compute_nn_classifier_accuracy(inputs: torch.Tensor,
                                   labels: torch.Tensor,
                                   n_classes: int,
                                   custom_input_length: int = None,
                                   learn_rate: float = 0.1,
                                   max_loss_difference: float = 0.005,
                                   loss_window_length: int = 5,
                                   max_epochs: int = 100,
                                   use_hidden_layer: bool = False,
                                   log_loss: bool = False) -> float:
    """Uses a simple (low-VC dimension) classifier to learn the labels.

    Accuracy of this classifier is returned as a measure of quality of the representation.

    Args:
        inputs: matrix of data [n_samples, input_size] - float (long shaped as [n_samples] if inputs_are_ids is True)
        labels: vector of labels [n_samples] - long
        n_classes: how many classes there is
        custom_input_length: by default, the inputs are expected to be [n_samples, input_size], if this parameter is set,
        inputs are expected to be vector of [n_samples] scalars, which is converted into one-hot format of this length
        learn_rate: 0.01, it uses SGD
        max_loss_difference: if the max difference between the loss values is smaller than this, stop training
        loss_window_length: from how long history of the loss values to determine when to stop training?
        max_epochs: in case that the data are too difficult, the training does not converge, this stops it
        use_hidden_layer: use a classifier with hidden layer (should be false)
        log_loss: should the loss be printed in time?

    Returns:
        accuracy of the classifier ~ quality of the input representation
    """
    if len(inputs.shape) != 2 and custom_input_length is None:
        raise ValueError(
            'input tensor is expected to have 2D shape [n_samples, data_length], view it appropriately'
        )

    if custom_input_length is not None:
        if len(inputs.shape) != 1:
            raise ValueError(
                'in case inputs_are_ids, the shape should be 1D [n_samples]')
        inputs = id_to_one_hot(inputs, vector_len=custom_input_length)

    trainer = train_nn_classifier(inputs, labels, n_classes, learn_rate,
                                  max_loss_difference, loss_window_length,
                                  max_epochs, use_hidden_layer, log_loss)
    return trainer.compute_accuracy(inputs, labels)
Exemplo n.º 10
0
    def step(self):
        """Returns nothing sets values of the tensors, which are marked as Node outputs (MemoryBlocks)."""

        # the data are held on CPU because they can be quite big and they are sent to GPU just when needed
        data, self.label_tensor = next(self._data_seq)

        # TODO (Time-Optim) the iterator could be changed so that the copying to output tensors is avoided?

        # copy the results to outputs
        self.output_data.copy_(data.to(self._device))
        self.label_tensor = self.label_tensor.to(self._device)

        if self._seq is not None:
            self.output_sequence_id[0] = self._seq.current_sequence_id
        if self._params.one_hot_labels:
            self.output_label.copy_(id_to_one_hot(self.label_tensor, 10))
        else:
            self.output_label.copy_(self.label_tensor)
Exemplo n.º 11
0
    def compute_closest_cluster_centers(self, cluster_centers: torch.Tensor, data: torch.Tensor) \
            -> Tuple[torch.Tensor, torch.Tensor]:
        """Calculates the closest cluster for a batch of datapoints for each member of the flock.

        Each member of the flock receives and clusters the datapoints and returns the closest cluster for each of them.

        Args:
            cluster_centers: [flock_size, n_cluster_centers, input_size]
            data (torch.Tensor): [flock_size, batch_size, input_size] containing datapoints
             for each member of the flock

        Returns:
            one_hot_cluster_centers (torch.Tensor): [flock_size, batch_size, n_cluster_centers] the one-hot clustering
             of each of the datapoints given their respective spatial poolers.
            datapoint_variances (torch.Tensor): [flock_size, n_cluster_centers] - variance of all points belonging
            to each cluster center or -1 if it has zero points.
        """

        # [flock_size, batch_size, n_cluster_centers]
        distances = self._compute_squared_distances(cluster_centers, data)
        # [flock_size, batch_size]
        closest = self._closest_cluster_center(distances)

        # Get one-hot representations of the assigned cluster centers
        # [flock_size, batch_size, n_cluster_centers]
        one_hot_cluster_centers = id_to_one_hot(closest,
                                                self._n_cluster_centers,
                                                dtype=self._float_dtype)

        # Set squared distance between datapoint and irrelevant (not closest) clusters centers to zero.
        # Then sum over batch.
        # [flock_size, n_cluster_centers]
        datapoint_variances = torch.sum(one_hot_cluster_centers * distances,
                                        dim=1)

        # identify cluster centers with zero points
        # [flock_size, n_cluster_centers]
        indices = torch.sum(one_hot_cluster_centers, dim=1) == 0

        # set their variance to -1
        datapoint_variances -= indices.type(self._float_dtype)

        return one_hot_cluster_centers, datapoint_variances
Exemplo n.º 12
0
    def get_landmarks(
            self,
            yx_positions: torch.Tensor) -> Tuple[torch.Tensor, torch.Tensor]:
        """Compute landmarks for no_positions stored in a 2D tensor.

        Args:
            yx_positions: tensor of size [num_positions, 2] containing list of YX positions in the square map

        Returns:
            Tensor of size [num_positions] (or [num_positions, num_landmarks]), which contains nearest landmark
            for each position.
        """
        yx_landmarks = torch.floor(yx_positions / self.segment_sizes)
        result = (yx_landmarks[:, 0] *
                  self.horizontal_segments) + yx_landmarks[:, 1]

        one_hot_result = id_to_one_hot(
            result.view(-1).long(), self.num_landmarks)

        return result, one_hot_result
Exemplo n.º 13
0
def train_svm_classifier(inputs: torch.Tensor,
                         labels: torch.Tensor,
                         n_classes: int,
                         custom_input_length: int = None) -> "SvmModel":
    model = SvmModel(num_classes=n_classes)

    if len(inputs.shape) != 2 and custom_input_length is None:
        raise ValueError(
            'input tensor is expected to have 2D shape [n_samples, data_length], view it appropriately'
        )

    if custom_input_length is not None:
        inputs = id_to_one_hot(inputs, custom_input_length)

    if len(labels.shape) >= 2:
        labels = one_hot_to_id(labels)

    inputs = np.array(inputs.cpu())
    labels = np.array(labels.cpu())

    model.train(inputs, labels)
    return model
Exemplo n.º 14
0
    def _check_and_standardize(
            data: Union[torch.Tensor, List[int], List[torch.Tensor]],
            classifier_input_size: int = None,
            device: str = 'cpu',
            verify_input_tensor: bool = False) -> torch.Tensor:
        """Converts input data or labels into the format used internally.

        Args:
            data: The data (input data or labels) to be standardized
            classifier_input_size: Size of one-hot vectors; must be specified when input is integer ids
            device: Device of tensors; must be specified when input is list
            verify_input_tensor: True if data is input data (not labels)

        Returns:
            The data in a standard format
        """
        if type(data) is list and type(data[0]) is int:
            data = torch.tensor(data, device=device, dtype=torch.long)

        if type(data) is list and type(data[0]) is torch.Tensor:
            data = torch.stack(data)

        if verify_input_tensor and data.dim(
        ) != 2 and classifier_input_size is None:
            raise ValueError(
                'input tensor is expected to have 2D shape [n_samples, data_length], view it appropriately'
            )

        if classifier_input_size is not None:
            if data.dim() != 1:
                raise ValueError(
                    'in case classifier_input_size is not None, the shape should be 1D [n_samples]'
                )
            data = id_to_one_hot(data, vector_len=classifier_input_size)

        if torch.isnan(data).any():
            logger.error(f'data is containing NaNs')

        return data
Exemplo n.º 15
0
 def argmin(inputs: List[torch.Tensor], outputs: List[torch.Tensor]):
     outputs[0].copy_(id_to_one_hot(inputs[0].argmin(), num_predictors))