-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathconv_layer.py
More file actions
121 lines (96 loc) · 4.46 KB
/
Copy pathconv_layer.py
File metadata and controls
121 lines (96 loc) · 4.46 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import numpy as np
from utils import im2col_conv, col2im_conv, im2col_conv_batch
def conv_layer_forward(input_data, layer, param):
"""
Forward pass for a convolutional layer.
Parameters:
- input_data (dict): A dictionary containing the input data.
- layer (dict): Layer configuration containing parameters such as kernel size, padding, stride, etc.
- param (dict): A dictionary containing the parameters 'b' and 'w'.
"""
h_in = input_data['height']
w_in = input_data['width']
c = input_data['channel']
batch_size = input_data['batch_size']
k = layer['k']
pad = layer['pad']
stride = layer['stride']
num = layer['num']
# resolve output shape
h_out = (h_in + 2*pad - k) // stride + 1
w_out = (w_in + 2*pad - k) // stride + 1
assert h_out == int(h_out), 'h_out is not integer'
assert w_out == int(w_out), 'w_out is not integer'
input_n = {
'height': h_in,
'width': w_in,
'channel': c,
'data': input_data['data'],
'batch_size': batch_size
}
output = {
'height': h_out,
'width': w_out,
'channel': num,
'batch_size': batch_size,
'data': np.zeros((h_out, w_out, num, batch_size)) # replace 'data' value with your implementation
}
############# Fill in the code here ###############
# Hint: use im2col_conv_batch for faster computation
# Convert the input data to its column form for batched computation.
input_data_columns = im2col_conv_batch(input_data, layer, h_out, w_out)
# Perform convolution
# convolved_output_columns = np.dot(param['w'].T, input_data_columns) + param['b'].reshape(-1, 1, 1)
# Perform convolution
convolved_output_columns = np.zeros((num, h_out * w_out, batch_size))
for i in range(h_out * w_out):
for j in range(batch_size):
# the dot product of each kernel
convolved_output_columns[:, i, j] = np.dot(param['w'].T, input_data_columns[:, i, j]) + param['b']
# Reshape output
matrix_output = convolved_output_columns.reshape(num, h_out, w_out, batch_size).transpose(2, 1, 0, 3)
output['data'] = np.reshape(matrix_output, (h_out * w_out * num, batch_size), order='F')
return output
def conv_layer_backward(output, input_data, layer, param):
"""
Compute the backward pass for the convolution layer.
Parameters:
- output (dict): A dictionary containing the output of the forward pass.
- input_data (dict): A dictionary containing the original input to the forward function.
- layer (dict): Layer configuration containing parameters such as kernel size, padding, stride, etc.
- param (dict): A dictionary containing the parameters 'b' and 'w'.
Returns:
- param_grad (dict): A dictionary containing the gradients with respect to the parameters 'b' and 'w'.
- input_od (numpy.ndarray): The gradients with respect to the input.
"""
h_in = input_data['height']
w_in = input_data['width']
c = input_data['channel']
batch_size = input_data['batch_size']
k = layer['k']
group = layer['group']
num = layer['num']
h_out = output['height']
w_out = output['width']
input_n = {'height': h_in, 'width': w_in, 'channel': c}
input_od = np.zeros(input_data['data'].shape)
param_grad = {'b': np.zeros(param['b'].shape), 'w': np.zeros(param['w'].shape)}
for n in range(batch_size):
input_n['data'] = input_data['data'][:, n]
col = im2col_conv(input_n, layer, h_out, w_out)
col = np.reshape(col, (k*k*c, h_out*w_out), order='F')
col_diff = np.zeros(col.shape)
temp_data_diff = np.reshape(output['diff'][:, n], (h_out*w_out, num), order='F')
for g in range(group):
g_c_idx = slice(g*k*k*c//group, (g+1)*k*k*c//group)
g_num_idx = slice(g*num//group, (g+1)*num//group)
col_g = col[g_c_idx, :]
weight = param['w'][:, g_num_idx]
# get the gradient of param
param_grad['b'][:, g_num_idx] += np.sum(temp_data_diff[:, g_num_idx], axis=0)
param_grad['w'][:, g_num_idx] += col_g.dot(temp_data_diff[:, g_num_idx])
col_diff[g_c_idx, :] = weight.dot(temp_data_diff[:, g_num_idx].T)
im = col2im_conv(col_diff.ravel(order='F'), input_data, layer, h_out, w_out)
# set the gradient w.r.t to input.data
input_od[:, n] = im.ravel(order='F')
return param_grad, input_od