● Chpater 07의 학습목표
1. 딥러닝의 핵심 알고리즘인 인공 신경망을 배웁니다.
2. 대표적인 인공 신경망 라이브러리인 텐서플로와 케라스를 소개합니다.
3. 인공 신경망 모델의 훈련을 돕는 도구를 익힙니다.
● 학습목표: 딥러닝과 인공 신경망 알고리즘을 이해하고 텐서플로를 사용해 간단한 인공 신경망 모델을 만들어 봅니다.
● 키워드: 인공 신경망, 텐서플로, 밀집층, 원-핫 인코딩
● 지난 시간 - 주성분 분석 알고리즘 문제 풀이
1. 데이터의 주성분 찾기
- n_components = 2 이상의 정수 → 찾고자 하는 주성분의 개수
- n_components = 0 ~ 1 사이의 실수 → 설명하고자 하는 분산의 비율
2. 데이터를 주성분에 투영하여 차원 축소하기 (transform)
3. 차원이 축소된 데이터를 이용해서 다른 Algorithm과 연계하여 시각화 하거나 성능을 높히기
3-1. Unsupervised learning algorithm (ex. KMeans를 통한 시각화)
3-2. Supervised learning algorithm (cross validation의 score 확인을 통한 성능 확인과 fit time 감소율 확인)
● 딥러닝 알고리즘 문제 풀이
1. Keras를 이용해 data 불러오기
2. Train set에서 validation set 일부 덜어내기 (train_test_split 사용)
3. Layer 만들기
4. Model 만들기
5. Loss function 정하기
6. 훈련하기
데이터 살펴보기
Train/Test 데이터는 총 몇개씩 존재하며, Train target 안의 각각의 데이터는 몇개씩 분포하는지 확인합니다.
딥러닝의 유명한 대표 데이터셋인 패션 MNIST 데이터셋을 불러옵니다. 패션 MNIST는 10종류의 패션 데이터를 총 60,000개 보유하고 있습니다.
#1. 데이터 다운 받기
from tensorflow import keras
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
#2. Train set의 샘플 형태 확인
print(train_input.shape, train_target.shape) # (60000, 28, 28) (60000,)
train set의 분포를 확인합니다. 28 x 28 데이터가 60,000개가 존재하며, target 데이터도 60,000개입니다,.
#3. Test set의 샘플 형태 확인
print(test_input.shape, test_target.shape) # (10000, 28, 28) (10000,)
test set는 10,000개입니다.
디음은 Train set 데이터셋의 처음 10가지를 확인합니다.
#4. 사진 10장 확인
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()
#5. 사진 10장의 분류 값 확인
print([train_target[i] for i in range(10)])
# [9, 0, 0, 3, 0, 2, 7, 2, 5, 5]
마지막 두개의 target 값이 똑같은것을 보니, 사진 두개의 신발이 유사한 이유가 있었습니다.
각 target 값들이 몇개씩 있는지 확인해봅니다.
#6. 데이터들이 어떻게 분포하는지 확인
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]))
각 target 값이 6,000개씩 있습니다.
총 train set의 개수가 60,000나 있으니 랜덤하게 샘플을 뽑아서 손실함수의 값을 최소화 하는 확률적 경사하강법을 이용하겠습니다.
스케일링 후, Logistic regression VS Deep learning model 비교
확률절 경사하강법을 이용 할 때, 스케일링의 이유
1. pixel의 값은 0 ~ 255까지 존재합니다. 하지만, 기울기가 너무 큰 값을 가지게 되면 확률적 경사하강법을 사용할 때 너무 큰 기울기 변화를 학습하게 불안정한 학습이 이루어지고 수렴하지 못하거나 수렴하는데 오랜 시간이 걸리며, 손실함수의 최소점을 지나버릴수 있습니다.
2. 또한, activation function은 큰 값일 때, 1 작은 값일때 0으로 비선형화를 이루게 되는데 너무 큰 값을 가지게 되면, activation function이 포화 될 수 있습니다.
따라서, pixel 값을 255로 나누는 방법을 주로 이용한다고 합니다. 이후, train_scaled의 2차원 3차원 데이터를 1차원 데이터로 변경해줍니다.
#7. 데이터 정규화 및 1차원으로 변형
train_scaled = train_input / 255.0
train_scaled = train_scaled.reshape(-1, 28*28)
print(train_scaled.shape) # (60000, 784) 6000개의 샘플이 784개의 pixel로 이루어짐.
이전에 했던것 처럼 로지스틱 회귀 모델을 활용해서 먼저 모델의 점수를 평가해보겠습니다.
#8. Logistic regression model로 훈련하여 cross validation 점수 확인
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import cross_validate
sc = SGDClassifier(loss = 'log_loss', max_iter = 5, random_state = 42)
scores = cross_validate(sc, train_scaled, train_target, n_jobs = -1)
print(np.mean(scores['test_score'])) # 0.8196000000000001
epoch 수를 9, 20으로 늘려도 0.9 이하의 값을 가져서 더 성능을 향상 시킬 알고리즘이 필요할것 같습니다. 픽셀 데이터를 이용하여 Logistic regression model의 z 값을 구하는 과정은 다음과 같습니다.
인공 신경망의 개념과 Tensorflow
인공 신경망: 생물학적 뉴런에서 영감을 받아 만든 머신러닝 알고리즘
인공 신경망 알고리즘과 딥러닝이 거의 동의어로 사용 됩니다. 혹은 심층 신경망 (deep nueral network, DNN)을 딥러닝이라고 부릅니다.사실 심층 신경망은 여러개의 층을 가진 인공 신경망입니다.
이미지 분류, 음성, 텍스트 문제를 처리 할 때는 인공 신경망이 굉장이 효율적입니다. 따라서, 지금부터 인공 신경망을 만들것이지만,
사실, 인공 신경망의 가장 기초적인 단계는 확률적 경사하강법을 이용한 Logistic regression model 입니다.
우선, 딥러닝 모델을 만들기전에 keras와 tensorflow에 대해서 이해하고 넘어가야합니다.
Tensorflow: 구글이 만든 딥러닝 라이브러리, CPU와 GPU를 사용해 인공 신경망 모델을 효율적으로 훈련며, 모델 구축과 서비스에 필요한 다양한 도구를 제공. 버전 2.0부터는 신경망 모델을 빠르게 구성할 수 있는 Keras를 핵심 API로 채택하여 간단한 모델에서 복잡한 모델까지 손쉽게 만들수 있음.
Tensorflow와 Keras (API 관점)
1. TensorFlow는 큰 기계, Keras는 그 기계를 쉽게 조작하는 리모컨
TensorFlow는 딥러닝과 머신러닝을 위한 **강력한 도구(프레임워크)**입니다. 이 도구를 사용하면 컴퓨터가 사람처럼 학습할 수 있게 모델을 만들고, 데이터에서 패턴을 찾아내는 일을 할 수 있습니다. 하지만, TensorFlow는 매우 복잡한 기능들을 다루기 때문에 처음부터 사용하기 어렵습니다. 마치 대형 기계를 조작하는 것처럼, 다양한 부품과 설정을 손으로 일일이 맞추는 일이 많죠.
Keras는 이 TensorFlow를 쉽게 사용할 수 있도록 도와주는 리모컨 같은 역할을 합니다. TensorFlow는 큰 기계를 움직이기 위한 복잡한 내부 메커니즘을 제공하고, Keras는 그 복잡한 부분을 알아서 처리해 주면서 사용자가 간단한 명령만으로 그 기계를 다룰 수 있게 해줍니다.
2. 비유: 자동차 엔진(Tensorflow)과 운전대 (Keras)의 관계
TensorFlow를 자동차 엔진이나 차체 같은 것이라고 생각해보세요. 엔진이 없으면 자동차는 움직이지 않죠. 하지만 엔진을 직접 다루려면 복잡한 기술이 필요합니다. 엔진을 이해하고 직접 연료를 넣거나, 여러 부품을 손으로 조작하는 건 어렵죠.
그런데 우리가 자동차를 쉽게 운전할 수 있는 이유는 운전대나 페달 같은 단순한 조작 장치가 있기 때문입니다. 운전자는 복잡한 엔진의 작동 원리를 몰라도, 운전대와 페달만 잘 사용하면 자동차를 마음대로 움직일 수 있습니다.
- TensorFlow는 자동차의 엔진과 같아요. 매우 강력하고 중요한 역할을 하지만, 직접 다루기에는 복잡해요.
- Keras는 운전대와 같아요. Keras를 사용하면 복잡한 TensorFlow의 기능을 몰라도 쉽게 딥러닝 모델을 만들고 학습시킬 수 있어요.
3. TensorFlow가 없으면 Keras는 작동하지 않아요
Keras는 TensorFlow 위에서 작동하는 고수준 API (Application programming interface)입니다. Keras는 자체적으로 모든 일을 처리하는 게 아니라, 내부적으로 TensorFlow의 기능을 활용해 딥러닝 모델을 만들어 줍니다. 그래서 Keras만으로는 모델을 학습시킬 수 없고, 반드시 TensorFlow가 함께 있어야 합니다.
4. 왜 Keras가 필요할까?
TensorFlow는 복잡한 일을 할 수 있어서 강력하지만, 그만큼 설정하고 사용하기 어려울 수 있어요. 반면, Keras는 이런 복잡함을 없애주고, 딥러닝을 처음 배우는 사람도 쉽게 사용할 수 있게 만들어 줍니다. 마치 터치 몇 번으로 복잡한 기계를 쉽게 다룰 수 있는 스마트폰 앱처럼요
API의 주요 역할
- 복잡성 숨기기: API는 복잡한 내부 구현을 감추고, 단순한 인터페이스만 제공하여 개발자가 쉽게 사용할 수 있도록 합니다.
- 재사용성: API를 통해 개발자는 이미 구현된 기능을 반복해서 사용할 수 있습니다.
- 유지보수성: API는 특정 기능에 대한 명확한 규칙을 제공하여 코드 변경을 최소화하면서 기능을 확장하거나 수정할 수 있게 합니다.
Keras는 TensorFlow의 고수준 API로, TensorFlow의 복잡한 저수준 동작을 숨기고, 더 간단한 방식으로 신경망 모델을 만들고 학습시킬 수 있게 해줍니다.
- 저수준 API: 세부적인 작업을 직접 제어하는 코드로, 매우 유연하고 강력하지만, 구현이 복잡할 수 있습니다. 예를 들어, TensorFlow의 저수준 API는 세세한 데이터 흐름과 그래프를 직접 설계하고 다루어야 합니다.
- 고수준 API: 복잡한 작업을 더 쉽게 처리할 수 있는 추상화된 인터페이스입니다. Keras는 딥러닝 모델을 쉽게 정의하고 학습할 수 있도록 간결한 명령어들을 제공합니다. 이로 인해 복잡한 신경망 모델도 몇 줄의 코드로 작성할 수 있습니다.
예시: Keras와 TensorFlow API 비교
- 저수준 TensorFlow API: 매트릭스 곱셈, 미분, 그래프 생성 등을 세밀하게 구현해야 함.
- 고수준 Keras API: 다음과 같이 간단한 코드로 모델을 생성하고 학습 가능.
Tensorflow와 Keras (Back-end 관점)
1. Keras와 TensorFlow는 어떻게 관련이 있을까?
Keras와 TensorFlow는 둘 다 딥러닝(인공지능 모델을 만드는 기술)을 위한 도구예요. 그런데 TensorFlow는 매우 강력하고 많은 기능을 제공하는 큰 프로그램이라서 다루기 복잡해요. Keras는 이 강력한 TensorFlow를 쉽게 사용할 수 있도록 도와주는 간단한 인터페이스라고 할 수 있어요.
비유:
- TensorFlow는 대형 엔진을 가진 복잡한 차라고 할 수 있어요. 이 차를 조작하려면 많은 버튼과 레버를 알아야 하죠.
- Keras는 그 차를 조작할 수 있는 리모컨이에요. 리모컨을 사용하면 버튼 몇 개만으로 쉽게 차를 운전할 수 있죠. 이 리모컨은 차가 어떻게 움직이는지(엔진 내부에서 무슨 일이 벌어지는지)를 몰라도 쉽게 사용할 수 있도록 만들어져 있어요.
2. 백엔드(Backend)란?
이제 **백엔드(backend)**에 대해 설명할게요. Keras는 사실 **딥러닝 모델을 만들 때 계산을 실제로 처리하는 일을 다른 프로그램(백엔드)**에 맡겨요. 즉, Keras는 계산의 "표면"을 담당하고, 그 아래에서 실제 계산을 처리하는 부분을 백엔드라고 해요.
비유로 이해하기:
- Keras는 식당의 메뉴판 같아요. 우리는 메뉴판을 보고 어떤 음식을 먹고 싶은지 고르기만 하면 되죠. 메뉴판을 통해 어떤 음식을 주문할지 쉽게 결정할 수 있어요.
- 그런데 실제로 음식을 만드는 건 주방에서 요리사가 하겠죠? **이 요리사가 바로 백엔드(backend)**입니다. 메뉴판(Keras)만으로는 음식이 나오지 않고, 실제로 요리를 해야 결과물이 나오죠.
이처럼 Keras는 "어떤 모델을 만들지" 쉽게 선택할 수 있게 해주지만, 실제로 그 모델을 만들고 학습하는 계산 작업은 백엔드가 처리해요.
3. TensorFlow는 Keras의 백엔드 중 하나다
TensorFlow는 Keras가 사용할 수 있는 여러 백엔드 중 하나예요. Keras가 "리모컨" 역할을 하면서 딥러닝 모델을 만들 때, 그 모델의 복잡한 계산을 처리해주는 시스템이 TensorFlow라는 말이에요.
Keras는 한때 TensorFlow 외에도 다른 백엔드(예: Theano, CNTK)도 사용할 수 있었지만, 지금은 주로 TensorFlow를 백엔드로 사용합니다. 그래서 Keras를 사용할 때 실제로는 TensorFlow가 뒤에서 모든 계산을 처리하고 있어요.
정리:
- Keras는 딥러닝을 쉽게 할 수 있는 도구(인터페이스)예요.
- 백엔드는 실제로 복잡한 계산을 처리하는 역할을 하는 프로그램이에요.
- TensorFlow는 Keras가 사용하는 백엔드 중 하나로, Keras가 만든 모델의 계산을 처리하는 역할을 해요.
4. 백엔드는 딥러닝 계산을 하기 위해 반드시 필요하다.
Keras는 그 자체로는 아무 계산도 하지 않아요. 백엔드(예: TensorFlow)가 있어야 실제로 모델이 작동하고, 학습이 진행될 수 있어요. 즉, Keras가 딥러닝 모델을 설계하고 설정해 주면, 백엔드가 그 모델을 가지고 계산을 하고 결과를 내는 방식이죠.
Tensorflow (Keras)로 딥러닝 모델 만들기
이제 딥러닝 알고리즘을 훈련하고 평가하기 위해서 train set와 validation set를 구분하겠습니다.
하지만, 다른 머신러닝 모델들처럼 K-fold validation을 수행하지 않습니다. 대신 Train set에서 일부를 validation set로만 사용합니다. 그 이유는 다음과 같습니다.
- 실제 딥러닝 모델의 Train set는 굉장히 커서 검증 점수가 안정적입니다.
- 한편, Train set가 크기 때문에, 훈련 하는데만 오랜시간이 걸립니다. 따라서, 교차 검증 시간까지 하면 너무 많은 시간이 걸리기 때문에, 일부만 사용합니다.
#2-1. 딥러닝에 사용할 Train set / Validation set 나누기
from sklearn.model_selection import train_test_split
train_scaled, val_input, train_target, val_target = train_test_split(train_scaled, train_target, test_size = 0.2, random_state = 42)
#2-2. 스케일링 된 훈련 데이터세트 확인
print(train_scaled.shape, train_target.shape) # (48000, 784) (48000,)
#2-3. 스케일링 된 validataion 데이터세트 확인
print(val_input.shape, val_target.shape) # (12000, 784) (12000,)
만약, 위처럼 입력층과 출력층을 모두 연결하고 있다면, 이를 완전 연결층 (Fully connected layer)라고 합니다. 혹은 밀집층 (Dense layer)라고도 합니다.
1. Layer (층) 만들기 (Keras의 layers 패키지 사용)
- 사용법: keras.layers.Dense(# of Output layer, activation = 'Name of activation function', input_shape = (# of input layer,))
- Activation function: 뉴런의 출력에 적용할 함수. 뉴런의 선형 방정식 계산 결과에 적용되는 함수.
- 밀집층(Dense layer) or 완전 연결층 (Fully connected layer): 가장 간단한 인공 신경망의 층, Input layer와 Output layer가 모두 연결 되어 있는층. 출력층에 밀집층을 사용할 때는 분류하려는 class와 동일한 개수의 뉴런을 사용합니다.
#2-4. 딥러닝 층 만들기
dense = keras.layers.Dense(10, activation = 'softmax', input_shape = (784,))
2. 모델 만들기
Keras의 Sequential 클래스로 만든 layer 객체 전달하여 모델 만들기. 추가할 층을 지정할 수도 있는데, 이는 파이썬 list로 전달 가능합니다.
#2-5. 모델 만들기
model = keras.Sequential([dense])
# 활성화 함수층은 별도의 층인가?
일반적으로 활성화 함수는 층의 일부로 표현한다. 하지만, 가끔 "softmax 함수층을 사용했어!" 와 같이 표현 하기도 한다.
가중치와 절편을 계산하는 선형 방정식 계산층을 좁은 신경망층의 개념이라고 생각한다면, 활성화 함수층은 넓은 층의 신경망 개념이라고 생각 할 수 있다.
3. 활성화 함수와 측정 지표의 지정
원-핫 인코딩 (One-hot encoding): 타깃값을 해당 클래스만 1이고 나머지는 모두 0인 배열로 만드는것.
- 다중분류 문제의 경우 출력층에서 만든 확률과 cross-entropy 값 중 각 class의 해당 확률과 cross-entropy 값만 필요하게 됩니다.
- 따라서, 여러 값에서 특정 값만 남기기 위해서 나머지는 모두 0, 해당 class만 1로 남기는 과정이 있습니다. 이를 원핫 인코딩이라고 합니다.
compile(): 모델 객체를 만든 후 훈련하기 전에 사용할 손실 함수와 측정 지표 등을 지정하는 method
- loss: 손실함수 지정
- metrics: 훈련 과정에서 측정하고 싶은 지표를 지정. 1개 이상인 경우 리스트로 전달
sparse_categological_crossentropy: 원-핫 인코딩을 하지 않고 정수로 된 타깃값을 다중분류 문제에 사용하여 cross-entropy 손실함수를 구하는 keras compile method의 매개변수 값 중 하나.
- 이진분류: loss = 'binary_cross_entropy'
- 다중분류: loss = 'categological_cross_entropy'
- 분류의 class label이 정수인 경우: loss = 'sparse_categological_cross_entropy'
- 회귀 모델: loss = 'mean_square_error'
다행이게도 원-핫 인코딩이 되어 있지 않더라도 다중분류 문제를 kears가 알아서 원-핫 인코딩을 진행하고 해당 출력층의 활성함수 값과 cross-entropy 값을 구하게 됩니다. 즉, 정수로 된 타깃값을 원-핫 인코딩으로 바꾸지 않고 그냥 바로 사용할 수 있습니다. 이때, 다중분류 값들이 연속적이지 않고 분리 되어 있어 spare(희소) 라는 단어를 적어서 sparse_categological_cross_entropy 라는 손실함수를 이용합니다.
# cross-entropy 손실함수와 인공 신경망의 관계
특히, logistic 손실 함수에서 출력층에서 activation 함수를 지난 값이 1에 가까워야 하는데, 이것이 바로 cross-entropy loss function이 인공신경망에 바라는 것입니다.
#2-6. 손실함수 정하고 Train set로 훈련하기 -> 이후 validation set로 검증
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
model.fit(train_scaled, train_target, epochs = 5)
model.evaluate(val_input, val_target)
확인 결과, SGDClassifier를 활용한 model 보다 accuracy가 개선된것을 확인할수 있었습니다. 인공신경망이 SGDClassifier보다 개선된 점은 다음 chapter에서 설명하겠습니다.
# 복습 코드
# 데이터 로딩 및 훈련 세트에 대한 정보 파악
from tensorflow import keras
import numpy as np
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
print(train_input.shape, train_target.shape)
print(np.unique(train_target, return_counts = True))
# train data 10개 확인하기
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()
print(train_target[:10])
print(train_target[i] for i in range(10))
# 학습에 좋게 2차원 데이터로 변경
train_input = train_input.reshape(-1,28*28)
test_input = test_input.reshape(-1,28*28)
# 데이터 전처리
train_scaled = train_input/255.0
test_scaled = test_input/255.0
# SGDClassifer를 이용한 모델의 학습 및 평가
from sklearn.linear_model import SGDClassifier
from sklearn.model_selection import cross_validate
sc = SGDClassifier(loss = 'log_loss', max_iter = 5, random_state = 42)
scores = cross_validate(sc, train_input, train_target)
print(np.mean(scores['test_score']))
for epoch in [5,9,20]:
sc = SGDClassifier(loss = 'log_loss', max_iter = epoch, random_state = 42)
scores = cross_validate(sc, train_input, train_target, n_jobs = -1)
print(f'Accuracy of Epoch: ',{epoch},' =', np.mean(scores['test_score']))
# 개선된 모델의 필요성 확인
#### 딥러닝 모델
# 딥러닝 모델에 훈련 세트와 validation set 나누기
from sklearn.model_selection import train_test_split
train_scaled, val_scaled, train_target, val_target = train_test_split(train_scaled, train_target, test_size = 0.2, random_state = 42)
print(train_scaled.shape, val_scaled.shape)
print(train_target.shape, val_target.shape)
# 층 생성
dense = keras.layers.Dense(10, activation = 'softmax', input_shape = (784,))
# 모델 생성
model = keras.Sequential([dense])
# 손실함수와 정확도 지정
model.compile(loss = 'sparse_categorical_crossentropy', metrics = ['accuracy'])
# 학습 후, model 평가
model.fit(train_scaled, train_target, epochs = 5)
model.evaluate(val_scaled, val_target)