Skip to content

Commit

Permalink
C2DTensor bug-fixed
Browse files Browse the repository at this point in the history
  • Loading branch information
MegaJoctan committed Jul 18, 2024
1 parent 9e231e2 commit b6ad50b
Show file tree
Hide file tree
Showing 2 changed files with 402 additions and 44 deletions.
336 changes: 336 additions & 0 deletions Convolutional Neural Networks(CNNs)/ConvNet.mqh
Original file line number Diff line number Diff line change
@@ -0,0 +1,336 @@
//+------------------------------------------------------------------+
//| CNN.mqh |
//| Copyright 2023, Omega Joctan |
//| https://www.mql5.com/en/users/omegajoctan |
//+------------------------------------------------------------------+
#property copyright "Copyright 2023, Omega Joctan"
#property link "https://www.mql5.com/en/users/omegajoctan"
//+------------------------------------------------------------------+
//| Class for loading the convolution Neural network class in onnx |
//| format, tested on keras built model. \
//+------------------------------------------------------------------+

#include <MALE5\Tensors.mqh>
#define UNDEFINED_REPLACE 1

class CConvNet
{

protected:

bool initialized;
long onnx_handle;
void PrintTypeInfo(const long num,const string layer,const OnnxTypeInfo& type_info);
long inputs[], outputs[];

void replace(long &arr[]) { for (uint i=0; i<arr.Size(); i++) if (arr[i] <= -1) arr[i] = UNDEFINED_REPLACE; }
string ConvertTime(double seconds);

public:
CConvNet(void);
~CConvNet(void);

bool Init(const uchar &onnx_buff[], ulong flags=ONNX_DEFAULT);
bool Init(string onnx_filename, uint flags=ONNX_DEFAULT);

virtual int predict_bin(const matrix &x, const vector &classes_in_data); //predicts classes | useful for live trading
virtual vector predict_bin(C3DTensor &x_tensor, const vector &classes_in_data); //predict classes for the entire data | useful for training purposes
virtual vector predict_proba(const matrix &x); //Predicts probabilities | Useful for live trading

double predict(const matrix &x); //for a regression problem
};
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CConvNet::CConvNet(void)
{

}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
CConvNet::~CConvNet(void)
{

}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+

bool CConvNet::Init(string onnx_filename, uint flags=ONNX_DEFAULT)
{
Print("Initilaizing ONNX model...");

onnx_handle = OnnxCreate(onnx_filename, flags);

//--- since not all sizes defined in the input tensor we must set them explicitly
//--- first index - batch size, second index - series size, third index - number of series (only Close)

OnnxTypeInfo type_info; //Getting onnx information for Reference In case you forgot what the loaded ONNX is all about

long input_count=OnnxGetInputCount(onnx_handle);
if (MQLInfoInteger(MQL_DEBUG))
Print("model has ",input_count," input(s)");

for(long i=0; i<input_count; i++)
{
string input_name=OnnxGetInputName(onnx_handle,i);
if (MQLInfoInteger(MQL_DEBUG))
Print(i," input name is ",input_name);

if(OnnxGetInputTypeInfo(onnx_handle,i,type_info))
{
if (MQLInfoInteger(MQL_DEBUG))
PrintTypeInfo(i,"input",type_info);
ArrayCopy(inputs, type_info.tensor.dimensions);
}
}

long output_count=OnnxGetOutputCount(onnx_handle);
if (MQLInfoInteger(MQL_DEBUG))
Print("model has ",output_count," output(s)");
for(long i=0; i<output_count; i++)
{
string output_name=OnnxGetOutputName(onnx_handle,i);
if (MQLInfoInteger(MQL_DEBUG))
Print(i," output name is ",output_name);

if(OnnxGetOutputTypeInfo(onnx_handle,i,type_info))
{
if (MQLInfoInteger(MQL_DEBUG))
PrintTypeInfo(i,"output",type_info);
ArrayCopy(outputs, type_info.tensor.dimensions);
}
}

//---

replace(inputs);
replace(outputs);

if (!OnnxSetInputShape(onnx_handle, 0, inputs)) //Giving the Onnx handle the input shape
{
printf("Failed to set the input shape Err=%d",GetLastError());
return false;
}

if (!OnnxSetOutputShape(onnx_handle, 0, outputs)) //giving the onnx handle the output shape
{
printf("Failed to set the Output shape Err=%d",GetLastError());
return false;
}

initialized = true;
Print("ONNX model Initialized");

return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
bool CConvNet::Init(const uchar &onnx_buff[], ulong flags=ONNX_DEFAULT)
{
Print("Initilaizing ONNX model...");

onnx_handle = OnnxCreateFromBuffer(onnx_buff, flags); //creating onnx handle buffer | rUN DEGUG MODE during debug mode


//--- since not all sizes defined in the input tensor we must set them explicitly
//--- first index - batch size, second index - series size, third index - number of series (only Close)

OnnxTypeInfo type_info; //Getting onnx information for Reference In case you forgot what the loaded ONNX is all about

long input_count=OnnxGetInputCount(onnx_handle);
if (MQLInfoInteger(MQL_DEBUG))
Print("model has ",input_count," input(s)");

for(long i=0; i<input_count; i++)
{
string input_name=OnnxGetInputName(onnx_handle,i);
if (MQLInfoInteger(MQL_DEBUG))
Print(i," input name is ",input_name);

if(OnnxGetInputTypeInfo(onnx_handle,i,type_info))
{
if (MQLInfoInteger(MQL_DEBUG))
PrintTypeInfo(i,"input",type_info);
ArrayCopy(inputs, type_info.tensor.dimensions);
}
}

long output_count=OnnxGetOutputCount(onnx_handle);
if (MQLInfoInteger(MQL_DEBUG))
Print("model has ",output_count," output(s)");
for(long i=0; i<output_count; i++)
{
string output_name=OnnxGetOutputName(onnx_handle,i);
if (MQLInfoInteger(MQL_DEBUG))
Print(i," output name is ",output_name);

if(OnnxGetOutputTypeInfo(onnx_handle,i,type_info))
{
if (MQLInfoInteger(MQL_DEBUG))
PrintTypeInfo(i,"output",type_info);
ArrayCopy(outputs, type_info.tensor.dimensions);
}
}

//---

replace(inputs);
replace(outputs);

if (!OnnxSetInputShape(onnx_handle, 0, inputs)) //Giving the Onnx handle the input shape
{
printf("Failed to set the input shape Err=%d",GetLastError());
return false;
}

if (!OnnxSetOutputShape(onnx_handle, 0, outputs)) //giving the onnx handle the output shape
{
printf("Failed to set the Output shape Err=%d",GetLastError());
return false;
}

initialized = true;

Print("ONNX model Initialized");
return true;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
void CConvNet::PrintTypeInfo(const long num,const string layer,const OnnxTypeInfo& type_info)
{
Print(" type ",EnumToString(type_info.type));
Print(" data type ",EnumToString(type_info.type));

if(type_info.tensor.dimensions.Size()>0)
{
bool dim_defined=(type_info.tensor.dimensions[0]>0);
string dimensions=IntegerToString(type_info.tensor.dimensions[0]);


for(long n=1; n<type_info.tensor.dimensions.Size(); n++)
{
if(type_info.tensor.dimensions[n]<=0)
dim_defined=false;
dimensions+=", ";
dimensions+=IntegerToString(type_info.tensor.dimensions[n]);
}
Print(" shape [",dimensions,"]");
//--- not all dimensions defined
if(!dim_defined)
PrintFormat(" %I64d %s shape must be defined explicitly before model inference",num,layer);
//--- reduce shape
uint reduced=0;
long dims[];
for(long n=0; n<type_info.tensor.dimensions.Size(); n++)
{
long dimension=type_info.tensor.dimensions[n];
//--- replace undefined dimension
if(dimension<=0)
dimension=UNDEFINED_REPLACE;
//--- 1 can be reduced
if(dimension>1)
{
ArrayResize(dims,reduced+1);
dims[reduced++]=dimension;
}
}
//--- all dimensions assumed 1
if(reduced==0)
{
ArrayResize(dims,1);
dims[reduced++]=1;
}
//--- shape was reduced
if(reduced<type_info.tensor.dimensions.Size())
{
dimensions=IntegerToString(dims[0]);
for(long n=1; n<dims.Size(); n++)
{
dimensions+=", ";
dimensions+=IntegerToString(dims[n]);
}
string sentence="";
if(!dim_defined)
sentence=" if undefined dimension set to "+(string)UNDEFINED_REPLACE;
PrintFormat(" shape of %s data can be reduced to [%s]%s",layer,dimensions,sentence);
}
}
else
PrintFormat("no dimensions defined for %I64d %s",num,layer);
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
int CConvNet::predict_bin(const matrix &x, const vector &classes_in_data)
{
if (!this.initialized)
{
printf("%s The model is not initialized yet to make predictions | call Init function first",__FUNCTION__);
return 0;
}

//---

matrixf x_float;
x_float.Assign(x);

vector output_data(this.outputs[outputs.Size()-1]);

if (!OnnxRun(onnx_handle, ONNX_DATA_TYPE_FLOAT, x_float, output_data))
{
printf("Failed to get predictions from Onnx err %d",GetLastError());
return false;
}

return (int)classes_in_data[output_data.ArgMax()]; //Return the class with highest probability
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
vector CConvNet::predict_proba(const matrix &x)
{

if (!this.initialized)
{
printf("%s The model is not initialized yet to make predictions | call Init function first",__FUNCTION__);
vector empty = {};
return empty;
}

//---

matrixf x_float;
x_float.Assign(x);

vector proba(this.outputs[outputs.Size()-1]);

if (!OnnxRun(onnx_handle, ONNX_DATA_TYPE_FLOAT, x_float, proba))
{
printf("Failed to get predictions from Onnx err %d",GetLastError());
return proba;
}

return proba; //Return the class with highest probability
}
//+------------------------------------------------------------------+
//| When given a matrix for timeseries data collected it provides |
//| a scalar binary value which is a prediction |
//+------------------------------------------------------------------+
vector CConvNet::predict_bin(C3DTensor &timeseries_tensor, const vector &classes_in_data)
{
vector preds(timeseries_tensor.SIZE);
for (uint i=0; i<timeseries_tensor.SIZE; i++)
{
matrix x = timeseries_tensor.Get(i);
preds[i] = predict_bin(x, classes_in_data);
}

return preds;
}
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
Loading

0 comments on commit b6ad50b

Please sign in to comment.