1695 líneas
125 KiB
MQL5
1695 líneas
125 KiB
MQL5
//+------------------------------------------------------------------+
|
|
//| NetCreatorPanel.mqh |
|
|
//| Copyright DNG® |
|
|
//| https://www.mql5.com/ru/users/dng |
|
|
//+------------------------------------------------------------------+
|
|
#property copyright "Copyright DNG®"
|
|
#property link "https://www.mql5.com/ru/users/dng"
|
|
#property version "1.00"
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
#include "..\..\NeuroNet_DNG\NeuroNet.mqh"
|
|
#include <Controls\Dialog.mqh>
|
|
#include <Controls\Label.mqh>
|
|
#include <Controls\ListView.mqh>
|
|
#include <Controls\SpinEdit.mqh>
|
|
#include <Controls\ComboBox.mqh>
|
|
#include <Controls\Button.mqh>
|
|
//+------------------------------------------------------------------+
|
|
//| defines |
|
|
//+------------------------------------------------------------------+
|
|
//--- indents and gaps
|
|
#define INDENT_LEFT (11) // indent from left (with allowance for border width)
|
|
#define INDENT_TOP (11) // indent from top (with allowance for border width)
|
|
#define INDENT_RIGHT (11) // indent from right (with allowance for border width)
|
|
#define INDENT_BOTTOM (11) // indent from bottom (with allowance for border width)
|
|
#define CONTROLS_GAP_X (5) // gap by X coordinate
|
|
#define CONTROLS_GAP_Y (5) // gap by Y coordinate
|
|
//--- for buttons
|
|
#define BUTTON_HEIGHT (20) // size by Y coordinate
|
|
//--- for the indication area
|
|
#define EDIT_WIDTH (100) // size by X coordinate
|
|
#define EDIT_HEIGHT (20) // size by Y coordinate
|
|
//--- for group controls
|
|
#define LIST_WIDTH (280) // size by X coordinate
|
|
#define ADDS_WIDTH (200) // size by X coordinate
|
|
//---
|
|
#define LABEL_NAME "Label"
|
|
#define EDIT_NAME "Edit"
|
|
//---
|
|
#define DEFAULT_NEURONS (1000)
|
|
#define DEFAULT_OPTIMIZATION ADAM
|
|
#define DEFAULT_ACTIVATION SIGMOID
|
|
#define DEFAULT_PROBABILITY (0.3)
|
|
//---
|
|
#define PANEL_WIDTH (2 * LIST_WIDTH + ADDS_WIDTH + \
|
|
2 * CONTROLS_GAP_X + \
|
|
INDENT_LEFT + INDENT_RIGHT + \
|
|
4 * CONTROLS_DIALOG_CLIENT_OFF)
|
|
#define PANEL_HEIGHT (INDENT_TOP + INDENT_BOTTOM + \
|
|
12 * (EDIT_HEIGHT + CONTROLS_GAP_Y) + \
|
|
BUTTON_HEIGHT + CONTROLS_GAP_Y + \
|
|
4 * CONTROLS_BORDER_WIDTH + \
|
|
CONTROLS_DIALOG_CAPTION_HEIGHT)
|
|
//---
|
|
#define EXTENSION ".nnw"
|
|
//---
|
|
#define KEY_UP 38
|
|
#define KEY_DOWN 40
|
|
#define KEY_DELETE 46
|
|
//---
|
|
#define ON_EVENT_CONTROL(event,control,handler) if(id==(event+CHARTEVENT_CUSTOM) && lparam==control.Id()) { handler(control); return(true); }
|
|
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CNetModify : public CNet
|
|
{
|
|
public:
|
|
CNetModify(void) {};
|
|
~CNetModify(void) {};
|
|
//---
|
|
uint LayersTotal(void);
|
|
CArrayObj* GetLayersDiscriptions(void);
|
|
virtual bool AddLayer(CLayer* new_layer);
|
|
virtual bool AddLayers(CArrayObj* new_layers);
|
|
virtual CLayer* GetLayer(uint layer);
|
|
COpenCLMy* GetOpenCL(void) {return opencl;}
|
|
void SetOpenCL(COpenCLMy *OpenCL) {opencl = OpenCL;}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
uint CNetModify::LayersTotal(void)
|
|
{
|
|
if(!layers)
|
|
return 0;
|
|
//---
|
|
return layers.Total();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CArrayObj* CNetModify::GetLayersDiscriptions(void)
|
|
{
|
|
CArrayObj* result = new CArrayObj();
|
|
for(uint i = 0; i < LayersTotal(); i++)
|
|
{
|
|
CLayer* layer = layers.At(i);
|
|
if(!layer)
|
|
break;
|
|
CNeuronBaseOCL* neuron = layer.At(0);
|
|
if(!neuron)
|
|
break;
|
|
if(!result.Add(neuron.GetLayerInfo()))
|
|
break;
|
|
}
|
|
//---
|
|
return result;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CLayer* CNetModify::GetLayer(uint layer)
|
|
{
|
|
if(!layers || LayersTotal() <= layer)
|
|
return NULL;
|
|
//---
|
|
return layers.At(layer);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetModify::AddLayer(CLayer *new_layer)
|
|
{
|
|
if(!new_layer)
|
|
return false;
|
|
if(!layers)
|
|
{
|
|
layers = new CArrayLayer();
|
|
if(!layers)
|
|
return false;
|
|
}
|
|
//---
|
|
return layers.Add(new_layer);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetModify::AddLayers(CArrayObj *new_layers)
|
|
{
|
|
if(!new_layers || new_layers.Total() <= 0)
|
|
return false;
|
|
//---
|
|
if(!layers || LayersTotal() <= 0)
|
|
{
|
|
Create(new_layers);
|
|
return true;
|
|
}
|
|
//---
|
|
CLayerDescription *desc = NULL, *next = NULL, *prev = NULL;
|
|
CLayer *temp;
|
|
//---
|
|
int shift = (int)LayersTotal() - 1;
|
|
CLayer* last_layer = layers.At(shift);
|
|
if(!last_layer)
|
|
return false;
|
|
//---
|
|
CNeuronBaseOCL* neuron = last_layer.At(0);
|
|
if(!neuron)
|
|
return false;
|
|
//---
|
|
desc = neuron.GetLayerInfo();
|
|
next = new_layers.At(0);
|
|
uint outputs = (next == NULL || (next.type != defNeuron && next.type != defNeuronBaseOCL) ? 0 : next.count);
|
|
if(!!next && next.type == defNeuronFQF)
|
|
outputs = next.count * next.window_out;
|
|
if(!neuron.numOutputs(outputs, next.optimization))
|
|
return false;
|
|
//---
|
|
int total = new_layers.Total();
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
if(i == 1 && !!prev)
|
|
delete prev;
|
|
prev = desc;
|
|
desc = new_layers.At(i);
|
|
next = new_layers.At(i + 1);
|
|
outputs = (next == NULL || (next.type != defNeuron && next.type != defNeuronBaseOCL) ? 0 : next.count);
|
|
if(!!next && next.type == defNeuronFQF)
|
|
outputs = next.count * next.window_out;
|
|
temp = new CLayer(outputs);
|
|
uint neurons = (desc.count + (desc.type == defNeuron || desc.type == defNeuronBaseOCL ? 1 : 0));
|
|
CNeuronBaseOCL *neuron_ocl = NULL;
|
|
CNeuronConvOCL *neuron_conv_ocl = NULL;
|
|
CNeuronProofOCL *neuron_proof_ocl = NULL;
|
|
CNeuronAttentionOCL *neuron_attention_ocl = NULL;
|
|
CNeuronMLMHAttentionOCL *neuron_mlattention_ocl = NULL;
|
|
CNeuronDropoutOCL *dropout = NULL;
|
|
CNeuronBatchNormOCL *batch = NULL;
|
|
CVAE *vae = NULL;
|
|
CNeuronLSTMOCL *lstm = NULL;
|
|
CNeuronSoftMaxOCL *softmax = NULL;
|
|
CNeuronFQF *fqf = NULL;
|
|
switch(desc.type)
|
|
{
|
|
case defNeuron:
|
|
case defNeuronBaseOCL:
|
|
neuron_ocl = new CNeuronBaseOCL();
|
|
if(CheckPointer(neuron_ocl) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!neuron_ocl.Init(outputs, 0, opencl, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete neuron_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_ocl.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(neuron_ocl))
|
|
{
|
|
delete neuron_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_ocl = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronConvOCL:
|
|
neuron_conv_ocl = new CNeuronConvOCL();
|
|
if(CheckPointer(neuron_conv_ocl) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!neuron_conv_ocl.Init(outputs, 0, opencl, desc.window, desc.step, desc.window_out, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete neuron_conv_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_conv_ocl.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(neuron_conv_ocl))
|
|
{
|
|
delete neuron_conv_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_conv_ocl = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronProofOCL:
|
|
neuron_proof_ocl = new CNeuronProofOCL();
|
|
if(!neuron_proof_ocl)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!neuron_proof_ocl.Init(outputs, 0, opencl, desc.window, desc.step, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete neuron_proof_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_proof_ocl.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(neuron_proof_ocl))
|
|
{
|
|
delete neuron_proof_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_proof_ocl = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronAttentionOCL:
|
|
neuron_attention_ocl = new CNeuronAttentionOCL();
|
|
if(CheckPointer(neuron_attention_ocl) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!neuron_attention_ocl.Init(outputs, 0, opencl, desc.window, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete neuron_attention_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_attention_ocl.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(neuron_attention_ocl))
|
|
{
|
|
delete neuron_attention_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_attention_ocl = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronMHAttentionOCL:
|
|
neuron_attention_ocl = new CNeuronMHAttentionOCL();
|
|
if(CheckPointer(neuron_attention_ocl) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!neuron_attention_ocl.Init(outputs, 0, opencl, desc.window, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete neuron_attention_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_attention_ocl.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(neuron_attention_ocl))
|
|
{
|
|
delete neuron_attention_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_attention_ocl = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronMLMHAttentionOCL:
|
|
neuron_mlattention_ocl = new CNeuronMLMHAttentionOCL();
|
|
if(CheckPointer(neuron_mlattention_ocl) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!neuron_mlattention_ocl.Init(outputs, 0, opencl, desc.window, desc.window_out, desc.step, desc.count, desc.layers, desc.optimization, desc.batch))
|
|
{
|
|
delete neuron_mlattention_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_mlattention_ocl.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(neuron_mlattention_ocl))
|
|
{
|
|
delete neuron_mlattention_ocl;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
neuron_mlattention_ocl = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronDropoutOCL:
|
|
dropout = new CNeuronDropoutOCL();
|
|
if(CheckPointer(dropout) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!dropout.Init(outputs, 0, opencl, desc.count, desc.probability, desc.optimization, desc.batch))
|
|
{
|
|
delete dropout;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!temp.Add(dropout))
|
|
{
|
|
delete dropout;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
dropout = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronBatchNormOCL:
|
|
batch = new CNeuronBatchNormOCL();
|
|
if(CheckPointer(batch) == POINTER_INVALID)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!batch.Init(outputs, 0, opencl, desc.count, desc.batch, desc.optimization))
|
|
{
|
|
delete batch;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
batch.SetActivationFunction(desc.activation);
|
|
if(!temp.Add(batch))
|
|
{
|
|
delete batch;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
batch = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronVAEOCL:
|
|
vae = new CVAE();
|
|
if(!vae)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!vae.Init(outputs, 0, opencl, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete vae;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!temp.Add(vae))
|
|
{
|
|
delete vae;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
vae = NULL;
|
|
break;
|
|
case defNeuronLSTMOCL:
|
|
lstm = new CNeuronLSTMOCL();
|
|
if(!lstm)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!lstm.Init(outputs, 0, opencl, desc.count, desc.optimization, desc.batch))
|
|
{
|
|
delete lstm;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(i > 0)
|
|
{
|
|
desc = new_layers.At(i - 1);
|
|
if(!lstm.SetInputs(desc.count))
|
|
{
|
|
delete lstm;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
}
|
|
if(!temp.Add(lstm))
|
|
{
|
|
delete lstm;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
lstm = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronSoftMaxOCL:
|
|
softmax = new CNeuronSoftMaxOCL();
|
|
if(!softmax)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!softmax.Init(outputs, 0, opencl, desc.count * desc.step, desc.optimization, desc.batch))
|
|
{
|
|
delete softmax;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
softmax.SetHeads(desc.step);
|
|
if(!temp.Add(softmax))
|
|
{
|
|
delete softmax;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
softmax = NULL;
|
|
break;
|
|
//---
|
|
case defNeuronFQF:
|
|
fqf = new CNeuronFQF();
|
|
if(!fqf)
|
|
{
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!fqf.Init(outputs, 0, opencl, desc.count, desc.window_out, prev.count * (prev.type == defNeuronConv ? prev.window_out : 1), desc.optimization, desc.batch))
|
|
{
|
|
delete fqf;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
if(!temp.Add(fqf.AsObject()))
|
|
{
|
|
delete fqf;
|
|
delete temp;
|
|
return false;
|
|
}
|
|
fqf = NULL;
|
|
break;
|
|
//---
|
|
default:
|
|
delete temp;
|
|
return false;
|
|
break;
|
|
}
|
|
//---
|
|
if(!layers.Add(temp))
|
|
{
|
|
delete temp;
|
|
delete layers;
|
|
return false;
|
|
}
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
class CNetCreatorPanel : protected CAppDialog
|
|
{
|
|
protected:
|
|
//--- pre-trained model
|
|
CNetModify m_Model;
|
|
CEdit m_edPTModel;
|
|
CEdit m_edPTModelLayers;
|
|
CSpinEdit m_spPTModelLayers;
|
|
CListView m_lstPTModel;
|
|
CArrayObj* m_arPTModelDescription;
|
|
bool b_UseCommonDirectory;
|
|
|
|
virtual CLabel* CreateLabel(const int id, const string text, const int x1, const int y1, const int x2, const int y2);
|
|
virtual bool CreateEdit(const int id, CEdit& object, const int x1, const int y1, const int x2, const int y2, bool read_only);
|
|
virtual bool EditReedOnly(CEdit& object, const bool flag);
|
|
virtual string LayerTypeToString(int type);
|
|
virtual int LayerDescriptionToString(const CLayerDescription* layer, string& result[]);
|
|
virtual bool LoadModel(string file_name);
|
|
//--- add layers
|
|
CComboBox m_cbNewNeuronType;
|
|
CLabel* m_lbCount;
|
|
CEdit m_edCount;
|
|
CEdit m_edWindow;
|
|
CEdit m_edWindowOut;
|
|
CLabel* m_lbWindowOut;
|
|
CEdit m_edStep;
|
|
CLabel* m_lbStepHeads;
|
|
CEdit m_edLayers;
|
|
CEdit m_edBatch;
|
|
CEdit m_edProbability;
|
|
CComboBox m_cbActivation;
|
|
CComboBox m_cbOptimization;
|
|
CButton m_btAddLayer;
|
|
CButton m_btDeleteLayer;
|
|
CArrayObj m_arAddLayers;
|
|
|
|
virtual bool CreateComboBoxType(const int x1, const int y1, const int x2, const int y2);
|
|
virtual bool CreateComboBoxActivation(const int x1, const int y1, const int x2, const int y2);
|
|
virtual bool ActivationListMain(void);
|
|
virtual bool ActivationListEmpty(void);
|
|
virtual bool CreateComboBoxOptimization(const int x1, const int y1, const int x2, const int y2);
|
|
virtual bool SetCounts(const uint type);
|
|
//--- new model
|
|
CListView m_lstNewModel;
|
|
CButton m_btSave;
|
|
//--- events
|
|
virtual bool OpenPreTrainedModel(void);
|
|
virtual bool ChangeNumberOfLayers(void);
|
|
virtual bool OnChangeListPTModel(void);
|
|
virtual bool OnChangeListNewModel(void);
|
|
virtual bool OnChangeNeuronType(void);
|
|
virtual bool OnClickAddButton(void);
|
|
virtual bool OnClickDeleteButton(void);
|
|
virtual bool OnClickSaveButton(void);
|
|
virtual bool OnChangeWindowStep(void);
|
|
virtual bool OnEndEdit(CEdit& object);
|
|
virtual bool OnEndEditProbability(void);
|
|
|
|
public:
|
|
CNetCreatorPanel();
|
|
~CNetCreatorPanel();
|
|
//--- main application dialog creation and destroy
|
|
virtual bool Create(const long chart, const string name, const int subwin, const int x1, const int y1, bool common);
|
|
virtual void Destroy(const int reason = REASON_PROGRAM) override { CAppDialog::Destroy(reason); }
|
|
//--- chart event handler
|
|
void ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
|
|
virtual bool OnEvent(const int id, const long &lparam, const double &dparam, const string &sparam);
|
|
|
|
bool Run(void) { return CAppDialog::Run();}
|
|
};
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CNetCreatorPanel::CNetCreatorPanel()
|
|
{
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CNetCreatorPanel::~CNetCreatorPanel()
|
|
{
|
|
if(!!m_arPTModelDescription)
|
|
delete m_arPTModelDescription;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::Create(const long chart, const string name, const int subwin, const int x1, const int y1, bool common)
|
|
{
|
|
if(!CAppDialog::Create(chart, name, subwin, x1, y1, x1 + PANEL_WIDTH, y1 + PANEL_HEIGHT))
|
|
return false;
|
|
//---
|
|
int lx1 = INDENT_LEFT;
|
|
int ly1 = INDENT_TOP;
|
|
int lx2 = lx1 + LIST_WIDTH;
|
|
int ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(0, "PreTrained model", lx1, ly1, lx2, ly2))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateEdit(0, m_edPTModel, lx1, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edPTModel.Text("Select file"))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(1, "Layers Total", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(1, m_edPTModelLayers, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edPTModelLayers.Text("0"))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(2, "Transfer Layers", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!m_spPTModelLayers.Create(m_chart_id, "spPTMCopyLayers", m_subwin, lx2 - EDIT_WIDTH, ly1, lx2, ly2))
|
|
return false;
|
|
m_spPTModelLayers.MinValue(0);
|
|
m_spPTModelLayers.MaxValue(0);
|
|
m_spPTModelLayers.Value(0);
|
|
if(!Add(m_spPTModelLayers))
|
|
return false;
|
|
//---
|
|
lx1 = INDENT_LEFT;
|
|
lx2 = lx1 + LIST_WIDTH;
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ClientAreaHeight() - INDENT_BOTTOM;
|
|
if(!m_lstPTModel.Create(m_chart_id, "lstPTModel", m_subwin, lx1, ly1, lx2, ly2))
|
|
return false;
|
|
if(!m_lstPTModel.VScrolled(true))
|
|
return false;
|
|
if(!Add(m_lstPTModel))
|
|
return false;
|
|
//---
|
|
lx1 = lx2 + CONTROLS_GAP_X;
|
|
lx2 = lx1 + ADDS_WIDTH;
|
|
ly1 = INDENT_TOP;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(3, "Add layer", lx1, ly1, lx2, ly2))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateComboBoxType(lx1, ly1, lx2, ly2))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!(m_lbCount = CreateLabel(4, "Neurons", lx1, ly1, lx1 + EDIT_WIDTH, ly2)))
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(2, m_edCount, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edCount.Text((string)DEFAULT_NEURONS))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(5, "Activation", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateComboBoxActivation(lx2 - EDIT_WIDTH, ly1, lx2, ly2))
|
|
return false;
|
|
m_cbActivation.Disable();
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(6, "Optimization", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateComboBoxOptimization(lx2 - EDIT_WIDTH, ly1, lx2, ly2))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(7, "Window", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(3, m_edWindow, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edWindow.Text((string)2))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
m_lbStepHeads = CreateLabel(8, "Step", lx1, ly1, lx1 + EDIT_WIDTH, ly2);
|
|
if(!m_lbStepHeads)
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(4, m_edStep, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edStep.Text((string)1))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
m_lbWindowOut = CreateLabel(9, "Window Out", lx1, ly1, lx1 + EDIT_WIDTH, ly2);
|
|
if(!m_lbWindowOut)
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(5, m_edWindowOut, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edWindowOut.Text((string)1))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(10, "Layers", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(6, m_edLayers, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edLayers.Text((string)1))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(11, "Batch size", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(7, m_edBatch, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edBatch.Text((string)1))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
if(!CreateLabel(12, "Probability", lx1, ly1, lx1 + EDIT_WIDTH, ly2))
|
|
return false;
|
|
//---
|
|
if(!CreateEdit(8, m_edProbability, lx2 - EDIT_WIDTH, ly1, lx2, ly2, true))
|
|
return false;
|
|
if(!m_edProbability.Text((string)DEFAULT_PROBABILITY))
|
|
return false;
|
|
if(!OnEndEditProbability())
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + BUTTON_HEIGHT;
|
|
if(!m_btAddLayer.Create(m_chart_id, "btAddLayer", m_subwin, lx1, ly1, lx1 + ADDS_WIDTH / 2, ly2))
|
|
return false;
|
|
if(!m_btAddLayer.Text("ADD LAYER"))
|
|
return false;
|
|
m_btAddLayer.Locking(false);
|
|
if(!Add(m_btAddLayer))
|
|
return false;
|
|
//---
|
|
if(!m_btDeleteLayer.Create(m_chart_id, "btDeleteLayer", m_subwin, lx2 - ADDS_WIDTH / 2, ly1, lx2, ly2))
|
|
return false;
|
|
if(!m_btDeleteLayer.Text("DELETE"))
|
|
return false;
|
|
m_btDeleteLayer.Locking(false);
|
|
if(!Add(m_btDeleteLayer))
|
|
return false;
|
|
//---
|
|
lx1 = lx2 + CONTROLS_GAP_X;
|
|
lx2 = lx1 + LIST_WIDTH;
|
|
ly1 = INDENT_TOP;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
int width = (LIST_WIDTH - CONTROLS_GAP_X) / 2;
|
|
if(!CreateLabel(99, "New model", lx1, ly1, lx1 + width, ly2))
|
|
return false;
|
|
//---
|
|
if(!m_btSave.Create(m_chart_id, "btSave", m_subwin, lx2 - width, ly1, lx2, ly2))
|
|
return false;
|
|
if(!m_btSave.Text("SAVE MODEL"))
|
|
return false;
|
|
m_btSave.Locking(false);
|
|
if(!Add(m_btSave))
|
|
return false;
|
|
//---
|
|
ly1 = ly2 + CONTROLS_GAP_Y;
|
|
ly2 = ly1 + EDIT_HEIGHT;
|
|
ly2 = ClientAreaHeight() - INDENT_BOTTOM;
|
|
if(!m_lstNewModel.Create(m_chart_id, "lstNewModel", m_subwin, lx1, ly1, lx2, ly2))
|
|
return false;
|
|
if(!m_lstNewModel.VScrolled(true))
|
|
return false;
|
|
if(!Add(m_lstNewModel))
|
|
return false;
|
|
//---
|
|
b_UseCommonDirectory = common;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
EVENT_MAP_BEGIN(CNetCreatorPanel)
|
|
ON_EVENT(ON_CLICK, m_edPTModel, OpenPreTrainedModel)
|
|
ON_EVENT(ON_CLICK, m_btAddLayer, OnClickAddButton)
|
|
ON_EVENT(ON_CLICK, m_btDeleteLayer, OnClickDeleteButton)
|
|
ON_EVENT(ON_CLICK, m_btSave, OnClickSaveButton)
|
|
ON_EVENT(ON_CHANGE, m_spPTModelLayers, ChangeNumberOfLayers)
|
|
ON_EVENT(ON_CHANGE, m_lstPTModel, OnChangeListPTModel)
|
|
ON_EVENT(ON_CHANGE, m_lstNewModel, OnChangeListNewModel)
|
|
ON_EVENT(ON_CHANGE, m_cbNewNeuronType, OnChangeNeuronType)
|
|
ON_EVENT(ON_END_EDIT, m_edWindow, OnChangeWindowStep)
|
|
ON_EVENT(ON_END_EDIT, m_edStep, OnChangeWindowStep)
|
|
ON_EVENT(ON_END_EDIT, m_edProbability, OnEndEditProbability)
|
|
ON_EVENT_CONTROL(ON_END_EDIT, m_edCount, OnEndEdit)
|
|
ON_EVENT_CONTROL(ON_END_EDIT, m_edWindowOut, OnEndEdit)
|
|
ON_EVENT_CONTROL(ON_END_EDIT, m_edLayers, OnEndEdit)
|
|
ON_EVENT_CONTROL(ON_END_EDIT, m_edBatch, OnEndEdit)
|
|
EVENT_MAP_END(CAppDialog)
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OpenPreTrainedModel(void)
|
|
{
|
|
string filenames[];
|
|
if(FileSelectDialog("Выберите файлы для загрузки", NULL,
|
|
"Neuron Net (*.nnw;*.inv;*.fwd)|*.nnw;*.inv;*.fwd|All files (*.*)|*.*",
|
|
FSD_FILE_MUST_EXIST | (b_UseCommonDirectory ? FSD_COMMON_FOLDER : NULL), filenames, NULL) > 0)
|
|
{
|
|
if(!LoadModel(filenames[0]))
|
|
return false;
|
|
}
|
|
else
|
|
m_edPTModel.Text("Files not selected");
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::LoadModel(string file_name)
|
|
{
|
|
float error, undefine, forecast;
|
|
datetime time;
|
|
ResetLastError();
|
|
if(!m_Model.Load(file_name, error, undefine, forecast, time, b_UseCommonDirectory))
|
|
{
|
|
m_lstPTModel.ItemsClear();
|
|
m_lstPTModel.ItemAdd("Error of load model", 0);
|
|
m_lstPTModel.ItemAdd(file_name, 1);
|
|
int err = GetLastError();
|
|
if(err == 0)
|
|
m_lstPTModel.ItemAdd("The file is damaged");
|
|
else
|
|
m_lstPTModel.ItemAdd(StringFormat("error id: %d", GetLastError()), 2);
|
|
m_edPTModel.Text("Select file");
|
|
return false;
|
|
}
|
|
m_edPTModel.Text(file_name);
|
|
m_edPTModelLayers.Text((string)m_Model.LayersTotal());
|
|
if(!!m_arPTModelDescription)
|
|
delete m_arPTModelDescription;
|
|
m_arPTModelDescription = m_Model.GetLayersDiscriptions();
|
|
m_lstPTModel.ItemsClear();
|
|
int total = m_arPTModelDescription.Total();
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
CLayerDescription* temp = m_arPTModelDescription.At(i);
|
|
if(!temp)
|
|
return false;
|
|
//---
|
|
string items[];
|
|
int total_items = LayerDescriptionToString(temp, items);
|
|
if(total_items < 0)
|
|
{
|
|
printf("%s %d Error at layer %d: %d", __FUNCSIG__, __LINE__, i, GetLastError());
|
|
return false;
|
|
}
|
|
if(!m_lstPTModel.AddItem(StringFormat("____ Layer %d ____", i + 1), i + 1))
|
|
return false;
|
|
for(int it = 0; it < total_items; it++)
|
|
if(!m_lstPTModel.AddItem(items[it], i + 1))
|
|
return false;
|
|
}
|
|
m_spPTModelLayers.MaxValue(total);
|
|
m_spPTModelLayers.Value(total);
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
string CNetCreatorPanel::LayerTypeToString(int type)
|
|
{
|
|
string result = "Unknown";
|
|
switch(type)
|
|
{
|
|
case defNeuronBaseOCL:
|
|
result = "Dense";
|
|
break;
|
|
case defNeuronConvOCL:
|
|
result = "Conolution";
|
|
break;
|
|
case defNeuronProofOCL:
|
|
result = "Proof";
|
|
break;
|
|
case defNeuronAttentionOCL:
|
|
result = "Self Attention";
|
|
break;
|
|
case defNeuronMHAttentionOCL:
|
|
result = "Multi-Head Attention";
|
|
break;
|
|
case defNeuronMLMHAttentionOCL:
|
|
result = "Multi-Layer MH Attention";
|
|
break;
|
|
case defNeuronDropoutOCL:
|
|
result = "Dropout";
|
|
break;
|
|
case defNeuronBatchNormOCL:
|
|
result = "Batchnorm";
|
|
break;
|
|
case defNeuronVAEOCL:
|
|
result = "VAE";
|
|
break;
|
|
case defNeuronLSTMOCL:
|
|
result = "LSTM";
|
|
break;
|
|
case defNeuronSoftMaxOCL:
|
|
result = "SoftMax";
|
|
break;
|
|
case defNeuronFQF:
|
|
result = "FQF";
|
|
break;
|
|
default:
|
|
result = StringFormat("%s %#x", result, type);
|
|
break;
|
|
}
|
|
//---
|
|
return result;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
int CNetCreatorPanel::LayerDescriptionToString(const CLayerDescription *layer, string& result[])
|
|
{
|
|
if(!layer)
|
|
return -1;
|
|
//---
|
|
string temp;
|
|
ArrayFree(result);
|
|
switch(layer.type)
|
|
{
|
|
case defNeuronBaseOCL:
|
|
temp = StringFormat("Dense (outputs %d, \activation %s, \optimization %s)", layer.count, EnumToString(layer.activation), EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronConvOCL:
|
|
temp = StringFormat("Conolution (outputs %d, \window %d, step %d, window out %d, \activation %s, \optimization %s)", layer.count * layer.window_out, layer.window, layer.step, layer.window_out, EnumToString(layer.activation), EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronProofOCL:
|
|
temp = StringFormat("Proof (outputs %d, \window %d, step %d, \optimization %s)", layer.count, layer.window, layer.step, EnumToString(layer.activation), EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronAttentionOCL:
|
|
temp = StringFormat("Self Attention (outputs %d, \units %d, window %d, \optimization %d)", layer.count * layer.window, layer.count, layer.window, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronMHAttentionOCL:
|
|
temp = StringFormat("Multi-Head Attention (outputs %d, \units %d, window %d, heads %d, \optimization %s)", layer.count * layer.window, layer.count, layer.window, layer.step, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronMLMHAttentionOCL:
|
|
temp = StringFormat("Multi-Layer MH Attention (outputs %d, \units %d, window %d, key size %d, \heads %d, layers %d, \optimization %s)", layer.count * layer.window, layer.count, layer.window, layer.window_out, layer.step, layer.layers, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronDropoutOCL:
|
|
temp = StringFormat("Dropout (outputs %d, \probability %d, \optimization %s)", layer.count, layer.probability, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronBatchNormOCL:
|
|
temp = StringFormat("Batchnorm (outputs %d, \batch size %d, \optimization %s)", layer.count, layer.batch, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronVAEOCL:
|
|
temp = StringFormat("VAE (outputs %d)", layer.count);
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronLSTMOCL:
|
|
temp = StringFormat("LSTM (outputs %d, \optimization %s)", layer.count, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronSoftMaxOCL:
|
|
temp = StringFormat("SoftMax (outputs %d, heads %d)", layer.count, layer.step);
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
case defNeuronFQF:
|
|
temp = StringFormat("FQF (outputs %d, quantiles %d, \optimization %s))", layer.count, layer.window_out, EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
default:
|
|
temp = StringFormat("Unknown type %#x (outputs %d, \activation %s, \optimization %s)", layer.type, layer.count, EnumToString(layer.activation), EnumToString(layer.optimization));
|
|
if(StringSplit(temp, '\\', result) < 0)
|
|
return -1;
|
|
break;
|
|
}
|
|
//---
|
|
return ArraySize(result);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::ChangeNumberOfLayers(void)
|
|
{
|
|
int total = m_spPTModelLayers.Value();
|
|
m_lstPTModel.SelectByValue(total);
|
|
//---
|
|
m_lstNewModel.ItemsClear();
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
CLayerDescription* temp = m_arPTModelDescription.At(i);
|
|
if(!temp)
|
|
return false;
|
|
//---
|
|
string items[];
|
|
int total_items = LayerDescriptionToString(temp, items);
|
|
if(total_items < 0)
|
|
{
|
|
printf("%s %d Error at layer %d: %d", __FUNCSIG__, __LINE__, i, GetLastError());
|
|
return false;
|
|
}
|
|
if(!m_lstNewModel.AddItem(StringFormat("____ Layer %d ____", i + 1), i + 1))
|
|
return false;
|
|
for(int it = 0; it < total_items; it++)
|
|
if(!m_lstNewModel.AddItem(items[it], i + 1))
|
|
return false;
|
|
}
|
|
//---
|
|
int shift = total;
|
|
total = m_arAddLayers.Total();
|
|
for(int i = 0; i < total; i++)
|
|
{
|
|
CLayerDescription* temp = m_arAddLayers.At(i);
|
|
if(!temp)
|
|
return false;
|
|
//---
|
|
string items[];
|
|
int total_items = LayerDescriptionToString(temp, items);
|
|
if(total_items < 0)
|
|
{
|
|
printf("%s %d Error at layer %d: %d", __FUNCSIG__, __LINE__, i, GetLastError());
|
|
return false;
|
|
}
|
|
if(!m_lstNewModel.AddItem(StringFormat("____ Layer %d ____", shift + i + 1), shift + i + 1))
|
|
return false;
|
|
for(int it = 0; it < total_items; it++)
|
|
if(!m_lstNewModel.AddItem(items[it], shift + i + 1))
|
|
return false;
|
|
}
|
|
m_lstNewModel.SelectByValue(shift + total);
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
CLabel* CNetCreatorPanel::CreateLabel(const int id, const string text, const int x1, const int y1, const int x2, const int y2)
|
|
{
|
|
CLabel *tmp_label = new CLabel();
|
|
if(!tmp_label)
|
|
return NULL;
|
|
if(!tmp_label.Create(m_chart_id, StringFormat("%s%d", LABEL_NAME, id), m_subwin, x1, y1, x2, y2))
|
|
{
|
|
delete tmp_label;
|
|
return NULL;
|
|
}
|
|
if(!tmp_label.Text(text))
|
|
{
|
|
delete tmp_label;
|
|
return NULL;
|
|
}
|
|
if(!Add(tmp_label))
|
|
{
|
|
delete tmp_label;
|
|
return NULL;
|
|
}
|
|
//---
|
|
return tmp_label;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::CreateEdit(const int id, CEdit& object, const int x1, const int y1, const int x2, const int y2, bool read_only)
|
|
{
|
|
if(!object.Create(m_chart_id, StringFormat("%s%d", EDIT_NAME, id), m_subwin, x1, y1, x2, y2))
|
|
return false;
|
|
if(!object.TextAlign(ALIGN_RIGHT))
|
|
return false;
|
|
if(!EditReedOnly(object, read_only))
|
|
return false;
|
|
if(!Add(object))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::EditReedOnly(CEdit& object, const bool flag)
|
|
{
|
|
if(!object.ReadOnly(flag))
|
|
return false;
|
|
if(!object.ColorBackground(flag ? CONTROLS_DIALOG_COLOR_CLIENT_BG : CONTROLS_EDIT_COLOR_BG))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::CreateComboBoxType(const int x1, const int y1, const int x2, const int y2)
|
|
{
|
|
if(!m_cbNewNeuronType.Create(m_chart_id, "cbNewNeuronType", m_subwin, x1, y1, x2, y2))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronBaseOCL), defNeuronBaseOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronConvOCL), defNeuronConvOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronProofOCL), defNeuronProofOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronLSTMOCL), defNeuronLSTMOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronAttentionOCL), defNeuronAttentionOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronMHAttentionOCL), defNeuronMHAttentionOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronMLMHAttentionOCL), defNeuronMLMHAttentionOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronDropoutOCL), defNeuronDropoutOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronBatchNormOCL), defNeuronBatchNormOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronVAEOCL), defNeuronVAEOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronSoftMaxOCL), defNeuronSoftMaxOCL))
|
|
return false;
|
|
if(!m_cbNewNeuronType.ItemAdd(LayerTypeToString(defNeuronFQF), defNeuronFQF))
|
|
return false;
|
|
if(!Add(m_cbNewNeuronType))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::CreateComboBoxActivation(const int x1, const int y1, const int x2, const int y2)
|
|
{
|
|
if(!m_cbActivation.Create(m_chart_id, "cbNewNeuronActivation", m_subwin, x1, y1, x2, y2))
|
|
return false;
|
|
if(!ActivationListMain())
|
|
return false;
|
|
if(!Add(m_cbActivation))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::ActivationListMain(void)
|
|
{
|
|
if(!m_cbActivation.ItemsClear())
|
|
return false;
|
|
for(int i = -1; i < 3; i++)
|
|
if(!m_cbActivation.ItemAdd(EnumToString((ENUM_ACTIVATION)i), i + 2))
|
|
return false;
|
|
if(!m_cbActivation.SelectByValue((int)DEFAULT_ACTIVATION + 2))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::ActivationListEmpty(void)
|
|
{
|
|
if(!m_cbActivation.ItemsClear() || !m_cbActivation.ItemAdd(EnumToString((ENUM_ACTIVATION) - 1), 1))
|
|
return false;
|
|
if(!m_cbActivation.SelectByValue((int) 1))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::CreateComboBoxOptimization(const int x1, const int y1, const int x2, const int y2)
|
|
{
|
|
if(!m_cbOptimization.Create(m_chart_id, "cbNewNeuronOptimization", m_subwin, x1, y1, x2, y2))
|
|
return false;
|
|
for(int i = 0; i < 3; i++)
|
|
if(!m_cbOptimization.ItemAdd(EnumToString((ENUM_OPTIMIZATION)i), i + 2))
|
|
return false;
|
|
if(!m_cbOptimization.SelectByValue((int)DEFAULT_OPTIMIZATION + 2))
|
|
return false;
|
|
if(!Add(m_cbOptimization))
|
|
return false;
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnChangeListPTModel(void)
|
|
{
|
|
long value = m_lstPTModel.Value();
|
|
//---
|
|
return m_spPTModelLayers.Value((int)value);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnChangeListNewModel(void)
|
|
{
|
|
long value = m_lstNewModel.Value();
|
|
//---
|
|
return m_lstNewModel.SelectByValue(value);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnClickAddButton(void)
|
|
{
|
|
int type = (int)m_cbNewNeuronType.Value();
|
|
if(StringFind(LayerTypeToString(type), "Unknown", 0) >= 0)
|
|
{
|
|
Print("Wrong type of new layer");
|
|
return false;
|
|
}
|
|
//---
|
|
int count = (int)StringToInteger(m_edCount.Text());
|
|
if(count <= 0)
|
|
{
|
|
Print("Layer don't have neurons");
|
|
return false;
|
|
}
|
|
//---
|
|
CLayerDescription *desc = new CLayerDescription();
|
|
if(!desc)
|
|
{
|
|
Print("Error of create description object: %d", GetLastError());
|
|
return false;
|
|
}
|
|
desc.type = type;
|
|
desc.count = count;
|
|
desc.activation = (ENUM_ACTIVATION)(m_cbActivation.Value() - 2);
|
|
desc.optimization = (ENUM_OPTIMIZATION)(m_cbOptimization.Value() - 2);
|
|
desc.batch = (int)StringToInteger(m_edBatch.Text());
|
|
desc.layers = (int)StringToInteger(m_edLayers.Text());
|
|
string text = m_edProbability.Text();
|
|
StringReplace(text, ",", ".");
|
|
StringReplace(text, " ", "");
|
|
desc.probability = (float)StringToDouble(text);
|
|
desc.step = (int)StringToInteger(m_edStep.Text());
|
|
desc.window = (int)StringToInteger(m_edWindow.Text());
|
|
desc.window_out = (int)StringToInteger(m_edWindowOut.Text());
|
|
//---
|
|
if(!m_arAddLayers.Add(desc))
|
|
{
|
|
Print("Error of adding description: %d", GetLastError());
|
|
return false;
|
|
}
|
|
//---
|
|
return ChangeNumberOfLayers();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnClickDeleteButton(void)
|
|
{
|
|
int shift = m_spPTModelLayers.Value();
|
|
int position = (int)m_lstNewModel.Value() - 1;
|
|
//---
|
|
if(position < 0)
|
|
{
|
|
Print("Layer not select");
|
|
return false;
|
|
}
|
|
//---
|
|
position -= shift;
|
|
if(position < 0)
|
|
{
|
|
Print("You can delete only added layers");
|
|
return false;
|
|
}
|
|
//---
|
|
if(!m_arAddLayers.Delete(position))
|
|
{
|
|
PrintFormat("Error of remove layer: %d", GetLastError());
|
|
return false;
|
|
}
|
|
//---
|
|
return ChangeNumberOfLayers();
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnClickSaveButton(void)
|
|
{
|
|
string filenames[];
|
|
if(FileSelectDialog("Выберите файлы для сохранения", NULL,
|
|
"Neuron Net (*.nnw;*.inv;*.fwd)|*.nnw;*.inv;*.fwd|All files (*.*)|*.*",
|
|
FSD_WRITE_FILE | (b_UseCommonDirectory ? FSD_COMMON_FOLDER : NULL), filenames, "NewModel.nnw") <= 0)
|
|
{
|
|
Print("File not selected");
|
|
return false;
|
|
}
|
|
//---
|
|
string file_name = filenames[0];
|
|
if(StringLen(file_name) - StringLen(EXTENSION) > StringFind(file_name, "."))
|
|
file_name += EXTENSION;
|
|
CNetModify* new_model = new CNetModify();
|
|
if(!new_model)
|
|
return false;
|
|
int total = m_spPTModelLayers.Value();
|
|
if(total > 0 && !m_Model.TrainMode(false))
|
|
return false;
|
|
bool result = true;
|
|
for(int i = 0; i < total && result; i++)
|
|
{
|
|
if(!new_model.AddLayer(m_Model.GetLayer((uint)i)))
|
|
result = false;
|
|
}
|
|
//---
|
|
new_model.SetOpenCL(m_Model.GetOpenCL());
|
|
if(result && m_arAddLayers.Total() > 0)
|
|
if(!new_model.AddLayers(GetPointer(m_arAddLayers)))
|
|
result = false;
|
|
//---
|
|
if(result && !new_model.Save(file_name, 1.0e37f, 100, 0, 0, b_UseCommonDirectory))
|
|
result = false;
|
|
//---
|
|
if(!!new_model)
|
|
delete new_model;
|
|
LoadModel(m_edPTModel.Text());
|
|
//---
|
|
return result;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
void CNetCreatorPanel::ChartEvent(const int id, const long &lparam, const double &dparam, const string &sparam)
|
|
{
|
|
CAppDialog::ChartEvent(id, lparam, dparam, sparam);
|
|
if(id == CHARTEVENT_KEYDOWN && m_spPTModelLayers.IsVisible())
|
|
{
|
|
switch((int)lparam)
|
|
{
|
|
case KEY_UP:
|
|
EventChartCustom(CONTROLS_SELF_MESSAGE, ON_CLICK, m_spPTModelLayers.Id() + 2, 0.0, m_spPTModelLayers.Name() + "Inc");
|
|
break;
|
|
case KEY_DOWN:
|
|
EventChartCustom(CONTROLS_SELF_MESSAGE, ON_CLICK, m_spPTModelLayers.Id() + 3, 0.0, m_spPTModelLayers.Name() + "Dec");
|
|
break;
|
|
case KEY_DELETE:
|
|
EventChartCustom(CONTROLS_SELF_MESSAGE, ON_CLICK, m_btDeleteLayer.Id(), 0.0, m_btDeleteLayer.Name());
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnChangeNeuronType(void)
|
|
{
|
|
long type = m_cbNewNeuronType.Value();
|
|
switch((int)type)
|
|
{
|
|
case defNeuronBaseOCL:
|
|
if(!EditReedOnly(m_edCount, false) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!ActivationListMain())
|
|
return false;
|
|
break;
|
|
case defNeuronConvOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, false) ||
|
|
!EditReedOnly(m_edWindow, false) ||
|
|
!EditReedOnly(m_edWindowOut, false))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!m_lbStepHeads.Text("Step"))
|
|
return false;
|
|
if(!m_lbWindowOut.Text("Window Out"))
|
|
return false;
|
|
if(!ActivationListMain())
|
|
return false;
|
|
if(!SetCounts(defNeuronConvOCL))
|
|
return false;
|
|
break;
|
|
case defNeuronProofOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, false) ||
|
|
!EditReedOnly(m_edWindow, false) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!m_lbStepHeads.Text("Step"))
|
|
return false;
|
|
if(!SetCounts(defNeuronProofOCL))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronLSTMOCL:
|
|
if(!EditReedOnly(m_edCount, false) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronDropoutOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, false) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!SetCounts(defNeuronDropoutOCL))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronBatchNormOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, false) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!SetCounts(defNeuronBatchNormOCL))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronAttentionOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, false) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!SetCounts(defNeuronAttentionOCL))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronMHAttentionOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, false) ||
|
|
!EditReedOnly(m_edWindow, false) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!m_lbStepHeads.Text("Heads"))
|
|
return false;
|
|
if(!SetCounts(defNeuronMHAttentionOCL))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronMLMHAttentionOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, false) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, false) ||
|
|
!EditReedOnly(m_edWindow, false) ||
|
|
!EditReedOnly(m_edWindowOut, false))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!m_lbStepHeads.Text("Heads"))
|
|
return false;
|
|
if(!m_lbWindowOut.Text("Keys size"))
|
|
return false;
|
|
if(!SetCounts(defNeuronMLMHAttentionOCL))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
break;
|
|
case defNeuronVAEOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
if(!SetCounts(defNeuronVAEOCL))
|
|
return false;
|
|
break;
|
|
case defNeuronSoftMaxOCL:
|
|
if(!EditReedOnly(m_edCount, true) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, false) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, true))
|
|
return false;
|
|
if(!m_lbCount.Text("Neurons"))
|
|
return false;
|
|
if(!m_lbStepHeads.Text("Heads"))
|
|
return false;
|
|
if(!m_edStep.Text("1"))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
if(!SetCounts(defNeuronSoftMaxOCL))
|
|
return false;
|
|
break;
|
|
case defNeuronFQF:
|
|
if(!EditReedOnly(m_edCount, false) ||
|
|
!EditReedOnly(m_edBatch, true) ||
|
|
!EditReedOnly(m_edLayers, true) ||
|
|
!EditReedOnly(m_edProbability, true) ||
|
|
!EditReedOnly(m_edStep, true) ||
|
|
!EditReedOnly(m_edWindow, true) ||
|
|
!EditReedOnly(m_edWindowOut, false))
|
|
return false;
|
|
if(!m_lbWindowOut.Text("Quantiles"))
|
|
return false;
|
|
if(!m_edWindowOut.Text("32"))
|
|
return false;
|
|
if(!m_lbCount.Text("Actions"))
|
|
return false;
|
|
if(!m_edCount.Text("3"))
|
|
return false;
|
|
if(!ActivationListEmpty())
|
|
return false;
|
|
if(!SetCounts(defNeuronFQF))
|
|
return false;
|
|
break;
|
|
default:
|
|
return false;
|
|
break;
|
|
}
|
|
//---
|
|
return true;
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::SetCounts(const uint type)
|
|
{
|
|
const uint position = m_arAddLayers.Total();
|
|
CLayerDescription *prev;
|
|
if(position <= 0)
|
|
{
|
|
if(!m_arPTModelDescription || m_spPTModelLayers.Value() <= 0)
|
|
return false;
|
|
prev = m_arPTModelDescription.At(m_spPTModelLayers.Value() - 1);
|
|
}
|
|
//---
|
|
else
|
|
{
|
|
if(m_arAddLayers.Total() < (int)position)
|
|
return false;
|
|
prev = m_arAddLayers.At(position - 1);
|
|
}
|
|
if(!prev)
|
|
return false;
|
|
//---
|
|
uint outputs = prev.count;
|
|
switch(prev.type)
|
|
{
|
|
case defNeuronAttentionOCL:
|
|
case defNeuronMHAttentionOCL:
|
|
case defNeuronMLMHAttentionOCL:
|
|
outputs *= prev.window;
|
|
break;
|
|
case defNeuronConvOCL:
|
|
outputs *= prev.window_out;
|
|
break;
|
|
}
|
|
//---
|
|
if(outputs <= 0)
|
|
return false;
|
|
//---
|
|
uint counts = 0;
|
|
int window = (int)StringToInteger(m_edWindow.Text());
|
|
int step = (int)StringToInteger(m_edStep.Text());
|
|
switch(type)
|
|
{
|
|
case defNeuronConvOCL:
|
|
case defNeuronProofOCL:
|
|
if(step <= 0)
|
|
break;
|
|
counts = (outputs - window - 1 + 2 * step) / step;
|
|
break;
|
|
case defNeuronAttentionOCL:
|
|
case defNeuronMHAttentionOCL:
|
|
case defNeuronMLMHAttentionOCL:
|
|
if(window <= 0)
|
|
break;
|
|
counts = (outputs + window - 1) / window;
|
|
break;
|
|
case defNeuronVAEOCL:
|
|
counts = outputs / 2;
|
|
break;
|
|
case defNeuronSoftMaxOCL:
|
|
counts = outputs / step;
|
|
break;
|
|
case defNeuronFQF:
|
|
return true;
|
|
default:
|
|
counts = outputs;
|
|
break;
|
|
}
|
|
//---
|
|
return m_edCount.Text((string)counts);
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnChangeWindowStep(void)
|
|
{
|
|
if(!OnEndEdit(m_edWindow) || !OnEndEdit(m_edStep))
|
|
return false;
|
|
return SetCounts((uint)m_cbNewNeuronType.Value());
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnEndEdit(CEdit& object)
|
|
{
|
|
long value = StringToInteger(object.Text());
|
|
return object.Text((string)fmax(1, value));
|
|
}
|
|
//+------------------------------------------------------------------+
|
|
//| |
|
|
//+------------------------------------------------------------------+
|
|
bool CNetCreatorPanel::OnEndEditProbability(void)
|
|
{
|
|
double value = StringToDouble(m_edProbability.Text());
|
|
return m_edProbability.Text(DoubleToString(fmax(0, fmin(1, value)), 2));
|
|
}
|
|
//+------------------------------------------------------------------+
|