参考 torch.nn.utils - 云+社区 - 腾讯云
torch.nn.utils(nn/utils/)
1、先看一下utils目录下的文件
torch.nn.utils(nn/utils/)
包括3个文件 init.py, rnn.py, clip_grad.py, weight_norm.py
这里面是一些nn的工具,比如rnn中的序列打包成PackedSequence和解包还原成程度不等序列
2、init.py
from . import rnn
from .clip_grad import clip_grad_norm
from .weight_norm import weight_norm, remove_weight_norm
#三句分别从当前目录的三个文件当中导入需要的函数或者类
#下面先看clip_grad.py
3、clip_grad.py
def clip_grad_norm(parameters, max_norm, norm_type=2):
#修剪可迭代Parameters的梯度范数
#范数由所有梯度共同计算得到, 把它们看做一个向量。
#梯度被in-place operation修改。
#参数:
#parameters (Iterable[Variable]): 要进行梯度归一化的可迭代的
# 变量Variable
#max_norm (float or int): 梯度的最大范数
#norm_type (float or int): p范数类型'inf' 代表无穷范数.
#返回值:
#所有参数的范数 (看成一个向量).
parameters = list(filter(lambda p: p.grad is not None, parameters))
max_norm = float(max_norm)
norm_type = float(norm_type)
if norm_type == float('inf'):
total_norm = max(p.grad.data.abs().max() for p in parameters) #无穷范数||X||inf = max(|Xi|)
else:
total_norm = 0
for p in parameters:
param_norm = p.grad.data.norm(norm_type)
# tensor.norm(p) 计算p范数
total_norm += param_norm ** norm_type
total_norm = total_norm ** (1. / norm_type)
#||X||p = Σ(Xi ** p) ** (1/p)
clip_coef = max_norm / (total_norm + 1e-6)
#防止total_norm等于0
if clip_coef < 1:
for p in parameters:
p.grad.data.mul_(clip_coef)
return total_norm
这个函数的作用是归一化p范数到max_norm,使得parameters的参数的p范数和为max_norm。默认为2范数,返回值为所有参数梯度的p范数
Gradient Clipping的引入是为了处理gradient explosion或者gradients vanishing的问题。
当在一次迭代中权重的更新过于迅猛的话,很容易导致loss divergence。Gradient Clipping的直观作用就是让权重的更新限制在一个合适的范围。所以经常在一个epoch之后加入clip_grad_norm在max_norm范围内。