You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用TSNE可视化VGG16模型输出?14分类模型可视化异常求助

解决VGG16特征TSNE可视化聚类混乱的问题

看起来你遇到的核心问题是标签处理逻辑错误,导致TSNE图的颜色映射完全偏离真实类别,这才出现每个簇都混杂所有颜色的情况。我们一步步来排查修复:

1. 先修正标签的收集逻辑

你的代码里,targets是把每个batch的标签数组直接append成列表,然后用target_ids = range(len(targets))——这相当于用batch的索引当标签,而不是每个样本的真实类别!比如你有10个batch,标签就变成0-9,但你实际有14个类别,每个样本的真实标签根本没被正确用上。

修正方法:把每个batch的标签数组展平后合并成一个一维数组,而不是存成列表:

# 初始化targets为numpy数组,指定类型避免后续类型错误
import numpy as np
targets = np.empty((0,), dtype=np.int64) 

with torch.no_grad():
    for step, (t_image, target, classess, image_path) in enumerate(test_loader):
        t_image = t_image.cuda()
        # 收集真实标签:合并到全局targets数组
        batch_targets = target.data.cpu().numpy()
        targets = np.append(targets, batch_targets, axis=0)
        
        # 提取特征
        features = model(t_image)
        features_np = features.data.cpu().numpy()
        logits_list = np.append(logits_list, features_np, axis=0)

绘制散点图时,直接用真实的targets数组作为颜色映射依据,替换错误的target_ids:

plt.figure(figsize=(10,8))
scatter = plt.scatter(tsne_results[:,0], tsne_results[:,1], c=targets, cmap=plt.cm.get_cmap("jet", 14), alpha=0.7)
plt.colorbar(scatter, ticks=range(14), label='Class')
# 手动创建多类别图例(scatter默认图例不友好)
from matplotlib.lines import Line2D
handles = [Line2D([0], [0], marker='o', color='w', markerfacecolor=plt.cm.jet(i/13), markersize=10, label=f'Class {i}') for i in range(14)]
plt.legend(handles=handles, bbox_to_anchor=(1.05, 1), loc='upper left')
plt.show()

2. 确认特征提取的正确性

虽然你替换了classifier的第6层为Identity,但可以打印模型结构确认是否替换正确:

print(model.classifier)

正常输出应该显示最后一层是Identity(),且你打印的logits.shape应该是(batch_size, 4096),这说明特征提取是对的。另外,model.eval()已经关闭了Dropout和BatchNorm的训练模式,这部分没问题,但可以再强制确认:

model.eval()
for m in model.modules():
    if isinstance(m, nn.Dropout):
        m.eval()

3. TSNE参数微调(可选)

对于1000个样本,你当前的perplexity=10是合理范围,但如果聚类效果仍不理想,可以尝试调整:

  • 把perplexity调到20-30(perplexity通常取样本数的1/50到1/10)
  • 增加n_iter到2000或3000,让TSNE迭代更充分
  • 调整learning_rate(默认200,可尝试100-500)

示例:

tsne = TSNE(n_components=2, verbose=1, perplexity=25, n_iter=3000, learning_rate=200)

修正后的完整代码片段

import numpy as np
import torch
import torch.nn as nn
from sklearn.manifold import TSNE
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D

# 加载模型
epoch = 800
PATH = 'vgg16_epoch{}.pth'.format(epoch)
checkpoint = torch.load(PATH)
model.load_state_dict(checkpoint['model_state_dict'])
optimizer.load_state_dict(checkpoint['optimizer_state_dict'])
epoch = checkpoint['epoch']

class Identity(nn.Module):
    def __init__(self):
        super(Identity, self).__init__()
    def forward(self, x):
        return x

# 替换classifier最后一层为Identity
model.classifier._modules['6'] = Identity()
model.eval()

# 初始化特征和标签容器
logits_list = np.empty((0, 4096))
targets = np.empty((0,), dtype=np.int64)

with torch.no_grad():
    for step, (t_image, target, classess, image_path) in enumerate(test_loader):
        t_image = t_image.cuda()
        # 收集真实标签
        batch_targets = target.data.cpu().numpy()
        targets = np.append(targets, batch_targets, axis=0)
        # 提取特征
        features = model(t_image)
        features_np = features.data.cpu().numpy()
        logits_list = np.append(logits_list, features_np, axis=0)
        print(f"Batch {step}: 当前特征形状 {features_np.shape}, 累计特征形状 {logits_list.shape}")

# 运行TSNE降维
tsne = TSNE(n_components=2, verbose=1, perplexity=25, n_iter=3000)
tsne_results = tsne.fit_transform(logits_list)

# 绘制可视化图
plt.figure(figsize=(10, 8))
scatter = plt.scatter(tsne_results[:,0], tsne_results[:,1], c=targets, cmap=plt.cm.get_cmap("jet", 14), alpha=0.7)
plt.colorbar(scatter, ticks=range(14), label='类别')
# 创建自定义图例
handles = [Line2D([0], [0], marker='o', color='w', markerfacecolor=plt.cm.jet(i/13), markersize=10, label=f'类别 {i}') for i in range(14)]
plt.legend(handles=handles, bbox_to_anchor=(1.05, 1), loc='upper left')
plt.title('VGG16特征TSNE可视化(14分类)')
plt.xlabel('TSNE维度1')
plt.ylabel('TSNE维度2')
plt.show()

额外提示

  • 如果聚类效果还是不好,先检查模型的测试准确率:如果模型本身训练不佳,特征自然无法有效区分类别。
  • 可以尝试提取更早层的特征(比如classifier的第3层,即第二个Linear层的输出),看看是否聚类效果更好。
  • 确保测试集的样本在14个类别中均匀分布,避免某类样本过多导致TSNE结果偏向该类。

内容的提问来源于stack exchange,提问作者AI_NA

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.06 14:07:28