실습 · 연습문제 2개
지연 계산하는 batch generator lazy-batches
샘플이 하나씩 나오는 iterable(파일의 줄, 센서 스트림, 다른 generator)을 받아 크기 batch_size의 리스트로 묶어 내보내는 generator 함수 batched(samples, batch_size)를 완성한다.
list(batched(range(7), 3))
# [[0, 1, 2], [3, 4, 5], [6]]
규칙은 다음과 같다.
- 마지막 batch는
batch_size보다 작을 수 있다. 빈 batch는 내보내지 않는다. batch_size가 1보다 작으면ValueError를 낸다. 이 검사는 첫 batch를 요청하기 전, 함수를 호출하는 순간 이루어져야 한다.- 입력을 한꺼번에 읽지 않는다. 끝이 없는 스트림(
itertools.count())에서도 앞의 몇 batch를 꺼낼 수 있어야 하고, batch 하나를 꺼낼 때 입력에서 정확히 그 batch에 필요한 만큼만 읽어야 한다. - 입력은 리스트가 아닐 수 있다. 인덱싱(
samples[i])이나len(samples)를 쓰지 않는다.
힌트: iter()로 iterator를 만든 뒤 itertools.islice로 필요한 만큼만 꺼낼 수 있다. generator 함수 본문은 첫 next() 호출 때 실행되기 시작한다는 점이 인자 검사 규칙과 어떻게 얽히는지 생각한다.
원본을 건드리지 않는 설정 병합 merge-config
실험 설정은 흔히 중첩 dict로 둔다. 기본 설정 base에 실험별 변경 사항 overrides를 덮어써 새 설정을 만드는 함수 merge_config(base, overrides)를 완성한다.
base = {"model": {"width": 64, "depth": 2}, "tags": ["baseline"]}
overrides = {"model": {"depth": 4}, "seed": 1}
merge_config(base, overrides)
# {"model": {"width": 64, "depth": 4}, "tags": ["baseline"], "seed": 1}
규칙은 다음과 같다.
- 같은 키의 값이 둘 다 dict이면 재귀적으로 병합한다.
- 그 밖의 경우(값이 dict가 아니거나 한쪽만 dict)에는
overrides의 값이 이긴다. base와overrides는 어떤 깊이에서도 바뀌면 안 된다.- 반환한 설정은 입력과 객체를 공유하지 않아야 한다. 반환값의 리스트에 원소를 추가해도
base의 리스트가 바뀌면 안 된다.
테스트는 결과 값뿐 아니라, 병합 뒤 입력이 그대로인지와 결과를 수정했을 때 입력이 영향을 받지 않는지를 확인한다.
힌트: dict(base)나 base.copy()는 얕은 복사다. 어느 단계에서 깊은 복사가 필요한지 생각한다.