{"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":"none","dataSources":[{"sourceId":97984,"databundleVersionId":14096757,"sourceType":"competition"},{"sourceId":2781575,"sourceType":"datasetVersion","datasetId":1279557},{"sourceId":13467323,"sourceType":"datasetVersion","datasetId":8548912}],"dockerImageVersionId":31153,"isInternetEnabled":false,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# =============================================================================\n# 1. Gerekli Kütüphanelerin Yüklenmesi\n# =============================================================================\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport os\nimport logging\nimport cv2\nimport time\nfrom tqdm.notebook import tqdm\nfrom scipy.signal import resample\nfrom sklearn.model_selection import train_test_split\nimport tensorflow as tf\nfrom tensorflow import keras\nfrom tensorflow.keras.models import Model\nfrom tensorflow.keras.layers import Input, Dense, GlobalAveragePooling2D, Dropout\nfrom tensorflow.keras.applications import EfficientNetB0\nfrom tensorflow.keras.callbacks import ReduceLROnPlateau\n\nprint(\"TensorFlow Sürümü:\", tf.__version__)\n\n# =============================================================================\n# 2. Yapılandırma ve Loglama\n# =============================================================================\nlog_format = '%(asctime)s - %(levelname)s - [%(filename)s:%(lineno)d] - %(message)s'\nlogging.basicConfig(level=logging.INFO, format=log_format)\n\nclass Config:\n    DEBUG_MODE = False\n    IMG_HEIGHT = 128\n    IMG_WIDTH = 512\n    SEQ_LENGTH = 512\n    BATCH_SIZE = 32\n    EPOCHS = 10 if not DEBUG_MODE else 2\n    TRAIN_SAMPLES = 2500 if not DEBUG_MODE else 50\n    VAL_SAMPLES = 400 if not DEBUG_MODE else 10\n    INITIAL_LEARNING_RATE = 5e-4\n\nCONFIG = Config()\nLEAD_NAMES = ['I', 'II', 'III', 'aVR', 'aVL', 'aVF', 'V1', 'V2', 'V3', 'V4', 'V5', 'V6']\nlogging.info(f\"Hızlı mod (DEBUG_MODE) {'AÇIK' if CONFIG.DEBUG_MODE else 'KAPALI'}.\")\n\n# --- HARMANLANACAK DOSYALARIN YOLLARI ---\nEFFICIENTNET_WEIGHTS_PATH = '/kaggle/input/keras-applications-models/EfficientNetB0.h5'\nEXTERNAL_SUBMISSION_PATH = '/kaggle/input/0-0900/submission - 2025-10-22T170405.663.csv'\n\n# Dosyaların varlığını kontrol et\nif not os.path.exists(EFFICIENTNET_WEIGHTS_PATH):\n    raise FileNotFoundError(\"Keras Applications Models veri setini eklemediniz!\")\nif not os.path.exists(EXTERNAL_SUBMISSION_PATH):\n    raise FileNotFoundError(\"Harmanlanacak harici submission.csv dosyasını eklemediniz!\")\n\n# =============================================================================\n# 3. Veri Yükleme ve Bölme\n# =============================================================================\nlogging.info(\"Yarışma verileri yükleniyor...\")\ndata_dir = \"/kaggle/input/physionet-ecg-image-digitization\"\nfull_train_df = pd.read_csv(os.path.join(data_dir, \"train.csv\"))\ntest_df = pd.read_csv(os.path.join(data_dir, \"test.csv\"))\nunique_ids = full_train_df['id'].unique()\ntrain_ids, val_ids = train_test_split(unique_ids, test_size=0.15, random_state=42)\ntrain_df = full_train_df[full_train_df['id'].isin(train_ids)].copy()\nval_df = full_train_df[full_train_df['id'].isin(val_ids)].copy()\n\nif CONFIG.DEBUG_MODE:\n    train_df = train_df.sample(n=CONFIG.TRAIN_SAMPLES, random_state=42).reset_index(drop=True)\n    val_df = val_df.sample(n=CONFIG.VAL_SAMPLES, random_state=42).reset_index(drop=True)\n\n# =============================================================================\n# 4. Veri Hattı Fonksiyonları\n# =============================================================================\ndef get_lead_images_from_file(image_path):\n    try:\n        image = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)\n        if image is None: return None\n        _, thresh = cv2.threshold(image, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)\n        height, width = thresh.shape\n        lead_boxes = [\n            (140, 205, 120, 620), (270, 335, 120, 620), (140, 205, 620, 1120), \n            (205, 270, 620, 1120), (270, 335, 620, 1120), (140, 205, 1120, 1620), \n            (205, 270, 1120, 1620), (270, 335, 1120, 1620), (140, 205, 1620, 2120), \n            (205, 270, 1620, 2120), (270, 335, 1620, 2120)\n        ]\n        rhythm_strip = thresh[400:480, 120:width-120]\n        lead_images = [thresh[y1:y2, x1:x2] for y1, y2, x1, x2 in lead_boxes]\n        lead_images.insert(1, rhythm_strip)\n        return lead_images\n    except Exception: return None\n\ndef process_path(image_path, signal_path=None):\n    lead_images_raw = get_lead_images_from_file(image_path.numpy().decode('utf-8'))\n    if lead_images_raw is None: return tf.zeros((12, CONFIG.IMG_HEIGHT, CONFIG.IMG_WIDTH, 3)), tf.zeros((12, CONFIG.SEQ_LENGTH))\n    processed_images = []\n    for img in lead_images_raw:\n        if img.shape[0] == 0 or img.shape[1] == 0: img = np.zeros((CONFIG.IMG_HEIGHT, CONFIG.IMG_WIDTH), dtype=np.uint8)\n        img_resized = tf.image.resize(img[..., tf.newaxis], [CONFIG.IMG_HEIGHT, CONFIG.IMG_WIDTH])\n        processed_images.append(tf.image.grayscale_to_rgb(img_resized))\n    images_tensor = tf.stack(processed_images)\n    if signal_path is not None:\n        true_ts_df = pd.read_csv(signal_path.numpy().decode('utf-8'))\n        true_ts_df.ffill(inplace=True); true_ts_df.bfill(inplace=True)\n        signals_tensor = tf.stack([resample(true_ts_df[lead].values.astype(np.float32), CONFIG.SEQ_LENGTH) for lead in LEAD_NAMES])\n        return images_tensor, signals_tensor\n    else: return images_tensor\n\ndef create_dataset(df, is_train=True):\n    image_paths = [f\"{data_dir}/train/{rec_id}/{rec_id}-0001.png\" for rec_id in df['id']]\n    signal_paths = [f\"{data_dir}/train/{rec_id}/{rec_id}.csv\" for rec_id in df['id']]\n    dataset = tf.data.Dataset.from_tensor_slices((image_paths, signal_paths))\n    def py_func_wrapper(img_p, sig_p):\n        images, signals = tf.py_function(process_path, [img_p, sig_p], [tf.float32, tf.float32])\n        images.set_shape([12, CONFIG.IMG_HEIGHT, CONFIG.IMG_WIDTH, 3]); signals.set_shape([12, CONFIG.SEQ_LENGTH])\n        return images, signals\n    dataset = dataset.map(py_func_wrapper, num_parallel_calls=tf.data.AUTOTUNE)\n    if is_train: dataset = dataset.shuffle(buffer_size=100)\n    dataset = dataset.unbatch().batch(CONFIG.BATCH_SIZE).prefetch(tf.data.AUTOTUNE)\n    return dataset\n\ntrain_dataset = create_dataset(train_df)\nval_dataset = create_dataset(val_df, is_train=False)\n\n# =============================================================================\n# 5. Model Mimarisi ve SNR Callback'i\n# =============================================================================\ndef align_and_get_powers(true_signal, pred_signal, fs):\n    try:\n        pred_centered, true_centered = pred_signal - np.mean(pred_signal), true_signal - np.mean(true_signal)\n        max_shift = int(0.2 * fs)\n        corr = np.correlate(pred_centered, true_centered, mode='full')\n        best_shift = np.clip(np.argmax(corr) - (len(pred_centered) - 1), -max_shift, max_shift)\n        if best_shift >= 0: aligned_pred, aligned_true = pred_centered[best_shift:], true_centered[:len(pred_centered) - best_shift]\n        else: aligned_pred, aligned_true = pred_centered[:len(true_centered) + best_shift], true_centered[-best_shift:]\n        min_len = min(len(aligned_pred), len(aligned_true))\n        if min_len == 0: return 0.0, 1.0\n        aligned_true, aligned_pred = aligned_true[:min_len], aligned_pred[:min_len]\n        return np.sum(aligned_true ** 2), max(np.sum((aligned_true - aligned_pred) ** 2), 1e-9)\n    except Exception: return 0.0, 1.0\n\nclass SNREvaluationCallback(keras.callbacks.Callback):\n    def __init__(self, val_df, full_df): super().__init__(); self.val_df, self.full_df, self.best_snr = val_df, full_df, -np.inf\n    def on_epoch_end(self, epoch, logs=None):\n        logs = logs or {}; cv_scores = []\n        for rec_id in self.val_df['id'].unique():\n            image_path = f\"{data_dir}/train/{rec_id}/{rec_id}-0001.png\"\n            lead_images_tensor = tf.py_function(process_path, [image_path], [tf.float32])[0]\n            if tf.shape(lead_images_tensor)[0] != 12: continue\n            predicted_sequences = self.model.predict(lead_images_tensor, verbose=0)\n            true_ts_df = pd.read_csv(f\"{data_dir}/train/{rec_id}/{rec_id}.csv\")\n            fs = self.full_df[self.full_df['id'] == rec_id].iloc[0]['fs']\n            total_signal_power, total_error_power = 0.0, 0.0\n            for i, lead_name in enumerate(LEAD_NAMES):\n                true_signal = true_ts_df[lead_name].values\n                if np.isnan(true_signal).any(): continue\n                pred_resampled = resample(predicted_sequences[i], len(true_signal))\n                signal_power, error_power = align_and_get_powers(true_signal, pred_resampled, fs)\n                total_signal_power += signal_power; total_error_power += error_power\n            if total_error_power > 0: cv_scores.append(10 * np.log10(total_signal_power / total_error_power))\n        avg_snr = np.mean(cv_scores) if cv_scores else -np.inf; logs['val_snr'] = avg_snr\n        if avg_snr > self.best_snr: self.best_snr = avg_snr; print(f\" - val_snr: {avg_snr:.4f} (Yeni en iyi skor!)\")\n        else: print(f\" - val_snr: {avg_snr:.4f}\")\n\ndef build_ecg_model(input_shape, seq_length):\n    base_model = EfficientNetB0(include_top=False, weights=EFFICIENTNET_WEIGHTS_PATH, input_shape=input_shape)\n    base_model.trainable = False\n    inputs = Input(shape=input_shape)\n    x = base_model(inputs, training=False)\n    x = GlobalAveragePooling2D()(x); x = Dropout(0.3)(x)\n    x = Dense(1024, activation='relu')(x); x = Dropout(0.3)(x)\n    x = Dense(1024, activation='relu')(x); x = Dropout(0.3)(x)\n    x = Dense(512, activation='relu')(x)\n    outputs = Dense(seq_length, activation='linear')(x)\n    model = Model(inputs, outputs)\n    optimizer = keras.optimizers.Adam(learning_rate=CONFIG.INITIAL_LEARNING_RATE)\n    model.compile(optimizer=optimizer, loss='mae')\n    return model\n\necg_digitizer_model = build_ecg_model(input_shape=(CONFIG.IMG_HEIGHT, CONFIG.IMG_WIDTH, 3), seq_length=CONFIG.SEQ_LENGTH)\necg_digitizer_model.summary()\n\n# =============================================================================\n# 6. Modelin Eğitilmesi\n# =============================================================================\nlogging.info(\"Model eğitimi başlıyor...\")\nsnr_callback = SNREvaluationCallback(val_df, full_train_df)\nlr_scheduler = ReduceLROnPlateau(monitor='val_loss', factor=0.5, patience=2, min_lr=1e-6, verbose=1)\nstart_time = time.time()\nhistory = ecg_digitizer_model.fit(\n    train_dataset,\n    epochs=CONFIG.EPOCHS,\n    validation_data=val_dataset,\n    callbacks=[snr_callback, lr_scheduler],\n    verbose=1\n)\nend_time = time.time()\nlogging.info(f\"Model eğitimi {end_time - start_time:.2f} saniyede tamamlandı.\")\n\n# =============================================================================\n# 7. Notebook Tahminlerinin Üretilmesi\n# =============================================================================\nlogging.info(\"Notebook'un test seti tahminleri üretiliyor...\")\nnotebook_predictions = []\nfor base_id, group in tqdm(test_df.groupby('id'), desc=\"Notebook Tahminleri\"):\n    image_path = f\"{data_dir}/test/{base_id}.png\"\n    lead_images_tensor = tf.py_function(process_path, [image_path], [tf.float32])[0]\n    if tf.shape(lead_images_tensor)[0] != 12:\n        for _, row in group.iterrows():\n            for i in range(row['number_of_rows']): notebook_predictions.append({'id': f\"{base_id}_{i}_{row['lead']}\", 'value': 0.0})\n        continue\n    predicted_sequences = ecg_digitizer_model.predict(lead_images_tensor, verbose=0)\n    for _, row in group.iterrows():\n        lead_name, num_rows_expected = row['lead'], row['number_of_rows']\n        lead_index = LEAD_NAMES.index(lead_name)\n        final_signal = resample(predicted_sequences[lead_index], num_rows_expected)\n        for i, value in enumerate(final_signal):\n            notebook_predictions.append({'id': f\"{base_id}_{i}_{row['lead']}\", 'value': float(value)})\n\nnotebook_submission_df = pd.DataFrame(notebook_predictions)\nlogging.info(\"Notebook tahminleri başarıyla üretildi.\")\n\n# =============================================================================\n# 8. Harmanlama (Blending) ve Son Sunum Dosyasını Oluşturma\n# =============================================================================\nlogging.info(\"Harmanlama süreci başlıyor...\")\n\n# Harici sunum dosyasını yükle\nlogging.info(f\"Harici sunum dosyası yükleniyor: {EXTERNAL_SUBMISSION_PATH}\")\nexternal_sub_df = pd.read_csv(EXTERNAL_SUBMISSION_PATH)\n\n# İki DataFrame'i birleştir\nmerged_df = pd.merge(notebook_submission_df, external_sub_df, on='id', suffixes=('_notebook', '_external'))\n\n# Birleştirme sonrası boyutları kontrol et\nif len(merged_df) != len(notebook_submission_df):\n    logging.warning(\"Birleştirme sonrası satır sayısı değişti! Bazı ID'ler eşleşmemiş olabilir.\")\n\n# Ağırlıklı ortalamayı uygula\nlogging.info(\"Ağırlıklı ortalama uygulanıyor (80% harici, 20% notebook)...\")\nmerged_df['value'] = 0.80 * merged_df['value_external'] + 0.20 * merged_df['value_notebook']\n\n# Nihai sunum dosyasını oluştur\nfinal_submission_df = merged_df[['id', 'value']]\n\n# Son dosyayı kaydet\nfinal_submission_df.to_csv('submission.csv', index=False)\n\nlogging.info(\"Harmanlanmış sunum dosyası 'submission.csv' başarıyla oluşturuldu!\")\nprint(\"\\nHarmanlanmış Sunum Dosyasından Örnekler:\")\ndisplay(final_submission_df.head(15))","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","trusted":true,"execution":{"iopub.status.busy":"2025-10-22T15:07:45.153205Z","iopub.execute_input":"2025-10-22T15:07:45.154139Z"}},"outputs":[],"execution_count":null}]}