Python 如何用Keras建立多类卷积神经网络
我正在尝试用Keras和Tensorflow后端实现一个用于图像分割任务的U-Net。我有大小为128,96的图像作为网络的输入,还有大小为12288,6的掩码图像,因为它们是扁平的。我有6个不同的类0-5,它给出了遮罩图像形状的第二部分。它们已使用to_分类函数编码为一个热标签。目前,我只使用一个输入图像,也使用相同的图像作为验证和测试数据 我希望U-Net执行图像分割,其中类0对应于背景。当我现在只训练我的U-Net几个时代1-10时,得到的预测掩模图像似乎只是给每个像素随机分类。当我训练网络超过50个历元时,所有像素都被分类为背景。由于我使用相同的图像进行训练和测试,我发现这非常奇怪,因为我正在加速网络训练。我如何解决这个问题?我给网络提供掩码图像和真实图像的方式可能有问题吗 我曾尝试手动给网络赋予权重,以减少对背景的强调,并尝试了不同的损失组合、不同的掩模图像塑造方法以及其他许多方法,但都没有取得好的效果 下面是我的网络代码。它基于从中获取的U形网。我设法把它训练成两个班的情况,效果很好,但现在我不知道如何把它扩展到更多的班Python 如何用Keras建立多类卷积神经网络,python,tensorflow,keras,conv-neural-network,image-segmentation,Python,Tensorflow,Keras,Conv Neural Network,Image Segmentation,我正在尝试用Keras和Tensorflow后端实现一个用于图像分割任务的U-Net。我有大小为128,96的图像作为网络的输入,还有大小为12288,6的掩码图像,因为它们是扁平的。我有6个不同的类0-5,它给出了遮罩图像形状的第二部分。它们已使用to_分类函数编码为一个热标签。目前,我只使用一个输入图像,也使用相同的图像作为验证和测试数据 我希望U-Net执行图像分割,其中类0对应于背景。当我现在只训练我的U-Net几个时代1-10时,得到的预测掩模图像似乎只是给每个像素随机分类。当我训练网
def get_unet(self):
inputs = Input((128, 96,1))
#Input shape=(?,128,96,1)
conv1 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal', input_shape=(None,128,96,6))(inputs)
#Conv1 shape=(?,128,96,64)
conv1 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(conv1)
#Conv1 shape=(?,128,96,64)
pool1 = MaxPooling2D(pool_size=(2, 2))(conv1)
#pool1 shape=(?,64,48,64)
conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(pool1)
#Conv2 shape=(?,64,48,128)
conv2 = Conv2D(128, 3, activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(conv2)
#Conv2 shape=(?,64,48,128)
pool2 = MaxPooling2D(pool_size=(2, 2))(conv2)
#Pool2 shape=(?,32,24,128)
conv5 = Conv2D(256, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(pool2)
conv5 = Conv2D(256, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(conv5)
up8 = Conv2D(128, 2, activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv5))
merge8 = concatenate([conv2,up8], axis = 3)
conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(merge8)
conv8 = Conv2D(128, 3, activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(conv8)
up9 = Conv2D(64, (2,2), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(UpSampling2D(size = (2,2))(conv8))
merge9 = concatenate([conv1,up9], axis = 3)
conv9 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(merge9)
conv9 = Conv2D(64, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(conv9)
conv9 = Conv2D(6, (3,3), activation = 'relu', padding = 'same',
kernel_initializer = 'he_normal')(conv9)
conv10 = Conv2D(6, (1,1), activation = 'sigmoid')(conv9)
conv10 = Reshape((128*96,6))(conv10)
model = Model(input = inputs, output = conv10)
model.compile(optimizer = Adam(lr = 1e-5), loss = 'binary_crossentropy',
metrics = ['accuracy'])
return model
有人能指出我的模型有什么问题吗?我看不到你的预测层,据我所知,它一定是密集层,而不是卷积层。
也许这就是你的问题。我没有看到你的预测层,据我所知,它一定是密集层,而不是卷积层。
也许这就是你的问题。根据我的经验,也有一个U-net用于细分。它倾向于这样做: 选择全黑或全白 在损失似乎冻结了很多时间之后,它终于找到了方向。 我还使用“只训练一幅图像”的方法来找到收敛点,然后添加其他图像就可以了 但是我试了很多次,唯一一次它运行得很快的是我使用: 最终激活='乙状结肠' 损失='二进制交叉熵' 但是我没有在任何地方使用relu…也许这会影响一点收敛速度。。。?考虑到relu,它只有0或正结果,这个函数中有一个很大的区域没有梯度。也许有很多relu激活会创建很多没有梯度的平坦区域?你必须好好想想才能确认 尝试几次,耐心等待不同权重初始化的多个时代 你的学习率也可能太高
即将分类:您是否尝试过绘制/打印您的面具?它们真的像你期望的那样吗?以我的经验,也有一个U-net用于细分。它倾向于这样做: 选择全黑或全白 在损失似乎冻结了很多时间之后,它终于找到了方向。 我还使用“只训练一幅图像”的方法来找到收敛点,然后添加其他图像就可以了 但是我试了很多次,唯一一次它运行得很快的是我使用: 最终激活='乙状结肠' 损失='二进制交叉熵' 但是我没有在任何地方使用relu…也许这会影响一点收敛速度。。。?考虑到relu,它只有0或正结果,这个函数中有一个很大的区域没有梯度。也许有很多relu激活会创建很多没有梯度的平坦区域?你必须好好想想才能确认 尝试几次,耐心等待不同权重初始化的多个时代 你的学习率也可能太高
即将分类:您是否尝试过绘制/打印您的面具?它们真的像你期望的那样吗?谢谢你@Daniel,你的建议最终帮助我让Unet发挥作用。当运行500多个历代时,我得到的结果不仅仅是将整个图像分类为背景。另外,与使用kernel\u initializer='he\u normal',kernel\u initializer='zeros'或kernel\u initializer=TruncatedNormalmean=0.0不同,stddev=0.07对我有效。我使用了“sigmoid”激活函数和loss='binary\u crossentropy'。我为所有隐藏的卷积层保留了“relu”激活。我注意到我的网络有时会陷入本地最小值,丢失情况不再改善,因此我需要重新启动 谢谢你@Daniel,你的建议最终帮助我让Unet开始工作。当运行500多个历代时,我得到的结果不仅仅是将整个图像分类为背景。而且相反
使用kernel_initializer='he_normal',kernel_initializer='zeros'或kernel_initializer=TruncatedNormalmean=0.0,stddev=0.07对我来说是有效的。我使用了“sigmoid”激活函数和loss='binary\u crossentropy'。我为所有隐藏的卷积层保留了“relu”激活。我注意到我的网络有时会陷入本地最小值,丢失情况不再改善,因此我需要重新启动 谢谢,弗洛。您可以指定添加预测层的含义吗?我正在遵循的架构,我不知道如何为网络添加一个密集层进行预测。谢谢,@Flo。您可以指定添加预测层的含义吗?我正在遵循的架构,我不知道如何为网络添加一个密集层进行预测。谢谢你的回答!我会试试你的建议!我使用的是带二元交叉熵损失的sigmoid激活。您对隐藏层使用了哪种激活方式?关于to_分类函数,我正在绘制遮罩,它们在转换为一个热标签并返回时看起来很好。但我不太确定这是否是Keras网络的正确标签格式。这个想法正是为了绘制一个热编码的面具,而不是原始的面具。正如它所说,一个hot通常只有一个值为1,其余的值都是0。这永远不会做一个面具你需要很多的1来做一个面具,但是我不习惯to_分类函数来知道它到底在做什么。但是你可能不应该把它和遮罩一起使用,你需要每个通道都有很多1。如果你的MAK来自于值在0到255之间的图像,你所要做的就是将图像除以255。我不认为,我理解你的意思。我有大小为128x96x6的遮罩,其中128x96是图像的像素大小,我有6个不同的类。在每个通道中,我有0和1,始终指示像素是否属于通道的相应类别。所以你说我不应该对掩模图像进行热编码?你关于如何组织掩模数据的想法是完美的。如果你描述的是y_训练,就像你把它传递给fit方法一样,那么你不必担心我说的话。我只是建议你在y_训练数据中绘制一个由一个或两个通道形成的图像。听起来像是你在绘制原始面具,然后才使用“分类”。目的只是检查to_Category是否真的给了你有效的面具。谢谢。是的,我的y_训练是我描述的面具的扁平版,所以它的尺寸不是128x96x6,而是128*96x6。但我也分别绘制了通道,它们精确地显示了应该显示的掩模部分。你能记得你的unet培训大约需要多少个阶段吗?我已经运行了5000现在,但这并没有什么不同。谢谢你的回答!我会试试你的建议!我使用的是带二元交叉熵损失的sigmoid激活。您对隐藏层使用了哪种激活方式?关于to_分类函数,我正在绘制遮罩,它们在转换为一个热标签并返回时看起来很好。但我不太确定这是否是Keras网络的正确标签格式。这个想法正是为了绘制一个热编码的面具,而不是原始的面具。正如它所说,一个hot通常只有一个值为1,其余的值都是0。这永远不会做一个面具你需要很多的1来做一个面具,但是我不习惯to_分类函数来知道它到底在做什么。但是你可能不应该把它和遮罩一起使用,你需要每个通道都有很多1。如果你的MAK来自于值在0到255之间的图像,你所要做的就是将图像除以255。我不认为,我理解你的意思。我有大小为128x96x6的遮罩,其中128x96是图像的像素大小,我有6个不同的类。在每个通道中,我有0和1,始终指示像素是否属于通道的相应类别。所以你说我不应该对掩模图像进行热编码?你关于如何组织掩模数据的想法是完美的。如果你描述的是y_训练,就像你把它传递给fit方法一样,那么你不必担心我说的话。我只是建议你在y_训练数据中绘制一个由一个或两个通道形成的图像。听起来像是你在绘制原始面具,然后才使用“分类”。目的只是检查to_Category是否真的给了你有效的面具。谢谢。是的,我的y_训练是我描述的面具的扁平版,所以它的尺寸不是128x96x6,而是128*96x6。但我也分别绘制了通道,它们精确地显示了应该显示的掩模部分。你能记得你的unet培训大约需要多少个阶段吗?我现在已经运行了5000次,但这并没有什么不同。