基本上,我想使用逻辑回归来检测图像中的故障。我希望能得到一些关于我的方法的反馈,具体如下:
用于训练的步骤:
- 从图像中选取标记为“坏”和“好的”小区域
- 将这些区域转换为灰度,然后将其分解为5*5像素的片段
- 计算每个片段的像素强度直方图
- 将直方图和标签一起传递给逻辑回归类进行训练
- 将整个图像分解为5*5的片段,并预测每个片段是“好的”还是“坏的”。
使用sigmoid函数的线性回归方程为:
1/ (1 - e^(xθ))
其中x是输入值,theta(θ)是权重。我使用梯度下降来训练网络。我的代码如下:
void LogisticRegression::Train(float **trainingSet,float *labels, int m){ float tempThetaValues[m_NumberOfWeights]; for (int iteration = 0; iteration < 10000; ++iteration) { // 重置theta的临时值。 memset(tempThetaValues,0,m_NumberOfWeights*sizeof(float)); float error = 0.0f; // 对于训练集中的每个示例 for (int trainingExample = 0; trainingExample < m; ++trainingExample) { float * x = trainingSet[trainingExample]; float y = labels[trainingExample]; // 成本函数的偏导数。 float h = Hypothesis(x) - y; for (int i =0; i < m_NumberOfWeights; ++i) { tempThetaValues[i] += h*x[i]; } float cost = h-y; //实际的J(theta), Cost(x,y), 一直返回NaN, 暂时使用MSE error += cost*cost; } // 使用批量梯度下降更新权重。 for (int theta = 0; theta < m_NumberOfWeights; ++theta) { m_pWeights[theta] = m_pWeights[theta] - 0.1f*tempThetaValues[theta]; } printf("Cost on iteration[%d] = %f\n",iteration,error); }}
其中sigmoid和假设函数的计算如下:
float LogisticRegression::Sigmoid(float z) const{ return 1.0f/(1.0f+exp(-z));}float LogisticRegression::Hypothesis(float *x) const{ float z = 0.0f; for (int index = 0; index < m_NumberOfWeights; ++index) { z += m_pWeights[index]*x[index]; } return Sigmoid(z);}
最终的预测结果如下:
int LogisticRegression::Predict(float *x){ return Hypothesis(x) > 0.5f;}
由于我们使用的是强度直方图,输入和权重数组都是255个元素。我希望将其用于类似于带有瘀伤的苹果图片,并用它来识别瘀伤部分。整个瘀伤和苹果训练集的(归一化)直方图看起来像这样:
我并不完全相信仅使用强度就能得到我想要的结果,但即使如此,使用它在一个明显可分的数据集上也行不通。为了测试,我传递了一个完全白色的和一个完全黑色的标记图像。然后我运行了下面的小图像:
即使在这个图像上,它也无法识别出任何被标记为黑色的片段。
使用MSE,我看到成本正在向下收敛到一个点并保持不变,对于黑白测试,它从大约250的成本开始,最后稳定在100。苹果块从大约4000开始,最后稳定在1600。
我无法判断问题出在哪里。
是方法正确但实现有问题吗?逻辑回归是否是用于此任务的错误算法?梯度下降是否不够健壮?
回答:
我忘了回答这个问题… 基本上问题出在我的直方图上,生成时没有使用memset清零。至于整体问题,即使用灰度图像的逻辑回归是否是一个好的解决方案,答案是否定的。灰度图像提供的信息不足以进行良好的分类。使用所有颜色通道会稍微好一些,但我认为我试图解决的问题(苹果上的瘀伤)的复杂性对于单纯的逻辑回归来说有点过高。你可以在我的博客这里看到结果。