【蜂口 | AI人工智慧】caffe新增新網路層——龍鵬的一站式caffe工程實踐連載(四)

絵飛的魚發表於2018-09-25

知識引入

這次,我主要給大家 分享 Caffe中如何新增新的網路層

我們的任務是一個影像分割任務,在Caffe官方的框架之中,並不包含影像分割的任務,所以我們需要新增本任務相關方面的一些程式碼,具體來說將包含三個方面的內容:

第一、新增一個新的影像分割資料層

新增這個新的資料層之後,我們才能按照影像分割這樣一個任務,讀取我們需要訓練的檔案,以及將我們需要訓練的檔案載入記憶體中進行訓練。

第二、修改序列化檔案

為什麼要修改這樣一個序列化檔案呢?是因為影像分割這種任務,他本身比影像分類任務來說要更難一些,而且為了使我們訓練出來的模型非常魯棒,我們一般需要做比較多的資料增強的操作。而在Caffe框架之中,它原生只支援映象操作跟影像crop這樣的兩個基本操作。所以我們需要修改這個序列化檔案,增加一些新的資料增強操作的介面,也就是增加新的引數。

第三,新增新的datatranformer方法

與上面是類似的。影像分割任務本身,它資料讀取的方法以及資料篩選的方法肯定與影像分類任務不同。 所以我們需要在 data_tranformer.cpp 這個CPP之中新增對應的函式,從而增加我們相應的資料操作。

下面我們開始分別分享。首先第一個我們新增新的資料層標頭檔案,我們在include/caffe/layers這個目錄下新增了image_seg_data_layer.hpp,我們定義了一個新的資料層,也就是我們的影像分割任務資料層,他繼承了BasePrefetchingDataLayer。而BasePrefetchingDataLayer,它本身又繼承了BaseDataLayer和InternalThread這兩個基本類。關鍵程式碼如下:

繼承了這兩個基本類之後,就可以實現資料的讀取。我們的影像分割層繼承了BasePrefetchingDataLayer,也就繼承了它的資料介面,從而我們在CPP檔案之中就可以過載相應的函式,實現影像分割這個任務本身的資料讀取。

另外在.hpp檔案之中還定義了一個lines這樣的一個變數,如下所示:

變數詳解

在影像分類任務中也有類似這個變數,但是與我們的分割任務中的lines變數有所不同。影像分類任務,它載入的是圖片和一個標籤。圖片是一個string型別的變數,而標籤是一個0123這樣的一個int型的變數,所以它的基本資料格式是<string,int>,我們分割任務有所不同,分割任務,它的標籤也是一張跟原圖大小相同的影像。所以我們載入的影像分割的資料檔案格式,它是<imagepath,imagelabelpath>,也就是說都是string型別。 所以我們要定義一個<string,string>這樣一個基本資料格式的一個變數。有的HPP檔案之後,我們在CPP檔案之中對他進行實現,主要包含兩個函式,第一個是DataLayerSetup函式。這個函式它本身實現了對我們的訓練檔案的讀取,以及做一些基本的初始化操作。這樣一個函式在其中最重要的一部分程式碼就是如圖所示,可以看到我們透過getline這樣的一個函式,迴圈地讀取我們輸入的檔案,也就是source,source就是我們的訓練檔案,每一行讀取的檔案就是兩個string變數,分別是影像以及影像標籤的變數,然後將其投入lines這個變數之中,隨後我們就在load_batcj這個函式對lines變數之中的圖片進行讀取。load_batch這個函式,真正實現了資料的讀取,以及將我們讀取的圖片資料塞入到我們的視訊記憶體之中進行訓練。所以它包含兩個方面的操作。首先我們透過ReadImagetoCVMat這樣一個函式,在這個函式的內部是呼叫了Opencv的介面,它實現了影像資料的讀取。讀取完資料之後,我們存到了cv mat這樣的一個格式中,我們得到了cv_image以及cv_label這樣的兩個檔案。隨後我們透過data_tranformer中的TransformImageSeg這樣的一個函式來實現,將我們剛剛讀取的兩張圖片塞入到真正的記憶體之中,也就是prefetch_data和prefetch_label這兩個變數。

工廠模式

如果大家真正的讀過資料層的CPP就會看到在CBB的最後包含了以下兩行程式碼,也就是INSTANTIATE_CLASS和REGISTER_LAYER_CLASS這樣的兩行程式碼。這兩行程式碼是什麼意思呢?這就涉及到了caffe裡面的一個重要的設計模式,也就是工廠設計模式。透過這樣的兩行程式碼,我們真正實現了一個新的資料層的註冊。那什麼是工廠設計模式呢?大家知道Caffe是使用C++程式碼進行編寫。C++標準中最重要的一個設計模式就是物件導向的設計模式。物件導向設計模式之中,工廠設計模式就是最常用的例項化物件的模式,也就是定義了一個用於建立物件的介面,從而讓我們實現一個新的子類的時候,它本身可以決定例項化哪一個類。工廠設計模式可以大大提升程式碼的效率。工程設計模式是caffe整個框架中非常核心的設計模式和思想。大家可以在課下去細細地閱讀。

caffe.proto序列檔案

下面我們開始第二部分,caffe.proto序列檔案。前面我說過了,我們這個新的任務可能需要做一些新的影像增強相關方面的操作。所以我們看TransformerParam這樣的一個message。在這個message之中,我們定義了一些新的變數,包括constrast_brightness_adjustment,smooth_filtering等等。這其中包含了一些顏色擾動、對比度變化、旋轉變化相關方面的一些變數。隨後我們會實現這樣的一些影像增強操作。在Caffe.proto中定義完這些變數之後,我們需要在data_tranformer.cpp之中使用它。

TransformImageSeg函式

具體的使用是在data_tranformer的TransformImageSeg這樣的一個函式里面,在這個函式里首先我們可以透過param這樣的一個變數獲取它的成員變數,獲取到它的成員變數之後,我們就可以進行相關的資料操作的控制。所有這些資料增強操作的引數, 引數變數的控制, 都是事先在train.prototxt中進行配置的。總結一句就是說我們首先在train.prototxt配置了我們需要使用的資料增強的操作,然後根據我們定義的引數去尋找到相關的資料操作。隨後在image_data_layer.cpp,再去TransformImageSeg這個函式中進行最終的呼叫。

do_rotation變數

下面我們說說do_rotation這個變數,就是我們剛剛獲取的一個是否進行影像旋轉這樣操作的一個控制變數,這個變數,它最終的控制是在train.prototxt中,也就是我們的網路配置檔案中進行控制。如果為true,我們就要呼叫旋轉操作,旋轉操作這個函式,我們可以直接定義到data_tranformer.cpp檔案之中,它是data_tranformer.cpp的區域性函式,對其他的CPP來說它是不可見的。

rotate函式

在rotate的函式之中,我們做一些影像旋轉的操作,更多的資料增強相關方面的操作,大家可以去我的github專案中進行仔細的閱讀,此處不再一一贅述。

在經過資料增強操作之後,我們就需要將我們的資料真正地塞入到視訊記憶體之中,這樣才能夠進行訓練。主要包含兩個方面。第一個是賦值,我們需要獲取到mutable_cpu_data這樣的一個資料指標,它是一個可擦寫的資料指標。透過這個資料指標,我們就可以獲tranformed_image_blob和tranformed_label_blob相應的資料指標。隨後我們透過一個for迴圈來進行賦值操作。在這個賦值操作之中,就做一些常見的影像變化,包括是否做scale,是否減去均值,是否做一些影像尺度相關方面的操作,關鍵程式碼如下所示:

新增一個新的影像分割任務的網路相關操作,我們本次就說到這裡。

完整內容及影片解讀,請微信搜尋關注蜂口小程式~?

參與內測,免費獲取蜂口所有內容,更有其他優惠福利多多,,若想獲得內測種子使用者資格,歡迎微信fengkou-IT勾搭,歡迎大家多多參與,盡情挑刺,凡是好的建議,我們都會虛心採納噠

蜂口小程式將持續為你帶來最新技術的落地方法,歡迎隨時關注瞭解~



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31553577/viewspace-2214817/,如需轉載,請註明出處,否則將追究法律責任。

相關文章