|
|
@ -3,9 +3,8 @@ |
|
|
|
#include "ofxOnnxRuntime.h" |
|
|
|
|
|
|
|
// code from
|
|
|
|
//https://github.com/microsoft/onnxruntime-inference-examples/blob/main/c_cxx/MNIST/MNIST.cpp
|
|
|
|
template <typename T> |
|
|
|
static void softmax(T& input) { |
|
|
|
// https://github.com/microsoft/onnxruntime-inference-examples/blob/main/c_cxx/MNIST/MNIST.cpp
|
|
|
|
template <typename T> static void softmax(T &input) { |
|
|
|
float rowmax = *std::max_element(input.begin(), input.end()); |
|
|
|
std::vector<float> y(input.size()); |
|
|
|
float sum = 0.0f; |
|
|
@ -18,23 +17,55 @@ static void softmax(T& input) { |
|
|
|
} |
|
|
|
|
|
|
|
// 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<float>(memory_info, input_image_.data(), input_image_.size(), input_shape_.data(), input_shape_.size()); |
|
|
|
output_tensor_ = Ort::Value::CreateTensor<float>(memory_info, results_.data(), results_.size(), output_shape_.data(), output_shape_.size()); |
|
|
|
|
|
|
|
#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<Ort::Session>(env, widestr.c_str(), sf); |
|
|
|
#else |
|
|
|
// OSX
|
|
|
|
session_ = make_shared<Ort::Session>( |
|
|
|
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<float>( |
|
|
|
memory_info, input_image_.data(), input_image_.size(), |
|
|
|
input_shape_.data(), input_shape_.size()); |
|
|
|
output_tensor_ = Ort::Value::CreateTensor<float>( |
|
|
|
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"}; |
|
|
|
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); |
|
|
|
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())); |
|
|
|
result_ = std::distance(results_.begin(), |
|
|
|
std::max_element(results_.begin(), results_.end())); |
|
|
|
return result_; |
|
|
|
} |
|
|
|
|
|
|
@ -43,29 +74,31 @@ struct MNIST { |
|
|
|
|
|
|
|
std::array<float, width_ * height_> input_image_{}; |
|
|
|
std::array<float, 10> results_{}; |
|
|
|
int64_t result_{0}; |
|
|
|
int64_t result_{ 0 }; |
|
|
|
|
|
|
|
private: |
|
|
|
private: |
|
|
|
Ort::Env env; |
|
|
|
Ort::Session session_{env, ofToDataPath("mnist-8.onnx", true).c_str(), Ort::SessionOptions{nullptr}}; |
|
|
|
shared_ptr<Ort::Session> |
|
|
|
session_; // {env, (const wchar_t*)ofToDataPath("mnist-8.onnx",
|
|
|
|
// true).c_str(), Ort::SessionOptions{ nullptr }};
|
|
|
|
|
|
|
|
Ort::Value input_tensor_{nullptr}; |
|
|
|
std::array<int64_t, 4> input_shape_{1, 1, width_, height_}; |
|
|
|
Ort::Value input_tensor_{ nullptr }; |
|
|
|
std::array<int64_t, 4> input_shape_{ 1, 1, width_, height_ }; |
|
|
|
|
|
|
|
Ort::Value output_tensor_{nullptr}; |
|
|
|
std::array<int64_t, 2> output_shape_{1, 10}; |
|
|
|
Ort::Value output_tensor_{ nullptr }; |
|
|
|
std::array<int64_t, 2> output_shape_{ 1, 10 }; |
|
|
|
}; |
|
|
|
|
|
|
|
class ofApp : public ofBaseApp{ |
|
|
|
class ofApp : public ofBaseApp { |
|
|
|
shared_ptr<MNIST> mnist; |
|
|
|
ofFbo fbo_render; |
|
|
|
ofFbo fbo_classification; |
|
|
|
ofFloatPixels pix; |
|
|
|
bool prev_pressed = false; |
|
|
|
glm::vec2 prev_pt; |
|
|
|
|
|
|
|
public: |
|
|
|
void setup() |
|
|
|
{ |
|
|
|
void setup() { |
|
|
|
ofSetVerticalSync(true); |
|
|
|
ofSetFrameRate(60); |
|
|
|
|
|
|
@ -79,10 +112,11 @@ public: |
|
|
|
fbo_classification.allocate(28, 28, GL_R32F, 0); |
|
|
|
|
|
|
|
pix.setFromExternalPixels(&mnist->input_image_.front(), 28, 28, 1); |
|
|
|
|
|
|
|
mnist->Run(); |
|
|
|
} |
|
|
|
|
|
|
|
void update() |
|
|
|
{ |
|
|
|
void update() { |
|
|
|
if (ofGetMousePressed()) { |
|
|
|
auto pt = glm::vec2(ofGetMouseX(), ofGetMouseY() - 60); |
|
|
|
fbo_render.begin(); |
|
|
@ -98,28 +132,30 @@ public: |
|
|
|
|
|
|
|
fbo_classification.begin(); |
|
|
|
ofClear(0); |
|
|
|
fbo_render.draw(0, 0, fbo_classification.getWidth(), fbo_classification.getHeight()); |
|
|
|
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 { |
|
|
|
} |
|
|
|
else { |
|
|
|
prev_pressed = false; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void draw() |
|
|
|
{ |
|
|
|
void draw() { |
|
|
|
ofClear(128); |
|
|
|
|
|
|
|
fbo_render.draw(0, 60); |
|
|
|
fbo_classification.draw(0, 340); |
|
|
|
|
|
|
|
// render result
|
|
|
|
for (int i=0; i<10; ++i) { |
|
|
|
for (int i = 0; i < 10; ++i) { |
|
|
|
stringstream ss; |
|
|
|
ss << i << ":" << std::fixed << std::setprecision(3) << mnist->results_[i]; |
|
|
|
ss << i << ":" << std::fixed << std::setprecision(3) |
|
|
|
<< mnist->results_[i]; |
|
|
|
ofDrawBitmapString(ss.str(), 300, 70 + i * 30); |
|
|
|
ofPushStyle(); |
|
|
|
ofSetColor(0, 255, 0); |
|
|
@ -134,8 +170,7 @@ public: |
|
|
|
ofDrawBitmapStringHighlight(ss.str(), 10, 20); |
|
|
|
} |
|
|
|
|
|
|
|
void keyPressed(int key) |
|
|
|
{ |
|
|
|
void keyPressed(int key) { |
|
|
|
if (key == 'c') { |
|
|
|
fbo_render.begin(); |
|
|
|
ofClear(0); |
|
|
@ -144,27 +179,23 @@ public: |
|
|
|
} |
|
|
|
|
|
|
|
void keyReleased(int key) {} |
|
|
|
void mouseMoved(int x, int y ) {} |
|
|
|
void mouseMoved(int x, int y) {} |
|
|
|
void mouseDragged(int x, int y, int button) {} |
|
|
|
|
|
|
|
void mousePressed(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
|
|
|
|
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()); |
|
|
|
|
|
|
|
} |
|
|
|