스스로 배우는 딥러닝 3장 1부
tensorflow - 2.7.0 / keras - 2.7.0 / python - 3.9.7 / CUDA - 11.5
3장 신경망 시작하기
3.1 신경망의 구조
신경망 훈련에는 다음 요소들이 관련되어 있습니다.
- 네트워크(또는 모델)을 구성하는 층
- 입력 데이터와 그에 상응하는 타깃
- 학습에 사용할 피드백 신호를 정의하는 손실 함수
- 학습 진행 방식을 결정하는 옵티마이저
이들 가느이 상호 작용을 아래의 그림에 나타냈습니다.
- 연속된 층으로 구성된 네트워크가 입력 데이터를 예측으로 매핑
- 손실 함수는 예측과 타깃을 비교하여 네트워크의 예측이 기댓값에 얼마나 잘 맞는지를 측정하는 손실 값을 만듬
- 옵티마이저는 손실 값을 사용하여 네트워크 가중치를 업데이트
3.1.1 층 : 딥러닝의 구성 단위
층은 하나 이상의 텐서를 입력으로 받아 하나 이상의 텐서를 출력하는 데이터 처리 모듈
어떤 종류의 층은 상태가 없지만 대부분의 경우 가중치라는 층의 상태를 가짐
가중치란 확률적 경사 하강법에 의해 학습되는 하나 이상의 텐서 여기에 학습한 지식이 담김
층마다 적절한 텐서 포맷과 데이터 처리 방식이 다릅니다.
- 2D 텐서 : 완전 연결 층(fully connected layer) 또는 밀집 층(dense layer)로 불리는 밀집 연결층(densely connnected layer)
- 3D 텐서 : LSTM 같은 순환 층(recurrent layer)
- 4D 텐서 : 2D 합성곱 층(convolution layer)
케라스 같은 프레임워크로 인해 층을 딥러닝의 레고 블록 처럼 생각할 수 있다.
케라스에서는 호환 가능한 층들을 엮어 데이터 변환 파이프라인(pipeline)을 구성함으로써 딥러닝 모델을 만듬
여기에서 층 호환성(layer compatibility)은 각 층이 특정 크기의 입력 텐서만 받고 특정 크기의 출력 텐서를 반환한다는 사실을 말합니다.
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(32. input_shape=(784,))) # 첫번째 차원
model.add(layer.Dense(10)) # 하위 층(두번째 층)
첫번째 차원이 784인 2D 텐서만 입력으로 받는 층을 만들었습니다. ( 배치 차원인 0번째 축은 지정하지 않기 때문에 어떤 배치 크기도 입력으로 받을 수 있음 ) 32로 변환된 텐서를 출력합니다.
이 층은 32차원의 벡터를 입력으로 받는 하위 층이 연결되어야 함.
( 케라스에서는 모델에 추가된 층을 자동으로 상위 층의 크기에 맞추어 주기 때문에 호환성을 걱정하지 않아도 됩니다. )
두번째 층에는 input_shape 매개변수를 지정하지 않습니다. 앞선 출력 크기를 입력 크기로 자동으로 채택합니다.
3.1.2 모델 : 층의 네트워크
딥러닝 모델은 층으로 만든 비순환 유향 프래프(Directed Acyclic Graph, DAG)입니다. 하나의 입력을 하나의 출력으로 매핑하는 층을 순서대로 쌓는 것 하지만 이후 다양한 네트워크 구조를 보게 될 것입니다.
- 가지(branch)가 2개인 네트워크
- 출력이 여러 개인 네트워크
- 인셉션(Inception) 블록
네트워크는 가설 공간(hypothesis space)을 정의합니다. 네트워크 구조를 선택함으로써 가능성 있는 공간을 입력 데이터에서 출력 데이터로 매핑하는 일련의 특정 텐서 연산으로 제한하게 됩니다. 여기서 찾아야 할 것은 텐서 연산에 포함된 가중치 텐서의 좋은 값입니다.
3.1.3 손실 함수와 옵티마이저 : 학습 과정을 조절하는 열쇠
네트워크 구조를 정의하고 나면 두 가지를 더 선택해야 합니다.
- 손실 함수(loss funtion) 또는 목적 함수(objective funtion) : 훈련하는 동안 최소화될 값, 문제에 대한 성공 지표
- 옵티마이저(optimizer) : 손실 함수를 기반으로 네트워크가 어떻게 업데이트될지 결정, 특정 종류의 확률적 경가 하강법(SGD) 구현
여러 개의 출력을 내는 신경망은 여러 개의 손실 함수를 가질 수 있습니다.(출력당 하나씩) 하지만 경사 하강법 과정은 하나의 스칼라 손실값을 기준으로 합니다. 따라서 손실이 여러 개인 네트워크에서는 모든 손실이 ( 평군을 내서 ) 하나의 스칼라 양으로 합쳐집니다.
문제에 맞는 올바른 목적 함수를 선택하는 것은 아주 중요
예를 들어 "모든 인류의 평균 행복 지수를 최대화하기" 잘못된 목적 함수로 훈련된 AI가 있다고 가정
문제를 해결하기 위해 행복 지수가 낮은 모든 사람을 죽여서 행복 지수를 최대화할 수 있습니다. 이는 의도한 바가 아닙니다.
이렇듯 우리가 만든 모든 신경망은 단지 손실 함수를 최소화하기만 한다는 것을 기억하세요. 목적 함수를 현명하게 선택하지 않으면 원하지 않는 부수 효과가 발생할 것입니다.
회귀와 시퀀스 예측 같은 일반적인 문제에서는 올바른 손실 함수를 선택하는 간단한 지침이 있습니다.
- 2개의 클래스가 있는 분류 : 이진 크로스엔트로피(binary crossentropy)
- 여러 개의 클래스가 있는 분류 : 범주형 크로스엔트로피(categorical crossentropy)
- 회귀 문제 : 평균 제곱 오차
- 시퀀스 학습 문제 : CTC(Connection Temporal Classification)
3.2 케라스 소개
케라스의 특징
- 동일한 코드로 CPU와 GPU에서 실행
- 사용하기 쉬운 API를 가지고 있어 딥러닝 모델의 프로토타입을 빠르게 만듬
- 합성곱 신경망, 순환 신경망을 지원하며 이 둘을 자유롭게 조합하여 사용
- 다중 입력이나 다중 출력 모델, 층의 공유, 모델 공유 등 어떤 네트워크 구조도 만들 수 있음
3.2.1 케라스, 텐서플로, 씨아노, CNTK
케라스는 딥러닝 모델을 만들기 위한 고수준의 구성 요소를 제공하는 모델 수준의 라이브러리입니다. 텐서 조작이나 미분 같은 저수준의 연산을 다루지 않습니다. 대신 케라스의 백엔드 엔진에서 제공하는 최적화되고 특화된 텐서 라이브러리를 사용합니다. 즉 여러 딥러닝용 라이브러리를 조합하여 사용하는 것입니다.
케라스에는 다음 백엔드 엔진을 필요에 따라서 선택하여 사용할 수 있습니다. 다음 벡엔드를 사용하기에 CPU와 GPU에서 모두 사용할 수 있습니다. CPU에서는 저수준 텐서 연산 라이브러리인 Eigen을, GPU에서는 NVIDIA CUDA 심층 신경망 라이브러리를 사용하여 최적화된 딥러닝 연산 라이브러리를 이용합니다.
3.2.2 케라스를 사용한 개발 : 빠르게 둘러보기
전형적인 케라스 작업 흐름은 다음과 같은 흐름을 지닙니다.
- 입력 텐서와 타깃 텐서로 이루어진 훈련 데이터를 정의
- 입력과 타깃을 매핑하는 층으로 이루어진 네트워크를 정의
- 손실함수, 옵티마이저, 모니터링하기 위한 측정 지표를 선택하여 학습 과정을 설정
- 훈련 데이터에 대해 모델의 fit() 메서드를 반복적으로 호출
모델을 정의하는 방법 2가지
- Sequential 클래스 : 층을 순서대로 쌓아 올린 네트워크
- 함수형 API : 임의의 구조를 만들 수 있는 비순환 유향 그래프
같은 모델을 2가지 방법으로 만들어 보겠습니다.
# Sequential 사용
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(32,activation='relu', input_shape=(784,)))
model.add(layers.Dense(10, activation='softmax'))
# 함수형 API
input_tensor = layers.Input(shape=(784,))
x = layers.Dense(32, activation='relu')(input_tensor)
output_tensor = layers.Dense(10,activation='softmax')(x)
model = models.Model(input=input_tensor, output=output_tensor)
함수형 API를 사용하면 모델이 처리할 데이터 텐서를 만들고 마치 함수처럼 이 텐서에 층을 적용
( 함수형 API에 대한 자세한 가이드는 7장에 있습니다. )
모델 구조가 정의된 후에는 Sequential 모델을 사용했는지 함수형 API를 사용했는지는 상관없습니다.
모델이 정의된 후에는 동일한 단계를 거치게 됩니다. 컴파일 단계에서는 학습 과정이 설정됩니다. 여기서는 옵티마이저, 손실함수, 모니터링에 필요한 측정 지표를 지정합니다. 그리고 마지막에 fit() 메서드에 전달함으로 학습 과정이 이루어집니다.
from keras import optimizers
model.compile(optimizer=optimizers.RMSprop(lr=0.001),
loss='mse',
metrics=[accuracy])
model.fit(input_tensor, target_tensor, batch_size=128, epochs=10)
3.3 딥려닝 컴퓨터 셋팅
최신 NVIDIA GPU에서 딥러닝 코드를 실행하는 것을 권장합니다. 특히 합성곱 신경망을 사용한 이미지 처리나 순환 신경망을 사용한 시퀀스 처리 같은 일부 애플리케이션을 CPU에서 실행하면 멀티코어 CPU라도 매우 오래 걸립니다.
- CPU가 아닌 GPU를 사용하면 보통 2배~10배 정도 속도가 빨라집니다.
- GPU를 설치하지 않고 대안으로 AWS EC2 GPU 인스턴스나 구글 클라우드 플랫폼을 고려해 볼 수 있습니다.
- 혹은 구글 코랩(Google Colab)이 있습니다. (추천)
추가적으로 우분투로 듀얼 부트가 되도록 컴퓨터를 셋팅하는 것입니다. 조금 번거로울 수 있지만 우분투를 사용하면 장기적으로 시간이 절약되고 문제가 발생할 가능성이 적습니다.
3.3.1 주피터 노트북 : 딥러닝 실험을 위한 최적의 방법
특징
- 노트북 은 주피터 노트북 어플리케이션으로 만든 파일이며 웹 브라우저에서 작성 가능
- 작업 내용을 기술하기 위해 서식 있는 텍스트 포맷을 지원하며 파이썬 코드 실행 가능
- 긴 코드를 작게 쪼개 독립적 실행 가능, 대화식 개발 가능
- 작업 중 잘못되었을 때 이전 코드를 모두 재실행할 필요 없음
추가 : 구글 코랩(Google Colab)
특징
- 주요 특징은 위의 주피터 노트북과 동일
- 추가적인 설치가 필요없고 간단하게 누구나 사용
- 구글 서버에 있는 GPU CPU를 사용하기 때문에 컴퓨터 사양의 영향을 받지않는다.
- 인터넷만 있다면 어디서든 코드를 실행할 수 있음
이제 실전 케라스 예제로 들어가 보겟습니다.
3.4 영화 리뷰 분류 : 이진 분류 예제
2중 분류(two-class classfication) 또는 이진 분류(binary classfication)은 가장 기본적인 머신 러닝 문제입니다. 본 장에서는 리뷰 텍스트를 기반으로 영화 리뷰를 긍정(positive)과 부정(negative)로 분류하는 방법을 배웁니다.
3.4.1 IMDB 데이터셋
IMDB(Internet Movie Database)는 양극단의 5만 개의 리뷰로 이루어진 데이터입니다. 25,000개의 훈련 데이터, 25,000개의 테스트 데이터로 이루어진 데이터입니다. 긍정과 부정이 1:1의 비율로 구성 되어있습니다.
왜 훈련과 테스트 데이터로 나눌까요? 만약 훈련한 데이터로 테스트시 잘 작동한다는 것이 처음 만난 데이터에서도 잘 작동한다는 것을 보장하지 않습니다. 예를 들어 훈련 샘플을 모두 외워 버린다면 테스트를 100%가 나올것입니다. 하지만 새로운 데이터를 보고 예측하는 작업에는 쓸모가 없습니다. 여기서 중요한 것은 새로운 데이터에 대한 모델의 성능입니다. 따라서 훈련과 테스트 데이터를 나눌 필요가 있습니다.
IMDB는 MNIST와 같이 이미 기존 데이터셋에 있습니다. 그렇기에 처음 실행한다면 다운로드 받는 작업이 진행됩니다.
# 코드 3-1 IMDB 데이터셋 로드하기
from keras.datasets import imdb
(train_data, train_labels), (test_data, test_labels) imdb.load_data(num_words=10000)
num_words
= 10000 매개변수는 훈련데이터에서 가장 자주 나타나는 단어 1만 개만 사용하겠다는 의미입니다.train_data
와test_data
는 리뷰의 목록으로 위에서 구한 10000개의 데이터 리스트에서 인덱스를 가지고 있는 리스트입니다.train_labels
와test_labels
는 긍정은 1, 부정은 0으로 각 리뷰에 대한 긍정/부정에 대한value
를 담고 있습니다.
가장 자주 등장하는 단어 1만 개로 제한 했기 대문에 단어 인덱스는 9,999를 넘지 않습니다.
이 리뷰 데이터 하나를 원래 영어 단어로 어떻게 바꾸는지 보겠습니다.
word_index = imdb.get_word_index()
# word_index는 단어와 정수 인덱스를 매핑한 딕셔너리 입니다.
reverse_word_index = dict([(value, key) for (key, value) in word_index.items()])
# 정수 인덱스와 단어를 매핑하도록 뒤집습니다.
decoded_review = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])
# 리뷰를 디코딩 합니다. 0,1,2는 '패딩', '문서 시작', '사전에 없음'을 위한 인덱스 이므로 3을 뻅니다.
-> 0,1,2 '패팅, 문서 시작, 사전에 없음'은 IMDB데이터에 만들어져 있는 형태 입니다.
3.4.2 데이터 준비
신경망에 숫자 리스트를 주입할 수는 없습니다. 리스트를 텐서로 바꾸는 두 가지 방법이 있습니다.
- 같은 길이가 되도록 리스트에 패딩을 추가하고 (samples, sequence_length) 크기의 정수 텐서로 변환합니다. 그 다음 정수 텐서를 다룰 수 있는 층을 신경망의 첫 번째 층으로 사용합니다. (Embedding 층)
- 리스트를 one-hot encoding하여 0과 1 벡터로 변환합니다. 예를 들어 시퀀스[3,5]를 인덱스 3과 5의 위치는 1이고 그 외는 모두 0인 10,000차원의 벡터로 각각 변환합니다. 그 다음 부동 소수 벡터 데이터를 다룰 수 있는 Dense 층을 신경망의 첫 번째 층으로 사용합니다.
# 코드 3-2 정수 시퀸스를 이진 행렬로 인코딩하기
import numpy as np
# 크기가(len(sequences, dimension)이고 모든 원소가 0인 행렬을 만듭니다.
def vectorize_sequences(sequences, dimension=10000):
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
results[i, sequence] = 1. # results[i]에서 특정 인덱스의 위치를 1로 만듭니다.
return results
x_train = vectorize_sequences(train_data) # 훈련 데이터를 벡터로 변환
x_test = vectorize_sequences(test_data) # 테스트 데이터를 벡터로 변환
# 레이블 벡터 변환
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')
이제 신경망에 주입할 데이터가 준비되었습니다.
3.4.3 신경망 모델 만들기
입력 데이터가 벡터고 레이블은 스칼라(1 또는 0)입니다. 앞으로 볼 수 있는 문제중 가장 간단할 겂입니다. 이런 문제에 잘 작동하는 네트워크 종류는 relu 활성화 함수를 사용한 완전 연결 층(즉 Dense(16, activation='relu')
)을 그냥 샇은 것입니다.
Dense층에 전달한 매개변수 (16)은 은직 유닉의 개수 입니다. 하나의 은닛 유닛은 층이 나타내는 표현 공간에서 하나의 차원이 됩니다.
2장에서 relu 활성화 함수를 사용한 Dense 층을 다음 텐서 연산을 견결하여 구현했습니다.
output = relu(dot(W,input) + b)
16개의 은닉 유닛이 있다는 것은 가중치 행렬 W 크기가 (input_dimension, 16)이라는 뜻 입니다. 입력 데이터와 W를 점곱하면 입력 데이터가 16차원으로 표현된 공간으로 투영됩니다.(그리고 편향 벡터 b를 더하고 relu 연산을 적용합니다.) 표현 공간의 차원을 '신경망이 내재된 표현을 학습할 때 가질 수 있는 자유도'로 이해할 수 있습니다. 은직 유닛을 늘리면(고차원으로 만들면) 신경망이 더욱 복잡한 표현을 학습할 수 있지만 계산 비용이 커지고 원하지 않는 패턴을 학습할 수도 있습니다.(훈련에서는 성능이 향상되지만 테스트에서는 그렇지 않은 패턴입니다)
Dense 층을 쌓을 때 두 가지 중요한 구조상의 결정이 필요합니다.
- 얼마나 많은 층을 사용할 것인가?
- 각 층에 얼마나 많은 은닉 유닛을 둘 것인가?
이 부분은 4장에서 다루겠습니다. 지금은 그냥 구조를 따라갑니다.
- 16개의 은식 유닛을 가진 2개의 은닉 층
- 현재 리뷰의 감정을 스칼라 값의 예측으로 출력하는 세 번째 층
중간에 있는 은닉 층은 활성화 함수로 relu를 사용하고 마지막 층은 확률을 출력하기 위해 시그모이드(sigmoid) 활성화 함수를 사용합니다. relu는 음수를 0으로 만드는 함수 입니다. 시그모이드는 임의의 값을 [0,1] 사이로 압축하므로 출력 값을 확률처럼 해석할 수 있습니다.
-> 활성화 함수란?
relu와 같은 활성화 함수(또는 비선형성(non-linearity))가 없다면 Dense층은 선형적인 연산인 점곱과 덧셈 2개로 구성됩니다.
output = dot(W, input) + b
그러므로 이 층은 입력에 대한 선형 변환만을 학습할 수 있습니다. 이 층의 가설 공간은 입력 데이터를 16차원의 공간으로 바꾸는 기능한 모든 선형 변환의 집합입니다. 이런 가설 공간은 매우 제약이 많으며, 선형 층을 깊게 쌓아도 여전히 하나의 선형 연산이기 때문에 층을 여러 개로 구성하는 장점이 없습니다. 즉 층을 추가해도 가설 공간이 확장되지 않습니다.
가설 공간을 풍부하게 만들어 층을 깊게 만드는 장점을 살리기 위해서는 비선형 또는 활성화 함수를 추가해야 합니다. relu는 딥러닝에서 가장 인기 있는 활성화 함수입니다. 물론 비슷한 다른 함수들도 많습니다.
신경망의 케라스 구현입니다.
# 코드 3-3 모델 정의하기
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
- 계속해서 추가
Author And Source
이 문제에 관하여(스스로 배우는 딥러닝 3장 1부), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@minukiki/스스로-배우는-딥러닝-3장저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)