Skip to content

Commit 5482fe7

Browse files
authored
Merge pull request #1228 from npcmaci/dev-postgresql
create the application folder for the healthcare model zoo
2 parents f5f2abe + 043b8ca commit 5482fe7

1 file changed

Lines changed: 318 additions & 0 deletions

File tree

  • examples/healthcare/application/Malaria_Detection
Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,318 @@
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, software
13+
# distributed under the License is distributed on an "AS IS" BASIS,
14+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
# See the License for the specific language governing permissions and
16+
# limitations under the License.
17+
#
18+
19+
from singa import singa_wrap as singa
20+
from singa import device
21+
from singa import tensor
22+
from singa import opt
23+
import numpy as np
24+
import time
25+
import argparse
26+
import sys
27+
sys.path.append("../../..")
28+
29+
from PIL import Image
30+
31+
from healthcare.data import malaria
32+
from healthcare.models import malaria_net
33+
34+
np_dtype = {"float16": np.float16, "float32": np.float32}
35+
36+
singa_dtype = {"float16": tensor.float16, "float32": tensor.float32}
37+
38+
39+
# Data augmentation
40+
def augmentation(x, batch_size):
41+
xpad = np.pad(x, [[0, 0], [0, 0], [4, 4], [4, 4]], 'symmetric')
42+
for data_num in range(0, batch_size):
43+
offset = np.random.randint(8, size=2)
44+
x[data_num, :, :, :] = xpad[data_num, :,
45+
offset[0]:offset[0] + x.shape[2],
46+
offset[1]:offset[1] + x.shape[2]]
47+
if_flip = np.random.randint(2)
48+
if (if_flip):
49+
x[data_num, :, :, :] = x[data_num, :, :, ::-1]
50+
return x
51+
52+
53+
# Calculate accuracy
54+
def accuracy(pred, target):
55+
# y is network output to be compared with ground truth (int)
56+
y = np.argmax(pred, axis=1)
57+
a = y == target
58+
correct = np.array(a, "int").sum()
59+
return correct
60+
61+
62+
# Data partition according to the rank
63+
def partition(global_rank, world_size, train_x, train_y, val_x, val_y):
64+
# Partition training data
65+
data_per_rank = train_x.shape[0] // world_size
66+
idx_start = global_rank * data_per_rank
67+
idx_end = (global_rank + 1) * data_per_rank
68+
train_x = train_x[idx_start:idx_end]
69+
train_y = train_y[idx_start:idx_end]
70+
71+
# Partition evaluation data
72+
data_per_rank = val_x.shape[0] // world_size
73+
idx_start = global_rank * data_per_rank
74+
idx_end = (global_rank + 1) * data_per_rank
75+
val_x = val_x[idx_start:idx_end]
76+
val_y = val_y[idx_start:idx_end]
77+
return train_x, train_y, val_x, val_y
78+
79+
80+
# Function to all reduce NUMPY accuracy and loss from multiple devices
81+
def reduce_variable(variable, dist_opt, reducer):
82+
reducer.copy_from_numpy(variable)
83+
dist_opt.all_reduce(reducer.data)
84+
dist_opt.wait()
85+
output = tensor.to_numpy(reducer)
86+
return output
87+
88+
89+
def resize_dataset(x, image_size):
90+
num_data = x.shape[0]
91+
dim = x.shape[1]
92+
X = np.zeros(shape=(num_data, dim, image_size, image_size),
93+
dtype=np.float32)
94+
for n in range(0, num_data):
95+
for d in range(0, dim):
96+
X[n, d, :, :] = np.array(Image.fromarray(x[n, d, :, :]).resize(
97+
(image_size, image_size), Image.BILINEAR),
98+
dtype=np.float32)
99+
return X
100+
101+
102+
def run(global_rank,
103+
world_size,
104+
dir_path,
105+
max_epoch,
106+
batch_size,
107+
model,
108+
data,
109+
sgd,
110+
graph,
111+
verbosity,
112+
dist_option='plain',
113+
spars=None,
114+
precision='float32'):
115+
# now CPU version only, could change to GPU device for GPU-support machines
116+
dev = device.get_default_device()
117+
dev.SetRandSeed(0)
118+
np.random.seed(0)
119+
if data == 'malaria':
120+
121+
train_x, train_y, val_x, val_y = malaria.load(dir_path=dir_path)
122+
else:
123+
print(
124+
'Wrong dataset!'
125+
)
126+
sys.exit(0)
127+
128+
num_channels = train_x.shape[1]
129+
image_size = train_x.shape[2]
130+
data_size = np.prod(train_x.shape[1:train_x.ndim]).item()
131+
num_classes = (np.max(train_y) + 1).item()
132+
133+
if model == 'cnn':
134+
model = malaria_net.create_model(model_option='cnn', num_channels=num_channels,
135+
num_classes=num_classes)
136+
else:
137+
print(
138+
'Wrong model!'
139+
)
140+
sys.exit(0)
141+
142+
# For distributed training, sequential has better performance
143+
if hasattr(sgd, "communicator"):
144+
DIST = True
145+
sequential = True
146+
else:
147+
DIST = False
148+
sequential = False
149+
150+
if DIST:
151+
train_x, train_y, val_x, val_y = partition(global_rank, world_size,
152+
train_x, train_y, val_x,
153+
val_y)
154+
155+
if model.dimension == 4:
156+
tx = tensor.Tensor(
157+
(batch_size, num_channels, model.input_size, model.input_size), dev,
158+
singa_dtype[precision])
159+
elif model.dimension == 2:
160+
tx = tensor.Tensor((batch_size, data_size),
161+
dev, singa_dtype[precision])
162+
np.reshape(train_x, (train_x.shape[0], -1))
163+
np.reshape(val_x, (val_x.shape[0], -1))
164+
165+
ty = tensor.Tensor((batch_size,), dev, tensor.int32)
166+
num_train_batch = train_x.shape[0] // batch_size
167+
num_val_batch = val_x.shape[0] // batch_size
168+
idx = np.arange(train_x.shape[0], dtype=np.int32)
169+
170+
# Attach model to graph
171+
model.set_optimizer(sgd)
172+
model.compile([tx], is_train=True, use_graph=graph, sequential=sequential)
173+
dev.SetVerbosity(verbosity)
174+
175+
# Training and evaluation loop
176+
for epoch in range(max_epoch):
177+
start_time = time.time()
178+
np.random.shuffle(idx)
179+
180+
if global_rank == 0:
181+
print('Starting Epoch %d:' % (epoch))
182+
183+
# Training phase
184+
train_correct = np.zeros(shape=[1], dtype=np.float32)
185+
test_correct = np.zeros(shape=[1], dtype=np.float32)
186+
train_loss = np.zeros(shape=[1], dtype=np.float32)
187+
188+
model.train()
189+
for b in range(num_train_batch):
190+
# if b % 100 == 0:
191+
# print ("b: \n", b)
192+
# Generate the patch data in this iteration
193+
x = train_x[idx[b * batch_size:(b + 1) * batch_size]]
194+
if model.dimension == 4:
195+
x = augmentation(x, batch_size)
196+
if (image_size != model.input_size):
197+
x = resize_dataset(x, model.input_size)
198+
x = x.astype(np_dtype[precision])
199+
y = train_y[idx[b * batch_size:(b + 1) * batch_size]]
200+
201+
# Copy the patch data into input tensors
202+
tx.copy_from_numpy(x)
203+
ty.copy_from_numpy(y)
204+
205+
# Train the model
206+
out, loss = model(tx, ty, dist_option, spars)
207+
train_correct += accuracy(tensor.to_numpy(out), y)
208+
train_loss += tensor.to_numpy(loss)[0]
209+
210+
# print('batch training loss = %f' % train_loss, flush=True)
211+
212+
if DIST:
213+
# Reduce the evaluation accuracy and loss from multiple devices
214+
reducer = tensor.Tensor((1,), dev, tensor.float32)
215+
train_correct = reduce_variable(train_correct, sgd, reducer)
216+
train_loss = reduce_variable(train_loss, sgd, reducer)
217+
218+
if global_rank == 0:
219+
print('Training loss = %f, training accuracy = %f' %
220+
(train_loss, train_correct /
221+
(num_train_batch * batch_size * world_size)),
222+
flush=True)
223+
224+
# Evaluation phase
225+
model.eval()
226+
for b in range(num_val_batch):
227+
x = val_x[b * batch_size:(b + 1) * batch_size]
228+
if model.dimension == 4:
229+
if (image_size != model.input_size):
230+
x = resize_dataset(x, model.input_size)
231+
x = x.astype(np_dtype[precision])
232+
y = val_y[b * batch_size:(b + 1) * batch_size]
233+
tx.copy_from_numpy(x)
234+
ty.copy_from_numpy(y)
235+
out_test = model(tx)
236+
test_correct += accuracy(tensor.to_numpy(out_test), y)
237+
238+
if DIST:
239+
# Reduce the evaulation accuracy from multiple devices
240+
test_correct = reduce_variable(test_correct, sgd, reducer)
241+
242+
# Output the evaluation accuracy
243+
if global_rank == 0:
244+
print('Evaluation accuracy = %f, Elapsed Time = %fs' %
245+
(test_correct / (num_val_batch * batch_size * world_size),
246+
time.time() - start_time),
247+
flush=True)
248+
249+
dev.PrintTimeProfiling()
250+
251+
252+
if __name__ == '__main__':
253+
# Use argparse to get command config: max_epoch, model, data, etc., for single gpu training
254+
parser = argparse.ArgumentParser(
255+
description='Training using the autograd and graph.')
256+
parser.add_argument(
257+
'model',
258+
choices=['cnn'],
259+
default='cnn')
260+
parser.add_argument('data',
261+
choices=['malaria'],
262+
default='malaria')
263+
parser.add_argument('-p',
264+
choices=['float32', 'float16'],
265+
default='float32',
266+
dest='precision')
267+
parser.add_argument('-dir',
268+
'--dir-path',
269+
default="/tmp/malaria",
270+
type=str,
271+
help='the directory to store the malaria dataset',
272+
dest='dir_path')
273+
parser.add_argument('-m',
274+
'--max-epoch',
275+
default=100,
276+
type=int,
277+
help='maximum epochs',
278+
dest='max_epoch')
279+
parser.add_argument('-b',
280+
'--batch-size',
281+
default=64,
282+
type=int,
283+
help='batch size',
284+
dest='batch_size')
285+
parser.add_argument('-l',
286+
'--learning-rate',
287+
default=0.005,
288+
type=float,
289+
help='initial learning rate',
290+
dest='lr')
291+
parser.add_argument('-g',
292+
'--disable-graph',
293+
default='True',
294+
action='store_false',
295+
help='disable graph',
296+
dest='graph')
297+
parser.add_argument('-v',
298+
'--log-verbosity',
299+
default=0,
300+
type=int,
301+
help='logging verbosity',
302+
dest='verbosity')
303+
304+
args = parser.parse_args()
305+
306+
sgd = opt.SGD(lr=args.lr, momentum=0.9, weight_decay=1e-5,
307+
dtype=singa_dtype[args.precision])
308+
run(0,
309+
1,
310+
args.dir_path,
311+
args.max_epoch,
312+
args.batch_size,
313+
args.model,
314+
args.data,
315+
sgd,
316+
args.graph,
317+
args.verbosity,
318+
precision=args.precision);

0 commit comments

Comments
 (0)