Report/12月20日本周科研工作进展.md

7.5 KiB
Raw Permalink Blame History

12月5日科研工作进展

目前进度

1.继续进行超参数调整

log7-l2s

log8

超参数:

# 批次大小
parser.add_argument('--batch-size', default=64, type=int)
parser.add_argument('--batch-size', default=96, type=int)

# 学习率
parser.add_argument('--lr', default=0.03, type=float)
parser.add_argument('--lr', default=0.08, type=float)

# 聚类数量
parser.add_argument('--num-cluster', default='2,5,10,20,33,50,100,200,400,800,1600,2400,3200', type=str)

parser.add_argument('--num-cluster', default='3200,2400,1600,800,400,200,100,50,25,20,10,5,2', type=str)

 # 负样本队列大小
parser.add_argument('--pcl-r', default=1024, type=int)
parser.add_argument('--pcl-r', default=640, type=int)
# MoCo动量
parser.add_argument('--moco-m', default=0.999, type=float, )

# softmax温度
parser.add_argument('--temperature', default=0.2, type=float)

# 数据增强
parser.add_argument('--aug-plus', default=True, type=bool)
parser.add_argument('--aug-plus', default=False, type=bool)

目前问题:

1存在过拟合的情况

2存在原型聚类损失不能很好引导两个精度的提升的问题

目前最佳训练:

log9-l2s

2.使用了软化标签的方式解决低聚类问题中的不确定影响

调用了nn.CrossEntropyLoss中的label_smoothing功能缓解硬标签对初期模型的破坏目前设定上限为0.2

def cac_smoothing_factor(cluster_result, args):
    # 获取当前聚类数
    cluster = int(cluster_result['centroids'][-1].shape[0])
    # 计算平滑因子使得聚类数越少平滑因子越大最大为0.2
    smoothing_factor = min(0.2, ((args.max_cluster - cluster) / args.max_cluster) ** 0.5 * 0.2)
    return smoothing_factor

3.改用了自行设计聚类数组而非直接翻倍的方式决定聚类数目

根据之前的实验聚类数在100左右时对训练提升最大这是因为使用的mini-imagenet数据集拥有100个类别的原因。使用直接翻倍的情况可能会导致跳过n倍数类别或1/n类别的聚类数导致计算损失时存在误差。

parser.add_argument('--num-cluster', default='2,5,10,20,33,50,100,200,400,800,1600,2400,3200', type=str)

# 改变聚类数逻辑
if should_change:
    # 取 num_clusters 的最后一个数字,与 all_clusters 比较
    last_cluster = num_clusters[-1]
    if last_cluster in all_clusters:
        index = all_clusters.index(last_cluster)
        if index + 1 < len(all_clusters):  # 确保不会超出范围
            next_cluster = all_clusters[index + 1]
            # 更新 num_clusters移除第一个添加新数字到末尾
            num_clusters.pop(0)
            num_clusters.append(next_cluster)
            print(f"Epoch {epoch}: 聚类数改变.")
            print(f"num_clusters 更新为: {num_clusters}")
        else:
            print("all_clusters 已用完,无法改变.")
    else:
        print("当前 num_clusters 的最后一个数字未在 all_clusters 中找到")

    sliding_window.reset(epoch)  # 重置窗口并更新init_threshold
elif should_change_threshold:
    print(f"Epoch {epoch}: 增加inst阈值")
else:
    print("滑动窗口未达到条件,不改变聚类数.")

4.增加了cos学习率衰减以控制更新以及防止过拟合

def adjust_learning_rate(optimizer, epoch, args):
    """Decay the learning rate based on schedule"""
    lr = args.lr
    if args.cos:  # cosine lr schedule
        lr *= 0.5 * (1. + math.cos(math.pi * epoch / args.epochs))
    else:  # stepwise lr schedule
        for milestone in args.schedule:
            lr *= 0.1 if epoch >= milestone else 1.
    for param_group in optimizer.param_groups:
        param_group['lr'] = lr

5.采用凝聚型层次聚类作为一次聚类任务的方式

避免出现样本a在细聚类时属于小原型1.1小原型1.1属于大原型1中但样本a却在粗聚类时被分配到大原型2中的问题提升聚类的可靠性。

图片1

    # 取得聚类中心0
    centroids_0, im2cluster_0, D0 = clus(x, num_clusters[0], args)
    # 取得聚类中心1
    centroids_1, im2cluster_1, D1 = clus(centroids_0, num_clusters[1], args)
    # 取得聚类中心2
    centroids_2, im2cluster_2, D2 = clus(centroids_1, num_clusters[2], args)

    density_0 = cau_density(im2cluster_0, num_clusters[0], D0, args)
    density_1 = cau_density(im2cluster_1, num_clusters[1], D1, args)
    density_2 = cau_density(im2cluster_2, num_clusters[2], D2, args)
    
    ...
    
    def clus(x, num_cluster, args):
    k= int(num_cluster)
    clus = faiss.Clustering(x.shape[1], k)
    clus.verbose = False
    clus.niter = 20  # 最大迭代次数
    clus.nredo = 5  # 聚类重新初始化次
    clus.seed = args.seed
    clus.max_points_per_centroid = int(x.shape[0] * 5 / 3 / int(num_cluster))
    clus.min_points_per_centroid = int(x.shape[0] / 3 / int(num_cluster))
    clus.is_relative_centroids = True
    clus.spherical = True
    print(
        f"num_cluster:{num_cluster}, min_points:{clus.min_points_per_centroid}, max_points:{clus.max_points_per_centroid}")
    res = faiss.StandardGpuResources()
    cfg = faiss.GpuIndexFlatConfig()
    cfg.useFloat16 = True
    cfg.device = args.gpu
    index = faiss.GpuIndexFlatL2(res, x.shape[1], cfg)

    clus.train(x, index)
    D, I = index.search(x, 1)  # for each sample, find cluster distance and assignments
    im2cluster = [int(n[0]) for n in I]

    # 取得聚类中心
    centroids = faiss.vector_to_array(clus.centroids).reshape(k, x.shape[1])

    return centroids, im2cluster, D

def cau_density(im2cluster, k, D, args):
    # 计算每个样本到其聚类中心的距离
    Dcluster = [[] for c in range(k)]
    for im, i in enumerate(im2cluster):
        Dcluster[i].append(D[im][0])

    # 聚类中心浓度估算
    density = np.zeros(k)
    for i, dist in enumerate(Dcluster):
        if len(dist) > 1:
            d = (np.asarray(dist) ** 0.5).mean() / np.log(len(dist) + 10)
            density[i] = d

    # 如果聚类只有一个点,最大化估计其浓度
    dmax = density.max()
    for i, dist in enumerate(Dcluster):
        if len(dist) <= 1:
            density[i] = dmax

    density = density.clip(np.percentile(density, 10),
                           np.percentile(density, 90))  # 去掉极端浓度值
    density = args.temperature * density / density.mean()  # 缩放浓度值

目前没有使用,原因是每层聚类数的差异不够,如聚类数为[2400,2000,1600]每层差距不到1.2,凝聚型聚类会导致从小样本中聚类大样本数,问题较大。

可能考虑在以后从小到大的聚类训练中使用,以获得高可信度的粗聚类中心。

6.改用聚类数从高到低的方式引导训练流程

在模型刚开始训练时,较粗的聚类可能导致边缘样本的错误分配,导致错误的累计。故引导聚类的方法从细到粗更可靠,最近邻和过度聚类通常更能被接受的;同时,凝聚聚类是一个循环过程,可以自然地在循环框架中进行解释;随着学习到更好的表示,这些聚类可以被合并。

目前正在实验,

从小到大loss_inst: 3.50, loss_proto: 2.84 Acc_Inst: 75.01, Acc_Proto: 60.28

从大到小loss_inst: 2.67e, loss_proto: 3.46, Acc_Inst: 91.45, Acc_Proto: 89.15

两种聚类方式会已进行比较图1和图3后续将补充一些说明作为论文的工作量。

下周任务

1.进行一些下游任务实验的进一步设计如few-shot、聚类效果等