Annuaire d'articles
guide
Code source : Detr
Le format d'ensemble de données utilisé par Detr est le format d'ensemble de données coco, donc avant d'exécuter l'algorithme Detr, nous devons convertir notre ensemble de données en un ensemble de données coco. Vous pouvez vous référer au modèle Detr de l'ensemble de données VOC à COCO
comme le montre la figure ci-dessus, simplement à En d'autres termes, une fois l'extraction de la caractéristique CNN effectuée sur l'image, elle est envoyée au module Transformer, puis la trame de prédiction est directement générée.Après avoir défini un seuil, la trame de prédiction générée est le résultat de la prédiction, et il n'est pas nécessaire de passer par l'opération NMS.
Après avoir téléchargé le code source, ouvrez directement le projet. Le projet Detr s'appuie sur plusieurs bibliothèques tierces créées par l'auteur, donc ouvrez d'abord le fichier README.md dans le projet.
Recherchez Usage - Object detection
la section et installez la bibliothèque tierce dans l'environnement du compilateur conformément aux instructions d'installation fournies dans cette section. Notez ici, vous pouvez obtenir une erreur lorsque vous entrez la commande, la raison peut être que vous ne l'avez pas installé git
. git
L'installation peut aller vérifier.
Une fois l'environnement configuré, vous pouvez exécuter main.py
le fichier pour commencer à exécuter l'intégralité du projet.
Avant de l'exécuter, main.py
vous devez définir ses paramètres initiaux, tels que batch_size, source de données, etc. default
Il y a deux façons de le définir : Tout d'abord, définissez-le directement après chaque paramètre dans le code :
Vous pouvez également modifier la configuration en cours grâce à lui lors du débogage Debug
:
Après main.py
avoir défini la source de données, vous pouvez exécuter le projet.
S'il y a une erreur telle que le fichier de données est introuvable :
rendez-vous directement dans le répertoire de cet article.
chargement des données
Cette partie examine d'abord comment le jeu de données est chargé dans le modèle. J'ai déjà écrit un article sur le mécanisme de chargement des données.
En fait, quel que soit l'algorithme de détection, il utilise DataLoader
l'échantillonnage des données. Trouvez-le
directement dans le fichier , le code est le suivantmain.py
DataLoader
data_loader_train = DataLoader(dataset_train, batch_sampler=batch_sampler_train,
collate_fn=utils.collate_fn, num_workers=args.num_workers)
DataLoader
Définissez l'ensemble de données dataset_train
, la stratégie d'échantillonnage batch_sampler
(l'échantillonnage aléatoire ou l'échantillonnage séquentiel peut être sélectionné), collate_fn
la stratégie de collecte (après le traitement préliminaire des données lues, dans quel format sera renvoyé à la fonction supérieure) num_workers
(indiquez à l'instance DataLoader combien de sous-processus utiliser Chargement de données (lié au CPU, non lié au GPU))
dataset_train
Cet exemple peut être considéré comme un itérateur de données, DataLoader
indiquant dataset_train
à l'itérateur qu'il doit échantillonner aléatoirement 16 images, dataset_train
il va itérer 16 fois, à chaque fois pour lire une image, et effectuer un traitement préliminaire sur cette image .
dataset_train
Appuyez sur pour rechercher ctrl+F
directement dans :main.py
dataset_tarin
dataset_train = build_dataset(image_set='train', args=args)
dataset_val = build_dataset(image_set='val', args=args)
Appuyez sur la fonction ctrl+鼠标左键
Entréebuild_dataset
:
def build_dataset(image_set, args):
if args.dataset_file == 'coco':
return build_coco(image_set, args)
if args.dataset_file == 'coco_panoptic':
# to avoid making panopticapi required for coco
from .coco_panoptic import build as build_coco_panoptic
return build_coco_panoptic(image_set, args)
raise ValueError(f'dataset {
args.dataset_file} not supported')
Le fichier d'ensemble de données dans cet article est coco , alors exécutez les deux premières phrases directement et entrez build_coco
la fonction
Le fichier de source de données n'existe pas et l'erreur est résolue
Une chose à noter ici PATHS
est le nom de l'ensemble de formation et de l'ensemble de validation sous l'ensemble de données actuel. S'il est différent du nom de votre ensemble de données, vous pouvez le remplacer par le nom sous votre ensemble de données ici.
Cette étape associe le chemin de l'ensemble de données à dataset
l'itérateur, puis l'itérateur peut lire les données sous le chemin de l'ensemble de données conformément à l'instruction.
CocoDétection
Cette partie est dataset_tarin
le contenu principal de cet itérateur de données.
dataset_train
La fonction correspondante pouvant DataLoader
être échantillonnée est la fonction CocoDetection
dans def __getitem__(self, idx):
, et cette fonction échantillonnera en fonction de l'index DataLoader
émis .idx
CocoDetection
La fonction de transformation d'image et la fonction de traitement des données sont définies dans : une fois
la valeur initiale définie, revenez main.py
à la recherche train_one_epoch
et les données train_one_epoch
sont lues. train_one_epoch
Il s'agit également d'un cycle formel de formation.
train_stats = train_one_epoch(
model, criterion, data_loader_train, optimizer, device, epoch,
args.clip_max_norm)
La train_one_epoch
fonction open for samples, targets in metric_logger.log_every(data_loader, print_freq, header):
échantillonne l'ensemble de données dans cette ligne d'instructions. En for in
accédant DataLoader
à la paire, la paire est échantillonnée DataLoader
en fonction de ce qui est configuré .dataset_train
DataLoader
Écrivez l' appel for in
en metric_logger.log_every
:
échantillonnage
DataLoader
Générez aléatoirement un index et transmettez-le à l'itérateur de données CocoDetection
, et def __getitem__(self, idx):
traitez les données correspondant à l'index : la fonction
dans la figure ci-dessous super(CocoDetection, self).__getitem__(idx)
est une fonction de la propre bibliothèque tierce de COCO, qui peut obtenir directement les images correspondantes dans l'ensemble de données et lui selon l'étiquette d'index. img
C'est l'image correspondant à cet index target
qui est l'annotation correspondante.
Traitement ultérieur img, target = self.prepare(img, target)
des images et des annotations :
img, target = self.prepare(img, target)
traitement de l'information
traiter avectarget
Pour self.prepare
traiter l'image d'entrée et l'annotation, obtenez d'abord l'identifiant de l'image, puis obtenez les informations d'annotation, obtenez la catégorie cible, puis convertissez-les en tensor
formats.
ConvertCocoPolysToMask
Convertissez la cible correspondant à chaque image en un dict, qui stocke toutes les informations d'annotation de l'image, et les informations utiles pour la détection de la cible sont les cases et les étiquettes, qui sont les suivantes : parce que la recherche est sur la détection de la cible, pas sur les points clés
Détecter et la segmentation d'instance afin d'ignorer keypoints、self.return_masks
les codes associés, tels que les deux éléments de code suivants :
if self.return_masks:
segmentations = [obj["segmentation"] for obj in anno]
masks = convert_coco_poly_to_mask(segmentations, h, w)
keypoints = None
if anno and "keypoints" in anno[0]:
keypoints = [obj["keypoints"] for obj in anno]
keypoints = torch.as_tensor(keypoints, dtype=torch.float32)
num_keypoints = keypoints.shape[0]
if num_keypoints:
keypoints = keypoints.view(num_keypoints, -1, 3)
Ensuite, réorganisez les informations d'annotation obtenues entarget字典中
:
target = {
}
target["boxes"] = boxes
target["labels"] = classes
target["image_id"] = image_id
map
De plus, un calcul de la surface du contenu marqué, ainsi que des informations sur la taille, etc., est préparé pour l'utilisation ultérieure de COCOAPI pour calculer la valeur détectée .
# for conversion to coco api
area = torch.tensor([obj["area"] for obj in anno])
iscrowd = torch.tensor([obj["iscrowd"] if "iscrowd" in obj else 0 for obj in anno])
target["area"] = area[keep]
target["iscrowd"] = iscrowd[keep]
target["orig_size"] = torch.as_tensor([int(h), int(w)])
target["size"] = torch.as_tensor([int(h), int(w)])
Le target
contenu résultant est le suivant :
en img, target = self.prepare(img, target)
transformant target
le format de l'annotation en dict
type :
traiter avecimg
Le traitement d'image est utilisé ici. transforms
Il
s'agit d'une fonction d'opération d'image courante. Regardez make_coco_transforms
la fonction directement.
Autrement dit, elle convertit l'image d'entrée dans tensor
un format, puis la normalise, puis juge s'il s'agit train
d'un mode ou val
d'un mode. S'il est tarin
un mode, retournez d'abord l'image, puis effectuez un zoom aléatoire et d'autres opérations. Enfin, retournez l'image. Le code spécifique est le suivant :
def make_coco_transforms(image_set):
normalize = T.Compose([
T.ToTensor(),
T.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])
])
scales = [480, 512, 544, 576, 608, 640, 672, 704, 736, 768, 800]
if image_set == 'train':
return T.Compose([
T.RandomHorizontalFlip(),#随机水平翻转给定的PIL.image 概率为0.5
T.RandomSelect(#随机选择两个字操作之一
T.RandomResize(scales, max_size=1333),#随机选择sizes中的一个值作为图象短边,并保持比例,最大不超过max_size
T.Compose([
T.RandomResize([400, 500, 600]),
T.RandomSizeCrop(384, 600),#对图片进行随机尺寸裁剪,最后缩放到统一大小
T.RandomResize(scales, max_size=1333),#
])
),
normalize,
])
if image_set == 'val':
return T.Compose([
T.RandomResize([800], max_size=1333),
normalize,
])
raise ValueError(f'unknown {
image_set}')
stratégie de collectecollate_fn(batch)
DataLoader
Après avoir échantillonné trainset
les données d'apprentissage une batch
par une, passez les données collectées dans collate_fn(batch)
la fonction, organisez ce lot de données et renvoyez-le au niveau supérieur.
Comme le montre la figure ci-dessous, DataLoader
deux images sont échantillonnées dans un lot :
Ici, les images sont à nouveau exploitées nested_tensor_from_tensor_list
. Pour chaque lot d'images, recherchez d'abord la valeur maximale Hmax et Wmax de H et W de chaque lot d'images, puis convertir l'original L'image est remplie avec une taille de 3 Hmax Wmax, et la partie image est définie sur False, et la partie de remplissage est définie sur True.Enfin, le tenseur et le masque de données d'image sont emballés au format nesttensor.
De cette façon, la taille des images de sortie dans chaque lot est cohérente.
def nested_tensor_from_tensor_list(tensor_list: List[Tensor]):
# TODO make this more general
if tensor_list[0].ndim == 3:
if torchvision._is_tracing():
# nested_tensor_from_tensor_list() does not export well to ONNX
# call _onnx_nested_tensor_from_tensor_list() instead
return _onnx_nested_tensor_from_tensor_list(tensor_list)
# TODO make it support different-sized images
max_size = _max_by_axis([list(img.shape) for img in tensor_list])
# min_size = tuple(min(s) for s in zip(*[img.shape for img in tensor_list]))
batch_shape = [len(tensor_list)] + max_size
b, c, h, w = batch_shape
dtype = tensor_list[0].dtype
device = tensor_list[0].device
tensor = torch.zeros(batch_shape, dtype=dtype, device=device)
mask = torch.ones((b, h, w), dtype=torch.bool, device=device)
for img, pad_img, m in zip(tensor_list, tensor, mask):
pad_img[: img.shape[0], : img.shape[1], : img.shape[2]].copy_(img)
m[: img.shape[1], :img.shape[2]] = False
else:
raise ValueError('not supported')
return NestedTensor(tensor, mask)
L'image traitée est illustrée ci-dessous :