{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":112509,"databundleVersionId":14254895,"sourceType":"competition"},{"sourceId":4534,"sourceType":"modelInstanceVersion","modelInstanceId":3326,"modelId":986},{"sourceId":4537,"sourceType":"modelInstanceVersion","modelInstanceId":3329,"modelId":986}],"dockerImageVersionId":31154,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import pandas as pd  # 导入 pandas 库用于数据处理\nimport numpy as np  # 导入 numpy 库用于数值计算\nimport torch  # 导入 PyTorch 库用于深度学习模型\nimport torchvision  # 导入 torchvision 库用于计算机视觉任务\nimport os  # 导入 os 库用于文件操作\nimport torchvision.transforms as transforms  # 导入 torchvision 的图像预处理模块\nfrom torchvision.datasets import ImageFolder  # 导入 ImageFolder 用于加载图像数据集\nfrom torch.utils.data import DataLoader, Subset, Dataset  # 导入 PyTorch 的数据加载器和子集工具\nfrom PIL import Image  # 导入 PIL 用于处理图像\n# !cp -r \"/kaggle/input/rsna-models/facebookresearch_dinov2_main (1)/root/.cache/torch/hub/facebookresearch_dinov2_main\" /kaggle/working/dinov2  # 将模型缓存拷贝到当前目录\n\nmean = [0.485, 0.456, 0.406]  # DINO 使用的图像均值\nstd = [0.229, 0.224, 0.225]  # DINO 使用的图像标准差\n\nfrom transformers import AutoImageProcessor, AutoModel  # 导入 Hugging Face 的 DINO 模型与处理器\n\n# 加载 DINO 预训练模型和图像处理器\nprocessor = AutoImageProcessor.from_pretrained('/kaggle/input/dinov2/pytorch/giant/1')\nmodel = AutoModel.from_pretrained('/kaggle/input/dinov2/pytorch/giant/1')\nmodel = model.cuda()  # 将模型转移到 GPU 上进行计算\n\n# 初始化特征提取和目标存储的容器\nembeds = []  # 存储提取的图像特征\ntargets = [[] for i in range(5)]  # 存储每个目标的实际值（有 5 个目标）\ncounter = 0  # 计数器，用于记录处理的图像批次数\n\n# 读取训练数据集\ntrain_df = pd.read_csv(\"/kaggle/input/csiro-biomass/train.csv\")\nroot = \"/kaggle/input/csiro-biomass/\"\n\n# 遍历训练数据集，提取图像特征\nfor i in range(len(train_df)):\n    entry = train_df.iloc[i]  # 获取当前行数据\n    file_path = root + entry['image_path']  # 获取图像文件路径\n    y = torch.tensor([[entry['target']]])  # 获取目标值\n    targets[i % 5].append(y)  # 将目标值按目标列分配\n    if i % 5 == 0:  # 每处理一张图像时执行一次\n        img = Image.open(file_path)  # 打开图像文件\n        x = torch.tensor(processor(img).pixel_values)  # 将图像转换为模型输入格式\n        with torch.no_grad():  # 禁用梯度计算\n            x = x.cuda()  # 将图像数据转移到 GPU\n            embeds.append(model(x).pooler_output.cpu())  # 提取特征并移动回 CPU\n            counter += 1  # 增加计数器\n            if counter % 100 == 0:  # 每处理 100 张图像时打印进度\n                print(f\"{counter} batches processed.\")  # 打印进度信息\n                \n# 数据分割和交叉验证的初始化\nimport random\nimport numpy as np\nfrom sklearn.linear_model import Lasso  # 导入 Lasso 回归模型\nfrom sklearn.metrics import r2_score  # 导入 R² 评分计算\n\n# 创建索引并随机打乱\nlst = list(range(len(embeds)))  # 将索引列表化\nrandom.seed(42)  # 设置随机种子\nrandom.shuffle(lst)  # 打乱数据\n\n# 创建多个 80/20 的随机划分\nn_splits = 5  # 设置交叉验证折数为 5\nsplits = []  # 存储每折的训练和验证索引\n\nfor i in range(n_splits):  # 创建 5 折交叉验证\n    temp_lst = lst.copy()  # 复制打乱的索引列表\n    random.seed(42 + i)  # 为每折使用不同的种子\n    random.shuffle(temp_lst)  # 打乱数据\n    split_point = int(len(temp_lst) * 0.8)  # 划分训练集和验证集的比例\n    train_idxs = temp_lst[:split_point]  # 获取训练集索引\n    val_idxs = temp_lst[split_point:]  # 获取验证集索引\n    splits.append((train_idxs, val_idxs))  # 将训练集和验证集的索引添加到 splits\n\n# 转换 embeds 为 numpy 数组以提高效率\nembeds_np = np.array(torch.cat(embeds))  # 将特征合并为一个 NumPy 数组\nregressors = [[None for i in range(5)] for j in range(5)]  # 初始化回归器列表，用于存储每个目标的模型\n\n# 遍历每个目标进行回归\nfor i in range(5):\n    print(f\"\\n=== Target {i+1} ===\")  # 输出当前目标编号\n    targets_np = np.array(torch.cat(targets[i]))  # 获取当前目标的目标值\n    \n    split_scores = []  # 存储每折的 R² 评分\n\n    for split_idx, (train_idxs, val_idxs) in enumerate(splits):  # 遍历每一折\n        print(f\"Fold {split_idx+1}:\")  # 输出当前折次\n\n        # 获取训练集和验证集的数据\n        X_train, y_train = embeds_np[train_idxs], targets_np[train_idxs]\n        X_val, y_val = embeds_np[val_idxs], targets_np[val_idxs]\n\n        # 使用 Lasso 回归模型进行训练\n        reg = Lasso()  # 初始化 Lasso 回归模型\n        reg.fit(X_train, y_train)  # 训练模型\n\n        # 预测并计算训练集和验证集的 R² 分数\n        train_preds = reg.predict(X_train)  # 对训练集进行预测\n        train_preds[train_preds < 0.0] = 0.0  # 将负值裁剪为 0\n        train_r2 = r2_score(y_train, train_preds)  # 计算训练集 R²\n\n        val_preds = reg.predict(X_val)  # 对验证集进行预测\n        val_preds[val_preds < 0.0] = 0.0  # 将负值裁剪为 0\n        val_r2 = r2_score(y_val, val_preds)  # 计算验证集 R²\n\n        print(f\"  Train R²: {train_r2:.4f}\")  # 输出训练集 R²\n        print(f\"  Val R²: {val_r2:.4f}\")  # 输出验证集 R²\n\n        split_scores.append((train_r2, val_r2))  # 保存当前折的评分\n        regressors[i][split_idx] = reg  # 保存当前折的回归器\n    \n    # 输出当前目标的平均 R² 分数\n    avg_train_r2 = np.mean([score[0] for score in split_scores])  # 计算训练集平均 R²\n    avg_val_r2 = np.mean([score[1] for score in split_scores])  # 计算验证集平均 R²\n\n    print(f\"\\nTarget {i+1} Average:\")  # 输出当前目标的平均值\n    print(f\"  Avg Train R²: {avg_train_r2:.4f}\")  # 输出训练集平均 R²\n    print(f\"  Avg Val R²: {avg_val_r2:.4f}\")  # 输出验证集平均 R²\n\n# 目标映射字典\nmapping = {\"Dry_Clover_g\": 0, \"Dry_Dead_g\": 1, \"Dry_Green_g\": 2, \"Dry_Total_g\": 3, \"GDM_g\": 4}\n\n# 测试集特征提取与预测\ntest_embeds = {}  # 存储测试集的图像特征\ncounter = 0  # 计数器\n\n# 读取测试数据\ntest_df = pd.read_csv(\"/kaggle/input/csiro-biomass/test.csv\")\nsample_ids = []  # 存储样本 ID\n\n# 提取测试集图像特征\nfor i in range(len(test_df)):\n    entry = test_df.iloc[i]  # 获取当前行数据\n    file_path = root + entry['image_path']  # 获取图像文件路径\n    sample_id = entry['sample_id']  # 获取样本 ID\n    if sample_id not in sample_ids:  # 确保每个样本只处理一次\n        img = Image.open(file_path)  # 打开图像文件\n        x = torch.tensor(processor(img).pixel_values)  # 将图像转换为模型输入格式\n        with torch.no_grad():  # 禁用梯度计算\n            x = x.cuda()  # 将图像数据转移到 GPU\n            test_embeds[sample_id.split(\"_\")[0]] = model(x).pooler_output.cpu()  # 提取特征并保存\n            counter += 1  # 增加计数器\n        sample_ids.append(sample_id)  # 添加样本 ID\n    if counter % 100 == 0:  # 每处理 100 张图像时打印进度\n        print(f\"{counter} batches processed.\")  # 打印进度信息\n\n# 预测测试集\npredictions = []  # 存储预测结果\nsample_ids = []  # 存储样本 ID\n\n# 遍历测试数据进行预测\nfor i in range(len(test_df)):\n    try:\n        entry = test_df.iloc[i]  # 获取当前行数据\n        X = np.array(test_embeds[entry['sample_id'].split(\"__\")[0]])  # 获取测试样本特征\n        sample_ids.append(entry['sample_id'])  # 存储样本 ID\n        models = regressors[mapping[entry['sample_id'].split(\"__\")[1]]]  # 获取当前目标的回归模型\n        prediction = 0.0  # 初始化预测值\n        for item in models:  # 对每个模型进行预测并加权平均\n            single_pred = item.predict(X)\n            if single_pred < 0.0:  # 若预测值为负则裁剪为 0\n                single_pred = 0.0\n            prediction += single_pred\n        prediction = prediction / 5  # 平均 5 折预测值\n        predictions.append(float(prediction))  # 存储预测结果\n    except Exception as e:  # 异常处理\n        predictions.append(0.0)  # 出现异常时预测为 0\n\n# 生成提交文件\n# %cd /kaggle/working  # 切换到当前工作目录\n\nsubmission = pd.DataFrame({\n    'sample_id': sample_ids,  # 样本 ID\n    'target': predictions  # 预测结果\n})\n\n# submission.to_csv('submission.csv', index=False)  # 保存为 CSV 文件\n# submission  # 输出提交数据\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T06:04:50.395026Z","iopub.execute_input":"2025-11-10T06:04:50.395286Z","iopub.status.idle":"2025-11-10T06:06:18.981339Z","shell.execute_reply.started":"2025-11-10T06:04:50.395268Z","shell.execute_reply":"2025-11-10T06:06:18.980469Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 用来实现用公式计算 dead ，然后再把处理好的提交\n# 创建一个字典来存储样本 ID 与目标值的映射\ntarget_dict = {}\nfor i in range(len(submission)):\n    sample_id = submission.loc[i, 'sample_id']\n    target_value = submission.loc[i, 'target']\n    target_dict[sample_id] = target_value  # 将样本 ID 与预测目标值存入字典\n\n# 计算 Dry_Dead_g：根据公式 Dry_Dead_g = Dry_Total_g - GDM_g\nfor i in range(len(submission)):\n    sample_id = submission.loc[i, 'sample_id']\n    \n    # 使用正则表达式提取样本 ID 和目标\n    sample_prefix = sample_id.split(\"__\")[0]\n    target = sample_id.split(\"__\")[1]\n\n    # 如果是 Dry_Dead_g，计算值\n    if target == \"Dry_Dead_g\":\n        dry_total_g = target_dict.get(f\"{sample_prefix}__Dry_Total_g\", 0)\n        gdm_g = target_dict.get(f\"{sample_prefix}__GDM_g\", 0)\n        # 计算 Dry_Dead_g = Dry_Total_g - GDM_g，并修正为非负\n        dead_value = max(dry_total_g - gdm_g, 0)\n        submission.loc[i, 'target'] = dead_value  # 更新 Dry_Dead_g 的预测值\n\n# 确保每个目标为非负\nsubmission['target'] = submission['target'].apply(lambda x: max(x, 0))\n\n# print(submission.head())  # 打印前几行确认结果\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T06:06:18.982976Z","iopub.execute_input":"2025-11-10T06:06:18.983261Z","iopub.status.idle":"2025-11-10T06:06:18.990179Z","shell.execute_reply.started":"2025-11-10T06:06:18.983243Z","shell.execute_reply":"2025-11-10T06:06:18.989377Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# print(submission['Dry_Dead_g'] )\n","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T06:06:18.990742Z","iopub.execute_input":"2025-11-10T06:06:18.990963Z","iopub.status.idle":"2025-11-10T06:06:19.005235Z","shell.execute_reply.started":"2025-11-10T06:06:18.990940Z","shell.execute_reply":"2025-11-10T06:06:19.004575Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# # 修改：将 Dry_Dead_g 计算为 Dry_Total_g - GDM_g\n# # 通过公式计算 Dry_Dead_g\n# submission['Dry_Dead_g'] = submission['Dry_Total_g'] - submission['GDM_g']\n\n# # 如果 Dry_Dead_g 小于 0，则将其置为 0\n# submission['Dry_Dead_g'] = submission['Dry_Dead_g'].apply(lambda x: max(x, 0))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T06:06:19.005989Z","iopub.execute_input":"2025-11-10T06:06:19.006238Z","iopub.status.idle":"2025-11-10T06:06:19.020712Z","shell.execute_reply.started":"2025-11-10T06:06:19.006222Z","shell.execute_reply":"2025-11-10T06:06:19.019995Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"%cd /kaggle/working  # 切换到当前工作目录\nsubmission.to_csv('submission.csv', index=False)  # 保存为 CSV 文件\nsubmission  # 输出提交数据","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-11-10T06:06:19.021341Z","iopub.execute_input":"2025-11-10T06:06:19.021536Z","iopub.status.idle":"2025-11-10T06:06:19.056408Z","shell.execute_reply.started":"2025-11-10T06:06:19.021521Z","shell.execute_reply":"2025-11-10T06:06:19.055737Z"}},"outputs":[],"execution_count":null}]}