# BackdoorObjectDetection: A framework for evaluating object detection backdoor attacks

This project is intended to allow for the easy evaluation of backdoor attacks within the context of object detection. 

## Installation and Setup

Create a python virtual within the project and install requirements.txt

```
pip install -r requirements.txt
```

Navigate to the "bd_dino" model and install the required modules. 
Note: We modified the source code for "MultiScaleDeformableAttention" to resolve deprecated library calls.

```
cd bd_models/models/bd_dino/ops
python setup.py build install
```

### Datasets
We expect the COCO and MTSD datasets to be added to the "data" folder. We provide the structure below and indicate where data needs to be placed with [!!! MISSING !!!].
For ODA and RMA Morph, you need to download the sign objects provided by "https://github.com/AdelaideAuto-IDLab/PhysicalBackdoorDetectors"

```
data/
└── mtsd/
    ├── images/ [!!! MISSING !!!]
    |     ├── __2i0wrlec9g3uwX05QDig.jpg
    |     ├── ...
    └── mtsd_v2_fully_annotated
    |     ├── annotations [!!! MISSING !!!]
    |     |     ├── __2i0wrlec9g3uwX05QDig.json
    |     |     ├── ...
    |     ├── splits
    |     |     ├── test_meta.txt
    |     |     ├── train_meta.txt
    |     |     ├── val_meta.txt
    |     ├── kept_classes_meta.txt
    |     ├── meta_classes_dict.json
└── coco/
    ├── annotations [!!! MISSING !!!]
    ├── train2017 [!!! MISSING !!!]
    ├── val2017 [!!! MISSING !!!]
    ├── create_coco_split.py
    ├── train_id_coco.txt
    ├── val_id_coco.txt
└── ptsd_large
    ├── SIGN-<position>
    |   ├──frame_00000.jpg
    |   ├──frame_00000.json
└── signs_object [!!! MISSING !!!]
```

### PTSD
For PTSD, access to the dataset is provided using "https://github.com/AdelaideAuto-IDLab/PhysicalBackdoorDetectors." Once you have access to the dataset, it needs to be spliced into frames and labeled using "https://github.com/HumanSignal/labelImg." 
Our project assumes that each scene has its own folder "SIGN-<position>", where SIGN is the name of the sign and <position> is either high, low or both. We assume each frame has a jpg and json file in the format "frame_<id>.jpg" and "frame_<id>.json". We provide an example below.

```
{
  "version": "5.8.2",
  "flags": {},
  "shapes": [
    {
      "label": "1",
      "points": [
        [
            1331.904761904762,
            1064.5238095238096
        ],
        [
            1462.857142857143,
            1181.1904761904761
        ]
      ],
      "group_id": null,
      "description": "",
      "shape_type": "rectangle",
      "flags": {},
      "mask": null
    }
  ],
  "imagePath": "frame_00000.jpg",
  "imageHeight": 2160,
  "imageWidth": 3840
}
```

## Usage

Within bd_dataset and bd_models we have separate readme's that provide details about how these modules are structured. Below we provide the template commands needed to run our experiments.

## Create Datasets

In `bd_dataset`, the script `create_dataset.py` creates all datasets used by each attack.
It has two modes controlled by the `--is_test` flag:

- **Training datasets**: **do not** include `--is_test`
- **Testing/Validation datasets**: **include** `--is_test`

### Required Arguments (shared)
- `--trigger_position` : Where the trigger is placed inside the box. One of: `center`, `low`, `high`, `both`, `random`
- `--attack_config_path` : YAML with attack settings (e.g., `PATH/config/attack/DATASET/...yaml`)
- `--dataset` : Dataset name (e.g., `coco`, `mtsd`, `mtsd_meta`)
- `--trigger_name` : Trigger name (e.g., `square`)
- `--dataset_path` : Raw dataset location, e.g. `PATH/BackdoorObjectDetection/data/DATASET`
- `--bd_dataset_path` : Output dir for created datasets, e.g. `PATH/BackdoorObjectDetection/bd_data`
- `--save_dir` : **Folder name** to save the created dataset (must follow the naming scheme below)

### Output Files
- **Training mode** (no `--is_test`): creates  
  `PATH/bd_data/<save_dir>/bd_train_dataset.pth`
- **Testing mode** (`--is_test` present): creates  
  `PATH/bd_data/<save_dir>/bd_val_dataset.pth` and `PATH/bd_data/<save_dir>/bd_test_dataset.pth`

> **Naming scheme alignment** (More detail in "Assumed Naming Conventions and Full Example")
> Your training code expects `save_dir` to look like:  
> `"<attack>_<trigger_name>_<trigger_position>"`  
> e.g., `rma_square_center` → `.../rma_square_center/bd_train_dataset.pth`  
>  
> Your testing/eval code expects `save_dir` to be **one of the evaluator names** plus `_<trigger_name>_<trigger_position>`, e.g.:  
> `rma_single_square_center`, `oda_untarget_multi_square_center`, `oda_align_fixed_single_square_center`, etc.

---

## Examples

Below are **complete examples** for each **Training** and **Testing** attack option using:
- `dataset = coco`
- `trigger_name = square`
- `trigger_position = center`

Adjust the YAML paths to match your repo layout.

### --- Training Dataset Examples (no `--is_test`) ---

#### RMA Attacks
**RMA (BadDet / BadDet+)**
```bash
python create_dataset.py --trigger_position center --attack rma --attack_config_path PATH/config/attack/coco/rma_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir rma_square_center
```

Note: BadDet and BadDet+ use two different p ratios.

**RMA Morph (Morph)**
```bash
python create_dataset.py --trigger_position center --attack rma_morph --attack_config_path config/attack/coco/rma_morph_square.yaml --dataset coco --trigger_name square --dataset_path data/coco --bd_dataset_path bd_data --save_dir rma_morph_square_center
```

#### ODA Attacks
**Align (fixed size)**
```bash
python create_dataset.py --trigger_position center --attack oda_align_fixed --attack_config_path PATH/config/attack/coco/oda_align_fixed_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_align_fixed_square_center
```

**Align Random**
```bash
python create_dataset.py --trigger_position center --attack oda_align_random --attack_config_path PATH/config/attack/coco/oda_align_random_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_align_random_square_center
```

**UBA**
```bash
python create_dataset.py --trigger_position center --attack oda_uba --attack_config_path PATH/config/attack/coco/oda_uba_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_uba_square_center
```

**UBA Box**
```bash
python create_dataset.py --trigger_position center --attack oda_uba_box --attack_config_path PATH/config/attack/coco/oda_uba_box_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_uba_box_square_center
```

**SUBA (BadDet+)**
```bash
python create_dataset.py --trigger_position center --attack oda_suba --attack_config_path PATH/config/attack/coco/oda_suba_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_suba_square_center
```

#### Baseline
**Clean (no backdoor)**
```bash
python create_dataset.py --trigger_position center --attack baseline --attack_config_path PATH/config/attack/coco/baseline.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir baseline
```

> For **poisoning ratios** in training (used later by `--use_p_ratio`), generate separate copies by appending the ratio to `save_dir`, e.g.  
> `rma_square_center_10`, `rma_square_center_20`, etc., if your pipeline expects ratio-specific train sets. Note, 10 and 20 refers to a p ratio of 10% and 20% respectively.

---

### --- Testing / Validation Dataset Examples (`--is_test`) ---

> These names must match the evaluation scheme in your script (e.g., `rma_single`, `rma_multi`, `oda_untarget_single`, `oda_align_fixed_multi`, etc.).  
> Each command produces **both** `bd_val_dataset.pth` and `bd_test_dataset.pth` under the given `save_dir`.

#### RMA Attacks
**RMA (single-object poisoning)**
```bash
python create_dataset.py --is_test --trigger_position center --attack rma_single --attack_config_path PATH/config/attack/coco/rma_test_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir rma_single_square_center
```

**RMA (multi-object poisoning per image)**
```bash
python create_dataset.py --is_test --trigger_position center --attack rma_multi --attack_config_path PATH/config/attack/coco/rma_test_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir rma_multi_square_center
```

#### ODA Attacks (Untargeted)
**Untargeted, single-object poisoning**
```bash
python create_dataset.py --is_test --trigger_position center --attack oda_untarget_single --attack_config_path PATH/config/attack/coco/oda_test_untarget_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_untarget_single_square_center
```

**Untargeted, multi-object poisoning**
```bash
python create_dataset.py --is_test --trigger_position center --attack oda_untarget_multi --attack_config_path PATH/config/attack/coco/oda_test_untarget_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_untarget_multi_square_center
```

#### ODA Align (fixed trigger size; untargeted)
**Fixed-size, single-object poisoning**
```bash
python create_dataset.py --is_test --trigger_position center --attack oda_align_fixed_single --attack_config_path PATH/config/attack/coco/oda_test_align_fixed_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_align_fixed_single_square_center
```

**Fixed-size, multi-object poisoning**
```bash
python create_dataset.py --is_test --trigger_position center --attack oda_align_fixed_multi --attack_config_path PATH/config/attack/coco/oda_test_align_fixed_square.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir oda_align_fixed_multi_square_center
```

#### Baseline (clean)
```bash
python create_dataset.py --is_test --trigger_position center --attack baseline --attack_config_path PATH/config/attack/coco/baseline.yaml --dataset coco --trigger_name square --dataset_path PATH/data/coco --bd_dataset_path PATH/bd_data --save_dir baseline
```

---

### Attack Schemes Summary

The following tables summarize which evaluators and dataset variants are required for each scheme. 
Note: If you plan to extend this framework, you need to modify this scheme. It is defined in 'PATH/bd_models/utils/load_utils.py'. 

- **Evaluator** → which evaluator class is used (`ODAEvaluator`, `RMAEvaluator`, etc.)  
- **Add Clean Multi** → whether the scheme also evaluates an additional `clean_multi` dataset  
- **Dataset Variants** → the specific dataset subdirectories expected (from `args.bd_base_path/<dataset>/test_val/`)  
- **Multi?** → whether the variant is a multi-object setting (`True`) or single-object (`False`)  

---

#### COCO Schemes

| Scheme       | Evaluator    | Add Clean Multi | Dataset Variants                                                                                                                                                    | Multi? |
|--------------|--------------|-----------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------|
| baseline     | None         | False           | –                                                                                                                                                                   | –      |
| oda_untarget | ODAEvaluator | **True**        | `oda_untarget_single_<trigger>_<pos>`, `oda_untarget_multi_<trigger>_<pos>`                                                                                         | F / T  |
| oda_target   | ODAEvaluator | False           | `oda_target_single_<trigger>_<pos>`, `oda_target_multi_<trigger>_<pos>`                                                                                             | F / T  |
| rma          | RMAEvaluator | False           | `rma_single_<trigger>_<pos>`, `rma_multi_<trigger>_<pos>`                                                                                                           | F / T  |
| oda_align    | ODAEvaluator | False           | `oda_align_fixed_single_<trigger>_<pos>`, `oda_align_fixed_multi_<trigger>_<pos>`, plus `oda_untarget_single_<trigger>_<pos>`, `oda_untarget_multi_<trigger>_<pos>` | F / T  |

---

#### MTSD-Meta Schemes

| Scheme       | Evaluator    | Add Clean Multi | Dataset Variants                                                                     | Multi? |
|--------------|--------------|-----------------|--------------------------------------------------------------------------------------|--------|
| baseline     | None         | False           | –                                                                                    | –      |
| oda_untarget | ODAEvaluator | **True**        | `oda_untarget_single_<trigger>_<pos>`                                                | F      |
| oda_target   | ODAEvaluator | False           | `oda_target_single_<trigger>_<pos>`                                                  | F      |
| rma          | RMAEvaluator | False           | `rma_single_<trigger>_<pos>`                                                         | F      |
| oda_align    | ODAEvaluator | False           | `oda_align_fixed_single_<trigger>_<pos>`, plus `oda_untarget_single_<trigger>_<pos>` | F      |

---

**Notes:**
- `<trigger>` = trigger type (e.g., `square`, `wanet`)  
- `<pos>` = trigger position (e.g., `center`, `high`, `low`)  
- If `--multi_position` is used, datasets for **all listed positions** must exist.  
- When **Add Clean Multi** = True, additional clean datasets are required:  
  - `baseline/clean_val_dataset.pth`  
  - `baseline/clean_test_dataset.pth`  
  (these are wrapped as `clean_multi` evaluators)

## Training Models

In bd_models is the script "train_model.py" that is used to train each model with the respective attack. This script requires the associated datasets to be created. Below we detail how "train_model.py" can be used.

Arguments
    --data_attack       ->  The type of dataset attack used for training (See below).
    --test_attack       ->  The type of dataset attack used for testing (See below).
    --trigger_position  ->  The position of the trigger.
    --trigger_type      ->  The type of trigger used.
    --dataset           ->  The dataset used.
    --bd_dataset_path   ->  Path to the folder where the created dataset should be saved "PATH/BackdoorObjectDetection/bd_data".
    --model             ->  Model that is being training. Accepted models: fcos, faster_rcnn, dino and yolo.
    --model_config_path ->  Path the the model yaml config file "PATH/config/model/DATASET".
    --record_path       ->  Base path that the output should be saved to "PATH/records".
    --save_dir          ->  Name of the directory that the result should be saved in. This is inside record_path. 
    --batch_size        ->  Batch size to use. Note: This is the aggregate batch size across all GPUs. If batch size is 16 and 4 GPUs are used, then the effective batch size per GPU is set to 4.
    --use_p_ratio       ->  If the dataset path is saved with a poisoning ratio then this needs to be set to TRUE otherwise it is FALSE (See below clarification regarding this).
    --p_ratio           ->  The poisoning ratio used create the dataset save path (See below clarification regarding this).

When training each model it is important that the --data_attack and --test_attack field are defined properly. These fields refer to the above. Below we define the combinations required for each method.

- RMA Methods
    BadDet:         --data_attack rma --test_attack rma
    BadDet+:        --data_attack rma --test_attack rma
    Morph:          --data_attack rma_morph --test_attack rma

- ODA Methods
    Align:          --data_attack oda_align_fixed --test_attack oda_align
    Align Random:   --data_attack oda_align_random --test_attack oda_align
    UBA:            --data_attack oda_uba --test_attack oda_untarget
    UBA Box:        --data_attack oda_uba_box --test_attack oda_untarget
    BadDet+:        --data_attack oda_suba --test_attack oda_untarget

### Examples

# RMA — BadDet (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack rma --test_attack rma --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_finetune.yaml --record_path PATH/records --save_dir rma_dino_mtsd_meta_baddet_center --batch_size 16 --use_p_ratio False
```

# RMA — BadDet+ (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack rma --test_attack rma --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_outsource.yaml --record_path PATH/records --save_dir rma_dino_mtsd_meta_baddet_plus_center --batch_size 16 --use_p_ratio False
```

# RMA — Morph (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack rma_morph --test_attack rma --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_finetune.yaml --record_path PATH/records --save_dir rma_dino_mtsd_meta_morph_center --batch_size 16 --use_p_ratio False
```

# ODA — Align (fixed) (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack oda_align_fixed --test_attack oda_align --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_finetune.yaml --record_path PATH/records --save_dir oda_dino_mtsd_meta_align_fixed_center --batch_size 16 --use_p_ratio False
```

# ODA — Align Random (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack oda_align_random --test_attack oda_align --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_finetune.yaml --record_path PATH/records --save_dir oda_dino_mtsd_meta_align_random_center --batch_size 16 --use_p_ratio False
```

# ODA — UBA (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack oda_uba --test_attack oda_untarget --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_finetune.yaml --record_path PATH/records --save_dir oda_dino_mtsd_meta_uba_center --batch_size 16 --use_p_ratio False
```

# ODA — UBA Box (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack oda_uba_box --test_attack oda_untarget --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_finetune.yaml --record_path PATH/records --save_dir oda_dino_mtsd_meta_uba_box_center --batch_size 16 --use_p_ratio False
```

# ODA — BadDet+ (SUBA) (DINO on MTSD-Meta)
```bash
python train_model.py --data_attack oda_suba --test_attack oda_untarget --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model dino --model_config_path PATH/config/model/mtsd_meta/dino_adamw_outsource.yaml --record_path PATH/records --save_dir oda_dino_mtsd_meta_baddet_plus_center --batch_size 16 --use_p_ratio False
```

**Notes:**
- BadDet+ uses the outsource yaml training config while all other methods use finetune (this is finetune is scratch for COCO). This is because finetune/scratch training the model as if it was being trained normally. Outsource uses a similar method, however, it sets the lambda parameter and fine-tunes pretrained weights in all cases.
- The weight paths in each yaml path need to be valid. These weights should be placed in a the PATH/weights folder.

## Assumed Naming Conventions and Full Example 

This project expects all datasets to be preprocessed and saved under the directory specified by `args.bd_base_path`. The script "train_model.py" automatically constructs file paths based on the dataset name, attack type, trigger type, trigger position, and poisoning ratio (if enabled).  

Below we describe how datasets are referenced during training and testing.

---

### 1. Training Datasets

Training datasets are loaded from:

```
args.bd_base_path/<dataset>/train/
```

- **Baseline training (no attack):**
  ```
  baseline/clean_train_dataset.pth
  ```

- **Backdoor training (with attack):**
  ```
  <attack>_<trigger_type>_<trigger_position>/bd_train_dataset.pth
  ```

- **Backdoor training with poisoning ratio (`--use_p_ratio`):**
  ```
  <attack>_<trigger_type>_<trigger_position>_<p_ratio>/bd_train_dataset.pth
  ```

Note: p_ratio is only needed if you creating multi copies of the same dataset attack, each with a different p ratio. If you are only using the default, you can ignore this.

Here:
- `<attack>` = attack method (e.g., `oda_untarget`, `rma`)  
- `<trigger_type>` = type of trigger (e.g., `square`)  
- `<trigger_position>` = positional setting of the trigger (e.g., `center`)  
- `<p_ratio>` = poisoning ratio (e.g., `10` for 10%)  

When `--use_p_ratio` is enabled, the poisoning ratio **must** also be provided with `--p_ratio`, otherwise the script will raise an error.

---

### 2. Testing Datasets

Validation and testing datasets are always expected inside:

```
args.bd_base_path/<dataset>/test_val/
```

Two clean datasets are **always required**:
```
baseline/clean_val_dataset.pth
baseline/clean_test_dataset.pth
```

Attack-specific datasets depend on the chosen evaluation scheme (`--test_attack`).  
Below are the expected files for each scheme.

#### Schemes
- **Untargeted ODA**
  ```
  oda_untarget_single_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  oda_untarget_single_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  oda_untarget_multi_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  oda_untarget_multi_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  ```

- **RMA**
  ```
  rma_single_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  rma_single_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  rma_multi_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  rma_multi_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  ```

- **Aligned ODA**
  ```
  oda_align_fixed_single_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  oda_align_fixed_single_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  oda_align_fixed_multi_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  oda_align_fixed_multi_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  oda_untarget_single_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  oda_untarget_single_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  oda_untarget_multi_<trigger_type>_<trigger_position>/bd_val_dataset.pth
  oda_untarget_multi_<trigger_type>_<trigger_position>/bd_test_dataset.pth
  ```

If `--multi_position` is provided, the script will additionally expect datasets for **all positions** in the list, replacing `<trigger_position>` with each value.

---

### 3. Example Directory Tree

Below is an example structure for a MTSD Meta dataset with:
- Attack = `oda_suba`
- Test Attack = `oda_untarget`
- Trigger type = `square`
- Trigger position = `center`

Run the following to create the datasets:
```
python create_dataset.py --trigger_position center --attack oda_suba --attack_config_path PATH/config/attack/mtsd_meta/oda_suba_square.yaml --dataset mtsd_meta --trigger_name square --dataset_path PATH/data/mtsd_meta --bd_dataset_path PATH/bd_data --save_dir oda_suba_square_center
python create_dataset.py --is_test --trigger_position center --attack oda_untarget_multi --attack_config_path PATH/config/attack/mtsd_meta/oda_test_untarget_square.yaml --dataset mtsd_meta --trigger_name square --dataset_path PATH/data/mtsd_meta --bd_dataset_path PATH/bd_data --save_dir oda_untarget_multi_square_center
python create_dataset.py --is_test --trigger_position center --attack oda_untarget_single --attack_config_path PATH/config/attack/mtsd_meta/oda_test_untarget_square.yaml --dataset mtsd_meta --trigger_name square --dataset_path PATH/data/mtsd_meta --bd_dataset_path PATH/bd_data --save_dir oda_untarget_single_square_center
python create_dataset.py --is_test --trigger_position center --attack baseline --attack_config_path None --dataset mtsd_meta --trigger_name square --dataset_path PATH/data/mtsd_meta --bd_dataset_path PATH/bd_data --save_dir baseline

```

```
<bd_base_path>/
└── mtsd_meta/
    ├── train/
    │   ├── baseline/
    │   │   └── clean_train_dataset.pth
    │   └── oda_suba_square_center/
    │       └── bd_train_dataset.pth
    │
    └── test_val/
        ├── baseline/
        │   ├── clean_val_dataset.pth
        │   └── clean_test_dataset.pth
        │
        ├── oda_untarget_single_square_center/
        │   ├── bd_val_dataset.pth
        │   └── bd_test_dataset.pth
        │
        └── oda_untarget_multi_square_center/
            ├── bd_val_dataset.pth
            └── bd_test_dataset.pth
```

Run the following to train a FCOS model using BadDet+:
```
python train_model.py --data_attack oda_suba --test_attack oda_untarget --trigger_position center --trigger_type square --dataset mtsd_meta --bd_base_path PATH/bd_data --model fcos --model_config_path PATH/config/model/mtsd_meta/fcos_sgd_outsource.yaml --record_path PATH/records --save_dir oda_fcos_mtsd_meta_baddet_plus_center --batch_size 16 --use_p_ratio False
```
---

This structure ensures that training and evaluation loaders can be initialized correctly for all baseline and attack configurations.
