question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Training on new custom dataset

See original GitHub issue

Hello! Thank you for the code.

I am trying to train the model on my own custom dataset (folder of images). But it’s a bit hard to do so. I tried to follow this:

` Create a new python script in the datasets package. Implement a dataset that inherits the fcdd.datasets.bases.TorchvisionDataset class. Your implementation needs to process all parameters of the fcdd.datasets.bases.load_dataset function in its initialization. You can use the preproc parameter to switch between different data preprocessing pipelines (augmentation, etc). In the end, your implementation needs to have at least all attributes defined in fcdd.datasets.bases.BaseADDataset class. Most importantly, the _train_set attribute and the _test_set attribute containing the corresponding torchvision-style datasets. Have a look at the already available implementations.

Add a name for your dataset to the fcdd.datasets.init.DS_CHOICES variable. Add your dataset to the “switch-case” in the fcdd.datasets.init.load_dataset function. Add the number of available class for your dataset to the fcdd.datasets.init.no_classes function and add the class names to fcdd.datasets.init.str_labels.

`

But I am finding it hard to do. I cant see where shall I put the images folder exactly and how to prepare those scripts. Can anyone help?

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

3reactions
liznerskicommented, May 19, 2021

Hi. You can put your image folder anywhere you want, in your implementation you just need to point to the correct location. Let’s go through this step by step. Consider your dataset being named foodata.

  1. Create a script foodata.py in fcdd.datasets. Implement a typical torchvision-style dataset for your image folder. You can reuse the PyTorch default implementation torchvision.datasets.ImageFolder. Read https://pytorch.org/docs/1.4.0/torchvision/datasets.html#datasetfolder for how your folder needs to be structured for this. So I imagine something like this:
import random
import torch
import torchvision.transforms as transforms
from torchvision.datasets import ImageFolder
from typing import Tuple


class FooData(ImageFolder):
    def __init__(self, root, transform=None, target_transform=None,
                 normal_classes=None, all_transform=None):
        super().__init__(root, transform=transform, target_transform=target_transform)
        self.normal_classes = normal_classes
        self.all_transform = all_transform  # contains the OnlineSupervisor

    def __getitem__(self, index: int) -> Tuple[torch.Tensor, int]:
        target = self.targets[index]

        if self.target_transform is not None:  # transforms labels (e.g. class labels to AD labels)
            target = self.target_transform(target)

        if self.all_transform is not None:  # replaces image and label with artificial anomalies 
            replace = random.random() < 0.5
            if replace:
                img, _, target = self.all_transform(None, None, target, replace=replace)
                img = transforms.ToPILImage()(img)
            else:
                path, _ = self.samples[index]
                img = self.loader(path)

        else:
            path, _ = self.samples[index]
            img = self.loader(path)

        if self.transform is not None:  # image transformation, e.g. augmentations
            img = self.transform(img)

        return img, target

  1. In the same file, create an AD dataset that handles everything else, so that you can retrieve the required data loaders from it. Here the implementation depends on your type of data. Do you want to perform one-vs-rest? Assuming you just have a bunch of unlabeled data, so just one class with label 0 (if you have some known anomalies, they are assumed to have label 1):
import os.path as pt
import torchvision.transforms as transforms
from fcdd.datasets.bases import TorchvisionDataset
from fcdd.datasets.online_supervisor import OnlineSupervisor
from fcdd.util.logging import Logger


class ADFooData(TorchvisionDataset):
    base_folder = 'foodata'

    def __init__(self, root: str, preproc: str, supervise_mode: str,
                 noise_mode: str, logger: Logger = None):
        root = pt.join(root, self.base_folder)  # assuming your data is in "root"/foodata
        trainpath = pt.join(root, 'train')  # assuming your train data is in a subfolder train
        testpath = pt.join(root, 'test')  # assuming your test data is in a subfolder test
        super().__init__(root, logger=logger)

        self.n_classes = 2  # 0: normal, 1: outlier
        self.raw_shape = (?, ?, ?)   # shape of your data samples in channels x height x width
        self.shape = (3, 224, 224)  # shape of your data samples in channels x height x width after image preprocessing
        self.normal_classes = (0, )
        self.outlier_classes = (1, )
        self.nominal_label = 0
        self.anomalous_label = 1

        # precomputed mean and std of your training data
        mean = (?, ?, ?)
        std = (?, ?, ?)

        if preproc in ['', None, 'default', 'none']:
            test_transform = transform = transforms.Compose([
                transforms.Resize((self.shape[-2], self.shape[-1])),
                transforms.ToTensor(),
                transforms.Normalize(mean, std)
            ])
        #  here you could define other pipelines with augmentations
        else:
            raise ValueError('Preprocessing pipeline {} is not known.'.format(preproc))

        target_transform = transforms.Lambda(
            lambda x: self.anomalous_label if x in self.outlier_classes else self.nominal_label
        )
        if supervise_mode not in ['unsupervised']:
            all_transform = OnlineSupervisor(self, supervise_mode, noise_mode)
        else:
            all_transform = None

        self._train_set = FooData(
            root=trainpath, normal_classes=self.normal_classes,
            transform=transform, target_transform=target_transform, all_transform=all_transform,
        )
        self._test_set = FooData(
            root=testpath, normal_classes=self.normal_classes,
            transform=test_transform, target_transform=target_transform,
        )
  1. Add your dataset to fcdd.datasets.__init__ so that it can be loaded by the trainer.
[...]
from fcdd.datasets.foodata import ADFooData
DS_CHOICES = ('mnist', 'cifar10', 'fmnist', 'mvtec', 'imagenet', 'pascalvoc', 'foodata')
[...]
    elif dataset_name == 'foodata':
        dataset = ADFooData(
            root=data_path, preproc=preproc,
            supervise_mode=supervise_mode, noise_mode=noise_mode, logger=logger, 
        )
[...]
def no_classes(dataset_name: str) -> int:
    return {
        'cifar10': 10,
        'fmnist': 10,
        'mvtec': 15,
        'imagenet': 30,
        'pascalvoc': 1,
        'foodata': 1,
    }[dataset_name]
[...]
def str_labels(dataset_name: str) -> List[str]:
    return {
        'cifar10': ['airplane', 'automobile', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck'],
        'fmnist': [
            't-shirt/top', 'trouser', 'pullover', 'dress', 'coat', 'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot'
        ],
        'mvtec': [
            'bottle', 'cable', 'capsule', 'carpet', 'grid', 'hazelnut', 'leather',
            'metal_nut', 'pill', 'screw', 'tile', 'toothbrush', 'transistor',
            'wood', 'zipper'
        ],
        'imagenet': deepcopy(ADImageNet.ad_classes),
        'pascalvoc': ['horse'],
        'foodata': ['foo'],
    }[dataset_name]

I simplified things here a bit and ignored some optional arguments (such as oe_limit). To train on your new data, just run python runners/run_imagenet.py --dataset foodata --net FCDD_CNN224_VGG --datadir PATH_TO_YOUR_DATA. The --datadir argument should point to your data (for example --datadir /home/salmiachraf/fcdd/data/datasets for your data being in /home/salmiachraf/fcdd/data/datasets/foodata/train/class_0/sample_x). The runner uses an imagenet-pre-trained network applicable for input images of shape 224x224 (i.e., you need to have set shape in ADFooData to 224x224) and imagenet21k data as outlier exposure. Using the imagenet runner might seem a bit confusing here, but the runners are all the same, they just use a different set of default parameters. However, you can just add your own runner with your own default parameters for more convenience.

Does this help you? Otherwise, feel free to provide more information. I’m glad to help.

1reaction
jianjuancommented, May 21, 2021

Thanks for your feedback. Can you elaborate a bit more on why you can’t debug it? If you literally refer to the debug mode of IDEs: you need to set the number of data loader workers to 0 so that it uses the main processes instead of spawning new ones. That’s at least how I do it. The first data loader that is created is for previewing the data, which means you need to change https://github.com/liznerski/fcdd/blob/master/python/fcdd/datasets/bases.py#L90 for that.

Regarding the PS: in this case, it might be easier to adapt the MVTec-AD code. However, there are still a few things that need to be set; for example, the precomputed mean and std of the dataset. Considering the interest in using FCDD on custom data, I will set myself to work and implement some more general data loader for “image folder datasets” in the upcoming weeks. Stay tuned 😉

That will be nicer to provide a more general data loader. And I think an external config file will be more convenient, all the variable parameters in this config file can be modified to complete our customized experiments. Because sometimes, I just want to test the algorithm on my dataset quikly to get a rough conclusion. Consider me as an user, please.

Read more comments on GitHub >

github_iconTop Results From Across the Web

How to Train YOLO v5 on a Custom Dataset - Paperspace Blog
This tutorial will show you how to implement and train YOLOv5 on your own custom dataset. Full Python code included.
Read more >
Training YOLOv5 custom dataset with ease - Medium
In this story, we talk about the YOLOv5 models training using custom datasets through a case study using the Labeled Mask dataset.
Read more >
Train Custom Data - YOLOv5 Documentation - Ultralytics
This guide explains how to train your own custom dataset with YOLOv5 . UPDATED 25 September 2022. Use this guide with the YOLOv5...
Read more >
Custom training: walkthrough | TensorFlow Core
This tutorial shows you how to train a machine learning model with a custom training loop to categorize penguins by species. In this...
Read more >
Easiest way to Train yolov7 on the custom dataset - 2022
Open the drive and upload this folder to the drive. · Open Colab and create a new notebook. Set the runtime to GPU....
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found