numpy - 计算和可视化 SVM 决策边界的正交向量以在嵌入空间内导航
问题描述
我已经用 CNN 从时尚物品的图像中计算了 2048 维的嵌入。我现在的目标是在这个多维嵌入空间中进行交互导航。为了实现这一点,我首先应用 PCA 将空间的维度降低到 2D 或 3D,以便我可以将其可视化并首先验证我的方法是否适用于较低维度的空间。2D 和 3D 的结果分别如下所示:
我已经根据我的目标特征给它上色了season
。如您所见,嵌入并没有很好地被此功能聚类。我的假设是,在多维空间中存在一个超平面,可以很好地分离这两个值。
现在,为了在 2D/3D 空间中导航,我现在使用具有 2048 维嵌入 as 的 SVMX
和一个season
表明某件物品是在夏季穿着还是在冬季穿着的特征Y
。由于生成的决策边界以最大边距将两个类别分开,因此我应该能够通过绘制与决策边界正交的另一个向量来从一个季节导航到另一个季节。因此,在 2D 中,我正在计算并绘制决策边界并将其旋转 90° 以获得正交轴,如下所示:
如您所见,除了两个轴之外,我还设置了一个用户标记,该标记根据ipywidgets
FloatSlider 的值进行更新。此外,我将 ID、季节和最近嵌入的预览图像返回到用户的位置(atm 仅在 2D 中)。看起来,旋转轴与决策边界并不真正正交。我在这里做错了吗?
到目前为止,3D 图目前看起来像这样,无法导航,因为我还没有找到如何计算和可视化决策边界的法线向量。
我如何计算 3D 和/或 R^n 的正交向量?我的一个w
想法是利用 scikit-learn LinearSVC
(coef_
属性)返回的向量,因为这实际上是决策边界的垂直向量。这会是一种有效的方法吗?你对我如何解决这个问题有其他想法吗?
以下是相关的代码片段:
二维绘图
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
解决方案
推荐阅读
- mongodb - 在 Mongoose 中保存数组
- memory-management - 如何测量 Julia 中一小部分代码的内存使用情况?
- ios - 如何在自定义键盘扩展中检查连接的外部键盘?
- python - Django - 基于多对多关联限制选择
- azure-ad-b2c - 在联合 Azure AD B2C 注册自定义策略流上获取 UPN 的问题
- java - 为什么需要获取未检查的番石榴期货
- netlify - 如何在 netlify 上部署站点?
- angular - 读写JSON结构
- node.js - 在 IIS 上运行的 Node.js 应用程序在浏览器中无法访问物理文件
- c# - 自定义工具栏,菜单图标不显示 Xamarin Android