687. CSIRO - Image2Biomass Prediction | csiro-biomass
首先,感谢主办方组织了如此有趣和愉快的比赛。这是我第一次认真参与竞赛,我很高兴我的解决方案实际上足够好,能够排名第 27 位。在这次参与过程中获得的经验和知识极大地开阔了我的视野。所以感谢你们拓宽了我们的知识 horizon。这也是我第一次使用交叉验证和集成策略。
在分析数据后,我注意到了以下观察结果:
Dry_Total_g = Dry_Green_g + Dry_Dead_g + Dry_Clover_g 和 GDM_g = Dry_Green_g + Dry_Clover_gDry_Total_g 和 GDM_g 噪声最小,且只有这两个大致服从高斯分布。Dry_Green_g 服从幂律分布,头部较短。Dry_Dead_g 和 Dry_Clover_g 也服从幂律分布,但头部更高且尾部更长。Dry_Clover_g 通常为零。lucerne(苜蓿),其质量值未按相同比例缩放。对于生物量目标,由于 Dry_Dead_g 和 Dry_Clover_g 噪声大且有很多零,我决定预测 Dry_Total_g、GDM_g 和 Dry_Green_g,并从中推导其余两个。我对这些生物量目标使用了对数归一化变换。
means = torch.tensor([3.6171854219925024, 3.217874424165861, 2.832479241567281])
stds = torch.tensor([0.5573042636308412, 0.8185179833598041, 1.2134970356508157])
normliazed = (torch.log(data + 1) - means) / stds
data = torch.exp((normliazed * stds) + means) - 1
对于辅助回归目标,我进行了以下预处理:
Height_Ave_cm 也以相同方式进行归一化和反归一化,均值为 1.7949544186979798,标准差为 0.7399843934368923。因为高度也服从幂律分布,头部高且尾部长。Pre_GSHH_NDVI 未进行变换,直接使用。def reduce_species(species):
new_species = []
for one_species in species.split("_"):
if one_species in ("BarleyGrass", "Barleygrass", "Bromegrass", "SilverGrass", "SpearGrass"):
new_species.append("grass")
elif one_species in ("SubcloverDalkeith", "SubcloverLosa", "Clover"):
new_species.append("clover")
elif one_species in ("Capeweed", "CrumbWeed"):
new_species.append("weed")
elif one_species == "Mixed":
new_species.append("ryegrass")
else:
new_species.append(one_species.lower())
return list(set(new_species))
由于数据集非常小,我试图创建数据拆分,使每个训练集都能看到完整的数值谱。但这在单个交叉折叠中无法实现,因为我总是在训练 - 验证拆分中泄露日期和状态。所以我决定创建两个交叉验证拆分。
5 折交叉验证 -> 我称之为 clean_folds,我在 State 和 Sampling_Date 上进行了分层,使用以下代码:
df = pd.read_csv('./datasets/csiro-biomass/train_unwrapped.csv')
df['session_id'] = df['State'].astype(str) + "_" + df['Sampling_Date'].astype(str)
df['biomass_bin'] = pd.qcut(df['Dry_Total_g'], q=5, labels=False)
sgkf = StratifiedGroupKFold(n_splits=5, shuffle=False)
3 折交叉验证 -> 这里我简单地按 Dry_Total_g 降序排序并创建了 3 个组,以便每个训练集都能看到完整的目标值谱。只使用了 3 折以避免训练/验证拆分过于相似。
测试了图像分辨率 384, 512, 768, 1024 与 patch 大小 2x1, 4x2 的组合。发现图像大小 768x768 配合两个 patches(left and right)效果最好,所以其余实验都以此方式进行。
对于增强,我使用了一些全局变换,应用于整张图像。以及局部变换,应用于 patch 级别。我为此编写了一个自定义 compose 类。我还尝试了在训练中途切换到较弱的 pipeline。最坏情况下它什么都没做,最好情况下给指标带来了一点提升,所以我默认在其余运行中使用它,在最后 5-10 个 epoch 切换 pipeline。
NORM_SETTING = {"type": "Normalize", "mean": [0.485, 0.456, 0.406], "std": [0.229, 0.224, 0.225]}
STRONG_AUG_TRANSFORMS = {
"type": "albu",
"compose_cls": "tiled_compose",
"global_transforms": [
{
"type": "OneOf", "p": 0.5,
"transforms": [
{"type": "AutoContrast", "method": "cdf", "p": 0.5},
{"type": "RandomBrightnessContrast", "brightness_limit": 0.3, "contrast_limit": 0.2, "p": 0.5},
{"type": "RandomToneCurve", "scale": 0.3, "p": 0.3},
{"type": "HueSaturationValue", "hue_shift_limit": 20, "sat_shift_limit": 30, "val_shift_limit": 20, "p": 0.5},
{"type": "PlanckianJitter", "mode": "blackbody", "temperature_limit": [4000, 8000], "sampling_method": "gaussian", "p": 0.5},
{"type": "CLAHE", "p": 0.5},
],
},
{"type": "ShiftScaleRotate", "shift_limit": [-0.1, 0.1], "scale_limit": [-0.1, 0.1], "rotate_limit": [10, 10], "border_mode": 4, "p": 0.5},
{"type": "GaussianBlur", "blur_limit": 3, "sigma_limit": 1, "p": 0.5},
{
"type": "OneOf", "p": 0.5,
"transforms": [
{"type": "GridDistortion", "distort_limit": 0.5, "p": 1.0},
{"type": "OpticalDistortion", "p": 1.0},
],
},
],
"local_transforms": [
{"type": "D4", "p": 1.0},
{
"type": "OneOf", "p": 0.5,
"transforms": [
{"type": "Sharpen", "alpha": [0.1, 0.5], "lightness": [1.0, 1.0], "method": "kernel", "p": 0.8},
{"type": "Emboss", "alpha": [0.4, 0.5], "strength": [0.3, 0.7], "p": 0.8},
],
},
],
"cvt_transforms": [NORM_SETTING, {"type": "ToTensorV2"}],
"n_patch_h": 1, "n_patch_w": 2,
"target_size": [IMAGE_SIZE, IMAGE_SIZE * 2]
}
SPECIES = ["clover", "ryegrass", "phalaris", "grass", "fescue", "lucerne", "weed", "whiteclover"]
SPECIES_WEIGHTS = [1.68, 1.86, 2.76, 3.59, 4.09, 5.01, 5.89, 7.08] # 根号 sqrt(N / Nc)
{"biomass": 3.0, "aux": 1.0, "species": 0.2}我为此编写了相当广泛的代码。你可以在我的 GitHub 仓库 找到代码。
这是我的 提交 notebook。我计划发布一篇详尽的文章,这需要一两周的时间。
最后,为什么在这次竞赛中 CNN consistently inferior 于 ViT?我很想听听其他人的见解。