日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

ssd训练自己数据集

發(fā)布時(shí)間:2025/3/15 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 ssd训练自己数据集 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

1、用labelImg標(biāo)數(shù)據(jù)

2、將數(shù)據(jù)轉(zhuǎn)換為tfrecord

錯(cuò)誤記錄:

NotFoundError:無法創(chuàng)建NewWriteableFile?

解決方法:您需要在運(yùn)行此腳本的運(yùn)行環(huán)境文件夾中自己創(chuàng)建一個(gè)目錄

1、前期準(zhǔn)備工作

第一步:先將SSD框架下載到本地,解壓出來;SSD源碼下載

第二步:在解壓出來的主目錄下依次創(chuàng)建tfrecords_、train_model、VOC2007文件夾,再將之前在SSD目標(biāo)檢測(2):如何制作自己的數(shù)據(jù)集(詳細(xì)說明附源碼)中制作的三個(gè)文件夾Annotations、ImageSets、JPEGImages全都拖入VOC2007文件夾內(nèi);
第2.5步:為方便操作不易混淆,請?jiān)赑yCharm里建立工程;得到的截圖如下,截圖說明如下:

? ? ? ? ?1、請注意紅色框VOCxxx使用的是具體的名字,不過一般都是VOC2007;

? ? ? ? ?2、目錄對應(yīng)的從屬關(guān)系不要出錯(cuò)

? ?3、tfrecords_文件夾是用來存儲.tfrecords文件(后面有程序可以直接生成)

? ?4、train_model文件夾是用來存儲模型的記錄與參數(shù)的

2、生成.tfrecords文件的代碼微調(diào)說明

第三步:修改標(biāo)簽項(xiàng)——打開datasets文件夾中pascalvoc_common.py文件,將自己的標(biāo)簽項(xiàng)填入。我之前做的圖片標(biāo)簽.xml文件中,就只有一個(gè)標(biāo)簽項(xiàng)“watch”,所以要根據(jù)你自己數(shù)據(jù)集實(shí)際情況進(jìn)行修改;

第四步:修改讀取個(gè)數(shù)、讀取方式——打開datasets文件夾中的pascalvoc_to_tfrecords.py文件,

  • 修改67行SAMPLES_PER_FILES的個(gè)數(shù);
  • 修改83行讀取方式為'rb';
  • 如果你的文件不是.jpg格式,也可以修改圖片的類型;

3、生成.tfrecords文件

第五步:生成.tfrecords文件——打開tf_convert_data.py文件,依次點(diǎn)擊:run、Edit Configuration,在Parameters中填入以下內(nèi)容,再運(yùn)行tf_convert_data.py文件,在面板中得到成功信息,可以在tfrecords_文件夾下看到生成的.tfrecords文件;
?

--dataset_name=pascalvoc --dataset_dir=./VOC2007/ --output_name=voc_2007_train --output_dir=./tfrecords_

4、重新訓(xùn)練模型的代碼微調(diào)說明

第六步:修改訓(xùn)練數(shù)據(jù)shape——打開datasets文件夾中的pascalvoc_2007.py文件,

? ? 根據(jù)自己訓(xùn)練數(shù)據(jù)修改:NUM_CLASSES = 類別數(shù);

說明:TRAIN_STATISTICS的數(shù)值我并沒有深入了解,大于新數(shù)據(jù)集該標(biāo)簽的總數(shù)一般都不會報(bào)錯(cuò)。我的數(shù)據(jù)集是由20張、每張包含一只手表的圖片組成,所以下圖的值我設(shè)定為20,大于20也沒有報(bào)錯(cuò),如果你有更精確的想法,請留言告訴大家!

第七步:修改類別個(gè)數(shù)——打開nets文件夾中的ssd_vgg_300.py文件,

? ? ?根據(jù)自己訓(xùn)練類別數(shù)修改96 和97行:等于類別數(shù)+1

第八步:修改類別個(gè)數(shù)——打開eval_ssd_network.py文件,

? ? ? ??修改66行的類別個(gè)數(shù):等于類別數(shù)+1

第九步:修改訓(xùn)練步數(shù)epoch——打開train_ssd_network.py文件

  • 修改27行的數(shù)據(jù)格式,改為'NHWC';
  • 修改135行的類別個(gè)數(shù):等于類別數(shù)+1
  • 修改154行訓(xùn)練總步數(shù),None會無限訓(xùn)練下去;
  • 說明:60行、63行是關(guān)于模型保存的參數(shù);

5、加載vgg_16,重新訓(xùn)練模型

第十步:下載vgg_16模型——下載地址請點(diǎn)擊,密碼:ge3x;下載完成解壓后存入checkpoint文件中;
最后一步:重新訓(xùn)練模型——打開train_ssd_network.py文件,依次點(diǎn)擊:run、Edit Configuration,在Parameters中填入以下內(nèi)容,再運(yùn)行train_ssd_network.py文件

--train_dir=./train_model/ --dataset_dir=./tfrecords_/ --dataset_name=pascalvoc_2007 --dataset_split_name=train --model_name=ssd_300_vgg --checkpoint_path=./checkpoints/vgg_16.ckpt --checkpoint_model_scope=vgg_16 --checkpoint_exclude_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box --trainable_scopes=ssd_300_vgg/conv6,ssd_300_vgg/conv7,ssd_300_vgg/block8,ssd_300_vgg/block9,ssd_300_vgg/block10,ssd_300_vgg/block11,ssd_300_vgg/block4_box,ssd_300_vgg/block7_box,ssd_300_vgg/block8_box,ssd_300_vgg/block9_box,ssd_300_vgg/block10_box,ssd_300_vgg/block11_box --save_summaries_secs=60 --save_interval_secs=100 --weight_decay=0.0005 --optimizer=adam --learning_rate=0.001 --learning_rate_decay_factor=0.94 --batch_size=4 --gpu_memory_fraction=0.7

注意:上面是輸入?yún)?shù):

? ? --save_interval_secs是訓(xùn)練多少次保存參數(shù)的步長;
? ? --optimizer是優(yōu)化器;
? ? --learning_rate是學(xué)習(xí)率;
? ? --learning_rate_decay_factor是學(xué)習(xí)率衰減因子;
? ? 如果你的機(jī)器比較強(qiáng)大,可以適當(dāng)增大--batch_size的數(shù)值,以及調(diào)高GPU的占比--gpu_memory_fraction
? ? --model_name:我并沒有嘗試使用其他的模型做增量訓(xùn)練,如果你有需要,也請留言聯(lián)系我,我很樂意研究;

若得到下圖日志,即說明模型開始訓(xùn)練:

訓(xùn)練結(jié)束可以在train_model文件夾下看到生成的參數(shù)文件;

到這里,訓(xùn)練終于結(jié)束了!!!

二、結(jié)果展示

這是我訓(xùn)練的loss,我的數(shù)據(jù)集總共就20張圖片,進(jìn)行4.8W次訓(xùn)練用了將近一個(gè)小時(shí),我的配置是GTX1060的單顯卡;

1、在日志中,選取最后一次生成模型作為測試模型進(jìn)行測試;
2、在demo文件夾下放入測試圖片;
3、最后在notebooks文件夾下建立demo_test.py測試文件,代碼如下:
4、注意第48行,導(dǎo)入的新模型的名稱是否正確

# -*- coding:utf-8 -*- # -*- author:zzZ_CMing CSDN address:https://blog.csdn.net/zzZ_CMing # -*- 2018/07/20; 15:19 # -*- python3.6 import os import math import random import numpy as np import tensorflow as tf import cv2 import matplotlib.pyplot as plt import matplotlib.image as mpimg from nets import ssd_vgg_300, ssd_common, np_methods from preprocessing import ssd_vgg_preprocessing from notebooks import visualization import syssys.path.append('../') slim = tf.contrib.slim # TensorFlow session: grow memory when needed. TF, DO NOT USE ALL MY GPU MEMORY!!! gpu_options = tf.GPUOptions(allow_growth=True) config = tf.ConfigProto(log_device_placement=False, gpu_options=gpu_options) isess = tf.InteractiveSession(config=config)# 定義數(shù)據(jù)格式,設(shè)置占位符 net_shape = (300, 300) # 輸入圖像的通道排列形式,'NHWC'表示 [batch_size,height,width,channel] data_format = 'NHWC' # 預(yù)處理,以Tensorflow backend, 將輸入圖片大小改成 300x300,作為下一步輸入 img_input = tf.placeholder(tf.uint8, shape=(None, None, 3)) # 數(shù)據(jù)預(yù)處理,將img_input輸入的圖像resize為300大小,labels_pre,bboxes_pre,bbox_img待解析 image_pre, labels_pre, bboxes_pre, bbox_img = ssd_vgg_preprocessing.preprocess_for_eval(img_input, None, None, net_shape, data_format, resize=ssd_vgg_preprocessing.Resize.WARP_RESIZE) # 拓展為4維變量用于輸入 image_4d = tf.expand_dims(image_pre, 0)# 定義SSD模型 # 是否復(fù)用,目前我們沒有在訓(xùn)練所以為None reuse = True if 'ssd_net' in locals() else None # 調(diào)出基于VGG神經(jīng)網(wǎng)絡(luò)的SSD模型對象,注意這是一個(gè)自定義類對象 ssd_net = ssd_vgg_300.SSDNet() # 得到預(yù)測類和預(yù)測坐標(biāo)的Tensor對象,這兩個(gè)就是神經(jīng)網(wǎng)絡(luò)模型的計(jì)算流程 with slim.arg_scope(ssd_net.arg_scope(data_format=data_format)):predictions, localisations, _, _ = ssd_net.net(image_4d, is_training=False, reuse=reuse)# 導(dǎo)入新訓(xùn)練的模型參數(shù) ckpt_filename = '../train_model/model.ckpt-xxx' # 注意xxx代表的數(shù)字是否和文件夾下的一致 # ckpt_filename = '../checkpoints/VGG_VOC0712_SSD_300x300_ft_iter_120000.ckpt' isess.run(tf.global_variables_initializer()) saver = tf.train.Saver() saver.restore(isess, ckpt_filename)# 在網(wǎng)絡(luò)模型結(jié)構(gòu)中,提取搜索網(wǎng)格的位置 # 根據(jù)模型超參數(shù),得到每個(gè)特征層(這里用了6個(gè)特征層,分別是4,7,8,9,10,11)的anchors_boxes ssd_anchors = ssd_net.anchors(net_shape) """ 每層的anchors_boxes包含4個(gè)arrayList,前兩個(gè)List分別是該特征層下x,y坐標(biāo)軸對于原圖(300x300)大小的映射 第三,四個(gè)List為anchor_box的長度和寬度,同樣是經(jīng)過歸一化映射的,根據(jù)每個(gè)特征層box數(shù)量的不同,這兩個(gè)List元素 個(gè)數(shù)會變化。其中,長寬的值根據(jù)超參數(shù)anchor_sizes和anchor_ratios制定。 """# 主流程函數(shù) def process_image(img, select_threshold=0.6, nms_threshold=.01, net_shape=(300, 300)):# select_threshold:box閾值——每個(gè)像素的box分類預(yù)測數(shù)據(jù)的得分會與box閾值比較,高于一個(gè)box閾值則認(rèn)為這個(gè)box成功框到了一個(gè)對象# nms_threshold:重合度閾值——同一對象的兩個(gè)框的重合度高于該閾值,則運(yùn)行下面去重函數(shù)# 執(zhí)行SSD模型,得到4維輸入變量,分類預(yù)測,坐標(biāo)預(yù)測,rbbox_img參數(shù)為最大檢測范圍,本文固定為[0,0,1,1]即全圖rimg, rpredictions, rlocalisations, rbbox_img = isess.run([image_4d, predictions, localisations, bbox_img],feed_dict={img_input: img})# ssd_bboxes_select()函數(shù)根據(jù)每個(gè)特征層的分類預(yù)測分?jǐn)?shù),歸一化后的映射坐標(biāo),# ancohor_box的大小,通過設(shè)定一個(gè)閾值計(jì)算得到每個(gè)特征層檢測到的對象以及其分類和坐標(biāo)rclasses, rscores, rbboxes = np_methods.ssd_bboxes_select(rpredictions, rlocalisations, ssd_anchors,select_threshold=select_threshold, img_shape=net_shape, num_classes=21, decode=True)"""這個(gè)函數(shù)做的事情比較多,這里說的細(xì)致一些:首先是輸入,輸入的數(shù)據(jù)為每個(gè)特征層(一共6個(gè),見上文)的:rpredictions: 分類預(yù)測數(shù)據(jù),rlocalisations: 坐標(biāo)預(yù)測數(shù)據(jù),ssd_anchors: anchors_box數(shù)據(jù)其中:分類預(yù)測數(shù)據(jù)為當(dāng)前特征層中每個(gè)像素的每個(gè)box的分類預(yù)測坐標(biāo)預(yù)測數(shù)據(jù)為當(dāng)前特征層中每個(gè)像素的每個(gè)box的坐標(biāo)預(yù)測anchors_box數(shù)據(jù)為當(dāng)前特征層中每個(gè)像素的每個(gè)box的修正數(shù)據(jù)函數(shù)根據(jù)坐標(biāo)預(yù)測數(shù)據(jù)和anchors_box數(shù)據(jù),計(jì)算得到每個(gè)像素的每個(gè)box的中心和長寬,這個(gè)中心坐標(biāo)和長寬會根據(jù)一個(gè)算法進(jìn)行些許的修正,從而得到一個(gè)更加準(zhǔn)確的box坐標(biāo);修正的算法會在后文中詳細(xì)解釋,如果只是為了理解算法流程也可以不必深究這個(gè),因?yàn)檫@個(gè)修正算法屬于經(jīng)驗(yàn)算法,并沒有太多邏輯可循。修正完box和中心后,函數(shù)會計(jì)算每個(gè)像素的每個(gè)box的分類預(yù)測數(shù)據(jù)的得分,當(dāng)這個(gè)分?jǐn)?shù)高于一個(gè)閾值(這里是0.5)則認(rèn)為這個(gè)box成功框到了一個(gè)對象,然后將這個(gè)box的坐標(biāo)數(shù)據(jù),所屬分類和分類得分導(dǎo)出,從而得到:rclasses:所屬分類rscores:分類得分rbboxes:坐標(biāo)最后要注意的是,同一個(gè)目標(biāo)可能會在不同的特征層都被檢測到,并且他們的box坐標(biāo)會有些許不同,這里并沒有去掉重復(fù)的目標(biāo),而是在下文中專門用了一個(gè)函數(shù)來去重"""# 檢測有沒有超出檢測邊緣rbboxes = np_methods.bboxes_clip(rbbox_img, rbboxes)rclasses, rscores, rbboxes = np_methods.bboxes_sort(rclasses, rscores, rbboxes, top_k=400)# 去重,將重復(fù)檢測到的目標(biāo)去掉rclasses, rscores, rbboxes = np_methods.bboxes_nms(rclasses, rscores, rbboxes, nms_threshold=nms_threshold)# 將box的坐標(biāo)重新映射到原圖上(上文所有的坐標(biāo)都進(jìn)行了歸一化,所以要逆操作一次)rbboxes = np_methods.bboxes_resize(rbbox_img, rbboxes)return rclasses, rscores, rbboxes# 測試的文件夾 path = '../demo/' image_names = sorted(os.listdir(path)) # 文件夾中的第幾張圖,-1代表最后一張 img = mpimg.imread(path + image_names[-1]) rclasses, rscores, rbboxes = process_image(img)# visualization.bboxes_draw_on_img(img, rclasses, rscores, rbboxes, visualization.colors_plasma) visualization.plt_bboxes(img, rclasses, rscores, rbboxes)

結(jié)果展示:這是我自己拍的照片,得到的識別效果還算勉強(qiáng)吧(請自動忽略我那性感的手毛!)

如果你的測試結(jié)果是下面這樣的:

導(dǎo)致的原因:

? ?1 訓(xùn)練次數(shù)太少,loss過高——解決方法除了優(yōu)化數(shù)據(jù)集外,就是增大訓(xùn)練次數(shù)(要明白谷歌公布的模型都是在大型集群上訓(xùn)練好多天的結(jié)果,我們就在GTX1060單顯卡上訓(xùn)練4.8W次就想出非常好的結(jié)果?偶然的成功比失敗更可怕,而且想彎道超谷歌不太可能吧!)
? ?2 另外上面程序65行的select_threshold、 nms_threshold參數(shù)你也可以做調(diào)整;觀察下圖可以發(fā)現(xiàn)誤標(biāo)框框的預(yù)測值都小于0.55,而唯一正確的框框預(yù)測值等于0.866。所以認(rèn)真理解上面程序66、67行我寫的注釋,對你的問題會有幫助;

本博客用的測試數(shù)據(jù)集在這,只有20張標(biāo)記圖片。并不包含最后訓(xùn)練得到的模型

參考自https://blog.csdn.net/zzZ_CMing/article/details/81131523

總結(jié)

以上是生活随笔為你收集整理的ssd训练自己数据集的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。