{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.12.12","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"nvidiaTeslaT4","dataSources":[{"sourceType":"datasetVersion","sourceId":3337316,"datasetId":2015227,"databundleVersionId":3388378}],"dockerImageVersionId":31329,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"# Instal library PyTorch Image Models (timm)\n!pip install timm -q\n\nimport os\nimport time\nimport pandas as pd\nimport torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torchvision import datasets, transforms\nfrom torch.utils.data import DataLoader\nimport timm\n\n# Cek ketersediaan GPU\ndevice = torch.device(\"cuda\" if torch.cuda.is_available() else \"cpu\")\nprint(f\"Menggunakan device: {device}\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-27T05:50:58.522048Z","iopub.execute_input":"2026-05-27T05:50:58.522423Z","iopub.status.idle":"2026-05-27T05:51:16.616348Z","shell.execute_reply.started":"2026-05-27T05:50:58.52238Z","shell.execute_reply":"2026-05-27T05:51:16.615593Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ganti tulisan hf_xxx di bawah dengan token asli yang baru saja Anda copy\nos.environ[\"HF_TOKEN\"] = \"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\"\n\nprint(\"Hugging Face Token berhasil dipasang!\")","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-27T05:51:16.618128Z","iopub.execute_input":"2026-05-27T05:51:16.618521Z","iopub.status.idle":"2026-05-27T05:51:16.623199Z","shell.execute_reply.started":"2026-05-27T05:51:16.618494Z","shell.execute_reply":"2026-05-27T05:51:16.622214Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Ganti dengan path dataset Malimg Anda di Kaggle\nDATA_DIR = '/kaggle/input/datasets/manmandes/malimg/malimg_dataset/train'\nBATCH_SIZE = 32\nIMG_SIZE = 224\n\n# 1. Definisi Transformasi Gambar (Resize & Normalisasi standar ImageNet)\ntransform = transforms.Compose([\n    transforms.Resize((IMG_SIZE, IMG_SIZE)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\n# 2. Muat Dataset\nfull_dataset = datasets.ImageFolder(root=DATA_DIR, transform=transform)\nnum_classes = len(full_dataset.classes)\nprint(f\"Jumlah kelas malware: {num_classes}\")\n\n# 3. Bagi dataset (80% Train, 20% Validasi)\ntrain_size = int(0.8 * len(full_dataset))\nval_size = len(full_dataset) - train_size\ntrain_dataset, val_dataset = torch.utils.data.random_split(full_dataset, [train_size, val_size])\n\n# 4. Buat DataLoader (Pengatur antrean batch)\ntrain_loader = DataLoader(train_dataset, batch_size=BATCH_SIZE, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_dataset, batch_size=BATCH_SIZE, shuffle=False, num_workers=2)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-27T05:51:16.62429Z","iopub.execute_input":"2026-05-27T05:51:16.624603Z","iopub.status.idle":"2026-05-27T05:51:21.263421Z","shell.execute_reply.started":"2026-05-27T05:51:16.624549Z","shell.execute_reply":"2026-05-27T05:51:21.262752Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"# Kamus (Dictionary) 5 Model Pilihan Tesis Anda\nmodels_to_test = {\n    \"ResNet50\": \"resnet50\",                             # Baseline (Arsitektur Berat)\n    \"MobileNetV3-Small\": \"mobilenetv3_small_100\",       # Lightweight CNN (Depthwise Separable)\n    \"EfficientNetV2-B0\": \"tf_efficientnetv2_b0\",        # Compound Scaling\n    \"GhostNet-100\": \"ghostnet_100\",                     # Cheap Linear Operations\n    \"MobileViT-Small\": \"mobilevit_s\"                    # Vision Transformer (Attention Mechanism)\n}\n\n# Fungsi untuk memuat dan memodifikasi model\ndef build_model(model_name, num_classes):\n    # Buat model pre-trained, ganti jumlah layer output (num_classes) secara otomatis\n    model = timm.create_model(model_name, pretrained=True, num_classes=num_classes)\n    return model.to(device)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-27T05:51:21.264247Z","iopub.execute_input":"2026-05-27T05:51:21.264603Z","iopub.status.idle":"2026-05-27T05:51:21.269278Z","shell.execute_reply.started":"2026-05-27T05:51:21.264551Z","shell.execute_reply":"2026-05-27T05:51:21.268393Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"EPOCHS = 10\nbenchmark_results = []\n\nprint(\"=\"*60)\nprint(\"MEMULAI BENCHMARKING 5 ARSITEKTUR (PYTORCH)\")\nprint(\"=\"*60)\n\nfor name, timm_name in models_to_test.items():\n    print(f\"\\n[INFO] Menyiapkan model: {name}...\")\n    \n    # Inisialisasi Model, Loss Function, dan Optimizer\n    model = build_model(timm_name, num_classes)\n    criterion = nn.CrossEntropyLoss()\n    optimizer = optim.Adam(model.parameters(), lr=0.001)\n    \n    # Hitung jumlah parameter\n    total_params = sum(p.numel() for p in model.parameters())\n    \n    start_time = time.time()\n    \n    # --- TRAINING LOOP ---\n    for epoch in range(EPOCHS):\n        model.train()\n        running_loss = 0.0\n        for inputs, labels in train_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            \n            optimizer.zero_grad()       # Bersihkan sisa gradien\n            outputs = model(inputs)     # Prediksi\n            loss = criterion(outputs, labels) # Hitung error\n            loss.backward()             # Hitung turunan (backprop)\n            optimizer.step()            # Update bobot\n            \n    training_time = (time.time() - start_time) / 60\n    \n    # --- EVALUATION LOOP ---\n    model.eval()\n    correct = 0\n    total = 0\n    with torch.no_grad(): # Matikan perhitungan gradien agar memori hemat\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            _, predicted = torch.max(outputs.data, 1)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n            \n    accuracy = 100 * correct / total\n    \n    # Simpan Hasil\n    benchmark_results.append({\n        \"Arsitektur\": name,\n        \"Filosofi\": \"Transformer\" if \"ViT\" in name else \"CNN\",\n        \"Total Parameter\": f\"{total_params:,}\",\n        \"Waktu Training (Menit)\": round(training_time, 2),\n        \"Akurasi Validasi (%)\": round(accuracy, 2)\n    })\n    \n    print(f\"[SELESAI] {name} | Akurasi: {accuracy:.2f}% | Waktu: {training_time:.2f} mnt\")\n    \n    # Hapus model dari VRAM GPU agar tidak Out of Memory\n    del model\n    torch.cuda.empty_cache()\n\n# Tampilkan Hasil Akhir\ndf_results = pd.DataFrame(benchmark_results)\nprint(\"\\n\" + \"=\"*70)\nprint(\"HASIL AKHIR BENCHMARKING (MALIMG DATASET)\")\nprint(\"=\"*70)\ndisplay(df_results)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-27T05:51:21.270657Z","iopub.execute_input":"2026-05-27T05:51:21.270964Z","iopub.status.idle":"2026-05-27T06:23:29.521067Z","shell.execute_reply.started":"2026-05-27T05:51:21.27094Z","shell.execute_reply":"2026-05-27T06:23:29.520373Z"}},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import time\nimport copy\n\n# 1. Tentukan Sang Juara & Variabel Penyimpan Sejarah (History)\nchampion_timm_name = \"tf_efficientnetv2_b0\"\nprint(f\"Membangun ulang Model Juara: {champion_timm_name}...\")\n\nchampion_model = build_model(champion_timm_name, num_classes)\ncriterion = nn.CrossEntropyLoss()\noptimizer = optim.Adam(champion_model.parameters(), lr=0.001)\n\nEPOCHS_FINAL = 10\nbest_val_acc = 0.0\nbest_model_wts = copy.deepcopy(champion_model.state_dict())\n\n# List untuk menyimpan data grafik Bab 4\nhistory = {'train_loss': [], 'val_loss': [], 'train_acc': [], 'val_acc': []}\n\nprint(\"\\nMemulai Pelatihan Final. Memantau Train & Val...\")\nprint(\"=\"*60)\n\n# 2. LOOP PELATIHAN & VALIDASI\nfor epoch in range(EPOCHS_FINAL):\n    start_time = time.time()\n    \n    # --- FASE TRAINING ---\n    champion_model.train()\n    running_loss, correct, total = 0.0, 0, 0\n    \n    for inputs, labels in train_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        optimizer.zero_grad()\n        outputs = champion_model(inputs)\n        loss = criterion(outputs, labels)\n        loss.backward()\n        optimizer.step()\n        \n        running_loss += loss.item() * inputs.size(0)\n        _, predicted = torch.max(outputs, 1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n        \n    epoch_train_loss = running_loss / total\n    epoch_train_acc = 100 * correct / total\n    \n    # --- FASE VALIDASI ---\n    champion_model.eval()\n    val_loss, val_correct, val_total = 0.0, 0, 0\n    \n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = champion_model(inputs)\n            loss = criterion(outputs, labels)\n            \n            val_loss += loss.item() * inputs.size(0)\n            _, predicted = torch.max(outputs, 1)\n            val_total += labels.size(0)\n            val_correct += (predicted == labels).sum().item()\n            \n    epoch_val_loss = val_loss / val_total\n    epoch_val_acc = 100 * val_correct / val_total\n    \n    # Simpan ke history untuk grafik\n    history['train_loss'].append(epoch_train_loss)\n    history['val_loss'].append(epoch_val_loss)\n    history['train_acc'].append(epoch_train_acc)\n    history['val_acc'].append(epoch_val_acc)\n    \n    # Cek dan simpan bobot terbaik\n    if epoch_val_acc > best_val_acc:\n        best_val_acc = epoch_val_acc\n        best_model_wts = copy.deepcopy(champion_model.state_dict())\n    \n    time_elapsed = time.time() - start_time\n    print(f\"Epoch {epoch+1}/{EPOCHS_FINAL} | \"\n          f\"Train Loss: {epoch_train_loss:.4f} Acc: {epoch_train_acc:.2f}% | \"\n          f\"Val Loss: {epoch_val_loss:.4f} Acc: {epoch_val_acc:.2f}% | {time_elapsed:.0f} dtk\")\n\n# 3. KEMBALIKAN BOBOT TERBAIK (Mencegah Overfitting)\nchampion_model.load_state_dict(best_model_wts)\nprint(\"=\"*60)\nprint(f\"Pelatihan Selesai! Bobot terbaik diambil dari Val Acc: {best_val_acc:.2f}%\")\n\n# 4. UJIAN AKHIR (TEST SET)\nTEST_DIR = '/kaggle/input/datasets/manmandes/malimg/malimg_dataset/test'\ntest_dataset = datasets.ImageFolder(root=TEST_DIR, transform=transform)\ntest_loader = DataLoader(test_dataset, batch_size=BATCH_SIZE, shuffle=False)\n\nprint(\"\\nMengevaluasi Model Terbaik pada Data Uji (Unseen Data)...\")\nchampion_model.eval()\ntest_correct, test_total = 0, 0\n\nwith torch.no_grad():\n    for inputs, labels in test_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        outputs = champion_model(inputs)\n        _, predicted = torch.max(outputs, 1)\n        test_total += labels.size(0)\n        test_correct += (predicted == labels).sum().item()\n\ntest_accuracy = 100 * test_correct / test_total\nprint(\"=\"*60)\nprint(f\"🌟 AKURASI FINAL DI DATA UJI (TEST SET): {test_accuracy:.2f}% 🌟\")\nprint(\"=\"*60)","metadata":{"trusted":true,"execution":{"iopub.status.busy":"2026-05-27T06:25:32.000835Z","iopub.execute_input":"2026-05-27T06:25:32.001641Z","iopub.status.idle":"2026-05-27T06:31:08.42071Z","shell.execute_reply.started":"2026-05-27T06:25:32.001599Z","shell.execute_reply":"2026-05-27T06:31:08.41981Z"}},"outputs":[],"execution_count":null}]}