多卡训练中的BN(BatchNorm)

     现有框架BatchNorm的实现(DP,DDP)都是只考虑了single gpu。也就是说BN使用的均值和标准差是单个gpu算的,相当于缩小了batchsize。

      对于比较消耗显存的训练任务时,往往单卡上的相对批量过小,影响模型的收敛效果。 之前在在图像语义分割的实验中,就发现使用大模型的效果反而变差,实际上就是BN在作怪。 跨卡同步 Batch Normalization 可以使用全局的样本进行归一化,这样相当于‘增大‘了批量大小,这样训练效果不再受到使用 GPU 数量的影响。 最近在图像分割、物体检测的论文中,使用跨卡BN也会显著地提高实验效果,所以跨卡 BN 已然成为竞赛刷分、发论文的必备神器。

但是为什么跨卡同步BN没有成为主流?

      1)因为没有sync的需求,因为对于大多数vision问题,单gpu上的mini-batch已经够大了,完全不会影响结果。

     2)影响训练速度,BN layer通常是在网络结构里面广泛使用的,这样每次都同步一下GPUs,十分影响训练速度。

从使用的经验来看,如果多卡训练没开BN同步,那么所得的结果和使用单GPU训练得到的结果基本一致,但是训练速度会得到提升。

而如果开了BN同步,训练结果会有将近一个点的提升

当然如果多卡训,但是单张卡上的batchsize就很大了,这样是开BN同步就没有太大作用

开了BN之后会让训练速度变慢,大概是不开5秒,开了8秒的样子

### 单机训练的配置与实现 #### TensorFlow 1.x 的单机训练 在 TensorFlow 1.x 中,可以通过 `tf.estimator` 和 `tf.train.MonitoredTrainingSession` 来实现单机训练。官方提供了一个脚本作为参考[^1]。主要思路是通过设置设备分配策略来利用个 GPU 并行处理数据。 以下是基于 TensorFlow 1.x 的简单实现框架: ```python import tensorflow as tf # 定义输入管道 def input_fn(): dataset = tf.data.Dataset.from_tensor_slices((features, labels)) dataset = dataset.shuffle(buffer_size).batch(batch_size) return dataset # 构建模型函数 def model_fn(features, labels, mode): predictions = ... loss = ... optimizer = tf.compat.v1.train.AdamOptimizer() # 使用分布式策略 with tf.device(tf.train.replica_device_setter(cluster=cluster_spec)): train_op = optimizer.minimize(loss) return tf.estimator.EstimatorSpec(mode=mode, loss=loss, train_op=train_op) # 设置集群规格 cluster_spec = tf.train.ClusterSpec({ 'worker': ['localhost:2222', 'localhost:2223'] }) # 初始化 Estimator config = tf.estimator.RunConfig( session_config=tf.ConfigProto(log_device_placement=True), train_distribute=tf.contrib.distribute.MirroredStrategy()) estimator = tf.estimator.Estimator(model_fn=model_fn, config=config) # 开始训练 estimator.train(input_fn=input_fn) ``` #### PyTorch 的单机训练 PyTorch 提供了更灵活的方式来进行单机训练,通常使用 `torch.nn.DataParallel` 或者更为推荐的 `torch.nn.DistributedDataParallel`[^3]。为了确保不同进程间同步初始化完成,可以调用 `torch.distributed.barrier()` 函数。 下面是一个简单的 PyTorch 训练示例: ```python import torch import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP # 初始化进程组 dist.init_process_group(backend='nccl') # 加载模型到指定设备上 device = torch.device(f'cuda:{rank}') model = YourModel().to(device) # 将模型封装成分布式模式 ddp_model = DDP(model, device_ids=[rank]) # 数据加载器需配合 DistributedSampler train_sampler = torch.utils.data.distributed.DistributedSampler(dataset) train_loader = torch.utils.data.DataLoader( dataset, batch_size=batch_size_per_gpu, sampler=train_sampler ) # 训练循环 for epoch in range(num_epochs): for data, target in train_loader: output = ddp_model(data.to(device)) loss = criterion(output, target.to(device)) loss.backward() optimizer.step() optimizer.zero_grad() # 同步屏障 dist.barrier() ``` #### Baichuan-2 的 Hybrid Shard Zero2 策略 Baichuan-2 提出了 hybrid shard zero2 方法,这是一种结合 ZeRO-2 和其他分片技术的混合策略[^2]。ZeRO-2 主要用于减少内存占用的同时保持较高的计算效率。Hybrid shard zero2 可能进一步优化了参数、梯度以及优化状态的分布方式,在大规模模型训练中有显著优势。 #### 配置文件中的 DataLoader 设定 对于大深度学习框架而言,调整 `dataloader` 是实现高效训练的重要部分之一。例如,在 MMDetection 或 MMCV 等库中,可以在配置文件里定义如下内容[^4]: ```yaml data: samples_per_gpu: 4 workers_per_gpu: 2 train: type: CustomDataset ann_file: path/to/train.json pipeline: - type: LoadImageFromFile - type: Normalize ``` 上述 YAML 文件片段展示了如何设定每张显上的样本数 (`samples_per_gpu`) 和工作线程数量 (`workers_per_gpu`)。 --- ###
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值