可解释性研究 -LRP-for-LSTM
LRP算法
- 一.LSTM
- 1.1.理论部分
- 1.2.作者代码
- 二.LRP_for_LSTM
- 2.1.理论部分
- 2.2.1.Weighted Connections
- 2.2.2.Multiplicative Interactions
- 2.2.作者代码
- 三.扩展到GRU
- 3.1.GRU
- 3.2.GRU的Relevance计算部分
- 四.参考文献
LRP算法也是可解释算法的一种,全称Layer-wise Relevance Propagation,原始LRP算法主要是应用在CV等领域,针对NLP中通过Word2Vec等手段将token转化为分布式词向量并通过RNN向量化文档的可解释手段真不多。LIME虽然可以针对文本数据进行解释,但适用场景是tf-idf或者bag-of-word这种词向量,向量中一个维度代表一个词。
这里参考的论文是Explaining Recurrent Neural Network Predictions in Sentiment Analysis,作者将LRP算法扩展到LSTM中,这里应用的任务是一个5分类情感任务,输入一个词序列,输出这句话属于哪个类别,LRP算法输出序列中哪几个词是重点。
代码开源到github,但是这里作者用numpy实现了个LSTM,并用LRP解释。如何添加对pytorch,keras框架还没人做过。先来研究下内部实现。
一.LSTM
1.1.理论部分
关于LSTM可以参考LSTM详解,这里为了跟作者的代码同步,再提几句。LSTM大致结构如下
这里模型每一个时间步的输出为 hth_tht,从t - 1时刻到t时刻可以用 Ct,ht=LSTMCell(Ct−1,ht−1,xt)C_t, h_t = LSTMCell(C_{t - 1}, h_{t - 1}, x_t)Ct,ht=LSTMCell(Ct−1,ht−1,xt) 表示,xtx_txt 是输入向量,Wf,Wi,Wo,Wg,bf,bi,bo,bgW_f, W_i, W_o, W_g, b_f, b_i, b_o, b_gWf,Wi,Wo,Wg,bf,bi,bo,bg 均为模型参数(模型参数写法有很多种,作者代码实现的就有些区别)。
- xt∈Rex_t \in R^ext∈Re
- ht∈Rdh_t \in R^dht∈Rd
- Ct∈RdC_t \in R^dCt∈Rd
- Wf,Wi,Wo,Wg∈R(d+e)×dW_f, W_i, W_o, W_g \in R^{(d + e) \times d}Wf,Wi,Wo,Wg∈R(d+e)×d
- bf,bi,bo,bg∈Rdb_f, b_i, b_o, b_g \in R^dbf,bi,bo,bg∈Rd
- ft,it,gt,ot∈Rdf_t, i_t, g_t, o_t \in R^dft,it,gt,ot∈Rd
上图
- ∣∣||∣∣ 表示concat操作,∣∣(ht−1,xt)=[ht−1;xt]||(h_{t - 1}, x_t) = [h_{t - 1};x_t]∣∣(ht−1,xt)=[ht−1;xt]
- σ\sigmaσ 表示sigmoid,箭头线带2个参数+sigmoid表示 σ(W.[ht−1;xt]+b)\sigma(W.[h_{t - 1};x_t] + b)σ(W.[ht−1;xt]+b)
- tanhtanhtanh 表示tanh激活函数
- +++ 表示向量加法
- ×\times× 表示向量乘法,这里相乘的元素都是1维向量,计算结果是对应位置的元素相乘,依旧是1维向量,比如 [1,2,3]×[4,5,6]=[4,10,18][1,2,3] \times [4, 5, 6] = [4, 10, 18][1,2,3]×[4,5,6]=[4,10,18]
这里就把上面涉及的公式总结下,要是觉得多余了就直接往下翻
- ft=σ(Wf.[ht−1;xt]+bf)f_t = \sigma(W_f.[h_{t - 1}; x_t] + b_f)ft=σ(Wf.[ht−1;xt]+bf)
- it=σ(Wi.[ht−1;xt]+bi)i_t = \sigma(W_i.[h_{t - 1}; x_t] + b_i)it=σ(Wi.[ht−1;xt]+bi)
- gt=tanh(Wg.[ht−1;xt]+bg)g_t = tanh(W_g.[h_{t - 1}; x_t] + b_g)gt=tanh(Wg.[ht−1;xt]+bg)
- ot=σ(Wo.[ht−1;xt]+bo)o_t = \sigma(W_o.[h_{t - 1}; x_t] + b_o)ot=σ(Wo.[ht−1;xt]+bo)
- Ct=Ct−1×ft+it×gtC_t = C_{t - 1} \times f_t + i_t \times g_tCt=Ct−1×ft+it×gt
- ht=ot×tanh(Ct)h_t = o_t \times tanh(C_t)ht=ot×tanh(Ct)
针对双向LSTM,假设输入序列长度为 TTT,那么最终输出 ccc
c=Wleft.hleftT+Wright.hrightTc = W_{left} . h_{left}^T + W_{right}. h_{right}^T c=Wleft.hleftT+Wright.hrightT
- c∈RCc \in R^Cc∈RC,CCC 为类别数
- Wleft,Wright∈RC×dW_{left}, W_{right} \in R^{C \times d}Wleft,Wright∈RC×d
1.2.作者代码
class LSTM_bidi:def __init__(self, model_path='./model/'):"""Load trained model from file."""# vocabularyf_voc = open(model_path + "vocab", 'rb')self.voc = pickle.load(f_voc)f_voc.close()# word embeddingsself.E = np.load(model_path + 'embeddings.npy', mmap_mode='r') # shape V*e# model weightsf_model = open(model_path + 'model', 'rb')model = pickle.load(f_model)f_model.close()# LSTM left encoderself.Wxh_Left = model["Wxh_Left"] # shape 4d*eself.bxh_Left = model["bxh_Left"] # shape 4dself.Whh_Left = model["Whh_Left"] # shape 4d*dself.bhh_Left = model["bhh_Left"] # shape 4d# LSTM right encoderself.Wxh_Right = model["Wxh_Right"]self.bxh_Right = model["bxh_Right"]self.Whh_Right = model["Whh_Right"]self.bhh_Right = model["bhh_Right"] # linear output layerself.Why_Left = model["Why_Left"] # shape C*dself.Why_Right = model["Why_Right"] # shape C*d
这里作者实现的是双向LSTM,一个left,一个right,我们只关注其中一个,left。可以看到作者这里并没有定义concat操作,而是对参数进行了重组,之前的 Wf,Wi,Wg,WoW_f, W_i, W_g, W_oWf,Wi,Wg,Wo 重组成了 WxhW_{xh}Wxh 和 WhhW_{hh}Whh,一个用来与 xtx_txt 运算一个用来与 ht−1h_{t - 1}ht−1 运算。WxhW_{xh}Wxh 包括了 Wf,Wi,Wg,WoW_f, W_i, W_g, W_oWf,Wi,Wg,Wo 中与 xtx_txt 运算的部分而 WhhW_{hh}Whh 包括了与 ht−1h_{t - 1}ht−1 运算的部分。
def forward(self):"""Standard forward pass.Compute the hidden layer values (assuming input x/x_rev was previously set)"""print(f"x.shape:{self.x.shape}")T = len(self.w)d = int(self.Wxh_Left.shape[0]/4)# gate indices (assuming the gate ordering in the LSTM weights is i,g,f,o):idx = np.hstack((np.arange(0,d), np.arange(2*d,4*d))).astype(int) # indices of gates i,f,o togetheridx_i, idx_g, idx_f, idx_o = np.arange(0,d), np.arange(d,2*d), np.arange(2*d,3*d), np.arange(3*d,4*d) # indices of gates i,g,f,o separately# initializeself.gates_xh_Left = np.zeros((T, 4*d))self.gates_hh_Left = np.zeros((T, 4*d))self.gates_pre_Left = np.zeros((T, 4*d)) # gates pre-activationself.gates_Left = np.zeros((T, 4*d)) # gates activationself.gates_xh_Right = np.zeros((T, 4*d)) self.gates_hh_Right = np.zeros((T, 4*d)) self.gates_pre_Right= np.zeros((T, 4*d))self.gates_Right = np.zeros((T, 4*d))for t in range(T): self.gates_xh_Left[t] = np.dot(self.Wxh_Left, self.x[t])self.gates_hh_Left[t] = np.dot(self.Whh_Left, self.h_Left[t-1])self.gates_pre_Left[t] = self.gates_xh_Left[t] + self.gates_hh_Left[t] + self.bxh_Left + self.bhh_Leftself.gates_Left[t,idx] = 1.0/(1.0 + np.exp(- self.gates_pre_Left[t,idx])) # it, ft, ot = sigmoid(it), sigmoid(ft), sigmoid(ot)self.gates_Left[t,idx_g] = np.tanh(self.gates_pre_Left[t,idx_g]) # g_t = tanh(g_t)self.c_Left[t] = self.gates_Left[t,idx_f]*self.c_Left[t-1] + self.gates_Left[t,idx_i]*self.gates_Left[t,idx_g] # ct = ft * ct-1 + it * gtself.h_Left[t] = self.gates_Left[t,idx_o]*np.tanh(self.c_Left[t]) # ht = ot * tanh(ct)self.gates_xh_Right[t] = np.dot(self.Wxh_Right, self.x_rev[t])self.gates_hh_Right[t] = np.dot(self.Whh_Right, self.h_Right[t-1])self.gates_pre_Right[t] = self.gates_xh_Right[t] + self.gates_hh_Right[t] + self.bxh_Right + self.bhh_Rightself.gates_Right[t,idx] = 1.0/(1.0 + np.exp(- self.gates_pre_Right[t,idx]))self.gates_Right[t,idx_g] = np.tanh(self.gates_pre_Right[t,idx_g]) self.c_Right[t] = self.gates_Right[t,idx_f]*self.c_Right[t-1] + self.gates_Right[t,idx_i]*self.gates_Right[t,idx_g]self.h_Right[t] = self.gates_Right[t,idx_o]*np.tanh(self.c_Right[t])self.y_Left = np.dot(self.Why_Left, self.h_Left[T-1])self.y_Right = np.dot(self.Why_Right, self.h_Right[T-1])self.s = self.y_Left + self.y_Rightreturn self.s.copy() # prediction scores
这里重点看for
循环,并且只关注left结尾的变量。
for
循环第4句self.gates_Left[t,idx] = 1.0/(1.0 + np.exp(- self.gates_pre_Left[t,idx]))
对应 ft=σ(Wf.[ht−1;xt]+bf)f_t = \sigma(W_f.[h_{t - 1}; x_t] + b_f)ft=σ(Wf.[ht−1;xt]+bf) ,it=σ(Wi.[ht−1;xt]+bi)i_t = \sigma(W_i.[h_{t - 1}; x_t] + b_i)it=σ(Wi.[ht−1;xt]+bi) 和 ot=σ(Wo.[ht−1;xt]+bo)o_t = \sigma(W_o.[h_{t - 1}; x_t] + b_o)ot=σ(Wo.[ht−1;xt]+bo)。- 第5句
self.gates_Left[t,idx_g] = np.tanh( self.gates_pre_Left[t,idx_g] )
对应 gt=tanh(Wg.[ht−1;xt]+bg)g_t = tanh(W_g.[h_{t - 1}; x_t] + b_g)gt=tanh(Wg.[ht−1;xt]+bg)。
二.LRP_for_LSTM
2.1.理论部分
在NLP任务中,每个词会首先用分布式词向量向量化,因此传统的给每个特征分配权值的方式在这里不太适用,作者这里针对每个词分配权重,计算方式就是将词向量的每个维度的权值相加,比如输入序列shape [8,60][8 , 60][8,60],8个词,每个词向量60维。LRP算法计算结果shape = [8,60][8, 60][8,60],经过一个sum之后成了 [8,],即为每个词分配权值。
作者认为LSTM和GRU中存在2种运算,Weighted Connections和Multiplicative Interactions
2.2.1.Weighted Connections
下图红框展现上面LSTM图中的Weighted Connections部分
Weighted Connections中基础运算依旧是 y=σ(W.x+b)y = \sigma(W.x + b)y=σ(W.x+b),这里作者避免显式引入非线性激活函数,所以在论文中很多公式没有带激活函数,但是,如果有激活函数,那么激活值采用激活函数之后的。假设前向计算有 zj=∑izi.ωij+bjz_j = \sum_i z_i. \omega_{ij} + b_jzj=∑izi.ωij+bj,这里如果引入激活函数,zjz_jzj 就是被激活函数激活后的值,iii 是 jjj 的前置神经元,LRP针对 jjj 的relevance计算结果为 RjR_jRj,那么 j→ij \rightarrow ij→i 的relevance 。
Ri←j=zi.ωij+ϵ.sign(zi)+δ.bjNzj+ϵ.sign(zj).RjR_{i \leftarrow j} = \frac{z_i.\omega_{ij} + \frac{\epsilon . sign(z_i) + \delta.b_j}{N}}{z_j + \epsilon.sign(z_j)}.R_j Ri←j=zj+ϵ.sign(zj)zi.ωij+Nϵ.sign(zi)+δ.bj.Rj
Ri=∑jRi←jR_i = \sum_j R_{i \leftarrow j} Ri=j∑Ri←j
这里作者设置 ϵ=0.001,δ=1.0,N\epsilon = 0.001, \delta = 1.0, Nϵ=0.001,δ=1.0,N 是对应神经网络层拥有的神经元数量,signsignsign 函数就是非负转1,负转-1的函数。
这里记 Rj→RiR_j \rightarrow R_iRj→Ri 为 LLLLLL (LRP_Linear)
2.2.2.Multiplicative Interactions
Multiplicative Interactions这个概念要和RNN中门的概念结合起来,下面红框框出的是Multiplicative Interactions部分。
LSTM和GRU中还有一种计算: zj=zg.zsz_j = z_g . z_szj=zg.zs。通常称为门,上图红框框出的部分,通常一个操作数值在 [0,1][0, 1][0,1] 之间(连接sigmoid),起到一个门的作用,作者称之为 gate neuron zgz_gzg,另一个称为 source neuron zsz_szs。
- 在 Ct−1×ftC_{t - 1} \times f_tCt−1×ft 中,ftf_tft 为 zgz_gzg,Ct−1C_{t - 1}Ct−1 为 zsz_szs。
- 在 it×gti_t \times g_tit×gt 中,iti_tit 为 zgz_gzg,gtg_tgt 为 zsz_szs。
- 在 ot×tanh(Ct)o_t \times tanh(C_t)ot×tanh(Ct) 中,oto_tot 为 zgz_gzg,tanh(Ct)tanh(C_t)tanh(Ct) 为 zsz_szs。
对于这种情况
- Rs=RjR_s = R_jRs=Rj
- Rg=0R_g = 0Rg=0
等于说在反向运算的时候,绿线标出部分直接清零,计算流图就不包括绿线部分了。Weighted Connections部分只有tanh激活函数参与反向计算。
所以对于上述计算过程可以总结成(无视激活函数,给定 RCt,RhtR_{C_t}, R_{h_t}RCt,Rht):
- RCt−1=RCt−1×ft=LL(Ct−1×ft,RCt+Rht)∈RdR_{C_{t - 1}} = R_{C_{t - 1} \times f_t} = LL(C_{t - 1} \times f_t, R_{C_t} + R_{h_t}) \in R^dRCt−1=RCt−1×ft=LL(Ct−1×ft,RCt+Rht)∈Rd
- Rgt=Rgt×it=LL(gt×it,RCt+Rht)∈RdR_{g_t} = R_{g_t \times i_t} = LL(g_t \times i_t, R_{C_t} + R_{h_t}) \in R^dRgt=Rgt×it=LL(gt×it,RCt+Rht)∈Rd
- Rht−1=LL(ht−1,Rgt)∈RdR_{h_{t - 1}} = LL(h_{t - 1}, R_{g_t}) \in R^dRht−1=LL(ht−1,Rgt)∈Rd
- Rxt=LL(xt,Rgt)∈RdR_{x_t} = LL(x_t, R_{g_t}) \in R^dRxt=LL(xt,Rgt)∈Rd
在 RRR 向量初始化上,模型最终输出向量 c=Wleft.hleftT+Wright.hrightTc = W_{left} . h_{left}^T + W_{right}. h_{right}^Tc=Wleft.hleftT+Wright.hrightT,这是个5分类任务,如果目标类别是2,那么 Rc=[0,0,1,0,0]R^c = [0, 0, 1, 0, 0]Rc=[0,0,1,0,0] ,其余均初始化0。
2.2.作者代码
LRP
函数:
def lrp(self, w, LRP_class, eps=0.001, bias_factor=0.0):"""Layer-wise Relevance Propagation (LRP) backward pass.Compute the hidden layer relevances by performing LRP for the target class LRP_class(according to the papers:- https://doi.org/10.1371/journal.pone.0130140- https://doi.org/10.18653/v1/W17-5221 )"""# forward passself.set_input(w)self.forward() T = len(self.w)d = int(self.Wxh_Left.shape[0]/4)e = self.E.shape[1] C = self.Why_Left.shape[0] # number of classesidx = np.hstack((np.arange(0,d), np.arange(2*d,4*d))).astype(int) # indices of gates i,f,o togetheridx_i, idx_g, idx_f, idx_o = np.arange(0,d), np.arange(d,2*d), np.arange(2*d,3*d), np.arange(3*d,4*d) # indices of gates i,g,f,o separately# initializeRx = np.zeros(self.x.shape)Rx_rev = np.zeros(self.x.shape)Rh_Left = np.zeros((T+1, d))Rc_Left = np.zeros((T+1, d))Rg_Left = np.zeros((T, d)) # gate g onlyRh_Right = np.zeros((T+1, d))Rc_Right = np.zeros((T+1, d))Rg_Right = np.zeros((T, d)) # gate g onlyRout_mask = np.zeros((C))Rout_mask[LRP_class] = 1.0 # format reminder: lrp_linear(hin, w, b, hout, Rout, bias_nb_units, eps, bias_factor)Rh_Left[T-1] = lrp_linear(self.h_Left[T-1], self.Why_Left.T , np.zeros((C)), self.s, self.s*Rout_mask, 2*d, eps, bias_factor, debug=False)Rh_Right[T-1] = lrp_linear(self.h_Right[T-1], self.Why_Right.T, np.zeros((C)), self.s, self.s*Rout_mask, 2*d, eps, bias_factor, debug=False)for t in reversed(range(T)):Rc_Left[t] += Rh_Left[t]Rc_Left[t-1] = lrp_linear(self.gates_Left[t,idx_f]*self.c_Left[t-1], np.identity(d), np.zeros((d)), self.c_Left[t], Rc_Left[t], 2*d, eps, bias_factor, debug=False)Rg_Left[t] = lrp_linear(self.gates_Left[t,idx_i]*self.gates_Left[t,idx_g], np.identity(d), np.zeros((d)), self.c_Left[t], Rc_Left[t], 2*d, eps, bias_factor, debug=False)Rx[t] = lrp_linear(self.x[t], self.Wxh_Left[idx_g].T, self.bxh_Left[idx_g]+self.bhh_Left[idx_g], self.gates_pre_Left[t,idx_g], Rg_Left[t], d+e, eps, bias_factor, debug=False)Rh_Left[t-1] = lrp_linear(self.h_Left[t-1], self.Whh_Left[idx_g].T, self.bxh_Left[idx_g]+self.bhh_Left[idx_g], self.gates_pre_Left[t,idx_g], Rg_Left[t], d+e, eps, bias_factor, debug=False)Rc_Right[t] += Rh_Right[t]Rc_Right[t-1] = lrp_linear(self.gates_Right[t,idx_f]*self.c_Right[t-1], np.identity(d), np.zeros((d)), self.c_Right[t], Rc_Right[t], 2*d, eps, bias_factor, debug=False)Rg_Right[t] = lrp_linear(self.gates_Right[t,idx_i]*self.gates_Right[t,idx_g], np.identity(d), np.zeros((d)), self.c_Right[t], Rc_Right[t], 2*d, eps, bias_factor, debug=False)Rx_rev[t] = lrp_linear(self.x_rev[t], self.Wxh_Right[idx_g].T, self.bxh_Right[idx_g]+self.bhh_Right[idx_g], self.gates_pre_Right[t,idx_g], Rg_Right[t], d+e, eps, bias_factor, debug=False)Rh_Right[t-1] = lrp_linear(self.h_Right[t-1], self.Whh_Right[idx_g].T, self.bxh_Right[idx_g]+self.bhh_Right[idx_g], self.gates_pre_Right[t,idx_g], Rg_Right[t], d+e, eps, bias_factor, debug=False)return Rx, Rx_rev[::-1,:], Rh_Left[-1].sum()+Rc_Left[-1].sum()+Rh_Right[-1].sum()+Rc_Right[-1].sum()
lrp_linear
函数
def lrp_linear(hin, w, b, hout, Rout, bias_nb_units, eps, bias_factor=0.0, debug=False):"""LRP for a linear layer with input dim D and output dim M.Args:- hin: forward pass input, of shape (D,)- w: connection weights, of shape (D, M)- b: biases, of shape (M,)- hout: forward pass output, of shape (M,) (unequal to np.dot(w.T,hin)+b if more than one incoming layer!)- Rout: relevance at layer output, of shape (M,)- bias_nb_units: total number of connected lower-layer units (onto which the bias/stabilizer contribution is redistributed for sanity check)- eps: stabilizer (small positive number)- bias_factor: set to 1.0 to check global relevance conservation, otherwise use 0.0 to ignore bias/stabilizer redistribution (recommended)Returns:- Rin: relevance at layer input, of shape (D,)"""sign_out = np.where(hout[na,:]>=0, 1., -1.) # shape (1, M)numer = (w * hin[:,na]) + ( bias_factor * (b[na,:]*1. + eps*sign_out*1.) / bias_nb_units ) # shape (D, M)# Note: here we multiply the bias_factor with both the bias b and the stabilizer eps since in fact# using the term (b[na,:]*1. + eps*sign_out*1.) / bias_nb_units in the numerator is only useful for sanity check# (in the initial paper version we were using (bias_factor*b[na,:]*1. + eps*sign_out*1.) / bias_nb_units instead)denom = hout[na,:] + (eps*sign_out*1.) # shape (1, M)message = (numer/denom) * Rout[na,:] # shape (D, M)Rin = message.sum(axis=1) # shape (D,)if debug:print("local diff: ", Rout.sum() - Rin.sum())# Note:# - local layer relevance conservation if bias_factor==1.0 and bias_nb_units==D (i.e. when only one incoming layer)# - global network relevance conservation if bias_factor==1.0 and bias_nb_units set accordingly to the total number of lower-layer connections# -> can be used for sanity checkreturn Rin
lrp_linear
针对神经网络中每一个线性操作 y=W.x+by = W.x + by=W.x+b,给定 yyy 处relevance RyR_yRy,计算 xxx 处值 RxR_xRx,numer
对应 zi.ωij+ϵ.sign(zi)+δ.bjNz_i.\omega_{ij} + \frac{\epsilon . sign(z_i) + \delta.b_j}{N}zi.ωij+Nϵ.sign(zi)+δ.bj,denom
对应 zj+ϵ.sign(zj)z_j + \epsilon.sign(z_j)zj+ϵ.sign(zj)。
回到LRP
函数,针对 Ct,ht=LSTMCell(Ct−1,ht−1,xt)C_t, h_t = LSTMCell(C_{t - 1}, h_{t - 1}, x_t)Ct,ht=LSTMCell(Ct−1,ht−1,xt),,给定 CtC_tCt 的relevance值 RCtR_{C_t}RCt 和 hth_tht 的relevance值 RhtR_{h_t}Rht ,需要计算 Rxt,Rht−1,RCt−1R_{x_t}, R_{h_{t - 1}}, R_{C_{t - 1}}Rxt,Rht−1,RCt−1。相应计算如下:
Rc_Left[t] += Rh_Left[t]
Rc_Left[t-1] = lrp_linear(self.gates_Left[t,idx_f]*self.c_Left[t-1], np.identity(d), np.zeros((d)), self.c_Left[t], Rc_Left[t], 2*d, eps, bias_factor, debug=False)
Rg_Left[t] = lrp_linear(self.gates_Left[t,idx_i]*self.gates_Left[t,idx_g], np.identity(d), np.zeros((d)), self.c_Left[t], Rc_Left[t], 2*d, eps, bias_factor, debug=False)
Rx[t] = lrp_linear(self.x[t], self.Wxh_Left[idx_g].T, self.bxh_Left[idx_g]+self.bhh_Left[idx_g], self.gates_pre_Left[t,idx_g], Rg_Left[t], d+e, eps, bias_factor, debug=False)
Rh_Left[t-1] = lrp_linear(self.h_Left[t-1], self.Whh_Left[idx_g].T, self.bxh_Left[idx_g]+self.bhh_Left[idx_g], self.gates_pre_Left[t,idx_g], Rg_Left[t], d+e, eps, bias_factor, debug=False)
再给一个LSTM图
红色线条表示 RCt−1R_{C_{t - 1}}RCt−1 和 RgtR_{g_t}Rgt 的计算流程,绿色线条表示 RxtR_{x_t}Rxt 和 Rht−1R_{h_{t - 1}}Rht−1 的计算流程。
三.扩展到GRU
3.1.GRU
流程如下:
涉及到的输入和模型参数:
- xt∈Rex_t \in R^ext∈Re
- ht∈Rdh_t \in R^dht∈Rd
- Wr,Wz,Wh∈R(d+e)×dW_r, W_z, W_h \in R^{(d + e) \times d}Wr,Wz,Wh∈R(d+e)×d
- br,bz,bh∈Rdb_r, b_z, b_h \in R^dbr,bz,bh∈Rd
- rt,zt,h~t∈Rdr_t, z_t, \widetilde h_t \in R^drt,zt,ht∈Rd
计算过程:
- rt=σ(Wr.[ht−1;xt]+br)r_t = \sigma(W_r.[h_{t - 1}; x_t] + b_r)rt=σ(Wr.[ht−1;xt]+br)
- zt=σ(Wz.[ht−1;xt]+bz)z_t = \sigma(W_z.[h_{t - 1}; x_t] + b_z)zt=σ(Wz.[ht−1;xt]+bz)
- h~t=tanh(Wh.[rt×ht−1;xt]+bh)\widetilde h_t = tanh(W_h.[r_t \times h_{t-1}; x_t] + b_h)ht=tanh(Wh.[rt×ht−1;xt]+bh)
- ht=(1−zt)×ht−1+zt×h~th_t = (1 - z_t) \times h_{t - 1} + z_t \times \widetilde h_tht=(1−zt)×ht−1+zt×ht
3.2.GRU的Relevance计算部分
按照前面的理论,RxtR_{x_t}Rxt 和 Rht−1R_{h_{t-1}}Rht−1 的计算过程按绿线所示反向进行,因为红框乘法部分 zgz_gzg 会被忽略掉,所以指挥按一个流程进行。
四.参考文献
[1] Arras, L. , et al. “Explaining Recurrent Neural Network
Predictions in Sentiment Analysis.” EMNLP’17 Workshop on Computational
Approaches to Subjectivity, Sentiment & Social Media Analysis 2017.
可解释性研究 -LRP-for-LSTM相关推荐
- 可解释性(1)—— lstm可视化工具LSTMVis
一.背景 深度模型成绩斐然,然而它就像一个黑箱子一样捉摸不透,使用者不知道它到底学到了些什么,也不知道它有什么凭据作出那样的预测,更不知道如何根据bad case去调特征,虽然能总结出几类bad ca ...
- A Survey on Neural Network Interpretability (神经网络的可解释性研究综述)
A Survey on Neural Network Interpretability 摘要 Ⅰ 引言 A 可解释性的(扩展)定义 B 可解释性的重要性 C 相关工作及贡献 D 综述组织结构 Ⅱ 分类 ...
- 万字长文概览深度学习的可解释性研究
↑ 点击蓝字 关注视学算法 作者丨王小贱@知乎 来源丨https://www.zhihu.com/column/buaabigcity 编辑丨极市平台 本文仅用于学术分享,如有侵权,请联系后台作删文处 ...
- 详解深度学习的可解释性研究(上篇)
作者 | 王小贱 来源 | BIGSCity知乎专栏 摘要:<深度学习的可解释性研究>系列文章希望能用尽可能浅显的语言带领大家了解可解释性的概念与方法,以及关于深度学习可解释性工作的研究成 ...
- 上海交大张拳石:神经网络的变量交互可解释性研究
文 | Qs.Zhang张拳石@知乎 可解释性研究一直有两副嘴脸,一副烈火烹油繁花似锦,一副如履薄冰零丁洋里叹零丁. 在2018年我开始发知乎是为了"活着"--被刷榜为王的风气屡屡 ...
- 干货 | 深度学习的可解释性研究(一):让模型「说人话」
在这篇文章中: 可解释性是什么? 我们为什么需要可解释性? 有哪些可解释性方法? 在建模之前的可解释性方法 建立本身具备可解释性的模型 在建模之后使用可解释性性方法作出解释 关于 BIGSCity 参 ...
- 可解释性研究(一)- GNNExplainer
GNNExplainer: Generating Explanationsfor Graph Neural Networks 1.问题描述 1.1. GNN背景 1.2. GNNExplainer:问 ...
- 深度学习可解释性研究(二): Understanding Black-box Predictions via Influence Functions(详细公式推导)
该文章从鲁棒性的角度出发,对深度学习模型的可解释性进行分析,这应该是我目前为止读过最难的一篇文章,有很多公式需要推导理解,有很多细节需要慢慢品味,但文章确实是难得一见的好文章,我会尽可能把我自己的理解 ...
- 研究lRP大佬提供的EHP虚拟机的时候的一点门道
记录1 今天把新买的SSD安上去 然后解压出来 了EHP8 但是在虚拟机启动的过程中发现了一些奇怪的地方 LRP SAP0 启动的时候始终是黄色的 目前调整后变成绿色 经过查询 得知需要在HOST ...
最新文章
- python连接oracle数据库_Python连接oracle数据库 例子一
- python处理excel-使用python将数据写入excel
- Windows 10 [ ERROR ] Can not init Myriad device: NC_ERROR Error
- cmd写java程序_用cmd写一个最简单的Java程序
- 人机协作机器人发展趋势_移动机器人:人机协作是未来的发展趋势
- loadrunner中对https证书的配置
- 计算机应用基础课程整体设计说课视频,计算机应用基础说课稿
- jdk1.5新特性5之枚举之模拟枚举类型
- 大数据分块_谷歌卫星影像金字塔分块下载原理说明
- 如何获得查询的执行计划?(一)
- ECS Linux 服务器解除ssh登陆后被锁定或暂停输入输出的终端
- 王者峡谷一呼百应,弹幕“666”,背后都离不开长连接,如何实现千万级高性能的长连接网关?...
- Qt 实现Windows系统Win10 c++音量调节
- 浅谈java实现桌面小程序
- 从基础接口工具postman开始夯实软件测试基础(一)
- html5 3d场景设计,基于 HTML5 WebGL 的加油站 3D 可视化监控
- 军犬舆情热点:千亿矿权案成立联合调查组;格力人均加薪1000元
- 利用手机作为渗透工具的一些思路
- 微信营销吸粉秘籍之:360谈谈
- A - 卡牌游戏 III