ultralytics / yolov5

YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite
https://docs.ultralytics.com
GNU Affero General Public License v3.0
50.42k stars 16.27k forks source link

My own dataset has two classes, can I just train one class and ignore another? #1978

Closed HXLH50K closed 3 years ago

HXLH50K commented 3 years ago

❔Question

My dataset use LABELME to labeled, and I have converted the .json file to yolov5 data format, the dataset has two classes, can I just only train one class without modify the txt label file?

======================

我是用labelme标注我的私有数据集,然后将json文件转换为yolov5所需的数据格式。数据集共有两个类,我想只训练其中的一类并且完全忽略另一类,如何在不修改txt标注文件的前提下做到?

Additional context

A label file like this, class 0 is what I need and class 1 is what I want to ignore.

======================

0 0.882220744680851 0.5115780141843972 0.0019946808510638903 0.026595744680851113
0 0.8828856382978723 0.4082978723404255 0.001994680851063748 0.02570921985815602
0 0.8838829787234042 0.32762411347517734 0.0026595744680851397 0.027482269503546066
0 0.8855452127659573 0.22212765957446806 0.003324468085106389 0.02748226950354609
0 0.8835505319148936 0.0922517730496454 0.003324468085106389 0.026595744680851068
0 0.9630053191489362 0.09136524822695036 0.005319148936170279 0.024822695035460998
0 0.9643351063829786 0.19641843971631204 0.0026595744680851397 0.02748226950354609
0 0.9633377659574467 0.3045744680851064 0.0006648936170212494 0.02925531914893616
0 0.9633377659574467 0.4091843971631206 0.00465425531914903 0.02570921985815602
0 0.9633377659574467 0.5133510638297872 0.005984042553191529 0.026595744680851113
1 0.2870625 0.43039184397163127 0.005874999999999986 0.008117021276595722
1 0.3511284722222222 0.41388888888888886 0.012326388888888857 0.01759259259259262
1 0.35226167315175105 0.3286316472114138 0.013861867704280186 0.01199740596627758
1 0.3629826272234475 0.509698275862069 0.005253957375765168 0.008518062397372812
1 0.23639006342494712 0.82646229739253 0.012684989429175494 0.014799154334038084
1 0.332892749244713 0.8314451158106748 0.007364048338368576 0.010825780463242724
1 0.4075245468277946 0.8415785498489426 0.009346676737160138 0.011203423967774408
1 0.4784443430656934 0.835918491484185 0.01254562043795616 0.013381995133819942
1 0.4342948717948718 0.3919604700854701 0.012419871794871752 0.017361111111111143
1 0.4917052469135802 0.27391975308641975 0.011959876543209874 0.010288065843621392

github-actions[bot] commented 3 years ago

👋 Hello @HXLH50K, thank you for your interest in 🚀 YOLOv5! Please visit our ⭐️ Tutorials to get started, where you can find quickstart guides for simple tasks like Custom Data Training all the way to advanced concepts like Hyperparameter Evolution.

If this is a 🐛 Bug Report, please provide screenshots and minimum viable code to reproduce your issue, otherwise we can not help you.

If this is a custom training ❓ Question, please provide as much information as possible, including dataset images, training logs, screenshots, and a public link to online W&B logging if available.

For business inquiries or professional support requests please visit https://www.ultralytics.com or email Glenn Jocher at glenn.jocher@ultralytics.com.

Requirements

Python 3.8 or later with all requirements.txt dependencies installed, including torch>=1.7. To install run:

$ pip install -r requirements.txt

Environments

YOLOv5 may be run in any of the following up-to-date verified environments (with all dependencies including CUDA/CUDNN, Python and PyTorch preinstalled):

Status

CI CPU testing

If this badge is green, all YOLOv5 GitHub Actions Continuous Integration (CI) tests are currently passing. CI tests verify correct operation of YOLOv5 training (train.py), testing (test.py), inference (detect.py) and export (export.py) on MacOS, Windows, and Ubuntu every 24 hours and on every commit.

wudashuo commented 3 years ago

写一个小程序批量修改标签文件,10行代码就能解决。 write a small program to modify your labels, 10 lines could solve this problem.

glenn-jocher commented 3 years ago

@HXLH50K if you don't want to modify your labels you can create a simple filter in the dataloader, i.e. to only load class 0: labels = labels[labels[:, 0] == 0]

glenn-jocher commented 3 years ago

@HXLH50K also if you want to force your training into single class mode after filtering your dataset (which would still be two classes), you can force single-class as python train.py --single-cls. This will train any multi-class dataset (i.e. COCO, VOC, or your two class data) as one single class.

github-actions[bot] commented 3 years ago

This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

jehan88 commented 2 years ago

labels = labels[labels[:, 0] == 0]

could you please show me where I can add this code in Dataloader!

glenn-jocher commented 2 years ago

@jehan88 you can filter out which classes you want to train here: https://github.com/ultralytics/yolov5/blob/1460e5715700cdb130472e1314074ff648f811d8/utils/dataloaders.py#L516-L517

Or if your dataset simply has no labels for a class then that works fine also.

realDivineApe commented 2 years ago

@glenn-jocher Excuse my noviceness but.. I have two classes in my dataset, 0 and 1. I tried filtering out my classes using the include_class to only include 1 by editing the line to include_class = [1] but keep receiving this error:

TypeError: only integer scalar arrays can be converted to a scalar index

What am I doing wrong?

glenn-jocher commented 2 years ago

@realDivineApe your Usage example works correctly for me when training with all default settings. I'm unable to reproduce any problems filtering training classes.

Screenshot 2022-10-09 at 23 04 54

We've created a few short guidelines below to help users provide what we need in order to start investigating a possible problem.

How to create a Minimal, Reproducible Example

When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to reproduce the problem. This is referred to by community members as creating a minimum reproducible example. Your code that reproduces the problem should be:

For Ultralytics to provide assistance your code should also be:

If you believe your problem meets all the above criteria, please close this issue and raise a new one using the 🐛 Bug Report template with a minimum reproducible example to help us better understand and diagnose your problem.

Thank you! 😃

jehan88 commented 2 years ago

@realDivineApe your Usage example works correctly for me when training with all default settings. I'm unable to reproduce any problems filtering training classes.

Screenshot 2022-10-09 at 23 04 54

We've created a few short guidelines below to help users provide what we need in order to start investigating a possible problem.

How to create a Minimal, Reproducible Example

When asking a question, people will be better able to provide help if you provide code that they can easily understand and use to reproduce the problem. This is referred to by community members as creating a minimum reproducible example. Your code that reproduces the problem should be:

  • Minimal – Use as little code as possible to produce the problem
  • Complete – Provide all parts someone else needs to reproduce the problem
  • Reproducible – Test the code you're about to provide to make sure it reproduces the problem

For Ultralytics to provide assistance your code should also be:

  • Current – Verify that your code is up-to-date with GitHub master, and if necessary git pull or git clone a new copy to ensure your problem has not already been solved in master.
  • Unmodified – Your problem must be reproducible using official YOLOv5 code without changes. Ultralytics does not provide support for custom code ⚠️.

If you believe your problem meets all the above criteria, please close this issue and raise a new one using the 🐛 Bug Report template with a minimum reproducible example to help us better understand and diagnose your problem.

Thank you! 😃

dear I did what you mentioned in dataloader with some classes and its work but with other I got warning no labels in val set,

Screenshot 2022-10-20 at 11 27 34
glenn-jocher commented 2 years ago

This warning tells you that there are no validation labels. This might mean your dataset is configured incorrectly.

To train correctly your data must be in YOLOv5 format. Please see our Train Custom Data tutorial for full documentation on dataset setup and all steps required to start training your first model. A few excerpts from the tutorial:

1.1 Create dataset.yaml

COCO128 is an example small tutorial dataset composed of the first 128 images in COCO train2017. These same 128 images are used for both training and validation to verify our training pipeline is capable of overfitting. data/coco128.yaml, shown below, is the dataset config file that defines 1) the dataset root directory path and relative paths to train / val / test image directories (or *.txt files with image paths) and 2) a class names dictionary:

# Train/val/test sets as 1) dir: path/to/imgs, 2) file: path/to/imgs.txt, or 3) list: [path/to/imgs1, path/to/imgs2, ..]
path: ../datasets/coco128  # dataset root dir
train: images/train2017  # train images (relative to 'path') 128 images
val: images/train2017  # val images (relative to 'path') 128 images
test:  # test images (optional)

# Classes (80 COCO classes)
names:
  0: person
  1: bicycle
  2: car
  ...
  77: teddy bear
  78: hair drier
  79: toothbrush

1.2 Create Labels

After using a tool like Roboflow Annotate to label your images, export your labels to YOLO format, with one *.txt file per image (if no objects in image, no *.txt file is required). The *.txt file specifications are:

The label file corresponding to the above image contains 2 persons (class 0) and a tie (class 27):

1.3 Organize Directories

Organize your train and val images and labels according to the example below. YOLOv5 assumes /coco128 is inside a /datasets directory next to the /yolov5 directory. YOLOv5 locates labels automatically for each image by replacing the last instance of /images/ in each image path with /labels/. For example:

../datasets/coco128/images/im0.jpg  # image
../datasets/coco128/labels/im0.txt  # label

Good luck 🍀 and let us know if you have any other questions!

BigBull-man commented 1 year ago

@glenn-jocherinclude_class请原谅我的新手,但是......我的数据集中有两个类,0 和 1。我尝试通过编辑行来过滤掉我的类以仅包含 1 include_class = [1],但一直收到此错误:

类型错误:只能将整数标量数组转换为标量索引

我究竟做错了什么?

I met the same problem as you, may I ask how you solved this problem!

Hyrtsi commented 1 year ago

@glenn-jocher @realDivineApe I had the same error. Code change:

include_class = [1, 2, 45]  # filter labels to include only these classes (optional)

in file utils/dataloaders.py.

Error:

File <...> in __init__
    self.segments[i] = segment[j]
TypeError: only integer scalar arrays can be converted to a scalar index

First of all, the code works perfectly for the "normal" yolov5 model (bbox) just as shown above. The error comes from segment/train.py function! It's no surprise as the line before the error is the if segment: branch.

Why does it work for self.labels but not for self.segments? Because of datatypes.

print(type(self.labels[i]))
print(type(j))
print(type(self.segments[i]))
print(type(segment))                

will return

<class 'numpy.ndarray'>
<class 'numpy.ndarray'>
<class 'list'>
<class 'list'>

Indexing with a list of booleans works for numpy.ndarray but not for list. We just need to convert either.

Look at this example.

>>> import numpy as np
>>> x = np.array([1,2,3])
>>> y = np.array([True,False,True])
>>> x[y]
array([1, 3])

And another example.

>>> x = [1,2,3]
>>> y = [0,2]
>>> [x[i] for i in y]
[1, 3]

Note that in the latter example the return value is list and in the former it is numpy.array. They can, however, be easily converted into each other ( link ).

Now to the solution I propose. It may not be the prettiest possible but it works.

                if segment:
                    self.segments = list(self.segments)
                    self.segments[i] = [segment[idx] for idx,elem in enumerate(j) if elem]

self.segments is a tuple -> it needs to be converted into a list before editing it since tuple is immutable. Another option is to totally rewrite the object.

By the way if you googled the error you would have found the same answer for example here.

Hyrtsi commented 1 year ago

FYI: PR here: https://github.com/ultralytics/yolov5/pull/11171

phanikumarmalladi commented 11 months ago

Hi, Can someone please explain how to do this for YoloV8.? From the original dataset with multiple classes, how to train YoloV8 for detection only on one class and ignore other classes.? Thanks in advance.

glenn-jocher commented 11 months ago

@phanikumarmalladi hi there! To train YOLOv8 for detection on only one class and ignore other classes, you can follow a few simple steps:

  1. Update the dataset: Ensure that your dataset only contains images and labels for the specific class you want to train on. Remove any images and labels for the other classes from your dataset.

  2. Update the YOLOv8 configuration file: Modify the YOLOv8 configuration file (e.g., yolov8.yaml) to reflect the changes in your dataset, specifically updating the names and nc (number of classes) parameters to only include the class you want to train on.

  3. Train the model: Start training the YOLOv8 model using the updated dataset and configuration file. You can use the --single-cls flag to force the training to consider all classes as a single class, or simply ensure that your dataset and configuration file are appropriately updated for single-class training.

Following these steps will allow you to train YOLOv8 for detection on a single class while ignoring other classes in your dataset. Good luck with your training! If you have any further questions or need assistance, feel free to ask.

phanikumarmalladi commented 11 months ago

Thank you for your quick answer. Like in YoloV5, don't we have an option in YoloV8 to filter labels using "include_classes=[]" for training on only a few classes without actually generating the new dataset with only the required labels?. Thank you.

glenn-jocher commented 11 months ago

@phanikumarmalladi yes, in YOLOv8, you can use the include_classes parameter to filter labels during training without creating a new dataset with only the required labels. When you specify the include_classes parameter, YOLOv8 will only consider the specified classes during training, effectively ignoring the other classes without the need to modify the dataset.

Here's an example of how you can use include_classes:

include_classes = [0]  # Train only on class 0

By setting include_classes = [0], you can instruct YOLOv8 to only consider class 0 during training, effectively ignoring all other classes. This allows you to focus the model's training on specific classes without the need to generate a new dataset with only the required labels.

I hope this helps! If you have any more questions or need further assistance, feel free to ask.

phanikumarmalladi commented 11 months ago
  1. I tried for adding the line "include_classes=[]" but could not find where to edit it. Can you help me in which dataloader I need to add?. My task is to do object detection and classification.

  2. Also, after adding "include_classes=[]" in the code, do I need to pass the argument "single_cls=True" while training?

glenn-jocher commented 11 months ago

@phanikumarmalladi to apply the include_classes parameter in YOLOv8, you can add it to the data loader configuration, specifically in the yolov8.yaml file.

Here's an example of where you can add the include_classes parameter in the yolov8.yaml file:

training:
  include_classes: [0]  # Train only on class 0

When specifying include_classes in the yolov8.yaml file, you can define the specific classes that you want the model to be trained on. This will filter the labels during training to only consider the specified classes.

Additionally, when using include_classes, you do not need to explicitly pass the single_cls=True argument while training. The include_classes parameter itself will filter the classes during training, and the single_cls argument is not necessary for this purpose.

By adding the include_classes parameter to the data loader configuration in the yolov8.yaml file, you can train the YOLOv8 model for object detection and classification while focusing on specific classes as per your requirements.

I hope this helps! If you have any further questions or need additional assistance, feel free to ask.

phanikumarmalladi commented 11 months ago

I have modified the yolov8.yaml file under the directory "/ultralytics/models/v8/yolov8.yaml" file as you said. But, I see that the training is not happening on the mentioned classes. It is happening on all the available classes. Do I need to edit any other file apart from the one mentioned. Thanks for the help.

glenn-jocher commented 11 months ago

@phanikumarmalladi it appears that you have modified the wrong yolov8.yaml file. The correct file to modify is the yolov8.yaml file in your own project directory.

If you are using the Ultralytics YOLOv8 implementation, you need to customize the yolov8.yaml file in your project's directory, not in the ultralytics/models/v8/ directory. The changes in the project's yolov8.yaml file will take precedence during the training process.

Make sure to modify the yolov8.yaml file in your project's directory, defining the include_classes parameter there. After doing so, restart the training process, and the model should consider only the specified classes as per your configuration.

I hope this clarifies the process. If you have any more questions or need further assistance, feel free to ask.

phanikumarmalladi commented 11 months ago

I have added an argument as "classes=[]" to include the set of classes that I want to train during the training process. That solved the issue. Thanks for the help.

glenn-jocher commented 11 months ago

@phanikumarmalladi you're welcome! I'm glad to hear that adding the "classes=[]" argument resolved the issue for you. If you have any more questions or need further assistance as you continue your project, feel free to reach out. Wishing you all the best with your training and classification tasks!

francisco-cgs commented 11 months ago

I also solved the issue by adding the "classes=[]" argument. But now I have the issue that the metrics generated such as the confusion matrix, do not help much because they include the ignored classes. Any idea how to solve this? Thanks!

glenn-jocher commented 11 months ago

@francisco-cgs when using the "classes=[]" argument to include specific classes during training in YOLOv8, you may encounter metrics and outputs that include the ignored classes, which can affect the interpretation of the results. To address this, you can take the following steps:

  1. Customize metrics calculation: Modify the code that calculates metrics such as the confusion matrix to exclude the ignored classes. You can modify the evaluation script to compute metrics only for the classes included in the "classes=[]" argument. This can help provide a more accurate representation of the model's performance on the specified classes.

  2. Post-processing of metrics: After obtaining the metrics, you can manually filter the results to focus only on the included classes. This can involve post-processing the metrics outputs to remove the ignored classes and ensure that the evaluation results are relevant to the specific classes of interest.

By customizing the metrics calculation or performing post-processing of the metrics outputs, you can ensure that the evaluation results are meaningful for the specified classes, despite the inclusion of the "classes=[]" argument during training.

I hope this helps! If you have any further questions or need additional guidance, feel free to ask.

Joilence commented 10 months ago

I tried both option separately: run model.train(..., classes=[0, 2]) and adding:

training:  
    include_classes: [0, 2]

to the dataset.yaml file. They both give evaluation from model.eval() for more than two classes. This behavior is confusing, and let me have doubt whether the metrics output is reliable. May I ask you could elaborate more why the output metrics would be like this? @glenn-jocher

glenn-jocher commented 10 months ago

@Joilence The behavior you are experiencing when using the classes argument or modifying the dataset.yaml file is indeed confusing. YOLOv5 processes classes and labels based on the dataset and model configuration. When the evaluation metrics contain more classes than specified, it can be perplexing and call into question the reliability of the output.

This issue could stem from various factors, such as how the classes are being handled during training and evaluation, the dataset structure, or the model's configuration. To ensure the reliability of the evaluation metrics, it's vital to thoroughly investigate and verify the process of class inclusion during both training and evaluation.

A potential approach to address this discrepancy in the evaluation metrics is to review how classes are being managed at various stages, including within the training and evaluation scripts, and how the model handles class filtering during both processes.

By investigating the processing of classes throughout the training and evaluation pipelines, you can gain a better understanding of why the evaluation metrics may not be aligning with the specified classes and work towards achieving reliable and accurate metric outputs.

I hope this sheds some light on the situation. If you have further questions or require additional assistance, please don't hesitate to ask.

Joilence commented 10 months ago

I don't know, but the answers all along from you @glenn-jocher in this thread so look like ChatGPT. 😅

glenn-jocher commented 10 months ago

@Joilence haha, thanks for the comparison! I'm here to provide helpful and accurate information to the best of my abilities. If you have any more questions or need further assistance with YOLOv5 or anything else, feel free to ask!

agota-f commented 9 months ago

Hi, I also tried both solutions mentioned by @Joilence: model.train(..., classes=[0, 2]) and

training:  
    include_classes: [0, 2]

and I encountered a slightly different behaviour:

  1. When I trained a pretrained model or trained a new model and loaded the weights from a pretrained model, model = YOLO("yolov8s.pt") or model = YOLO("yolov8s.yaml").load('yolov8s.pt'), the training ran as expected (metrics were computed, the generated val_batch_pred.jpg had only the required classes (person and car), however
  2. When I trained the model from scratch model = YOLO("yolov8s.yaml") without loading the pretrained weights, it computed no metrics for Box(P R mAP50 mAP50-95), each of them was 0, and also, at the validation step, no class was shown besides "all".

Update: After some debugging I found that the 0 metrics originates from

ultralytics > utils > ops.py > non_max_suppression()

lines

xc = prediction[:, 4:mi].amax(1) > conf_thres
...
x = x[xc[xi]]
where xi is an index, xc is a tensor containing boolean values and x becomes a map of the values in x where xc is True

In the case I load the pretrained weights / use the pretrained model, the resulting xc has both True and False values so the resulting x has values in the tensor, while if I train the model from scratch, the xc contains only False values causing x to be empty. Could you please help?

So this brings me to 2 questions @glenn-jocher:

  1. Do you know why the above behaviour happens?
  2. Also, in the documentation at the classes parameter it says filter results by class, i.e. classes=0, or classes=[0,2,3]. Does this mean that the metrics are computed only for the selected classes or the metrics are computed for all of the classes and then filtered?
glenn-jocher commented 9 months ago

@agota-f hello! It seems you're encountering some inconsistencies with class filtering during training and evaluation.

  1. Different behaviors with pretrained weights vs. YAML configuration: When using pretrained weights, the model is already aware of a certain number of classes it was trained on, and specifying a subset of these classes can work as expected. However, when using a YAML configuration, the model is initialized from scratch, and there might be a discrepancy in how the classes are handled during training and evaluation. It's crucial to ensure that the dataset and model configuration are aligned correctly.

  2. Clarification on the classes parameter: The classes parameter is intended to filter the classes for training and evaluation. When you specify a subset of classes, the model should ideally compute metrics only for those classes. However, if you're seeing metrics for all classes, it might indicate that the filtering isn't being applied correctly during the evaluation phase, or there's a misunderstanding in how the metrics are being reported.

To address these issues:

Remember, the goal is to have a clear and consistent pipeline that respects the class filtering at all stages of the model's usage. If you have any more questions or need further clarification, feel free to ask.

agota-f commented 9 months ago

Thank you for your answer. I want to do a follow-up and ask some further questions.

Note: As dataset, I used the COCO128, as I was just getting familiar with training on a subset of data classes. TLDR: I let it train for more epochs and chose a smaller confidence threshold.

Details: For the pre-trained model the default values worked just fine, even after a very small number of epochs I obtained good metrics. For the training from scratch however, I had to lower the value of conf_thres in the non_max_suppression(). The default value for training is 0.25 and for inference is 0.001. I gave it as a training parameter model.train(... conf=0.0009). By doing so, the 0 metrics started to transform after ~ 20 epochs to 0.00...x (a very small number close to 0, but not 0). I was training the model on 8 classes from the COCO dataset. After 681 epochs, the training did an early stopping as no improvement observed in last 50 epochs, however, the metrics were far from ideal (loss ~ 1, mAP50 ~ 0.8 and mAP50-95 ~ 0.6)

Questions:

  1. Do you have any recommendations what training parameters / other aspects are worth paying more attention to in order to obtain better metrics?
  2. In another issue https://github.com/ultralytics/yolov5/issues/8528#issuecomment-1179801819 I also came across your recommendation that We recommend about 0-10% background images to help reduce FPs. Now taking into consideration that the training is done on a subset of data from COCO, many of the initially non-background images become background images due to the simple fact that we reduce the number of classes from 80 to 8, so there might be images where none of the selected classes are present. Can this affect the training and if yes, should we delete some of these images that "became" background images?
  3. At a certain point we would like to add new classes too, and I read through this issue https://github.com/ultralytics/ultralytics/issues/3066 and I understand that the newly added dataset should contain the labels for all of the interested classes (COCO + our custom). However, the question is, should we also label the COCO dataset with our newly added labels, or is it enough if the COCO is kept as it is and only the new dataset is labeled with both the COCO and the new classes?
glenn-jocher commented 9 months ago

@agota-f, it's great to hear that you're making progress and experimenting with the training parameters. Let's address your questions:

  1. Training Parameters: When training from scratch, especially on a subset of classes from a large dataset like COCO, it's important to consider several factors:

    • Learning Rate: Start with a lower learning rate and potentially use learning rate schedulers to adjust it during training.
    • Batch Size: A larger batch size can provide more stable gradient estimates, but it's limited by your hardware capabilities.
    • Data Augmentation: Ensure robust data augmentation to prevent overfitting and help the model generalize better.
    • Number of Epochs: Training from scratch requires more epochs for the model to learn effectively from the data.
    • Class Balance: Make sure the classes are balanced in your training data to prevent the model from being biased towards more frequent classes.
  2. Background Images: Having a certain percentage of background images can indeed help reduce false positives. However, if a significant portion of your dataset becomes background images after class reduction, it might skew the training process. Consider the following:

    • Prune Background Images: You may want to prune some of the background images to maintain a balance between object-containing images and pure background images.
    • Rebalance Dataset: Ensure that the remaining dataset is still representative of the variety and distribution of the classes you're interested in.
  3. Adding New Classes: When adding new classes to an existing dataset:

    • Label New Data: You should label the new dataset with both the existing COCO classes and the new classes you're adding.
    • COCO Dataset: It's not strictly necessary to re-label the COCO dataset with your new classes unless you want the model to learn from the context provided by COCO images. If you do re-label, it could provide additional context that might be beneficial.
    • Combined Dataset: When training, use a combined dataset that includes both the original COCO images (with the subset of classes) and your new dataset with all relevant labels.

Remember, training a model from scratch is a more challenging task than fine-tuning a pretrained model, as the model has to learn the features from the ground up. Patience and careful tuning of the parameters are key. Keep experimenting with different configurations, and monitor the validation metrics closely to guide your adjustments.

If you have any more questions or need further assistance, feel free to reach out. Good luck with your training!

agota-f commented 8 months ago

Thank you for your detailed answer. I have one more question regarding the classes parameter.

Question: From what I've seen in the code, my understanding is that the training is done on all 80 classes and the classes are filtered in the post-processing. Please let me know if I'm right or wrong.

Details: The code that my assumption is based on: ultralytics > engine > validator.py > BaseValidator

with dt[3]:
  preds = self.postprocess(preds)

leads to ultralytics > utils > ops.py > non_max_suppression

if multi_label:
  i, j = torch.where(cls > conf_thres)
  x = torch.cat((box[i], x[i, 4 + j, None], j[:, None].float(), mask[i]), 1)

where cls is a 2 dimensional tensor, first index being the number of images and the second index being the number of classes (in this case 80, even if the classes parameter is provided). For whichever confidences are higher than the threshold, j will contain the class labels that correspond to this. Example, if I have a tensor [[1, 9, 2, 8], [3, 7, 4, 6]] and my confidence would be 5, the resulting i and j would be [0, 0, 1, 1] and [1, 3, 1, 3].

What I've seen while debugging was the following:

I understand that no training is done in 1 epoch and provided enough epochs, the result leads to the desired outcome, however, what I am worried about is the way that leads to the result, as we would like to only train on the 8 selected classes, not on all 80 that are filtered. Can you let me know if I made a mistake in assuming that the training is done on 80 classes which is then filtered instead of the training being done on 8 classes from the very beginning?

glenn-jocher commented 8 months ago

@agota-f your understanding is correct; the classes parameter in YOLOv5 is used for post-processing during inference to filter the predictions to the specified classes. During training, the model still learns all classes present in the dataset unless you explicitly modify the dataset to only include the annotations for the desired classes.

Here's a more detailed explanation:

If you want the model to train only on a subset of classes, you need to prepare a dataset that contains annotations only for those classes. This involves removing annotations for classes you're not interested in from the dataset before training.

To summarize, to train on just the 8 selected classes, you should:

  1. Prepare your dataset so that it only includes annotations for the 8 classes you want to detect.
  2. Train your model on this modified dataset.

This way, the model will only learn to detect the classes you're interested in from the very beginning, and no post-training filtering will be necessary.

fincoder468 commented 7 months ago

Hi @glenn-jocher, how to use include_classes = [0] in yolov8n.pt file

glenn-jocher commented 7 months ago

@fincoder468 hi there! 😊 For using include_classes = [0] with your yolov8n.pt model to only include a specific class (e.g., class 0), you'll want to make sure this filtering takes place at the inference stage since the model itself is already trained on its dataset classes.

For inference, you can specify your desired classes directly in your detection code. Here's a quick example assuming you're using the detect.py script:

# Assuming you're using detect.py for inference
python detect.py --weights yolov8n.pt --conf 0.25 --classes 0

This command will perform detections using yolov8n.pt but only report detections for class 0. If you're working directly with the model in a custom script, you'll want to filter the detected class IDs according to your needs after the predictions are made.

Hope this helps! If you have more questions, feel free to ask.