{"metadata":{"kernelspec":{"language":"python","display_name":"Python 3","name":"python3"},"language_info":{"name":"python","version":"3.10.13","mimetype":"text/x-python","codemirror_mode":{"name":"ipython","version":3},"pygments_lexer":"ipython3","nbconvert_exporter":"python","file_extension":".py"},"kaggle":{"accelerator":"gpu","dataSources":[{"sourceId":19991,"databundleVersionId":1117522,"sourceType":"competition"}],"dockerImageVersionId":30716,"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":true}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import numpy as np # linear algebra\nimport pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)\nfrom PIL import Image, ImageDraw\nimport torch\nimport torchvision\nimport os\nfrom torch.utils.data import Dataset, DataLoader\nimport torchvision.transforms as transforms\nfrom tqdm import tqdm\nimport torch.nn.functional as F\nfrom sklearn.metrics import roc_auc_score, f1_score, balanced_accuracy_score\nfrom sklearn.metrics import confusion_matrix\n\n#for dirname, _, filenames in os.walk('/kaggle/input'):\n#    for filename in filenames:\n#        print(os.path.join(dirname, filename))\n\n# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using \"Save & Run All\" \n# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session","metadata":{"_uuid":"8f2839f25d086af736a60e9eeb907d3b93b6e0e5","_cell_guid":"b1076dfc-b9ad-4769-8c92-a6c4dae69d19","execution":{"iopub.status.busy":"2024-06-02T09:10:05.054803Z","iopub.execute_input":"2024-06-02T09:10:05.055360Z","iopub.status.idle":"2024-06-02T09:10:05.061588Z","shell.execute_reply.started":"2024-06-02T09:10:05.055331Z","shell.execute_reply":"2024-06-02T09:10:05.060597Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"\n\n# ---- STATICS ----\nbase_path = '../input/alaska2-image-steganalysis'\n\ndef read_images_path(dir_name, label):\n    '''series_name: 0001.jpg, 0002.jpg etc.\n    series_paths: is the complete path to a certain image.'''\n    \n    # Get name of the files\n    def add_prefix(string):\n        #print('aaaaaa', string)\n        return [base_path + '/' + dir_name + '/' + string, label]\n    #files = \n    name = list(map(add_prefix, os.listdir(base_path + '/' + dir_name)))\n    return name\n\n","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:05.063177Z","iopub.execute_input":"2024-06-02T09:10:05.063473Z","iopub.status.idle":"2024-06-02T09:10:05.074708Z","shell.execute_reply.started":"2024-06-02T09:10:05.063448Z","shell.execute_reply":"2024-06-02T09:10:05.073900Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"#os.listdir(base_path + '/' + 'Cover')","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:05.075583Z","iopub.execute_input":"2024-06-02T09:10:05.075820Z","iopub.status.idle":"2024-06-02T09:10:05.087754Z","shell.execute_reply.started":"2024-06-02T09:10:05.075800Z","shell.execute_reply":"2024-06-02T09:10:05.086916Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"sample_size = 7500\n\n# Read in the data\ncover_paths = read_images_path('Cover', 0)[:sample_size]\njmipod_paths = read_images_path('JMiPOD', 1)[:(sample_size//3)]\njuniward_paths = read_images_path('JUNIWARD', 1)[:(sample_size//3)]\nuerd_paths = read_images_path('UERD', 1)[:(sample_size//3)]\n#test_paths = read_images_path('Test')\n\n","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:05.089637Z","iopub.execute_input":"2024-06-02T09:10:05.089965Z","iopub.status.idle":"2024-06-02T09:10:16.773395Z","shell.execute_reply.started":"2024-06-02T09:10:05.089942Z","shell.execute_reply":"2024-06-02T09:10:16.772604Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"total = pd.DataFrame(data = cover_paths + jmipod_paths + juniward_paths + uerd_paths, columns = ['path', 'label'])","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.774516Z","iopub.execute_input":"2024-06-02T09:10:16.774796Z","iopub.status.idle":"2024-06-02T09:10:16.790239Z","shell.execute_reply.started":"2024-06-02T09:10:16.774772Z","shell.execute_reply":"2024-06-02T09:10:16.789293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def split_dataframe(df, proportion):\n    \"\"\"\n    Splits a DataFrame into two parts based on a given proportion.\n\n    :param df: DataFrame to be split\n    :param proportion: Proportion of the split (between 0 and 1)\n    :return: Two resulting DataFrames from the split\n    \"\"\"\n    # Shuffle the DataFrame rows to ensure random splitting\n    df = df.sample(frac=1).reset_index(drop=True)\n    \n    # Determine the size of the first DataFrame\n    split_size = int(len(df) * proportion)\n    \n    # Split the DataFrame into two\n    df1 = df.iloc[:split_size].reset_index(drop=True)\n    df2 = df.iloc[split_size:].reset_index(drop=True)\n    \n    return df1, df2\n\ntrain_df, val_df = split_dataframe(total, 0.8)","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.791241Z","iopub.execute_input":"2024-06-02T09:10:16.791540Z","iopub.status.idle":"2024-06-02T09:10:16.807412Z","shell.execute_reply.started":"2024-06-02T09:10:16.791516Z","shell.execute_reply":"2024-06-02T09:10:16.806525Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_df","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.810154Z","iopub.execute_input":"2024-06-02T09:10:16.810458Z","iopub.status.idle":"2024-06-02T09:10:16.830413Z","shell.execute_reply.started":"2024-06-02T09:10:16.810423Z","shell.execute_reply":"2024-06-02T09:10:16.829464Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"val_df","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.831653Z","iopub.execute_input":"2024-06-02T09:10:16.831996Z","iopub.status.idle":"2024-06-02T09:10:16.841543Z","shell.execute_reply.started":"2024-06-02T09:10:16.831969Z","shell.execute_reply":"2024-06-02T09:10:16.840608Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# ----- STATICS -----\nsample_size = 256\n","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.842690Z","iopub.execute_input":"2024-06-02T09:10:16.842991Z","iopub.status.idle":"2024-06-02T09:10:16.849977Z","shell.execute_reply.started":"2024-06-02T09:10:16.842967Z","shell.execute_reply":"2024-06-02T09:10:16.849061Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\nprint('Device available now:', device)","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.850842Z","iopub.execute_input":"2024-06-02T09:10:16.851160Z","iopub.status.idle":"2024-06-02T09:10:16.888436Z","shell.execute_reply.started":"2024-06-02T09:10:16.851137Z","shell.execute_reply":"2024-06-02T09:10:16.887596Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Carregar o modelo MobileNetV2 pré-treinado na ImageNet\nmodel = torchvision.models.efficientnet_v2_s(weights='DEFAULT')\nmodel.classifier[1] = torch.nn.Linear(model.classifier[1].in_features, 2)\n\nfor param in model.parameters():\n    param.requires_grad = False\n\n# Descongelar a última camada\nfor param in model.classifier[1].parameters():\n    param.requires_grad = True\n\n# Colocar o modelo em modo de avaliação\nmodel.to(device)\nmodel.eval()\n\n# Verificar se as camadas estão congeladas corretamente\n#for name, param in model.named_parameters():\n#    print(f'{name}: requires_grad={param.requires_grad}')\n","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:16.889581Z","iopub.execute_input":"2024-06-02T09:10:16.889833Z","iopub.status.idle":"2024-06-02T09:10:18.386913Z","shell.execute_reply.started":"2024-06-02T09:10:16.889812Z","shell.execute_reply":"2024-06-02T09:10:18.385810Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Transformações para pré-processar a imagem\nclass RGBToYCbCr:\n    def __call__(self, img):\n        return img.convert('YCbCr')\n\npreprocess = transforms.Compose([\n    RGBToYCbCr(),\n    transforms.Resize((384, 384)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),\n])\n\n# Função para carregar e pré-processar a imagem\ndef load_image(path):\n    img = Image.open(path)\n    img = img.convert(\"YCbCr\")\n    img = preprocess(img)\n    #img = img.unsqueeze(0)  # Adicionar dimensão batch\n    return img\n\n# URL de exemplo de uma imagem\nurl = '/kaggle/input/alaska2-image-steganalysis/Cover/00001.jpg'\nimg = load_image(url)\nimg","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.388190Z","iopub.execute_input":"2024-06-02T09:10:18.388526Z","iopub.status.idle":"2024-06-02T09:10:18.477990Z","shell.execute_reply.started":"2024-06-02T09:10:18.388500Z","shell.execute_reply":"2024-06-02T09:10:18.477051Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"class datareader(Dataset):\n    def __init__(self, dataframe, transform=None):\n        self.dataframe = dataframe\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.dataframe)\n\n    def __getitem__(self, idx):\n        if torch.is_tensor(idx):\n            idx = idx.tolist()\n        \n        path = self.dataframe['path'][idx]\n        image = Image.open(path).convert(\"RGB\")\n        label =  self.dataframe['label'][idx]\n        \n        samples = {'images': image,\n                  'labels': label}\n        if self.transform:\n            samples['images'] = self.transform(samples['images'])\n        \n        return samples","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.478945Z","iopub.execute_input":"2024-06-02T09:10:18.479189Z","iopub.status.idle":"2024-06-02T09:10:18.486243Z","shell.execute_reply.started":"2024-06-02T09:10:18.479168Z","shell.execute_reply":"2024-06-02T09:10:18.485293Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"BATCHSIZE = 256\nEPOCHS = 10\nLR = 1e-4\nWEIGHT_DECAY = 0\nWEIGHTS = torch.tensor([4, 1], dtype=torch.float32).to(device)","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.487310Z","iopub.execute_input":"2024-06-02T09:10:18.487567Z","iopub.status.idle":"2024-06-02T09:10:18.495685Z","shell.execute_reply.started":"2024-06-02T09:10:18.487538Z","shell.execute_reply":"2024-06-02T09:10:18.494767Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"optimizer = torch.optim.Adam(model.parameters(), lr=LR, weight_decay=WEIGHT_DECAY)","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.498893Z","iopub.execute_input":"2024-06-02T09:10:18.499185Z","iopub.status.idle":"2024-06-02T09:10:18.511667Z","shell.execute_reply.started":"2024-06-02T09:10:18.499162Z","shell.execute_reply":"2024-06-02T09:10:18.510900Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"train_dataset = datareader(train_df, transform=preprocess)\ntraining_dataloader = DataLoader(train_dataset, batch_size=BATCHSIZE, shuffle=True, num_workers=2, pin_memory=True)\n\nval_dataset = datareader(val_df, transform=preprocess)\nval_dataloader = DataLoader(val_dataset, batch_size=BATCHSIZE, shuffle=False, num_workers=2, pin_memory=True)\n","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.512824Z","iopub.execute_input":"2024-06-02T09:10:18.513577Z","iopub.status.idle":"2024-06-02T09:10:18.522027Z","shell.execute_reply.started":"2024-06-02T09:10:18.513545Z","shell.execute_reply":"2024-06-02T09:10:18.521250Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def calculate_metrics(model, dataloader, device='cpu'):\n    model.to(device)\n    model.eval()\n\n    all_labels = []\n    all_preds = []\n    all_probs = []\n\n    with torch.no_grad():\n        for data in dataloader:\n            inputs = data['images'].to(device)\n            labels = data['labels'].to(device)\n            #inputs, labels = inputs.to(device), labels.to(device)\n            outputs = model(inputs)\n            probs = F.softmax(outputs, dim=1)[:, 1]\n            preds = torch.argmax(outputs, dim=1)\n\n            all_labels.extend(labels.cpu().numpy())\n            all_preds.extend(preds.cpu().numpy())\n            all_probs.extend(probs.cpu().numpy())\n\n    all_labels = np.array(all_labels)\n    all_preds = np.array(all_preds)\n    all_probs = np.array(all_probs)\n\n    # AUC\n    auc = roc_auc_score(all_labels, all_probs)\n\n    # HTER (Half Total Error Rate)\n    tn, fp, fn, tp = confusion_matrix(all_labels, all_preds).ravel()\n    far = fp / (fp + tn)\n    frr = fn / (fn + tp)\n    hter = (far + frr) / 2\n\n    # F1-score\n    f1 = f1_score(all_labels, all_preds)\n\n    # Balanced Accuracy\n    balanced_acc = balanced_accuracy_score(all_labels, all_preds)\n\n    return {\n        'AUC': auc,\n        'HTER': hter,\n        'F1-score': f1,\n        'Balanced Accuracy': balanced_acc\n    }","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.523161Z","iopub.execute_input":"2024-06-02T09:10:18.523469Z","iopub.status.idle":"2024-06-02T09:10:18.533757Z","shell.execute_reply.started":"2024-06-02T09:10:18.523446Z","shell.execute_reply":"2024-06-02T09:10:18.533004Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"best_hter = float('inf')\nbest_model_wts = None\nfor epoch in range(EPOCHS):\n    model.train()\n    loss_list = []\n    correct_labels = []\n    predict = []\n    print('EPOCH: ', epoch+1)\n    for step, data in enumerate(tqdm(training_dataloader)):\n        optimizer.zero_grad()\n        images = data['images'].to(device)\n        label = data['labels'].to(device)\n        \n        logits = model(images)\n        cel = F.cross_entropy(logits, label, weight = WEIGHTS)\n        \n        loss = cel\n        loss = loss.cpu()\n\n        loss.backward()\n        optimizer.step()\n        \n        loss_list.append(loss.item())\n    loss_mean = np.mean(loss_list)\n    print('Loss: ', loss_mean)\n    print()\n    metrics = calculate_metrics(model, val_dataloader, device)\n    print(metrics)\n    val_hter = metrics['HTER']\n    if val_hter < best_hter:\n        best_hter = val_hter\n        best_model_wts = model.state_dict().copy()\n        torch.save(best_model_wts, 'best_model.pth')\n\nmodel.load_state_dict(best_model_wts)","metadata":{"execution":{"iopub.status.busy":"2024-06-02T09:10:18.534612Z","iopub.execute_input":"2024-06-02T09:10:18.534833Z"},"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"def generate_predictions(model, test_dataloader, device='cpu'):\n    model.to(device)\n    model.eval()\n\n    all_preds = []\n\n    with torch.no_grad():\n        for data in test_dataloader:\n            inputs = data['images'].to(device)\n            outputs = model(inputs)\n            preds = F.softmax(outputs, dim=1)[:, 1]\n            all_preds.extend(preds.cpu().numpy())\n\n    return all_preds\n","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"test_paths = read_images_path('Test', 0.7)\ntest_df = pd.DataFrame(data = test_paths, columns = ['path', 'label'])\n\ntest_dataset = datareader(test_df, transform=preprocess)\ntest_dataloader = DataLoader(test_dataset, batch_size=BATCHSIZE, shuffle=False, num_workers=2, pin_memory=True)","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"predictions = generate_predictions(model, test_dataloader, device='cuda')\n\n# Carregar o arquivo de exemplo de submissão do Kaggle\nsubmission = pd.read_csv('/kaggle/input/alaska2-image-steganalysis/sample_submission.csv')\nsubmission['Label'] = predictions\n\n# Salvar o arquivo de submissão\nsubmission.to_csv('submission.csv', index=False)\n\nprint('Submissão salva como submission.csv')","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"submission","metadata":{"trusted":true},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"","metadata":{},"execution_count":null,"outputs":[]}]}