Я пытаюсь создать 3D-Unet для изучения пространственных и спектральных характеристик по спутниковым снимкам для мультиклассовой классификации. Форма ввода - это (samples, image_height, image_width, band, channel), тогда как выходные данные - это только 2D-изображение и измерение вероятности для определенного класса ('categoryorical_crossentropy').
Формы ввода и вывода:
x_train.shape
# (samples = 200, image_height= 512, image_width = 512, bands= 64, channels = 1)
y_train.shape
# (samples= 200, image_height = 512, image_width 512, classes = 12)
Пока что я строю простой 3D-Unet с Keras, который дает мне вектор пространственных объектов 4D, где первые 3 измерения содержат трехмерные объекты, а четвертое измерение содержит вероятность 12 классов,
def conv_block3D(tensor, nfilters, size=3, padding='same', initializer="he_normal"):
x = Conv3D(filters=nfilters, kernel_size=(size, size,size), padding=padding)(tensor)
x = BatchNormalization()(x)
x = Activation("relu")(x)
x = Conv3D(filters=nfilters, kernel_size=(size, size,size), padding=padding)(x)
x = BatchNormalization()(x)
x = Activation("relu")(x)
return x
def deconv_block3D(tensor, residual, nfilters, size=3, padding='same', strides=(2, 2, 2)):
y = Conv3DTranspose(nfilters, kernel_size=(size, size,size), strides=strides, padding=padding)(tensor)
y = concatenate([y, residual], axis=4)
y = conv_block3D(y, nfilters)
return y
def Unet3D(img_height, img_width,bands, nclasses=12, filters=64):
input_layer = Input(shape=(img_height, img_width,bands,1), name='image_input')
conv1 = conv_block3D(input_layer, nfilters=filters)
conv1_out = MaxPooling3D(pool_size=(2, 2, 2))(conv1)
conv2 = conv_block3D(conv1_out, nfilters=filters*2)
conv2_out = MaxPooling3D(pool_size=(2, 2, 2))(conv2)
conv3 = conv_block3D(conv2_out, nfilters=filters*4)
conv3_out = MaxPooling3D(pool_size=(2, 2, 2))(conv3)
conv4 = conv_block3D(conv3_out, nfilters=filters*8)
conv4_out = MaxPooling3D(pool_size=(2, 2, 2))(conv4)
conv4_out = Dropout(0.5)(conv4_out)
conv5 = conv_block3D(conv4_out, nfilters=filters*16)
conv5 = Dropout(0.5)(conv5)
deconv6 = deconv_block3D(conv5, residual=conv4, nfilters=filters*8)
deconv6 = Dropout(0.5)(deconv6)
deconv7 = deconv_block3D(deconv6, residual=conv3, nfilters=filters*4)
deconv7 = Dropout(0.5)(deconv7)
deconv8 = deconv_block3D(deconv7, residual=conv2, nfilters=filters*2)
deconv8 = Dropout(0.5)(deconv8)
deconv9 = deconv_block3D(deconv8, residual=conv1, nfilters=filters)
conv10 = Conv3D(filters=nclasses, kernel_size=(1, 1, 1), padding='same')(deconv9)
conv10 = BatchNormalization()(conv10)
output = Activation("relu")(conv10)
model = Model(inputs=input_layer, outputs=output, name='Unet')
model.compile(optimizer = optimizers.Adam(lr = 1e-5), loss = 'categorical_crossentropy', metrics = ['accuracy'])
return model
Таким образом, вывод теперь (512,512,64,12). Я хотел бы иметь форму (512,512,12).
Я уже пытался использовать Среднее объединение по третьему измерению и преобразовал данные, но Unet ничего не изучает:
average = AveragePooling3D(pool_size=(1, 1, 64), padding='same')(conv10)
output = Reshape((img_height, img_width, nclasses), input_shape=(average.shape))(average)
output = Conv2D(filters=nclasses, kernel_size=(1, 1))(output)
output = BatchNormalization()(output)
output = Activation('softmax')(output)
model = Model(inputs=input_layer, outputs=output, name='Unet')
model.compile(optimizer = optimizers.Adam(lr = 1e-5), loss = 'categorical_crossentropy', metrics = ['accuracy'])
return model
Есть ли идеи?