{"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":"nvidiaTeslaT4","dataSources":[{"sourceId":3362,"databundleVersionId":31148,"isSourceIdPinned":false,"sourceType":"competition"},{"sourceId":112503022,"sourceType":"kernelVersion"}],"dockerImageVersionId":31193,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import os\nimport zipfile\nimport shutil\nimport tensorflow as tf\nfrom tensorflow.keras.preprocessing.image import ImageDataGenerator\nimport matplotlib.pyplot as plt\nimport numpy as np\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score, confusion_matrix\nimport pandas as pd\nimport seaborn as sns\nimport time\n\nprint(\"原始数据集路径:\", os.listdir(\"/kaggle/input/dogs-vs-cats\"))\n\n# 解压原始数据集\ndog_cat_zip_path = \"/kaggle/input/dogs-vs-cats/train.zip\"\ndog_cat_train_dir = \"/kaggle/working/dogs-vs-cats-train\"\nos.makedirs(dog_cat_train_dir, exist_ok=True)\n\nwith zipfile.ZipFile(dog_cat_zip_path, 'r') as zip_ref:\n    zip_ref.extractall(dog_cat_train_dir)\n\nprint(\"原始数据集解压后内容:\", os.listdir(dog_cat_train_dir)[:5])","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:37:46.172426Z","iopub.execute_input":"2025-12-04T09:37:46.172672Z","iopub.status.idle":"2025-12-04T09:38:17.404916Z","shell.execute_reply.started":"2025-12-04T09:37:46.172648Z","shell.execute_reply":"2025-12-04T09:38:17.404299Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 检查Mammals数据集\nprint(\"所有挂载的数据集:\", os.listdir(\"/kaggle/input/\"))\nmammals_path = \"/kaggle/input/mammals-9-classify-torch-cnn\"\nprint(\"对比数据集 (Mammals) 路径内容:\", os.listdir(mammals_path))\n\n# 整理Dogs vs Cats数据集\ndef organize_dog_cat_dataset(base_dir):\n    \"\"\"整理Dogs vs Cats数据集\"\"\"\n    # 创建目标目录\n    cat_dir = os.path.join(base_dir, \"cat\")\n    dog_dir = os.path.join(base_dir, \"dog\")\n    os.makedirs(cat_dir, exist_ok=True)\n    os.makedirs(dog_dir, exist_ok=True)\n    \n    # 移动猫图片\n    cat_images = [f for f in os.listdir(base_dir) if f.startswith(\"cat.\") and f.endswith(('.jpg', '.jpeg', '.png'))]\n    for img in cat_images:\n        src = os.path.join(base_dir, img)\n        dst = os.path.join(cat_dir, img)\n        if os.path.isfile(src):\n            shutil.move(src, dst)\n    \n    # 移动狗图片\n    dog_images = [f for f in os.listdir(base_dir) if f.startswith(\"dog.\") and f.endswith(('.jpg', '.jpeg', '.png'))]\n    for img in dog_images:\n        src = os.path.join(base_dir, img)\n        dst = os.path.join(dog_dir, img)\n        if os.path.isfile(src):\n            shutil.move(src, dst)\n    \n    print(f\"整理完成: {len(cat_images)} 张猫图片, {len(dog_images)} 张狗图片\")\n\n# 整理数据集\norganize_dog_cat_dataset(os.path.join(dog_cat_train_dir, \"train\"))\nprint(\"整理后原始数据集的父文件夹:\", os.listdir(dog_cat_train_dir))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:38:17.406522Z","iopub.execute_input":"2025-12-04T09:38:17.407142Z","iopub.status.idle":"2025-12-04T09:38:18.115484Z","shell.execute_reply.started":"2025-12-04T09:38:17.407089Z","shell.execute_reply":"2025-12-04T09:38:18.11486Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 数据生成器设置\ndef create_data_generators():\n    train_datagen = ImageDataGenerator(\n        rescale=1./255,\n        rotation_range=30,  # 增加随机旋转（增强数据多样性）\n        width_shift_range=0.2,  # 宽度随机偏移\n        height_shift_range=0.2,  # 高度随机偏移\n        shear_range=0.2,\n        zoom_range=0.2,\n        horizontal_flip=True,\n        fill_mode='nearest',  # 填充边缘像素\n        validation_split=0.2  # 划分20%为验证集\n    )\n    test_datagen = ImageDataGenerator(rescale=1./255)\n    return train_datagen, test_datagen\n\n# 创建数据生成器\ntrain_datagen, test_datagen = create_data_generators()\n\n# Dogs vs Cats 数据流\ndog_cat_train_generator = train_datagen.flow_from_directory(\n    os.path.join(dog_cat_train_dir, \"train\"),  # 改成train子文件夹（里面有cat/dog）\n    target_size=(128, 128),\n    batch_size=32,\n    class_mode='binary',\n    subset='training'\n)\n\ndog_cat_val_generator = train_datagen.flow_from_directory(\n    os.path.join(dog_cat_train_dir, \"train\"),  # 同样改成train子文件夹\n    target_size=(128, 128),\n    batch_size=32,\n    class_mode='binary',\n    subset='validation'\n)\n\nprint(\"猫狗分类类别：\", dog_cat_train_generator.class_indices)\nprint(\"猫+狗训练样本数：\", dog_cat_train_generator.samples)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:38:18.116239Z","iopub.execute_input":"2025-12-04T09:38:18.116455Z","iopub.status.idle":"2025-12-04T09:38:18.376478Z","shell.execute_reply.started":"2025-12-04T09:38:18.116438Z","shell.execute_reply":"2025-12-04T09:38:18.375888Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 对于对比数据集，需要先处理Mammals数据集\ndef prepare_mammals_dataset():\n    \"\"\"准备Mammals数据集用于bear vs dog分类\"\"\"\n    mammals_data_path = os.path.join(mammals_path, \"data\")\n    \n    # 检查数据集结构\n    if os.path.exists(mammals_data_path):\n        print(\"Mammals数据集结构:\", os.listdir(mammals_data_path))\n        \n        # 这里需要根据实际数据集结构调整\n        # 假设数据集有bear和dog文件夹\n        bear_dir = os.path.join(mammals_data_path, \"bear\")\n        dog_dir = os.path.join(mammals_data_path, \"dog\")\n        \n        if os.path.exists(bear_dir) and os.path.exists(dog_dir):\n            # 创建bear vs dog数据生成器\n            bear_dog_train = train_datagen.flow_from_directory(\n                mammals_data_path,\n                target_size=(128, 128),\n                batch_size=32,\n                class_mode='binary',\n                classes=['bear', 'dog'],\n                subset='training'\n            )\n            \n            bear_dog_val = train_datagen.flow_from_directory(\n                mammals_data_path,\n                target_size=(128, 128),\n                batch_size=32,\n                class_mode='binary',\n                classes=['bear', 'dog'],\n                subset='validation'\n            )\n            \n            return bear_dog_train, bear_dog_val\n    \n    print(\"Mammals数据集格式不匹配，使用Dogs vs Cats数据创建模拟对比数据集\")\n    # 如果没有合适的对比数据集，使用Dogs vs Cats数据创建模拟对比\n    return dog_cat_train_generator, dog_cat_val_generator\n\n# 准备对比数据集\nbear_dog_train, bear_dog_val = prepare_mammals_dataset()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:38:18.377064Z","iopub.execute_input":"2025-12-04T09:38:18.377269Z","iopub.status.idle":"2025-12-04T09:38:18.65461Z","shell.execute_reply.started":"2025-12-04T09:38:18.377253Z","shell.execute_reply":"2025-12-04T09:38:18.654082Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# CNN模型构建\ndef build_cnn_model():\n    model = tf.keras.Sequential([\n        tf.keras.layers.Input(shape=(128, 128, 3)),\n        # 增加1层卷积层，提升特征提取能力\n        tf.keras.layers.Conv2D(32, (3,3), activation='relu', padding='same'),\n        tf.keras.layers.MaxPooling2D((2,2)),\n        tf.keras.layers.Conv2D(64, (3,3), activation='relu', padding='same'),\n        tf.keras.layers.MaxPooling2D((2,2)),\n        tf.keras.layers.Conv2D(128, (3,3), activation='relu', padding='same'),\n        tf.keras.layers.MaxPooling2D((2,2)),\n        tf.keras.layers.Conv2D(256, (3,3), activation='relu', padding='same'),  # 新增卷积层\n        tf.keras.layers.MaxPooling2D((2,2)),\n        # 全连接层调整：增加神经元+提高Dropout比例\n        tf.keras.layers.Flatten(),\n        tf.keras.layers.Dense(128, activation='relu'),\n        tf.keras.layers.Dropout(0.5),  # 防止模型“死记硬背”\n        tf.keras.layers.Dense(1, activation='sigmoid')\n    ])\n    # 调整学习率，让模型学习更稳定\n    model.compile(\n        optimizer=tf.keras.optimizers.Adam(learning_rate=0.001),\n        loss='binary_crossentropy',\n        metrics=['accuracy']\n    )\n    return model\n\n# 创建模型\nmodel_dog_cat = build_cnn_model()\nmodel_bear_dog = build_cnn_model()\n\nprint(\"CNN模型结构:\")\nmodel_dog_cat.summary()","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:38:18.655266Z","iopub.execute_input":"2025-12-04T09:38:18.655503Z","iopub.status.idle":"2025-12-04T09:38:22.078703Z","shell.execute_reply.started":"2025-12-04T09:38:18.655486Z","shell.execute_reply":"2025-12-04T09:38:22.078169Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 训练模型\n\nfrom tensorflow.keras.callbacks import EarlyStopping\n\n# 【早停】监控验证集准确率，5轮没提升就停止（保留最优模型）\nearly_stop = EarlyStopping(\n    monitor='val_accuracy',\n    patience=5,\n    restore_best_weights=True\n)\nprint(\"=== 原始数据集训 ===\")\nstart_dc = time.time()\nhist_dc = model_dog_cat.fit(\n    dog_cat_train_generator,\n    validation_data=dog_cat_val_generator,\n    epochs=5,  # 增加训练轮次（早停会自动终止）\n    callbacks=[early_stop],\n    verbose=1\n)\ntrain_time_dc = time.time() - start_dc\n\n\nprint(\"=== 训练对比数据集  ===\")\nstart_bd = time.time()\n\nhistory_bd = model_bear_dog.fit(\n    bear_dog_train,\n    validation_data=bear_dog_val,\n    epochs=5,\n    verbose=1\n)\n\ntrain_time_bd = time.time() - start_bd\n\nprint(f\"原始数据集训练耗时: {train_time_dc:.2f}秒\")\nprint(f\"对比数据集训练耗时: {train_time_bd:.2f}秒\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:38:22.079381Z","iopub.execute_input":"2025-12-04T09:38:22.079597Z","iopub.status.idle":"2025-12-04T09:48:38.58865Z","shell.execute_reply.started":"2025-12-04T09:38:22.079572Z","shell.execute_reply":"2025-12-04T09:48:38.588064Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 评估函数\ndef evaluate_model(model, test_generator, train_time):\n    test_generator.reset()\n    y_pred = model.predict(test_generator, verbose=1)\n    y_pred = (y_pred > 0.5).astype(int).flatten()\n    y_true = test_generator.classes\n    # 加入zero_division=0，避免全类预测时的报错\n    metrics = {\n        \"准确率\": round(accuracy_score(y_true, y_pred), 4),\n        \"精确率\": round(precision_score(y_true, y_pred, zero_division=0), 4),\n        \"召回率\": round(recall_score(y_true, y_pred, zero_division=0), 4),\n        \"F1分数\": round(f1_score(y_true, y_pred, zero_division=0), 4),\n        \"训练时间(秒)\": round(train_time, 2)\n    }\n    return metrics\n\n# 评估模型\nmetrics_dc = evaluate_model(model_dog_cat, dog_cat_val_generator, train_time_dc)\nmetrics_bd = evaluate_model(model_bear_dog, bear_dog_val, train_time_bd)\n\n# 创建对比表格\ncompare_df = pd.DataFrame({\n    \"评估指标\": list(metrics_dc.keys()),\n    \"原始数据集 (Dogs vs Cats)\": list(metrics_dc.values()),\n    \"对比数据集 (bear vs dog)\": list(metrics_bd.values())\n})\n\nprint(\"=== 双数据集定量对比表 ===\")\nprint(compare_df.to_string(index=False))","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:48:38.590306Z","iopub.execute_input":"2025-12-04T09:48:38.590787Z","iopub.status.idle":"2025-12-04T09:49:04.778005Z","shell.execute_reply.started":"2025-12-04T09:48:38.590761Z","shell.execute_reply":"2025-12-04T09:49:04.777428Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# 混淆矩阵函数\ndef plot_confusion_matrix(model, test_generator, title):\n    test_generator.reset()\n    y_pred = (model.predict(test_generator, verbose=0) > 0.5).astype(int).flatten()\n    y_true = test_generator.classes\n    cm = confusion_matrix(y_true, y_pred)\n    classes = list(test_generator.class_indices.keys())\n    \n    plt.figure(figsize=(6, 4))\n    sns.heatmap(cm, annot=True, fmt=\"d\", cmap=\"Blues\", xticklabels=classes, yticklabels=classes)\n    plt.xlabel(\"预测标签\")\n    plt.ylabel(\"真实标签\")\n    plt.title(f\"{title} - 混淆矩阵\")\n    plt.savefig(f\"/kaggle/working/{title}_cm.png\")\n    plt.show()\n\n# 绘制混淆矩阵\nplot_confusion_matrix(model_dog_cat, dog_cat_val_generator, \"Dogs vs Cats\")\nplot_confusion_matrix(model_bear_dog, bear_dog_val, \"bear vs dog\")\n\n# 预测示例函数\ndef show_predict_examples(model, test_generator, title):\n    test_generator.reset()\n    images, labels = next(test_generator)\n    y_pred = (model.predict(images, verbose=0) > 0.5).astype(int).flatten()\n    y_true = labels.flatten().astype(int)\n    classes = list(test_generator.class_indices.keys())\n    \n    plt.figure(figsize=(18, 3))\n    for i in range(min(6, len(images))):\n        plt.subplot(1, 6, i+1)\n        plt.imshow(images[i])\n        plt.axis(\"off\")\n        color = \"green\" if y_true[i] == y_pred[i] else \"red\"\n        plt.title(f\"真实: {classes[y_true[i]]}\\n预测: {classes[y_pred[i]]}\", color=color, fontsize=8)\n    plt.suptitle(f\"{title} - 预测案例(绿=正确，红=错误)\")\n    plt.savefig(f\"/kaggle/working/{title}_examples.png\")\n    plt.show()\n\n# 显示预测示例\nshow_predict_examples(model_dog_cat, dog_cat_val_generator, \"Dogs vs Cats\")\nshow_predict_examples(model_bear_dog, bear_dog_val, \"bear vs dog\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-12-04T09:49:04.77879Z","iopub.execute_input":"2025-12-04T09:49:04.779075Z","iopub.status.idle":"2025-12-04T09:49:33.7785Z","shell.execute_reply.started":"2025-12-04T09:49:04.779047Z","shell.execute_reply":"2025-12-04T09:49:33.7776Z"}},"outputs":[],"execution_count":null}]}