You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mxnet.apache.org by GitBox <gi...@apache.org> on 2019/01/14 10:56:51 UTC

[GitHub] hengdos opened a new issue #13870: [C++] Linking static library (error or bug?) to load python trained model

hengdos opened a new issue #13870: [C++] Linking static library (error or bug?) to load python trained model
URL: https://github.com/apache/incubator-mxnet/issues/13870
 
 
   Hi. I'm trying to train a simple model using python api and load the trained model for predicting using c++ api.
   
   Following the [tutorials](http://mxnet.incubator.apache.org/versions/master/install/c_plus_plus.html), I've already built mxnet from source with `USE_CPP_PACKAGE=1` and `USE_BLAS = openblas`. Then I got `libmxnet.a libmxnet.so` files.
   
   While I build executable program with linking to dynamic library (libmxnet.so), my codes work well. However, if I tried to build executable program with linking to static library (libmxnet.a), then I receive an error like `"transformer: lrcplus/main.cc:101: int main(): Assertion 'pred_hnd' failed."`
   
   Please help out. Thanks in advance!!!
   
   ### Environment info
   Compiler: gcc version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC) | Cmake version 3.9.4
   Package used (Python/R/Scala/Julia): C++
   MXNet commit hash (`git rev-parse HEAD`): c2110ada6d43f10710d181c0deb0673fe6d829b2
   
   ### Steps to reproduce
   I'm running my own project. The tree is like this.
   ```
   lrcplus
   ├── CMakeLists-static.txt
   ├── CMakeLists-dynamic.txt
   ├── build
   ├── main.cc
   ├── include
   │   ├── mxnet (Contains hedder files from `/mxnet/include/mxnet/`)
   └── lib
   │   ├── libmxnet.so  (Copy from  `/mxnet/lib/`)
   │   ├── libmxnet.a (Copy from  `/mxnet/lib/`)
   │   ├── libdmlc.a (Copy from  `/mxnet/3rdparty/dmlc-core/`)
   │   └── libnnvm.a (Copy from  `/mxnet/3rdparty/3rdparty/tvm/nnvm/lib/`)
   └── python
   │   ├── train.py  (Implement a simple network and save with export)
   │   ├── net-0000.params (Generated by train.py)
   │   ├── net-symbol.json (Generated by train.py)
   │   └── test.csv (Generated by train.py)
   ```
   
   The `train.py` file is like this:
   ```
   from __future__ import print_function
   import mxnet as mx
   from mxnet import nd, autograd, gluon
   
   
   data_ctx = mx.cpu()
   model_ctx = mx.cpu()
   
   num_inputs = 2
   num_outputs = 1
   num_examples = 10000
   
   def real_fn(X):
       return 2 * X[:, 0] - 3.4 * X[:, 1] + 4.2
               
   X = nd.random_normal(shape=(num_examples, num_inputs))
   noise = 0.01 * nd.random_normal(shape=(num_examples,))
   y = real_fn(X) + noise
   
   
   batch_size = 4
   train_data = gluon.data.DataLoader(gluon.data.ArrayDataset(X, y), batch_size=batch_size, shuffle=True)
   net = gluon.nn.Dense(1, in_units=2)
   net.initialize(mx.init.Normal(sigma=1.), ctx=model_ctx)
   net.hybridize()
   
   trainer = gluon.Trainer(net.collect_params(), 'sgd', {'learning_rate': 0.0001})
   sq_loss = gluon.loss.L2Loss()
   sq_loss.hybridize()
   
   epochs = 5
   loss_sequence = []
   num_batches = num_examples / batch_size
   
   for e in range(epochs):
       cumulative_loss = 0
       for i, (data, label) in enumerate(train_data):
           data = data.as_in_context(model_ctx)
           label = label.as_in_context(model_ctx)
           with autograd.record():
               output = net(data)
               loss = sq_loss(output, label)
           loss.backward()
           trainer.step(batch_size)
           cumulative_loss += nd.mean(loss).asscalar()
           
       print("Epoch %s, loss: %s" % (e, cumulative_loss / num_examples))
       loss_sequence.append(cumulative_loss)
   
   net.export('net')
   
   f = open('test.csv','w',encoding='utf-8')
   a = X[0].asnumpy()
   s = ','.join([str(x) for x in a]) 
   f.write(s)
   f.close()
   ```
   
   The `main.cc` file is like this:
   ```
   #include "mxnet/c_predict_api.h"
   
   #include <assert.h>
   #include <iostream>
   #include <sstream>
   #include <fstream>
   #include <string>
   #include <vector>
   
   using namespace std;
   
   
   class BufferFile {
   
   public:
   	string file_path_;
   	int length_;
   	char* buffer_;
   
   	explicit BufferFile(string file_path)
   		:file_path_(file_path) {
   
   		ifstream ifs(file_path.c_str(), ios::in | ios::binary);
   		if (!ifs) {
   			cerr << "Can't open the file. Please check " << file_path << ". \n";
   			length_ = 0;
   			buffer_ = NULL;
   			return;
   		}
   
   		ifs.seekg(0, ios::end);
   		length_ = ifs.tellg();
   		ifs.seekg(0, ios::beg);
   		cout << file_path.c_str() << " ... " << length_ << " bytes\n";
   
   		buffer_ = new char[sizeof(char) * length_];
   		ifs.read(buffer_, length_);
   		ifs.close();
   	}
   
   	int GetLength() {
   		return length_;
   	}
   	char* GetBuffer() {
   		return buffer_;
   	}
   
   	~BufferFile() {
   		if (buffer_) {
   			delete[] buffer_;
   			buffer_ = NULL;
   		}
   	}
   };
   
   int main(){
       ifstream fin("test.csv");
       string line;
       vector<mx_float> data;
       while (getline(fin, line)) {
   
           istringstream sin(line);
           string field;
           while (getline(sin, field, ',')) {
               data.push_back(atof(field.c_str()));
           }
       }
       fin.close();
   
       string json_file = "net-symbol.json";
       string param_file = "net-0000.params";
       
       BufferFile json_data(json_file);
       BufferFile param_data(param_file);
       
       mx_uint num_input_nodes = 1;
       const char* input_key[1] = { "data" };
       const char** input_keys = input_key;
   
       int input_shape[1] = { 2 };
       const mx_uint input_shape_indptr[2] = { 0,2 };
       const mx_uint input_shape_data[2] = { 1, static_cast<mx_uint>(input_shape[0])};
   
       mx_uint input_data_size = input_shape[0];
       PredictorHandle pred_hnd = 0;
   
       int dev_type = 1;
       int dev_id = 1;
       
       MXPredCreate(static_cast<const char*>(json_data.GetBuffer()),
           static_cast<const char*>(param_data.GetBuffer()),
           static_cast<int>(param_data.GetLength()),
           dev_type,
           dev_id,
           num_input_nodes,
           input_keys,
           input_shape_indptr,
           input_shape_data,
           &pred_hnd);
   
       assert(pred_hnd);
   
       MXPredSetInput(pred_hnd, "data", data.data(), input_data_size);
       
       MXPredForward(pred_hnd);
       mx_uint output_index = 0;
   
       mx_uint* shape = nullptr;
       mx_uint shape_len;
   
       // Get Output Result
       MXPredGetOutputShape(pred_hnd, output_index, &shape, &shape_len);
   
       size_t size = 1;
       for (mx_uint i = 0; i < shape_len; ++i) { size *= shape[i]; }
   
       vector<float> output(size);
   
       MXPredGetOutput(pred_hnd, output_index, &(output[0]), static_cast<mx_uint>(size));
   
       for (auto i = output.begin(); i != output.end(); ++i) {
           std::cout << *i << ' ';
       }
   }
   ```
   
   The `CMakeLists-dynamic.txt` file is like this:
   ```
   cmake_minimum_required(VERSION 3.9)
   
   set (CMAKE_CXX_STANDARD 11) 
   
   add_executable(transformer 
           main.cc
   )
   
   target_link_libraries(transformer
           ${PROJECT_SOURCE_DIR}/lib/libmxnet.so
   )
   
   target_include_directories(transformer PUBLIC
           ${PROJECT_SOURCE_DIR}/include
   )
   ```
   
   The `CMakeLists-static.txt` file is like this:
   ```
   cmake_minimum_required(VERSION 3.9)
   
   set (CMAKE_CXX_STANDARD 11) 
   
   add_executable(transformer 
           main.cc
   )
   
   target_link_libraries(transformer
           rt  
           ${PROJECT_SOURCE_DIR}/lib/libmxnet.a
           ${PROJECT_SOURCE_DIR}/lib/libdmlc.a
           ${PROJECT_SOURCE_DIR}/lib/libnnvm.a
   )
   
   target_include_directories(transformer PUBLIC
           ${PROJECT_SOURCE_DIR}/include
   )
   ```
   
   so, to try my situation easily.
   ```
   # Try model using python script
   cd lrcplus/python
   python train.py
   
   # Try to build executable program with linking to dynamic library
   cd ../build
   cp ../CMakeLists-dynamic.txt ../CMakeLists.txt
   cmake ../
   make
   mv ./transformer ../python/
   cd ../python
   ./transformer
   
   #Then you may see message like this
   #net-symbol.json ... 1022 bytes
   #net-0000.params ... 164 bytes
   #4.0142
   
   # Try to build executable program with linking to static library
   cd ../build
   cp ../CMakeLists-static.txt ../CMakeLists.txt
   cmake ../
   make
   mv ./transformer ../python/
   cd ../python
   ./transformer
   
   #Then you may see message like this
   #net-symbol.json ... 1022 bytes
   #net-0000.params ... 164 bytes
   #transformer: /data1/qspace/christding/workspace/mxnet_c++/Basic/lrcplus/main.cc:101: int main(): Assertion `pred_hnd' failed.
   ```
   
   I really appreciate your  cooperation.
   

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services