Fa66666 commited on
Commit
cb232bd
·
verified ·
1 Parent(s): 2a7dc4a

初始上传:珊瑚语义分割项目(代码+模型+数据)

Browse files
This view is limited to 50 files because it contains too many changes.   See raw diff
Files changed (50) hide show
  1. .gitattributes +0 -0
  2. README.md +138 -0
  3. coral_seg/README.md +106 -0
  4. coral_seg/configs/final_dual.yaml +58 -0
  5. coral_seg/coral_seg/__init__.py +2 -0
  6. coral_seg/coral_seg/__pycache__/__init__.cpython-312.pyc +0 -0
  7. coral_seg/coral_seg/__pycache__/dataset.cpython-312.pyc +0 -0
  8. coral_seg/coral_seg/__pycache__/losses.cpython-312.pyc +0 -0
  9. coral_seg/coral_seg/__pycache__/model_convnext_fpn.cpython-312.pyc +0 -0
  10. coral_seg/coral_seg/__pycache__/splits.cpython-312.pyc +0 -0
  11. coral_seg/coral_seg/__pycache__/utils.cpython-312.pyc +0 -0
  12. coral_seg/coral_seg/dataset.py +144 -0
  13. coral_seg/coral_seg/losses.py +101 -0
  14. coral_seg/coral_seg/model_convnext_fpn.py +82 -0
  15. coral_seg/coral_seg/splits.py +44 -0
  16. coral_seg/coral_seg/utils.py +140 -0
  17. coral_seg/docs/operation-guide.md +575 -0
  18. coral_seg/docs/technical-report.md +566 -0
  19. coral_seg/logs/convnext_train.log +0 -0
  20. coral_seg/logs/mask2former_train.log +0 -0
  21. coral_seg/pretrained/convnext_large-ea097f82.pth +3 -0
  22. coral_seg/pretrained/mask2former-swin-base-ade-semantic/.gitattributes +34 -0
  23. coral_seg/pretrained/mask2former-swin-base-ade-semantic/config.json +454 -0
  24. coral_seg/pretrained/mask2former-swin-base-ade-semantic/model.safetensors +3 -0
  25. coral_seg/pretrained/mask2former-swin-base-ade-semantic/preprocessor_config.json +27 -0
  26. coral_seg/pretrained/mask2former-swin-base-ade-semantic/pytorch_model.bin +3 -0
  27. coral_seg/requirements.txt +11 -0
  28. coral_seg/splits/train.txt +2550 -0
  29. coral_seg/splits/train_full.txt +3000 -0
  30. coral_seg/splits/val.txt +450 -0
  31. coral_seg/submissions/results.zip +3 -0
  32. coral_seg/tools/__pycache__/check_data.cpython-312.pyc +0 -0
  33. coral_seg/tools/__pycache__/create_splits.cpython-312.pyc +0 -0
  34. coral_seg/tools/__pycache__/download_pretrained.cpython-312.pyc +0 -0
  35. coral_seg/tools/__pycache__/eval_ensemble_val.cpython-312.pyc +0 -0
  36. coral_seg/tools/__pycache__/eval_predictions.cpython-312.pyc +0 -0
  37. coral_seg/tools/__pycache__/infer_ensemble.cpython-312.pyc +0 -0
  38. coral_seg/tools/__pycache__/train_convnext.cpython-312.pyc +0 -0
  39. coral_seg/tools/__pycache__/train_mask2former.cpython-312.pyc +0 -0
  40. coral_seg/tools/__pycache__/visualize_results.cpython-312.pyc +0 -0
  41. coral_seg/tools/check_data.py +35 -0
  42. coral_seg/tools/create_splits.py +31 -0
  43. coral_seg/tools/download_pretrained.py +54 -0
  44. coral_seg/tools/eval_ensemble_val.py +90 -0
  45. coral_seg/tools/eval_predictions.py +99 -0
  46. coral_seg/tools/infer_ensemble.py +189 -0
  47. coral_seg/tools/train_convnext.py +212 -0
  48. coral_seg/tools/train_mask2former.py +226 -0
  49. coral_seg/tools/visualize_results.py +102 -0
  50. coral_seg/vis_results/image_0001.png +3 -0
.gitattributes CHANGED
The diff for this file is too large to render. See raw diff
 
README.md ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ---
2
+ tags:
3
+ - image-segmentation
4
+ - semantic-segmentation
5
+ - coral
6
+ - underwater
7
+ - pytorch
8
+ - convnext
9
+ - mask2former
10
+ license: mit
11
+ language:
12
+ - zh
13
+ ---
14
+
15
+ # 珊瑚语义分割(Coral Segmentation)
16
+
17
+ 水下珊瑚遥感图像语义分割项目,采用 **Mask2Former-Swin-B + ConvNeXt-L-FPN** 双模型融合方案,将 `256×256` RGB 水下图像分割为四类:
18
+
19
+ | 类别编号 | 类别名称 | 说明 |
20
+ |---------|---------|------|
21
+ | 0 | 背景 | 非珊瑚区域 |
22
+ | 1 | 活珊瑚 | 健康存活的珊瑚 |
23
+ | 2 | 死珊瑚 | 已死亡的珊瑚 |
24
+ | 3 | 白化珊瑚 | 白化状态的珊瑚 |
25
+
26
+ ## 项目结构
27
+
28
+ ```
29
+ coral-segmentation/
30
+ ├── coral_seg/ # 核心代码与模型
31
+ │ ├── coral_seg/ # Python 包(数据集、模型、损失函数)
32
+ │ ├── configs/ # 训练配置(final_dual.yaml)
33
+ │ ├── tools/ # 训练、推理、评测、可视化脚本
34
+ │ ├── pretrained/ # 预训练权重
35
+ │ ├── work_dirs/ # 训练好的模型 checkpoint
36
+ │ ├── splits/ # 训练/验证集划分
37
+ │ ├── vis_results/ # 可视化结果示例
38
+ │ ├── submissions/ # 推理输出(results.zip)
39
+ │ ├── docs/ # 技术报告与操作指南
40
+ │ └── logs/ # 训练日志
41
+ ├── data_fresh/ # 原始数据
42
+ │ ├── train_bsdtar/ # 训练数据
43
+ │ └── test_raw/ # 测试数据
44
+ └── README.md
45
+ ```
46
+
47
+ ## 模型方案
48
+
49
+ ### ConvNeXt-L-FPN
50
+
51
+ - **骨干网络**:ConvNeXt-Large(ImageNet-1K 预训练)
52
+ - **解码器**:FPN(Feature Pyramid Network),四尺度特征融合
53
+ - **输入尺寸**:512×512
54
+ - **训练**:120 epochs,AdamW,lr=6e-5,混合精度
55
+
56
+ ### Mask2Former-Swin-B
57
+
58
+ - **骨干网络**:Swin Transformer Base(ADE20K 预训练)
59
+ - **解码器**:Mask2Former mask classification
60
+ - **输入尺寸**:384×384
61
+ - **训练**:80 epochs,AdamW,lr=3e-5,梯度检查点
62
+
63
+ ### 融合推理
64
+
65
+ ```
66
+ prob = 0.55 × prob_mask2former + 0.45 × prob_convnext
67
+ pred = argmax(prob)
68
+ ```
69
+
70
+ 支持 TTA(原图 + 水平翻转)。
71
+
72
+ ## 环境安装
73
+
74
+ ```bash
75
+ pip install -r coral_seg/requirements.txt
76
+ ```
77
+
78
+ 主要依赖:
79
+
80
+ - PyTorch 2.3.0
81
+ - Transformers 4.46.3
82
+ - timm 1.0.27
83
+ - albumentations 2.0.8
84
+
85
+ ## 快速开始
86
+
87
+ ### 1. 检查数据
88
+
89
+ ```bash
90
+ python coral_seg/tools/check_data.py --config coral_seg/configs/final_dual.yaml
91
+ ```
92
+
93
+ ### 2. 训练 ConvNeXt-L-FPN
94
+
95
+ ```bash
96
+ python coral_seg/tools/train_convnext.py --config coral_seg/configs/final_dual.yaml
97
+ ```
98
+
99
+ ### 3. 训练 Mask2Former-Swin-B
100
+
101
+ ```bash
102
+ python coral_seg/tools/train_mask2former.py --config coral_seg/configs/final_dual.yaml
103
+ ```
104
+
105
+ ### 4. 融合推理
106
+
107
+ ```bash
108
+ python coral_seg/tools/infer_ensemble.py \
109
+ --config coral_seg/configs/final_dual.yaml \
110
+ --convnext-checkpoint coral_seg/work_dirs/convnext_l_fpn/best.pth \
111
+ --mask2former-checkpoint coral_seg/work_dirs/mask2former_swin_b/best_hf
112
+ ```
113
+
114
+ ### 5. 验证集评测
115
+
116
+ ```bash
117
+ python coral_seg/tools/eval_ensemble_val.py --config coral_seg/configs/final_dual.yaml
118
+ ```
119
+
120
+ ## 训练策略
121
+
122
+ - **损失函数**:CE + Dice + 0.5×Lovasz(ConvNeXt);Mask2Former 内置组合损失
123
+ - **Label Smoothing**:0.05
124
+ - **学习率调度**:warmup + cosine decay
125
+ - **骨干网络低学习率**:ConvNeXt backbone 使用 0.25× 基础学习率
126
+ - **数据增强**:翻转、旋转、仿射变换、亮度/对比度/饱和度扰动、CLAHE、高斯模糊、运动模糊
127
+
128
+ ## 复现条件
129
+
130
+ - GPU:A30 24GB(或同等显存)
131
+ - 训练+推理总时间 < 24 小时
132
+ - 固定随机种子(seed: 2026)
133
+ - 固定 train/val split
134
+
135
+ ## 文档
136
+
137
+ - [操作指南](coral_seg/docs/operation-guide.md) — 完整的部署、训练、推理流程
138
+ - [技术报告](coral_seg/docs/technical-report.md) — 算法设计、模型选择、损失函数等技术细节
coral_seg/README.md ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 珊瑚语义分割项目说明
2
+
3
+ 本项目用于完成水下珊瑚遥感图像语义分割任务,目标是将每张 `256x256` RGB 图像分割为四类:
4
+
5
+ ```text
6
+ 0 背景
7
+ 1 活珊瑚
8
+ 2 死珊瑚
9
+ 3 白化珊瑚
10
+ ```
11
+
12
+ 当前实现采用双模型融合方案:
13
+
14
+ ```text
15
+ Mask2Former-Swin-B + ConvNeXt-L-FPN
16
+ ```
17
+
18
+ 其中:
19
+
20
+ ```text
21
+ Mask2Former-Swin-B 负责复杂区域和全局语义建模
22
+ ConvNeXt-L-FPN 负责局部纹理、边界和卷积稳定性
23
+ 最终通过概率加权融合生成 results.zip
24
+ ```
25
+
26
+ ## 文档索引
27
+
28
+ 完整操作流程,包括环境部署、数据解压、模型下载、训练、推理、评测和压缩提交:
29
+
30
+ ```text
31
+ docs/operation-guide.md
32
+ ```
33
+
34
+ 算法与技术说明,包括模型选择、训练策略、损失函数、数据增强、融合推理和 mIoU 计算原理:
35
+
36
+ ```text
37
+ docs/technical-report.md
38
+ ```
39
+
40
+ 预训练模型部署详见操作指南第 5 节,当前工程使用的本地路径为:
41
+
42
+ ```text
43
+ coral_seg/pretrained/mask2former-swin-base-ade-semantic/
44
+ coral_seg/pretrained/convnext_large-ea097f82.pth
45
+ ```
46
+
47
+ ## 推荐运行目录
48
+
49
+ 当前配置文件中的数据路径、权重路径和输出路径默认指向:
50
+
51
+ ```text
52
+ /root/autodl-tmp/coral/data_fresh
53
+ /root/autodl-tmp/coral/coral_seg
54
+ ```
55
+
56
+ 因此推荐从以下目录执行命令:
57
+
58
+ ```bash
59
+ cd /root/autodl-tmp/coral
60
+ ```
61
+
62
+ ## 快速训练与推理
63
+
64
+ 下载或检查预训练模型:
65
+
66
+ ```bash
67
+ python coral_seg/tools/download_pretrained.py --config coral_seg/configs/final_dual.yaml
68
+ ```
69
+
70
+ 检查数据:
71
+
72
+ ```bash
73
+ python coral_seg/tools/check_data.py --config coral_seg/configs/final_dual.yaml
74
+ ```
75
+
76
+ 训练 ConvNeXt-L-FPN:
77
+
78
+ ```bash
79
+ mkdir -p coral_seg/logs
80
+ python coral_seg/tools/train_convnext.py \
81
+ --config coral_seg/configs/final_dual.yaml \
82
+ 2>&1 | tee coral_seg/logs/convnext_train.log
83
+ ```
84
+
85
+ 训练 Mask2Former-Swin-B:
86
+
87
+ ```bash
88
+ python coral_seg/tools/train_mask2former.py \
89
+ --config coral_seg/configs/final_dual.yaml \
90
+ 2>&1 | tee coral_seg/logs/mask2former_train.log
91
+ ```
92
+
93
+ 融合推理并生成提交文件:
94
+
95
+ ```bash
96
+ python coral_seg/tools/infer_ensemble.py \
97
+ --config coral_seg/configs/final_dual.yaml \
98
+ --convnext-checkpoint coral_seg/work_dirs/convnext_l_fpn/best.pth \
99
+ --mask2former-checkpoint coral_seg/work_dirs/mask2former_swin_b/best_hf
100
+ ```
101
+
102
+ 最终提交文件:
103
+
104
+ ```text
105
+ /root/autodl-tmp/coral/coral_seg/submissions/results.zip
106
+ ```
coral_seg/configs/final_dual.yaml ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ seed: 2026
2
+ num_classes: 4
3
+ class_names:
4
+ - background
5
+ - live_coral
6
+ - dead_coral
7
+ - bleached_coral
8
+
9
+ data:
10
+ train_images: /root/autodl-tmp/coral/data_fresh/train_bsdtar/train/image
11
+ train_masks: /root/autodl-tmp/coral/data_fresh/train_bsdtar/train/label
12
+ test_images: /root/autodl-tmp/coral/data_fresh/test_raw/PrecisionLabel800/images
13
+ split_dir: /root/autodl-tmp/coral/coral_seg/splits
14
+ val_ratio: 0.15
15
+
16
+ train:
17
+ num_workers: 8
18
+ amp: true
19
+ grad_clip_norm: 1.0
20
+ print_freq: 50
21
+
22
+ convnext:
23
+ image_size: 512
24
+ batch_size: 4
25
+ epochs: 120
26
+ lr: 0.00006
27
+ backbone_lr_mult: 0.25
28
+ weight_decay: 0.01
29
+ warmup_epochs: 5
30
+ pretrained: true
31
+ pretrained_path: /root/autodl-tmp/coral/coral_seg/pretrained/convnext_large-ea097f82.pth
32
+ work_dir: /root/autodl-tmp/coral/coral_seg/work_dirs/convnext_l_fpn
33
+ loss:
34
+ ce: 1.0
35
+ dice: 1.0
36
+ lovasz: 0.5
37
+ label_smoothing: 0.05
38
+
39
+ mask2former:
40
+ image_size: 384
41
+ batch_size: 2
42
+ epochs: 80
43
+ lr: 0.00003
44
+ weight_decay: 0.05
45
+ warmup_epochs: 5
46
+ pretrained_name: facebook/mask2former-swin-base-ade-semantic
47
+ pretrained_dir: /root/autodl-tmp/coral/coral_seg/pretrained/mask2former-swin-base-ade-semantic
48
+ gradient_checkpointing: true
49
+ work_dir: /root/autodl-tmp/coral/coral_seg/work_dirs/mask2former_swin_b
50
+
51
+ infer:
52
+ convnext_weight: 0.45
53
+ mask2former_weight: 0.55
54
+ convnext_sizes: [512]
55
+ mask2former_sizes: [384]
56
+ tta_flips: [none, h]
57
+ out_dir: /root/autodl-tmp/coral/coral_seg/submissions/results
58
+ zip_path: /root/autodl-tmp/coral/coral_seg/submissions/results.zip
coral_seg/coral_seg/__init__.py ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ """Coral reef semantic segmentation training package."""
2
+
coral_seg/coral_seg/__pycache__/__init__.cpython-312.pyc ADDED
Binary file (216 Bytes). View file
 
coral_seg/coral_seg/__pycache__/dataset.cpython-312.pyc ADDED
Binary file (8.01 kB). View file
 
coral_seg/coral_seg/__pycache__/losses.cpython-312.pyc ADDED
Binary file (7.07 kB). View file
 
coral_seg/coral_seg/__pycache__/model_convnext_fpn.cpython-312.pyc ADDED
Binary file (5.77 kB). View file
 
coral_seg/coral_seg/__pycache__/splits.cpython-312.pyc ADDED
Binary file (2.88 kB). View file
 
coral_seg/coral_seg/__pycache__/utils.cpython-312.pyc ADDED
Binary file (10.5 kB). View file
 
coral_seg/coral_seg/dataset.py ADDED
@@ -0,0 +1,144 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from typing import Dict, List, Optional
3
+
4
+ import albumentations as A
5
+ import cv2
6
+ import numpy as np
7
+ import torch
8
+ from torch.utils.data import Dataset
9
+
10
+ from .splits import read_ids
11
+ from .utils import IMAGENET_MEAN, IMAGENET_STD, list_pngs, read_image, read_mask
12
+
13
+
14
+ def build_train_transform(size: int) -> A.Compose:
15
+ return A.Compose(
16
+ [
17
+ A.HorizontalFlip(p=0.5),
18
+ A.VerticalFlip(p=0.5),
19
+ A.RandomRotate90(p=0.5),
20
+ A.Affine(
21
+ scale=(0.75, 1.25),
22
+ translate_percent=(-0.06, 0.06),
23
+ rotate=(-25, 25),
24
+ shear=(-5, 5),
25
+ interpolation=cv2.INTER_LINEAR,
26
+ mask_interpolation=cv2.INTER_NEAREST,
27
+ border_mode=cv2.BORDER_REFLECT_101,
28
+ p=0.65,
29
+ ),
30
+ A.OneOf(
31
+ [
32
+ A.RandomBrightnessContrast(brightness_limit=0.25, contrast_limit=0.25, p=1.0),
33
+ A.HueSaturationValue(hue_shift_limit=8, sat_shift_limit=18, val_shift_limit=18, p=1.0),
34
+ A.RandomGamma(gamma_limit=(75, 130), p=1.0),
35
+ A.CLAHE(clip_limit=(1, 3), tile_grid_size=(8, 8), p=1.0),
36
+ ],
37
+ p=0.85,
38
+ ),
39
+ A.OneOf(
40
+ [
41
+ A.GaussianBlur(blur_limit=(3, 5), p=1.0),
42
+ A.MotionBlur(blur_limit=3, p=1.0),
43
+ ],
44
+ p=0.20,
45
+ ),
46
+ A.Resize(size, size, interpolation=cv2.INTER_LINEAR, mask_interpolation=cv2.INTER_NEAREST),
47
+ A.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD),
48
+ ]
49
+ )
50
+
51
+
52
+ def build_val_transform(size: int) -> A.Compose:
53
+ return A.Compose(
54
+ [
55
+ A.Resize(size, size, interpolation=cv2.INTER_LINEAR, mask_interpolation=cv2.INTER_NEAREST),
56
+ A.Normalize(mean=IMAGENET_MEAN, std=IMAGENET_STD),
57
+ ]
58
+ )
59
+
60
+
61
+ class CoralSegDataset(Dataset):
62
+ def __init__(
63
+ self,
64
+ image_dir: str,
65
+ mask_dir: Optional[str] = None,
66
+ split_file: Optional[str] = None,
67
+ transform: Optional[A.Compose] = None,
68
+ ) -> None:
69
+ self.image_dir = Path(image_dir)
70
+ self.mask_dir = Path(mask_dir) if mask_dir else None
71
+ self.transform = transform
72
+
73
+ if split_file:
74
+ ids = read_ids(split_file)
75
+ self.image_paths = [self.image_dir / f"{sample_id}.png" for sample_id in ids]
76
+ else:
77
+ self.image_paths = list_pngs(self.image_dir)
78
+
79
+ if not self.image_paths:
80
+ raise RuntimeError(f"No PNG images found in {self.image_dir}")
81
+
82
+ def __len__(self) -> int:
83
+ return len(self.image_paths)
84
+
85
+ def __getitem__(self, idx: int) -> Dict[str, torch.Tensor | str]:
86
+ image_path = self.image_paths[idx]
87
+ image = read_image(image_path)
88
+ mask = None
89
+ if self.mask_dir is not None:
90
+ mask_path = self.mask_dir / image_path.name
91
+ mask = read_mask(mask_path)
92
+
93
+ if self.transform is not None:
94
+ if mask is None:
95
+ transformed = self.transform(image=image)
96
+ image = transformed["image"]
97
+ else:
98
+ transformed = self.transform(image=image, mask=mask)
99
+ image, mask = transformed["image"], transformed["mask"]
100
+
101
+ image_tensor = torch.from_numpy(image.transpose(2, 0, 1)).float()
102
+ sample: Dict[str, torch.Tensor | str] = {
103
+ "image": image_tensor,
104
+ "name": image_path.name,
105
+ }
106
+ if mask is not None:
107
+ sample["mask"] = torch.from_numpy(mask.astype(np.int64))
108
+ return sample
109
+
110
+
111
+ def segmentation_collate(batch: List[Dict[str, torch.Tensor | str]]) -> Dict[str, torch.Tensor | List[str]]:
112
+ images = torch.stack([item["image"] for item in batch]) # type: ignore[arg-type]
113
+ names = [str(item["name"]) for item in batch]
114
+ result: Dict[str, torch.Tensor | List[str]] = {"image": images, "name": names}
115
+ if "mask" in batch[0]:
116
+ result["mask"] = torch.stack([item["mask"] for item in batch]) # type: ignore[arg-type]
117
+ return result
118
+
119
+
120
+ def mask2former_collate(
121
+ batch: List[Dict[str, torch.Tensor | str]],
122
+ num_classes: int,
123
+ ) -> Dict[str, torch.Tensor | List[torch.Tensor] | List[str]]:
124
+ images = torch.stack([item["image"] for item in batch]) # type: ignore[arg-type]
125
+ names = [str(item["name"]) for item in batch]
126
+ result: Dict[str, torch.Tensor | List[torch.Tensor] | List[str]] = {"image": images, "name": names}
127
+ if "mask" not in batch[0]:
128
+ return result
129
+
130
+ masks = [item["mask"].long() for item in batch] # type: ignore[union-attr]
131
+ mask_labels: List[torch.Tensor] = []
132
+ class_labels: List[torch.Tensor] = []
133
+ for mask in masks:
134
+ labels = torch.unique(mask)
135
+ labels = labels[(labels >= 0) & (labels < num_classes)]
136
+ labels = labels.sort()[0]
137
+ binary_masks = torch.stack([(mask == cls).float() for cls in labels], dim=0)
138
+ mask_labels.append(binary_masks)
139
+ class_labels.append(labels.long())
140
+
141
+ result["raw_mask"] = torch.stack(masks)
142
+ result["mask_labels"] = mask_labels
143
+ result["class_labels"] = class_labels
144
+ return result
coral_seg/coral_seg/losses.py ADDED
@@ -0,0 +1,101 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from typing import Optional
2
+
3
+ import torch
4
+ import torch.nn as nn
5
+ import torch.nn.functional as F
6
+
7
+
8
+ class DiceLoss(nn.Module):
9
+ def __init__(self, num_classes: int, smooth: float = 1.0, ignore_index: int = 255) -> None:
10
+ super().__init__()
11
+ self.num_classes = num_classes
12
+ self.smooth = smooth
13
+ self.ignore_index = ignore_index
14
+
15
+ def forward(self, logits: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
16
+ probs = torch.softmax(logits, dim=1)
17
+ valid = target != self.ignore_index
18
+ target_safe = target.clamp(0, self.num_classes - 1)
19
+ one_hot = F.one_hot(target_safe, self.num_classes).permute(0, 3, 1, 2).float()
20
+ valid = valid.unsqueeze(1).float()
21
+ probs = probs * valid
22
+ one_hot = one_hot * valid
23
+ dims = (0, 2, 3)
24
+ intersection = torch.sum(probs * one_hot, dims)
25
+ cardinality = torch.sum(probs + one_hot, dims)
26
+ dice = (2.0 * intersection + self.smooth) / (cardinality + self.smooth)
27
+ return 1.0 - dice.mean()
28
+
29
+
30
+ def lovasz_grad(gt_sorted: torch.Tensor) -> torch.Tensor:
31
+ gts = gt_sorted.sum()
32
+ intersection = gts - gt_sorted.float().cumsum(0)
33
+ union = gts + (1 - gt_sorted).float().cumsum(0)
34
+ jaccard = 1.0 - intersection / union.clamp_min(1e-6)
35
+ if gt_sorted.numel() > 1:
36
+ jaccard[1:] = jaccard[1:] - jaccard[:-1]
37
+ return jaccard
38
+
39
+
40
+ def lovasz_softmax_flat(probs: torch.Tensor, labels: torch.Tensor, num_classes: int) -> torch.Tensor:
41
+ losses = []
42
+ for cls in range(num_classes):
43
+ fg = (labels == cls).float()
44
+ if fg.sum() == 0:
45
+ continue
46
+ class_pred = probs[:, cls]
47
+ errors = (fg - class_pred).abs()
48
+ errors_sorted, perm = torch.sort(errors, descending=True)
49
+ fg_sorted = fg[perm]
50
+ losses.append(torch.dot(errors_sorted, lovasz_grad(fg_sorted)))
51
+ if not losses:
52
+ return probs.sum() * 0.0
53
+ return torch.stack(losses).mean()
54
+
55
+
56
+ class LovaszSoftmaxLoss(nn.Module):
57
+ def __init__(self, num_classes: int, ignore_index: int = 255) -> None:
58
+ super().__init__()
59
+ self.num_classes = num_classes
60
+ self.ignore_index = ignore_index
61
+
62
+ def forward(self, logits: torch.Tensor, target: torch.Tensor) -> torch.Tensor:
63
+ probs = torch.softmax(logits, dim=1).permute(0, 2, 3, 1).reshape(-1, self.num_classes)
64
+ labels = target.reshape(-1)
65
+ valid = labels != self.ignore_index
66
+ if valid.sum() == 0:
67
+ return logits.sum() * 0.0
68
+ return lovasz_softmax_flat(probs[valid], labels[valid], self.num_classes)
69
+
70
+
71
+ class ComboSegLoss(nn.Module):
72
+ def __init__(
73
+ self,
74
+ num_classes: int,
75
+ ce_weight: float = 1.0,
76
+ dice_weight: float = 1.0,
77
+ lovasz_weight: float = 0.5,
78
+ label_smoothing: float = 0.05,
79
+ ignore_index: int = 255,
80
+ ) -> None:
81
+ super().__init__()
82
+ self.ce_weight = ce_weight
83
+ self.dice_weight = dice_weight
84
+ self.lovasz_weight = lovasz_weight
85
+ self.label_smoothing = label_smoothing
86
+ self.ignore_index = ignore_index
87
+ self.dice = DiceLoss(num_classes, ignore_index=ignore_index)
88
+ self.lovasz = LovaszSoftmaxLoss(num_classes, ignore_index=ignore_index)
89
+
90
+ def forward(self, logits: torch.Tensor, target: torch.Tensor, epoch: Optional[int] = None) -> torch.Tensor:
91
+ ce = F.cross_entropy(
92
+ logits,
93
+ target,
94
+ ignore_index=self.ignore_index,
95
+ label_smoothing=self.label_smoothing,
96
+ )
97
+ dice = self.dice(logits, target)
98
+ loss = self.ce_weight * ce + self.dice_weight * dice
99
+ if self.lovasz_weight > 0:
100
+ loss = loss + self.lovasz_weight * self.lovasz(logits, target)
101
+ return loss
coral_seg/coral_seg/model_convnext_fpn.py ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from typing import List
3
+
4
+ import torch
5
+ import torch.nn as nn
6
+ import torch.nn.functional as F
7
+ from torchvision.models import ConvNeXt_Large_Weights, convnext_large
8
+
9
+
10
+ class ConvBNAct(nn.Module):
11
+ def __init__(self, in_channels: int, out_channels: int, kernel_size: int = 3, dropout: float = 0.0) -> None:
12
+ super().__init__()
13
+ padding = kernel_size // 2
14
+ layers: List[nn.Module] = [
15
+ nn.Conv2d(in_channels, out_channels, kernel_size, padding=padding, bias=False),
16
+ nn.BatchNorm2d(out_channels),
17
+ nn.GELU(),
18
+ ]
19
+ if dropout > 0:
20
+ layers.append(nn.Dropout2d(dropout))
21
+ self.block = nn.Sequential(*layers)
22
+
23
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
24
+ return self.block(x)
25
+
26
+
27
+ class ConvNeXtFPN(nn.Module):
28
+ def __init__(
29
+ self,
30
+ num_classes: int = 4,
31
+ fpn_channels: int = 256,
32
+ pretrained: bool = True,
33
+ pretrained_path: str | None = None,
34
+ dropout: float = 0.1,
35
+ ) -> None:
36
+ super().__init__()
37
+ if pretrained and pretrained_path and Path(pretrained_path).is_file():
38
+ backbone = convnext_large(weights=None)
39
+ state = torch.load(pretrained_path, map_location="cpu")
40
+ if isinstance(state, dict) and "model" in state:
41
+ state = state["model"]
42
+ backbone.load_state_dict(state, strict=True)
43
+ else:
44
+ weights = ConvNeXt_Large_Weights.IMAGENET1K_V1 if pretrained else None
45
+ backbone = convnext_large(weights=weights)
46
+ self.features = backbone.features
47
+ in_channels = [192, 384, 768, 1536]
48
+ self.lateral = nn.ModuleList([nn.Conv2d(c, fpn_channels, 1) for c in in_channels])
49
+ self.smooth = nn.ModuleList([ConvBNAct(fpn_channels, fpn_channels, 3) for _ in in_channels])
50
+ self.decoder = nn.Sequential(
51
+ ConvBNAct(fpn_channels * 4, fpn_channels, 3, dropout=dropout),
52
+ ConvBNAct(fpn_channels, fpn_channels, 3, dropout=dropout),
53
+ nn.Conv2d(fpn_channels, num_classes, 1),
54
+ )
55
+
56
+ def forward_features(self, x: torch.Tensor) -> List[torch.Tensor]:
57
+ feats: List[torch.Tensor] = []
58
+ for idx, layer in enumerate(self.features):
59
+ x = layer(x)
60
+ if idx in (1, 3, 5, 7):
61
+ feats.append(x)
62
+ return feats
63
+
64
+ def forward(self, x: torch.Tensor) -> torch.Tensor:
65
+ input_size = x.shape[-2:]
66
+ feats = self.forward_features(x)
67
+ pyramid = [lat(feat) for lat, feat in zip(self.lateral, feats)]
68
+ for i in range(len(pyramid) - 1, 0, -1):
69
+ pyramid[i - 1] = pyramid[i - 1] + F.interpolate(
70
+ pyramid[i],
71
+ size=pyramid[i - 1].shape[-2:],
72
+ mode="bilinear",
73
+ align_corners=False,
74
+ )
75
+ pyramid = [smooth(feat) for smooth, feat in zip(self.smooth, pyramid)]
76
+ target_size = pyramid[0].shape[-2:]
77
+ pyramid = [
78
+ feat if feat.shape[-2:] == target_size else F.interpolate(feat, size=target_size, mode="bilinear", align_corners=False)
79
+ for feat in pyramid
80
+ ]
81
+ logits = self.decoder(torch.cat(pyramid, dim=1))
82
+ return F.interpolate(logits, size=input_size, mode="bilinear", align_corners=False)
coral_seg/coral_seg/splits.py ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+ from typing import Iterable, List, Tuple
3
+
4
+ import numpy as np
5
+
6
+ from .utils import ensure_dir, list_pngs
7
+
8
+
9
+ def create_split_files(
10
+ image_dir: str,
11
+ mask_dir: str,
12
+ split_dir: str,
13
+ val_ratio: float = 0.15,
14
+ seed: int = 2026,
15
+ ) -> Tuple[Path, Path, Path]:
16
+ image_paths = list_pngs(image_dir)
17
+ mask_dir_path = Path(mask_dir)
18
+ ids = []
19
+ for image_path in image_paths:
20
+ if not (mask_dir_path / image_path.name).exists():
21
+ raise FileNotFoundError(f"Missing mask for {image_path.name}")
22
+ ids.append(image_path.stem)
23
+
24
+ rng = np.random.default_rng(seed)
25
+ ids = np.array(ids)
26
+ order = rng.permutation(len(ids))
27
+ val_count = max(1, int(round(len(ids) * val_ratio)))
28
+ val_ids = sorted(ids[order[:val_count]].tolist())
29
+ train_ids = sorted(ids[order[val_count:]].tolist())
30
+ full_ids = sorted(ids.tolist())
31
+
32
+ split_path = ensure_dir(split_dir)
33
+ train_file = split_path / "train.txt"
34
+ val_file = split_path / "val.txt"
35
+ full_file = split_path / "train_full.txt"
36
+ train_file.write_text("\n".join(train_ids) + "\n", encoding="utf-8")
37
+ val_file.write_text("\n".join(val_ids) + "\n", encoding="utf-8")
38
+ full_file.write_text("\n".join(full_ids) + "\n", encoding="utf-8")
39
+ return train_file, val_file, full_file
40
+
41
+
42
+ def read_ids(path: str | Path) -> List[str]:
43
+ p = Path(path)
44
+ return [line.strip() for line in p.read_text(encoding="utf-8").splitlines() if line.strip()]
coral_seg/coral_seg/utils.py ADDED
@@ -0,0 +1,140 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import json
2
+ import math
3
+ import os
4
+ import random
5
+ import time
6
+ import zipfile
7
+ from pathlib import Path
8
+ from typing import Any, Dict, Iterable, List, Optional, Sequence, Tuple
9
+
10
+ import numpy as np
11
+ import torch
12
+ import yaml
13
+ from PIL import Image
14
+
15
+
16
+ IMAGENET_MEAN = (0.485, 0.456, 0.406)
17
+ IMAGENET_STD = (0.229, 0.224, 0.225)
18
+
19
+
20
+ def load_config(path: str | os.PathLike[str]) -> Dict[str, Any]:
21
+ with open(path, "r", encoding="utf-8") as f:
22
+ return yaml.safe_load(f)
23
+
24
+
25
+ def ensure_dir(path: str | os.PathLike[str]) -> Path:
26
+ p = Path(path)
27
+ p.mkdir(parents=True, exist_ok=True)
28
+ return p
29
+
30
+
31
+ def set_seed(seed: int) -> None:
32
+ random.seed(seed)
33
+ np.random.seed(seed)
34
+ torch.manual_seed(seed)
35
+ torch.cuda.manual_seed_all(seed)
36
+ torch.backends.cudnn.benchmark = True
37
+
38
+
39
+ def read_image(path: str | os.PathLike[str]) -> np.ndarray:
40
+ return np.array(Image.open(path).convert("RGB"))
41
+
42
+
43
+ def read_mask(path: str | os.PathLike[str]) -> np.ndarray:
44
+ return np.array(Image.open(path), dtype=np.uint8)
45
+
46
+
47
+ def save_mask(path: str | os.PathLike[str], mask: np.ndarray) -> None:
48
+ mask = np.asarray(mask, dtype=np.uint8)
49
+ Image.fromarray(mask, mode="L").save(path)
50
+
51
+
52
+ def normalize_tensor(image: np.ndarray) -> torch.Tensor:
53
+ image = image.astype(np.float32) / 255.0
54
+ mean = np.array(IMAGENET_MEAN, dtype=np.float32)
55
+ std = np.array(IMAGENET_STD, dtype=np.float32)
56
+ image = (image - mean) / std
57
+ return torch.from_numpy(image.transpose(2, 0, 1)).float()
58
+
59
+
60
+ def denormalize_tensor(x: torch.Tensor) -> torch.Tensor:
61
+ mean = torch.tensor(IMAGENET_MEAN, device=x.device).view(1, 3, 1, 1)
62
+ std = torch.tensor(IMAGENET_STD, device=x.device).view(1, 3, 1, 1)
63
+ return x * std + mean
64
+
65
+
66
+ class AverageMeter:
67
+ def __init__(self) -> None:
68
+ self.reset()
69
+
70
+ def reset(self) -> None:
71
+ self.sum = 0.0
72
+ self.count = 0
73
+
74
+ @property
75
+ def avg(self) -> float:
76
+ return self.sum / max(1, self.count)
77
+
78
+ def update(self, value: float, n: int = 1) -> None:
79
+ self.sum += float(value) * n
80
+ self.count += n
81
+
82
+
83
+ def fast_hist(pred: np.ndarray, target: np.ndarray, num_classes: int, ignore_index: int = 255) -> np.ndarray:
84
+ pred = pred.reshape(-1)
85
+ target = target.reshape(-1)
86
+ valid = (target != ignore_index) & (target >= 0) & (target < num_classes)
87
+ hist = np.bincount(
88
+ num_classes * target[valid].astype(np.int64) + pred[valid].astype(np.int64),
89
+ minlength=num_classes**2,
90
+ )
91
+ return hist.reshape(num_classes, num_classes)
92
+
93
+
94
+ def compute_iou(hist: np.ndarray) -> Tuple[np.ndarray, float]:
95
+ denom = hist.sum(1) + hist.sum(0) - np.diag(hist)
96
+ iou = np.divide(np.diag(hist), denom, out=np.full_like(denom, np.nan, dtype=np.float64), where=denom != 0)
97
+ return iou, float(np.nanmean(iou))
98
+
99
+
100
+ def format_metrics(iou: np.ndarray, miou: float, class_names: Sequence[str]) -> str:
101
+ parts = [f"mIoU={miou:.5f}"]
102
+ for name, value in zip(class_names, iou):
103
+ parts.append(f"{name}={value:.5f}" if not np.isnan(value) else f"{name}=nan")
104
+ return " ".join(parts)
105
+
106
+
107
+ def save_json(path: str | os.PathLike[str], obj: Dict[str, Any]) -> None:
108
+ with open(path, "w", encoding="utf-8") as f:
109
+ json.dump(obj, f, indent=2, ensure_ascii=False)
110
+
111
+
112
+ def cosine_warmup_lambda(
113
+ current_step: int,
114
+ *,
115
+ total_steps: int,
116
+ warmup_steps: int,
117
+ min_factor: float = 0.01,
118
+ ) -> float:
119
+ if current_step < warmup_steps:
120
+ return float(current_step + 1) / float(max(1, warmup_steps))
121
+ progress = float(current_step - warmup_steps) / float(max(1, total_steps - warmup_steps))
122
+ cosine = 0.5 * (1.0 + math.cos(math.pi * progress))
123
+ return min_factor + (1.0 - min_factor) * cosine
124
+
125
+
126
+ def make_results_zip(results_dir: str | os.PathLike[str], zip_path: str | os.PathLike[str]) -> None:
127
+ results_dir = Path(results_dir)
128
+ zip_path = Path(zip_path)
129
+ ensure_dir(zip_path.parent)
130
+ with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as zf:
131
+ for path in sorted(results_dir.glob("*.png")):
132
+ zf.write(path, arcname=f"results/{path.name}")
133
+
134
+
135
+ def list_pngs(path: str | os.PathLike[str]) -> List[Path]:
136
+ return sorted(Path(path).glob("*.png"))
137
+
138
+
139
+ def timestamp() -> str:
140
+ return time.strftime("%Y-%m-%d %H:%M:%S")
coral_seg/docs/operation-guide.md ADDED
@@ -0,0 +1,575 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 完整操作指南
2
+
3
+ 本文档说明如何从环境部署开始,完成数据解压、预训练模型下载、模型训练、结果推理、可视化、mIoU 评估和 `results.zip` 压缩提交。
4
+
5
+ ## 1. 运行目录
6
+
7
+ 推荐从工作区根目录执行所有命令:
8
+
9
+ ```bash
10
+ cd /root/autodl-tmp/coral
11
+ ```
12
+
13
+ 当前配置默认使用以下路径:
14
+
15
+ ```text
16
+ 训练图像:/root/autodl-tmp/coral/data_fresh/train_bsdtar/train/image
17
+ 训练标签:/root/autodl-tmp/coral/data_fresh/train_bsdtar/train/label
18
+ 测试图像:/root/autodl-tmp/coral/data_fresh/test_raw/PrecisionLabel800/images
19
+ 工程目录:/root/autodl-tmp/coral/coral_seg
20
+ ```
21
+
22
+ ## 2. 环境部署
23
+
24
+ 本项目没有单独新建 conda 环境,直接使用当前默认 Python 环境。
25
+
26
+ 检查当前环境:
27
+
28
+ ```bash
29
+ which python
30
+ python -V
31
+ python -c "import torch; print(torch.__version__, torch.cuda.is_available())"
32
+ ```
33
+
34
+ 当前已验证版本:
35
+
36
+ ```text
37
+ Python 3.12.3
38
+ PyTorch 2.3.0+cu121
39
+ torchvision 0.18.0+cu121
40
+ transformers 4.46.3
41
+ timm 1.0.27
42
+ albumentations 2.0.8
43
+ opencv-python-headless 4.13.0.92
44
+ ```
45
+
46
+ 如果需要重新安装依赖:
47
+
48
+ ```bash
49
+ python -m pip install -U \
50
+ transformers==4.46.3 \
51
+ timm==1.0.27 \
52
+ albumentations==2.0.8 \
53
+ opencv-python-headless==4.13.0.92 \
54
+ safetensors \
55
+ accelerate \
56
+ PyYAML \
57
+ huggingface-hub
58
+ ```
59
+
60
+ 不要随意升级 `torch` 和 `torchvision`,当前训练代码已经按现有版本验证通过。
61
+
62
+ ## 3. 数据解压
63
+
64
+ 如果 `data_fresh/` 已经存在且检查正常,可以跳过本节。
65
+
66
+ 外层数据包:
67
+
68
+ ```text
69
+ /root/autodl-tmp/比赛data.zip
70
+ ```
71
+
72
+ 解压外层 zip:
73
+
74
+ ```bash
75
+ mkdir -p extracted_zip
76
+ unzip -q -o '比赛data.zip' -d extracted_zip
77
+ ```
78
+
79
+ 外层解压后包含:
80
+
81
+ ```text
82
+ 比赛data/train.rar
83
+ 比赛data/test.zip
84
+ ```
85
+
86
+ 训练集建议使用 `bsdtar` 解压。旧版 `7z` 对该 RAR5 压缩方式可能报 `Unsupported Method`。
87
+
88
+ ```bash
89
+ mkdir -p data_fresh/train_bsdtar
90
+ bsdtar -xf 'extracted_zip/比赛data/train.rar' -C data_fresh/train_bsdtar
91
+ ```
92
+
93
+ 测试集解压:
94
+
95
+ ```bash
96
+ mkdir -p data_fresh/test_raw
97
+ unzip -q -o 'extracted_zip/比赛data/test.zip' -d data_fresh/test_raw
98
+ ```
99
+
100
+ 清理旧数据和临时目录:
101
+
102
+ ```bash
103
+ rm -rf data data_fresh/train_raw extracted_zip
104
+ ```
105
+
106
+ ## 4. 检查数据
107
+
108
+ 执行:
109
+
110
+ ```bash
111
+ python coral_seg/tools/check_data.py --config coral_seg/configs/final_dual.yaml
112
+ ```
113
+
114
+ 正常输出应包含:
115
+
116
+ ```text
117
+ train_images 3000 0000.png 2999.png
118
+ train_masks 3000 0000.png 2999.png
119
+ test_images 800 image_0001.png image_0800.png
120
+ mask values: [0, 1, 2, 3]
121
+ bad masks: 0 []
122
+ ```
123
+
124
+ 如果 `bad masks` 不为 0,说明训练标签像素值异常,不应继续训练。
125
+
126
+ ## 5. 预训练模型部署和下载
127
+
128
+ 本方案需要两类预训练模型,均通过配置文件显式指定路径。
129
+
130
+ ```text
131
+ Mask2Former-Swin-B:facebook/mask2former-swin-base-ade-semantic
132
+ ConvNeXt-L:torchvision convnext_large ImageNet-1K 权重
133
+ ```
134
+
135
+ 配置位置:
136
+
137
+ ```text
138
+ coral_seg/configs/final_dual.yaml
139
+ ```
140
+
141
+ 对应字段:
142
+
143
+ ```text
144
+ mask2former.pretrained_name: facebook/mask2former-swin-base-ade-semantic
145
+ mask2former.pretrained_dir: /root/autodl-tmp/coral/coral_seg/pretrained/mask2former-swin-base-ade-semantic
146
+ convnext.pretrained_path: /root/autodl-tmp/coral/coral_seg/pretrained/convnext_large-ea097f82.pth
147
+ ```
148
+
149
+ ### 5.1 在线下载
150
+
151
+ 如果机器可以访问 HuggingFace 和 PyTorch 权重源,直接执行:
152
+
153
+ ```bash
154
+ python coral_seg/tools/download_pretrained.py --config coral_seg/configs/final_dual.yaml
155
+ ```
156
+
157
+ 该脚本会完成两件事:
158
+
159
+ ```text
160
+ 1. 下载 Mask2Former-Swin-B 到 coral_seg/pretrained/mask2former-swin-base-ade-semantic/
161
+ 2. 下载 ConvNeXt-L 的 torchvision 权重,并复制到 coral_seg/pretrained/convnext_large-ea097f82.pth
162
+ ```
163
+
164
+ 下载完成后,工程内应存在:
165
+
166
+ ```text
167
+ coral_seg/pretrained/
168
+ ├── convnext_large-ea097f82.pth
169
+ └── mask2former-swin-base-ade-semantic/
170
+ ├── config.json
171
+ ├── preprocessor_config.json
172
+ ├── model.safetensors
173
+ └── pytorch_model.bin
174
+ ```
175
+
176
+ `model.safetensors` 和 `pytorch_model.bin` 至少保留一个即可;当前目录同时保留两者,便于不同版本 `transformers` 加载。
177
+
178
+ ### 5.2 离线部署
179
+
180
+ 如果复现环境不能联网,需要提前把预训练模型放到以下位置。
181
+
182
+ Mask2Former 目录:
183
+
184
+ ```text
185
+ /root/autodl-tmp/coral/coral_seg/pretrained/mask2former-swin-base-ade-semantic/
186
+ ```
187
+
188
+ 该目录至少需要包含:
189
+
190
+ ```text
191
+ config.json
192
+ preprocessor_config.json
193
+ model.safetensors 或 pytorch_model.bin
194
+ ```
195
+
196
+ ConvNeXt-L 权重文件:
197
+
198
+ ```text
199
+ /root/autodl-tmp/coral/coral_seg/pretrained/convnext_large-ea097f82.pth
200
+ ```
201
+
202
+ 如果当前机器已经有 torchvision 缓存,可以复制到工程目录:
203
+
204
+ ```bash
205
+ mkdir -p coral_seg/pretrained
206
+ cp /root/.cache/torch/hub/checkpoints/convnext_large-ea097f82.pth \
207
+ coral_seg/pretrained/convnext_large-ea097f82.pth
208
+ ```
209
+
210
+ 训练代码会优先读取 `convnext.pretrained_path`。只要该文件存在,就不会依赖 `/root/.cache/torch` 中的缓存。
211
+
212
+ ### 5.3 完整性检查
213
+
214
+ 执行以下命令检查预训练模型文件是否齐全:
215
+
216
+ ```bash
217
+ python - <<'PY_CHECK'
218
+ from pathlib import Path
219
+
220
+ root = Path('coral_seg/pretrained')
221
+ mask2former = root / 'mask2former-swin-base-ade-semantic'
222
+ convnext = root / 'convnext_large-ea097f82.pth'
223
+
224
+ required = [
225
+ mask2former / 'config.json',
226
+ mask2former / 'preprocessor_config.json',
227
+ convnext,
228
+ ]
229
+ missing = [str(p) for p in required if not p.is_file()]
230
+ has_weight = (mask2former / 'model.safetensors').is_file() or (mask2former / 'pytorch_model.bin').is_file()
231
+ if not has_weight:
232
+ missing.append(str(mask2former / 'model.safetensors 或 pytorch_model.bin'))
233
+
234
+ print('missing:', missing)
235
+ print('mask2former_dir:', mask2former.resolve())
236
+ print('convnext_weight:', convnext.resolve(), convnext.stat().st_size if convnext.is_file() else 0)
237
+ PY_CHECK
238
+ ```
239
+
240
+ 正常情况下:
241
+
242
+ ```text
243
+ missing: []
244
+ ```
245
+
246
+ ### 5.4 加载说明
247
+
248
+ ConvNeXt 分支:
249
+
250
+ ```text
251
+ coral_seg/model_convnext_fpn.py 会优先读取 convnext.pretrained_path
252
+ 如果该文件不存在,才会退回到 torchvision 自动下载或缓存加载
253
+ ```
254
+
255
+ Mask2Former 分支:
256
+
257
+ ```text
258
+ train_mask2former.py 会从 mask2former.pretrained_dir 加载本地目录
259
+ 分类头从 ADE20K 的 150 类改为本任务的 4 类,因此分类头重新初始化是正常现象
260
+ ```
261
+
262
+ 常见日志:
263
+
264
+ ```text
265
+ class_predictor shape mismatch
266
+ ```
267
+
268
+ 这是正常现象,不是权重损坏。
269
+
270
+ 如果在线下载时出现网络超时,可以改用离线部署方式,只要上述文件清单完整即可继续训练。
271
+
272
+ ## 6. 生成训练和验证划分
273
+
274
+ 执行:
275
+
276
+ ```bash
277
+ python coral_seg/tools/create_splits.py --config coral_seg/configs/final_dual.yaml
278
+ ```
279
+
280
+ 生成:
281
+
282
+ ```text
283
+ coral_seg/splits/train.txt
284
+ coral_seg/splits/val.txt
285
+ coral_seg/splits/train_full.txt
286
+ ```
287
+
288
+ 默认划分:
289
+
290
+ ```text
291
+ 85% 训练集
292
+ 15% 验证集
293
+ seed = 2026
294
+ ```
295
+
296
+ ## 7. 训练 ConvNeXt-L-FPN
297
+
298
+ 建议先训练 ConvNeXt 分支,因为它更稳定、速度更快。
299
+
300
+ ```bash
301
+ mkdir -p coral_seg/logs
302
+
303
+ python coral_seg/tools/train_convnext.py \
304
+ --config coral_seg/configs/final_dual.yaml \
305
+ 2>&1 | tee coral_seg/logs/convnext_train.log
306
+ ```
307
+
308
+ 主要配置:
309
+
310
+ ```text
311
+ 输入尺寸:512
312
+ batch size:4
313
+ epoch:120
314
+ 优化器:AdamW
315
+ 学习率:6e-5
316
+ 损失函数:CE + Dice + Lovasz
317
+ label smoothing:0.05
318
+ ```
319
+
320
+ 训练产物:
321
+
322
+ ```text
323
+ coral_seg/work_dirs/convnext_l_fpn/best.pth
324
+ coral_seg/work_dirs/convnext_l_fpn/latest.pth
325
+ ```
326
+
327
+ 查看日志:
328
+
329
+ ```bash
330
+ tail -f coral_seg/logs/convnext_train.log
331
+ ```
332
+
333
+ 查看验证集 mIoU:
334
+
335
+ ```bash
336
+ grep "convnext val" coral_seg/logs/convnext_train.log
337
+ ```
338
+
339
+ ## 8. 训练 Mask2Former-Swin-B
340
+
341
+ ConvNeXt 训练完成后,训练 Mask2Former:
342
+
343
+ ```bash
344
+ python coral_seg/tools/train_mask2former.py \
345
+ --config coral_seg/configs/final_dual.yaml \
346
+ 2>&1 | tee coral_seg/logs/mask2former_train.log
347
+ ```
348
+
349
+ 主要配置:
350
+
351
+ ```text
352
+ 输入尺寸:384
353
+ batch size:2
354
+ epoch:80
355
+ 优化器:AdamW
356
+ 学习率:3e-5
357
+ 预训练权重:facebook/mask2former-swin-base-ade-semantic
358
+ ```
359
+
360
+ 训练产物:
361
+
362
+ ```text
363
+ coral_seg/work_dirs/mask2former_swin_b/best.pth
364
+ coral_seg/work_dirs/mask2former_swin_b/latest.pth
365
+ coral_seg/work_dirs/mask2former_swin_b/best_hf/
366
+ ```
367
+
368
+ 查看日志:
369
+
370
+ ```bash
371
+ tail -f coral_seg/logs/mask2former_train.log
372
+ ```
373
+
374
+ 查看验证集 mIoU:
375
+
376
+ ```bash
377
+ grep "mask2former val" coral_seg/logs/mask2former_train.log
378
+ ```
379
+
380
+ 常见日志说明:
381
+
382
+ ```text
383
+ class_predictor shape mismatch
384
+ ```
385
+
386
+ 这是正常现象。ADE20K 预训练模型是 150 类,本任务是 4 类,分类头需要重新初始化。
387
+
388
+ ```text
389
+ Gradient checkpointing is not supported
390
+ ```
391
+
392
+ 这是正常现象。本地 transformers 的 Mask2Former 类不支持梯度检查点,代码会自动跳过。
393
+
394
+ ## 9. 查看 GPU 状态
395
+
396
+ ```bash
397
+ nvidia-smi
398
+ ```
399
+
400
+ 持续刷新:
401
+
402
+ ```bash
403
+ watch -n 2 nvidia-smi
404
+ ```
405
+
406
+ ## 10. 中断后继续训练
407
+
408
+ ConvNeXt 继续训练:
409
+
410
+ ```bash
411
+ python coral_seg/tools/train_convnext.py \
412
+ --config coral_seg/configs/final_dual.yaml \
413
+ --resume coral_seg/work_dirs/convnext_l_fpn/latest.pth
414
+ ```
415
+
416
+ Mask2Former 继续训练:
417
+
418
+ ```bash
419
+ python coral_seg/tools/train_mask2former.py \
420
+ --config coral_seg/configs/final_dual.yaml \
421
+ --resume coral_seg/work_dirs/mask2former_swin_b/latest.pth
422
+ ```
423
+
424
+ ## 11. 验证集融合 mIoU
425
+
426
+ 两个模型都训练完成后,计算验证集双模型融合 mIoU:
427
+
428
+ ```bash
429
+ python coral_seg/tools/eval_ensemble_val.py \
430
+ --config coral_seg/configs/final_dual.yaml \
431
+ --convnext-checkpoint coral_seg/work_dirs/convnext_l_fpn/best.pth \
432
+ --mask2former-checkpoint coral_seg/work_dirs/mask2former_swin_b/best_hf
433
+ ```
434
+
435
+ ## 12. 测试集推理
436
+
437
+ 双模型融合推理:
438
+
439
+ ```bash
440
+ python coral_seg/tools/infer_ensemble.py \
441
+ --config coral_seg/configs/final_dual.yaml \
442
+ --convnext-checkpoint coral_seg/work_dirs/convnext_l_fpn/best.pth \
443
+ --mask2former-checkpoint coral_seg/work_dirs/mask2former_swin_b/best_hf
444
+ ```
445
+
446
+ 推理输出:
447
+
448
+ ```text
449
+ coral_seg/submissions/results/
450
+ coral_seg/submissions/results.zip
451
+ ```
452
+
453
+ `results/` 中应包含 800 张单通道 PNG:
454
+
455
+ ```text
456
+ image_0001.png
457
+ image_0002.png
458
+ ...
459
+ image_0800.png
460
+ ```
461
+
462
+ 每张 PNG 的像素值只能是:
463
+
464
+ ```text
465
+ 0, 1, 2, 3
466
+ ```
467
+
468
+ ## 13. 检查并压缩 results
469
+
470
+ 推理脚本会自动压缩 `results.zip`。如果需要手动检查:
471
+
472
+ ```bash
473
+ python - <<'PY_CHECK'
474
+ import zipfile
475
+ from pathlib import Path
476
+ from PIL import Image
477
+ import numpy as np
478
+
479
+ zip_path = Path('coral_seg/submissions/results.zip')
480
+ with zipfile.ZipFile(zip_path) as zf:
481
+ names = zf.namelist()
482
+ print('num files:', len(names))
483
+ print('first:', names[:3])
484
+ print('last:', names[-3:])
485
+
486
+ values = set()
487
+ for p in sorted(Path('coral_seg/submissions/results').glob('*.png')):
488
+ arr = np.array(Image.open(p))
489
+ values |= set(np.unique(arr).tolist())
490
+ print('values:', sorted(values))
491
+ PY_CHECK
492
+ ```
493
+
494
+ 正常结果:
495
+
496
+ ```text
497
+ num files: 800
498
+ first: ['results/image_0001.png', ...]
499
+ values: [0, 1, 2, 3]
500
+ ```
501
+
502
+ 如果需要手动重新压缩:
503
+
504
+ ```bash
505
+ cd coral_seg/submissions
506
+ zip -r results.zip results
507
+ cd /root/autodl-tmp/coral
508
+ ```
509
+
510
+ 压缩包内部结构必须是:
511
+
512
+ ```text
513
+ results.zip
514
+ └── results/
515
+ ├── image_0001.png
516
+ ├── image_0002.png
517
+ ├── ...
518
+ └── image_0800.png
519
+ ```
520
+
521
+ ## 14. 生成可视化结果
522
+
523
+ ```bash
524
+ python coral_seg/tools/visualize_results.py \
525
+ --image-dir data_fresh/test_raw/PrecisionLabel800/images \
526
+ --pred-dir coral_seg/submissions/results \
527
+ --out-dir coral_seg/vis_results \
528
+ --num 24
529
+ ```
530
+
531
+ 输出目录:
532
+
533
+ ```text
534
+ coral_seg/vis_results/
535
+ ```
536
+
537
+ 每张可视化图包含:
538
+
539
+ ```text
540
+ 原图
541
+ 预测彩色 mask
542
+ 预测叠加图
543
+ ```
544
+
545
+ ## 15. 本地 test mIoU
546
+
547
+ 只有当 `data_fresh/test_raw/PrecisionLabel800/mask` 确认为官方测试集真值时,下面的 test mIoU 才有意义。
548
+
549
+ 当前识别到该目录是 RGB 彩色 mask,颜色映射为:
550
+
551
+ ```text
552
+ (0, 0, 0) -> 0 背景
553
+ (240, 110, 170) -> 1 活珊瑚
554
+ (240, 171, 203) -> 2 死珊瑚
555
+ (0, 162, 232) -> 3 白化珊瑚
556
+ ```
557
+
558
+ 计算命令:
559
+
560
+ ```bash
561
+ python coral_seg/tools/eval_predictions.py \
562
+ --pred-dir coral_seg/submissions/results \
563
+ --gt-dir data_fresh/test_raw/PrecisionLabel800/mask \
564
+ --color-map '0,0,0:0;240,110,170:1;240,171,203:2;0,162,232:3'
565
+ ```
566
+
567
+ 如果该 `mask` 目录不是官方真值,而只是参考或占位 mask,则最终测试集成绩以竞赛平台为准。
568
+
569
+ ## 16. 最终提交文件
570
+
571
+ 最终提交文件位置:
572
+
573
+ ```text
574
+ /root/autodl-tmp/coral/coral_seg/submissions/results.zip
575
+ ```
coral_seg/docs/technical-report.md ADDED
@@ -0,0 +1,566 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # 方法与技术细节说明
2
+
3
+ 本文档说明本项目解决水下珊瑚语义分割任务的完整技术方案,包括任务分析、模型设计、训练策略、损失函数、数据增强、融合推理、mIoU 计算和复现设计。
4
+
5
+ ## 1. 任务定义
6
+
7
+ 输入为 `256x256` RGB 水下图像,输出为同尺寸单通道语义分割图。
8
+
9
+ 类别定义:
10
+
11
+ ```text
12
+ 0 背景
13
+ 1 活珊瑚
14
+ 2 死珊瑚
15
+ 3 白化珊瑚
16
+ ```
17
+
18
+ 评价指标为 mIoU。
19
+
20
+ 比赛限制:
21
+
22
+ ```text
23
+ 只允许使用官方训练集
24
+ 测试集只允许用于推理
25
+ 不得使用伪标签、自训练或测试集分布统计更新
26
+ 预训练模型必须是 2026-01-01 前公开发布的开源模型
27
+ 最终复现要求在 A30 单卡 24G 上训练和推理总时间不超过 24 小时
28
+ ```
29
+
30
+ ## 2. 数据难点
31
+
32
+ 水下珊瑚图像相比普通自然图像有明显差异:
33
+
34
+ ```text
35
+ 光照不均
36
+ 颜色偏移
37
+ 水体浑浊
38
+ 悬浮颗粒干扰
39
+ 珊瑚边界不规则
40
+ 活珊瑚、死珊瑚、白化珊瑚外观相似
41
+ 标签存在噪声
42
+ ```
43
+
44
+ 因此,模型需要同时利用:
45
+
46
+ ```text
47
+ 局部纹理
48
+ 边界形态
49
+ 多尺度上下文
50
+ 全局语义信息
51
+ ```
52
+
53
+ 单纯依赖颜色容易失败,尤其在水下颜色失真严重时。
54
+
55
+ ## 3. 总体方案
56
+
57
+ 最终采用双模型融合:
58
+
59
+ ```text
60
+ Mask2Former-Swin-B + ConvNeXt-L-FPN
61
+ ```
62
+
63
+ 职责划分:
64
+
65
+ ```text
66
+ Mask2Former-Swin-B:负责复杂区域、全局上下文和 mask 级建模
67
+ ConvNeXt-L-FPN:负责局部纹理、边界细节和卷积稳定性
68
+ ```
69
+
70
+ 融合方式:
71
+
72
+ ```text
73
+ final_prob = 0.55 * prob_mask2former + 0.45 * prob_convnext
74
+ prediction = argmax(final_prob)
75
+ ```
76
+
77
+ 选择异构融合的原因:
78
+
79
+ ```text
80
+ 两类模型错误模式不同
81
+ Transformer 更擅长全局关系
82
+ 卷积模型更擅长局部纹理和边界
83
+ 概率融合可以降低单模型偶然错误
84
+ ```
85
+
86
+ ## 4. ConvNeXt-L-FPN 分支
87
+
88
+ ### 4.1 ConvNeXt-L 骨干
89
+
90
+ ConvNeXt 是现代卷积网络,吸收了 Transformer 时代的一些结构设计,例如:
91
+
92
+ ```text
93
+ 大卷积核深度卷积
94
+ 更合理的 stage 设计
95
+ GELU 激活
96
+ LayerNorm 风格结构
97
+ 倒瓶颈结构
98
+ ```
99
+
100
+ 本项目使用 torchvision 的 `convnext_large`,并加载 ImageNet-1K 预训练权重。
101
+
102
+ 优势:
103
+
104
+ ```text
105
+ 原生 torchvision 支持,环境稳定
106
+ 卷积归纳偏置强,适合小数据和纹理任务
107
+ 局部边界表达能力好
108
+ 训练速度可控
109
+ ```
110
+
111
+ ### 4.2 FPN 解码器
112
+
113
+ ConvNeXt-L 输出四个尺度特征:
114
+
115
+ ```text
116
+ 192, 384, 768, 1536 channels
117
+ ```
118
+
119
+ FPN 解码流程:
120
+
121
+ ```text
122
+ 1. 每层特征用 1x1 卷积投影到 256 通道
123
+ 2. 高层特征逐级上采样并与低层相加
124
+ 3. 每层用 3x3 卷积平滑
125
+ 4. 所有尺度上采样到同一分辨率
126
+ 5. 拼接后输出 4 类 logits
127
+ ```
128
+
129
+ FPN 的作用:
130
+
131
+ ```text
132
+ 高层特征提供语义
133
+ 低层特征提供边界
134
+ 多尺度融合提升小目标和复杂区域分割效果
135
+ ```
136
+
137
+ ### 4.3 ConvNeXt 训练配置
138
+
139
+ ```text
140
+ 输入尺寸:512
141
+ batch size:4
142
+ epoch:120
143
+ 优化器:AdamW
144
+ 基础学习率:6e-5
145
+ backbone 学习率:基础学习率的 0.25
146
+ weight decay:0.01
147
+ 学习率策略:warmup + cosine decay
148
+ 混合精度:开启
149
+ ```
150
+
151
+ 骨干网络使用更低学习率,是为了保护预训练特征,降低小数据噪声标签导致的过拟合风险。
152
+
153
+ ## 5. Mask2Former-Swin-B 分支
154
+
155
+ ### 5.1 Mask2Former 思想
156
+
157
+ Mask2Former 将分割任务建模为 mask classification。
158
+
159
+ 普通语义分割直接输出每个像素的类别;Mask2Former 则预测一组 query,每个 query 包含:
160
+
161
+ ```text
162
+ 类别概率
163
+ 对应的二值 mask
164
+ ```
165
+
166
+ 最终语义分割通过:
167
+
168
+ ```text
169
+ 类别概率 x mask 概率
170
+ ```
171
+
172
+ 组合成每个类别的像素概率图。
173
+
174
+ 这种方式对复杂、不规则区域更友好,适合珊瑚这类边界复杂的对象。
175
+
176
+ ### 5.2 Swin Transformer 骨干
177
+
178
+ Swin Transformer 使用窗口注意力机制:
179
+
180
+ ```text
181
+ 局部窗口 self-attention 降低计算量
182
+ shifted window 实现跨窗口信息交互
183
+ 分层结构输出多尺度特征
184
+ ```
185
+
186
+ 它同时具备 Transformer 的上下文建模能力和类似 CNN 的层级特征结构。
187
+
188
+ ### 5.3 预训练模型
189
+
190
+ Mask2Former 分支使用:
191
+
192
+ ```text
193
+ facebook/mask2former-swin-base-ade-semantic
194
+ ```
195
+
196
+ 该模型是 ADE20K 语义分割预训练模型。ADE20K 为 150 类,本任务为 4 类,因此加载时分类头会重新初始化,这是正常现象。
197
+
198
+ ConvNeXt 分支使用:
199
+
200
+ ```text
201
+ torchvision convnext_large ImageNet-1K 权重
202
+ ```
203
+
204
+ 本地部署路径由配置文件固定:
205
+
206
+ ```text
207
+ mask2former.pretrained_dir = /root/autodl-tmp/coral/coral_seg/pretrained/mask2former-swin-base-ade-semantic
208
+ convnext.pretrained_path = /root/autodl-tmp/coral/coral_seg/pretrained/convnext_large-ea097f82.pth
209
+ ```
210
+
211
+ 这样复现时不依赖临时下载缓存;联网环境可以运行 `tools/download_pretrained.py` 下载,离线环境只需要提前放入对应文件。
212
+
213
+ ### 5.4 标签格式转换
214
+
215
+ 原始标签格式:
216
+
217
+ ```text
218
+ H x W,像素值为 0/1/2/3
219
+ ```
220
+
221
+ Mask2Former 训练需要转换为:
222
+
223
+ ```text
224
+ class_labels:当前图像中出现过的类别编号
225
+ mask_labels:每个类别对应一个二值 mask
226
+ ```
227
+
228
+ 例如图像中出现类别 0、1、3,则:
229
+
230
+ ```text
231
+ class_labels = [0, 1, 3]
232
+ mask_labels.shape = [3, H, W]
233
+ ```
234
+
235
+ ## 6. 数据增强
236
+
237
+ 水下图像受光照、水体和成像条件影响明显,因此增强策略重点覆盖几何变化和颜色变化。
238
+
239
+ 使用增强:
240
+
241
+ ```text
242
+ HorizontalFlip
243
+ VerticalFlip
244
+ RandomRotate90
245
+ Affine scale/translate/rotate/shear
246
+ RandomBrightnessContrast
247
+ HueSaturationValue
248
+ RandomGamma
249
+ CLAHE
250
+ GaussianBlur
251
+ MotionBlur
252
+ Resize
253
+ Normalize
254
+ ```
255
+
256
+ 几何增强模拟:
257
+
258
+ ```text
259
+ 拍摄方向变化
260
+ 视角变化
261
+ 尺度变化
262
+ 轻微形变
263
+ ```
264
+
265
+ 颜色增强模拟:
266
+
267
+ ```text
268
+ 水下光照变化
269
+ 色偏
270
+ 对比度变化
271
+ 相机白平衡差异
272
+ ```
273
+
274
+ 模糊增强模拟:
275
+
276
+ ```text
277
+ 水体浑浊
278
+ 运动模糊
279
+ 散射导致的细节损失
280
+ ```
281
+
282
+ ## 7. 损失函数
283
+
284
+ ConvNeXt 分支使用组合损失:
285
+
286
+ ```text
287
+ Loss = CE + Dice + 0.5 * Lovasz
288
+ ```
289
+
290
+ ### 7.1 交叉熵损失
291
+
292
+ 交叉熵用于像素级分类监督:
293
+
294
+ ```text
295
+ CE = -log P(correct_class)
296
+ ```
297
+
298
+ 优点是稳定、收敛快。
299
+
300
+ ### 7.2 Dice Loss
301
+
302
+ Dice 衡量预测区域与真实区域的重叠程度:
303
+
304
+ ```text
305
+ Dice = 2 * intersection / (prediction + target)
306
+ ```
307
+
308
+ 适合类别不均衡和小区域分割。
309
+
310
+ ### 7.3 Lovasz Loss
311
+
312
+ Lovasz Softmax 是 IoU 的可优化近似,更贴近比赛 mIoU 指标。
313
+
314
+ 作用:
315
+
316
+ ```text
317
+ 优化目标更接近 mIoU
318
+ 提升区域交并比表现
319
+ ```
320
+
321
+ ### 7.4 Label Smoothing
322
+
323
+ 使用:
324
+
325
+ ```text
326
+ label_smoothing = 0.05
327
+ ```
328
+
329
+ 作用:
330
+
331
+ ```text
332
+ 降低模型对噪声标签的过度自信
333
+ 提高泛化能力
334
+ 缓解标注误差
335
+ ```
336
+
337
+ Mask2Former 分支使用模型内部的分类、mask 和 dice 损失组合。
338
+
339
+ ## 8. 学习率策略
340
+
341
+ 两个模型均使用:
342
+
343
+ ```text
344
+ warmup + cosine decay
345
+ ```
346
+
347
+ warmup 作用:
348
+
349
+ ```text
350
+ 避免训练初期学习率过大破坏预训练权重
351
+ 降低 loss 震荡
352
+ 提升训练稳定性
353
+ ```
354
+
355
+ cosine decay 作用:
356
+
357
+ ```text
358
+ 后期平滑降低学习率
359
+ 帮助模型收敛到更稳定的局部最优
360
+ ```
361
+
362
+ ## 9. 噪声标签处理
363
+
364
+ 当前方案通过以下方式降低噪声标签影响:
365
+
366
+ ```text
367
+ 使用强预训练模型
368
+ 使用 label smoothing
369
+ 使用 Dice 和 Lovasz 关注区域级一致性
370
+ 强数据增强提升泛化
371
+ 保存验证集 best checkpoint
372
+ 双模型融合降低单模型噪声敏感性
373
+ ```
374
+
375
+ 没有使用测试集伪标签、自训练或测试集分布统计,符合比赛规则。
376
+
377
+ ## 10. 融合推理
378
+
379
+ 两个模型分别输出每个类别的概率图:
380
+
381
+ ```text
382
+ prob_convnext: [4, H, W]
383
+ prob_mask2former: [4, H, W]
384
+ ```
385
+
386
+ 融合:
387
+
388
+ ```text
389
+ prob = 0.45 * prob_convnext + 0.55 * prob_mask2former
390
+ pred = argmax(prob)
391
+ ```
392
+
393
+ 使用概率融合而不是硬投票的原因:
394
+
395
+ ```text
396
+ 可以保留模型置信度
397
+ 对边界和混淆区域更平滑
398
+ 高置信模型可以纠正低置信模型
399
+ ```
400
+
401
+ ## 11. TTA 推理
402
+
403
+ 当前使用:
404
+
405
+ ```text
406
+ 原图
407
+ 水平翻转
408
+ ```
409
+
410
+ 流程:
411
+
412
+ ```text
413
+ 1. 原图推理得到概率
414
+ 2. 水平翻转图像推理
415
+ 3. 将翻转预测翻回原方向
416
+ 4. 对概率求平均
417
+ ```
418
+
419
+ TTA 可以降低方向相关误差,提升预测稳定性。
420
+
421
+ ## 12. mIoU 计算原理
422
+
423
+ 对每个类别 c:
424
+
425
+ ```text
426
+ TP_c:预测为 c 且真值为 c 的像素数
427
+ FP_c:预测为 c 但真值不是 c 的像素数
428
+ FN_c:真值为 c 但预测不是 c 的像素数
429
+ ```
430
+
431
+ 类别 IoU:
432
+
433
+ ```text
434
+ IoU_c = TP_c / (TP_c + FP_c + FN_c)
435
+ ```
436
+
437
+ 最终:
438
+
439
+ ```text
440
+ mIoU = mean(IoU_0, IoU_1, IoU_2, IoU_3)
441
+ ```
442
+
443
+ 这里的“区域”是同一类别的像素集合,不是实例框、连通块或单独目标实例。
444
+
445
+ ## 13. 本地 test mask 说明
446
+
447
+ `data_fresh/test_raw/PrecisionLabel800/mask` 是 RGB 彩色图,不是标准单通道标签。
448
+
449
+ 统计到的颜色:
450
+
451
+ ```text
452
+ (0, 0, 0)
453
+ (240, 110, 170)
454
+ (240, 171, 203)
455
+ (0, 162, 232)
456
+ ```
457
+
458
+ 当前最合理颜色映射:
459
+
460
+ ```text
461
+ (0, 0, 0) -> 0 背景
462
+ (240, 110, 170) -> 1 活珊瑚
463
+ (240, 171, 203) -> 2 死珊瑚
464
+ (0, 162, 232) -> 3 白化珊瑚
465
+ ```
466
+
467
+ 如果该目录不是官方真值,则该结果不能代表平台成绩。
468
+
469
+ ## 14. 复现性设计
470
+
471
+ 为满足 A30 单卡 24G、24 小时内复现,方案做了以下取舍:
472
+
473
+ ```text
474
+ 不使用 5-fold
475
+ 不使用第三个大模型
476
+ 不使用超大输入尺寸
477
+ 不使用测试集伪标签
478
+ 不使用测试集统计更新
479
+ 固定 seed
480
+ 保存固定 train/val split
481
+ 保存 best/latest checkpoint
482
+ 提供完整训练、推理和打包脚本
483
+ ```
484
+
485
+ 推荐复现流程:
486
+
487
+ ```text
488
+ 1. 检查数据
489
+ 2. 下载预训练权重
490
+ 3. 训练 ConvNeXt-L-FPN
491
+ 4. 训练 Mask2Former-Swin-B
492
+ 5. 验证集融合评估
493
+ 6. 测试集融合推理
494
+ 7. 生成 results.zip
495
+ ```
496
+
497
+ ## 15. 代码模块说明
498
+
499
+ ```text
500
+ coral_seg/coral_seg/dataset.py
501
+ ```
502
+
503
+ 负责图像读取、标签读取、数据增强和 Mask2Former 标签格式转换。
504
+
505
+ ```text
506
+ coral_seg/coral_seg/model_convnext_fpn.py
507
+ ```
508
+
509
+ 负责 ConvNeXt-L 骨��和 FPN 解码器。
510
+
511
+ ```text
512
+ coral_seg/coral_seg/losses.py
513
+ ```
514
+
515
+ 负责 CE、Dice、Lovasz 和组合损失。
516
+
517
+ ```text
518
+ coral_seg/tools/train_convnext.py
519
+ ```
520
+
521
+ 负责 ConvNeXt 分支训练、验证和 checkpoint 保存。
522
+
523
+ ```text
524
+ coral_seg/tools/train_mask2former.py
525
+ ```
526
+
527
+ 负责 Mask2Former 分支训练、验证和 HuggingFace 格式权重保存。
528
+
529
+ ```text
530
+ coral_seg/tools/infer_ensemble.py
531
+ ```
532
+
533
+ 负责双模型 TTA 推理、概率融合、PNG 输出和 `results.zip` 生成。
534
+
535
+ ```text
536
+ coral_seg/tools/eval_ensemble_val.py
537
+ ```
538
+
539
+ 负责验证集双模型融合 mIoU 计算。
540
+
541
+ ```text
542
+ coral_seg/tools/eval_predictions.py
543
+ ```
544
+
545
+ 负责已有预测和标签目录之间的 mIoU 计算,支持 RGB 标签颜色映射。
546
+
547
+ ```text
548
+ coral_seg/tools/visualize_results.py
549
+ ```
550
+
551
+ 负责预测结果彩色化和叠加可视化。
552
+
553
+ ## 16. 可提升方向
554
+
555
+ 如果后续还有时间,可以尝试:
556
+
557
+ ```text
558
+ 调整融合权重,例如 0.50/0.50 或 0.60/0.40
559
+ 对白化珊瑚增加类别权重
560
+ 增加轻量多尺度 TTA
561
+ 人工清洗明显错误标签
562
+ 最终阶段使用 train_full.txt 全量复训
563
+ 后处理去除极小孤立区域
564
+ ```
565
+
566
+ 正式复现阶段应优先保持当前稳定配置,避免引入不可控变量。
coral_seg/logs/convnext_train.log ADDED
The diff for this file is too large to render. See raw diff
 
coral_seg/logs/mask2former_train.log ADDED
The diff for this file is too large to render. See raw diff
 
coral_seg/pretrained/convnext_large-ea097f82.pth ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:ea097f822cdb2cab40905cec3949f4bdf6d6bf1d546c3ec5e43f0b1c6275e144
3
+ size 791189585
coral_seg/pretrained/mask2former-swin-base-ade-semantic/.gitattributes ADDED
@@ -0,0 +1,34 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ *.7z filter=lfs diff=lfs merge=lfs -text
2
+ *.arrow filter=lfs diff=lfs merge=lfs -text
3
+ *.bin filter=lfs diff=lfs merge=lfs -text
4
+ *.bz2 filter=lfs diff=lfs merge=lfs -text
5
+ *.ckpt filter=lfs diff=lfs merge=lfs -text
6
+ *.ftz filter=lfs diff=lfs merge=lfs -text
7
+ *.gz filter=lfs diff=lfs merge=lfs -text
8
+ *.h5 filter=lfs diff=lfs merge=lfs -text
9
+ *.joblib filter=lfs diff=lfs merge=lfs -text
10
+ *.lfs.* filter=lfs diff=lfs merge=lfs -text
11
+ *.mlmodel filter=lfs diff=lfs merge=lfs -text
12
+ *.model filter=lfs diff=lfs merge=lfs -text
13
+ *.msgpack filter=lfs diff=lfs merge=lfs -text
14
+ *.npy filter=lfs diff=lfs merge=lfs -text
15
+ *.npz filter=lfs diff=lfs merge=lfs -text
16
+ *.onnx filter=lfs diff=lfs merge=lfs -text
17
+ *.ot filter=lfs diff=lfs merge=lfs -text
18
+ *.parquet filter=lfs diff=lfs merge=lfs -text
19
+ *.pb filter=lfs diff=lfs merge=lfs -text
20
+ *.pickle filter=lfs diff=lfs merge=lfs -text
21
+ *.pkl filter=lfs diff=lfs merge=lfs -text
22
+ *.pt filter=lfs diff=lfs merge=lfs -text
23
+ *.pth filter=lfs diff=lfs merge=lfs -text
24
+ *.rar filter=lfs diff=lfs merge=lfs -text
25
+ *.safetensors filter=lfs diff=lfs merge=lfs -text
26
+ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
27
+ *.tar.* filter=lfs diff=lfs merge=lfs -text
28
+ *.tflite filter=lfs diff=lfs merge=lfs -text
29
+ *.tgz filter=lfs diff=lfs merge=lfs -text
30
+ *.wasm filter=lfs diff=lfs merge=lfs -text
31
+ *.xz filter=lfs diff=lfs merge=lfs -text
32
+ *.zip filter=lfs diff=lfs merge=lfs -text
33
+ *.zst filter=lfs diff=lfs merge=lfs -text
34
+ *tfevents* filter=lfs diff=lfs merge=lfs -text
coral_seg/pretrained/mask2former-swin-base-ade-semantic/config.json ADDED
@@ -0,0 +1,454 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_commit_hash": null,
3
+ "activation_function": "relu",
4
+ "architectures": [
5
+ "Mask2FormerForUniversalSegmentation"
6
+ ],
7
+ "backbone_config": {
8
+ "_name_or_path": "",
9
+ "add_cross_attention": false,
10
+ "architectures": null,
11
+ "attention_probs_dropout_prob": 0.0,
12
+ "bad_words_ids": null,
13
+ "begin_suppress_tokens": null,
14
+ "bos_token_id": null,
15
+ "chunk_size_feed_forward": 0,
16
+ "cross_attention_hidden_size": null,
17
+ "decoder_start_token_id": null,
18
+ "depths": [
19
+ 2,
20
+ 2,
21
+ 18,
22
+ 2
23
+ ],
24
+ "diversity_penalty": 0.0,
25
+ "do_sample": false,
26
+ "drop_path_rate": 0.3,
27
+ "early_stopping": false,
28
+ "embed_dim": 128,
29
+ "encoder_no_repeat_ngram_size": 0,
30
+ "encoder_stride": 32,
31
+ "eos_token_id": null,
32
+ "exponential_decay_length_penalty": null,
33
+ "finetuning_task": null,
34
+ "forced_bos_token_id": null,
35
+ "forced_eos_token_id": null,
36
+ "hidden_act": "gelu",
37
+ "hidden_dropout_prob": 0.0,
38
+ "hidden_size": 1024,
39
+ "id2label": {
40
+ "0": "LABEL_0",
41
+ "1": "LABEL_1"
42
+ },
43
+ "image_size": 224,
44
+ "initializer_range": 0.02,
45
+ "is_decoder": false,
46
+ "is_encoder_decoder": false,
47
+ "label2id": {
48
+ "LABEL_0": 0,
49
+ "LABEL_1": 1
50
+ },
51
+ "layer_norm_eps": 1e-05,
52
+ "length_penalty": 1.0,
53
+ "max_length": 20,
54
+ "min_length": 0,
55
+ "mlp_ratio": 4.0,
56
+ "model_type": "swin",
57
+ "no_repeat_ngram_size": 0,
58
+ "num_beam_groups": 1,
59
+ "num_beams": 1,
60
+ "num_channels": 3,
61
+ "num_heads": [
62
+ 4,
63
+ 8,
64
+ 16,
65
+ 32
66
+ ],
67
+ "num_layers": 4,
68
+ "num_return_sequences": 1,
69
+ "out_features": [
70
+ "stage1",
71
+ "stage2",
72
+ "stage3",
73
+ "stage4"
74
+ ],
75
+ "output_attentions": false,
76
+ "output_hidden_states": false,
77
+ "output_scores": false,
78
+ "pad_token_id": null,
79
+ "patch_size": 4,
80
+ "path_norm": true,
81
+ "prefix": null,
82
+ "problem_type": null,
83
+ "pruned_heads": {},
84
+ "qkv_bias": true,
85
+ "remove_invalid_values": false,
86
+ "repetition_penalty": 1.0,
87
+ "return_dict": true,
88
+ "return_dict_in_generate": false,
89
+ "sep_token_id": null,
90
+ "stage_names": [
91
+ "stem",
92
+ "stage1",
93
+ "stage2",
94
+ "stage3",
95
+ "stage4"
96
+ ],
97
+ "suppress_tokens": null,
98
+ "task_specific_params": null,
99
+ "temperature": 1.0,
100
+ "tf_legacy_loss": false,
101
+ "tie_encoder_decoder": false,
102
+ "tie_word_embeddings": true,
103
+ "tokenizer_class": null,
104
+ "top_k": 50,
105
+ "top_p": 1.0,
106
+ "torch_dtype": null,
107
+ "torchscript": false,
108
+ "transformers_version": "4.26.0.dev0",
109
+ "typical_p": 1.0,
110
+ "use_absolute_embeddings": false,
111
+ "use_bfloat16": false,
112
+ "window_size": 12
113
+ },
114
+ "class_weight": 2.0,
115
+ "common_stride": 4,
116
+ "decoder_layers": 10,
117
+ "dice_weight": 5.0,
118
+ "dim_feedforward": 2048,
119
+ "dropout": 0.0,
120
+ "encoder_feedforward_dim": 1024,
121
+ "encoder_layers": 6,
122
+ "enforce_input_proj": false,
123
+ "enforce_input_projection": false,
124
+ "feature_size": 256,
125
+ "feature_strides": [
126
+ 4,
127
+ 8,
128
+ 16,
129
+ 32
130
+ ],
131
+ "hidden_dim": 256,
132
+ "id2label": {
133
+ "0": "wall",
134
+ "1": "building",
135
+ "2": "sky",
136
+ "3": "floor",
137
+ "4": "tree",
138
+ "5": "ceiling",
139
+ "6": "road",
140
+ "7": "bed ",
141
+ "8": "windowpane",
142
+ "9": "grass",
143
+ "10": "cabinet",
144
+ "11": "sidewalk",
145
+ "12": "person",
146
+ "13": "earth",
147
+ "14": "door",
148
+ "15": "table",
149
+ "16": "mountain",
150
+ "17": "plant",
151
+ "18": "curtain",
152
+ "19": "chair",
153
+ "20": "car",
154
+ "21": "water",
155
+ "22": "painting",
156
+ "23": "sofa",
157
+ "24": "shelf",
158
+ "25": "house",
159
+ "26": "sea",
160
+ "27": "mirror",
161
+ "28": "rug",
162
+ "29": "field",
163
+ "30": "armchair",
164
+ "31": "seat",
165
+ "32": "fence",
166
+ "33": "desk",
167
+ "34": "rock",
168
+ "35": "wardrobe",
169
+ "36": "lamp",
170
+ "37": "bathtub",
171
+ "38": "railing",
172
+ "39": "cushion",
173
+ "40": "base",
174
+ "41": "box",
175
+ "42": "column",
176
+ "43": "signboard",
177
+ "44": "chest of drawers",
178
+ "45": "counter",
179
+ "46": "sand",
180
+ "47": "sink",
181
+ "48": "skyscraper",
182
+ "49": "fireplace",
183
+ "50": "refrigerator",
184
+ "51": "grandstand",
185
+ "52": "path",
186
+ "53": "stairs",
187
+ "54": "runway",
188
+ "55": "case",
189
+ "56": "pool table",
190
+ "57": "pillow",
191
+ "58": "screen door",
192
+ "59": "stairway",
193
+ "60": "river",
194
+ "61": "bridge",
195
+ "62": "bookcase",
196
+ "63": "blind",
197
+ "64": "coffee table",
198
+ "65": "toilet",
199
+ "66": "flower",
200
+ "67": "book",
201
+ "68": "hill",
202
+ "69": "bench",
203
+ "70": "countertop",
204
+ "71": "stove",
205
+ "72": "palm",
206
+ "73": "kitchen island",
207
+ "74": "computer",
208
+ "75": "swivel chair",
209
+ "76": "boat",
210
+ "77": "bar",
211
+ "78": "arcade machine",
212
+ "79": "hovel",
213
+ "80": "bus",
214
+ "81": "towel",
215
+ "82": "light",
216
+ "83": "truck",
217
+ "84": "tower",
218
+ "85": "chandelier",
219
+ "86": "awning",
220
+ "87": "streetlight",
221
+ "88": "booth",
222
+ "89": "television receiver",
223
+ "90": "airplane",
224
+ "91": "dirt track",
225
+ "92": "apparel",
226
+ "93": "pole",
227
+ "94": "land",
228
+ "95": "bannister",
229
+ "96": "escalator",
230
+ "97": "ottoman",
231
+ "98": "bottle",
232
+ "99": "buffet",
233
+ "100": "poster",
234
+ "101": "stage",
235
+ "102": "van",
236
+ "103": "ship",
237
+ "104": "fountain",
238
+ "105": "conveyer belt",
239
+ "106": "canopy",
240
+ "107": "washer",
241
+ "108": "plaything",
242
+ "109": "swimming pool",
243
+ "110": "stool",
244
+ "111": "barrel",
245
+ "112": "basket",
246
+ "113": "waterfall",
247
+ "114": "tent",
248
+ "115": "bag",
249
+ "116": "minibike",
250
+ "117": "cradle",
251
+ "118": "oven",
252
+ "119": "ball",
253
+ "120": "food",
254
+ "121": "step",
255
+ "122": "tank",
256
+ "123": "trade name",
257
+ "124": "microwave",
258
+ "125": "pot",
259
+ "126": "animal",
260
+ "127": "bicycle",
261
+ "128": "lake",
262
+ "129": "dishwasher",
263
+ "130": "screen",
264
+ "131": "blanket",
265
+ "132": "sculpture",
266
+ "133": "hood",
267
+ "134": "sconce",
268
+ "135": "vase",
269
+ "136": "traffic light",
270
+ "137": "tray",
271
+ "138": "ashcan",
272
+ "139": "fan",
273
+ "140": "pier",
274
+ "141": "crt screen",
275
+ "142": "plate",
276
+ "143": "monitor",
277
+ "144": "bulletin board",
278
+ "145": "shower",
279
+ "146": "radiator",
280
+ "147": "glass",
281
+ "148": "clock",
282
+ "149": "flag"
283
+ },
284
+ "ignore_value": 255,
285
+ "importance_sample_ratio": 0.75,
286
+ "init_std": 0.02,
287
+ "init_xavier_std": 1.0,
288
+ "label2id": {
289
+ "airplane": 90,
290
+ "animal": 126,
291
+ "apparel": 92,
292
+ "arcade machine": 78,
293
+ "armchair": 30,
294
+ "ashcan": 138,
295
+ "awning": 86,
296
+ "bag": 115,
297
+ "ball": 119,
298
+ "bannister": 95,
299
+ "bar": 77,
300
+ "barrel": 111,
301
+ "base": 40,
302
+ "basket": 112,
303
+ "bathtub": 37,
304
+ "bed ": 7,
305
+ "bench": 69,
306
+ "bicycle": 127,
307
+ "blanket": 131,
308
+ "blind": 63,
309
+ "boat": 76,
310
+ "book": 67,
311
+ "bookcase": 62,
312
+ "booth": 88,
313
+ "bottle": 98,
314
+ "box": 41,
315
+ "bridge": 61,
316
+ "buffet": 99,
317
+ "building": 1,
318
+ "bulletin board": 144,
319
+ "bus": 80,
320
+ "cabinet": 10,
321
+ "canopy": 106,
322
+ "car": 20,
323
+ "case": 55,
324
+ "ceiling": 5,
325
+ "chair": 19,
326
+ "chandelier": 85,
327
+ "chest of drawers": 44,
328
+ "clock": 148,
329
+ "coffee table": 64,
330
+ "column": 42,
331
+ "computer": 74,
332
+ "conveyer belt": 105,
333
+ "counter": 45,
334
+ "countertop": 70,
335
+ "cradle": 117,
336
+ "crt screen": 141,
337
+ "curtain": 18,
338
+ "cushion": 39,
339
+ "desk": 33,
340
+ "dirt track": 91,
341
+ "dishwasher": 129,
342
+ "door": 14,
343
+ "earth": 13,
344
+ "escalator": 96,
345
+ "fan": 139,
346
+ "fence": 32,
347
+ "field": 29,
348
+ "fireplace": 49,
349
+ "flag": 149,
350
+ "floor": 3,
351
+ "flower": 66,
352
+ "food": 120,
353
+ "fountain": 104,
354
+ "glass": 147,
355
+ "grandstand": 51,
356
+ "grass": 9,
357
+ "hill": 68,
358
+ "hood": 133,
359
+ "house": 25,
360
+ "hovel": 79,
361
+ "kitchen island": 73,
362
+ "lake": 128,
363
+ "lamp": 36,
364
+ "land": 94,
365
+ "light": 82,
366
+ "microwave": 124,
367
+ "minibike": 116,
368
+ "mirror": 27,
369
+ "monitor": 143,
370
+ "mountain": 16,
371
+ "ottoman": 97,
372
+ "oven": 118,
373
+ "painting": 22,
374
+ "palm": 72,
375
+ "path": 52,
376
+ "person": 12,
377
+ "pier": 140,
378
+ "pillow": 57,
379
+ "plant": 17,
380
+ "plate": 142,
381
+ "plaything": 108,
382
+ "pole": 93,
383
+ "pool table": 56,
384
+ "poster": 100,
385
+ "pot": 125,
386
+ "radiator": 146,
387
+ "railing": 38,
388
+ "refrigerator": 50,
389
+ "river": 60,
390
+ "road": 6,
391
+ "rock": 34,
392
+ "rug": 28,
393
+ "runway": 54,
394
+ "sand": 46,
395
+ "sconce": 134,
396
+ "screen": 130,
397
+ "screen door": 58,
398
+ "sculpture": 132,
399
+ "sea": 26,
400
+ "seat": 31,
401
+ "shelf": 24,
402
+ "ship": 103,
403
+ "shower": 145,
404
+ "sidewalk": 11,
405
+ "signboard": 43,
406
+ "sink": 47,
407
+ "sky": 2,
408
+ "skyscraper": 48,
409
+ "sofa": 23,
410
+ "stage": 101,
411
+ "stairs": 53,
412
+ "stairway": 59,
413
+ "step": 121,
414
+ "stool": 110,
415
+ "stove": 71,
416
+ "streetlight": 87,
417
+ "swimming pool": 109,
418
+ "swivel chair": 75,
419
+ "table": 15,
420
+ "tank": 122,
421
+ "television receiver": 89,
422
+ "tent": 114,
423
+ "toilet": 65,
424
+ "towel": 81,
425
+ "tower": 84,
426
+ "trade name": 123,
427
+ "traffic light": 136,
428
+ "tray": 137,
429
+ "tree": 4,
430
+ "truck": 83,
431
+ "van": 102,
432
+ "vase": 135,
433
+ "wall": 0,
434
+ "wardrobe": 35,
435
+ "washer": 107,
436
+ "water": 21,
437
+ "waterfall": 113,
438
+ "windowpane": 8
439
+ },
440
+ "mask_feature_size": 256,
441
+ "mask_weight": 5.0,
442
+ "model_type": "mask2former",
443
+ "no_object_weight": 0.1,
444
+ "num_attention_heads": 8,
445
+ "num_hidden_layers": 10,
446
+ "num_queries": 100,
447
+ "output_auxiliary_logits": null,
448
+ "oversample_ratio": 3.0,
449
+ "pre_norm": false,
450
+ "torch_dtype": "float32",
451
+ "train_num_points": 12544,
452
+ "transformers_version": null,
453
+ "use_auxiliary_loss": true
454
+ }
coral_seg/pretrained/mask2former-swin-base-ade-semantic/model.safetensors ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:09e2ba3efa9f18fa6a313c88ef7d862fc15da10ddb4bbc034df54160089e130e
3
+ size 431785608
coral_seg/pretrained/mask2former-swin-base-ade-semantic/preprocessor_config.json ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ {
2
+ "_max_size": 2560,
3
+ "do_normalize": true,
4
+ "do_rescale": true,
5
+ "do_resize": true,
6
+ "ignore_index": 255,
7
+ "image_mean": [
8
+ 0.48500001430511475,
9
+ 0.4560000002384186,
10
+ 0.4059999883174896
11
+ ],
12
+ "image_processor_type": "Mask2FormerImageProcessor",
13
+ "image_std": [
14
+ 0.2290000021457672,
15
+ 0.2239999920129776,
16
+ 0.22499999403953552
17
+ ],
18
+ "num_labels": 150,
19
+ "reduce_labels": false,
20
+ "resample": 2,
21
+ "rescale_factor": 0.00392156862745098,
22
+ "size": {
23
+ "height": 384,
24
+ "width": 384
25
+ },
26
+ "size_divisor": 32
27
+ }
coral_seg/pretrained/mask2former-swin-base-ade-semantic/pytorch_model.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:197bab4870fea7287635f62fe52538a4cf053767ddd0f2c9cb7611deca618f1d
3
+ size 431950789
coral_seg/requirements.txt ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ torch==2.3.0
2
+ torchvision==0.18.0
3
+ transformers==4.46.3
4
+ timm==1.0.27
5
+ albumentations==2.0.8
6
+ opencv-python-headless==4.13.0.92
7
+ safetensors==0.8.0
8
+ accelerate==1.14.0
9
+ numpy>=1.26
10
+ Pillow>=10.0
11
+ PyYAML>=6.0
coral_seg/splits/train.txt ADDED
@@ -0,0 +1,2550 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0000
2
+ 0001
3
+ 0002
4
+ 0004
5
+ 0005
6
+ 0006
7
+ 0007
8
+ 0009
9
+ 0011
10
+ 0012
11
+ 0013
12
+ 0015
13
+ 0016
14
+ 0017
15
+ 0018
16
+ 0020
17
+ 0021
18
+ 0022
19
+ 0023
20
+ 0025
21
+ 0026
22
+ 0027
23
+ 0028
24
+ 0030
25
+ 0031
26
+ 0032
27
+ 0033
28
+ 0036
29
+ 0037
30
+ 0038
31
+ 0039
32
+ 0040
33
+ 0041
34
+ 0042
35
+ 0043
36
+ 0044
37
+ 0046
38
+ 0047
39
+ 0049
40
+ 0050
41
+ 0051
42
+ 0052
43
+ 0054
44
+ 0055
45
+ 0056
46
+ 0058
47
+ 0059
48
+ 0060
49
+ 0064
50
+ 0065
51
+ 0067
52
+ 0068
53
+ 0069
54
+ 0070
55
+ 0071
56
+ 0072
57
+ 0073
58
+ 0074
59
+ 0075
60
+ 0076
61
+ 0077
62
+ 0078
63
+ 0080
64
+ 0081
65
+ 0082
66
+ 0083
67
+ 0085
68
+ 0086
69
+ 0087
70
+ 0088
71
+ 0089
72
+ 0090
73
+ 0091
74
+ 0092
75
+ 0093
76
+ 0094
77
+ 0095
78
+ 0096
79
+ 0097
80
+ 0098
81
+ 0100
82
+ 0101
83
+ 0102
84
+ 0103
85
+ 0105
86
+ 0107
87
+ 0108
88
+ 0110
89
+ 0111
90
+ 0113
91
+ 0114
92
+ 0115
93
+ 0116
94
+ 0117
95
+ 0118
96
+ 0119
97
+ 0120
98
+ 0121
99
+ 0122
100
+ 0123
101
+ 0124
102
+ 0125
103
+ 0126
104
+ 0127
105
+ 0128
106
+ 0129
107
+ 0131
108
+ 0132
109
+ 0133
110
+ 0134
111
+ 0137
112
+ 0138
113
+ 0139
114
+ 0140
115
+ 0141
116
+ 0142
117
+ 0143
118
+ 0144
119
+ 0145
120
+ 0146
121
+ 0148
122
+ 0149
123
+ 0150
124
+ 0151
125
+ 0152
126
+ 0153
127
+ 0154
128
+ 0155
129
+ 0156
130
+ 0157
131
+ 0158
132
+ 0159
133
+ 0160
134
+ 0162
135
+ 0163
136
+ 0164
137
+ 0165
138
+ 0166
139
+ 0168
140
+ 0169
141
+ 0170
142
+ 0171
143
+ 0172
144
+ 0174
145
+ 0175
146
+ 0176
147
+ 0178
148
+ 0179
149
+ 0180
150
+ 0181
151
+ 0182
152
+ 0183
153
+ 0184
154
+ 0185
155
+ 0186
156
+ 0187
157
+ 0188
158
+ 0189
159
+ 0190
160
+ 0191
161
+ 0192
162
+ 0193
163
+ 0194
164
+ 0195
165
+ 0197
166
+ 0198
167
+ 0199
168
+ 0200
169
+ 0201
170
+ 0202
171
+ 0203
172
+ 0204
173
+ 0205
174
+ 0206
175
+ 0208
176
+ 0209
177
+ 0210
178
+ 0211
179
+ 0212
180
+ 0213
181
+ 0214
182
+ 0215
183
+ 0216
184
+ 0217
185
+ 0218
186
+ 0219
187
+ 0220
188
+ 0221
189
+ 0222
190
+ 0224
191
+ 0225
192
+ 0227
193
+ 0228
194
+ 0229
195
+ 0230
196
+ 0231
197
+ 0232
198
+ 0233
199
+ 0234
200
+ 0235
201
+ 0236
202
+ 0237
203
+ 0238
204
+ 0239
205
+ 0240
206
+ 0241
207
+ 0242
208
+ 0243
209
+ 0244
210
+ 0245
211
+ 0246
212
+ 0247
213
+ 0248
214
+ 0249
215
+ 0250
216
+ 0251
217
+ 0252
218
+ 0253
219
+ 0254
220
+ 0255
221
+ 0256
222
+ 0257
223
+ 0258
224
+ 0259
225
+ 0260
226
+ 0261
227
+ 0262
228
+ 0263
229
+ 0264
230
+ 0265
231
+ 0266
232
+ 0267
233
+ 0268
234
+ 0269
235
+ 0270
236
+ 0273
237
+ 0274
238
+ 0275
239
+ 0277
240
+ 0278
241
+ 0279
242
+ 0281
243
+ 0282
244
+ 0283
245
+ 0284
246
+ 0285
247
+ 0286
248
+ 0287
249
+ 0288
250
+ 0289
251
+ 0290
252
+ 0292
253
+ 0293
254
+ 0294
255
+ 0295
256
+ 0296
257
+ 0297
258
+ 0298
259
+ 0299
260
+ 0300
261
+ 0302
262
+ 0303
263
+ 0304
264
+ 0305
265
+ 0306
266
+ 0307
267
+ 0308
268
+ 0309
269
+ 0310
270
+ 0311
271
+ 0312
272
+ 0313
273
+ 0314
274
+ 0315
275
+ 0316
276
+ 0317
277
+ 0318
278
+ 0319
279
+ 0320
280
+ 0321
281
+ 0322
282
+ 0323
283
+ 0325
284
+ 0326
285
+ 0327
286
+ 0328
287
+ 0329
288
+ 0330
289
+ 0331
290
+ 0332
291
+ 0334
292
+ 0336
293
+ 0337
294
+ 0338
295
+ 0339
296
+ 0340
297
+ 0341
298
+ 0342
299
+ 0344
300
+ 0345
301
+ 0346
302
+ 0349
303
+ 0351
304
+ 0352
305
+ 0355
306
+ 0356
307
+ 0357
308
+ 0358
309
+ 0359
310
+ 0361
311
+ 0362
312
+ 0364
313
+ 0365
314
+ 0366
315
+ 0367
316
+ 0368
317
+ 0371
318
+ 0372
319
+ 0373
320
+ 0374
321
+ 0375
322
+ 0376
323
+ 0377
324
+ 0379
325
+ 0381
326
+ 0382
327
+ 0383
328
+ 0384
329
+ 0385
330
+ 0386
331
+ 0387
332
+ 0388
333
+ 0389
334
+ 0390
335
+ 0391
336
+ 0393
337
+ 0394
338
+ 0395
339
+ 0396
340
+ 0397
341
+ 0398
342
+ 0400
343
+ 0401
344
+ 0402
345
+ 0403
346
+ 0404
347
+ 0405
348
+ 0406
349
+ 0407
350
+ 0408
351
+ 0409
352
+ 0410
353
+ 0411
354
+ 0413
355
+ 0414
356
+ 0415
357
+ 0416
358
+ 0417
359
+ 0418
360
+ 0419
361
+ 0420
362
+ 0421
363
+ 0422
364
+ 0423
365
+ 0424
366
+ 0425
367
+ 0426
368
+ 0427
369
+ 0429
370
+ 0430
371
+ 0431
372
+ 0432
373
+ 0434
374
+ 0436
375
+ 0437
376
+ 0438
377
+ 0439
378
+ 0440
379
+ 0441
380
+ 0442
381
+ 0443
382
+ 0445
383
+ 0446
384
+ 0447
385
+ 0448
386
+ 0449
387
+ 0451
388
+ 0452
389
+ 0453
390
+ 0454
391
+ 0455
392
+ 0456
393
+ 0457
394
+ 0458
395
+ 0459
396
+ 0460
397
+ 0461
398
+ 0463
399
+ 0464
400
+ 0465
401
+ 0466
402
+ 0467
403
+ 0468
404
+ 0469
405
+ 0471
406
+ 0472
407
+ 0473
408
+ 0474
409
+ 0475
410
+ 0476
411
+ 0477
412
+ 0478
413
+ 0479
414
+ 0480
415
+ 0481
416
+ 0482
417
+ 0483
418
+ 0484
419
+ 0486
420
+ 0487
421
+ 0488
422
+ 0490
423
+ 0491
424
+ 0492
425
+ 0493
426
+ 0495
427
+ 0496
428
+ 0498
429
+ 0500
430
+ 0501
431
+ 0502
432
+ 0503
433
+ 0504
434
+ 0505
435
+ 0506
436
+ 0508
437
+ 0509
438
+ 0510
439
+ 0511
440
+ 0512
441
+ 0513
442
+ 0515
443
+ 0516
444
+ 0517
445
+ 0518
446
+ 0519
447
+ 0520
448
+ 0521
449
+ 0522
450
+ 0523
451
+ 0524
452
+ 0525
453
+ 0526
454
+ 0528
455
+ 0529
456
+ 0531
457
+ 0532
458
+ 0534
459
+ 0535
460
+ 0536
461
+ 0537
462
+ 0538
463
+ 0539
464
+ 0540
465
+ 0542
466
+ 0543
467
+ 0545
468
+ 0546
469
+ 0548
470
+ 0549
471
+ 0550
472
+ 0551
473
+ 0554
474
+ 0556
475
+ 0557
476
+ 0558
477
+ 0559
478
+ 0560
479
+ 0561
480
+ 0562
481
+ 0563
482
+ 0564
483
+ 0565
484
+ 0566
485
+ 0567
486
+ 0568
487
+ 0569
488
+ 0571
489
+ 0572
490
+ 0573
491
+ 0574
492
+ 0575
493
+ 0576
494
+ 0577
495
+ 0578
496
+ 0579
497
+ 0580
498
+ 0581
499
+ 0582
500
+ 0583
501
+ 0584
502
+ 0585
503
+ 0586
504
+ 0588
505
+ 0589
506
+ 0590
507
+ 0591
508
+ 0592
509
+ 0594
510
+ 0595
511
+ 0596
512
+ 0597
513
+ 0598
514
+ 0599
515
+ 0600
516
+ 0601
517
+ 0602
518
+ 0603
519
+ 0604
520
+ 0605
521
+ 0606
522
+ 0607
523
+ 0608
524
+ 0609
525
+ 0610
526
+ 0611
527
+ 0613
528
+ 0614
529
+ 0615
530
+ 0616
531
+ 0617
532
+ 0618
533
+ 0619
534
+ 0620
535
+ 0621
536
+ 0622
537
+ 0623
538
+ 0624
539
+ 0625
540
+ 0626
541
+ 0627
542
+ 0628
543
+ 0629
544
+ 0630
545
+ 0631
546
+ 0632
547
+ 0633
548
+ 0634
549
+ 0635
550
+ 0636
551
+ 0637
552
+ 0638
553
+ 0639
554
+ 0640
555
+ 0642
556
+ 0643
557
+ 0644
558
+ 0645
559
+ 0646
560
+ 0647
561
+ 0648
562
+ 0649
563
+ 0650
564
+ 0651
565
+ 0652
566
+ 0653
567
+ 0654
568
+ 0655
569
+ 0656
570
+ 0657
571
+ 0658
572
+ 0660
573
+ 0661
574
+ 0662
575
+ 0663
576
+ 0664
577
+ 0665
578
+ 0666
579
+ 0667
580
+ 0668
581
+ 0669
582
+ 0671
583
+ 0672
584
+ 0673
585
+ 0674
586
+ 0675
587
+ 0676
588
+ 0677
589
+ 0678
590
+ 0679
591
+ 0680
592
+ 0681
593
+ 0682
594
+ 0683
595
+ 0684
596
+ 0685
597
+ 0686
598
+ 0688
599
+ 0689
600
+ 0690
601
+ 0691
602
+ 0692
603
+ 0693
604
+ 0696
605
+ 0697
606
+ 0698
607
+ 0699
608
+ 0700
609
+ 0701
610
+ 0702
611
+ 0704
612
+ 0705
613
+ 0706
614
+ 0707
615
+ 0708
616
+ 0709
617
+ 0710
618
+ 0711
619
+ 0712
620
+ 0713
621
+ 0714
622
+ 0715
623
+ 0716
624
+ 0718
625
+ 0719
626
+ 0721
627
+ 0722
628
+ 0723
629
+ 0725
630
+ 0726
631
+ 0727
632
+ 0728
633
+ 0729
634
+ 0731
635
+ 0732
636
+ 0733
637
+ 0734
638
+ 0735
639
+ 0736
640
+ 0737
641
+ 0740
642
+ 0741
643
+ 0742
644
+ 0743
645
+ 0744
646
+ 0745
647
+ 0746
648
+ 0747
649
+ 0748
650
+ 0749
651
+ 0750
652
+ 0751
653
+ 0752
654
+ 0754
655
+ 0755
656
+ 0756
657
+ 0759
658
+ 0760
659
+ 0761
660
+ 0762
661
+ 0763
662
+ 0764
663
+ 0765
664
+ 0768
665
+ 0769
666
+ 0770
667
+ 0771
668
+ 0772
669
+ 0773
670
+ 0774
671
+ 0775
672
+ 0776
673
+ 0777
674
+ 0778
675
+ 0780
676
+ 0781
677
+ 0782
678
+ 0783
679
+ 0784
680
+ 0786
681
+ 0787
682
+ 0789
683
+ 0790
684
+ 0791
685
+ 0792
686
+ 0794
687
+ 0795
688
+ 0796
689
+ 0797
690
+ 0799
691
+ 0800
692
+ 0801
693
+ 0802
694
+ 0803
695
+ 0804
696
+ 0805
697
+ 0806
698
+ 0807
699
+ 0809
700
+ 0810
701
+ 0811
702
+ 0812
703
+ 0816
704
+ 0817
705
+ 0818
706
+ 0819
707
+ 0820
708
+ 0821
709
+ 0823
710
+ 0824
711
+ 0826
712
+ 0827
713
+ 0828
714
+ 0829
715
+ 0831
716
+ 0832
717
+ 0833
718
+ 0835
719
+ 0836
720
+ 0837
721
+ 0838
722
+ 0839
723
+ 0840
724
+ 0841
725
+ 0842
726
+ 0843
727
+ 0844
728
+ 0845
729
+ 0846
730
+ 0847
731
+ 0848
732
+ 0849
733
+ 0850
734
+ 0852
735
+ 0854
736
+ 0855
737
+ 0856
738
+ 0857
739
+ 0858
740
+ 0859
741
+ 0860
742
+ 0861
743
+ 0862
744
+ 0863
745
+ 0864
746
+ 0865
747
+ 0866
748
+ 0867
749
+ 0869
750
+ 0870
751
+ 0871
752
+ 0873
753
+ 0874
754
+ 0875
755
+ 0876
756
+ 0877
757
+ 0878
758
+ 0879
759
+ 0880
760
+ 0881
761
+ 0883
762
+ 0884
763
+ 0885
764
+ 0886
765
+ 0888
766
+ 0890
767
+ 0891
768
+ 0892
769
+ 0893
770
+ 0895
771
+ 0896
772
+ 0898
773
+ 0899
774
+ 0900
775
+ 0902
776
+ 0903
777
+ 0904
778
+ 0905
779
+ 0907
780
+ 0908
781
+ 0910
782
+ 0911
783
+ 0913
784
+ 0914
785
+ 0917
786
+ 0918
787
+ 0919
788
+ 0920
789
+ 0921
790
+ 0922
791
+ 0923
792
+ 0924
793
+ 0927
794
+ 0928
795
+ 0929
796
+ 0931
797
+ 0932
798
+ 0933
799
+ 0934
800
+ 0935
801
+ 0936
802
+ 0937
803
+ 0938
804
+ 0939
805
+ 0940
806
+ 0941
807
+ 0942
808
+ 0943
809
+ 0944
810
+ 0945
811
+ 0946
812
+ 0947
813
+ 0948
814
+ 0949
815
+ 0950
816
+ 0951
817
+ 0954
818
+ 0955
819
+ 0957
820
+ 0958
821
+ 0959
822
+ 0960
823
+ 0962
824
+ 0963
825
+ 0964
826
+ 0966
827
+ 0967
828
+ 0968
829
+ 0969
830
+ 0972
831
+ 0973
832
+ 0974
833
+ 0975
834
+ 0976
835
+ 0979
836
+ 0980
837
+ 0981
838
+ 0982
839
+ 0983
840
+ 0984
841
+ 0985
842
+ 0986
843
+ 0987
844
+ 0988
845
+ 0990
846
+ 0991
847
+ 0992
848
+ 0993
849
+ 0994
850
+ 0995
851
+ 0996
852
+ 0997
853
+ 0998
854
+ 0999
855
+ 1000
856
+ 1001
857
+ 1002
858
+ 1003
859
+ 1004
860
+ 1005
861
+ 1006
862
+ 1007
863
+ 1008
864
+ 1009
865
+ 1010
866
+ 1011
867
+ 1012
868
+ 1013
869
+ 1014
870
+ 1015
871
+ 1016
872
+ 1017
873
+ 1018
874
+ 1019
875
+ 1022
876
+ 1024
877
+ 1025
878
+ 1026
879
+ 1027
880
+ 1028
881
+ 1029
882
+ 1030
883
+ 1031
884
+ 1032
885
+ 1033
886
+ 1034
887
+ 1035
888
+ 1036
889
+ 1037
890
+ 1038
891
+ 1039
892
+ 1040
893
+ 1041
894
+ 1042
895
+ 1043
896
+ 1044
897
+ 1046
898
+ 1047
899
+ 1048
900
+ 1050
901
+ 1053
902
+ 1054
903
+ 1056
904
+ 1057
905
+ 1058
906
+ 1059
907
+ 1061
908
+ 1062
909
+ 1063
910
+ 1065
911
+ 1066
912
+ 1068
913
+ 1070
914
+ 1071
915
+ 1072
916
+ 1073
917
+ 1074
918
+ 1075
919
+ 1076
920
+ 1077
921
+ 1078
922
+ 1080
923
+ 1081
924
+ 1082
925
+ 1083
926
+ 1084
927
+ 1085
928
+ 1086
929
+ 1087
930
+ 1088
931
+ 1089
932
+ 1090
933
+ 1092
934
+ 1093
935
+ 1094
936
+ 1095
937
+ 1096
938
+ 1097
939
+ 1098
940
+ 1100
941
+ 1101
942
+ 1103
943
+ 1104
944
+ 1105
945
+ 1107
946
+ 1109
947
+ 1112
948
+ 1114
949
+ 1115
950
+ 1116
951
+ 1117
952
+ 1119
953
+ 1120
954
+ 1122
955
+ 1125
956
+ 1126
957
+ 1127
958
+ 1128
959
+ 1129
960
+ 1130
961
+ 1131
962
+ 1132
963
+ 1133
964
+ 1134
965
+ 1135
966
+ 1136
967
+ 1138
968
+ 1139
969
+ 1142
970
+ 1143
971
+ 1144
972
+ 1145
973
+ 1146
974
+ 1147
975
+ 1148
976
+ 1149
977
+ 1150
978
+ 1151
979
+ 1152
980
+ 1153
981
+ 1154
982
+ 1155
983
+ 1156
984
+ 1157
985
+ 1158
986
+ 1159
987
+ 1160
988
+ 1161
989
+ 1163
990
+ 1164
991
+ 1165
992
+ 1166
993
+ 1167
994
+ 1168
995
+ 1171
996
+ 1172
997
+ 1173
998
+ 1174
999
+ 1175
1000
+ 1177
1001
+ 1179
1002
+ 1181
1003
+ 1182
1004
+ 1183
1005
+ 1184
1006
+ 1186
1007
+ 1187
1008
+ 1188
1009
+ 1189
1010
+ 1190
1011
+ 1191
1012
+ 1192
1013
+ 1193
1014
+ 1194
1015
+ 1195
1016
+ 1196
1017
+ 1198
1018
+ 1200
1019
+ 1201
1020
+ 1203
1021
+ 1205
1022
+ 1207
1023
+ 1208
1024
+ 1209
1025
+ 1210
1026
+ 1211
1027
+ 1212
1028
+ 1213
1029
+ 1214
1030
+ 1215
1031
+ 1216
1032
+ 1217
1033
+ 1218
1034
+ 1219
1035
+ 1220
1036
+ 1221
1037
+ 1222
1038
+ 1223
1039
+ 1224
1040
+ 1225
1041
+ 1226
1042
+ 1227
1043
+ 1228
1044
+ 1229
1045
+ 1230
1046
+ 1231
1047
+ 1232
1048
+ 1233
1049
+ 1234
1050
+ 1236
1051
+ 1237
1052
+ 1238
1053
+ 1239
1054
+ 1240
1055
+ 1241
1056
+ 1243
1057
+ 1244
1058
+ 1245
1059
+ 1246
1060
+ 1247
1061
+ 1248
1062
+ 1249
1063
+ 1250
1064
+ 1252
1065
+ 1253
1066
+ 1254
1067
+ 1255
1068
+ 1256
1069
+ 1257
1070
+ 1258
1071
+ 1259
1072
+ 1260
1073
+ 1261
1074
+ 1262
1075
+ 1264
1076
+ 1265
1077
+ 1266
1078
+ 1268
1079
+ 1269
1080
+ 1270
1081
+ 1271
1082
+ 1272
1083
+ 1273
1084
+ 1274
1085
+ 1275
1086
+ 1276
1087
+ 1277
1088
+ 1278
1089
+ 1279
1090
+ 1280
1091
+ 1281
1092
+ 1282
1093
+ 1283
1094
+ 1285
1095
+ 1286
1096
+ 1287
1097
+ 1288
1098
+ 1289
1099
+ 1290
1100
+ 1291
1101
+ 1292
1102
+ 1293
1103
+ 1294
1104
+ 1295
1105
+ 1296
1106
+ 1298
1107
+ 1299
1108
+ 1300
1109
+ 1301
1110
+ 1302
1111
+ 1303
1112
+ 1305
1113
+ 1306
1114
+ 1307
1115
+ 1308
1116
+ 1309
1117
+ 1310
1118
+ 1311
1119
+ 1312
1120
+ 1313
1121
+ 1314
1122
+ 1315
1123
+ 1316
1124
+ 1317
1125
+ 1318
1126
+ 1319
1127
+ 1320
1128
+ 1321
1129
+ 1322
1130
+ 1323
1131
+ 1324
1132
+ 1325
1133
+ 1326
1134
+ 1327
1135
+ 1328
1136
+ 1329
1137
+ 1330
1138
+ 1332
1139
+ 1333
1140
+ 1334
1141
+ 1335
1142
+ 1336
1143
+ 1337
1144
+ 1338
1145
+ 1339
1146
+ 1340
1147
+ 1341
1148
+ 1343
1149
+ 1344
1150
+ 1345
1151
+ 1347
1152
+ 1348
1153
+ 1349
1154
+ 1350
1155
+ 1351
1156
+ 1353
1157
+ 1354
1158
+ 1355
1159
+ 1356
1160
+ 1358
1161
+ 1359
1162
+ 1360
1163
+ 1361
1164
+ 1362
1165
+ 1363
1166
+ 1364
1167
+ 1365
1168
+ 1366
1169
+ 1367
1170
+ 1368
1171
+ 1370
1172
+ 1371
1173
+ 1372
1174
+ 1373
1175
+ 1374
1176
+ 1377
1177
+ 1378
1178
+ 1379
1179
+ 1380
1180
+ 1381
1181
+ 1384
1182
+ 1386
1183
+ 1388
1184
+ 1390
1185
+ 1391
1186
+ 1392
1187
+ 1393
1188
+ 1394
1189
+ 1395
1190
+ 1396
1191
+ 1398
1192
+ 1400
1193
+ 1401
1194
+ 1402
1195
+ 1403
1196
+ 1404
1197
+ 1405
1198
+ 1406
1199
+ 1407
1200
+ 1408
1201
+ 1409
1202
+ 1410
1203
+ 1411
1204
+ 1413
1205
+ 1414
1206
+ 1416
1207
+ 1417
1208
+ 1418
1209
+ 1419
1210
+ 1420
1211
+ 1422
1212
+ 1424
1213
+ 1425
1214
+ 1427
1215
+ 1428
1216
+ 1429
1217
+ 1430
1218
+ 1431
1219
+ 1432
1220
+ 1433
1221
+ 1434
1222
+ 1437
1223
+ 1438
1224
+ 1439
1225
+ 1440
1226
+ 1441
1227
+ 1442
1228
+ 1443
1229
+ 1444
1230
+ 1445
1231
+ 1447
1232
+ 1448
1233
+ 1449
1234
+ 1451
1235
+ 1452
1236
+ 1453
1237
+ 1454
1238
+ 1455
1239
+ 1456
1240
+ 1457
1241
+ 1458
1242
+ 1459
1243
+ 1460
1244
+ 1461
1245
+ 1462
1246
+ 1463
1247
+ 1464
1248
+ 1465
1249
+ 1466
1250
+ 1467
1251
+ 1468
1252
+ 1469
1253
+ 1470
1254
+ 1471
1255
+ 1472
1256
+ 1473
1257
+ 1474
1258
+ 1475
1259
+ 1476
1260
+ 1477
1261
+ 1478
1262
+ 1479
1263
+ 1480
1264
+ 1481
1265
+ 1482
1266
+ 1483
1267
+ 1484
1268
+ 1485
1269
+ 1487
1270
+ 1488
1271
+ 1489
1272
+ 1491
1273
+ 1493
1274
+ 1494
1275
+ 1496
1276
+ 1498
1277
+ 1499
1278
+ 1500
1279
+ 1501
1280
+ 1503
1281
+ 1504
1282
+ 1505
1283
+ 1506
1284
+ 1507
1285
+ 1508
1286
+ 1510
1287
+ 1512
1288
+ 1513
1289
+ 1514
1290
+ 1515
1291
+ 1516
1292
+ 1517
1293
+ 1518
1294
+ 1519
1295
+ 1520
1296
+ 1521
1297
+ 1524
1298
+ 1526
1299
+ 1527
1300
+ 1528
1301
+ 1529
1302
+ 1530
1303
+ 1531
1304
+ 1533
1305
+ 1534
1306
+ 1535
1307
+ 1537
1308
+ 1539
1309
+ 1542
1310
+ 1543
1311
+ 1544
1312
+ 1545
1313
+ 1546
1314
+ 1547
1315
+ 1548
1316
+ 1550
1317
+ 1551
1318
+ 1552
1319
+ 1553
1320
+ 1554
1321
+ 1555
1322
+ 1556
1323
+ 1557
1324
+ 1558
1325
+ 1559
1326
+ 1560
1327
+ 1561
1328
+ 1562
1329
+ 1563
1330
+ 1564
1331
+ 1565
1332
+ 1566
1333
+ 1567
1334
+ 1569
1335
+ 1570
1336
+ 1572
1337
+ 1573
1338
+ 1574
1339
+ 1575
1340
+ 1577
1341
+ 1578
1342
+ 1579
1343
+ 1580
1344
+ 1582
1345
+ 1583
1346
+ 1585
1347
+ 1586
1348
+ 1588
1349
+ 1589
1350
+ 1590
1351
+ 1591
1352
+ 1593
1353
+ 1594
1354
+ 1595
1355
+ 1596
1356
+ 1597
1357
+ 1598
1358
+ 1599
1359
+ 1600
1360
+ 1601
1361
+ 1602
1362
+ 1603
1363
+ 1606
1364
+ 1607
1365
+ 1608
1366
+ 1610
1367
+ 1611
1368
+ 1612
1369
+ 1613
1370
+ 1614
1371
+ 1616
1372
+ 1617
1373
+ 1618
1374
+ 1619
1375
+ 1620
1376
+ 1621
1377
+ 1622
1378
+ 1623
1379
+ 1625
1380
+ 1626
1381
+ 1627
1382
+ 1628
1383
+ 1629
1384
+ 1630
1385
+ 1631
1386
+ 1632
1387
+ 1633
1388
+ 1634
1389
+ 1635
1390
+ 1636
1391
+ 1638
1392
+ 1640
1393
+ 1641
1394
+ 1642
1395
+ 1643
1396
+ 1644
1397
+ 1645
1398
+ 1646
1399
+ 1647
1400
+ 1649
1401
+ 1650
1402
+ 1651
1403
+ 1652
1404
+ 1653
1405
+ 1655
1406
+ 1656
1407
+ 1657
1408
+ 1658
1409
+ 1659
1410
+ 1660
1411
+ 1661
1412
+ 1662
1413
+ 1663
1414
+ 1664
1415
+ 1665
1416
+ 1666
1417
+ 1668
1418
+ 1669
1419
+ 1671
1420
+ 1672
1421
+ 1673
1422
+ 1674
1423
+ 1675
1424
+ 1677
1425
+ 1678
1426
+ 1679
1427
+ 1681
1428
+ 1683
1429
+ 1684
1430
+ 1685
1431
+ 1686
1432
+ 1687
1433
+ 1688
1434
+ 1690
1435
+ 1691
1436
+ 1692
1437
+ 1693
1438
+ 1694
1439
+ 1695
1440
+ 1696
1441
+ 1697
1442
+ 1698
1443
+ 1699
1444
+ 1700
1445
+ 1703
1446
+ 1704
1447
+ 1705
1448
+ 1706
1449
+ 1708
1450
+ 1709
1451
+ 1712
1452
+ 1714
1453
+ 1715
1454
+ 1716
1455
+ 1718
1456
+ 1720
1457
+ 1722
1458
+ 1723
1459
+ 1725
1460
+ 1726
1461
+ 1727
1462
+ 1728
1463
+ 1729
1464
+ 1730
1465
+ 1731
1466
+ 1732
1467
+ 1733
1468
+ 1734
1469
+ 1735
1470
+ 1736
1471
+ 1737
1472
+ 1738
1473
+ 1739
1474
+ 1740
1475
+ 1741
1476
+ 1742
1477
+ 1743
1478
+ 1744
1479
+ 1745
1480
+ 1746
1481
+ 1747
1482
+ 1749
1483
+ 1750
1484
+ 1751
1485
+ 1752
1486
+ 1754
1487
+ 1756
1488
+ 1757
1489
+ 1758
1490
+ 1759
1491
+ 1760
1492
+ 1761
1493
+ 1763
1494
+ 1764
1495
+ 1765
1496
+ 1766
1497
+ 1767
1498
+ 1768
1499
+ 1770
1500
+ 1771
1501
+ 1772
1502
+ 1775
1503
+ 1776
1504
+ 1777
1505
+ 1778
1506
+ 1781
1507
+ 1783
1508
+ 1785
1509
+ 1786
1510
+ 1787
1511
+ 1788
1512
+ 1789
1513
+ 1790
1514
+ 1791
1515
+ 1792
1516
+ 1794
1517
+ 1795
1518
+ 1796
1519
+ 1797
1520
+ 1798
1521
+ 1799
1522
+ 1800
1523
+ 1802
1524
+ 1803
1525
+ 1804
1526
+ 1806
1527
+ 1807
1528
+ 1809
1529
+ 1810
1530
+ 1811
1531
+ 1812
1532
+ 1813
1533
+ 1814
1534
+ 1816
1535
+ 1817
1536
+ 1818
1537
+ 1820
1538
+ 1821
1539
+ 1822
1540
+ 1823
1541
+ 1824
1542
+ 1825
1543
+ 1826
1544
+ 1827
1545
+ 1828
1546
+ 1829
1547
+ 1830
1548
+ 1831
1549
+ 1832
1550
+ 1833
1551
+ 1834
1552
+ 1835
1553
+ 1836
1554
+ 1837
1555
+ 1838
1556
+ 1839
1557
+ 1840
1558
+ 1842
1559
+ 1843
1560
+ 1844
1561
+ 1845
1562
+ 1846
1563
+ 1847
1564
+ 1848
1565
+ 1849
1566
+ 1852
1567
+ 1855
1568
+ 1856
1569
+ 1857
1570
+ 1858
1571
+ 1859
1572
+ 1860
1573
+ 1861
1574
+ 1862
1575
+ 1863
1576
+ 1866
1577
+ 1870
1578
+ 1871
1579
+ 1872
1580
+ 1873
1581
+ 1874
1582
+ 1875
1583
+ 1876
1584
+ 1877
1585
+ 1879
1586
+ 1880
1587
+ 1882
1588
+ 1883
1589
+ 1884
1590
+ 1885
1591
+ 1886
1592
+ 1887
1593
+ 1890
1594
+ 1891
1595
+ 1892
1596
+ 1893
1597
+ 1895
1598
+ 1896
1599
+ 1897
1600
+ 1898
1601
+ 1899
1602
+ 1900
1603
+ 1901
1604
+ 1902
1605
+ 1903
1606
+ 1904
1607
+ 1905
1608
+ 1907
1609
+ 1908
1610
+ 1909
1611
+ 1911
1612
+ 1912
1613
+ 1913
1614
+ 1914
1615
+ 1915
1616
+ 1916
1617
+ 1917
1618
+ 1918
1619
+ 1919
1620
+ 1921
1621
+ 1922
1622
+ 1923
1623
+ 1924
1624
+ 1925
1625
+ 1926
1626
+ 1927
1627
+ 1928
1628
+ 1929
1629
+ 1930
1630
+ 1931
1631
+ 1932
1632
+ 1933
1633
+ 1934
1634
+ 1935
1635
+ 1936
1636
+ 1937
1637
+ 1938
1638
+ 1941
1639
+ 1942
1640
+ 1943
1641
+ 1944
1642
+ 1946
1643
+ 1947
1644
+ 1948
1645
+ 1950
1646
+ 1951
1647
+ 1952
1648
+ 1953
1649
+ 1954
1650
+ 1955
1651
+ 1956
1652
+ 1957
1653
+ 1958
1654
+ 1959
1655
+ 1960
1656
+ 1961
1657
+ 1962
1658
+ 1963
1659
+ 1964
1660
+ 1965
1661
+ 1966
1662
+ 1967
1663
+ 1968
1664
+ 1969
1665
+ 1970
1666
+ 1971
1667
+ 1972
1668
+ 1973
1669
+ 1974
1670
+ 1975
1671
+ 1976
1672
+ 1977
1673
+ 1978
1674
+ 1979
1675
+ 1980
1676
+ 1981
1677
+ 1982
1678
+ 1984
1679
+ 1985
1680
+ 1986
1681
+ 1988
1682
+ 1989
1683
+ 1991
1684
+ 1992
1685
+ 1993
1686
+ 1994
1687
+ 1995
1688
+ 1996
1689
+ 1998
1690
+ 1999
1691
+ 2001
1692
+ 2002
1693
+ 2003
1694
+ 2004
1695
+ 2005
1696
+ 2006
1697
+ 2007
1698
+ 2009
1699
+ 2010
1700
+ 2011
1701
+ 2012
1702
+ 2013
1703
+ 2014
1704
+ 2015
1705
+ 2016
1706
+ 2017
1707
+ 2018
1708
+ 2019
1709
+ 2020
1710
+ 2021
1711
+ 2022
1712
+ 2023
1713
+ 2024
1714
+ 2025
1715
+ 2026
1716
+ 2027
1717
+ 2028
1718
+ 2029
1719
+ 2030
1720
+ 2032
1721
+ 2033
1722
+ 2034
1723
+ 2035
1724
+ 2036
1725
+ 2037
1726
+ 2038
1727
+ 2039
1728
+ 2040
1729
+ 2041
1730
+ 2043
1731
+ 2044
1732
+ 2045
1733
+ 2046
1734
+ 2047
1735
+ 2048
1736
+ 2049
1737
+ 2051
1738
+ 2052
1739
+ 2054
1740
+ 2055
1741
+ 2057
1742
+ 2058
1743
+ 2059
1744
+ 2060
1745
+ 2062
1746
+ 2063
1747
+ 2064
1748
+ 2065
1749
+ 2066
1750
+ 2067
1751
+ 2069
1752
+ 2070
1753
+ 2071
1754
+ 2072
1755
+ 2073
1756
+ 2074
1757
+ 2075
1758
+ 2077
1759
+ 2078
1760
+ 2079
1761
+ 2080
1762
+ 2081
1763
+ 2082
1764
+ 2083
1765
+ 2084
1766
+ 2085
1767
+ 2086
1768
+ 2087
1769
+ 2088
1770
+ 2089
1771
+ 2090
1772
+ 2093
1773
+ 2094
1774
+ 2095
1775
+ 2096
1776
+ 2097
1777
+ 2098
1778
+ 2100
1779
+ 2101
1780
+ 2102
1781
+ 2103
1782
+ 2104
1783
+ 2105
1784
+ 2106
1785
+ 2107
1786
+ 2108
1787
+ 2109
1788
+ 2110
1789
+ 2111
1790
+ 2112
1791
+ 2114
1792
+ 2115
1793
+ 2116
1794
+ 2117
1795
+ 2118
1796
+ 2119
1797
+ 2120
1798
+ 2121
1799
+ 2122
1800
+ 2123
1801
+ 2124
1802
+ 2126
1803
+ 2127
1804
+ 2129
1805
+ 2130
1806
+ 2131
1807
+ 2132
1808
+ 2133
1809
+ 2134
1810
+ 2135
1811
+ 2136
1812
+ 2137
1813
+ 2138
1814
+ 2139
1815
+ 2140
1816
+ 2141
1817
+ 2142
1818
+ 2143
1819
+ 2144
1820
+ 2145
1821
+ 2147
1822
+ 2149
1823
+ 2150
1824
+ 2151
1825
+ 2152
1826
+ 2153
1827
+ 2154
1828
+ 2155
1829
+ 2156
1830
+ 2157
1831
+ 2158
1832
+ 2160
1833
+ 2161
1834
+ 2162
1835
+ 2163
1836
+ 2164
1837
+ 2165
1838
+ 2166
1839
+ 2167
1840
+ 2168
1841
+ 2170
1842
+ 2171
1843
+ 2172
1844
+ 2173
1845
+ 2175
1846
+ 2176
1847
+ 2177
1848
+ 2178
1849
+ 2179
1850
+ 2180
1851
+ 2181
1852
+ 2182
1853
+ 2184
1854
+ 2185
1855
+ 2186
1856
+ 2187
1857
+ 2189
1858
+ 2190
1859
+ 2191
1860
+ 2192
1861
+ 2193
1862
+ 2195
1863
+ 2196
1864
+ 2197
1865
+ 2198
1866
+ 2199
1867
+ 2200
1868
+ 2201
1869
+ 2202
1870
+ 2203
1871
+ 2204
1872
+ 2205
1873
+ 2206
1874
+ 2207
1875
+ 2208
1876
+ 2210
1877
+ 2211
1878
+ 2212
1879
+ 2213
1880
+ 2214
1881
+ 2215
1882
+ 2216
1883
+ 2217
1884
+ 2218
1885
+ 2219
1886
+ 2220
1887
+ 2221
1888
+ 2222
1889
+ 2223
1890
+ 2224
1891
+ 2225
1892
+ 2226
1893
+ 2227
1894
+ 2228
1895
+ 2229
1896
+ 2231
1897
+ 2232
1898
+ 2233
1899
+ 2234
1900
+ 2236
1901
+ 2238
1902
+ 2239
1903
+ 2240
1904
+ 2241
1905
+ 2242
1906
+ 2244
1907
+ 2245
1908
+ 2246
1909
+ 2247
1910
+ 2249
1911
+ 2250
1912
+ 2251
1913
+ 2252
1914
+ 2253
1915
+ 2254
1916
+ 2255
1917
+ 2256
1918
+ 2257
1919
+ 2258
1920
+ 2259
1921
+ 2260
1922
+ 2261
1923
+ 2262
1924
+ 2263
1925
+ 2264
1926
+ 2265
1927
+ 2266
1928
+ 2267
1929
+ 2268
1930
+ 2270
1931
+ 2271
1932
+ 2272
1933
+ 2273
1934
+ 2274
1935
+ 2275
1936
+ 2276
1937
+ 2278
1938
+ 2279
1939
+ 2280
1940
+ 2281
1941
+ 2282
1942
+ 2283
1943
+ 2284
1944
+ 2285
1945
+ 2287
1946
+ 2288
1947
+ 2289
1948
+ 2290
1949
+ 2291
1950
+ 2292
1951
+ 2293
1952
+ 2294
1953
+ 2295
1954
+ 2296
1955
+ 2297
1956
+ 2299
1957
+ 2301
1958
+ 2302
1959
+ 2303
1960
+ 2304
1961
+ 2305
1962
+ 2306
1963
+ 2307
1964
+ 2308
1965
+ 2309
1966
+ 2310
1967
+ 2312
1968
+ 2313
1969
+ 2315
1970
+ 2316
1971
+ 2317
1972
+ 2318
1973
+ 2319
1974
+ 2320
1975
+ 2321
1976
+ 2322
1977
+ 2323
1978
+ 2324
1979
+ 2325
1980
+ 2326
1981
+ 2327
1982
+ 2329
1983
+ 2330
1984
+ 2331
1985
+ 2332
1986
+ 2333
1987
+ 2335
1988
+ 2336
1989
+ 2337
1990
+ 2338
1991
+ 2339
1992
+ 2341
1993
+ 2342
1994
+ 2343
1995
+ 2346
1996
+ 2347
1997
+ 2349
1998
+ 2350
1999
+ 2352
2000
+ 2353
2001
+ 2354
2002
+ 2355
2003
+ 2356
2004
+ 2357
2005
+ 2359
2006
+ 2360
2007
+ 2361
2008
+ 2363
2009
+ 2364
2010
+ 2365
2011
+ 2366
2012
+ 2367
2013
+ 2368
2014
+ 2369
2015
+ 2370
2016
+ 2371
2017
+ 2373
2018
+ 2374
2019
+ 2375
2020
+ 2376
2021
+ 2378
2022
+ 2379
2023
+ 2380
2024
+ 2381
2025
+ 2382
2026
+ 2383
2027
+ 2384
2028
+ 2385
2029
+ 2386
2030
+ 2387
2031
+ 2388
2032
+ 2389
2033
+ 2390
2034
+ 2391
2035
+ 2392
2036
+ 2393
2037
+ 2394
2038
+ 2396
2039
+ 2398
2040
+ 2399
2041
+ 2400
2042
+ 2401
2043
+ 2402
2044
+ 2403
2045
+ 2404
2046
+ 2405
2047
+ 2407
2048
+ 2408
2049
+ 2409
2050
+ 2410
2051
+ 2411
2052
+ 2412
2053
+ 2413
2054
+ 2414
2055
+ 2417
2056
+ 2418
2057
+ 2420
2058
+ 2421
2059
+ 2422
2060
+ 2423
2061
+ 2424
2062
+ 2425
2063
+ 2426
2064
+ 2427
2065
+ 2429
2066
+ 2431
2067
+ 2432
2068
+ 2434
2069
+ 2436
2070
+ 2439
2071
+ 2440
2072
+ 2441
2073
+ 2442
2074
+ 2443
2075
+ 2444
2076
+ 2445
2077
+ 2446
2078
+ 2447
2079
+ 2448
2080
+ 2449
2081
+ 2451
2082
+ 2452
2083
+ 2454
2084
+ 2455
2085
+ 2456
2086
+ 2457
2087
+ 2458
2088
+ 2460
2089
+ 2461
2090
+ 2462
2091
+ 2463
2092
+ 2464
2093
+ 2465
2094
+ 2466
2095
+ 2467
2096
+ 2468
2097
+ 2469
2098
+ 2470
2099
+ 2471
2100
+ 2472
2101
+ 2473
2102
+ 2474
2103
+ 2475
2104
+ 2476
2105
+ 2477
2106
+ 2478
2107
+ 2479
2108
+ 2480
2109
+ 2481
2110
+ 2482
2111
+ 2483
2112
+ 2484
2113
+ 2486
2114
+ 2487
2115
+ 2488
2116
+ 2489
2117
+ 2490
2118
+ 2491
2119
+ 2494
2120
+ 2496
2121
+ 2497
2122
+ 2498
2123
+ 2499
2124
+ 2500
2125
+ 2501
2126
+ 2502
2127
+ 2504
2128
+ 2505
2129
+ 2506
2130
+ 2507
2131
+ 2508
2132
+ 2510
2133
+ 2511
2134
+ 2512
2135
+ 2513
2136
+ 2514
2137
+ 2515
2138
+ 2516
2139
+ 2518
2140
+ 2519
2141
+ 2520
2142
+ 2521
2143
+ 2522
2144
+ 2523
2145
+ 2524
2146
+ 2525
2147
+ 2527
2148
+ 2528
2149
+ 2529
2150
+ 2530
2151
+ 2531
2152
+ 2532
2153
+ 2533
2154
+ 2534
2155
+ 2536
2156
+ 2537
2157
+ 2538
2158
+ 2539
2159
+ 2540
2160
+ 2541
2161
+ 2543
2162
+ 2544
2163
+ 2545
2164
+ 2546
2165
+ 2547
2166
+ 2548
2167
+ 2549
2168
+ 2550
2169
+ 2551
2170
+ 2552
2171
+ 2553
2172
+ 2554
2173
+ 2555
2174
+ 2556
2175
+ 2557
2176
+ 2558
2177
+ 2559
2178
+ 2560
2179
+ 2561
2180
+ 2562
2181
+ 2563
2182
+ 2564
2183
+ 2565
2184
+ 2566
2185
+ 2567
2186
+ 2568
2187
+ 2570
2188
+ 2571
2189
+ 2572
2190
+ 2573
2191
+ 2574
2192
+ 2575
2193
+ 2576
2194
+ 2577
2195
+ 2578
2196
+ 2579
2197
+ 2580
2198
+ 2581
2199
+ 2582
2200
+ 2583
2201
+ 2584
2202
+ 2586
2203
+ 2587
2204
+ 2588
2205
+ 2589
2206
+ 2590
2207
+ 2591
2208
+ 2592
2209
+ 2594
2210
+ 2595
2211
+ 2596
2212
+ 2598
2213
+ 2600
2214
+ 2601
2215
+ 2602
2216
+ 2604
2217
+ 2605
2218
+ 2606
2219
+ 2607
2220
+ 2608
2221
+ 2612
2222
+ 2615
2223
+ 2616
2224
+ 2617
2225
+ 2618
2226
+ 2620
2227
+ 2621
2228
+ 2622
2229
+ 2623
2230
+ 2624
2231
+ 2625
2232
+ 2626
2233
+ 2628
2234
+ 2629
2235
+ 2630
2236
+ 2631
2237
+ 2632
2238
+ 2636
2239
+ 2637
2240
+ 2638
2241
+ 2639
2242
+ 2640
2243
+ 2641
2244
+ 2642
2245
+ 2643
2246
+ 2644
2247
+ 2645
2248
+ 2646
2249
+ 2647
2250
+ 2648
2251
+ 2649
2252
+ 2650
2253
+ 2651
2254
+ 2652
2255
+ 2653
2256
+ 2655
2257
+ 2656
2258
+ 2657
2259
+ 2658
2260
+ 2659
2261
+ 2661
2262
+ 2662
2263
+ 2663
2264
+ 2664
2265
+ 2665
2266
+ 2666
2267
+ 2667
2268
+ 2668
2269
+ 2669
2270
+ 2670
2271
+ 2672
2272
+ 2673
2273
+ 2674
2274
+ 2675
2275
+ 2676
2276
+ 2677
2277
+ 2680
2278
+ 2682
2279
+ 2683
2280
+ 2684
2281
+ 2686
2282
+ 2687
2283
+ 2689
2284
+ 2690
2285
+ 2691
2286
+ 2692
2287
+ 2693
2288
+ 2694
2289
+ 2695
2290
+ 2696
2291
+ 2697
2292
+ 2698
2293
+ 2699
2294
+ 2700
2295
+ 2701
2296
+ 2702
2297
+ 2703
2298
+ 2704
2299
+ 2705
2300
+ 2706
2301
+ 2707
2302
+ 2709
2303
+ 2710
2304
+ 2713
2305
+ 2714
2306
+ 2715
2307
+ 2716
2308
+ 2717
2309
+ 2718
2310
+ 2719
2311
+ 2720
2312
+ 2721
2313
+ 2722
2314
+ 2723
2315
+ 2726
2316
+ 2727
2317
+ 2728
2318
+ 2729
2319
+ 2730
2320
+ 2732
2321
+ 2733
2322
+ 2734
2323
+ 2735
2324
+ 2736
2325
+ 2737
2326
+ 2738
2327
+ 2740
2328
+ 2741
2329
+ 2743
2330
+ 2744
2331
+ 2745
2332
+ 2746
2333
+ 2747
2334
+ 2749
2335
+ 2750
2336
+ 2751
2337
+ 2752
2338
+ 2753
2339
+ 2755
2340
+ 2756
2341
+ 2758
2342
+ 2759
2343
+ 2760
2344
+ 2761
2345
+ 2762
2346
+ 2764
2347
+ 2765
2348
+ 2766
2349
+ 2767
2350
+ 2768
2351
+ 2769
2352
+ 2770
2353
+ 2771
2354
+ 2772
2355
+ 2775
2356
+ 2776
2357
+ 2777
2358
+ 2780
2359
+ 2781
2360
+ 2782
2361
+ 2783
2362
+ 2784
2363
+ 2786
2364
+ 2788
2365
+ 2789
2366
+ 2790
2367
+ 2791
2368
+ 2792
2369
+ 2793
2370
+ 2794
2371
+ 2795
2372
+ 2796
2373
+ 2797
2374
+ 2798
2375
+ 2799
2376
+ 2800
2377
+ 2802
2378
+ 2804
2379
+ 2805
2380
+ 2806
2381
+ 2807
2382
+ 2808
2383
+ 2809
2384
+ 2810
2385
+ 2811
2386
+ 2812
2387
+ 2813
2388
+ 2814
2389
+ 2815
2390
+ 2816
2391
+ 2817
2392
+ 2818
2393
+ 2819
2394
+ 2822
2395
+ 2823
2396
+ 2824
2397
+ 2825
2398
+ 2826
2399
+ 2827
2400
+ 2828
2401
+ 2829
2402
+ 2830
2403
+ 2831
2404
+ 2832
2405
+ 2833
2406
+ 2834
2407
+ 2835
2408
+ 2836
2409
+ 2837
2410
+ 2838
2411
+ 2839
2412
+ 2840
2413
+ 2842
2414
+ 2844
2415
+ 2845
2416
+ 2846
2417
+ 2847
2418
+ 2848
2419
+ 2850
2420
+ 2851
2421
+ 2852
2422
+ 2853
2423
+ 2854
2424
+ 2855
2425
+ 2856
2426
+ 2857
2427
+ 2858
2428
+ 2859
2429
+ 2860
2430
+ 2861
2431
+ 2862
2432
+ 2863
2433
+ 2864
2434
+ 2865
2435
+ 2866
2436
+ 2867
2437
+ 2868
2438
+ 2869
2439
+ 2870
2440
+ 2871
2441
+ 2873
2442
+ 2874
2443
+ 2875
2444
+ 2876
2445
+ 2877
2446
+ 2878
2447
+ 2879
2448
+ 2881
2449
+ 2882
2450
+ 2883
2451
+ 2884
2452
+ 2885
2453
+ 2886
2454
+ 2887
2455
+ 2888
2456
+ 2889
2457
+ 2890
2458
+ 2891
2459
+ 2892
2460
+ 2893
2461
+ 2896
2462
+ 2897
2463
+ 2898
2464
+ 2899
2465
+ 2900
2466
+ 2901
2467
+ 2902
2468
+ 2903
2469
+ 2904
2470
+ 2905
2471
+ 2906
2472
+ 2907
2473
+ 2908
2474
+ 2909
2475
+ 2910
2476
+ 2911
2477
+ 2912
2478
+ 2913
2479
+ 2914
2480
+ 2915
2481
+ 2916
2482
+ 2917
2483
+ 2918
2484
+ 2919
2485
+ 2920
2486
+ 2921
2487
+ 2923
2488
+ 2925
2489
+ 2927
2490
+ 2928
2491
+ 2929
2492
+ 2930
2493
+ 2931
2494
+ 2932
2495
+ 2933
2496
+ 2934
2497
+ 2935
2498
+ 2936
2499
+ 2937
2500
+ 2938
2501
+ 2939
2502
+ 2940
2503
+ 2941
2504
+ 2942
2505
+ 2943
2506
+ 2944
2507
+ 2945
2508
+ 2946
2509
+ 2947
2510
+ 2948
2511
+ 2950
2512
+ 2951
2513
+ 2952
2514
+ 2953
2515
+ 2954
2516
+ 2955
2517
+ 2956
2518
+ 2957
2519
+ 2958
2520
+ 2959
2521
+ 2960
2522
+ 2962
2523
+ 2964
2524
+ 2965
2525
+ 2966
2526
+ 2967
2527
+ 2968
2528
+ 2969
2529
+ 2970
2530
+ 2971
2531
+ 2972
2532
+ 2973
2533
+ 2974
2534
+ 2977
2535
+ 2978
2536
+ 2979
2537
+ 2980
2538
+ 2981
2539
+ 2982
2540
+ 2984
2541
+ 2987
2542
+ 2988
2543
+ 2990
2544
+ 2991
2545
+ 2992
2546
+ 2993
2547
+ 2994
2548
+ 2995
2549
+ 2998
2550
+ 2999
coral_seg/splits/train_full.txt ADDED
@@ -0,0 +1,3000 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0000
2
+ 0001
3
+ 0002
4
+ 0003
5
+ 0004
6
+ 0005
7
+ 0006
8
+ 0007
9
+ 0008
10
+ 0009
11
+ 0010
12
+ 0011
13
+ 0012
14
+ 0013
15
+ 0014
16
+ 0015
17
+ 0016
18
+ 0017
19
+ 0018
20
+ 0019
21
+ 0020
22
+ 0021
23
+ 0022
24
+ 0023
25
+ 0024
26
+ 0025
27
+ 0026
28
+ 0027
29
+ 0028
30
+ 0029
31
+ 0030
32
+ 0031
33
+ 0032
34
+ 0033
35
+ 0034
36
+ 0035
37
+ 0036
38
+ 0037
39
+ 0038
40
+ 0039
41
+ 0040
42
+ 0041
43
+ 0042
44
+ 0043
45
+ 0044
46
+ 0045
47
+ 0046
48
+ 0047
49
+ 0048
50
+ 0049
51
+ 0050
52
+ 0051
53
+ 0052
54
+ 0053
55
+ 0054
56
+ 0055
57
+ 0056
58
+ 0057
59
+ 0058
60
+ 0059
61
+ 0060
62
+ 0061
63
+ 0062
64
+ 0063
65
+ 0064
66
+ 0065
67
+ 0066
68
+ 0067
69
+ 0068
70
+ 0069
71
+ 0070
72
+ 0071
73
+ 0072
74
+ 0073
75
+ 0074
76
+ 0075
77
+ 0076
78
+ 0077
79
+ 0078
80
+ 0079
81
+ 0080
82
+ 0081
83
+ 0082
84
+ 0083
85
+ 0084
86
+ 0085
87
+ 0086
88
+ 0087
89
+ 0088
90
+ 0089
91
+ 0090
92
+ 0091
93
+ 0092
94
+ 0093
95
+ 0094
96
+ 0095
97
+ 0096
98
+ 0097
99
+ 0098
100
+ 0099
101
+ 0100
102
+ 0101
103
+ 0102
104
+ 0103
105
+ 0104
106
+ 0105
107
+ 0106
108
+ 0107
109
+ 0108
110
+ 0109
111
+ 0110
112
+ 0111
113
+ 0112
114
+ 0113
115
+ 0114
116
+ 0115
117
+ 0116
118
+ 0117
119
+ 0118
120
+ 0119
121
+ 0120
122
+ 0121
123
+ 0122
124
+ 0123
125
+ 0124
126
+ 0125
127
+ 0126
128
+ 0127
129
+ 0128
130
+ 0129
131
+ 0130
132
+ 0131
133
+ 0132
134
+ 0133
135
+ 0134
136
+ 0135
137
+ 0136
138
+ 0137
139
+ 0138
140
+ 0139
141
+ 0140
142
+ 0141
143
+ 0142
144
+ 0143
145
+ 0144
146
+ 0145
147
+ 0146
148
+ 0147
149
+ 0148
150
+ 0149
151
+ 0150
152
+ 0151
153
+ 0152
154
+ 0153
155
+ 0154
156
+ 0155
157
+ 0156
158
+ 0157
159
+ 0158
160
+ 0159
161
+ 0160
162
+ 0161
163
+ 0162
164
+ 0163
165
+ 0164
166
+ 0165
167
+ 0166
168
+ 0167
169
+ 0168
170
+ 0169
171
+ 0170
172
+ 0171
173
+ 0172
174
+ 0173
175
+ 0174
176
+ 0175
177
+ 0176
178
+ 0177
179
+ 0178
180
+ 0179
181
+ 0180
182
+ 0181
183
+ 0182
184
+ 0183
185
+ 0184
186
+ 0185
187
+ 0186
188
+ 0187
189
+ 0188
190
+ 0189
191
+ 0190
192
+ 0191
193
+ 0192
194
+ 0193
195
+ 0194
196
+ 0195
197
+ 0196
198
+ 0197
199
+ 0198
200
+ 0199
201
+ 0200
202
+ 0201
203
+ 0202
204
+ 0203
205
+ 0204
206
+ 0205
207
+ 0206
208
+ 0207
209
+ 0208
210
+ 0209
211
+ 0210
212
+ 0211
213
+ 0212
214
+ 0213
215
+ 0214
216
+ 0215
217
+ 0216
218
+ 0217
219
+ 0218
220
+ 0219
221
+ 0220
222
+ 0221
223
+ 0222
224
+ 0223
225
+ 0224
226
+ 0225
227
+ 0226
228
+ 0227
229
+ 0228
230
+ 0229
231
+ 0230
232
+ 0231
233
+ 0232
234
+ 0233
235
+ 0234
236
+ 0235
237
+ 0236
238
+ 0237
239
+ 0238
240
+ 0239
241
+ 0240
242
+ 0241
243
+ 0242
244
+ 0243
245
+ 0244
246
+ 0245
247
+ 0246
248
+ 0247
249
+ 0248
250
+ 0249
251
+ 0250
252
+ 0251
253
+ 0252
254
+ 0253
255
+ 0254
256
+ 0255
257
+ 0256
258
+ 0257
259
+ 0258
260
+ 0259
261
+ 0260
262
+ 0261
263
+ 0262
264
+ 0263
265
+ 0264
266
+ 0265
267
+ 0266
268
+ 0267
269
+ 0268
270
+ 0269
271
+ 0270
272
+ 0271
273
+ 0272
274
+ 0273
275
+ 0274
276
+ 0275
277
+ 0276
278
+ 0277
279
+ 0278
280
+ 0279
281
+ 0280
282
+ 0281
283
+ 0282
284
+ 0283
285
+ 0284
286
+ 0285
287
+ 0286
288
+ 0287
289
+ 0288
290
+ 0289
291
+ 0290
292
+ 0291
293
+ 0292
294
+ 0293
295
+ 0294
296
+ 0295
297
+ 0296
298
+ 0297
299
+ 0298
300
+ 0299
301
+ 0300
302
+ 0301
303
+ 0302
304
+ 0303
305
+ 0304
306
+ 0305
307
+ 0306
308
+ 0307
309
+ 0308
310
+ 0309
311
+ 0310
312
+ 0311
313
+ 0312
314
+ 0313
315
+ 0314
316
+ 0315
317
+ 0316
318
+ 0317
319
+ 0318
320
+ 0319
321
+ 0320
322
+ 0321
323
+ 0322
324
+ 0323
325
+ 0324
326
+ 0325
327
+ 0326
328
+ 0327
329
+ 0328
330
+ 0329
331
+ 0330
332
+ 0331
333
+ 0332
334
+ 0333
335
+ 0334
336
+ 0335
337
+ 0336
338
+ 0337
339
+ 0338
340
+ 0339
341
+ 0340
342
+ 0341
343
+ 0342
344
+ 0343
345
+ 0344
346
+ 0345
347
+ 0346
348
+ 0347
349
+ 0348
350
+ 0349
351
+ 0350
352
+ 0351
353
+ 0352
354
+ 0353
355
+ 0354
356
+ 0355
357
+ 0356
358
+ 0357
359
+ 0358
360
+ 0359
361
+ 0360
362
+ 0361
363
+ 0362
364
+ 0363
365
+ 0364
366
+ 0365
367
+ 0366
368
+ 0367
369
+ 0368
370
+ 0369
371
+ 0370
372
+ 0371
373
+ 0372
374
+ 0373
375
+ 0374
376
+ 0375
377
+ 0376
378
+ 0377
379
+ 0378
380
+ 0379
381
+ 0380
382
+ 0381
383
+ 0382
384
+ 0383
385
+ 0384
386
+ 0385
387
+ 0386
388
+ 0387
389
+ 0388
390
+ 0389
391
+ 0390
392
+ 0391
393
+ 0392
394
+ 0393
395
+ 0394
396
+ 0395
397
+ 0396
398
+ 0397
399
+ 0398
400
+ 0399
401
+ 0400
402
+ 0401
403
+ 0402
404
+ 0403
405
+ 0404
406
+ 0405
407
+ 0406
408
+ 0407
409
+ 0408
410
+ 0409
411
+ 0410
412
+ 0411
413
+ 0412
414
+ 0413
415
+ 0414
416
+ 0415
417
+ 0416
418
+ 0417
419
+ 0418
420
+ 0419
421
+ 0420
422
+ 0421
423
+ 0422
424
+ 0423
425
+ 0424
426
+ 0425
427
+ 0426
428
+ 0427
429
+ 0428
430
+ 0429
431
+ 0430
432
+ 0431
433
+ 0432
434
+ 0433
435
+ 0434
436
+ 0435
437
+ 0436
438
+ 0437
439
+ 0438
440
+ 0439
441
+ 0440
442
+ 0441
443
+ 0442
444
+ 0443
445
+ 0444
446
+ 0445
447
+ 0446
448
+ 0447
449
+ 0448
450
+ 0449
451
+ 0450
452
+ 0451
453
+ 0452
454
+ 0453
455
+ 0454
456
+ 0455
457
+ 0456
458
+ 0457
459
+ 0458
460
+ 0459
461
+ 0460
462
+ 0461
463
+ 0462
464
+ 0463
465
+ 0464
466
+ 0465
467
+ 0466
468
+ 0467
469
+ 0468
470
+ 0469
471
+ 0470
472
+ 0471
473
+ 0472
474
+ 0473
475
+ 0474
476
+ 0475
477
+ 0476
478
+ 0477
479
+ 0478
480
+ 0479
481
+ 0480
482
+ 0481
483
+ 0482
484
+ 0483
485
+ 0484
486
+ 0485
487
+ 0486
488
+ 0487
489
+ 0488
490
+ 0489
491
+ 0490
492
+ 0491
493
+ 0492
494
+ 0493
495
+ 0494
496
+ 0495
497
+ 0496
498
+ 0497
499
+ 0498
500
+ 0499
501
+ 0500
502
+ 0501
503
+ 0502
504
+ 0503
505
+ 0504
506
+ 0505
507
+ 0506
508
+ 0507
509
+ 0508
510
+ 0509
511
+ 0510
512
+ 0511
513
+ 0512
514
+ 0513
515
+ 0514
516
+ 0515
517
+ 0516
518
+ 0517
519
+ 0518
520
+ 0519
521
+ 0520
522
+ 0521
523
+ 0522
524
+ 0523
525
+ 0524
526
+ 0525
527
+ 0526
528
+ 0527
529
+ 0528
530
+ 0529
531
+ 0530
532
+ 0531
533
+ 0532
534
+ 0533
535
+ 0534
536
+ 0535
537
+ 0536
538
+ 0537
539
+ 0538
540
+ 0539
541
+ 0540
542
+ 0541
543
+ 0542
544
+ 0543
545
+ 0544
546
+ 0545
547
+ 0546
548
+ 0547
549
+ 0548
550
+ 0549
551
+ 0550
552
+ 0551
553
+ 0552
554
+ 0553
555
+ 0554
556
+ 0555
557
+ 0556
558
+ 0557
559
+ 0558
560
+ 0559
561
+ 0560
562
+ 0561
563
+ 0562
564
+ 0563
565
+ 0564
566
+ 0565
567
+ 0566
568
+ 0567
569
+ 0568
570
+ 0569
571
+ 0570
572
+ 0571
573
+ 0572
574
+ 0573
575
+ 0574
576
+ 0575
577
+ 0576
578
+ 0577
579
+ 0578
580
+ 0579
581
+ 0580
582
+ 0581
583
+ 0582
584
+ 0583
585
+ 0584
586
+ 0585
587
+ 0586
588
+ 0587
589
+ 0588
590
+ 0589
591
+ 0590
592
+ 0591
593
+ 0592
594
+ 0593
595
+ 0594
596
+ 0595
597
+ 0596
598
+ 0597
599
+ 0598
600
+ 0599
601
+ 0600
602
+ 0601
603
+ 0602
604
+ 0603
605
+ 0604
606
+ 0605
607
+ 0606
608
+ 0607
609
+ 0608
610
+ 0609
611
+ 0610
612
+ 0611
613
+ 0612
614
+ 0613
615
+ 0614
616
+ 0615
617
+ 0616
618
+ 0617
619
+ 0618
620
+ 0619
621
+ 0620
622
+ 0621
623
+ 0622
624
+ 0623
625
+ 0624
626
+ 0625
627
+ 0626
628
+ 0627
629
+ 0628
630
+ 0629
631
+ 0630
632
+ 0631
633
+ 0632
634
+ 0633
635
+ 0634
636
+ 0635
637
+ 0636
638
+ 0637
639
+ 0638
640
+ 0639
641
+ 0640
642
+ 0641
643
+ 0642
644
+ 0643
645
+ 0644
646
+ 0645
647
+ 0646
648
+ 0647
649
+ 0648
650
+ 0649
651
+ 0650
652
+ 0651
653
+ 0652
654
+ 0653
655
+ 0654
656
+ 0655
657
+ 0656
658
+ 0657
659
+ 0658
660
+ 0659
661
+ 0660
662
+ 0661
663
+ 0662
664
+ 0663
665
+ 0664
666
+ 0665
667
+ 0666
668
+ 0667
669
+ 0668
670
+ 0669
671
+ 0670
672
+ 0671
673
+ 0672
674
+ 0673
675
+ 0674
676
+ 0675
677
+ 0676
678
+ 0677
679
+ 0678
680
+ 0679
681
+ 0680
682
+ 0681
683
+ 0682
684
+ 0683
685
+ 0684
686
+ 0685
687
+ 0686
688
+ 0687
689
+ 0688
690
+ 0689
691
+ 0690
692
+ 0691
693
+ 0692
694
+ 0693
695
+ 0694
696
+ 0695
697
+ 0696
698
+ 0697
699
+ 0698
700
+ 0699
701
+ 0700
702
+ 0701
703
+ 0702
704
+ 0703
705
+ 0704
706
+ 0705
707
+ 0706
708
+ 0707
709
+ 0708
710
+ 0709
711
+ 0710
712
+ 0711
713
+ 0712
714
+ 0713
715
+ 0714
716
+ 0715
717
+ 0716
718
+ 0717
719
+ 0718
720
+ 0719
721
+ 0720
722
+ 0721
723
+ 0722
724
+ 0723
725
+ 0724
726
+ 0725
727
+ 0726
728
+ 0727
729
+ 0728
730
+ 0729
731
+ 0730
732
+ 0731
733
+ 0732
734
+ 0733
735
+ 0734
736
+ 0735
737
+ 0736
738
+ 0737
739
+ 0738
740
+ 0739
741
+ 0740
742
+ 0741
743
+ 0742
744
+ 0743
745
+ 0744
746
+ 0745
747
+ 0746
748
+ 0747
749
+ 0748
750
+ 0749
751
+ 0750
752
+ 0751
753
+ 0752
754
+ 0753
755
+ 0754
756
+ 0755
757
+ 0756
758
+ 0757
759
+ 0758
760
+ 0759
761
+ 0760
762
+ 0761
763
+ 0762
764
+ 0763
765
+ 0764
766
+ 0765
767
+ 0766
768
+ 0767
769
+ 0768
770
+ 0769
771
+ 0770
772
+ 0771
773
+ 0772
774
+ 0773
775
+ 0774
776
+ 0775
777
+ 0776
778
+ 0777
779
+ 0778
780
+ 0779
781
+ 0780
782
+ 0781
783
+ 0782
784
+ 0783
785
+ 0784
786
+ 0785
787
+ 0786
788
+ 0787
789
+ 0788
790
+ 0789
791
+ 0790
792
+ 0791
793
+ 0792
794
+ 0793
795
+ 0794
796
+ 0795
797
+ 0796
798
+ 0797
799
+ 0798
800
+ 0799
801
+ 0800
802
+ 0801
803
+ 0802
804
+ 0803
805
+ 0804
806
+ 0805
807
+ 0806
808
+ 0807
809
+ 0808
810
+ 0809
811
+ 0810
812
+ 0811
813
+ 0812
814
+ 0813
815
+ 0814
816
+ 0815
817
+ 0816
818
+ 0817
819
+ 0818
820
+ 0819
821
+ 0820
822
+ 0821
823
+ 0822
824
+ 0823
825
+ 0824
826
+ 0825
827
+ 0826
828
+ 0827
829
+ 0828
830
+ 0829
831
+ 0830
832
+ 0831
833
+ 0832
834
+ 0833
835
+ 0834
836
+ 0835
837
+ 0836
838
+ 0837
839
+ 0838
840
+ 0839
841
+ 0840
842
+ 0841
843
+ 0842
844
+ 0843
845
+ 0844
846
+ 0845
847
+ 0846
848
+ 0847
849
+ 0848
850
+ 0849
851
+ 0850
852
+ 0851
853
+ 0852
854
+ 0853
855
+ 0854
856
+ 0855
857
+ 0856
858
+ 0857
859
+ 0858
860
+ 0859
861
+ 0860
862
+ 0861
863
+ 0862
864
+ 0863
865
+ 0864
866
+ 0865
867
+ 0866
868
+ 0867
869
+ 0868
870
+ 0869
871
+ 0870
872
+ 0871
873
+ 0872
874
+ 0873
875
+ 0874
876
+ 0875
877
+ 0876
878
+ 0877
879
+ 0878
880
+ 0879
881
+ 0880
882
+ 0881
883
+ 0882
884
+ 0883
885
+ 0884
886
+ 0885
887
+ 0886
888
+ 0887
889
+ 0888
890
+ 0889
891
+ 0890
892
+ 0891
893
+ 0892
894
+ 0893
895
+ 0894
896
+ 0895
897
+ 0896
898
+ 0897
899
+ 0898
900
+ 0899
901
+ 0900
902
+ 0901
903
+ 0902
904
+ 0903
905
+ 0904
906
+ 0905
907
+ 0906
908
+ 0907
909
+ 0908
910
+ 0909
911
+ 0910
912
+ 0911
913
+ 0912
914
+ 0913
915
+ 0914
916
+ 0915
917
+ 0916
918
+ 0917
919
+ 0918
920
+ 0919
921
+ 0920
922
+ 0921
923
+ 0922
924
+ 0923
925
+ 0924
926
+ 0925
927
+ 0926
928
+ 0927
929
+ 0928
930
+ 0929
931
+ 0930
932
+ 0931
933
+ 0932
934
+ 0933
935
+ 0934
936
+ 0935
937
+ 0936
938
+ 0937
939
+ 0938
940
+ 0939
941
+ 0940
942
+ 0941
943
+ 0942
944
+ 0943
945
+ 0944
946
+ 0945
947
+ 0946
948
+ 0947
949
+ 0948
950
+ 0949
951
+ 0950
952
+ 0951
953
+ 0952
954
+ 0953
955
+ 0954
956
+ 0955
957
+ 0956
958
+ 0957
959
+ 0958
960
+ 0959
961
+ 0960
962
+ 0961
963
+ 0962
964
+ 0963
965
+ 0964
966
+ 0965
967
+ 0966
968
+ 0967
969
+ 0968
970
+ 0969
971
+ 0970
972
+ 0971
973
+ 0972
974
+ 0973
975
+ 0974
976
+ 0975
977
+ 0976
978
+ 0977
979
+ 0978
980
+ 0979
981
+ 0980
982
+ 0981
983
+ 0982
984
+ 0983
985
+ 0984
986
+ 0985
987
+ 0986
988
+ 0987
989
+ 0988
990
+ 0989
991
+ 0990
992
+ 0991
993
+ 0992
994
+ 0993
995
+ 0994
996
+ 0995
997
+ 0996
998
+ 0997
999
+ 0998
1000
+ 0999
1001
+ 1000
1002
+ 1001
1003
+ 1002
1004
+ 1003
1005
+ 1004
1006
+ 1005
1007
+ 1006
1008
+ 1007
1009
+ 1008
1010
+ 1009
1011
+ 1010
1012
+ 1011
1013
+ 1012
1014
+ 1013
1015
+ 1014
1016
+ 1015
1017
+ 1016
1018
+ 1017
1019
+ 1018
1020
+ 1019
1021
+ 1020
1022
+ 1021
1023
+ 1022
1024
+ 1023
1025
+ 1024
1026
+ 1025
1027
+ 1026
1028
+ 1027
1029
+ 1028
1030
+ 1029
1031
+ 1030
1032
+ 1031
1033
+ 1032
1034
+ 1033
1035
+ 1034
1036
+ 1035
1037
+ 1036
1038
+ 1037
1039
+ 1038
1040
+ 1039
1041
+ 1040
1042
+ 1041
1043
+ 1042
1044
+ 1043
1045
+ 1044
1046
+ 1045
1047
+ 1046
1048
+ 1047
1049
+ 1048
1050
+ 1049
1051
+ 1050
1052
+ 1051
1053
+ 1052
1054
+ 1053
1055
+ 1054
1056
+ 1055
1057
+ 1056
1058
+ 1057
1059
+ 1058
1060
+ 1059
1061
+ 1060
1062
+ 1061
1063
+ 1062
1064
+ 1063
1065
+ 1064
1066
+ 1065
1067
+ 1066
1068
+ 1067
1069
+ 1068
1070
+ 1069
1071
+ 1070
1072
+ 1071
1073
+ 1072
1074
+ 1073
1075
+ 1074
1076
+ 1075
1077
+ 1076
1078
+ 1077
1079
+ 1078
1080
+ 1079
1081
+ 1080
1082
+ 1081
1083
+ 1082
1084
+ 1083
1085
+ 1084
1086
+ 1085
1087
+ 1086
1088
+ 1087
1089
+ 1088
1090
+ 1089
1091
+ 1090
1092
+ 1091
1093
+ 1092
1094
+ 1093
1095
+ 1094
1096
+ 1095
1097
+ 1096
1098
+ 1097
1099
+ 1098
1100
+ 1099
1101
+ 1100
1102
+ 1101
1103
+ 1102
1104
+ 1103
1105
+ 1104
1106
+ 1105
1107
+ 1106
1108
+ 1107
1109
+ 1108
1110
+ 1109
1111
+ 1110
1112
+ 1111
1113
+ 1112
1114
+ 1113
1115
+ 1114
1116
+ 1115
1117
+ 1116
1118
+ 1117
1119
+ 1118
1120
+ 1119
1121
+ 1120
1122
+ 1121
1123
+ 1122
1124
+ 1123
1125
+ 1124
1126
+ 1125
1127
+ 1126
1128
+ 1127
1129
+ 1128
1130
+ 1129
1131
+ 1130
1132
+ 1131
1133
+ 1132
1134
+ 1133
1135
+ 1134
1136
+ 1135
1137
+ 1136
1138
+ 1137
1139
+ 1138
1140
+ 1139
1141
+ 1140
1142
+ 1141
1143
+ 1142
1144
+ 1143
1145
+ 1144
1146
+ 1145
1147
+ 1146
1148
+ 1147
1149
+ 1148
1150
+ 1149
1151
+ 1150
1152
+ 1151
1153
+ 1152
1154
+ 1153
1155
+ 1154
1156
+ 1155
1157
+ 1156
1158
+ 1157
1159
+ 1158
1160
+ 1159
1161
+ 1160
1162
+ 1161
1163
+ 1162
1164
+ 1163
1165
+ 1164
1166
+ 1165
1167
+ 1166
1168
+ 1167
1169
+ 1168
1170
+ 1169
1171
+ 1170
1172
+ 1171
1173
+ 1172
1174
+ 1173
1175
+ 1174
1176
+ 1175
1177
+ 1176
1178
+ 1177
1179
+ 1178
1180
+ 1179
1181
+ 1180
1182
+ 1181
1183
+ 1182
1184
+ 1183
1185
+ 1184
1186
+ 1185
1187
+ 1186
1188
+ 1187
1189
+ 1188
1190
+ 1189
1191
+ 1190
1192
+ 1191
1193
+ 1192
1194
+ 1193
1195
+ 1194
1196
+ 1195
1197
+ 1196
1198
+ 1197
1199
+ 1198
1200
+ 1199
1201
+ 1200
1202
+ 1201
1203
+ 1202
1204
+ 1203
1205
+ 1204
1206
+ 1205
1207
+ 1206
1208
+ 1207
1209
+ 1208
1210
+ 1209
1211
+ 1210
1212
+ 1211
1213
+ 1212
1214
+ 1213
1215
+ 1214
1216
+ 1215
1217
+ 1216
1218
+ 1217
1219
+ 1218
1220
+ 1219
1221
+ 1220
1222
+ 1221
1223
+ 1222
1224
+ 1223
1225
+ 1224
1226
+ 1225
1227
+ 1226
1228
+ 1227
1229
+ 1228
1230
+ 1229
1231
+ 1230
1232
+ 1231
1233
+ 1232
1234
+ 1233
1235
+ 1234
1236
+ 1235
1237
+ 1236
1238
+ 1237
1239
+ 1238
1240
+ 1239
1241
+ 1240
1242
+ 1241
1243
+ 1242
1244
+ 1243
1245
+ 1244
1246
+ 1245
1247
+ 1246
1248
+ 1247
1249
+ 1248
1250
+ 1249
1251
+ 1250
1252
+ 1251
1253
+ 1252
1254
+ 1253
1255
+ 1254
1256
+ 1255
1257
+ 1256
1258
+ 1257
1259
+ 1258
1260
+ 1259
1261
+ 1260
1262
+ 1261
1263
+ 1262
1264
+ 1263
1265
+ 1264
1266
+ 1265
1267
+ 1266
1268
+ 1267
1269
+ 1268
1270
+ 1269
1271
+ 1270
1272
+ 1271
1273
+ 1272
1274
+ 1273
1275
+ 1274
1276
+ 1275
1277
+ 1276
1278
+ 1277
1279
+ 1278
1280
+ 1279
1281
+ 1280
1282
+ 1281
1283
+ 1282
1284
+ 1283
1285
+ 1284
1286
+ 1285
1287
+ 1286
1288
+ 1287
1289
+ 1288
1290
+ 1289
1291
+ 1290
1292
+ 1291
1293
+ 1292
1294
+ 1293
1295
+ 1294
1296
+ 1295
1297
+ 1296
1298
+ 1297
1299
+ 1298
1300
+ 1299
1301
+ 1300
1302
+ 1301
1303
+ 1302
1304
+ 1303
1305
+ 1304
1306
+ 1305
1307
+ 1306
1308
+ 1307
1309
+ 1308
1310
+ 1309
1311
+ 1310
1312
+ 1311
1313
+ 1312
1314
+ 1313
1315
+ 1314
1316
+ 1315
1317
+ 1316
1318
+ 1317
1319
+ 1318
1320
+ 1319
1321
+ 1320
1322
+ 1321
1323
+ 1322
1324
+ 1323
1325
+ 1324
1326
+ 1325
1327
+ 1326
1328
+ 1327
1329
+ 1328
1330
+ 1329
1331
+ 1330
1332
+ 1331
1333
+ 1332
1334
+ 1333
1335
+ 1334
1336
+ 1335
1337
+ 1336
1338
+ 1337
1339
+ 1338
1340
+ 1339
1341
+ 1340
1342
+ 1341
1343
+ 1342
1344
+ 1343
1345
+ 1344
1346
+ 1345
1347
+ 1346
1348
+ 1347
1349
+ 1348
1350
+ 1349
1351
+ 1350
1352
+ 1351
1353
+ 1352
1354
+ 1353
1355
+ 1354
1356
+ 1355
1357
+ 1356
1358
+ 1357
1359
+ 1358
1360
+ 1359
1361
+ 1360
1362
+ 1361
1363
+ 1362
1364
+ 1363
1365
+ 1364
1366
+ 1365
1367
+ 1366
1368
+ 1367
1369
+ 1368
1370
+ 1369
1371
+ 1370
1372
+ 1371
1373
+ 1372
1374
+ 1373
1375
+ 1374
1376
+ 1375
1377
+ 1376
1378
+ 1377
1379
+ 1378
1380
+ 1379
1381
+ 1380
1382
+ 1381
1383
+ 1382
1384
+ 1383
1385
+ 1384
1386
+ 1385
1387
+ 1386
1388
+ 1387
1389
+ 1388
1390
+ 1389
1391
+ 1390
1392
+ 1391
1393
+ 1392
1394
+ 1393
1395
+ 1394
1396
+ 1395
1397
+ 1396
1398
+ 1397
1399
+ 1398
1400
+ 1399
1401
+ 1400
1402
+ 1401
1403
+ 1402
1404
+ 1403
1405
+ 1404
1406
+ 1405
1407
+ 1406
1408
+ 1407
1409
+ 1408
1410
+ 1409
1411
+ 1410
1412
+ 1411
1413
+ 1412
1414
+ 1413
1415
+ 1414
1416
+ 1415
1417
+ 1416
1418
+ 1417
1419
+ 1418
1420
+ 1419
1421
+ 1420
1422
+ 1421
1423
+ 1422
1424
+ 1423
1425
+ 1424
1426
+ 1425
1427
+ 1426
1428
+ 1427
1429
+ 1428
1430
+ 1429
1431
+ 1430
1432
+ 1431
1433
+ 1432
1434
+ 1433
1435
+ 1434
1436
+ 1435
1437
+ 1436
1438
+ 1437
1439
+ 1438
1440
+ 1439
1441
+ 1440
1442
+ 1441
1443
+ 1442
1444
+ 1443
1445
+ 1444
1446
+ 1445
1447
+ 1446
1448
+ 1447
1449
+ 1448
1450
+ 1449
1451
+ 1450
1452
+ 1451
1453
+ 1452
1454
+ 1453
1455
+ 1454
1456
+ 1455
1457
+ 1456
1458
+ 1457
1459
+ 1458
1460
+ 1459
1461
+ 1460
1462
+ 1461
1463
+ 1462
1464
+ 1463
1465
+ 1464
1466
+ 1465
1467
+ 1466
1468
+ 1467
1469
+ 1468
1470
+ 1469
1471
+ 1470
1472
+ 1471
1473
+ 1472
1474
+ 1473
1475
+ 1474
1476
+ 1475
1477
+ 1476
1478
+ 1477
1479
+ 1478
1480
+ 1479
1481
+ 1480
1482
+ 1481
1483
+ 1482
1484
+ 1483
1485
+ 1484
1486
+ 1485
1487
+ 1486
1488
+ 1487
1489
+ 1488
1490
+ 1489
1491
+ 1490
1492
+ 1491
1493
+ 1492
1494
+ 1493
1495
+ 1494
1496
+ 1495
1497
+ 1496
1498
+ 1497
1499
+ 1498
1500
+ 1499
1501
+ 1500
1502
+ 1501
1503
+ 1502
1504
+ 1503
1505
+ 1504
1506
+ 1505
1507
+ 1506
1508
+ 1507
1509
+ 1508
1510
+ 1509
1511
+ 1510
1512
+ 1511
1513
+ 1512
1514
+ 1513
1515
+ 1514
1516
+ 1515
1517
+ 1516
1518
+ 1517
1519
+ 1518
1520
+ 1519
1521
+ 1520
1522
+ 1521
1523
+ 1522
1524
+ 1523
1525
+ 1524
1526
+ 1525
1527
+ 1526
1528
+ 1527
1529
+ 1528
1530
+ 1529
1531
+ 1530
1532
+ 1531
1533
+ 1532
1534
+ 1533
1535
+ 1534
1536
+ 1535
1537
+ 1536
1538
+ 1537
1539
+ 1538
1540
+ 1539
1541
+ 1540
1542
+ 1541
1543
+ 1542
1544
+ 1543
1545
+ 1544
1546
+ 1545
1547
+ 1546
1548
+ 1547
1549
+ 1548
1550
+ 1549
1551
+ 1550
1552
+ 1551
1553
+ 1552
1554
+ 1553
1555
+ 1554
1556
+ 1555
1557
+ 1556
1558
+ 1557
1559
+ 1558
1560
+ 1559
1561
+ 1560
1562
+ 1561
1563
+ 1562
1564
+ 1563
1565
+ 1564
1566
+ 1565
1567
+ 1566
1568
+ 1567
1569
+ 1568
1570
+ 1569
1571
+ 1570
1572
+ 1571
1573
+ 1572
1574
+ 1573
1575
+ 1574
1576
+ 1575
1577
+ 1576
1578
+ 1577
1579
+ 1578
1580
+ 1579
1581
+ 1580
1582
+ 1581
1583
+ 1582
1584
+ 1583
1585
+ 1584
1586
+ 1585
1587
+ 1586
1588
+ 1587
1589
+ 1588
1590
+ 1589
1591
+ 1590
1592
+ 1591
1593
+ 1592
1594
+ 1593
1595
+ 1594
1596
+ 1595
1597
+ 1596
1598
+ 1597
1599
+ 1598
1600
+ 1599
1601
+ 1600
1602
+ 1601
1603
+ 1602
1604
+ 1603
1605
+ 1604
1606
+ 1605
1607
+ 1606
1608
+ 1607
1609
+ 1608
1610
+ 1609
1611
+ 1610
1612
+ 1611
1613
+ 1612
1614
+ 1613
1615
+ 1614
1616
+ 1615
1617
+ 1616
1618
+ 1617
1619
+ 1618
1620
+ 1619
1621
+ 1620
1622
+ 1621
1623
+ 1622
1624
+ 1623
1625
+ 1624
1626
+ 1625
1627
+ 1626
1628
+ 1627
1629
+ 1628
1630
+ 1629
1631
+ 1630
1632
+ 1631
1633
+ 1632
1634
+ 1633
1635
+ 1634
1636
+ 1635
1637
+ 1636
1638
+ 1637
1639
+ 1638
1640
+ 1639
1641
+ 1640
1642
+ 1641
1643
+ 1642
1644
+ 1643
1645
+ 1644
1646
+ 1645
1647
+ 1646
1648
+ 1647
1649
+ 1648
1650
+ 1649
1651
+ 1650
1652
+ 1651
1653
+ 1652
1654
+ 1653
1655
+ 1654
1656
+ 1655
1657
+ 1656
1658
+ 1657
1659
+ 1658
1660
+ 1659
1661
+ 1660
1662
+ 1661
1663
+ 1662
1664
+ 1663
1665
+ 1664
1666
+ 1665
1667
+ 1666
1668
+ 1667
1669
+ 1668
1670
+ 1669
1671
+ 1670
1672
+ 1671
1673
+ 1672
1674
+ 1673
1675
+ 1674
1676
+ 1675
1677
+ 1676
1678
+ 1677
1679
+ 1678
1680
+ 1679
1681
+ 1680
1682
+ 1681
1683
+ 1682
1684
+ 1683
1685
+ 1684
1686
+ 1685
1687
+ 1686
1688
+ 1687
1689
+ 1688
1690
+ 1689
1691
+ 1690
1692
+ 1691
1693
+ 1692
1694
+ 1693
1695
+ 1694
1696
+ 1695
1697
+ 1696
1698
+ 1697
1699
+ 1698
1700
+ 1699
1701
+ 1700
1702
+ 1701
1703
+ 1702
1704
+ 1703
1705
+ 1704
1706
+ 1705
1707
+ 1706
1708
+ 1707
1709
+ 1708
1710
+ 1709
1711
+ 1710
1712
+ 1711
1713
+ 1712
1714
+ 1713
1715
+ 1714
1716
+ 1715
1717
+ 1716
1718
+ 1717
1719
+ 1718
1720
+ 1719
1721
+ 1720
1722
+ 1721
1723
+ 1722
1724
+ 1723
1725
+ 1724
1726
+ 1725
1727
+ 1726
1728
+ 1727
1729
+ 1728
1730
+ 1729
1731
+ 1730
1732
+ 1731
1733
+ 1732
1734
+ 1733
1735
+ 1734
1736
+ 1735
1737
+ 1736
1738
+ 1737
1739
+ 1738
1740
+ 1739
1741
+ 1740
1742
+ 1741
1743
+ 1742
1744
+ 1743
1745
+ 1744
1746
+ 1745
1747
+ 1746
1748
+ 1747
1749
+ 1748
1750
+ 1749
1751
+ 1750
1752
+ 1751
1753
+ 1752
1754
+ 1753
1755
+ 1754
1756
+ 1755
1757
+ 1756
1758
+ 1757
1759
+ 1758
1760
+ 1759
1761
+ 1760
1762
+ 1761
1763
+ 1762
1764
+ 1763
1765
+ 1764
1766
+ 1765
1767
+ 1766
1768
+ 1767
1769
+ 1768
1770
+ 1769
1771
+ 1770
1772
+ 1771
1773
+ 1772
1774
+ 1773
1775
+ 1774
1776
+ 1775
1777
+ 1776
1778
+ 1777
1779
+ 1778
1780
+ 1779
1781
+ 1780
1782
+ 1781
1783
+ 1782
1784
+ 1783
1785
+ 1784
1786
+ 1785
1787
+ 1786
1788
+ 1787
1789
+ 1788
1790
+ 1789
1791
+ 1790
1792
+ 1791
1793
+ 1792
1794
+ 1793
1795
+ 1794
1796
+ 1795
1797
+ 1796
1798
+ 1797
1799
+ 1798
1800
+ 1799
1801
+ 1800
1802
+ 1801
1803
+ 1802
1804
+ 1803
1805
+ 1804
1806
+ 1805
1807
+ 1806
1808
+ 1807
1809
+ 1808
1810
+ 1809
1811
+ 1810
1812
+ 1811
1813
+ 1812
1814
+ 1813
1815
+ 1814
1816
+ 1815
1817
+ 1816
1818
+ 1817
1819
+ 1818
1820
+ 1819
1821
+ 1820
1822
+ 1821
1823
+ 1822
1824
+ 1823
1825
+ 1824
1826
+ 1825
1827
+ 1826
1828
+ 1827
1829
+ 1828
1830
+ 1829
1831
+ 1830
1832
+ 1831
1833
+ 1832
1834
+ 1833
1835
+ 1834
1836
+ 1835
1837
+ 1836
1838
+ 1837
1839
+ 1838
1840
+ 1839
1841
+ 1840
1842
+ 1841
1843
+ 1842
1844
+ 1843
1845
+ 1844
1846
+ 1845
1847
+ 1846
1848
+ 1847
1849
+ 1848
1850
+ 1849
1851
+ 1850
1852
+ 1851
1853
+ 1852
1854
+ 1853
1855
+ 1854
1856
+ 1855
1857
+ 1856
1858
+ 1857
1859
+ 1858
1860
+ 1859
1861
+ 1860
1862
+ 1861
1863
+ 1862
1864
+ 1863
1865
+ 1864
1866
+ 1865
1867
+ 1866
1868
+ 1867
1869
+ 1868
1870
+ 1869
1871
+ 1870
1872
+ 1871
1873
+ 1872
1874
+ 1873
1875
+ 1874
1876
+ 1875
1877
+ 1876
1878
+ 1877
1879
+ 1878
1880
+ 1879
1881
+ 1880
1882
+ 1881
1883
+ 1882
1884
+ 1883
1885
+ 1884
1886
+ 1885
1887
+ 1886
1888
+ 1887
1889
+ 1888
1890
+ 1889
1891
+ 1890
1892
+ 1891
1893
+ 1892
1894
+ 1893
1895
+ 1894
1896
+ 1895
1897
+ 1896
1898
+ 1897
1899
+ 1898
1900
+ 1899
1901
+ 1900
1902
+ 1901
1903
+ 1902
1904
+ 1903
1905
+ 1904
1906
+ 1905
1907
+ 1906
1908
+ 1907
1909
+ 1908
1910
+ 1909
1911
+ 1910
1912
+ 1911
1913
+ 1912
1914
+ 1913
1915
+ 1914
1916
+ 1915
1917
+ 1916
1918
+ 1917
1919
+ 1918
1920
+ 1919
1921
+ 1920
1922
+ 1921
1923
+ 1922
1924
+ 1923
1925
+ 1924
1926
+ 1925
1927
+ 1926
1928
+ 1927
1929
+ 1928
1930
+ 1929
1931
+ 1930
1932
+ 1931
1933
+ 1932
1934
+ 1933
1935
+ 1934
1936
+ 1935
1937
+ 1936
1938
+ 1937
1939
+ 1938
1940
+ 1939
1941
+ 1940
1942
+ 1941
1943
+ 1942
1944
+ 1943
1945
+ 1944
1946
+ 1945
1947
+ 1946
1948
+ 1947
1949
+ 1948
1950
+ 1949
1951
+ 1950
1952
+ 1951
1953
+ 1952
1954
+ 1953
1955
+ 1954
1956
+ 1955
1957
+ 1956
1958
+ 1957
1959
+ 1958
1960
+ 1959
1961
+ 1960
1962
+ 1961
1963
+ 1962
1964
+ 1963
1965
+ 1964
1966
+ 1965
1967
+ 1966
1968
+ 1967
1969
+ 1968
1970
+ 1969
1971
+ 1970
1972
+ 1971
1973
+ 1972
1974
+ 1973
1975
+ 1974
1976
+ 1975
1977
+ 1976
1978
+ 1977
1979
+ 1978
1980
+ 1979
1981
+ 1980
1982
+ 1981
1983
+ 1982
1984
+ 1983
1985
+ 1984
1986
+ 1985
1987
+ 1986
1988
+ 1987
1989
+ 1988
1990
+ 1989
1991
+ 1990
1992
+ 1991
1993
+ 1992
1994
+ 1993
1995
+ 1994
1996
+ 1995
1997
+ 1996
1998
+ 1997
1999
+ 1998
2000
+ 1999
2001
+ 2000
2002
+ 2001
2003
+ 2002
2004
+ 2003
2005
+ 2004
2006
+ 2005
2007
+ 2006
2008
+ 2007
2009
+ 2008
2010
+ 2009
2011
+ 2010
2012
+ 2011
2013
+ 2012
2014
+ 2013
2015
+ 2014
2016
+ 2015
2017
+ 2016
2018
+ 2017
2019
+ 2018
2020
+ 2019
2021
+ 2020
2022
+ 2021
2023
+ 2022
2024
+ 2023
2025
+ 2024
2026
+ 2025
2027
+ 2026
2028
+ 2027
2029
+ 2028
2030
+ 2029
2031
+ 2030
2032
+ 2031
2033
+ 2032
2034
+ 2033
2035
+ 2034
2036
+ 2035
2037
+ 2036
2038
+ 2037
2039
+ 2038
2040
+ 2039
2041
+ 2040
2042
+ 2041
2043
+ 2042
2044
+ 2043
2045
+ 2044
2046
+ 2045
2047
+ 2046
2048
+ 2047
2049
+ 2048
2050
+ 2049
2051
+ 2050
2052
+ 2051
2053
+ 2052
2054
+ 2053
2055
+ 2054
2056
+ 2055
2057
+ 2056
2058
+ 2057
2059
+ 2058
2060
+ 2059
2061
+ 2060
2062
+ 2061
2063
+ 2062
2064
+ 2063
2065
+ 2064
2066
+ 2065
2067
+ 2066
2068
+ 2067
2069
+ 2068
2070
+ 2069
2071
+ 2070
2072
+ 2071
2073
+ 2072
2074
+ 2073
2075
+ 2074
2076
+ 2075
2077
+ 2076
2078
+ 2077
2079
+ 2078
2080
+ 2079
2081
+ 2080
2082
+ 2081
2083
+ 2082
2084
+ 2083
2085
+ 2084
2086
+ 2085
2087
+ 2086
2088
+ 2087
2089
+ 2088
2090
+ 2089
2091
+ 2090
2092
+ 2091
2093
+ 2092
2094
+ 2093
2095
+ 2094
2096
+ 2095
2097
+ 2096
2098
+ 2097
2099
+ 2098
2100
+ 2099
2101
+ 2100
2102
+ 2101
2103
+ 2102
2104
+ 2103
2105
+ 2104
2106
+ 2105
2107
+ 2106
2108
+ 2107
2109
+ 2108
2110
+ 2109
2111
+ 2110
2112
+ 2111
2113
+ 2112
2114
+ 2113
2115
+ 2114
2116
+ 2115
2117
+ 2116
2118
+ 2117
2119
+ 2118
2120
+ 2119
2121
+ 2120
2122
+ 2121
2123
+ 2122
2124
+ 2123
2125
+ 2124
2126
+ 2125
2127
+ 2126
2128
+ 2127
2129
+ 2128
2130
+ 2129
2131
+ 2130
2132
+ 2131
2133
+ 2132
2134
+ 2133
2135
+ 2134
2136
+ 2135
2137
+ 2136
2138
+ 2137
2139
+ 2138
2140
+ 2139
2141
+ 2140
2142
+ 2141
2143
+ 2142
2144
+ 2143
2145
+ 2144
2146
+ 2145
2147
+ 2146
2148
+ 2147
2149
+ 2148
2150
+ 2149
2151
+ 2150
2152
+ 2151
2153
+ 2152
2154
+ 2153
2155
+ 2154
2156
+ 2155
2157
+ 2156
2158
+ 2157
2159
+ 2158
2160
+ 2159
2161
+ 2160
2162
+ 2161
2163
+ 2162
2164
+ 2163
2165
+ 2164
2166
+ 2165
2167
+ 2166
2168
+ 2167
2169
+ 2168
2170
+ 2169
2171
+ 2170
2172
+ 2171
2173
+ 2172
2174
+ 2173
2175
+ 2174
2176
+ 2175
2177
+ 2176
2178
+ 2177
2179
+ 2178
2180
+ 2179
2181
+ 2180
2182
+ 2181
2183
+ 2182
2184
+ 2183
2185
+ 2184
2186
+ 2185
2187
+ 2186
2188
+ 2187
2189
+ 2188
2190
+ 2189
2191
+ 2190
2192
+ 2191
2193
+ 2192
2194
+ 2193
2195
+ 2194
2196
+ 2195
2197
+ 2196
2198
+ 2197
2199
+ 2198
2200
+ 2199
2201
+ 2200
2202
+ 2201
2203
+ 2202
2204
+ 2203
2205
+ 2204
2206
+ 2205
2207
+ 2206
2208
+ 2207
2209
+ 2208
2210
+ 2209
2211
+ 2210
2212
+ 2211
2213
+ 2212
2214
+ 2213
2215
+ 2214
2216
+ 2215
2217
+ 2216
2218
+ 2217
2219
+ 2218
2220
+ 2219
2221
+ 2220
2222
+ 2221
2223
+ 2222
2224
+ 2223
2225
+ 2224
2226
+ 2225
2227
+ 2226
2228
+ 2227
2229
+ 2228
2230
+ 2229
2231
+ 2230
2232
+ 2231
2233
+ 2232
2234
+ 2233
2235
+ 2234
2236
+ 2235
2237
+ 2236
2238
+ 2237
2239
+ 2238
2240
+ 2239
2241
+ 2240
2242
+ 2241
2243
+ 2242
2244
+ 2243
2245
+ 2244
2246
+ 2245
2247
+ 2246
2248
+ 2247
2249
+ 2248
2250
+ 2249
2251
+ 2250
2252
+ 2251
2253
+ 2252
2254
+ 2253
2255
+ 2254
2256
+ 2255
2257
+ 2256
2258
+ 2257
2259
+ 2258
2260
+ 2259
2261
+ 2260
2262
+ 2261
2263
+ 2262
2264
+ 2263
2265
+ 2264
2266
+ 2265
2267
+ 2266
2268
+ 2267
2269
+ 2268
2270
+ 2269
2271
+ 2270
2272
+ 2271
2273
+ 2272
2274
+ 2273
2275
+ 2274
2276
+ 2275
2277
+ 2276
2278
+ 2277
2279
+ 2278
2280
+ 2279
2281
+ 2280
2282
+ 2281
2283
+ 2282
2284
+ 2283
2285
+ 2284
2286
+ 2285
2287
+ 2286
2288
+ 2287
2289
+ 2288
2290
+ 2289
2291
+ 2290
2292
+ 2291
2293
+ 2292
2294
+ 2293
2295
+ 2294
2296
+ 2295
2297
+ 2296
2298
+ 2297
2299
+ 2298
2300
+ 2299
2301
+ 2300
2302
+ 2301
2303
+ 2302
2304
+ 2303
2305
+ 2304
2306
+ 2305
2307
+ 2306
2308
+ 2307
2309
+ 2308
2310
+ 2309
2311
+ 2310
2312
+ 2311
2313
+ 2312
2314
+ 2313
2315
+ 2314
2316
+ 2315
2317
+ 2316
2318
+ 2317
2319
+ 2318
2320
+ 2319
2321
+ 2320
2322
+ 2321
2323
+ 2322
2324
+ 2323
2325
+ 2324
2326
+ 2325
2327
+ 2326
2328
+ 2327
2329
+ 2328
2330
+ 2329
2331
+ 2330
2332
+ 2331
2333
+ 2332
2334
+ 2333
2335
+ 2334
2336
+ 2335
2337
+ 2336
2338
+ 2337
2339
+ 2338
2340
+ 2339
2341
+ 2340
2342
+ 2341
2343
+ 2342
2344
+ 2343
2345
+ 2344
2346
+ 2345
2347
+ 2346
2348
+ 2347
2349
+ 2348
2350
+ 2349
2351
+ 2350
2352
+ 2351
2353
+ 2352
2354
+ 2353
2355
+ 2354
2356
+ 2355
2357
+ 2356
2358
+ 2357
2359
+ 2358
2360
+ 2359
2361
+ 2360
2362
+ 2361
2363
+ 2362
2364
+ 2363
2365
+ 2364
2366
+ 2365
2367
+ 2366
2368
+ 2367
2369
+ 2368
2370
+ 2369
2371
+ 2370
2372
+ 2371
2373
+ 2372
2374
+ 2373
2375
+ 2374
2376
+ 2375
2377
+ 2376
2378
+ 2377
2379
+ 2378
2380
+ 2379
2381
+ 2380
2382
+ 2381
2383
+ 2382
2384
+ 2383
2385
+ 2384
2386
+ 2385
2387
+ 2386
2388
+ 2387
2389
+ 2388
2390
+ 2389
2391
+ 2390
2392
+ 2391
2393
+ 2392
2394
+ 2393
2395
+ 2394
2396
+ 2395
2397
+ 2396
2398
+ 2397
2399
+ 2398
2400
+ 2399
2401
+ 2400
2402
+ 2401
2403
+ 2402
2404
+ 2403
2405
+ 2404
2406
+ 2405
2407
+ 2406
2408
+ 2407
2409
+ 2408
2410
+ 2409
2411
+ 2410
2412
+ 2411
2413
+ 2412
2414
+ 2413
2415
+ 2414
2416
+ 2415
2417
+ 2416
2418
+ 2417
2419
+ 2418
2420
+ 2419
2421
+ 2420
2422
+ 2421
2423
+ 2422
2424
+ 2423
2425
+ 2424
2426
+ 2425
2427
+ 2426
2428
+ 2427
2429
+ 2428
2430
+ 2429
2431
+ 2430
2432
+ 2431
2433
+ 2432
2434
+ 2433
2435
+ 2434
2436
+ 2435
2437
+ 2436
2438
+ 2437
2439
+ 2438
2440
+ 2439
2441
+ 2440
2442
+ 2441
2443
+ 2442
2444
+ 2443
2445
+ 2444
2446
+ 2445
2447
+ 2446
2448
+ 2447
2449
+ 2448
2450
+ 2449
2451
+ 2450
2452
+ 2451
2453
+ 2452
2454
+ 2453
2455
+ 2454
2456
+ 2455
2457
+ 2456
2458
+ 2457
2459
+ 2458
2460
+ 2459
2461
+ 2460
2462
+ 2461
2463
+ 2462
2464
+ 2463
2465
+ 2464
2466
+ 2465
2467
+ 2466
2468
+ 2467
2469
+ 2468
2470
+ 2469
2471
+ 2470
2472
+ 2471
2473
+ 2472
2474
+ 2473
2475
+ 2474
2476
+ 2475
2477
+ 2476
2478
+ 2477
2479
+ 2478
2480
+ 2479
2481
+ 2480
2482
+ 2481
2483
+ 2482
2484
+ 2483
2485
+ 2484
2486
+ 2485
2487
+ 2486
2488
+ 2487
2489
+ 2488
2490
+ 2489
2491
+ 2490
2492
+ 2491
2493
+ 2492
2494
+ 2493
2495
+ 2494
2496
+ 2495
2497
+ 2496
2498
+ 2497
2499
+ 2498
2500
+ 2499
2501
+ 2500
2502
+ 2501
2503
+ 2502
2504
+ 2503
2505
+ 2504
2506
+ 2505
2507
+ 2506
2508
+ 2507
2509
+ 2508
2510
+ 2509
2511
+ 2510
2512
+ 2511
2513
+ 2512
2514
+ 2513
2515
+ 2514
2516
+ 2515
2517
+ 2516
2518
+ 2517
2519
+ 2518
2520
+ 2519
2521
+ 2520
2522
+ 2521
2523
+ 2522
2524
+ 2523
2525
+ 2524
2526
+ 2525
2527
+ 2526
2528
+ 2527
2529
+ 2528
2530
+ 2529
2531
+ 2530
2532
+ 2531
2533
+ 2532
2534
+ 2533
2535
+ 2534
2536
+ 2535
2537
+ 2536
2538
+ 2537
2539
+ 2538
2540
+ 2539
2541
+ 2540
2542
+ 2541
2543
+ 2542
2544
+ 2543
2545
+ 2544
2546
+ 2545
2547
+ 2546
2548
+ 2547
2549
+ 2548
2550
+ 2549
2551
+ 2550
2552
+ 2551
2553
+ 2552
2554
+ 2553
2555
+ 2554
2556
+ 2555
2557
+ 2556
2558
+ 2557
2559
+ 2558
2560
+ 2559
2561
+ 2560
2562
+ 2561
2563
+ 2562
2564
+ 2563
2565
+ 2564
2566
+ 2565
2567
+ 2566
2568
+ 2567
2569
+ 2568
2570
+ 2569
2571
+ 2570
2572
+ 2571
2573
+ 2572
2574
+ 2573
2575
+ 2574
2576
+ 2575
2577
+ 2576
2578
+ 2577
2579
+ 2578
2580
+ 2579
2581
+ 2580
2582
+ 2581
2583
+ 2582
2584
+ 2583
2585
+ 2584
2586
+ 2585
2587
+ 2586
2588
+ 2587
2589
+ 2588
2590
+ 2589
2591
+ 2590
2592
+ 2591
2593
+ 2592
2594
+ 2593
2595
+ 2594
2596
+ 2595
2597
+ 2596
2598
+ 2597
2599
+ 2598
2600
+ 2599
2601
+ 2600
2602
+ 2601
2603
+ 2602
2604
+ 2603
2605
+ 2604
2606
+ 2605
2607
+ 2606
2608
+ 2607
2609
+ 2608
2610
+ 2609
2611
+ 2610
2612
+ 2611
2613
+ 2612
2614
+ 2613
2615
+ 2614
2616
+ 2615
2617
+ 2616
2618
+ 2617
2619
+ 2618
2620
+ 2619
2621
+ 2620
2622
+ 2621
2623
+ 2622
2624
+ 2623
2625
+ 2624
2626
+ 2625
2627
+ 2626
2628
+ 2627
2629
+ 2628
2630
+ 2629
2631
+ 2630
2632
+ 2631
2633
+ 2632
2634
+ 2633
2635
+ 2634
2636
+ 2635
2637
+ 2636
2638
+ 2637
2639
+ 2638
2640
+ 2639
2641
+ 2640
2642
+ 2641
2643
+ 2642
2644
+ 2643
2645
+ 2644
2646
+ 2645
2647
+ 2646
2648
+ 2647
2649
+ 2648
2650
+ 2649
2651
+ 2650
2652
+ 2651
2653
+ 2652
2654
+ 2653
2655
+ 2654
2656
+ 2655
2657
+ 2656
2658
+ 2657
2659
+ 2658
2660
+ 2659
2661
+ 2660
2662
+ 2661
2663
+ 2662
2664
+ 2663
2665
+ 2664
2666
+ 2665
2667
+ 2666
2668
+ 2667
2669
+ 2668
2670
+ 2669
2671
+ 2670
2672
+ 2671
2673
+ 2672
2674
+ 2673
2675
+ 2674
2676
+ 2675
2677
+ 2676
2678
+ 2677
2679
+ 2678
2680
+ 2679
2681
+ 2680
2682
+ 2681
2683
+ 2682
2684
+ 2683
2685
+ 2684
2686
+ 2685
2687
+ 2686
2688
+ 2687
2689
+ 2688
2690
+ 2689
2691
+ 2690
2692
+ 2691
2693
+ 2692
2694
+ 2693
2695
+ 2694
2696
+ 2695
2697
+ 2696
2698
+ 2697
2699
+ 2698
2700
+ 2699
2701
+ 2700
2702
+ 2701
2703
+ 2702
2704
+ 2703
2705
+ 2704
2706
+ 2705
2707
+ 2706
2708
+ 2707
2709
+ 2708
2710
+ 2709
2711
+ 2710
2712
+ 2711
2713
+ 2712
2714
+ 2713
2715
+ 2714
2716
+ 2715
2717
+ 2716
2718
+ 2717
2719
+ 2718
2720
+ 2719
2721
+ 2720
2722
+ 2721
2723
+ 2722
2724
+ 2723
2725
+ 2724
2726
+ 2725
2727
+ 2726
2728
+ 2727
2729
+ 2728
2730
+ 2729
2731
+ 2730
2732
+ 2731
2733
+ 2732
2734
+ 2733
2735
+ 2734
2736
+ 2735
2737
+ 2736
2738
+ 2737
2739
+ 2738
2740
+ 2739
2741
+ 2740
2742
+ 2741
2743
+ 2742
2744
+ 2743
2745
+ 2744
2746
+ 2745
2747
+ 2746
2748
+ 2747
2749
+ 2748
2750
+ 2749
2751
+ 2750
2752
+ 2751
2753
+ 2752
2754
+ 2753
2755
+ 2754
2756
+ 2755
2757
+ 2756
2758
+ 2757
2759
+ 2758
2760
+ 2759
2761
+ 2760
2762
+ 2761
2763
+ 2762
2764
+ 2763
2765
+ 2764
2766
+ 2765
2767
+ 2766
2768
+ 2767
2769
+ 2768
2770
+ 2769
2771
+ 2770
2772
+ 2771
2773
+ 2772
2774
+ 2773
2775
+ 2774
2776
+ 2775
2777
+ 2776
2778
+ 2777
2779
+ 2778
2780
+ 2779
2781
+ 2780
2782
+ 2781
2783
+ 2782
2784
+ 2783
2785
+ 2784
2786
+ 2785
2787
+ 2786
2788
+ 2787
2789
+ 2788
2790
+ 2789
2791
+ 2790
2792
+ 2791
2793
+ 2792
2794
+ 2793
2795
+ 2794
2796
+ 2795
2797
+ 2796
2798
+ 2797
2799
+ 2798
2800
+ 2799
2801
+ 2800
2802
+ 2801
2803
+ 2802
2804
+ 2803
2805
+ 2804
2806
+ 2805
2807
+ 2806
2808
+ 2807
2809
+ 2808
2810
+ 2809
2811
+ 2810
2812
+ 2811
2813
+ 2812
2814
+ 2813
2815
+ 2814
2816
+ 2815
2817
+ 2816
2818
+ 2817
2819
+ 2818
2820
+ 2819
2821
+ 2820
2822
+ 2821
2823
+ 2822
2824
+ 2823
2825
+ 2824
2826
+ 2825
2827
+ 2826
2828
+ 2827
2829
+ 2828
2830
+ 2829
2831
+ 2830
2832
+ 2831
2833
+ 2832
2834
+ 2833
2835
+ 2834
2836
+ 2835
2837
+ 2836
2838
+ 2837
2839
+ 2838
2840
+ 2839
2841
+ 2840
2842
+ 2841
2843
+ 2842
2844
+ 2843
2845
+ 2844
2846
+ 2845
2847
+ 2846
2848
+ 2847
2849
+ 2848
2850
+ 2849
2851
+ 2850
2852
+ 2851
2853
+ 2852
2854
+ 2853
2855
+ 2854
2856
+ 2855
2857
+ 2856
2858
+ 2857
2859
+ 2858
2860
+ 2859
2861
+ 2860
2862
+ 2861
2863
+ 2862
2864
+ 2863
2865
+ 2864
2866
+ 2865
2867
+ 2866
2868
+ 2867
2869
+ 2868
2870
+ 2869
2871
+ 2870
2872
+ 2871
2873
+ 2872
2874
+ 2873
2875
+ 2874
2876
+ 2875
2877
+ 2876
2878
+ 2877
2879
+ 2878
2880
+ 2879
2881
+ 2880
2882
+ 2881
2883
+ 2882
2884
+ 2883
2885
+ 2884
2886
+ 2885
2887
+ 2886
2888
+ 2887
2889
+ 2888
2890
+ 2889
2891
+ 2890
2892
+ 2891
2893
+ 2892
2894
+ 2893
2895
+ 2894
2896
+ 2895
2897
+ 2896
2898
+ 2897
2899
+ 2898
2900
+ 2899
2901
+ 2900
2902
+ 2901
2903
+ 2902
2904
+ 2903
2905
+ 2904
2906
+ 2905
2907
+ 2906
2908
+ 2907
2909
+ 2908
2910
+ 2909
2911
+ 2910
2912
+ 2911
2913
+ 2912
2914
+ 2913
2915
+ 2914
2916
+ 2915
2917
+ 2916
2918
+ 2917
2919
+ 2918
2920
+ 2919
2921
+ 2920
2922
+ 2921
2923
+ 2922
2924
+ 2923
2925
+ 2924
2926
+ 2925
2927
+ 2926
2928
+ 2927
2929
+ 2928
2930
+ 2929
2931
+ 2930
2932
+ 2931
2933
+ 2932
2934
+ 2933
2935
+ 2934
2936
+ 2935
2937
+ 2936
2938
+ 2937
2939
+ 2938
2940
+ 2939
2941
+ 2940
2942
+ 2941
2943
+ 2942
2944
+ 2943
2945
+ 2944
2946
+ 2945
2947
+ 2946
2948
+ 2947
2949
+ 2948
2950
+ 2949
2951
+ 2950
2952
+ 2951
2953
+ 2952
2954
+ 2953
2955
+ 2954
2956
+ 2955
2957
+ 2956
2958
+ 2957
2959
+ 2958
2960
+ 2959
2961
+ 2960
2962
+ 2961
2963
+ 2962
2964
+ 2963
2965
+ 2964
2966
+ 2965
2967
+ 2966
2968
+ 2967
2969
+ 2968
2970
+ 2969
2971
+ 2970
2972
+ 2971
2973
+ 2972
2974
+ 2973
2975
+ 2974
2976
+ 2975
2977
+ 2976
2978
+ 2977
2979
+ 2978
2980
+ 2979
2981
+ 2980
2982
+ 2981
2983
+ 2982
2984
+ 2983
2985
+ 2984
2986
+ 2985
2987
+ 2986
2988
+ 2987
2989
+ 2988
2990
+ 2989
2991
+ 2990
2992
+ 2991
2993
+ 2992
2994
+ 2993
2995
+ 2994
2996
+ 2995
2997
+ 2996
2998
+ 2997
2999
+ 2998
3000
+ 2999
coral_seg/splits/val.txt ADDED
@@ -0,0 +1,450 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ 0003
2
+ 0008
3
+ 0010
4
+ 0014
5
+ 0019
6
+ 0024
7
+ 0029
8
+ 0034
9
+ 0035
10
+ 0045
11
+ 0048
12
+ 0053
13
+ 0057
14
+ 0061
15
+ 0062
16
+ 0063
17
+ 0066
18
+ 0079
19
+ 0084
20
+ 0099
21
+ 0104
22
+ 0106
23
+ 0109
24
+ 0112
25
+ 0130
26
+ 0135
27
+ 0136
28
+ 0147
29
+ 0161
30
+ 0167
31
+ 0173
32
+ 0177
33
+ 0196
34
+ 0207
35
+ 0223
36
+ 0226
37
+ 0271
38
+ 0272
39
+ 0276
40
+ 0280
41
+ 0291
42
+ 0301
43
+ 0324
44
+ 0333
45
+ 0335
46
+ 0343
47
+ 0347
48
+ 0348
49
+ 0350
50
+ 0353
51
+ 0354
52
+ 0360
53
+ 0363
54
+ 0369
55
+ 0370
56
+ 0378
57
+ 0380
58
+ 0392
59
+ 0399
60
+ 0412
61
+ 0428
62
+ 0433
63
+ 0435
64
+ 0444
65
+ 0450
66
+ 0462
67
+ 0470
68
+ 0485
69
+ 0489
70
+ 0494
71
+ 0497
72
+ 0499
73
+ 0507
74
+ 0514
75
+ 0527
76
+ 0530
77
+ 0533
78
+ 0541
79
+ 0544
80
+ 0547
81
+ 0552
82
+ 0553
83
+ 0555
84
+ 0570
85
+ 0587
86
+ 0593
87
+ 0612
88
+ 0641
89
+ 0659
90
+ 0670
91
+ 0687
92
+ 0694
93
+ 0695
94
+ 0703
95
+ 0717
96
+ 0720
97
+ 0724
98
+ 0730
99
+ 0738
100
+ 0739
101
+ 0753
102
+ 0757
103
+ 0758
104
+ 0766
105
+ 0767
106
+ 0779
107
+ 0785
108
+ 0788
109
+ 0793
110
+ 0798
111
+ 0808
112
+ 0813
113
+ 0814
114
+ 0815
115
+ 0822
116
+ 0825
117
+ 0830
118
+ 0834
119
+ 0851
120
+ 0853
121
+ 0868
122
+ 0872
123
+ 0882
124
+ 0887
125
+ 0889
126
+ 0894
127
+ 0897
128
+ 0901
129
+ 0906
130
+ 0909
131
+ 0912
132
+ 0915
133
+ 0916
134
+ 0925
135
+ 0926
136
+ 0930
137
+ 0952
138
+ 0953
139
+ 0956
140
+ 0961
141
+ 0965
142
+ 0970
143
+ 0971
144
+ 0977
145
+ 0978
146
+ 0989
147
+ 1020
148
+ 1021
149
+ 1023
150
+ 1045
151
+ 1049
152
+ 1051
153
+ 1052
154
+ 1055
155
+ 1060
156
+ 1064
157
+ 1067
158
+ 1069
159
+ 1079
160
+ 1091
161
+ 1099
162
+ 1102
163
+ 1106
164
+ 1108
165
+ 1110
166
+ 1111
167
+ 1113
168
+ 1118
169
+ 1121
170
+ 1123
171
+ 1124
172
+ 1137
173
+ 1140
174
+ 1141
175
+ 1162
176
+ 1169
177
+ 1170
178
+ 1176
179
+ 1178
180
+ 1180
181
+ 1185
182
+ 1197
183
+ 1199
184
+ 1202
185
+ 1204
186
+ 1206
187
+ 1235
188
+ 1242
189
+ 1251
190
+ 1263
191
+ 1267
192
+ 1284
193
+ 1297
194
+ 1304
195
+ 1331
196
+ 1342
197
+ 1346
198
+ 1352
199
+ 1357
200
+ 1369
201
+ 1375
202
+ 1376
203
+ 1382
204
+ 1383
205
+ 1385
206
+ 1387
207
+ 1389
208
+ 1397
209
+ 1399
210
+ 1412
211
+ 1415
212
+ 1421
213
+ 1423
214
+ 1426
215
+ 1435
216
+ 1436
217
+ 1446
218
+ 1450
219
+ 1486
220
+ 1490
221
+ 1492
222
+ 1495
223
+ 1497
224
+ 1502
225
+ 1509
226
+ 1511
227
+ 1522
228
+ 1523
229
+ 1525
230
+ 1532
231
+ 1536
232
+ 1538
233
+ 1540
234
+ 1541
235
+ 1549
236
+ 1568
237
+ 1571
238
+ 1576
239
+ 1581
240
+ 1584
241
+ 1587
242
+ 1592
243
+ 1604
244
+ 1605
245
+ 1609
246
+ 1615
247
+ 1624
248
+ 1637
249
+ 1639
250
+ 1648
251
+ 1654
252
+ 1667
253
+ 1670
254
+ 1676
255
+ 1680
256
+ 1682
257
+ 1689
258
+ 1701
259
+ 1702
260
+ 1707
261
+ 1710
262
+ 1711
263
+ 1713
264
+ 1717
265
+ 1719
266
+ 1721
267
+ 1724
268
+ 1748
269
+ 1753
270
+ 1755
271
+ 1762
272
+ 1769
273
+ 1773
274
+ 1774
275
+ 1779
276
+ 1780
277
+ 1782
278
+ 1784
279
+ 1793
280
+ 1801
281
+ 1805
282
+ 1808
283
+ 1815
284
+ 1819
285
+ 1841
286
+ 1850
287
+ 1851
288
+ 1853
289
+ 1854
290
+ 1864
291
+ 1865
292
+ 1867
293
+ 1868
294
+ 1869
295
+ 1878
296
+ 1881
297
+ 1888
298
+ 1889
299
+ 1894
300
+ 1906
301
+ 1910
302
+ 1920
303
+ 1939
304
+ 1940
305
+ 1945
306
+ 1949
307
+ 1983
308
+ 1987
309
+ 1990
310
+ 1997
311
+ 2000
312
+ 2008
313
+ 2031
314
+ 2042
315
+ 2050
316
+ 2053
317
+ 2056
318
+ 2061
319
+ 2068
320
+ 2076
321
+ 2091
322
+ 2092
323
+ 2099
324
+ 2113
325
+ 2125
326
+ 2128
327
+ 2146
328
+ 2148
329
+ 2159
330
+ 2169
331
+ 2174
332
+ 2183
333
+ 2188
334
+ 2194
335
+ 2209
336
+ 2230
337
+ 2235
338
+ 2237
339
+ 2243
340
+ 2248
341
+ 2269
342
+ 2277
343
+ 2286
344
+ 2298
345
+ 2300
346
+ 2311
347
+ 2314
348
+ 2328
349
+ 2334
350
+ 2340
351
+ 2344
352
+ 2345
353
+ 2348
354
+ 2351
355
+ 2358
356
+ 2362
357
+ 2372
358
+ 2377
359
+ 2395
360
+ 2397
361
+ 2406
362
+ 2415
363
+ 2416
364
+ 2419
365
+ 2428
366
+ 2430
367
+ 2433
368
+ 2435
369
+ 2437
370
+ 2438
371
+ 2450
372
+ 2453
373
+ 2459
374
+ 2485
375
+ 2492
376
+ 2493
377
+ 2495
378
+ 2503
379
+ 2509
380
+ 2517
381
+ 2526
382
+ 2535
383
+ 2542
384
+ 2569
385
+ 2585
386
+ 2593
387
+ 2597
388
+ 2599
389
+ 2603
390
+ 2609
391
+ 2610
392
+ 2611
393
+ 2613
394
+ 2614
395
+ 2619
396
+ 2627
397
+ 2633
398
+ 2634
399
+ 2635
400
+ 2654
401
+ 2660
402
+ 2671
403
+ 2678
404
+ 2679
405
+ 2681
406
+ 2685
407
+ 2688
408
+ 2708
409
+ 2711
410
+ 2712
411
+ 2724
412
+ 2725
413
+ 2731
414
+ 2739
415
+ 2742
416
+ 2748
417
+ 2754
418
+ 2757
419
+ 2763
420
+ 2773
421
+ 2774
422
+ 2778
423
+ 2779
424
+ 2785
425
+ 2787
426
+ 2801
427
+ 2803
428
+ 2820
429
+ 2821
430
+ 2841
431
+ 2843
432
+ 2849
433
+ 2872
434
+ 2880
435
+ 2894
436
+ 2895
437
+ 2922
438
+ 2924
439
+ 2926
440
+ 2949
441
+ 2961
442
+ 2963
443
+ 2975
444
+ 2976
445
+ 2983
446
+ 2985
447
+ 2986
448
+ 2989
449
+ 2996
450
+ 2997
coral_seg/submissions/results.zip ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:19326a534acc1de1c4b4a901d94f11e92699cf347d3e13901f8da343a65c9502
3
+ size 950074
coral_seg/tools/__pycache__/check_data.cpython-312.pyc ADDED
Binary file (2.24 kB). View file
 
coral_seg/tools/__pycache__/create_splits.cpython-312.pyc ADDED
Binary file (1.73 kB). View file
 
coral_seg/tools/__pycache__/download_pretrained.cpython-312.pyc ADDED
Binary file (2.03 kB). View file
 
coral_seg/tools/__pycache__/eval_ensemble_val.cpython-312.pyc ADDED
Binary file (5.45 kB). View file
 
coral_seg/tools/__pycache__/eval_predictions.cpython-312.pyc ADDED
Binary file (7.2 kB). View file
 
coral_seg/tools/__pycache__/infer_ensemble.cpython-312.pyc ADDED
Binary file (10.4 kB). View file
 
coral_seg/tools/__pycache__/train_convnext.cpython-312.pyc ADDED
Binary file (11.2 kB). View file
 
coral_seg/tools/__pycache__/train_mask2former.cpython-312.pyc ADDED
Binary file (13.7 kB). View file
 
coral_seg/tools/__pycache__/visualize_results.cpython-312.pyc ADDED
Binary file (6.51 kB). View file
 
coral_seg/tools/check_data.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ import numpy as np
6
+ from PIL import Image
7
+
8
+ ROOT = Path(__file__).resolve().parents[1]
9
+ sys.path.insert(0, str(ROOT))
10
+
11
+ from coral_seg.utils import list_pngs, load_config
12
+
13
+
14
+ def main() -> None:
15
+ parser = argparse.ArgumentParser()
16
+ parser.add_argument("--config", default=str(ROOT / "configs/final_dual.yaml"))
17
+ args = parser.parse_args()
18
+ cfg = load_config(args.config)
19
+ for key in ("train_images", "train_masks", "test_images"):
20
+ paths = list_pngs(cfg["data"][key])
21
+ print(key, len(paths), paths[0].name if paths else None, paths[-1].name if paths else None)
22
+ values = set()
23
+ bad = []
24
+ for path in list_pngs(cfg["data"]["train_masks"]):
25
+ arr = np.array(Image.open(path))
26
+ unique = set(np.unique(arr).tolist())
27
+ values |= unique
28
+ if not unique <= {0, 1, 2, 3}:
29
+ bad.append((path.name, sorted(unique)))
30
+ print("mask values:", sorted(values))
31
+ print("bad masks:", len(bad), bad[:5])
32
+
33
+
34
+ if __name__ == "__main__":
35
+ main()
coral_seg/tools/create_splits.py ADDED
@@ -0,0 +1,31 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ ROOT = Path(__file__).resolve().parents[1]
6
+ sys.path.insert(0, str(ROOT))
7
+
8
+ from coral_seg.splits import create_split_files
9
+ from coral_seg.utils import load_config
10
+
11
+
12
+ def main() -> None:
13
+ parser = argparse.ArgumentParser()
14
+ parser.add_argument("--config", default=str(ROOT / "configs/final_dual.yaml"))
15
+ args = parser.parse_args()
16
+
17
+ cfg = load_config(args.config)
18
+ train_file, val_file, full_file = create_split_files(
19
+ cfg["data"]["train_images"],
20
+ cfg["data"]["train_masks"],
21
+ cfg["data"]["split_dir"],
22
+ val_ratio=float(cfg["data"].get("val_ratio", 0.15)),
23
+ seed=int(cfg.get("seed", 2026)),
24
+ )
25
+ print(f"train split: {train_file}")
26
+ print(f"val split: {val_file}")
27
+ print(f"full split: {full_file}")
28
+
29
+
30
+ if __name__ == "__main__":
31
+ main()
coral_seg/tools/download_pretrained.py ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import shutil
3
+ import sys
4
+ from pathlib import Path
5
+
6
+ import torch
7
+
8
+ ROOT = Path(__file__).resolve().parents[1]
9
+ sys.path.insert(0, str(ROOT))
10
+
11
+ from huggingface_hub import snapshot_download
12
+ from torchvision.models import ConvNeXt_Large_Weights, convnext_large
13
+
14
+ from coral_seg.utils import ensure_dir, load_config
15
+
16
+
17
+ def main() -> None:
18
+ parser = argparse.ArgumentParser()
19
+ parser.add_argument("--config", default=str(ROOT / "configs/final_dual.yaml"))
20
+ args = parser.parse_args()
21
+
22
+ cfg = load_config(args.config)
23
+ mask2former_dir = Path(cfg["mask2former"]["pretrained_dir"])
24
+ ensure_dir(mask2former_dir.parent)
25
+ has_mask2former_weight = (mask2former_dir / "model.safetensors").is_file() or (mask2former_dir / "pytorch_model.bin").is_file()
26
+ has_mask2former_config = (mask2former_dir / "config.json").is_file() and (mask2former_dir / "preprocessor_config.json").is_file()
27
+ if has_mask2former_weight and has_mask2former_config:
28
+ print(f"Mask2Former local files already exist: {mask2former_dir}")
29
+ else:
30
+ print("Downloading Mask2Former-Swin-B from HuggingFace cache/source...")
31
+ snapshot_download(
32
+ repo_id=cfg["mask2former"]["pretrained_name"],
33
+ local_dir=mask2former_dir,
34
+ local_dir_use_symlinks=False,
35
+ )
36
+ print(f"Mask2Former saved to {mask2former_dir}")
37
+
38
+ convnext_path = Path(cfg["convnext"].get("pretrained_path", ROOT / "pretrained/convnext_large-ea097f82.pth"))
39
+ ensure_dir(convnext_path.parent)
40
+ if convnext_path.is_file():
41
+ print(f"ConvNeXt-L local weight already exists: {convnext_path}")
42
+ else:
43
+ print("Downloading torchvision ConvNeXt-L ImageNet-1K weights...")
44
+ _ = convnext_large(weights=ConvNeXt_Large_Weights.IMAGENET1K_V1)
45
+ cache_name = Path(ConvNeXt_Large_Weights.IMAGENET1K_V1.url).name
46
+ cache_path = Path(torch.hub.get_dir()) / "checkpoints" / cache_name
47
+ if not cache_path.is_file():
48
+ raise FileNotFoundError(f"torchvision cache weight not found: {cache_path}")
49
+ shutil.copy2(cache_path, convnext_path)
50
+ print(f"ConvNeXt-L local weight saved to {convnext_path}")
51
+
52
+
53
+ if __name__ == "__main__":
54
+ main()
coral_seg/tools/eval_ensemble_val.py ADDED
@@ -0,0 +1,90 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import sys
3
+ from pathlib import Path
4
+
5
+ import numpy as np
6
+ import torch
7
+ from PIL import Image
8
+
9
+ ROOT = Path(__file__).resolve().parents[1]
10
+ sys.path.insert(0, str(ROOT))
11
+
12
+ from coral_seg.utils import compute_iou, fast_hist, format_metrics, load_config, read_image, set_seed
13
+ from coral_seg.splits import read_ids
14
+ from tools.infer_ensemble import load_convnext, load_mask2former, predict_convnext, predict_mask2former
15
+
16
+
17
+ def main() -> None:
18
+ parser = argparse.ArgumentParser()
19
+ parser.add_argument('--config', default=str(ROOT / 'configs/final_dual.yaml'))
20
+ parser.add_argument('--convnext-checkpoint', default='')
21
+ parser.add_argument('--mask2former-checkpoint', default='')
22
+ parser.add_argument('--split-file', default='')
23
+ parser.add_argument('--max-samples', type=int, default=0)
24
+ args = parser.parse_args()
25
+
26
+ cfg = load_config(args.config)
27
+ set_seed(int(cfg.get('seed', 2026)))
28
+ device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
29
+ infer_cfg = cfg['infer']
30
+ num_classes = int(cfg['num_classes'])
31
+
32
+ conv_model = load_convnext(args.convnext_checkpoint, cfg, device) if args.convnext_checkpoint else None
33
+ mask_model = load_mask2former(args.mask2former_checkpoint, cfg, device) if args.mask2former_checkpoint else None
34
+ if conv_model is None and mask_model is None:
35
+ raise ValueError('Provide --convnext-checkpoint and/or --mask2former-checkpoint')
36
+
37
+ conv_w = float(infer_cfg.get('convnext_weight', 0.45)) if conv_model is not None else 0.0
38
+ mask_w = float(infer_cfg.get('mask2former_weight', 0.55)) if mask_model is not None else 0.0
39
+ norm = max(1e-6, conv_w + mask_w)
40
+ conv_w /= norm
41
+ mask_w /= norm
42
+ flips = list(infer_cfg.get('tta_flips', ['none']))
43
+
44
+ split_file = args.split_file or str(Path(cfg['data']['split_dir']) / 'val.txt')
45
+ ids = read_ids(split_file)
46
+ if args.max_samples > 0:
47
+ ids = ids[:args.max_samples]
48
+
49
+ hist = np.zeros((num_classes, num_classes), dtype=np.int64)
50
+ image_dir = Path(cfg['data']['train_images'])
51
+ mask_dir = Path(cfg['data']['train_masks'])
52
+
53
+ for idx, sample_id in enumerate(ids, start=1):
54
+ image_path = image_dir / f'{sample_id}.png'
55
+ mask_path = mask_dir / f'{sample_id}.png'
56
+ image = read_image(image_path)
57
+ target = np.array(Image.open(mask_path), dtype=np.uint8)
58
+ total = None
59
+ if conv_model is not None:
60
+ probs = predict_convnext(
61
+ conv_model,
62
+ image,
63
+ infer_cfg.get('convnext_sizes', [cfg['convnext']['image_size']]),
64
+ flips,
65
+ num_classes,
66
+ device,
67
+ )
68
+ total = conv_w * probs if total is None else total + conv_w * probs
69
+ if mask_model is not None:
70
+ probs = predict_mask2former(
71
+ mask_model,
72
+ image,
73
+ infer_cfg.get('mask2former_sizes', [cfg['mask2former']['image_size']]),
74
+ flips,
75
+ num_classes,
76
+ device,
77
+ )
78
+ total = mask_w * probs if total is None else total + mask_w * probs
79
+ pred = total.argmax(dim=1).squeeze(0).cpu().numpy().astype(np.uint8)
80
+ hist += fast_hist(pred, target, num_classes)
81
+ if idx % 50 == 0 or idx == len(ids):
82
+ iou, miou = compute_iou(hist)
83
+ print(f'evaluated {idx}/{len(ids)} {format_metrics(iou, miou, cfg["class_names"])}')
84
+
85
+ iou, miou = compute_iou(hist)
86
+ print('final', format_metrics(iou, miou, cfg['class_names']))
87
+
88
+
89
+ if __name__ == '__main__':
90
+ main()
coral_seg/tools/eval_predictions.py ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from pathlib import Path
3
+ from typing import Dict, Tuple
4
+
5
+ import numpy as np
6
+ from PIL import Image
7
+
8
+ CLASS_NAMES = ['background', 'live_coral', 'dead_coral', 'bleached_coral']
9
+
10
+
11
+ def parse_color_map(text: str) -> Dict[Tuple[int, int, int], int]:
12
+ mapping = {}
13
+ if not text:
14
+ return mapping
15
+ for item in text.split(';'):
16
+ item = item.strip()
17
+ if not item:
18
+ continue
19
+ color, label = item.split(':')
20
+ rgb = tuple(int(x) for x in color.split(','))
21
+ if len(rgb) != 3:
22
+ raise ValueError(f'Bad RGB color: {color}')
23
+ mapping[rgb] = int(label)
24
+ return mapping
25
+
26
+
27
+ def read_pred(path: Path) -> np.ndarray:
28
+ arr = np.array(Image.open(path))
29
+ if arr.ndim == 3:
30
+ arr = arr[:, :, 0]
31
+ return arr.astype(np.uint8)
32
+
33
+
34
+ def read_gt(path: Path, color_map: Dict[Tuple[int, int, int], int]) -> np.ndarray:
35
+ arr = np.array(Image.open(path))
36
+ if arr.ndim == 2:
37
+ return arr.astype(np.uint8)
38
+ if not color_map:
39
+ colors = np.unique(arr.reshape(-1, arr.shape[-1])[:, :3], axis=0)
40
+ raise ValueError(
41
+ 'GT is RGB. Provide --color-map, for example '
42
+ '"0,0,0:0;0,162,232:1;240,110,170:2". '
43
+ f'Found colors: {colors.tolist()}'
44
+ )
45
+ rgb = arr[:, :, :3]
46
+ out = np.full(rgb.shape[:2], 255, dtype=np.uint8)
47
+ for color, label in color_map.items():
48
+ out[np.all(rgb == np.array(color, dtype=np.uint8), axis=-1)] = label
49
+ unknown = out == 255
50
+ if unknown.any():
51
+ colors = np.unique(rgb[unknown].reshape(-1, 3), axis=0)
52
+ raise ValueError(f'Unknown GT colors: {colors.tolist()}')
53
+ return out
54
+
55
+
56
+ def fast_hist(pred: np.ndarray, target: np.ndarray, num_classes: int) -> np.ndarray:
57
+ pred = pred.reshape(-1)
58
+ target = target.reshape(-1)
59
+ valid = (target >= 0) & (target < num_classes)
60
+ hist = np.bincount(num_classes * target[valid].astype(np.int64) + pred[valid].astype(np.int64), minlength=num_classes**2)
61
+ return hist.reshape(num_classes, num_classes)
62
+
63
+
64
+ def main() -> None:
65
+ parser = argparse.ArgumentParser()
66
+ parser.add_argument('--pred-dir', default='/root/autodl-tmp/coral/coral_seg/submissions/results')
67
+ parser.add_argument('--gt-dir', required=True)
68
+ parser.add_argument('--color-map', default='')
69
+ parser.add_argument('--num-classes', type=int, default=4)
70
+ args = parser.parse_args()
71
+
72
+ pred_dir = Path(args.pred_dir)
73
+ gt_dir = Path(args.gt_dir)
74
+ color_map = parse_color_map(args.color_map)
75
+ hist = np.zeros((args.num_classes, args.num_classes), dtype=np.int64)
76
+ count = 0
77
+ for pred_path in sorted(pred_dir.glob('*.png')):
78
+ gt_path = gt_dir / pred_path.name
79
+ if not gt_path.exists():
80
+ continue
81
+ pred = read_pred(pred_path)
82
+ gt = read_gt(gt_path, color_map)
83
+ if pred.shape != gt.shape:
84
+ raise ValueError(f'Shape mismatch for {pred_path.name}: pred={pred.shape}, gt={gt.shape}')
85
+ hist += fast_hist(pred, gt, args.num_classes)
86
+ count += 1
87
+ if count == 0:
88
+ raise RuntimeError('No matched prediction/GT PNG files found')
89
+ denom = hist.sum(1) + hist.sum(0) - np.diag(hist)
90
+ iou = np.divide(np.diag(hist), denom, out=np.full(args.num_classes, np.nan, dtype=np.float64), where=denom != 0)
91
+ print('matched_files:', count)
92
+ print('mIoU:', float(np.nanmean(iou)))
93
+ for idx, value in enumerate(iou):
94
+ name = CLASS_NAMES[idx] if idx < len(CLASS_NAMES) else f'class_{idx}'
95
+ print(f'{idx} {name}: {value}')
96
+
97
+
98
+ if __name__ == '__main__':
99
+ main()
coral_seg/tools/infer_ensemble.py ADDED
@@ -0,0 +1,189 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import sys
3
+ from pathlib import Path
4
+ from typing import Dict, Iterable, List, Optional
5
+
6
+ import cv2
7
+ import numpy as np
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from PIL import Image
11
+ from transformers import Mask2FormerForUniversalSegmentation
12
+
13
+ ROOT = Path(__file__).resolve().parents[1]
14
+ sys.path.insert(0, str(ROOT))
15
+
16
+ from coral_seg.model_convnext_fpn import ConvNeXtFPN
17
+ from coral_seg.utils import (
18
+ ensure_dir,
19
+ list_pngs,
20
+ load_config,
21
+ make_results_zip,
22
+ normalize_tensor,
23
+ read_image,
24
+ save_mask,
25
+ set_seed,
26
+ timestamp,
27
+ )
28
+ from tools.train_mask2former import semantic_logits_from_mask2former
29
+
30
+
31
+ def apply_flip_tensor(x: torch.Tensor, flip: str) -> torch.Tensor:
32
+ if flip == "h":
33
+ return torch.flip(x, dims=[-1])
34
+ if flip == "v":
35
+ return torch.flip(x, dims=[-2])
36
+ if flip == "hv":
37
+ return torch.flip(x, dims=[-2, -1])
38
+ return x
39
+
40
+
41
+ def resize_normalize(image: np.ndarray, size: int) -> torch.Tensor:
42
+ resized = cv2.resize(image, (size, size), interpolation=cv2.INTER_LINEAR)
43
+ return normalize_tensor(resized).unsqueeze(0)
44
+
45
+
46
+ def load_convnext(checkpoint: str, cfg: Dict, device: torch.device) -> ConvNeXtFPN:
47
+ model = ConvNeXtFPN(num_classes=int(cfg["num_classes"]), pretrained=False)
48
+ ckpt = torch.load(checkpoint, map_location="cpu")
49
+ model.load_state_dict(ckpt["model"], strict=True)
50
+ return model.to(device).eval()
51
+
52
+
53
+ def load_mask2former(path_or_ckpt: str, cfg: Dict, device: torch.device) -> Mask2FormerForUniversalSegmentation:
54
+ path = Path(path_or_ckpt)
55
+ if path.is_dir():
56
+ model = Mask2FormerForUniversalSegmentation.from_pretrained(path)
57
+ else:
58
+ mcfg = cfg["mask2former"]
59
+ base = mcfg.get("pretrained_dir") if Path(str(mcfg.get("pretrained_dir", ""))).exists() else mcfg["pretrained_name"]
60
+ model = Mask2FormerForUniversalSegmentation.from_pretrained(
61
+ base,
62
+ num_labels=int(cfg["num_classes"]),
63
+ ignore_mismatched_sizes=True,
64
+ )
65
+ ckpt = torch.load(path_or_ckpt, map_location="cpu")
66
+ model.load_state_dict(ckpt["model"], strict=True)
67
+ return model.to(device).eval()
68
+
69
+
70
+ @torch.no_grad()
71
+ def predict_convnext(
72
+ model: ConvNeXtFPN,
73
+ image: np.ndarray,
74
+ sizes: Iterable[int],
75
+ flips: Iterable[str],
76
+ num_classes: int,
77
+ device: torch.device,
78
+ ) -> torch.Tensor:
79
+ h, w = image.shape[:2]
80
+ probs_sum = torch.zeros((1, num_classes, h, w), device=device)
81
+ count = 0
82
+ for size in sizes:
83
+ x = resize_normalize(image, int(size)).to(device)
84
+ for flip in flips:
85
+ xf = apply_flip_tensor(x, flip)
86
+ logits = model(xf)
87
+ logits = apply_flip_tensor(logits, flip)
88
+ logits = F.interpolate(logits, size=(h, w), mode="bilinear", align_corners=False)
89
+ probs_sum += torch.softmax(logits, dim=1)
90
+ count += 1
91
+ return probs_sum / max(1, count)
92
+
93
+
94
+ @torch.no_grad()
95
+ def predict_mask2former(
96
+ model: Mask2FormerForUniversalSegmentation,
97
+ image: np.ndarray,
98
+ sizes: Iterable[int],
99
+ flips: Iterable[str],
100
+ num_classes: int,
101
+ device: torch.device,
102
+ ) -> torch.Tensor:
103
+ h, w = image.shape[:2]
104
+ probs_sum = torch.zeros((1, num_classes, h, w), device=device)
105
+ count = 0
106
+ for size in sizes:
107
+ x = resize_normalize(image, int(size)).to(device)
108
+ for flip in flips:
109
+ xf = apply_flip_tensor(x, flip)
110
+ outputs = model(pixel_values=xf)
111
+ logits = semantic_logits_from_mask2former(outputs, target_size=(h, w))
112
+ logits = apply_flip_tensor(logits, flip)
113
+ probs_sum += torch.softmax(logits, dim=1)
114
+ count += 1
115
+ return probs_sum / max(1, count)
116
+
117
+
118
+ def main() -> None:
119
+ parser = argparse.ArgumentParser()
120
+ parser.add_argument("--config", default=str(ROOT / "configs/final_dual.yaml"))
121
+ parser.add_argument("--convnext-checkpoint", default="")
122
+ parser.add_argument("--mask2former-checkpoint", default="")
123
+ parser.add_argument("--test-dir", default="")
124
+ parser.add_argument("--out-dir", default="")
125
+ parser.add_argument("--zip-path", default="")
126
+ parser.add_argument("--no-zip", action="store_true")
127
+ args = parser.parse_args()
128
+
129
+ cfg = load_config(args.config)
130
+ set_seed(int(cfg.get("seed", 2026)))
131
+ infer_cfg = cfg["infer"]
132
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
133
+ test_dir = args.test_dir or cfg["data"]["test_images"]
134
+ out_dir = ensure_dir(args.out_dir or infer_cfg["out_dir"])
135
+ num_classes = int(cfg["num_classes"])
136
+
137
+ conv_model = None
138
+ mask_model = None
139
+ if args.convnext_checkpoint:
140
+ conv_model = load_convnext(args.convnext_checkpoint, cfg, device)
141
+ if args.mask2former_checkpoint:
142
+ mask_model = load_mask2former(args.mask2former_checkpoint, cfg, device)
143
+ if conv_model is None and mask_model is None:
144
+ raise ValueError("Provide at least one checkpoint: --convnext-checkpoint or --mask2former-checkpoint")
145
+
146
+ conv_w = float(infer_cfg.get("convnext_weight", 0.45)) if conv_model is not None else 0.0
147
+ mask_w = float(infer_cfg.get("mask2former_weight", 0.55)) if mask_model is not None else 0.0
148
+ norm = max(1e-6, conv_w + mask_w)
149
+ conv_w /= norm
150
+ mask_w /= norm
151
+ flips = list(infer_cfg.get("tta_flips", ["none"]))
152
+
153
+ image_paths = list_pngs(test_dir)
154
+ for idx, image_path in enumerate(image_paths, start=1):
155
+ image = read_image(image_path)
156
+ total = None
157
+ if conv_model is not None:
158
+ probs = predict_convnext(
159
+ conv_model,
160
+ image,
161
+ infer_cfg.get("convnext_sizes", [cfg["convnext"]["image_size"]]),
162
+ flips,
163
+ num_classes,
164
+ device,
165
+ )
166
+ total = conv_w * probs if total is None else total + conv_w * probs
167
+ if mask_model is not None:
168
+ probs = predict_mask2former(
169
+ mask_model,
170
+ image,
171
+ infer_cfg.get("mask2former_sizes", [cfg["mask2former"]["image_size"]]),
172
+ flips,
173
+ num_classes,
174
+ device,
175
+ )
176
+ total = mask_w * probs if total is None else total + mask_w * probs
177
+ pred = total.argmax(dim=1).squeeze(0).cpu().numpy().astype(np.uint8)
178
+ save_mask(out_dir / image_path.name, pred)
179
+ if idx % 50 == 0 or idx == len(image_paths):
180
+ print(f"{timestamp()} inferred {idx}/{len(image_paths)}")
181
+
182
+ if not args.no_zip:
183
+ zip_path = args.zip_path or infer_cfg["zip_path"]
184
+ make_results_zip(out_dir, zip_path)
185
+ print(f"saved zip: {zip_path}")
186
+
187
+
188
+ if __name__ == "__main__":
189
+ main()
coral_seg/tools/train_convnext.py ADDED
@@ -0,0 +1,212 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import functools
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Dict
6
+
7
+ import numpy as np
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from torch.cuda.amp import GradScaler, autocast
11
+ from torch.optim import AdamW
12
+ from torch.optim.lr_scheduler import LambdaLR
13
+ from torch.utils.data import DataLoader
14
+
15
+ ROOT = Path(__file__).resolve().parents[1]
16
+ sys.path.insert(0, str(ROOT))
17
+
18
+ from coral_seg.dataset import CoralSegDataset, build_train_transform, build_val_transform, segmentation_collate
19
+ from coral_seg.losses import ComboSegLoss
20
+ from coral_seg.model_convnext_fpn import ConvNeXtFPN
21
+ from coral_seg.splits import create_split_files
22
+ from coral_seg.utils import (
23
+ AverageMeter,
24
+ compute_iou,
25
+ cosine_warmup_lambda,
26
+ ensure_dir,
27
+ fast_hist,
28
+ format_metrics,
29
+ load_config,
30
+ save_json,
31
+ set_seed,
32
+ timestamp,
33
+ )
34
+
35
+
36
+ def build_loaders(cfg: Dict, image_size: int, batch_size: int, full_train: bool) -> tuple[DataLoader, DataLoader | None]:
37
+ data_cfg = cfg["data"]
38
+ train_file, val_file, full_file = create_split_files(
39
+ data_cfg["train_images"],
40
+ data_cfg["train_masks"],
41
+ data_cfg["split_dir"],
42
+ val_ratio=float(data_cfg.get("val_ratio", 0.15)),
43
+ seed=int(cfg.get("seed", 2026)),
44
+ )
45
+ split_file = full_file if full_train else train_file
46
+ train_ds = CoralSegDataset(
47
+ data_cfg["train_images"],
48
+ data_cfg["train_masks"],
49
+ str(split_file),
50
+ build_train_transform(image_size),
51
+ )
52
+ train_loader = DataLoader(
53
+ train_ds,
54
+ batch_size=batch_size,
55
+ shuffle=True,
56
+ num_workers=int(cfg["train"].get("num_workers", 8)),
57
+ pin_memory=True,
58
+ drop_last=True,
59
+ collate_fn=segmentation_collate,
60
+ persistent_workers=int(cfg["train"].get("num_workers", 8)) > 0,
61
+ )
62
+ val_loader = None
63
+ if not full_train:
64
+ val_ds = CoralSegDataset(
65
+ data_cfg["train_images"],
66
+ data_cfg["train_masks"],
67
+ str(val_file),
68
+ build_val_transform(image_size),
69
+ )
70
+ val_loader = DataLoader(
71
+ val_ds,
72
+ batch_size=batch_size,
73
+ shuffle=False,
74
+ num_workers=int(cfg["train"].get("num_workers", 8)),
75
+ pin_memory=True,
76
+ collate_fn=segmentation_collate,
77
+ persistent_workers=int(cfg["train"].get("num_workers", 8)) > 0,
78
+ )
79
+ return train_loader, val_loader
80
+
81
+
82
+ @torch.no_grad()
83
+ def validate(model: torch.nn.Module, loader: DataLoader, cfg: Dict, device: torch.device) -> tuple[float, np.ndarray]:
84
+ model.eval()
85
+ num_classes = int(cfg["num_classes"])
86
+ hist = np.zeros((num_classes, num_classes), dtype=np.int64)
87
+ for batch in loader:
88
+ images = batch["image"].to(device, non_blocking=True)
89
+ masks = batch["mask"].numpy()
90
+ logits = model(images)
91
+ preds = logits.argmax(dim=1).cpu().numpy().astype(np.uint8)
92
+ for pred, target in zip(preds, masks):
93
+ hist += fast_hist(pred, target, num_classes)
94
+ iou, miou = compute_iou(hist)
95
+ return miou, iou
96
+
97
+
98
+ def main() -> None:
99
+ parser = argparse.ArgumentParser()
100
+ parser.add_argument("--config", default=str(ROOT / "configs/final_dual.yaml"))
101
+ parser.add_argument("--resume", default="")
102
+ parser.add_argument("--full-train", action="store_true")
103
+ args = parser.parse_args()
104
+
105
+ cfg = load_config(args.config)
106
+ set_seed(int(cfg.get("seed", 2026)))
107
+ conv_cfg = cfg["convnext"]
108
+ work_dir = ensure_dir(conv_cfg["work_dir"])
109
+ save_json(work_dir / "resolved_config.json", cfg)
110
+
111
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
112
+ train_loader, val_loader = build_loaders(
113
+ cfg,
114
+ image_size=int(conv_cfg["image_size"]),
115
+ batch_size=int(conv_cfg["batch_size"]),
116
+ full_train=args.full_train,
117
+ )
118
+
119
+ model = ConvNeXtFPN(
120
+ num_classes=int(cfg["num_classes"]),
121
+ pretrained=bool(conv_cfg.get("pretrained", True)),
122
+ pretrained_path=conv_cfg.get("pretrained_path"),
123
+ ).to(device)
124
+
125
+ if args.resume:
126
+ ckpt = torch.load(args.resume, map_location="cpu")
127
+ model.load_state_dict(ckpt["model"], strict=True)
128
+
129
+ loss_cfg = conv_cfg["loss"]
130
+ criterion = ComboSegLoss(
131
+ num_classes=int(cfg["num_classes"]),
132
+ ce_weight=float(loss_cfg.get("ce", 1.0)),
133
+ dice_weight=float(loss_cfg.get("dice", 1.0)),
134
+ lovasz_weight=float(loss_cfg.get("lovasz", 0.5)),
135
+ label_smoothing=float(loss_cfg.get("label_smoothing", 0.05)),
136
+ )
137
+
138
+ backbone_params = []
139
+ head_params = []
140
+ for name, param in model.named_parameters():
141
+ if not param.requires_grad:
142
+ continue
143
+ if name.startswith("features"):
144
+ backbone_params.append(param)
145
+ else:
146
+ head_params.append(param)
147
+
148
+ optimizer = AdamW(
149
+ [
150
+ {"params": backbone_params, "lr": float(conv_cfg["lr"]) * float(conv_cfg.get("backbone_lr_mult", 0.25))},
151
+ {"params": head_params, "lr": float(conv_cfg["lr"])},
152
+ ],
153
+ weight_decay=float(conv_cfg["weight_decay"]),
154
+ )
155
+ epochs = int(conv_cfg["epochs"])
156
+ total_steps = epochs * len(train_loader)
157
+ warmup_steps = int(conv_cfg.get("warmup_epochs", 5)) * len(train_loader)
158
+ scheduler = LambdaLR(
159
+ optimizer,
160
+ functools.partial(cosine_warmup_lambda, total_steps=total_steps, warmup_steps=warmup_steps),
161
+ )
162
+ scaler = GradScaler(enabled=bool(cfg["train"].get("amp", True)))
163
+ best_miou = -1.0
164
+
165
+ for epoch in range(1, epochs + 1):
166
+ model.train()
167
+ meter = AverageMeter()
168
+ for step, batch in enumerate(train_loader, start=1):
169
+ images = batch["image"].to(device, non_blocking=True)
170
+ masks = batch["mask"].to(device, non_blocking=True)
171
+ optimizer.zero_grad(set_to_none=True)
172
+ with autocast(enabled=bool(cfg["train"].get("amp", True))):
173
+ logits = model(images)
174
+ loss = criterion(logits, masks, epoch)
175
+ scaler.scale(loss).backward()
176
+ grad_clip = float(cfg["train"].get("grad_clip_norm", 0.0))
177
+ if grad_clip > 0:
178
+ scaler.unscale_(optimizer)
179
+ torch.nn.utils.clip_grad_norm_(model.parameters(), grad_clip)
180
+ scaler.step(optimizer)
181
+ scaler.update()
182
+ scheduler.step()
183
+ meter.update(loss.item(), images.size(0))
184
+ if step % int(cfg["train"].get("print_freq", 50)) == 0:
185
+ lr = optimizer.param_groups[-1]["lr"]
186
+ print(f"{timestamp()} epoch={epoch}/{epochs} step={step}/{len(train_loader)} loss={meter.avg:.5f} lr={lr:.8f}")
187
+
188
+ metrics = {"epoch": epoch, "train_loss": meter.avg}
189
+ if val_loader is not None:
190
+ miou, iou = validate(model, val_loader, cfg, device)
191
+ metrics.update({"val_miou": miou, "val_iou": iou.tolist()})
192
+ print(f"{timestamp()} convnext val {format_metrics(iou, miou, cfg['class_names'])}")
193
+ is_best = miou > best_miou
194
+ best_miou = max(best_miou, miou)
195
+ else:
196
+ is_best = True
197
+
198
+ state = {
199
+ "model": model.state_dict(),
200
+ "epoch": epoch,
201
+ "best_miou": best_miou,
202
+ "config": cfg,
203
+ "metrics": metrics,
204
+ }
205
+ torch.save(state, work_dir / "latest.pth")
206
+ if is_best:
207
+ torch.save(state, work_dir / "best.pth")
208
+ print(f"{timestamp()} saved {work_dir / 'best.pth'}")
209
+
210
+
211
+ if __name__ == "__main__":
212
+ main()
coral_seg/tools/train_mask2former.py ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ import functools
3
+ import sys
4
+ from pathlib import Path
5
+ from typing import Dict, List
6
+
7
+ import numpy as np
8
+ import torch
9
+ import torch.nn.functional as F
10
+ from torch.cuda.amp import GradScaler, autocast
11
+ from torch.optim import AdamW
12
+ from torch.optim.lr_scheduler import LambdaLR
13
+ from torch.utils.data import DataLoader
14
+ from transformers import Mask2FormerForUniversalSegmentation
15
+
16
+ ROOT = Path(__file__).resolve().parents[1]
17
+ sys.path.insert(0, str(ROOT))
18
+
19
+ from coral_seg.dataset import CoralSegDataset, build_train_transform, build_val_transform, mask2former_collate
20
+ from coral_seg.splits import create_split_files
21
+ from coral_seg.utils import (
22
+ AverageMeter,
23
+ compute_iou,
24
+ cosine_warmup_lambda,
25
+ ensure_dir,
26
+ fast_hist,
27
+ format_metrics,
28
+ load_config,
29
+ save_json,
30
+ set_seed,
31
+ timestamp,
32
+ )
33
+
34
+
35
+ def semantic_logits_from_mask2former(outputs, target_size: tuple[int, int]) -> torch.Tensor:
36
+ class_logits = outputs.class_queries_logits
37
+ mask_logits = outputs.masks_queries_logits
38
+ class_probs = torch.softmax(class_logits, dim=-1)[..., :-1]
39
+ mask_probs = torch.sigmoid(mask_logits)
40
+ semseg = torch.einsum("bqc,bqhw->bchw", class_probs, mask_probs)
41
+ return F.interpolate(semseg, size=target_size, mode="bilinear", align_corners=False)
42
+
43
+
44
+ def build_model(cfg: Dict) -> Mask2FormerForUniversalSegmentation:
45
+ mcfg = cfg["mask2former"]
46
+ id2label = {i: name for i, name in enumerate(cfg["class_names"])}
47
+ label2id = {name: i for i, name in id2label.items()}
48
+ model_name_or_path = mcfg.get("pretrained_dir") or mcfg["pretrained_name"]
49
+ if not Path(str(model_name_or_path)).exists():
50
+ model_name_or_path = mcfg["pretrained_name"]
51
+ model = Mask2FormerForUniversalSegmentation.from_pretrained(
52
+ model_name_or_path,
53
+ num_labels=int(cfg["num_classes"]),
54
+ id2label=id2label,
55
+ label2id=label2id,
56
+ ignore_mismatched_sizes=True,
57
+ )
58
+ if bool(mcfg.get("gradient_checkpointing", True)):
59
+ try:
60
+ model.gradient_checkpointing_enable()
61
+ except ValueError:
62
+ print("Gradient checkpointing is not supported by this Mask2Former class; continuing without it.")
63
+ return model
64
+
65
+
66
+ def build_loaders(cfg: Dict, image_size: int, batch_size: int, full_train: bool) -> tuple[DataLoader, DataLoader | None]:
67
+ data_cfg = cfg["data"]
68
+ train_file, val_file, full_file = create_split_files(
69
+ data_cfg["train_images"],
70
+ data_cfg["train_masks"],
71
+ data_cfg["split_dir"],
72
+ val_ratio=float(data_cfg.get("val_ratio", 0.15)),
73
+ seed=int(cfg.get("seed", 2026)),
74
+ )
75
+ split_file = full_file if full_train else train_file
76
+ collate = functools.partial(mask2former_collate, num_classes=int(cfg["num_classes"]))
77
+ train_ds = CoralSegDataset(
78
+ data_cfg["train_images"],
79
+ data_cfg["train_masks"],
80
+ str(split_file),
81
+ build_train_transform(image_size),
82
+ )
83
+ train_loader = DataLoader(
84
+ train_ds,
85
+ batch_size=batch_size,
86
+ shuffle=True,
87
+ num_workers=int(cfg["train"].get("num_workers", 8)),
88
+ pin_memory=True,
89
+ drop_last=True,
90
+ collate_fn=collate,
91
+ persistent_workers=int(cfg["train"].get("num_workers", 8)) > 0,
92
+ )
93
+ val_loader = None
94
+ if not full_train:
95
+ val_ds = CoralSegDataset(
96
+ data_cfg["train_images"],
97
+ data_cfg["train_masks"],
98
+ str(val_file),
99
+ build_val_transform(image_size),
100
+ )
101
+ val_loader = DataLoader(
102
+ val_ds,
103
+ batch_size=batch_size,
104
+ shuffle=False,
105
+ num_workers=int(cfg["train"].get("num_workers", 8)),
106
+ pin_memory=True,
107
+ collate_fn=collate,
108
+ persistent_workers=int(cfg["train"].get("num_workers", 8)) > 0,
109
+ )
110
+ return train_loader, val_loader
111
+
112
+
113
+ @torch.no_grad()
114
+ def validate(model: torch.nn.Module, loader: DataLoader, cfg: Dict, device: torch.device) -> tuple[float, np.ndarray]:
115
+ model.eval()
116
+ num_classes = int(cfg["num_classes"])
117
+ hist = np.zeros((num_classes, num_classes), dtype=np.int64)
118
+ for batch in loader:
119
+ images = batch["image"].to(device, non_blocking=True)
120
+ masks = batch["raw_mask"].numpy()
121
+ outputs = model(pixel_values=images)
122
+ logits = semantic_logits_from_mask2former(outputs, target_size=masks.shape[-2:])
123
+ preds = logits.argmax(dim=1).cpu().numpy().astype(np.uint8)
124
+ for pred, target in zip(preds, masks):
125
+ hist += fast_hist(pred, target, num_classes)
126
+ iou, miou = compute_iou(hist)
127
+ return miou, iou
128
+
129
+
130
+ def main() -> None:
131
+ parser = argparse.ArgumentParser()
132
+ parser.add_argument("--config", default=str(ROOT / "configs/final_dual.yaml"))
133
+ parser.add_argument("--resume", default="")
134
+ parser.add_argument("--full-train", action="store_true")
135
+ args = parser.parse_args()
136
+
137
+ cfg = load_config(args.config)
138
+ set_seed(int(cfg.get("seed", 2026)))
139
+ mcfg = cfg["mask2former"]
140
+ work_dir = ensure_dir(mcfg["work_dir"])
141
+ save_json(work_dir / "resolved_config.json", cfg)
142
+
143
+ device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
144
+ train_loader, val_loader = build_loaders(
145
+ cfg,
146
+ image_size=int(mcfg["image_size"]),
147
+ batch_size=int(mcfg["batch_size"]),
148
+ full_train=args.full_train,
149
+ )
150
+ model = build_model(cfg).to(device)
151
+ if args.resume:
152
+ ckpt = torch.load(args.resume, map_location="cpu")
153
+ model.load_state_dict(ckpt["model"], strict=True)
154
+
155
+ no_decay = ("bias", "LayerNorm.weight", "layer_norm.weight", "norm.weight")
156
+ grouped = [
157
+ {
158
+ "params": [p for n, p in model.named_parameters() if p.requires_grad and not any(nd in n for nd in no_decay)],
159
+ "weight_decay": float(mcfg["weight_decay"]),
160
+ },
161
+ {
162
+ "params": [p for n, p in model.named_parameters() if p.requires_grad and any(nd in n for nd in no_decay)],
163
+ "weight_decay": 0.0,
164
+ },
165
+ ]
166
+ optimizer = AdamW(grouped, lr=float(mcfg["lr"]))
167
+ epochs = int(mcfg["epochs"])
168
+ total_steps = epochs * len(train_loader)
169
+ warmup_steps = int(mcfg.get("warmup_epochs", 5)) * len(train_loader)
170
+ scheduler = LambdaLR(
171
+ optimizer,
172
+ functools.partial(cosine_warmup_lambda, total_steps=total_steps, warmup_steps=warmup_steps),
173
+ )
174
+ scaler = GradScaler(enabled=bool(cfg["train"].get("amp", True)))
175
+ best_miou = -1.0
176
+
177
+ for epoch in range(1, epochs + 1):
178
+ model.train()
179
+ meter = AverageMeter()
180
+ for step, batch in enumerate(train_loader, start=1):
181
+ images = batch["image"].to(device, non_blocking=True)
182
+ mask_labels = [m.to(device, non_blocking=True) for m in batch["mask_labels"]]
183
+ class_labels = [c.to(device, non_blocking=True) for c in batch["class_labels"]]
184
+ optimizer.zero_grad(set_to_none=True)
185
+ with autocast(enabled=bool(cfg["train"].get("amp", True))):
186
+ outputs = model(pixel_values=images, mask_labels=mask_labels, class_labels=class_labels)
187
+ loss = outputs.loss
188
+ scaler.scale(loss).backward()
189
+ grad_clip = float(cfg["train"].get("grad_clip_norm", 0.0))
190
+ if grad_clip > 0:
191
+ scaler.unscale_(optimizer)
192
+ torch.nn.utils.clip_grad_norm_(model.parameters(), grad_clip)
193
+ scaler.step(optimizer)
194
+ scaler.update()
195
+ scheduler.step()
196
+ meter.update(loss.item(), images.size(0))
197
+ if step % int(cfg["train"].get("print_freq", 50)) == 0:
198
+ lr = optimizer.param_groups[0]["lr"]
199
+ print(f"{timestamp()} epoch={epoch}/{epochs} step={step}/{len(train_loader)} loss={meter.avg:.5f} lr={lr:.8f}")
200
+
201
+ metrics = {"epoch": epoch, "train_loss": meter.avg}
202
+ if val_loader is not None:
203
+ miou, iou = validate(model, val_loader, cfg, device)
204
+ metrics.update({"val_miou": miou, "val_iou": iou.tolist()})
205
+ print(f"{timestamp()} mask2former val {format_metrics(iou, miou, cfg['class_names'])}")
206
+ is_best = miou > best_miou
207
+ best_miou = max(best_miou, miou)
208
+ else:
209
+ is_best = True
210
+
211
+ state = {
212
+ "model": model.state_dict(),
213
+ "epoch": epoch,
214
+ "best_miou": best_miou,
215
+ "config": cfg,
216
+ "metrics": metrics,
217
+ }
218
+ torch.save(state, work_dir / "latest.pth")
219
+ if is_best:
220
+ torch.save(state, work_dir / "best.pth")
221
+ model.save_pretrained(work_dir / "best_hf")
222
+ print(f"{timestamp()} saved {work_dir / 'best.pth'} and {work_dir / 'best_hf'}")
223
+
224
+
225
+ if __name__ == "__main__":
226
+ main()
coral_seg/tools/visualize_results.py ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import argparse
2
+ from pathlib import Path
3
+ from typing import Optional
4
+
5
+ import numpy as np
6
+ from PIL import Image, ImageDraw, ImageFont
7
+
8
+ PALETTE = np.array(
9
+ [
10
+ [0, 0, 0],
11
+ [0, 162, 232],
12
+ [240, 110, 170],
13
+ [255, 242, 0],
14
+ ],
15
+ dtype=np.uint8,
16
+ )
17
+
18
+
19
+ def label_to_color(mask: np.ndarray) -> np.ndarray:
20
+ mask = np.asarray(mask)
21
+ if mask.ndim == 3:
22
+ return mask.astype(np.uint8)
23
+ mask = np.clip(mask, 0, len(PALETTE) - 1)
24
+ return PALETTE[mask]
25
+
26
+
27
+ def overlay(image: np.ndarray, color_mask: np.ndarray, alpha: float = 0.45) -> np.ndarray:
28
+ image = image.astype(np.float32)
29
+ color_mask = color_mask.astype(np.float32)
30
+ fg = color_mask.sum(axis=-1) > 0
31
+ out = image.copy()
32
+ out[fg] = image[fg] * (1.0 - alpha) + color_mask[fg] * alpha
33
+ return np.clip(out, 0, 255).astype(np.uint8)
34
+
35
+
36
+ def add_title(arr: np.ndarray, title: str) -> np.ndarray:
37
+ h, w = arr.shape[:2]
38
+ canvas = np.full((h + 28, w, 3), 255, dtype=np.uint8)
39
+ canvas[28:] = arr
40
+ img = Image.fromarray(canvas)
41
+ draw = ImageDraw.Draw(img)
42
+ draw.text((8, 7), title, fill=(0, 0, 0))
43
+ return np.array(img)
44
+
45
+
46
+ def read_rgb(path: Path) -> np.ndarray:
47
+ return np.array(Image.open(path).convert('RGB'))
48
+
49
+
50
+ def read_mask(path: Path) -> np.ndarray:
51
+ arr = np.array(Image.open(path))
52
+ if arr.ndim == 3:
53
+ return arr[:, :, :3]
54
+ return arr.astype(np.uint8)
55
+
56
+
57
+ def main() -> None:
58
+ parser = argparse.ArgumentParser()
59
+ parser.add_argument('--image-dir', default='/root/autodl-tmp/coral/data_fresh/test_raw/PrecisionLabel800/images')
60
+ parser.add_argument('--pred-dir', default='/root/autodl-tmp/coral/coral_seg/submissions/results')
61
+ parser.add_argument('--gt-dir', default='')
62
+ parser.add_argument('--out-dir', default='/root/autodl-tmp/coral/coral_seg/vis_results')
63
+ parser.add_argument('--num', type=int, default=24)
64
+ parser.add_argument('--alpha', type=float, default=0.45)
65
+ args = parser.parse_args()
66
+
67
+ image_dir = Path(args.image_dir)
68
+ pred_dir = Path(args.pred_dir)
69
+ gt_dir = Path(args.gt_dir) if args.gt_dir else None
70
+ out_dir = Path(args.out_dir)
71
+ out_dir.mkdir(parents=True, exist_ok=True)
72
+
73
+ pred_paths = sorted(pred_dir.glob('*.png'))[: args.num]
74
+ if not pred_paths:
75
+ raise RuntimeError(f'No prediction PNG files found in {pred_dir}')
76
+
77
+ for pred_path in pred_paths:
78
+ image_path = image_dir / pred_path.name
79
+ if not image_path.exists():
80
+ raise FileNotFoundError(image_path)
81
+ image = read_rgb(image_path)
82
+ pred = read_mask(pred_path)
83
+ pred_color = label_to_color(pred)
84
+ panels = [
85
+ add_title(image, 'image'),
86
+ add_title(pred_color, 'prediction'),
87
+ add_title(overlay(image, pred_color, args.alpha), 'pred overlay'),
88
+ ]
89
+ if gt_dir is not None:
90
+ gt_path = gt_dir / pred_path.name
91
+ if gt_path.exists():
92
+ gt = read_mask(gt_path)
93
+ gt_color = label_to_color(gt)
94
+ panels.append(add_title(gt_color, 'gt'))
95
+ panels.append(add_title(overlay(image, gt_color, args.alpha), 'gt overlay'))
96
+ canvas = np.concatenate(panels, axis=1)
97
+ Image.fromarray(canvas).save(out_dir / pred_path.name)
98
+ print(f'saved {len(pred_paths)} visualizations to {out_dir}')
99
+
100
+
101
+ if __name__ == '__main__':
102
+ main()
coral_seg/vis_results/image_0001.png ADDED

Git LFS Details

  • SHA256: 5a699870ed3aa0f710b8c4b72c18e42696701cc6f5b70f3b2c5f87dc2e6dbe03
  • Pointer size: 131 Bytes
  • Size of remote file: 234 kB