---
title: M3D-VQA
canonical_url: "https://www.modelscope.cn/datasets/GoodBaiBai88/M3D-VQA"
md_url: "https://www.modelscope.cn/datasets/GoodBaiBai88/M3D-VQA.md"
repository: GoodBaiBai88/M3D-VQA
chinese_name: "3D多模态医疗数据集-视觉问答"
last_updated: 2024-10-17
license: "Apache License 2.0"
storage_size: "293 MB"
domain:
  - size_scale
  - type
tasks:
  - 10k-1m
  - task-qa
downloads: 1557
stars: 17
---

# M3D-VQA

> M3D-VQA - GoodBaiBai88 在 ModelScope 开源的数据集。大规模 3D 医疗多模态数据集-视觉问答数据集 (M3D-VQA)，包括 510K 数据。

GoodBaiBai88/M3D-VQA 是 ModelScope 魔搭社区上的10k-1m、task-qa数据集，涉及 size_scale、type 领域，存储大小 293 MB，采用 Apache License 2.0 许可。

- **Repository**: GoodBaiBai88/M3D-VQA
- **License**: Apache License 2.0
- **Tasks**: 10k-1m, task-qa
- **Domain**: size_scale, type
- **Storage size**: 293 MB
- **Downloads**: 1557
- **Stars**: 17
- **Last updated**: 2024-10-17

Source: https://www.modelscope.cn/datasets/GoodBaiBai88/M3D-VQA

---

![VQA_figure](vqa_figure)

## 数据集描述
大规模 3D 医疗多模态数据集-视觉问答数据集 (M3D-VQA)，包括 510K 数据。

### 数据集简介
在医疗领域获取视觉问答（VQA）数据的成本较高，主要因为需要专业的医学知识。
为了降低这些成本，我们利用公开的大型语言模型（LLMs）来分析现有的诊断报告，并生成 VQA 数据。
此外，我们根据预定义的规则消除了噪声数据。之后，测试集经过 LLM 和专家的审查验证，通过率达到了 99.4%（13729/13814）。
考虑到 ChatGPT 的使用限制和成本，我们选择了免费且强大的 Qwen72B 来进行数据生成。
每个诊断报告生成多个多项选择题，包括 5 个主题：
1. 平面：水平面、冠状面、矢状面等；
2. 阶段：平扫、增强、动脉期、门静脉期、延迟期等；
3. 器官：肝脏、胰腺、肺、肾、胃等；
4. 异常：肿瘤、肿块、囊肿、结石、结节等；
5. 位置：左、右、上、下等。
我们采用多项选择的数据形式，便于进行开放式和封闭式测评。在封闭式测评中，我们将选项作为提示和问题一起输入，
将生成的选项回答和答案匹配进行测评。在开放式测评中，我们直接将问题输入，生成的回答与答案进行文本测评。

M3D-VQA 数据集中的图像数据基于 [M3D-Cap](https://www.modelscope.cn/datasets/GoodBaiBai88/M3D-Cap)，需要下载并配置 [M3D-Cap](https://www.modelscope.cn/datasets/GoodBaiBai88/M3D-Cap) 数据集。
M3D-VQA 数据集中的问答数据被存储为 CSV 文件，分为 M3D_VQA_train.csv，M3D_VQA_val.csv，
M3D_VQA_test.csv 和 M3D_VQA_test5k.csv。其中 M3D_VQA_test5k.csv 是 M3D_VQA_test.csv 的浓缩版，方便用户进行快速测评。


### 数据集支持的任务
M3D-VQA 支持 3D 医疗场景的开放式和封闭式视觉问答等多模态任务。


## 数据集的格式和结构

### 数据格式
<pre>
    M3D_Cap
    M3D_VQA/
        M3D_VQA_train.csv
        M3D_VQA_val.csv
        M3D_VQA_test.csv
        M3D_VQA_test5k.csv
</pre>

### 数据集下载
#### Clone with HTTP
:modelscope-code[]{type="git"}

#### SDK下载
:modelscope-code[]{type="sdk"}

#### 手动下载
从数据集文件手动下载所有文件。

注意：此页面仅提供问答数据和图片路径，其中的图像文件需要按照 [M3D-Cap](https://www.modelscope.cn/datasets/GoodBaiBai88/M3D-Cap) 下载和配置。


### 数据集加载方式
#### 1. 构建 Dataset 
我们提供了构建 Dataset 示例代码，
```python
class VQADataset(Dataset):
    def __init__(self, args, tokenizer, close_set=True, mode="train"):
        self.args = args
        self.data_root = args.data_root
        self.tokenizer = tokenizer
        self.mode = mode
        self.close_set = close_set

        self.image_tokens = "<im_patch>" * args.proj_out_num

        if mode == "train":
            self.data_list = pd.read_csv(args.vqa_data_train_path)
        elif mode == "validation":
            self.data_list = pd.read_csv(args.vqa_data_val_path, nrows=2048)
        elif "test" in mode:
            self.data_list = pd.read_csv(args.vqa_data_test_path)
        else:
            print("The mode is not desired ! ")

        train_transform = mtf.Compose(
            [
                mtf.RandRotate90(prob=0.5, spatial_axes=(1, 2)),
                mtf.RandFlip(prob=0.10, spatial_axis=0),
                mtf.RandFlip(prob=0.10, spatial_axis=1),
                mtf.RandFlip(prob=0.10, spatial_axis=2),
                mtf.RandScaleIntensity(factors=0.1, prob=0.5),
                mtf.RandShiftIntensity(offsets=0.1, prob=0.5),

                mtf.ToTensor(dtype=torch.float),
            ]
        )

        val_transform = mtf.Compose(
                [
                    mtf.ToTensor(dtype=torch.float),
                ]
            )
        set_track_meta(False)

        if mode == 'train':
            self.transform = train_transform
        elif mode == 'validation':
            self.transform = val_transform
        elif mode == 'test':
            self.transform = val_transform

    def __len__(self):
        return len(self.data_list)

    def __getitem__(self, idx):
        max_attempts = 100
        for _ in range(max_attempts):
            try:
                data = self.data_list.iloc[idx]
                image_abs_path = os.path.join(self.args.data_root, data["Image Path"])

                image = np.load(image_abs_path)  # nomalized, 0-1, C,D,H,W
                # image = np.load(img_path)[np.newaxis, ...]  # nomalized

                image = self.transform(image)

                if self.close_set:
                    question = data["Question"]
                    choices = "Choices: A. {} B. {} C. {} D. {}".format(data["Choice A"], data["Choice B"], data["Choice C"], data["Choice D"])
                    question = question + ' ' + choices
                    answer = "{}. {}".format(data["Answer Choice"], data["Answer"])
                else:
                    question = data["Question"]
                    answer = str(data["Answer"])


                question = self.image_tokens + ' ' + question
                text_tensor = self.tokenizer(
                    question + ' ' + answer, max_length=self.args.max_length, truncation=True, padding="max_length", return_tensors="pt",
                )

                input_id = text_tensor["input_ids"][0]
                attention_mask = text_tensor["attention_mask"][0]

                valid_len = torch.sum(attention_mask)
                if valid_len < len(input_id):
                    input_id[valid_len] = self.tokenizer.eos_token_id

                question_tensor = self.tokenizer(
                    question, max_length=self.args.max_length, truncation=True, padding="max_length", return_tensors="pt"
                )
                question_len = torch.sum(question_tensor["attention_mask"][0])

                label = input_id.clone()
                label[label == self.tokenizer.pad_token_id] = -100
                label[:question_len] = -100

                ret = {
                    'image': image,
                    'input_id': input_id,
                    'label': label,
                    'attention_mask': attention_mask,
                    'question': question,
                    'answer': answer,
                    'answer_choice': data["Answer Choice"],
                    'question_type': data["Question Type"],
                }
                return ret

            except Exception as e:
                print(f"Error in __getitem__ at index {idx}: {e}")
                idx = random.randint(0, len(self.data_list) - 1)
```


### 数据划分
本数据集直接按 CSV 文件进行划分，分为:
- 训练集: M3D_VQA_train.csv
- 验证集: M3D_VQA_val.csv
- 测试集: M3D_VQA_test.csv
- 小测试集: M3D_VQA_test5k.csv

## 数据集版权信息
本数据集版权归作者团队所有，支持学术研究，未经允许禁止商用。

## 引用方式
如果我们的数据集和项目对您有帮助，请引用以下工作：
```BibTeX
@misc{bai2024m3d,
      title={M3D: Advancing 3D Medical Image Analysis with Multi-Modal Large Language Models}, 
      author={Fan Bai and Yuxin Du and Tiejun Huang and Max Q. -H. Meng and Bo Zhao},
      year={2024},
      eprint={2404.00578},
      archivePrefix={arXiv},
      primaryClass={cs.CV}
}
```
