Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pull request for dto-supervised-connector #1150

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 26 additions & 0 deletions src/apidata.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <vector>
#include <sstream>
#include <typeinfo>
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"

namespace dd
{
Expand Down Expand Up @@ -288,6 +289,31 @@ namespace dd
*/
void toJDoc(JDoc &jd) const;

/**
* \brief converts APIData to oat++ DTO
*/
template <typename T> inline std::shared_ptr<T> createSharedDTO() const
{
rapidjson::Document d;
d.SetObject();
toJDoc(reinterpret_cast<JDoc &>(d));

rapidjson::StringBuffer buffer;
rapidjson::Writer<rapidjson::StringBuffer, rapidjson::UTF8<>,
rapidjson::UTF8<>, rapidjson::CrtAllocator,
rapidjson::kWriteNanAndInfFlag>
writer(buffer);
bool done = d.Accept(writer);
if (!done)
throw DataConversionException("JSON rendering failed");

std::shared_ptr<oatpp::data::mapping::ObjectMapper> object_mapper
= oatpp::parser::json::mapping::ObjectMapper::createShared();
return object_mapper
->readFromString<oatpp::Object<T>>(buffer.GetString())
.getPtr();
}

/**
* \brief converts APIData to rapidjson JSON value
* @param jd JSON Document hosting the destination JSON value
Expand Down
123 changes: 36 additions & 87 deletions src/backends/ncnn/ncnnlib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
#include "outputconnectorstrategy.h"
#include <thread>
#include <algorithm>
#include "utils/utils.hpp"

// NCNN
#include "ncnnlib.h"
Expand Down Expand Up @@ -53,10 +52,10 @@ namespace dd
{
this->_libname = "ncnn";
_net = new ncnn::Net();
_net->opt.num_threads = _threads;
_net->opt.num_threads = 1;
_net->opt.blob_allocator = &_blob_pool_allocator;
_net->opt.workspace_allocator = &_workspace_pool_allocator;
_net->opt.lightmode = _lightmode;
_net->opt.lightmode = true;
}

template <class TInputConnectorStrategy, class TOutputConnectorStrategy,
Expand All @@ -69,12 +68,9 @@ namespace dd
this->_libname = "ncnn";
_net = tl._net;
tl._net = nullptr;
_nclasses = tl._nclasses;
_threads = tl._threads;
_timeserie = tl._timeserie;
_old_height = tl._old_height;
_inputBlob = tl._inputBlob;
_outputBlob = tl._outputBlob;
_init_dto = tl._init_dto;
}

template <class TInputConnectorStrategy, class TOutputConnectorStrategy,
Expand All @@ -94,6 +90,8 @@ namespace dd
void NCNNLib<TInputConnectorStrategy, TOutputConnectorStrategy,
TMLModel>::init_mllib(const APIData &ad)
{
_init_dto = ad.createSharedDTO<NcnnInitDto>();

bool use_fp32 = (ad.has("datatype")
&& ad.get("datatype").get<std::string>()
== "fp32"); // default is fp16
Expand Down Expand Up @@ -124,35 +122,11 @@ namespace dd
_old_height = this->_inputc.height();
_net->set_input_h(_old_height);

if (ad.has("nclasses"))
_nclasses = ad.get("nclasses").get<int>();

if (ad.has("threads"))
_threads = ad.get("threads").get<int>();
else
_threads = dd_utils::my_hardware_concurrency();

_timeserie = this->_inputc._timeserie;
if (_timeserie)
this->_mltype = "timeserie";

if (ad.has("lightmode"))
{
_lightmode = ad.get("lightmode").get<bool>();
_net->opt.lightmode = _lightmode;
}

// setting the value of Input Layer
if (ad.has("inputblob"))
{
_inputBlob = ad.get("inputblob").get<std::string>();
}
// setting the final Output Layer
if (ad.has("outputblob"))
{
_outputBlob = ad.get("outputblob").get<std::string>();
}

_net->opt.lightmode = _init_dto->lightmode;
_blob_pool_allocator.set_size_compare_ratio(0.0f);
_workspace_pool_allocator.set_size_compare_ratio(0.5f);
model_type(this->_mlmodel._params, this->_mltype);
Expand Down Expand Up @@ -212,61 +186,34 @@ namespace dd
}

APIData ad_output = ad.getobj("parameters").getobj("output");

// Get bbox
bool bbox = false;
if (ad_output.has("bbox"))
bbox = ad_output.get("bbox").get<bool>();

// Ctc model
bool ctc = false;
int blank_label = -1;
if (ad_output.has("ctc"))
{
ctc = ad_output.get("ctc").get<bool>();
if (ctc)
{
if (ad_output.has("blank_label"))
blank_label = ad_output.get("blank_label").get<int>();
}
}
auto output_params
= ad_output.createSharedDTO<PredictOutputParametersDto>();

// Extract detection or classification
int ret = 0;
std::string out_blob = _outputBlob;
std::string out_blob;
if (_init_dto->outputBlob != nullptr)
out_blob = _init_dto->outputBlob->std_str();

if (out_blob.empty())
{
if (bbox == true)
if (output_params->bbox == true)
out_blob = "detection_out";
else if (ctc == true)
else if (output_params->ctc == true)
out_blob = "probs";
else if (_timeserie)
out_blob = "rnn_pred";
else
out_blob = "prob";
}

std::vector<APIData> vrad;

// Get confidence_threshold
float confidence_threshold = 0.0;
if (ad_output.has("confidence_threshold"))
{
apitools::get_float(ad_output, "confidence_threshold",
confidence_threshold);
}

// Get best
int best = -1;
if (ad_output.has("best"))
{
best = ad_output.get("best").get<int>();
}
if (best == -1 || best > _nclasses)
best = _nclasses;
if (output_params->best == -1 || output_params->best > _init_dto->nclasses)
output_params->best = _init_dto->nclasses;

std::vector<APIData> vrad;

// for loop around batch size
#pragma omp parallel for num_threads(_threads)
// for loop around batch size
#pragma omp parallel for num_threads(*_init_dto->threads)
for (size_t b = 0; b < inputc._ids.size(); b++)
{
std::vector<double> probs;
Expand All @@ -276,16 +223,16 @@ namespace dd
APIData rad;

ncnn::Extractor ex = _net->create_extractor();
ex.set_num_threads(_threads);
ex.input(_inputBlob.c_str(), inputc._in.at(b));
ex.set_num_threads(_init_dto->threads);
ex.input(_init_dto->inputBlob->c_str(), inputc._in.at(b));

ret = ex.extract(out_blob.c_str(), inputc._out.at(b));
int ret = ex.extract(out_blob.c_str(), inputc._out.at(b));
if (ret == -1)
{
throw MLLibInternalException("NCNN internal error");
}

if (bbox == true)
if (output_params->bbox == true)
{
std::string uri = inputc._ids.at(b);
auto bit = inputc._imgs_size.find(uri);
Expand All @@ -305,7 +252,7 @@ namespace dd
for (int i = 0; i < inputc._out.at(b).h; i++)
{
const float *values = inputc._out.at(b).row(i);
if (values[1] < confidence_threshold)
if (values[1] < output_params->confidence_threshold)
break; // output is sorted by confidence

cats.push_back(this->_mlmodel.get_hcorresp(values[0]));
Expand All @@ -323,7 +270,7 @@ namespace dd
bboxes.push_back(ad_bbox);
}
}
else if (ctc == true)
else if (output_params->ctc == true)
{
int alphabet = inputc._out.at(b).w;
int time_step = inputc._out.at(b).h;
Expand All @@ -336,11 +283,11 @@ namespace dd
}

std::vector<int> pred_label_seq;
int prev = blank_label;
int prev = output_params->blank_label;
for (int t = 0; t < time_step; ++t)
{
int cur = pred_label_seq_with_blank[t];
if (cur != prev && cur != blank_label)
if (cur != prev && cur != output_params->blank_label)
pred_label_seq.push_back(cur);
prev = cur;
}
Expand Down Expand Up @@ -388,12 +335,13 @@ namespace dd
vec[i] = std::make_pair(cls_scores[i], i);
}

std::partial_sort(vec.begin(), vec.begin() + best, vec.end(),
std::partial_sort(vec.begin(), vec.begin() + output_params->best,
vec.end(),
std::greater<std::pair<float, int>>());

for (int i = 0; i < best; i++)
for (int i = 0; i < output_params->best; i++)
{
if (vec[i].first < confidence_threshold)
if (vec[i].first < output_params->confidence_threshold)
continue;
cats.push_back(this->_mlmodel.get_hcorresp(vec[i].second));
probs.push_back(vec[i].first);
Expand All @@ -403,7 +351,7 @@ namespace dd
rad.add("uri", inputc._ids.at(b));
rad.add("loss", 0.0);
rad.add("cats", cats);
if (bbox == true)
if (output_params->bbox == true)
rad.add("bboxes", bboxes);
if (_timeserie)
{
Expand All @@ -423,8 +371,9 @@ namespace dd
} // end for batch_size

tout.add_results(vrad);
out.add("nclasses", this->_nclasses);
if (bbox == true)
int nclasses = this->_init_dto->nclasses;
out.add("nclasses", nclasses);
if (output_params->bbox == true)
out.add("bbox", true);
out.add("roi", false);
out.add("multibox_rois", false);
Expand Down
14 changes: 7 additions & 7 deletions src/backends/ncnn/ncnnlib.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,15 @@
#ifndef NCNNLIB_H
#define NCNNLIB_H

#include "apidata.h"
#include "utils/utils.hpp"

#include "dto/ncnn.hpp"

// NCNN
#include "net.h"
#include "ncnnmodel.h"

#include "apidata.h"

namespace dd
{
template <class TInputConnectorStrategy, class TOutputConnectorStrategy,
Expand All @@ -53,20 +56,17 @@ namespace dd

public:
ncnn::Net *_net = nullptr;
int _nclasses = 0;
bool _timeserie = false;
bool _lightmode = true;

private:
std::shared_ptr<NcnnInitDto> _init_dto;
static ncnn::UnlockedPoolAllocator _blob_pool_allocator;
static ncnn::PoolAllocator _workspace_pool_allocator;

protected:
int _threads = 1;
int _old_height = -1;
std::string _inputBlob = "data";
std::string _outputBlob;
};

}

#endif
34 changes: 29 additions & 5 deletions src/http/controller.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,16 @@
#include <vector>
#include <iostream>

#include <boost/lexical_cast.hpp>

#include "oatpp/web/server/api/ApiController.hpp"
#include "oatpp/parser/json/mapping/ObjectMapper.hpp"
#include "oatpp/core/macro/codegen.hpp"
#include "oatpp/core/macro/component.hpp"

#include "apidata.h"
#include "oatppjsonapi.h"
#include "http/dto/info.hpp"

#include OATPP_CODEGEN_BEGIN(ApiController)

Expand Down Expand Up @@ -61,11 +65,31 @@ class DedeController : public oatpp::web::server::api::ApiController
}
ENDPOINT("GET", "info", get_info, QUERIES(QueryParams, queryParams))
{
// TODO(sileht): why do serialize the query string to char*
// to later get again a APIData...
std::string jsonstr = _oja->uri_query_to_json(queryParams);
auto janswer = _oja->info(jsonstr);
return _oja->jdoc_to_response(janswer);
auto info_resp = InfoResponse::createShared();
info_resp->head = InfoHead::createShared();
info_resp->head->services = {};

auto qs_status = queryParams.get("status");
bool status = false;
if (qs_status)
status = boost::lexical_cast<bool>(qs_status->std_str());

auto hit = _oja->_mlservices.begin();
while (hit != _oja->_mlservices.end())
{
// TODO(sileht): update visitor_info to return directly a Service()
JDoc jd;
jd.SetObject();
mapbox::util::apply_visitor(dd::visitor_info(status), (*hit).second)
.toJDoc(jd);
auto json_str = _oja->jrender(jd);
auto service_info
= getDefaultObjectMapper()->readFromString<oatpp::Object<Service>>(
json_str.c_str());
info_resp->head->services->emplace_back(service_info);
++hit;
}
return createDtoResponse(Status::CODE_200, info_resp);
}

ENDPOINT_INFO(get_service)
Expand Down
Loading