페이지

2022년 8월 19일 금요일

16.2 세대 순으로 꺼내기

 지금까지의 수정을 반영하여 일반적인 계산(순전파)을 하면 모든 변수와 함수에 세대가 설정됩니다. 구체적인 예로 [그림 16-3]과 같은 계산 그래프를 살펴보죠.


[그림 16-3]을 보면 함수 A, B, C, D의 세대는 차례로 0,1,1,2입니다. 이렇게 세대가 설정되어 있으면 역전파 때 함수를 올바른 순서로 꺼낼 수 있습니다. 예를 들어 함수 A보다 세대가 큰 B와 C를 먼저 꺼내게 됩니다.


이전 단계에서 이야기한 것처럼 Variable클래스의 backward메서드 안에서는 처리할 함수의 후보들을 funcs리스트에 보관합니다. 따라서 funcs에서 세대가 큰 함수부터 꺼내게 하면 올바른 순서로 역전파를 할 수 있습니다.


이어서 함수를 새대 순으로 꺼낼 차례입니다. 그 준비 작업으로 더미(dummy) DeZero함수를 사용하여 간단한 실험을 해보겠습니다.

generations = [2014,2]
funcs = []

for g in generations:
  f = Function()   # 더미 함수 클래스
  f.generation = g
  funcs.append(f)

[f.generation for f in funcs]

[2, 0, 1, 4, 2]

이와 같이 더미 함수를 준비하고 funcs리스트에 추가합니다. 그런 다음 이 리스트에서 세대가 가장 큰 함수를 꺼내보겠습니다.

funcs.sort(key=lambda x: x.generation)  # 리스트 정렬
[f.generation for f in funcs]

[0, 1, 2, 2, 4]

f = funcs.pop()   # 가장 큰 값을 꺼낸다.
f.generation

4

코드에서 보듯 리스트의 sort 메서드를 이용하여 generation을 오름차순으로 정렬합니다. 이 메서드의 인수인 key=lambda x: x.generation은 '리스트의 원소를 x라고 했을 때 x.generation을 키로 사용해 정렬하라'라는 뜻입니다. 정렬 후 pop메서드를 써서 리스트의 끝 원소를 꺼내면 자연스럽게 세대가 가장 큰 함수를 얻을 수 있습니다.


지금 우리가 원하는 것은 세대가 가장 큰 함수를 꺼내는 것뿐입니다. 따라서 모든 원소를 정렬할 필요 없이 '우선순위 큐'를 이용하면 더 효율적입니다. 이 책에서는 우선순위 쿠까지는 구현하지 않습니다. 관심 있는 분은 직접 구현해보기 바랍니다.(힌트: 파이썬에는 heapq 라는 모듈이 있습니다).


댓글 없음: