基于深度学习的太阳活动区(黑子)磁类型图像分类项目,参加天池竞赛 531803。
任务为将太阳活动区的观测图像分为三个磁类型类别:Alpha、Beta、BetaX。每个活动区提供两种观测图:白光图(continuum)与磁图(magnetogram),原始数据为天文领域常用的 FITS 格式。
整体方案为:FITS 转 PNG(含数据增强)→ 可选的白光图 / 磁图加权融合 → 构建 tf.data 数据集(按活动区观测日划分,避免数据泄漏)→ 微调多个 ImageNet 预训练卷积网络 → 预测 → 多模型投票融合。
sun-spot/
├── README.md
├── requriments.txt # Python 依赖清单
├── .gitignore
└── src/
├── train_data_trans_png.py # 训练集 FITS → PNG(含数据增强、类别平衡)
├── test_dataset_trans_png.py # 测试集 FITS → PNG
├── addweight.py # 训练集:白光图 + 磁图按权重融合为单张图
├── test_pic_addweight.py # 测试集:白光图 + 磁图按权重融合(权重由命令行传入)
├── data_factory.py # 读取 PNG 目录,构建训练 / 验证 / 全量 Dataset
├── predict_pic.py # 加载 checkpoint,对测试集预测并写出结果文件
├── make_result.py # 多模型预测结果投票融合
└── model/ # 各网络结构 + 训练脚本
├── sunspot_private_conv_model.py # 自定义 3 层卷积网络(杨博士提出)
├── sunspot_resnet50.py # ResNet50 fine-tuning
├── sunspot_nas_net_large.py # NASNetLarge fine-tuning
├── sunspot_inception.py # InceptionV3 fine-tuning
├── sunspot_inception_resnet.py # InceptionResNetV2 fine-tuning
└── sunspot_vgg16.py # VGG16(占位,待实现)
- Python 3.x
- TensorFlow 2.2.0(核心训练框架)
- astropy 4.0(读取 FITS 天文数据)
- opencv-python、Pillow、matplotlib(图像处理与保存)
- scikit-learn(F1 / precision / recall 等评估指标)
- pandas、numpy
安装:
pip install -r requriments.txt说明:训练脚本默认使用 ImageNet 预训练权重,首次运行会自动下载对应模型权重。
原始数据按 类型/类别 组织,每个活动区在 continuum(白光图)和 magnetogram(磁图)下各有对应的 FITS 文件,类别为 alpha / beta / betax。
转换时读取 FITS 数据并归一化到 [0, 1] 区间后保存为 PNG:
python src/train_data_trans_png.py # 训练集转换(含数据增强)
python src/test_dataset_trans_png.py # 测试集转换数据增强(在训练集转换中完成,用于平衡类别):
- BetaX:每张图都做水平镜像和对角线镜像,分别另存为
_1、_2。 - Alpha:每隔一张图做一次水平镜像,另存为
_1。 - 关键点:白光图与磁图的增强必须一一对应(同一活动区两种图做相同变换)。
增强后三类数据量基本均衡。
将同一活动区的白光图与磁图按权重 alpha 用 cv2.addWeighted 融合成单张图,作为模型输入的一种方案:
python src/addweight.py # 训练集融合,权重固定 0.5
python src/test_pic_addweight.py 9 # 测试集融合,命令行参数为权重(如 9 表示 0.9)data_factory.py 读取 PNG 目录,自动按父目录名映射标签(alpha→0、beta→1、betax→2,按字母排序),并构建 tf.data.Dataset:
get_ds(...):返回训练集与验证集。get_alldata_ds(...):返回全量数据集(用于全量训练)。
训练 / 验证集划分(防数据泄漏): 按文件名解析活动区编号与观测日,把同一活动区的不同观测日分别划入训练集或验证集,确保同一活动区不会同时出现在两边:
- 观测天数 > 4 的活动区:按
[1::3]抽取观测日作为验证集,其余为训练集。 - 观测天数 ≤ 4 的活动区:随机抽取 30% 整体作为验证集,其余为训练集。
src/model/ 下每个文件既是网络结构定义,也是可直接运行的训练脚本。除自定义卷积网络外,均采用 ImageNet 预训练模型做迁移学习(Fine-Tuning):在卷积主干后接 GlobalAveragePooling2D → Dense(1024) → Dropout → Dense(512) → Dropout → Dense(3, softmax) 的分类头。
| 文件 | 主干网络 | 说明 |
|---|---|---|
sunspot_private_conv_model.py |
自定义 3 层卷积网络 | 杨博士提出的结构,输入 500×500,用于第一版基线 |
sunspot_resnet50.py |
ResNet50 | 冻结前 80% 层,微调后 20% 层 |
sunspot_nas_net_large.py |
NASNetLarge | 冻结主干,仅训练分类头 |
sunspot_inception.py |
InceptionV3 | 迁移学习 |
sunspot_inception_resnet.py |
InceptionResNetV2 | 迁移学习 |
sunspot_vgg16.py |
VGG16 | 占位,待实现 |
选型思路:由于训练与推理均离线进行、对算力与速度无要求,因此不限制网络参数量、尽量使用更大的输入尺寸,并选取 Keras Applications 中 Top-1 / Top-5 Accuracy 排名靠前的若干模型。
训练相关公共组件:
- 自定义
Metrics回调:每个 epoch 结束打印 macro F1、recall、precision 及三分类classification_report。 - TensorBoard 日志回调与
ModelCheckpoint权重保存。 - 部分模型(如 ResNet50)使用
LearningRateScheduler做学习率衰减。
运行训练(以 ResNet50 为例):
python src/model/sunspot_resnet50.py加载对应 checkpoint,对测试集 PNG 逐张预测,写出 image_id label 格式的结果文件(标签输出为 1/2/3):
python src/predict_pic.py 9 # 命令行参数对应权重 / checkpoint 编号make_result.py 读取多个模型的预测结果,对每个样本按多数投票(Counter.most_common)得到最终类别。
融合策略:
- 分别用白光图训练 5 个模型,投票融合;若出现 5:5 平票,则对各模型 softmax 数值求和,取较大的一类。
- 将白光图与磁图一并输入训练 5 个模型,再投票融合。
第一版基线(杨博士提出的卷积网络,未做数据增强、类别不平衡,仅用 2/3 白光图训练)三类 F1-Score:
| Alpha | Beta | BetaX |
|---|---|---|
| 0.56 | 0.61 | 0.65 |
数据增强 + NASNetLarge(3 个 Epoch)验证集表现:
| 类别 | precision | recall | f1-score | support |
|---|---|---|---|---|
| Alpha | 0.96 | 0.90 | 0.93 | 2449 |
| Beta | 0.74 | 0.88 | 0.80 | 2385 |
| BetaX | 0.91 | 0.80 | 0.85 | 2558 |
验证集上 Beta 类 F1 最低、Alpha 类最高,与竞赛测试集表现规律一致,可作为离线验证的可靠参考。
当前最好成绩(ResNet50,数据增强后)三类得分:
| Alpha | Beta | BetaX |
|---|---|---|
| 0.835 | 0.708 | 0.931 |
当前脚本中的数据路径、checkpoint 路径等多为硬编码的绝对路径(如 /home/ps/Projects/data/...),运行前需根据本地实际环境修改对应文件顶部的 path / prepath / checkpoint_path 等变量。