SINGA-217 build python package with setup.py
  - Singa python binding, package with pip or create wheel
  - In the cmake file, specify USE_PYTHON ON, then cmake and make.
    After that run "<sudo> pip install ." under "build/python" path
    User can run command 'singa' in a model workspace to serve and train
  - dependent on numpy>=1.11.0; protobuf>=2.5.0,<3; flask>=0.10.1
    Users should also install openblas
  - Models are sharing on github gists.
  - Todo, optimize cmake compile method to avoid compile source file twice
    refine singa command


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

Branch: refs/heads/master
Commit: bf81f252647f60d525ffc9ddfa7031183afbc6e5
Parents: 05720c2
Author: aaronwwf <[email protected]>
Authored: Wed Jul 20 17:23:19 2016 +0800
Committer: aaronwwf <[email protected]>
Committed: Thu Aug 11 16:55:43 2016 +0800

----------------------------------------------------------------------
 CMakeLists.txt                |   5 +-
 cmake/Dependencies.cmake      |   2 +-
 include/singa/core/device.h   |   3 +
 src/CMakeLists.txt            |  39 +++---
 src/python/setup.py.in        |   7 +-
 src/python/singa/__init__.py  | 244 ++++++++++++++++++++++++++++++++++++-
 src/python/singa/net.py       |   2 +-
 src/python/swig/config.i.in   |   5 +
 src/python/swig/core_device.i |   2 +
 src/python/swig/model_layer.i |   6 +
 src/python/swig/singa.i       |   1 +
 test/python/test_layer.py     |   2 +-
 12 files changed, 285 insertions(+), 33 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 9efadc0..9c4f326 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,6 +1,7 @@
 CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
 
 PROJECT(singa)
+SET(PACKAGE_VERSION "1.0.0")
 SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -g -O2 ")
 
 LIST(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake/Thirdparty)
@@ -19,8 +20,8 @@ SET(SINGA_INCLUDE_DIR
 INCLUDE_DIRECTORIES(${SINGA_INCLUDE_DIR})
 
 OPTION(USE_CBLAS "Use CBlas libs" ON)
-OPTION(USE_CUDA "Use Cuda libs" ON)
-OPTION(USE_CUDNN "Use Cudnn libs" ON)
+OPTION(USE_CUDA "Use Cuda libs" OFF)
+OPTION(USE_CUDNN "Use Cudnn libs" OFF)
 OPTION(USE_OPENCV "Use opencv" OFF)
 OPTION(USE_LMDB "Use LMDB libs" OFF)
 OPTION(USE_PYTHON "Generate py wrappers" ON)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/cmake/Dependencies.cmake
----------------------------------------------------------------------
diff --git a/cmake/Dependencies.cmake b/cmake/Dependencies.cmake
index 68d0bfc..ceef429 100644
--- a/cmake/Dependencies.cmake
+++ b/cmake/Dependencies.cmake
@@ -5,7 +5,7 @@ SET(SINGA_LINKER_LIBS "")
 FIND_PACKAGE( Protobuf REQUIRED )
 INCLUDE_DIRECTORIES(SYSTEM ${PROTOBUF_INCLUDE_DIR})
 MESSAGE(STATUS "proto libs " ${PROTOBUF_LIBRARIES})
-LIST(APPEND singa_linker_libs ${PROTOBUF_LIBRARIES})
+LIST(APPEND SINGA_LINKER_LIBS ${PROTOBUF_LIBRARIES})
 INCLUDE("cmake/Protobuf.cmake")
 
 IF(USE_LMDB)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/include/singa/core/device.h
----------------------------------------------------------------------
diff --git a/include/singa/core/device.h b/include/singa/core/device.h
index 4c46114..a564524 100644
--- a/include/singa/core/device.h
+++ b/include/singa/core/device.h
@@ -303,6 +303,7 @@ private:
 /// If CUDA or OPENCL are not enabled, then the respective related methods 
should
 /// return something that indicates their absence (for example, 0 devices);
 /// however they should always be available regardless of compile-time 
switches.
+#ifdef USE_CUDA
 class Platform {
 public:
 
@@ -372,6 +373,8 @@ private:
 #endif  // USE_OPENCL
 };
 
+#endif // USE_CUDA
+
 }  // namespace singa
 
 #endif  // SINGA_CORE_DEVICE_H_

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/CMakeLists.txt
----------------------------------------------------------------------
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 06f177d..66d89dc 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -6,6 +6,7 @@ IF (USE_PYTHON)
     protobuf_generate_python(proto_pys ${proto_files})
 ENDIF()
 INCLUDE_DIRECTORIES("${CMAKE_BINARY_DIR}/include")
+
 #message(STATUS "include: ${CMAKE_BINARY_DIR} ")
 #message(STATUS "srcs: ${proto_srcs}")
 #message(STATUS "hdrs: ${proto_hdrs}")
@@ -21,6 +22,8 @@ FOREACH(fil ${proto_hdrs})
 ENDFOREACH()
 LIST(APPEND SINGA_LINKER_LIBS proto)
 
+SET(PREVIOUS_LINKER_LIBS ${SINGA_LINKER_LIBS})
+
 #FILE(GLOB_RECURSE utils_source ${CMAKE_CURRENT_SOURCE_DIR}/utils/ "*.cc")
 AUX_SOURCE_DIRECTORY(utils utils_source)
 #message(STATUS "UTILS ${utils_source}")
@@ -28,7 +31,6 @@ ADD_LIBRARY(singa_utils SHARED ${utils_source})
 TARGET_LINK_LIBRARIES(singa_utils ${SINGA_LINKER_LIBS})
 LIST(APPEND SINGA_LINKER_LIBS singa_utils)
 
-
 #FILE(GLOB_RECURSE core_source ${CMAKE_CURRENT_SOURCE_DIR}/core/ "*.cc")
 AUX_SOURCE_DIRECTORY(core/device core_source)
 AUX_SOURCE_DIRECTORY(core/memory core_source)
@@ -74,18 +76,11 @@ ADD_LIBRARY(singa_io SHARED ${io_source})
 TARGET_LINK_LIBRARIES(singa_io ${SINGA_LINKER_LIBS})
 LIST(APPEND SINGA_LINKER_LIBS singa_io)
 
-#ADD_LIBRARY(singa_layer SHARED ${LAYER_SOURCE})
-#ADD_LIBRARY(singa_model SHARED ${MODEL_SOURCE})
-#ADD_LIBRARY(singa_utils SHARED ${UTILS_SOURCE})
-
-#TARGET_LINK_LIBRARIES(singa_core singa_utils)
-#TARGET_LINK_LIBRARIES(singa_layer singa_core singa_utils)
-#TARGET_LINK_LIBRARIES(singa_model singa_layer singa_core singa_utils)
-
-#ADD_LIBRARY(singa SHARED ${SINGA_LINKER_LIBS})
-
 IF(USE_PYTHON)
 
+    FILE(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/python/swig/config.i")
+    CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/python/swig/config.i.in" 
"${CMAKE_CURRENT_SOURCE_DIR}/python/swig/config.i")
+
     FILE(GLOB python_files python/swig/singa.i)
     # delete old .cxx file
     FILE(REMOVE "${CMAKE_CURRENT_SOURCE_DIR}/python/swig/singa_wrap.cxx")
@@ -98,17 +93,13 @@ IF(USE_PYTHON)
     file(GLOB_RECURSE python_source_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} 
*.py)
 
     create_symlinks(${python_source_files})
-
-    FILE(GLOB_RECURSE layer_source_files 
${CMAKE_SOURCE_DIR}/src/model/layer/*.cc)
-    # message(STATUS "layer_source_files ${layer_source_files}")
-    FILE(GLOB_RECURSE metric_source_files 
${CMAKE_SOURCE_DIR}/src/model/metric/*.cc)
-    FILE(GLOB_RECURSE loss_source_files 
${CMAKE_SOURCE_DIR}/src/model/loss/*.cc)
-    SET(python_cxxs 
"${CMAKE_SOURCE_DIR}/src/core/tensor/tensor.cc;${CMAKE_SOURCE_DIR}/src/core/device/device.cc;${layer_source_files};${metric_source_files};${loss_source_files}")
-    ADD_LIBRARY(_singa_wrap SHARED ${python_srcs} ${python_cxxs})
-    SET(WRAPPER_LINKER_LIBS "${SINGA_LINKER_LIBS};protobuf")
+    
+    SET(python_cxxs 
"${core_source};${io_source};${model_source};${utils_source}")
+    ADD_LIBRARY(_singa_wrap SHARED ${python_srcs} ${python_cxxs} ${cuda_objs})
+    SET(WRAPPER_LINKER_LIBS "${PREVIOUS_LINKER_LIBS}")
     TARGET_LINK_LIBRARIES(_singa_wrap ${WRAPPER_LINKER_LIBS})
     TARGET_INCLUDE_DIRECTORIES(_singa_wrap PRIVATE ${PYTHON_INCLUDE_DIRS})
-    #message(STATUS "PYTHON_INCLUDE_DIRS ${PYTHON_INCLUDE_DIRS}")
+    #message(STATUS "PREVIOUS_LINKER_LIBS ${PREVIOUS_LINKER_LIBS}")
 
     SET_TARGET_PROPERTIES(_singa_wrap
         PROPERTIES PREFIX ""
@@ -117,10 +108,10 @@ IF(USE_PYTHON)
 
     #SETUP
     SET(SETUP_PY_IN "python/setup.py.in")
-    set(SETUP_PY    "${CMAKE_BINARY_DIR}/python/setup.py")
-    configure_file(${SETUP_PY_IN} ${SETUP_PY})
+    SET(SETUP_PY    "${CMAKE_BINARY_DIR}/python/setup.py")
+    CONFIGURE_FILE(${SETUP_PY_IN} ${SETUP_PY})
 
-    #COPY protobuf files to python/singa/proto
-    FILE(COPY ${CMAKE_BINARY_DIR}/python/singa/__init__.py DESTINATION 
${CMAKE_BINARY_DIR}/python/singa/proto )
+    #create python/singa/proto/__init__.py
+    FILE(WRITE ${CMAKE_BINARY_DIR}/python/singa/proto/__init__.py "")
 
 ENDIF(USE_PYTHON)

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/setup.py.in
----------------------------------------------------------------------
diff --git a/src/python/setup.py.in b/src/python/setup.py.in
index b53e54b..d1ac3c9 100644
--- a/src/python/setup.py.in
+++ b/src/python/setup.py.in
@@ -40,7 +40,12 @@ setup(
 
     #py_modules=["singa"],
 
-    #install_requires=['peppercorn'],
+    install_requires=[
+        'numpy>=1.11.0',
+        'protobuf>=2.5.0,<3',
+        'flask>=0.10.1'
+        ],
+
     #List additional groups of dependencies here (e.g. development
     #dependencies). You can install these using the following syntax,
     #for example:

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/singa/__init__.py
----------------------------------------------------------------------
diff --git a/src/python/singa/__init__.py b/src/python/singa/__init__.py
index d5e48bb..ec26906 100644
--- a/src/python/singa/__init__.py
+++ b/src/python/singa/__init__.py
@@ -1,3 +1,241 @@
-def main():
-    """Entry point for the application script"""
-    print("Welcome to SINGA!")
+# 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 script is the main entrance for user to run singa inside a model workspace
+
+To use this script, user sudo install these dependencies: flask pillow and 
protobuf 
+'''
+
+import sys, glob, os, random, shutil, time
+from flask import Flask, request, redirect, url_for
+from PIL import Image
+import numpy as np
+import ConfigParser 
+import urllib, traceback
+
+
+from argparse import ArgumentParser
+from argparse import RawDescriptionHelpFormatter
+sys.path.append(os.getcwd())
+
+__all__ = []
+__version__ = 0.1
+__date__ = '2016-07-20'
+__updated__ = '2016-07-20'
+__shortdesc__ = '''
+welcome to singa
+'''
+
+app = Flask(__name__)
+config = ConfigParser.RawConfigParser()    
+service = {}
+data_path = "data_"
+parameter_path = "parameter_"
+
+debug = False
+
+class CLIError(Exception):
+    '''Generic exception to raise and log different fatal errors.'''
+    def __init__(self, msg):
+        super(CLIError).__init__(type(self))
+        self.msg = "E: %s" % msg
+    def __str__(self):
+        return self.msg
+    def __unicode__(self):
+        return self.msg
+
+def main(argv=None): # IGNORE:C0111
+    '''Command line options.'''
+
+    from . import device
+
+    if argv is None:
+        argv = sys.argv
+    else:
+        sys.argv.extend(argv)
+
+    program_name = os.path.basename(sys.argv[0])
+    program_version = "v%s" % __version__
+    program_build_date = str(__updated__)
+    program_version_message = '%%(prog)s %s (%s)' % (program_version, 
program_build_date)
+    program_shortdesc = __shortdesc__
+    program_license = '''%s
+
+  Created by dbsystem group on %s.
+  Copyright 2016 NUS School of Computing. All rights reserved.
+
+  Licensed under the Apache License 2.0
+  http://www.apache.org/licenses/LICENSE-2.0
+
+  Distributed on an "AS IS" basis without warranties
+  or conditions of any kind, either express or implied.
+
+USAGE
+''' % (program_shortdesc, str(__date__))
+
+    global debug
+
+    try:
+        # Setup argument parser
+        parser = ArgumentParser(description=program_license, 
formatter_class=RawDescriptionHelpFormatter)
+        parser.add_argument("-p", "--port", dest="port", default=5000, 
help="the port to listen to, default is 5000")
+        parser.add_argument("-param", "--parameter", dest="parameter",  
help="the parameter file path to be loaded")
+        parser.add_argument("-D", "--debug", dest="debug", 
action="store_true", help="whether need to debug")
+        parser.add_argument("-R", "--reload", dest="reload_data", 
action="store_true", help="whether need to reload data")
+        parser.add_argument("-C", "--cpu", dest="use_cpu", 
action="store_true", help="Using cpu or not, default is using gpu")
+        parser.add_argument("-m", "--mode", dest="mode", 
choices=['train','test','serve'], default='serve', help="On Which mode 
(train,test,serve) to run singa")
+        parser.add_argument('-V', '--version', action='version', 
version=program_version_message)
+
+        # Process arguments
+        args = parser.parse_args()
+
+        port = args.port
+        parameter_file = args.parameter
+        mode = args.mode
+        need_reload = args.reload_data
+        use_cpu = args.use_cpu
+        debug = args.debug
+
+        #prepare data files
+        config.read('file.cfg')
+        file_prepare(need_reload)
+
+
+        import network as net
+        model = net.create()
+
+        #load parameter
+        parameter_file=get_parameter(parameter_file)
+
+        if parameter_file:
+            print "load parameter file: %s" % parameter_file
+            model.load(parameter_file)
+        
+        if use_cpu:
+            raise CLIError("Currently cpu is not support!")
+        else:
+            print "runing with gpu"
+            d = device.create_cuda_gpu()
+
+        model.to_device(d)
+
+        if mode == "serve":
+            print "runing singa in serve mode, listen to  port: %s " % port
+            global service
+            from serve import Service
+            service =Service(model,d)
+
+            app.debug = debug 
+            app.run(host='0.0.0.0', port= port)
+        elif mode == "train":
+            print "runing singa in train mode"
+            global trainer 
+            from train import Trainer 
+            trainer= Trainer(model,d)
+            if not parameter_file:
+                trainer.initialize()
+            trainer.train()
+        else:
+            raise CLIError("Currently only serve mode is surpported!")
+        return 0
+    except KeyboardInterrupt:
+        ### handle keyboard interrupt ###
+        return 0
+    except Exception, e:
+        if debug:
+            traceback.print_exc()
+            raise(e)
+        indent = len(program_name) * " "
+        sys.stderr.write(program_name + ": " + str(e) + "\n")
+        sys.stderr.write(indent + "  for help use --help \n\n")
+        return 2
+
+def file_prepare(reload_data=False):
+    '''
+        download all files and generate data.py
+    '''
+    if not reload_data and os.path.exists("data_.py"):
+        return
+
+    print "download file"
+    #clean data
+    shutil.rmtree("data_.py",ignore_errors=True)
+    shutil.rmtree("data_",ignore_errors=True)
+
+    data_py=open("data_.py",'w') 
+    data_py.write("#%s" % "This file is Generated by SINGA, please don't 
edit\n\n")
+    if config.has_section("data"):
+        file_list = config.items("data")
+        #download files
+        for f in file_list:
+            name,path=download_file(f[0],f[1],data_path)
+            data_py.write("%s=\"%s\"\n" % (name,path)) 
+
+    data_py.flush()
+    data_py.close()
+    
+    if config.has_section("parameter"):
+        parameter_list = config.items("parameter")
+        for p in parameter_list:
+            download_file(p[0],p[1],parameter_path)
+
+def download_file(name,path,dest):
+    '''
+    download one file to dest
+    '''
+    if not os.path.exists(dest):
+        os.makedirs(dest)
+    if (path.startswith('http')):
+        file_name = path.split('/')[-1]
+        target = os.path.join(dest,file_name)
+        urllib.urlretrieve(path,target)
+    return name,target
+
+
+def get_parameter(file_name=None):
+    '''
+    get the paticular file name or get the last parameter file
+    '''
+    if not os.path.exists(parameter_path):
+        os.makedirs(parameter_path)
+        return 
+
+    if file_name:
+       return os.path.join(parameter_path,file_name)
+
+    parameter_list = [ os.path.join(parameter_path,f) for f in 
os.listdir(parameter_path)]
+    if len(parameter_list)==0:
+        return
+    parameter_list.sort()
+
+    return parameter_list[-1]
+       
[email protected]("/")
+def index():
+    return "Hello SINGA User!"
+
[email protected]('/predict', methods=['POST'])
+def predict():
+    if request.method == 'POST':
+        try:
+            response=service.serve(request)
+        except Exception as e:
+            return e
+        return response
+    return "error, should be post request"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/singa/net.py
----------------------------------------------------------------------
diff --git a/src/python/singa/net.py b/src/python/singa/net.py
index 1617717..f040378 100644
--- a/src/python/singa/net.py
+++ b/src/python/singa/net.py
@@ -48,7 +48,7 @@ class FeedForwardNet(object):
         """
         if len(self.layers) > 0 and lyr.has_setup is False:
             shape = self.layers[-1].get_output_sample_shape()
-            print shape
+            #print shape
             lyr.setup(shape)
         self.layers.append(lyr)
 

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/swig/config.i.in
----------------------------------------------------------------------
diff --git a/src/python/swig/config.i.in b/src/python/swig/config.i.in
new file mode 100644
index 0000000..ed386b2
--- /dev/null
+++ b/src/python/swig/config.i.in
@@ -0,0 +1,5 @@
+// Pass in cmake configurations to swig
+#cmakedefine01 USE_CUDA 
+#cmakedefine01 USE_CUDNN 
+#cmakedefine CUDNN_VERSION_MAJOR ${CUDNN_VERSION_MAJOR}
+#cmakedefine CUDNN_VERSION_PATCH ${CUDNN_VERSION_PATCH} 

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/swig/core_device.i
----------------------------------------------------------------------
diff --git a/src/python/swig/core_device.i b/src/python/swig/core_device.i
index a5d0731..21b97b4 100644
--- a/src/python/swig/core_device.i
+++ b/src/python/swig/core_device.i
@@ -49,6 +49,7 @@ class Device {
   int id() const;
 };
 
+#if USE_CUDA
 class Platform {
  public:
   static int GetNumGPUs();
@@ -63,5 +64,6 @@ class Platform {
   static std::shared_ptr<Device> GetDefaultDevice();
 };
 
+#endif // USE_CUDA
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/swig/model_layer.i
----------------------------------------------------------------------
diff --git a/src/python/swig/model_layer.i b/src/python/swig/model_layer.i
index a6cdad1..f82b0f1 100644
--- a/src/python/swig/model_layer.i
+++ b/src/python/swig/model_layer.i
@@ -44,7 +44,9 @@ using singa::LayerConf;
 
 %shared_ptr(singa::Layer)
 %shared_ptr(singa::RNN)
+#if USE_CUDNN
 %shared_ptr(singa::CudnnRNN)
+#endif
 
 namespace std {
   %template(strVector) vector<string>;
@@ -81,6 +83,8 @@ const std::vector<std::string> GetRegisteredLayers();
 class RNN : public Layer {
 };
 
+#if USE_CUDA && USE_CUDNN
+#if CUDNN_VERSION_MAJOR >= 5 && CUDNN_VERSION_PATCH >= 5
 class CudnnRNN : public RNN {
  public:
  // note: Must use std::vector instead of vector.
@@ -92,5 +96,7 @@ class CudnnRNN : public RNN {
     const std::vector<size_t> GetOutputSampleShape() const override;
 };
 
+#endif  // CUDNN_VERSION_MINOR >= 5 && CUDNN_VERSION_PATCH >= 5
+#endif  // USE_CUDA && USE_CUDNN
 }
 

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/src/python/swig/singa.i
----------------------------------------------------------------------
diff --git a/src/python/swig/singa.i b/src/python/swig/singa.i
index 3f12569..12f46f3 100644
--- a/src/python/swig/singa.i
+++ b/src/python/swig/singa.i
@@ -22,6 +22,7 @@
 /*interface file for swig */
 
 %module singa_wrap
+%include "config.i"
 %include "core_tensor.i"
 %include "core_device.i"
 %include "model_layer.i"

http://git-wip-us.apache.org/repos/asf/incubator-singa/blob/bf81f252/test/python/test_layer.py
----------------------------------------------------------------------
diff --git a/test/python/test_layer.py b/test/python/test_layer.py
index 7e1059e..7078240 100644
--- a/test/python/test_layer.py
+++ b/test/python/test_layer.py
@@ -3,7 +3,7 @@ import os
 import unittest
 import numpy as np
 
-sys.path.append(os.path.join(os.path.dirname(__file__), '../../build/python'))
+#sys.path.append(os.path.join(os.path.dirname(__file__), '../../build/python'))
 
 from singa import layer
 from singa import device

Reply via email to