Unet:Convolutional Networks for Biomedical Image Segmentation拜读
0、文章链接
https://arxiv.org/pdf/1505.04597.pdf
1、网络结构
网络模型结构看起来像U字母。该网络由一个下采样过程(左半部分)和一个上采样过程(右半部分)组成。
1.1、下采样过程
典型的卷积神经网络结构。四组相同的下采样,组成:
- 两个3*3卷积层(unpadded方式)
- ReLU激活
- 2*2 最大池化层(步长为2)
每组下采样后,都会加倍特征通道数(以两倍的方式)。
1.2、上采样过程
同样的四组上采样,组成:
- 1个2*2上卷积
- 下采样过程中的特征图裁剪crop的连接concatenation
- 两个3*3卷积层
- ReLU激活
上述裁剪crop的存在,考虑到避免在每次卷积时边缘像素的损失。
1.3、最后一层
1*1卷积。为了64个特征值期望类别。整个网络中总共有23个卷积层。
2、Training训练
- Caffe随机梯度下降法
- UnPadded方式卷积,输出图像比输入图像少一个边界宽度。
- 输入大图块代替大batch size。(最小化占用率、最大化GPU使用率)
- high momentum (0.99)
2.1、损失函数
思想:逐像素进行,softmax激活函数结合交叉熵损失函数。
-
softmax function
p k ( x ) = e x p ( a k ( x ) ) ∑ k ′ = 0 K e x p ( a k ′ ( x ) ) p_k(x) = \frac {exp(a_k(x))} {\sum_{k^{'}=0}^K exp(a_{k^{'}}(x)) } pk(x)=∑k′=0Kexp(ak′(x))exp(ak(x))
其中, a k ( x ) a_k(x) ak(x)是像素位置x,k特征通道下的激活函数。K是类别数; p k ( x ) p_k(x) pk(x)是近似最大函数 -
cross entropy交叉熵
交叉熵惩罚,每个位置的偏差 p l ( x ) p_{l}(x) pl(x):
E = ∑ X ∈ Ω ω ( X ) l o g ( p l ( x ) ( X ) ) E=\sum_{X\in\Omega}\omega(X)log(_{p_{l}(x)}(X)) E=X∈Ω∑ω(X)log(pl(x)(X))
其中, l : Ω → { 1 , . . . , K } l:{\Omega}→ \{1, . . . , K\} l:Ω→{1,...,K} 是每个像素的真实标签; w : Ω → R w : Ω → R w:Ω→R 权重函数。 -
权重函数
分离边界通过形态学morphological处理计算。权重函数定义如下:
ω ( X ) = ω c ( X ) + ω 0 ∗ e x p ( − ( d 1 ( X ) + d 2 ( X ) ) 2 2 σ 2 ) \omega(X) = \omega_{c}(X) + \omega_{0}*exp(-\frac{(d_1(X)+d_2(X))^2}{2\sigma^2}) ω(X)=ωc(X)+ω0∗exp(−2σ2(d1(X)+d2(X))2)
其中, w c : Ω → R w_c : Ω → R wc:Ω→R 类别频率权重; d 1 : Ω → R d_1 : Ω → R d1:Ω→R最近邻边界距离?; d 2 : Ω → R d_2 : Ω → R d2:Ω→R次近邻边界距离?。初始状态 w 0 = 10 w_0 =10 w0=10, σ ≈ 5 \sigma \approx5 σ≈5像素
3、数据增强Data Augmentation
- 在一个粗糙的3*3网格上,使用随机位移矢量生成平滑变形
- 上述位移通过高斯分布(10像素标准差)进行采样
- 每像素位移使用双三次插值算法计算
- 在下采样过程的末端避免过拟合DropOut层,进一步执行隐式数据增强
4、实例测试
使用github中,https://github.com/zhixuhao/unet.git这个朋友的模型。我的硬件环境是CPU,tensorflow 2.x;有如下修改的部分,才能跑通:
- trainUnet.ipynb文件
os.environ["CUDA_DEVICE_ORDER"] = "PCI_BUS_ID"
os.environ["CUDA_VISIBLE_DEVICES"] = "-1"
因为GPU没有配置,所以一直报 cuda 初始化失败,基于此进行CPU的设置。
- model.py文件
model = Model(inputs = inputs, outputs = conv10)
将Model类的参数名进行修改与之我当前tensorflow keras包进行匹配。input改成inputs;output改成outputs。
model.compile(optimizer = tf.keras.optimizers.Adam(learning_rate = 1e-4), loss = 'binary_crossentropy', metrics = ['accuracy'])
optimizer = tf.keras.optimizers.Adam(learning_rate = 1e-4) 此为修改后的Adam;
修改前optimizer = Adam(learning_rate = 1e-4),python环境不认,报错找不到Adam。
4.1、训练模型
训练模型,生成模型文件unet_membrane.hdf5。训练结果log,看着精度不太高。
2000/2000 [==============================] - ETA: 0s - loss: 0.6673 - accuracy: 0.7812
Epoch 00001: loss improved from inf to 0.66732, saving model to unet_membrane.hdf5
2000/2000 [==============================] - 8041s 4s/step - loss: 0.6673 - accuracy: 0.7812
Epoch 2/5
2000/2000 [==============================] - ETA: 0s - loss: 0.6236 - accuracy: 0.7813
Epoch 00002: loss improved from 0.66732 to 0.62358, saving model to unet_membrane.hdf5
2000/2000 [==============================] - 7973s 4s/step - loss: 0.6236 - accuracy: 0.7813
Epoch 3/5
2000/2000 [==============================] - ETA: 0s - loss: 0.5896 - accuracy: 0.7814
Epoch 00003: loss improved from 0.62358 to 0.58965, saving model to unet_membrane.hdf5
2000/2000 [==============================] - 7874s 4s/step - loss: 0.5896 - accuracy: 0.7814
Epoch 4/5
2000/2000 [==============================] - ETA: 0s - loss: 0.5640 - accuracy: 0.7815
Epoch 00004: loss improved from 0.58965 to 0.56398, saving model to unet_membrane.hdf5
2000/2000 [==============================] - 7919s 4s/step - loss: 0.5640 - accuracy: 0.7815
Epoch 5/5
2000/2000 [==============================] - ETA: 0s - loss: 0.5458 - accuracy: 0.7815
Epoch 00005: loss improved from 0.56398 to 0.54583, saving model to unet_membrane.hdf5
2000/2000 [==============================] - 7914s 4s/step - loss: 0.5458 - accuracy: 0.7815
4.2、测试模型
待测试图:
分割预测结果: