예제 #1
0
class RNNAutoencoder:
    def __init__(self, vac_size: int, hidden_sizes: Tuple[int, int],
                 seq_size: int):
        """
        Class implements RNNAutoencoder.

        Architecture of RNNAutoencoder have 2 lstm layers in encoder and
        2 lstm layers with linear layer in decoder

        :param vac_size: int
        :param hidden_sizes: Tuple[int, int]
        :param seq_size: int
        """

        self.vac_size = vac_size
        self.hidden_size_1 = hidden_sizes[0]
        self.hidden_size_2 = hidden_sizes[1]
        self.seq_size = seq_size

        #Encode
        self.lstm1 = LSTMCell(vac_size=self.vac_size,
                              hidden_size=self.hidden_size_1,
                              return_seq=True)
        self.lstm2 = LSTMCell(vac_size=self.hidden_size_1,
                              hidden_size=self.hidden_size_2,
                              return_seq=False)

        self.repeat = RepeatVector(self.seq_size)

        #Decode
        self.lstm3 = LSTMCell(self.hidden_size_2,
                              self.hidden_size_1,
                              return_seq=True)
        self.lstm4 = LSTMCell(self.hidden_size_1,
                              self.vac_size,
                              return_seq=True)

        self.linear = Linear(self.vac_size, self.vac_size)

    def params(self):
        """
        returns parameters of all model

        :return: dict
        """
        return {
            'lstm1': self.lstm1.params(),
            'lstm2': self.lstm2.params(),
            'lstm3': self.lstm3.params(),
            'lstm4': self.lstm4.params(),
            'linear': self.linear.params()
        }

    def clear_gradients(self):
        """
        function which clears gradients
        :return:
        """
        self.lstm1.clear_gradients()
        self.lstm2.clear_gradients()
        self.lstm3.clear_gradients()
        self.lstm4.clear_gradients()
        self.linear.clear_gradients()

    def forward(self, X: np.ndarray):
        """
        forward pass through the model

        :param X: np.ndarray
        :return: predictions of model
        """
        self.clear_gradients()

        encode = self.lstm2.forward(self.lstm1.forward(X))
        bridge = self.repeat.forward(encode)
        decode = self.lstm4.forward(self.lstm3.forward(bridge))

        decode = decode.reshape(decode.shape[0], decode.shape[1])

        pred = self.linear.forward(decode)

        return pred

    def compute_loss_and_gradient(self, X: np.ndarray, y: np.ndarray):
        """
        function which implement forward pass and calculation of loss and its derivative

        :param X: not-sorted one-hot array (seq_size, vac_size, 1)
        :param y: sorted sequence (seq_size, )
        :return: loss and its derivative
        """
        pred = self.forward(X)
        loss, dpredication = softmax_cross_entropy(pred, y)
        return loss, dpredication

    def repeat_backward(self, x: np.ndarray):
        """
        function which repeat vector for backward pass

        :param x: np.ndarray size (vac_size, 1)
        :return: d_out :np.ndarray size(seq_size, vac_size, 1)
        """
        d_out = np.zeros((self.seq_size, *x.shape))
        d_out[-1] = x
        return d_out

    def backward(self, d_out: np.ndarray):
        """
        backward pass through model

        :param d_out: derivative of loss
        :return:
        """
        d_l = self.linear.backward(d_out)
        d_l = d_l.reshape(*d_l.shape, 1)

        d_l = self.lstm3.backward(self.lstm4.backward(d_l))

        bridge = self.repeat_backward(self.repeat.backward(d_l))

        d_x = self.lstm1.backward(self.lstm2.backward(bridge))

        return d_x

    def predict(self, X: np.ndarray):
        """
        predict answer of the model
        :param X:
        :return:
        """
        pred = self.forward(X)
        probs = softmax(pred)
        return np.argmax(probs, axis=1)