Beispiel #1
0
    def forward(self, X: Variable):
        """
        :param X: X is a 4d tensor, [batch, channel, row, col]
        # TODO add channel in different places
        :return:
        """
        # print("starting convolution.")

        def idx_three2one(idx, shape):
            new_idx = idx[0] * np.prod(shape[1:]) + idx[1] * shape[2] + idx[2]
            return new_idx

        # Notice that we only need to calculate mapping once for all epochs
        if self.initialize:
            self.n, self.in_channel, self.x, self.y = X.shape

            # We first calculate the new matrix size.
            self.x_new = int((self.x - self.kernel_size[0] + 2 * self.padding[0]) / self.stride[0] + 1)
            self.y_new = int((self.y - self.kernel_size[1] + 2 * self.padding[1]) / self.stride[1] + 1)

            self.old_length = self.in_channel * self.x * self.y
            self.new_length = self.out_channel * self.x_new * self.y_new

            # The thing about mapping is that we have to calculate the mapping during each iteration,
            # Because w has changed within each iteration
            # On the other hand, we have to keep w changing at the same time.
            # We only need to initialize b once, with the knowledge of xnew and ynew
            # Initialize the kernel
            self.w = Variable(np.random.normal(0, 0.01, (self.out_channel, self.in_channel,
                                                      self.kernel_size[0], self.kernel_size[1])),
                              trainable=self.trainable)

            self.b = Variable(np.random.normal(0, 0.01, (1, self.out_channel, self.x_new, self.y_new)),
                              trainable=self.trainable, param_share=True)

            '''
            Now we create a w2mapping, the mapping itself we only need it once for all. 
            After we know the mapping, we can easily do the back-prop and forward-prop each time.
            '''
            self.w2mapping = []

            # Logic 1, without sorting
            for filter_idx in range(self.out_channel):
                for i in range(self.x_new):
                    for j in range(self.y_new):
                        # Index for new matrix
                        mapping_new = idx_three2one((filter_idx, i, j),
                                                    (self.out_channel, self.x_new, self.y_new))
                        x_start = int(i * self.stride[0])
                        y_start = int(j * self.stride[1])
                        for ix in range(self.kernel_size[0]):
                            for jx in range(self.kernel_size[1]):
                                for channel_idx in range(self.in_channel):
                                    # Index for old matrix
                                    mapping_old = idx_three2one((channel_idx, x_start + ix, y_start + jx),
                                                                (self.in_channel, self.x, self.y))
                                    # We have to record, which one in the mapping matrix is from which w
                                    self.w2mapping.append([(filter_idx, channel_idx, ix, jx),
                                                                   (mapping_old, mapping_new)])

            self.initialize = False
        # End Initialize

        input_image_flattened = X.reshape((self.n, self.old_length))

        new_image_flattened = input_image_flattened.sparse_dot_with_mapping(self.w, self.w2mapping,
                                                                            self.old_length,
                                                                            self.new_length)

        output = new_image_flattened.reshape((self.n, self.out_channel,
                                              self.x_new, self.y_new))

        # Add bias if necessary
        if self.bias:
            output1 = output + self.b
            return output1

        return output
Beispiel #2
0
 def forward(self, X: Variable):
     self.n, self.c, self.x, self.y = X.shape
     output = X.reshape((self.n, self.c * self.x * self.y))
     return output