{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.11.11","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceId":19991,"databundleVersionId":1117522,"sourceType":"competition"}],"dockerImageVersionId":31011,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Hücre 1: Importlar, Sabitler ve Veri Hazırlık\n\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras import layers\nimport numpy as np\nimport os\nimport random\n# Uyarıları kapatma kodları (isteğe bağlı)\nimport warnings\nwarnings.filterwarnings('ignore')\nos.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'\n\n# Sabitler\nDATA_DIR = '/kaggle/input/alaska2-image-steganalysis/' # Kaggle veri seti yolu\n# Sınıflar - Alaska2 için J-EMB sınıfı olmalı, UERD değil\nCLASSES = ['Cover', 'JMiPOD', 'JUNIWARD', 'UERD']\nCLASS_LABELS = {cls: i for i, cls in enumerate(CLASSES)}\n\nIMG_HEIGHT = 224\nIMG_WIDTH = 224\nBATCH_SIZE = 32\nNUM_CLASSES = len(CLASSES)\nAUTOTUNE = tf.data.AUTOTUNE\n\n# Transformer Ayarları (Model mimarisi için, burada tanımlı kalabilir veya Hücre 2'ye taşınabilir)\nNUM_HEADS = 8\nFF_DIM = 2048\nNUM_TRANSFORMER_BLOCKS = 1\nMLP_HIDDEN_UNITS = [512]\nDROPOUT_RATE = 0.1\n\n\n# --- Veri Yükleme ve Hazırlık ---\ndef list_files_and_labels(data_dir):\n    all_image_paths = []\n    all_image_labels = []\n    for cls_name in CLASSES:\n        cls_dir = os.path.join(data_dir, cls_name)\n        if os.path.exists(cls_dir):\n            image_files = [os.path.join(cls_dir, f) for f in os.listdir(cls_dir) if f.endswith('.jpg')]\n            all_image_paths.extend(image_files)\n            all_image_labels.extend([CLASS_LABELS[cls_name]] * len(image_files))\n        else:\n            print(f\"Uyarı: Klasör bulunamadı: {cls_dir}\")\n    return all_image_paths, all_image_labels\n\nall_paths, all_labels = list_files_and_labels(DATA_DIR)\n\ncombined = list(zip(all_paths, all_labels))\nrandom.shuffle(combined) # Veriyi karıştır\nall_paths, all_labels = zip(*combined)\n\n\n# !!! BURASI DEĞİŞTİRİLDİ: Veri setini %80 Eğitim / %10 Doğrulama / %10 Test olarak ayırıyoruz !!!\nTRAIN_SPLIT = 0.8\nVAL_SPLIT = 0.1\nTEST_SPLIT = 0.1 # TRAIN_SPLIT + VAL_SPLIT + TEST_SPLIT = 1.0 olduğundan emin olun\n\ntotal_size = len(all_paths)\ntrain_size = int(total_size * TRAIN_SPLIT)\nval_size = int(total_size * VAL_SPLIT)\n# Test boyutu kalan kısım\ntest_size = total_size - train_size - val_size\n\n\n# Veriyi ayırma için indexleri hesapla\ntrain_end_index = train_size\nval_end_index = train_size + val_size # Validasyonun bittiği yer, testin başladığı yer\n\n\n# Veriyi dilimleme\ntrain_paths = all_paths[:train_end_index]\ntrain_labels = all_labels[:train_end_index]\n\nval_paths = all_paths[train_end_index:val_end_index]\nval_labels = all_labels[train_end_index:val_end_index]\n\ntest_paths = all_paths[val_end_index:]\ntest_labels = all_labels[val_end_index:]\n\n\n# !!! BURASI GÜNCELLENDİ: Üç yeni veri set boyutunu gösteriyoruz !!!\nprint(f\"Toplam veri: {total_size}\")\nprint(f\"Eğitim verisi ({TRAIN_SPLIT*100}%): {len(train_paths)}\")\nprint(f\"Doğrulama verisi ({VAL_SPLIT*100}%): {len(val_paths)}\")\nprint(f\"Test verisi ({TEST_SPLIT*100}%): {len(test_paths)}\")\n\n\n# EfficientNet preprocessing kullanılıyor (Aynı)\ndef preprocess_image(image_path, label):\n    img = tf.io.read_file(image_path)\n    img = tf.image.decode_jpeg(img, channels=3)\n    img = tf.image.resize(img, [IMG_HEIGHT, IMG_WIDTH])\n    # EfficientNet'in kendi ön işlemcisini kullan\n    img = tf.keras.applications.efficientnet.preprocess_input(img)\n    label = tf.one_hot(label, NUM_CLASSES)\n    return img, label\n\n\n# tf.data datasetlerini oluşturma (Üç dataset olacak)\ntrain_dataset = tf.data.Dataset.from_tensor_slices((list(train_paths), list(train_labels)))\ntrain_dataset = train_dataset.map(preprocess_image, num_parallel_calls=AUTOTUNE)\ntrain_dataset = train_dataset.shuffle(buffer_size=1000).batch(BATCH_SIZE).prefetch(buffer_size=AUTOTUNE)\n\nval_dataset = tf.data.Dataset.from_tensor_slices((list(val_paths), list(val_labels)))\nval_dataset = val_dataset.map(preprocess_image, num_parallel_calls=AUTOTUNE)\nval_dataset = val_dataset.batch(BATCH_SIZE).prefetch(buffer_size=AUTOTUNE)\n\n# !!! BURASI EKLENDİ: Test dataseti oluşturma !!!\ntest_dataset = tf.data.Dataset.from_tensor_slices((list(test_paths), list(test_labels)))\ntest_dataset = test_dataset.map(preprocess_image, num_parallel_calls=AUTOTUNE)\n# Test seti için shuffle ve prefetch gerekli olmayabilir, sadece batch yeterli\ntest_dataset = test_dataset.batch(BATCH_SIZE).prefetch(buffer_size=AUTOTUNE)\n\n\nprint(\"\\nHücre 1 Tamamlandı: Veri 3 parçaya ayrıldı ve hazırlandı.\")","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-05-04T21:30:08.378401Z","iopub.execute_input":"2025-05-04T21:30:08.379029Z","iopub.status.idle":"2025-05-04T21:30:12.804324Z","shell.execute_reply.started":"2025-05-04T21:30:08.379004Z","shell.execute_reply":"2025-05-04T21:30:12.803497Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Hücre 2: Model Mimarisi Tanımları\n\n# EfficientNet Özellik Çıkarıcıyı ayrı bir fonksiyonla oluşturalım\ndef get_efficientnet_backbone(input_shape=(IMG_HEIGHT, IMG_WIDTH, 3)):\n     base_model = tf.keras.applications.EfficientNetB0(\n         include_top=False,\n         weights='imagenet',\n         input_shape=input_shape\n     )\n     return base_model\n\n# Transformer Encoder Bloğu\nclass TransformerBlock(layers.Layer):\n    def __init__(self, embed_dim, num_heads, ff_dim, rate=0.1):\n        super().__init__()\n        self.att = layers.MultiHeadAttention(num_heads=num_heads, key_dim=embed_dim)\n        self.ffn = keras.Sequential(\n            [layers.Dense(ff_dim, activation=\"relu\"), layers.Dense(embed_dim),]\n        )\n        self.layernorm1 = layers.LayerNormalization(epsilon=1e-6)\n        self.layernorm2 = layers.LayerNormalization(epsilon=1e-6)\n        self.dropout1 = layers.Dropout(rate)\n        self.dropout2 = layers.Dropout(rate)\n\n    def call(self, inputs, training=None):\n        attn_output = self.att(inputs, inputs)\n        attn_output = self.dropout1(attn_output, training=training)\n        out1 = self.layernorm1(inputs + attn_output)\n        ffn_output = self.ffn(out1)\n        ffn_output = self.dropout2(ffn_output, training=training)\n        return self.layernorm2(out1 + ffn_output)\n\n# Özellik haritasını token dizisine dönüştürme katmanı\nclass RearrangeToTokens(layers.Layer):\n    def call(self, x):\n        batch_size, h, w, c = tf.unstack(tf.shape(x))\n        x = tf.reshape(x, (batch_size, h * w, c))\n        return x\n\n# Konumsal Embedding katmanı\nclass PositionEmbedding(layers.Layer):\n    def __init__(self, sequence_length, embed_dim):\n        super().__init__()\n        self.sequence_length = sequence_length\n        self.embed_dim = embed_dim\n        self.position_embedding = layers.Embedding(\n            input_dim=sequence_length, output_dim=embed_dim\n        )\n\n    def call(self, inputs):\n        positions = tf.range(start=0, limit=self.sequence_length, delta=1)\n        embedded_positions = self.position_embedding(positions)\n        return inputs + embedded_positions\n\n# Hibrit Modeli Oluşturan Ana Fonksiyon\n# Bu fonksiyon sadece mimariyi kurar, dondurma/çözme dışarıda yapılacak\ndef build_hybrid_model(input_shape=(IMG_HEIGHT, IMG_WIDTH, 3), num_classes=NUM_CLASSES):\n    inputs = keras.Input(shape=input_shape)\n\n    # EfficientNet Backbone'u burada oluşturuyoruz\n    effnet_backbone = get_efficientnet_backbone(input_shape)\n    # Backbone'dan çıkan özellikleri alıyoruz\n    effnet_features = effnet_backbone(inputs)\n\n    # Geri kalan katmanlar (Transformer ve Sınıflandırma başlığı)\n    tokens = RearrangeToTokens()(effnet_features)\n    embed_dim = tokens.shape[-1]\n    sequence_length = tokens.shape[1]\n    position_embedding_layer = PositionEmbedding(sequence_length, embed_dim)\n    x = position_embedding_layer(tokens)\n    x = layers.Dropout(DROPOUT_RATE)(x)\n\n    for _ in range(NUM_TRANSFORMER_BLOCKS):\n        x = TransformerBlock(embed_dim, NUM_HEADS, FF_DIM, DROPOUT_RATE)(x)\n\n    representation = layers.GlobalAveragePooling1D()(x)\n\n    for units in MLP_HIDDEN_UNITS:\n        representation = layers.Dense(units, activation=\"relu\")(representation)\n        representation = layers.Dropout(DROPOUT_RATE)(representation)\n\n    outputs = layers.Dense(num_classes, activation=\"softmax\")(representation)\n\n    # Modeli döndürürken backbone'u da döndürelim ki dışarıdan erişip dondurabilelim\n    model = keras.Model(inputs=inputs, outputs=outputs)\n    return model, effnet_backbone # Modeli ve backbone'u döndür\n\nprint(\"Hücre 2 Tamamlandı: Model mimarisi tanımlandı.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T21:31:21.992845Z","iopub.execute_input":"2025-05-04T21:31:21.993430Z","iopub.status.idle":"2025-05-04T21:31:22.005109Z","shell.execute_reply.started":"2025-05-04T21:31:21.993405Z","shell.execute_reply":"2025-05-04T21:31:22.004317Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Hücre 3: Model Oluşturma ve Aşama 1 Eğitim (Backbone Dondurulmuş)\n\n# Modeli ve backbone referansını oluştur\n# Bu fonksiyonu sadece bir kez çalıştırmanız gerekir!\nmodel, effnet_backbone = build_hybrid_model()\n\n\nprint(\"\\n--- Aşama 1: Backbone Donduruluyor ---\")\n# Backbone'u dondur\neffnet_backbone.trainable = False\n\n# Modeli Aşama 1 için derle\n# Sadece yeni katmanları eğiteceğimiz için biraz daha yüksek bir LR kullanabiliriz\noptimizer_phase1 = tf.keras.optimizers.Adam(learning_rate=1e-4)\nmodel.compile(optimizer=optimizer_phase1,\n              loss='categorical_crossentropy',\n              metrics=['accuracy'])\n\nprint(\"Aşama 1 Model Özeti (Trainable params sadece ek katmanlar olmalı):\")\nmodel.summary()\n\nEPOCHS_PHASE1 = 5 # Örn: Backbone dondurulmuşken 5 epoch eğit\n\nprint(f\"\\nAşama 1 Eğitime başlıyor ({EPOCHS_PHASE1} epoch)...\")\nhistory_phase1 = model.fit(\n    train_dataset,\n    epochs=EPOCHS_PHASE1,\n    validation_data=val_dataset\n)\n\nprint(\"\\nHücre 3 Tamamlandı: Aşama 1 Eğitim Bitti.\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2025-05-04T21:31:47.772828Z","iopub.execute_input":"2025-05-04T21:31:47.773303Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Hücre 4: Aşama 2 Eğitim (Backbone Çözülmüş - İnce Ayar)\n\nprint(\"\\n--- Aşama 2: Backbone Çözülüyor ve İnce Ayar ---\")\n# Backbone'u çöz\neffnet_backbone.trainable = True\n\n# Modeli tekrar derle (Önemli! Trainability değiştiğinde tekrar derlemek gerekir)\n# İnce ayar için çok daha düşük bir LR kullan\noptimizer_phase2 = tf.keras.optimizers.Adam(learning_rate=1e-5) # Genellikle 1e-5 veya daha düşük\n\n# Aşama 2 için Learning Rate Scheduler (İsteğe bağlı)\nreduce_lr_phase2 = tf.keras.callbacks.ReduceLROnPlateau(\n    monitor='val_loss',\n    factor=0.5,\n    patience=3,\n    min_lr=1e-8,\n    verbose=1\n)\n\nmodel.compile(optimizer=optimizer_phase2,\n              loss='categorical_crossentropy',\n              metrics=['accuracy'])\n\nprint(\"Aşama 2 Model Özeti (Tüm katmanlar trainable olmalı):\")\nmodel.summary() # Trainable params sayısının arttığını göreceksiniz\n\nEPOCHS_PHASE2 = 15 # Örn: İnce ayar için 15 epoch daha eğit\nTOTAL_EPOCHS = EPOCHS_PHASE1 + EPOCHS_PHASE2 # Toplam epoch sayısı Hücre 3'teki EPOCHS_PHASE1'den alınır\n\n\nprint(f\"\\nAşama 2 Eğitime başlıyor ({EPOCHS_PHASE2} epoch, toplam {TOTAL_EPOCHS} epoch)...\")\nhistory_phase2 = model.fit(\n    train_dataset,\n    epochs=TOTAL_EPOCHS,         # Toplam epoch sayısı\n    initial_epoch=EPOCHS_PHASE1,  # Aşama 1'in bittiği epoch'tan başla\n    validation_data=val_dataset,\n    callbacks=[reduce_lr_phase2] # Learning Rate Scheduler'ı ekle\n)\n\nprint(\"\\nHücre 4 Tamamlandı: İki Aşamalı Eğitim Bitti.\")\n","metadata":{"trusted":true},"outputs":[],"execution_count":null}]}