.. _sublinear: 亚线性内存优化 ============================== 使用大 batch size 通常能够提升深度学习模型性能。然而,我们经常遇到的困境是有限的 GPU 内存资源无法满足大 batch size 模型训练。为了缓解这一问题, MegEngine 提供了亚线性内存 ( sublinear memory ) 优化技术用于降低网络训练的内存占用量。该技术基于 `gradient checkpointing `_ 算法,通过事先搜索最优的计算图节点作为前向传播和反向传播检查点( checkpoints ),省去其它中间结果存储,大幅节约了内(显)存使用。 用户在编译静态图时使用 :class:`~.SublinearMemoryConfig` 设置 :class:`~.trace` 的参数 ``sublinear_memory_config`` ,就可以打开亚线性内存优化。 .. testcode:: from megengine.jit import trace, SublinearMemoryConfig config = SublinearMemoryConfig() @trace(symbolic=True, sublinear_memory_config=config) def train_func(data, label, *, net, optimizer): ... 使用亚线性内存在编译计算图和训练模型时有少量的额外时间开销,但是可以大幅减少显存的开销。下面我们以 `ResNet50 `_ 为例,说明如何使用亚线性内存优化技术,突破显存瓶颈来训练更大batch size的模型。 .. testcode:: import os from multiprocessing import Process def train_resnet_demo(batch_size, enable_sublinear, genetic_nr_iter=0): import megengine as mge import megengine.functional as F import megengine.hub as hub import megengine.optimizer as optim from megengine import tensor from megengine.jit import trace, SublinearMemoryConfig import numpy as np print( "Run with batch_size={}, enable_sublinear={}, genetic_nr_iter={}".format( batch_size, enable_sublinear, genetic_nr_iter ) ) # 使用GPU运行这个例子 assert mge.is_cuda_available(), "Please run with GPU" try: # 我们从 megengine hub 中加载一个 resnet50 模型。 resnet = hub.load("megengine/models", "resnet50") optimizer = optim.SGD(resnet.parameters(), lr=0.1,) config = None if enable_sublinear: config = SublinearMemoryConfig(genetic_nr_iter=genetic_nr_iter) @trace(symbolic=True, sublinear_memory_config=config) def train_func(data, label, *, net, optimizer): pred = net(data) loss = F.cross_entropy_with_softmax(pred, label) optimizer.backward(loss) data = mge.tensor() label = mge.tensor(dtype="int32") resnet.train() for i in range(10): batch_data = np.random.randn(batch_size, 3, 224, 224).astype(np.float32) batch_label = np.random.randint(1000, size=(batch_size,)).astype(np.int32) data.set_value(batch_data) label.set_value(batch_label) optimizer.zero_grad() train_func(data, label, net=resnet, optimizer=optimizer) optimizer.step() except: print("Failed") return print("Success") # 以下示例结果在2080Ti GPU运行得到,显存容量为 11 GB # 不使用亚线性内存优化,允许的batch_size最大为 100 左右 p = Process(target=train_resnet_demo, args=(100, False)) p.start() p.join() # 报错显存不足 p = Process(target=train_resnet_demo, args=(200, False)) p.start() p.join() # 使用亚线性内存优化,允许的batch_size最大为 200 左右 p = Process(target=train_resnet_demo, args=(200, True, 20)) p.start() p.join()