Skip to content

Commit b65e244

Browse files
authored
Merge pull request #1358 from solopku/patch-21
Add the implementation for the autograd convolutional neural network
2 parents 25a2797 + 0e6b3a5 commit b65e244

1 file changed

Lines changed: 163 additions & 0 deletions

File tree

Lines changed: 163 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,163 @@
1+
#
2+
# Licensed to the Apache Software Foundation (ASF) under one
3+
# or more contributor license agreements. See the NOTICE file
4+
# distributed with this work for additional information
5+
# regarding copyright ownership. The ASF licenses this file
6+
# to you under the Apache License, Version 2.0 (the
7+
# "License"); you may not use this file except in compliance
8+
# with the License. You may obtain a copy of the License at
9+
#
10+
# http://www.apache.org/licenses/LICENSE-2.0
11+
#
12+
# Unless required by applicable law or agreed to in writing,
13+
# software distributed under the License is distributed on an
14+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
# KIND, either express or implied. See the License for the
16+
# specific language governing permissions and limitations
17+
# under the License.
18+
#
19+
20+
from singa import singa_wrap as singa
21+
from singa import autograd
22+
from singa import layer
23+
from singa import tensor
24+
from singa import device
25+
from singa import opt
26+
import numpy as np
27+
import os
28+
import sys
29+
import gzip
30+
import codecs
31+
import time
32+
33+
34+
class CNN:
35+
36+
def __init__(self):
37+
self.conv1 = layer.Conv2d(1, 20, 5, padding=0)
38+
self.conv2 = layer.Conv2d(20, 50, 5, padding=0)
39+
self.linear1 = layer.Linear(4 * 4 * 50, 500)
40+
self.linear2 = layer.Linear(500, 10)
41+
self.pooling1 = layer.MaxPool2d(2, 2, padding=0)
42+
self.pooling2 = layer.MaxPool2d(2, 2, padding=0)
43+
self.relu1 = layer.ReLU()
44+
self.relu2 = layer.ReLU()
45+
self.relu3 = layer.ReLU()
46+
self.flatten = layer.Flatten()
47+
48+
def forward(self, x):
49+
y = self.conv1(x)
50+
y = self.relu1(y)
51+
y = self.pooling1(y)
52+
y = self.conv2(y)
53+
y = self.relu2(y)
54+
y = self.pooling2(y)
55+
y = self.flatten(y)
56+
y = self.linear1(y)
57+
y = self.relu3(y)
58+
y = self.linear2(y)
59+
return y
60+
61+
62+
def check_dataset_exist(dirpath):
63+
if not os.path.exists(dirpath):
64+
print(
65+
'The MNIST dataset does not exist. Please download the mnist dataset using download_mnist.py (e.g. python3 download_mnist.py)'
66+
)
67+
sys.exit(0)
68+
return dirpath
69+
70+
71+
def load_dataset():
72+
train_x_path = '/tmp/train-images-idx3-ubyte.gz'
73+
train_y_path = '/tmp/train-labels-idx1-ubyte.gz'
74+
valid_x_path = '/tmp/t10k-images-idx3-ubyte.gz'
75+
valid_y_path = '/tmp/t10k-labels-idx1-ubyte.gz'
76+
77+
train_x = read_image_file(check_dataset_exist(train_x_path)).astype(
78+
np.float32)
79+
train_y = read_label_file(check_dataset_exist(train_y_path)).astype(
80+
np.float32)
81+
valid_x = read_image_file(check_dataset_exist(valid_x_path)).astype(
82+
np.float32)
83+
valid_y = read_label_file(check_dataset_exist(valid_y_path)).astype(
84+
np.float32)
85+
return train_x, train_y, valid_x, valid_y
86+
87+
88+
def read_label_file(path):
89+
with gzip.open(path, 'rb') as f:
90+
data = f.read()
91+
assert get_int(data[:4]) == 2049
92+
length = get_int(data[4:8])
93+
parsed = np.frombuffer(data, dtype=np.uint8, offset=8).reshape((length))
94+
return parsed
95+
96+
97+
def get_int(b):
98+
return int(codecs.encode(b, 'hex'), 16)
99+
100+
101+
def read_image_file(path):
102+
with gzip.open(path, 'rb') as f:
103+
data = f.read()
104+
assert get_int(data[:4]) == 2051
105+
length = get_int(data[4:8])
106+
num_rows = get_int(data[8:12])
107+
num_cols = get_int(data[12:16])
108+
parsed = np.frombuffer(data, dtype=np.uint8, offset=16).reshape(
109+
(length, 1, num_rows, num_cols))
110+
return parsed
111+
112+
113+
def to_categorical(y, num_classes):
114+
y = np.array(y, dtype="int")
115+
n = y.shape[0]
116+
categorical = np.zeros((n, num_classes))
117+
categorical[np.arange(n), y] = 1
118+
categorical = categorical.astype(np.float32)
119+
return categorical
120+
121+
122+
def accuracy(pred, target):
123+
y = np.argmax(pred, axis=1)
124+
t = np.argmax(target, axis=1)
125+
a = y == t
126+
return np.array(a, "int").sum()
127+
128+
129+
# Function to all reduce NUMPY accuracy and loss from multiple devices
130+
def reduce_variable(variable, dist_opt, reducer):
131+
reducer.copy_from_numpy(variable)
132+
dist_opt.all_reduce(reducer.data)
133+
dist_opt.wait()
134+
output = tensor.to_numpy(reducer)
135+
return output
136+
137+
138+
# Function to sychronize SINGA TENSOR initial model parameters
139+
def synchronize(tensor, dist_opt):
140+
dist_opt.all_reduce(tensor.data)
141+
dist_opt.wait()
142+
tensor /= dist_opt.world_size
143+
144+
145+
# Data augmentation
146+
def augmentation(x, batch_size):
147+
xpad = np.pad(x, [[0, 0], [0, 0], [4, 4], [4, 4]], 'symmetric')
148+
for data_num in range(0, batch_size):
149+
offset = np.random.randint(8, size=2)
150+
x[data_num, :, :, :] = xpad[data_num, :, offset[0]:offset[0] + 28,
151+
offset[1]:offset[1] + 28]
152+
if_flip = np.random.randint(2)
153+
if (if_flip):
154+
x[data_num, :, :, :] = x[data_num, :, :, ::-1]
155+
return x
156+
157+
158+
# Data partition
159+
def data_partition(dataset_x, dataset_y, global_rank, world_size):
160+
data_per_rank = dataset_x.shape[0] // world_size
161+
idx_start = global_rank * data_per_rank
162+
idx_end = (global_rank + 1) * data_per_rank
163+
return dataset_x[idx_start:idx_end], dataset_y[idx_start:idx_end]

0 commit comments

Comments
 (0)