| #!/usr/bin/env python |
| |
| # Licensed to the Apache Software Foundation (ASF) under one |
| # or more contributor license agreements. See the NOTICE file |
| # distributed with this work for additional information |
| # regarding copyright ownership. The ASF licenses this file |
| # to you under the Apache License, Version 2.0 (the |
| # "License"); you may not use this file except in compliance |
| # with the License. You may obtain a copy of the License at |
| # |
| # http://www.apache.org/licenses/LICENSE-2.0 |
| # |
| # Unless required by applicable law or agreed to in writing, |
| # software distributed under the License is distributed on an |
| # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| # KIND, either express or implied. See the License for the |
| # specific language governing permissions and limitations |
| # under the License. |
| |
| # lenet with multiple gpus |
| # |
| # using different kvstore will get almost identical results |
| # |
| # must disable CUDNN, which results randomness |
| # |
| # where the gradients are aggregated and the weights are updated results |
| # different results, it might be gpu's precision is much lower than |
| # cpu. however, the results should be still identical if not too many iterations |
| # are performed, which can be controlled by either increasing the batch size or |
| # decreasing the number of epochs |
| |
| import os, sys |
| curr_path = os.path.abspath(os.path.dirname(__file__)) |
| sys.path.append(os.path.join(curr_path, "../../example/image-classification")) |
| sys.path.append(os.path.join(curr_path, "../../python")) |
| import mxnet as mx |
| import numpy as np |
| import logging |
| import logging |
| import train_mnist |
| |
| # number of gpus |
| ngpus = 4 |
| # the batch size |
| batch_size = 200 |
| |
| def mnist(batch_size, input_shape): |
| """return mnist iters without randomness""" |
| flat = len(input_shape)==1 |
| train = mx.io.MNISTIter( |
| image = "data/mnist/train-images-idx3-ubyte", |
| label = "data/mnist/train-labels-idx1-ubyte", |
| data_shape = input_shape, |
| batch_size = batch_size, |
| shuffle = False, |
| flat = flat, |
| silent = True) |
| val = mx.io.MNISTIter( |
| image = "data/mnist/t10k-images-idx3-ubyte", |
| label = "data/mnist/t10k-labels-idx1-ubyte", |
| data_shape = input_shape, |
| batch_size = batch_size, |
| shuffle = False, |
| flat = flat, |
| silent = True) |
| return (train, val) |
| |
| def accuracy(model, data): |
| """evaluate acc""" |
| data.reset() |
| prob = model.predict(data) |
| py = np.argmax(prob, axis=1) |
| # get label |
| data.reset() |
| y = np.concatenate([d.label[0].asnumpy() for d in data]).astype('int') |
| y = y[0:len(py)] |
| acc = float(np.sum(py == y)) / len(y) |
| logging.info('Accuracy = %f', acc) |
| return acc |
| |
| def get_XY(data_iter): |
| data_iter.reset() |
| Y = np.concatenate([d.label[0].asnumpy() for d in data_iter]) |
| data_iter.reset() |
| X = np.concatenate([d.data[0].asnumpy() for d in data_iter]) |
| assert X.shape[0] == Y.shape[0] |
| return (X,Y) |
| |
| def test_data(data_iter): |
| # test whether we will get the identical data each time |
| X, Y = get_XY(data_iter) |
| print X.shape, Y.shape |
| for i in range(4): |
| A, B = get_XY(data_iter) |
| assert(A.shape == X.shape) |
| assert(B.shape == Y.shape) |
| assert(np.sum(A != X) == 0) |
| assert(np.sum(B != Y) == 0) |
| |
| # must use the same net, since the system will automatically assign namees to |
| # layers, which affects the order of the weight initialization |
| net = train_mnist.get_lenet() |
| |
| def test_lenet(devs, kv_type): |
| logging.basicConfig(level=logging.DEBUG) |
| (train, val) = mnist(batch_size = batch_size, input_shape=(1,28,28)) |
| # guarantee the same weight init for each run |
| mx.random.seed(0) |
| model = mx.model.FeedForward( |
| ctx = devs, |
| symbol = net, |
| num_epoch = 2, |
| learning_rate = 0.1, |
| momentum = 0.9, |
| wd = 0.00001) |
| model.fit( |
| kvstore = kv_type, |
| X = train) |
| return accuracy(model, val) |
| |
| |
| if __name__ == "__main__": |
| # test data |
| (train, val) = mnist(batch_size = 100, input_shape=(1,28,28)) |
| test_data(train) |
| test_data(val) |
| |
| (train, val) = mnist(batch_size = 110, input_shape=(784,)) |
| test_data(train) |
| test_data(val) |
| |
| # test model |
| gpus = [mx.gpu(i) for i in range(ngpus)] |
| |
| base = test_lenet(mx.gpu(), 'none') |
| acc1 = test_lenet(mx.gpu(), 'none') |
| acc2 = test_lenet(gpus, 'local_update_cpu') |
| acc3 = test_lenet(gpus, 'local_allreduce_cpu') |
| acc4 = test_lenet(gpus, 'local_allreduce_device') |
| |
| assert base > 0.95 |
| assert abs(base - acc1) < 1e-4 |
| assert abs(base - acc2) < 1e-3 |
| assert abs(base - acc3) < 1e-3 |
| assert abs(acc3 - acc4) < 1e-4 |