算法与深度学习·

ML2023Spring-hw3 Bossline 0.95733

首发于 CSDN原文链接

d
notion image
查看GPU
# check GPU type. !nvidia-smi
导入需要的包
# Import necessary packages. import numpy as np import pandas as pd import torch import os import torch.nn as nn import torchvision.transforms as transforms from PIL import Image # "ConcatDataset" and "Subset" are possibly useful when doing semi-supervised learning. from torch.utils.data import ConcatDataset, DataLoader, Subset, Dataset from torchvision.datasets import DatasetFolder, VisionDataset # This is for the progress bar. from tqdm.auto import tqdm import random
设置种子
_exp_name = "sample" myseed = 6666 # set a random seed for reproducibility torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False np.random.seed(myseed) torch.manual_seed(myseed) if torch.cuda.is_available(): torch.cuda.manual_seed_all(myseed) print("Using GPU")
图像增强
# Normally, We don't need augmentations in testing and validation. # All we need here is to resize the PIL image and transform it into Tensor. test_tfm = transforms.Compose([ transforms.Resize((128, 128)), transforms.ToTensor(), ]) # However, it is also possible to use augmentation in the testing phase. # You may use train_tfm to produce a variety of images and then test using ensemble methods train_tfm = transforms.Compose([ # Resize the image into a fixed shape (height = width = 128) # transforms.Resize((128, 128)), # You may add some transforms here. transforms.RandomResizedCrop(224, scale=(0.9, 1)), # 随机裁剪到 224x224 transforms.RandomVerticalFlip(), # 随机垂直翻转 transforms.RandomHorizontalFlip(), # 随机水平翻转 transforms.RandomAffine(degrees=45, translate=(0.05, 0.05), shear=10), transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.2), # 颜色抖动 transforms.RandomGrayscale(p=0.1), # 以10%的概率将图像转换为灰度 transforms.ToTensor(), transforms.RandomErasing(scale=(0.02, 0.33)), transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225]), # 标准化 # ToTensor() should be the last one of the transforms. # transforms.ToTensor(), ])
初始化
数据集
class FoodDataset(Dataset): def __init__(self,path,tfm=test_tfm,files = None): super(FoodDataset).__init__() self.path = path self.files = sorted([os.path.join(path,x) for x in os.listdir(path) if x.endswith(".jpg")]) if files != None: self.files = files self.transform = tfm def __len__(self): return len(self.files) def __getitem__(self,idx): fname = self.files[idx] im = Image.open(fname) im = self.transform(im) try: label = int(fname.split("/")[-1].split("_")[0]) except: label = -1 # test has no label return im,label
分类
器
class Classifier(nn.Module): def __init__(self): super(Classifier, self).__init__() # torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding) # torch.nn.MaxPool2d(kernel_size, stride, padding) # input 維度 [3, 128, 128] self.cnn = nn.Sequential( nn.Conv2d(3, 64, 3, 1, 1), # [64, 128, 128] nn.BatchNorm2d(64), nn.ReLU(), nn.MaxPool2d(2, 2, 0), # [64, 64, 64] nn.Conv2d(64, 128, 3, 1, 1), # [128, 64, 64] nn.BatchNorm2d(128), nn.ReLU(), nn.MaxPool2d(2, 2, 0), # [128, 32, 32] nn.Conv2d(128, 256, 3, 1, 1), # [256, 32, 32] nn.BatchNorm2d(256), nn.ReLU(), nn.MaxPool2d(2, 2, 0), # [256, 16, 16] nn.Conv2d(256, 512, 3, 1, 1), # [512, 16, 16] nn.BatchNorm2d(512), nn.ReLU(), nn.MaxPool2d(2, 2, 0), # [512, 8, 8] nn.Conv2d(512, 512, 3, 1, 1), # [512, 8, 8] nn.BatchNorm2d(512), nn.ReLU(), nn.MaxPool2d(2, 2, 0), # [512, 4, 4] ) self.fc = nn.Sequential( nn.Linear(512*4*4, 1024), nn.ReLU(), nn.Linear(1024, 512), nn.ReLU(), nn.Linear(512, 11) ) def forward(self, x): out = self.cnn(x) out = out.view(out.size()[0], -1) return self.fc(out)
相关配置
# "cuda" only when GPUs are available. device = "cuda" if torch.cuda.is_available() else "cpu" # Initialize a model, and put it on the device specified. # model = Classifier().to(device) num_classes = 11 # model = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) # model.fc = nn.Linear(model.fc.in_features, num_classes) model = models.swin_t(weights=models.Swin_T_Weights.DEFAULT) model.head = nn.Linear(model.head.in_features, num_classes) model.to(device) _exp_name = "sample" # The number of batch size. batch_size = 64 # The number of training epochs. n_epochs = 8 # If no improvement in 'patience' epochs, early stop. patience = 5 # For the classification task, we use cross-entropy as the measurement of performance. criterion = nn.CrossEntropyLoss() # Initialize optimizer, you may fine-tune some hyperparameters such as learning rate on your own. optimizer = torch.optim.Adam(model.parameters(), lr=1e-4, weight_decay=1e-5) scheduler = MultiStepLR(optimizer, milestones=[int(n_epochs * 0.5), int(n_epochs * 0.8)], gamma=0.5)
DataLoader
# Construct train and valid datasets. # The argument "loader" tells how torchvision reads the data. train_set = FoodDataset("/kaggle/input/ml2023spring-hw3/train", tfm=train_tfm) train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=0, pin_memory=True) valid_set = FoodDataset("/kaggle/input/ml2023spring-hw3/valid", tfm=test_tfm) valid_loader = DataLoader(valid_set, batch_size=batch_size, shuffle=False, num_workers=0, pin_memory=True)
start train
# Initialize trackers, these are not parameters and should not be changed stale = 0 best_acc = 0 for epoch in range(n_epochs): # ---------- Training ---------- # Make sure the model is in train mode before training. model.train() # These are used to record information in training. train_loss = [] train_accs = [] for batch in tqdm(train_loader): # A batch consists of image data and corresponding labels. imgs, labels = batch #imgs = imgs.half() #print(imgs.shape,labels.shape) # Forward the data. (Make sure data and model are on the same device.) logits = model(imgs.to(device)) # Calculate the cross-entropy loss. # We don't need to apply softmax before computing cross-entropy as it is done automatically. loss = criterion(logits, labels.to(device)) # Gradients stored in the parameters in the previous step should be cleared out first. optimizer.zero_grad() # Compute the gradients for parameters. loss.backward() # Clip the gradient norms for stable training. grad_norm = nn.utils.clip_grad_norm_(model.parameters(), max_norm=10) # Update the parameters with computed gradients. optimizer.step() # Compute the accuracy for current batch. acc = (logits.argmax(dim=-1) == labels.to(device)).float().mean() # Record the loss and accuracy. train_loss.append(loss.item()) train_accs.append(acc) train_loss = sum(train_loss) / len(train_loss) train_acc = sum(train_accs) / len(train_accs) # Print the information. print(f"[ Train | {epoch + 1:03d}/{n_epochs:03d} ] loss = {train_loss:.5f}, acc = {train_acc:.5f}") current_lr = scheduler.get_last_lr()[0] scheduler.step() # ---------- Validation ---------- # Make sure the model is in eval mode so that some modules like dropout are disabled and work normally. model.eval() # These are used to record information in validation. valid_loss = [] valid_accs = [] # Iterate the validation set by batches. for batch in tqdm(valid_loader): # A batch consists of image data and corresponding labels. imgs, labels = batch #imgs = imgs.half() # We don't need gradient in validation. # Using torch.no_grad() accelerates the forward process. with torch.no_grad(): logits = model(imgs.to(device)) # We can still compute the loss (but not the gradient). loss = criterion(logits, labels.to(device)) # Compute the accuracy for current batch. acc = (logits.argmax(dim=-1) == labels.to(device)).float().mean() # Record the loss and accuracy. valid_loss.append(loss.item()) valid_accs.append(acc) #break # The average loss and accuracy for entire validation set is the average of the recorded values. valid_loss = sum(valid_loss) / len(valid_loss) valid_acc = sum(valid_accs) / len(valid_accs) # Print the information. print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f}") # update logs if valid_acc > best_acc: with open(f"./{_exp_name}_log.txt","a"): print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f} -> best") else: with open(f"./{_exp_name}_log.txt","a"): print(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {valid_loss:.5f}, acc = {valid_acc:.5f}") # save models if valid_acc > best_acc: print(f"Best model found at epoch {epoch}, saving model") torch.save(model.state_dict(), f"{_exp_name}_best.ckpt") # only save best to prevent output memory exceed error best_acc = valid_acc stale = 0 else: stale += 1 if stale > patience: print(f"No improvment {patience} consecutive epochs, early stopping") break
Test
# Construct test datasets. # The argument "loader" tells how torchvision reads the data. test_set = FoodDataset("/kaggle/input/ml2023spring-hw3/test", tfm=test_tfm) test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False, num_workers=0, pin_memory=True) # model_best = Classifier().to(device) # model_best = models.resnet18(weights=models.ResNet18_Weights.DEFAULT) # model_best.fc = nn.Linear(model.fc.in_features, num_classes) model_best = models.swin_t(weights=models.Swin_T_Weights.DEFAULT) model_best.head = nn.Linear(model.head.in_features, num_classes) model_best.to(device) model_best.load_state_dict(torch.load(f"{_exp_name}_best.ckpt")) model_best.eval() prediction = [] with torch.no_grad(): for data,_ in tqdm(test_loader): test_pred = model_best(data.to(device)) test_label = np.argmax(test_pred.cpu().data.numpy(), axis=1) prediction += test_label.squeeze().tolist()
提交文件
#create test csv df = pd.DataFrame() df["Id"] = [f"{i:>04}" for i in range(len(test_set))] df["Category"] = prediction df.to_csv("submission.csv", index = False)

评论加载中…