{"metadata":{"kernelspec":{"name":"python3","display_name":"Python 3"},"language_info":{"name":"python"},"colab":{"provenance":[],"gpuType":"T4","authorship_tag":"ABX9TyMcHMZgxJx+/n9UZb8gkX8n"},"accelerator":"GPU","kaggle":{"accelerator":"none","dataSources":[{"sourceId":87323,"databundleVersionId":9934427,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"from google.colab import drive\ndrive.mount('/content/drive')","metadata":{"id":"dTxGZyVphVP2","executionInfo":{"status":"ok","timestamp":1733102213541,"user_tz":-540,"elapsed":33953,"user":{"displayName":"현우","userId":"13721909872316796663"}},"outputId":"76a6c9bf-8224-4f97-ef8f-049e1403e6fd"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"!pip install torch torchvision pandas matplotlib","metadata":{"id":"-LXAOAzJhbE-"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport torch\nimport numpy as np\nimport pandas as pd\nfrom sklearn.model_selection import train_test_split\nfrom torch import nn, optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models, transforms\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom google.colab import drive\n\n# CUDA 설정 관련 오류 처리\ntorch.use_deterministic_algorithms(False)  # 결정적 알고리즘 비활성화\nos.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'  # CUDA에서 발생하는 비결정적 오류 해결\n\n# GPU 사용 여부 확인\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n# 랜덤 시드 고정\nrandom_seed = 999\nrandom.seed(random_seed)\nnp.random.seed(random_seed)\ntorch.manual_seed(random_seed)\ntorch.cuda.manual_seed_all(random_seed)\n\n# Google Drive 마운트\ndrive.mount('/content/drive')\n\n# 데이터셋 디렉토리 설정\nbase_dir = \"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024\"\ntrain_csv_path = os.path.join(base_dir, \"train.csv\")\ntest_dir = os.path.join(base_dir, \"Test\")\ntrain_images_dir = os.path.join(base_dir, 'Train')\n\n# CSV 파일 읽기\ntrain_df = pd.read_csv(train_csv_path)\n\n# 클래스 레이블을 0과 1로 매핑\ntrain_df['label'] = train_df['label'].map({'editada': 0, 'real': 1})\n\n# 이미지 데이터셋 클래스 정의\nclass CustomDataset(Dataset):\n    def __init__(self, dataframe, image_folder, transform=None):\n        self.img_labels = dataframe\n        self.image_folder = image_folder\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.img_labels)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.image_folder, self.img_labels.iloc[idx, 0])  # 이미지 경로\n        image = Image.open(img_name).convert('RGB')  # 이미지 열기\n        label = int(self.img_labels.iloc[idx, 1])  # 레이블\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n\n# 데이터 변환 정의 (데이터 증강 포함)\ntransform = transforms.Compose([\n    transforms.Resize((224, 224)),\n    transforms.RandomHorizontalFlip(),  # 좌우 반전\n    transforms.RandomRotation(30),  # 회전\n    transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2),  # 색상 조정\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\n# 학습 및 검증 데이터셋 분리\ntrain_df, val_df = train_test_split(train_df, test_size=0.2, random_state=random_seed)\n\n# CustomDataset으로 데이터셋 객체 생성\ntrain_dataset = CustomDataset(train_df, train_images_dir, transform=transform)\nval_dataset = CustomDataset(val_df, train_images_dir, transform=transform)\n\n# DataLoader 객체 생성\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=2)\n\n# ConvNeXt 모델 정의\nclass ConvNextModel(nn.Module):\n    def __init__(self):\n        super(ConvNextModel, self).__init__()\n        self.model = models.convnext_small(pretrained=True)  # ConvNeXt Small 모델\n        self.model.classifier[2] = nn.Linear(self.model.classifier[2].in_features, 2)  # 출력 클래스 수를 2로 설정\n\n    def forward(self, x):\n        return self.model(x)\n\n# 모델 초기화 및 GPU 설정\nconvnext_model = ConvNextModel().to(device)\n\n# 손실 함수와 최적화 함수 정의\ncriterion = nn.CrossEntropyLoss()  # CrossEntropyLoss는 로짓을 기대\noptimizer = optim.Adam(convnext_model.parameters(), lr=1e-4, weight_decay=1e-5)  # Weight decay 추가\n\n# 학습률 스케줄러 (CosineAnnealingLR 예시)\nscheduler = optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max=10)  # 10 에폭 후 주기적으로 학습률을 감소\n\n# 모델 학습\nnum_epochs = 15\nbest_val_accuracy = 0.0\nbest_val_loss = float('inf')  # 최저 검증 손실\nfor epoch in range(num_epochs):\n    convnext_model.train()\n    running_loss = 0.0\n    correct = 0\n    total = 0\n    for inputs, labels in tqdm(train_loader, desc=f\"Epoch {epoch+1}/{num_epochs}\", leave=False):\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        # 모델 예측\n        outputs = convnext_model(inputs)\n        loss = criterion(outputs, labels)\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        running_loss += loss.item()\n\n        # 정확도 계산\n        _, predicted = torch.max(outputs.data, 1)\n        correct += (predicted == labels).sum().item()\n        total += labels.size(0)\n\n    scheduler.step()  # 학습률 업데이트\n\n    # 에폭 종료 후 출력\n    epoch_loss = running_loss / len(train_loader)\n    epoch_acc = 100 * correct / total\n    print(f\"Epoch {epoch + 1}/{num_epochs}, Loss: {epoch_loss:.4f}, Accuracy: {epoch_acc:.2f}%\")\n\n    # 검증 데이터셋에서 성능 평가\n    convnext_model.eval()  # 평가 모드\n    val_correct = 0\n    val_total = 0\n    val_loss = 0.0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = convnext_model(inputs)\n            loss = criterion(outputs, labels)\n            _, predicted = torch.max(outputs.data, 1)\n            val_total += labels.size(0)\n            val_correct += (predicted == labels).sum().item()\n            val_loss += loss.item()\n\n    val_accuracy = 100 * val_correct / val_total\n    val_loss /= len(val_loader)\n\n    print(f\"Validation Accuracy: {val_accuracy:.2f}%, Validation Loss: {val_loss:.4f}\")\n\n    # 최고의 모델 저장 (검증 정확도가 개선되거나 검증 손실이 최소일 때)\n    if val_accuracy == 100.0:  # 정확도가 100%일 때 저장\n        print(\"Validation Accuracy reached 100%. Saving best model!\")\n        torch.save(convnext_model.state_dict(), \"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/best_model.pth\")\n\n    if val_loss < best_val_loss:  # 최소 검증 손실 기준으로 모델 저장\n        best_val_loss = val_loss\n        torch.save(convnext_model.state_dict(), \"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/best_model.pth\")\n        print(\"Best model saved based on validation loss!\")\n\n# 테스트 데이터셋에 대해 예측 수행\ntest_images = sorted(os.listdir(test_dir))  # 이미지 파일 목록\ntest_data = []\n\nfor img_name in test_images:\n    img_path = os.path.join(test_dir, img_name)\n    img = Image.open(img_path).convert('RGB')\n    img = transform(img).unsqueeze(0).to(device)  # 배치 차원 추가\n\n    convnext_model.eval()\n    with torch.no_grad():\n        output = convnext_model(img)\n        _, predicted = torch.max(output.data, 1)\n        test_data.append((img_name, predicted.item()))  # 0과 1로 된 label 저장\n\n# 제출 파일 준비\nsubmission = pd.DataFrame(test_data, columns=[\"image\", \"label\"])\nsubmission.to_csv(\"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/submission.csv\", index=False)\n\nprint(\"Submission file created at '/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/submission.csv'\")","metadata":{"id":"Ljg_5HfUhcpN","executionInfo":{"status":"ok","timestamp":1733103544896,"user_tz":-540,"elapsed":432080,"user":{"displayName":"현우","userId":"13721909872316796663"}},"outputId":"9d24d091-5c21-4aef-c3d5-969239bf861c"},"outputs":[],"execution_count":null},{"cell_type":"code","source":"import os\nimport random\nimport torch\nimport numpy as np\nimport pandas as pd\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nfrom sklearn.model_selection import train_test_split\nfrom torch import nn, optim\nfrom torch.utils.data import Dataset, DataLoader\nfrom torchvision import models, transforms\nfrom PIL import Image\nfrom tqdm import tqdm\nfrom google.colab import drive\nfrom sklearn.metrics import confusion_matrix\n\n# CUDA 설정 관련 오류 처리\ntorch.use_deterministic_algorithms(False)  # 결정적 알고리즘 비활성화\nos.environ['CUBLAS_WORKSPACE_CONFIG'] = ':4096:8'  # CUDA에서 발생하는 비결정적 오류 해결\n\n# GPU 사용 여부 확인\ndevice = torch.device(\"cuda:0\" if torch.cuda.is_available() else \"cpu\")\n\n# 랜덤 시드 고정\nrandom_seed = 999\nrandom.seed(random_seed)\nnp.random.seed(random_seed)\ntorch.manual_seed(random_seed)\ntorch.cuda.manual_seed_all(random_seed)\n\n# Google Drive 마운트\ndrive.mount('/content/drive')\n\n# 데이터셋 디렉토리 설정\nbase_dir = \"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024\"\ntrain_csv_path = os.path.join(base_dir, \"train.csv\")\ntest_dir = os.path.join(base_dir, \"Test\")\ntrain_images_dir = os.path.join(base_dir, 'Train')\n\n# CSV 파일 읽기\ntrain_df = pd.read_csv(train_csv_path)\n\n# 클래스 레이블을 0과 1로 매핑\ntrain_df['label'] = train_df['label'].map({'editada': 0, 'real': 1})\n\n# 데이터 분포 시각화\nclass_counts = train_df['label'].value_counts()\n\nplt.figure(figsize=(6, 4))\nsns.barplot(x=class_counts.index, y=class_counts.values, palette='viridis')\nplt.title('Class Distribution in Training Data')\nplt.xlabel('Class')\nplt.ylabel('Number of Samples')\nplt.xticks([0, 1], ['Fake (0)', 'Real (1)'])\nplt.show()\n\n# 이미지 데이터셋 클래스 정의\nclass CustomDataset(Dataset):\n    def __init__(self, dataframe, image_folder, transform=None):\n        self.img_labels = dataframe\n        self.image_folder = image_folder\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.img_labels)\n\n    def __getitem__(self, idx):\n        img_name = os.path.join(self.image_folder, self.img_labels.iloc[idx, 0])  # 이미지 경로\n        image = Image.open(img_name).convert('RGB')  # 이미지 열기\n        label = int(self.img_labels.iloc[idx, 1])  # 레이블\n\n        if self.transform:\n            image = self.transform(image)\n\n        return image, label\n\n# 데이터 변환 정의\ntransform = transforms.Compose([\n    transforms.RandomResizedCrop(224),\n    transforms.RandomHorizontalFlip(),\n    transforms.RandomRotation(20),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\n# 학습 및 검증 데이터셋 분리\ntrain_df, val_df = train_test_split(train_df, test_size=0.2, random_state=random_seed)\n\n# CustomDataset으로 데이터셋 객체 생성\ntrain_dataset = CustomDataset(train_df, train_images_dir, transform=transform)\nval_dataset = CustomDataset(val_df, train_images_dir, transform=transform)\n\n# DataLoader 객체 생성\ntrain_loader = DataLoader(train_dataset, batch_size=32, shuffle=True, num_workers=2)\nval_loader = DataLoader(val_dataset, batch_size=32, shuffle=False, num_workers=2)\n\n# ConvNeXt 모델 정의\nclass ConvNextModel(nn.Module):\n    def __init__(self):\n        super(ConvNextModel, self).__init__()\n        self.model = models.convnext_small(weights='DEFAULT')  # ConvNeXt Small 모델\n        self.model.classifier[2] = nn.Linear(self.model.classifier[2].in_features, 2)  # 출력 클래스 수를 2로 설정\n\n    def forward(self, x):\n        return self.model(x)  # 로짓을 반환\n\n# 모델 초기화 및 GPU 설정\nconvnext_model = ConvNextModel().to(device)\n\n# 손실 함수와 최적화 함수 정의\ncriterion = nn.CrossEntropyLoss()  # CrossEntropyLoss는 로짓을 기대\noptimizer = optim.Adam(convnext_model.parameters(), lr=1e-4)\n\n# 학습률 스케줄러\nscheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)\n\n# 학습을 위한 변수\nnum_epochs = 15\ntrain_losses = []\nval_losses = []\ntrain_accuracies = []\nval_accuracies = []\n\n# 모델 학습\nbest_val_accuracy = 0.0\nbest_val_loss = float('inf')  # 로스를 무한대로 초기화\nfor epoch in range(num_epochs):\n    convnext_model.train()\n    running_loss = 0.0\n    correct = 0\n    total = 0\n    for inputs, labels in tqdm(train_loader, desc=f\"Epoch {epoch+1}/{num_epochs}\", leave=False):\n        inputs, labels = inputs.to(device), labels.to(device)\n\n        # 모델 예측\n        outputs = convnext_model(inputs)  # 로짓을 반환\n        loss = criterion(outputs, labels)  # CrossEntropyLoss는 로짓을 기대\n        optimizer.zero_grad()  # 기울기 초기화\n        loss.backward()  # 역전파\n        optimizer.step()  # 최적화\n\n        running_loss += loss.item()\n\n        _, predicted = torch.max(outputs.data, 1)\n        total += labels.size(0)\n        correct += (predicted == labels).sum().item()\n\n    # 학습률 스케줄러\n    scheduler.step()\n\n    # 기록 저장\n    train_losses.append(running_loss / len(train_loader))\n    train_accuracies.append(100 * correct / total)\n\n    # 검증 데이터셋에서 성능 평가\n    convnext_model.eval()  # 평가 모드\n    val_loss = 0.0\n    correct = 0\n    total = 0\n    with torch.no_grad():\n        for inputs, labels in val_loader:\n            inputs, labels = inputs.to(device), labels.to(device)\n            outputs = convnext_model(inputs)\n            loss = criterion(outputs, labels)\n            val_loss += loss.item()\n\n            _, predicted = torch.max(outputs.data, 1)\n            total += labels.size(0)\n            correct += (predicted == labels).sum().item()\n\n    val_accuracy = 100 * correct / total\n    val_loss = val_loss / len(val_loader)  # 평균 로스 계산\n\n    val_losses.append(val_loss)\n    val_accuracies.append(val_accuracy)\n\n    print(f\"Epoch {epoch + 1}/{num_epochs}, Loss: {running_loss/len(train_loader):.4f}\")\n    print(f\"Validation Accuracy: {val_accuracy:.2f}%\")\n    print(f\"Validation Loss: {val_loss:.4f}\")\n\n    # 최고의 모델 저장 (검증 정확도 또는 로스 기준으로)\n    if val_loss < best_val_loss:  # 로스를 기준으로 모델 저장\n        best_val_loss = val_loss\n        torch.save(convnext_model.state_dict(), \"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/best_model.pth\")\n        print(f\"Best model saved! (Epoch {epoch+1})\")\n\n# 학습 및 검증 Loss, Accuracy 시각화\nepochs = range(1, num_epochs + 1)\n\nplt.figure(figsize=(12, 5))\n\n# 손실 시각화\nplt.subplot(1, 2, 1)\nplt.plot(epochs, train_losses, label='Train Loss', color='blue')\nplt.plot(epochs, val_losses, label='Validation Loss', color='red')\nplt.title('Training and Validation Loss')\nplt.xlabel('Epoch')\nplt.ylabel('Loss')\nplt.legend()\n\n# 정확도 시각화\nplt.subplot(1, 2, 2)\nplt.plot(epochs, train_accuracies, label='Train Accuracy', color='blue')\nplt.plot(epochs, val_accuracies, label='Validation Accuracy', color='red')\nplt.title('Training and Validation Accuracy')\nplt.xlabel('Epoch')\nplt.ylabel('Accuracy')\nplt.legend()\n\nplt.tight_layout()\nplt.show()\n\n# 테스트 데이터셋에 대해 예측 수행\ntest_images = sorted(os.listdir(test_dir))  # 이미지 파일 목록\ntest_data = []\n\nfor img_name in test_images:\n    img_path = os.path.join(test_dir, img_name)\n    img = Image.open(img_path).convert('RGB')\n    img = transform(img).unsqueeze(0).to(device)  # 배치 차원 추가\n\n    convnext_model.eval()\n    with torch.no_grad():\n        output = convnext_model(img)\n        _, predicted = torch.max(output.data, 1)\n        test_data.append((img_name, predicted.item()))  # 0과 1로 된 label 저장\n\n# 제출 파일 준비\nsubmission = pd.DataFrame(test_data, columns=[\"image\", \"label\"])\nsubmission.to_csv(\"/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/submission.csv\", index=False)\n\nprint(\"Submission file created at '/content/drive/MyDrive/cidaut-ai-fake-scene-classification-2024/submission.csv'\")\n\n# Confusion Matrix 시각화\nall_preds = []\nall_labels = []\n\nconvnext_model.eval()\nwith torch.no_grad():\n    for inputs, labels in val_loader:\n        inputs, labels = inputs.to(device), labels.to(device)\n        outputs = convnext_model(inputs)\n        _, predicted = torch.max(outputs.data, 1)\n        all_preds.extend(predicted.cpu().numpy())\n        all_labels.extend(labels.cpu().numpy())\n\ncm = confusion_matrix(all_labels, all_preds)\nplt.figure(figsize=(6, 4))\nsns.heatmap(cm, annot=True, fmt='d', cmap='Blues', xticklabels=['Fake', 'Real'], yticklabels=['Fake', 'Real'])\nplt.title('Confusion Matrix')\nplt.xlabel('Predicted')\nplt.ylabel('Actual')\nplt.show()","metadata":{"id":"AnSnQIzDI9Sv","executionInfo":{"status":"ok","timestamp":1733106291597,"user_tz":-540,"elapsed":724275,"user":{"displayName":"현우","userId":"13721909872316796663"}},"outputId":"95b13163-a032-4d4e-a10e-d25c57dae070"},"outputs":[],"execution_count":null}]}