innerL 内循环代码 Args: i 具体的某一行 oS optStruct对象 Returns: 0 找不到最优的值 1 找到了最优的值,并且oS.Cache到缓存中
(i, oS)
| 213 | |
| 214 | |
| 215 | def innerL(i, oS): |
| 216 | """innerL |
| 217 | 内循环代码 |
| 218 | Args: |
| 219 | i 具体的某一行 |
| 220 | oS optStruct对象 |
| 221 | |
| 222 | Returns: |
| 223 | 0 找不到最优的值 |
| 224 | 1 找到了最优的值,并且oS.Cache到缓存中 |
| 225 | """ |
| 226 | |
| 227 | # 求 Ek误差:预测值-真实值的差 |
| 228 | Ei = calcEk(oS, i) |
| 229 | |
| 230 | # 约束条件 (KKT条件是解决最优化问题的时用到的一种方法。我们这里提到的最优化问题通常是指对于给定的某一函数,求其在指定作用域上的全局最小值) |
| 231 | # 0<=alphas[i]<=C,但由于0和C是边界值,我们无法进行优化,因为需要增加一个alphas和降低一个alphas。 |
| 232 | # 表示发生错误的概率:labelMat[i]*Ei 如果超出了 toler, 才需要优化。至于正负号,我们考虑绝对值就对了。 |
| 233 | ''' |
| 234 | # 检验训练样本(xi, yi)是否满足KKT条件 |
| 235 | yi*f(i) >= 1 and alpha = 0 (outside the boundary) |
| 236 | yi*f(i) == 1 and 0<alpha< C (on the boundary) |
| 237 | yi*f(i) <= 1 and alpha = C (between the boundary) |
| 238 | ''' |
| 239 | if ((oS.labelMat[i] * Ei < -oS.tol) and (oS.alphas[i] < oS.C)) or ((oS.labelMat[i] * Ei > oS.tol) and (oS.alphas[i] > 0)): |
| 240 | # 选择最大的误差对应的j进行优化。效果更明显 |
| 241 | j, Ej = selectJ(i, oS, Ei) |
| 242 | alphaIold = oS.alphas[i].copy() |
| 243 | alphaJold = oS.alphas[j].copy() |
| 244 | |
| 245 | # L和H用于将alphas[j]调整到0-C之间。如果L==H,就不做任何改变,直接return 0 |
| 246 | if (oS.labelMat[i] != oS.labelMat[j]): |
| 247 | L = max(0, oS.alphas[j] - oS.alphas[i]) |
| 248 | H = min(oS.C, oS.C + oS.alphas[j] - oS.alphas[i]) |
| 249 | else: |
| 250 | L = max(0, oS.alphas[j] + oS.alphas[i] - oS.C) |
| 251 | H = min(oS.C, oS.alphas[j] + oS.alphas[i]) |
| 252 | if L == H: |
| 253 | # print("L==H") |
| 254 | return 0 |
| 255 | |
| 256 | # eta是alphas[j]的最优修改量,如果eta==0,需要退出for循环的当前迭代过程 |
| 257 | # 参考《统计学习方法》李航-P125~P128<序列最小最优化算法> |
| 258 | eta = 2.0 * oS.K[i, j] - oS.K[i, i] - oS.K[j, j] # changed for kernel |
| 259 | if eta >= 0: |
| 260 | print("eta>=0") |
| 261 | return 0 |
| 262 | |
| 263 | # 计算出一个新的alphas[j]值 |
| 264 | oS.alphas[j] -= oS.labelMat[j] * (Ei - Ej) / eta |
| 265 | # 并使用辅助函数,以及L和H对其进行调整 |
| 266 | oS.alphas[j] = clipAlpha(oS.alphas[j], H, L) |
| 267 | # 更新误差缓存 |
| 268 | updateEk(oS, j) |
| 269 | |
| 270 | # 检查alpha[j]是否只是轻微的改变,如果是的话,就退出for循环。 |
| 271 | if (abs(oS.alphas[j] - alphaJold) < 0.00001): |
| 272 | # print("j not moving enough") |