ArrayFromFP8関数の働き・役割
ArrayFromFP8関数は、uchar型の配列を、float型またはdouble型の配列に変換するために使用されます。この変換では、指定されたFP8形式に基づいて、元の配列データを適切な浮動小数点数形式にコピーします。特に、ONNXモデルを扱う際に使用され、FP8(8ビット浮動小数点)形式で出力されたデータを効率的に扱えるようにします。
FP8形式は、浮動小数点数をコンパクトに表現するために使用され、ストレージと計算効率のバランスを保つのに適しています。FP8形式のデータをfloatまたはdouble配列に変換することで、より高精度なデータ操作が可能となります。
ArrayFromFP8関数の引数について
ArrayFromFP8関数は、float型またはdouble型の配列に、uchar型の配列からデータをコピーします。書式が2種類あり、それぞれfloat型の配列またはdouble型の配列を対象としています。この関数は、同じ名前で異なる引数リストを持つ「オーバーロード関数」です。
float型の書式
1つ目の書式では、float型の配列にデータをコピーします。引数の詳細は以下の通りです。
bool ArrayFromFP8(
const float& dst_array[], // 受信側のfloat型配列
const uchar& src_array[], // コピー元のuchar型配列
ENUM_FLOAT8_FORMAT fmt // FP8形式
);
- dst_array[]
受信側のfloat型配列です。この配列に、コピーされたデータが格納されます。 - src_array[]
コピー元のuchar型配列です。FP8形式で格納されたデータがこの配列に入っています。 - fmt
データの形式を指定します。ENUM_FLOAT8_FORMAT列挙型の値を指定し、データをどのFP8形式で解釈するかを決定します。
double型の書式
2つ目の書式では、double型の配列にデータをコピーします。引数の詳細は以下の通りです。
bool ArrayFromFP8(
const double& dst_array[], // 受信側のdouble型配列
const uchar& src_array[], // コピー元のuchar型配列
ENUM_FLOAT8_FORMAT fmt // FP8形式
);
- dst_array[]
受信側のdouble型配列です。この配列に、コピーされたデータが格納されます。 - src_array[]
コピー元のuchar型配列です。FP8形式で格納されたデータがこの配列に入っています。 - fmt
データの形式を指定します。ENUM_FLOAT8_FORMAT列挙型の値を指定し、データをどのFP8形式で解釈するかを決定します。
この関数は、float型とdouble型のいずれの配列に対しても使用でき、それぞれのデータ型に応じた書式が用意されています。
ArrayFromFP8関数の戻り値について
ArrayFromFP8関数は、変換が成功した場合にtrueを返し、失敗した場合にfalseを返します。戻り値は、配列データの変換が正常に行われたかどうかを確認するために使用されます。
たとえば、uchar型の配列からfloat型またはdouble型の配列に正しくデータをコピーできた場合にはtrueが返され、何らかの理由で変換に失敗した場合にはfalseが返されます。失敗した場合の理由としては、入力配列やフォーマットの指定が不正であることが考えられます。
戻り値を適切に確認し、変換が正しく行われたかどうかを判断することが重要です。
ArrayFromFP8関数を使った公式リファレンスのサンプルコード
//+------------------------------------------------------------------+
//| RunCastFloat8Float |
//| この関数は、指定されたFP8形式に基づいて、float型配列をFP8形式に変換し、 |
//| さらにONNXモデルを使用して、FP8形式のデータをfloat型に戻す処理を行います。 |
//+------------------------------------------------------------------+
bool RunCastFloat8ToFloat(long model_handle,const ENUM_FLOAT8_FORMAT fmt)
{
// 関数のテスト開始のメッセージをエキスパートログに出力します。
PrintFormat("TEST: %s(%s)",__FUNCTION__,EnumToString(fmt));
//--- 変換対象となるfloat型のテストデータを15個用意します。
float test_data[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//--- 変換後のFP8形式のデータを格納するuchar型の配列を用意します。
uchar data_float8[15] = {};
//--- float型データをFP8形式に変換し、結果をdata_float8に格納します。
if(!ArrayToFP8(data_float8,test_data,fmt))
{
// エラー発生時の処理。エラー内容とエラーコードをエキスパートログに出力し、
// モデルを解放して関数を終了します。
Print("error in ArrayToFP8. error code=",GetLastError());
OnnxRelease(model_handle);
return(false); // エラー発生のためfalseを返します。
}
//--- FP8形式のデータを入力として扱う配列を用意します。
U<uchar> input_float8_values[3*5];
//--- モデル実行後に取得するfloat型の出力値を格納する配列を用意します。
U<float> output_float_values[3*5];
//--- float型に戻す際の一時変数を用意します。
float test_data_float[];
//--- FP8形式からfloat型にデータを変換します。
if(!ArrayFromFP8(test_data_float,data_float8,fmt))
{
// エラー発生時の処理。エラー内容とエラーコードをエキスパートログに出力し、
// モデルを解放して関数を終了します。
Print("error in ArrayFromFP8. error code=",GetLastError());
OnnxRelease(model_handle);
return(false); // エラー発生のためfalseを返します。
}
//--- 変換されたデータをエキスパートログに出力します。
for(uint i=0; i<data_float8.Size(); i++)
{
// FP8形式の各データを16進数の文字列として出力し、値と比較します。
input_float8_values[i].value = data_float8[i];
PrintFormat("%d input value =%f Hex float8 = %s ushort value=%d",
i, test_data_float[i],
ArrayToHexString(input_float8_values[i].uc),
input_float8_values[i].value);
}
//--- ONNXモデルに渡す入力データとしてFP8データをエキスパートログに出力します。
Print("ONNX input array: ",ArrayToString(input_float8_values));
//--- ONNXモデルを実行し、FP8形式のデータをfloat型に変換します。
if(!OnnxRun(model_handle,ONNX_NO_CONVERSION, input_float8_values, output_float_values))
{
// エラー発生時の処理。エラー内容とエラーコードをエキスパートログに出力し、
// モデルを解放して関数を終了します。
PrintFormat("error in OnnxRun. error code=%d",GetLastError());
OnnxRelease(model_handle);
return(false); // エラー発生のためfalseを返します。
}
//--- ONNXモデルの出力データをエキスパートログに出力します。
Print("ONNX output array: ",ArrayToString(output_float_values));
//--- ONNXモデルの出力結果とFP8から変換した結果を比較し、誤差を計算します。
double sum_error = 0.0;
for(uint i=0; i<test_data.Size(); i++)
{
//--- 各データの差分(誤差)を計算し、合計誤差に加算します。
double delta = test_data_float[i] - (double)output_float_values[i].value;
sum_error += MathAbs(delta);
//--- 各出力値の詳細と差分をエキスパートログに出力します。
PrintFormat("%d output float %f = %s difference=%f",
i, output_float_values[i].value,
ArrayToHexString(output_float_values[i].uc), delta);
}
//--- 最終的な合計誤差をエキスパートログに出力します。
PrintFormat("%s(%s): sum_error=%f\n", __FUNCTION__, EnumToString(fmt), sum_error);
//--- 正常終了の場合はtrueを返します。
return(true);
}
コンパイルエラーに関する注意
上記のサンプルコードは、ONNXモデルを使用してfloat型配列をFP8形式に変換し、再度float型に戻して誤差を確認する内容となっています。
しかし、このコードには、MQL5標準のライブラリに存在しないデータ型や関数が使用されています。具体的には、U<uchar>
やU<float>
という未定義の型、およびArrayToString関数やArrayToHexString関数が含まれており、これらはそのままではコンパイルエラーを引き起こします。
U
の文法的役割は、何らかのユーザー定義型またはテンプレートとして使用されることが意図されていた可能性があります。例えば、FP8形式のデータをuchar型やfloat型で管理したり、それらを操作するためのカスタムクラスであることが考えられますが、このコード内では明示的な定義がないため、エラーが発生します。
また、ArrayToStringおよびArrayToHexString関数も標準ライブラリには含まれていないため、これらの関数は別途実装が必要です。
したがって、これらの未定義な型や関数を適切に修正、または定義する必要があることを念頭に置いてください。
サンプルコード解説1
//+------------------------------------------------------------------+
//| RunCastFloat8Float |
//| この関数は、指定されたFP8形式に基づいて、float型配列をFP8形式に変換し、 |
//| さらにONNXモデルを使用して、FP8形式のデータをfloat型に戻す処理を行います。 |
//+------------------------------------------------------------------+
bool RunCastFloat8ToFloat(long model_handle,const ENUM_FLOAT8_FORMAT fmt)
{
// 関数のテスト開始のメッセージをエキスパートログに出力します。
PrintFormat("TEST: %s(%s)",__FUNCTION__,EnumToString(fmt));
//--- 変換対象となるfloat型のテストデータを15個用意します。
float test_data[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
//--- 変換後のFP8形式のデータを格納するuchar型の配列を用意します。
uchar data_float8[15] = {};
このセクションでは、サンプルコードの冒頭部分を解説します。このコードは、float型のデータをFP8形式に変換し、ONNXモデルを使用してfloat型に再変換する処理の一部です。
関数の目的
RunCastFloat8ToFloat関数は、指定されたFP8形式に基づいて、float型の配列をFP8形式に変換し、さらにONNXモデルを使ってそのデータを再びfloat型に変換する処理を行います。この関数は、FP8形式でのデータ操作がONNXモデルで正しく行われているかを確認するために使用されます。
PrintFormat関数の役割
この部分では、PrintFormat関数を使用して、エキスパートログにテスト開始のメッセージを出力しています。__FUNCTION__は現在実行中の関数名を示し、EnumToString関数を使ってENUM_FLOAT8_FORMATの値を文字列に変換してログに表示します。これにより、関数がどのFP8形式を使って実行されているかを確認できます。
float型配列の準備
この部分では、テストデータとして15個のfloat型の数値が格納された配列test_dataが定義されています。この配列は、FP8形式に変換するための元データとして使用されます。このように、あらかじめデータが用意されていることで、後の処理で変換対象となるデータが明確になります。
uchar型配列の準備
ここでは、FP8形式に変換された結果を受け取るためのuchar型配列のdata_float8が定義されています。この配列のサイズは、変換前のfloat型配列と同じ15要素です。uchar型は、8ビット単位のデータを格納する型で、FP8形式に変換されたデータを効率よく保存するために使用されます。
この時点で、test_data配列のfloat型の数値が後にFP8形式に変換され、その結果がdata_float8に格納される準備が整っています。
サンプルコード解説2
//--- float型データをFP8形式に変換し、結果をdata_float8に格納します。
if(!ArrayToFP8(data_float8,test_data,fmt))
{
// エラー発生時の処理。エラー内容とエラーコードをエキスパートログに出力し、
// モデルを解放して関数を終了します。
Print("error in ArrayToFP8. error code=",GetLastError());
OnnxRelease(model_handle);
return(false); // エラー発生のためfalseを返します。
}
このセクションでは、float型データをFP8形式に変換する部分と、エラーハンドリングの処理について解説します。
FP8形式への変換処理
ここでは、float型の配列をFP8形式に変換しています。ArrayToFP8関数は、float型またはdouble型の配列をFP8形式のuchar型配列に変換し、その結果を指定された配列に格納します。この場合、test_dataに格納されたfloat型の数値をFP8形式に変換し、その結果をdata_float8配列に格納しています。
ArrayToFP8関数が正常に実行されると、変換されたFP8形式のデータがdata_float8配列に格納されます。
エラーハンドリング
ArrayToFP8関数がfalseを返した場合、何らかの理由で変換が失敗したことを示します。以下のように、変換が失敗した際には、GetLastError関数を使ってエラーコードを取得し、エキスパートログにエラー内容を出力します。
エラーが発生すると、まずログにエラー内容とエラーコードを出力し、次にOnnxRelease関数を使ってモデルを解放します。最後に、falseを返して関数を終了します。このように、エラーが発生した場合の処理を明確に定義することで、予期しない動作を防ぎ、プログラムの信頼性を高めることができます。
この部分では、float型データのFP8形式への変換が正しく行われなかった場合に備えて、エラーハンドリングが実装されています。
サンプルコード解説3
//--- FP8形式のデータを入力として扱う配列を用意します。
U<uchar> input_float8_values[3*5];
//--- モデル実行後に取得するfloat型の出力値を格納する配列を用意します。
U<float> output_float_values[3*5];
//--- float型に戻す際の一時変数を用意します。
float test_data_float[];
このセクションでは、FP8形式のデータを処理するための配列と、モデル実行後に取得するfloat型のデータを格納する配列の準備について解説します。
FP8形式のデータを入力として扱う配列の準備
まず、FP8形式のデータを保持するためにU型の配列input_float8_valuesが用意されています。
ここで注意が必要なのは、Uという型はMQL5標準には存在しないため、このコードはそのままではコンパイルエラーを引き起こします。Uが何らかのユーザー定義型やテンプレートとして使用されることを意図している可能性があります。したがって、この部分を使用するには、Uの定義を追加するか、別の型に変更する必要があります。
FP8形式のデータは8ビット(1バイト)で表されるため、uchar型(符号なしの1バイト整数型)が使われています。この配列は、FP8形式に変換されたデータをONNXモデルに入力として渡すために使用されます。
モデル実行後のfloat型データを格納する配列の準備
次に、ONNXモデルの実行結果として得られるfloat型のデータを格納するためにU型の配列output_float_valuesが用意されています。
UはMQL5標準の型ではないため、この部分もコンパイルエラーを引き起こします。適切な定義を追加するか、標準のデータ型を使うように修正する必要があります。
この配列には、ONNXモデルを実行した結果として得られるfloat型の数値データが格納されます。
一時変数の準備
最後に、float型データをFP8形式から再びfloat型に戻す際に、一時的に使用する変数としてtest_data_floatが宣言されています。この変数に変換されたfloat型のデータが格納され、その後の処理で使用されます。ONNXモデルの実行結果と比較するために、ここで一時的なfloat型配列を使用してデータを保持します。
サンプルコード解説4
//--- FP8形式からfloat型にデータを変換します。
if(!ArrayFromFP8(test_data_float,data_float8,fmt))
{
// エラー発生時の処理。エラー内容とエラーコードをエキスパートログに出力し、
// モデルを解放して関数を終了します。
Print("error in ArrayFromFP8. error code=",GetLastError());
OnnxRelease(model_handle);
return(false); // エラー発生のためfalseを返します。
}
このセクションでは、FP8形式のデータを再度float型に変換する部分と、その際のエラーハンドリングについて解説します。
FP8形式からfloat型への変換処理
この部分では、FP8形式に変換されたデータを再度float型に戻す処理が行われています。ArrayFromFP8関数を使用して、data_float8に格納されているFP8形式のデータをtest_data_floatというfloat型の配列に変換しています。
ArrayFromFP8関数は、FP8形式のデータを指定されたフォーマット(fmt)に従ってfloat型に変換し、結果をtest_data_floatに格納します。これにより、変換されたデータを再度float型として利用できるようになります。
エラーハンドリング
ArrayFromFP8関数がfalseを返した場合、FP8形式からfloat型への変換が失敗したことを示します。この場合、エラー処理が行われ、以下の手順でエラーハンドリングが実施されます。
- GetLastError関数を使用して、エラーコードを取得します。
- エキスパートログにエラー内容とエラーコードを出力します。これにより、何が原因でエラーが発生したのかを確認できるようにしています。
- OnnxRelease関数を呼び出して、モデルを解放します。これにより、リソースを適切に管理し、無駄なメモリ使用を防ぎます。
- 最終的にfalseを返し、関数を終了します。これにより、エラーが発生した場合は適切に処理が中断されます。
このエラーハンドリングによって、変換処理が正しく行われなかった際の対策が講じられており、プログラムが予期しない動作を引き起こすのを防ぐことができます。
サンプルコード解説5
//--- 変換されたデータをエキスパートログに出力します。
for(uint i=0; i<data_float8.Size(); i++)
{
// FP8形式の各データを16進数の文字列として出力し、値と比較します。
input_float8_values[i].value = data_float8[i];
PrintFormat("%d input value =%f Hex float8 = %s ushort value=%d",
i, test_data_float[i],
ArrayToHexString(input_float8_values[i].uc),
input_float8_values[i].value);
}
//--- ONNXモデルに渡す入力データとしてFP8データをエキスパートログに出力します。
Print("ONNX input array: ",ArrayToString(input_float8_values));
このセクションでは、FP8形式に変換されたデータをログに出力し、ONNXモデルに渡すデータの確認を行う部分について解説します。
変換されたデータのログ出力
FP8形式に変換されたデータを確認するために、エキスパートログに出力する処理が行われています。ここでは、forループを使って、FP8形式に変換された各データを16進数表記で出力しています。
まず、data_float8配列に格納されたFP8形式のデータが、input_float8_valuesにコピーされ、その後ログに出力されます。ArrayToHexString関数を使って、FP8形式のデータを16進数の文字列として出力していますが、この関数はMQL5標準の関数ではないため、別途実装する必要があります。
ログ出力される情報は以下の通りです:
- 変換後のfloat型のデータ
- そのデータのFP8形式での16進数表現
- ushort(符号なしの整数)としてのFP8値
これにより、変換されたFP8データと、その対応するfloat型データを比較し、どのように変換が行われたかを詳細に確認できます。
ONNXモデルに渡すデータのログ出力
FP8形式のデータをONNXモデルに渡す際、そのデータの内容をエキスパートログに出力して確認します。Print関数を使用して、input_float8_values配列全体をログに出力しています。
ArrayToString関数が使われていますが、この関数もMQL5標準の関数ではないため、実装する必要があります。この出力により、ONNXモデルに渡す前に、入力データが正しく準備されているかを確認することができます。
サンプルコード解説6
//--- ONNXモデルを実行し、FP8形式のデータをfloat型に変換します。
if(!OnnxRun(model_handle,ONNX_NO_CONVERSION, input_float8_values, output_float_values))
{
// エラー発生時の処理。エラー内容とエラーコードをエキスパートログに出力し、
// モデルを解放して関数を終了します。
PrintFormat("error in OnnxRun. error code=%d",GetLastError());
OnnxRelease(model_handle);
return(false); // エラー発生のためfalseを返します。
}
//--- ONNXモデルの出力データをエキスパートログに出力します。
Print("ONNX output array: ",ArrayToString(output_float_values));
このセクションでは、ONNXモデルを実行してFP8形式のデータをfloat型に変換する部分と、その結果をログに出力する処理について解説します。
ONNXモデルの実行
まず、OnnxRun関数を使用して、ONNXモデルを実行しています。この処理では、input_float8_valuesに格納されたFP8形式のデータをモデルに渡し、出力としてoutput_float_valuesにfloat型のデータを格納します。OnnxRun関数は、指定されたモデルハンドルを用いてモデルを実行し、FP8形式からfloat型への変換を行います。
ONNX_NO_CONVERSIONというフラグを使用して、入力データの形式変換を行わないよう指定しています。これにより、FP8形式のデータがそのままONNXモデルに渡され、float型に変換されることが想定されています。
エラーハンドリング
もしOnnxRun関数がfalseを返した場合、モデルの実行が失敗したことを意味します。この場合、以下のようにエラーハンドリングが行われます。
- GetLastError関数を使用してエラーコードを取得し、エキスパートログにエラー内容を出力します。
- OnnxRelease関数を呼び出して、モデルを解放します。これにより、モデル実行後にメモリやリソースが適切に管理されます。
- 最終的にfalseを返して関数を終了し、モデル実行が失敗したことを呼び出し元に伝えます。
ONNXモデルの出力データのログ出力
ONNXモデルの実行が成功すると、output_float_valuesにモデルの出力結果としてfloat型のデータが格納されます。これらのデータをエキスパートログに出力するために、Print関数を使用しています。
この部分では、ArrayToString関数を使用してoutput_float_values配列全体を文字列としてログに出力しますが、この関数はMQL5標準の関数ではないため、別途実装が必要です。ログ出力によって、ONNXモデルが正しく実行され、期待通りのfloat型データが出力されているかを確認できます。
このセクションでは、ONNXモデルの実行結果を確認し、正しくfloat型に変換されたデータをログに出力することで、モデルの実行が成功したかどうかをチェックしています。
サンプルコード解説7
double sum_error = 0.0;
for(uint i=0; i<test_data.Size(); i++)
{
//--- 各データの差分(誤差)を計算し、合計誤差に加算します。
double delta = test_data_float[i] - (double)output_float_values[i].value;
sum_error += MathAbs(delta);
//--- 各出力値の詳細と差分をエキスパートログに出力します。
PrintFormat("%d output float %f = %s difference=%f",
i, output_float_values[i].value,
ArrayToHexString(output_float_values[i].uc), delta);
}
このセクションでは、ONNXモデルの実行結果で得られたfloat型のデータと、元のデータ(test_data_float)の差分(誤差)を計算し、その結果をエキスパートログに出力する部分について解説します。
誤差の計算
まず、sum_errorという変数を使って、全体の誤差の合計を管理しています。この変数は初期値として0.0に設定され、各データごとの誤差が加算されます。
forループを使って、test_data_float配列とoutput_float_values配列の各要素を比較しています。各データの差分、すなわち誤差は、output_float_valuesの値からtest_data_floatの値を引くことで計算され、その結果がdeltaという変数に格納されます。
誤差の絶対値をMathAbs関数を使って計算し、それをsum_errorに加算することで、全体の誤差の合計を求めています。このように、各データ間の誤差を積み上げることで、モデルがどれだけ正確にデータを再現したかを把握します。
各データの出力と差分のログ出力
各データの差分(誤差)が計算された後、PrintFormat関数を使って詳細をエキスパートログに出力しています。ログには、以下の情報が出力されます:
- 現在処理しているデータのインデックス
- output_float_values配列に格納されたfloat型データの値
- そのデータのFP8形式における16進数表現
- test_data_floatとoutput_float_valuesの差分(誤差)
ここで、ArrayToHexString関数を使ってoutput_float_valuesのFP8形式を16進数表記で出力していますが、この関数もMQL5標準には含まれていないため、別途実装が必要です。
この処理により、各データごとの誤差を詳細に確認でき、ONNXモデルがどの程度正確にデータを処理しているかを把握することが可能になります。
サンプルコード解説8
//--- 最終的な合計誤差をエキスパートログに出力します。
PrintFormat("%s(%s): sum_error=%f\n", __FUNCTION__, EnumToString(fmt), sum_error);
//--- 正常終了の場合はtrueを返します。
return(true);
}
このセクションでは、ONNXモデルの実行結果で計算された合計誤差をログに出力し、関数が正常に終了する処理について解説します。
合計誤差のログ出力
誤差の合計値(sum_error)は、各データ間の誤差を累積した結果です。この合計誤差をエキスパートログに出力することで、モデル全体の精度を確認します。
PrintFormat関数を使用して、関数名、FP8のフォーマット(fmt)、および合計誤差(sum_error)をログに出力しています。これにより、どのフォーマットで実行されたか、そして全体の誤差がどの程度であったかを確認できます。特に、複数のフォーマットで処理を試す場合、このログが重要になります。
EnumToString関数は、enum列挙型を文字列に変換するために使用されます。fmtというENUM_FLOAT8_FORMAT列挙型の値を文字列に変換し、どのFP8形式で処理が行われたかをログに記録します。
正常終了時の処理
最後に、関数が正常に終了したことを示すためにtrueを返しています。このreturn文により、呼び出し元の処理が関数の結果に基づいて次の処理を行うことが可能になります。
この部分では、エラーが発生しなかった場合の最終的な処理が完了し、モデルの実行結果が正しく取得されたことを確認するための終着点となっています。ログ出力によって合計誤差が記録され、呼び出し元へ成功の結果を返す重要な部分です。