Fully Convolutional Net Training in C++ - c++

I'm trying to transfer FCN training from BrainScript to a C++ program. To start with I'm just loading and re-training an existing model. I'm getting somewhere, but trainer->TrainMinibatch() is throwing an exception (and I can't work out how to get a description of the exception either). Rough code below:
CNTK::DeviceDescriptor& device= CNTK::DeviceDescriptor::GPUDevice(gpuid);
FunctionPtr rootFunc = nullptr;
try {
rootFunc = Function::Load(modelname, device);
}
catch (char *err) {
printf("Load fail: %s\n",err);
return;
}
catch (...) {
printf("Load fail\n");
return;
}
std::cerr << "Loaded model ok" << std::endl;
MinibatchSourcePtr minibatchSource;
try {
minibatchSource = HG_CreateMinibatchSource(64);
}
catch (char* err) {
std::cerr << "Failed to init src: " << err << std::endl;
return;
}
catch (...) {
std::cerr << "Failed to init src " << std::endl;
return;
}
auto imageStreamInfo = minibatchSource->StreamInfo(L"features");
auto labelStreamInfo = minibatchSource->StreamInfo(L"labels"); // We don't use labels as is FCN
auto inputImageShape = imageStreamInfo.m_sampleLayout;
std::cerr << "Input Shape: " << inputImageShape.AsString() << std::endl;
auto imageInputName = L"features";
auto imageInput = InputVariable(inputImageShape, imageStreamInfo.m_elementType, imageInputName);
auto classifierOutput = rootFunc;
//EITHER - construct error from output+target
std::wstring outputLayerName = L"op";
FunctionPtr outputLayer = rootFunc->FindByName(outputLayerName);
std::wstring targetLayerName = L"opool3";
FunctionPtr targetLayer = rootFunc->FindByName(targetLayerName);
// OR - just get from network
std::wstring errLayerName = L"e";
FunctionPtr errLayer = rootFunc->FindByName(errLayerName);
std::cerr << "Setup-got op layer" << outputLayer->Output().Shape().AsString() << std::endl;
std::cerr << "Setup-got tgt layer" << targetLayer->Output().Shape().AsString() << std::endl;
std::cerr << "Setup-got err layer" << errLayer->Output().Shape().AsString() << std::endl;
auto trainingLoss = CNTK::SquaredError(outputLayer, targetLayer);
auto prediction = CNTK::SquaredError(outputLayer, targetLayer);
LearningRateSchedule learningRatePerSample = TrainingParameterPerSampleSchedule(5e-8);
// Either
auto trainer = CreateTrainer(classifierOutput, trainingLoss->Output(), prediction->Output(), { SGDLearner(classifierOutput->Parameters(), learningRatePerSample) });
// Or
//auto trainer = CreateTrainer(classifierOutput, errLayer, errLayer, { SGDLearner(classifierOutput->Parameters(), learningRatePerSample) });
const size_t minibatchSize = 1;
size_t numMinibatchesToTrain = 100;
size_t outputFrequencyInMinibatches = 10;
try {
for (size_t i = 0; i < numMinibatchesToTrain; ++i)
{
std::cerr << "Iteration: " << i << std::endl;
auto minibatchData = minibatchSource->GetNextMinibatch(minibatchSize, device);
std::cerr << " got data for "<< imageInput.AsString() << std::endl;
trainer->TrainMinibatch({ { imageInput, minibatchData[imageStreamInfo] } }, device); // This line throws exception!
std::cerr << "Eval=" << trainer->PreviousMinibatchEvaluationAverage() << "," << trainer->PreviousMinibatchLossAverage() << std::endl;
}
}
// Question edited as result of comment on exceptions below
catch (const std::exception & err) {
std::cerr << "Training error:" << err.what() << std::endl;
}
catch (...) {
std::cerr << "Training error" << std::endl;
}
It's not clear exactly how to define the loss function (I'm guessing here - there's no documentation really). The network has a loss ('e') used by CNTK.exe/Brainscript, which is the Squared error between output ('op') and a target ('opool3'). I tried both using e directly, and defining the error in C++ using CNTK::SquaredError(). Both give the same output, indicating an exception thrown by trainer->TrainMinibatch:
Loaded model ok
Input Shape:B[1024 x 1024 x 3]
Setup-got op layeB[63 x 127 x 3]
Setup-got tgt layeB[63 x 127 x 3]
Setup-got err layeB[]
Iteration: 0
got data forB,Input('features', [1024 x 1024 x 3], [*, #])
Training error:Values for 1 required arguments 'Input('features', [1024 x 1024 x 3], [, #])', that the requested output(s) 'Output('aggregateLoss', [], []), Output('Block233_Output_0', [], [, #]), Output('aggregateEvalMetric', [], [])' depend on, have not been provided.
What am I doing wrong here?
Thanks!
D.
Edit: Exception is:
Training error:Values for 1 required arguments 'Input('features', [1024 x 1024 x 3], [, #])', that the requested output(s) 'Output('aggregateLoss', [], []), Output('Block233_Output_0', [], [, #]), Output('aggregateEvalMetric', [], [])' depend on, have not been provided.
Update: Having looked at the cntk code (CompositeFunction.cpp), the issue seems to be a mismatch between the input and the required input:
Supplied variable: Input('features', [1024 x 1024 x 3], [*, #])
Required argument: Input('features', [1024 x 1024 x 3], [, #])
The difference being the [*. #] vs [, #]
Not sure how to fix it though!

This issue is because imageInput is a new variable that has nothing to do with the network's arguments. Instead you need to get the input variable(s) associated with the network's arguments and bind those to minibatchData e.g. something like
std::unordered_map<Variable, ValuePtr> inputDataMap = { { classifierOutput.Arguments()[0], minibatchData[imageStreamInfo] } }
Then pass inputDataMap to TrainMinibatch. See also this evaluation example (training and evaluation have pretty similar APIs)

Related

msvc std::chrono::time_zone::get_info throws an exception saying: The operation completed successfully

I was trying to convert utc time returned from std::chrono::system_clock to local time before displaying it using std::format but I got a surprising exception from std::chrono::time_zone::to_local and its what message says: The operation completed successfully. What a surprise ! I looked into this method and it called std::chrono::time_zone::get_info on the passed time parameter and did a simple conversion so I tested std::chrono::time_zone::get_info separately and it was the source of this exception. I don't know is it a bug in the implementation or my code is buggy ?
Here is a simple code which throws this error:
try
{
const std::chrono::time_zone* current_z = std::chrono::current_zone();
std::cout << "current timezone name: " << current_z->name() << "\n";
auto sys_time = std::chrono::system_clock::now();
std::cout << "current system time: " << sys_time << "\n";
auto sys_info = current_z->get_info(sys_time); // throws exception what(): The operation completed successfully.
std::cout << "sys_info: offset: " << sys_info.offset << ", abbrev" << sys_info.abbrev << "\n";
//auto local_time = current_z->to_local(sys_time); // throws exception since it calls get_info
//std::cout << "current local time: " << local_time << "\n";
}
catch (const std::exception& ex)
{
std::cout << "caught exception: " << ex.what();
}
EDIT: After looking at std::chrono::time_zone::get_info source code it will invoke this method: std::chrono::time_zone::_Get_info and its source
template <class _Duration>
_NODISCARD sys_info _Get_info(const _Duration& _Dur) const {
using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>;
const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur);
const unique_ptr<__std_tzdb_sys_info, _Tzdb_deleter<__std_tzdb_sys_info>> _Info{
__std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count())};
if (_Info == nullptr) {
_Xbad_alloc();
} else if (_Info->_Err == __std_tzdb_error::_Win_error) {
_XGetLastError();
} else if (_Info->_Err == __std_tzdb_error::_Icu_error) {
_Xruntime_error("Internal error loading IANA database information");
}
constexpr auto _Min_internal =
_CHRONO duration_cast<_Internal_duration>(_Min_seconds.time_since_epoch()).count();
constexpr auto _Max_internal =
_CHRONO duration_cast<_Internal_duration>(_Max_seconds.time_since_epoch()).count();
const auto _Begin =
_Info->_Begin <= _Min_internal
? _Min_seconds
: sys_seconds{_CHRONO duration_cast<sys_seconds::duration>(_Internal_duration{_Info->_Begin})};
const auto _End =
_Info->_End >= _Max_internal
? _Max_seconds
: sys_seconds{_CHRONO duration_cast<sys_seconds::duration>(_Internal_duration{_Info->_End})};
return {.begin = _Begin,
.end = _End,
.offset = _CHRONO duration_cast<seconds>(_Internal_duration{_Info->_Offset}),
.save = _CHRONO duration_cast<minutes>(_Internal_duration{_Info->_Save}),
.abbrev = _Info->_Abbrev};
}
the _Info pointer returned by __std_tzdb_get_sys_info is not nullptr but its _Err is set to 1 which equals __std_tzdb_error::_Win_error so _XGetLastError is called to throw an exception with the error code from GetLastError and it will return 0 indicating no error code so an exception is thrown indicating that no error has happened ! seems a bug in microsoft stl code
Per
https://learn.microsoft.com/en-us/cpp/standard-library/time-zone-class?view=msvc-170
Looks like you should first use get_tzdb() as in
const auto& timeZoneDatabase = get_tzdb(); // initialize the time zone database
const auto& currentZone = timeZoneDatabase.current_zone();

Passing multiple arguments in C++ to MatLab shared library function

I've implemented a feature matching algorithm in Matlab and trying to use it in my C++ application using shared libraries. The problem is that I am only getting values for one argument though I am passing four arguments to the function.
The Matlab function:
[c, d, e, f] = fm_test("C:\0.jpg", "C:\1.jpg");
function [FSC_1, FSC_2, NBCS_1, NBCS_2] = fm_test(path_im1, path_im2)
...
% Performed feature matching - output are 4 matrices with format n x 2 single
FSC_1 = matchedPoints1(inliersIndex, :);
FSC_2 = matchedPoints2(inliersIndex, :);
NBCS_1 = matchedPoints1(inliers_NBCS, :);
NBCS_2 = matchedPoints2(inliers_NBCS, :);
end
I am using the Library Compiler to create shared libraries for C++ and call the function:
mclmcrInitialize();
//const char *args[] = { "-nojvm" };
//const int count = sizeof(args) / sizeof(args[0]);
if (!mclInitializeApplication(NULL, 0)) {
std::cerr << "Could not initialize the application properly" << std::endl;
return -1;
}
if (!fm_testInitialize()) {
std::cerr << "Could not initialize the library properly" << std::endl;
return -1;
}
else {
try {
for (size_t i = 0; i < cameras.size() - 1; ++i){
mwArray FSC_1, FSC_2, NBCS_1, NBCS_2;
mwArray path_1 = cameras[i].image_path.c_str();
mwArray path_2 = cameras[i+1].image_path.c_str();
fm_test(1, FSC_1, FSC_2, NBCS_1, NBCS_2, path_1, path_2);
// Convert mwArray to vector<double>
std::cout << " Printing sizes of mwArray" << std::endl;
std::cout << FSC_1.NumberOfElements() << std::endl;
std::cout << FSC_2.NumberOfElements() << std::endl;
std::cout << NBCS_1.NumberOfElements() << std::endl;
std::cout << NBCS_2.NumberOfElements() << std::endl;
}
}
catch (const mwException& e) {
std::cerr << e.what() << std::endl;
return -2;
}
catch (...) {
std::cerr << "Unexpected error thrown" << std::endl;
return -3;
}
fm_testTerminate();
}
The result is e.g.:
Printing sizes of mwArray
100
0
0
0
Is it possible to pass multiple arguments to the function? Do I have to define the mwArray more specifically?
I needed to pass a different first argument to the function in contrast to the example on the Matlab website.
The function is defined as:
extern LIB_fm_test_CPP_API void MW_CALL_CONV fm_test(int nargout, mwArray& FSC_1, mwArray& FSC_2, mwArray& NBCS_1, mwArray& NBCS_2, const mwArray& path_im1, const mwArray& path_im2);
The first argument has to be changed to the number of arguments I have as output (in my case 4). The correct function call is:
fm_test(4, FSC_1, FSC_2, NBCS_1, NBCS_2, path_1, path_2);

Access to CV_32SC1 nx1 opencv matrix

I have an artificial matrix which I pass to the EM Gaussian Mixture Model algorithm in OpenCV - version 3.0.0 of the form :
[1.1, 3.2;
1.15, 3.1500001;
3.0999999, 4.1999998;
3.2, 4.3000002;
5, 5]
I call the GMM prediction via:
cv::Ptr<cv::ml::EM> source_model = cv::ml::EM::create();
source_model->setClustersNumber(3);
cv::Mat logs;
cv::Mat labels;
cv::Mat probs;
source_model->trainEM( openCVPointCloud,logs,labels,probs)
The documentation states about the matrix labels which I am interested in:
labels – The optional output 'class label' for each sample:
labels_i = {arg max}k(p{i,k}), i=1..N (indices of the most probable mixture component for each sample). It has nsamples x 1 size and 'CV_32SC1' type.
My non working access to 'labels' prints (0,0,0,0,0) instead of expected (0,0,1,1,2) which is plotted via
std::cout << labels <<std::endl;
. I need though working with the integer indices to work with my original PCL point cloud which I want to cluster via poitn cloud features:
std::cout << labels.data[0] << std::endl;
std::cout << labels.data[1] << std::endl;
std::cout << labels.data[2] << std::endl;
std::cout << labels.data[3] << std::endl;
std::cout << labels.data[4] << std::endl;
The code fragments wrapped together in an untested minimal example (I have problems with qmake without using my frame work):
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/ml.hpp>
int main()
{
cv::Mat openCVPointCloud(5, 2, CV_32FC(1));
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(0,0);
values1.val[0] = 1.1;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(0,1);
values2.val[0] = 3.2;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(1,0);
values1.val[0] = 1.15;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(1,1);
values2.val[0] = 3.15;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(2,0);
values1.val[0] = 3.1;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(2,1);
values2.val[0] = 4.2;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(3,0);
values1.val[0] = 3.2;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(3,1);
values2.val[0] = 4.3;
}
{
cv::Vec<float,1> & values1 = openCVPointCloud.at<cv::Vec<float,1> >(4,0);
values1.val[0] = 5;
cv::Vec<float,1> & values2 = openCVPointCloud.at<cv::Vec<float,1> >(4,1);
values2.val[0] = 5;
}
std::cout << openCVPointCloud << std::endl;
cv::Ptr<cv::ml::EM> source_model = cv::ml::EM::create();
source_model->setClustersNumber(3);
cv::Mat logs;
cv::Mat labels;
cv::Mat probs;
if(source_model->trainEM( openCVPointCloud,logs,labels,probs))
{
std::cout << "true train em";
std::cout << labels.data[0] << std::endl;
std::cout << labels.data[1] << std::endl;
std::cout << labels.data[2] << std::endl;
std::cout << labels.data[3] << std::endl;
std::cout << labels.data[4] << std::endl;
} else {
std::cout <<"false train em" << std::endl;
}
}
What can I do to get access to the integer numbers stored in labels?
This stackexchange topic states, that if I know the matrix element type I can use the templated at() function. The api states that the label Matrix is of type $CV_32SC1$. Accessing now via:
std::cout << labels.at<CV_32SC1>(2,0) << std::endl;
Results in the following error:
invalid template argument for '_Tp', type expected
At the time of creation of this question I was also 100% sure I tested
std::cout << labels.at<int>(2,0) << std::endl;
also which plotted 0 (and should have been 1). Code in front of me after accepted answer adaptian though prooves me wrong. Might be a duplicate because of a typo I did not see for some hours and the "typo" might have been QT's qdebug() usage instead of std::cout. If still considered valuable someone might improve the constructor in the minimal example I provided and remove this sentence and the following. I still hope for a one line solution which I yet failed to perform.
Proper way to print Mat value is to use operator<<. You already have it.
Your cv::Mat labels has type CV_32SC1. It contain 32 bit signed integer elements. So you can access items by labels.at<int> method.
Better way to access items is to use iterator cv::MatIterator_< _Tp >:
for(cv::MatIterator_<int> it(labels.begin<int>()); it != labels.end<int>(); it++)
{
std::cout << (*it) << std::endl; // int i = *it
}

Flatbuffers encoding then decoding C++ double array + table + union returns junk

I'm filling out some flatbuffer messages but when I encode then decode them I get junk back out. I've not included the full message to avoid extraneous information, but I'm able to extract the enum value of the union component successfully. However, when I go to extract the type identified by the enum the double array I print out contains junk as illustrated below.
Here are the important parts of the buffers:
Input/Output:
KukaJAVAdriver sending armposition command:[1, 0, 0, 0, 0, 0, 1]
re-extracted 7 joint angles: 0 11 02 03 04 05 06 1
JointState.fbs:
table JointState {
// #todo consider adding name string
position:[double]; // angle in radians
velocity:[double]; // velocity in radians/second
acceleration:[double]; // acceleration in radians/(second^2)
torque:[double]; // Newton Meters (N*m)
}
ArmControlState.fbs:
include "JointState.fbs";
include "Geometry.fbs";
namespace grl.flatbuffer;
table StartArm {
}
table StopArm {
}
table PauseArm {
}
table TeachArm {
}
table ShutdownArm {
}
table MoveArmTrajectory {
traj:[JointState];
}
table MoveArmJointServo {
goal:JointState;
}
table MoveArmCartesianServo {
parent:string; // Object/Frame/Coordinate System to move wrt. Empty default is robot base
goal:Pose;
}
union ArmState { StartArm, StopArm, PauseArm, ShutdownArm, TeachArm, MoveArmTrajectory, MoveArmJointServo, MoveArmCartesianServo }
table ArmControlState {
name:string; // entity to move
sequenceNumber:long;
timeStamp:double;
state:ArmState;
}
encode:
flatbuffers::Offset<flatbuffer::ArmControlState> controlState;
switch (armControlMode_) {
case flatbuffer::ArmState::ArmState_StartArm: {
controlState = flatbuffer::CreateArmControlState(*fbbP,bns,sequenceNumber++,duration,armControlMode_,flatbuffer::CreateStartArm(*fbbP).Union());
break;
}
case flatbuffer::ArmState::ArmState_MoveArmJointServo: {
/// #todo when new
JointScalar armPosVelAccelEmpty;
auto armPositionBuffer = fbbP->CreateVector(armPosition_.data(),armPosition_.size());
auto goalJointState = grl::flatbuffer::CreateJointState(*fbbP,armPositionBuffer);
auto moveArmJointServo = grl::flatbuffer::CreateMoveArmJointServo(*fbbP,goalJointState);
controlState = flatbuffer::CreateArmControlState(*fbbP,bns,sequenceNumber++,duration,armControlMode_,moveArmJointServo.Union());
std::cout << "KukaJAVAdriver sending armposition command:" <<armPosition_<<"\n";
break;
}
//...snip...
}
decode:
auto states = flatbuffer::CreateKUKAiiwaStates(*fbbP,kukaiiwaStateVec);
grl::flatbuffer::FinishKUKAiiwaStatesBuffer(*fbbP, states);
flatbuffers::Verifier verifier(fbbP->GetBufferPointer(),fbbP->GetSize());
BOOST_VERIFY(grl::flatbuffer::VerifyKUKAiiwaStatesBuffer(verifier));
if(armControlMode_ == flatbuffer::ArmState::ArmState_MoveArmJointServo)
{
auto states2 = flatbuffer::GetKUKAiiwaStates(fbbP->GetBufferPointer());
auto movearm = static_cast<const flatbuffer::MoveArmJointServo*>(states2->states()->Get(0)->armControlState()->state());
std::cout << "re-extracted " << movearm->goal()->position()->size() << " joint angles: ";
for(std::size_t i = 0; i < movearm->goal()->position()->size(); ++i)
{
std::cout << i << " " << movearm->goal()->position()->Get(i);
}
std::cout << "\n";
}
kukaJavaDriverP->async_send_flatbuffer(fbbP);
You don't get junk out, the data is actually correct. The bug is in this statement: std::cout << i << " " << movearm->goal()->position()->Get(i);
If instead you wrote something like: std::cout << i << "=" << movearm->goal()->position()->Get(i) << ", "; it be more readable :)

forecast.HoltWinters is not getting mapped into C++

Based on the example code I was trying to run forecast method using c++ and RInside , but I am getting Read 100 items
Exception caught: not a matrix
Can somebody please take a look at my code.
#include <RInside.h>
int main ( int argc, char **argv) {
try {
// create an embedded R instance
RInside R ( argc, argv);
std::string txt =
"rain <- scan(\"http://robjhyndman.com/tsdldata/hurst/precip1.dat\",skip=1);"
"rainseries <- ts(rain,start=c(1813));"
"rainseriesforecasts <- HoltWinters(rainseries, beta=FALSE, gamma=FALSE);"
"suppressMessages(require(forecast));";
R.parseEvalQ(txt); // eval command, no return
Rcpp::NumericMatrix M((SEXP)R.parseEval("rainseriesforecasts2 <- forecast.HoltWinters(rainseriesforecasts, h=8)"));
Rcpp::StringVector cnames( (SEXP) R.parseEval("colnames(rainseriesforecasts2)"));
Rcpp::StringVector rnames( (SEXP) R.parseEval("rownames(rainseriesforecasts2)"));
std::cout << "\n\nAnd now from C++\n\n\t\t\t";
for (int i=0; i<cnames.size(); i++) {
std::cout << std::setw(11) << cnames[i] << "\t";
}
std::cout << std::endl;
for (int i=0; i<rnames.size(); i++) {
std::cout << std::setw(16) << rnames[i] << "\t";
for (int j=0; j<cnames.size(); j++) {
std::cout << std::setw(11) << M(i,j) << "\t";
}
std::cout << std::endl;
}
std::cout << std::endl;
} catch(std::exception& ex) {
std::cerr << "Exception caught: " << ex.what() << std::endl;
} catch(...) {
std::cerr << "Unknown exception caught" << std::endl;
}
}
This looks like a straight-up adaptation of one of the over a dozen examples I have included in the RInside sources -- so that is a good starting point.
The error you quote is an R error, not a C++ error so I would start by trying the few lines of R code by themselves in R. Pay particular attention to the class() of the returns you want to assign to make sure you do cast it to the right C++ types.
Edit: Ok, had some time to look at it. You were close, but as I suspected the types from the forecast package get in the way. Try this:
R.parseEvalQ(txt); // eval command, no return
Rcpp::NumericMatrix M((SEXP)R.parseEval("rainseriesforecasts2 <- as.matrix(as.data.frame(forecast.HoltWinters(rainseriesforecasts, h=8)))"));
Rcpp::StringVector cnames( (SEXP) R.parseEval("colnames(as.data.frame(rainseriesforecasts2))"));
Rcpp::StringVector rnames( (SEXP) R.parseEval("rownames(as.data.frame(rainseriesforecasts2))"));
and with that it works for me:
edd#dexter:~/svn/rinside/pkg/inst/examples/standard$ ./rinside_sample12
Read 100 items
And now from C++
Point Forecast Lo 80 Hi 80 Lo 95 Hi 95
1913 24.6782 19.1749 30.1815 16.2617 33.0947
1914 24.6782 19.1733 30.1831 16.2592 33.0972
1915 24.6782 19.1717 30.1847 16.2568 33.0996
1916 24.6782 19.1701 30.1863 16.2543 33.102
1917 24.6782 19.1685 30.1879 16.2519 33.1045
1918 24.6782 19.1669 30.1895 16.2495 33.1069
1919 24.6782 19.1653 30.1911 16.247 33.1094
1920 24.6782 19.1637 30.1926 16.2446 33.1118
edd#dexter:~/svn/rinside/pkg/inst/examples/standard$