CNN Fashion-MNIST 테스트 (PyTorch)

Fashion-MNIST에 대한 설명은 아래 링크로 대신하겠습니다.

Fashion-MNIST is a dataset of Zalando‘s article images—consisting of a training set of 60,000 examples and a test set of 10,000 examples. Each example is a 28×28 grayscale image, associated with a label from 10 classes. We intend Fashion-MNIST to serve as a direct drop-in replacement for the original MNIST dataset for benchmarking machine learning algorithms. It shares the same image size and structure of training and testing splits.

본 예제 코드는 데이터셋을 학습해서 입력되는 이미지가 어떤 분류에 속하는지를 예측해보는 것입니다. Fashion-MNIST 데이터셋을 벡터 공간에 표시하면 위와 같은 이미지로 분류할 수 있습니다.

이제 학습을 위해 해당 데이터셋을 다운로드합니다.

# Define a transform to normalize the data
transform = transforms.Compose([transforms.ToTensor(),
                                transforms.Normalize((0.5,), (0.5,))])

# Download and load the training data
train_loader = torch.utils.data.DataLoader(datasets.FashionMNIST('../F_MNIST_data/', download=True, train=True, transform=transform), batch_size=128, shuffle=True)

# Download and load the test data
test_loader = torch.utils.data.DataLoader(datasets.FashionMNIST('../F_MNIST_data/', download=True, train=False, transform=transform), batch_size=128, shuffle=True)

다운로드한 데이터가 어떤 이미지가 있는지 살펴보기 위해서 랜덤하게 몇개의 샘플을 추출해서 표시해보겠습니다. 해당 이미지들은 10개 [‘t-shirt’, ‘trouser’, ‘pullover’, ‘press’, ‘coat’, ‘sandal’, ‘shirt’, ‘sneaker’, ‘bag’, ‘ankleboot’]로 분류할 수 있는 패션 아이템들입니다.

x_train, y_train = next(iter(train_loader))
x_valid, y_valid = next(iter(test_loader))

fig, ax = plt.subplots(5,5)
fig.set_size_inches((20,14))
for i in range(5):
    for j in range(5):
        idx = numpy.random.randint(128)
        ax[i][j].imshow(x_train[idx,0,:])
        ax[i][j].set_xlabel(label[y_train[idx].item()])
        ax[i][j].set_xticklabels([])
        ax[i][j].set_yticklabels([])

학습을 위한 모델을 선언합니다. 이전 MNIST 데이터셋을 테스트했을 때와 같은 모델을 재활용했습니다.

class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()
        
        self.convs = nn.Sequential(
            nn.Conv2d(1, 10, kernel_size=3), # input_channel, output_channel, kernel_size
            nn.ReLU(),
            nn.BatchNorm2d(10),
            nn.Conv2d(10, 20, kernel_size=3, stride=2),
            nn.ReLU(),
            nn.BatchNorm2d(20),
            nn.Conv2d(20, 40, kernel_size=3, stride=2)
        )
        
        self.layers = nn.Sequential(
            nn.Linear(40*5*5, 500),
            nn.Dropout(p=0.2),
            nn.ReLU(),
            nn.BatchNorm1d(500),
            nn.Linear(500,250),
            nn.Linear(250,100),
            nn.Dropout(p=0.2),
            nn.ReLU(),
            nn.BatchNorm1d(100),
            nn.Linear(100,50),
            nn.Linear(50, 10),
            nn.Softmax(dim=-1)
        )

    def forward(self, x):
        x = self.convs(x)
        x = x.view(-1, 40*5*5)
        return self.layers(x)
    
cnn = Net().to(DEVICE)

이전 MNIST 코드는 하나의 mini batch 데이터만 학습했다면 이번에는 전체 데이터를 대상으로 학습을 진행합니다. 많은 학습을 거친다면 모델의 정확도가 높아지겠지만 성능을 높이는 테스트가 아니기 때문에 최소한의 학습 epcohs만 수행합니다.

optimizer = optim.Adam(cnn.parameters())
criterion = nn.CrossEntropyLoss()

hist_loss = []
hist_accr = []

epochs = 30

for epoch in range(epochs):

    for idx, (data, label) in enumerate(train_loader):
        data, label = data.to(DEVICE), label.to(DEVICE)
        output = cnn(data)
        loss = criterion(output, label)
        
        predict = torch.argmax(output, dim=-1) == label
        accuracy = predict.float().mean().item()

        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        
        hist_loss.append(loss.item())
        hist_accr.append(accuracy)

        if idx % 100 == 0:
            print('Epoch {}, idx {}, Loss : {:.5f}, Accuracy : {:.5f}'.format(epoch, idx, loss.item(), accuracy))

학습이 완료되고 학습의 진행이 어떻게 되었는지 알기 위해서 사전에 정의한 hist_loss와 hist_accr을 사용해서 시각화 해보겠습니다.

fig, ax = plt.subplots(2,1)
fig.set_size_inches((12,8))

ax[0].set_title('Loss')
ax[0].plot(hist_loss, color='red')
ax[0].set_ylabel('Loss')
ax[1].set_title('Accuracy')
ax[1].plot(hist_accr, color='blue')
ax[1].set_ylabel('Accuracy')
ax[1].set_xlabel('Epochs')

학습이 완료된 후에 테스트 데이터를 사용해서 모델의 정확도를 확인해보았고 결과 값으로 Accuracy : 0.93750를 얻었습니다.

cnn.eval()

with torch.no_grad():
    for idx, (data, label) in enumerate(test_loader):
        data, label = data.to(DEVICE), label.to(DEVICE)
        output = cnn(data)
        loss = criterion(output, label)
    
        predict = torch.argmax(output, dim=-1) == label
        accuracy =  predict.float().mean().item()
    
        print('Accuracy : {:.5f}'.format(accuracy))

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 항목은 *(으)로 표시합니다