<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          基于表征學(xué)習(xí)的行人重實(shí)別

          共 5926字,需瀏覽 12分鐘

           ·

          2021-04-25 11:03

          在學(xué)術(shù)界,行人重識別的任務(wù),一般分為兩種方法,一種是表征學(xué)習(xí),另一種是度量學(xué)習(xí)。劃分這兩種方法的依據(jù)是使用的損失不同。兩者同樣是輸入數(shù)據(jù)進(jìn)入CNN網(wǎng)絡(luò)提取特征,而表征學(xué)習(xí)在訓(xùn)練的時(shí)候沒有考慮圖片間的相似度,而把行人重識別任務(wù)當(dāng)作分類問題或者驗(yàn)證問題來做,而度量學(xué)習(xí)通過網(wǎng)絡(luò)學(xué)習(xí)出兩張圖片的相似度,表現(xiàn)為同一行人的不同圖片的相似度大于不同行人的不同圖片。

           



          在本節(jié)中,我們使用表征學(xué)習(xí)進(jìn)行行人的重識別。具體的流程如下:在訓(xùn)練時(shí),我們輸入數(shù)據(jù)進(jìn)入深度神經(jīng)網(wǎng)絡(luò),提取出特征向量,然后連接一個(gè)FC層進(jìn)行softmax分類。這就稱為ID損失,在訓(xùn)練集中行人的ID數(shù)為網(wǎng)絡(luò)的類別數(shù)。而在測試時(shí),我們一般使用到倒數(shù)第二層的特征向量進(jìn)行檢索,將FC層丟棄。


          #1    數(shù)據(jù)集

          DukeMTMC-reID

          在數(shù)據(jù)集方面,我們使用了DukeMTMC-reID數(shù)據(jù)集,這是在杜克大學(xué)內(nèi)采集的,圖像來自8個(gè)不同的攝像頭。該數(shù)據(jù)集提供訓(xùn)練集和測試集。訓(xùn)練集包含16522張圖像,測試集包含1761張圖像。訓(xùn)練集幾乎共有702人,平均每個(gè)人有23.5張訓(xùn)練數(shù)據(jù)。是目前最大的行人重識別數(shù)據(jù)集,并且提供了行人屬性,如性別,長短袖,是否有背包等標(biāo)注。


          接下來,我們進(jìn)行數(shù)據(jù)處理,首先,我們先觀察數(shù)據(jù)的命名格式,發(fā)現(xiàn)數(shù)據(jù)的命名是00xx_**_**.jpg。后面的不用管,我們的目的是提取對應(yīng)行人的索引。所以可以對_前的數(shù)值進(jìn)行提取,新建一個(gè)data2txt.py寫入如下代碼:

          import osdata_path=r'E:\DataSets\DukeMTMC-reID\DukeMTMC-reID\bounding_box_train'
          image_paths=[os.path.join(data_path,p)for p in os.listdir(data_path)]nameid=[]for image_path in image_paths: name=image_path.split('\\')[-1].split('_')[0] if name+'\n' not in nameid: nameid.append(name+'\n')
          with open('name.txt','w',encoding='utf8') as f: f.writelines(nameid)


          運(yùn)行程序,我們會(huì)發(fā)現(xiàn)多了一個(gè)name.txt文件,里面存放著我們的標(biāo)簽數(shù)據(jù),接著,我們新建一個(gè)load_data.py文件,寫入如下代碼,用來組合文件路徑以及打亂數(shù)據(jù)集:

          import osimport  randomimport cv2import numpy as np
          # 加載文件路徑def load_data(): path=r'E:\DataSets\DukeMTMC-reID\DukeMTMC-reID\bounding_box_train' image_names=os.listdir(path) with open('name.txt','r',encoding='utf8') as f: names=f.readlines() data=[] label=[] # 組合路徑 for index,name in enumerate(names): n=name.strip('\n') image_paths=[os.path.join(path,i) for i in image_names if i.startswith((n))] for image_path in image_paths: data.append(image_path) label.append(index) # 隨機(jī)打亂 random_seed=random.randint(1,1000) random.seed(random_seed) random.shuffle(data) random.seed(random_seed)    random.shuffle(label) return data,label


          接著,我們需要將數(shù)據(jù)集制作成生成器的形式:

          def gan_data(data,label,batch_size,n_classes=702):    while True:        x=[]        y=[]        for index,value in enumerate(data):            image=cv2.imread(value)            # 使用cv2縮放圖片,由于圖片是長方形,cv2.resize的參數(shù)是(寬,高)            # 而后續(xù)的reshape的參數(shù)是(高,寬),所以是相反的            image=cv2.resize(image,(60,200))            x.append(image)
          lb=label[index] y_=np.zeros((n_classes,)) y_[lb]=1. y.append(y_) # 當(dāng)數(shù)據(jù)量等于一個(gè)批次是放回?cái)?shù)據(jù) if len(x)==batch_size: x=np.array(x).reshape(-1,200,60,3)/255. y=np.array(y) # print(y.shape) yield x,y x=[] y=[]




          #2      模型搭建

          DarkNet

          在本節(jié)中,我們使用的模型是DarkNet,事實(shí)上,DarkNet還是一個(gè)小眾的深度學(xué)習(xí)框架,但是我們這里所說的DarkNet是一個(gè)名為DarkNet53的深度神經(jīng)網(wǎng)絡(luò)。它實(shí)際上是有名的yolov3目標(biāo)檢測寬框架的backbone。

           

          完整的yolov3的網(wǎng)絡(luò)結(jié)構(gòu)如下,這里我們只取backbone的部分網(wǎng)絡(luò),也就是虛線中的部分作為我們的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)。


          事實(shí)上,DarkNet53的網(wǎng)絡(luò)結(jié)構(gòu)和ResNet很相似,同樣是擁有殘差連接的結(jié)構(gòu),基礎(chǔ)的卷積方式同樣是Conv+BN+激活函數(shù),只不過激活函數(shù)換成了LeakyReLu,并且殘差的位置發(fā)生了改變。以下是DarkNet53的網(wǎng)絡(luò)結(jié)構(gòu)圖,我們可以根據(jù)這一結(jié)構(gòu)圖編寫我們的代碼。


          新建一個(gè)model.py文件,先導(dǎo)入依賴庫,然后定義一個(gè)compose()函數(shù):

          from tensorflow.keras.layers import *from tensorflow.keras.regularizers import l2from functools import reduceimport tensorflow.keras as kfrom image_recognition.DarkNet.load_data import load_data,gan_data
          def compose(*funcs): if funcs: return reduce(lambda f,g:lambda *a, **kw:g(f(*a,**kw)),funcs) else: raise ValueError('Composition of empty sequence not supported.')


          這個(gè)函數(shù)的作用是對輸入進(jìn)來的一個(gè)數(shù)據(jù)集合或元組中的所有數(shù)據(jù)進(jìn)行疊加操作,例如下面的代碼中:

          # 單個(gè)卷積def conv2D(filter,kernel_size,stride=2,l2_=True,bise=False):    padding='valid' if stride==2 else 'same'    return Conv2D(filters=filter,                      kernel_size=kernel_size,                      padding=padding,                      kernel_regularizer=l2(5e-4),                      strides=stride,use_bias=bise)
          # 卷積+標(biāo)準(zhǔn)化+激活def Conv2D_BN_Leaky(filter,kernel_size,stride=2,l2=True,bise=False): return compose( conv2D(filter,kernel_size,stride,l2,bise), BatchNormalization(), LeakyReLU(alpha=0.1) )


          Conv2D_BN_Leaky()函數(shù)中的代碼一般情況下我們是這么寫的,使用reduce的話,可以使用和keras類似的函數(shù)式的方式搭建網(wǎng)絡(luò)。

          def Conv2D_BN_Leaky(x,filter,kernel_size,stride=2,l2=True,bise=False):    x=conv2D(x,filter,kernel_size,stride,l2,bise)    x=BatchNormalization()(x)    x=LeakyReLU(alpha=0.1)(x)    return  x


          接著是 殘差網(wǎng)絡(luò),DarkNet的殘差結(jié)構(gòu)并不是和ResNet相同,而是和DenseNet類似,下采樣放到了殘差連接的外面,但連接處又使用add操作區(qū)別于DenseNetconcatenate操作。

          # 殘差塊def res_block(x,filters,num_res_blocks):    x=ZeroPadding2D(((1,0),(1,0)))(x)    # 下采樣    x=Conv2D_BN_Leaky(filters,kernel_size=3)(x)    # 多個(gè)殘差塊    for i in range(num_res_blocks):        y=Conv2D_BN_Leaky(filters//2,kernel_size=1,stride=1)(x)        y=Conv2D_BN_Leaky(filters,kernel_size=3,stride=1)(y)        x=Add()([x,y])    return x


          接著,是主干網(wǎng)絡(luò)的搭建,這一部分比較簡單,直接寫入模型結(jié)構(gòu)中的參數(shù),然后調(diào)用前面的函數(shù)即可,再這里我們進(jìn)行了32倍下采樣,再最后使用全局平均池化展平特征向量,并在最后連接一個(gè)輸出層,是我們數(shù)據(jù)集的類別數(shù)。

          def dreaknet53_output(inpt):    # 200*60    x=Conv2D_BN_Leaky(32,3,stride=1)(inpt)    # 100*30    x = res_block(x, 64, 1)    # 50*15    x = res_block(x,128 ,2)    # 25*7    x = res_block(x ,256, 8)    # 12*3    x = res_block(x ,512, 8)    # 6*1    x = res_block(x ,1024, 4)    x=GlobalAveragePooling2D()(x)    x=Dense(702,activation='softmax')(x)    model=k.models.Model(inpt,x)    return model


          最后,在mian函數(shù)中創(chuàng)建模型結(jié)構(gòu),編譯模型,加載數(shù)據(jù),進(jìn)行訓(xùn)練,這里我們使用了一個(gè)回調(diào)函數(shù)用來保存最優(yōu)模型。

          if __name__ == '__main__':
          model=dreaknet53_output(k.Input((200,60,3))) model.summary() # batch_size=4 data,label=load_data() m=k.callbacks.ModelCheckpoint('darknet_reid_{loss:.4f}.h5', monitor='loss',save_best_only=True) model.compile(loss='categorical_crossentropy', optimizer=k.optimizers.Adam(lr=3e-5), metrics=['acc']) model.fit(gan_data(data,label,batch_size), steps_per_epoch=len(data)//batch_size, epochs=100, callbacks=[m]) model.save('darknet_reid.h5')


          #3  康康結(jié)果

          Grain Rain


          由于篇幅的原因,模型使用以及預(yù)測的代碼將在下一篇中放出,先康康最終效果咯。點(diǎn)個(gè)關(guān)注能夠第一時(shí)間收到更新哈!




          瀏覽 37
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  小黄片下载免费视频 | 亚洲第一大成人网站 | 超碰在线中文1159 | 中国三级片翔田千里老师高潮网站 | 亚洲无码短视频 |