Skip to content

[Testing Team] Template testing tutorial using SWIG

Sarah Aguasvivas edited this page May 18, 2020 · 68 revisions

Q & A:

Do I need to have figured out nn4mc's full installation before this? (Including nlohmann-json and h5cpp) Not necessarily

Installing SWIG:

Linux:
$ sudo apt-get install -y swig
$ sudo apt-get install python-dev #doesn't hurt to have
Mac OSX:

$ brew install swig

Step 1: Acquire the testing branch called testing_templates:

You can use your favorite method, but if you have to Google it just do this:

$ git fetch origin

Then set a local branch to track the remote testing branch.

$ git branch --track [testing_templates] origin/testing_templates
$ git checkout testing_templates

In this branch, all of the generated code from nn4mc will appear under the file called testing_output_files/ in root.

Now you are in the testing branch. Within this branch go to the testing_output_files/ folder. Whenever a new code is generated (I set out the generated codes to do to the `testing_output_files/code_test' folder in this branch).

Testing activation module [Etash]:

Go to testing_output_files/src/activation/ If you are interested in testing activation.cpp, it should already be good to go and just type `python3.7 -c "import activation" if there are no errors you should be able to start building testing code. However, if there are errors or you want to test code that is not wrapped yet, you might have to use the following instructions to wrap the code to be tested. If it needs compiling go to these instructions.

Building new wrapper code:

For this example I'm going to be testing activations.cpp you can import the function prototypes that you want to read into Python this way:

activations.i:

/* File: activation.i:

    This is the file that gives us enough to wrap the code. 
    Here we introduce headers that import the functions or header
    files. Since activations.h also imports all of the function 
    prototypes from activation.cpp, you only need to import the 
    header.
*/

%include "../../code_test/activations.cpp"
%include "../../code_test/activations.h"
%module activation
%{
 extern float activate(float input, int output_shape, char type);
 
 extern float sigmoid(float input);
 
 extern float softplus(float input);
 
 extern float softsign(float input);
 
 extern float hard_sigmoid(float input);
 
 extern float exponential(float input);
 
 extern float relu(float input);
 
 extern float hyper_tan(float input);
 
 extern float softmax(float input, int output_shape);

%}

 extern float activate(float input, int output_shape, char type);
 
 extern float sigmoid(float input);
 
 extern float softplus(float input);
 
 extern float softsign(float input);
 
 extern float hard_sigmoid(float input);
 
 extern float exponential(float input);
 
 extern float relu(float input);
 
 extern float hyper_tan(float input);
 
 extern float softmax(float input, int output_shape);

Go to testing_output_files/src and run:

Step 2: Wrap the code into a Python module:

For Linux:

$ swig -python -c++ activation.i
$ c++ -c -fpic ../../code_test/activations.cpp
$ c++ -c -fpic activation_wrap.cxx -I/usr/include/python3.5
$ c++ -shared activations.o activation_wrap.o -o _activation.so

If you compile this wrapper in python3.5, you should feel free to use it for python conda versions >=3.5. For example, to test if it worked just type $ python3.7 -c "import activation" into the command line and if there are no import errors you are ready to go.

For Apple computers:

$ swig -python -c++ activation.i
$ c++ -c -fpic ../../code_test/activations.cpp
$ c++ -c -fpic activation_wrap.cxx -I/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/include/python3.7m
$ c++ -bundle -flat_namespace activations.o activation_wrap.o -undefined suppress -o _activation.so

Step 3: Build your testing module:

Then, when building your testing module, make sure you import the c code (now Python code) as:

testing_module.py:

import activation
from testing_output_files.template_test import TemplateTest
[...]

class ActivationTest(TemplateTest):
     def __init__(self):
          [...]
     def individual_functions_test(self):
          [...]
     def passes(self)->bool:
          [...] # this method is necessary to all TemplateTest objects

[Your Python code]

To access the functions specified in the activation module, just type, for example, activation.sigmoid(3.5).

If you get an error that says that Python.h wasn't found, that means that the include path in the second command is wrong or doesn't lead to the right folders. To find where python is installed in you Mac type:

$ find / -name 'Python.h'

for Linux machines: sudo apt-get install python-dev

Then substitute the path after the -I part of the command for the path that you found using find.

If you get an error saying ld: symbol(s) not found for architecture x86_64, then substitute the last command for:

clang $(python3-config --ldflags) -dynamiclib activations_wrap.o activations.o -o _activations.so

Possible errors:

In short, undefined symbol may occur when the function prototype in the .h file is different than the implementation in the .cpp.

Example: Code that requires multiple other code files

In this case I'll be testing conv1d, which requires activation.cpp's functions. Here is the list of commands (for MacOS):

Handling the const float * issue:

Link to guide on this

Go to the testing_output_files/ and run:

$ python -c "import numpy; print(numpy.get_include())"

See the path that gets printed from there and include that path in the following swig lines:

$ swig -python -c++ conv1d.i
$  c++ -c -fpic -I/Users/sarahaguasvivas/anaconda3/lib/python3.7/site-packages/numpy/core/include 
 ../../code_test/conv1d.cpp ../../code_test/activations.cpp
$ c++ -c -fpic conv1d_wrap.cxx -I/usr/local/Cellar/python/3.7.7/Frameworks/Python.framework/Versions/3.7/include/python3.7m -I/Users/sarahaguasvivas/anaconda3/lib/python3.7/site-packages/numpy/core/include
$ c++ -bundle -flat_namespace conv1d.o activations.o conv1d_wrap.o -undefined suppress -o _conv1d.so