[DETR] Entraînez votre propre ensemble de données - notes d'entraînement

DETR (Detection with TRansformers) forme son propre ensemble de données - notes de pratique et résumé du problème

DETR (Detection with TRansformers) est une détection de cible de bout en bout basée sur des transformateurs, sans étapes de post-traitement NMS, et sans ancres.
Réaliser la formation de DETR en utilisant le jeu de données NWPUVHR10.Le
jeu de données NWPU contient un total de dix catégories de cibles, dont 650 échantillons positifs et 150 échantillons négatifs (non utilisés).

NWPU_CATEGORIES=['airplane','ship','storage tank','baseball diamond','tennis court',\
					'basketball court','ground track field','harbor','bridge','vehicle']

Code : https://github.com/facebookresearch/detr

1. Formation

1. Préparation du jeu de données

Le format de l'ensemble de données requis par DETR est le format coco, et les images et les fichiers d'étiquettes sont enregistrés dans quatre dossiers : ensemble d'apprentissage, ensemble de test, ensemble de vérification et fichiers d'étiquettes, parmi lesquels les fichiers d'étiquettes au format json sont stockés dans des annotations
insérez la description de l'image ici

insérez la description de l'image ici

Le code suivant contient plusieurs jeux de données RSOD, NWPU, DIOR, YOLO data set label file conversion json function. Créez un nouveau fichier py tojson.py et utilisez le code suivant pour générer le fichier json requis.

Générer instances_train2017.json
(a) Modifier le chemin par défaut de image_path à la ligne 29 vers le chemin de train2017 ;
(b) Modifier le chemin par défaut de annotation_path à la ligne 31 vers le chemin du fichier d'étiquettes (les étiquettes de train et val sont placées dans ce dossier, générez donc instances_val2017.json (c) Modifiez le
jeu de données de 33 lignes avec votre propre nom de jeu de données NWPU
(d) Modifiez le chemin par défaut de la sauvegarde de 34 lignes vers le chemin de sauvegarde du fichier json.../NWPUVHR -10/annotations/instances_train2017.json

import os
import cv2
import json
import argparse
from tqdm import tqdm
import xml.etree.ElementTree as ET

COCO_DICT=['images','annotations','categories']
IMAGES_DICT=['file_name','height','width','id']

ANNOTATIONS_DICT=['image_id','iscrowd','area','bbox','category_id','id']

CATEGORIES_DICT=['id','name']
## {'supercategory': 'person', 'id': 1, 'name': 'person'}
## {'supercategory': 'vehicle', 'id': 2, 'name': 'bicycle'}
YOLO_CATEGORIES=['person']
RSOD_CATEGORIES=['aircraft','playground','overpass','oiltank']
NWPU_CATEGORIES=['airplane','ship','storage tank','baseball diamond','tennis court',\
					'basketball court','ground track field','harbor','bridge','vehicle']

VOC_CATEGORIES=['aeroplane','bicycle','bird','boat','bottle','bus','car','cat','chair','cow',\					'diningtable','dog','horse','motorbike','person','pottedplant','sheep','sofa','train','tvmonitor']

DIOR_CATEGORIES=['golffield','Expressway-toll-station','vehicle','trainstation','chimney','storagetank',\
					'ship','harbor','airplane','groundtrackfield','tenniscourt','dam','basketballcourt',\
					'Expressway-Service-area','stadium','airport','baseballfield','bridge','windmill','overpass']

parser=argparse.ArgumentParser(description='2COCO')
#parser.add_argument('--image_path',type=str,default=r'T:/shujuji/DIOR/JPEGImages-trainval/',help='config file')
parser.add_argument('--image_path',type=str,default=r'G:/NWPU VHR-10 dataset/positive image set/',help='config file')
#parser.add_argument('--annotation_path',type=str,default=r'T:/shujuji/DIOR/Annotations/',help='config file')
parser.add_argument('--annotation_path',type=str,default=r'G:/NWPU VHR-10 dataset/ground truth/',help='config file')
parser.add_argument('--dataset',type=str,default='NWPU',help='config file')
parser.add_argument('--save',type=str,default='G:/NWPU VHR-10 dataset/instances_train2017.json',help='config file')
args=parser.parse_args()
def load_json(path):
	with open(path,'r') as f:
		json_dict=json.load(f)
		for i in json_dict:
			print(i)
		print(json_dict['annotations'])
def save_json(dict,path):
	print('SAVE_JSON...')
	with open(path,'w') as f:
		json.dump(dict,f)
	print('SUCCESSFUL_SAVE_JSON:',path)
def load_image(path):
	img=cv2.imread(path)
	return img.shape[0],img.shape[1]
def generate_categories_dict(category):       #ANNOTATIONS_DICT=['image_id','iscrowd','area','bbox','category_id','id']
	print('GENERATE_CATEGORIES_DICT...')
	return [{
    
    CATEGORIES_DICT[0]:category.index(x)+1,CATEGORIES_DICT[1]:x} for x in category]  #CATEGORIES_DICT=['id','name']
def generate_images_dict(imagelist,image_path,start_image_id=11725):  #IMAGES_DICT=['file_name','height','width','id']
	print('GENERATE_IMAGES_DICT...')
	images_dict=[]
	with tqdm(total=len(imagelist)) as load_bar:
		for x in imagelist:  #x就是图片的名称
			#print(start_image_id)
			dict={
    
    IMAGES_DICT[0]:x,IMAGES_DICT[1]:load_image(image_path+x)[0],\
					IMAGES_DICT[2]:load_image(image_path+x)[1],IMAGES_DICT[3]:imagelist.index(x)+start_image_id}
			load_bar.update(1)
			images_dict.append(dict)
	return images_dict

def DIOR_Dataset(image_path,annotation_path,start_image_id=11725,start_id=0):
	categories_dict=generate_categories_dict(DIOR_CATEGORIES)    #CATEGORIES_DICT=['id':,1'name':golffield......]  id从1开始
	imgname=os.listdir(image_path)
	images_dict=generate_images_dict(imgname,image_path,start_image_id)  #IMAGES_DICT=['file_name','height','width','id']  id从0开始的
	print('GENERATE_ANNOTATIONS_DICT...')  #生成cooc的注记   ANNOTATIONS_DICT=['image_id','iscrowd','area','bbox','category_id','id']
	annotations_dict=[]
	id=start_id
	for i in images_dict:
		image_id=i['id']
		print(image_id)
		image_name=i['file_name']
		annotation_xml=annotation_path+image_name.split('.')[0]+'.xml'
		tree=ET.parse(annotation_xml)
		root=tree.getroot()
		for j in root.findall('object'):
			category=j.find('name').text
			category_id=DIOR_CATEGORIES.index(category)  #字典的索引,是从1开始的
			x_min=float(j.find('bndbox').find('xmin').text)
			y_min=float(j.find('bndbox').find('ymin').text)
			w=float(j.find('bndbox').find('xmax').text)-x_min
			h=float(j.find('bndbox').find('ymax').text)-y_min
			area = w * h
			bbox = [x_min, y_min, w, h]
			dict = {
    
    'image_id': image_id, 'iscrowd': 0, 'area': area, 'bbox': bbox, 'category_id': category_id,
					'id': id}
			annotations_dict.append(dict)
			id=id+1
	print('SUCCESSFUL_GENERATE_DIOR_JSON')
	return {
    
    COCO_DICT[0]:images_dict,COCO_DICT[1]:annotations_dict,COCO_DICT[2]:categories_dict}
def NWPU_Dataset(image_path,annotation_path,start_image_id=0,start_id=0):
	categories_dict=generate_categories_dict(NWPU_CATEGORIES)
	imgname=os.listdir(image_path)
	images_dict=generate_images_dict(imgname,image_path,start_image_id)
	print('GENERATE_ANNOTATIONS_DICT...')
	annotations_dict=[]
	id=start_id
	for i in images_dict:
		image_id=i['id']
		image_name=i['file_name']
		annotation_txt=annotation_path+image_name.split('.')[0]+'.txt'
		txt=open(annotation_txt,'r')
		lines=txt.readlines()
		for j in lines:
			if j=='\n':
				continue
			category_id=int(j.split(',')[4])
			category=NWPU_CATEGORIES[category_id-1]
			print(category_id,'        ',category)
			x_min=float(j.split(',')[0].split('(')[1])
			y_min=float(j.split(',')[1].split(')')[0])
			w=float(j.split(',')[2].split('(')[1])-x_min
			h=float(j.split(',')[3].split(')')[0])-y_min
			area=w*h
			bbox=[x_min,y_min,w,h]
			dict = {
    
    'image_id': image_id, 'iscrowd': 0, 'area': area, 'bbox': bbox, 'category_id': category_id,
					'id': id}
			id=id+1
			annotations_dict.append(dict)
	print('SUCCESSFUL_GENERATE_NWPU_JSON')
	return {
    
    COCO_DICT[0]:images_dict,COCO_DICT[1]:annotations_dict,COCO_DICT[2]:categories_dict}

def YOLO_Dataset(image_path,annotation_path,start_image_id=0,start_id=0):
	categories_dict=generate_categories_dict(YOLO_CATEGORIES)
	imgname=os.listdir(image_path)
	images_dict=generate_images_dict(imgname,image_path)
	print('GENERATE_ANNOTATIONS_DICT...')
	annotations_dict=[]
	id=start_id
	for i in images_dict:
		image_id=i['id']
		image_name=i['file_name']
		W,H=i['width'],i['height']
		annotation_txt=annotation_path+image_name.split('.')[0]+'.txt'
		txt=open(annotation_txt,'r')
		lines=txt.readlines()
		for j in lines:
			category_id=int(j.split(' ')[0])+1
			category=YOLO_CATEGORIES
			x=float(j.split(' ')[1])
			y=float(j.split(' ')[2])
			w=float(j.split(' ')[3])
			h=float(j.split(' ')[4])
			x_min=(x-w/2)*W
			y_min=(y-h/2)*H
			w=w*W
			h=h*H
			area=w*h
			bbox=[x_min,y_min,w,h]
			dict={
    
    'image_id':image_id,'iscrowd':0,'area':area,'bbox':bbox,'category_id':category_id,'id':id}
			annotations_dict.append(dict)
			id=id+1
	print('SUCCESSFUL_GENERATE_YOLO_JSON')
	return {
    
    COCO_DICT[0]:images_dict,COCO_DICT[1]:annotations_dict,COCO_DICT[2]:categories_dict}
def RSOD_Dataset(image_path,annotation_path,start_image_id=0,start_id=0):
	categories_dict=generate_categories_dict(RSOD_CATEGORIES)
	imgname=os.listdir(image_path)
	images_dict=generate_images_dict(imgname,image_path,start_image_id)
	print('GENERATE_ANNOTATIONS_DICT...')
	annotations_dict=[]
	id=start_id
	for i in images_dict:
		image_id=i['id']
		image_name=i['file_name']
		annotation_txt=annotation_path+image_name.split('.')[0]+'.txt'
		txt=open(annotation_txt,'r')
		lines=txt.readlines()
		for j in lines:
			category=j.split('\t')[1]
			category_id=RSOD_CATEGORIES.index(category)+1
			x_min=float(j.split('\t')[2])
			y_min=float(j.split('\t')[3])
			w=float(j.split('\t')[4])-x_min
			h=float(j.split('\t')[5])-y_min
			area = w * h
			bbox = [x_min, y_min, w, h]
			dict = {
    
    'image_id': image_id, 'iscrowd': 0, 'area': area, 'bbox': bbox, 'category_id': category_id,
					'id': id}
			annotations_dict.append(dict)
			id=id+1
	print('SUCCESSFUL_GENERATE_RSOD_JSON')

	return {
    
    COCO_DICT[0]:images_dict,COCO_DICT[1]:annotations_dict,COCO_DICT[2]:categories_dict}
if __name__=='__main__':
	dataset=args.dataset   #数据集名字
	save=args.save  #json的保存路径
	image_path=args.image_path     #对于coco是图片的路径
	annotation_path=args.annotation_path   #coco的annotation路径
	if dataset=='RSOD':
		json_dict=RSOD_Dataset(image_path,annotation_path,0)
	if dataset=='NWPU':
		json_dict=NWPU_Dataset(image_path,annotation_path,0)
	if dataset=='DIOR':
		json_dict=DIOR_Dataset(image_path,annotation_path,11725)
	if dataset=='YOLO':
		json_dict=YOLO_Dataset(image_path,annotation_path,0)
	save_json(json_dict,save)

Exécutez pour générer instances_train2017.json, puis modifiez le chemin pour générer instances_train2017.json.
(Après avoir été rappelé par les amis dans la zone de commentaire, il y a un problème et a été modifié)

Si votre propre ensemble de données est au format voc, vous pouvez utiliser le code donné dans le lien de référence 1.

2. Configuration de l'environnement

Activez l'environnement dans lequel se trouve le projet actuel et utilisez la commande suivante pour terminer la configuration de l'environnement :

pip install -r requirements.txt

3. génération de fichier pth

Téléchargez d'abord le fichier de pré-formation , l'officiel fournit les modèles DETR et DETR-DC5, deux modèles, ce dernier utilise la convolution des trous dans la cinquième couche du réseau dorsal, choisissez-en un à télécharger

Créez un nouveau fichier py, mydataset.py, utilisez le code suivant pour modifier num_classes au nombre de vos propres catégories + 1

import torch
pretrained_weights  = torch.load('detr-r50-e632da11.pth')

#NWPU数据集,10类
num_class = 11    #类别数+1,1为背景
pretrained_weights["model"]["class_embed.weight"].resize_(num_class+1, 256)
pretrained_weights["model"]["class_embed.bias"].resize_(num_class+1)
torch.save(pretrained_weights, "detr-r50_%d.pth"%num_class)

Exécuter, générer detr-r50_11.pth

4. Modification des paramètres

Modifiez le fichier models/detr.py, dans la fonction build(), vous pouvez commenter le code dans la case rouge et définir directement num_classes sur le nombre de vos propres catégories + 1
insérez la description de l'image ici

5. Formation

Certains paramètres doivent être définis pour la formation, qui peuvent être modifiés directement dans le fichier main.py ou en utilisant la ligne de commande

[a] Modifiez directement le fichier main.py
Modifiez les paramètres d'entraînement tels que epochs, lr, batch_size du fichier main.py
insérez la description de l'image ici
Modifiez votre propre chemin d'accès à l'ensemble de données :
insérez la description de l'image ici

Définissez le chemin de sortie :
insérez la description de l'image ici
modifiez le résumé pour qu'il soit votre propre chemin de fichier de poids avant l'entraînement
insérez la description de l'image ici
[b] ligne de commande

python main.py --dataset_file "coco" --coco_path "/home/NWPUVHR-10" --epoch 300 --lr=1e-4 --batch_size=8 --num_workers=4 --output_dir="outputs" --resume="detr_r50_11.pth"

Exécutez le fichier main.py

2. Bugs qui apparaissent

1. KeyError : 'zone'

area = torch.tensor([obj["area"] for obj in anno])
KeyError : 'area'
insérez la description de l'image ici
peut être vu à partir de l'instruction localisée, il se peut que le dictionnaire obj n'ait pas de clé nommée area, vérifiez mon étiquette fichier, il y a effectivement un problème avec la génération, il ne contient aucune information de zone, il est régénéré et il s'exécute avec succès.
insérez la description de l'image ici

3. Évaluation et prévision

1. Évaluation

En fait, pendant le processus de formation, DETR effectuera automatiquement une évaluation de la précision à chaque époque. Les résultats de l'évaluation peuvent être visualisés directement dans la sortie ou dans les fichiers intermédiaires générés. Vous pouvez également utiliser main.py pour évaluer la précision et modifier - reprendre dans le code suivant jusqu'au dernier

python main.py --batch_size 6 --no_aux_loss --eval --resume /home/detr-main/outputs/checkpoint0299.pth --coco_path /home/NWPUVHR-10

Résultats de l'évaluation de la précision :
après un entraînement de 300 époques, l'AP avec IoU=0,5 est d'environ 88 %
insérez la description de l'image ici

2. Prévision

Utilisez le code du lien de référence 3 pour enregistrer les images à prédire dans un dossier et afficher les résultats de prédiction de toutes les images en même temps pendant la prédiction

Les paramètres à modifier sont :

Backbone, le backbone que j'ai téléchargé à l'époque était resnet50, modifié (le réseau de caractéristiques du backbone qui a été téléchargé pendant la formation est le fichier de poids DETR de Resnet50, placé dans le dossier principal) les paramètres pertinents de l'ensemble de données - coco_path est modifié pour votre propre
insérez la description de l'image ici
chemin d'accès à l'ensemble de données

outputdir Changez pour le dossier enregistré de l'image de prédiction créée
–resume Changez pour le chemin du fichier modèle formé
insérez la description de l'image ici
Changez le chemin_du_fichier_image et le chemin_de l'image du chemin du dossier de l'image à prédire
insérez la description de l'image ici

ps : Comme j'ai couru avec le serveur et que je n'ai pas pu renvoyer l'image, une erreur s'est produite, j'ai donc commenté ces deux phrases :

#cv2.imshow("images",image)
#cv2.waitKey(1)

Il est possible de signaler une erreur, qui est causée par la non-détection de la cible lors de la prédiction d'une de vos photos :
insérez la description de l'image ici
Résultat de la prédiction :
insérez la description de l'image ici

Références :
1. Windows 10 reproduit DEtection TRansformers (DETR)
2. Comment utiliser DETR (transformateur de détection) pour former votre propre ensemble de données
3. Pytorch réalise le programme de raisonnement de DETR

Je suppose que tu aimes

Origine blog.csdn.net/gsgs1234/article/details/125654021
conseillé
Classement