




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡介
第python目標(biāo)檢測SSD算法訓(xùn)練部分源碼詳解目錄學(xué)習(xí)前言講解構(gòu)架模型訓(xùn)練的流程1、設(shè)置參數(shù)2、讀取數(shù)據(jù)集3、建立ssd網(wǎng)絡(luò)。4、預(yù)處理數(shù)據(jù)集5、框的編碼6、計(jì)算loss值7、訓(xùn)練模型并保存開始訓(xùn)練
學(xué)習(xí)前言
又看了很久的SSD算法,今天講解一下訓(xùn)練部分的代碼。
預(yù)測部分的代碼可以參照/article/246905.htm
講解構(gòu)架
本次教程的講解主要是對(duì)訓(xùn)練部分的代碼進(jìn)行講解,該部分講解主要是對(duì)訓(xùn)練函數(shù)的執(zhí)行過程與執(zhí)行思路進(jìn)行詳解。
訓(xùn)練函數(shù)的執(zhí)行過程大體上分為:
1、設(shè)定訓(xùn)練參數(shù)。
2、讀取數(shù)據(jù)集。
3、建立ssd網(wǎng)絡(luò)。
4、預(yù)處理數(shù)據(jù)集。
5、對(duì)groundtruth實(shí)際框進(jìn)行編碼,使其格式符合神經(jīng)網(wǎng)絡(luò)的預(yù)測結(jié)果,便于比較。
6、計(jì)算loss值。
7、利用優(yōu)化器完成梯度下降并保存模型。
在看本次算法前,建議先下載我簡化過的源碼,配合觀看,具體運(yùn)行方法在開始訓(xùn)練部分
下載鏈接/s/1K4RAJvLj11blywuX2CrLSA
提取碼:4wbi
模型訓(xùn)練的流程
本文使用的ssd_vgg_300的源碼點(diǎn)擊下載,本文對(duì)其進(jìn)行了簡化,保留了上一次篩選出的預(yù)測部分,還加入了訓(xùn)練部分,便于理順整個(gè)SSD的框架。
1、設(shè)置參數(shù)
在載入數(shù)據(jù)庫前,首先要設(shè)定一系列的參數(shù),這些參數(shù)可以分為幾個(gè)部分。第一部分是SSD網(wǎng)絡(luò)中的一些標(biāo)志參數(shù):
#===========================================================================#
#SSDNetworkflags.
#===========================================================================#
#localization框的衰減比率
tf.app.flags.DEFINE_float(
'loss_alpha',1.,'Alphaparameterinthelossfunction.')
#正負(fù)樣本比率
tf.app.flags.DEFINE_float(
'negative_ratio',3.,'Negativeratiointhelossfunction.')
#groundtruth處理后,匹配得分高于match_threshold屬于正樣本
tf.app.flags.DEFINE_float(
'match_threshold',0.5,'Matchingthresholdinthelossfunction.')
第二部分是訓(xùn)練時(shí)的參數(shù)(包括訓(xùn)練效果輸出、保存方案等):
#===========================================================================#
#GeneralFlags.
#===========================================================================#
#train_dir用于保存訓(xùn)練后的模型和日志
tf.app.flags.DEFINE_string(
'train_dir','/tmp/tfmodel/',
'Directorywherecheckpointsandeventlogsarewrittento.')
#num_readers是在對(duì)數(shù)據(jù)集進(jìn)行讀取時(shí)所用的平行讀取器個(gè)數(shù)
tf.app.flags.DEFINE_integer(
'num_readers',4,
'Thenumberofparallelreadersthatreaddatafromthedataset.')
#在進(jìn)行訓(xùn)練batch的構(gòu)建時(shí),所用的線程數(shù)
tf.app.flags.DEFINE_integer(
'num_preprocessing_threads',4,
'Thenumberofthreadsusedtocreatethebatches.')
#每十步進(jìn)行一次log輸出,在窗口上
tf.app.flags.DEFINE_integer(
'log_every_n_steps',10,
'Thefrequencywithwhichlogsareprint.')
#每600秒存儲(chǔ)一次記錄
tf.app.flags.DEFINE_integer(
'save_summaries_secs',600,
'Thefrequencywithwhichsummariesaresaved,inseconds.')
#每600秒存儲(chǔ)一次模型
tf.app.flags.DEFINE_integer(
'save_interval_secs',600,
'Thefrequencywithwhichthemodelissaved,inseconds.')
#可以使用的gpu內(nèi)存數(shù)量
tf.app.flags.DEFINE_float(
'gpu_memory_fraction',0.7,'GPUmemoryfractiontouse.')
第三部分是優(yōu)化器參數(shù):
#===========================================================================#
#OptimizationFlags.
#===========================================================================#
#優(yōu)化器參數(shù)
#weight_decay參數(shù)
tf.app.flags.DEFINE_float(
'weight_decay',0.00004,'Theweightdecayonthemodelweights.')
#使用什么優(yōu)化器
tf.app.flags.DEFINE_string(
'optimizer','rmsprop',
'Thenameoftheoptimizer,oneof"adadelta","adagrad","adam",'
'"ftrl","momentum","sgd"or"rmsprop".')
tf.app.flags.DEFINE_float(
'adadelta_rho',0.95,
'Thedecayrateforadadelta.')
tf.app.flags.DEFINE_float(
'adagrad_initial_accumulator_value',0.1,
'StartingvaluefortheAdaGradaccumulators.')
tf.app.flags.DEFINE_float(
'adam_beta1',0.9,
'Theexponentialdecayrateforthe1stmomentestimates.')
tf.app.flags.DEFINE_float(
'adam_beta2',0.999,
'Theexponentialdecayrateforthe2ndmomentestimates.')
tf.app.flags.DEFINE_float('opt_epsilon',1.0,'Epsilontermfortheoptimizer.')
tf.app.flags.DEFINE_float('ftrl_learning_rate_power',-0.5,
'Thelearningratepower.')
tf.app.flags.DEFINE_float(
'ftrl_initial_accumulator_value',0.1,
'StartingvaluefortheFTRLaccumulators.')
tf.app.flags.DEFINE_float(
'ftrl_l1',0.0,'TheFTRLl1regularizationstrength.')
tf.app.flags.DEFINE_float(
'ftrl_l2',0.0,'TheFTRLl2regularizationstrength.')
tf.app.flags.DEFINE_float(
'momentum',0.9,
'ThemomentumfortheMomentumOptimizerandRMSPropOptimizer.')
tf.app.flags.DEFINE_float('rmsprop_momentum',0.9,'Momentum.')
tf.app.flags.DEFINE_float('rmsprop_decay',0.9,'DecaytermforRMSProp.')
第四部分是學(xué)習(xí)率參數(shù):
#===========================================================================#
#LearningRateFlags.
#===========================================================================#
#學(xué)習(xí)率衰減的方式,有固定、指數(shù)衰減等
tf.app.flags.DEFINE_string(
'learning_rate_decay_type',
'exponential',
'Specifieshowthelearningrateisdecayed.Oneof"fixed","exponential",'
'or"polynomial"')
#初始學(xué)習(xí)率
tf.app.flags.DEFINE_float('learning_rate',0.01,'Initiallearningrate.')
#結(jié)束時(shí)的學(xué)習(xí)率
tf.app.flags.DEFINE_float(
'end_learning_rate',0.0001,
'Theminimalendlearningrateusedbyapolynomialdecaylearningrate.')
tf.app.flags.DEFINE_float(
'label_smoothing',0.0,'Theamountoflabelsmoothing.')
#學(xué)習(xí)率衰減因素
tf.app.flags.DEFINE_float(
'learning_rate_decay_factor',0.94,'Learningratedecayfactor.')
tf.app.flags.DEFINE_float(
'num_epochs_per_decay',2.0,
'Numberofepochsafterwhichlearningratedecays.')
tf.app.flags.DEFINE_float(
'moving_average_decay',None,
'Thedecaytouseforthemovingaverage.'
'IfleftasNone,thenmovingaveragesarenotused.')
第五部分是數(shù)據(jù)集參數(shù):
#===========================================================================#
#DatasetFlags.
#===========================================================================#
#數(shù)據(jù)集名稱
tf.app.flags.DEFINE_string(
'dataset_name','imagenet','Thenameofthedatasettoload.')
#數(shù)據(jù)集種類個(gè)數(shù)
tf.app.flags.DEFINE_integer(
'num_classes',21,'Numberofclassestouseinthedataset.')
#訓(xùn)練還是測試
tf.app.flags.DEFINE_string(
'dataset_split_name','train','Thenameofthetrain/testsplit.')
#數(shù)據(jù)集目錄
tf.app.flags.DEFINE_string(
'dataset_dir',None,'Thedirectorywherethedatasetfilesarestored.')
tf.app.flags.DEFINE_integer(
'labels_offset',0,
'Anoffsetforthelabelsinthedataset.Thisflagisprimarilyusedto'
'evaluatetheVGGandResNetarchitectureswhichdonotuseabackground'
'classfortheImageNetdataset.')
tf.app.flags.DEFINE_string(
'model_name','ssd_300_vgg','Thenameofthearchitecturetotrain.')
tf.app.flags.DEFINE_string(
'preprocessing_name',None,'Thenameofthepreprocessingtouse.Ifleft'
'as`None`,thenthemodel_nameflagisused.')
#每一次訓(xùn)練batch的大小
tf.app.flags.DEFINE_integer(
'batch_size',32,'Thenumberofsamplesineachbatch.')
#訓(xùn)練圖片的大小
tf.app.flags.DEFINE_integer(
'train_image_size',None,'Trainimagesize')
#最大訓(xùn)練次數(shù)
tf.app.flags.DEFINE_integer('max_number_of_steps',50000,
'Themaximumnumberoftrainingsteps.')
第六部分是微修已有的模型所需的參數(shù):
#===========================================================================#
#Fine-TuningFlags.
#===========================================================================#
#該部分參數(shù)用于微修已有的模型
#原模型的位置
tf.app.flags.DEFINE_string(
'checkpoint_path',None,
'Thepathtoacheckpointfromwhichtofine-tune.')
tf.app.flags.DEFINE_string(
'checkpoint_model_scope',None,
'Modelscopeinthecheckpoint.Noneifthesameasthetrainedmodel.')
#哪些變量不要
tf.app.flags.DEFINE_string(
'checkpoint_exclude_scopes',None,
'Comma-separatedlistofscopesofvariablestoexcludewhenrestoring'
'fromacheckpoint.')
#那些變量不訓(xùn)練
tf.app.flags.DEFINE_string(
'trainable_scopes',None,
'Comma-separatedlistofscopestofilterthesetofvariablestotrain.'
'Bydefault,Nonewouldtrainallthevariables.')
#忽略丟失的變量
tf.app.flags.DEFINE_boolean(
'ignore_missing_vars',False,
'Whenrestoringacheckpointwouldignoremissingvariables.')
FLAGS=tf.app.flags.FLAGS
所有的參數(shù)的意義我都進(jìn)行了標(biāo)注,在實(shí)際訓(xùn)練的時(shí)候需要修改一些參數(shù)的內(nèi)容,這些參數(shù)看起來多,其實(shí)只是包含了一個(gè)網(wǎng)絡(luò)訓(xùn)練所有必須的部分:
網(wǎng)絡(luò)主體參數(shù);訓(xùn)練時(shí)的普通參數(shù)(包括訓(xùn)練效果輸出、保存方案等);優(yōu)化器參數(shù);學(xué)習(xí)率參數(shù);數(shù)據(jù)集參數(shù);微修已有的模型的參數(shù)設(shè)置。
2、讀取數(shù)據(jù)集
在訓(xùn)練流程中,其通過如下函數(shù)讀取數(shù)據(jù)集
##########################讀取數(shù)據(jù)集部分#############################
#選擇數(shù)據(jù)庫
dataset=dataset_factory.get_dataset(
FLAGS.dataset_name,FLAGS.dataset_split_name,FLAGS.dataset_dir)
dataset_factory里面放的是數(shù)據(jù)集獲取和處理的函數(shù),這里面對(duì)應(yīng)了4個(gè)數(shù)據(jù)集,利用datasets_map存儲(chǔ)了四個(gè)數(shù)據(jù)集的處理代碼。
from__future__importabsolute_import
from__future__importdivision
from__future__importprint_function
fromdatasetsimportcifar10
fromdatasetsimportimagenet
fromdatasetsimportpascalvoc_2007
fromdatasetsimportpascalvoc_2012
datasets_map={
'cifar10':cifar10,
'imagenet':imagenet,
'pascalvoc_2007':pascalvoc_2007,
'pascalvoc_2012':pascalvoc_2012,
defget_dataset(name,split_name,dataset_dir,file_pattern=None,reader=None):
給定一個(gè)數(shù)據(jù)集名和一個(gè)拆分名返回一個(gè)數(shù)據(jù)集。
name:String,數(shù)據(jù)集名稱
split_name:訓(xùn)練還是測試
dataset_dir:存儲(chǔ)數(shù)據(jù)集文件的目錄。
file_pattern:用于匹配數(shù)據(jù)集源文件的文件模式。
reader:tf.readerbase的子類。如果保留為“none”,則使用每個(gè)數(shù)據(jù)集定義的默認(rèn)讀取器。
Returns:
ifnamenotindatasets_map:
raiseValueError('Nameofdatasetunknown%s'%name)
returndatasets_map[name].get_split(split_name,
dataset_dir,
file_pattern,
reader)
我們這里用到pascalvoc_2012的數(shù)據(jù),所以當(dāng)返回datasets_map[name].get_split這個(gè)代碼時(shí),實(shí)際上調(diào)用的是:
pascalvoc_2012.get_split(split_name,
dataset_dir,
file_pattern,
reader)
在pascalvoc_2012中g(shù)et_split的執(zhí)行過程如下,其中file_pattern=voc_2012_%s_*.tfrecord,這個(gè)名稱是訓(xùn)練的圖片的默認(rèn)名稱,實(shí)際訓(xùn)練的tfrecord文件名稱像這樣voc_2012_train_001.tfrecord,意味著可以讀取這樣的訓(xùn)練文件:
defget_split(split_name,dataset_dir,file_pattern=None,reader=None):
"""GetsadatasettuplewithinstructionsforreadingImageNet.
Args:
split_name:訓(xùn)練還是測試
dataset_dir:數(shù)據(jù)集的位置
file_pattern:匹配數(shù)據(jù)集源時(shí)要使用的文件模式。
假定模式包含一個(gè)'%s'字符串,以便可以插入拆分名稱
reader:TensorFlow閱讀器類型。
Returns:
數(shù)據(jù)集.
ifnotfile_pattern:
file_pattern=FILE_PATTERN
returnpascalvoc_common.get_split(split_name,dataset_dir,
file_pattern,reader,
SPLITS_TO_SIZES,
ITEMS_TO_DESCRIPTIONS,
NUM_CLASSES)
再進(jìn)入到pascalvoc_common文件后,實(shí)際上就開始對(duì)tfrecord的文件進(jìn)行分割了,通過代碼注釋我們了解代碼的執(zhí)行過程,其中tfrecord的文件讀取就是首先按照keys_to_features的內(nèi)容進(jìn)行文件解碼,解碼后的結(jié)果按照items_to_handlers的格式存入數(shù)據(jù)集:
defget_split(split_name,dataset_dir,file_pattern,reader,
split_to_sizes,items_to_descriptions,num_classes):
"""GetsadatasettuplewithinstructionsforreadingPascalVOCdataset.
給定一個(gè)數(shù)據(jù)集名和一個(gè)拆分名返回一個(gè)數(shù)據(jù)集。
name:String,數(shù)據(jù)集名稱
split_name:訓(xùn)練還是測試
dataset_dir:存儲(chǔ)數(shù)據(jù)集文件的目錄。
file_pattern:用于匹配數(shù)據(jù)集源文件的文件模式。
reader:tf.readerbase的子類。如果保留為“none”,則使用每個(gè)數(shù)據(jù)集定義的默認(rèn)讀取器。
Returns:
ifsplit_namenotinsplit_to_sizes:
raiseValueError('splitname%swasnotrecognized.'%split_name)
#file_pattern是取得的tfrecord數(shù)據(jù)集的位置
file_pattern=os.path.join(dataset_dir,file_pattern%split_name)
#當(dāng)沒有的時(shí)候使用默認(rèn)reader
ifreaderisNone:
reader=tf.TFRecordReader
#VOC數(shù)據(jù)集中的文檔內(nèi)容
keys_to_features={
'image/encoded':tf.FixedLenFeature((),tf.string,default_value=''),
'image/format':tf.FixedLenFeature((),tf.string,default_value='jpeg'),
'image/height':tf.FixedLenFeature([1],64),
'image/width':tf.FixedLenFeature([1],64),
'image/channels':tf.FixedLenFeature([1],64),
'image/shape':tf.FixedLenFeature([3],64),
'image/object/bbox/xmin':tf.VarLenFeature(dtype=tf.float32),
'image/object/bbox/ymin':tf.VarLenFeature(dtype=tf.float32),
'image/object/bbox/xmax':tf.VarLenFeature(dtype=tf.float32),
'image/object/bbox/ymax':tf.VarLenFeature(dtype=tf.float32),
'image/object/bbox/label':tf.VarLenFeature(dtype=64),
'image/object/bbox/difficult':tf.VarLenFeature(dtype=64),
'image/object/bbox/truncated':tf.VarLenFeature(dtype=64),
#解碼方式
items_to_handlers={
'image':slim.tfexample_decoder.Image('image/encoded','image/format'),
'shape':slim.tfexample_decoder.Tensor('image/shape'),
'object/bbox':slim.tfexample_decoder.BoundingBox(
['ymin','xmin','ymax','xmax'],'image/object/bbox/'),
'object/label':slim.tfexample_decoder.Tensor('image/object/bbox/label'),
'object/difficult':slim.tfexample_decoder.Tensor('image/object/bbox/difficult'),
'object/truncated':slim.tfexample_decoder.Tensor('image/object/bbox/truncated'),
#將tfrecord上keys_to_features的部分解碼到items_to_handlers上
decoder=slim.tfexample_decoder.TFExampleDecoder(
keys_to_features,items_to_handlers)
labels_to_names=None
ifdataset_utils.has_labels(dataset_dir):
labels_to_names=dataset_utils.read_label_file(dataset_dir)
returnslim.dataset.Dataset(
data_sources=file_pattern,#數(shù)據(jù)源
reader=reader,#tf.TFRecordReader
decoder=decoder,#解碼結(jié)果
num_samples=split_to_sizes[split_name],#17125
items_to_descriptions=items_to_descriptions,#每一個(gè)item的描述
num_classes=num_classes,#種類
labels_to_names=labels_to_names)
通過上述一系列操作,實(shí)際上是返回了一個(gè)slim.dataset.Dataset數(shù)據(jù)集,而一系列函數(shù)的調(diào)用,實(shí)際上是為了調(diào)用對(duì)應(yīng)的數(shù)據(jù)集。
3、建立ssd網(wǎng)絡(luò)。
建立ssd網(wǎng)絡(luò)的過程并不復(fù)雜,沒有許多函數(shù)的調(diào)用,實(shí)際執(zhí)行過程如果了解ssd網(wǎng)絡(luò)的預(yù)測部分就很好理解,我這里只講下邏輯:
1、利用ssd_class=ssd_vgg_300.SSDNet獲得SSDNet的類
2、替換種類的數(shù)量num_classes參數(shù)
3、利用ssd_net=ssd_class(ssd_params)建立網(wǎng)絡(luò)
4、獲得先驗(yàn)框
調(diào)用的代碼如下:
###########################建立ssd網(wǎng)絡(luò)##############################
#獲得SSD的網(wǎng)絡(luò)和它的先驗(yàn)框
ssd_class=ssd_vgg_300.SSDNet
#替換種類的數(shù)量num_classes參數(shù)
ssd_params=ssd_class.default_params._replace(num_classes=FLAGS.num_classes)
#成功建立了網(wǎng)絡(luò)net,替換參數(shù)
ssd_net=ssd_class(ssd_params)
#獲得先驗(yàn)框
ssd_shape=ssd_net.params.img_shape
ssd_anchors=ssd_net.anchors(ssd_shape)#包括六個(gè)特征層的先驗(yàn)框
4、預(yù)處理數(shù)據(jù)集
預(yù)處理數(shù)據(jù)集的代碼比較長,但是邏輯并不難理解。
1、獲得數(shù)據(jù)集名稱。
2、獲取數(shù)據(jù)集處理的函數(shù)。
3、利用DatasetDataProviders從數(shù)據(jù)集中提供數(shù)據(jù),進(jìn)行數(shù)據(jù)的預(yù)加載。
4、獲取原始的圖片和它對(duì)應(yīng)的label,框groundtruth的位置
5、預(yù)處理圖片標(biāo)簽和框的位置
具體實(shí)現(xiàn)的代碼如下:
###########################預(yù)處理數(shù)據(jù)集##############################
#preprocessing_name等于ssd_300_vgg
preprocessing_name=FLAGS.preprocessing_nameorFLAGS.model_name
#根據(jù)名字進(jìn)行處理獲得處理函數(shù)
image_preprocessing_fn=preprocessing_factory.get_preprocessing(
preprocessing_name,is_training=True)
#打印參數(shù)
tf_utils.print_configuration(FLAGS.__flags,ssd_params,
dataset.data_sources,FLAGS.train_dir)
#DatasetDataProviders從數(shù)據(jù)集中提供數(shù)據(jù).通過配置,
#可以同時(shí)使用多個(gè)readers或者使用單個(gè)reader提供數(shù)據(jù)。此外,被讀取的數(shù)據(jù)
#可以被打亂順序
#預(yù)加載
with_scope(FLAGS.dataset_name+'_data_provider'):
provider=slim.dataset_data_provider.DatasetDataProvider(
dataset,
num_readers=FLAGS.num_readers,
common_queue_capacity=20*FLAGS.batch_size,
common_queue_min=10*FLAGS.batch_size,
shuffle=True)
#獲取原始的圖片和它對(duì)應(yīng)的label,框groundtruth的位置
[image,_,glabels,gbboxes]=provider.get(['image','shape',
'object/label',
'object/bbox'])
#預(yù)處理圖片標(biāo)簽和框的位置
image,glabels,gbboxes=\
image_preprocessing_fn(image,glabels,gbboxes,
out_shape=ssd_shape,
data_format=DATA_FORMAT)
在這一部分中,可能存在的疑惑的是第二步和第五步,實(shí)際上第五步調(diào)用的就是第二步中的圖像預(yù)處理函數(shù),所以我們只要看懂第二步獲取數(shù)據(jù)集處理的函數(shù)即可。
獲得處理函數(shù)的代碼是:
#根據(jù)名字進(jìn)行處理獲得處理函數(shù)
image_preprocessing_fn=preprocessing_factory.get_preprocessing(
preprocessing_name,is_training=True)
preprocessing_factory的文件夾內(nèi)存放的都是圖片處理的代碼,在進(jìn)入到get_preprocessing方法后,實(shí)際上會(huì)返回一個(gè)preprocessing_fn函數(shù)。
該函數(shù)的作用實(shí)際上是返回ssd_vgg_preprocessing.preprocess_image處理后的結(jié)果。
而ssd_vgg_preprocessing.preprocess_image實(shí)際上是preprocess_for_train處理后的結(jié)果。
preprocessing_factory的get_preprocessing代碼如下:
defget_preprocessing(name,is_training=False):
preprocessing_fn_map={
'ssd_300_vgg':ssd_vgg_preprocessing
ifnamenotinpreprocessing_fn_map:
raiseValueError('Preprocessingname[%s]wasnotrecognized'%name)
defpreprocessing_fn(image,labels,bboxes,
out_shape,data_format='NHWC',**kwargs):
#這里實(shí)際上調(diào)用ssd_vgg_preprocessing.preprocess_image
returnpreprocessing_fn_map[name].preprocess_image(
image,labels,bboxes,out_shape,data_format=data_format,
is_training=is_training,**kwargs)
returnpreprocessing_fn
ssd_vgg_preprocessing的preprocess_image代碼如下:
defpreprocess_image(image,
labels,
bboxes,
out_shape,
data_format,
is_training=False,
**kwargs):
"""Pre-processangivenimage.
Args:
image:A`Tensor`representinganimageofarbitrarysize.
output_height:預(yù)處理后圖像的高度。
output_width:預(yù)處理后圖像的寬度。
is_training:如果我們正在對(duì)圖像進(jìn)行預(yù)處理以進(jìn)行訓(xùn)練,則為true;否則為false
resize_side_min:圖像最小邊的下界,用于保持方向的大小調(diào)整,
如果“is_training”為“false”,則此值
用于重新縮放
resize_side_max:圖像最小邊的上界,用于保持方向的大小調(diào)整
如果“is_training”為“false”,則此值
用于重新縮放
theresizesideissampledfrom
[resize_size_min,resize_size_max].
Returns:
預(yù)處理后的圖片
ifis_training:
returnpreprocess_for_train(image,labels,bboxes,
out_shape=out_shape,
data_format=data_format)
else:
returnpreprocess_for_eval(image,labels,bboxes,
out_shape=out_shape,
data_format=data_format,
**kwargs)
實(shí)際上最終是通過preprocess_for_train處理數(shù)據(jù)集。
preprocess_for_train處理的過程是:
1、改變數(shù)據(jù)類型。
2、樣本框扭曲。
3、將圖像大小調(diào)整為輸出大小。
4、隨機(jī)水平翻轉(zhuǎn)圖像。
5、隨機(jī)扭曲顏色。有四種方法。
6、圖像減去平均值
執(zhí)行代碼如下:
defpreprocess_for_train(image,labels,bboxes,
out_shape,data_format='NHWC',
scope='ssd_preprocessing_train'):
"""Preprocessesthegivenimagefortraining.
Notethattheactualresizingscaleissampledfrom
[`resize_size_min`,`resize_size_max`].
image:圖片,任意size的圖片.
output_height:處理后的圖片高度.
output_width:處理后的圖片寬度.
resize_side_min:圖像最小邊的下界,用于保方面調(diào)整大小
resize_side_max:圖像最小邊的上界,用于保方面調(diào)整大小
Returns:
處理過的圖片
fast_mode=False
with_scope(scope,'ssd_preprocessing_train',[image,labels,bboxes]):
ifimage.get_shape().ndims!=3:
raiseValueError('Inputmustbeofsize[height,width,C0]')
#改變圖片的數(shù)據(jù)類型
ifimage.dtype!=tf.float32:
image=tf.image.convert_image_dtype(image,dtype=tf.float32)
#樣本框扭曲
dst_image=image
dst_image,labels,bboxes,_=\
distorted_bounding_box_crop(image,labels,bboxes,
min_object_covered=MIN_OBJECT_COVERED,
aspect_ratio_range=CROP_RATIO_RANGE)
#將圖像大小調(diào)整為輸出大小。
dst_image=tf_image.resize_image(dst_image,out_shape,
method=tf.image.ResizeMethod.BILINEAR,
align_corners=False)
#隨機(jī)水平翻轉(zhuǎn)圖像.
dst_image,bboxes=tf_image.random_flip_left_right(dst_image,bboxes)
#隨機(jī)扭曲顏色。有四種方法.
dst_image=apply_with_random_selector(
dst_image,
lambdax,ordering:distort_color(x,ordering,fast_mode),
num_cases=4)
#圖像減去平均值
image=dst_image*255.
image=tf_image_whitened(image,[_R_MEAN,_G_MEAN,_B_MEAN])
#圖像的類型
ifdata_format=='NCHW':
image=tf.transpose(image,perm=(2,0,1))
returnimage,labels,bboxes
5、框的編碼
該部分利用如下代碼調(diào)用框的編碼代碼:
gclasses,glocalisations,gscores=ssd_net.bboxes_encode(glabels,gbboxes,ssd_anchors)
實(shí)際上bboxes_encode方法中,調(diào)用的是ssd_common模塊中的tf_ssd_bboxes_encode。
defbboxes_encode(self,labels,bboxes,anchors,
scope=None):
進(jìn)行編碼操作
returnssd_common.tf_ssd_bboxes_encode(
labels,bboxes,anchors,
self.params.num_classes,
self.params.no_annotation_label,
ignore_threshold=0.5,
prior_scaling=self.params.prior_scaling,
scope=scope)
ssd_common.tf_ssd_bboxes_encode執(zhí)行的代碼是對(duì)特征層每一層進(jìn)行編碼操作。
deftf_ssd_bboxes_encode(labels,
bboxes,
anchors,
num_classes,
no_annotation_label,
ignore_threshold=0.5,
prior_scaling=[0.1,0.1,0.2,0.2],
dtype=tf.float32,
scope='ssd_bboxes_encode'):
對(duì)每一個(gè)特征層進(jìn)行解碼
with_scope(scope):
target_labels=[]
target_localizations=[]
target_scores=[]
fori,anchors_layerinenumerate(anchors):
with_scope('bboxes_encode_block_%i'%i):
t_labels,t_loc,t_scores=\
tf_ssd_bboxes_encode_layer(labels,bboxes,anchors_layer,
num_classes,no_annotation_label,
ignore_threshold,
prior_scaling,dtype)
target_labels.append(t_labels)
target_localizations.append(t_loc)
target_scores.append(t_scores)
returntarget_labels,target_localizations,target_scores
實(shí)際上具體解碼的操作在函數(shù)tf_ssd_bboxes_encode_layer里,tf_ssd_bboxes_encode_layer解碼的思路是:
1、創(chuàng)建一系列變量用于存儲(chǔ)編碼結(jié)果。
yref,xref,href,wref=anchors_layer
ymin=yref-href/2.
xmin=xref-wref/2.
ymax=yref+href/2.
xmax=xref+wref/2.
vol_anchors=(xmax-xmin)*(ymax-ymin)
#1、創(chuàng)建一系列變量存儲(chǔ)編碼結(jié)果
#每個(gè)特征層的shape
shape=(yref.shape[0],yref.shape[1],href.size)
#每個(gè)特征層特定點(diǎn),特定框的label
feat_labels=tf.zeros(shape,dtype=64)#(m,m,k)
#每個(gè)特征層特定點(diǎn),特定框的得分
feat_scores=tf.zeros(shape,dtype=dtype)
#每個(gè)特征層特定點(diǎn),特定框的位置
feat_ymin=tf.zeros(shape,dtype=dtype)
feat_xmin=tf.zeros(shape,dtype=dtype)
feat_ymax=tf.ones(shape,dtype=dtype)
feat_xmax=tf.ones(shape,dtype=dtype)
2、對(duì)所有的實(shí)際框都尋找其在特征層中對(duì)應(yīng)的點(diǎn)與其對(duì)應(yīng)的框,并將其標(biāo)簽找到。
#用于計(jì)算IOU
defjaccard_with_anchors(bbox):
int_ymin=tf.maximum(ymin,bbox[0])#(m,m,k)
int_xmin=tf.maximum(xmin,bbox[1])
int_ymax=tf.minimum(ymax,bbox[2])
int_xmax=tf.minimum(xmax,bbox[3])
h=tf.maximum(int_ymax-int_ymin,0.)
w=tf.maximum(int_xmax-int_xmin,0.)
#Volumes.
#處理搜索框和bbox之間的聯(lián)系
inter_vol=h*w#交集面積
union_vol=vol_anchors-inter_vol\
+(bbox[2]-bbox[0])*(bbox[3]-bbox[1])#并集面積
jaccard=tf.div(inter_vol,union_vol)#交集/并集,即IOU
returnjaccard#(m,m,k)
defcondition(i,feat_labels,feat_scores,
feat_ymin,feat_xmin,feat_ymax,feat_xmax):
r=tf.less(i,tf.shape(labels))
returnr[0]
#該部分用于尋找實(shí)際中的框?qū)?yīng)特征層的哪個(gè)框
defbody(i,feat_labels,feat_scores,
feat_ymin,feat_xmin,feat_ymax,feat_xmax):
更新功能標(biāo)簽、分?jǐn)?shù)和bbox。
-JacCard0.5時(shí)賦值;
#取出第i個(gè)標(biāo)簽和第i個(gè)bboxes
label=labels[i]#當(dāng)前圖片上第i個(gè)對(duì)象的標(biāo)簽
bbox=bboxes[i]#當(dāng)前圖片上第i個(gè)對(duì)象的真實(shí)框bbox
#計(jì)算該box和所有anchor_box的IOU
jaccard=jaccard_with_anchors(bbox)#當(dāng)前對(duì)象的bbox和當(dāng)前層的搜索網(wǎng)格IOU
#所有高于歷史的分的box被篩選
mask=tf.greater(jaccard,feat_scores)#掩碼矩陣,IOU大于歷史得分的為True
mask=tf.logical_and(mask,feat_scores-0.5)
imask=tf.cast(mask,64)#[1,0,1,1,0]
fmask=tf.cast(mask,dtype)#[1.,0.,1.,0....]
#Updatevaluesusingmask.
#保證feat_labels存儲(chǔ)對(duì)應(yīng)位置得分最大對(duì)象標(biāo)簽,feat_scores存儲(chǔ)那個(gè)得分
#(m,m,k)×當(dāng)前類別+(1-(m,m,k))×(m,m,k)
#更新label記錄,此時(shí)的imask已經(jīng)保證了True位置當(dāng)前對(duì)像得分高于之前的對(duì)象得分,其他位置值不變
#將所有被認(rèn)為是label的框的值賦予feat_labels
feat_labels=imask*label+(1-imask)*feat_labels
#用于尋找最匹配的框
feat_scores=tf.where(mask,jaccard,feat_scores)
#下面四個(gè)矩陣存儲(chǔ)對(duì)應(yīng)label的真實(shí)框坐標(biāo)
#(m,m,k)×當(dāng)前框坐標(biāo)scalar+(1-(m,m,k))×(m,m,k)
feat_ymin=fmask*bbox[0]+(1-fmask)*feat_ymin
feat_xmin=fmask*bbox[1]+(1-fmask)*feat_xmin
feat_ymax=fmask*bbox[2]+(1-fmask)*feat_ymax
feat_xmax=fmask*bbox[3]+(1-fmask)*feat_xmax
return[i+1,feat_labels,feat_scores,
feat_ymin,feat_xmin,feat_ymax,feat_xmax]
i=0
#2、對(duì)所有的實(shí)際框都尋找其在特征層中對(duì)應(yīng)的點(diǎn)與其對(duì)應(yīng)的框,并將其標(biāo)簽找到。
(i,feat_labels,feat_scores,feat_ymin,feat_xmin,
feat_ymax,feat_xmax)=tf.while_loop(condition,body,
feat_labels,feat_scores,
feat_ymin,feat_xmin,
feat_ymax,feat_xmax])
3、轉(zhuǎn)化成ssd中網(wǎng)絡(luò)的輸出格式。
#Transformtocenter/size.
#3、轉(zhuǎn)化成ssd中網(wǎng)絡(luò)的輸出格式。
feat_cy=(feat_ymax+feat_ymin)/2.
feat_cx=(feat_xmax+feat_xmin)/2.
feat_h=feat_ymax-feat_ymin
feat_w=feat_xmax-feat_xmin
#Encodefeatures.
#利用公式進(jìn)行計(jì)算
#以搜索網(wǎng)格中心點(diǎn)為參考,真實(shí)框中心的偏移,單位長度為網(wǎng)格hw
feat_cy=(feat_cy-yref)/href/prior_scaling[0]
feat_cx=(feat_cx-xref)/wref/prior_scaling[1]
#log((m,m,k)/(m,m,1))*5
#真實(shí)框?qū)捀?搜索網(wǎng)格寬高,取對(duì)
feat_h=tf.log(feat_h/href)/prior_scaling[2]
feat_w=tf.log(feat_w/wref)/prior_scaling[3]
#UseSSDordering:x/y/w/hinsteadofours.(m,m,k,4)
feat_localizations=tf.stack([feat_cx,feat_cy,feat_w,feat_h],axis=-1)
returnfeat_labels,feat_localizations,feat_scores
真實(shí)情況下的標(biāo)簽和框在編碼完成后,格式與經(jīng)過網(wǎng)絡(luò)預(yù)測出的標(biāo)簽與框相同,此時(shí)才可以計(jì)算loss進(jìn)行對(duì)比。
6、計(jì)算loss值
通過第五步獲得的框的編碼后的scores和locations指的是數(shù)據(jù)集標(biāo)注的結(jié)果,是真實(shí)情況。而計(jì)算loss值還需要預(yù)測情況。
通過如下代碼可以獲得每個(gè)image的預(yù)測情況,將圖片通過網(wǎng)絡(luò)進(jìn)行預(yù)測:
#設(shè)置SSD網(wǎng)絡(luò)的參數(shù)
arg_scope=ssd_net.arg_scope(weight_decay=FLAGS.weight_decay,
data_format=DATA_FORMAT)
#將圖片經(jīng)過網(wǎng)絡(luò)獲得它們的框的位置和prediction
withslim.arg_scope(arg_scope):
_,localisations,logits,_=\
ssd_(b_image,is_training=True)
再調(diào)用loss計(jì)算函數(shù)計(jì)算三個(gè)loss值,分別對(duì)應(yīng)正樣本,負(fù)樣本,定位。
#計(jì)算loss值
n_positives_loss,n_negative_loss,localization_loss=ssd_net.losses(logits,localisations,
b_gclasses,b_glocalisations,b_gscores,
match_threshold=FLAGS.match_threshold,
negative_ratio=FLAGS.negative_ratio,
alpha=FLAGS.loss_alpha,
label_smoothing=FLAGS.label_smoothing)
#會(huì)得到三個(gè)loss值,分別對(duì)應(yīng)正樣本,負(fù)樣本,定位
loss_all=n_positives_loss+n_negative_loss+localization_loss
ssd_net.losses中,具體通過如下方式進(jìn)行損失值的計(jì)算。
1、對(duì)所有的圖片進(jìn)行鋪平,將其種類預(yù)測的轉(zhuǎn)化為(,num_classes),框預(yù)測的格式轉(zhuǎn)化為(,4),實(shí)際種類和實(shí)際得分的格式轉(zhuǎn)化為(),該步可以便于后面的比較與處理。最后將batch個(gè)圖片平鋪到同一表上。
2、在gscores中得到滿足正樣本得分的pmask正樣本,不滿足正樣本得分的為nmask負(fù)樣本,因?yàn)槭褂玫氖莋scores,我們可以知道正樣本負(fù)樣本分類是針對(duì)真實(shí)值的。
3、將不滿足正樣本的位置設(shè)成對(duì)應(yīng)prediction中背景的得分,其它設(shè)為1。
4、找到n_neg個(gè)最不可能為背景的點(diǎn)(實(shí)際上它是背景,這樣利用二者計(jì)算的loss就很大)
5、分別計(jì)算正樣本、負(fù)樣本、框的位置的交叉熵。
defssd_losses(logits,localisations,
gclasses,glocalisations,gscores,
match_threshold=0.5,
negative_ratio=3.,
alpha=1.,
label_smoothing=0.,
device='/cpu:0',
scope=None):
with_scope(scope,'ssd_losses'):
lshape=tfe.get_shape(logits[0],5)
num_classes=lshape[-1]
batch_size=lshape[0]
#鋪平所有vector
flogits=[]
fgclasses=[]
fgscores=[]
flocalisations=[]
fglocalisations=[]
foriinrange(len(logits)):#按照圖片循環(huán)
flogits.append(tf.reshape(logits[i],[-1,num_classes]))
fgclasses.append(tf.reshape(gclasses[i],[-1]))
fgscores.append(tf.reshape(gscores[i],[-1]))
flocalisations.append(tf.reshape(localisations[i],[-1,4]))
fglocalisations.append(tf.reshape(glocalisations[i],[-1,4]))
#上一步所得的還存在batch個(gè)行里面,對(duì)應(yīng)batch個(gè)圖片
#這一步將batch個(gè)圖片平鋪到同一表上
logits=tf.concat(flogits,axis=0)
gclasses=tf.concat(fgclasses,axis=0)
gscores=tf.concat(fgscores,axis=0)
localisations=tf.concat(flocalisations,axis=0)
glocalisations=tf.concat(fglocalisations,axis=0)
dtype=logits.dtype
#gscores中滿足正樣本得分的mask
pmask=gscoresmatch_threshold
fpmask=tf.cast(pmask,dtype)
no_classes=tf.cast(pmask,32)
nmask=tf.logical_and(tf.logical_not(pmask),#IOU達(dá)不到閾值的類別搜索框位置記1
gscores-0.5)
fnmask=tf.cast(nmask,dtype)
n_positives=tf.reduce_sum(fpmask)
#將預(yù)測結(jié)果轉(zhuǎn)化成比率
predictions=slim.softmax(logits)
nvalues=tf.where(nmask,
predictions[:,0],#框內(nèi)無物體標(biāo)記為背景預(yù)測概率
1.-fnmask)#框內(nèi)有物體位置標(biāo)記為1
nvalues_flat=tf.reshape(nvalues,[-1])
#max_neg_entries為實(shí)際上負(fù)樣本的個(gè)數(shù)
max_neg_entries=tf.cast(tf.reduce_sum(fnmask),32)
#n_neg為正樣本的個(gè)數(shù)*3+batch_size,之所以+batchsize是因?yàn)槊總€(gè)圖最少有一個(gè)負(fù)樣本背景
n_neg=tf.cast(negative_ratio*n_positives,32)+batch_size
n_neg=tf.minimum(n_neg,max_neg_entries)
#找到n_neg個(gè)最不可能為背景的點(diǎn)
val,idxes=tf.nn.top_k(-nvalues_flat,k=n_neg)
max_hard_pred
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- TD/T 1017-2008第二次全國土地調(diào)查基本農(nóng)田調(diào)查技術(shù)規(guī)程
- JJG(煙草)01-2012卷煙和濾棒物理性能綜合測試臺(tái)檢定規(guī)程
- JJF(煙草)4.5-2024煙草及煙草制品連續(xù)流動(dòng)法測定常規(guī)化學(xué)成分測量不確定度評(píng)定指南第5部分:鉀
- 2025初三升高一數(shù)學(xué)暑假銜接講義25講含答案(必修一內(nèi)容)3.4 冪函數(shù)-(必修第一冊)
- 南山實(shí)驗(yàn)教育集團(tuán)2025年中考語文一模試卷
- 2004年江蘇省淮安市中考數(shù)學(xué)真題【含答案、解析】
- 考研復(fù)習(xí)-風(fēng)景園林基礎(chǔ)考研試題附參考答案詳解【輕巧奪冠】
- 考研復(fù)習(xí)-風(fēng)景園林基礎(chǔ)考研試題(預(yù)熱題)附答案詳解
- 風(fēng)景園林基礎(chǔ)考研資料試題及參考答案詳解【模擬題】
- 《風(fēng)景園林招投標(biāo)與概預(yù)算》試題A帶答案詳解(綜合題)
- 3D打印技術(shù)與應(yīng)用智慧樹知到期末考試答案2024年
- 預(yù)防盜竊教育
- 《精益生產(chǎn)培訓(xùn)》課件
- 紀(jì)檢干部心理培訓(xùn)課件模板
- 地基基礎(chǔ)工程監(jiān)理實(shí)施細(xì)則
- 《紅樓夢》中的愛情觀與婚姻制度的評(píng)析
- 《生命的意義》課件
- 中國中小學(xué)生積極心理品質(zhì)量表心理課之后
- 永久供電施工方案
- GB 5009.88-2023食品安全國家標(biāo)準(zhǔn)食品中膳食纖維的測定
- DB32T 4536-2023環(huán)境水質(zhì)(地表水)自動(dòng)監(jiān)測站運(yùn)行維護(hù)技術(shù)規(guī)范
評(píng)論
0/150
提交評(píng)論