subclass balancing代码解读3

def cluster (train_loader_cluster,model,cluster_number,args):
    model.eval()
    features_sum = []
    for i, (input, target,cluster_target) in enumerate(train_loader_cluster):
        input = input[0].cuda() # input[0]=input[1].shape =(1024, 3, 32, 32)
        target =target.cuda() # target.shape=(1024)
        with torch.no_grad():
            features  = model(input) # (1024, 128)
            features = features.detach()
            features_sum.append(features) # len(features_sum)=11 最后一个feature.shape = (607, 128)
    features= torch.cat(features_sum,dim=0) # features.shape = (10847, 128)   # 整个cifar100里面的样本数为10847个
    features = torch.split(features, args.cls_num_list, dim=0) # features是一个元组,features[0].shape=(500, 128) cls_num_list就是cifar100数据集中的100个类别,每个类别的样本数
    if args.train_rule == 'Rank':  # cls_num_list = [500, 477, 455, 434, 415, 396, 378, 361, 344, 328, 314, 299,...,5,5,5]
         feature_center = [torch.mean(t, dim=0) for t in features] #feature_center.shape=(128) 先大致找到中心点,大致按cls_num_list的数量将整体的数据集划分为一堆一堆的
         feature_center = torch.cat(feature_center,axis = 0) # feature_center.shape = (12800)  有100类,每个类别的中心点的维度都是128维
         feature_center=feature_center.reshape(args.num_classes,args.feat_dim) 
         # feature_center.shape=(100, 128)
         density = np.zeros(len(cluster_number)) # cluster_number就是每个类别应该划分为多少个小块,len(cluster_number)=100
         # 初始化一个长度为类别数的密度向量density,用于后续村粗每个类别的密度值

         # 计算每个类别的密度
         for i in range(len(cluster_number)):   # 对于每个类别i,计算其密度     features[0].shape = (500, 128)  也就是计算划分的第一个类里面的元素到中心点的距离
            center_distance = F.pairwise_distance(features[i], feature_center[i], p=2).mean()/np.log(len(features[i])+10) 
            density[i] = center_distance.cpu().numpy()
         density = density.clip(np.percentile(density,20),np.percentile(density,80))  # len(density)=100
         #density = args.temperature*np.exp(density/density.mean())
         density = args.temperature*(density/density.mean())
         for index, value in enumerate(cluster_number): # cluster_number = [50,47,... 1],也就是每个类别应该划分为几个小块,如果某个类别在cluster_number的对应值为1,表示此类别不需要进一步划分,直接将其密度设置为agrs.temperature
            if value==1:
                density[index] = args.temperature
    target = [[] for i in range(len(cluster_number))]
    for i in range(len(cluster_number)):  
        if cluster_number[i] >1:
          if args.cluster_method: # false
            cluster_ids_x, _ = balanced_kmean(X=features[i], num_clusters=cluster_number[i], distance='cosine', init='k-means++',iol=50,tol=1e-3,device=torch.device("cuda"))
          else:# features是一个元组,features[0].shape=(500, 128)  cluster_number[0]=50
            cluster_ids_x, _ = kmeans(X=features[i], num_clusters=cluster_number[i], distance='cosine', tol=1e-3, iter_limit=35, device=torch.device("cuda"))
            #run faster for cluster
          target[i]=cluster_ids_x # cluster_idx_x就是每个点距离最近的中心点的索引,target[0].shape=500
        else:# features[i].shape=(19, 128)    features[i].size()[0]=19
            target[i] = torch.zeros(1,features[i].size()[0], dtype=torch.int).squeeze(0) # target[i].shape=19,全是0,因为他们只有一个块,那只有一个中心点
    cluster_number_sum=[sum(cluster_number[:i]) for i in range(len(cluster_number))]# cluster_number就是每个类别应该划分为多少个小块,len(cluster_number)=100
    for i ,k in enumerate(cluster_number_sum): #cluster_number_sum= [0, 50, 97, 142, 185, 226, 265, 302, 338, 372, 404, 435, 464, 492, ...]  len =100
         target[i] =  torch.add(target[i], k)  # 这里面的add(target[i], k)是做什么的
    targets=torch.cat(target,dim=0)
    targets = targets.numpy().tolist()
    if args.train_rule == 'Rank':
        return targets,density
    else:
        return targets

target[i] =  torch.add(target[i], k)  # 这里面的add(target[i], k)是做什么的

这段代码的功能是使用K-means聚类算法对一个卷积神经网络模型的特征进行聚类,其中model参数是一个预先训练好的模型,它将输入的图像转换成高维的特征向量,train_loader_cluster提供了需要聚类的数据集,cluster_number是一个定义了每个类别应分为多少个簇的列表。

以下是代码中不同部分的详细说明:

  1. 遍历数据加载器(train_loader_cluster),使用模型提取每个批次的特征向量,并将这些特征向量累积在features_sum列表中。

  2. 将累积的特征向量拼接在一起(torch.cat(features_sum, dim=0)),得到整个数据集的特征矩阵。

  3. 使用torch.split按照各个类别的样本数量将特征矩阵分割成一个元组(分割后的每部分对应一个类别)。

  4. 计算每一类的平均特征向量,即特征中心(feature_center)。

  5. 计算每个类别的密度density,用于后面调整每个类别中聚类的数量。

  6. 对于每个类别,如果它的cluster_number[i]大于1,则使用K-means进行聚类,并将聚类结果存储在target[i]

  7. 如果类别的cluster_number[i]等于1,就意味着该类别不需要进行进一步的聚类,因此将对应的target[i]设置为全零张量,零表示所有样本都属于同一个簇。

  8. 计算每个类别的累积聚类数量(cluster_number_sum)。

  9. 修改target列表中的每一项,基于累积聚类数量来调整簇的编号,保证不同类别的簇编号不会重叠。

下面我将解释target[i] = torch.add(target[i], k)这一行代码的作用:

这行代码的目的是给每个类别的簇编号添加一个偏移量,使得每个类别的簇编号是唯一的,并且不同类别之间的编号是连续的。比如,如果第一个类别有50个簇,那么第二个类别的簇编号就应该从50开始,以此类推。

torch.add(target[i], k)这段代码将target[i]中的每个聚类索引加上一个偏移量k,其中k是之前类别中所有簇的累积数量(即该类别前面所有类别的簇总数)。这样确保每个样本点的簇标签在全局范围内是唯一的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值