Is there a way to obtain the same results of numpy function with tensorflow tensors?

103 Views Asked by At

I want to create a custom keras layer that compute the "predict" of a Self Organizing Map. Here is my implementation of the layer `

class SOMLayer(keras.layers.Layer):
    def __init__(self, X_train, y_train, w, n=50, input_shape=265):
        super(SOMLayer, self).__init__()
        self.inputs = None
        self.X_train = X_train
        self.y_train = y_train
        self._input_len = input_shape

        # weights of pre-trained SOM, two versions: _weights is a tensor, _weights_nc is a numpy array
        self._weights = tf.convert_to_tensor(w, dtype=tf.float32)
        self._weights_nc = w

        self._activation_map = zeros((n, n))

        # activation distance calc., lblmap version works with numpy arrays, the other one with tf tensors
        self._activation_distance = self._manhattan_distance
        self._activation_distance_lblmap = self._manhattan_distance_lblmap

        self.winmap = self.labels_map(X_train, y_train)

        self.default_class = sum(list(self.winmap.values())).most_common()[0][0]

    @tf.function
    def call(self, inputs):
        ret_arr = np.array(np.full(6, 0.01), ndmin=2)
        win_position = self.winner(inputs)
        if win_position.ref() in self.winmap:
            ret_arr[0][self.winmap[win_position.ref()].most_common()[0][0]] = 0.95

        else:
            ret_arr[0][self.default_class] = 0.95
        return ret_arr

    def _activate(self, x):
        """Updates matrix activation_map, in this matrix
           the element i,j is the response of the neuron i,j to x."""
        self._activation_map = self._activation_distance(x, self._weights)

    def _activate_lblmap(self, x):
        """Updates matrix activation_map, in this matrix
           the element i,j is the response of the neuron i,j to x."""
        self._activation_map = self._activation_distance_lblmap(x, self._weights_nc)

    def _manhattan_distance(self, x, w):
        return tf.linalg.norm(tf.subtract(x, w), ord=1, axis=-1)

    def _manhattan_distance_lblmap(self, x, w):
        return linalg.norm(subtract(x, w), ord=1, axis=-1)

    def _check_input_len(self, data):
        """Checks that the data in input is of the correct shape."""
        data_len = len(data[0])
        if self._input_len != data_len:
            msg = 'Received %d features, expected %d.' % (data_len,
                                                          self._input_len)
            raise ValueError(msg)

    @tf.function
    def winner(self, x):
        """Computes the coordinates of the winning neuron for the sample x."""
        self._activate(x)
        return tf.unravel_index(tf.argmin(self._activation_map, output_type=tf.int32),
                                tf.shape(self._activation_map))

    def winner_lblmap(self, x):
        """Computes the coordinates of the winning neuron for the sample x."""
        self._activate_lblmap(x)
        return unravel_index(self._activation_map.argmin(),
                             self._activation_map.shape)

    def labels_map(self, data, labels):
        """Returns a dictionary wm where wm[(i,j)] is a dictionary
        that contains the number of samples from a given label
        that have been mapped in position i,j.

        Parameters
        ----------
        data : np.array or list
            Data matrix.

        label : np.array or list
            Labels for each sample in data.
        """
        self._check_input_len(data)
        if not len(data) == len(labels):
            raise ValueError('data and labels must have the same length.')
        winmap = defaultdict(list)
        for x, l in zip(data, labels):
            winmap[self.winner_lblmap(x)].append(l)
        for position in winmap:
            winmap[position] = Counter(winmap[position])
        return winmap

` There are two implementation of the same method for methods like "activate", "manhattan_distance" and "winner".

The implementation with "_lblmap" in the name works with numpy arrays (is the impl. of the minisom python library) and the other impl. uses tensorflow tensors because the input of the layer when the model execute is a tensor and i was not able to convert that tensor in a numpy array.

The problem is in the "winner" method, the winner method that works with numpy array return this:

self.winner_lblmap numpy array implementation
(0, 2)

that is the position (like x,y coordinates) of the Best Matching Unit that will determine the class of the input, and its called inside "labels_map" method.

The winner method called inside "call" method works with tensorflow tensors because it will manage the input passed when you use model.predict(...) and this input is a tensor. The output of this implementation is:

self.winner tensorflow tensors implementation
Tensor("UnravelIndex:0", shape=(2, 50), dtype=int32)

And looking the shape it's easy to see that is not the correct shape of the desired output, and also i'm not able to directly access the data inside this tensor (or previuos calculated ones).

I tried to force "eager evaluation" in different ways to try to visualize the data but without success. I tried also to tune the "tf.linalg.norm" parameters but the shape of the result is (0,).

Is there a way to access the data inside the tensor and obtain tha same result of the "winner_lblmap" method that works with numpy arrays?

0

There are 0 best solutions below