<jupyter_start><jupyter_text>Download Data<jupyter_code>!gdown --id 1HLJlpPtgys73C3epBTgGRON3mSvsLHC1 --output hw4_data.zip
!unzip -q hw4_data.zip
!rm hw4_data.zip<jupyter_output>Downloading...
From: https://drive.google.com/uc?id=1HLJlpPtgys73C3epBTgGRON3mSvsLHC1
To: /content/hw4_data.zip
100% 1.13G/1.13G [00:09<00:00, 119MB/s]<jupyter_text>Import Packages<jupyter_code>!pip install byol-pytorch
import glob
import numpy as np
import os
import random
import torch
import torch.nn as nn
from byol_pytorch import BYOL
from PIL import Image
from torch.utils import data
from torch.utils.data import DataLoader
from torchvision.transforms import transforms
from torchvision import models
from tqdm.auto import tqdm<jupyter_output><empty_output><jupyter_text>Set Random Seed<jupyter_code>def fix_random_seeds(seed):
    random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.enabled = False<jupyter_output><empty_output><jupyter_text><jupyter_code>class Mini_Imagenet(data.Dataset):
    def __init__(self, paths, transforms):
        super().__init__()
        self.paths = paths
        self.transforms = transforms

    def __len__(self):
        return len(self.paths)
    
    def __getitem__(self, index):
        path = self.paths[index]
        img = Image.open(path).convert('RGB')
        return self.transforms(img)
        
def get_train_dataset(train_folder, image_size, batch_size, n_workers):
    train_transforms = transforms.Compose([
        transforms.Resize(image_size),
        transforms.ToTensor(),
    ])
    
    train_paths = glob.glob(os.path.join(train_folder, '*'))
    train_paths.sort()

    train_set = Mini_Imagenet(train_paths, train_transforms)
    train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=n_workers)
    return train_loader
def pretrain(device, resnet, learner, optim, train_loader, start_epoch, n_epochs):
    for epoch in range(start_epoch, n_epochs):
        train_losses = []
        for imgs in tqdm(train_loader):
        # for i, imgs in enumerate(train_loader):
            loss = learner(imgs)
            train_losses.append(loss.item())
            optim.zero_grad()
            loss.backward()
            optim.step()
            learner.update_moving_average()

        loss = sum(train_losses) / len(train_losses)
        with open('./record.txt', 'a') as f:
            f.write(f"[ Train | {epoch + 1:03d}/{n_epochs:03d} ] loss = {loss:.5f}")

        # save your improved network
        torch.save(resnet.state_dict(), './hw4_2.pt')
device = "cuda" if torch.cuda.is_available() else "cpu"
seed = 0
fix_random_seeds(seed)

batch_size = 32
n_workers = 0
n_epochs = 100
image_size = 128
resnet = models.resnet50(pretrained=False).to(device)

learner = BYOL(
    resnet,
    image_size = image_size,
    hidden_layer = 'avgpool'
).to(device)

optim = torch.optim.Adam(learner.parameters(), lr=3e-4)

load_learner = os.path.exists('./hw4_2.pt')
start_epoch = 0
if load_learner:
    with open('./record.txt', 'a') as f:
        f.write('Loading model...\n')
    ckpt = torch.load(f'./hw4_2.pt', map_location='cpu')
    start_epoch = ckpt['last_epoch'] + 1
    learner.load_state_dict(ckpt['learner'])
    optim.load_state_dict(ckpt['optim'])
else:
    with open('./record.txt', 'w') as f:
        f.write('')

train_folder = './hw4_data/mini/train'
train_loader = get_train_dataset(train_folder, image_size, batch_size, n_workers)
pretrain(device, resnet, learner, optim, train_loader, start_epoch, n_epochs)
class Office_Imagenet(data.Dataset):
    def __init__(self, fns, labels, transforms):
        super().__init__()
        self.fns = fns
        self.labels = labels
        self.transforms = transforms

    def __len__(self):
        return len(self.fns)
    
    def __getitem__(self, index):
        fn = self.fns[index]
        img = Image.open(fn).convert('RGB')
        return self.transforms(img), self.labels[index]
        
def get_train_dataset(folder, image_size, batch_size, n_workers):
    train_transforms = transforms.Compose([
        transforms.Resize((image_size, image_size)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
    
    train_path = os.path.join(folder, 'train')

    csv_path = os.path.join(folder, 'train.csv')
    labels = []
    label_num = -1
    fns = []
    label_num_pairs = []
    with open(csv_path, 'r') as f:
        for line in f.readlines()[1:]:
            _, fn, label = line[:-1].split(',')
            fns.append(os.path.join(train_path, fn))
            if label not in label_num_pairs:
                label_num += 1
                label_num_pairs.append(label)
            labels.append(label_num_pairs.index(label))
    # print(fns)
    # print(labels)
    # print(label_num_pairs)
    classes = len(label_num_pairs)

    train_set = Office_Imagenet(fns, labels, train_transforms)
    train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True, num_workers=n_workers)
    return train_loader, label_num_pairs

def get_val_dataset(folder, image_size, batch_size, n_workers, label_num_pairs):
    val_transforms = transforms.Compose([
        transforms.Resize((image_size, image_size)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
    
    val_path = os.path.join(folder, 'val')

    csv_path = os.path.join(folder, 'val.csv')
    
    fns = []
    labels = []
    with open(csv_path, 'r') as f:
        for line in f.readlines()[1:]:
            _, fn, label = line[:-1].split(',')
            fns.append(os.path.join(val_path, fn))
            labels.append(label_num_pairs.index(label))

    val_set = Office_Imagenet(fns, labels, val_transforms)
    val_loader = DataLoader(val_set, batch_size=batch_size, shuffle=False, num_workers=n_workers)
    return val_loader
class Classifier(nn.Module):
    def __init__(self, classes, train_backbone):
        super().__init__()

        self.resnet = models.resnet50(pretrained=False)
        # ckpt = torch.load(f'./hw4_2.pt', map_location='cpu')
        # self.resnet.load_state_dict(ckpt['resnet'])
        # ckpt = torch.load(f'./hw4_data/pretrain_model_SL.pt', map_location='cpu')
        # self.resnet.load_state_dict(ckpt)
        for params in self.resnet.parameters():
            params.requires_grad = train_backbone
        self.resnet.fc = nn.Linear(2048, classes)

    def forward(self, x):
        x = self.resnet(x)
        return x
def train(
    device,
    classifier,
    optim,
    train_loader,
    val_loader,
    start_epoch,
    n_epochs,
    ckpt_path,
    record_path
):
    
    loss_fn = nn.CrossEntropyLoss()

    for epoch in range(start_epoch, n_epochs):
        classifier.train()
        train_losses = []
        train_accs = []
        max_train_acc = 0
        for batch in tqdm(train_loader):
        # for i, batch in enumerate(train_loader):
            imgs, labels = batch
            imgs = imgs.to(device)
            labels = labels.to(device)

            logits = classifier(imgs)
            loss = loss_fn(logits, labels)
            train_losses.append(loss.item())

            optim.zero_grad()
            loss.backward()
            optim.step()

            acc = (logits.argmax(dim=-1) == labels.to(device)).float().mean()
            train_accs.append(acc)

        loss = sum(train_losses) / len(train_losses)
        acc = sum(train_accs) / len(train_accs)

        with open(record_path, 'a') as f:
            f.write(f"[ Train | {epoch + 1:03d}/{n_epochs:03d} ] loss = {loss:.5f}, acc = {acc:.5f}\n")
        
        if max_train_acc < acc:
            with open(record_path, 'a') as f:
                f.write('Saving model...\n')
            torch.save({
                'classifier': classifier.state_dict(),
                'last_epoch': epoch,
                'optim': optim.state_dict()
            }, ckpt_path)
            max_trian_acc = acc

        classifier.eval()
        val_losses = []
        val_accs = []
        with torch.no_grad():
            for batch in tqdm(val_loader):
            # for i, batch in enumerate(val_loader):
                imgs, labels = batch
                imgs = imgs.to(device)
                labels = labels.to(device)

                logits = classifier(imgs)
                loss = loss_fn(logits, labels)
                val_losses.append(loss.item())

                acc = (logits.argmax(dim=-1) == labels.to(device)).float().mean()
                val_accs.append(acc)

        loss = sum(val_losses) / len(val_losses)
        acc = sum(val_accs) / len(val_accs)

        with open(record_path, 'a') as f:
            f.write(f"[ Valid | {epoch + 1:03d}/{n_epochs:03d} ] loss = {loss:.5f}, acc = {acc:.5f}\n")
device = "cuda" if torch.cuda.is_available() else "cpu"
seed = 0
fix_random_seeds(seed)

batch_size = 32
n_workers = 0
n_epochs = 10
image_size = 128
classes = 65
ckpt_path = './hw4_2_train_C.pt'
record_path = './record.txt'

classifier = Classifier(classes, True).to(device)

optim = torch.optim.Adam(classifier.parameters(), lr=1e-3)

load_model = os.path.exists(ckpt_path)

start_epoch = 0
if load_model:
    with open(record_path, 'a') as f:
        f.write('Loading model...\n')

    ckpt = torch.load(ckpt_path, map_location='cpu')

    start_epoch = ckpt['last_epoch'] + 1
    classifier.load_state_dict(ckpt['classifier'])
    optim.load_state_dict(ckpt['optim'])
else:
    with open(record_path, 'w') as f:
        f.write('')

data_folder = './hw4_data/office'
train_loader, label_num_pairs = get_train_dataset(data_folder, image_size, batch_size, n_workers)
print(label_num_pairs)
with open('./label_pairs.txt', 'w') as f:
    for i in label_num_pairs:
        f.write(f'{i}\n')
input()
val_loader = get_val_dataset(data_folder, image_size, batch_size, n_workers, label_num_pairs)
train(
    device,
    classifier,
    optim,
    train_loader,
    val_loader,
    start_epoch,
    n_epochs,
    ckpt_path,
    record_path
)
with open('text.txt', 'w') as f:
    for label_num_pair in label_num_pairs:
        f.write(f'{label_num_pair}\n')<jupyter_output><empty_output><jupyter_text>Test<jupyter_code>import argparse
import csv
import glob
import numpy as np
import os
import random
import torch
import torch.nn as nn
from PIL import Image
from torch.utils import data
from torch.utils.data import DataLoader
from torchvision.transforms import transforms
from torchvision import models

def fix_random_seeds(seed):
    random.seed(seed)
    os.environ['PYTHONHASHSEED'] = str(seed)
    np.random.seed(seed)
    torch.manual_seed(seed)
    torch.cuda.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True
    torch.backends.cudnn.enabled = False

class Office_Imagenet(data.Dataset):
    def __init__(self, fns, labels, transforms):
        super().__init__()
        self.fns = fns
        self.labels = labels
        self.transforms = transforms

    def __len__(self):
        return len(self.fns)
    
    def __getitem__(self, index):
        fn = self.fns[index]
        img = Image.open(fn).convert('RGB')
        return self.transforms(img), self.labels[index]

def get_test_dataset(
    test_csv_path,
    test_img_repo,
    image_size,
    batch_size,
    n_workers,
    label_num_pairs
):
    test_transforms = transforms.Compose([
        transforms.Resize((image_size, image_size)),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
    ])
    
    fns = []
    labels = []
    with open(test_csv_path, 'r') as f:
        for line in f.readlines()[1:]:
            _, fn, label = line[:-1].split(',')
            fns.append(os.path.join(test_img_repo, fn))
            labels.append(label_num_pairs.index(label))

    test_set = Office_Imagenet(fns, labels, test_transforms)
    test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False, num_workers=n_workers)
    return fns, test_loader

class Classifier(nn.Module):
    def __init__(self, classes, train_backbone=True):
        super().__init__()

        self.resnet = models.resnet50(pretrained=False)
        self.resnet.fc = nn.Linear(2048, classes)

    def forward(self, x):
        x = self.resnet(x)
        return x

def test(
    device,
    classifier,
    test_loader,
    output_csv,
    label_pairs,
    fns
):
    ckpt = torch.load('./hw4_2.pt', map_location='cpu')
    classifier.load_state_dict(ckpt['classifier'])
    classifier.eval()
    preds = []
    
    with torch.no_grad():
        for batch in tqdm(test_loader):
        # for i, batch in enumerate(test_loader):
            imgs, _ = batch
            imgs = imgs.to(device)

            logits = classifier(imgs)
            preds.extend(logits.argmax(dim=-1))
    firstrow = [['id', 'filename', 'label']]
    rows = firstrow + [[i, fns[i].split('/')[-1], label_pairs[pred]] for i, pred in enumerate(preds)]
    with open(output_csv, 'w') as f:
        mywriter = csv.writer(f, delimiter=',')
        mywriter.writerows(rows)
    # print(preds)
    

# if __name__ == "__main__":
    
    # ap = argparse.ArgumentParser()
    # ap.add_argument('--test_csv_path', required=True)
    # ap.add_argument('--test_img_repo', required=True)
    # ap.add_argument('--output_csv', required=True)
    # args = ap.parse_args()
    test_csv_path = './hw4_data/office/val.csv'
    test_img_repo = './hw4_data/office/val'
    output_csv = './output.csv'

    device = "cuda" if torch.cuda.is_available() else "cpu"
    seed = 0
    fix_random_seeds(seed)

    batch_size = 32
    n_workers = 0
    n_epochs = 10
    image_size = 128
    classes = 65

    classifier = Classifier(classes, True).to(device)

    data_folder = './hw4_data/office'
    label_pairs = []
    with open('label_pairs.txt', 'r', newline='') as f:
        for line in f.readlines():
            label_pairs.append(line[:-1])

    fns, test_loader = get_test_dataset(
        test_csv_path,
        test_img_repo,
        image_size,
        batch_size,
        n_workers,
        label_num_pairs
    )
    test(
        device,
        classifier,
        test_loader,
        output_csv,
        label_pairs,
        fns
    )
label_pairs = []
with open('label_pairs.txt', 'r', newline='') as f:
    for line in f.readlines():
        label_pairs.append(line[:-1])
# print(len(label_pairs))
import csv
test_a = []
with open('./output.csv', 'r', newline='') as f:
    rows = csv.reader(f)
    for i, row in enumerate(rows):
        if i != 0:
            test_a.append(row[2])
# print(test_a)
# input()
test_b = []
with open('./hw4_data/office/val.csv', 'r', newline='') as f:
    rows = csv.reader(f)
    for i, row in enumerate(rows):
        if i != 0:
            test_b.append(row[2])

correct = 0
total = 0
for i in range(len(test_a)):
    total += 1
    if test_a[i] == test_b[i]:
        correct += 1
print(f'acc = {correct/total:.5f}')
!wget https://www.dropbox.com/s/1pbrd597o5haj8k/hw4_2_train_C.pt?dl=0 -O hw4_2.pt
!bash hw4_p2.sh './hw4_data/office/val.csv' './hw4_data/office/val' './output.csv'<jupyter_output>['Couch', 'Helmet', 'Refrigerator', 'Alarm_Clock', 'Bike', 'Bottle', 'Calculator', 'Chair', 'Mouse', 'Monitor', 'Table', 'Pen', 'Pencil', 'Flowers', 'Shelf', 'Laptop', 'Speaker', 'Sneakers', 'Printer', 'Calendar', 'Bed', 'Knives', 'Backpack', 'Paper_Clip', 'Candles', 'Soda', 'Clipboards', 'Fork', 'Exit_Sign', 'Lamp_Shade', 'Trash_Can', 'Computer', 'Scissors', 'Webcam', 'Sink', 'Postit_Notes', 'Glasses', 'File_Cabinet', 'Radio', 'Bucket', 'Drill', 'Desk_Lamp', 'Toys', 'Keyboard', 'Notebook', 'Ruler', 'ToothBrush', 'Mop', 'Flipflops', 'Oven', 'TV', 'Eraser', 'Telephone', 'Kettle', 'Curtains', 'Mug', 'Fan', 'Push_Pin', 'Batteries', 'Pan', 'Marker', 'Spoon', 'Screwdriver', 'Hammer', 'Folder']
['./hw4_data/office/val/Fork00005.jpg', './hw4_data/office/val/Fork00002.jpg', './hw4_data/office/val/Fork00032.jpg', './hw4_data/office/val/Radio00039.jpg', './hw4_data/office/val/Radio00020.jpg', './hw4_data/office/val/Radio00025.jpg', './hw4_data/office/val/Radio00005.jpg', './hw4_data/office/val/R[...]
{'fraction_non_alphanumeric': 0.13831662108781526, 'fraction_numerical': 0.017198419933151018, 'mean_word_length': 2.9293218720152816, 'pattern_counts': {'":': 1, '<': 21, '<?xml version=': 0, '>': 19, 'https://': 2, 'lorem ipsum': 0, 'www.': 1, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '573096', 'license': 'MIT', 'n_tokens_mistral': 6093, 'n_tokens_neox': 5855, 'n_words': 1099, 'path': 'HW4/hw4_2.ipynb', 'repo_name': 'YDBX/Deep-Learning-for-Computer-Vision', 'size': '16455'}