[혼공머신] Chapter7. (드디어)딥러닝 시작

JB·2022년 2월 23일
0

혼공머신

목록 보기
7/9
post-thumbnail

혼공학습단 마지막주차이자 딥러닝의 시작이다. 솔직히 숙제처럼 안했으면 족장님한테 멱살 잡혀서(족장님 : 잡은 적 없는데요...?) 여기까지 오지 못했을거다. 매우 감사...

그럼 마지막까지 화이팅하고 일단 ㄱ


아래 내용은 <혼자 공부하는 머신러닝 + 딥러닝>과 숙명여자대학교 소프트웨어학부 <데이터사이언스개론> <빅데이터처리> 수업을 참고하여 작성한 내용입니다.

1. 인공신경망

럭키백 이벤트가 성공해서 패션까지 간다고 한다. 번창을 축하합니다 패션 상품도 럭키백을 만들어보자고 한다. 로지스틱 회귀로 럭키백의 정확도를 높이고 싶다. 그럼 해보자

패션 MNIST

일단 상품 데이터가 없으니까 패션 아이템 10종으로 이루어진 데이터셋으로 모델을 만들어보자. 텐서플로우를 사용해서 모델을 만들 예정이다.
처음 사용하는 데이터셋이므로 데이터를 불러오는 방법을 정리하도록 하겠다.

  1. 케라스 패키지에서 fashion_mnist 모듈에서 데이터를 불러온다.
  2. 사이즈 확인하기 -> 28x28 이미지 6만장(train), 1만장(test)
  3. 출력해보니 화질이 좋지 않은 옷이 몇 개 나온다.
  4. target 값을 보니 0~9까지로 분류된 것 같다. 구체적인건...구글에 쳐보자!



로지스틱 회귀로 분류하기

SGDClassifier 로 로지스틱 회귀를 해보자! 입니다. 대신 이미지 픽셀은 0~255 사이의 값을 가지므로 0~1 사이의 값으로 정규화해줍니다(255로 나누기). 그리고 돌려돌려돌림판모델!
이상한 경고가 떴다. max_iter가 낮아서 생기는 경고인 것 같다.
(경고 전문 : ConvergenceWarning: Maximum number of iteration reached before convergence. Consider increasing max_iter to improve the fit.)

사실 모델 입장에서는
'나한테 지금 무슨 짓을...?' 싶을 것 같은 게
28x28 픽셀 하나하나에 대한 가중치를 6만장을 뒤져서 찾고 심지어 그것을 10번이나 해내야한다. 물론 83% 정확도로 해냈지만 약간 ㄴㅇㄱ 느낌. 그럼 이것을 해결할 수 있는 것은 뭐가 있을까요?


인공신경망

  • 인공신경망(ANN, Artificial Neural Network) : 기계학습과 인지과학에서 생물학의 신경망(동물의 중추신경계중 특히 뇌)에서 영감을 얻은 통계학적 학습 알고리즘이다. (출처 : 위키백과 '인공신경망')

인공신경망은 확률적 경사하강법을 사용하는 로지스틱 회귀와 비슷하다고 한다. 먼저 간단한 용어들을 정리하고 넘어가자

  • 입력층 : 입력 데이터를 그대로 다음 단계로 넘겨주는 문 같은 층이다. 특별한 계산이나 변환을 수행하지 않는다.
  • 출력층 : 신경망의 최종 결과값을 내놓는 층이다.
  • 뉴런 : 각 출력층을 계산하는 단위, 선형 계산을 하며 '유닛'이라고 많이 불림.
  • 텐서플로우 : 구글이 공개한 딥러닝 라이브러리
  • 케라스 : 딥러닝 고수준 API 라이브러리 : GPU를 사용함


모델 만들기

먼저 딥러닝 모델을 만들 때에는 train, test를 따로 떼어놓거나 n-fold 검증을 했는데, 딥러닝은 데이터셋이 충분히 크고 훈련 시간이 너무 오래 걸리기 때문에 그 방법을 사용하지 않는다고 한다.
케라스에서 모델을 만드는 방법은 사이킷런과 비슷하게 아직은 간단하다. 층생성-모델-컴파일-훈련-평가 이다. 사이킷런에서 '층생성', '컴파일(우리가 아는 그 컴파일보다는 설정같은 단계)' 가 추가되었다.
알려준대로 코딩해보았다. 먼저 클래스가 10개이므로 소프트맥수 함수를 사용해주고 입력이 784 짜리 1차원 배열임을 명시해주어 층을 만든다. 다중분류이므로 'sparse_categorical_crossentropy' 손실함수를 사용해준다.
sparse_categorical_crossentropy 는 별도의 one-hot encoding 없이도 정수로된 타깃값을 크로스 엔트로피로 손실을 계산해준다.

심심하니까(?) 에폭을 20으로 늘려준다.

성능은 비슷비슷한 것 같다. 다음은 층을 여러개 넣은 인공신경망을 다뤄보자!


2. 심층 신경망

층을 여러개 추가하여 성능을 더 높여봅시다.

n개의 층

인공 신경망 모델에 층을 추가해봅시다! 형태는 입력->입력층->은닉층->출력층->활성화 함수 가 되겠죠?

  • 은닉층 : 입력층-출력층 사이에 있는 층

은닉층에도 활성화 함수가 붙어있는데, 출력층의 활성화함수는 정해져있지만 은닉층 활성화함수는 자유롭다고 한다.
은닉층에 활성화 함수를 붙이는 이유는 '선형방정식'을 두 번 지나봤자 하나로 정리가 가능하기 때문이다. 다음 식을 보자

4a+2=b4a + 2 = b
6b3=c6b - 3 = c
6(4a+2)3=c6(4a + 2) - 3 = c
24a+9=c\therefore 24a + 9 = c

a 가 b를 거쳐 c가 되지만 선형 방정식이기 때문에 a를 변수로 하는 선형방정식으로 정리할 수 있다. 이러면 층이 있을이유가 없다. 따라서 중간에 비선형 함수를 활성화함수로 넣어주어 어떤 역할을 할 수 있도록 해준다.

다음과 같이 add()로 층을 추가해서 모델을 완성해준다. 이렇게 하는 게 if문을 사용하거나 동적으로 모델을 만들기 좋다고 한다. 역시 개발자들은 똑똑한 것 같다.

성능이 조금 더 좋아졌다!


렐루 함수

활성화함수를 시그모이드로 실습해보았지만 사실 렐루를 많이 써서 '시그모이드 자주 쓰나?' 싶었다. 렐루(ReLU)함수는 입력이 양수일 경우엔 통과시키고 음수일 때에는 0으로 바꾸어버린다.

출처 : PyTorch로 시작하는 딥 러닝 입문(비선형 활성화함수 중 렐루함수), https://wikidocs.net/60683

특히 이미지 처리에 좋은 성능을 낸다고 한다(자율주행 연구실이다보니 이미지처리를 많이해서 렐루함수에 익숙한거였나!). 다시 생각해보니 픽셀에 값이 0~255 사이가 되어야하기 때문에 당연한거였다. 이래서 공부가 중요하다.
또하나 기능성(?) 클래스로 Flatten 이 있다. 이것도 익숙한 클래스였는데 사실 그냥 입력 차원을 일렬로 펼쳐주는 역할만 하는 거였다.
그렇다면 우리는 이미지처리를 하기 때문에 렐루를 사용하여 모델을 만들어보자!
성능이 아주 조금 좋아졌다. 다만 우리가 몇 개의 층을 더 추가해야 성능이 좋아질 지 어떻게 알 수 있을까?


옵티마이저

우리는
1) 몇 개의 은닉층을 추가할 지
2 각 은닉층의 뉴런 개수는 얼마로 정할 지
3) 활성화 함수는 무엇을 사용할 지
4) fit 메소드의 batch_size 는 얼마로 할 지(default = 32)
5) epochs는 얼마로 할 지

정해야한다. 또한 complie 메소드에서는 케라스의 default 경사하강법 알고리즘인 RMSprop를 사용했다. 케라스가 제공하는 다양한 종류의 경사하강법 알고리즘을 '옵티마이저(Optimizer)' 라고 부른다. 6번으로 추가...
먼저 우리가 배웠던 확률 경사하강법을 사용해보자.

model.compile(optimizer = 'sgd', loss='sparse_categorical_crossentropy', metrics = 'accuracy')

만 추가해주면 된다. 성능은 오히려 하락했으므로 결과를 캡쳐하진 않겠다. 만약 SGD 의 learning_rate = 0.01(default)를 바꾸고 싶다면 직접 선언하여 지정할 수 있다.
SGD클래스는 momentum=0(default)이다. 0보다 큰 값으로 지정하면 이전의 그레디언트를 가속도처럼 사용하는 모멘텀 최적화를 사용한다. 보통 0.9 이상을 지정한다고 한다. nesterov=False(default)는 네스테로프 모멘텀 최적화를 사용하고 기본 확률적 경사하강법보다 성능이 좋다고 한다.

상황에 따라 학습률을 조정할 수 있는 '적응적 학습률'을 사용하는 옵티마이저는 Adagrad, RMSprop 가 있다. 모멘텀 최적화와 RMSprop의 장점을 접목한 Adam도 있다. 개많다 장점을 접목시켰다니까 Adam을 써보겠다.

성능이 default인 RMSprop와 거의 같다. 0.5% 낮은 정도...? 사실 이정도면 한 20번 돌려서 검증해도 비슷하게 나올 것 같다.


3. 신경망 모델 훈련

딥러닝은 뭔가 층을 추가하면서 무엇을 넣을지, 혹은 어떤 함수를 쓸지를 결정하면서 내가 만드는 느낌이 든다. 왜 사람들이 딥러닝에 미쳐있는지 약간 알 것 같다. 이제부터는 다양한 기능들을 배워보겠다

손실곡선

fit() 메소드는 History 클래스 객체를 반환한다. 이 객체에는 loss, accuracy 값이 저장되어 있따. 이 데이터로 그래프를 그려보자!
실제로 잘 저장되어있으니 plot을 그려보자
에폭에 따라서 loss는 내려가고 정확도는 올라가는 것을 알 수 있다. 에폭을 20까지 올려보자 잘 훈련한 것 같습니다. 그럼 이제 우리를 항상 따라다니는 과소/과대적합 여부를 보기 위해 검증셋으로 테스트해봅시다.

이 내용을 기억하고 검증 손실을 계산해봅시다.
fit에 validation_data=(val_scaled, val_target) 파라미터를 추가한다.

에폭 5정도가 적당한 것 같다. 5를 넘어가면 과대적합이 일어나는 것으로 보인다. 정확도는 12가 적당한 것 같지만 5와 비슷하고, loss를 보면 5보다는 높은 편이다. 인공신경망에서 사용하는 경사하강법이 최적화하는 대상은 손실함수이므로, 모델이 잘 훈련되었는지 확인하려면 손실함수의 값을 확인하는 게 더 낫다고 한다.

이번에는 옵티마이저를 바꿔서 실험해보자. default인 RMSprop는 누적값과 새로운 gradient를 반비례로 구성해서 학습률을 결정한다.

rate=αxrate+(1α)g2rate = \alpha x rate + (1-\alpha)g^2

adam은 속도, gradient 누적값으로 학습률을 적용하고 누적이 많을 수록 적게 반영한다고 한다. 두 가지 모두 비교하기 위해서 같은 Plot을 그려보았다.
전반적으로 adam(Adaptive Moment)가 효과가 좋은 것을 볼 수 있다.


드롭아웃

드롭아웃(dropout)은 뉴런을 랜덤하게 dropOut 시켜서 overfitting을 방지한다. 몇 개를 드랍시킬지는 개발자가 정한다. 특정 뉴런에 의존하는 것을 줄이고 차원수를 줄일 수 있기 때문에 더 견고한 모델을 만들 수 있다. 드랍될 뉴런은 출력을 0으로 만들지만 사라지진 않는다. 다만, 평가할 때에 드랍아웃을 사용하면 모델이 바뀌므로 사용하면 안된다. 케라스에서는 알아서 평가, 예측 시에는 드롭아웃을 적용하지 않는다고 한다. 착하다.
과대적합이 줄었다. 대충 10정도 하면 더 좋을 것 같다.


모델 저장과 복원, 콜백

케라스에서는 save_weight()를 제공한다. 또 모델구조&파라미터를 저장하는 save()도 제공한다. 다시 불러오는 load_weight()도 제공한다. 착하다

콜백은 훈련 과정 중간에 '어떤 작업'을 할 수 있는 객체로 ModelCheckpoint 콜백으로 에포크마다 모델을 저장할 수 있다. save_best_only=True 로 가장 낮은 검증 점수 모델을 저장할 수 있다.
잘되네요. 오히려 이게 편할지도... 이렇게 훈련을 미리 중지하는 것을 '조기종료(early stopping) 이라고 한다.
patience 매개변수를 넣으면 검증 점수가 향상되지 않더라도 잠깐 기다려줄(?) 에폭 횟수를 지정한다. 이만큼 지났는데도 향상되지 않으면 종료시킨다.
최적은 epoch10(0부터 시작이므로 11번째) 이다. 이렇게 적절한 모델을 찾을 수 있을 것 같다!


7-1 확인문제

Q1. 어떤 인공 신경망의 입력 특성이 100개이고 밀집층에 있는 뉴런 개수가 10개일 때 필요한 모델 파라미터의 수는?
A1. 가중치 1000개 + 절편 10개

Q2. 케라스의 Dense 클래스를 사용해 신경망의 출력층을 만들고자 한다. 이 신경망이 이진분류모델이라면 activation 매개 변수에 어떤 활성화 함수를 지정해야하나?
A2. sigmoid

Q3. 케라스 모델에서 손실 함수와 측정 지표 등을 지정하는 메소드는?
A3. compile()

Q4. 정수 레이블을 타깃으로 가지는 다중 분류 문제일 때 케라스의 모델의 compile 에 지정할 손실 함수로 적절한 것은?
A4. 'sparse_categorical_crossentropy'

7-2 확인문제

Q1. 다음중 모델의 add()메소드를 올바르게 사용한 것은?
A1. model.add(keras.layers.Dense(10, activation='relu'))

Q2. 크기가 300x300 인 입력을 케라스 층으로 펼치려고 한다. 어떤 층을 사용해야할까?
A2. Flatten

Q3. 다음 중 이미지 분류를 위한 심층 신경망에서 널리 사용되는 케라스의 활성화 함수는?
A3. relu

Q4. 다음 중 적응적 학습률을 사용하지 않는 옵티마이저는?
A4. SGD

7-3 확인문제

Q1. 케라스 모델의 fit() 에서 검증세트를 올바르게 전달하는 코드는?
A1. model.fit(..., validation_data=(val_scaled, val_target))

Q2. 이전 층의 뉴런 출력 중 70% 만 사용하기 위해 드롭아웃 층을 추가하려고 한다. 다음중 옳게 설정한 것은?
A2. keras.layers.Dropout(0.3)

Q3. 케라스 모델의 가중치만 저장하는 메소드는?
A3. save_weights()

Q4. 케라스의 조기 종료 콜백을 사용하려고 한다. 3번의 에포크동안 손실이 감소하지 않으면 종료하고 최상의 모델 가중치를 복원하도록 올바르게 설정한 것은?
A4. EarlyStopping(monitor='val_loss', patience=3, restore_best_weights=True)


드디어 혼공학습단 진도가 끝났다.
수고했다 나 자신...

그리고 혼공족 모두...고생하셨어요...(좀비상태)

이제 남은 이미지를 위한 인공신경망과 순차데이터를 해내야한다... 애초에 자율주행에서는 이미지처리도 중요하고, 직전 스텝의 제어값와 피드백값도 중요하기 때문에 일단 해본다...

사실 이런 프로그램(?)은 일단 끝내는 사람이 몇 없기 때문에 맞고 틀리고를 떠나서 존버하는 사람이 이긴다.

존버로는 중3 때부터 유명(?)했기 때문에... 대학교 4학년이 되어도 그 성질머리는 변하지 않는다. 그 덕분에 우수혼공족에도 선정된 거 아닐까?(사실 불쌍하셨던거지...)


이번주~다음주 내에 chapter8, 9를 포스팅할 것이기 때문에 족장님 입장에서는 "작년에 왓떤 개발자가 죽지 않고 또 왔네" 싶을 수도 있을 것 같다. 하지만 이왕 시작한 거 끝을 보고 이왕 끝 본 김에 자랑도 하자!

٩(๑•̀Ⱉ•́๑)و 화이팅!

profile
자율주행 이동체를 배우고 있는 JB입니다.

0개의 댓글