Structuring Your TensorFlow Models

이 글은 저자의 허락을 받아 번역한 글 입니다. 원문 링크

TensorFlow에서 모델을 정의하다보면 어느새 많은 양의 코드가 생성된 경험이 있을 것 입니다. 어떻게 하면 가독성과 재사용성이 높은 코드로 구성할 수 있을까요? 여기에서 실제 동작하는 예시 코드를 확인하실 수 있습니다. Gist Link

Defining the Compute Graph

모델 당 하나의 클래스부터 시작하는 것이 좋습니다. 그 클래스의 인터페이스는 무엇인가요? 일반적으로 모델은 input data와 target placeholder를 연결하며 training, evaluation 그리고 inference 관련 함수를 제공합니다.

위의 코드가 기본적으로 TensorFlow codebase에서 모델이 정의되는 방식입니다. 그러나 여기에도 몇 가지 문제가 있습니다. 가장 중요한 문제는 전체 그래프가 단일 함수 생성자로 정의된다는 점 입니다. 이렇게 되면 가독성이 떨어지며 재사용이 어렵습니다.

Using Properties

함수가 호출 될 때마다 그래프는 확장되기 때문에 함수로 분할하는 것만으로는 부족합니다. 따라서 함수를 처음 호출하는 시점에 operation들이 그래프에 추가되도록 해야합니다. 이러한 방식을 기본적으로 lazy-loading이라고 합니다.

위의 방식이 첫 번째 예제보다 훨씬 좋습니다. 이제 코드는 독립적인 함수로 구성되어 있습니다. 그러나 아직 코드는 lazy-loading으로 인해 약간 복잡해보입니다. 이를 어떻게 개선 할 수 있는지 보도록 하겠습니다.

Lazy Property Decorator

파이썬은 아주 유연한 언어입니다. 이제 마지막 예제에서 중복 코드를 제거하는 방법을 보여드리겠습니다. 우리는 @property처럼 동작하지만 한번만 함수를 평가하는 decorator를 사용할 것입니다. decorator는 함수(접두사를 앞에 붙임)의 이름을 따서 멤버에 결과를 저장하고 나중에 호출되는 시점에 해당 값을 반환합니다. custom decorator를 아직 사용해본적이 없다면, 이 가이드를 참고하시면 됩니다.

위의 decorator를 사용해서 예시 코드는 아래와 같이 간결해졌습니다.

생성자에서 property를 언급했다는 부분이 중요합니다. 이렇게 구성한다면 tf.initialize_variables()를 실행할 때 전체 그래프가 정의됩니다.

Organizing the Graph with Scopes

이제 코드에서 모델을 정의하는 부분은 깔끔해졌지만, 그래프의 연산 부분은 여전히 복잡합니다. 만일 그래프를 시각화한다면, 서로 연결되어 있는 노드가 많이 나타날 것 입니다. 이를 해결하기 위한 방법은 tf.name_scope('name') 또는 tf.variable_scope('name')을 사용하여 각 함수의 내용을 래핑하는 것 입니다. 이렇게 하면 노드들은 그래프 상에서 그룹화되어 있을 것 입니다. 우리는 이전에 만들었던 decorator를 이용하여 이를 자동으로 적용시켜보겠습니다.

lazy caching 이외에도 TensorFlow의 기능을 포함시키므로 decorator에 새로운 이름을 지정했습니다. 그 외의 나머지 부분은 이전과 동일합니다.

이제 @define_scope decorator를 통해 tf.variable_scope()에 인자를 전달할 수 있습니다. 예를 들어 해당 scope에 default initializer를 정의할 수 있습니다. 이 부분이 더 궁금하다면 전체 예제 코드를 확인해보시면 됩니다.

Reference

https://danijar.com/structuring-your-tensorflow-models/