基于CVXPY的SVM实现问题:RBF与线性核持续报错
SVM(CVXPY实现)维度错误与核函数问题修正方案
核心问题分析
- 变量维度定义错误:原代码中
alpha = cp.Variable(n),但SVM对偶问题中alpha是每个样本对应的拉格朗日乘子,维度应为样本数m而非特征数n,混淆了原始问题与对偶问题的变量定义。 - 约束条件维度不匹配:原约束用
cp.sum()压缩维度,导致无法对应每个样本的约束要求,正确逻辑应为每个样本单独满足y_i*(决策函数) >= 1 - xi_i。 - 核函数未实际调用:仅定义了线性/RBF核函数,但
fit过程未使用,无法实现核SVM的非线性分类能力。 - 类方法缩进错误:
plot_decision_boundary未作为SVM类的方法缩进,导致调用失败。 - 预测逻辑错误:原
predict函数的决策边界计算不符合SVM理论,尤其无法适配核函数场景。
修正步骤与完整代码
1. 基于对偶问题实现通用核SVM
统一采用对偶形式实现,同时支持线性与RBF核:
import numpy as np import cvxpy as cp import matplotlib.pyplot as plt class SVM: def __init__(self, kernel='linear', C=1.0, gamma=0.1): self.kernel = kernel self.C = C self.gamma = gamma self.alpha = None self.b = None self.X_train = None self.y_train = None def _linear_kernel(self, X1, X2): # 计算线性核矩阵:(m1,n) @ (n,m2) -> (m1,m2) return np.dot(X1, X2.T) def _rbf_kernel(self, X1, X2): # 计算RBF核矩阵 m1, _ = X1.shape m2, _ = X2.shape kernel_matrix = np.zeros((m1, m2)) for i in range(m1): for j in range(m2): kernel_matrix[i,j] = np.exp(-self.gamma * np.sum((X1[i] - X2[j])**2)) return kernel_matrix def _get_kernel_matrix(self, X1, X2): if self.kernel == 'linear': return self._linear_kernel(X1, X2) elif self.kernel == 'rbf': return self._rbf_kernel(X1, X2) else: raise ValueError("仅支持'linear'或'rbf'核函数") def fit(self, X, y): m, n = X.shape self.X_train = X self.y_train = y # 对偶问题变量:alpha为每个样本的拉格朗日乘子,维度(m,) alpha = cp.Variable(m) # 松弛变量xi,每个样本对应一个,维度(m,) xi = cp.Variable(m) # 计算核矩阵 K = self._get_kernel_matrix(X, X) # 构建约束条件 constraints = [] constraints.append(alpha >= 0) constraints.append(alpha <= self.C) constraints.append(xi >= 0) # 每个样本的约束:y_i*(sum_j(alpha_j*y_j*K_ij) + b) >= 1 - xi_i y_col = y.reshape(-1, 1) constraints.append(cp.multiply(y_col, K @ cp.multiply(alpha, y_col) + self.b) >= 1 - xi) # 对偶问题目标函数(转为最小化形式) obj = cp.Minimize(0.5 * cp.quad_form(cp.multiply(alpha, y), K) - cp.sum(alpha) + self.C * cp.sum(xi)) # 求解优化问题 prob = cp.Problem(obj, constraints) prob.solve() # 保存结果 self.alpha = alpha.value # 从支持向量计算偏置b(选取0<alpha<C的样本) support_vec_idx = np.where((self.alpha > 1e-5) & (self.alpha < self.C - 1e-5))[0] if len(support_vec_idx) > 0: self.b = np.mean(y[support_vec_idx] - np.dot(K[support_vec_idx], cp.multiply(alpha.value, y).value)) else: self.b = 0.0 def predict(self, X): # 计算决策函数:sum_j(alpha_j*y_j*K(x, X_j)) + b K = self._get_kernel_matrix(X, self.X_train) decision = np.dot(K, cp.multiply(self.alpha, self.y_train).value) + self.b return np.sign(decision) def plot_decision_boundary(self, X, y): plt.scatter(X[:, 0], X[:, 1], c=y, cmap=plt.cm.Paired, edgecolors='k', marker='o') x_min, x_max = X[:, 0].min() - 1, X[:, 0].max() + 1 y_min, y_max = X[:, 1].min() - 1, X[:, 1].max() + 1 xx, yy = np.meshgrid(np.arange(x_min, x_max, 0.1), np.arange(y_min, y_max, 0.1)) Z = self.predict(np.c_[xx.ravel(), yy.ravel()]) Z = Z.reshape(xx.shape) plt.contourf(xx, yy, Z, alpha=0.3, levels=[-1, 0, 1], cmap=plt.cm.Paired) plt.xlabel('Feature 1') plt.ylabel('Feature 2') plt.title(f'Decision Boundary for {self.kernel.capitalize()} SVM') plt.show() # 训练数据 X_train = np.array([[1, 2], [2, 3], [3, 4], [4, 5]]) y_train = np.array([-1, -1, 1, 1]) # 线性核SVM测试 svm_linear = SVM(kernel='linear', C=1.0) svm_linear.fit(X_train, y_train) svm_linear.plot_decision_boundary(X_train, y_train) # RBF核SVM测试 svm_rbf = SVM(kernel='rbf', C=1.0, gamma=0.5) svm_rbf.fit(X_train, y_train) svm_rbf.plot_decision_boundary(X_train, y_train)
关键修正说明
- 变量维度修正:将
alpha维度改为样本数m,符合对偶SVM的理论定义。 - 核矩阵适配:实现线性与RBF核的矩阵计算逻辑,满足对偶问题的核函数需求。
- 约束条件修复:去掉错误的维度压缩操作,确保每个样本单独满足约束,解决维度不兼容问题。
- 偏置b计算:从支持向量中推导计算b,符合SVM的理论推导逻辑。
- 预测逻辑修正:基于核矩阵计算决策函数,同时支持线性与非线性分类场景。
- 类方法修复:将
plot_decision_boundary调整为类的内部方法,确保调用正常。
内容的提问来源于stack exchange,提问作者fallou0202
相关产品推荐
相关产品推荐

