我有一个 2000x256x256x3 RGB 图像(包含紫色/蓝色核的粉红色组织)和相应大小为 200x256x256x1 的地面实况的数据集。地面实况图像是二进制的。现在,这是我的模型(Tensorflow 版本 1.x 和 Keras):
def createFCNSameWidthModel(is1,fn,dpth,ksze,dm):
input_shape=is1
filter_num=fn
depth=dpth
ksize=ksze
dim=dm
import math
from keras import backend as K
def gelu(x):
constant=math.sqrt(2*math.pi)
return 0.5*x*(1+K.tanh(constant*(x+0.044715*K.pow(x,3))))
_input=Input(shape=(input_shape,input_shape,dim))
batch1=BatchNormalization()(_input)
prev=batch1
for i in range(0,depth):
conv=Conv2D(filters=filter_num,kernel_size=ksize,padding='same',activation=gelu)(prev)
#maxpool=MaxPooling2D(strides=(1,1))(conv)
#batch=BatchNormalization()(conv)
prev=conv
_output=Conv2D(filters=1,kernel_size=3,padding='same',activation='sigmoid')(prev)
model=Model(inputs=_input,outputs=_output)
model.summary()
return model
我正在为隐藏的卷积层使用称为GeLU的自定义激活。
型号总结:
[Run:AI] [DEBUG ] [12-01-2021 18:48:01.575] [71] [optimizers.py :16 ] Wrapping 'Adam' Keras optimizer with GA of 4 steps
Model: "model_58"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
input_62 (InputLayer) (None, 256, 256, 3) 0
_________________________________________________________________
batch_normalization_78 (Batc (None, 256, 256, 3) 12
_________________________________________________________________
conv2d_964 (Conv2D) (None, 256, 256, 16) 1216
_________________________________________________________________
conv2d_965 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_966 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_967 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_968 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_969 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_970 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_971 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_972 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_973 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_974 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_975 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_976 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_977 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_978 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_979 (Conv2D) (None, 256, 256, 16) 6416
_________________________________________________________________
conv2d_980 (Conv2D) (None, 256, 256, 1) 145
=================================================================
Total params: 97,613
Trainable params: 97,607
Non-trainable params: 6
_________________________________________________________________
Effective batch size: 16
我想要实现的目标:我正在获取数据集的一个子集(64 张具有基本事实的图像)并尝试过度拟合模型以查看我的模型是否工作正常。
问题:模型没有过度拟合数据集(从现在开始,数据集意味着仅包含 64 张图像的数据集),并且如果模型过度拟合/篡改数据集,则损失会稳定在一个预期之外的值。
规格:
- Optimizer = Adam(learning_rate=0.001),发现 0.001 可以快速减少损失(在 10 个时期内)。
- Gradient Accumulation = Adam 被包裹在runai wrapper 中,以便进行梯度累积。这是由于 GPU 内存限制。
- 损失函数 = 我使用了 Dice 系数损失,但我发现它本质上是非凸的(论文:语义分割损失函数的调查),因此我使用了 logcosh(骰子损失)。我观察到的指标是准确度、骰子系数和杰卡德指数
- 批量大小 = 我发现最好的批量大小是 16。请注意,这是有效的批量大小,即更新梯度的大小。
相关代码:
import tensorflow as tf
from keras import backend as K
def jaccard_index_iou(y_true,y_pred,smooth=1):
intersection = K.sum(K.abs(y_true * y_pred), axis=[1,2]) # y_pred is mXrXcX1 (axis=0,1,2,3), we want only axis 1 and 2
union = K.sum(y_true,axis=[1,2])+K.sum(y_pred,axis=[1,2])-intersection
iou = K.mean((intersection + smooth) / (union + smooth), axis=0)
return iou
def dice_coef_f1(y_true, y_pred, smooth=1):
intersection = K.sum(y_true * y_pred, axis=[1,2])
union = K.sum(y_true,axis=[1,2]) + K.sum(y_pred, axis=[1,2])
dice = K.mean((2. * intersection + smooth)/(union + smooth), axis=0)
return dice
def logcoshDice(y_true,y_pred):
dice=dice_coef_f1(y_true,y_pred)
diceloss=1-dice
return K.log((K.exp(diceloss)+K.exp(-diceloss))/2.0) # log of cosh of dice loss
model=createFCNSameWidthModel(is1=256,fn=16,dpth=16,ksze=5,dm=3)
import runai.ga.keras as rgk
bs=4
my_steps=4
my_optimizer=Adam(learning_rate=0.001)
my_optimizer=rgk.optimizers.Optimizer(my_optimizer,steps=my_steps)
print("Effective batch size:",my_steps*bs)
model.compile(optimizer=my_optimizer,loss=logcoshDice,metrics=['acc',dice_coef_f1,jaccard_index_iou])
数据集存在于形状为 64,256,256,3(图像)的 numpy 数组中,地面实况为 64,256,256,1(Gt)。图像数据集在通过 BatchNormalization 层时未进行归一化。
训练:
相关代码:
history=model.fit(X_data,Y_data,validation_data(X_val,Y_val),batch_size=bs,epochs=50)
结果:损失和骰子系数处于平稳状态。这不应该发生在过度拟合中。
我试过的:
- 使用优化器(Adam、SGD)、批量大小、学习率、时期 ->无效果
- 玩学习率调度,reduceLRPlateau,EarlyStopping->无效果
- 使用模型宽度、深度、内核大小 -> 16 宽度和深度可以获得上述性能。我发现增加宽度或深度会进一步降低性能。内核大小 5 可提供最佳性能。
- 使用不同的损失函数-> Dice loss, log IoU loss, logcoshloss, BCE, BCE+Dice loss, Sensitivity-Specificity loss, Tversky loss, Focal tversyky loss-> logcosh(dice loss) 给出了最好的减少,但最终会出现平台期。
根据近似的普遍定理,我的模型还不够深,无法记住这个小数据集。如果不学习,它至少应该过拟合。我现在的调试知识已经接近尾声,迫切需要帮助以进一步进行。
我还怀疑这个问题可能是我的数据集对模型来说太难学习了?但它不能过拟合吗?因此,这是一个示例数据集图像(右侧带有基本事实):