个人笔记本上win10+yolov3+python+tensorflow+keras训练自己的识别模型
本文是在前人的很多基礎(chǔ)上自己整理所得,借鑒的資料見文末鏈接,感謝各位大神的無私分享。
對(duì)于yolo小白,參閱博文學(xué)習(xí):keras-yolov3目標(biāo)檢測(cè)詳解——適合新手,?(環(huán)境配置、用官方權(quán)重識(shí)別自己的圖片)
前提準(zhǔn)備:
1、配置好環(huán)境的 python、pycharm
2、labelimg 軟件:下載方法: labelme
3、準(zhǔn)備一些圖片,創(chuàng)建訓(xùn)練需要的 VOC 文件
(1) 官方的VOC2007下載鏈接:http://host.robots.ox.ac.uk/pascal/VOC/voc2007/VOCtrainval_06-Nov-2007.tar,可以從這里找需要的圖片,或者一些有基礎(chǔ)的朋友可以寫爬蟲去爬一些圖片
(2) voc2007百度網(wǎng)盤下載鏈接:
?
正式訓(xùn)練步驟:
1、打開文件夾
先按照這篇文章的步驟操作:keras-yolov3目標(biāo)檢測(cè)詳解——適合新手
完成后打開的文件夾應(yīng)該是這樣的:
2、新建voc2007數(shù)據(jù)集(存放自己的圖片及標(biāo)注信息)
新建的文件夾:如下
ImageSets?文件夾下還有個(gè)名為?Main?的小文件夾
文件結(jié)構(gòu)
VOCdevkit{VOC2007{ AnnotationsImageSets{main}JPEGImages } } 雖然表達(dá)的很丑,但是上面有圖,應(yīng)該還是可以看明白的 注意:文件夾的名稱必須和上面展示的一樣,這是 yolo 默認(rèn)的不然還需要改代碼才行3、用labelimg軟件對(duì)自己的圖片進(jìn)行信息標(biāo)注
----labelimg 的使用方法:labelimg 下載和標(biāo)注 xlm 文件
(1)需要訓(xùn)練的圖片放在?JPEGImages?里面:
(2)labelimg 標(biāo)注的 xml 文件放在?Annotations?里面:
4、在 VOC2007 里新建一個(gè) py 文件,取名 voc.py
import os import randomtrainval_percent = 0.2 #測(cè)試集占0.2 train_percent = 0.8 #訓(xùn)練集占0.8 xmlfilepath = 'Annotations' txtsavepath = 'ImageSets\Main' total_xml = os.listdir(xmlfilepath)num = len(total_xml) list = range(num) tv = int(num * trainval_percent) tr = int(tv * train_percent) trainval = random.sample(list, tv) train = random.sample(trainval, tr)ftrainval = open('ImageSets/Main/trainval.txt', 'w') ftest = open('ImageSets/Main/test.txt', 'w') ftrain = open('ImageSets/Main/train.txt', 'w') fval = open('ImageSets/Main/val.txt', 'w')for i in list:name = total_xml[i][:-4] + '\n'if i in trainval:ftrainval.write(name)if i in train:ftest.write(name)else:fval.write(name)else:ftrain.write(name)ftrainval.close() ftrain.close() fval.close() ftest.close()然后運(yùn)行 voc.py 文件,運(yùn)行成功的話 mian 文件夾里會(huì)多了四個(gè) txt 文件
二、進(jìn)行訓(xùn)練前的最后準(zhǔn)備
1、修改?voc_annotation.py?文件并運(yùn)行
更改這里的 classes 的數(shù)量,你voc2007里標(biāo)注了哪幾種,你就留哪幾種就行
比如我的 voc 中只標(biāo)注了 “person”,那我只留下“person”,然后再運(yùn)行一下就行
運(yùn)行完成后會(huì)多出這幾個(gè) txt 文件
2、修改 model_data
將 coco_classes.txt 和 voc_classes.txt 中也只留下VOC2007 中所標(biāo)注的那個(gè)類型
比如我標(biāo)注的只有 “person”。那我只留下“person”
3、修改 yolo3.cfg
大概在 610、696 和 783 行的位置,把 classes 的數(shù)值都改為 1
注:IDE里直接打開cfg文件,ctrl+f搜 yolo, 總共會(huì)搜出3個(gè)含有yolo的地方,睜開你的卡姿蘭大眼睛,3個(gè)yolo!!
????每個(gè)地方都要改3處,filters:3*(5+len(classes));
????????????????????????????????????classes: len(classes) = 3,這里以紅、黃、藍(lán)三個(gè)顏色為例?
4、添加官方權(quán)重
按照上篇博文步驟進(jìn)行的朋友應(yīng)該下載好了?yolov3.weights?文件并轉(zhuǎn)為了?yolo.h5?文件
附上上篇博文的鏈接(里面有下載鏈接和轉(zhuǎn)化方法):keras-yolov3目標(biāo)檢測(cè)詳解——適合新手
將?yolo.h5?改名為?yolo_weights.h5
5、新建 logs 文件夾存放訓(xùn)練的 權(quán)重文件
6、開始訓(xùn)練
有官方版本,有些大神說官方版本出錯(cuò),自己寫了訓(xùn)練腳本,我用的官方的,沒出問題,整體的原理一樣,主要是第三方庫(kù)的問題。
""" Retrain the YOLO model for your own dataset. """import numpy as np # import keras.backend as K from tensorflow.compat.v1.keras import backend as K from keras.layers import Input, Lambda from keras.models import Model from keras.optimizers import Adam from keras.callbacks import TensorBoard, ModelCheckpoint, ReduceLROnPlateau, EarlyStoppingfrom yolo3.model import preprocess_true_boxes, yolo_body, tiny_yolo_body, yolo_loss from yolo3.utils import get_random_datadef _main():annotation_path = 'train.txt'log_dir = 'logs/'classes_path = 'model_data/voc_classes.txt'anchors_path = 'model_data/yolo_anchors.txt'class_names = get_classes(classes_path)num_classes = len(class_names)anchors = get_anchors(anchors_path)input_shape = (416, 416) # multiple of 32, hwis_tiny_version = len(anchors) == 6 # default settingif is_tiny_version:model = create_tiny_model(input_shape, anchors, num_classes,freeze_body=2, weights_path='model_data/tiny_yolo_weights.h5')else:model = create_model(input_shape, anchors, num_classes,freeze_body=2, weights_path='model_data/yolo_weights.h5') # make sure you know what you freezelogging = TensorBoard(log_dir=log_dir)checkpoint = ModelCheckpoint(log_dir + 'ep{epoch:03d}-loss{loss:.3f}-val_loss{val_loss:.3f}.h5',monitor='val_loss', save_weights_only=True, save_best_only=True, period=3)reduce_lr = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=3, verbose=1)early_stopping = EarlyStopping(monitor='val_loss', min_delta=0, patience=10, verbose=1)val_split = 0.1with open(annotation_path) as f:lines = f.readlines()np.random.seed(10101)np.random.shuffle(lines)np.random.seed(None)num_val = int(len(lines)*val_split)num_train = len(lines) - num_val# Train with frozen layers first, to get a stable loss.# Adjust num epochs to your dataset. This step is enough to obtain a not bad model.if True:model.compile(optimizer=Adam(lr=1e-3), loss={# use custom yolo_loss Lambda layer.'yolo_loss': lambda y_true, y_pred: y_pred})batch_size = 32print('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),steps_per_epoch=max(1, num_train//batch_size),validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors, num_classes),validation_steps=max(1, num_val//batch_size),epochs=50,initial_epoch=0,callbacks=[logging, checkpoint])model.save_weights(log_dir + 'trained_weights_stage_1.h5')# Unfreeze and continue training, to fine-tune.# Train longer if the result is not good.if True:for i in range(len(model.layers)):model.layers[i].trainable = Truemodel.compile(optimizer=Adam(lr=1e-4), loss={'yolo_loss': lambda y_true, y_pred: y_pred}) # recompile to apply the changeprint('Unfreeze all of the layers.')batch_size = 32 # note that more GPU memory is required after unfreezing the bodyprint('Train on {} samples, val on {} samples, with batch size {}.'.format(num_train, num_val, batch_size))model.fit_generator(data_generator_wrapper(lines[:num_train], batch_size, input_shape, anchors, num_classes),steps_per_epoch=max(1, num_train//batch_size),validation_data=data_generator_wrapper(lines[num_train:], batch_size, input_shape, anchors, num_classes),validation_steps=max(1, num_val//batch_size),epochs=100,initial_epoch=50,callbacks=[logging, checkpoint, reduce_lr, early_stopping])model.save_weights(log_dir + 'trained_weights_final.h5')# Further training if needed.def get_classes(classes_path):'''loads the classes'''with open(classes_path) as f:class_names = f.readlines()class_names = [c.strip() for c in class_names]return class_namesdef get_anchors(anchors_path):'''loads the anchors from a file'''with open(anchors_path) as f:anchors = f.readline()anchors = [float(x) for x in anchors.split(',')]return np.array(anchors).reshape(-1, 2)def create_model(input_shape, anchors, num_classes, load_pretrained=True, freeze_body=2,weights_path='model_data/yolo_weights.h5'):'''create the training model'''K.clear_session() # get a new sessionimage_input = Input(shape=(None, None, 3))h, w = input_shapenum_anchors = len(anchors)y_true = [Input(shape=(h//{0:32, 1:16, 2:8}[l], w//{0:32, 1:16, 2:8}[l], \num_anchors//3, num_classes+5)) for l in range(3)]model_body = yolo_body(image_input, num_anchors//3, num_classes)print('Create YOLOv3 model with {} anchors and {} classes.'.format(num_anchors, num_classes))if load_pretrained:model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)print('Load weights {}.'.format(weights_path))if freeze_body in [1, 2]:# Freeze darknet53 body or freeze all but 3 output layers.num = (185, len(model_body.layers)-3)[freeze_body-1]for i in range(num): model_body.layers[i].trainable = Falseprint('Freeze the first {} layers of total {} layers.'.format(num, len(model_body.layers)))model_loss = Lambda(yolo_loss, output_shape=(1,), name='yolo_loss',arguments={'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.5})([*model_body.output, *y_true])model = Model([model_body.input, *y_true], model_loss)return modeldef create_tiny_model(input_shape, anchors, num_classes, load_pretrained=True, freeze_body=2,weights_path='model_data/tiny_yolo_weights.h5'):'''create the training model, for Tiny YOLOv3'''K.clear_session() # get a new sessionimage_input = Input(shape=(None, None, 3))h, w = input_shapenum_anchors = len(anchors)y_true = [Input(shape=(h//{0:32, 1:16}[l], w//{0:32, 1:16}[l], \num_anchors//2, num_classes+5)) for l in range(2)]model_body = tiny_yolo_body(image_input, num_anchors//2, num_classes)print('Create Tiny YOLOv3 model with {} anchors and {} classes.'.format(num_anchors, num_classes))if load_pretrained:model_body.load_weights(weights_path, by_name=True, skip_mismatch=True)print('Load weights {}.'.format(weights_path))if freeze_body in [1, 2]:# Freeze the darknet body or freeze all but 2 output layers.num = (20, len(model_body.layers)-2)[freeze_body-1]for i in range(num): model_body.layers[i].trainable = Falseprint('Freeze the first {} layers of total {} layers.'.format(num, len(model_body.layers)))model_loss = Lambda(yolo_loss, output_shape=(1,), name='yolo_loss',arguments={'anchors': anchors, 'num_classes': num_classes, 'ignore_thresh': 0.7})([*model_body.output, *y_true])model = Model([model_body.input, *y_true], model_loss)return modeldef data_generator(annotation_lines, batch_size, input_shape, anchors, num_classes):'''data generator for fit_generator'''n = len(annotation_lines)i = 0while True:image_data = []box_data = []for b in range(batch_size):if i == 0:np.random.shuffle(annotation_lines)image, box = get_random_data(annotation_lines[i], input_shape, random=True)image_data.append(image)box_data.append(box)i = (i+1) % nimage_data = np.array(image_data)box_data = np.array(box_data)y_true = preprocess_true_boxes(box_data, input_shape, anchors, num_classes)yield [image_data, *y_true], np.zeros(batch_size)def data_generator_wrapper(annotation_lines, batch_size, input_shape, anchors, num_classes):n = len(annotation_lines)if n == 0 or batch_size <= 0:return Nonereturn data_generator(annotation_lines, batch_size, input_shape, anchors, num_classes)if __name__ == '__main__':_main()成功開始訓(xùn)練,訓(xùn)練時(shí)間比較長(zhǎng),需要耐心等待
訓(xùn)練完成:
我的結(jié)果還沒跑完,下面結(jié)果看看就行
訓(xùn)練好的權(quán)重都放在 logs 文件夾下的 000 文件夾里:
?
按理說訓(xùn)練會(huì)經(jīng)過兩個(gè)階段,且自動(dòng)從一堆 loss 中選則出 loss最低的文件(應(yīng)該是 earlystop函數(shù)的作用):
應(yīng)該就是下面的框選的這兩個(gè) h5文件,都可以使用
使用的方法就和前面那篇博文操作一樣了(用這個(gè)h5權(quán)重模型去識(shí)別自己圖片),
?
?
?
參考資料:
1、https://blog.csdn.net/qq_45504119/article/details/105052478?重點(diǎn)
2、https://blog.csdn.net/Patrick_Lxc/article/details/80615433
3、https://blog.csdn.net/m0_37857151/article/details/81330699
4、https://blog.csdn.net/mingqi1996/article/details/83343289
5、https://blog.csdn.net/davidlee8086/article/details/79693079
6、https://blog.csdn.net/u012746060/article/details/81183006
7、https://blog.csdn.net/weixin_45488478/article/details/98397947
8、https://blog.csdn.net/sinat_26917383/article/details/85614247?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.nonecase
9、
?
?
總結(jié)
以上是生活随笔為你收集整理的个人笔记本上win10+yolov3+python+tensorflow+keras训练自己的识别模型的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Python2和Python3除法差别
- 下一篇: python3批量修改文件名称 代码说明