【机器学习笔记】 SVM 里面的 SMO 算法

SVM 好难理解,之前看吴恩达的教程就一知半解的。
现在学习了《机器学习实战》,实现了一下 SMO 算法
简单版本的代码如下

def selectJRand(i, m):
    j = i

    while j == i:
        j = int(random.uniform(0, m))

    return j


def clipAlpha(aj, H, L):
    if aj > H:
        return H
    elif aj < L:
        return L
    else:
        return aj

def smoSimple(dataMatIn, classLabels, C, tolerateVal, maxIter):
    """
    简化版 SMO 算法
    :param dataMatIn: 数据集
    :param classLabels: 类别标签
    :param C: 常数
    :param tolerateVal: 容错率、容忍值
    :param maxIter: 最大循环次数
    """

    dataMatrix = mat(dataMatIn)
    labelMatrix = mat(classLabels).transpose()
    b = 0
    m, n = shape(dataMatrix)
    alphas = mat(zeros((m, 1)))
    iterNum = 0

    while iterNum < maxIter:

        alphaPairsChanged = False

        for i in range(m):

            # f(x_i) = w^T * x_i + b
            fXi = float(multiply(alphas, labelMatrix).T * dataMatrix * dataMatrix[i, :].T) + b
            Ei = fXi - float(labelMatrix[i])  # 误差

            # 判断 alpha 是否可以优化,先选取违背 KKT 条件的 alpha
            # 如果所有样本在容忍值范围内满足 KKT 条件则认为训练可以结束
            if ((labelMatrix[i] * Ei < -tolerateVal) and (alphas[i] < C)) or \
                    ((labelMatrix[i] * Ei > tolerateVal) and (alphas[i] > 0)):

                # 随机选择第二个 alpha
                j = selectJRand(i, m)
                fXj = float(multiply(alphas, labelMatrix).T * dataMatrix * dataMatrix[j, :].T) + b
                Ej = fXj - float(labelMatrix[j])

                oldAlphaI = alphas[i].copy()
                oldAlphaJ = alphas[j].copy()

                # 保证 alpha 在 0 与 C 之间
                if labelMatrix[i] != labelMatrix[j]:
                    L = max(0, alphas[j] - alphas[i])
                    H = min(C, C + alphas[j] - alphas[i])
                else:
                    L = max(0, alphas[j] + alphas[i] - C)
                    H = min(C, alphas[j] + alphas[i])

                if L == H:
                    print('L == H')
                    continue

                # 最优修改量
                eta = 2.0 * dataMatrix[i, :] * dataMatrix[j, :].T - dataMatrix[i, :] * dataMatrix[i, :].T \
                    - dataMatrix[j, :] * dataMatrix[j, :].T

                if eta >= 0:
                    print('eta >= 0')
                    continue

                alphas[j] -= labelMatrix[j] * (Ei - Ej) / eta
                alphas[j] = clipAlpha(alphas[j], H, L)

                if abs(alphas[j] - oldAlphaJ) < 0.00001:
                    print('j not moving enough')
                    continue

                # alpha[i] 的修改量与 alpha[j] 相同,方向相反
                alphas[i] += labelMatrix[j] * labelMatrix[i] * (oldAlphaJ - alphas[j])

                # 设置常数项
                b1 = b - Ei - labelMatrix[i] * (alphas[i] - oldAlphaI) * dataMatrix[i, :] * dataMatrix[i, :].T \
                    - labelMatrix[j] * (alphas[j] - oldAlphaJ) * dataMatrix[i, :] * dataMatrix[j, :].T
                b2 = b - Ej - labelMatrix[i] * (alphas[i] - oldAlphaI) * dataMatrix[i, :] * dataMatrix[j, :].T \
                     - labelMatrix[j] * (alphas[j] - oldAlphaJ) * dataMatrix[j, :] * dataMatrix[j, :].T

                if 0 < alphas[i] < C:
                    b = b1
                elif 0 < alphas[j] < C:
                    b = b2
                else:
                    b = (b1 + b2) / 2.0

                alphaPairsChanged = True
                print('iter:', iterNum, 'i:', i, 'pairs changed:', alphaPairsChanged)

        iterNum = 0 if alphaPairsChanged else iterNum + 1
        print('iteration number:', iterNum)

    return b, alphas

然后阅读了一下 Platt 的论文

有以下思考

  1. 常数 C 为何物
    该算法限制 α \alpha α 在 0 到 C 之间,折中经验风险和置信风险(这里没有使用松弛向量)

  2. 容忍值
    KKT 条件的精度设置,加快运行速度

  3. L 和 H 的作用
    尚未搞懂,有待进一步理解

  4. 修改量
    保证 y i α i + y j α j = c y_i\alpha_i + y_j\alpha_j = c yiαi+yjαj=c

你可能感兴趣的:(机器学习)