<jupyter_start><jupyter_text>Data preprocess<jupyter_code>training_prefix_path = './animal-10/train/'
testing_prefix_path = './animal-10/val/'

training_image_folder_list = glob.glob(training_prefix_path + '*')
testing_image_folder_list = glob.glob(testing_prefix_path + '*')
print(training_image_folder_list)
label_name_list = [_.split('/')[-1] for _ in training_image_folder_list]
print(label_name_list)
preprocess = transforms.Compose([
             transforms.Resize((256, 256)),
             transforms.ToTensor(), # transform to (0, 1)
             transforms.Normalize(mean = (0.5, 0.5, 0.5), std = (0.5, 0.5, 0.5)), # transform to (-1, 1)
             ])
# load training dataset
if not (os.path.isfile('./images_train_X.npy') and os.path.isfile('./images_train_y.npy')): 
    images = []
    labels = []
    label_count = 0

    for training_image_floder in training_image_folder_list:
        print('load images from: ', training_image_floder )
        imgs_path_list = glob.glob(training_image_floder + '/*')

        for idx, img_path in enumerate(imgs_path_list):
            img = preprocess(Image.open(img_path).convert('RGB'))
            img = img.numpy()

            images.append(img)

        labels.extend([label_count] * len(imgs_path_list))
        label_count += 1

    images = np.array(images)
    labels = np.array(labels)

    np.save('./images_train_X.npy', images)
    np.save('./images_train_y.npy', labels)
    print(images.shape, labels.shape)
else:
    images = np.load('./images_train_X.npy')
    labels = np.load('./images_train_y.npy')

    print(images.shape, labels.shape)
    
train_X = torch.from_numpy(images)
train_y = torch.from_numpy(labels)
if not (os.path.isfile('./images_test_X.npy') and os.path.isfile('./images_test_y.npy')): 
    images = []
    labels = []
    label_count = 0

    for testing_image_floder in testing_image_folder_list:
        print('load images from: ', testing_image_floder )
        imgs_path_list = glob.glob(testing_image_floder + '/*')

        for idx, img_path in enumerate(imgs_path_list):
            img = preprocess(Image.open(img_path).convert('RGB'))
            img = img.numpy()

            images.append(img)

        labels.extend([label_count] * len(imgs_path_list))
        label_count += 1

    images = np.array(images)
    labels = np.array(labels)

    np.save('./images_test_X.npy', images)
    np.save('./images_test_y.npy', labels)
    print(images.shape, labels.shape)
else:
    images = np.load('./images_test_X.npy')
    labels = np.load('./images_test_y.npy')

    print(images.shape, labels.shape)
    
test_X = torch.from_numpy(images)
test_y = torch.from_numpy(labels)
train_dataset = Data.TensorDataset(train_X, train_y)
test_dataset = Data.TensorDataset(test_X, test_y)
train_loader = Data.DataLoader(
    dataset = train_dataset,      # torch TensorDataset format
    batch_size = 128,      # mini batch size
    shuffle = True,               # 要不要打乱数据 (打乱比较好)
    num_workers=4,              # 多线程来读数据
)
test_loader = Data.DataLoader(
    dataset = test_dataset,      # torch TensorDataset format
    batch_size = 64,      # mini batch size
    shuffle = False,
    num_workers=4,              # 多线程来读数据
)<jupyter_output><empty_output><jupyter_text>ResNet<jupyter_code>class ResidualBlock(nn.Module):
    def __init__(self, in_channel, out_channel, stride=1, shortcut=None):
        super(ResidualBlock, self).__init__()
        self.left = nn.Sequential(
            nn.Conv2d(in_channel, out_channel, 3, stride, 1, bias=False), # bias=False是因為bias再BN中已經有了，如果stride=2則shape會變成一半
            nn.BatchNorm2d(out_channel),
            nn.ReLU(),
            nn.Conv2d(out_channel, out_channel, 3, 1, 1, bias=False), # shape前後仍然一漾
            nn.BatchNorm2d(out_channel),
        )
        
        self.right = shortcut #根據情況是否做出增維或是縮小shape
        
    def forward(self, x):
        out = self.left(x)
        residual = x if self.right is None else self.right(x)
        out = out + residual
        out = F.relu(out)
        return out
    
class ResNet(nn.Module):
    def __init__(self, num_classes=10):
        super(ResNet, self).__init__()
        
        self.pre_layer = nn.Sequential(
            nn.Conv2d(3, 64, 7, 2, 3, bias=False), #為了使shape變一半，stride必須是2，在固定kernel=7下由公式推得padding=3
            nn.BatchNorm2d(64),
            nn.ReLU(),
            nn.MaxPool2d(3, 2, 1) , #為了使shape變一半，stride必須是2，在固定kernel=3下由公式推得padding=1
        )
        
        self.layer1 = self._make_layer(64, 64, 3)
        self.layer2 = self._make_layer(64, 128, 4, stride=2) # 對照架構圖，第二段後每次都會將shape再度縮小一半
        self.layer3 = self._make_layer(128, 256, 6, stride=2)
        self.layer4 = self._make_layer(256, 512, 3, stride=2)
        
        self.fc = nn.Linear(512, num_classes)
        
    def _make_layer(self, in_channel, out_channel, block_num, stride=1):
        
        # shortcut的部份必須和該block最後一層維度相同，所以這裡做1d conv增加維度
        # 並且根據有沒有縮小shape(stride=2)做相同的動作
        shortcut = nn.Sequential(
            nn.Conv2d(in_channel, out_channel,  1, stride, bias=False),
            nn.BatchNorm2d(out_channel),
        )
        
        layers = []
        # 第一次的ResidualBlock可能會縮小shape(根據stride)，所以要獨立出來做
        layers.append(ResidualBlock(in_channel, out_channel, stride, shortcut)) 
        
        #注意這邊都是第二次以後的ResidualBlock，所以不會有維度或大小不同的問題，參數跟shortcut都不用做
        for i in range(1, block_num):
            layers.append(ResidualBlock(out_channel, out_channel))
            
        return nn.Sequential(*layers)
    
    def forward(self, x):
        # print('origin:', x.shape) # (batch, channel, w, h)
        
        x = self.pre_layer(x)
        # print('pre_layer:', x.shape) # (batch, channel, w, h) -> # (batch, 64, w/4, h/4)
        
        x = self.layer1(x)
        # print('layer1:', x.shape) # (batch, 64, w/4, h/4) -> (batch, 64, w/4, h/4)
        
        x = self.layer2(x)
        # print('layer2:', x.shape) # (batch, 64, w/4, h/4) -> (batch, 128, w/8, h/8)
        
        x = self.layer3(x)
        # print('layer3:', x.shape) # (batch, 128, w/8, h/8) -> (batch, 256, w/16, h/16)
        
        x = self.layer4(x)
        # print('layer4:', x.shape) # (batch, 256, w/16, h/16) -> (batch, 512, w/32, h/32)
        
        x = F.avg_pool2d(x, x.shape[3]) 
        # print('avg_pool:', x.shape) # (batch, 512, w/32, h/32) -> (batch, 512, 1, 1)
        
        x = x.view(x.size(0), -1) # (batch, 512, 1, 1) -> (batch, 512 * 1 * 1)
        # print('flatten:', x.shape)
        
        out = self.fc(x)
        return out
class CNN_1(nn.Module):
    def __init__(self):
        super(CNN_1, self).__init__()
        self.conv1 = nn.Sequential( # input shape:(1, 256, 256)
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=7, stride=1, padding=3),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2) # output shape: (32, 128, 128)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=32,  out_channels=64, kernel_size=7, stride=1, padding=3),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2) # output shape: (64, 64, 64)
        )
        self.out = nn.Linear(in_features=64 * 64 * 64, out_features=10)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # flatten
        x = x.view(x.size()[0], -1) # (batch size, 28*28)
        output = self.out(x)
        return output
class CNN_2(nn.Module):
    def __init__(self):
        super(CNN_2, self).__init__()
        self.conv1 = nn.Sequential( # input shape:(1, 256, 256)
            nn.Conv2d(in_channels=3, out_channels=32, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2) # output shape: (32, 128, 128)
        )
        self.conv2 = nn.Sequential(
            nn.Conv2d(in_channels=32, out_channels=64, kernel_size=3, stride=1, padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=2) # output shape: (64, 64, 64)
        )
        self.out = nn.Linear(in_features=64 * 64 * 64, out_features=10)
    def forward(self, x):
        x = self.conv1(x)
        x = self.conv2(x)
        # flatten
        x = x.view(x.size()[0], -1) # (batch size, 28*28)
        output = self.out(x)
        return output
class module():
    def __init__(self, net, train_loader, test_loader, EPOCH=20, LR=0.0001):
        self.net = net
        self.optimizer = torch.optim.Adam(net.parameters(), lr = LR)
        self.criterion = nn.CrossEntropyLoss()
        self.train_loader = train_loader
        self.test_loader = test_loader
        self.EPOCH_ = EPOCH
        self.LR_ = LR

        self.net = self.net.to(device)
        if device == 'cuda':
            self.net = torch.nn.DataParallel(self.net)
            torch.backends.cudnn.benchmark = True

    def start(self):

        history_loss = []
        history_train_acc = []
        history_test_acc = []
        for epoch in range(self.EPOCH_):
            print('Epoch:', epoch)
            train_loss, train_acc = self.train()
            test_loss, test_acc = self.test()

            history_loss.append(train_loss)
            history_train_acc.append(train_acc)
            history_test_acc.append(test_acc)
        return history_loss, history_train_acc, history_test_acc

    def train(self):
        self.net.train()
        train_loss = 0
        correct = 0
        total = 0
        for step, (batch_X, batch_y) in enumerate(self.train_loader):
            batch_X, batch_y = batch_X.to(device), batch_y.to(device)
            self.optimizer.zero_grad()
            outputs = self.net(batch_X)
            loss = self.criterion(outputs, batch_y)
            loss.backward()
            self.optimizer.step()

            train_loss += loss.item()
            _, predicted = outputs.max(1)
            total += batch_y.size(0)
            correct += predicted.eq(batch_y).sum().item()        

        print('【Training】Loss: %.3f | Acc: %.3f%% (%d/%d)' % ( train_loss, 100.*(correct/total), correct, total ))
        return train_loss, (correct/total)

    def test(self):
        self.net.eval()

        test_loss = 0
        correct = 0
        total = 0
        with torch.no_grad(): 
            for step, (batch_X, batch_y) in enumerate(self.test_loader):
                batch_X, batch_y = batch_X.to(device), batch_y.to(device)
                outputs = self.net(batch_X)
                loss = self.criterion(outputs, batch_y)

                test_loss += loss.item()
                _, predicted = outputs.max(1)
                total += batch_y.size(0)
                correct += predicted.eq(batch_y).sum().item()   

        print('【Testing】Loss: %.3f | Acc: %.3f%% (%d/%d)' % ( test_loss, 100.*(correct/total), correct, total ))
        return test_loss, (correct/total)<jupyter_output><empty_output><jupyter_text>CNN_1結果<jupyter_code>cnn1_module = module(CNN_1(), train_loader, test_loader)
history_loss, history_train_acc, history_test_acc = cnn1_module.start()
print('total number of parameters:', sum(p.numel() for p in cnn1_module.net.parameters()))
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(12, 4)
ax[0].set_title('Learning Cruve', color='r')
ax[0].set_xlabel('Number of Epochs')
ax[0].set_ylabel('Cross Entropy')
ax[0].plot(history_loss)

ax[1].set_title('Accuracy', color='r')
ax[1].set_xlabel('Number of Epochs')
ax[1].set_ylabel('Accuracy')
ax[1].plot(history_train_acc, label = 'train')
ax[1].plot(history_test_acc, label = 'test')
plt.legend(loc=1)<jupyter_output><empty_output><jupyter_text>CNN_2結果<jupyter_code>cnn2_module = module(CNN_2(), train_loader, test_loader)
history_loss, history_train_acc, history_test_acc = cnn2_module.start()
print('total number of parameters:', sum(p.numel() for p in cnn2_module.net.parameters()))
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(12, 4)
ax[0].set_title('Learning Cruve', color='r')
ax[0].set_xlabel('Number of Epochs')
ax[0].set_ylabel('Cross Entropy')
ax[0].plot(history_loss)

ax[1].set_title('Accuracy', color='r')
ax[1].set_xlabel('Number of Epochs')
ax[1].set_ylabel('Accuracy')
ax[1].plot(history_train_acc, label = 'train')
ax[1].plot(history_test_acc, label = 'test')
plt.legend(loc=1)<jupyter_output><empty_output><jupyter_text>Resnet結果<jupyter_code>resnet_module = module(ResNet(), train_loader, test_loader)
history_loss, history_train_acc, history_test_acc = resnet_module.start()
print('total number of parameters:', sum(p.numel() for p in resnet_module.net.parameters()))
fig, ax = plt.subplots(1, 2)
fig.set_size_inches(12, 4)
ax[0].set_title('Learning Cruve', color='r')
ax[0].set_xlabel('Number of Epochs')
ax[0].set_ylabel('Cross Entropy')
ax[0].plot(history_loss)

ax[1].set_title('Accuracy', color='r')
ax[1].set_xlabel('Number of Epochs')
ax[1].set_ylabel('Accuracy')
ax[1].plot(history_train_acc, label = 'train')
ax[1].plot(history_test_acc, label = 'test')
plt.legend(loc=1)
def plot_imgs():
    fig = plt.gcf()
    fig.set_size_inches((15,20))

    with torch.no_grad(): 
        for i in range(10):
            idx = i * 400 + 1
            temp = torch.from_numpy(np.expand_dims(test_X[idx], axis=0)).to(device)
            outputs = resnet_module.net(temp)
            _, predicted = outputs.max(1)

            ax = plt.subplot(5, 5, i+1)
            ax.imshow(np.transpose(test_X[idx].numpy(), (1, 2, 0)))
            title = 'label:' + label_name_list[test_y[idx]] + ', predict:' + label_name_list[predicted]
            if(test_y[idx].item() == predicted.item()):
                ax.set_title(title, fontsize=10)
            else:
                ax.set_title(title, fontsize=10, color='red')
plot_imgs()
print('%22s'%'Accuracy of classes')
print('--------------------------')
with torch.no_grad(): 
    for label_idx in range(10):
        temp_input = test_X[400*label_idx : 400*(label_idx+1)]
        temp_label = test_y[400*label_idx : 400*(label_idx+1)]
#         temp_input = temp_input.to(device)
#         temp_label = temp_label.to(device)
        outputs = resnet_module.net(temp_input)

        _, predicted = outputs.max(1)
        # print(predicted)
        correct = predicted.eq(temp_label.cuda()).sum().item()  
        print('%9s'%label_name_list[label_idx] + 
              ' : %.2f'% (correct/len(temp_label)) + '('+ str(correct) + '/'+ str(len(temp_label)) + ')')<jupyter_output>Accuracy of classes
--------------------------
   spider : 0.62(247/400)
 squirrel : 0.49(198/400)
      cat : 0.60(239/400)
      cow : 0.54(217/400)
    horse : 0.49(195/400)
    sheep : 0.76(304/400)
butterfly : 0.76(304/400)
  chicken : 0.78(310/400)
 elephant : 0.52(209/400)
      dog : 0.55(218/400)
{'fraction_non_alphanumeric': 0.14798880010926724, 'fraction_numerical': 0.036126476814860344, 'mean_word_length': 2.6427860696517413, 'pattern_counts': {'":': 0, '<': 20, '<?xml version=': 0, '>': 27, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '5', 'dir': 'jupyter-structured-clean-dedup', 'id': '437116', 'license': 'MIT', 'n_tokens_mistral': 5683, 'n_tokens_neox': 5370, 'n_words': 921, 'path': 'Assignment2/hw2_p1_0756708.ipynb', 'repo_name': 'john850512/Deep_Learning', 'size': '14643'}