1. 程式人生 > 程式設計 >Keras實現支援masking的Flatten層程式碼

Keras實現支援masking的Flatten層程式碼

不知道為什麼,我總是需要實現某種騷操作,而這種騷操作往往是Keras不支援的。例如,我有一個padding過的矩陣,那麼它一定是帶masking的,然後我想要把它Flatten,再輸入到Dense層。然而Keras的Flatten層不支援masking。

Keras原本Flatten的實現

class Flatten(Layer):
 def __init__(self,**kwargs):
  super(Flatten,self).__init__(**kwargs)
  self.input_spec = InputSpec(min_ndim=3)

 def compute_output_shape(self,input_shape):
  if not all(input_shape[1:]):
   raise ValueError('The shape of the input to "Flatten" '
        'is not fully defined '
        '(got ' + str(input_shape[1:]) + '. '
        'Make sure to pass a complete "input_shape" '
        'or "batch_input_shape" argument to the first '
        'layer in your model.')
  return (input_shape[0],np.prod(input_shape[1:]))

 def call(self,inputs):
  return K.batch_flatten(inputs)

自定義支援masking的實現

事實上,Keras層的mask有時候是需要參與運算的,比如Dense之類的,有時候則只是做某種變換然後傳遞給後面的層。Flatten屬於後者,因為mask總是與input有相同的shape,所以我們要做的就是在compute_mask函式裡對mask也做flatten。

from keras import backend as K
from keras.engine.topology import Layer
import tensorflow as tf
import numpy as np

class MyFlatten(Layer):
 def __init__(self,**kwargs):
  self.supports_masking = True
  super(MyFlatten,self).__init__(**kwargs)

 def compute_mask(self,inputs,mask=None):
  if mask==None:
   return mask
  return K.batch_flatten(mask)

 def call(self,mask=None):
  return K.batch_flatten(inputs)

 def compute_output_shape(self,input_shape):
  return (input_shape[0],np.prod(input_shape[1:]))

正確性檢驗

from keras.layers import *
from keras.models import Model
from MyFlatten import MyFlatten
from MySumLayer import MySumLayer
from keras.initializers import ones

data = [[1,0],[1,2,3,4]]

A = Input(shape=[4]) # None * 4
emb = Embedding(5,mask_zero=True,embeddings_initializer=ones())(A) # None * 4 * 3
fla = MyFlatten()(emb) # None * 12
out = MySumLayer(axis=1)(fla) # None * 1

model = Model(inputs=[A],outputs=[out])
print model.predict(data)

輸出:

[ 3. 6. 9. 12.]

補充知識:pytorch中的reshape()、view()、transpose()和flatten()

1、torch.reshape()

reshape()可以由torch.reshape(),也可由torch.Tensor.reshape()呼叫

其作用是在不改變tensor元素數目的情況下改變tensor的shape

import torch
import numpy as np
a = np.arange(24)
b = a.reshape(4,2)
print(np.shape(a))
print(b,np.shape(b))

'''結果
(24,)
[[[ 0 1]
 [ 2 3]
 [ 4 5]]

 [[ 6 7]
 [ 8 9]
 [10 11]]

 [[12 13]
 [14 15]
 [16 17]]

 [[18 19]
 [20 21]
 [22 23]]] (4,2)
'''

2、view()

view()只可以由torch.Tensor.view()來呼叫

view()和reshape()在效果上是一樣的,區別是view()只能操作contiguous的tensor,且view後的tensor和原tensor共享儲存,reshape()對於是否contiuous的tensor都可以操作。

3、transpose()

torch.transpose(input,dim0,dim1) -> Tensor

將輸入資料input的第dim0維和dim1維進行交換

#官方例子
>>> x = torch.randn(2,3)
>>> x
tensor([[ 0.9068,1.8803,-0.5021],[-0.6576,0.6334,-0.8961]])
>>> torch.transpose(x,1)
tensor([[ 0.9068,-0.6576],[ 1.8803,0.6334],[-0.5021,-0.8961]])

4、flatten()

torch.flatten()的輸入是tensor

torch.flatten(input,start_dim=0,end_dim=-1) → Tensor

其作用是將輸入tensor的第start_dim維到end_dim維之間的資料“拉平”成一維tensor,

#官方例子
>>> t = torch.tensor([[[1,2],[3,4]],[[5,6],[7,8]]])
>>> torch.flatten(t)
tensor([1,4,5,6,7,8])
>>> torch.flatten(t,start_dim=1)
tensor([[1,4],[5,8]])

torch.nn.Flatten()可以理解為一種網路結構,類似Conv2d、Linear。一般放在卷積層和全連線層之間,將卷積層輸出“拉平”成一維,

>>> m = torch.nn.Sequential(
 torch.nn.Conv2d(1,32,1,1),torch.nn.Flatten(),torch.nn.Linear(160,10))
>>> m
Sequential(
 (0): Conv2d(1,kernel_size=(5,5),stride=(1,padding=(1,1))
 (1): Flatten()
 (2): Linear(in_features=160,out_features=10,bias=True)
)

以上這篇Keras實現支援masking的Flatten層程式碼就是小編分享給大家的全部內容了,希望能給大家一個參考,也希望大家多多支援我們。