python3extract_model.py对应代码解读抽取式提取+⽣成式提取摘要代码解。。
沃尔沃xc40
extract_model.py对⽂本进⾏向量化操作的过程解读
由之前extract_vectorize.py保存权重说起
之前extract_vectorize.py之中的
np.save(data_extract_npy, embeddings)
是将输出的权重内容保存到对应的⽂件之中,这⾥extract_model.py之中⾸先将先前保存的内容读取出来
data = load_data(data_extract_json)
data_x = np.load(data_extract_npy)
data_y = np.zeros_like(data_x[...,:1])
这⾥的data是之前抽取的data,还是data[0]为切分出来的字符串,data[1]为对应的下标,data[2]为正式的summaries⽂本字符串
⾸先解读这⾥的data_x[…,:1]的操作
⽤类似的案例来解读⼀下这⾥进⾏的截取的操作
import tensorflow as tf
import numpy as np
a = np.array([[[1,2,21],[3,4,34]],[[5,6,56],[7,8,78]]])
print('a.shape:',a.shape)
b = a[...,0:2]
print('b :',b)
print('shape.b:',b.shape)
得到的结果如下:
a.shape: (2, 2, 3)
b : [[[1 2]
[3 4]]
[[5 6]
[7 8]]]
shape.b: (2, 2, 2)
可以看出,这⾥的
b = a[...,0:2]
是截取的最后⼀维的0开始的两个数值,得到的b的结果
如果操作为
a = np.array([[[1,2,21],[3,4,34]],[[5,6,56],[7,8,78]]])
b = a[ (1)
只取出⼀个,得到的坐标会减少⼀维
得到的b的结果为
a.shape = (2,2,3)
b: [[2 4]
[6 8]]
shape.b: (2,2)
如果想要只取出⼀个数值并且最后得到的结果保持不变,则写法应该像作者所写的那样,在1的前⾯加上⼀个冒号
data_y = np.zeros_like(data_x[...,:1])
汽车座垫然后进⼊对于data的循环处理之中
for i, d in enumerate(data):
for j in d[1]:
j =int(j)
data_y[i, j]=1
这⾥的i,j依次代表第⼀维,第⼆维的参数,[i,j]引申起来之后可以不仅仅代表⼀个对应的数值,也可以代表⼀整个list
import numpy as np
data = np.array([[2,2],[2,2]])
data[0]=1
这⾥得到的结果为
data =
[[1 1]
[2 2]]
原因在于在使⽤data[0] = 1的时候,指向的是[2,2]这整个list,所以整个list都会变成1
车辆防盗同理,这⾥的data_y[i,j]指向的是第(i,j)个位置的list,数值为[0],这⾥标记为data_y[i,j] = 1之后[0]变换为[1],这⾥同样为整个list的变换过程
接下来,为了弄清楚抽取⽂本这部分是如何学习的,我们需要弄明⽩前⾯预测是如何得来的
(具体内容详见上⼀篇博客⽂章,这⾥简单概述⼀下,就是(256,80)->(256,80,768)->(256,768)
(117,82)->(117,82,768)->(117,768)
最后这⽆数的向量拼在⼀起,并且如果第⼀维如果没有到达最长长度的时候,补充零矩阵,最终的结果为
(20,256,768)
)
⽽这⾥的data_y初始化全为零矩阵,如果这⼀句话被选中为能够作为摘要的备选句⼦,则将对应的标
志置为0,256代表每⼀个摘要总共有256个句⼦,这⾥的train_y = (20,256,1),代表着总共20个摘要,每个摘要256个句⼦,每个句⼦1个标签
观察train_x到train_y的模型
其实
data = load_data(data_extract_json)
这⼀波操作没有什么⽤,这⼀个现象我们从训练过程中就能看到,主要是train_x到train_y的操作过程
这⾥切出来的train_x = (18,256,768)
model.fit(
train_x,
train_y,
epochs=epochs,
batch_size=batch_size,
callbacks=[evaluator]
)
对应经历过的⽹络层结构如下所⽰:
x = Masking()(x)
x = Dropout(0.1)(x)
#x = (18,256,768)
x = Dense(hidden_size, use_bias=False)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = ResidualGatedConv1D(hidden_size,3, dilation_rate=1)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = ResidualGatedConv1D(hidden_size,3, dilation_rate=2)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = ResidualGatedConv1D(hidden_size,3, dilation_rate=4)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = ResidualGatedConv1D(hidden_size,3, dilation_rate=8)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = ResidualGatedConv1D(hidden_size,3, dilation_rate=1)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = ResidualGatedConv1D(hidden_size,3, dilation_rate=1)(x)
x = Dropout(0.1)(x)
#x = (18,256,384)
x = Dense(1, activation='sigmoid')(x)
#x = (18,256,1)
这⾥的keras.Masking()⽹络层的作⽤,我写了⼀段代码测试了⼀下:
from keras.layers import*
import numpy as np
dels import Model
import tensorflow as tf
data = tf.convert_to_tensor([[1,1,1,2,3],[1,1,0,0,0]],dtype=tf.float32)
x_in = Input(shape=(None,5))
x_out = Masking()(x_in)
model = Model(x_in,x_out)
data = model(data)
print('data = ')
print(data)
sess = tf.InteractiveSession()
长租车
print(data.eval())
得到的结果
data =
Tensor("model_1/masking_1/mul:0", shape=(2, 5), dtype=float32)
[[1. 1. 1. 2. 3.]高速公路过路费查询
[1. 1. 0. 0. 0.]]
感觉这⾥输出的内容没有具体的变化
Masking⽹络层的源码解读
Masking对应的⽹络层结构在keras中的core.py中的Masking之中,查看定义
class Masking(Layer):
"""Masks a sequence by using a mask value to skip timesteps.
If all features for a given sample timestep are equal to `mask_value`,
then the sample timestep will be masked (skipped) in all downstream layers
(as long as they support masking).
If any downstream layer does not support masking yet receives such
an input mask, an exception will be raised.
# Example
Consider a Numpy data array `x` of shape `(samples, timesteps, features)`,
to be fed to an LSTM layer.
You want to mask sample #0 at timestep #3, and sample #2 at timestep #5,
because you lack features for these sample timesteps. You can do:
- set `x[0, 3, :] = 0.` and `x[2, 5, :] = 0.`
- insert a `Masking` layer with `mask_value=0.` before the LSTM layer:
```python
model = Sequential()
model.add(Masking(mask_value=0., input_shape=(timesteps, features)))
model.add(LSTM(32))
```
# Arguments
mask_value: Either None or mask value to skip
"""
def__init__(self, mask_value=0.,**kwargs):
super(Masking, self).__init__(**kwargs)
self.supports_masking =True
self.mask_value = mask_value
def compute_mask(self, inputs, mask=None):
output_mask = K._equal(inputs, self.mask_value), axis=-1)
return output_mask
def call(self, inputs):
boolean_mask = K._equal(inputs, self.mask_value),
axis=-1, keepdims=True)
return inputs * K.cast(boolean_mask, K.dtype(inputs))
def get_config(self):
config ={'mask_value': self.mask_value}
base_config =super(Masking, self).get_config()
return dict(list(base_config.items())+list(config.items()))
def compute_output_shape(self, input_shape):
return input_shape
这⾥发现mask对于⽹络层的结构很重要
最常见的⼀种情况, 在NLP问题的句⼦补全⽅法中, 按照⼀定的长度, 对句⼦进⾏填补和截取操作. ⼀般使⽤keras.preprocessing.sequence 包中的pad_sequences⽅法, 在句⼦前⾯或者后⾯补0. 但是这些零是我们不需要的, 只是为了组成可以计算的结构才填补的. 因此计算过程中, 我们希望⽤mask的思想, 在计算中, 屏蔽这些填补0值得作⽤. keras中提供了mask相关的操作⽅法.
也就是说,我们填充的0值为了不影响后续的操作,必须使⽤mask将⾃⼰加上的0值掩盖掉,这点是之前我⼀直忽略的。
复习keras中的compute_mask函数
如果你看到⼀个⽹络层的call函数如下所⽰:
class MultiHeadAttention(keras.layers.Layer):
def__init__():
def call(self,inputs,mask=None,**kwargs):
发现调⽤的时候mask并不为None,但却不到mask定义的位置,有可能是前⾯的⽹络层调⽤了mask内容。
def compute_mask(self,inputs,mask=None):
if not self.mask_zero:
return None
output_mask = K.not_equal(inputs,0)
return output_mask
前⾯定义的mask会⼀直传下去,不断地向下⾯的⽹络层进⾏传递。
这⾥我们通过⼀个例⼦来说明mask的作⽤
import numpy as np
data = np.array([[[1,2,3,0,0],
[1,2,3,4,5]]])
masks = np.array([[[True],[False]]])
荣光result = data*masks
print('result = ')
print(result)
结果为
result =
[[[1 2 3 0 0]
[0 0 0 0 0]]]
可以看出,由于第⼆个id为False,所以第⼆个向量[1,2,3,4,5]相乘之后被全部置0了,如果数值为后⾯的补零数值的话,这⾥输出的共有768个维度,通过这⼀操作之后768个维度将被全部置0。
继续⽹络结构的代码解读
接下来越过⼀个Dense的⽹络层
x = Dense(hidden_size,use_bias=False)(x)
x = Dropout(0.1)(x)
得到x的对应维度(18,256,384)
接下来进⼊⼀个作者定义的ResidualGatedConv1D⽹络层门控卷积的神经⽹络层之中