softmax 회귀(regression) 구현에 앞서 적절한 데이터셋이 필요하다. 시각적으로 돋보이게 만들기 위해서, 분류 문제중에서 선택해보자
가장 흔한 이미지 분류 데이터셋은 MNIST 손글씨 숫자 인식 데이터셋이 있다. 하지만 거의 모든 모델이 MNIST 데이터셋에 대해서 95% 이상의 정확도를 보여주기 위해서, 더 복잡한 데이터셋을 사용하겠다. 이 데이터셋은 Fashion-MNIST라고 한다.
소프트맥스 회귀란 3개 이상의 선택지 중에서 1개를 고르는 다중 클래스 분류 문제를 풀기위해 사용된다.
우선 필요한 패키지와 모듈을 import한다
!pip install d2l
!pip install mxnet==1.9.0
!pip install mxnet-mkl
import sys
sys.path.insert(0,'..')
%matplotlib inline
import d2l
from mxnet.gluon import data as gdata
import sys
import time
Gluon의 data 패키지를 이용해서 이 데이터셋을 다운로드한다. train 파라미터를 통해서 학습 데이터셋을 받을건지 테스트 데이터셋을 받을 것인지를 정할 수 있다. test dataset 또는 testing dataset은 모델의 성능을 평가할 때만 쓰이고, 학습에는 사용되지 않는 데이터다.
mnist_train = gdata.vision.FashionMNIST(train=True)
mnist_test = gdata.vision.FashionMNIST(train=False)
학습 데이터셋과 테스트 데이터셋은 각 카테코리별로 각각 6000개와 1000개의 이미지들로 구성되어있다. 카테고리수는 10개이고 학습데이터는 총 60,000개의 이미지들로 테스팅 셋은 10,000개 이미지들을 가지고 있다.
len(mnist_train), len(mnist_test)

-> []을 이용하면 각 샘플을 접근할 수 있다.
feature, label = mnist_train[0]
feature 변수는 변수의 높이와 넓이가 모두 28픽셀인 이미지 데이터를 가지고 있다. 각 픽셀은 8bit 부호없는 정수이고 0~255 사이의 값을 가진다. 이미지의 모양이 높이 h, 넓이는 w 픽셀인 경우 (h,w)로 표기하도록 하자
feature.shape, feature.dtype

-> 3차원 NDArray에 저장되고 마지막 차원은 채널의 개수를 의미한다. 데이터셋이 회색 이미지이기 때문에 채널의 수는 1이 된다
label, type(label), label.dtype

-> 각 이미지에 대한 레이블은 NumPy의 스칼라로 저장되어있고, 32bit 정수 형태이다
Fashion-MNIST에는 10개의 카테고리가 있다(티셔츠, 바지, 드레스, 코트 등등...). 숫자 형태의 레이블을 텍스트 레이블로 바꿔주는 함수를 정의하자
def get_fashion_mnist_labels(labels):
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal,' , 'shirt', 'sneaker', 'bag', 'ankle boot']
return [text_labels[int(i)] for i in labels]
이제 한 줄에 여러 이미지와 그 이미지의 레이블을 그리는 것을 정의하자
def show_fashion_mnist(images, labels):
d2l.use_svg_display() #SVG를 사용하여 이미지를 표시
_,figs = d2l.plt.subplots(1, len(images), figsize=(12, 12)) # len(images) 개의 서브플롯을 가로로 1행에 배치한다
for f, img, lbl in zip(figs, images, labels): #각 서브플롯, 이미지, 레이블에 대해 반복
f.imshow(img.reshape((28,28)).asnumpy()) #이미지를 28x28 형태로 재구성하여 서브플롯에 표시, MXNet NDArray를 NumPy 배열로 변환
f.set_title(lbl) #제목에 레이블 표시
f.axes.get_xaxis().set_visible(False) # x축 숨기기
f.axes.get_yaxis().set_visible(False) # y축 숨기기
이제 학습 데이터셋의 처음 9개의 샘플들에 대한 이미지와 텍스트 레이블을 살펴보자
x,y = mnist_train[0:9]
show_fashion_mnist(x, get_fashion_mnist_labels(y))

미니배치
- 인공지능이 학습을 할 때 거대한 양의 데이터를 한꺼번에 학습하지 않고 단위 별로 쪼개서 하는 것
이번에는 학습 데이터나 테스트 데이터를 읽는 코드를 직접 짜지 않고 DataLoad를 사용하자. dataload는 매번batch_size 개수의 샘플을 갖는 미니 배치를 읽는다
DataLoader의 특징은 데이터 읽기 속도를 빠르게 하기 위해서 멀티 프로세스들을 사용할 수 있다. 예를 들면! num_workers를 4로 설정하면 4개의 프로세스가 데이터를 읽도록 만들 수 있다.
ToTensor 클래스를 이용해서 이미지 데이터를 unit8에서 32bit 부동 소수점 숫자로 변환한다. 이후 모든 숫자를 255로 나눠서 모든 픽셀의 값이 0과 1 사이가 되오록 만든다. 이 클래스는 이미지 채널을 마지막에서 첫번째 차원으로 바꿔주는 기능이 있다 -> 합성곱 신경망(convolutional neural network)
#Fashion-MNIST 데이터셋을 로드하여 훈련 및 테스트 데이터로 나누고, 이를 배치 단위로 나누어 모델에 공급할 준비.
#배치 단위로 데이터를 공급하면 모델이 한 번에 여러 샘플을 처리할 수 있어 훈련 및 추론 속도가 빨라진다
#또한 데이터 변환 및 병렬 로딩을 통해 효율적인 데이터 처리가 가능
batch_size = 256
transformer = gdata.vision.transforms.ToTensor() # 이미지를 텐서(tensor)로 변환하는 객체. 이미지 데이터를 0과 1 사이의 값으로 정규화
if sys.platform.startswith('win'):
num_workers = 0 # window면 0
else:
num_workers = 4 # window가 아니면 4개의 워커 사용
train_iter = gdata.DataLoader(mnist_train.transform_first(transformer),
batch_size, shuffle=True, # 데이터를 섞어서 훈련의 무작위성을 증가시켜 모델의 일반화 성능을 높인다
num_workers=num_workers)
test_iter = gdata.DataLoader(mnist_test.transform_first(transformer),
batch_size, shuffle=False, # 데이터 섞지않고 일관성 유지
num_workers=num_workers)
-> transform_first 함수를 사용하면, ToTensor의 변환을 각 데이터 샘플의 첫번째 원소인 이미지에 적용할 수 있다.
학습 데이터를 읽는데 걸리는 시간을 측정해보자
start = time.time()
for x,y in train_iter:
continue
print('%.2f sec' % (time.time()-start))
