受到end-to-end model 所賜,非資工領域的人可以很容易實現各種Model (例如我)。然而我們還是需要了解model的架構才能知道如何設計的。
以下我們會搭配圖與程式碼一同解釋別人如何實現Unet的。我參考的開源程式碼是這篇zhixuhao
的U-net,實現的程式碼蠻簡潔的而且可讀性很是不錯。
為了配合文章,我們從model.py這個檔案開始說明起:
import numpy as np
import os
import skimage.io as io
import skimage.transform as trans
import numpy as np
from keras.models import *
from keras.layers import *
from keras.optimizers import *
from keras.callbacks import ModelCheckpoint, LearningRateScheduler
from keras import backend as keras
主要的import 包含 numpy, os, skimage, keras。
skimage: 也是個影像處理的庫,有點像OPENCV,庫也是超大的。
keras: 是tensorflow 的的高級API,所以如果要用keras,需要裝tensorflow。
os: 路徑控制庫
numpy: 數學運算庫/可以與keras, skimage等一起使用。
def unet(pretrained_weights = None,input_size = (256,256,1)):
首先這是一個2D U-net, 所以只能輸入一個channel的資料,大小是256*256
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)
這是一個可讀性比較低的寫法,但學習這個其實還蠻簡單的。廢話不多說,直接讀文件
tf.keras.layers.Conv2D(
filters, # 要產生 feature map 的數量
kernel_size, # kernal size
strides=(1, 1), # 卷積的步幅
padding="valid", # 是否要填充邊界
data_format=None, # 上一層的結構
dilation_rate=(1, 1), # 卷積的擴張率
groups=1, # 如果有多通道,要拆成幾組做convolution
activation=None, # 激活函數
use_bias=True, # 卷積的時候是否有常數項
kernel_initializer="glorot_uniform", # 權重初始化
bias_initializer="zeros", # 偏權初始化
kernel_regularizer=None, # 是否要對kernal regularizer
bias_regularizer=None, # 是否要對bias regularizer
activity_regularizer=None, #是否要對 activity regularizer
kernel_constraint=None, # 是否對kernel應用 constraint
bias_constraint=None, # 是否對bias應用 constraint
**kwargs # etc...
)
開始解釋各參數的意義。
filters: int
代表filters要應用的數量,代表會產生多少個feature map,如果數字是64,就代表第一次convolution 會產生64個feature map。
padding: string
代表周圍是否要補0,如果不補,size會變小,變小(keneral size -1)的大小,我們可以知道,paper與程式碼在這邊的策略不同,但是理論上不太影響訓練成果。
kernel_initializer:string
初始化方法,有一篇文章有詳細的介紹,這個方法是根據權重tensor的數量 (理解成矩陣/向量的元素數量) (fan_in)
標準差為 sqrt(2/fan_in) , 平均為0 的隨機亂數。
有一點要注意
inputs = Input((256,256,1))
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')
print(type(conv1))
conv1 = Conv2D(64, 3, activation = 'relu', padding = 'same', kernel_initializer = 'he_normal')(inputs)
print(type(conv1))
output
<class 'keras.layers.convolutional.Conv2D'>
<class 'tensorflow.python.framework.ops.Tensor'>
第一種寫法代表我建立的一個convolution layer
第二種寫法代表建立了相對應的tensor
Conv2D 這個function已經略懂略懂,接下來再來看看有那些值得注意的結構吧。
[1] zhixuhao's unet
[2] 2D Covolution layers
[3] henormal
[4] initializers