免费期货量化软件:多层感知器和反向传播算法
什么是 TensorFlow?
TensorFlow 是一个快速数值处理的开源函数库。
它是由 Google 依照 Apache 开源许可下创建、支持和发布。 该 API 是为 Python 语言设计的,尽管它也可以访问基本的 C++ API。
与设计用于深度学习的其它数字函数库(例如 Theano)不同,TensorFlow 意在研究和生产。 例如,Google 用到的基于机器学习的搜索引擎 RankBrain,和一个非常有趣的计算机视觉项目 DeepDream。
它可以在一个 CPU、GPU 或小型移动设备上的系统中运行,也可在由数百台计算机组成的大型分布式系统中运行。
什么是 Keras?
Keras 是一个功能强大,且易于使用的开源 Python 函数库,用于开发和评估深度学习模型。
它涉及强大的 Theano 和 TensorFlow 计算函数库。 它能够在短短几行代码中定义和训练神经网络模型。
教程
本教程分为 4 个章节:
-
在 MetaEditor 中安装和准备 Python 环境。
-
初期步骤和模型重建(感知器和 MLP)。
-
利用 Keras 和 TensorFlow 创建一个简单的模型。
-
如何集成 MQL5 和 Python。
1. 安装和准备 Python 环境。 首先,您应该从官方网站 www.python.org/downloads/ 下载 Python 为了使用 TensorFlow,您应该安装 3.3 和 3.8 之间的版本(我个人使用 3.7)。 下载并开始安装过程后,选中 “Add Python 3.7 to PATH” 选项。 这可确保某些事情马上就能工作,且无需以后额外配置。 然后可以直接从赫兹期货量化终端轻松运行 Python 脚本。
-
定义 Python 可执行路径(环境)
-
安装项目所需的依赖部件
打开 MetaEditor,并进入“工具\选项”。 在此处指定 Python 可执行文件所在的路径。 注意,安装后它应该有默认的 Python 路径。 如果没有,则需手工输入可执行文件的完整路径。 如此即可令您直接从 MetaTrader 5 终端运行脚本。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
我个人使用一个完全独立的函数库环境,称为虚拟环境。 这是一种获得“干净”安装并仅收集产品所需的库的方法。 有关 venv 包的更多信息,请阅读此处。 一旦完毕,您就能够直接从终端运行 Python 脚本。 对于这个项目,赫兹期货量化需要安装以下函数库。 如果您不确定如何安装这些库,请参阅相关的模块安装指南。
现在,赫兹期货量化已经安装并配置好了环境,下面我们来进行一个小测试,了解如何在终端中创建和运行一个小脚本。 为了直接从 MetaEditor 启动新脚本,请按照以下步骤操作: 新建 > Python 脚本
编辑
添加图片注释,不超过 140 字(可选)
为您的脚本指定名称。 MetaEditor 中的 MQL 向导会自动提示您需要导入一些函数库。 这很有趣,且对于我们的实验,我们要选择 Numpy 选项。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
现在,赫兹期货量化创建一个生成正弦图的简单脚本。 # Copyright 2021, Lethan Corp. # https://www.mql5.com/pt/users/14134597 import numpy as np import matplotlib.pyplot as plt data = np.linspace(-np.pi, np.pi, 201) plt.plot(data, np.sin(data)) plt.xlabel('Angle [rad]') plt.ylabel('sin(data)') plt.axis('tight') plt.show() 为了运行脚本,只需按 F7 进行编译,然后打开 MetaTrader 5 终端,并在图表上运行脚本。 如果有需要打印的内容,则结果将显示在智能系统选项卡中。 在我们的例子中,脚本会打开一个窗口,其中包含我们所创建的函数图。
编辑切换为居中
添加图片注释,不超过 140 字(可选)
2. 初期步骤和模型重建(感知器和 MLP)。 出于便利起见,赫兹期货量化将采用与 MQL5 示例中相同的数据集合。 下面是 predict() 函数,它针对给定权重集合的指标线预测其输出值。 此处的第一种情况也是偏差。 此外,还有一个激活函数。 # Transfer neuron activation def activation(activation): return 1.0 if activation >= 0.0 else 0.0 # Make a prediction with weights def predict(row, weights): z = weights[0] for i in range(len(row) - 1): z += weights[i + 1] * row[i] return activation(z) 如您所知,为了训练网络,我们需要实现梯度下降过程,这已在上一篇文章中有详细解释。 作为延续,我将展示一个训练函数 “train_weights()”。 # Estimate Perceptron weights using stochastic gradient descent def train_weights(train, l_rate, n_epoch): weights = [0.0 for i in range(len(train[0]))] #random.random() for epoch in range(n_epoch): sum_error = 0.0 for row in train: y = predict(row, weights) error = row[-1] - y sum_error += error**2 weights[0] = weights[0] + l_rate * error for i in range(len(row) - 1): weights[i + 1] = weights[i + 1] + l_rate * error * row[i] print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error)) return weights MLP 模型的应用: 本教程分为 5 个部分:
-
网络启动
-
前馈
-
反向传播
-
训练
-
预测
网络启动 赫兹期货量化从简单的事情开始,先创建一个新网络,并准备好进行学习。 每个神经元都有一组需要维护的权重,每个输入与一个权重连接,且有一个额外的偏置权重。 我们需要在训练期间保存神经元的其它属性,因此我们将利用字典来表示每个神经元,并按名称存储属性,例如对于权重就是 “weights”。 from random import seed from random import random # Initialize a network def initialize_network(n_inputs, n_hidden, n_outputs): network = list() hidden_layer = [{'weights':[random() for i in range(n_inputs + 1)]} for i in range(n_hidden)] network.append(hidden_layer) output_layer = [{'weights':[random() for i in range(n_hidden + 1)]} for i in range(n_outputs)] network.append(output_layer) return network seed(1) network = initialize_network(2, 1, 2) for layer in network: print(layer) 现在我们知道如何创建和启动网络,我们来看看如何用它来计算输出数据。
前馈
from math import exp # Calculate neuron activation for an input def activate(weights, inputs): activation = weights[-1] for i in range(len(weights)-1): activation += weights[i] * inputs[i] return activation # Transfer neuron activation def transfer(activation): return 1.0 / (1.0 + exp(-activation)) # Forward propagate input to a network output def forward_propagate(network, row): inputs = row for layer in network: new_inputs = [] for neuron in layer: activation = activate(neuron['weights'], inputs) neuron['output'] = transfer(activation) new_inputs.append(neuron['output']) inputs = new_inputs return inputs # test forward propagation network = [[{'weights': [0.13436424411240122, 0.8474337369372327, 0.763774618976614]}], [{'weights': [0.2550690257394217, 0.49543508709194095]}, {'weights': [0.4494910647887381, 0.651592972722763]}]] row = [1, 0, None] output = forward_propagate(network, row) print(output)
通过运行上面的脚本,赫兹期货量化得到以下结果:
[0.6629970129852887, 0.7253160725279748]
实际输出值现在看来很荒谬。 但我们很快就会看到神经元中的权重如何起更大作用。
反向传播
# Calculate the derivative of an neuron output def transfer_derivative(output): return output * (1.0 - output) # Backpropagate error and store in neurons def backward_propagate_error(network, expected): for i in reversed(range(len(network))): layer = network[i] errors = list() if i != len(network)-1: for j in range(len(layer)): error = 0.0 for neuron in network[i + 1]: error += (neuron['weights'][j] * neuron['delta']) errors.append(error) else: for j in range(len(layer)): neuron = layer[j] errors.append(expected[j] - neuron['output']) for j in range(len(layer)): neuron = layer[j] neuron['delta'] = errors[j] * transfer_derivative(neuron['output']) # test backpropagation of error network = [[{'output': 0.7105668883115941, 'weights': [0.13436424411240122, 0.8474337369372327, 0.763774618976614]}], [{'output': 0.6213859615555266, 'weights': [0.2550690257394217, 0.49543508709194095]}, {'output': 0.6573693455986976, 'weights': [0.4494910647887381, 0.651592972722763]}]] expected = [0, 1] backward_propagate_error(network, expected) for layer in network: print(layer)
当运行时,该示例在完成错误检查后打印网络。 如您所见,输出层和隐藏层的误差值已进行计算,并保存在神经元之中。
[{'output': 0.7105668883115941, 'weights': [0.13436424411240122, 0.8474337369372327, 0.763774618976614], 'delta': -0.0005348048046610517}] [{'output': 0.6213859615555266, 'weights': [0.2550690257394217, 0.49543508709194095], 'delta': -0.14619064683582808}, {'output': 0.6573693455986976, 'weights': [0.4494910647887381, 0.651592972722763], 'delta': 0.0771723774346327}]
网络训练
from math import exp from random import seed from random import random # Initialize a network def initialize_network(n_inputs, n_hidden, n_outputs): network = list() hidden_layer = [{'weights':[random() for i in range(n_inputs + 1)]} for i in range(n_hidden)] network.append(hidden_layer) output_layer = [{'weights':[random() for i in range(n_hidden + 1)]} for i in range(n_outputs)] network.append(output_layer) return network # Calculate neuron activation for an input def activate(weights, inputs): activation = weights[-1] for i in range(len(weights)-1): activation += weights[i] * inputs[i] return activation # Transfer neuron activation def transfer(activation): return 1.0 / (1.0 + exp(-activation)) # Forward propagate input to a network output def forward_propagate(network, row): inputs = row for layer in network: new_inputs = [] for neuron in layer: activation = activate(neuron['weights'], inputs) neuron['output'] = transfer(activation) new_inputs.append(neuron['output']) inputs = new_inputs return inputs # Calculate the derivative of an neuron output def transfer_derivative(output): return output * (1.0 - output) # Backpropagate error and store in neurons def backward_propagate_error(network, expected): for i in reversed(range(len(network))): layer = network[i] errors = list() if i != len(network)-1: for j in range(len(layer)): error = 0.0 for neuron in network[i + 1]: error += (neuron['weights'][j] * neuron['delta']) errors.append(error) else: for j in range(len(layer)): neuron = layer[j] errors.append(expected[j] - neuron['output']) for j in range(len(layer)): neuron = layer[j] neuron['delta'] = errors[j] * transfer_derivative(neuron['output']) # Update network weights with error def update_weights(network, row, l_rate): for i in range(len(network)): inputs = row[:-1] if i != 0: inputs = [neuron['output'] for neuron in network[i - 1]] for neuron in network[i]: for j in range(len(inputs)): neuron['weights'][j] += l_rate * neuron['delta'] * inputs[j] neuron['weights'][-1] += l_rate * neuron['delta'] # Train a network for a fixed number of epochs def train_network(network, train, l_rate, n_epoch, n_outputs): for epoch in range(n_epoch): sum_error = 0 for row in train: outputs = forward_propagate(network, row) expected = [0 for i in range(n_outputs)] expected[row[-1]] = 1 sum_error += sum([(expected[i]-outputs[i])**2 for i in range(len(expected))]) backward_propagate_error(network, expected) update_weights(network, row, l_rate) print('>epoch=%d, lrate=%.3f, error=%.3f' % (epoch, l_rate, sum_error)) # Test training backprop algorithm seed(1) dataset = [[2.7810836,2.550537003,0], [1.465489372,2.362125076,0], [3.396561688,4.400293529,0], [1.38807019,1.850220317,0], [3.06407232,3.005305973,0], [7.627531214,2.759262235,1], [5.332441248,2.088626775,1], [6.922596716,1.77106367,1], [8.675418651,-0.242068655,1], [7.673756466,3.508563011,1]] n_inputs = len(dataset[0]) - 1 n_outputs = len(set([row[-1] for row in dataset])) network = initialize_network(n_inputs, 2, n_outputs) train_network(network, dataset, 0.5, 20, n_outputs) for layer in network: print(layer)
训练后,打印网络,显示学习到的权重。 此外,网络仍然拥有可以忽略的输出和增量值。 如有必要,赫兹期货量化可以更新我们的训练函数,去删除这些数据。