촉촉한초코칩
[혼공머신] Ch07 본문
https://colab.research.google.com/drive/1sfIIY16vBHCjrX5VPn4HrCZR5UYLzgpy#scrollTo=ALNT4WJfKtkt
Ch07. 딥러닝을 시작합니다.
패션 럭키백을 판매합니다!
- 딥러닝의 핵심 알고리즘인 인공 신경망을 배운다.
- 인공 신경망 라이브러리인 텐서플로와 케라스를 배운다.
- 인공 신경망 모델의 훈련을 돕는 도구를 익힌다.
07-1 인공 신경망
딥러닝과 인공 신경망 알고리즘을 이해하고 텐서플로를 사용해 간단한 인공 신경망 모델을 만든다.
목표 : 로지스틱 회귀 알고리즘의 정확도를 올려야 한다.
MNIST 데이터셋 : 머신러닝과 딥러닝 배울 때 많이 사용하는 데이터셋
→ Tensorflow를 사용하여 데이터를 불러와서 사용한다. (구글이 만든 딥러닝 라이브러리)
데이터 불러오기
#Tensorflow의 Keras 패키지를 import하고 패션 MNIST 데이터를 다운로드한다.
from tensorflow import keras
#keras.datasets.fasion_mnist 모듈 아래 load)data()는 훈련/테스트 데이터를 나누어 반환한다.
#데이터는 각각 입력과 타깃 쌍으로 구성되어 있다.
#데이터는 sample_data 폴더에 있다.
(train_input, train_target), (test_input,test_target) =\
keras.datasets.fashion_mnist.load_data()
데이터 확인하기
print(train_input.shape, train_target.shape)
#(60000, 28, 28) (60000,)
- 훈련 데이터는 60000개의 이미지로 이루어져 있다.
- 각 이미지 크기는 28 x 28이다.
- 타깃도 60000개의 원소가 있는 1차원 배열이다.
print(test_input.shape, test_target.shape)
#(10000,28,28) (10000,)
- 테스트 세트는 10000개의 이미지로 이루어져 있다.
import matplotlib.pyplot as plt
fig, axs = plt.subplots(1,10, figsize=(10,10))
for i in range(10):
axs[i].imshow(train_input[i], cmap='gray_r')
axs[i].axis('off')
plt.show()
샘플 타깃값 확인하기
#list를 사용하여 처음 10개의 샘플 타깃값을 리스트로 만든다.
print([train_target[i] for i in range(10)])
#[9, 0, 0, 3, 0, 2, 7, 2, 5, 5]
패션 MNIST 타깃은 0~9까지의 숫자 레이블로 구성된다.
마지막 2개의 샘플이 같은 레이블을 가지고 있는 것으로 보아, 2개의 샘플은 같은 종류로 유추해본다.
패션 MNIST에 포함된 10개 레이블의 의미는 다음과 같다.
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 |
티셔츠 | 바지 | 스웨터 | 드레스 | 코트 | 샌달 | 셔츠 | 스니커즈 | 가방 | 앵클 부츠 |
이 값을 출력값과 비교해보고, 넘파이 unique() 함수로 레이블 당 샘플 개수를 확인해본다.
import numpy as np
print(np.unique(train_target, return_counts=True))
#(array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], dtype=uint8), array([6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000, 6000]))
0~9까지 레이블마다 6000개의 샘플이 들어있는 것을 확인할 수 있다.
로지스틱 회귀로 패션 아이템 분류하기
1. 데이터 준비
샘플 개수가 60000개이기 때문에, 데이터를 한꺼번에 사용해서 모델을 훈련하는 것보다 샘플을 하나씩 꺼내서 모델을 훈련하는 방식이 더 효율적이다.
이때 효율적인 방법이 확률적 경사 하강법이다.
(4강에서 SGDClassifier 클래스의 loss 매개변수를 'log_loss'로 지정하여 로지스틱 손실 함수를 최소화하는 확률적 경사 하강법 모델을 만들었다.)
확률적 경사 하강법은 여러 특성 중 기울기가 가장 가파른 방향을 따라 이동한다. 만약 특성마다 값의 범위가 많이 다르면 올바르게 손실 함수의 경사를 내려올 수 없다.
패션 MNIST의 경우 각 픽셀은 0~255 사이의 정수값을 가진다. 이런 경우, 보통 255로 나누어 0~1 사이의 값으로 정규화한다.
reshape() 메서드를 사용하여 2차원 배열인 샘플을 1차원 배열로 만든다. (SGDClassifier는 2차원 입력을 다루지 못하기 때문)
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)
두번째 매개변수를 28*28로, 이미지 크기에 맞게 지정하면 첫번째 차원(샘플 개수)은 변하지 않고 원본 데이터의 두번째, 세번째 차원이 1차원으로 합쳐진다.
print(train_scaled.shape)
2. 성능 확인
샘플이 준비되었으므로 SGDClassifier 클래스와 cross_validate 함수를 사용해 데이터에서 교차 검증으로 성능을 확인해본다.
from sklearn.model_selection import cross_validate
from sklearn.linear_model import SGDClassifier
sc = SGDClassifier(loss='log_loss', max_iter=5, random_state=42)
#반복횟수를 5로 지정했지만, 늘려도 성능이 크게 향상되지는 않는다.
scores = cross_validate(sc, train_scaled, train_target, n_jobs=-1)
print(np.mean(scores['test_score']))
#0.8194166666666666
3. 성능 높이기
로지스틱 회귀 공식 :
패션 MNIST 데이터에 맞게 변형한 공식 (티셔츠) :
가중치를 더하고 마지막에 절편 b를 더한다.
패션 MNIST 데이터에 맞게 변형한 공식 (바지) :
SGDClassifier 모델은 패션 MNIST 데이터의 클래스를 구분할 수 있도록 10개의 방정식에 대한 모델 파라미터(가중치와 절편)를 찾는다.
모든 클래스에 대한 선형 방정식을 모두 계산한다음, 소프트맥스 함수를 통과하여 각 클래스에 대한 확률을 얻는다.
인공 신경망
인공 신경망 : 기존의 머신러닝 알고리즘이 잘 해결하지 못했던 문제에서 높은 성능을 발휘하는 새로운 종류의 머신러닝 알고리즘
딥러닝 라이브러리가 다른 머신러닝 라이브러리와 다른 점 중 하나는 그래픽 처리 장치인 GPU를 사용하여 인공 신경망을 훈련한다는 것이다. (GPU는 벡터와 행렬 연산에 최적화되어 있기 때문에 곱셈, 덧셈이 많이 수행되는 인공 신경망에 큰 도움이 된다.)
가장 기본적인 인공 신경망 : 확률적 경사 하강법을 사용하는 로지스틱 회귀
- 출력층 (Output layer) : 신경망의 최종 값을 만듦
- 뉴런 (Neuron, 유닛) : z 값 계산하는 단위
- 입력층 (Input layer) : 픽셀값 자체이며 특별한 계산을 수행하지 않는다.
인공 신경망 모델을 만드는 최신 라이브러리들은 SGDClassifier에는 없는 기능(Tensorflow)을 제공한다. 이 기능을 활용하여 성능을 올린다.
Tensorflow
- 구글이 공개한 딥러닝 라이브러리
- 텐서플로우에는 저수준 API와 고수준 API가 있다.
- Keras는 고수준 API.
- Keras는 직접 GPU 연산을 수행하지 않고, GPU 연산을 수행하는 다른 라이브러리를 백엔드로 사용한다. (ex. 텐서플로우)
import tensorflow as tf
from tensorflow import keras
인공 신경망으로 모델 만들기
1. 로지스틱 회귀에서는 교차 검증을 사용하여 모델을 평가했지만, 인공 신경망에서는 교차 검증 대신 검증 세트를 별도로 덜어내어 사용한다.
from sklearn.model_selection import train_test_split
train_scaled, val_scaled, trian_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)
#훈련 세트와 검증 세트 크기
print(train_scaled.shape, train_target.shape)
#(48000, 784) (60000,)
print(val_scaled.shape, val_target.shape)
#(12000, 784) (12000,) -> 60000개 중에서 12000개가 검증 세트로 분리되었다.
2. 케라스의 Dense 클래스를 사용해 밀집층을 만든다.
- Dense() : 신경망에서 가장 기본 층인 밀집층을 만드는 클래스
- 뉴런의 개수를 정한다.
- activation : 활성화 함수 지정 → sigmoid, softmax
- Sequential 클래스에 맨 처음 추가되는 층에는 input_shape 매개변수로 입력의 크기를 지정해야 한다.
- Sequential : 케라스에서 신경망 모델을 만드는 클래스
- 해당 클래스의 객체를 생성할 때 신경망 모델에 추가할 층을 지정할 수 있다.
- 추가할 층이 1개 이상일 경우 파이썬 리스트로 전달한다.
밀집층 (Dense layer) : 784개의 픽셀과 10의 뉴런이 연결된 선 (가장 간단한 인공 신경망 층으로, 뉴런들이 모두 연결되어 있기 때문에 완전 연결 층이라고도 부른다.)
#뉴런 개수, 뉴런의 출력에 적용할 함수, 입력 크기
dense = keras.layers.Dense(10, activation='softmax', input_shape=(784,)))
3. 밀집층을 가진 신경망 모델을 만든다.
model = keras.Sequential(dense)
인공 신경망으로 패션 아이템 분류하기
케라스 모델을 훈련하기 전 손실 함수의 종류를 지정해야 한다.
- 이진 분류 : loss = 'binary_crossentropy'
- 다중 분류 : loss = 'catorical_crossentropy'
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
이중분류
다중분류 (MNIST 데이터셋에 적용)
각 클래스에 대한 확률이 출력되기 때문에 타깃에 해당하는 확률만 남겨 놓기 위해 나머지 확률에는 0을 곱한다.
그리고 출력층의 활성화 값의 배열과 곱한다. (두 배열의 동일한 위치의 원소끼리 곱해지도록 함)
이때 해당 위치의 뉴런 활성화 출력 a의 값을 가능한 1에 가깝게 만들어야 한다. 그러려면 해당 위치의 배열 값만 1로 남기고 나머지는 0으로 타깃값을 준비하면 된다. → 샘플을 정확하게 분류하기 위해 신경망 출력을 가능한 높이는 것 :
타깃값을 해당 클래스만 1이고 나머지는 모두 0인 배열로 만드는 것을 원-핫 인코딩이라고 부른다.
print(train_target[:10]) #[9 0 0 3 0 2 7 2 5 5]
텐서플로에서는 정수로 된 타깃값을 원-핫 인코딩으로 바꾸지 않고 그냥 사용할 수 있다.
- sparse_categorical_crossentropy : 정수로된 타깃값을 사용해 크로스 엔트로피 손실을 계산하는 것
- 티갓값을 원-핫 인코딩으로 준비했다면 compile() 메서드에 손실 함수를 loss='categorical_crossentropy'로 지정한다.
- compile() 메서드 매개변수
- metrics : 모델이 훈련할 때 기본적으로 에포크마다 손실 값을 출력해준다.
- fit() 메서드
- 두 매개변수에 입력(train_scaled)과 타깃(train_target)을 지정한다.
- 반복할 에포크 횟수를 매개변수로 지정한다.
model.fit(train_scaled, train_target, epochs=5)
- evaluate() 메서드 : 모델 성능 확인
model.evaluate(val_scaled, val_target)
인공 신경망 모델로 성능 향상
- 흑백 이미지로 저장된 패션 아이템 데이터셋인 패션 MNIST 데이터셋을 사용했다.
- 먼저 로지스틱 손실 함수를 사용한 SGDClassifier 모델을 만들어 교차 검증 점수 확인
- 케라스를 사용해 간단한 인공 신경망 모델을 만들어 패션 아이템 분류 (경사 하강법을 사용한 로지스틱 회귀 모델과 거의 비슷하다.)
- 인공 신경망에서 손실 함수를 어떻게 계산하는지, 원-핫인코딩에 대해 배웠다.
전체 코드 : https://colab.research.google.com/github/rickiepark/hg-mldl/blob/master/7-1.ipynb
07-2 심층 신경망
인공 신경망에 층을 여러 개 추가하여 패션 MNIST 데이터셋을 분류하면서 케라스로 심층 신경망을 만든다.
2개의 층
- 패션 MNIST를 불러온다.
- 이미지 픽셀값을 0~255 범위에서 0~1 사이로 변환하고, 28*28 크기의 2차원 배열을 784 크기의 1차원 배열로 펼친다.
- train_test_split() 함수로 훈련/검증 세트로 나눈다.
from tensorflow import keras
from sklearn.model_selection import train_test_split
(train_input, train_target), (test_input, test_target) =\ keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)
위 인공 신경망 모델에 층을 2개 추가한다. → 입력층, 출력층 사이에 밀집층 추가
- 은닉층 (Hidden layer) : 입력층과 출력층 사이에 있는 모든 층
- 은닉층의 활성화 함수 : 신경망 층의 선형 방정식의 계산 값에 적용하는 함수
- 이진 분류 : sigmoid
- 다중 분류 : softmax
* 분류 문제는 클래스에 대한 확률을 출력하기 위해 활성화 함수를 사용한다.
회귀, 출력은 임의의 어떤 숫자이므로 활성화 함수를 적용할 필요가 없다.
* 은닉층에 활성화 함수를 적용하는 이유
은닉층에 비선형적 계산을 해서 수행 역할을 주기 위함
- 시그모이드 활성화 함수 : 은닉층과 소프트맥스 함수를 사용한 출력층을 케라스의 Dense 클래스로 만든다.
dense1 = keras.layes.Dense(100, activation='sigmoid', input_shape=(784,))
dense2 = keras.layers.Dense(10, activation='softmax')
- dense1 : 은닉층, 100개의 뉴런을 가진 밀집층, 활성화 함수 sigmoid 지정, 입력 크기를 784로 지정
- dense2 : 출력층, 10개의 클래스를 분류하므로 뉴런 개수를 10개로 두고, 활성화 함수 softmax 지정
* 은닉층의뉴런 개수는 출력층의 뉴런 개수보다 많아야 한다.
ex) 10개의 확류을 예측해야 하는데 이전 은닉층의 뉴런이 10개보다 적으면 정보가 부족하기 때문
심층 신경망 만들기 (Sequential)
dense1과 dense2 객체를 Sequential 클래스에 추가해 심층 신경망을 만든다.
이때 여러 개의 층을 추가하려면 dense1과 dense2를 리스트로 만들어서 전달해야 한다.
* 출력층을 가장 마지막에 두어야 한다. (은닉층 → 출력층)
model = keras.Sequential([dense1, dense2])
model.summary()
출력 결과
#모델 명
#모델에 있는 층 순서대로 나열 (은닉층~출력층)
#[Layer이름] [출력 크기] [파라미터 개수]
#총 모델 파라미터 개수
#훈련 파라미터 개수
#훈련되지 않은 파라미터 개수
미니배치 경사 하강법을 사용하여 데이터를 한 번에 모두 사용하지 않고 잘게 나누어 여러 번에 걸쳐 경사 하강법 단계를 수행한다.
층을 추가하는 다른 방법
Sequential 클래스의 생성자 안에서 바로 Dense 클래스의 객체를 만든다.
model = keras.Sequential([
keras.layers.Dense(100, activation='sigmoid', input_shape=(784,),
name='hidden'),
keras.layers.Dense(10, activation='softmax', name='output')
], name='패션 MNIST 모델')
model.summary()
위 방식이랑 다르게 층 이름을 hidden, output으로 지정해주었다. (모델 이름과 달리 층 이름은 반드시 영문이어야 한다.)
add() 메서드를 사용하여 층을 추가하는 방식도 있다.
model = keras.Sequential()
model.add(keras.layers.Dense(100, activation='sigmoid', input_shape=(784,)))
model.add(keras.layers.Dense(10, activation='softmax'))
model.summary()
에포크를 5로 설정하여 모델을 훈련시킨다.
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
model.fit(train_scaled, train_target, epochs=5)
렐루 함수 (활성화 함수)
시그모이드 함수 단점
- 올바른 출력을 만드는데 신속하게 대응하지 못한다.
- 특히 층이 많은 심층 신경망일수록 그 효과가 누적되어 학습을 더 어렵게 만든다.
렐루 (ReLU) 함수
- 입력이 양수일 경우 마치 활성화 함수가 없는 것처럼 그냥 입력을 통과시키고 음수일 경우 0으로 만든다.
model = keras.Sequential()
model.add(keras.layers.Flatten(input_shape=(28,28)))
model.add(keras.layers.Dense(100, activation='relu'))
model.add(keras.layers.Dense(10, activation='softmax'))
model.summary()
input_shape 매개변수를 Flatten 층으로 옮기고 첫 번째 Dense 층의 활성화 함수를 relu로 변경하였다.
* Flatten 클래스는 학습하는 층이 아니므로 해당 신경망을 깊이가 3인 신경망이라고 부르지 않는다.
모델 훈련
(train_input, train_target), (test_input, test_target) =\
keras.datasets.fashion_mnist.load_data()
train_scaled = train_input / 255.0
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size=0.2, random_state=42)
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
#성능 확인
model.fit(train_scaled, train_target, epochs=5)
#검증 세트 성능 확인
model.evaluate(val_scaled, val_target)
옵티마이저
07-3 신경망 모델 훈련
'Study > PBL' 카테고리의 다른 글
[혼공머신] Ch06 (1) | 2024.07.24 |
---|---|
[혼공머신] Ch05 (0) | 2024.07.23 |
[혼공머신] Ch04 (0) | 2024.07.18 |
[혼공머신] Ch03 (0) | 2024.07.17 |
[혼공머신] Ch01, 2 (1) | 2024.07.12 |