Interprétation du code détr (1) chargement des données

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
insérez la description de l'image ici
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.
insérez la description de l'image ici
Recherchez Usage - Object detectionla 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. gitL'installation peut aller vérifier.
insérez la description de l'image ici
Une fois l'environnement configuré, vous pouvez exécuter main.pyle fichier pour commencer à exécuter l'intégralité du projet.
Avant de l'exécuter, main.pyvous devez définir ses paramètres initiaux, tels que batch_size, source de données, etc. defaultIl y a deux façons de le définir : Tout d'abord, définissez-le directement après chaque paramètre dans le code :
insérez la description de l'image ici
Vous pouvez également modifier la configuration en cours grâce à lui lors du débogage Debug:
insérez la description de l'image ici
Après main.pyavoir 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 :
insérez la description de l'image ici
rendez-vous directement dans le répertoire de cet article.insérez la description de l'image ici

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.

Partie de chargement de l'ensemble de données Interprétation du code de la classe SSDDataset - mécanisme d'échantillonnage des données

En fait, quel que soit l'algorithme de détection, il utilise DataLoaderl'échantillonnage des données. Trouvez-le
directement dans le fichier , le code est le suivantmain.pyDataLoader

  data_loader_train = DataLoader(dataset_train, batch_sampler=batch_sampler_train,
                                   collate_fn=utils.collate_fn, num_workers=args.num_workers)

DataLoaderDé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_fnla 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_trainCet exemple peut être considéré comme un itérateur de données, DataLoaderindiquant dataset_trainà l'itérateur qu'il doit échantillonner aléatoirement 16 images, dataset_trainil 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+Fdirectement dans :main.pydataset_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_cocola fonction
insérez la description de l'image ici

Le fichier de source de données n'existe pas et l'erreur est résolue

Une chose à noter ici PATHSest 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.
insérez la description de l'image ici

Cette étape associe le chemin de l'ensemble de données à datasetl'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_tarinle contenu principal de cet itérateur de données.

insérez la description de l'image ici

dataset_trainLa fonction correspondante pouvant DataLoaderêtre échantillonnée est la fonction CocoDetectiondans def __getitem__(self, idx):, et cette fonction échantillonnera en fonction de l'index DataLoaderémis .idx

insérez la description de l'image ici
CocoDetectionLa fonction de transformation d'image et la fonction de traitement des données sont définies dans : une fois
insérez la description de l'image ici
la valeur initiale définie, revenez main.pyà la recherche train_one_epochet les données train_one_epochsont lues. train_one_epochIl 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_epochfonction 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 inaccédant DataLoaderà la paire, la paire est échantillonnée DataLoaderen fonction de ce qui est configuré .dataset_train

insérez la description de l'image ici
DataLoaderÉcrivez l' appel for inen metric_logger.log_every:
insérez la description de l'image ici

échantillonnage

DataLoaderGé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. imgC'est l'image correspondant à cet index targetqui est l'annotation correspondante.

insérez la description de l'image ici
insérez la description de l'image ici
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.preparetraiter 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 tensorformats.
ConvertCocoPolysToMaskConvertissez 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
insérez la description de l'image ici
Détecter et la segmentation d'instance afin d'ignorer keypoints、self.return_masksles 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

mapDe 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 targetcontenu résultant est le suivant :
insérez la description de l'image ici
en img, target = self.prepare(img, target)transformant targetle format de l'annotation en dicttype :
insérez la description de l'image ici

traiter avecimg

Le traitement d'image est utilisé ici. transformsIl insérez la description de l'image ici
s'agit d'une fonction d'opération d'image courante. Regardez make_coco_transformsla fonction directement.
insérez la description de l'image ici
Autrement dit, elle convertit l'image d'entrée dans tensorun format, puis la normalise, puis juge s'il s'agit traind'un mode ou vald'un mode. S'il est tarinun 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)

DataLoaderAprès avoir échantillonné trainsetles données d'apprentissage une batchpar 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, DataLoaderdeux images sont échantillonnées dans un lot :
insérez la description de l'image ici
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 :
insérez la description de l'image ici

Je suppose que tu aimes

Origine blog.csdn.net/weixin_55224780/article/details/130506070
conseillé
Classement