AI Fundamentals/BITAmin DL

[BITAmin DL] Session 2.1 - DL Basics 5 (Framework, ML vs DL, Terms, CEE, DNN, Activation & Loss Function, MNIST Fashion)

Jae. 2024. 2. 8. 16:10
728x90

 


1. Deep Learning Framework

 

 

 

Framework

 

 

'Framework'란 Frame(틀, 규칙)과 Work(일, 소프트웨어의 목적)의 합성어로, 일정한 틀과 뼈대를 가지고 무언가를 만드는 일을 의미

 

그렇기에 Deep Learning에서 사용하는 Framework는 

 

'딥러닝을 쓰고 싶은 사람들이 쉽게 사용할 수 있도록 다양한 기능을 구현한 작성 규칙이 있는 라이브러리' 를 의미

 

 

 

 

DL Framework 종류

 

  • theano 
  • Tensorflow
  • Keras
  • PyTorch

 

 

theano

 

  • 최초의 딥러닝 라이브러리
  • 파이썬 기반이며 CPU 및 GPU의 수치 계산에 매우 유용
  • 다만 확장성이 뛰어나지 않고 다중 GPU지원이 부족하다는 단점이 있음

 

 

Tensorflow

 

  • 인기있는 DL 라이브러리 중 하나이며, 구글에서 개발되었으며 2015년에 오픈소스로 공개됨
  • Python 기반이고 여러 CPU 및 GPU와 모든 플랫폼에서 사용 가능함
  • C++과 R과 같은 다른 언어도 지원
  • 다만 다른 Framework에 비해 속도가 느린편

 

 

Keras

 

  • 효율적인 신경망 구축을 위해 단순화된 인터페이스로 개발됨
  • Python 기반이며 배우기 쉽다는 장점이 있음
  • 문서화가 제대로 되어 있지 않고 이용자 수가 적은 단점이 존재

PyTorch

 

  • Lua 기반의 딥러닝 Framework로 GPU 처리를 위해 C/C++ 라이브러리와 CUDA를 사용
  • Python을 기반으로 한 PyTorch가 최근 큰 인기를 얻음
  • 심층 신경망과 강력한 GPU 가속을 가진 Tensor Computing이 포함된 Python 패키지 형태로 제공됨
  • 다만 TensorFlow보다는 디테일한 모델링이 불가능함
  • 현재는 가장 인기 있는 TensorFLow를 PyTorch가 빠른 속도로 따라잡고 있음

 

 


2. ML vs DL

 

 

 

 

AI (Artificial Intelligence)

  • 지능형 기계를 만드는 과학이나 공학의 분야 / 인간의 지능(지적능력, 사고방식) 을 인공적으로 컴퓨터 시스템을 통해 구현한 것

 

 

ML (Machine Learning)

  • 입력 데이터가 주어졌을 때 답을 유추해 줄 수 있는 최적의 함수를 기계가 찾는 것
  • 기존 데이터에 알고리즘을 사용해 모델을 만들어내고, 새로운 데이터에 해당 모델을 적용시켜 패턴을 학습하고 결과를 추론하는 기법
    • 데이터를 기반으로 통계적인 신뢰도를 강화
    • 예측 오류를 최소화하기 위해 다양한 수학적 기법을 사용
    • 데이터 내의 패턴을 스스로 인지하고 신뢰도있는 예측결과를 도출해 내는 함수를 찾는 것

 

 

 

  • 머신러닝 개요

 

 

DL (Deep Learning)

  • 머신러닝의 방법론 중 하나 (비선형 정보처리를 수행하는 계층을 여러 겹으로 쌓아서 학습모델을 구현하는 머신러닝의 한 분야)
  • 엄청나게 많은 데이터에서 중요한 패턴을 잘 찾아냄, 규칙도 잘 찾아내고, 의사결정을 잘하게 됨

 

 

 

ML vs DL

 

  • 특성 추출
  • 학습 과정

 

 

Feature Extraction (특성 추출)

 

  • ML과 DL의 차이 중 하나는 데이터에 접근하는 방식이 다름
  • Machine Learning은 주어진 데이터의 특성을 인간이 직접 추출함
  • Deep Learning은 컴퓨터가 데이터의 특징을 스스로 추출함
  • DL은 ML보다 더 많은 양의 데이터를 요구하기 때문에 훈련 시간이 일반적으로 더 길다

 

  • Feature Extraction: 데이터별로 어떤 특징을 가지고 있는지 찾아내고, 그것을 토대로 데이터를 벡터로 변환하는 과정

 

 

Learning Process (학습 과정)

 

  • Machine Learning은 학습 단계와 예측 단계로 나뉘어 학습 단계에서 만든 모델로 예측을 함
  • Deep Learning도 크게 다르지 않지만 특성 추출을 하는 과정이 없고 모델을 정의하는 부분이 있음

 

 

DL Process

 

  • 데이터 준비 = 데이터 전처리
  • 모델 정의
    • Neural Network를 형성
    • Performance와 Overfitting 사이의 trade-off에서 적절한 모델을 생성
  • Model Compile
    • Optimizer, Loss function, Activation Function을 선택
  • Model Training
    • 모델이 한 번에 처리해야 할 Data Sample의 개수 = Batch Size를 결정
    • 훈련의 횟수 = Epoch를 설정
  • Model Prediction
    • 실제로 예측을 진행

 

 

 

 


3. Deep Learning Terminology

 

 

 

 

 

 

Layer (층)

  • Input Layer: Input Features (Input Vector)등의 데이터를 받아들이는 층
  • Hidden Layer: 앞의 입력 노드들(Layer)로부터 Input을 받아 Linear Model(가중합)을 계산하고, 이 값을 Activation Function에 적용하여 Output Layer에 전달하는 층
  • Output Layer: Neural Network의 최종 결과값이 포함된 층

 

 

Weight

  • Node간의 연갈 강도
  • Weight가 클수록 대응되는 입력(x)의 영향도가 커짐

 

Bias

  • 가중합(Linear Combination)에 더해주는 상수
  • 하나의 Neuron에서 Activation Function을 거쳐 최종적으로 출력되는 값을 조절하는 역할
  • 민감도로, bias가 클수록 해당 Neuron은 쉽게 활성화됨

 

 

Function

  • Activation Function: Input 신호를 전달받아 이를 비선형 정보처리하여 출력해 주는 함수
  • Loss Function: Weight 학습을 위해 실제 값과 예측값(출력 함수의 결과)간의 오차를 측정하는 함수

 

 

Activation Function

 

 

  • Sigmoid Function
    • 하나의 뉴런 or 퍼셉트론이 입력 신호를 선형결합하여 만든 값에 hard threshold(Step Function)를 부드러운 형태의 곡선으로 근사
    • 실수 전체의 값을 (0,1) 사이의 실수 값으로 mapping
    • logistic regression의 경우 positive class에 대응하는 확률 값으로 해석

 

 

  • Gradient Vanishing Problem
    • $ 0 < \frac{\partial \sigma (x)}{\partial x} = (1-\sigma(x))\sigma(x) \leq \frac {1} {4}, 0<\sigma(x) <1 $, 즉 Gradient의 범위가 $(0, \frac {1} {4}]$ 이므로 Backpropagtion 할 때마다 Gradient값이 점차 작아지는 양상을 보임
    • multi-layer neural network에서 sigmoid function의 backpropgation을 수행할 때마다 gradient 값이 0에 수렴
    • 앞쪽의 layer의 parameter에 도달하는 gradient 값이 굉장히 작음: 앞쪽의 parameter들의 update가 거의 일어나지 않음

 

 

  • Hyperbolic Tangent Function
    • $tahh(x) = 2 \times sigmoid(2x) -1 =  \frac{e^{z} - e^{-z}}{e^{z} + e^{-z}}$
    • Sigmoid 함수를 x축으로 $\frac {1} {2}$배 압축 & y축으로 2배 확대 -> y축으로 -1만큼 평행이동
    • 치역의 범위가 (-1,1)으로 한정
    • Strength
      • Zero-centered (average = 0)
    • Weakness
      • gradient의 범위가 $0< \frac{\partial tanh(x)}{\partial x} = 1 - tanh(x)^{2} = (1+tanh(x))(1-tanh(x)) \leq 1$, $(0,1]$
      • backpropagation할 때마다 gradient vanishing 문제를 여전히 가지게 됨

 

 

 

 

  • ReLU Activation (Rectified Linear Unit)
    • $f(x) = max(0,x)$
    •  Strength
      • gradient vanishing 문제를 해결 (gradient 값이 계속 1)
      • 다른 활성함수에 비해 간단한 연산: computationally efficient
    •  Weakness
      • Not zero-centered output
      • 음수 범위에서는 gradient 값이 0: 이후의 gradient가 모두 0이 되는 문제

 

  • Leakly ReLU Activation (Rectified Linear Unit)
    • $f(x) = max(\alpha x, x)$, $\alpha$는 매우 작은 값
    • ReLU 함수를 사용시 음수 값을 입력받으면 항상 0을 출력해(뉴런이 죽음) 학습 능력이 감소하는 문제를 해결하기 위해 고안됨
    • 음수 부분의 기울기는 작은 값 사용 (음수 부분의 기울기는 학습하지 않기 위해서)

 

 

 

  • Softmax Activation
    • $ p_{j} = \frac {e^{z_{j}}} {\sum_{k=1}^{K} e^{z_{k}}}, j= 1, 2, ..., K$
    • Output Vector의 총합이 1이고, 각각 [0.1] 사이의 확률분포를 가지는 Activation Function
    • 지수함수 $e^{z_{j}}$를 사용하는 이유 
      • 미분가능하게 만들기 위해
      • 작은 값은 더 작게, 큰 값은 더 크게 scaling하기 위해

 

 

 

 

 

Loss Function

 

  • MSE (Mean Squared Error)
    • 회귀 문제에서 주로 사용

 

  • Cross - Entropy Error (CEE)
    • 분류 문제에서 정답 Label에 One-Hot Encoding을 했을 때만 사용
    • Sigmoid + MSE: 매끄럽지 않은 그래프가 출력되는 문제 발생
    • Softmax + CEE: 다중 분류 문제에서 주로 사용

 

 

 

DNN (Deep Neural Network)

  • Input Layer과 Output Layer 사이에 여러 Hidden Layer로 이루어진 ANN (Artificial Neural Network)
  • DNN을 기반으로 목적에 따라 CNN, RNN, RBM, DBN으로 분류됨
    • CNN: Convolutional Neural Network
    • RNN: Recurrent Neural Network
    • RBM: Restricted Boltzmann Machine
    • DBN: Deep Belief Network

 

 

 

CNN (Convolutional Neural Network)

 

  • 음성 인식이나 이미지, 영상 인식에서 주로 사용됨
  • 다차원 배열 처리에 특화되어 있으며, 다음의 계층으로 구성됨

 

 

  •  Input Layer
    • Input Image Data가 최초로 거치는 계층
    • Image는 Height, Width, Channel의 3차원 데이터 (Channel은 Image가 grayscale이면 1, Color면 3)

 

 

  • Convolutional Layer
    • Input Image Data에서 특성을 추출하는 역할
    • Image 전체를 Stride라는 간격에 따라 순차적으로 이동해 Kernel(Filter)로 이미지의 특성을 추출함
    • 이렇게 추출된 결과를 Feature Map 이라 한다
    • 외곽에 있는 정보들의 유실을 막기 위해 특정 값으로 채우는 Padding이 있음

 

 

  • Pooling Layer
    • Feature Map의 Dimension을 Down-Sampling하여 연산량을 감소시킴
    • 중요한 특성 벡터를 추출함
    • Max - Pooling: 대상 영역에서 Maximum 값을 추출
    • Average - Pooling: 대상 영역에서 Average 값을 반환

 

 

  • Fully Connected Layer
    • Image를 1-dimension vector로 펼친 후 다음의 층의 노드와 이전 층의 노드가 모두 연결되어 신호를 전달
    • 이미지를 분류, 설명하는 데 가장 적합하게 예측

 

 

  • Output Layer
    • Multi-Class Classification의 경우 softmax 함수를 사용

 

 

 

 


4. Cross - Entropy Loss

 

 

 

$Cross \: Entropy = -\sum_{i=1}^{n} y_{i}log \hat{y}_{i}$

 

 

 

  • CEE는 분포간의 차이에 집중함
  • 분류 문제에서 정답 Label에 One-Hot Encoding을 했을 때만 사용
  • ML/DL Model은 실제로 존재하는 어떤 분포를 잘 묘사해주는 확률 모델을 구하는 것과 같음
    • 정답 분포가 신경망으로 구성된 분포인가에 상관없이 신경망을 이용해서 해당 분포를 묘사할 수 있다고 생각함
    • 보편 근사 정리(Universal approximation Theorem): 하나의 Hidden Layer를 갖는 ANN은 임의의 연속인 다변수 함수를 원하는 정도의 정확도로 근사할 수 있음

 

 

 

Kullback - Lively Divergence (KLD)

 

 

$ D_{KL}(p\parallel q) = \sum_{x}^{}p(x)log\frac{p(x)}{q(x)} = E_{x\sim p}\left [ log \frac{p(x)}{q(x)} \right ]$

 

  • 모델로 만든 분포 q와 실제 분포 p 사이에서 분포간의 차이를 나타낼 때 사용
  • x가 실제 분포 P를 따른다: $x \sim p$

 

 

 

CE with Distribution (분포 p,q)

 

$ D_{KL}(p\parallel q) = \sum_{x}^{}p(x)log\frac{p(x)}{q(x)}$

 

$= \sum_{x}^{}p(x)logp(x) - \sum_{x}^{}p(x)logq(x) = -H(p) + CE(p,q) = CE(p,q)$

 

$\therefore D_{KL}(p\parallel q) = CE(p,q)$

 

  • 식 변형을 하면 KL Divergence는 p, q의 Cross - Entropy에서 p의 Entropy를 뺀 값
  • 그런데 Classification Problem의 경우 p는 실제 값(고정값 하나)를 갖기 때문에 p의 Entropy $H(p) = 0$가 됨 ($p(x) = 1$)
  • 따라서, Classfication Problem의 경우 $D_{KL}(p\parallel q) =CE(p,q)$

 

 

CE with Probability (확률 P)

 

$CE(X_{a}, Y_{a}) = -\sum_{c=1}^{C}P(X_{a}=c)logP(Y_{a}=c) $

 

$= -P(X_{a}=1)logP(Y_{a}=1) = -logP(Y_{a}=1)$

 

  • Cross - Entropy는 위와 같이 적을 수도 있다
  • Classification에서 One- Hot Encoding을 하므로 정답 Label만 1이다
  • 따라서 정답 Label이 1인 $P(X_{a}=1)=1$항만 남고, 나머지는 지워진다

 

 

 

Expectation of Random Variable g(X)

 

 

$E\left [ g(X) \right ] = \sum g(x)P_{X}(x)$

 

  • $\sum (변수 \times \: 확률)$
  • 변수는 합성 form 그대로
  • 확률은 Main(원본) 변수의 확률

 

 

Jensen Inequality

 

$f(E_{x\sim p}\left [ x \right ]) \leq E_{x \sim p}\left [ f(x) \right ]$

 

  • 볼록함수 f와 적절한 분포 p에 대해 위의 식이 성립한다
  • $f(x) = - log(x)$는 볼록함수이다

 

 

$CE(X_{a}, Y_{a}) = - \sum_{c=1}^{C} P(X_{a} = c)log P(Y_{a} = c) = \sum_{c=1}^{C} p(c) (-log q(c)) $

 

 

$= \sum_{c=1}^{C}p(c)f(q(c)) = E_{c \sim p}\left [ f(q(c)) \right ] \geq f(E_{c \sim p}\left [ q(c) \right ])$ (Jensen)

 

 

$= f(\sum_{c=1}^{C}p(c)q(c))$

 

 

$ f(\sum_{c=1}^{C}p(c)q(c)) = f(P(X_{a} =Y_{a}))$

 

  • 위의 식의 마지막 부분은 분포 p와 분포 q가 같은 값을 가질 때의 확률을 의미함
  • 즉, 우리가 예측한 Y와 실제 X가 같은 값(c)을 가질 확률이다
  • Two Independent Discrete Random Variable X, Y가 있고, 각각이 취할 수 있는 값이 1부터 n이라고 할 때, 두 Random Variable이 같을 확률은 다음과 같다: $P(X = Y) = \sum_{i=1}^{n} P(X = i) \cdot P(Y = i)$

 

 

$CE(X_{a}, Y_{a}) \geq f(P(X_{a} = Y_{a}))$

 

 

$CE(X_{a}, Y_{a}) \geq -log P(X_{a} = Y_{a})$

 

 

$- CE(X_{a}, Y_{a}) \leq log P(X_{a} = Y_{a})$

 

 

$ e^{-CE(X_{a}, Y_{a})} \leq P(X_{a} = Y_{a})$

 

 

  • 위에서부터 식 정리를 해보면 Two Random Variable이 같을 Probability의 Minimum을 Cross - Entropy로 구할 수 있음
  • 만약 Cross - Entropy Error = 0.5라면 $ \frac{1}{\sqrt{e}} \approx 0.6065 \leq P(X_{a} = Y_{a})$ 60%의 정답률을 보장할 수 있음
  • 추상적인 손실 함수인 Cross - Entropy를 넘어서 하한선을 제시하게 된 것이 Point라 할 수 있다

 

 


5. Regularization (Weight Decay) for Overfitting

 

 

 

 

 

 

 


6. DNN & Activation Function

 

 

DNN (Deep Neural Network)

 

  • Input Layer과 Output Layer 사이에 2개 이상의 Hidden Layer로 이루어진 Neural Network
  • Input Vector에 Weight를 곱하고 Bias를 더한 뒤 Activation Function을 거쳐 출력됨

 

 

 

Activation Function

 

  • 입력 신호의 총합을 출력 신호로 변환하는 함수 (= 뉴런을 활성화하는 함수)
  • 입력 신호의 총합이 활성화를 일으키는지를 정하는 역할을 한다
  • Input: Input Vector(Feature) & Weight(Model Parameter)의 선형결합
  • Hidden Layer과 Output Layer에 사용하는 Activation Function이 다르다

 

 

 

Hidden Layer Activation

 

  • 연산에 따라 Hidden Layer의 Activation Functio이 다름
  • MLP (Multi-Layer Perceptron): ReLU 계열
  • CNN (Convolutional Neural Network): ReLU 계열
  • RNN (Recurrent Neural Network): Sigmoid, Tanh

 

 

 

Output Layer Activation

 

  • Task에 따라 Output Layer의 Activation Function이 다름
  • Regression: 출력 노드 1개 + Linear Activation
  • Binary Classification: 출력 노드 1개 + Sigmoid
  • Multi-Class Classification: 출력 노드 Class 개수 + Softmax

 

 

Sigmoid

 

$Sigmoid(x) = \sigma (x) = \frac{1}{1 + exp(-x)}$

 

 

  • Shape
    • Input: 차원은 마음대로 (element-wise operation)
    • Output: 입력차원과 출력차원의 수가 같음

 

  • Parameters
    • x

 

 

import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import numpy as np

 

class DenseBlock(nn.Module):
    def __init__(self, in_dim, out_dim):
        super(DenseBlock, self).__init__()
        self.dense = nn.Linear(in_dim, out_dim)
        self.act = nn.Sigmoid() # activation Function
    
    def forward(self, x):
        out = self.act(self.dense(x))
        return out

 

sigmoid = DenseBlock(1, 1)
sigmoid.forward(torch.arange(5).float().unsqueeze(1))
tensor([[0.7101],
        [0.5348],
        [0.3504],
        [0.2021],
        [0.1062]], grad_fn=<SigmoidBackward0>)

 

 

Tanh

 

$tanh(x) = \frac{e^{x} - e^{-x}} {e^{x} + e^{-x}}$

 

 

 

  • Shape
    • Input: 차원은 마음대로 (element-wise operation)
    • Output: 입력차원과 출력차원의 수가 같음

 

  • Parameters
    • x

 

 

class DenseBlock2(nn.Module):
    def __init__(self, in_dim, out_dim):
        super(DenseBlock2, self).__init__()
        self.dense = nn.Linear(in_dim, out_dim)
        self.act = nn.Tanh() # activation Function
    def forward(self, x):
        out = self.act(self.dense(x))
        return out
tanh = DenseBlock2(1, 1)
tanh.forward(torch.arange(5).float().unsqueeze(1))

 

tensor([[0.7324],
        [0.9043],
        [0.9678],
        [0.9894],
        [0.9965]], grad_fn=<TanhBackward0>)

 

 

ReLU

 

$ReLU(x) = (x)^{+} = \max(0, x)$

 

 

 

  • Shape
    • Input: 차원은 마음대로 (element-wise operation)
    • Output: 입력차원과 출력차원의 수가 같음

 

  • Parameters
    • inplace: (default: False)
    • inplace=True로 설정할 경우, 입력을 따로 저장하지 않고 바로 Operation을 진행하기 때문에 메모리를 소량 절약가능
    • 대신 원본 입력이 destroy 되는 점을 주의해서 사용할 것

 

class DenseBlock3(nn.Module):
    def __init__(self, in_dim, out_dim):
        super(DenseBlock3, self).__init__()
        self.dense = nn.Linear(in_dim, out_dim)
        self.act = nn.ReLU()  # activation function

    def forward(self, x):
        out = self.act(self.dense(x))
        return out

 

 

relu = DenseBlock3(1, 1)
relu.forward(torch.arange(5).float().unsqueeze(1))
tensor([[0.0000],
        [0.0000],
        [0.0288],
        [0.1603],
        [0.2918]], grad_fn=<ReluBackward0>)

 

 

Leaky ReLU

 

$Leaky \: ReLU = \begin{cases}
x & \text{ if }\; x \geq 0 \\ negative \: slope \times x
 & \text{ if } \;  otherwise
\end{cases}$

 

 

  • Shape
    • Input: 차원은 마음대로 (element-wise operation)
    • Output: 입력차원과 출력차원의 수가 같음

 

  • Parameters
    • negative_slope: 음수 구간에 대하여 음의 기울기를 주는데 이때 기울기의 각도 (default: 1e-2)
    • inplace: (default=False)

 

 

class DenseBlock4(nn.Module):
    def __init__(self, in_dim, out_dim):
        super(DenseBlock4, self).__init__()
        self.dense = nn.Linear(in_dim, out_dim)
        self.act = nn.LeakyReLU()

    def forward(self, x):
        out = self.act(self.dense(x))
        return out

 

 

leakyrelu = DenseBlock4(1, 1)
relu.forward(torch.arange(5).float().unsqueeze(1))
tensor([[0.0000],
        [0.0000],
        [0.0288],
        [0.1603],
        [0.2918]], grad_fn=<ReluBackward0>)

 

 

 


7. Loss Function

 

 

Loss Function (손실 함수)

 

  • 실제값과 예측값 간의 차이(오차)를 비교하기 위한 함수
  • Loss Function을 통해 '오차(Loss)'를 구할 수 있고, 이 '오차'를 Optimizer를 통해 Backpropagation을 진행하면서 Model Parameter들(Weight, Bias)을 업데이트
  • 이 과정을 반복해서 '오차'를 최소화하는 Model Parameter를 찾는 것이 '학습'의 목표
  • MSE (Mean Squared Error): 회귀 문제에서 주로 사용
  • Cross - Entropy Loss (CEE): 분류 문제에서 정답 Label에 One-Hot Encoding을 했을 때만 사용

 

 

MSE (Mean Squared Error)

 

 

$MSE = \frac{1}{N} \sum_{i=1}^{N} (y_{i} - \hat{y}_{i})^{2}$

 

 

 

 

  • Shape
    • Input: 차원은 마음대로 (element-wise operation)
    • Output: 입력차원과 출력차원의 수가 같음

 

  • Parameters
    • reduction: 손실 값을 어떻게 줄일지를 지정하는 함수로, 기본값은 'mean'임

 

import torch.nn as nn
criterion = nn.MSELoss(reduction='mean')
loss = criterion(output, target)

 

 

CEE (Cross-Entropy Loss)

 

 

 

$CEE = - \sum_{i=1}^{n} t_{i} \times log_{e}(y_{i})$

 

 

 

  • Shape
    • Input: 차원은 마음대로 (element-wise operation)
    • Output: 입력차원과 출력차원의 수가 같음

 

  • Parameters
    • weight: Class별 가중치를 적용할 경우 사용하는 가중치 Tensor, 기본값은 'None'
    • ignore_index: 무시할 Class의 index, 기본값은 -100
    • reduction: 손실을 감소(reduce)할 방법을 지정
      • 'mean'(평균), 'sum'(합), 'None'(감소하지 않음) 중 하나를 선택
      • 기본값은 'mean'

 

import torch.nn as nn
criterion = nn.CrossEntropyLoss(weight=None, ignore_index=-100, reduction='mean')
loss = criterion(output, target)

 

 


7. MNIST Fashion - Code Implementation

 

  • 라이브러리 불러오기
import torch
import torch.nn as nn
import torch.optim as optim
import torch.nn.functional as F
from torchvision import transforms, datasets
from torch.utils.data import DataLoader

import matplotlib.pyplot as plt

 

  • M1 Mac에서 GPU 사용
device = torch.device("mps:0" if torch.backends.mps.is_available() else "cpu")
print(f"Using {device} device")
Using mps:0 device

 

print (f"PyTorch version:{torch.__version__}") # 1.12.1 이상
print(f"MPS 장치를 지원하도록 build 되었는지: {torch.backends.mps.is_built()}") # True 여야 합니다.
print(f"MPS 장치가 사용 가능한지: {torch.backends.mps.is_available()}") # True 여야 합니다.
!python -c 'import platform;print(platform.platform())'
PyTorch version:2.1.2
MPS 장치를 지원하도록 build 되었는지: True
MPS 장치가 사용 가능한지: True
macOS-14.2-arm64-arm-64bit

 

  • 데이터 불러오기
  • DataLoader 객체 생성
transform = transforms.Compose([transforms.ToTensor()])

trainset = datasets.FashionMNIST(
    root="mnist/data/", train=True, download=True, transform=transform
)

testset = datasets.FashionMNIST(
    root="mnist/data/", train=False, download=True, transform=transform
)
batch_size = 64

# Data Loading object define
train_loader = DataLoader(dataset=trainset, batch_size=batch_size)
test_loader = DataLoader(dataset=testset, batch_size=batch_size)

 

images, labels = next(iter(train_loader))
images.shape, labels.shape
(torch.Size([64, 1, 28, 28]), torch.Size([64]))

 

  • 불러온 데이터 확인
labels_map = {
    0: "T-shirt",
    1: "Trouser",
    2: "Pullover",
    3: "Dress",
    4: "Coat",
    5: "Sandal",
    6: "Shirt",
    7: "Sneaker",
    8: "Bag",
    9: "Ankle Boot",
}

figure = plt.figure(figsize=(12, 12))
cols, rows = 4, 4

for i in range(1, cols * rows + 1):
    image = images[i].squeeze()
    label_idx = labels[i].item()
    label = labels_map[label_idx]

    figure.add_subplot(rows, cols, i)
    plt.title(label)
    plt.axis("off")
    plt.imshow(image, cmap="gray")

plt.show()

 

  • DNN Model 정의
class DNN(nn.Module):
    def __init__(self):
        super(DNN, self).__init__()
        self.fc1 = nn.Linear(784, 256)
        self.fc2 = nn.Linear(256, 128)
        self.fc3 = nn.Linear(128, 10)
        
    def forward(self, x):
        # input data(image) = x
        # x.shape = torch.Size([64, 1, 28, 28])
        x = x.view(-1, 784)
        # x.shape = torch.Size([64, 784])
        x = F.relu(self.fc1(x))
        # x.shape = torch.Size([64, 1, 28, 28])
        x = F.relu(self.fc2(x))
        # x.shape = torch.Size([64, 1, 28, 28])
        x = self.fc3(x)
        # x.shape = torch.Size([64, 1, 28, 28])
        return x

 

  • Loss Function, Optimizer 정의
dnn = DNN()
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(dnn.parameters(), lr=0.01)
print(dnn)
DNN(
  (fc1): Linear(in_features=784, out_features=256, bias=True)
  (fc2): Linear(in_features=256, out_features=128, bias=True)
  (fc3): Linear(in_features=128, out_features=10, bias=True)
)

 

  • Model Training
for epoch in range(10):
    running_loss = 0.0

    for idx, (inputs, labels) in enumerate(train_loader, start=1):
        optimizer.zero_grad()

        outputs = dnn(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        running_loss += loss.item()

        if idx % 100 == 0:
            print(f"Epoch: {epoch+1}, Iter: {idx}, Loss: {running_loss / 2000}")
            running_loss = 0.0
Epoch: 1, Iter: 100, Loss: 0.11274098908901214
Epoch: 1, Iter: 200, Loss: 0.10534593224525451
Epoch: 1, Iter: 300, Loss: 0.0916677051782608
Epoch: 1, Iter: 400, Loss: 0.07444168597459794
Epoch: 1, Iter: 500, Loss: 0.06211770743131637
Epoch: 1, Iter: 600, Loss: 0.053908924639225
Epoch: 1, Iter: 700, Loss: 0.048291422337293624
Epoch: 1, Iter: 800, Loss: 0.04505948832631111
Epoch: 1, Iter: 900, Loss: 0.04227367272973061
Epoch: 2, Iter: 100, Loss: 0.03963514050841332
Epoch: 2, Iter: 200, Loss: 0.03892774763703346
Epoch: 2, Iter: 300, Loss: 0.0377043505012989
Epoch: 2, Iter: 400, Loss: 0.036420322865247726
Epoch: 2, Iter: 500, Loss: 0.03534371593594551
Epoch: 2, Iter: 600, Loss: 0.03452681921422482
Epoch: 2, Iter: 700, Loss: 0.03307179023325443
Epoch: 2, Iter: 800, Loss: 0.0329482177644968
Epoch: 2, Iter: 900, Loss: 0.03249312244355679
Epoch: 3, Iter: 100, Loss: 0.031308667823672295
Epoch: 3, Iter: 200, Loss: 0.031194300472736358
Epoch: 3, Iter: 300, Loss: 0.03099349170923233
Epoch: 3, Iter: 400, Loss: 0.03020917384326458
Epoch: 3, Iter: 500, Loss: 0.029420241340994836
Epoch: 3, Iter: 600, Loss: 0.029409253150224687
Epoch: 3, Iter: 700, Loss: 0.028218515291810034
Epoch: 3, Iter: 800, Loss: 0.028444199815392493
Epoch: 3, Iter: 900, Loss: 0.028653488397598268
Epoch: 4, Iter: 100, Loss: 0.02750851745903492
Epoch: 4, Iter: 200, Loss: 0.027589963987469674
Epoch: 4, Iter: 300, Loss: 0.02766475374996662
Epoch: 4, Iter: 400, Loss: 0.027145448565483093
Epoch: 4, Iter: 500, Loss: 0.026435795396566392
Epoch: 4, Iter: 600, Loss: 0.0267858769595623
Epoch: 4, Iter: 700, Loss: 0.025765796557068826
Epoch: 4, Iter: 800, Loss: 0.026108163818717004
Epoch: 4, Iter: 900, Loss: 0.02662244676053524
Epoch: 5, Iter: 100, Loss: 0.025493521004915237
Epoch: 5, Iter: 200, Loss: 0.025620816096663473
Epoch: 5, Iter: 300, Loss: 0.025844009295105934
Epoch: 5, Iter: 400, Loss: 0.025410002455115318
Epoch: 5, Iter: 500, Loss: 0.024744934543967246
Epoch: 5, Iter: 600, Loss: 0.025264536753296853
Epoch: 5, Iter: 700, Loss: 0.024344489380717278
Epoch: 5, Iter: 800, Loss: 0.024727902069687842
Epoch: 5, Iter: 900, Loss: 0.025351004973053932
Epoch: 6, Iter: 100, Loss: 0.02423600558936596
Epoch: 6, Iter: 200, Loss: 0.024362894237041473
Epoch: 6, Iter: 300, Loss: 0.02468249760568142
Epoch: 6, Iter: 400, Loss: 0.024239493906497954
Epoch: 6, Iter: 500, Loss: 0.02359827287495136
Epoch: 6, Iter: 600, Loss: 0.024212505787611006
Epoch: 6, Iter: 700, Loss: 0.023365655660629273
Epoch: 6, Iter: 800, Loss: 0.023749616876244543
Epoch: 6, Iter: 900, Loss: 0.024404321275651456
Epoch: 7, Iter: 100, Loss: 0.02330154873430729
Epoch: 7, Iter: 200, Loss: 0.023423816330730915
Epoch: 7, Iter: 300, Loss: 0.023817730844020845
Epoch: 7, Iter: 400, Loss: 0.023337094768881798
Epoch: 7, Iter: 500, Loss: 0.022725234165787696
Epoch: 7, Iter: 600, Loss: 0.023402464270591734
Epoch: 7, Iter: 700, Loss: 0.022606307789683342
Epoch: 7, Iter: 800, Loss: 0.022971770383417606
Epoch: 7, Iter: 900, Loss: 0.023632540181279183
Epoch: 8, Iter: 100, Loss: 0.022537152357399462
Epoch: 8, Iter: 200, Loss: 0.022644519045948983
Epoch: 8, Iter: 300, Loss: 0.023108271449804305
Epoch: 8, Iter: 400, Loss: 0.022592625133693218
Epoch: 8, Iter: 500, Loss: 0.02200370978564024
Epoch: 8, Iter: 600, Loss: 0.022730184391140936
Epoch: 8, Iter: 700, Loss: 0.02196316412091255
Epoch: 8, Iter: 800, Loss: 0.022315398395061494
Epoch: 8, Iter: 900, Loss: 0.022968250036239625
Epoch: 9, Iter: 100, Loss: 0.02190307091921568
Epoch: 9, Iter: 200, Loss: 0.02201009753346443
Epoch: 9, Iter: 300, Loss: 0.0225182880833745
Epoch: 9, Iter: 400, Loss: 0.02196325647085905
Epoch: 9, Iter: 500, Loss: 0.02140403341501951
Epoch: 9, Iter: 600, Loss: 0.022170505486428738
Epoch: 9, Iter: 700, Loss: 0.02142414051294327
Epoch: 9, Iter: 800, Loss: 0.02177253632247448
Epoch: 9, Iter: 900, Loss: 0.022394394293427468
Epoch: 10, Iter: 100, Loss: 0.021370605804026128
Epoch: 10, Iter: 200, Loss: 0.021461036421358586
Epoch: 10, Iter: 300, Loss: 0.021997104831039907
Epoch: 10, Iter: 400, Loss: 0.021426668494939804
Epoch: 10, Iter: 500, Loss: 0.020882543794810773
Epoch: 10, Iter: 600, Loss: 0.021686403773725032
Epoch: 10, Iter: 700, Loss: 0.020940099701285363
Epoch: 10, Iter: 800, Loss: 0.021298846505582333
Epoch: 10, Iter: 900, Loss: 0.021890796065330505

 

  • Accuracy Evaluation
correct = 0
total = 0

with torch.no_grad():
    for images, labels in test_loader:
        outputs = dnn(images)
        _, predicted = torch.max(outputs.data, 1)
        total += labels.size(0)
        correct += (predicted == labels).sum().item()

print(f"{(correct / total) * 100:.2f}%")
83.24%

 

 

 

728x90