관리 메뉴

클라이언트/ 서버/ 엔지니어 "게임 개발자"를 향한 매일의 공부일지

딥러닝을 시작합니다 3 - 심층 신경망 1 : 심층 신경망 만들기 및 층을 추가하는 다른 방법 본문

인공지능/딥러닝

딥러닝을 시작합니다 3 - 심층 신경망 1 : 심층 신경망 만들기 및 층을 추가하는 다른 방법

huenuri 2024. 10. 25. 10:30

인공 신경망 공부를 마치고 드디어 심층 신경망에 대해서 공부해보려고 한다. 인공 신경망에 층을 여러 개 추가하여 패션 MNIST 데이터셋을 분류하면서 케라스로 심층 신경망을 만드는 방법을 자세히 배우게 된다.

 

지난 시간 복습

 

이렇게 층과 모델은 분리되어 관리하고 있다.


 

 

 

시작하기 전에

이전 절에서 만들었던 인공 신경망의 성능을 더 높여보려고 한다.


 

 

 

2개의 층

다시 케라스 API를 사용해서 패션 MNIST 데이터셋을 불러오겠다.

 

 

그다음 이미지 픽셀값을 0~255 범위에서 0~1 사이로 변환하고, 28 x 28 크기의 2차원 배열을 784 크기의 1차원 배열로 펼친다. 마지막으로 사이킷런의 train_test_split() 함수로 훈련 세트와 검증 세트로 나눈다.

 

 

 

 

인공 신경망 모델에 층을 2개 추가해보겠다. 여기서 만들 모델의 대략적인 구조는 다음 그림과 같다.

 

앞에서 만든 신경망 모델과 다른 점은 입력층과 출력층 사이에 밀집층이 추가된 것이다. 이렇게 입력층과 출력층 사이에 있는 모든 층을 은닉층이라고 부른다.

은닉층에는 주황색 원으로 활성화 함수가 표시되어 있다. 활성화 함수는 신경망 층의 선형 방정식의 계산값에 적용하는 함수이다. 출력증에 적용했던 소프트맥스 함수도 활성화 함수이다. 

 

출력층에 적용하는 활성화함수는 종류가 제한되어 있다. 이진 부류일 경우 시그모이드 함수를 사용하고, 다중 분류일 경우 소프트맥스 함수를 사용한다. 은닉층의 활성화 함수는 비교적 자유롭다. 대표적으로 시그모이드 함수와 볼 렐루 함수 등을 사용한다.

 

그런데 은닉층에 왜 활성화 함수를 적용할까? 다음 그림에 있는 2개의 선형 방정식을 생각해 보자. 두 번째 식에 첫 번째 식을 대입하면 오른쪽으로 합쳐질 수 있다.

 

 

신경망도 마찬가지다. 선형 계산을 적당하게 비선형적으로 비틀어 주어야 다음 층의 계산과 단순히 합쳐지지 않고 나름의 역할 을 할 수 있다.

 

 

많이 사용하는 활성화 함수 중 하나는 시그모이드 함수이다.

 

이 함수는 뉴런의 출력 z값을 0과 1 사이로 압축한다. 그럼 시그모이드 활성화 함수를 사용한 은닉층과 소프트맥스 함수를 사용한 출력층을 캐라스의 Dense 클래스로 만들어보겠다.

캐라스에서 신경망의 첫 번째 층은 input_shape 매개변수로 입력의 크기를 꼭 지정해 주어야 한다.

 

 

dense1이 은닉층이고 100개의 뉴런을 가진 밀집층이다. 여기서 한 가지 제약 사항이 있다면 적어도 출력층의 뉴런보다는 많게 만들어야 한다. 클래스 10개에 대한 확률을 예측해야 하는데 이전 은닉층의 뉴런이 10개보다 적다면 뾰족한 정보가 전달될 것이다.

dense2는 출력층이다. 10개의 클래스를 분류하므로 10개의 뉴런을 두었고 활성화 함수는 소프트맥스 함수로 지정했다.


 

 

 

 

심층 신경층 만들기

앞에서 만든 dense1과 dense2 객체를 Sequential 클래스에 추가하여 심층 신경망을 만들어보겠다.

 

 

Sequential 클래스의 객치를 만들 때 여러 개의 층을 추가하려면 이처럼 dense1과 dense2를 리스트로 만들어 전달한다. 여기서 주의할 것은 출력층을 가장 마지막에 두어야 한다는 것이다. 이 리스트는 가장 처음 등장하는 은닉층에서 마지막 출력층의 순서로 나열해야 한다.

 

인공 신경망의 강력한 성능은 바로 층을 추가하여 입력 데이터에 대해 연속적인 학습을 진행하는 능력에서 나온다. 물론 두 개 이상의 층을 추가할 수 있다.

 

케라스는 모딜 summary() 메서드를 호출하면 층에 대한 유용한 정보를 얻을 수 있다.

 

 

첫 줄에 모델의 이름이 나온다. 그다음 이 모델에 들어 있는 층이 순서대로 나열된다. 이 순서는 맨 처음 추가한 은닉층에서 출력층의 순서대로 나열된다. 층마다 층 이름, 클래스, 출력 크기, 모델 파라미터 개수가 출력된다. 

 

 

 

출력 크기를 보면 (None, 100)이다. 첫 번째 차원은 샘플의 개수를 나타낸다. 샘플 개수가 아직 정의되어 있지 않기 때문에 None이다. 왜 그럴까? 케라스 모델의 fit() 메서드에 훈련 데이터를 주입하면 이 데이터를 한 번에 모두 사용하지 않고 잘게 나누어 여러 번에 걸쳐 경사 하강법 단계를 수행한다. 바로 미니배치 경사 하강법을 사용하는 것이다.

따라서 샘플 개수를 고정하지 않고 어떤 배치 크기에도 유연하게 대응할 수 있도록 None으로 설정한다. 이렇게 신경망 층에 입력되거나 출력되는 배열의 첫 번째 차원을 배치 차원이라고 부른다.

 

두 번째 100은 쉽다. 은닉층의 뉴런 개수는 100개로 두었으니 100개의 출력이 나온다. 즉 샘플마다 784개의 픽셀값이 은닉층을 통과하면서 100개의 특성으로 압축되었다.

마지막으로 모델 파라미터 개수가 출력된다. 이 층은 Dense 층이므로 입력 픽셀 784개와 100개의 모든 조합에 대한 가중치가 있다. 그리고 뉴런마다 1개의 절편이 있다.

 

 

두 번째 층의 출력 크기는 (None, 10)이다. 배치 차원은 동일하게 None이고 출력 뉴런 개수가 10개이기 때문이다. 이 층의 모델 파라미터 개수는 몇 개일까?

 

100개의 은닉층과 뉴런과 10개의 출력층 뉴런이 모두 연결되고 출력층의 뉴런마다 하나의 절편이 있기 때문에 총 1010개의 모델 파라미터가 있다.

summary() 메서드의 마지막에는 총 모델 파라미터 개수와 훈련되는 파라미터 개수가 동일하게 79,510개로 나온다. 은닉층과 출력층의 파라미터 개수를 합친 값이다. 


 

 

 

 

층을 추가하는 다른 방법

모델을 훈련하기 전에 Sequential 클래스에 층을 추가하는 다른 방법을 알아보겠다. Dense1, Dense2 객체를 따로 저장하여 쓸 일이 없기 때문에 다음처럼 Sequential 클래스의 생성자 안에 바로 Dense 클래스의 객체를 만드는 경우가 많다.

 

 

 

이렇게 작업하면 추가되는 층을 한눈에 쉽게 알아보는 장점이 있다. 이전과 달리 이번에는 Sequential 클래스의 name 매개변수로 모델의 이름을 지정했다.

 

 

2개의 Dense 층이 이전과 동일하게 추가되었고 파미터 개수도 같다. 바뀐 것은 모델 이름과 층 이름이다. 여러 모델과 많은 층을 사용할 때 name 매개변수를 사용하면 구분하기 쉽다.

Sequential 클래스에서 층을 추가할 때 가장 널리 사용하는 방법은 모델의 add() 메서드이다.

 

 

이 방법은 한눈에 추가되는 층을 볼 수 있고 실행 시 동적으로 층을 선택하여 추가할 수 있다. 

 

이제 모델을 훈련해 보겠다.

 

 

훈련 세트에 대한 성능을 보면 추가된 층이 성능을 향상했다는 것을 잘 알 수 있다. 인고공 신경망에 몇 개의 층을 추가하더라도 compile() 메서드와 fit() 메서드의 사용법은 동일하다. 이것이 케라스 API의 장점이다.

 


 

 

 

학습을 마치고

이번 시간에는 심층 신경망의 2개의 층과 심층 신경망을 만드는 방법 등에 대해서 공부해 보았다. 처음에는 먼저 이론 학습을 모두 진행한 다음에 실습 프로젝트로 코드를 실행하며 과정을 학습일지로 기록했었다. 하지만 지난번에 머신러닝 복습을 하면서 이렇게 하면 내용이 머릿속에 잘 기억되지 않는다는 것을 알게 되었다.

대신 두 개의 단원으로 나눠서 공부를 하게 되었다.

 

다음 포스트에 이어서 심층 신경망 공부를 이어갈 것이다.