def __init__(self, filters, shape, kernel_size, stride=1, name=None, initializer=Normal(loc=0, scale=0.01)): super(Conv2D, self).__init__(shape=shape, name=name) self.initializer = initializer self.trainable = True assert len(shape) == 3 # (image_height, image_width, num_channels) self.input_size = shape assert len(kernel_size) == 2 # (kernel_height, kernel_width) self.kernel_size = kernel_size self.nb_filters = filters self.stride = stride # TODO: not used self.weights = self.initializer( (self.nb_filters, self.input_size[-1], self.kernel_size[0], self.kernel_size[1])) self.bias = Zeros()(self.nb_filters) self.weights_grad = Zeros()(shape=self.weights.shape) self.bias_grad = Zeros()(shape=self.bias.shape)
def forward(self, x): self.last_input = x assert len( x.shape) == 4 # (batch, channels, image_height, image_width) nb_batches = x.shape[0] img_height, img_width = x.shape[1:3] output_height = (img_height - self.kernel_size[0]) // self.stride + 1 output_width = (img_width - self.kernel_size[1]) // self.stride + 1 output = Zeros()(shape=(nb_batches, output_height, output_width, self.nb_filters)) kernel_height, kernel_width = self.kernel_size for batch in np.arange(nb_batches): for filter in np.arange(self.nb_filters): for h in np.arange(img_height - kernel_height): for w in np.arange(img_width - kernel_width): patch = x[batch, h:h + kernel_height, w:w + kernel_width, :] output[batch, h, w, filter] = np.sum(patch * self.weights[filter] + self.bias[filter]) return output
def backward(self, prev_delta): kernel_height, kernel_width = self.kernel_size nb_batch, input_img_height, input_img_width, nb_input_channels = self.last_input.shape for filter in np.arange(self.nb_filters): for input_channel in np.arange(nb_input_channels): for h in np.arange(kernel_height): for w in np.arange(kernel_width): patch = self.last_input[:, h:h + input_img_height - kernel_height + 1, w:w + input_img_width - kernel_width + 1, input_channel] grad_window = prev_delta[..., filter] self.weights_grad[filter, input_channel, h, w] = np.sum( patch * grad_window) / nb_batch for filter in np.arange(self.nb_filters): self.bias_grad[filter] = np.sum(prev_delta[..., filter]) / nb_batch kernel_grads = Zeros()(shape=self.last_input.shape) for batch in np.arange(nb_batch): for filter in np.arange(self.nb_filters): for input_channel in np.arange(nb_input_channels): for h in np.arange(input_img_height - kernel_height): for w in np.arange(input_img_width - kernel_width): kernel_grads[ batch, h:h + kernel_height, w:w + kernel_width, input_channel] += self.weights[ filter, input_channel] * prev_delta[batch, h, w, filter] return kernel_grads
def __init__(self, num_in, num_out, w_init=XavierUniform(), b_init=Zeros()): super().__init__('Dense') self.params = { "w": w_init([num_in, num_out]), "b": b_init([1, num_out]) } self.inputs = None
def __init__(self, shape, name=None, initializer=Normal(loc=0, scale=0.01)): super(Dense, self).__init__(shape=shape, name=name) self.initializer = initializer self.trainable = True self.weights = self.initializer(shape) self.bias = Zeros()(self.weights.shape[-1]) self.weights_grad = None self.bias_grad = None
def __init__(self, num_out, num_in=None, w_init=XavierUniform(), b_init=Zeros()): super().__init__("Linear") self.initializers = {"w": w_init, "b": b_init} self.shapes = {"w": [num_in, num_out], "b": [num_out]} self.params = {"w": None, "b": None} self.is_init = False if num_in is not None: self._init_parameters(num_in) self.inputs = None
def backward(self, prev_delta): nb_batch, input_img_height, input_img_width, nb_input_channels = self.last_input.shape pool_height, pool_width = self.shape grads = Zeros()(self.last_input.shape) for batch in np.arange(nb_batch): for channel in np.arange(nb_input_channels): for h in np.arange(input_img_height, step=pool_height): for w in np.arange(input_img_width, step=pool_width): patch = self.last_input[batch, h:h + pool_height, w:w + pool_width, channel] if patch.sum() <= 0.: continue h_shift, w_shift = np.unravel_index( patch.argmax(), patch.shape) grads[batch, h + h_shift, w + w_shift, channel] = prev_delta[batch, h // pool_height, w // pool_width, channel] return grads
def forward(self, x): self.last_input = x nb_batch, input_img_height, input_img_width, nb_input_channels = self.last_input.shape pool_height, pool_width = self.shape output_height = input_img_height // pool_height output_width = input_img_width // pool_width output = Zeros()( (nb_batch, output_height, output_width, nb_input_channels)) for batch in np.arange(nb_batch): for channel in np.arange(nb_input_channels): for h in np.arange(input_img_height, step=pool_height): for w in np.arange(input_img_width, step=pool_width): output[batch, h // pool_height, w // pool_width, channel] = np.max(x[batch, h:h + pool_height, w:w + pool_width, channel]) return output
def __init__(self, kernel, stride=(1, 1), padding="SAME", w_init=XavierUniform(), b_init=Zeros()): super().__init__("Conv2D") # verify arguments assert len(kernel) == 4 assert len(stride) == 2 assert padding in ("SAME", "VALID") self.kernel_shape = kernel self.stride = stride self.initializers = {"w": w_init, "b": b_init} # calculate padding needed for this layer self.pad = self._get_padding(kernel[:2], padding) self.is_init = False