Udacity机器人软件工程师课程笔记(三十) - 语义分割与实例实现 - 使用keras实现语义分割
語義分割
1.語義分割介紹
計算機視覺與機器學習研究者對圖像語義分割問題越來越感興趣。越來越多的應用場景需要精確且高效的分割技術,如自動駕駛、室內導航、甚至虛擬現實與增強現實等。這個需求與視覺相關的各個領域及應用場景下的深度學習技術的發展相符合,包括語義分割及場景理解等…
更多可以參考語義分割概述.
在這個項目中,我們將訓練一個深度神經網絡,以從Quadcoptor模擬器生成的圖像中識別目標人。擁有訓練完成的網絡后,我們可以通過推理使用它在新圖像中找到目標。
在最終的Follow Me項目中,推理步驟必須在仿真中連續運行,就像直升機向其提供圖像一樣快。在本項目中引入了一些額外的代碼抽象和性能增強,這些在進行仿真時是必需的,
- 環境設置
- TensorFlow中的Keras層
- 具有可分離卷積的編碼器
- 批量歸一化
- 具有雙線性上采樣的解碼器
- 層級聯
本實驗使用來自模擬器的實際數據,最后,我們將擁有一個理論上可以正常運行的網絡,可以將其整合到Follow Me項目中。我們將需要通過附加層,參數調整甚至收集更多數據來最大化網絡性能。
(1)環境設置
在本實驗中, 課程還是以jupternotebook的形式提供,為了方便我以后使用,我會再將來的內容更改成.py格式。
運行以下命令以克隆實驗室存儲庫:
git clone https://github.com/udacity/RoboND-Segmentation-Lab.git
# Make sure your conda environment is activated!
jupyter notebook
或者進入https://github.com/udacity/RoboND-Segmentation-Lab.git去下載相應的壓縮包解壓到相應的路徑中。其中包括儲存庫,訓練數據和驗證數據。
(2)Keras
Keras 是目前使用最為廣泛的深度學習工具之一,它的底層可以支持Tensor Flow 、
MXNet、CNTK 和Theano 。如今, Keras 更是被直接引入了TensorFlow 的核心代碼庫,成為TensorFlow 官方提供的高層封裝之一。
選擇Keras的優點:
- 訓練例程已簡化,并通過標準接口提供。
- 不必自己管理tensorflow會話。
- 數據生成器具有標準接口。
- 這些層是具有語法層()(prev_layer)的類,而不是具有layer(prev_layer)的功能接口,層的命名約定在它們之間是相當標準的。
- Keras有額外的層來處理諸如上采樣和其他小的特性,而在tensorflow中這些是分散的。
- 若想要向網絡添加新功能,那么需要將功能包裝在一個自定義層中,或者編寫為lambda層。
(3)編碼器
FCN是由編碼器和解碼器組成的。編碼器部分是一個卷積網絡,可簡化為更深的1x1卷積層,而不是用于圖像基本分類的平面全連接層。這種差異具有從圖像中保留空間信息的效果。
這里介紹的可分離卷積是一種減少所需參數數量的技術,從而提高了編碼器網絡的效率。
可分離卷積
可分離卷積,也稱為深度可分離卷積,由一個在輸入層的每個通道上執行的卷積和一個1x1卷積組成,1x1卷積將前一步的輸出通道合并成輸出層。
這與我們之前介紹的常規卷積不同,主要是因為減少了參數的數量。讓我們考慮一個簡單的例子。
設輸入形狀是32x32x3。需要9個輸出通道和形狀為3x3x3的過濾器(內核)。在常規卷積中,9個內核遍歷3個輸入通道。這將導致總共933*3個特征(忽略偏置)。總共243個參數。
在可分卷積的情況下,通過3個輸入通道,每個通道有一個內核。這給了我們27個參數(333)和3個特征圖。在下一步中,這3個特征映射將被9個1x1卷積遍歷。結果總共有27(9*3)個參數。總共有54(27 + 27)個參數!比我們上面得到的243個參數少得多。隨著層或通道的大小的增加,這種差異將會更加明顯。
參數的減少使得可分卷積在提高運行時性能的同時非常高效,因此對于移動應用程序也非常有用。由于參數較少,它們還具有在一定程度上減少過擬合的額外好處。
可分離卷積相關代碼
在utils所提供的倉庫的模塊中提供了可分離卷積的優化版本。它基于tf.contrib.keras函數定義,可以實現如下:
output = SeparableConv2DKeras(filters, kernel_size, strides, padding, activation)(input)
其中,
input是輸入層,
filters 是輸出濾波器的數量(深度),
kernel_size是一個數字,指定內核的(寬度,高度),
padding 是“SAME”或“VALID”
activation是激活函數,例如“ relu”。
以下是如何使用上述功能的示例:
output = SeparableConv2DKeras(filters=32, kernel_size=3, strides=2,padding='same', activation='relu')(input)
(4)批處理歸一化
批處理歸一化是優化網絡訓練的另一種方法。
批量歸一化基于以下思想:我們不僅將輸入歸一化到網絡中,還將輸入歸一化到網絡中的各個層。之所以稱為“批處理”歸一化,是因為在訓練期間,我們使用當前迷你批處理中的值的均值和方差來歸一化每一層的輸入。
網絡是一系列的層,其中一層的輸出成為另一層的輸入。這意味著我們可以把神經網絡中的任何一層想象成更小網絡的第一層。
例如,設想一個3層的網絡。不要把它看作是一個具有輸入、網絡的層和輸出的單一網絡,而是把第1層的輸出看作是一個兩層網絡的輸入。這兩層網絡將由我們原來的網絡中的第2層和第3層組成。
同樣地,第2層的輸出可以被認為是一個單層網絡的輸入,該網絡只包含第3層。
當我們把它看作是一系列相互作用的神經網絡時,就很容易想象把每一層的輸入歸一化會有多大幫助。這就像對任何其他神經網絡的輸入進行歸一化一樣,但是在每一層(子網絡)都在這么做。
批歸一化代碼
在中tf.contrib.keras,可以使用以下函數定義來實現批量標準化:
from tensorflow.contrib.keras.python.keras import layers
output = layers.BatchNormalization()(input)
該separable_conv2d_batchnorm()函數在可分離卷積層之后添加批處理歸一化層。引入批處理規范化層為我們提供了很多優勢。
例如:
- 網絡訓練速度更快 – 由于前向傳遞期間的額外計算,每個訓練迭代實際上會更慢。但是,它的收斂速度應該快得多,所以總體上訓練應該更快。
- 允許更高的學習率 – 梯度下降法通常需要較小的學習速率才能使網絡收斂。當網絡越深,它們的梯度在反向傳播時就越小,因此它們需要更多的迭代。使用批處理規范化允許我們使用更高的學習率,這進一步提高了網絡訓練的速度。
- 簡化了更深層網絡的創建 – 由于上述原因,在使用批處理規范化時,更容易構建并且更快地訓練更深層的神經網絡。
- 提供一些正則化 – 批處理歸一化會給網絡增加一些干擾。在某些情況下,例如在Inception模塊中,批處理歸一化已經被證明與dropout一樣有效。
(5)解碼器
在前面講過轉置卷積,作為將層向上采樣到更高維度或分辨率的一種方法。實際上,有幾種方法可以實現向上采樣。在本節中,將介紹另一種方法,稱為雙線性上采樣或雙線性插值。
雙線性上采樣
雙線性上采樣是一種重采樣技術,該技術利用與給定像素對角線的四個最接近的已知像素的加權平均值來估計新的像素強度值。加權平均值通常取決于距離。
讓我們考慮這樣一種情況:有4個已知像素值,因此本質上是2x2灰度圖像。需要將此圖像上采樣為4x4圖像。下圖更好地說明了此過程。
上面4x4插圖中未標記的像素實際上是空白。雙線性上采樣方法將嘗試通過插值來填充所有剩余的像素值。考慮P5P_5P5?的情況來理解這個算法。
我們首先使用線性插值計算P12P_{12}P12?和P34P_{34}P34?的像素值。
P12=P1+W1?(P2?P1)/W2P_{12}= P_1 + W_1*(P_2 - P_1)/W_2P12?=P1?+W1??(P2??P1?)/W2?
P34=P3+W1?(P4?P3)/W2P_{34}= P_3 + W_1*(P_4 - P_3)/W_2P34?=P3?+W1??(P4??P3?)/W2?
使用P12和P34,我們可以得到P5:
P5=P12+H1?(P34?P12)/H2P_5 = P_{12}+ H_1*(P_{34}- P_{12})/H_2P5?=P12?+H1??(P34??P12?)/H2?
為了簡單起見,我們假設H_2 = W_2 = 1
將P34和P12代入后,P5像素值的最終方程為:
P5=P1?(1?W1)?(1?H1)+P2?W1?(1?H1)+P3?H1?(1?W1)+P4?W1?H1P_5 = P_1 * (1 - W_1) * (1 - H_1) + P_2 * W_1 * (1 - H_1) + P_3 * H_1 * (1 - W_1) + P_4 * W_1* H_1P5?=P1??(1?W1?)?(1?H1?)+P2??W1??(1?H1?)+P3??H1??(1?W1?)+P4??W1??H1?
雖然數學變得更加復雜,上面的技術也可以擴展到RGB圖像。
雙線性上采樣器代碼
已在utils所提供的repo 的模塊中提供了雙線性上采樣器的優化版本,可以按以下方式實現:
output = BilinearUpSampling2D(row, col)(input)
其中,
input是輸入層,
row 是輸出層各行的上采樣系數,
col 是輸出層各列的上采樣系數,并且
output 是輸出層。
以下是如何使用上述功能的示例:
output = BilinearUpSampling2D((2,2))(input)
雙線性升采樣方法沒有像體系結構中的轉置卷積那樣有助于學習,并且容易丟失一些更詳細的細節,但有助于提高性能。
(6)層級聯
前面介紹了跳躍連接,這是一種很好的方法,可以在我們解碼或將層提升到原始大小時保留前一層的一些更精細的細節。在前面,我們討論了實現此目的的一種方法,即使用元素添加操作添加兩個層。我們現在將學習另一個簡單的技術,我們將連接兩個層,而不是添加它們。
連接兩個層,上采樣層和一個比上采樣層具有更多空間信息的層,向我們展示了相同的功能。實現此功能也非常簡單。
使用tf.contrib.keras函數定義,它可以實現如下:
from tensorflow.contrib.keras.python.keras import layers
output = layers.concatenate(inputs)
其中,
inputs 是要連接的圖層的列表。
可以使用類似的格式在decoder_block()函數中實現上述操作:
output = layers.concatenate([input_layer_1, input_layer_2])
層級聯的另一個好處是,它提供了一定的靈活性,因為與必須添加它們時不同,輸入層的深度不需要匹配。這也有助于簡化實施。
雖然層級聯本身對模型有幫助,但通常最好在此步驟之后添加一些常規或可分離的卷積層,以使模型能夠更好地從之前的圖層中學習那些更精細的空間細節。
3. 交并比(IoU)
交并比(IoU)是一個重要的指標,該指標可以幫助評估語義分割網絡的性能。
IoU函數的定義為:預測邊界和實際邊界 交集的面積 比 并集的面積。
IntersectionSet(AND)UnionSet(OR)≤1\frac{Intersection \ Set(AND)}{Union\ Set(OR)} \le 1Union?Set(OR)Intersection?Set(AND)?≤1
TensorFlow IoU
讓我們看一下tf.metrics.mean_iou函數。與所有其他TensorFlow度量函數一樣,它返回度量結果的Tensor和Tensor Operation來生成結果。在這種情況下,它將返回mean_iou結果和update_op更新操作。確保update_op從獲得結果之前運行mean_iou。
sess.run(update_op)
sess.run(mean_iou)
TensorFlow度量函數的另一個特征 是使用本地TensorFlow變量。這些是臨時TensorFlow變量,必須通過運行進行初始化 tf.local_variables_initializer()。這類似于tf.global_variables_initializer(),但針對不同的TensorFlow變量。
程序如下:
import tensorflow as tfdef mean_iou(ground_truth, prediction, num_classes):iou, iou_op = tf.metrics.mean_iou(ground_truth, prediction, num_classes)return iou, iou_opground_truth = tf.constant([[0, 0, 0, 0],[1, 1, 1, 1],[2, 2, 2, 2],[3, 3, 3, 3]], dtype=tf.float32)
prediction = tf.constant([[0, 0, 0, 0],[1, 0, 0, 1],[1, 2, 2, 1],[3, 3, 0, 3]], dtype=tf.float32)iou, iou_op = mean_iou(ground_truth, prediction, 4)with tf.Session() as sess:sess.run(tf.global_variables_initializer())# 需要初始化本地變量來運行' tf.metrics.mean_iou 'sess.run(tf.local_variables_initializer())sess.run(iou_op)# should be 0.53869print("Mean IoU =", sess.run(iou))
程序注釋:
tf.metrics.mean_iou(labels,predictions,num_classes,weights=None,metrics_collections=None,updates_collections=None,name=None
)
labels:一個Tensor地面實況的具有形狀[批量大小]和類型的標簽int32或int64。如果張量等級> 1,則張量將被展平。predictions:Tensor語義標簽的預測結果A ,其形狀為[批量大小]且類型為int32或int64。如果張量等級> 1,則張量將被展平。num_classes:預測任務可以具有的標簽數量。必須提供此值,因為將分配維度= [num_classes,num_classes]的混淆矩陣。weights:Tensor等級為0或與等級相同的 可選labels,并且必須向廣播labels(即,所有尺寸必須為1,或與相應labels尺寸相同)。metrics_collections:mean_iou 應添加到集合的可選列表。updates_collections:update_op應該添加可選的收藏列表。name:可選的variable_scope名稱。
4.語義分割實例
我們將建立一個深度學習網絡,定位一個特定的人類目標在一個圖像里。前提是一個四軸飛行器(模擬)正在尋找一個目標,然后一旦找到目標就會跟隨。在這種情況下,僅僅說目標出現在圖像中是不夠的,而是要知道目標在圖像中的位置,以便直升機可以調整其方向以便跟蹤。
因此,一個圖像分類網絡不足以解決這個問題。相反,需要一個語義分割網絡,以便目標可以被明確地定位在圖像中。
猜測是tensorflow版本的問題,程序頻繁報錯,查了一天錯之后也沒有實質性的進展,因此將tensorflow版本更改到與推薦的版本一致。
pip install tensorflow==1.2.1
(1)引入函數
import os
import glob
import sys
import tensorflow as tffrom scipy import misc
import numpy as npfrom tensorflow.contrib.keras.python import keras
from tensorflow.contrib.keras.python.keras import layers, modelsfrom tensorflow import imagefrom utils import scoring_utils
# 引入可分卷積函數
from utils.separable_conv2d import SeparableConv2DKeras, BilinearUpSampling2D
from utils import data_iterator
from utils import plotting_tools
from utils import model_tools
來自utils的六個文件是課程自帶的,之前使用tensorflow1.13.0的時候,程序不停的出錯。個人猜測是因為升級后的tensorflow的各個函數的位置更改造成的。這個問題確實很遭人心,函數的位置的更改,導致了對以后程序的復現難度上升。而且出一些很玄學的bug。
(2)FCN層
可分卷積函數:
def separable_conv2d_batchnorm(input_layer, filters, strides=1):output_layer = SeparableConv2DKeras(filters=filters,kernel_size=3, strides=strides,padding='same', activation='relu')(input_layer)output_layer = layers.BatchNormalization()(output_layer) return output_layer
常規卷積函數:
def conv2d_batchnorm(input_layer, filters, kernel_size=3, strides=1):output_layer = layers.Conv2D(filters=filters, kernel_size=kernel_size, strides=strides, padding='same', activation='relu')(input_layer)output_layer = layers.BatchNormalization()(output_layer) return output_layer
這兩種卷積都可以使用,正如之前提到的,但是可分卷積函數在訓練的時候速度較快。在tensorflow==1.13.0中,separable_conv2d_batchnorm函數一直會報錯如下:
TypeError: __call__() got an unexpected keyword argument 'partition_info'
大量的嘗試后,這個錯誤還是不能規避掉。個人猜測是因為tensorflow的版本沖突。果然在退回了版本和引入keras的位置后,程序正常運行。
def bilinear_upsample(input_layer):output_layer = BilinearUpSampling2D((2,2))(input_layer)return output_layer
雙線性上采樣也是另一個bug出現的地方,這個bug的原因是在后面的layerc.concatenate函數中,兩層的shape不匹配。但是比較玄學的是,當我將它們print出來之后,兩者的shape完全一樣,但是根據報的錯誤來顯示,雙線性上采樣完全沒有起作用,輸出維度和采樣之前完全一樣。
這個錯誤最終我也沒有解決掉,猜測和上面的可分卷積函數出現的錯誤一樣。因為這兩者都采用了utils中的輔助函數SeparableConv2DKeras,這也很好的提醒了我,對于函數的使用,尤其是在tensorflow中,一定要注意版本的問題。
# 編碼器模塊
def encoder_block(input_layer, filters, strides):# TODO Create a separable convolution layer using the separable_conv2d_batchnorm() function.output_layer = separable_conv2d_batchnorm(input_layer, filters, strides)return output_layer# 解碼器模塊
def decoder_block(small_ip_layer, large_ip_layer, filters):# TODO Upsample the small input layer using the bilinear_upsample() function.upsampled = bilinear_upsample(small_ip_layer)print('upsampled_shape:', upsampled.shape)print('large_input_shape:', large_ip_layer.shape)# TODO Concatenate the upsampled and large input layers using layers.concatenateconcat_layer = layers.concatenate([upsampled, large_ip_layer])print('concat_layer_shape:', concat_layer.shape)# TODO Add some number of separable convolution layersoutput_layer = separable_conv2d_batchnorm(concat_layer, filters)return output_layer
之后我們就可以將上采樣和可分卷積整合到編碼器和解碼器之中了。
(3)建立模型
# 構建FCN模型
def fcn_model(inputs, num_classes):# TODO Add Encoder Blocks.# Remember that with each encoder layer, the depth of your model (the number of filters) increases.# TODO 添加編碼器模塊。# 請記住,對于每個編碼器層,模型的深度(過濾器的數量)都會增加。mid_layer_0 = encoder_block(inputs, filters=32, strides=2)print('mid_layer_0:', mid_layer_0)# TODO 使用conv2d_batchnorm()添加1x1卷積層。mid_layer_1 = conv2d_batchnorm(mid_layer_0, 32, 3, 1)print('mid_layer_1:', mid_layer_1)# TODO: 添加與編碼器塊數量相同的解碼器塊數量x = decoder_block(mid_layer_1, inputs, 32)# 該函數返回模型的輸出層。“x”是從最后一個decoder_block()中獲得的最后一層return layers.Conv2D(num_classes, 3, activation='softmax', padding='same')(x)
再有了上采樣和可分卷積之后,我們就可以搭建我們的FCN模型
(4)訓練
# 輸入圖片寬度
image_hw = 128
# 輸入圖片shape
image_shape = (image_hw, image_hw, 3)
inputs = layers.Input(image_shape)
num_classes = 3# Call fcn_model()
output_layer = fcn_model(inputs, num_classes)
建立完整的模型,有了模型之后我們就可以使用keras進行訓練了。
learning_rate = 0.001 # 學習率
batch_size = 32 # 批大小
num_epochs = 5 # 訓練輪數
steps_per_epoch = 200 # 每輪訓練步數
validation_steps = 50 # 驗證部署
workers = 2 # 最多啟動的進程數
定義一些超參數,解釋如上。
"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
# Define the Keras model and compile it for training
model = models.Model(inputs=inputs, outputs=output_layer)model.compile(optimizer=keras.optimizers.Adam(learning_rate), loss='categorical_crossentropy')# Data iterators for loading the training and validation data
train_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,data_folder=os.path.join('..', 'data', 'train'),image_shape=image_shape,shift_aug=True)val_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,data_folder=os.path.join('..', 'data', 'validation'),image_shape=image_shape)logger_cb = plotting_tools.LoggerPlotter()
callbacks = [logger_cb]model.fit_generator(train_iter,steps_per_epoch = steps_per_epoch, # the number of batches per epoch,epochs = num_epochs, # the number of epochs to train for,validation_data = val_iter, # validation iteratorvalidation_steps = validation_steps, # the number of batches to validate oncallbacks=callbacks,workers = workers)
使用keras訓練自定義的模型。
完整程序如下,其中還包括了驗證和預測部分:
import os
import glob
import sys
import tensorflow as tffrom scipy import misc
import numpy as npfrom tensorflow.contrib.keras.python import keras
from tensorflow.contrib.keras.python.keras import layers, modelsfrom tensorflow import imagefrom utils import scoring_utils
# 引入可分卷積函數
from utils.separable_conv2d import SeparableConv2DKeras, BilinearUpSampling2D
from utils import data_iterator
from utils import plotting_tools
from utils import model_tools# # 兩種方法構建編碼器
# 使用可分卷積構建編碼器
def separable_conv2d_batchnorm(input_layer, filters, strides=1):output_layer = SeparableConv2DKeras(filters=filters, kernel_size=3, strides=strides,padding='same', activation='relu')(input_layer)output_layer = layers.BatchNormalization()(output_layer)return output_layer# 使用常規卷積構建編碼器
def conv2d_batchnorm(input_layer, filters, kernel_size=3, strides=1):output_layer = layers.Conv2D(filters=filters, kernel_size=kernel_size, strides=strides,padding='same', activation='relu')(input_layer)output_layer = layers.BatchNormalization()(output_layer)return output_layer# # 構建上采樣函數
# 使用雙線性上采樣
def bilinear_upsample(input_layer):output_layer = BilinearUpSampling2D((2,2))(input_layer)return output_layer# # 建立模型
# 使用separable_conv2d_batchnorm()函數創建一個可分離的卷積層。
# 該filters參數定義輸出層的大小或深度。例如32或64。
def encoder_block(input_layer, filters, strides):# TODO Create a separable convolution layer using the separable_conv2d_batchnorm() function.output_layer = separable_conv2d_batchnorm(input_layer, filters, strides)return output_layer# 解碼器模塊
def decoder_block(small_ip_layer, large_ip_layer, filters):# TODO Upsample the small input layer using the bilinear_upsample() function.upsampled = bilinear_upsample(small_ip_layer)print('upsampled_shape:', upsampled.shape)print('large_input_shape:', large_ip_layer.shape)# TODO Concatenate the upsampled and large input layers using layers.concatenateconcat_layer = layers.concatenate([upsampled, large_ip_layer])print('concat_layer_shape:', concat_layer.shape)# TODO Add some number of separable convolution layersoutput_layer = separable_conv2d_batchnorm(concat_layer, filters)return output_layer# 構建FCN模型
def fcn_model(inputs, num_classes):# TODO Add Encoder Blocks.# Remember that with each encoder layer, the depth of your model (the number of filters) increases.# TODO 添加編碼器模塊。# 請記住,對于每個編碼器層,模型的深度(過濾器的數量)都會增加。mid_layer_0 = encoder_block(inputs, filters=32, strides=2)print('mid_layer_0:', mid_layer_0)# TODO 使用conv2d_batchnorm()添加1x1卷積層。mid_layer_1 = conv2d_batchnorm(mid_layer_0, 32, 3, 1)print('mid_layer_1:', mid_layer_1)# TODO: 添加與編碼器塊數量相同的解碼器塊數量x = decoder_block(mid_layer_1, inputs, 32)# 該函數返回模型的輸出層。“x”是從最后一個decoder_block()中獲得的最后一層return layers.Conv2D(num_classes, 3, activation='softmax', padding='same')(x)# # 訓練
# 以下單元格將利用您創建的模型并根據輸入和類數定義輸出層,隨后將定義用于編譯和訓練模型的超參數
image_hw = 128
image_shape = (image_hw, image_hw, 3)
inputs = layers.Input(image_shape)
num_classes = 3# Call fcn_model()
output_layer = fcn_model(inputs, num_classes)# 定義超參數。
#
# batch_size:一次通過網絡傳播的訓練樣本/圖像的數量。
# num_epochs:整個訓練數據集通過網絡傳播的次數。
# steps_per_epoch:在1個時期內通過網絡的訓練圖像的批次數。一種建議值是基于訓練數據集中的圖片總數除以batch_size。
# validation_steps:在1個時期內通過網絡的驗證圖像的批數。這與steps_per_epoch相似,只不過validation_steps用于驗證數據集。這里提供了默認值。
# worker:最多啟動的進程數。這會影響訓練速度,并取決于硬件配置。
learning_rate = 0.001
batch_size = 32
num_epochs = 2
steps_per_epoch = 200
validation_steps = 50
workers = 8"""
DON'T MODIFY ANYTHING IN THIS CELL THAT IS BELOW THIS LINE
"""
# Define the Keras model and compile it for training
model = models.Model(inputs=inputs, outputs=output_layer)model.compile(optimizer=keras.optimizers.Adam(learning_rate), loss='categorical_crossentropy')# Data iterators for loading the training and validation data
train_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,data_folder=os.path.join('..', 'data', 'train'),image_shape=image_shape,shift_aug=True)val_iter = data_iterator.BatchIteratorSimple(batch_size=batch_size,data_folder=os.path.join('..', 'data', 'validation'),image_shape=image_shape)logger_cb = plotting_tools.LoggerPlotter()
callbacks = [logger_cb]model.fit_generator(train_iter,steps_per_epoch = steps_per_epoch, # the number of batches per epoch,epochs = num_epochs, # the number of epochs to train for,validation_data = val_iter, # validation iteratorvalidation_steps = validation_steps, # the number of batches to validate oncallbacks=callbacks,workers = workers)# Save your trained model weights
weight_file_name = 'model_weights'
model_tools.save_network(model, weight_file_name)run_number = 'run1'
validation_path, output_path = model_tools.write_predictions_grade_set(model,run_number,'validation')im_files = plotting_tools.get_im_file_sample(run_number,validation_path)
for i in range(3):im_tuple = plotting_tools.load_images(im_files[i])plotting_tools.show_images(im_tuple)scoring_utils.score_run(validation_path, output_path)
input_shape: (?, 128, 128, 3)
encoder_shape: (?, 32, 32, 64)
1x1_shape: (?, 32, 32, 128)
upsampled_shape: (?, 64, 64, 128)
large_input_shape: (?, 64, 64, 32)
concat_layer_shape: (?, 64, 64, 160)
upsampled_shape: (?, 128, 128, 64)
large_input_shape: (?, 128, 128, 3)
concat_layer_shape: (?, 128, 128, 67)
output_shape: Tensor("batch_normalization_5/batchnorm/add_1:0", shape=(?, 128, 128, 32), dtype=float32)
Epoch 1/2
200/200 [==============================] - 823s - loss: 0.3584 - val_loss: 0.1122
Epoch 2/5
200/200 [==============================] - 836s - loss: 0.0561 - val_loss: 0.0936
Epoch 3/5
200/200 [==============================] - 833s - loss: 0.0501 - val_loss: 0.0782
Epoch 4/5
200/200 [==============================] - 925s - loss: 0.0465 - val_loss: 0.0716
Epoch 5/5
200/200 [==============================] - 829s - loss: 0.0456 - val_loss: 0.0640
(5)預測
以上是給出的某張驗證圖像。
這張是經過訓練后的模型的輸出,可以看出模型大致可以分出輪廓。
(6)評價
number of validation samples intersection over the union evaulated on 1184
average intersection over union for background is 0.9858371822735106
average intersection over union for other people is 0.14932455085825228
average intersection over union for hero is 0.0684055264892006
global average intersection over union is 0.40118908654032115
綜合來看,這個模型的正確率還是很低的,因為模型比較簡單,可以選擇增加模型深度來獲取更好的輸出,在這里我因為時間關系,只能簡單的構建模型然后訓練了。
總結
以上是生活随笔為你收集整理的Udacity机器人软件工程师课程笔记(三十) - 语义分割与实例实现 - 使用keras实现语义分割的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Udacity机器人软件工程师课程笔记(
- 下一篇: 【从零开始的ROS四轴机械臂控制】(一)