def output_shape(self): pad_height, pad_width = get_pad(self.padding, self.input_shape[1], self.input_shape[2], self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) # alternate formula: [((W - KernelW + 2P) / Sw) + 1] and [((H - KernelH + 2P) / Sh) + 1] # output_height = ((self.input_shape[1] - self.kernel_size[0] + np.sum(pad_height)) / self.strides[0]) + 1 # output_width = ((self.input_shape[2] - self.kernel_size[1] + np.sum(pad_width)) / self.strides[1]) + 1 if self.padding == 'same': output_height = np.ceil( np.float32(self.input_shape[1]) / np.float32(self.strides[0])) output_width = np.ceil( np.float32(self.input_shape[2]) / np.float32(self.strides[1])) if self.padding == 'valid': output_height = np.ceil( np.float32(self.input_shape[1] - self.kernel_size[0] + 1) / np.float32(self.strides[0])) output_width = np.ceil( np.float32(self.input_shape[2] - self.kernel_size[1] + 1) / np.float32(self.strides[1])) return self.filters, int(output_height), int(output_width)
def output_shape(self): input_channels, input_height, input_width = self.input_shape self.pad_height, self.pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.pool_size[0], self.pool_size[1]) # alternate formula: [((W - PoolW + 2P) / Sw) + 1] and [((H - PoolH + 2P) / Sh) + 1] # out_height = ((input_height - self.pool_size[0] + np.sum(self.pad_height)) / self.strides[0]) + 1 # out_width = ((input_width - self.pool_size[1] + np.sum(self.pad_width)) / self.strides[1]) + 1 if self.padding == 'same': out_height = np.ceil( np.float32(input_height) / np.float32(self.strides[0])) out_width = np.ceil( np.float32(input_width) / np.float32(self.strides[1])) if self.padding == 'valid': out_height = np.ceil( np.float32(input_height - self.pool_size[0] + 1) / np.float32(self.strides[0])) out_width = np.ceil( np.float32(input_width - self.pool_size[1] + 1) / np.float32(self.strides[1])) assert out_height % 1 == 0 assert out_width % 1 == 0 return input_channels, int(out_height), int(out_width)
def pass_forward(self, inputs, train_mode=True, **kwargs): self.filter_num, _, _, _ = self.weights.shape input_num, input_depth, input_height, input_width = inputs.shape self.input_shape = inputs.shape self.inputs = inputs pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) x_padded = np.pad(self.inputs, ((0, 0), (0, 0), pad_height, pad_width), mode='constant') # confirm dimensions assert (input_height + np.sum(pad_height) - self.kernel_size[0] ) % self.strides[0] == 0, 'height does not work' assert (input_width + np.sum(pad_width) - self.kernel_size[1] ) % self.strides[1] == 0, 'width does not work' # alternate formula: [((W - KernelW + 2P) / Sw) + 1] and [((H - KernelH + 2P) / Sh) + 1] # output_height = (input_height - self.kernel_size[0] + np.sum(pad_height)) / self.strides[0] + 1 # output_width = (input_width - self.kernel_size[1] + np.sum(pad_width)) / self.strides[1] + 1 if self.padding == 'same': output_height = np.ceil( np.float32(input_height) / np.float32(self.strides[0])) output_width = np.ceil( np.float32(input_width) / np.float32(self.strides[1])) if self.padding == 'valid': output_height = np.ceil( np.float32(input_height - self.kernel_size[0] + 1) / np.float32(self.strides[0])) output_width = np.ceil( np.float32(input_width - self.kernel_size[1] + 1) / np.float32(self.strides[1])) output = np.zeros( (input_num, self.filter_num, output_height, output_width)) # convolutions for b in np.arange(input_num): # batch number for f in np.arange(self.filter_num): # filter number for h in np.arange(output_height): # output height for w in np.arange(output_width): # output width h_stride, w_stride = h * self.strides[ 0], w * self.strides[1] x_patch = x_padded[b, :, h_stride:h_stride + self.kernel_size[0], w_stride:w_stride + self.kernel_size[1]] output[b, f, h, w] = np.sum( x_patch * self.weights[f]) + self.bias[f] return output
def output_shape(self): pad_height, pad_width = get_pad(self.padding, self.input_shape[1], self.input_shape[2], self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) output_height, output_width = get_output_dims(self.input_shape[1], self.input_shape[2], self.kernel_size, self.strides, self.padding) return self.filters, int(output_height), int(output_width)
def pass_forward(self, inputs, train_mode=True, **kwargs): self.filter_num, _, _, _ = self.weights.shape input_num, input_depth, input_height, input_width = inputs.shape self.input_shape = inputs.shape self.inputs = inputs pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) # confirm dimensions assert (input_height + np.sum(pad_height) - self.kernel_size[0] ) % self.strides[0] == 0, 'height does not work' assert (input_width + np.sum(pad_width) - self.kernel_size[1] ) % self.strides[1] == 0, 'width does not work' # alternate formula: [((W - KernelW + 2P) / Sw) + 1] and [((H - KernelH + 2P) / Sh) + 1] # output_height = ((input_height - self.kernel_size[0] + np.sum(pad_height)) / self.strides[0]) + 1 # output_width = ((input_width - self.kernel_size[1] + np.sum(pad_width)) / self.strides[1]) + 1 if self.padding == 'same': output_height = np.ceil( np.float32(input_height) / np.float32(self.strides[0])) output_width = np.ceil( np.float32(input_width) / np.float32(self.strides[1])) if self.padding == 'valid': output_height = np.ceil( np.float32(input_height - self.kernel_size[0] + 1) / np.float32(self.strides[0])) output_width = np.ceil( np.float32(input_width - self.kernel_size[1] + 1) / np.float32(self.strides[1])) # convert to columns self.input_col = im2col_indices(inputs, self.kernel_size[0], self.kernel_size[1], padding=(pad_height, pad_width), stride=1) self.weight_col = self.weights.reshape(self.filter_num, -1) # calculate ouput output = self.weight_col @ self.input_col + self.bias output = output.reshape(self.filter_num, int(output_height), int(output_width), input_num) return output.transpose(3, 0, 1, 2)
def pass_forward(self, inputs, train_mode=True, **kwargs): self.filter_num, _, _, _ = self.weights.shape self.input_shape = inputs.shape self.inputs = inputs input_num, input_depth, input_height, input_width = inputs.shape pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) x_padded = np.pad(self.inputs, ((0, 0), (0, 0), pad_height, pad_width), mode='constant') # confirm dimensions assert (input_height + np.sum(pad_height) - self.kernel_size[0] ) % self.strides[0] == 0, 'height does not work' assert (input_width + np.sum(pad_width) - self.kernel_size[1] ) % self.strides[1] == 0, 'width does not work' # compute output_height and output_width output_height, output_width = get_output_dims(input_height, input_width, self.kernel_size, self.strides, self.padding) output = np.zeros( (input_num, self.filter_num, output_height, output_width)) self.input_col = unroll_inputs(x_padded, x_padded.shape[0], x_padded.shape[1], output_height, output_width, self.kernel_size[0]) # TODO: weights need to be rearraged in a way to have a matrix # multiplication with the generated toeplitz matrix self.weight_col = self.weights.reshape(self.filter_num, -1) # calculate ouput output = self.weight_col @ self.input_col + self.bias # output = np.matmul(self.weight_col, self.input_col) + self.bias output = output.reshape(self.filter_num, int(output_height), int(output_width), input_num) return output.transpose(3, 0, 1, 2)
def pass_forward(self, inputs, train_mode=True, **kwargs): self.filter_num, _, _, _ = self.weights.shape self.input_shape = inputs.shape self.inputs = inputs input_num, input_depth, input_height, input_width = inputs.shape pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) x_padded = np.pad(self.inputs, ((0, 0), (0, 0), pad_height, pad_width), mode='constant') # confirm dimensions assert (input_height + np.sum(pad_height) - self.kernel_size[0] ) % self.strides[0] == 0, 'height does not work' assert (input_width + np.sum(pad_width) - self.kernel_size[1] ) % self.strides[1] == 0, 'width does not work' # compute output_height and output_width output_height, output_width = get_output_dims(input_height, input_width, self.kernel_size, self.strides, self.padding) output = np.zeros( (input_num, self.filter_num, output_height, output_width)) # convolutions for b in np.arange(input_num): # batch number for f in np.arange(self.filter_num): # filter number for h in np.arange(output_height): # output height for w in np.arange(output_width): # output width h_stride, w_stride = h * self.strides[ 0], w * self.strides[1] x_patch = x_padded[b, :, h_stride:h_stride + self.kernel_size[0], w_stride:w_stride + self.kernel_size[1]] output[b, f, h, w] = np.sum( x_patch * self.weights[f]) + self.bias[f] return output
def output_shape(self): input_channels, input_height, input_width = self.input_shape self.pad_height, self.pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.pool_size[0], self.pool_size[1]) output_height, output_width = get_output_dims(input_height, input_width, self.pool_size, self.strides, self.padding) assert output_height % 1 == 0 assert output_width % 1 == 0 return input_channels, int(output_height), int(output_width)
def pass_forward(self, inputs, train_mode=True, **kwargs): self.filter_num, _, _, _ = self.weights.shape self.input_shape = inputs.shape self.inputs = inputs input_num, input_depth, input_height, input_width = inputs.shape pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) # confirm dimensions assert (input_height + np.sum(pad_height) - self.kernel_size[0] ) % self.strides[0] == 0, 'height does not work' assert (input_width + np.sum(pad_width) - self.kernel_size[1] ) % self.strides[1] == 0, 'width does not work' # compute output_height and output_width output_height, output_width = get_output_dims(input_height, input_width, self.kernel_size, self.strides, self.padding) # convert to columns self.input_col = im2col_indices(inputs, self.kernel_size[0], self.kernel_size[1], padding=(pad_height, pad_width), stride=1) self.weight_col = self.weights.reshape(self.filter_num, -1) # calculate ouput output = self.weight_col @ self.input_col + self.bias output = output.reshape(self.filter_num, int(output_height), int(output_width), input_num) return output.transpose(3, 0, 1, 2)
def pass_backward(self, grad): input_num, input_depth, input_height, input_width = self.input_shape if self.is_trainable: dbias = np.sum(grad, axis=(0, 2, 3)) dbias = dbias.reshape(self.filter_num, -1) doutput_reshaped = grad.transpose(1, 2, 3, 0).reshape(self.filter_num, -1) dweights = doutput_reshaped @ self.input_col.T dweights = dweights.reshape(self.weights.shape) # optimize the weights and bias self.weights = optimizer(self.weight_optimizer).update( self.weights, dweights) self.bias = optimizer(self.weight_optimizer).update( self.bias, dbias) # endif self.is_trainable weight_reshape = self.weights.reshape(self.filter_num, -1) dinput_col = weight_reshape.T @ doutput_reshaped pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) dinputs = col2im_indices(dinput_col, self.input_shape, self.kernel_size[0], self.kernel_size[1], padding=(pad_height, pad_width), stride=self.strides[0]) return dinputs
def pass_backward(self, grad): input_num, input_depth, input_height, input_width = self.inputs.shape # initialize the gradient(s) dinputs = np.zeros(self.inputs.shape) if self.is_trainable: # initialize the gradient(s) dweights = np.zeros(self.weights.shape) dbias = np.zeros(self.bias.shape) pad_height, pad_width = get_pad(self.padding, input_height, input_width, self.strides[0], self.strides[1], self.kernel_size[0], self.kernel_size[1]) pad_size = np.sum(pad_height) / 2 if pad_size != 0: grad = grad[:, :, pad_size:-pad_size, pad_size:-pad_size] # dweights for f in np.arange(self.filter_num): # filter number for c in np.arange(input_depth): # input depth (channels) for h in np.arange(self.kernel_size[0]): # kernel height for w in np.arange( self.kernel_size[1]): # kernel width input_patch = self.inputs[:, c, h:input_height - self.kernel_size[0] + h + 1:self.strides[0], w:input_width - self.kernel_size[1] + w + 1:self.strides[1]] grad_patch = grad[:, f] dweights[f, c, h, w] = np.sum( input_patch * grad_patch) / input_num # dbias for f in np.arange(self.filter_num): # filter number dbias[f] = np.sum(grad[:, f]) / input_num # optimize the weights and bias self.weights = optimizer(self.weight_optimizer).update( self.weights, dweights) self.bias = optimizer(self.weight_optimizer).update( self.bias, dbias) # endif self.is_trainable # dinputs for b in np.arange(input_num): # batch number for f in np.arange(self.filter_num): # filter number for c in np.arange(input_depth): # input depth (channels) for h in np.arange(self.kernel_size[0]): # kernel height for w in np.arange( self.kernel_size[1]): # kernel width h_stride, w_stride = h * self.strides[ 0], w * self.strides[1] dinputs[b, c, h_stride:h_stride + self.kernel_size[0], w_stride:w_stride + self.kernel_size[1]] += self.weights[ f, c] * grad[b, f, h, w] return dinputs