Skip to content

Commit fbbad68

Browse files
committed
droupout, AveragePool, Bug fix
1 parent 69784fd commit fbbad68

9 files changed

Lines changed: 129 additions & 142 deletions

File tree

README.md

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ This is Convolutional Neural Network only in python & numpy. It is simple and sl
1010

1111
**Regulization :** Droupout(only on fc), L2
1212

13+
**Pooling :** Max, Average
14+
1315
**Loss Function :** Softmax, Logistic
1416

1517
## Prerequisites
@@ -22,62 +24,54 @@ AND gate and CIFAR-10 examples are included.
2224

2325
```python
2426

25-
from classes.neural_net import NeuralNetwork
26-
2727
lr = 1e-4
28-
l2_reg = 5e-6
29-
30-
# 32 * 32 color image
31-
input_size = (3,32,32)
28+
l2_reg = 8e-6
3229

33-
cnn = NeuralNetwork(input_size,
30+
cnn = NeuralNetwork(train_images.shape[1:],
3431
[
3532
{'type': 'conv', 'k': 16, 'u_type': 'nag', 'f': 5, 's': 1, 'p': 2},
36-
{'type': 'pool'},
33+
{'type': 'pool', 'method': 'average'},
3734
{'type': 'conv', 'k': 20, 'u_type': 'nag', 'f': 5, 's': 1, 'p': 2},
38-
{'type': 'pool'},
35+
{'type': 'pool', 'method': 'average'},
3936
{'type': 'conv', 'k': 20, 'u_type': 'nag', 'f': 5, 's': 1, 'p': 2},
40-
{'type': 'pool'},
37+
{'type': 'pool', 'method': 'average'},
4138
{'type': 'output', 'k': len(le.classes_), 'u_type': 'adam'}
4239
]
4340
, lr, l2_reg=l2_reg)
4441

45-
46-
for i in range(600000):
47-
loss, acc = cnn.epoch(train_images, train_labels)
48-
test_loss, test_acc = cnn.predict(train_images, train_labels)
49-
5042
```
5143

5244
CIFAR-10 example gets ~72% test accuracy in 20 epoch.
5345

5446

5547
## API Reference
5648
```python
57-
classes.NeuralNetwork(input_shape, layer_list, lr, l2_reg=0, dropout_p=1, loss='softmax'):
49+
classes.NeuralNetwork(self, input_shape, layer_list, lr, l2_reg=0, loss='softmax'):
5850
```
59-
51+
<br />
6052

6153
| Parameter | Description |
6254
| --- | --- |
6355
| input_shape | Data's numpy shape. |
6456
| layer_list | List of layers you want to be networked. All of properties goes to **kwargs. |
6557
| lr | Learning rate. |
66-
| l2_reg | L2 regularization lambda. |
67-
| drouput_p | Dropout rate. 0 < dropout_p <= 1
58+
| l2_reg | L2 regularization|
6859
| loss | Loss function. 'softmax', 'logistic' |
6960

7061

7162
```python
7263
# type fc, output
73-
classes.NeuralLayer(input_size, k, u_type='adam', a_type='relu')
64+
classes.NeuralLayer(input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu', dropout=1)
7465

7566
# type pool
76-
classes.PoolLayer(input_size, f=2, s=2)
67+
classes.PoolLayer(input_size, f=2, s=2, method='max', dropout=1):
7768

7869
# type conv
79-
classes.ConvLayer(input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu')
70+
classes.ConvLayer(input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu', dropout=1)
8071
```
72+
<br />
73+
74+
8175

8276
| Update Policy | u_type|
8377
| --- | --- |
@@ -92,6 +86,10 @@ classes.ConvLayer(input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu')
9286
| ReLU | 'relu' |
9387
| Sigmoid | 'sigmoid' |
9488

89+
| Pooling |method|
90+
| --- | --- |
91+
| Max |'max' |
92+
|Avverage |'average'|
9593

9694
## License
9795
MIT

classes/conv_layer.py

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55

66
class ConvLayer(NeuralLayer):
77

8-
def __init__(self, input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu'):
8+
def __init__(self, input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu', dropout=1):
99
self.image_size = 0
1010
self.w = input_size[2]
1111
self.h = input_size[1]
@@ -20,7 +20,7 @@ def __init__(self, input_size, k, f=3, s=1, p=1, u_type='adam', a_type='relu'):
2020
self.h2 = int((self.h - self.f + 2 * self.p) / self.s + 1)
2121
self.d2 = k
2222

23-
super(ConvLayer, self).__init__(f*f*self.d, k, u_type=u_type, a_type=a_type)
23+
super(ConvLayer, self).__init__(f*f*self.d, k, u_type=u_type, a_type=a_type, dropout=dropout)
2424

2525
def predict(self, batch):
2626
self.image_size = batch.shape[0]
@@ -55,7 +55,8 @@ def forward(self, batch):
5555
l2 += n.regularization()
5656

5757
sum_weights = np.array(sum_weights)
58-
strength = (sum_weights.dot(cols) + np.array(bias).reshape(sum_weights.shape[0], 1)).reshape(self.k, self.h2, self.w2, -1).transpose(3, 0, 1, 2)
58+
strength = (sum_weights.dot(cols) + np.array(bias).reshape(sum_weights.shape[0], 1))
59+
strength = strength.reshape(self.k, self.h2, self.w2, -1).transpose(3, 0, 1, 2)
5960

6061
if self.activation:
6162
if self.a_type == 'sigmoid':
@@ -71,23 +72,32 @@ def backward(self, d, need_d=True):
7172
if d.ndim < 4:
7273
d = d.reshape(self.w2, self.h2, self.k, -1).T
7374

74-
delta = d * u.relu_d(self.forward_result)
75-
padding = ((self.w - 1) * self.s + self.f - self.w2) // 2
76-
cols = u.im2col_indices(delta, self.f, self.f, padding=padding, stride=self.s)
75+
if self.activation:
76+
if self.a_type == 'sigmoid':
77+
delta = d * u.sigmoid_d(self.forward_result)
78+
else:
79+
delta = d * u.relu_d(self.forward_result)
80+
else:
81+
delta = d
82+
7783
sum_weights = []
7884
for index, n in enumerate(self.neurons):
79-
n.delta = delta[:, index, :, :].flatten()
85+
n.delta = delta[:, index, :, :].transpose(1, 2, 0).flatten()
8086
if need_d:
81-
rot = np.rot90(n.weights.reshape(self.d, self.f * self.f), 2).reshape(self.d, self.f, self.f)[::-1]
87+
rot = np.rot90(n.weights.reshape(self.d, self.f, self.f), k=2, axes=(1, 2))
8288
sum_weights.append(rot)
8389

8490
if not need_d:
8591
return
8692

87-
sum_weights = np.array(sum_weights).transpose(1,0,2,3).reshape(self.d, -1)
93+
padding = ((self.w - 1) * self.s + self.f - self.w2) // 2
94+
cols = u.im2col_indices(delta, self.f, self.f, padding=padding, stride=self.s)
95+
96+
sum_weights = np.array(sum_weights).transpose(1, 0, 2, 3).reshape(self.d, -1)
8897

8998
result = sum_weights.dot(cols)
9099
im = result.reshape(self.d, self.h, self.w, -1).transpose(3, 0, 1, 2)
100+
91101
return im
92102

93103
def output_size(self):

classes/layer.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ class Layer(object):
77
is_output = False
88
activation = True
99
u_type = 'adam'
10+
dropout = 1
1011

1112
@abstractmethod
1213
def forward(self, batch):

classes/neural_layer.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,11 @@
66

77
class NeuralLayer(Layer):
88

9-
def __init__(self, input_size, k, u_type='adam', a_type='relu'):
9+
def __init__(self, input_size, k, u_type='adam', a_type='relu', dropout=1):
1010
self.neurons = []
1111
self.forward_result = None
1212
self.k = k
13+
self.dropout = dropout
1314

1415
self.u_type = u_type
1516
self.a_type= a_type
@@ -19,14 +20,16 @@ def __init__(self, input_size, k, u_type='adam', a_type='relu'):
1920

2021
for n in range(k):
2122
n = Neuron(input_size)
23+
2224
if u_type == 'adam':
23-
n.m_bias, n.v_bias, n.m, n.v = 0, 0, 0, 0
25+
n.m, n.v = 0, 0
2426
elif u_type == 'm':
25-
n.v_bias, n.v = 0, 0
27+
n.v = 0, 0
2628
elif u_type == 'nag':
27-
n.v, n.v_bias, n.v_prev, n.v_prev_bias = 0, 0, 0, 0
29+
n.v, n.v_prev = 0, 0
2830
elif u_type == 'rmsprop':
29-
n.cache, n.cache_bias, n.v, n.v = 0, 0, 0, 0
31+
n.cache, n.v = 0, 0
32+
3033
self.neurons.append(n)
3134

3235
def predict(self, batch):
@@ -51,7 +54,6 @@ def forward(self, batch):
5154

5255
if batch.ndim > 2:
5356
batch = batch.reshape(batch.shape[0], -1).T
54-
5557
forward_result = []
5658
l2 = 0
5759
for n in self.neurons:

classes/neural_net.py

Lines changed: 15 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,13 @@
55
import numpy as np
66

77
class NeuralNetwork(object):
8-
def __init__(self, input_shape, layer_list, lr, l2_reg=0, dropout_p=1, loss='softmax'):
8+
def __init__(self, input_shape, layer_list, lr, l2_reg=0, loss='softmax'):
99
self.layers = []
1010
self.lr = np.float32(lr)
1111
self.l2_reg = np.float32(l2_reg)
1212
self.loss = loss
13+
self.epoch_count = 0
1314

14-
self.dropout_p = dropout_p
1515
self.dropout_masks = []
1616
self.t = 0
1717

@@ -48,9 +48,6 @@ def predict(self, batch, label):
4848
for index, layer in enumerate(self.layers):
4949
next_input = layer.predict(next_input)
5050

51-
if (self.dropout_p < 1) and (type(layer).__name__ == 'NeuralLayer') and not layer.is_output:
52-
next_input *= self.dropout_p
53-
5451
result = np.array(next_input)
5552
if self.loss == 'softmax':
5653
loss, delta = utils.softmax_loss(result, label)
@@ -64,39 +61,44 @@ def predict(self, batch, label):
6461

6562
def epoch(self, batch, label):
6663
# forward
67-
self.dropout_masks = []
6864
l2 = 0
6965
next_input = batch
7066
for index, layer in enumerate(self.layers):
7167
layer_result = layer.forward(next_input)
7268
next_input = layer_result[0]
7369
l2 += layer_result[1]
74-
if (self.dropout_p < 1) and (type(layer).__name__ == 'NeuralLayer') and not layer.is_output:
75-
dropout_mask = np.random.rand(*next_input.shape) < self.dropout_p
70+
if layer.dropout < 1 and not layer.is_output:
71+
dropout_mask = np.random.rand(*next_input.shape) < layer.dropout
72+
next_input *= dropout_mask / layer.dropout
7673
self.dropout_masks.append(dropout_mask)
77-
next_input *= dropout_mask
74+
7875

7976
result = np.array(next_input)
8077
if self.loss == 'softmax':
8178
loss, delta = utils.softmax_loss(result, label)
8279
elif self.loss == 'logistic':
8380
loss, delta = utils.logistic_loss(result, label)
8481

82+
loss += 0.5 * self.l2_reg * l2
8583
max_result = np.argmax(result, axis=0)
8684
correct_count = np.sum(max_result == label)
8785

8886
# backprop
8987
back_input = delta.T
9088
for index, layer in enumerate(reversed(self.layers)):
9189
is_input_layer = index < len(self.layers) - 1
92-
back_input = layer.backward(back_input, is_input_layer)
9390

94-
if self.dropout_masks:
91+
if layer.dropout < 1 and not layer.is_output and self.dropout_masks:
9592
dropout_mask = self.dropout_masks.pop()
96-
back_input *= dropout_mask
93+
if dropout_mask.ndim > 2 and back_input.ndim == 2:
94+
back_input *= dropout_mask.T.reshape(-1, back_input.shape[1])
95+
else:
96+
back_input *= dropout_mask
97+
98+
back_input = layer.backward(back_input, is_input_layer)
9799

98100
# update
99101
for index, layer in enumerate(self.layers):
100102
layer.update(self.lr, l2_reg=self.l2_reg, t=self.t)
101103

102-
return loss + self.l2_reg * l2 / 2, correct_count / float(len(max_result)) * 100
104+
return loss + self.l2_reg * l2 / 2, correct_count / float(len(max_result)) * 100

classes/neuron.py

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,13 @@
33

44
class Neuron(object):
55
def __init__(self, input_size, bias=0.0):
6-
limit = np.sqrt(2.0 / input_size)
7-
self.weights = (np.random.randn(input_size) * limit).astype(np.float32)
6+
self.weights = (np.random.randn(input_size) * np.sqrt(2.0 / input_size)).astype(np.float32)
87
self.b = np.float32(bias)
98
self.last_input = None
10-
self.delta = 0
9+
self.delta = None
1110

1211
def strength(self, values):
1312
return np.dot(self.weights, values) + self.b
1413

1514
def regularization(self):
16-
return np.sum(np.square(self.weights))
15+
return np.sum(np.square(self.weights))

0 commit comments

Comments
 (0)