它只是为了娱乐 - 不是为了盈利,写了一个神经网络应用程序,它预测交换市场中处理比特币的实时数据的输出。 现在只是为了澄清,我不是在问我的算法是否正确,或者我的模型会让我变得富有 - 我正在研究NN和现场预测,所以请你这样阅读。
有两个来源(市场)可以从中获得真实数据。 我考虑作为输入的数据显然是当前的买入价,而网络正试图猜测下一个价格。但是我不在乎这里的时间安排,我想预测下一个可能的价格,所以我不考虑没有改变的买入价作为输入。我每100毫秒轮询市场并要求当前价格,如果价格已经改变然后我存储它,如果价格没有改变我忽略它。
我通过提供历史价格来培训网络,每个市场约2k - 网络配置如下:
INPUT:3个输入 隐藏:输入* 2 +1 输出:1
训练直到误差达到0.001因子。
现在回答问题。
1)我只存储更改的值,所以如果没有更改,我不会保存价格,因此 - 这种方法可以吗?或者即使它没有改变,我应该得到价格吗?这会影响预测吗?多少钱?我不想在15:00预测价值,我希望网络预测下一个可能的买入价 - 时间与此无关。
2)如果你看下面的图表,你可以清楚地看到网络有点落后' (特别是在第二个截图中)它并不像“高峰”那样。 - 什么甚至更好,甚至可以预测这些它总是预测相反的趋势 - 这是正常的还是对这种行为有一些解释?
源代码:
#include <chrono>
#include <thread>
#include <math.h>
#include <iostream>
#include "Core/CMemTracer.h"
#include "Core/CDatabase.h"
#include "Core/CCalcModule.h"
#include "Core/CCalcModuleNN.h"
#include "Core/CNeuralNetwork.h"
CNeuralNetwork _NeuralNetwork;
CDatabase _Database;
int main(int argc, const char * argv[])
{
std::string m_strDatabaseHost;
std::string m_strDatabaseName;
std::string m_strDatabaseUsername;
std::string m_strDatabasePassword;
std::string m_strExchange;
int m_iNumOfHistoryForTraining = 0;
int iNeuralNetworkInputs = 5;
int iNeuralNetworkHidden = 2 * iNeuralNetworkInputs + 1;
int iNeuralNetworkOutputs = 1;
int iMaximumTrainingEpoch = 10000000;
float fMinimum = 0;
float fMaximum = 1000;
float fMaximumNetworkError = 0.000720;
float fNeuralNetworkLearningRate = 0.5;
float fNeuralNetworkMomentum = 0.1;
std::vector<float> vHistory;
std::vector<float> vNormalisedData;
m_strDatabaseHost = "192.168.0.10";
m_strDatabaseName = "Trader";
m_strDatabasePassword = "password";
m_strDatabaseUsername = "root";
m_strExchange = "exBitMarket";
// How much data we fetch from the DB
m_iNumOfHistoryForTraining = 2000;
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Connecting to Database");
// Load up Database
if(_Database.Connect(m_strDatabaseUsername, m_strDatabasePassword, m_strDatabaseHost) == false)
{
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Error, cant connect to Database");
return false;
}
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Selecting Database");
// Select Database
if(_Database.SelectDatabase(m_strDatabaseName) == false)
{
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Error, cant select Database");
return false;
}
// Get x Data from Database
std::string strQuery = "SELECT * FROM (SELECT * FROM exData WHERE Exchange='"+m_strExchange+"' ORDER BY Epoch DESC LIMIT "+stringify(m_iNumOfHistoryForTraining)+")sub ORDER BY Epoch ASC";
// Query DB
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Querying database");
CDatabase::tDatabaseQueryResult _QuerySelect;
if(_Database.Query(strQuery, _QuerySelect) == false)
{
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Error, cannot query database");
//
return false;
}
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Got %i results", _QuerySelect.m_iRows);
// If Data available
if(_QuerySelect.m_iRows >= m_iNumOfHistoryForTraining )
{
// Push back Buy value to Historical Data Vector
for(int c = 0; c < _QuerySelect.m_vRows.size(); c++)
vHistory.push_back(atof(_QuerySelect.m_vRows[c].m_vstrColumns[3].data()));
vNormalisedData = vHistory;
}
else
{
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Error, not enough data returned (%i of %i required)", _QuerySelect.m_iRows,m_iNumOfHistoryForTraining);
//
return false;
}
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Normalising data for Neural network input");
// Normalise
// Find max, min values from the dataset for later normalization
std::vector<float>::iterator itMax = std::max_element(vHistory.begin(), vHistory.end(),[](const float& x, const float& y) { return x < y; });
std::vector<float>::iterator itMin = std::min_element(vHistory.begin(), vHistory.end(),[](const float& x, const float& y) { return x < y; });
// Store Min/Max
fMinimum = itMin[0];
fMaximum = itMax[0];
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Normalised data <%f, %f>", fMinimum, fMaximum);
// Important - Neural Network has to be setup correctly for activation function
// both this normalization and NN has to be setup the same way.
// Log sigmoid activation function (0,1)
// logistic sigmoid function [0, 1]
for(int a = 0; a < vHistory.size(); a++)
vNormalisedData[a] = (vHistory[a] - itMin[0]) / (itMax[0] - itMin[0]);
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, Initializing neural network with the setup %i/%i/%i Learning Rate: %f, Momentum: %f",
iNeuralNetworkInputs,
iNeuralNetworkHidden,
iNeuralNetworkOutputs,
fNeuralNetworkLearningRate,
fNeuralNetworkMomentum);
// Build the network with arguments passed
_NeuralNetwork.Initialize(iNeuralNetworkInputs, iNeuralNetworkHidden, iNeuralNetworkOutputs);
_NeuralNetwork.SetLearningRate(fNeuralNetworkLearningRate);
_NeuralNetwork.SetMomentum(false, fNeuralNetworkMomentum);
// Train
double dMaxError = 100.0;
double dLastError = 12345.0;
int iEpoch = 0;
int iLastDump = 0;
int iNumberOfDataForTraining = (vNormalisedData.size() / 2) - iNeuralNetworkInputs + iNeuralNetworkOutputs;
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, starting training with %i data out of %i", iNumberOfDataForTraining, vNormalisedData.size());
// Perform training on the training data
while ( (dMaxError > fMaximumNetworkError) && (iEpoch < iMaximumTrainingEpoch) )
{
//
dMaxError = 0;
// Now the input is normalized and ready for use perform the training
// Use 1/2 of the Normalised Data for training purposes, the rest will be used to
// Validate the network.
for(int a = 0; a < iNumberOfDataForTraining; a++)
{
// Set Inputs
for(int b = 0; b < iNeuralNetworkInputs; b++)
_NeuralNetwork.SetInput(b, vNormalisedData[a+b]);
// Set desired Output for the newest value
_NeuralNetwork.SetDesiredOutput(0, vNormalisedData[a + iNeuralNetworkInputs]);
// Feed data
_NeuralNetwork.FeedForward();
//
dMaxError += _NeuralNetwork.CalculateError();
// Backpropagate to learn
_NeuralNetwork.BackPropagate();
}
// Divide by the number of total array size to get global network error
dMaxError /= vNormalisedData.size();
// Dump some stats now
if(CUtils::GetEpoch() - iLastDump > 1)
{
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Training Error Factor: %f / %f Epoch: %i", dMaxError, fMaximumNetworkError, iEpoch);
iLastDump = CUtils::GetEpoch();
}
// Increment the epoch count
iEpoch++;
// Store last error for early-stop
dLastError = dMaxError;
}
//
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "Info, starting validation with %i data", vNormalisedData.size() - iNumberOfDataForTraining);
//
dMaxError = 0;
// Now check against 'Validation' Data
for(int a = iNumberOfDataForTraining; a < vNormalisedData.size(); a++)
{
// Set Inputs
for(int b = 0; b < iNeuralNetworkInputs; b++)
_NeuralNetwork.SetInput(b, vNormalisedData[a+b]);
// Set desired Output for the newest value
_NeuralNetwork.SetDesiredOutput(0, vNormalisedData[a + iNeuralNetworkInputs]);
// Feed data
_NeuralNetwork.FeedForward();
//
dMaxError += _NeuralNetwork.CalculateError();
}
// Divide by the number of total array size to get global network error
dMaxError /= vNormalisedData.size();
CLogger::Instance()->Write(XLOGEVENT_LOCATION, "%i Network Trained, Error Factor on Validation data = %f",
CUtils::GetEpoch(),
dMaxError);
// Save the network to an output filer
return 0;
}
不询问算法,只询问网络的输出,这是否正常发生,或看起来网络是否过度装配?
更新: 添加了反映培训数据培训和验证数据验证的更新代码。
答案 0 :(得分:1)
如果您的问题是过度拟合,可以遵循一些明确的指导原则。例如,请参阅here。
首先,您可以使用权重衰减,在其他回归方法中也称为 Tikhonov正则化或岭回归。在这里,您可以在误差函数上添加一个术语,该术语会对NN权重参数的平方和进行惩罚。这使得它们很小,只有当NN真正需要时才会学习。
通常具有类似效果的更简单的方法是提前停止。在这里,您在经过一定次数的迭代后或当您的误差函数低于一个不太小的常数时停止。
此外,您可以使用交叉验证之类的东西,并尽量避免泛化错误(或者也可能是训练和泛化错误的某种组合)。
答案 1 :(得分:1)
您正在进行机器学习和机器学习,您从不使用培训数据来评估您的模型。
要回答您的问题,您是否过度拟合,或者这是否正常:如果您没有将数据集拆分为基本的培训和测试,那么您将会过度拟合。
第一步:拆分您的数据,使其达到50/50,或者可能足以获得90%的培训数据和10%的测试数据。您可以使用培训数据执行您想要的操作,但您可以使用测试数据的唯一方法是查看模型的好坏。理想情况下,您只需执行一次。
进一步的步骤:这在某种程度上得到了简化。您可以使用交叉验证(即您使用不同的拆分)。或者您可以使用评估集来适应您的参数或玩弄事物,因此您只需触摸测试集一次。真的,你可以做的事情是没有限制的,但是基本的分裂会产生奇迹。
好的,我已经告诉你如何正确地做到这一点但是并没有告诉你你是否过度拟合。
您使用(在您的情况下为NN)学习模型的数据会受到污染。除非学习算法非常糟糕,否则它总是很合适。问题是,它是否适合来自同一分布的所有其他数据?为此你使用测试集。如果模型可以很好地适应,你就没有过度装配。如果它是一个完整的混乱,你已经过度拟合(或有其他错误)。