본문 바로가기
Artificial Intelligence/Keras

[Tensorflow 2][Keras] Week 4 - Using the Model class to simplify complex architectures

by 개발자J의일상 2021. 4. 5.
반응형

본 포스팅은 다음 과정을 정리 한 글입니다.

 

Custom Models, Layers, and Loss Functions with TensorFlow

www.coursera.org/specializations/tensorflow-advanced-techniques

 

지난 시간 리뷰

2021.03.30 - [Artificial Intelligence/Keras] - [Tensorflow 2][Keras] Week 4 - Complex Architectures with the Functional API

 

[Tensorflow 2][Keras] Week 4 - Complex Architectures with the Functional API

본 포스팅은 다음 과정을 정리 한 글입니다. Custom Models, Layers, and Loss Functions with TensorFlow www.coursera.org/specializations/tensorflow-advanced-techniques 지난 시간 리뷰 2021.03.27 - [Artif..

mypark.tistory.com

Using the Model class to simplify architectures, Understanding Residual networks

 

지난 시간에 keras모델 클래스를 상속하여 모델을 확장하고, 캡슐화하고 코드에서 모델을 실행하는 방법을 살펴보았습니다.

wide and deep mode을 한 줄의 코드로 custom class를 생성하는 예제를 보았는데요. 

이를 사용하는 방법에 대한 몇 가지 예를 자세히 살펴보기 전에 이러한 방식으로 코드를 작성하는 것의 의미를 간략하게 요약해 보겠습니다.

 

우선, 모델 클래스를 사용하는 것은 Sequential or Functional API를 사용하여 모델을 생성하는 것과 동일합니다.

원래 모델 클래스를 서브 클래싱(subclassing)하고 확장하기 때문에 기본 제공 학습 평가 및 예측 루프를 사용할 수 있는 기능을 포함하여 모델 클래스에서 이미 있는 기능을 활용할 수 있습니다.

fit, evaluate, predict 같은 model function을 그대로 사용할 수 있다는 것입니다. 물론 원하는 경우 이 기능을 override 하고 customize도 할 수 있습니다. 

 

또한 우리는 저장 및 직렬화를 위한 API도 사용할 수 있습니다. 모델 또는 특정 가중치 집합 저장과 같은 작업을 쉽게 수행할 수 있습니다. 

 

마지막으로 모델을 요약하거나 시각화하는 데 사용하는 API도 사용할 수 있으므로 custom model에서도 model.summary 또는 plot_model을 사용할 수 있습니다.

 

Sequential or Functional API를 사용하는 경우 매우 복잡한 model을 만들 때 몇 가지 제한 사항이 있습니다.

 

예를 들어, 순환하지 않는 순차(방향성) 레이어로 구성된 방향 비순환 그래프와 같은 네트워크는 Sequential이나 Functional API로 구현하기 매우 적합합니다. 그 예로 MobileNetInception이 있습니다. 

 

이 경우 데이터는 입력에서 출력으로 흐르고 때로는 이미 살펴본 것처럼 여러 분기에 있지만 방향은 항상 동일하며 훈련이나 추론 중에 절대로 루프백 되지 않습니다. 따라서 재귀가 사용되는 네트워크 또는 아키텍처가 즉시 변경될 수 있는 동적 네트워크는 이러한 API를 사용하는 경우 구축하기가 매우 어려울 수 있습니다.

 

Sequential로는 구현이 불가능하고 Functional API로는 가능할 수는 있지만 많은 코딩이 필요합니다. 

그러니 Model subclassing(모델 상속)으로는 이러한 복잡한 시나리오를 쉽게 만들 수 있습니다.

 

모델을 subclassing 할 때 많은 장점이 있습니다.

 

첫 번째는 기존의 Sequential, Functional API를 사용하여 모델을 자연스러운 방식으로 확장한다는 것입니다. 이것은 혁신적인 변경이 아니며 광범위한 새로운 기술을 배울 필요가 없습니다.

 

두 번째는 이전에 Sequential, Functional API와 함께 사용한 모델 코드를 계속 사용할 수 있으므로 만들었던 코드를 재활용할 수 있습니다. 

 

세 번째는 subclassing 모델을 사용하여 아키텍처를 만들 때 전체를 교체하지 않고도 아키텍처의 일부를 교체할 수 있는 모듈 방식으로 아키텍처를 설계할 수 있습니다. 이를 통해 빠르게 실험을 시도할 수 있습니다. 

예를 들어 아키텍처 일부에 4개가 아닌 3개의 컨볼루션 레이어가 필요할 때, 전체 아키텍처에 대한 코드를 다시 작성하는 대신 3개의 레이어가 있는 컨볼루션 모델을 사용하고 해당 모듈만 4개로 변경할 수 있습니다. 

 

네 번째로 네트워크의 데이터 흐름을 변경할 수 있습니다. 데이터가 최상위 계층에서 하단 계층으로 이동하는 대신 분기 및 루프와 같은 것을 가질 수 있습니다.

 

결국 모델 클래스를 사용하고 subclassing 하면 강력하고 유연한 모델 아키텍처를 얻을 수 있습니다.

 

그럼 이제 Residual network(Resnet)에 대해 알아보려고 합니다. 일단 간략화된 버전부터 한번 살펴봅시다.

 

Resnet은 잠재적으로 정확도를 잃지 않으면서 네트워크의 깊이를 높이는데 도움이 되는 것으로 이미 입증이 된 방법입니다.

 

궁극적으로 입력에서 출력으로의 대체 경로를 갖는 네트워크이며, 아래와 같이 그림으로 표현할 수 있습니다.

아래 그림은 2개의 Dense layer로 이루어져 있습니다. 

아래 빨간색으로 표시된 부분을 일반적으로 입력으로부터 데이터가 통과하는 부분으로 main path라고 부르겠습니다.

 

하지만 resnet은 main path와는 다른 경로인 shortcut(지름길)이 있으며 input을 그대로 통과시킵니다.

결국 main path의 데이터와 shortcut을 통해 오는 input이 합산되어 데이터가 계산이 됩니다.

그래서 만약 코드 블록이나 함수에서 이것을 정의한다면 전체 flow를 아래와 같이 캡슐화할 수 있습니다. 

 

 

이제 더 큰 네트워크 아키텍처를 봅시다!

 

여기에는 두 가지 유형이 있는데요. 파란색으로 표기된 Residual Type 1과 주황색으로 표기된 Residual Type 2가 있습니다. 

우선 Residual Type 2 부분을 먼저 살펴보겠습니다. 여기 보면 세 개가 동일하게 연결되는 것을 볼 수 있는데요.

프로그래밍의 황금률 중 하나는 반복하지 않는 것입니다!!

 

Residual Type 2를 위처럼 세 번 연결하는 대신 세 번 실행하는 루프로 만들면 어떨까요? 굳이 위에 처럼 세 개의 코드 블록이 있어야 할 필요가 있을까요? 각 블록에서 동일한 가중치가 사용되므로 각각 독립적으로 세 개의 블록을 학습하기보다는 하나의 블록으로 만들어서 3번 호출하여 학습시키는 게 더 효율적인 방법 같습니다.

 

이 유형의 디자인은 Sequential API를 사용하고 있고 Functional API를 사용하는 경우 많은 스파게티 코드를 포함한다면 완전히 낯설게 보일 수 있습니다.

 

다음으로 모델 subclassing을 사용하여 이를 구현하는 방법을 살펴보겠습니다. 

 

Residual Type 1부터 구현해 봅시다. 

 

이 사용자 정의 레이어 블록은 Residual과 Convolution을 포함할 될 것이기 때문에 이것을 CNNResidual이라고 정의하겠습니다. 

 

지난 시간에 배웠던 것처럼 __init__을 통해 객체를 생성할 때 원하는 레이어 수와 각 레이어 내의 컨벌루션 필터 수에 대한 정보를 매개 변수로 전달합니다. 

 

이를 통해 CNNResidual 클래스 내에 hidden layer세트를 3x3 filter이고 layer의 개수만큼 연결하는 컨볼루션 2D layer를 정의할 수 있습니다. 루프를 매개변수에 지정된 layers의 숫자만큼 생성하는 것입니다.

 

그런 다음 call 함수 내에서 입력부터 시작하여 레이어를 통해 데이터 흐름을 만들 수 있습니다. 

 

Functional API를 사용하여 각 동작은 self.hidden에 저장된 동작을 따르며 self.hidden에 여러 레이어가 있으므로 각 동작을 반복합니다. 

 

이것이 Residual 네트워크 블록을 통과하는 주요 경로입니다.

 

그런 다음 마지막에 입력이 결과에 더해지는데 이것은 위에서 본 main path와 shortcut path의 조합으로 볼 수 있습니다. 

 

Residual Type 2 은 DNNResidual이며 이에 대한 코드는 매우 유사합니다.

 

컨볼루션 레이어 대신 Dense 레이어를 사용하여 self.hidden의 내부 레이어를 구성합니다.

init함수는 매우 유사하지만 Dense 레이어로 구성하고 컨볼루션 필터에서와는 parameter가 다른데 뉴런의 수를 채워줍니다.

 

이제 계층이 멋지게 추상화되었습니다. Call function도 위에 CNNResidual과 동일합니다.

 

이제 전체 모델 아키텍처를 다시 살펴봅시다. Residual Type 1을 CNNResidual으로 Residual Type 2를 DNNResidual로 대체할 수 있습니다. 

 

우리는 CNNResidual 한 번과 DNNResidual 세 번을 둘러싼 루프를 구현해야 합니다.

 

아래 그림의 오른쪽을 보면 우리가 원하는 아키텍처의 그림을 볼 수 있습니다. 

왼쪽에는 코드가 어떻게 구성되어야 하는지 설명이 되어 있습니다.

 

차근차근 살펴봅시다.

 

첫 번째는 상태가 선언된 모델의 초기화입니다. 

 

지금 우리는 모델의 레이어를 정의하고 있으므로 hidden1이라는 첫 번째 항목은 Relu에 의해 활성화된 30개의 뉴런이 있는 Dense 레이어를 생성합니다. 

 

앞서 CNNResidual를 생성했으므로 각각 32개의 필터를 포함하는 2개의 레이어로 초기화할 수 있습니다.

그 블록을 block 1이라고 선언합니다. 

 

그런 다음 각각 64개의 뉴런이 있는 두 개의 내부 레이어가 있는 DNNResidual을 정의합니다.

 

이 블록을 block 2로 선언하겠습니다. 우리는 이것을 3번 선언하지 않을 것이고 한 번의 선언으로 Loop x3을 구현해 볼 것입니다. 선언에는 이 것 한 개만 해줍니다!

 

 

그리고 output이 있는데 이것은 Dense에 unit이 1개 있는 레이어입니다.

 

이제 중요한 부분은 call function에서 이루어집니다.

 

여기가 아키텍처를 구성할 곳입니다. 

 

이것은 Functional API를 사용하고 있으므로 구문은 레이어를 정의한 다음 어떤 레이어를 따르는지 괄호 안에 넣는 것입니다.

 

따라서 hidden1은 inputs을 따르고 해당 chunk는 x라고 합시다.

 

block 1은 x라고 위에서 정의한 x를 따르고 이제 x를 다시 block 1으로 대입합니다. 보시다시피 CNNResidual 레이어입니다. 

이제 루프를 봅시다.

 

데이터가 동일한 DNNResidual 레이어를 세 번 반복하여 호출 블록에서 루프를 가질 수 있도록 했어야 했는데요.

 

DNNResidual이 3번 복사되지 않은 인스턴스가 하나뿐(self.block 2)이라는 것을 기억하셔야 합니다. 대신 cyclic network에 대해 3번 반복합니다.

※ for _ in range(1,3)이 아니고 range(1,4)를 해야 3번이 됩니다.

 

따라서 Functional API 구문에 따라 이것은 네트워크에 추가되고 이 chunk를 다시 x라고 합니다. 

 

마지막 요소는 출력 레이어로 chunk x를 따르도록 하고 그것을 return 해주면 끝입니다.

 

 

이제 우리는 하나의 간단한 compact 클래스로 캡슐화된 custom residual 레이어를 사용하는 cyclic 기능이 있는 완전한 모델을 만들었습니다. 

 

다음 시간에는 Resnet18이라는 유명한 네트워크 아키텍처를 살펴보고 여기에서 배운 내용을 사용하여 어떻게 구축할 수 있는지 살펴보겠습니다.

 

긴 글 읽어주셔서 감사합니다.

300x250

댓글