모델 실행

MQL5에서 ONNX 모델을 실행하려면 다음과 같은 3단계를 거치세요:

  1. 다음을 사용하여 *.onnx 파일에서 모델을 로드합니다.OnnxCreate 함수 또는 배열OnnxCreateFromBuffer.
  2. 다음을 사용하여 입력 및 출력 데이터 쉐이프 지정OnnxSetInputShapeOnnxSetOutputShape 함수.
  3. OnnxRun함수를 사용하여 모델을 실행합니다. 관련 입력 및 출력 매개변수에 전달합니다.
  4. 필요한 경우 다음을 사용하여 모델 작업을 종료할 수 있습니다.OnnxRelease 함수.

 

ONNX 모델을 생성할 때 https://github.com/microsoft/onnxruntime/blob/rel-1.14.0/docs/OperatorKernels.md에 설명된 현재 제한 사항 및 금지 사항을 고려해야 합니다.

이러한 제한 사항의 일부 예는 다음과 같습니다:

Operation

지원되는 데이터 유형

ReduceSum

tensor(double), tensor(float), tensor(int32), tensor(int64)

Mul

tensor(bfloat16), tensor(double), tensor(float), tensor(float16), tensor(int32), tensor(int64), tensor(uint32), tensor(uint64)

 

아래는 공개 프로젝트의 MQL5 코드 예제입니다.ONNX.Price.Prediction.

const long   ExtOutputShape[] = {1,1};    // 모델의 출력 쉐이프
const long   ExtInputShape [] = {1,10,4}; // 모델의 입력 쉐이프
#resource "Python/model.onnx" as uchar ExtModel[]// 자원으로서의 모델
/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                        |
/+------------------------------------------------------------------+
int OnStart(void)
  {
   matrix rates;
//--- 10개 바
   if(!rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,2,10))
      return(-1);
//--- OHLC 벡터 세트 입력
   matrix x_norm=rates.Transpose();
   vector m=x_norm.Mean(0);               
   vector s=x_norm.Std(0);
   matrix mm(10,4);
   matrix ms(10,4);
//--- 정규화 행렬을 채움
   for(int i=0i<10i++)
     {
      mm.Row(m,i);
      ms.Row(s,i);
     }
//--- 입력 데이터 정규화
   x_norm-=mm;
   x_norm/=ms;
//--- 모델 생성
   long handle=OnnxCreateFromBuffer(ExtModel,ONNX_DEBUG_LOGS);
//--- 입력 데이터의 쉐이프 지정
   if(!OnnxSetInputShape(handle,0,ExtInputShape))
     {
      Print("OnnxSetInputShape failed, error ",GetLastError());
      OnnxRelease(handle);
      return(-1);
     }
//--- 출력 데이터의 쉐이프 지정
   if(!OnnxSetOutputShape(handle,0,ExtOutputShape))
     {
      Print("OnnxSetOutputShape failed, error ",GetLastError());
      OnnxRelease(handle);
      return(-1);
     }
//--- 정규화된 입력 데이터를 부동 소수점 유형으로 변환
   matrixf x_normf;
   x_normf.Assign(x_norm);
//--- 여기에서 모델의 출력 데이터 예를 들어 가격 예측을 얻습니다.
   vectorf y_norm(1);
//--- 모델 실행
   if(!OnnxRun(handle,ONNX_DEBUG_LOGS | ONNX_NO_CONVERSION,x_normf,y_norm))
     {
      Print("OnnxRun failed, error ",GetLastError());
      OnnxRelease(handle);
      return(-1);
     }
//--- 모델의 출력 값을 로그에 출력
   Print(y_norm);
//--- 역변환을 수행하여 예상 가격을 얻습니다.
   double y_pred=y_norm[0]*s[3]+m[3];
   Print("price predicted:",y_pred);
//--- 작업 완료
   OnnxRelease(handle);
   return(0);
  }

스크립트 실행 예:

ONNXCreating and using per session threadpools since use_per_session_threads_ is true
ONNXDynamic block base set to 0
ONNXInitializing session.
ONNXAdding default CPU execution provider.
ONNXTotal shared scalar initializer count0
ONNXTotal fused reshape node count0
ONNXTotal shared scalar initializer count0
ONNXTotal fused reshape node count0
ONNXUse DeviceBasedPartition as default
ONNXSaving initialized tensors.
ONNXDone saving initialized tensors
ONNXSession successfully initialized.
[0.28188983]
predicted 1.0559258806393044

MetaTrader 5 터미널은 계산을 위한 최적의 executor를 선택했습니다 —ONNX Runtime Execution Provider. 이 예에서 모델은 CPU에서 실행되었습니다.

이전 10개 바의 값을 기반으로 괜찮은 레벨의 종가 예측의 백분율을 계산하도록 스크립트를 수정해 보겠습니다.

#resource "Python/model.onnx" as uchar ExtModel[]// 자원으로서의 모델
 
#define TESTS 10000  // 테스트 데이터세트의 수
/+------------------------------------------------------------------+
//| 프로그램 시작 함수 스크립트                                        |
/+------------------------------------------------------------------+
int OnStart()
  {
//--- 모델 생성
   long session_handle=OnnxCreateFromBuffer(ExtModel,ONNX_DEBUG_LOGS);
   if(session_handle==INVALID_HANDLE)
     {
      Print("Cannot create model. Error ",GetLastError());
      return(-1);
     }
 
//--- 입력 텐서 크기가 모델에 대해 정의되어 있지 않으므로 명시적으로 지정합니다.
//--- 첫 번째 인덱스는 배치 크기, 두 번째 인덱스는 시리즈 크기, 세 번째 인덱스는 시리즈 수(OHLC)
   const long input_shape[]={1,10,4};
   if(!OnnxSetInputShape(session_handle,0,input_shape))
     {
      Print("OnnxSetInputShape error ",GetLastError());
      return(-2);
     }
 
//--- 출력 텐서 크기가 모델에 개해 정의되어 있지 않으므로 명시적으로 지정합니다.
//--- 첫 번째 인덱스는 배치 크기이며 입력 텐서의 배치 크기와 일치해야 합니다.
//--- 두 번째 인덱스는 예상 가격들의 수입니다(여기서는 종가만 예측됨).
   const long output_shape[]={1,1};
   if(!OnnxSetOutputShape(session_handle,0,output_shape))
     {
      Print("OnnxSetOutputShape error ",GetLastError());
      return(-3);
     }
//--- 테스트 실행
   vector closes(TESTS);      // 검증 가격을 저장할 벡터
   vector predicts(TESTS);    // 구한 예측들을 저장할 벡터
   vector prev_closes(TESTS); // 이어지는 가격들을 저장할 벡터
 
   matrix rates;              // OHLC 시리즈를 얻기 위한 행렬
matrixsplitted[2];// 시리즈를 테스트와 검증으로 나누는 두 부분 행렬
   ulong  parts[]={10,1};     // 나누어진 부분 행렬�l 크기
 
//--- 이전 바부터 시작
   for(int i=1i<=TESTSi++)
     {
      //--- 11개의 바를 얻음
      rates.CopyRates("EURUSD",PERIOD_H1,COPY_RATES_OHLC,i,11);
//--- 행렬을 테스트와 검증으로 나눕니다.
      rates.Vsplit(parts,splitted);
//--- 유효성 검증 매트릭스에서 종가를 가져옵니다.
      closes[i-1]=splitted[1][3][0];
//--- 테스트된 시리즈의 마지막 종가
      prev_closes[i-1]=splitted[0][3][9];
 
//--- 10개의 바의 테스트 매트릭스를 테스팅에 제출
      predicts[i-1]=PricePredictionTest(session_handle,splitted[0]);
//--- 런타임 에러
      if(predicts[i-1]<=0)
        {
         OnnxRelease(session_handle);
         return(-4);
        }
     }
//--- 작업 완료
   OnnxRelease(session_handle);
//--- 가격 움직임이 올바르게 예측되었는지를 평가
   int    right_directions=0;
   vector delta_predicts=prev_closes-predicts;
   vector delta_actuals=prev_closes-closes;
 
   for(int i=0i<TESTSi++)
      if((delta_predicts[i]>0 && delta_actuals[i]>0) || (delta_predicts[i]<0 && delta_actuals[i]<0))
         right_directions++;
   PrintFormat("right direction predictions = %.2f%%",(right_directions*100.0)/double(TESTS));
//--- 
   return(0);
  }
/+------------------------------------------------------------------+
//| 데이터 준비하고 모델 실행                                          |
/+------------------------------------------------------------------+
double PricePredictionTest(const long session_handle,matrixrates)
  {
   static matrixf input_data(10,4); // 변환된 입력을 위한 행렬
   static vectorf output_data(1);   // 결과를 받을 벡터
   static matrix mm(10,4);          //수평 벡터의 행렬 Mean
   static matrix ms(10,4);          // 수평 벡터의 Std
 
//--- OHLC 수직 벡터 세트가 모델에 입력되어야 합니다.
   matrix x_norm=rates.Transpose();
//--- 가격 정규화
   vector m=x_norm.Mean(0);
   vector s=x_norm.Std(0);
   for(int i=0i<10i++)
     {
      mm.Row(m,i);
      ms.Row(s,i);
     }
   x_norm-=mm;
   x_norm/=ms;
 
//--- 모델 실행
   input_data.Assign(x_norm);
   if(!OnnxRun(session_handle,ONNX_DEBUG_LOGS,input_data,output_data))
     {
      Print("OnnxRun error ",GetLastError());
      return(0);
     }
//--- 출력 값에서 가격을 비정규화
   double y_pred=output_data[0]*s[3]+m[3];
 
   return(y_pred);
  }

스크립트 실행: 예측 정확도는 약 51%입니다.

ONNX: Creating and using per session threadpools since use_per_session_threads_ is true
ONNX: Dynamic block base set to 0
ONNX: Initializing session.
ONNX: Adding default CPU execution provider.
ONNX: Total shared scalar initializer count: 0
ONNX: Total fused reshape node count: 0
ONNX: Total shared scalar initializer count: 0
ONNX: Total fused reshape node count: 0
ONNX: Use DeviceBasedPartition as default
ONNX: Saving initialized tensors.
ONNX: Done saving initialized tensors
ONNX: Session successfully initialized.
올바른 방향 예측 = 51.34%