前言
這篇博客記錄的是如何製作自己的數據集,並使用FCN模型訓練數據,前提要搭建caffe框架,可以參考這篇博客,我製作的數據集是仿照voc2012數據集來在做的
製作圖像標籤
這一部分是最難的部分,在製作標籤之前要搞清楚你的圖像共分爲幾類
-
調整圖像尺寸
網上很多寫的代碼,但是我試了都不成功,於是自己寫了一個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
-
製作索引圖(即標籤)
這就是最難也是最煩的部分,很多博客都說用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)
訓練數據集
- benchmark數據集下載地址:benchmark數據集
VOC2012數據集下載地址:VOC2012數據集
benchmark數據集是用來存放訓練的數據,VOC2012數據集用來存放測試數據。 - 進入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)下載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
至此所有的工作已完成,在這探索的過程真的很心酸,所以想把過程記錄下來以方便以後的學習。