singa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From zhaoj...@apache.org
Subject [1/2] incubator-singa git commit: SINGA-328 - Add VGG models for ImageNet classification
Date Sun, 27 Aug 2017 03:13:58 GMT
Repository: incubator-singa
Updated Branches:
  refs/heads/master d30920f6c -> aa9747bab


SINGA-328 - Add VGG models for ImageNet classification

Add vgg models and the parameter conversion script.
The converted parameters are stored on S3.
The download links are providied in the readme file.


Project: http://git-wip-us.apache.org/repos/asf/incubator-singa/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-singa/commit/4fe5271d
Tree: http://git-wip-us.apache.org/repos/asf/incubator-singa/tree/4fe5271d
Diff: http://git-wip-us.apache.org/repos/asf/incubator-singa/diff/4fe5271d

Branch: refs/heads/master
Commit: 4fe5271d0a09684ddadfd5feb98333f10ddac0a2
Parents: a94fa10
Author: wangwei <wangwei@comp.nus.edu.sg>
Authored: Mon Jul 3 22:01:57 2017 +0800
Committer: wangwei <wangwei@comp.nus.edu.sg>
Committed: Tue Jul 4 14:09:52 2017 +0800

----------------------------------------------------------------------
 examples/imagenet/vgg/README.md  |  51 ++++++++++++
 examples/imagenet/vgg/convert.py |  90 +++++++++++++++++++++
 examples/imagenet/vgg/model.py   |  91 +++++++++++++++++++++
 examples/imagenet/vgg/serve.py   | 146 ++++++++++++++++++++++++++++++++++
 4 files changed, 378 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/4fe5271d/examples/imagenet/vgg/README.md
----------------------------------------------------------------------
diff --git a/examples/imagenet/vgg/README.md b/examples/imagenet/vgg/README.md
new file mode 100644
index 0000000..2c99902
--- /dev/null
+++ b/examples/imagenet/vgg/README.md
@@ -0,0 +1,51 @@
+---
+name: VGG models on ImageNet
+SINGA version: 1.1.1
+SINGA commit:
+license: https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py
+---
+
+# Image Classification using VGG
+
+
+In this example, we convert VGG on [PyTorch](https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py)
+to SINGA for image classification.
+
+## Instructions
+
+* Download one parameter checkpoint file (see below) and the synset word file of ImageNet
into this folder, e.g.,
+
+        $ wget https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg11.tar.gz
+        $ wget https://s3-ap-southeast-1.amazonaws.com/dlfile/resnet/synset_words.txt
+        $ tar xvf vgg11.tar.gz
+
+* Usage
+
+        $ python serve.py -h
+
+* Example
+
+        # use cpu
+        $ python serve.py --use_cpu --parameter_file vgg11.pickle --depth 11 --use_cpu &
+        # use gpu
+        $ python serve.py --use_cpu --parameter_file vgg11.pickle --depth 11 &
+
+  The parameter files for the following model and depth configuration pairs are provided:
+  * Without batch-normalization, [11](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg11.tar.gz),
[13](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg13.tar.gz), [16](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg16.tar.gz),
[19](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg19.tar.gz)
+  * With batch-normalization, [11](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg11_bn.tar.gz),
[13](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg13_bn.tar.gz), [16](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg16_bn.tar.gz),
[19](https://s3-ap-southeast-1.amazonaws.com/dlfile/vgg/vgg19_bn.tar.gz)
+
+* Submit images for classification
+
+        $ curl -i -F image=@image1.jpg http://localhost:9999/api
+        $ curl -i -F image=@image2.jpg http://localhost:9999/api
+        $ curl -i -F image=@image3.jpg http://localhost:9999/api
+
+image1.jpg, image2.jpg and image3.jpg should be downloaded before executing the above commands.
+
+## Details
+
+The parameter files were converted from the pytorch via the convert.py program.
+
+Usage:
+
+    $ python convert.py -h

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/4fe5271d/examples/imagenet/vgg/convert.py
----------------------------------------------------------------------
diff --git a/examples/imagenet/vgg/convert.py b/examples/imagenet/vgg/convert.py
new file mode 100644
index 0000000..bd90a87
--- /dev/null
+++ b/examples/imagenet/vgg/convert.py
@@ -0,0 +1,90 @@
+# 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.
+
+'''Extract the net parameters from the pytorch file and store them
+as python dict using cPickle. Must install pytorch.
+'''
+
+import torch.utils.model_zoo as model_zoo
+
+import numpy as np
+import cPickle as pickle
+from argparse import ArgumentParser
+
+import model
+
+
+model_urls = {
+    'vgg11': 'https://download.pytorch.org/models/vgg11-bbd30ac9.pth',
+    'vgg13': 'https://download.pytorch.org/models/vgg13-c768596a.pth',
+    'vgg16': 'https://download.pytorch.org/models/vgg16-397923af.pth',
+    'vgg19': 'https://download.pytorch.org/models/vgg19-dcbb9e9d.pth',
+    'vgg11_bn': 'https://download.pytorch.org/models/vgg11_bn-6002323d.pth',
+    'vgg13_bn': 'https://download.pytorch.org/models/vgg13_bn-abd245e5.pth',
+    'vgg16_bn': 'https://download.pytorch.org/models/vgg16_bn-6c64b313.pth',
+    'vgg19_bn': 'https://download.pytorch.org/models/vgg19_bn-c79401a0.pth',
+}
+
+
+def rename(pname):
+    p1 = pname.find('/')
+    p2 = pname.rfind('/')
+    assert p1 != -1 and p2 != -1, 'param name = %s is not correct' % pname
+    if 'gamma' in pname:
+        suffix = 'weight'
+    elif 'beta' in pname:
+        suffix = 'bias'
+    elif 'mean' in pname:
+        suffix = 'running_mean'
+    elif 'var' in pname:
+        suffix = 'running_var'
+    else:
+        suffix = pname[p2 + 1:]
+    return pname[p1+1:p2] + '.' + suffix
+
+
+if __name__ == '__main__':
+    parser = ArgumentParser(description='Convert params from torch to python'
+                            'dict. ')
+    parser.add_argument("depth", type=int, choices=[11, 13, 16, 19])
+    parser.add_argument("outfile")
+    parser.add_argument("--batchnorm", action='store_true',
+                        help='use batchnorm or not')
+
+    args = parser.parse_args()
+
+    net = model.create_net(args.depth, 1000, args.batchnorm)
+    url = 'vgg%d' % args.depth
+    if args.batchnorm:
+        url += '_bn'
+    torch_dict = model_zoo.load_url(model_urls[url])
+    params = {'SINGA_VERSION': 1101}
+    # params = net.param_values()
+    for pname, pval in zip(net.param_names(), net.param_values()):
+        torch_name = rename(pname)
+        if torch_name in torch_dict:
+            ary = torch_dict[torch_name].numpy()
+            ary = np.array(ary, dtype=np.float32)
+            if len(ary.shape) == 4:
+                params[pname] = np.reshape(ary, (ary.shape[0], -1))
+            else:
+                params[pname] = np.transpose(ary)
+        else:
+            print('param=%s is missing in the ckpt file' % pname)
+        assert pval.shape == params[pname].shape, 'shape mismatch for %s' % pname
+
+    with open(args.outfile, 'wb') as fd:
+        pickle.dump(params, fd)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/4fe5271d/examples/imagenet/vgg/model.py
----------------------------------------------------------------------
diff --git a/examples/imagenet/vgg/model.py b/examples/imagenet/vgg/model.py
new file mode 100644
index 0000000..d2244af
--- /dev/null
+++ b/examples/imagenet/vgg/model.py
@@ -0,0 +1,91 @@
+# 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.
+# =============================================================================
+''' This models are created following
+https://github.com/pytorch/vision/blob/master/torchvision/models/vgg.py
+'''
+from singa.layer import Conv2D, Activation, MaxPooling2D, \
+        Flatten, Dense, BatchNormalization, Dropout
+from singa import net as ffnet
+from singa import initializer
+from singa import layer
+
+
+ffnet.verbose=False
+cfg = {
+        11: [64, 'M', 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
+        13: [64, 64, 'M', 128, 128, 'M', 256, 256, 'M', 512, 512, 'M', 512, 512, 'M'],
+        16: [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 'M', 512, 512, 512, 'M', 512, 512,
512, 'M'],
+        19: [64, 64, 'M', 128, 128, 'M', 256, 256, 256, 256, 'M', 512, 512, 512, 512, 'M',
512, 512, 512, 512, 'M'],
+}
+
+
+def create_layers(net, cfg, sample_shape, batch_norm=False):
+    lid = 0
+    for idx, v in enumerate(cfg):
+        if v == 'M':
+            net.add(MaxPooling2D('pool/features.%d' % lid, 2, 2, pad=0))
+            lid += 1
+        else:
+            net.add(Conv2D('conv/features.%d' % lid, v, 3, pad=1,
+                           input_sample_shape=sample_shape))
+            lid += 1
+            if batch_norm:
+                net.add(BatchNormalization('bn/features.%d' % lid))
+                lid += 1
+            net.add(Activation('act/features.%d' % lid))
+            lid += 1
+        sample_shape = None
+    return net
+
+
+def init_params(net, weight_path=None):
+    if weight_path is None:
+        for pname, pval in zip(net.param_names(), net.param_values()):
+            print(pname, pval.shape)
+            if 'conv' in pname and len(pval.shape) > 1:
+                initializer.gaussian(pval, 0, pval.shape[1])
+            elif 'dense' in pname:
+                if len(pval.shape) > 1:
+                    initializer.gaussian(pval, 0, pval.shape[0])
+                else:
+                    pval.set_value(0)
+            # init params from batch norm layer
+            elif 'mean' in pname or 'beta' in pname:
+                pval.set_value(0)
+            elif 'var' in pname or 'gamma' in pname:
+                pval.set_value(1)
+    else:
+        net.load(weight_path, use_pickle='pickle' in weight_path)
+
+
+def create_net(depth, nb_classes, batchnorm=False, use_cpu=False):
+    if use_cpu:
+        layer.engine = 'singacpp'
+    net = ffnet.FeedForwardNet()
+    net = create_layers(net, cfg[depth], (3, 224, 224), batchnorm)
+    net.add(Flatten('flat'))
+    net.add(Dense('dense/classifier.0', 4096))
+    net.add(Activation('act/classifier.1'))
+    net.add(Dropout('dropout/classifier.2'))
+    net.add(Dense('dense/classifier.3', 4096))
+    net.add(Activation('act/classifier.4'))
+    net.add(Dropout('dropout/classifier.5'))
+    net.add(Dense('dense/classifier.6', nb_classes))
+    return net
+
+if __name__ == '__main__':
+    create_net(13, 1000)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/4fe5271d/examples/imagenet/vgg/serve.py
----------------------------------------------------------------------
diff --git a/examples/imagenet/vgg/serve.py b/examples/imagenet/vgg/serve.py
new file mode 100644
index 0000000..9cdfbd9
--- /dev/null
+++ b/examples/imagenet/vgg/serve.py
@@ -0,0 +1,146 @@
+# 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.
+
+import sys
+import time
+import numpy as np
+import traceback
+from argparse import ArgumentParser
+from scipy.misc import imread
+
+from singa import device
+from singa import tensor
+from singa import image_tool
+from rafiki.agent import Agent, MsgType
+import model
+
+tool = image_tool.ImageTool()
+num_augmentation = 1
+crop_size = 224
+mean = np.array([0.485, 0.456, 0.406])
+std = np.array([0.229, 0.224, 0.225])
+
+
+def allowed_file(filename):
+    return '.' in filename and filename.rsplit('.', 1)[1] in \
+        ["PNG", "png", "jpg", "JPG", "JPEG", "jpeg"]
+
+
+def serve(net, label_map, dev, agent, topk=5):
+    '''Serve to predict image labels.
+
+    It prints the topk food names for each image.
+
+    Args:
+        label_map: a list of food names, corresponding to the index in meta_file
+    '''
+
+    images = tensor.Tensor((num_augmentation, 3, crop_size, crop_size), dev)
+    while True:
+        msg, val = agent.pull()
+        if msg is None:
+            time.sleep(0.1)
+            continue
+        msg = MsgType.parse(msg)
+        if msg.is_request():
+            try:
+                # process images
+                img = imread(val['image'], mode='RGB').astype(np.float32) / 255
+                height,width = img.shape[:2]
+                img -= mean
+                img /= std
+                img = img.transpose((2, 0, 1))
+                img = img[:,(height-224)//2:(height+224)//2,(width-224)//2:(width+224)//2]
+                images.copy_from_numpy(img)
+                print("input: ", images.l1())
+                # do prediction
+                y = net.predict(images)
+                prob = np.average(tensor.to_numpy(y), 0)
+                idx = np.argsort(-prob)
+                # prepare results
+                response = ""
+                for i in range(topk):
+                    response += "%s:%f <br/>" % (label_map[idx[i]],
+                                                 prob[idx[i]])
+            except:
+                traceback.print_exc()
+                response = "sorry, system error during prediction."
+            agent.push(MsgType.kResponse, response)
+        elif msg.is_command():
+            if MsgType.kCommandStop.equal(msg):
+                print('get stop command')
+                agent.push(MsgType.kStatus, "success")
+                break
+            else:
+                print('get unsupported command %s' % str(msg))
+                agent.push(MsgType.kStatus, "Unknown command")
+        else:
+            print('get unsupported message %s' % str(msg))
+            agent.push(MsgType.kStatus, "unsupported msg; going to shutdown")
+            break
+    print("server stop")
+
+
+def main():
+    try:
+        # Setup argument parser
+        parser = ArgumentParser(description="VGG inference")
+
+        parser.add_argument("--port", default=9999, help="listen port")
+        parser.add_argument("--use_cpu", action="store_true",
+                            help="If set, load models onto CPU devices")
+        parser.add_argument("--parameter_file", default="")
+        parser.add_argument("--depth", type=int, choices=[11, 13, 16, 19],
+                            default='11')
+        parser.add_argument("--batchnorm", action='store_true',
+                            help='use batchnorm or not')
+
+        # Process arguments
+        args = parser.parse_args()
+        port = args.port
+
+        # start to train
+        agent = Agent(port)
+
+        net = model.create_net(args.depth, 1000, args.batchnorm, args.use_cpu)
+        if args.use_cpu:
+            print('Using CPU')
+            dev = device.get_default_device()
+        else:
+            print('Using GPU')
+            dev = device.create_cuda_gpu()
+            net.to_device(dev)
+        model.init_params(net, args.parameter_file)
+        print('Finish loading models')
+
+        labels = np.loadtxt('synset_words.txt', str, delimiter='\t ')
+        serve(net, labels, dev, agent)
+
+        # acc = evaluate(net, '../val_list.txt',  'image/val', dev)
+        # print acc
+
+        # wait the agent finish handling http request
+        agent.stop()
+    except SystemExit:
+        return
+    except:
+        traceback.print_exc()
+        sys.stderr.write("  for help use --help \n\n")
+        return 2
+
+
+if __name__ == '__main__':
+    main()


Mime
View raw message