t-SNE는 PCA 더불어 대중적(?)으로 사용되는 차원 축소 기법이다. 현업에서 사용되는 데이터는 수 ~ 수백 차원으로 이루어진 경우가 많은데, 이런 경우 데이터의 분포 확인이나 시각화 진행에 어려움이 있다. 이런 경우 보통 2~3차원으로 데이터를 축소하는데 이를 차원 축소라 말한다.
from sklearn.manifold import TSNE # sklearn 사용하면 easy !!
import numpy as np
from matplotlib import pyplot as plt
import torch
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
import torch.nn as nn
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])
testset = torchvision.datasets.CIFAR10(root='./data', train=False, download=True, transform=transform)
testloader = torch.utils.data.DataLoader(testset, batch_size=16)
class Identity(nn.Module):
def __init__(self):
super(Identity, self).__init__()
def forward(self, x):
return x
model = torchvision.models.resnet18(pretrained=False)
num_ftrs = model.fc.in_features # fc의 입력 노드 수를 산출한다. 512개
model.fc = nn.Linear(num_ftrs, 10) # fc를 nn.Linear(num_ftrs, 10)로 대체, CIFAR10,,
model = model.to(device)
# classifier 들어가기 직전에 값을 뽑아낼 것임
# (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
print(model)
# result
# (이전 생략) 마지막 부분 fully connected
(1): BasicBlock(
(conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
(fc): Linear(in_features=512, out_features=10, bias=True)
)
model.load_state_dict(torch.load('./models/cifar10_resnet18.pth'))
model.fc = Identity() # resnet18의 fc 부분을 위에서 만든 indentity class로 대체!
# result
(1): BasicBlock(
(conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(relu): ReLU(inplace=True)
(conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
(bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
)
(avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
(fc): Identity()
)
# fc: indentity로 바뀜!
actual = []
deep_features = []
model.eval() # resnet18
with torch.no_grad():
for data in testloader:
images, labels = data[0].to(device), data[1].to(device)
features = model(images) # 512 차원
deep_features += features.cpu().numpy().tolist()
actual += labels.cpu().numpy().tolist()
tsne = TSNE(n_components=2, random_state=0) # 사실 easy 함 sklearn 사용하니..
cluster = np.array(tsne.fit_transform(np.array(deep_features)))
actual = np.array(actual)
plt.figure(figsize=(10, 10))
cifar = ['plane', 'car', 'bird', 'cat', 'deer', 'dog', 'frog', 'horse', 'ship', 'truck']
for i, label in zip(range(10), cifar):
idx = np.where(actual == i)
plt.scatter(cluster[idx, 0], cluster[idx, 1], marker='.', label=label)
plt.legend()
plt.show()