반응형
반응형

가장 많이 쓰이고 중요한 케라스 함수를 정리했습니다.

 

📝Tokenizer

from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences

tokenizer = Tokenizer()
train_text = "The earth is an awesome place live"

# 단어 집합 생성
tokenizer.fit_on_texts([train_text])

# 정수 인코딩
sub_text = "The earth is an great place live"
sequences = tokenizer.texts_to_sequences([sub_text])[0]

print("정수 인코딩 : ",sequences)
print("단어 집합 : ",tokenizer.word_index)

# 정수 인코딩 :  [1, 2, 3, 4, 6, 7]
# 단어 집합 :  {'the': 1, 'earth': 2, 'is': 3, 'an': 4, 'awesome': 5, 'place': 6, 'live': 7}

전처리 과정에 사용 되며 문장을 토큰으로 나누고 정수 인코딩에 사용 됩니다.

 

pad_sequences([[1, 2, 3], [3, 4, 5, 6], [7, 8]], maxlen=3, padding='pre')
  • pad_sequence()
    • 각 샘플의 길이가 서로 다를 수 있는데 모델에 입력할 때 모든 샘플의 길이를 동일하게 맞춰야 할 때가 있습니다. 이걸 패딩이라고 하는데 부족한 곳에는 0을 채워넣고 너무 과한 곳은 아예 잘라버립니다.

 

📝층 입력하기

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()

# 워드 임베딩
model.add(Embedding(vocab_size, output_dim, input_length))

# 전결합층 추가
model.add(Dense(1, input_dim=3, activation='relu'))
  • Sequential()
    • 층을 만들기 위한 작업입니다.
  • Embedding
    • 첫번째 인자 → 단어의 잡합의크기로 총 단어의 개수를 의미합니다.
    • 두번째 인자 임베딩 벡터의 출력 차원 (대체로 상황에 쓰이는 추천 출력 차원 존재) [너무 작으면 의미가 사라지며 크면 커지고 과적합 위험]
    • 세번째 인자 입력 시퀀스 길이 (문장안에 몇 단어로 들어가는지로 정하게 되며 길이가 부족한 건 패딩처럼 처리가 된다)
  • Dense
    • 첫번째 인자 → 출력 뉴런 수
    • input_dim → 입력 뉴런 수
    • activation → 활성화 함수

 

📝모델 정보 요약

model.summary()

_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
dense_1 (Dense)              (None, 8)                 40        
_________________________________________________________________
dense_2 (Dense)              (None, 1)                 9         
=================================================================
Total params: 49
Trainable params: 49
Non-trainable params: 0
_________________________________________________________________

 

 

📝컴파일

model.compile(optimizer='rmsprop', loss='binary_crossentropy', metrics=['acc'])
  • compile
    • 모델을 기계가 이해할 수 있게 컴파일 합니다.
    • optmizer → 훈련 과정을 설정하는 옵티마이저 설정
    • loss → 훈련 과정에 사용할 손실 함수 설정
    • metrics훈련을 모니터링하기 위한 지표를 선택

 

문제 유형 손실 함수명 출력층의 활성화 함수명 참고 실습
회귀 문제 mean_squared_error - 선형 회귀 실습
다중 클래스 분류 categorical_crossentropy 소프트맥스 로이터 뉴스 분류하기
다중 클래스 분류 sparse_categorical_crossentropy 소프트맥스 양방향 LSTM를 이용한 품사 태깅
이진 분류 binary_crossentropy 시그모이드 IMDB 리뷰 감성 분류하기

 

 

📝훈련

model.fit(X_train, y_train, epochs=10, batch_size=32)

model.fit(X_train, y_train, epochs=10, batch_size=32, verbose=0, validation_data(X_val, y_val))

# 훈련 데이터의 20%를 검증 데이터로 사용.
model.fit(X_train, y_train, epochs=10, batch_size=32, verbose=0, validation_split=0.2))
  • fit
    • 모델을 학습합니다.
    • 첫번째 인자 → 훈련 데이터에 해당
    • 두번째 인자 → 지도 학습에서 레이블 데이터에 해당
    • epochs  에포크로 1은 전체 데이터를 한 차례 훑고 지나갔음을 의미. 총 훈련 횟수를 정의
    • batch_size  배치 크기로 기본값은 32입니다. 미니 배치 경사 하강법을 사용하고 싶지 않을 경우 batch_size=None
    • verbose  학습 중 출력 문구를 설정 (0 → 출력 X, 1 → 훈련 진행에 대한 막대, 2 → 미니 배치마다 손실 정보 출력)
    • validation_data(x_val, y_val)  검증 데이터를 사용합니다. 각 에포크 마다 검증 데이터의 정확도나 오차를 출력하는데 이건 훈련이 잘 되고 있는지를 보여줄 뿐이지 이 데이터를 학습하진 않습니다. (과적합에 대한 판단 가능)
    • validation_split  훈련 데이터와 훈련 데이터의 레이블인 x_train, y_train에서 일정 비율 분리해 검증 데이터로 사용

 

📝평가

# 위의 fit() 코드의 연장선상인 코드
model.evaluate(X_test, y_test, batch_size=32)
  • evaluate
    • 테스트 데이터를 통해 학습한 모델에 대한 정확도를 평가합니다.
    • 첫번째 인자 테스트 데이터에 해당
    • 두번째 인자 지도 학습에서 레이블 테스트 데이터에 해당
    • batch_size → 배치 크기

 

📝예측

# 위의 fit() 코드의 연장선상인 코드
model.predict(X_input, batch_size=32)
    • predict
      • 임의의 입력에 대한 모델의 출력값을 확인합니다.
      • 첫번째 인자  예측하고자 하는 데이터
      • batch_size → 배치 크기

 

📝모델 저장과 로드

model.save("model_name.h5")

from tensorflow.keras.models import load_model
model = load_model("model_name.h5")
  • save
    • 인경 신경망 모델을 hdf5 파일에 저장
  • load_model
    • 저장해둔 모델을 불러옵니다.

 

 

🔗 참고 및 출처

https://wikidocs.net/32105

반응형
반응형

📝기울기 소실

# 시그모이드 함수 그래프를 그리는 코드
def sigmoid(x):
    return 1/(1+np.exp(-x))
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)

plt.plot(x, y)
plt.plot([0,0],[1.0,0.0], ':') # 가운데 점선 추가
plt.title('Sigmoid Function')
plt.show()

 

시그모이드 함수의 출력값이 0 또는 1에 가까워지면, 그래프의 기울기가 완만해지는 모습을 볼 수 있습니다. 기울기가 완만해지는 구간을 주황색, 그렇지 않은 구간을 초록색으로 칠해보겠습니다.

 

주황색 구간에서는 미분값이 0에 가까운 아주 작은 값입니다. 초록색 구간에서의 미분값은 최대값이 0.25입니다. 다시 말해 시그모이드 함수를 미분한 값은 적어도 0.25 이하의 값입니다. 시그모이드 함수를 활성화 함수로하는 인공 신경망의 층을 쌓는다면, 가중치와 편향을 업데이트 하는 과정인 역전파 과정에서 0에 가까운 값이 누적해서 곱해지게 되면서, 앞단에는 기울기(미분값)가 잘 전달되지 않게 됩니다. 이러한 현상을 기울기 소실(Vanishing Gradient) 문제라고 합니다.

 

시그모이드 함수를 사용하는 은닉층의 개수가 다수가 될 경우에는 0에 가까운 기울기가 계속 곱해지면 앞단에서는 거의 기울기를 전파받을 수 없게 됩니다. 다시 말해 매개변수 w가 업데이트 되지 않아 학습이 되지를 않습니다.

 

 

📝기울기 폭주

기울기 소실과 다르게 기울기가 점차 커지더니 비정상적인 큰 값이 되면서 발산되는 것을 기울기 폭주라고 합니다.

 

 

 

📝그래디언트 클리핑

그래디언트 클리핑은 말 그대로 기울기 값을 자르는 것을 의미합니다. 기울기 폭주를 막기 위해 임계값을 넘지 않도록 값을 자릅니다. 다시 말해서 임계치만큼 크기를 감소시킵니다. 이는 뒤에서 배울 신경망인 RNN에서 유용합니다.

 

📝가중치 초기화

기울기 소실과 폭주를 방지하기 위한 초기화에는 다양한 방법이 있습니다. (가중치 초기화는 레이어가 시작할 때 진행 됩니다.)

 

 

세이비어 초기화

  • 세이비어 초기화는 여러 층의 기울기 분산 사이에 균형을 맞춰서 특정 층이 너무 주목을 받거나 다른 층이 뒤쳐지는 것을 막습니다. 그런데 세이비어 초기화는 시그모이드 함수나 하이퍼볼릭 탄젠트 함수와 같은 S자 형태인 활성화 함수와 함께 사용할 경우에는 좋은 성능을 보이지만, ReLU와 함께 사용할 경우에는 성능이 좋지 않습니다. 즉, 시그모이드 함수나 하이퍼볼릭탄젠트 함수(대칭적인 함수)를 사용할 경우에는 세이비어 초기화 방법이 효율적입니다.
  • 입력뉴런 수와 출력 뉴런 수를 둘다 고려합니다.

 

He 초기화

  • He 초기화는 ReLU 계열의 활성화 함수(비대칭적인 함수) 를 사용할 때 좋은 성능을 보이는 초기화 방식입니다.
  • 입력 뉴런수만 고려합니다. 왜냐하면 ReLU에서는 출력이 많이 죽기 때문에 입력만 잘 조절하자는 입장입니다.

 

📝배치 정규화

ReLU 계열의 함수와 He 초기화를 사용하는 것만으로도 어느 정도 기울기 소실과 폭주를 완화시킬 수 있지만, 이 두 방법을 사용하더라도 훈련 중에 언제든 다시 발생할 수 있습니다. 기울기 소실이나 폭주를 예방하는 또 다른 방법은 배치 정규화(Batch Normalization)입니다. 배치 정규화는 인공 신경망의 각 층에 들어가는 입력을 평균과 분산으로 정규화하여 학습을 효율적으로 만듭니다.

 

📝내부 공변량 변화

딥러닝 모델의 학습 도중, 앞쪽 레이어의 파라미터가 조금만 바뀌어도 뒤쪽 레이어에 전달되는 입력값의 분포가 계속 바뀌는 현상으로 이걸 해결 하기 위해 배치 정규화 같은 과정을 하게 되어 입력값을 고르게 가져갈 수 있게 합니다.

 

 

📝 층 정규화

배치정규화

배치 정규화

 

층정규화

층정규화

배치 정규화는 각 특성에 대한 스케일 조절을 통한 정규화 과정이지만 층 정규화의 경우 하나의 샘플에 대한 정규화 과정입니다.

뒤에 배울 RNN, 트랜스포머등에 적합합니다.

 

 

 

📝평균, 분산, 표준편차

평균 (Mean) 모든 값을 더해서 개수로 나눈 값 점수 평균이 80점
분산 (Variance) 값들이 평균에서 얼마나 퍼져 있는지의 제곱된 평균 거리 평균에서 멀수록 분산 ↑
표준편차 (Std) 분산의 제곱근. 퍼짐 정도를 원래 단위로 표현 분산이 25면, 표준편차는 5

 

표준편차의 경우 사람이 들었을 때 더 와닿을 수 있는 표현 방식이다.

 

📝정규화를 하는 이유

나이 연봉
22 170 2500
45 180 8000
나이와 키와 연봉의 상관관계를 구하는데 정규화를 하지 않으면 연봉이 다른 모델에 지배적인 영향을 끼춥니다. Z 정규화 후에는 비교가 공평해지고 더 높은 특성에는 더 높은 가중치가 들어가게 됩니다.
 
 
또다른 예를 들면 시험에서 어떤 과목은 100점, 어떤 과목은 1000점 만점이라면 총점 기준이라면 1000점짜리가 항상 더 중요해 보이게 되기 때문이다.

 

정규화를 한다고 정규분포를 만드는 게 아니라 스케일 작업을 통해 평균을 0, 분산을 1로 고정시킵니다.

 

 

🔗 참고 및 출처

https://wikidocs.net/book/2155

 

 

 

 

반응형
반응형

📝활성화 함수(Activation Function)

앞서 배운 퍼셉트론에서는 계단 함수(Step function)를 통해 출력값이 0이 될지, 1이 될지를 결정했습니다. 이러한 매커니즘은 실제 뇌를 구성하는 신경 세포 뉴런이 전위가 일정치 이상이 되면 시냅스가 서로 화학적으로 연결되는 모습을 모방한 것입니다. 이렇게 은닉층과 출력층의 뉴런에서 출력값을 결정하는 함수 활성화 함수(Activation function)라고 하는데 계단 함수는 이러한 활성화 함수의 하나의 예제에 불과합니다.

 

비선형 함수(Nonlinear function)

비선형 함수는 직선 1개로는 그릴 수 없는 함수를 말합니다. 예를 들면 f(x) = wx + b라는 선형 함수가 있는데 이걸 은닉층에 여러개를 써도 복잡한 형태를 학습할 수 없습니다. 해당 선형 함수를 은닉층 두번 거치면 이런 합성함수로 표현할 수 있는데 f(f(x)) = w(wx + b) + b 형태라 이것도 결국에는 선형함수입니다. 그렇기 때문에 비선형 함수여야합니다. 물론 간단하거나 필요한 상황에는 쓰긴 써야합니다.

 

📝계단 함수(Step function)

def step(x):
    return np.array(x > 0, dtype=np.int)
x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = step(x)
plt.title('Step Function')
plt.plot(x,y)
plt.show()

계단 함수는 거의 사용되지 않지만 처음 배울 때 접하게 되는 활성화 함수입니다.

 

 

 

 

📝하이퍼볼릭탄젠트 함수(Hyperbolic tangent function)

 

 

x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = np.tanh(x)

plt.plot(x, y)
plt.plot([0,0],[1.0,-1.0], ':')
plt.axhline(y=0, color='orange', linestyle='--')
plt.title('Tanh Function')
plt.show()

하이퍼볼릭탄젠트 함수는 시그모이드 함수와 비슷한데 미분했을 때 시그모이드 함수보다는 전반적으로 큰 값이 나오게 됩니다. 그래서 시그모이드 함수보다는 기울기 소실 증상이 적은 편이며 은닉층에서 시그모이드 함수보다는 선호됩니다.

 

 

 

 

📝렐루 함수(ReLU)

def relu(x):
    return np.maximum(0, x)

x = np.arange(-5.0, 5.0, 0.1)
y = relu(x)

plt.plot(x, y)
plt.plot([0,0],[5.0,0.0], ':')
plt.title('Relu Function')
plt.show()

인공 신경망의 은닉층에서 가장 인기있는 함수입니다. 수식은 f(x)=max(0,x)로 아주 간단합니다. 렐루 함수는 음수를 입력하면 0을 출력하고, 양수를 입력하면 입력값을 그대로 반환하는 것이 특징인 함수로 출력값이 특정 양수값에 수렴하지 않습니다. 0이상의 입력값의 경우에는 미분값이 항상 1입니다. 깊은 신경망의 은닉층에서 시그모이드 함수보다 훨씬 더 잘 작동합니다. 뿐만 아니라, 렐루 함수는 시그모이드 함수와 하이퍼볼릭탄젠트 함수와 같이 어떤 연산이 필요한 것이 아니라 단순 임계값이므로 연산 속도도 빠릅니다.

 

하지만 여전히 문제점이 존재하는데, 입력값이 음수면 기울기. 즉, 미분값도 0이 됩니다. 그리고 이 뉴런은 다시 회생하는 것이 매우 어렵습니다. 이 문제를 죽은 렐루(dying ReLU)라고 합니다.

 

📝리키 렐루(Leaky ReLU)

a = 0.1

def leaky_relu(x):
    return np.maximum(a*x, x)

x = np.arange(-5.0, 5.0, 0.1)
y = leaky_relu(x)

plt.plot(x, y)
plt.plot([0,0],[5.0,0.0], ':')
plt.title('Leaky ReLU Function')
plt.show()

죽은 렐루를 보완하기 위해 ReLU의 변형 함수들이 등장하기 시작했습니다. 변형 함수는 여러 개가 있지만 여기서는 Leaky ReLU에 대해서만 소개합니다. Leaky ReLU는 입력값이 음수일 경우에 0이 아니라 0.001과 같은 매우 작은 수를 반환하도록 되어있습니다. 수식은 f(x)=max(ax,x)로 아주 간단합니다

 

 

📝소프트맥스 함수(Softmax function)

x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = np.exp(x) / np.sum(np.exp(x))

plt.plot(x, y)
plt.title('Softmax Function')
plt.show()

은닉층에서는 ReLU(또는 ReLU 변형) 함수들을 사용하는 것이 일반적입니다. 반면, 소프트맥스 함수는 시그모이드 함수처럼 출력층에서 주로 사용됩니다. 시그모이드 함수가 두 가지 선택지 중 하나를 고르는 이진 분류 (Binary Classification) 문제에 사용된다면 소프트맥스 함수는 세 가지 이상의 (상호 배타적인) 선택지 중 하나를 고르는 다중 클래스 분류(MultiClass Classification) 문제에 주로 사용됩니다.

 

 

🔗 참고 및 출처

https://www.startupcode.kr/1ea8ea02-a0ec-4a00-bb48-d50f65b27f06

https://wikidocs.net/24958

반응형
반응형

📝인공신경망 처리 과정

인공 신경망은 입력에 대해서 순전파(forward propagation) 연산을 하고, 그리고 순전파 연산을 통해 나온 예측값과 실제값의 오차를 손실 함수(loss function)을 통해 계산하고, 그리고 이 손실(오차)을 미분을 통해서 기울기(gradient)를 구하고, 이를 통해 출력층에서 입력층 방향으로 가중치와 편향을 업데이트 하는 과정인 역전파(back propagation)를 수행합니다.

 

 

📝 순전파

 

활성화 함수, 은닉층의 수, 각 은닉층의 뉴런 수 등 딥 러닝 모델을 설계하고나면 입력값은 입력층, 은닉층을 지나면서 각 층에서의 가중치와 함께 연산되며 출력층으로 향합니다. 그리고 출력층에서 모든 연산을 마친 예측값이 나오게 됩니다. 이와 같이 입력층에서 출력층 방향으로 예측값의 연산이 진행되는 과정을 순전파라고 합니다.

 

 

예제

입력의 차원이 3, 출력의 차원이 2인 위 인공 신경망으로 되어있습니다.

 

w1~w6 과 b1,b2 총 8개의 매개변수를 가지게 됩니다.

각 입력(특징)은 서로 다른 가중치를 거쳐서 y라는 결과를 만들어지게 됩니다.

 

이걸 일상생활에 대입하면 코, 입, 얼굴 이라는 3개의 특징을 넣어서 y1인 고양이일 확률 y2인 강아지일 확률에 대해서 출력하는 걸로 정의 할 수 있습니다.

 

 

병렬로 처리하면 연산이 빨리 처리 되기 때문에 이런식으로 활용할 수 있습니다.

이렇게 인공 신경망이 다수의 샘플을 동시에 처리하는 것을 우리는 '배치 연산'이라고 부릅니다.

 

 

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()

# 4개의 입력과 8개의 출력
model.add(Dense(8, input_dim=4, activation='relu'))

# 이어서 8개의 출력
model.add(Dense(8, activation='relu'))

# 이어서 3개의 출력
model.add(Dense(3, activation='softmax'))

코드로 표현하면 4개의 입력이 있고 렐루를 거쳐서 비선형을 만들며 8개의 출력을 가지게 됩니다.

 

 

 

 

📝 역전

순전파를 통해서 나온 결과가 마음에 안 들 때 결과를 재조정하기 위해서 가중치와 절편을 업데이트해야하는데 그 과정을 역전파라고합니다. 

 

 

 

 

📝 손실함수

역전파에 사용되며 실제값하고 예측값하고의 차이를 알아내기 위해 손실함수를 이용합니다.

가중치 하나당 손실함수를 통해 나오는 손실값이 1개이고 역전파를 거치며 가중치 수정하면서 그래프 처럼 그리면 위와 같습니다. 최적의 가중치는 손실값이 작은 값이여야하기 때문에 이걸 찾아내기 위해 여러번 반복(역전파)합니다.

 

문제 유형 출력층 형태 활성화 함수 손실 함수
회귀 (Regression) 1개 실수값 없음 또는 선형 MSE (Mean Squared Error)
이진 분류 (Binary Classification) 1개 확률값 시그모이드(sigmoid) Binary Cross-Entropy
다중 클래스 분류 (Multiclass Classification) 클래스 수만큼 소프트맥스(softmax) Categorical Cross-Entropy
다중 레이블 분류 (Multi-label) 각 클래스마다 예/아니오 시그모이드(sigmoid) Binary Cross-Entropy (각 클래스마다 따로 계산)

대부분의 손실함수는 정해져있는 편입니다.

 

 

📝 옵티마이저 (모멘텀)

손실함수를 통해 가장 최적의 가중치를 구하기 위해 반복합니다. 가중치를 변화시켜가며 손실값이 가장 적은 값을 구하는 것입니다. 손실값이 가장 적다는 건 가장 이상적인 것이라 판단합니다.

 

글로벌 미니멈이 가장 최적의 값이지만 로컬 미니멈의 경우 도달했을 때 이게 최적의 값인줄 알고 탈출하지 못하는 상황에서 관성(모멘텀)을 이용해 로컬 미니멈을 탈출해 더 낮은 미니멈을 찾을 수 있는 효과를 얻을 수 있습니다.

 

 

📝 옵티마이저 (아다그라드)

서로 다른 매개변수에 서로 다른 학습률을 적용시킵니다. 변화가 많은 매개변수는 학습률이 작게 설정되며 변화가 적은 매개변수는 학습률을 높게 설정시킵니다.

 

📝 옵티마이저 (알엠에스프롭)

아다그라드의 경우 학습을 계속 진행한 경우에는 나중에 가서 학습률이 지나치게 떨어지는 단점이 있는데 이를 대체하여 단점을 개선했습니다.

 

📝 옵티마이저 (아담)

알엠에스프롭과 모멘텀 두가지를 합친 방법으로 방향과 학습률 두 가지를 모두 잡기 위한 방법으로 가장 많이 쓰인다.

 

 

 

📝기울기 소실

역전파 과정에서 입력층으로 갈수록 기울기(Gradient)가 점차적으로 작아지는 현상이 발생할 수 있습니다. 입력층에 가까운 층들에서 가중치들이 업데이트가 제대로 되지 않으면 결국 최적의 모델을 찾을 수 없게 됩니다. 이를 기울기 소실(Gradient Vanishing) 이라고 합니다.

 

기울기 소실을 완화하는 가장 간단한 방법은 은닉층의 활성화 함수로 시그모이드나 하이퍼볼릭탄젠트 함수 대신에 ReLU나 ReLU의 변형 함수와 같은 Leaky ReLU를 사용하는 것입니다.

  • 은닉층에서는 시그모이드 함수를 사용하지 마세요.
  • Leaky ReLU를 사용하면 모든 입력값에 대해서 기울기가 0에 수렴하지 않아 죽은 ReLU 문제를 해결합니다.
  • 은닉층에서는 ReLU나 Leaky ReLU와 같은 ReLU 함수의 변형들을 사용하세요.

 

# 시그모이드 함수 그래프를 그리는 코드
def sigmoid(x):
    return 1/(1+np.exp(-x))
x = np.arange(-5.0, 5.0, 0.1)
y = sigmoid(x)

plt.plot(x, y)
plt.plot([0,0],[1.0,0.0], ':') # 가운데 점선 추가
plt.title('Sigmoid Function')
plt.show()

 

시그모이드 함수의 출력값이 0 또는 1에 가까워지면, 그래프의 기울기가 완만해지는 모습을 볼 수 있습니다. 기울기가 완만해지는 구간을 주황색, 그렇지 않은 구간을 초록색으로 칠해보겠습니다.

 

주황색 구간에서는 미분값이 0에 가까운 아주 작은 값입니다. 초록색 구간에서의 미분값은 최대값이 0.25입니다. 다시 말해 시그모이드 함수를 미분한 값은 적어도 0.25 이하의 값입니다. 시그모이드 함수를 활성화 함수로하는 인공 신경망의 층을 쌓는다면, 가중치와 편향을 업데이트 하는 과정인 역전파 과정에서 0에 가까운 값이 누적해서 곱해지게 되면서, 앞단에는 기울기(미분값)가 잘 전달되지 않게 됩니다. 이러한 현상을 기울기 소실(Vanishing Gradient) 문제라고 합니다.

 

시그모이드 함수를 사용하는 은닉층의 개수가 다수가 될 경우에는 0에 가까운 기울기가 계속 곱해지면 앞단에서는 거의 기울기를 전파받을 수 없게 됩니다. 다시 말해 매개변수 w가 업데이트 되지 않아 학습이 되지를 않습니다.

 

 

📝기울기 폭주

기울기가 점차 커지더니 가중치들이 비정상적으로 큰 값이 되면서 결국 발산되기도 합니다. 이를 기울기 폭주(Gradient Exploding) 라고 합니다.

 

 

📝가중치 초기화

입력값에 무작정 가중치를 대입하면서 찾아야하지만 무작정 가중치를 넣다가 기울기 소실이나 폭주가 일어날 수 있다. 이거를 효율적으로 처리하기 위해서 가중치 초기화 방법을 이용한다.

 

  • 세이비어 초기화(Xavier Initialization)
    • 이전 층과 다음 층의 뉴런 수를 고려해서, 각 층의 출력값들이 너무 커지거나 작아지지 않도록 초기화합니다.
    • 시그모이드(sigmoid), tanh 같은 S자 함수에 잘 맞습니다.
  • He 초기화(He initialization)
    • ReLU는 음수 다 죽이니까, 이전 층 뉴런 수만 고려해서 더 크게 분산을 준다 → 0으로 죽은 놈들은 어쩔 수 없지만 남아있는 애들에게 가중치를 더 크게 주어서 의미를 살린다는 의미이다.
    • ReLU 계열 함수 (ReLU, LeakyReLU 등)에 잘 맞습니다.

 

 

 

📝과적합 막는 방법

데이터 양을 늘리기

데이터 양이 적은 경우 데이터 특정 패턴이나 노이즈까지 쉽게 암기가 되기 때문에 과적합 현상이 발생할 확률이 높습니다.

 

데이터 양이 적은 경우 의도적 기존 데이터를 변형해 데이터 양을 늘리는 이러한 걸 데이터 증식 또는 증강이라고 합니다. 텍스트 데이터의 경우 번역 후 재 번역을 통해 새로운 데이터를 만들어내는 역번역 등이 있습니다.

 

모델 복잡도 줄이기

신경망은 복잡도는 은닉층과 매개변수 등으로 결정되는데 해당 신경망의 복잡도를 줄입니다.

 

가중치 규제 적용

복잡한 모델이 간단한 모델보다 과적합될 가능성이 높습니다. 복잡한 모델의 경우 간단한 방법으로 바꾸는 방법으로는 가중치 규제가 있습니다.

 

  • L1 규제
    • 중치 w들의 절대값 합계를 비용 함수에 추가합니다. L1 노름이라고도 합니다.
    • 예를 들면 가중치를 죽여서 어떤 특성은 아예 비활성합니다.
  • L2 규제
    • 모든 가중치 w들의 제곱합을 비용 함수에 추가합니다. L2 노름이라고도 합니다.
    • 예를 들면 가중치를 전체적으로 약하게 줘버립니다.

 

 

 

 

드롭아웃

드롭아웃은 학습 과정에서 신경망의 일부를 사용하지 않는 방법입니다. 예를 들어 드롭아웃의 비율을 0.5로 한다면 학습 과정마다 랜덤으로 절반의 뉴런을 사용하지 않고, 절반의 뉴런만을 사용합니다. 그러다 테스트 할 때는 전부 켜서 테스트를 합니다. 매번 학습할 때마다 뉴런이 랜덤으로 꺼지고 켜지고 하기 때문에 과적합 방법을 방지합니다.

 

 

 

반응형
반응형

📝퍼셉트론(Perceptron)

퍼셉트론(Perceptron)은 프랑크 로젠블라트(Frank Rosenblatt)가 1957년에 제안한 초기 형태의 인공 신경망으로 다수의 입력으로부터 하나의 결과를 내보내는 알고리즘입니다.

실제 뇌를 구성하는 신경 세포 뉴런의 동작과 유사한데, 신경 세포 뉴런의 그림을 먼저 보도록 하겠습니다. 뉴런은 가지돌기에서 신호를 받아들이고, 이 신호가 일정치 이상의 크기를 가지면 축삭돌기를 통해서 신호를 전달합니다.

 

다수의 입력을 받는 퍼셉트론의 그림을 보겠습니다. 신경 세포 뉴런의 입력 신호와 출력 신호가 퍼셉트론에서 각각 입력값과 출력값에 해당됩니다. 각각의 입력값에는 각각의 가중치가 존재하는데, 이때 가중치의 값이 크면 클수록 해당 입력 값이 중요하다는 것을 의미합니다.

 

가중치의 곱의 전체 합이 임계치(threshold)를 넘으면 종착지에 있는 인공 뉴런은 출력 신호로서 1을 출력하고, 그렇지 않을 경우에는 0을 출력합니다.

 

📝단층 퍼셉트론(Single-Layer Perceptron)

위에서 배운 퍼셉트론을 단층 퍼셉트론이라고 합니다. 퍼셉트론은 단층 퍼셉트론과 다층 퍼셉트론으로 나누어지는데, 단층 퍼셉트론은 값을 보내는 단계과 값을 받아서 출력하는 두 단계로만 이루어집니다.

이 각 단계를 보통 층(layer)이라고 부르며, 이 두 개의 층을 입력층(input layer)과 출력층(output layer)입니다.

그렇기 때문에 복잡한 건 표현할 수 없습니다.

 

📝다층 퍼셉트론(MultiLayer Perceptron, MLP)

퍼셉트론 관점에서 말하면 층을 더 쌓으면 만들 수 있습니다. 다층 퍼셉트론과 단층 퍼셉트론의 차이는 단층 퍼셉트론은 입력층과 출력층만 존재하지만, 다층 퍼셉트론은 중간에 층을 더 추가하였다는 점입니다. 이렇게 입력층과 출력층 사이에 존재하는 층을 은닉층(hidden layer)이라고 합니다.

 

 

📝피드 포워드 신경망(Feed-Forward Neural Network, FFNN)

다층 퍼셉트론(MLP)과 같이 오직 입력층에서 출력층 방향으로 연산이 전개되는 신경망을 피드 포워드 신경망(Feed-Forward Neural Network, FFNN)이라고 합니다.

 

📝전결합층

전결합층의 경우 학습을 통해 벡터를 다른 벡터로 변환하는 역할로 즉, 학습과정을 의미합니다. 입력은 실수 벡터가 들어가며 출력은 가중치 x 입력 + 바이어스 + 활성화 함수로 만들어집니다.

 

 

🔗 참고 및 출처

https://wikidocs.net/24958

https://wikidocs.net/24987

 

 

반응형
반응형

📝 경사 하강법

배치는 가중치 등의 매개 변수의 값을 조정하기 위해 사용하는 데이터의 양을 말합니다. 전체 데이터를 가지고 매개 변수의 값을 조정할 수도 있고, 정해준 양의 데이터만 가지고도 매개 변수의 값을 조정할 수 있습니다.

 

📝 배치 경사 하강법

배치 경사 하강법(Batch Gradient Descent)은 가장 기본적인 경사 하강법입니다. 딥 러닝에서는 전체 데이터에 대한 한 번의 훈련 횟수1에포크라고 하는데, 배치 경사 하강법은 한 번의 에포크에 모든 매개변수 업데이트를 단 한 번 수행합니다. 

  • 1000개 데이터가 있으면 1000개 데이터의 순전파 → 손실 평균 계산 → 역전파 → 업데이트 1회

 

 

📝 배치 크기가 1인 확률적 경사 하강법(Stochastic Gradient Descent, SGD)

기존의 배치 경사 하강법은 전체 데이터에 대해서 계산을 하다보니 시간이 너무 오래걸린다는 단점이 있습니다. 배치 크기가 1인 확률적 경사 하강법은 매개변수 값을 조정 시 전체 데이터가 아니라 랜덤으로 선택한 하나의 데이터에 대해서만 계산하는 방법입니다. 더 적은 데이터를 사용하므로 더 빠르게 계산할 수 있습니다.

  • 1000개 데이터가 있으면 1개 데이터의 순전파 → 손실 계산 → 역전파 → 업데이트 이러한 행위를 1000번 반복

 

 

📝 미니 배치 경사 하강법(Mini-Batch Gradient Descent)

model.fit(X_train, y_train, batch_size=128)

전체 데이터도, 1개의 데이터도 아닐 때, 배치 크기를 지정하여 해당 데이터 개수만큼에 대해서 계산하여 매개 변수의 값을 조정하는 경사 하강법을 미니 배치 경사 하강법이라고 합니다. 미니 배치 경사 하강법은 전체 데이터를 계산하는 것보다 빠르며, SGD보다 안정적이라는 장점이 있습니다. 가장 많이 사용되는 경사 하강법입니다

  • 1000개 데이터가 있으면 정해둔 배치 사이즈 데이터의 순전파 → 손실 평균 계산 → 역전파 → 업데이트 배치 사이즈 만큼 업데이트 후 1000개 데이터 다 처리할 때까지 반복

 

📝에포크

에포크란 인공 신경망에서 전체 데이터에 대해서 순전파와 역전파가 끝난 상태를 말합니다. 전체 데이터를 하나의 문제지에 비유한다면 문제지의 모든 문제를 끝까지 다 풀고, 정답지로 채점을 하여 문제지에 대한 공부를 한 번 끝낸 상태를 말합니다. 에포크가 50이라고 하면, 전체 데이터 단위로는 총 50번 학습합니다. 문제지에 비유하면 문제지를 50번 푼 셈입니다. 이 에포크 횟수가 지나치거나 너무 적으면 앞서 배운 과적합과 과소적합이 발생할 수 있습니다.

 

📝배치 크기(Batch size)

배치 크기는 몇 개의 데이터 단위로 매개변수를 업데이트 하는지를 말합니다. 현실에 비유하면 문제지에서 몇 개씩 문제를 풀고나서 정답지를 확인하느냐의 문제입니다. 사람은 문제를 풀고 정답을 보는 순간 부족했던 점을 깨달으며 지식이 업데이트 된다고 하였습니다. 기계 입장에서는 실제값과 예측값으로부터 오차를 계산하고 옵티마이저가 매개변수를 업데이트합니다. 여기서 중요한 포인트는 업데이트가 시작되는 시점이 정답지/실제값을 확인하는 시점이라는 겁니다.

 

 

📝이터레이션(Iteration) 또는 스텝(Step)

이터레이션이란 한 번의 에포크를 끝내기 위해서 필요한 배치의 수를 말합니다. 또는 한 번의 에포크 내에서 이루어지는 매개변수의 업데이트 횟수이기도 합니다. 전체 데이터가 2,000일 때 배치 크기를 200으로 한다면 이터레이션의 수는 총 10입니다. 이는 한 번의 에포크 당 매개변수 업데이트가 10번 이루어진다는 것을 의미합니다. 배치 크기가 1인 확률적 경사 하강법을 이 개념을 가지고 다시 설명하면 배치 크기가 1이므로 모든 이터레이션마다 하나의 데이터를 선택하여 경사 하강법을 수행합니다. 이터레이션은 스텝(Step)이라고 부르기도 하므로 두 용어 모두 기억해둡시다.

 

 

📝 옵티마이저 (모멘텀)

손실함수를 통해 가장 최적의 가중치를 구하기 위해 반복합니다. 가중치를 변화시켜가며 손실값이 가장 적은 값을 구하는 것입니다. 손실값이 가장 적다는 건 가장 이상적인 것이라 판단합니다.

 

글로벌 미니멈이 가장 최적의 값이지만 로컬 미니멈의 경우 도달했을 때 이게 최적의 값인줄 알고 탈출하지 못하는 상황에서 관성(모멘텀)을 이용해 로컬 미니멈을 탈출해 더 낮은 미니멈을 찾을 수 있는 효과를 얻을 수 있습니다.

 

 

📝 옵티마이저 (아다그라드)

서로 다른 매개변수에 서로 다른 학습률을 적용시킵니다. 변화가 많은 매개변수는 학습률이 작게 설정되며 변화가 적은 매개변수는 학습률을 높게 설정시킵니다.

 

 

📝 옵티마이저 (알엠에스프롭)

아다그라드의 경우 학습을 계속 진행한 경우에는 나중에 가서 학습률이 지나치게 떨어지는 단점이 있는데 이를 대체하여 단점을 개선했습니다.

 

 

📝 옵티마이저 (아담)

알엠에스프롭과 모멘텀 두가지를 합친 방법으로 방향과 학습률 두 가지를 모두 잡기 위한 방법으로 가장 많이 쓰인다.

 

 

 

🔗 참고 및 출처

https://wikidocs.net/36033

 

 

 

 

 

 

반응형
반응형

📝활성화 함수(Activation Function)

앞서 배운 퍼셉트론에서는 계단 함수(Step function)를 통해 출력값이 0이 될지, 1이 될지를 결정했습니다. 이러한 매커니즘은 실제 뇌를 구성하는 신경 세포 뉴런이 전위가 일정치 이상이 되면 시냅스가 서로 화학적으로 연결되는 모습을 모방한 것입니다. 이렇게 은닉층과 출력층의 뉴런에서 출력값을 결정하는 함수활성화 함수(Activation function)라고 하는데 계단 함수는 이러한 활성화 함수의 하나의 예제에 불과합니다.

 

비선형 함수(Nonlinear function)

비선형 함수는 직선 1개로는 그릴 수 없는 함수를 말합니다. 예를 들면 f(x) = wx + b라는 선형 함수가 있는데 이걸 은닉층에 여러개를 써도 복잡한 형태를 학습할 수 없습니다. 해당 선형 함수를 은닉층 두번 거치면 이런 합성함수로 표현할 수 있는데 f(f(x)) = w(wx + b) + b 형태라 이것도 결국에는 선형함수입니다. 그렇기 때문에 비선형 함수여야합니다. 물론 간단하거나 필요한 상황에는 쓰긴 써야합니다.

 

📝계단 함수(Step function)

def step(x):
    return np.array(x > 0, dtype=np.int)
x = np.arange(-5.0, 5.0, 0.1) # -5.0부터 5.0까지 0.1 간격 생성
y = step(x)
plt.title('Step Function')
plt.plot(x,y)
plt.show()

계단 함수는 거의 사용되지 않지만 처음 배울 때 접하게 되는 활성화 함수입니다.

 

 

📝인경신경망 처리 과정

인공 신경망은 입력에 대해서 순전파(forward propagation) 연산을 하고, 그리고 순전파 연산을 통해 나온 예측값과 실제값의 오차를 손실 함수(loss function)을 통해 계산하고, 그리고 이 손실(오차)을 미분을 통해서 기울기(gradient)를 구하고, 이를 통해 출력층에서 입력층 방향으로 가중치와 편향을 업데이트 하는 과정인 역전파(back propagation)를 수행합니다.

 

 

📝 순전파

 

활성화 함수, 은닉층의 수, 각 은닉층의 뉴런 수 등 딥 러닝 모델을 설계하고나면 입력값은 입력층, 은닉층을 지나면서 각 층에서의 가중치와 함께 연산되며 출력층으로 향합니다. 그리고 출력층에서 모든 연산을 마친 예측값이 나오게 됩니다. 이와 같이 입력층에서 출력층 방향으로 예측값의 연산이 진행되는 과정을 순전파라고 합니다.

 

 

예제

입력의 차원이 3, 출력의 차원이 2인 위 인공 신경망으로 되어있습니다.

 

w1~w6 과 b1,b2 총 8개의 매개변수를 가지게 됩니다.

각 입력(특징)은 서로 다른 가중치를 거쳐서 y라는 결과를 만들어지게 됩니다.

 

이걸 일상생활에 대입하면 코, 입, 얼굴 이라는 3개의 특징을 넣어서 y1인 고양이일 확률 y2인 강아지일 확률에 대해서 출력하는 걸로 정의 할 수 있습니다.

 

 

병렬로 처리하면 연산이 빨리 처리 되기 때문에 이런식으로 활용할 수 있습니다.

이렇게 인공 신경망이 다수의 샘플을 동시에 처리하는 것을 우리는 '배치 연산'이라고 부릅니다.

 

 

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model = Sequential()

# 4개의 입력과 8개의 출력
model.add(Dense(8, input_dim=4, activation='relu'))

# 이어서 8개의 출력
model.add(Dense(8, activation='relu'))

# 이어서 3개의 출력
model.add(Dense(3, activation='softmax'))

코드로 표현하면 4개의 입력이 있고 렐루를 거쳐서 비선형을 만들며 8개의 출력을 가지게 됩니다.

 

 

 

 

📝 역전

순전파를 통해서 나온 결과가 마음에 안 들 때 결과를 재조정하기 위해서 가중치와 절편을 업데이트해야하는데 그 과정을 역전파라고합니다. 

 

 

 

 

📝 손실함수

실제값하고 예측값하고의 차이를 알아내기 위해 손실함수를 이용합니다. (역전파에 사용)

가중치를 업데이트하려면 미분이 가능해야합니다.

 

문제 유형 출력층 형태 활성화 함수 손실 함수
회귀 (Regression) 1개 실수값 없음 또는 선형 MSE (Mean Squared Error)
이진 분류 (Binary Classification) 1개 확률값 시그모이드(sigmoid) Binary Cross-Entropy
다중 클래스 분류 (Multiclass Classification) 클래스 수만큼 소프트맥스(softmax) Categorical Cross-Entropy
다중 레이블 분류 (Multi-label) 각 클래스마다 예/아니오 시그모이드(sigmoid) Binary Cross-Entropy (각 클래스마다 따로 계산)

대부분의 손실함수는 정해져있는 편입니다.

 

 

 

📝과적합 막는 방법

데이터 양을 늘리기

데이터 양이 적은 경우 데이터 특정 패턴이나 노이즈까지 쉽게 암기가 되기 때문에 과적합 현상이 발생할 확률이 높습니다.

 

데이터 양이 적은 경우 의도적 기존 데이터를 변형해 데이터 양을 늘리는 이러한 걸 데이터 증식 또는 증강이라고 합니다. 텍스트 데이터의 경우 번역 후 재 번역을 통해 새로운 데이터를 만들어내는 역번역 등이 있습니다.

 

모델 복잡도 줄이기

신경망은 복잡도는 은닉층과 매개변수 등으로 결정되는데 해당 신경망의 복잡도를 줄입니다.

 

가중치 규제 적용

복잡한 모델이 간단한 모델보다 과적합될 가능성이 높습니다. 복잡한 모델의 경우 간단한 방법으로 바꾸는 방법으로는 가중치 규제가 있습니다.

 

  • L1 규제
    • 중치 w들의 절대값 합계를 비용 함수에 추가합니다. L1 노름이라고도 합니다.
    • 예를 들면 가중치를 죽여서 어떤 특성은 아예 비활성합니다.
  • L2 규제
    • 모든 가중치 w들의 제곱합을 비용 함수에 추가합니다. L2 노름이라고도 합니다.
    • 예를 들면 가중치를 전체적으로 약하게 줘버립니다.

 

 

 

 

드롭아웃

드롭아웃은 학습 과정에서 신경망의 일부를 사용하지 않는 방법입니다. 예를 들어 드롭아웃의 비율을 0.5로 한다면 학습 과정마다 랜덤으로 절반의 뉴런을 사용하지 않고, 절반의 뉴런만을 사용합니다. 그러다 테스트 할 때는 전부 켜서 테스트를 합니다. 매번 학습할 때마다 뉴런이 랜덤으로 꺼지고 켜지고 하기 때문에 과적합 방법을 방지합니다.

 

 

🔗 참고 및 출처

https://www.startupcode.kr/1ea8ea02-a0ec-4a00-bb48-d50f65b27f06

https://wikidocs.net/24958

 

 

 

 

 

 

 

반응형
반응형

📝2개 이상 변수 이중 선형 회귀

딥러닝 챕터로 들어가게되면 대부분의 입력들은 독립 변수가 2개 이상입니다.

Midterm(x1) Final(x2) Added point(x3) Score($1000)(y)
70 85 11 73
71 89 18 82
50 80 20 72
99 20 10 57
50 10 10 34
20 99 10 58
40 50 20 56

 

import numpy as np
import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras import optimizers

# 중간 고사, 기말 고사, 가산점 점수
X = np.array([[70,85,11], [71,89,18], [50,80,20], [99,20,10], [50,10,10]])
y = np.array([73, 82 ,72, 57, 34]) # 최종 성적


model = Sequential()
# 입력 차원 설정 (3으로 변경)
model.add(Dense(1, input_dim=3, activation='linear'))

sgd = optimizers.SGD(learning_rate=0.0001)
model.compile(optimizer=sgd, loss='mse', metrics=['mse'])
model.fit(X, y, epochs=2000)

print(model.predict(X))

X_test = np.array([[20,99,10], [40,50,20]])
print(model.predict(X_test))

 

📝2개 이상 변수 로지스틱 회귀


y를 결정하는데 있어 독립 변수 x가 2개인 로지스틱 회귀를 풀어봅시다. 꽃받침(Sepal)의 길이와 꽃잎(Petal)의 길이와 해당 꽃이 A인지 B인지가 적혀져 있는 데이터가 있을 때, 새로 조사한 꽃받침의 길이와 꽃잎의 길이로부터 무슨 꽃인지 예측할 수 있는 모델을 만들고자 한다면 이때 독립 변수 x는 2개가 됩니다.

 

 

import numpy as np
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

X = np.array([[0, 0], [0, 1], [1, 0], [0, 2], [1, 1], [2, 0]])
y = np.array([0, 0, 0, 1, 1, 1])

model = Sequential()
model.add(Dense(1, input_dim=2, activation='sigmoid'))
model.compile(optimizer='sgd', loss='binary_crossentropy', metrics=['binary_accuracy'])

model.fit(X, y, epochs=2000)
print(model.predict(X))
# [
#  [0.15245897]
#  [0.4477718 ]
#  [0.43305928]
#  [0.7851759 ]
#  [0.7749343 ]
#  [0.764351  ]
# ]

 

 

다중 로지스틱 회귀를 인공 신경망의 형태로 표현하면 다음과 같습니다. 아직 인공 신경망을 배우지 않았음에도 이렇게 다이어그램으로 표현해보는 이유는 로지스틱 회귀를 일종의 인공 신경망 구조로 해석해도 무방함을 보여주기 위함입니다.

 

 

📝텐서, 벡터

1차원배열 또는 리스트로 표현합니다. 반면, 행렬은 행과 열을 가지는 2차원 형상을 가진 구조입니다. 파이썬에서는 2차원 배열로 표현합니다. 가로줄을 행(row)라고 하며, 세로줄을 열(column)이라고 합니다. 3차원부터는 주로 텐서라고 부릅니다. 텐서는 파이썬에서는 3차원 이상의 배열로 표현합니다.

 

 

0차원 텐서(스칼라)

d = np.array(5)
print('텐서의 차원 :',d.ndim)
print('텐서의 크기(shape) :',d.shape)
# 텐서의 차원 : 0
# 텐서의 크기(shape) : ()

스칼라는 하나의 실수값으로 이루어진 데이터를 말합니다. 이를 0차원 텐서라고 합니다. 차원을 영어로 Dimension이라고 하므로 0D 텐서라고도 합니다.

 

1차원 텐서(벡터)

d = np.array([1, 2, 3, 4])
print('텐서의 차원 :',d.ndim)
print('텐서의 크기(shape) :',d.shape)
# 텐서의 차원 : 1
# 텐서의 크기(shape) : (4,)

벡터는 1차원 텐서입니다. 주의할 점은 벡터에서도 차원이라는 용어를 쓰는데, 벡터의 차원과 텐서의 차원은 다른 개념이라는 점입니다. 위 예제는 4차원 벡터이지만, 1차원 텐서입니다. 1D 텐서라고도 합니다. 참고로 벡터는 1차 텐서에서만 쓰이는 말입니다. → [1,2,3] 일 경우 3차원 벡터이며 x,y,z좌표로 표현한 거라 생각하면 된다.

 

2차원 텐서(행렬)

# 3행 4열의 행렬
d = np.array([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])
print('텐서의 차원 :',d.ndim)
print('텐서의 크기(shape) :',d.shape)
# 텐서의 차원 : 2
# 텐서의 크기(shape) : (3, 4)

행과 열이 존재하는 벡터의 배열. 즉, 행렬(matrix)을 2차원 텐서라고 합니다. 2D 텐서라고도 합니다. 텐서의 크기란, 각 축을 따라서 얼마나 많은 차원이 있는지를 나타낸 값입니다. 텐서의 크기를 바로 머릿속으로 떠올릴 수 있으면 모델 설계 시에 유용합니다. 

 

 

3차원 텐서(다차원 배열)

d = np.array([
            [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [10, 11, 12, 13, 14]],
            [[15, 16, 17, 18, 19], [19, 20, 21, 22, 23], [23, 24, 25, 26, 27]]
            ])
print('텐서의 차원 :',d.ndim)
print('텐서의 크기(shape) :',d.shape)
# 텐서의 차원 : 3
# 텐서의 크기(shape) : (2, 3, 5)

0차원 ~ 2차원 텐서는 각각 스칼라, 벡터, 행렬이라고 해도 무방하므로 3차원 이상의 텐서부터 본격적으로 텐서라고 부릅니다. 데이터 사이언스 분야 한정으로 주로 3차원 이상의 배열을 텐서라고 부른다고 이해해도 좋습니다. 이 3차원 텐서의 구조를 이해하지 않으면, 복잡한 인공 신경망의 입, 출력값을 이해하는 것이 쉽지 않습니다. 개념 자체는 어렵지 않지만 반드시 알아야하는 개념입니다.

 

 

3차원 텐서를 활용한 예제는 나중에 RNN을 배울텐데 그걸 이용해 대략적으로 알려드리면 아래와 같습니다.

  • 문서1  →  I like NLP
  • 문서2  →  I like DL
  • 문서3  →  DL is AI

 

3차원 텐서 예제

단어 One-hot vector
I [1 0 0 0 0 0]
like [0 1 0 0 0 0]
NLP [0 0 1 0 0 0]
DL [0 0 0 1 0 0]
is [0 0 0 0 1 0]
AI [0 0 0 0 0 1]
[[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 1, 0, 0, 0]],  
[[1, 0, 0, 0, 0, 0], [0, 1, 0, 0, 0, 0], [0, 0, 0, 1, 0, 0]],  
[[0, 0, 0, 1, 0, 0], [0, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 1]]]

컴퓨터는 이진수로 처리가능하기 때문에 이렇게 문자로 주어지면 모릅니다. 그리고 각 단어가 어떤 유사성을 가지고 있는지도 모르지만 이거를 원-핫 벡터를 이용해 벡터로 표현하면 위와 같고 (3,3,6)의 크기를 가지는 3D 텐서가 만들어집니다.

 

 

텐서 시각적 표현

 

 

📝벡터 덧셈과 뺄셈

 

A = np.array([8, 4, 5])
B = np.array([1, 2, 3])
print('두 벡터의 합 :',A+B)
print('두 벡터의 차 :',A-B)
# 두 벡터의 합 : [9 6 8]
# 두 벡터의 차 : [7 2 2]

 

 

📝행렬 덧셈과 뺄셈

A = np.array([[10, 20, 30, 40], [50, 60, 70, 80]])
B = np.array([[5, 6, 7, 8],[1, 2, 3, 4]])
print('두 행렬의 합 :')
print(A + B)
print('두 행렬의 차 :')
print(A - B)
# 두 행렬의 합 :
# [[15 26 37 48]
# [51 62 73 84]]
# 두 행렬의 차 :
# [[ 5 14 23 32]
# [49 58 67 76]]

 

 

📝벡터의 내적

A = np.array([1, 2, 3])
B = np.array([4, 5, 6])
print('두 벡터의 내적 :',np.dot(A, B))
# 두 벡터의 내적 : 32

 

📝행렬의 곱셈

A = np.array([[1, 3],[2, 4]])
B = np.array([[5, 7],[6, 8]])
print('두 행렬의 행렬곱 :')
print(np.matmul(A, B))
# 두 행렬의 행렬곱 :
# [[23 31]
# [34 46]]

 

 

📝다중선형 회귀 행렬 연산으로 이해하기

 

다중 선형 회귀

 

다중 선형 회귀 행렬 표현

다중 선형 회귀식을 행렬로 표현이 가능하다. 왜 이렇게 할까?

  1. 기본적으로 가독성이 좋아진다.
  2. 벡터화된 계산은 컴퓨터가 빨리 처리할 수 있습니다.
  3. 반복문 없이 한줄로 처리가 가능합니다.
# 내적 사용
import numpy as np

x = np.array([1.2, 0.7, 3.1])
w = np.array([0.5, 2.1, -1.3])
b = 0.2

y = np.dot(w, x) + b

# 내적 사용하지 않은 코드 (반복문)
x = [1.2, 0.7, 3.1]
w = [0.5, 2.1, -1.3]
b = 0.2

y = 0
for i in range(len(x)):
    y += w[i] * x[i]
y += b

 

 

행렬 연산 예제

size(feet2)(x1) number of bedrooms(x2) number of floors(x3) age of home(x4) price($1000)(y)
1800 2 1 10 207
1200 4 2 20 176
1700 3 2 15 213
1500 5 1 10 234
1100 2 2 10 155

 

가중치와 입력값을 곱하고 절편값 b를 더해 원하는 결과를 얻어낼 수 있습니다.

 

📝다중 클래스 분류(Multi-class Classification)

이진 분류가 두 개의 선택지 중 하나를 고르는 문제였다면, 세 개 이상의 선택지 중 하나를 고르는 문제를 다중 클래스 분류라고 합니다. 아래의 붓꽃 품종 예측 데이터는 꽃받침 길이, 꽃받침 넓이, 꽃잎 길이, 꽃잎 넓이로부터 setosa, versicolor, virginica라는 3개의 품종 중 어떤 품종인지를 예측하는 문제를 위한 데이터로 전형적인 다중 클래스 분류 문제를 위한 데이터입니다.

 

📝소프트맥스 함수(Softmax function)

 

소프트맥스 함수는 선택해야 하는 선택지의 총 개수를 k라고 할 때, k차원의 벡터를 입력받아 각 클래스에 대한 확률을 추정합니다. 꽃에 대한 분류를 할 때 4가지의 입력값을 받고 각 꽃의 특징에 따른 가중치를 받으며 Softmax함수를 거치면 그걸 0~1사이에 값으로 변환시켜줍니다. 오차로 인한 가중치화 편향을 업데이트하며 꽃에 해당하는 원-핫 벡터로 변경합니다.

 

문제 사항이 두가지가 있습니다.

  1. 변수는 4개지만 예측 클래스는 3개인 경우 차원을 축소시켜야합니다.
  2. 예측값으로부터 실제값에 대한 오차를 수정해서 실제값하고 동일하게 만들어야합니다.

 

1) 차원축소

x1, x2, x3, x4는 꽃에 대한 입력값이면 Z에 해당하는 건 꽃에 대한 확률값입니다. 예를 들면 Z에 1번째 해당하는 부분은 개나리, 2번째는 장미, 3번째는 진달래 이런것인 거죠 그래서 각 꽃에 해당하는 가중치값이 존재합니다. 이걸 계산식으로 표현하면 아래와 같습니다.

  • x1w11 + x2w12 + x3w13+ x4w14 = z1
  • x1w21 + x2w22 + x3w23+ x4w24 = z2
  • x1w31 + x2w32 + x3w33+ x4w34 = z3

 

2) 오차 범위수정

실제 원-핫 벡터와 값이 유사하지만 다르기 때문에 맞추는 과정인 가중치와 편향 업데이트 과정을 거칩니다.

 


인공 신경망으로 소프트 맥스 함수를 표현하면 위와 같습니다.

 

📝정수인코딩 vs 원핫인코딩

바나나 0
토마토 1
사과 2

정수 인코딩은 배열의 인덱스 처럼 뭔가 의미 있는 숫자는 아니고 그냥 단지 순서입니다.

 

바나나 [1,0,0]
토마토 [0,1,0]
사과 [0,0,1]

원-핫 벡터의 경우 각 숫자들이 인덱스처럼 구분만 되는 것이 아니라 단어의 방향성을 부여하는 것으로 숫자와 크기가 의미가 있습니다.

 

오차 범위 수정을 위해 제곱오차를 이용했을 때 값이 다릅니다

즉, Banana과 Tomato 사이의 오차보다 Banana과 Apple의 오차가 더 큽니다. 이는 기계에게 Banana가 Apple보다는 Tomato에 더 가깝다는 정보를 주는 것과 다름없습니다.

 

원-핫 벡터를 이용했을 때는 오차범위가 동일하게 책정됩니다.

 

 

📝비용 함수(Cost function)

해당 식을 도출하기 위한 과정을 자세히 보려면 참고 및 출처 사이트를 보시길 바랍니다.

소프트맥스 회귀에서는 비용 함수로 크로스 엔트로피 함수를 사용합니다.

 

 

 

🔗 참고 및 출처

https://wikidocs.net/35821

https://wikidocs.net/37001

https://wikidocs.net/35476

 

 

반응형
반응형

📝선형회귀

시험 공부하는 시간을 늘리면 늘릴 수록 성적이 잘 나옵니다. 하루에 걷는 횟수를 늘릴 수록, 몸무게는 줄어듭니다. 집의 평수가 클수록, 집의 매매 가격은 비싼 경향이 있습니다. 이는 수학적으로 생각해보면 어떤 요인의 수치에 따라서 특정 요인의 수치가 영향을 받고있다고 말할 수 있습니다. 수학적인 표현을 써보면 어떤 변수의 값에 따라서 특정 변수의 값이 영향을 받고 있다고 볼 수 있습니다.

 

즉, 핵심은 어떤 데이터들로부터 상관관계를 함수로 표현하고 그 함수에 해당하는 가중치와 절편 값을 찾아가는 과정입니다. 그러면 어떠한 모르는 값이 들어가도 함수로 유추할 수 있죠

 

 

📝단순 선형회귀

단순 선형회귀의 경우 하나의 변수만 있는 경우를 의미합니다. 예를 들면 몸무게에 따른 키로 봤을 때 몸무게가 x값이 되는 거고 그에 따른 통계를 냈을 때 몸무게에 대한 영향은 w(가중치)를 갖게 됩니다. 절편의 값은 그에 따른 조정이 필요할 때  추가적으로 들어가게 됩니다.

 

즉, 독립 변수 x와 곱해지는 값 w를 머신 러닝에서는 가중치(weight), 별도로 더해지는 값 b를 편향(bias)이라고 합니다.

 

📝다중 선형회귀

 

집의 매매 가격은 단순히 집의 평수가 크다고 결정되는 게 아니라 집의 층의 수, 방의 개수, 지하철 역과의 거리와도 영향이 있습니다. 이러한 다수의 요소를 가지고 집의 매매 가격을 예측해보고 싶습니다. y는 여전히 1개이지만 이제 x는 1개가 아니라 여러 개가 되었습니다. 즉, 다양한 요인들이 포함된 경우를 다중 선형 회귀 분석이라고 합니다.

 

📝목적함수, 비용함수, 손실함수

결국 w와 b를 잘 찾아내는게 목표입니다. w와 b를 찾기 위해서 실제값과 가설로부터 얻은 예측값의 오차를 계산하는 식을 세우고, 이 식의 값을 최소화하는 최적의 w와 b를 찾아냅니다.

 

실제값과 예측값에 대한 오차에 대한 식을 목적 함수(Objective function) 또는 비용 함수(Cost function) 또는 손실 함수(Loss function) 라고 합니다. 

 

비용 함수는 단순히 실제값과 예측값에 대한 오차를 표현하면 되는 것이 아니라, 예측값의 오차를 줄이는 일에 최적화 된 식이어야 합니다.

 

 

손실함수 = (평균제곱오차)

실제값과 예측값을 비교하는 표가 있는데 오차는 = 실제값 - 예측값으로 모든 오차를 다 더하면 음수 오차도 있고 양수 오차도 있기 때문에 거리를 제곱하고 더한 후에 개수만큼 나눕니다.

 

더하는 과정
전체로 나눠서 평균 구하는 과정

오차가 클수록 평균 제곱 오차는 커지며 작을수록 평균 제곱 오차는 작아집니다.

 

 

📝옵티마이저, 경사하강법

비용 함수를 최소화하기 위해 파라미터 조정하는 과정을 의미합니다. 위 그림은 가중치에 따른 손실함수의 값을 그래프로 만든것인데 cost가 가장 낮은 범위를 찾아야 가장 최적의 조건의 학습이 되는 것입니다. 위 그림을 보면 한눈에 w에따른 cost값을 알수 있지만 전부 다 저렇게 알 수 있지 않습니다.

 

그렇기 때문에 하나하나씩 차근차근 경사 하강법을 이용해 미분해서 기울기 값이 가장 작아지는 경우를 찾아가는 겁니다.

 

📝선형회귀 실습

import tensorflow as tf

# tf.Variable은 변수에 대한 값을 지정할 때 사용 (가중치와 절편에 값 지정)
w = tf.Variable(4.0)
b = tf.Variable(1.0)

# w*x + b 형태의 선형회귀함수를 가진다.
@tf.function
def hypothesis(x):
  return w*x + b

# 손실함수 (제곱오차의 평균)
@tf.function
def mse_loss(y_pred, y):
  # 두 개의 차이값을 제곱을 해서 평균을 취한다.
  return tf.reduce_mean(tf.square(y_pred - y))

x = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 공부하는 시간
y = [11, 22, 33, 44, 53, 66, 77, 87, 95] # 각 공부하는 시간에 맵핑되는 성적

# 경사 하강법을 이용하며 0.01 정도로 하강하며 적용
optimizer = tf.optimizers.SGD(0.01)


# 300번을 순회하며 처음 설정한 w, b값을 기준으로 선형회귀함수를 가지는 걸 제곱오차로 따져서 경사 하강법을 적용시키며 최적의 cost값을 찾는 과정
for i in range(301):
  with tf.GradientTape() as tape:
    # 현재 파라미터에 기반한 입력 x에 대한 예측값을 y_pred
    y_pred = hypothesis(x)

    # 평균 제곱 오차를 계산 (예측값과 실제값 비교)
    cost = mse_loss(y_pred, y)

  # 손실 함수에 대한 파라미터의 미분값 계산
  gradients = tape.gradient(cost, [w, b])

  # 경사하강법에 나온 w와 b값을 조정하며 파라미터 업데이트
  optimizer.apply_gradients(zip(gradients, [w, b]))

  # 10번 루프마다 체크
  if i % 10 == 0:
    print("epoch : {:3} | w의 값 : {:5.4f} | b의 값 : {:5.4} | cost : {:5.6f}".format(i, w.numpy(), b.numpy(), cost))

Tensorflow로 직접 구현하기

 

import matplotlib.pyplot as plt
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from tensorflow.keras import optimizers

x = [1, 2, 3, 4, 5, 6, 7, 8, 9] # 공부하는 시간
y = [11, 22, 33, 44, 53, 66, 77, 87, 95] # 각 공부하는 시간에 맵핑되는 성적

model = Sequential()

# 출력 y의 차원은 1. 입력 x의 차원(input_dim)은 1
# 선형 회귀이므로 activation은 'linear'
model.add(Dense(1, input_dim=1, activation='linear'))

# sgd는 경사 하강법을 의미. 학습률(learning rate, lr)은 0.01.
sgd = optimizers.SGD(lr=0.001)

# 손실 함수(Loss function)은 평균제곱오차 mse를 사용합니다.
model.compile(optimizer=sgd, loss='mse', metrics=['mse'])

# 주어진 x와 y데이터에 대해서 오차를 최소화하는 작업을 300번 시도합니다.
model.fit(x, y, epochs=300)

plt.plot(x, model.predict(x), 'b', x, y, 'k.')
plt.show()

# 8.5시간 공부했을 때 성적 예측하기
print(model.predict([9.5]))
# [[89.20797]]

Keras로 구현해보기

 

로직에 대해서 대충 파악하고 이미 잘 만들어진 Keras를 이용하는게 좋긴합니다.

 

📝이진 분류 (로지스틱 회귀)

둘 중 하나를 결정하는 문제를 이진 분류(Binary Classification)라고 합니다. 그리고 이런 문제를 풀기 위한 대표적인 알고리즘으로 로지스틱 회귀(Logistic Regression)가 있습니다

 

score(x) result(y)
45 불합격
50 불합격
55 불합격
60 합격
65 합격
70 합격

 

위 데이터에서 합격을 1, 불합격을 0이라고 하였을 때 그래프를 그려보면 아래와 같습니다.

 

그래프는 알파벳의 S자 형태로 표현됩니다. 이러한 x와 y의 관계를 표현하기 위해서는 직선을 표현하는 함수가 아니라 S자 형태로 표현할 수 있는 함수가 필요합니다.

 

레이블에 해당하는 y가 0 또는 1이라는 두 가지 값만을 가지므로, 이 문제를 풀기 위해서 예측값은 0과 1사이의 값을 가지도록 합니다. 0과 1사이의 값을 확률로 해석하면 문제를 풀기가 훨씬 용이해집니다. 최종 예측값이 0.5보다 작으면 0으로 예측했다고 판단하고, 0.5보다 크면 1로 예측했다고 판단합니다.

 

출력이 0과 1사이의 값을 가지면서 S자 형태로 그려지는 함수로 시그모이드 함수(Sigmoid function)가 있습니다.

 

 

📝시그모이드 함수(Sigmoid function)

시그모이드 함수는 종종 σ로 축약해서 표현하기도 합니다. 해당 함수는 위와 같이 함수를 표현하는 함수인 것이고 인공지능이 찾아야할 건 결국 w와 b입니다.

 

w변화에 따른 함수 변화 b에 따른 함수 변화

 

📝로지스틱 손실함수(크로스 엔트로피함수) 

로지스틱 회귀에서 평균 제곱 오차를 비용 함수로 사용하면, 경사 하강법을 사용하였을때 찾고자 하는 최소값이 아닌 잘못된 최소값에 빠질 가능성이 매우 높습니다. 이를 전체 함수에 걸쳐 최소값 글로벌 미니멈(Global Minimum) 이 아닌 특정 구역에서의 최소값 로컬 미니멈(Local Minimum) 에 도달했다고 합니다. 로컬 미니멈에 지나치게 쉽게 빠지는 비용 함수는 cost가 가능한한 최소가 되는 가중치 w를 찾는다는 목적에는 좋지 않은 선택입니니다. 그리고 로지스틱 회귀에서의 평균 제곱 오차는 바로 그 좋지 않은 선택에 해당합니다.

 

 

여러가지 계산을 거쳐서 나온 손실함수인데 그 과정을 완전히 무에서 유추하는 거는 솔직히 의미없는 것 같습니다. (사실 안 해봐서 잘 모름) 로지스틱 회귀에서 찾아낸 비용 함수를 크로스 엔트로피(Cross Entropy)함수라고 합니다.

 

 

결국엔 아래와 같은 과정을 통해서 진행되게 됩니다.

  1. 테스트 데이터가 주어진다. (문제와 정답)
  2. 데이터 결과에 가까운 함수를 사용한다.
  3. 학습을 시키며 손실함수로 오차범위를 수정하며 해당 함수의 w와 b값을 구한다
  4. 최적의 w와 b를 이용해 예측이 가능해진다.

 

 

 

🔗 참고 및 출처

https://wikidocs.net/21670

 

반응형