首页 > 解决方案 > 计算和可视化 SVM 决策边界的正交向量以在嵌入空间内导航

问题描述

我已经用 CNN 从时尚物品的图像中计算了 2048 维的嵌入。我现在的目标是在这个多维嵌入空间中进行交互导航。为了实现这一点,我首先应用 PCA 将空间的维度降低到 2D 或 3D,以便我可以将其可视化并首先验证我的方法是否适用于较低维度的空间。2D 和 3D 的结果分别如下所示:

嵌入空间 2d 嵌入空间 3d

我已经根据我的目标特征给它上色了season。如您所见,嵌入并没有很好地被此功能聚类。我的假设是,在多维空间中存在一个超平面,可以很好地分离这两个值。

现在,为了在 2D/3D 空间中导航,我现在使用具有 2048 维嵌入 as 的 SVMX和一个season表明某件物品是在夏季穿着还是在冬季穿着的特征Y。由于生成的决策边界以最大边距将两个类别分开,因此我应该能够通过绘制与决策边界正交的另一个向量来从一个季节导航到另一个季节。因此,在 2D 中,我正在计算并绘制决策边界并将其旋转 90° 以获得正交轴,如下所示:

嵌入空间 2d 与轴

如您所见,除了两个轴之外,我还设置了一个用户标记,该标记根据ipywidgetsFloatSlider 的值进行更新。此外,我将 ID、季节和最近嵌入的预览图像返回到用户的位置(atm 仅在 2D 中)。看起来,旋转轴与决策边界并不真正正交。我在这里做错了吗?

到目前为止,3D 图目前看起来像这样,无法导航,因为我还没有找到如何计算和可视化决策边界的法线向量。

嵌入空间 3d 与轴

我如何计算 3D 和/或 R^n 的正交向量?我的一个w想法是利用 scikit-learn LinearSVCcoef_属性)返回的向量,因为这实际上是决策边界的垂直向量。这会是一种有效的方法吗?你对我如何解决这个问题有其他想法吗?

以下是相关的代码片段:

二维绘图

from ipywidgets import AppLayout, FloatSlider
from matplotlib.offsetbox import (AnnotationBbox, OffsetImage, TextArea)

plt.ioff()

fig, ax = plt.subplots(figsize=(15,7))
fig.canvas.header_visible = False
fig.canvas.layout.min_height = '400px'

# Create Scatterplot of filtered dataset colored by season feature
sns.scatterplot(x="x", y="y",
                  hue="season",
                  data=df_filtered,
                  legend="full",
                  alpha=0.8)

# Computes the decision boundary of a trained classifier
db_xx, db_yy = calc_svm_decision_boundary(svm_clf, -35, 35)

# Rotate 90 degrees
neg_yy = np.negative(db_yy)

# Plot the axes
plt.plot(db_xx, db_yy, "k-", linewidth=2)
plt.plot(neg_yy, db_xx, "k-", linewidth=2)

# Choose a random starting position
rand_idx = random.choice(range(len(db_xx)))
x = neg_yy[rand_idx]
y = db_xx[rand_idx]
user_marker, user_positon = create_user_marker(x, y)

nearest_neighbour, nearest_neighbour_pos = get_nearest_neighbour(user_positon, df_filtered)
annotate_nearest_neighbour(nearest_neighbour, nearest_neighbour_pos, ax, df_filtered)

plt.title('Nearest Embedding: {} with season: {}'.format(nearest_neighbour, df_filtered.loc[df_filtered['id'] == nearest_neighbour].season.values[0]))

# Create Slider to interact with the plot
slider = FloatSlider(
    orientation="horizontal",
    description="Position:",
    value=user_positon[0],
    min=min(neg_yy),
    max=max(neg_yy)
)
slider.layout.margin = '0px 30% 0px 30%'
slider.layout.width = '40%'

slider.observe(update_user_position, names='value')

AppLayout(
    center=fig.canvas,
    footer=slider,
    pane_heights=[0, 6, 1]
)

3D 绘图

%matplotlib widget 

from matplotlib.colors import ListedColormap
from ipywidgets import AppLayout, FloatSlider

sns.set_style("white")

xx,yy = np.meshgrid(np.linspace(-150, 150, 200), np.linspace(-150, 150, 200))
z1 = (-svm_clf.intercept_[0] - svm_clf.coef_[0][0] * xx - svm_clf.coef_[0][1] * yy) / svm_clf.coef_[0][2]

theta = (svm_clf.coef_[0][0] * xx - svm_clf.coef_[0][1] * yy) / svm_clf.coef_[0][2]

fig = plt.figure(figsize=(12, 8))
ax = fig.add_subplot(111, projection='3d')

for s in df_filtered.season.unique():
    ax.scatter(df_filtered.x[df_filtered.season == s], df_filtered.y[df_filtered.season == s], df_filtered.z[df_filtered.season == s], label=s)
ax.legend()

ax.plot_surface(xx, yy, z1, color='seashell')
#ax.plot(theta, yy, color='green')

plt.title('3D Embedding Space')

# Create Slider to interact with the plot
slider = FloatSlider(
    orientation="horizontal",
    description="Position:",
    value=0,
    min=-150,
    max=150
)
slider.layout.margin = '0px 20% 0px 20%'
slider.layout.width = '40%'

slider.observe(update_user_position, names='value')

display(slider)

计算决策边界

def calc_svm_decision_boundary(svm_clf, xmin, xmax):
    """Compute a decision boundary and ret"""
    w = svm_clf.coef_[0]
    b = svm_clf.intercept_[0]
    xx = np.linspace(xmin, xmax, 200)
    yy = -w[0]/w[1] * xx - b/w[1]
    return xx, yy

标签: numpymatplotlibscikit-learnembeddingipywidgets

解决方案


推荐阅读