线性回归梯度下降性能差
Linear regression poor gradient descent performance
我已经在 C++ 中实现了一个简单的线性回归(目前为单变量)示例,以帮助我理解这些概念。我很确定关键算法是正确的,但我的表现很糟糕。
这是实际执行梯度下降的方法:
void LinearRegression::BatchGradientDescent(std::vector<std::pair<int,int>> & data,float& theta1,float& theta2)
{
float weight = (1.0f/static_cast<float>(data.size()));
float theta1Res = 0.0f;
float theta2Res = 0.0f;
for(auto p: data)
{
float cost = Hypothesis(p.first,theta1,theta2) - p.second;
theta1Res += cost;
theta2Res += cost*p.first;
}
theta1 = theta1 - (m_LearningRate*weight* theta1Res);
theta2 = theta2 - (m_LearningRate*weight* theta2Res);
}
其他关键功能如下:
float LinearRegression::Hypothesis(float x,float theta1,float theta2) const
{
return theta1 + x*theta2;
}
float LinearRegression::CostFunction(std::vector<std::pair<int,int>> & data,
float theta1,
float theta2) const
{
float error = 0.0f;
for(auto p: data)
{
float prediction = (Hypothesis(p.first,theta1,theta2) - p.second) ;
error += prediction*prediction;
}
error *= 1.0f/(data.size()*2.0f);
return error;
}
void LinearRegression::Regress(std::vector<std::pair<int,int>> & data)
{
for(unsigned int itr = 0; itr < MAX_ITERATIONS; ++itr)
{
BatchGradientDescent(data,m_Theta1,m_Theta2);
//Some visualisation code
}
}
现在的问题是,如果学习率大于 0.000001,成本函数的值 after 梯度下降比 before.也就是说,算法是反向工作的。该线很快形成一条穿过原点的直线,但随后需要 数百万次 次迭代才能真正达到相当合适的直线。
学习率为 0.01,经过六次迭代后的输出为:(差异为 costAfter-costBefore)
Cost before 102901.945312, cost after 517539430400.000000, difference 517539332096.000000
Cost before 517539430400.000000, cost after 3131945127824588800.000000, difference 3131944578068774912.000000
Cost before 3131945127824588800.000000, cost after 18953312418560698826620928.000000, difference 18953308959796185006080000.000000
Cost before 18953312418560698826620928.000000, cost after 114697949347691988409089177681920.000000, difference 114697930004878874575022382383104.000000
Cost before 114697949347691988409089177681920.000000, cost after inf, difference inf
Cost before inf, cost after inf, difference nan
在此示例中,thetas 设置为零,学习率设置为 0.000001,并且有 8,000,000 次迭代!可视化代码仅在每 100,000 次迭代后更新图形。
创建数据点的函数:
static void SetupRegressionData(std::vector<std::pair<int,int>> & data)
{
srand (time(NULL));
for(int x = 50; x < 750; x += 3)
{
data.push_back(std::pair<int,int>(x+(rand() % 100), 400 + (rand() % 100) ));
}
}
简而言之,如果我的学习率太高,梯度下降算法会有效地向后运行并趋于无穷大,如果它降低到实际收敛到最小值的点,则实际这样做所需的迭代次数高得无法接受。
我错过了 anything/made 核心算法中的错误吗?
看起来一切都按预期运行,但您在选择合理的学习率时遇到了问题。这不是一个完全微不足道的问题,并且有许多方法,从逐渐降低学习率的预定义时间表(参见例如 this paper) to adaptive methods such as AdaGrad 或 AdaDelta。
对于具有固定学习率的原始实现,您应该在将数据输入梯度下降算法之前将数据归一化为零均值和单位标准差,从而使您的生活更轻松。这样你就可以更容易地推断学习率。然后您可以相应地重新调整您的预测。
我已经在 C++ 中实现了一个简单的线性回归(目前为单变量)示例,以帮助我理解这些概念。我很确定关键算法是正确的,但我的表现很糟糕。
这是实际执行梯度下降的方法:
void LinearRegression::BatchGradientDescent(std::vector<std::pair<int,int>> & data,float& theta1,float& theta2)
{
float weight = (1.0f/static_cast<float>(data.size()));
float theta1Res = 0.0f;
float theta2Res = 0.0f;
for(auto p: data)
{
float cost = Hypothesis(p.first,theta1,theta2) - p.second;
theta1Res += cost;
theta2Res += cost*p.first;
}
theta1 = theta1 - (m_LearningRate*weight* theta1Res);
theta2 = theta2 - (m_LearningRate*weight* theta2Res);
}
其他关键功能如下:
float LinearRegression::Hypothesis(float x,float theta1,float theta2) const
{
return theta1 + x*theta2;
}
float LinearRegression::CostFunction(std::vector<std::pair<int,int>> & data,
float theta1,
float theta2) const
{
float error = 0.0f;
for(auto p: data)
{
float prediction = (Hypothesis(p.first,theta1,theta2) - p.second) ;
error += prediction*prediction;
}
error *= 1.0f/(data.size()*2.0f);
return error;
}
void LinearRegression::Regress(std::vector<std::pair<int,int>> & data)
{
for(unsigned int itr = 0; itr < MAX_ITERATIONS; ++itr)
{
BatchGradientDescent(data,m_Theta1,m_Theta2);
//Some visualisation code
}
}
现在的问题是,如果学习率大于 0.000001,成本函数的值 after 梯度下降比 before.也就是说,算法是反向工作的。该线很快形成一条穿过原点的直线,但随后需要 数百万次 次迭代才能真正达到相当合适的直线。
学习率为 0.01,经过六次迭代后的输出为:(差异为 costAfter-costBefore)
Cost before 102901.945312, cost after 517539430400.000000, difference 517539332096.000000
Cost before 517539430400.000000, cost after 3131945127824588800.000000, difference 3131944578068774912.000000
Cost before 3131945127824588800.000000, cost after 18953312418560698826620928.000000, difference 18953308959796185006080000.000000
Cost before 18953312418560698826620928.000000, cost after 114697949347691988409089177681920.000000, difference 114697930004878874575022382383104.000000
Cost before 114697949347691988409089177681920.000000, cost after inf, difference inf
Cost before inf, cost after inf, difference nan
在此示例中,thetas 设置为零,学习率设置为 0.000001,并且有 8,000,000 次迭代!可视化代码仅在每 100,000 次迭代后更新图形。
创建数据点的函数:
static void SetupRegressionData(std::vector<std::pair<int,int>> & data)
{
srand (time(NULL));
for(int x = 50; x < 750; x += 3)
{
data.push_back(std::pair<int,int>(x+(rand() % 100), 400 + (rand() % 100) ));
}
}
简而言之,如果我的学习率太高,梯度下降算法会有效地向后运行并趋于无穷大,如果它降低到实际收敛到最小值的点,则实际这样做所需的迭代次数高得无法接受。
我错过了 anything/made 核心算法中的错误吗?
看起来一切都按预期运行,但您在选择合理的学习率时遇到了问题。这不是一个完全微不足道的问题,并且有许多方法,从逐渐降低学习率的预定义时间表(参见例如 this paper) to adaptive methods such as AdaGrad 或 AdaDelta。
对于具有固定学习率的原始实现,您应该在将数据输入梯度下降算法之前将数据归一化为零均值和单位标准差,从而使您的生活更轻松。这样你就可以更容易地推断学习率。然后您可以相应地重新调整您的预测。