From 2e925a41888aaa6fa96314fb2485c56f78f2df0f Mon Sep 17 00:00:00 2001 From: MythEclipse Date: Fri, 12 Jun 2026 14:16:11 +0000 Subject: [PATCH] a --- Machine_Learning/notebook.ipynb | 113 ++------------------------------ Machine_Learning/save_model.py | 18 +++-- 2 files changed, 16 insertions(+), 115 deletions(-) diff --git a/Machine_Learning/notebook.ipynb b/Machine_Learning/notebook.ipynb index aef3cef..a46c3c8 100644 --- a/Machine_Learning/notebook.ipynb +++ b/Machine_Learning/notebook.ipynb @@ -892,39 +892,7 @@ "id": "decaf5cb", "metadata": {}, "outputs": [], - "source": [ - "IMG_128 = (128, 128)\n", - "\n", - "# Rebuild datasets at 128x128\n", - "train_ds_128 = tf.keras.utils.image_dataset_from_directory(\n", - " train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_128)\n", - "val_ds_128 = tf.keras.utils.image_dataset_from_directory(\n", - " val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_128)\n", - "\n", - "train_ds_128 = (train_ds_128.map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n", - " .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n", - " .map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n", - "val_ds_128 = (val_ds_128.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n", - " .map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n", - "\n", - "EPOCHS_P1 = 25\n", - "steps_per_epoch = tf.data.experimental.cardinality(train_ds_128).numpy() or 100\n", - "total_steps = steps_per_epoch * EPOCHS_P1\n", - "warmup_steps = steps_per_epoch * 3 # 3 epoch warmup\n", - "\n", - "lr_schedule_p1 = WarmupCosineDecay(warmup_steps, total_steps, peak_lr=1e-3, min_lr=1e-5)\n", - "\n", - "model.compile(\n", - " optimizer=AdamW(\n", - " learning_rate=lr_schedule_p1, weight_decay=1e-4),\n", - " loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.15),\n", - " metrics=['accuracy']\n", - ")\n", - "\n", - "print(\"Phase 1: Head training at 128×128...\")\n", - "history_1 = model.fit(train_ds_128, validation_data=val_ds_128,\n", - " epochs=EPOCHS_P1, callbacks=make_callbacks())\n" - ] + "source": "IMG_128 = (128, 128)\n\n# Rebuild datasets at 128x128\ntrain_ds_128 = tf.keras.utils.image_dataset_from_directory(\n train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_128)\nval_ds_128 = tf.keras.utils.image_dataset_from_directory(\n val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_128)\n\ntrain_ds_128 = (train_ds_128.map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n .map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\nval_ds_128 = (val_ds_128.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n .map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n\nEPOCHS_P1 = 25\ncard = tf.data.experimental.cardinality(train_ds_128).numpy()\nsteps_per_epoch = card if card > 0 else 100\ntotal_steps = steps_per_epoch * EPOCHS_P1\nwarmup_steps = steps_per_epoch * 3 # 3 epoch warmup\n\nlr_schedule_p1 = WarmupCosineDecay(warmup_steps, total_steps, peak_lr=1e-3, min_lr=1e-5)\n\nmodel.compile(\n optimizer=AdamW(\n learning_rate=lr_schedule_p1, weight_decay=1e-4),\n loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.15),\n metrics=['accuracy']\n)\n\nprint(\"Phase 1: Head training at 128×128...\")\nhistory_1 = model.fit(train_ds_128, validation_data=val_ds_128,\n epochs=EPOCHS_P1, callbacks=make_callbacks())" }, { "cell_type": "markdown", @@ -943,44 +911,7 @@ "id": "fd7fb926", "metadata": {}, "outputs": [], - "source": [ - "IMG_192 = (192, 192)\n", - "\n", - "train_ds_192 = tf.keras.utils.image_dataset_from_directory(\n", - " train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_192)\n", - "val_ds_192 = tf.keras.utils.image_dataset_from_directory(\n", - " val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_192)\n", - "\n", - "train_ds_192 = (train_ds_192.map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n", - " .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n", - " .map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n", - "val_ds_192 = (val_ds_192.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n", - " .map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n", - "\n", - "# Unfreeze top 100 layers\n", - "base_model.trainable = True\n", - "for layer in base_model.layers[:-100]:\n", - " layer.trainable = False\n", - "\n", - "EPOCHS_P2 = 30\n", - "steps_p2 = tf.data.experimental.cardinality(train_ds_192).numpy() or 100\n", - "total_p2 = steps_p2 * EPOCHS_P2\n", - "warmup_p2 = steps_p2 * 2\n", - "\n", - "lr_schedule_p2 = WarmupCosineDecay(warmup_p2, total_p2, peak_lr=5e-4, min_lr=1e-6)\n", - "\n", - "model.compile(\n", - " optimizer=AdamW(\n", - " learning_rate=lr_schedule_p2, weight_decay=1e-4),\n", - " loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.15),\n", - " metrics=['accuracy']\n", - ")\n", - "\n", - "print(\"Phase 2: Fine-tuning top 100 layers at 192×192...\")\n", - "history_2 = model.fit(train_ds_192, validation_data=val_ds_192,\n", - " epochs=EPOCHS_P1 + EPOCHS_P2, initial_epoch=history_1.epoch[-1] + 1,\n", - " callbacks=make_callbacks())\n" - ] + "source": "IMG_192 = (192, 192)\n\ntrain_ds_192 = tf.keras.utils.image_dataset_from_directory(\n train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_192)\nval_ds_192 = tf.keras.utils.image_dataset_from_directory(\n val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=IMG_192)\n\ntrain_ds_192 = (train_ds_192.map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n .map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\nval_ds_192 = (val_ds_192.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n .map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n\n# Unfreeze top 100 layers\nbase_model.trainable = True\nfor layer in base_model.layers[:-100]:\n layer.trainable = False\n\nEPOCHS_P2 = 30\ncard_p2 = tf.data.experimental.cardinality(train_ds_192).numpy()\nsteps_p2 = card_p2 if card_p2 > 0 else 100\ntotal_p2 = steps_p2 * EPOCHS_P2\nwarmup_p2 = steps_p2 * 2\n\nlr_schedule_p2 = WarmupCosineDecay(warmup_p2, total_p2, peak_lr=5e-4, min_lr=1e-6)\n\nmodel.compile(\n optimizer=AdamW(\n learning_rate=lr_schedule_p2, weight_decay=1e-4),\n loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.15),\n metrics=['accuracy']\n)\n\nprint(\"Phase 2: Fine-tuning top 100 layers at 192×192...\")\nhistory_2 = model.fit(train_ds_192, validation_data=val_ds_192,\n epochs=EPOCHS_P1 + EPOCHS_P2, initial_epoch=history_1.epoch[-1] + 1,\n callbacks=make_callbacks())" }, { "cell_type": "markdown", @@ -1000,43 +931,7 @@ "id": "14115063", "metadata": {}, "outputs": [], - "source": [ - "img_size = IMG_SIZE # (224, 224)\n", - "\n", - "train_ds_full = tf.keras.utils.image_dataset_from_directory(\n", - " train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=img_size)\n", - "val_ds_full = tf.keras.utils.image_dataset_from_directory(\n", - " val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=img_size)\n", - "\n", - "train_ds_full = (train_ds_full.map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n", - " .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n", - " .map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n", - "val_ds_full = (val_ds_full.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n", - " .map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n", - "\n", - "# Full unfreeze\n", - "for layer in base_model.layers:\n", - " layer.trainable = True\n", - "\n", - "EPOCHS_P3 = 30\n", - "steps_p3 = tf.data.experimental.cardinality(train_ds_full).numpy() or 100\n", - "total_p3 = steps_p3 * EPOCHS_P3\n", - "warmup_p3 = steps_p3 * 2\n", - "\n", - "lr_schedule_p3 = WarmupCosineDecay(warmup_p3, total_p3, peak_lr=1e-4, min_lr=1e-7)\n", - "\n", - "model.compile(\n", - " optimizer=AdamW(\n", - " learning_rate=lr_schedule_p3, weight_decay=1e-4),\n", - " loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.10),\n", - " metrics=['accuracy']\n", - ")\n", - "\n", - "print(\"Phase 3: Full fine-tuning at 224×224...\")\n", - "history_3 = model.fit(train_ds_full, validation_data=val_ds_full,\n", - " epochs=EPOCHS_P1 + EPOCHS_P2 + EPOCHS_P3, initial_epoch=(history_2.epoch[-1] + 1) if history_2.epoch else EPOCHS_P1 + EPOCHS_P2,\n", - " callbacks=make_callbacks())\n" - ] + "source": "img_size = IMG_SIZE # (224, 224)\n\ntrain_ds_full = tf.keras.utils.image_dataset_from_directory(\n train_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=img_size)\nval_ds_full = tf.keras.utils.image_dataset_from_directory(\n val_dir, shuffle=True, batch_size=BATCH_SIZE, image_size=img_size)\n\ntrain_ds_full = (train_ds_full.map(augment_and_mix, num_parallel_calls=AUTOTUNE)\n .map(preprocess_fn, num_parallel_calls=AUTOTUNE)\n .map(add_sample_weight, num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\nval_ds_full = (val_ds_full.map(lambda img, lbl: (preprocess_input(tf.cast(img, tf.float32)), lbl), num_parallel_calls=AUTOTUNE)\n .map(lambda img, lbl: (img, tf.one_hot(lbl, NUM_CLASSES)), num_parallel_calls=AUTOTUNE).prefetch(AUTOTUNE))\n\n# Full unfreeze\nfor layer in base_model.layers:\n layer.trainable = True\n\nEPOCHS_P3 = 30\ncard_p3 = tf.data.experimental.cardinality(train_ds_full).numpy()\nsteps_p3 = card_p3 if card_p3 > 0 else 100\ntotal_p3 = steps_p3 * EPOCHS_P3\nwarmup_p3 = steps_p3 * 2\n\nlr_schedule_p3 = WarmupCosineDecay(warmup_p3, total_p3, peak_lr=1e-4, min_lr=1e-7)\n\nmodel.compile(\n optimizer=AdamW(\n learning_rate=lr_schedule_p3, weight_decay=1e-4),\n loss=tf.keras.losses.CategoricalCrossentropy(from_logits=True, label_smoothing=0.10),\n metrics=['accuracy']\n)\n\nprint(\"Phase 3: Full fine-tuning at 224×224...\")\nhistory_3 = model.fit(train_ds_full, validation_data=val_ds_full,\n epochs=EPOCHS_P1 + EPOCHS_P2 + EPOCHS_P3, initial_epoch=(history_2.epoch[-1] + 1) if history_2.epoch else EPOCHS_P1 + EPOCHS_P2,\n callbacks=make_callbacks())" }, { "cell_type": "markdown", @@ -1577,4 +1472,4 @@ }, "nbformat": 4, "nbformat_minor": 5 -} +} \ No newline at end of file diff --git a/Machine_Learning/save_model.py b/Machine_Learning/save_model.py index 2a805eb..97f266b 100644 --- a/Machine_Learning/save_model.py +++ b/Machine_Learning/save_model.py @@ -11,7 +11,7 @@ log = logging.getLogger(__name__) def cbam_block(x, ratio=8, name="cbam"): """Convolutional Block Attention Module — lightweight foreground attention.""" - channels = tf.shape(x)[-1] + channels = x.shape[-1] # Channel attention avg_pool = layers.GlobalAveragePooling2D()(x) @@ -34,17 +34,23 @@ def cbam_block(x, ratio=8, name="cbam"): return x -def build_clean_model(num_classes, img_size=(224, 224)): - """Build the production architecture: CBAM + lightweight head, outputting raw logits.""" +def build_clean_model(num_classes, target_size=(224, 224)): + """Build the production architecture: CBAM + lightweight head, outputting raw logits. + + Mirrors the notebook's build_model() exactly so set_weights() maps correctly. + """ base_model = tf.keras.applications.EfficientNetV2B0( - input_shape=img_size + (3,), + input_shape=target_size + (3,), include_top=False, weights=None, ) base_model.trainable = False - inputs = tf.keras.Input(shape=img_size + (3,), name="input") - x = base_model(inputs, training=False) + inputs = tf.keras.Input(shape=(None, None, 3), name="input") + x = layers.Resizing(target_size[0], target_size[1], interpolation="bilinear", + name="resize_input")(inputs) + x = layers.GaussianNoise(0.05, name="gauss_noise")(x) + x = base_model(x, training=False) # CBAM attention — focus on leaf regions, ignore background x = cbam_block(x, ratio=8, name="cbam") x = layers.GlobalAveragePooling2D(name="gap")(x)