#一旦不再使用即释放内存垃圾,=1.0 垃圾占用内存大小达到 10G 时,释放内存垃圾
export FLAGS_eager_delete_tensor_gb=0.0
#启用快速垃圾回收策略,不等待 cuda kernel 结束,直接释放显存
export FLAGS_fast_eager_deletion_mode=1
#该环境变量设置只占用 0%的显存
export FLAGS_fraction_of_gpu_memory_to_use=0
详细请参考官方文档存储分配与优化 调整相关配置。
此外,建议您使用AI Studio 学习与 实训社区训练,获取免费 GPU 算力,提升您的训练效率。
问题:如何提升模型训练时的 GPU 利用率?
答复:有如下两点建议:
如果数据预处理耗时较长,可使用 DataLoader 加速数据读取过程,具体请参考 API 文档:paddle.io.DataLoader。
如果提高 GPU 计算量,可以增大batch_size
,但是注意同时调节其他超参数以确保训练配置的正确性。
以上两点均为比较通用的方案,其他的优化方案和模型相关,可参考官方模型库 models 中的具体示例。
问题:如何处理变长 ID 导致程序内存占用过大的问题?
答复:请先参考显存分配与优化文档 开启存储优化开关,包括显存垃圾及时回收和 Op 内部的输出复用输入等。若存储空间仍然不够,建议:
降低 batch_size
;
对 index 进行排序,减少 padding 的数量。
检查数据集中训练数据的准确率,数据是否有错误,特征是否归一化;
简化网络结构,先基于 benchmark 实验,确保在 baseline 网络结构和数据集上的收敛结果正确;
对于复杂的网络,每次只增加一个改动,确保改动后的网络正确;
检查网络在训练数据上的 Loss 是否下降;
检查学习率、优化算法是否合适,学习率过大会导致不收敛;
检查batch_size
设置是否合适,batch_size
过小会导致不收敛;
检查梯度计算是否正确,是否有梯度过大的情况,是否为NaN
。
# 设置 config:
def set_config(args):
config = Config(args.model_file, args.params_file)
config.disable_gpu()
# enable_profile()打开后会统计每一步耗时
config.enable_profile()
config.switch_use_feed_fetch_ops(False)
config.switch_specify_input_names(True)
config.switch_ir_optim(False)
return config
使用paddle.static.Print()接口,可以打印中间变量及其梯度。
将变量梯度名放到 fetch_list 里,通过Executor.run()获取,一般 variable 的梯度名是 variable 的名字加上 "@GRAD"。
对于参数(不适用于中间变量和梯度),还可以通过Scope.find_var()接口,通过变量名字查找对应的 tensor。
后两个方法需要使用变量名,飞桨中变量的命名规则请参见Name 。
# paddlepaddle>=2.0
import paddle
import numpy as np
paddle.enable_static()
data = paddle.static.data('data', shape=[4, 2])
out = paddle.static.nn.fc(x=data, size=1, num_flatten_dims=1, name='fc')
loss = paddle.mean(out)
loss = paddle.static.Print(loss) # 通过 Print 算子打印中间变量及梯度
opt = paddle.optimizer.SGD(learning_rate=0.01)
opt.minimize(loss)
exe = paddle.static.Executor()
exe.run(paddle.static.default_startup_program())
loss, loss_g, fc_bias_g = exe.run(
paddle.static.default_main_program(),
feed={'data': np.random.rand(4, 2).astype('float32')},
fetch_list=[loss, loss.name + '@GRAD', 'fc.b_0@GRAD']) # 通过将变量名加入到 fetch_list 获取变量
print(loss, loss_g, fc_bias_g)
print(paddle.static.global_scope().find_var('fc.b_0').get_tensor()) # 通过 scope.find_var 获取变量
paddle.seed(123)
x = paddle.rand([3, 3], dtype='float32')
# Tensor(shape=[3, 3], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
# [[0.00276479, 0.45899123, 0.96637046],
# [0.66818708, 0.05855134, 0.33184195],
# [0.34202638, 0.95503175, 0.33745834]])
mask = paddle.randint(0, 2, [3, 3]).astype('bool')
# Tensor(shape=[3, 3], dtype=bool, place=CUDAPlace(0), stop_gradient=True,
# [[True , True , False],
# [True , True , True ],
# [True , True , True ]])
def masked_fill(x, mask, value):
y = paddle.full(x.shape, value, x.dtype)
return paddle.where(mask, y, x)
out = masked_fill(x, mask, 2)
# Tensor(shape=[3, 3], dtype=float32, place=CUDAPlace(0), stop_gradient=True,
# [[2. , 2. , 0.96637046],
# [2. , 2. , 2. ],
# [2. , 2. , 2. ]])
问题:在 paddle 中如何实现torch.nn.utils.rnn.pack_padded_sequence
和torch.nn.utils.rnn.pad_packed_sequence
这两个 API?
答复:目前 paddle 中没有和上述两个 API 完全对应的实现。关于 torch 中这两个 API 的详细介绍可以参考知乎上的文章 pack_padded_sequence 和 pad_packed_sequence : pack_padded_sequence
的功能是将 mini-batch 数据进行压缩,压缩掉无效的填充值,然后输入 RNN 网络中;pad_packed_sequence
则是把 RNN 网络输出的压紧的序列再填充回来,便于进行后续的处理。 在 paddle 中,大家可以在 GRU、LSTM 等 RNN 网络中输入含有填充值的 mini-batch 数据的同时传入对应的sequence_length
参数实现上述等价功能,具体用法可以参考 RNN 。
问题:BatchNorm在训练时加载预测时保存的模型参数时报错 AssertionError: Optimizer set error, batch_norm_1.w_0_moment_0 should in state dict.
答复:BatchNorm 在 train 模式和 eval 模式下需要的变量有差别,在 train 模式下要求传入优化器相关的变量,在 eval 模式下不管是保存参数还是加载参数都是不需要优化器相关变量的,因此如果在 train 模式下加载 eval 模式下保存的 checkpoint,没有优化器相关的变量则会报错。如果想在 train 模式下加载 eval 模式下保存的 checkpoint 的话,用 paddle.load
加载进来参数之后,通过 set_state_dict
接口把参数赋值给模型,参考以下示例:
import paddle
bn = paddle.nn.BatchNorm(3)
bn_param = paddle.load('./bn.pdparams')
bn.set_state_dict()