当前位置:   article > 正文

使用keras.layers.Reshape实现不同维度任意层之间的对接

layers.reshape

1. 引入

keras提供了很多不同的layer给我们使用,常用的比如Dense, Dropout, Flatten, Activation, BatchNormalization, GlobalAveragePooling2D,Conv2D, MaxPooling2D, ZeroPadding2D,LSTM等等。我们使用这些layer,像搭积木一样逐层链接,就能实现深度学习模型。

但是,keras提供的layer都是传统的layer。有一些比较新的layer,keras是不能那么快提供给我们用的。所以一些比较特别的layer,我们还是会去github上找到其他开发者写好的拿来用。

那么,问题就来了,这些第三方提供的layer,和keras提供的layer,对接到一起时,常常是会报错的。大部分情况下,这样直接的对接layer,会得到这个错误:ValueError: Dimensions must be equal。

错误的原因,是因为第三方的layer,可能已经写死了要一个2D的输入,但我们keras输出的layer数据维度可能是3D的,所以维度不匹配。

那我们应该怎么样把不同类型的layer,正确的对接到一起组成模型呢?用keras.layers.Reshape就能很好的解决这样的问题。下面以一个实际案例进行阐述。

2. 案例

  1. 案例目标

我们这里的目标,是用keras构建一个模型,把Attention层接入到CNN层的后面。也就是实现Attention层对接到模型的任意位置。

  1. Attention

Attention层使用第三方的工具包:https://pypi.org/project/keras-self-attention/

  1. 训练数据

使用numpy的random生成随机的训练数据:

import numpy as np

num_classes = 6 # classification number
x_train = np.random.randn(100, 15, 20, 3) # x_train.shape = (100, 15, 20, 3)
y_train = np.random.randint(1, size=(100,num_classes)) # y_train.shape = (100, 6)
input_shape = x_train.shape[-3:]# (15, 20, 3)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

数据的维度见代码中的注释。

  1. 构建模型

首先建立CNN模型,然后在CNN后面加上SeqSelfAttention层。具体代码如下:

from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras_self_attention import SeqSelfAttention
import keras

model = Sequential()
model.add(Conv2D(32, (2,11), activation='relu', padding='same', input_shape=input_shape))
model.add(Conv2D(32, (2,11), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 1)))
model.add(Conv2D(128, (2,7), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 1)))
model.add( SeqSelfAttention( attention_type=SeqSelfAttention.ATTENTION_TYPE_MUL) )
model.add(Flatten())
model.add(Dense(440, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()                            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  1. 报错

上面的代码是会报错的,模型不能直接这样构建。报错信息如下:

    ValueError: Dimensions must be equal, but are 128 and 16 for '{{node seq_self_attention/MatMul}} = MatMul[T=DT_FLOAT, transpose_a=false, transpose_b=false](seq_self_attention/Reshape, seq_self_attention/Reshape_1)' with input shapes: [?,128], [16,16].
  • 1

分析:这种错误,一般就是进行计算的多个矩阵的维度不匹配。比如两个矩阵相乘,必须要满足一定的维度要求。

我们也可以看到,报错的具体位置,是CNN后面加入Attention的那行代码:

---> 23 model.add( SeqSelfAttention( attention_type=SeqSelfAttention.ATTENTION_TYPE_MUL) )

  • 1
  • 2

3. 使用keras.layers.Reshape实现不同层的良好对接

根据如上报错(及报错的位置),可知是SeqSelfAttention上一层的输出数据维度,与SeqSelfAttention要求的输入数据维度不匹配。所以需要让数据进入SeqSelfAttention之前,做一个Reshape。

把模型部分的代码改为:

model = Sequential()
model.add(Conv2D(32, (2,11), activation='relu', padding='same', input_shape=input_shape))
model.add(Conv2D(32, (2,11), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 1)))
model.add(Conv2D(128, (2,7), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 1)))
model.add( keras.layers.Reshape((5,128)) )
model.add( SeqSelfAttention( attention_type=SeqSelfAttention.ATTENTION_TYPE_MUL) )
model.add(Flatten())
model.add(Dense(440, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

至于keras.layers.Reshape的具体shape,先随便设置一个值,这里设置的是(5,128)。运行程序,得到报错如下:

ValueError: total size of new array must be unchanged, input_shape = [3, 16, 128], output_shape = [5, 128]

  • 1
  • 2

从这个报错中,可以知道,输入Reshape的数据维度是[3, 16, 128],所以Reshape后的数据维度,也必须等于3x16x128。而我们刚才设置的(5,128),5x128是不等于3x16x128的。

把(5,128)改为(48,128),模型就够构建成功了。修改后能正确运行的完整代码如下:

from keras.models import Sequential
from keras.layers import Dense, Dropout, Flatten
from keras.layers import Conv2D, MaxPooling2D
from keras_self_attention import SeqSelfAttention
import keras
import numpy as np

num_classes = 6 # classification number
x_train = np.random.randn(100, 15, 20, 3) # x_train.shape = (100, 15, 20, 3)
y_train = np.random.randint(1, size=(100,num_classes)) # y_train.shape = (100, 6)
input_shape = x_train.shape[-3:]# (15, 20, 3)


model = Sequential()
model.add(Conv2D(32, (2,11), activation='relu', padding='same', input_shape=input_shape))
model.add(Conv2D(32, (2,11), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 1)))
model.add(Conv2D(128, (2,7), activation='relu', padding='same'))
model.add(MaxPooling2D(pool_size=(3, 3), strides=(2, 1)))
model.add( keras.layers.Reshape((48,128)) )
model.add( SeqSelfAttention( attention_type=SeqSelfAttention.ATTENTION_TYPE_MUL) )
model.add(Flatten())
model.add(Dense(440, activation='relu'))
model.add(Dropout(0.5))
model.add(Dense(num_classes, activation='softmax'))
model.compile(loss='categorical_crossentropy', optimizer='adam')
model.summary()                            
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27

4. 总结

本文提供了一种方式,从技术上,使用keras.layers.Reshape实现keras不同层的对接。但要注意的是,它毕竟改变了数据的维度,也就改变了数据的组成方式,这可能会对后续的识别产生影响。而这种影响必须要根据情况具体分析。

5. 参考

  1. https://keras.io/zh/layers/core/
  2. https://stackoverflow.com/questions/49628739/reshaping-keras-layers
  3. https://blog.csdn.net/u014535666/article/details/106183386
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/你好赵伟/article/detail/94446
推荐阅读
相关标签
  

闽ICP备14008679号