5주차 | 딥러닝(Deep learning)(1)
KT AIVLE SCHOOL 5기 5주차에 진행한 딥러닝(Deep learning) 강의 내용 정리 글입니다.
CRISP-DM
머신러닝 알고리즘 정리
딥러닝 개념 익히기
모델링 : 파라미터를 잘 찾는것 → train error를 최소화하는 과정
튜닝 : val error를 최소화하는 과정
학습 절차
- 어떤 정보 : node 혹은 뉴런(Neuron)
- 어떤 정보에 알맞은 가중치와 절편을 찾아가는 과정
model.fit
하는 순간- 가중치(파라미터)에 초기값을 할당 (랜덤으로)
- 예측 결과를 뽑는다
- 오차를 계산(
loss
) → forward propagation(순전파) - 오차를 줄이는 방향으로 가중치 조정(방향 :
optimizer
, 얼만큼 :learning rate
(중요)) → back propagation(역전파) - 다시 1단계로 올라가 반복 (
epoch
)
하이퍼파라미터 : 머신러닝에서 사람이 개입할 여지
[30번 조정하며 최적의 가중치 찾는 과정]
딥러닝 모델링 : 회귀
딥러닝 과정 및 구조
- 딥러닝에서 스케일링은 필수
- Normalization(정규화) : 모든 값의 범위를 0 ~ 1로 변환 → 보통 많이 사용
- Standardization(표준화) : 모든 값을 , 평균 = 0, 표준편차 = 1로 변환
- Process
- 각 단계(task)는 이전 단계의 output을 input으로 받아 처리한 후 다음 단계로 전달
- 공통의 목표를 달성하기 위해서 동작
- ex) 상품 기획 → 디자인 → 생산 → 물류 입고 → 매장 판매
- 딥러닝 구조
- Input : 입력되는 x의 분석 단위(Layer 아님)
- Hidden Layer
- layer 여러개 : 리스트[]로 입력
- hidden layer
- input_shape는 첫번째 layer만 필요
- activation
- 히든 레이어는 활성함수 필요(보통 ‘relu’ 사용)
- output layer : 예측 결과가 1개
- 활성화 함수(Activation Function)
- 현재 레이어의 결과값을 다음 레이어(연결된 각 노드)로 어떻게 전달할지 결정 변환 해주는 함수
- 없으면 히든 레이어를 아무리 추가해도 그냥 선형회귀
- Hidden Layer: 선형함수 → 비선형 (ReLU), Output Layer: 결과값 다른 값으로 변환 (주로 분류 모델에서 필요)
- Sigmoid, tanh, ReLU(Hidden Layer 국룰)
- 보통 노드의 수를 점차 줄여간다
- Output Layer
- Output
딥러닝 코드
Dense
input_shape = ( , )
: 분석 단위에 대한 shape- 1차원 : (feature수, ), 2차원 : (rows, cols)
output
: 예측 결과가 1개 변수
Compile
- 선언된 모델에 대해 몇가지 설정을 한 후, 컴퓨터가 이해할 수 있는 형태로 변환하는 작업
loss function(오차 함수)
- 오차 계산 무엇으로 할지 결정
- 회귀는 보통 mse
optimizer
- 오차를 최소화 하도록 가중치 조절
optimizer = ‘adam’
:learning_rate
기본 값 = 0.001optimizer = Adam(learning_rate = 0.1)
: 옵션 값 조정 가능
learning_rate
- 적절하게 조절하는 것이 좋다
- 학습
epochs
: 반복 횟수 → 전체 데이터를 몇 번 학습validation_split = 0.2
→ 학습 데이터의 20%를 검증 데이터로 사용
- 학습 곡선
.history
- 학습 수행 과정에 가중치가 업데이트 되면서 그 때 마다의 성능 측정하여 기록
- 학습 시 계산된 오차 기록(가이드)
- 바람직한 곡선
- epoch가 증가하면서 loss가 큰 폭으로 축소 후, 점차 loss 감소 폭이 줄어들면서 감소
- 들쑬 날쑥하면서 loss 감소 → learning_rate 줄이기
- val_loss가 줄어들다가 다시 상승(과적합)
- epoch와 learnig_rate 조절
실습
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.metrics import *
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.backend import clear_session
from tensorflow.keras.optimizers import Adam
#from keras.optimizers import Adam : 버전에 따라 다르다
def dl_history_plot(history):
plt.figure(figsize=(10,6))
plt.plot(history['loss'], label='train_err', marker = '.')
plt.plot(history['val_loss'], label='val_err', marker = '.')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend()
plt.grid()
plt.show()
path = 'https://raw.githubusercontent.com/DA4BAM/dataset/master/boston.csv'
data = pd.read_csv(path)
target = 'medv'
x = data.drop(target, axis = 1)
y = data.loc[:, target]
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size=.2, random_state = 20)
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_val = scaler.transform(x_val)
nfeatures = x_train.shape[1]
model3 = Sequential([ Dense(2, input_shape = (nfeatures,), activation = 'relu'),
Dense(1) ])
model3.summary()
model3.compile( optimizer= Adam(learning_rate=0.08), loss = 'mse')
hist = model3.fit(x_train, y_train, epochs = 50 , validation_split= .2, verbose = 0).history
dl_history_plot(hist)
pred3 = model3.predict(x_val)
print(f'RMSE : {mean_squared_error(y_val, pred3, squared=False)}')
print(f'MAE : {mean_absolute_error(y_val, pred3)}')
print(f'MAPE : {mean_absolute_percentage_error(y_val, pred3)}')
Feature Representation
Hidden Layer
- 연결
- 모든 노드 간 연결(Fully Connected)
- 연결 제어(Locally Connected)
- 학습
- 오차를 계산하고 오차를 줄이기 위해 파라미터(가중치) 업데이트
- 각 노드 별로 값 생성
- Hidden Layer 내부에서 발생한 일
- 기존 데이터로 새로운 특징(new feature)를 만듦
- 예측 값과 실제 값 사이의 오차를 최소화 해주는 유익한 특징일 것이다
- 기존 데이터가 새롭게 표현(Representation)되는 Feature Engineering이 진행된 것
- Deep Learning → Representation Learning
딥러닝 모델링: 이진 분류
- 결과를 변환시켜줄 활성화 함수가 필요(시그모이드 함수)
활성 함수(Activation Function)
- node의 결과를 변환 시켜주는 역할
- Hidden Layer
- Activation Function : ReLU
- 기능 : 좀 더 깊이 있는 학습을 시키려고
- Output Layer
- 회귀 : X
- 이진 분류
- Activation Function: sigmoid
- 기능: 결과를 0, 1로 변환
- 다중 분류
- Activation Function: softmax
- 기능: 각 범주에 대한 결과를 범주별 확률 값으로 변환
- Hidden Layer
Loss Function : binary_crossentropy
- 이진 분류 모델에서 사용되는 loss function
- y=1, y=0 일 때 각각 오차들의 평균
실습
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.metrics import *
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.backend import clear_session
from tensorflow.keras.optimizers import Adam
from imblearn.over_sampling import RandomOverSampler
# 학습곡선 함수
def dl_history_plot(history):
plt.figure(figsize=(10,6))
plt.plot(history['loss'], label='train_err', marker = '.')
plt.plot(history['val_loss'], label='val_err', marker = '.')
plt.ylabel('Loss')
plt.xlabel('Epoch')
plt.legend()
plt.grid()
plt.show()
path = "https://raw.githubusercontent.com/DA4BAM/dataset/master/Attrition_train_validation.CSV"
data = pd.read_csv(path)
data['Attrition'] = np.where(data['Attrition']=='Yes', 1, 0)
target = 'Attrition'
data.drop('EmployeeNumber', axis = 1, inplace = True)
x = data.drop(target, axis = 1)
y = data.loc[:, target]
dum_cols = ['BusinessTravel','Department','Education','EducationField','EnvironmentSatisfaction','Gender',
'JobRole', 'JobInvolvement', 'JobSatisfaction', 'MaritalStatus', 'OverTime', 'RelationshipSatisfaction',
'StockOptionLevel','WorkLifeBalance' ]
x = pd.get_dummies(x, columns = dum_cols ,drop_first = True)
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size = 200, random_state = 2022)
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_val = scaler.transform(x_val)
n = x_train.shape[1]
# 60, 60, 10, 5, 1
clear_session()
model = Sequential([Dense(60, input_shape = (n, ), activation = 'relu'),
Dense(60, activation = 'relu'),
Dense(10, activation = 'relu'),
Dense(5, activation = 'relu'),
Dense(1, activation = 'sigmoid')])
model.summary()
model.compile(optimizer = Adam(learning_rate = 0.001), loss = 'binary_crossentropy')
hist = model.fit(x_train, y_train, epochs = 100, validation_split = 0.2, verbose = 0).history
dl_history_plot(hist)
pred = model.predict(x_val)
pred = np.where(pred >= 0.5, 1, 0)
print(confusion_matrix(y_val, pred))
print(classification_report(y_val, pred))
# resampling
ros = RandomOverSampler()
x_train_ros, y_train_ros = ros.fit_resample(x_train, y_train)
print(y_train_ros.value_counts(normalize = True))
print(y_train_ros.value_counts())
딥러닝 모델링: 다중 분류
Output Layer
- Node 수: y의 범주수
- Softmax: 각 class 별(Output Node)로 예측한 값을, 하나의 확률 값으로 반환
다중 분류 모델링을 위한 전처리
- 다중 분류: y가 범주이고, 범주가 3개 이상
- 방법 1: 정수 인코딩 + sparse_categorical_crossentropy
- y: Integer Encoding → class들을 0부터 시작하여 순차 증가하는 정수로 인코딩
int_encoder.classes_
→ 배열의 인덱스가 인코딩 된 범주loss='sparse_categorical_crossentropy’
- y는 인덱스로 사용됨 : 해당 인덱스의 예측 확률로 계산(\(-log(y)\))
- 방법 2: y값 one-hot encoding 하고,
loss = ‘categorical_crossentropy’
- y: One-Hot Encoding
loss = ‘categorical_crossentropy’
실습
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from sklearn.model_selection import train_test_split
from sklearn.metrics import *
from sklearn.preprocessing import MinMaxScaler
from keras.models import Sequential
from keras.layers import Dense
from keras.backend import clear_session
from tensorflow.keras.optimizers import Adam
path = "https://raw.githubusercontent.com/DA4BAM/dataset/master/iris.csv"
data = pd.read_csv(path)
data['Species'] = data['Species'].map({'setosa':0, 'versicolor':1, 'virginica':2})
target = 'Species'
x = data.drop(target, axis = 1)
y = data.loc[:, target]
# 방법 1
x_train, x_val, y_train, y_val = train_test_split(x, y, test_size = .3, random_state = 20)
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_val = scaler.transform(x_val)
nfeatures = x_train.shape[1] #num of columns
clear_session()
model = Sequential( Dense( 3 , input_shape = (nfeatures,), activation = 'softmax') )
model.summary()
model.compile(optimizer=Adam(learning_rate=0.1), loss= 'sparse_categorical_crossentropy')
history = model.fit(x_train, y_train, epochs = 50, validation_split=0.2).history
dl_history_plot(history)
pred = model.predict(x_val)
pred_1 = pred.argmax(axis=1)
print(confusion_matrix(y_val, pred_1))
print(classification_report(y_val, pred_1))
# 방법 2
from tensorflow.keras.utils import to_categorical
y_c = to_categorical(y.values, 3)
x_train, x_val, y_train, y_val = train_test_split(x, y_c, test_size = .3, random_state = 2022)
scaler = MinMaxScaler()
x_train = scaler.fit_transform(x_train)
x_val = scaler.transform(x_val)
nfeatures = x_train.shape[1] #num of columns
clear_session()
model = Sequential([Dense(3, input_shape = (nfeatures,), activation = 'softmax')])
model.summary()
model.compile(optimizer=Adam(learning_rate=0.1), loss='categorical_crossentropy')
history = model.fit(x_train, y_train, epochs = 100,
validation_split=0.2).history
dl_history_plot(history)
pred = model.predict(x_val)
pred_1 = pred.argmax(axis=1)
y_val_1 = y_val.argmax(axis=1)
print(confusion_matrix(y_val_1, pred_1))
print(classification_report(y_val_1, pred_1))
요약
참조
가중치 업데이트
- Gradient : 기울기(벡터)
- Gradient Descent(경사 하강법, optimizer의 기본)
- \(w\)의 초기값 지정 : \(w_0\)
- 기울기 -이면 오른쪽, +이면 왼쪽 방향
- eta, learning rate로 조정하는 비율 설정
Vanishing Gradient(기울기 소실)
- 기울기 소실
- 네트워크의 깊은 부분으로 갈수록 기울기가 점점 작아져서, 가중치가 거의 또는 전혀 업데이트되지 않게 되는 현상
- 문제 최소화 노력
- 초기 sigmoid에서 심각 → ReLU로 기울기 소실 문제 완화
- ReLU의 변형된 활성화 함수
- Leaky ReLU, PReLU, ELU : 음수 입력에 대해서도 매우 작은 기울기를 허용
- 그외 방법들
- 가중치 초기화, 배치 정규화, Residual Connections, Gradient Clipping
클래스 불균형 문제
- Class Imbalances
- 일반적인 알고리즘들
- 데이터가 클래스 내에서 고르게 분포되어 있다고 가정
- 다수 클래스를 더 많이 예측하는 쪽으로 모델이 편향되는 경향이 있음
- 소수의 클래스에서 오분류 비율이 높아짐
- 문제점
- Accuracy는 높지만 적은 클래스 쪽 Recall은 형편없이 낮게 나옴
- 일반적인 알고리즘들
해결 방법
전반적인 성능을 높이기 위한 작업이 아니라 소수 class의 성능을 높이기 위한 작업(다수 class의 성능 떨어짐)
- Resampling
- Down Sampling(비복원 추출)
- 다수 class의 데이터를 소수 class 수만큼 random sampling
- Up Sampling(복원 추출)
- 소수 class의 데이터를 다수 class 수 만큼 random sampling
- SMOTE
- 소수 class의 데이터를 보간법(Interpolation)으로 새로운 데이터를 만들어냄
- Down Sampling(비복원 추출)
- Class Weight 조정
- 모델링 절차
- 모델의 구조 잡기
- 초기값(parameter) 할당
- 예측
- 오차 계산
- 오차를 줄이는 방향으로 parameter 조정
- 다시 3단계에서 반복
- Resampling 없이 클래스에 가중치를 부여하여 해결
- 학습 동안 알고리즘의 비용 함수에서 소수 클래스에 더 많은 가중치 부여
- sklearn의 알고리즘 대부분 class_weight 옵션 제공
- 모델링 절차
- Resampling
코드
from imblearn.under_sampling import RandomUnderSampler # down from imblearn.over_sampling import RandomOverSampler, SMOTE # up, smote ## Resampling # Down sampling : 적은 쪽 클래스는 그대로, 많은 쪽 클래스는 랜덤 샘플링(적은쪽 클래수 수 만큼) rus = RandomUnderSampler(random_state = 4) x_d, y_d = rus.fit_resample(x, y) # Up sampling : 많은 클래스는 그대로, 적은 클래스는 랜덤 복원추출(많은 클래스 만큼) ros = RandomOverSampler(random_state = 4) x_u, y_u = ros.fit_resample(x, y) # SMOTE : 많은쪽은 그대로(혹은 약간 down sampling), 적은쪽은 보간법! smote = SMOTE(random_state = 4) x_sm, y_sm = smote.fit_resample(x, y) ## Class Weight # class_weight 조정1 model1 = SVC(kernel='linear', class_weight='balanced') model1.fit(x, y) # class_weight 조정2 weight_1 = 0.99 model1 = SVC(kernel='linear', class_weight= { 0:(1-weight_1) , 1:weight_1} ) model1.fit(x, y)