diff --git a/README.md b/README.md index 96ba14b..a6725c1 100644 --- a/README.md +++ b/README.md @@ -7,9 +7,23 @@ ## Installation - macOS - copy `libonnxruntime.1.10.0.dylib` to `/usr/local/lib` + - Generate a project using ProjectGenerator. +- Windows + - There are two ways to install ONNX Runtime on your project. + 1. Install using NuGet + - I recommend this way in general. + - Generate a project using ProjectGenerator. + - Open `sln` file. + - Right click your project on `Solution Explorer` pane, and then select `Manage NuGet Packages...`. + - From `Browse` tab, search `Microsoft.ML.OnnxRuntime` (CPU) or `Microsoft.ML.OnnxRuntime.Gpu` (GPU) and install it. + 2. DLL direct download + - You can download prebuilt DLLs from (here)[https://github.com/microsoft/onnxruntime/releases]. + - Unzip downloaded `onnxruntime-win-x64-(gpu-)1.10.0.zip` and locate files on `libs\onnxruntime\lib\vs\x64\` . + - Generate a project using ProjectGenerator, then all libs are linked correctly and all dlls are copied to `bin`. ## Tested environment -- MacBookPro 2018 Intel + macOS Catalina +- oF 0.11.2 + MacBookPro 2018 Intel + macOS Catalina +- oF 0.11.2 + VS2017 + Windows 10 + RTX2080Ti + CUDA 11.4 ## ToDo -- check M1 Mac (should work), Windows CPU&GPU, Linux CPU&GPU +- check M1 Mac (should work), Linux CPU&GPU diff --git a/example-onnx_mnist/src/ofApp.cpp b/example-onnx_mnist/src/ofApp.cpp index 35543d1..278f6e1 100644 --- a/example-onnx_mnist/src/ofApp.cpp +++ b/example-onnx_mnist/src/ofApp.cpp @@ -3,168 +3,199 @@ #include "ofxOnnxRuntime.h" // code from -//https://github.com/microsoft/onnxruntime-inference-examples/blob/main/c_cxx/MNIST/MNIST.cpp -template -static void softmax(T& input) { - float rowmax = *std::max_element(input.begin(), input.end()); - std::vector y(input.size()); - float sum = 0.0f; - for (size_t i = 0; i != input.size(); ++i) { - sum += y[i] = std::exp(input[i] - rowmax); - } - for (size_t i = 0; i != input.size(); ++i) { - input[i] = y[i] / sum; - } +// https://github.com/microsoft/onnxruntime-inference-examples/blob/main/c_cxx/MNIST/MNIST.cpp +template static void softmax(T &input) { + float rowmax = *std::max_element(input.begin(), input.end()); + std::vector y(input.size()); + float sum = 0.0f; + for (size_t i = 0; i != input.size(); ++i) { + sum += y[i] = std::exp(input[i] - rowmax); + } + for (size_t i = 0; i != input.size(); ++i) { + input[i] = y[i] / sum; + } } // This is the structure to interface with the MNIST model -// After instantiation, set the input_image_ data to be the 28x28 pixel image of the number to recognize -// Then call Run() to fill in the results_ data with the probabilities of each -// result_ holds the index with highest probability (aka the number the model thinks is in the image) +// After instantiation, set the input_image_ data to be the 28x28 pixel image of +// the number to recognize Then call Run() to fill in the results_ data with the +// probabilities of each result_ holds the index with highest probability (aka +// the number the model thinks is in the image) struct MNIST { - MNIST() { - auto memory_info = Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); - input_tensor_ = Ort::Value::CreateTensor(memory_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size()); - output_tensor_ = Ort::Value::CreateTensor(memory_info, results_.data(), results_.size(), output_shape_.data(), output_shape_.size()); - } - - std::ptrdiff_t Run() { - const char* input_names[] = {"Input3"}; - const char* output_names[] = {"Plus214_Output_0"}; - - session_.Run(Ort::RunOptions{nullptr}, input_names, &input_tensor_, 1, output_names, &output_tensor_, 1); - softmax(results_); - result_ = std::distance(results_.begin(), std::max_element(results_.begin(), results_.end())); - return result_; - } - - static constexpr const int width_ = 28; - static constexpr const int height_ = 28; - - std::array input_image_{}; - std::array results_{}; - int64_t result_{0}; - - private: - Ort::Env env; - Ort::Session session_{env, ofToDataPath("mnist-8.onnx", true).c_str(), Ort::SessionOptions{nullptr}}; - - Ort::Value input_tensor_{nullptr}; - std::array input_shape_{1, 1, width_, height_}; - - Ort::Value output_tensor_{nullptr}; - std::array output_shape_{1, 10}; + MNIST() { + +#ifdef _MSC_VER + Ort::SessionOptions sf; + +#define USE_CUDA +#define USE_TENSORRT + +#ifdef USE_CUDA +#ifdef USE_TENSORRT + sf.AppendExecutionProvider_TensorRT(OrtTensorRTProviderOptions{ 0 }); +#endif + sf.AppendExecutionProvider_CUDA(OrtCUDAProviderOptions()); +#endif + + string path = ofToDataPath("mnist-8.onnx", true); + std::wstring widestr = std::wstring(path.begin(), path.end()); + session_ = make_shared(env, widestr.c_str(), sf); +#else + // OSX + session_ = make_shared( + env, ofToDataPath("mnist-8.onnx", true).c_str(), + Ort::SessionOptions{ nullptr }); +#endif + + auto memory_info = + Ort::MemoryInfo::CreateCpu(OrtDeviceAllocator, OrtMemTypeCPU); + input_tensor_ = Ort::Value::CreateTensor( + memory_info, input_image_.data(), input_image_.size(), + input_shape_.data(), input_shape_.size()); + output_tensor_ = Ort::Value::CreateTensor( + memory_info, results_.data(), results_.size(), output_shape_.data(), + output_shape_.size()); + } + + std::ptrdiff_t Run() { + const char *input_names[] = { "Input3" }; + const char *output_names[] = { "Plus214_Output_0" }; + + session_->Run(Ort::RunOptions{ nullptr }, input_names, &input_tensor_, 1, + output_names, &output_tensor_, 1); + softmax(results_); + result_ = std::distance(results_.begin(), + std::max_element(results_.begin(), results_.end())); + return result_; + } + + static constexpr const int width_ = 28; + static constexpr const int height_ = 28; + + std::array input_image_{}; + std::array results_{}; + int64_t result_{ 0 }; + +private: + Ort::Env env; + shared_ptr + session_; // {env, (const wchar_t*)ofToDataPath("mnist-8.onnx", + // true).c_str(), Ort::SessionOptions{ nullptr }}; + + Ort::Value input_tensor_{ nullptr }; + std::array input_shape_{ 1, 1, width_, height_ }; + + Ort::Value output_tensor_{ nullptr }; + std::array output_shape_{ 1, 10 }; }; -class ofApp : public ofBaseApp{ - shared_ptr mnist; - ofFbo fbo_render; - ofFbo fbo_classification; - ofFloatPixels pix; - bool prev_pressed = false; - glm::vec2 prev_pt; +class ofApp : public ofBaseApp { + shared_ptr mnist; + ofFbo fbo_render; + ofFbo fbo_classification; + ofFloatPixels pix; + bool prev_pressed = false; + glm::vec2 prev_pt; + public: - void setup() - { - ofSetVerticalSync(true); - ofSetFrameRate(60); - - mnist = make_shared(); - - fbo_render.allocate(280, 280, GL_RGB, 0); - fbo_render.getTexture().setTextureMinMagFilter(GL_NEAREST, GL_NEAREST); - fbo_render.begin(); - ofClear(0); - fbo_render.end(); - fbo_classification.allocate(28, 28, GL_R32F, 0); - - pix.setFromExternalPixels(&mnist->input_image_.front(), 28, 28, 1); - } - - void update() - { - if (ofGetMousePressed()) { - auto pt = glm::vec2(ofGetMouseX(), ofGetMouseY() - 60); - fbo_render.begin(); - ofPushStyle(); - ofSetColor(255); - if (prev_pressed) { - ofSetLineWidth(20); - ofDrawLine(prev_pt, pt); - } - ofDrawCircle(pt.x, pt.y, 10); - ofPopStyle(); - fbo_render.end(); - - fbo_classification.begin(); - ofClear(0); - fbo_render.draw(0, 0, fbo_classification.getWidth(), fbo_classification.getHeight()); - fbo_classification.end(); - fbo_classification.readToPixels(pix); - mnist->Run(); - prev_pt = pt; - prev_pressed = true; - } else { - prev_pressed = false; - } - } - - void draw() - { - ofClear(128); - - fbo_render.draw(0, 60); - fbo_classification.draw(0, 340); - - // render result - for (int i=0; i<10; ++i) { - stringstream ss; - ss << i << ":" << std::fixed << std::setprecision(3) << mnist->results_[i]; - ofDrawBitmapString(ss.str(), 300, 70 + i * 30); - ofPushStyle(); - ofSetColor(0, 255, 0); - ofDrawRectangle(360.0, 55 + i * 30, mnist->results_[i] * 300.0, 20); - ofPopStyle(); - } - - stringstream ss; - ss << "FPS : " << ofGetFrameRate() << endl; - ss << "Draw any digit (0-9) here" << endl; - ss << "Press c to clear buffer"; - ofDrawBitmapStringHighlight(ss.str(), 10, 20); - } - - void keyPressed(int key) - { - if (key == 'c') { - fbo_render.begin(); - ofClear(0); - fbo_render.end(); - } - } - - void keyReleased(int key) {} - void mouseMoved(int x, int y ) {} - void mouseDragged(int x, int y, int button) {} - - void mousePressed(int x, int y, int button) { - - } - - void mouseReleased(int x, int y, int button) {} - void windowResized(int w, int h) {} - void dragEvent(ofDragInfo dragInfo) {} - void gotMessage(ofMessage msg) {} - + void setup() { + ofSetVerticalSync(true); + ofSetFrameRate(60); + + mnist = make_shared(); + + fbo_render.allocate(280, 280, GL_RGB, 0); + fbo_render.getTexture().setTextureMinMagFilter(GL_NEAREST, GL_NEAREST); + fbo_render.begin(); + ofClear(0); + fbo_render.end(); + fbo_classification.allocate(28, 28, GL_R32F, 0); + + pix.setFromExternalPixels(&mnist->input_image_.front(), 28, 28, 1); + + mnist->Run(); + } + + void update() { + if (ofGetMousePressed()) { + auto pt = glm::vec2(ofGetMouseX(), ofGetMouseY() - 60); + fbo_render.begin(); + ofPushStyle(); + ofSetColor(255); + if (prev_pressed) { + ofSetLineWidth(20); + ofDrawLine(prev_pt, pt); + } + ofDrawCircle(pt.x, pt.y, 10); + ofPopStyle(); + fbo_render.end(); + + fbo_classification.begin(); + ofClear(0); + fbo_render.draw(0, 0, fbo_classification.getWidth(), + fbo_classification.getHeight()); + fbo_classification.end(); + fbo_classification.readToPixels(pix); + mnist->Run(); + prev_pt = pt; + prev_pressed = true; + } + else { + prev_pressed = false; + } + } + + void draw() { + ofClear(128); + + fbo_render.draw(0, 60); + fbo_classification.draw(0, 340); + + // render result + for (int i = 0; i < 10; ++i) { + stringstream ss; + ss << i << ":" << std::fixed << std::setprecision(3) + << mnist->results_[i]; + ofDrawBitmapString(ss.str(), 300, 70 + i * 30); + ofPushStyle(); + ofSetColor(0, 255, 0); + ofDrawRectangle(360.0, 55 + i * 30, mnist->results_[i] * 300.0, 20); + ofPopStyle(); + } + + stringstream ss; + ss << "FPS : " << ofGetFrameRate() << endl; + ss << "Draw any digit (0-9) here" << endl; + ss << "Press c to clear buffer"; + ofDrawBitmapStringHighlight(ss.str(), 10, 20); + } + + void keyPressed(int key) { + if (key == 'c') { + fbo_render.begin(); + ofClear(0); + fbo_render.end(); + } + } + + void keyReleased(int key) {} + void mouseMoved(int x, int y) {} + void mouseDragged(int x, int y, int button) {} + + void mousePressed(int x, int y, int button) {} + + void mouseReleased(int x, int y, int button) {} + void windowResized(int w, int h) {} + void dragEvent(ofDragInfo dragInfo) {} + void gotMessage(ofMessage msg) {} }; //======================================================================== -int main( ){ - ofSetupOpenGL(640,400,OF_WINDOW); // <-------- setup the GL context - - // this kicks off the running of my app - // can be OF_WINDOW or OF_FULLSCREEN - // pass in width and height too: - ofRunApp(new ofApp()); - +int main() { + ofSetupOpenGL(640, 400, OF_WINDOW); // <-------- setup the GL context + + // this kicks off the running of my app + // can be OF_WINDOW or OF_FULLSCREEN + // pass in width and height too: + ofRunApp(new ofApp()); }