使用基于 ConvLSTM2D 的 Keras 模型从较低的图像估计高分辨率图像
Posted
技术标签:
【中文标题】使用基于 ConvLSTM2D 的 Keras 模型从较低的图像估计高分辨率图像【英文标题】:Estimating high resolution images from lower ones using a Keras model based on ConvLSTM2D 【发布时间】:2018-09-01 03:19:13 【问题描述】:我正在尝试使用以下ConvLSTM2D
架构从低分辨率图像序列中估计高分辨率图像序列:
import numpy as np, scipy.ndimage, matplotlib.pyplot as plt
from keras.models import Sequential
from keras.layers import Dense, Dropout, Activation, Flatten
from keras.layers import Convolution2D, ConvLSTM2D, MaxPooling2D, UpSampling2D
from sklearn.metrics import accuracy_score, confusion_matrix, cohen_kappa_score
from sklearn.preprocessing import MinMaxScaler, StandardScaler
np.random.seed(123)
raw = np.arange(96).reshape(8,3,4)
data1 = scipy.ndimage.zoom(raw, zoom=(1,100,100), order=1, mode='nearest') #low res
print (data1.shape)
#(8, 300, 400)
data2 = scipy.ndimage.zoom(raw, zoom=(1,100,100), order=3, mode='nearest') #high res
print (data2.shape)
#(8, 300, 400)
X_train = data1.reshape(data1.shape[0], 1, data1.shape[1], data1.shape[2], 1)
Y_train = data2.reshape(data2.shape[0], 1, data2.shape[1], data2.shape[2], 1)
#(samples,time, rows, cols, channels)
model = Sequential()
input_shape = (data1.shape[0], data1.shape[1], data1.shape[2], 1)
#samples, time, rows, cols, channels
model.add(ConvLSTM2D(16, kernel_size=(3,3), activation='sigmoid',padding='same',input_shape=input_shape))
model.add(ConvLSTM2D(8, kernel_size=(3,3), activation='sigmoid',padding='same'))
print (model.summary())
model.compile(loss='mean_squared_error',
optimizer='adam',
metrics=['accuracy'])
model.fit(X_train, Y_train,
batch_size=1, epochs=10, verbose=1)
x,y = model.evaluate(X_train, Y_train, verbose=0)
print (x,y)
此声明将导致以下Value
错误:
ValueError: Input 0 is in compatible with layer conv_lst_m2d_2: expected ndim=5, found ndim=4
我该如何纠正这个ValueError
?我认为问题出在输入形状上,但无法弄清楚到底出了什么问题。
请注意,输出也应该是图像序列,而不是分类结果。
【问题讨论】:
【参考方案1】:发生这种情况是因为 LSTMs
需要时间数据,但您的第一个模型被声明为 many-to-one
模型,它输出形状为 (batch_size, 300, 400, 16)
的张量。也就是批量图片:
model.add(ConvLSTM2D(16, kernel_size=(3,3), activation='sigmoid',padding='same',input_shape=input_shape))
model.add(ConvLSTM2D(8, kernel_size=(3,3), activation='sigmoid',padding='same'))
您希望输出为形状为 (batch_size, 8, 300, 400, 16)
的张量(即图像序列),以便第二个 LSTM 可以使用它们。解决这个问题的方法是在第一个 LSTM 定义中添加return_sequences
:
model.add(ConvLSTM2D(16, kernel_size=(3,3), activation='sigmoid',padding='same',input_shape=input_shape,
return_sequences=True))
model.add(ConvLSTM2D(8, kernel_size=(3,3), activation='sigmoid',padding='same'))
你提到了分类。如果你缩进的是对整个序列进行分类,那么你需要一个分类器:
model.add(ConvLSTM2D(16, kernel_size=(3,3), activation='sigmoid',padding='same',input_shape=input_shape,
return_sequences=True))
model.add(ConvLSTM2D(8, kernel_size=(3,3), activation='sigmoid',padding='same'))
model.add(GlobalAveragePooling2D())
model.add(Dense(10, activation='softmax')) # output shape: (None, 10)
但是,如果您尝试对序列内中的每个图像进行分类,那么您可以简单地使用TimeDistributed
重新应用分类器:
x = Input(shape=(300, 400, 8))
y = GlobalAveragePooling2D()(x)
y = Dense(10, activation='softmax')(y)
classifier = Model(inputs=x, outputs=y)
x = Input(shape=(data1.shape[0], data1.shape[1], data1.shape[2], 1))
y = ConvLSTM2D(16, kernel_size=(3, 3),
activation='sigmoid',
padding='same',
return_sequences=True)(x)
y = ConvLSTM2D(8, kernel_size=(3, 3),
activation='sigmoid',
padding='same',
return_sequences=True)(y)
y = TimeDistributed(classifier)(y) # output shape: (None, 8, 10)
model = Model(inputs=x, outputs=y)
最后,看看 keras 存储库中的示例。有一个generative model using ConvLSTM2D。
编辑:从 data1 估计 data2...
如果我这次做对了,X_train
应该是 8 个 (300, 400, 1) 图像堆栈中的 1 个样本,而不是 1 个形状 (300, 400, 1) 图像堆栈中的 8 个样本.
如果是真的,那么:
X_train = data1.reshape(data1.shape[0], 1, data1.shape[1], data1.shape[2], 1)
Y_train = data2.reshape(data2.shape[0], 1, data2.shape[1], data2.shape[2], 1)
应更新为:
X_train = data1.reshape(1, data1.shape[0], data1.shape[1], data1.shape[2], 1)
Y_train = data2.reshape(1, data2.shape[0], data2.shape[1], data2.shape[2], 1)
另外,accuracy
在您的损失为 mse 时通常没有意义。您可以使用其他指标,例如 mae
。
现在你只需要更新你的模型以返回序列并在最后一层有一个单元(因为你试图估计的图像有一个通道):
model = Sequential()
input_shape = (data1.shape[0], data1.shape[1], data1.shape[2], 1)
model.add(ConvLSTM2D(16, kernel_size=(3, 3), activation='sigmoid', padding='same',
input_shape=input_shape,
return_sequences=True))
model.add(ConvLSTM2D(1, kernel_size=(3, 3), activation='sigmoid', padding='same',
return_sequences=True))
model.compile(loss='mse', optimizer='adam')
之后model.fit(X_train, Y_train, ...)
会正常开始训练:
Using TensorFlow backend.
(8, 300, 400)
(8, 300, 400)
Epoch 1/10
1/1 [==============================] - 5s 5s/step - loss: 2993.8701
Epoch 2/10
1/1 [==============================] - 5s 5s/step - loss: 2992.4492
Epoch 3/10
1/1 [==============================] - 5s 5s/step - loss: 2991.4536
Epoch 4/10
1/1 [==============================] - 5s 5s/step - loss: 2989.8523
【讨论】:
我不太明白你的评论。time
是时间暗淡,1
是输入通道数,是的。经过您声明的两个ConvLSTM2D
之后,输出形状将为(batch_size, time, 300, 400, 8)
,因为它正在返回序列并且最后一个LSTM
中有8 个单元。分类器接受形状为(batch_size, 300, 400, 8)
的输入,即成批的图像。包裹在TimeDistributed
周围,它将能够处理来自第二个ConvLSTM2D
的序列。
好的,所以有两个堆栈,你想融合它们。你想怎么做?您打算比较它们还是将它们连接起来?
哦,我明白了。我已经更新了答案以匹配您的图像估计任务。
这与您的原始问题略有不同,其中y_train
与x_train
具有相同的形状。我建议从最后一层删除return_sequences=True
(这会创建一个输出形状为(300, 400, 1)
的图像的模型)。请注意,y_train
需要从 (samples, 1, 300, 400, 1)
重新调整为 (samples, 300, 400, 1)
。如果这不能带来好的结果,那么也许保留return_sequences=True
并在最后添加一些Conv3d
层,这将通过卷积LSTM输出的(8, 300, 400)
特征空间产生图像。以上是关于使用基于 ConvLSTM2D 的 Keras 模型从较低的图像估计高分辨率图像的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Keras 中定义 ConvLSTM 编码器解码器?
基于Keras 的VGG16神经网络模型的Mnist数据集识别并使用GPU加速