本期分析Senta中的评估标准Metric
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import time
import numpy as np
from scipy.stats import pearsonr, spearmanr
from six.moves import xrange
import paddle.fluid as fluid
from functools import partial
def scale_l2(x, norm_length):
"""
# copy lines from here https://github.com/tensorflow/models/blob/master/research/adversarial_text/adversarial_losses.py#L190
# shape(x) = (batch, num_timesteps, d)
# Divide x by max(abs(x)) for a numerically stable L2 norm.
# 2norm(x) = a * 2norm(x/a)
# Scale over the full sequence, dims (1, 2)
"""
alpha = fluid.layers.reduce_max(fluid.layers.abs(x), dim=1, keep_dim=True) + 1e-12
l2_norm = alpha * fluid.layers.sqrt(
fluid.layers.reduce_sum(fluid.layers.pow(x / alpha), dim=1, keep_dim=True) + 1e-6)
x_unit = x / l2_norm
return norm_length * x_unit
paddle.fluid.layers.reduce_max(input, dim=None, keep_dim=False, name=None) :对指定维度上的Tensor元素求最大值运算,并输出相应的计算结果。 input (Variable)- 输入变量为多维Tensor或LoDTensor,支持数据类型为float32,float64,int32,int64。
dim (list | int ,可选)- 求最大值运算的维度。如果为None,则计算所有元素的最大值并返回包含单个元素的Tensor变量,否则必须在 [?rank(input),rank(input)] 范围内。如果 dim[i]<0 ,则维度将变为 rank+dim[i] ,默认值为None。
keep_dim (bool)- 是否在输出Tensor中保留减小的维度。如 keep_dim 为true,否则结果张量的维度将比输入张量小,默认值为False。
paddle.fluid.layers.abs(x, name=None) :绝对值激活函数。
x (Variable)- 多维Tenosr,数据类型为float32或float64。
paddle.fluid.layers.reduce_sum(input, dim=None, keep_dim=False, name=None) : 对指定维度上的Tensor元素进行求和运算,并输出相应的计算结果。
input (Variable)- 输入变量为多维Tensor或LoDTensor,支持数据类型为float32,float64,int32,int64。
dim (list | int ,可选)- 求和运算的维度。如果为None,则计算所有元素的和并返回包含单个元素的Tensor变量,否则必须在[?rank(input),rank(input)] 范围内。如果 dim[i]<0 ,则维度将变为 rank+dim[i] ,默认值为None。
keep_dim (bool)- 是否在输出Tensor中保留减小的维度。如 keep_dim 为true,否则结果张量的维度将比输入张量小,默认值为False。
def pgd_loss(ernie, labels, loss, task_fc_fn, epsilon=0.25):
""" refer code from
https://github.com/tensorflow/models/blob/master/research/adversarial_text/adversarial_losses.py#L145
but we didn't use the vat loss for now
"""
program = fluid.default_main_program()
param_grads = fluid.backward.append_backward(loss, parameter_list=[ernie._word_emb_name])
d = filter(lambda p: p[0].name == ernie._word_emb_name, param_grads)[0][1]
emb = program.block(0).var(ernie._word_emb_name)
K_iteration = 8
small_constant_for_finite_diff = 1e-5
emb_hat = emb
d = fluid.layers.gaussian_random(emb.shape)
for _ in range(K_iteration):
d = scale_l2(d, small_constant_for_finite_diff)
emb_hat = emb_hat + d
ernie._build_model(emb=emb_hat)
graph_vars = task_fc_fn(ernie, labels)
gradient = filter(lambda p: p[0].name == ernie._word_emb_name, param_grads)[0][1]
gradient.stop_gradient = True
d = gradient
d = scale_l2(d, small_constant_for_finite_diff)
emb_hat = emb_hat + d
ernie._build_model(emb=emb_hat)
graph_vars = task_fc_fn(ernie, labels)
return graph_vars['loss']
paddle.fluid.default_main_program() : 获取当前用于存储op和variable描述信息的 default main program
paddle.fluid.backward.append_backward(loss, parameter_list=None, no_grad_set=None, callbacks=None) 该接口将向主程序(main_program)追加反向部分。 完整的神经网络训练由前向和反向传播组成。但是当我们配置网络时,我们只需要指定其前向部分。 该接口使用链式法则,能够根据前向部分自动生成反向部分。
参数: loss ( Variable ) - 网络的损失变量。 parameter_list (list [str],可选)-指定优化器需要更新的参数名称列表。如果为 None ,则将更新所有参数。默认值为 None。
no_grad_set (set [str],可选)- 在 block0 ( Block ) 中要忽略梯度的 Variable 的名字的集合。所有的 Block 中带stop_gradient = True 的所有 Variable 的名字都会被自动添加到此集合中。如果该参数不为None,则会将该参数集合的内容添加到默认的集合中。默认值为 None。
callbacks (list [callable object],可选)- 回调函数列表。用于在反向传播构建中执行一些自定义作业。每次将新的梯度OP添加到程序中时,将调用其中的所有可调用对象。可调用对象必须有两个输入参数: Block 和 context 。 Block 是将被添加到新梯度算子的块。 context 是一个映射,其键是梯度 Variable名,值是对应的原始 Variable 。除此之外, context 还有另一个特殊的键值对:键是字符串 __ current_op_desc__ ,值是刚刚触发可调用对象的梯度OP的 op_desc 。默认值为 None。
本篇到此结束,下篇将续接本篇继续分析评估标准Metric。
|