# OrthogonalMatchingPursuit.py # The code demonstrates the process of training OrthogonalMatchingPursuit model, exporting it to ONNX format (both float and double), and making predictions using the ONNX models. # Copyright 2023, MetaQuotes Ltd. # https://www.mql5.com # function to compare matching decimal places def compare_decimal_places(value1, value2): # convert both values to strings str_value1 = str(value1) str_value2 = str(value2) # find the positions of the decimal points in the strings dot_position1 = str_value1.find(".") dot_position2 = str_value2.find(".") # if one of the values doesn't have a decimal point, return 0 if dot_position1 == -1 or dot_position2 == -1: return 0 # calculate the number of decimal places decimal_places1 = len(str_value1) - dot_position1 - 1 decimal_places2 = len(str_value2) - dot_position2 - 1 # find the minimum of the two decimal places counts min_decimal_places = min(decimal_places1, decimal_places2) # initialize a count for matching decimal places matching_count = 0 # compare characters after the decimal point for i in range(1, min_decimal_places + 1): if str_value1[dot_position1 + i] == str_value2[dot_position2 + i]: matching_count += 1 else: break return matching_count # import necessary libraries import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import OrthogonalMatchingPursuit from sklearn.metrics import r2_score,mean_absolute_error,mean_squared_error import onnx import onnxruntime as ort from skl2onnx import convert_sklearn from skl2onnx.common.data_types import FloatTensorType from skl2onnx.common.data_types import DoubleTensorType from sys import argv # define the path for saving the model data_path = argv[0] last_index = data_path.rfind("\\") + 1 data_path = data_path[0:last_index] # generate synthetic data for regression X = np.arange(0,100,1).reshape(-1,1) y = 4*X + 10*np.sin(X*0.5) model_name = "OrthogonalMatchingPursuit" onnx_model_filename = data_path + "..\\models\\orthogonal_matching_pursuit" # create an OrthogonalMatchingPursuit model regression_model = OrthogonalMatchingPursuit() # fit the model to the data regression_model.fit(X, y) # predict values for the entire dataset y_pred = regression_model.predict(X) # evaluate the model's performance r2 = r2_score(y, y_pred) mse = mean_squared_error(y, y_pred) mae = mean_absolute_error(y, y_pred) print("\n"+model_name+" Original model (double)") print("R-squared (Coefficient of determination):", r2) print("Mean Absolute Error:", mae) print("Mean Squared Error:", mse) # convert to ONNX-model (float) # define the input data type as FloatTensorType initial_type_float = [('float_input', FloatTensorType([None, X.shape[1]]))] # export the model to ONNX format onnx_model_float = convert_sklearn(regression_model, initial_types=initial_type_float, target_opset=12) # save the model to a file onnx_filename=onnx_model_filename+"_float.onnx" onnx.save_model(onnx_model_float, onnx_filename) print("\n"+model_name+" ONNX model (float)") # print model path print(f"ONNX model saved to {onnx_filename}") # load the ONNX model and make predictions onnx_session = ort.InferenceSession(onnx_filename) input_name = onnx_session.get_inputs()[0].name output_name = onnx_session.get_outputs()[0].name # display information about input tensors in ONNX print("Information about input tensors in ONNX:") for i, input_tensor in enumerate(onnx_session.get_inputs()): print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}") # display information about output tensors in ONNX print("Information about output tensors in ONNX:") for i, output_tensor in enumerate(onnx_session.get_outputs()): print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}") # define the input data type as FloatTensorType initial_type_float = X.astype(np.float32) # predict values for the entire dataset using ONNX y_pred_onnx_float = onnx_session.run([output_name], {input_name: initial_type_float})[0] # calculate and display the errors for the original and ONNX models r2_onnx_float = r2_score(y, y_pred_onnx_float) mse_onnx_float = mean_squared_error(y, y_pred_onnx_float) mae_onnx_float = mean_absolute_error(y, y_pred_onnx_float) print("R-squared (Coefficient of determination)", r2_onnx_float) print("Mean Absolute Error:", mae_onnx_float) print("Mean Squared Error:", mse_onnx_float) print("R^2 matching decimal places: ",compare_decimal_places(r2, r2_onnx_float)) print("MAE matching decimal places: ",compare_decimal_places(mae, mae_onnx_float)) print("MSE matching decimal places: ",compare_decimal_places(mse, mse_onnx_float)) print("float ONNX model precision: ",compare_decimal_places(mae, mae_onnx_float)) # set the figure size plt.figure(figsize=(8, 5)) # plot the original data and the regression data plt.scatter(X, y, label='Original Data', marker='o') plt.scatter(X, y_pred, color='blue', label='Scikit-Learn '+model_name+' Output', marker='o') plt.scatter(X, y_pred_onnx_float, color='red', label='ONNX '+model_name+' Output', marker='o', linestyle='--') plt.xlabel('X') plt.ylabel('y') plt.legend() plt.title(model_name+' Comparison (with float ONNX)') #plt.show() plt.savefig(data_path + model_name+'_plot_float.png') # convert to ONNX-model (double) # define the input data type as DoubleTensorType initial_type_double = [('double_input', DoubleTensorType([None, X.shape[1]]))] # export the model to ONNX format onnx_model_double = convert_sklearn(regression_model, initial_types=initial_type_double, target_opset=12) # save the model to a file onnx_filename=onnx_model_filename+"_double.onnx" onnx.save_model(onnx_model_double, onnx_filename) print("\n"+model_name+" ONNX model (double)") # print model path print(f"ONNX model saved to {onnx_filename}") # load the ONNX model and make predictions onnx_session = ort.InferenceSession(onnx_filename) input_name = onnx_session.get_inputs()[0].name output_name = onnx_session.get_outputs()[0].name # display information about input tensors in ONNX print("Information about input tensors in ONNX:") for i, input_tensor in enumerate(onnx_session.get_inputs()): print(f"{i + 1}. Name: {input_tensor.name}, Data Type: {input_tensor.type}, Shape: {input_tensor.shape}") # display information about output tensors in ONNX print("Information about output tensors in ONNX:") for i, output_tensor in enumerate(onnx_session.get_outputs()): print(f"{i + 1}. Name: {output_tensor.name}, Data Type: {output_tensor.type}, Shape: {output_tensor.shape}") # define the input data type as DoubleTensorType initial_type_double = X.astype(np.float64) # predict values for the entire dataset using ONNX y_pred_onnx_double = onnx_session.run([output_name], {input_name: initial_type_double})[0] # calculate and display the errors for the original and ONNX models r2_onnx_double = r2_score(y, y_pred_onnx_double) mse_onnx_double = mean_squared_error(y, y_pred_onnx_double) mae_onnx_double = mean_absolute_error(y, y_pred_onnx_double) print("R-squared (Coefficient of determination)", r2_onnx_double) print("Mean Absolute Error:", mae_onnx_double) print("Mean Squared Error:", mse_onnx_double) print("R^2 matching decimal places: ",compare_decimal_places(r2, r2_onnx_double)) print("MAE matching decimal places: ",compare_decimal_places(mae, mae_onnx_double)) print("MSE matching decimal places: ",compare_decimal_places(mse, mse_onnx_double)) print("double ONNX model precision: ",compare_decimal_places(mae, mae_onnx_double)) # set the figure size plt.figure(figsize=(8, 5)) # plot the original data and the regression line plt.scatter(X, y, label='Original Data', marker='o') plt.scatter(X, y_pred, color='blue', label='Scikit-Learn '+model_name+' Output', marker='o') plt.scatter(X, y_pred_onnx_float, color='red', label='ONNX '+model_name+' Output', marker='o', linestyle='--') plt.xlabel('X') plt.ylabel('y') plt.legend() plt.title(model_name+' Comparison (with double ONNX)') #plt.show() plt.savefig(data_path + model_name+'_plot_double.png')