學習點:
製作LMDB數據集需要分類好的原始圖像文件夾、對應的txt文件、還可能有mean均值文件,所以寫了一個腳本文件生成LMDB數據集需要的train.txt和val.txt文件,並針對小樣本進行了數據增強,平移旋轉亮度等操作。
1、原始數據源
根據上圖可知,我們需要將每個類的名稱改稱從0開始的,所以先保存類列表到word.txt中,根據.重命名類名稱,修改後的文件類表如右圖所示:對應的這部分代碼爲:
#將每個分類的名稱寫入word.txt 86.Betta picta ( Spotted betta )-6334,並以開頭數字作爲文件夾的新名稱
def save_and_rename_file():
with open('./words.txt', 'w') as f:
#os.walk()根據你要遍歷的總目錄地址,返回:root 文件夾的本身地址;dirs:該文件夾內所有目錄的名字-list
#files:該文件夾中所有的文件(不包括子目錄)
for root, dirs, files in os.walk(data_dir):
for dir in dirs:
print(dir)
f.write(dir + "\n")
new_name = str(int(dir.split('.')[0]))
os.rename(os.path.join(data_dir, dir), os.path.join(data_dir, new_name))
保存的word.txt內容爲:
2、形成train.txt和al.txt文件
2.1 首先獲得總目錄下的所有文件,並寫入到all_image.txt文件夾中,代碼如下
#創建對應的數據集txt文檔
def create_dataset(txt_file):
dirs = os.listdir(data_dir)
with open(txt_file, 'w') as f:
for dir in dirs:
#caffe標籤從0開始,否則會出現錯誤
label = int(dir) - 1
#遍歷子文件夾內容
for file in os.listdir(os.path.join(data_dir, dir)):
# check image format;取文件的屬性一屆
prefix = file.split('.')[-1]
#如果不是圖像則進入下次判斷
if prefix not in ['jpg', 'JPG', 'png', 'PNG']:
continue
# check is valid image
file_path = os.path.join(data_dir, dir, file)
if not is_valid_image(file_path):
continue
#打標籤 42/3a5d40992dba684c665f536ec7c52ecc.jpg 41
f.write(dir+'/'+file + " " + str(label) + "\n")
這樣即形成了初始的txt文件,內容如下
2.2 數據增強
由於我們的樣本比較少,這裏我們對數據集進行了數據增強(旋轉,亮度)代碼如下,效果如下
#擴增數據集
def do_img_aument(txt_file):
images = list()
paths = list()
count = 0
with open(txt_file, 'r') as f:
for line in f:
file = line.split(" ")[0]
path = os.path.join(data_dir, file)
paths.append(path)
img = cv.imread(path)
images.append(img)
count = count + 1
#隨機增強,每過20就對累計圖像作一次擴增,相當於線程池
if count % 20 == 0:
print("do image augment")
new_images = img_aug(images)
for j in range(len(new_images)):
new_img = new_images[j]
new_path = paths[j].split(".")[0] + "_aug.jpg"
print(new_path)
cv.imwrite(new_path, new_img)
#清空池
images = []
paths = []
2.3 形成train.txt和val.txt文件
注意:這裏需要將數據集打亂才能得到比較好的結果,我數據集和驗證集的比例爲[8:2],代碼如下
#根據得到總的數據集,從中分離出一部分作爲驗證集[8:2]
def split_trainval(txt_file):
data_set = list()
with open(txt_file, 'r') as f:
for line in f:
data_set.append(line)
#打亂順序
random.shuffle(data_set)
#得到總的大小
size = len(data_set)
train_size = int(size * 0.8)
train_set = data_set[0:train_size]
valid_set = data_set[train_size:]
# 將結果分別存入對應的訓練集和測試集
with open('./train.txt', 'w') as f:
for data in train_set:
f.write(data)
with open('./val.txt', 'w') as f:
for data in valid_set:
f.write(data)
效果如圖所示:
2.4label映射
根據第一部獲取的word.txt,我們將label和Class進行映射,這樣最後會方便我的尋找【0,1,2】表示的是什麼類別,代碼如下
#打標籤 [0,1,2,3]-[XXX的種類]
def make_labels():
labels = list()
with open("./words.txt", 'r') as f:
for line in f:
class_numb = int(line.split('.')[0]) - 1
class_name = line.split('.')[-1].split(" ")[0]
labels.append(str(class_numb) + " " + class_name)
with open("./labels.txt", 'w') as f:
for label in labels:
f.write(label + "\n")
3、製作均值文件
執行一段代碼caffe代碼就可以,比較簡單,
#!/usr/bin/env sh
# Compute the mean image from the imagenet training lmdb
# N.B. this is available in data/ilsvrc12
EXAMPLE=examples/fishes
DATA=data/fishes
TOOLS=build/tools
$TOOLS/compute_image_mean $EXAMPLE/train_lmdb \
$DATA/imagenet_mean.binaryproto
echo "Done."
4、製作LMDB 文件
基本條件滿足後,就開始製作LMDB文件了,製作也是比較簡單,網上都有,這裏簡單說一下過程:
1、執行caffe-example文件下的create_imagenet.sh文件(創建均值文件是第二個)
2、執行後就可以看到效果了。這裏在說一下文件裏面的內容
代碼中resize一般要設置爲Resize=true;不然製作LMDB文件時會出現killed,這並不是CNN要求,主要是最後連接層的原因,後面的圖像就可以置爲false。具體可以網上搜索一下:resize爲什麼需要設置爲true?剩下的就是路徑的問題了。我們可以用心去看看EXAMPLE-DATA-TOOLS對應的什麼?其中tools比較好理解就是caffe的工具;data主要是你訓練集的總目錄和下面的TRAIN_DATA_ROOT /VAL_DATA_ROOT相關(可以從目錄中看出存在父子關係);EXAMPLE就和LMDB文件的存放相關了。
原始的數據源名稱是比較亂的,但是caffe分類需要從0開始,不然會報錯,