KT AIVLE School/[TIL] AIVLE School 당일 복습

[TIL] [KT AIVLE School] 에이블스쿨 DX 트랙 10주차 1일. 딥러닝 기초(4). 총정리 + CNN

guoyee94 2024. 11. 4. 16:25

 

오늘은 총복습 + CNN을 배운다.

 

ADsP도 잘 끝났고, 2주 후 SQLD, 4주 후 경영정보시각화... 바쁘다 바빠.

 

 


 

CIRSP-DM

 

한기영 강사님께서 주구장창 강조하시는 CRISP-DM.

 

어제 ADsP 시험에서도 요긴하게 써먹었더랬다.

 

Business Understanding

비즈니스 문제 정의

가설 수립

데이터 분석의 방향성 수립

 

Data Understanding

원본식별

분석을 위한 구조 만들기 : Data Dictionary 구성, x record가 하나의 자료(사건)임을 잊지말자.

EDA & CDA : 단변량분석 / 이변량분석 등 활용

 

Data Preparation

모든 셀은 값이 있어야 한다. : NaN이 없어야 한다.

모든 값은 숫자여야 한다. : 가변수화를 진행해야 한다.

숫자의 범위가 일치해야 한다. : Scaling을 수행해야 한다.

 

Modeling

모델 만들기 : 모델이란 결국 하나의 수학식이며, 모든 것은 계산으로 처리된다.

검증하기 : 우리는 검증성능을 높이기 위해 하이퍼파라미터를 조정해야 한다.

 

Evaluation

평가 : 기술적 관점, 비즈니스 관점

 

Deployment

모델 관리, 서비스 구축

 

 

 


 

 

 

회귀모델의 평가

 

오차의 크기를 재는 방법 :

제곱오차(Squared Error = SE), 절대값오차(Absolute Error = AE), 오차율(Absolute Percentage Error = APE)

 이들의 평균으로 성능 측정 : MSE, MAE, MAPE

 

 

딥러닝의 학습 절차

 

model.fit(x_train, y_train)의 실행 단계는 다음과 같다.

1. 랜덤하게 가중치(parameter)를 정한다.
2. 예측결과를 뽑는다.
3. 오차를 계산한다. : 이 단계에서 loss(손실함수)가 이용된다.
  → forward propagation(feed forward)
4. 오차를 줄이는 방향을 찾고, 가중치를 조정한다. : 이 간계에서 Optimizer(최적화 알고리즘)가 사용된다.
  → back propagation
5. 오차의 변동이 거의 없거나, max iteration에 도달할 때까지 반복한다.

 

 

Optimizer의 기본 수행 원리는 경사하강법(Gradient Descent)을 따른다.

 

위는 모델이 계산하는 오차를 그래프로 그린 것이다.

 

2차함수인 이유는 MSE 기반이기 때문.

 

우리는 오류( = 손실, 비용, loss, cost)가 최솟값이 되도록 해야 하므로,

오차가 Minimun Cost에 위치하게 만들고 싶다.

 

위의 1단계에서 랜덤하게 정해진 초기 가중치(Initial Weight)오차를 발생시키겠지.

 

그러면 미분을 통해 초기 가중치의 오차 위치에 있는 접선 기울기를 구한다.

 

위 그림처럼 기울기가 +라면, Minimum Point는 - 방향에 있겠지?

 

그러니까 오차가 - 방향이 되게 가중치를 수정하는 것이다.

 

 


 

 

딥러닝 코드

 

머신러닝이랑 기본 골자는 같고,

[모델 구조 선언 + 컴파일] 단계만 좀 차이가 있다.

모델 구조 선언
기본형 : model = Sequential()
  - 매개변수 : 레이어들을 정의할 것이므로 리스트 안에 담아서 표현
    - Input(shape=(nfeatures, )) : 입력층, 입력 데이터를 정의(nfeatures는 train셋의 컬럼수)
    - Dense(n, activation='relu') : 하나의 층을 정의.(n은 노드 수, activation은 활성화 함수의 종류)

 

※ 활성화 함수 : 선형회귀식을 기반으로 하는 딥러닝 특성상, 비선형 데이터에 적합되지 못한다.

그것을 극복하기 위해 각 layer에 들어가는 함수.

  - Hidden layer : 'relu'

  - Output layer :  'sigmoid'(이진분류), 'softmax'(다중분류) / 회귀문제에서는 안 씀

 

 

컴파일
기본형 : model.compile()
  - 매개변수
    - loss : 손실함수 정의.
      - 회귀모델 : mse
      - 분류모델 : binary_crossentropy(이진분류)
                         categorycal_crossentropy / sparse_categorycal_crossentropy(다중분류)
    - optimizer=Adam(learning_rate=n=0.001) : 최적화 알고리즘 정의.
      - 그냥 Adam으로 고정. learning_rate 하이퍼파라미터 조절 필요

 

※ 분류 문제는 sigmoid와 softmax가 확률값을 반환하므로,

그 확률값을 결과(0, 1, 2 등)으로 만들어 주어야 한다.

이진분류 np.where(pred >=, 1, 0)
다중분류 np.argmax(pred, axis=1)

 

 

 


 

 

모델의 복잡도

 

복잡도 = 과적합 위험이다.

 

알고리즘에 따라 모델의 복잡도를 결정하는 요인이 있고,

딥러닝에서는 다음과 같은 요소들이 복잡도를 정한다.

Hidden layer의 수
node의 수
epoch의 수

 

그러나 이것들은 성능으로 직결되기도 한다.

 

따라서 최근의 딥러닝은,

최대한 복잡한 구조의 모델을 만들고, 규제를 통해 과적합을 해결하는 추세를 보인다.

 

여기서 말하는 규제란 다음과 같다.

Early Stopping
Dropout
가중치 규제

 

 

 

 

 

 

 

 

 

 

 

 


 

 

 

 

 

 

CNN

 

CNN(Convolutional Neural Network)은 이미지나 영상 데이터를 처리하는 데에 특화된 신경망이다.

 

입력 데이터의 '공간적 구조'를 학습하고, 이로부터 '특징을 추출'하는 작업을 수행한다.

 

기본적인 모델링 방법은 이전 방식들과 같고,

입력하는 데이터가 이미지라는 차이만이 있을 뿐이다.

 

  • CNN 전처리 단계
# 이미지 데이터셋 전처리
x_train = x_train.reshape(60000,28,28,1)
x_val = x_val.reshape(10000,28,28,1)

# 스케일링
x_train = x_train / 255
x_val = x_val / 255

 

이미지 데이터는 3차원을 가지고 있다. 

 

이를테면 위 코드를 실행하기 전 x_train.shape을 찍어 보면

(60000, 28, 28)

 

이런 결과가 나온다.

 

28 X 28 이미지가 60000개 있다는 뜻.

 

이 데이터에 reshape()를 통해 차원을 하나 추가해 줘야 하는데

(도는 원래 데이터셋이 4차원으로 되어 있을 수도 있다.)

 

이 추가되는 차원은 '채널'이다.

 

이미지의 색상을 나타내는 값으로, 흑백은 1, 컬러는 3(RGB)로 나타낸다.

 

위에서는 흑백이라서 1을 입력. (60000, 28, 28, 1)로 만들어 준다.

 

이런 형태이므로 나중에 input_shape이 (세로, 가로, 채널) 형태를 가지고 있다.

 

 

스케일링은 수동으로 진행할 수 있다.

 

안 그래도 되긴 하지만... 이미지 픽셀이 갖는 최댓값이 255기 때문에,

이미지의 스케일링은 255로 나누면 된다.

 

 

  • CNN 모델링 단계
# CNN 모델 선언
model = Sequential([Input(shape = (28, 28, 1)),
                    Conv2D(16, kernel_size = 3, padding='same', activation='relu'),
                    MaxPooling2D(pool_size = 2 ),          
                    Flatten(),
                    Dense(10, activation='softmax')])

# 모델 컴파일
model.compile(optimizer=Adam(learning_rate=0.001), loss='sparse_categorical_crossentropy')

 

기본적으로 이미지 판정은 다중 분류 모델이므로 컴파일은 다중 분류를 따른다.

 

모델링 과정을 보면, 몇가지 다른 점들이 있다.

 

하나씩 톺아보자.

 


 

1. Input data의 상태
위에서 말했듯, 이미지는 하나의 record가 (세로, 가로, 채널)의 모양을 가진다.
따라서 Input(shape = (n, m, channel) 형태의 코드가 입력된다.

 


 


2. Convolution layer
필터를 통해 지역적인 특징을 찾아내는 층.
Dense 대신 Conv2d를 사용한다.
활성함수로 relu를 사용하는 것은 기존의 히든 레이어와 동일하다.

필터를 통해 이미지 데이터에 합성곱 필터링을 적용하는 과정

 

다행히(?) 예전에 모의고사 비문학에 나온 적 있는 원리다.

 

활성함수를 제외하고 필요로 하는 매개변수는 총 세 개다.

 

필터 수, 필터 크기, 패딩.


노드 수를 입력받는 Dense와 달리, Conv2D는 합성곱 필터링에 사용할 필터 수를 입력받는다.
필터는 정사각형 형태이므로, kernel_size에 변의 길이를 입력한다.

 

padding은 충전재를 뜻한다. 택배 뽁뽁이 같은거.

원래 입력받은 데이터가 필터의 배수가 아닐 때,

특정 원소들이 여러번 필터링될 수 있다.

 

따라서 위 그림처럼 0으로 이루어진 패딩을 넣어

필터가 모든 요소에 같은 횟수로 쓰일 수 있게 하는 것.

 

padding='same' 형태로 넣으면 된다.

 

이런 식으로 합성곱 층 하나를 지나면,

이미지의 각 특징을 나타내는 요소는 강화되고

특징과 무관한 요소는 약화된다.

 

Dense처럼 Conv2D도 여러 층 쌓곤 하는데,

특징 구분이 점점 더 명확해지도록 필터 수를 차츰 늘려가는게 일반적이다.

 

 

 

 

 


 


3. Max_Poolling
필터링된 데이터의 최댓값만 뽑아 온다. 

 

Conv2D의 원리가 합성곱을 이용해 이미지의 특징을 추출하는 것인데,

이 방법은 데이터 수를 기하급수적으로 늘린하는 문제가 있다.

 

따라서 해당 데이터를 한번 요약하여 다음 층에 전달할 필요가 있는 것.

 


필터링된 데이터의 일정 영역을 지정한 후,
그 영역 내 최댓값을 당겨 옴으로써 다음 층으로 넘어갈 데이터를 만든다.

그 '일정 영역'을 MaxPooling2D()가 pool_size라는 매개변수로 결정한다.

 

strides 매개변수성큼걸이

Max_pooling도 일종의 필터링같은 역할을 한다고 볼 수 있다.
pool_size에 해당하는 필터가 이동하면서 최댓값을 탐색하는 거니까.

다시말해 Conv2d와 MaxPooling2d는 공통적으로 필터가 이동하는 과정이 있다.

이때 필터가 한칸씩이 아니라 여러 칸씩 움직이게 만들 수도 있는데,
그것을 결정하는 매개변수가 strides이다.

 


4. Flatten : 일자로 펼쳐서 Dense layer로 연결해 주는 역할을 한다.

 

 

 

그 결과 볼 수 있는 CNN 모델링 플로우

# 모델1
clear_session()

model1 = Sequential([Input(shape = (28, 28, 1)),
                    Conv2D(32, kernel_size=4, padding='same', activation ='relu'),
                    MaxPooling2D(pool_size = 2), 
                    Conv2D(64, kernel_size = 4, padding='same', activation = 'relu'),
                    MaxPooling2D(pool_size = 2),
                    Conv2D(128, kernel_size = 4, padding='same', activation = 'relu'),
                    MaxPooling2D(pool_size = 2),
                    Flatten(),
                    Dense(128, activation = 'relu'),
                    Dense(10, activation = 'softmax')
])

model1.summary()
model1.compile(optimizer=Adam(learning_rate=0.0001), loss='sparse_categorical_crossentropy')

# es
es = EarlyStopping(monitor='val_loss', patience=5, min_delta=0.001)

# fit
history = model1.fit(x_train, y_train, epochs = 50,
                    validation_split=0.2, callbacks=[es]).history

dl_history_plot(history)
pred = model1.predict(x_val)
pred_1 = pred.argmax(axis=1)
print(accuracy_score(y_val,pred_1))
print('-'*60)
print(confusion_matrix(y_val, pred_1))
print('-'*60)
print(classification_report(y_val, pred_1))