singa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From kaip...@apache.org
Subject [4/6] incubator-singa git commit: SINGA-278 Convert trained caffe parameters to singa
Date Fri, 23 Dec 2016 03:44:38 GMT
SINGA-278 Convert trained caffe parameters to singa

Rename the example folder to be 'caffe', which could be used for all caffe models
Update the readme and instructions to let users type in image paths
Swap the first conv layer's weight matrix for RGB input images
Feed images in RGB order to SINGA


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

Branch: refs/heads/master
Commit: bd41fd1d4d3a55bdd8234c357c967a7372a55c83
Parents: aae9d3e
Author: wangwei <wangwei@comp.nus.edu.sg>
Authored: Tue Dec 6 14:20:59 2016 +0800
Committer: wangwei <wangwei@comp.nus.edu.sg>
Committed: Tue Dec 6 14:33:57 2016 +0800

----------------------------------------------------------------------
 examples/caffe/README.md      |  39 ++++++++++++
 examples/caffe/predict.py     | 109 ++++++++++++++++++++++++++++++++
 examples/caffe/run.sh         |  51 +++++++++++++++
 examples/caffe_vgg/README.md  |  23 -------
 examples/caffe_vgg/predict.py | 124 -------------------------------------
 examples/caffe_vgg/run.sh     |  51 ---------------
 python/singa/converter.py     |  10 ++-
 7 files changed, 206 insertions(+), 201 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/examples/caffe/README.md
----------------------------------------------------------------------
diff --git a/examples/caffe/README.md b/examples/caffe/README.md
new file mode 100644
index 0000000..af14d27
--- /dev/null
+++ b/examples/caffe/README.md
@@ -0,0 +1,39 @@
+# Use parameters pre-trained from Caffe in SINGA
+
+In this example, we use SINGA to load the VGG parameters trained by Caffe to do image classification.
+
+## Run this example
+You can run this example by simply executing `run.sh vgg16` or `run.sh vgg19`
+The script does the following work.
+
+### Obtain the Caffe model
+* Download caffe model prototxt and parameter binary file.
+* Currently we only support the latest caffe format, if your model is in
+    previous version of caffe, please update it to current format.(This is
+    supported by caffe)
+* After updating, we can obtain two files, i.e., the prototxt and parameter
+    binary file.
+
+### Prepare test images
+A few sample images are downloaded into the `test` folder.
+
+### Predict
+The `predict.py` script creates the VGG model and read the parameters,
+
+    usage: predict.py [-h] model_txt model_bin imgclass
+
+where `imgclass` refers to the synsets of imagenet dataset for vgg models.
+You can start the prediction program by executing the following command:
+
+    python predict.py ./vgg16.prototxt ./vgg16.caffemodel ./synset_words.txt
+
+Then you type in the image path, and the program would output the top-5 labels.
+
+**NOTE** Caffe uses OpenCV to load images, whose channels are in BGR order. To
+do prediction using Caffe's pre-trained parameters, please make sure the input
+tensor of SINGA net is in BGR order. cv2 loads images as BGR, hence you don't need
+to do any additional processing. If you use pillow to read images, you need to
+swap the channel as shown in predict.py.
+
+
+More Caffe models would be tested soon.

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/examples/caffe/predict.py
----------------------------------------------------------------------
diff --git a/examples/caffe/predict.py b/examples/caffe/predict.py
new file mode 100644
index 0000000..9ef34ed
--- /dev/null
+++ b/examples/caffe/predict.py
@@ -0,0 +1,109 @@
+# 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 numpy as np
+import os
+import argparse
+from PIL import Image
+
+from singa import device
+from singa import tensor
+from singa import converter
+from singa import layer
+from singa import net
+
+#for debug: print norm of each layer
+#net.verbose = True
+
+
+def convert_model(prototxt, caffemodel):
+    cvt = converter.CaffeConverter(net_proto=prototxt, param_path=caffemodel)
+    model = cvt.create_net()
+    cvt.convert_params(model)
+    return model
+
+
+def check_path(path):
+    assert os.path.exists(path), 'File not found: ' + path
+
+
+def read_image(img_path):
+    # According to the VGG paper(Very Deep Convolutional Networks for
+    # Large-Scale Image Recognition), the input images are zero-centered by
+    # mean pixel(rather than mean image) substraction.
+    mean_RGB =[123.68, 116.779, 103.939]
+
+    img = Image.open(img_path)
+    img = img.convert('RGB')
+    resized = img.resize((224, 224))
+    # order of axes: width,height,channel
+    img_ary = np.asarray(resized, dtype=np.float32)
+    img_ary -= mean_RGB
+    # HWC -> CHW
+    img_ary = np.swapaxes(img_ary, 0, 2)
+    return np.asarray(img_ary)
+
+
+def predict(net, dev, synset_list, topk=5):
+    '''Predict the label of each image.
+
+    Args:
+        net, a pretrained neural net
+        images, a batch of images [batch_size, 3, 32, 32], which have been
+            pre-processed
+        dev, the training device
+        synset_list: the synset of labels
+        topk, return the topk labels for each image.
+    '''
+    while True:
+        img_path = raw_input("Enter input image path('quit' to exit): ")
+        if img_path == 'quit':
+            return
+        if not os.path.exists(img_path):
+            print 'Path is invalid'
+            continue
+        img = read_image(img_path)
+        x = tensor.from_numpy(img.astype(np.float32)[np.newaxis,:])
+        x.to_device(dev)
+        y = net.predict(x)
+        y.to_host()
+        prob = tensor.to_numpy(y)
+        lbl = np.argsort(-prob[0])  # sort prob in descending order
+        print [synset_list[lbl[i]] for i in range(topk)]
+
+
+if __name__ == '__main__':
+    parser = argparse.ArgumentParser(
+        description='Convert caffe vgg into singa. \
+            This tool only supports caffe model in current version(29-Nov-2016). \
+            You can use caffe tool to update previous model')
+    parser.add_argument('--model_txt', default='./vgg16.prototxt')
+    parser.add_argument('--model_bin', default='./vgg16.caffemodel')
+    parser.add_argument('--imgclass', default='./synset_words.txt')
+    args = parser.parse_args()
+
+    check_path(args.model_txt)
+    check_path(args.model_bin)
+    check_path(args.imgclass)
+
+    model = convert_model(args.model_txt, args.model_bin)
+    dev = device.get_default_device()
+    model.to_device(dev)
+
+    with open(args.imgclass, 'r') as fd:
+        syn_li = [line.split(' ', 1)[1].strip('\n') for line in fd.readlines()]
+
+    predict(model, dev, synset_list=syn_li, topk=5)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/examples/caffe/run.sh
----------------------------------------------------------------------
diff --git a/examples/caffe/run.sh b/examples/caffe/run.sh
new file mode 100755
index 0000000..4845f7b
--- /dev/null
+++ b/examples/caffe/run.sh
@@ -0,0 +1,51 @@
+#!/bin/bash
+if [[ $# -ne 1 ]]; then
+    echo "usage: $0 model_name"
+    echo "   model_name: [vgg16|vgg19], ..."
+    exit -1
+fi
+
+if [[ $1 == "vgg19" ]]; then
+    echo "Downloading label list..."
+    if [[ ! -f synset_words.txt ]]; then
+        wget -c https://www.dropbox.com/s/qe66xwwc78q7fe5/synset_words.txt?dl=0 -O synset_words.txt
+    fi
+    echo "Downloading vgg19..."
+    if [[ ! -f vgg19.prototxt ]]; then
+        wget -c https://www.dropbox.com/s/ehi6dxxp3s1rl8t/vgg19.prototxt?dl=0 -O vgg19.prototxt
+    fi
+
+    if [[ ! -f vgg19.caffemodel ]]; then
+        wget -c https://www.dropbox.com/s/y8ksbfp3iq0kvdn/vgg19.caffemodel?dl=0 -O vgg19.caffemodel
+    fi
+    echo "Downloading test images..."
+    if [[ ! -d test ]]; then
+        wget -c https://www.dropbox.com/s/ch5ktahijwof6ka/test.tar.gz?dl=0 -O test.tar.gz
+        tar -zxvf test.tar.gz
+    fi
+    echo "Converting..."
+    python predict.py ./vgg19.prototxt ./vgg19.caffemodel ./synset_words.txt ./test
+
+elif [[ $1 == "vgg16" ]]; then
+    echo "Downloading label list..."
+    if [[ ! -f synset_words.txt ]]; then
+        wget -c https://www.dropbox.com/s/qe66xwwc78q7fe5/synset_words.txt?dl=0 -O synset_words.txt
+    fi
+    echo "Downloading vgg16..."
+    if [[ ! -f vgg16.prototxt ]]; then
+        wget -c https://www.dropbox.com/s/ilpt58tle8jqtxj/vgg16.prototxt?dl=0 -O vgg16.prototxt
+    fi
+
+    if [[ ! -f vgg16.caffemodel ]]; then
+        wget -c https://www.dropbox.com/s/3qidow3qr77ruob/vgg16.caffemodel?dl=0 -O vgg16.caffemodel
+    fi
+    echo "Downloading test images..."
+    if [[ ! -d test ]]; then
+        wget -c https://www.dropbox.com/s/ch5ktahijwof6ka/test.tar.gz?dl=0 -O test.tar.gz
+        tar -zxvf test.tar.gz
+    fi
+    echo "Converting..."
+    python predict.py ./vgg16.prototxt ./vgg16.caffemodel ./synset_words.txt ./test
+else
+    echo "unsupported model: $1"
+fi

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/examples/caffe_vgg/README.md
----------------------------------------------------------------------
diff --git a/examples/caffe_vgg/README.md b/examples/caffe_vgg/README.md
deleted file mode 100644
index 7661242..0000000
--- a/examples/caffe_vgg/README.md
+++ /dev/null
@@ -1,23 +0,0 @@
-#Convert model parameter of caffe to singa
-
-## Run this example
-You can run this example by simply execute `run.sh vgg16` or `run.sh vgg19`
-
-## Obtain caffe model
-* Download caffe model prototxt and parameter binary file. 
-* Currently we only support the latest caffe format, if your model is in
-    previous version of caffe, please update it to current format.(This is
-    supported by caffe)
-* After updating, we can obtain two files, i.e., the prototxt and parameter
-    binary file.
-
-## Prepare test images
-As an example, we just put several images in a single folder, for example,
-`./test`, the program will load all images in the folder and will run to test.
-
-## Predict
-Run `predict.py`
-`usage: predict.py [-h] model_txt model_bin imgclass testdir`
-where `imgclass` refers to the synsets of imagenet dataset for vgg models.
-In vgg example, you can run it by executing the following command:
-`python predict.py ./vgg16.prototxt ./vgg16.caffemodel ./synset_words.txt ./test`

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/examples/caffe_vgg/predict.py
----------------------------------------------------------------------
diff --git a/examples/caffe_vgg/predict.py b/examples/caffe_vgg/predict.py
deleted file mode 100644
index f49fd7e..0000000
--- a/examples/caffe_vgg/predict.py
+++ /dev/null
@@ -1,124 +0,0 @@
-# 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 numpy as np
-import os
-import argparse
-from PIL import Image
-
-from singa import device
-from singa import tensor
-from singa import converter
-from singa import layer
-from singa import net
-
-#for debug: print norm of each layer
-#net.verbose = True
-
-
-def convert_model(prototxt, caffemodel):
-    cvt = converter.CaffeConverter(net_proto=prototxt, param_path=caffemodel)
-    model = cvt.create_net()
-    cvt.convert_params(model)
-    return model
-
-
-def check_path(path):
-    assert os.path.exists(
-        path), 'File not found: ' + path
-
-
-def synset_list(sw_path):
-    with open(sw_path, 'rb') as synsets:
-        syn_li = []
-        for line in synsets:
-            syn_word = line.split(' ', 1)[1].strip('\n')
-            syn_li.append(syn_word)
-        return syn_li
-
-
-def load_test_data(test_dir, mean):
-    paths = os.listdir(test_dir)
-    print paths
-    test = []
-    for path in paths:
-        img = Image.open(os.path.join(test_dir, path))
-        # BGR is the default model in caffe
-        # convert RGB to BGR
-        img = img.convert('RGB')
-        r, g, b = img.split()
-        img = Image.merge('RGB', (b, g, r))
-        resized = img.resize((224, 224))
-        # order of axes: width,height,channel
-        img_ary = np.asarray(resized, dtype=np.float32)
-        img_ary -= mean
-        img_ary = np.swapaxes(img_ary, 0, 2)
-        test.append(img_ary)
-    return np.asarray(test)
-
-
-def predict(net, images, dev, synset_list=None, topk=5):
-    '''Predict the label of each image.
-
-    Args:
-        net, a pretrained neural net
-        images, a batch of images [batch_size, 3, 32, 32], which have been
-            pre-processed
-        dev, the training device
-        synset_list: the synset of labels
-        topk, return the topk labels for each image.
-    '''
-    x = tensor.from_numpy(images.astype(np.float32))
-    x.to_device(dev)
-    y = net.predict(x)
-    y.to_host()
-    prob = tensor.to_numpy(y)
-    labels = np.fliplr(np.argsort(prob))  # sort prob in descending order
-    print labels[:, 0:topk]
-    for i in range(labels.shape[0]):
-        l = [synset_list[labels[i][j]] for j in range(topk)]
-        print l
-
-
-if __name__ == '__main__':
-    parser = argparse.ArgumentParser(
-        description='Convert caffe vgg into singa. \
-            This tool only supports caffe model in current version(29-Nov-2016). \
-            You can use caffe tool to update previous model')
-    parser.add_argument('model_txt', default='./vgg16.prototxt')
-    parser.add_argument('model_bin', default='./vgg16.caffemodel')
-    parser.add_argument('imgclass', default='./synset_words.txt')
-    parser.add_argument('testdir', default='./test/')
-    args = parser.parse_args()
-
-    check_path(args.model_txt)
-    check_path(args.model_bin)
-    check_path(args.imgclass)
-    check_path(args.testdir)
-
-    model = convert_model(args.model_txt, args.model_bin)
-    dev = device.get_default_device()
-    model.to_device(dev)
-
-    syn_li = synset_list(args.imgclass)
-
-    # According to the VGG paper(Very Deep Convolutional Networks for
-    # Large-Scale Image Recognition), the input images are zero-centered by
-    # mean pixel(rather than mean image) substraction.
-    mean_BGR =[103.939, 116.779, 123.68]
-    test_images = load_test_data(args.testdir, mean_BGR)
-
-    predict(model, test_images, dev, synset_list=syn_li, topk=5)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/examples/caffe_vgg/run.sh
----------------------------------------------------------------------
diff --git a/examples/caffe_vgg/run.sh b/examples/caffe_vgg/run.sh
deleted file mode 100755
index 4845f7b..0000000
--- a/examples/caffe_vgg/run.sh
+++ /dev/null
@@ -1,51 +0,0 @@
-#!/bin/bash
-if [[ $# -ne 1 ]]; then
-    echo "usage: $0 model_name"
-    echo "   model_name: [vgg16|vgg19], ..."
-    exit -1
-fi
-
-if [[ $1 == "vgg19" ]]; then
-    echo "Downloading label list..."
-    if [[ ! -f synset_words.txt ]]; then
-        wget -c https://www.dropbox.com/s/qe66xwwc78q7fe5/synset_words.txt?dl=0 -O synset_words.txt
-    fi
-    echo "Downloading vgg19..."
-    if [[ ! -f vgg19.prototxt ]]; then
-        wget -c https://www.dropbox.com/s/ehi6dxxp3s1rl8t/vgg19.prototxt?dl=0 -O vgg19.prototxt
-    fi
-
-    if [[ ! -f vgg19.caffemodel ]]; then
-        wget -c https://www.dropbox.com/s/y8ksbfp3iq0kvdn/vgg19.caffemodel?dl=0 -O vgg19.caffemodel
-    fi
-    echo "Downloading test images..."
-    if [[ ! -d test ]]; then
-        wget -c https://www.dropbox.com/s/ch5ktahijwof6ka/test.tar.gz?dl=0 -O test.tar.gz
-        tar -zxvf test.tar.gz
-    fi
-    echo "Converting..."
-    python predict.py ./vgg19.prototxt ./vgg19.caffemodel ./synset_words.txt ./test
-
-elif [[ $1 == "vgg16" ]]; then
-    echo "Downloading label list..."
-    if [[ ! -f synset_words.txt ]]; then
-        wget -c https://www.dropbox.com/s/qe66xwwc78q7fe5/synset_words.txt?dl=0 -O synset_words.txt
-    fi
-    echo "Downloading vgg16..."
-    if [[ ! -f vgg16.prototxt ]]; then
-        wget -c https://www.dropbox.com/s/ilpt58tle8jqtxj/vgg16.prototxt?dl=0 -O vgg16.prototxt
-    fi
-
-    if [[ ! -f vgg16.caffemodel ]]; then
-        wget -c https://www.dropbox.com/s/3qidow3qr77ruob/vgg16.caffemodel?dl=0 -O vgg16.caffemodel
-    fi
-    echo "Downloading test images..."
-    if [[ ! -d test ]]; then
-        wget -c https://www.dropbox.com/s/ch5ktahijwof6ka/test.tar.gz?dl=0 -O test.tar.gz
-        tar -zxvf test.tar.gz
-    fi
-    echo "Converting..."
-    python predict.py ./vgg16.prototxt ./vgg16.caffemodel ./synset_words.txt ./test
-else
-    echo "unsupported model: $1"
-fi

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bd41fd1d/python/singa/converter.py
----------------------------------------------------------------------
diff --git a/python/singa/converter.py b/python/singa/converter.py
index 64204be..cc42ef0 100644
--- a/python/singa/converter.py
+++ b/python/singa/converter.py
@@ -186,7 +186,7 @@ class CaffeConverter:
         first_conv = True
         for layer in layers:
             if layer.type == 'Convolution' or layer.type == 'InnerProduct':
-                assert(len(layer.blobs) == 2)
+                assert(len(layer.blobs) == 2), 'Either 2 params per layer or 0'
                 wmat_dim = []
                 if getattr(layer.blobs[0].shape, 'dim', None) is not None:
                     if len(layer.blobs[0].shape.dim) > 0:
@@ -199,7 +199,7 @@ class CaffeConverter:
                 else:
                     wmat_dim = list(layer.blobs[0].shape)
 
-                wmat = np.array(layer.blobs[0].data, dtype=np.float32).reshape(wmat_dim)
+                wmat = np.array(layer.blobs[0].data, dtype=np.float32)
                 bias = np.array(layer.blobs[1].data, dtype=np.float32)
                 #print layer.name, ' wmat_dim: ', wmat_dim
 
@@ -207,6 +207,10 @@ class CaffeConverter:
                 if layer.type == 'InnerProduct':
                     wdim = wmat_dim[-2:]
                 else:
+                    if wmat_dim[1] == 3 and first_conv:  # BGR -> RGB
+                        wmat = wmat.reshape(wmat_dim)
+                        wmat[:, [0, 1, 2], :, :] = wmat[:, [2, 1, 0], :, :]
+                        first_conv = False
                     nb_filters = wmat_dim[0]
                     chw = 1
                     for k in range(1, len(wmat_dim)):
@@ -215,6 +219,7 @@ class CaffeConverter:
                 #print layer.name, ' wdim: ', wdim
                 w = np.reshape(wmat, wdim)
 
+                # TODO(wangwei) transpose SINGA's weight following caffe
                 if layer.type == 'InnerProduct':
                     w = np.transpose(w)
                 params[i].copy_from_numpy(w)
@@ -222,4 +227,3 @@ class CaffeConverter:
                 params[i].copy_from_numpy(bias)
                 i += 1
                 print 'converting layer {0}, wmat shape = {1}, bias shape = {2}'.format(layer.name,
w.shape, bias.shape)
-


Mime
View raw message