FCN製作自己的數據集並訓練和測試

前言

這篇博客記錄的是如何製作自己的數據集,並使用FCN模型訓練數據,前提要搭建caffe框架,可以參考這篇博客,我製作的數據集是仿照voc2012數據集來在做的

製作圖像標籤

這一部分是最難的部分,在製作標籤之前要搞清楚你的圖像共分爲幾類

  1. 調整圖像尺寸
    網上很多寫的代碼,但是我試了都不成功,於是自己寫了一個matlab代碼,可以將整個文件夾圖片縮成256*256大小,我圖片的命名規則是1,2,3,4……如果你圖像不是這樣命名的話就不能使用。如果誰有更好的代碼麻煩告知一二。

    ObjDir = 'D:\image1\';%將被改變的圖像地址,稱爲目標地址
    OtpDir = 'D:\image2\';%輸出圖像地址,稱爲輸出地址
    for i = 1:101 %我的圖片是101張
        bgFile = [ObjDir,num2str(i),'.jpg'];%這句話讀取目標地址裏面的格式爲jpg的圖片
        bgFile = imread(bgFile);%把圖片讀成matlab認識的,類型爲:圖片
        img = imresize(bgFile,[256,256]);%調整大小到高256,長256
        filename=[num2str(i),'.jpg'];%輸出的圖片名稱
        path=fullfile(OtpDir,filename);%輸出的路徑
        imwrite(img,path,'jpg');%以jpg格式輸出出去
    end
    
  2. 製作索引圖(即標籤)
    這就是最難也是最煩的部分,很多博客都說用labelme工具製作標籤,這工具確實方便,但是我試了之後才發現會出現問題,比如說第一張圖片有汽車,有小貓,這是兩個不同的類將會標註爲兩個不同的顏色,如果第二張圖片沒有汽車只有小貓的話,那這張圖片小貓將會和汽車標註成同一張顏色。可能我這樣解釋會有點蒙,你可以參考labelme安裝json批量轉化數據兩篇博客試試,有人解釋說是因爲labelme的版本變高自動生成顏色,但是並沒有給出解決辦法,於是在這一步的操作我選擇了使用photoshop工具。
    對應的voc數據集顏色類別爲:

    類別名稱 R G B
    background 0 0 0 背景
    aeroplane 128 0 0 飛機
    bicycle 0 128 0
    bird 128 128 0
    boat 0 0 128
    bottle 128 0 128 瓶子
    bus 0 128 128 大巴
    car 128 128 128
    cat 64 0 0 貓
    chair 192 0 0
    cow 64 128 0
    diningtable 192 128 0 餐桌
    dog 64 0 128
    horse 192 0 128
    motorbike 64 128 128
    person 192 128 128
    pottedplant 0 64 0 盆栽
    sheep 128 64 0
    sofa 0 192 0
    train 128 192 0
    tvmonitor 0 64 128 顯示器

這裏有21個類別,因爲我的圖片只有4類加上背景共5類,所以只用到了前五中顏色。如下面的圖是我是做的標籤,我是將所有一類放在一起製作的,這樣不容易亂,但是在訓練數據的時候,要將所有圖片打亂順序,以免出現訓練效果差的結果。(下面有好的方法不用打亂圖像順序)
在這裏插入圖片描述
用ps製作成的圖像保存爲png格式,這時你的圖片是24位的,接下來需要將圖像改爲8位的,下面是matlab代碼可以將整個文件夾的圖片改成8位。

dirs=dir('D:\24-testlabel\*.png');
for n=1:numel(dirs)
     strname=strcat('D:\24-testlabel\',dirs(n).name);
     img=imread(strname);
     x=rgb2ind(img,map);
     newname=strcat('D:\8-testlabel\',dirs(n).name);
     imwrite(x,map,newname,'png');
end

轉化完成後在Python中檢查一下圖片的格式。
在命令窗口輸入idle(前提你裝了python),輸入

import PIL.Image
import numpy as np
img = PIL.Image.open(D:/8-testlabel/1l.png')
np.unique(img)

如果輸出爲如下,則說明標籤製作成功。

array([0, 1, 2], dtype=uint8)

訓練數據集

  1. benchmark數據集下載地址:benchmark數據集
    VOC2012數據集下載地址:VOC2012數據集
    benchmark數據集是用來存放訓練的數據,VOC2012數據集用來存放測試數據。
  2. 進入fcn-master/data目錄,新建sbdd文件夾(如果沒有),將benchmark解壓到sbdd中,進入dataset文件夾,你將看到如圖所示五個文件,cls是用來存放索引圖(標籤),img用來存放訓練數據(原訓練圖像),train.txt用來存放訓練數據的名稱,val.txt用來存放驗證集的名稱(這裏並沒有用到)。
    在這裏插入圖片描述
    將你的訓練圖片複製到img文件夾下,圖片標籤複製到cls文件夾下,將你訓練圖片的名稱寫入到train.txt文件中,如下圖所示
    在這裏插入圖片描述
    因爲打亂圖片順序比較麻煩,所以可以將圖片名稱順序打亂,這樣方便的多。
    進入cls文件夾,這裏原本需要存放mat格式的文件,但是製作mat文件有點麻煩,參考了網上的資料,修改代碼,使得這裏也可以直接存放索引圖。
    方式如下:
    修改fcn目錄下的voc_layers.py
#    def load_label(self, idx):
#        """
#        Load label image as 1 x height x width integer array of label indices.
#        The leading singleton dimension is required by the loss.
#        """
#        import scipy.io
#        mat = scipy.io.loadmat('{}/cls/{}.mat'.format(self.sbdd_dir, idx))
#        label = mat['GTcls'][0]['Segmentation'][0].astype(np.uint8)
#        label = label[np.newaxis, ...]
#        return label

    def load_label(self, idx):
        """
        Load label image as 1 x height x width integer array of label indices.
        The leading singleton dimension is required by the loss.
        """
        im = Image.open('{}/cls/{}.png'.format(self.sbdd_dir, idx))
        label = np.array(im, dtype=np.uint8)
        label = label[np.newaxis, ...]
        return label

測試集的製作簡單一寫,進入VOC2012,進入JPEGImages文件夾,裏面存放測試用的原圖,然後進入SegmentationClass,裏面存放測試用的索引圖,最後進入ImageSets/Segmentation,新建seg11valid.txt的文件,它和train.txt的性質一樣,存放測試用的圖片名。
到此,數據集就準備完成了。

  1. 修改網絡參數
    (1)下載VGG16的預訓練模型VGG_ILSVRC_16_layers_deploy.prototxt並放在FCN源碼文件夾中的ilsvrc-nets文件夾下
    在這裏插入圖片描述
    (2)進入fcn-master目錄下,將所有py文件全部複製到voc-fcn32s(這裏用voc-fcn32s模型訓練數據),新建snapshot文件夾。
    在這裏插入圖片描述
    (3)打開solve.py文件
    爲了避免運行程序時候出現no module named caffe ,在代碼中包含import caffe的py文件的第一行加入

    import sys  
    sys.path.append('C:/caffe/caffe-master/python')
    

    其中,C:/caffe/caffe-master/python爲你下載的caffe源碼中python文件夾的路徑
    (4)修改solve.py文件

    ```
    import caffe
    import surgery, score
    
    import numpy as np
    import os
    import sys
    sys.path.append('C:/caffe/caffe-master/python')
    
    try:
       import setproctitle
       setproctitle.setproctitle(os.path.basename(os.getcwd()))
    except:
       pass
    
    #weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
    vgg_weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
    vgg_proto = '../ilsvrc-nets/VGG_ILSVRC_16_layers_deploy.prototxt'
    weights = '../ilsvrc-nets/vgg16-fcn.caffemodel'
    
    # init
    #caffe.set_device(int(sys.argv[1]))               
    caffe.set_mode_gpu()
    caffe.set_device(0)
    
    #solver = caffe.SGDSolver('solver.prototxt')
    #solver.net.copy_from(weights)
    solver = caffe.SGDSolver('solver.prototxt')
    vgg_net=caffe.Net(vgg_proto,vgg_weights,caffe.TRAIN)
    surgery.transplant(solver.net,vgg_net)
    del vgg_net
    
    
    # surgeries
    interp_layers = [k for k in solver.net.params.keys() if 'up' in k]
    surgery.interp(solver.net, interp_layers)
    
    # scoring
    val = np.loadtxt('D:/caffe/caffe-master/fcn-master/data/pascal/VOCdevkit/VOC2012/ImageSets/Segmentation/seg11valid.txt', dtype=str)       #根據你電腦自己的路徑修改
    
    for _ in range(25):
       solver.step(4000)
       score.seg_tests(solver, False, val, layer='score')
    ```
    

(5)solver.prototxt文件修改

	```
	train_net: "train.prototxt"
	test_net: "val.prototxt"
	test_iter: 2    #因爲我的圖片少,所以這裏測試圖片參數就寫少一點,如果圖片多的話可以使用默認參數
	# make test net, but don't invoke it from the solver itself
	test_interval: 999999999
	display: 20
	average_loss: 20
	lr_policy: "fixed"
	# lr for unnormalized softmax
	base_lr: 1e-10
	# high momentum
	momentum: 0.99
	# no gradient accumulation
	iter_size: 1
	max_iter: 100000
	weight_decay: 0.0005
	snapshot: 4000
	snapshot_prefix: "snapshot1/train"
	test_initialization: false
	```

(6)修改訓練,測試文件參數
用vs2013打開train.prototxt文件,根據自己電腦的路徑代碼修改爲:

param_str: "{\'sbdd_dir\': \'D:/caffe/caffe-master/fcn-master/data/sbdd/benchmark/benchmark_RELEASE/dataset\', \'seed\': 1337, \'split\': \'train\', \'mean\': (104.00699, 116.66877, 122.67892)}"

所有num_output 爲21 的地方都修改爲自己分類數 + 1 (加的1是背景)
用vs2013打開val.prototxt文件,根據自己電腦的路徑代碼修改爲:

param_str: "{\'voc_dir\': \'D:/caffe/caffe-master/fcn-master/data/pascal/VOCdevkit/VOC2012\', \'seed\': 1337, \'split\': \'seg11valid\', \'mean\': (104.00699, 116.66877, 122.67892)}"

所有num_output 爲21 的地方都修改爲自己分類數 + 1 (加的1是背景)
到此所有工作準備完成了,接下來開始訓練數據
(7)訓練數據
開cmd命令窗口,將目錄指定到voc-fcn32s路徑下,輸入

python.exe  solve.py

如下圖所示
在這裏插入圖片描述
(8)單張測試
在fcn-32s文件夾中找到infer.py文件,修改代碼爲

import numpy as np
from PIL import Image
import matplotlib.pyplot as plt
import caffe
import vis
import sys
sys.path.append('D:/caffe/caffe-master/python')

# the demo image is "2007_000129" from PASCAL VOC

# load image, switch to BGR, subtract mean, and make dims C x H x W for Caffe
im = Image.open('D:/caffe/caffe-master/fcn-master/voc-fcn32s/data/1.jpg')  #可以自己創建路徑
in_ = np.array(im, dtype=np.float32)
in_ = in_[:,:,::-1]
in_ -= np.array((104.00698793,116.66876762,122.67891434))
in_ = in_.transpose((2,0,1))

# load net
#net = caffe.Net('voc-fcn8s/deploy.prototxt', 'voc-fcn8s/fcn8s-heavy-pascal.caffemodel', caffe.TEST)
net = caffe.Net('D:/caffe/caffe-master/fcn-master/voc-fcn32s/deploy.prototxt', 'D:/caffe/caffe-master/fcn-master/voc-fcn32s/snapshot/train_iter_100000.caffemodel', caffe.TEST)
# shape for input (data blob is N x C x H x W), set data
net.blobs['data'].reshape(1, *in_.shape)
net.blobs['data'].data[...] = in_
# run net and take argmax for prediction
net.forward()
out = net.blobs['score'].data[0].argmax(axis=0)


# visualize segmentation in PASCAL VOC colors
voc_palette = vis.make_palette(21)
out_im = Image.fromarray(vis.color_seg(out, voc_palette))
out_im.save('data/output3.png')
masked_im = Image.fromarray(vis.vis_seg(im, out, voc_palette))
masked_im.save('data/visualization3.jpg')

fcn-32s和fcn-16s是沒有deploy文件,很多博客都是說參考train.prototxt創建deploy文件,我就是按照這樣的方法,但是根本不能正確測試圖片,這讓我一度懷疑自己的方向是不是錯的,走了很多彎路。後來我找到別人的deploy文件,直接下載複製到對應爲文件夾下就行。
deploy下載地址:deploy.prototxt

至此所有的工作已完成,在這探索的過程真的很心酸,所以想把過程記錄下來以方便以後的學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章