深度学习不同显卡跑出来的模型精度不一样

参考链接
一个由GPU型号不同导致模型掉点问题的排查过程TF32 vs FP32
https://blog.csdn.net/wohenibdxt/article/details/124542075

怪不得说深度学习是神学,本来在精度%1就很重要的情况下,发现3090和4090跑出来的结果是不一样的。。。。。。。。。。

参考:最靠谱的pytorch训练可复现性设置方案 https://zhuanlan.zhihu.com/p/629526120

一些发现-相同显卡跑出来是有办法一致的

服务器1:30904
服务器2:4090
3
服务器3:4090*4

只要随机种子一致,发现只是显卡影响精度,不是系统环境和设备,例如:

服务器1的3090每一张显卡每次跑出来的精度一致;
服务器2的4090每一张显卡每次跑出来的精度一致;
并且!:
服务器2和服务器3的4090每一张显卡每次跑出来的精度一致。

所以可以得出结论,其他条件一样的情况下,相同显卡跑出来的精度一致

2026-1-29记录 碰到最难搞的一次,服务器显卡一致,跑出来的精度居然不一致

这次是
CCE 4:40903 64核
CCE 5:4090
2 48核
CCE 6:4090*4 48核

申请的事情发生了,刚开始一直都是5=6,但4不一样,然后发现是dataloader有一个地方搞的鬼,就是这个num_workers没有固定,会造成精度不一致

    data_loader = DataLoader(
        dataset=ds_train,
        sampler=sampler,
        shuffle=(sampler is None),
        batch_size=args.batch_size,
        num_workers=args.num_workers,
        pin_memory=True,
        drop_last=True,
        worker_init_fn=seed_worker,
        generator=g,
    )

解决完这个发现还是精度对不齐,偶然发现了model改为deit_small_distilled_patch16_224后是一致的,也就是上述解决了deit_small_distilled_patch16_224的精度一致问题,但是resnet50还是对不齐。

最后发现是这里搞的鬼:

    if args.model == 'resnet50':
        bdim = 2048
    else:
        freeze(body, 0)
        bdim = 384
    last_norm = nn.LayerNorm(bdim, elementwise_affine=False).cuda() if args.use_lastnorm else nn.Identity()
    last_layer = nn.Sequential(last_norm, nn.Linear(bdim, args.emb), last)
    last_layer.apply(_init_weights)
    
    if args.model.startswith("vit") or args.model.startswith("deit"):
        body.reset_classifier(0, args.pool)
    else:
        rm_head(body)

最后需要在这里把把线程锁死成单线程,不然线程数不同(64 核 vs 48 核)会导致结果微差

    if args.model == 'resnet50':
        bdim = 2048
    else:
        freeze(body, 0)
        bdim = 384

    #####################固定线程数#################################
    import os  # 用于设置 OpenMP / MKL / OpenBLAS 等线程环境变量
    import random  # Python 随机数
    import numpy as np  # NumPy 随机数
    # ---- (1) 锁死 CPU 相关库线程数:尽量在调用任何线性代数/初始化函数之前设置 ----
    os.environ["OMP_NUM_THREADS"] = "1"  # OpenMP 线程数(很多底层库会用)
    os.environ["MKL_NUM_THREADS"] = "1"  # Intel MKL 线程数(如果用到 MKL)
    os.environ["OPENBLAS_NUM_THREADS"] = "1"  # OpenBLAS 线程数(如果用到 OpenBLAS)
    os.environ["NUMEXPR_NUM_THREADS"] = "1"  # numexpr 线程数(以防间接用到)
    torch.set_num_threads(1)  # PyTorch CPU 算子线程数
    torch.set_num_interop_threads(1)  # PyTorch 并行调度线程数(interop)
    # ---- (2) 在 head 初始化前重新置随机种子:确保这里用到的随机数序列固定 ----
    random.seed(args.seed)  # 重置 Python random 的 RNG 状态
    np.random.seed(args.seed)  # 重置 NumPy 的 RNG 状态
    torch.manual_seed(args.seed)  # 重置 PyTorch CPU RNG 状态
    #####################固定线程数#################################

    last_norm = nn.LayerNorm(bdim, elementwise_affine=False).cuda() if args.use_lastnorm else nn.Identity()
    last_layer = nn.Sequential(last_norm, nn.Linear(bdim, args.emb), last)
    last_layer.apply(_init_weights)
posted @ 2024-12-09 21:17  JaxonYe  阅读(872)  评论(5)    收藏  举报