{"metadata":{"kernelspec":{"display_name":"cse163","language":"python","name":"python3"},"language_info":{"codemirror_mode":{"name":"ipython","version":3},"file_extension":".py","mimetype":"text/x-python","name":"python","nbconvert_exporter":"python","pygments_lexer":"ipython3","version":"3.8.19"},"kaggle":{"accelerator":"none","dataSources":[{"sourceId":70905,"databundleVersionId":7746452,"sourceType":"competition"}],"isInternetEnabled":true,"language":"python","sourceType":"notebook","isGpuEnabled":false}},"nbformat_minor":4,"nbformat":4,"cells":[{"cell_type":"code","source":"import torch\nimport torch.nn as nn\nimport torch.optim as optim\nfrom torch.utils.data import Dataset, DataLoader, random_split\nfrom torchvision import transforms, models\nfrom PIL import Image\nimport pandas as pd","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Define the custom dataset\nnrow = 'all'\nclass AgeDataset(Dataset):\n    def __init__(self, csv_file, root_dir, transform=None):\n        self.data = pd.read_csv(csv_file)\n        # self.data = pd.read_csv(csv_file).iloc[1: 10001]\n        self.root_dir = root_dir\n        self.transform = transform\n\n    def __len__(self):\n        return len(self.data)\n\n    def __getitem__(self, idx):\n        img_name = self.data.iloc[idx, 1]\n        image = Image.open(self.root_dir + img_name).convert('RGB')\n        age = self.data.iloc[idx, 2]\n        if self.transform:\n            image = self.transform(image)\n        return image, age","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"model = models.resnet18()  # Assuming you're using ResNet-18 as an example\nmodel.fc = nn.Sequential(\n    nn.Linear(model.fc.in_features, 512),\n    nn.ReLU(),\n    nn.Dropout(0),\n    nn.Linear(512, 1)  # Predicting a single continuous value\n)\n\nmodel.load_state_dict(torch.load('loss-36.13 batch-16 lr-0.0001 nrow-first 5000 no_dropout.pth'))\n\n\n\n# Set device\ndevice = torch.device('cuda' if torch.cuda.is_available() else 'cpu')\n\n# Hyperparameters\nbatch_size = 32\nlearning_rate = 0.000001\nnum_epochs = 200\n\n# Loss function and optimizer\ncriterion = nn.MSELoss()\noptimizer = optim.Adam(model.parameters(), lr=learning_rate)\n# optimizer = optim.SGD(model.parameters(), lr=learning_rate, momentum=0.9)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load and preprocess the data （dont touch this cell）\ntransform = transforms.Compose([\n    transforms.Resize((512, 512)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\ndataset = AgeDataset(csv_file='train.csv', root_dir='', transform=transform)\n\n# Split the dataset into train and validation sets\ntrain_size = int(0.8 * len(dataset))\nval_size = len(dataset) - train_size\ntrain_dataset, val_dataset = random_split(dataset, [train_size, val_size])\n\ntrain_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)\nval_loader = DataLoader(val_dataset, batch_size=batch_size, shuffle=False)\n\n# Move the model to the device\nmodel = model.to(device)\n\n","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Training loop with early stopping\ntrain_losses = []\nval_losses = []\nbest_val_loss = float('inf')\npatience = 15\ncounter = 0\n\nfor epoch in range(num_epochs):\n    model.train()\n    train_loss = 0.0\n    for images, ages in train_loader:\n        images = images.to(device)\n        ages = ages.float().unsqueeze(1).to(device)\n\n        # Forward pass\n        outputs = model(images)\n        loss = criterion(outputs, ages)\n\n        # Backward pass and optimization\n        optimizer.zero_grad()\n        loss.backward()\n        optimizer.step()\n\n        train_loss += loss.item() * images.size(0)\n\n    train_loss /= len(train_dataset)\n    train_losses.append(train_loss)\n\n    # Validation\n    model.eval()\n    val_loss = 0.0\n    with torch.no_grad():\n        for images, ages in val_loader:\n            images = images.to(device)\n            ages = ages.float().unsqueeze(1).to(device)\n            outputs = model(images)\n            val_loss += criterion(outputs, ages).item() * images.size(0)\n\n    val_loss /= len(val_dataset)\n    val_losses.append(val_loss)\n\n    print(f\"Epoch [{epoch+1}/{num_epochs}], Train Loss: {train_loss:.4f}, Val Loss: {val_loss:.4f}\")\n\n    # Early stopping\n    if val_loss < 15:\n        break\n\n    # if val_loss < best_val_loss:\n    #     best_val_loss = val_loss\n    #     counter = 0\n    # else:\n    #     counter += 1\n    #     if counter >= patience:\n    #         print(f\"Early stopping at epoch {epoch+1}\")\n    #         break","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Create a DataFrame with train and validation losses\nloss_data = {'Epoch': list(range(1, len(train_losses)+1)),\n             'Train Loss': train_losses,\n             'Val Loss': val_losses}\nloss_df = pd.DataFrame(loss_data)\n\n# Save the DataFrame to a CSV file\nloss_df.to_csv('losses.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"label = 'no_dropout at epoch 97'\ntorch.save(model.state_dict(), f'loss-{round(val_loss, 2)} batch-{batch_size} lr-{learning_rate} nrow-{nrow} label-{label}.pth')","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"prediction_transform = transforms.Compose([\n    transforms.Resize((512, 512)),\n    transforms.ToTensor(),\n    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])\n])\n\ndef predict_age(model, image_path, device):\n    # Load and preprocess the input image\n    image = Image.open(image_path).convert('RGB')\n    image_tensor = prediction_transform(image).unsqueeze(0).to(device)\n\n    # Set the model to evaluation mode\n    model.eval()\n\n    # Disable gradient calculation for inference\n    with torch.no_grad():\n        outputs = model(image_tensor)\n        predicted_age = outputs.item()\n\n    return predicted_age","metadata":{},"execution_count":null,"outputs":[]},{"cell_type":"code","source":"# Load the best model\nbest_model_path = 'loss-22.39 batch-32 lr-1e-06 nrow-all label-no_dropout at epoch 26.pth'\nmodel.load_state_dict(torch.load(best_model_path))\n\ndf = pd.read_csv('test.csv')\ndf['age'] = df.apply(lambda row: predict_age(model, row['filename'], device), axis=1)\ndf = df[['id', 'age']]\n\ndf.to_csv('submission.csv', index=False)","metadata":{},"execution_count":null,"outputs":[]}]}