call() 이 계약
Layer 가 *하는 일* 은 전부 call() 안에 살아. 입력 tensor 받아서 출력 tensor 돌려주고, 시그니처엔 Keras 가 해당될 때 자동으로 넘겨주는 두 인자가 있어:
training— train 과 inference 사이를 가르는 boolean. Dropout 은training=True일 때만 unit 을 떨구고, BatchNormalization 은 train 중엔 현재 batch 통계를, inference 중엔 누적된 moving 통계를 써. layer 가 둘 중 하나라도 감싸면 이 flag 를 받아서 아래로 넘겨야 해.mask— 어느 timestep 이 진짜고 어느 게 padding 인지 표시하는 optional boolean tensor. attention / recurrent layer 가 padding 자리를 무시할 수 있게 해줘.
Python 자유가 빛을 발하는 자리
call() 은 그냥 메서드라서 안에 진짜 제어 흐름을 넣을 수 있어 — if training: 분기, loop, shape 의존 계산. 이게 Functional API 대신 subclass 하는 이유 그 자체야 (Code block 참고). 그 자유를 portable 하게 유지하는 단 하나의 규율: tensor 연산은 keras.ops 로 하고, backend 의 native op 은 절대 쓰지 마. keras.ops.relu(x) 로 쓰면 같은 layer 가 TensorFlow / PyTorch / JAX 에서 안 바뀌고 돌아가. dynamic shape 도 마찬가지 — keras.ops.shape(x)[0] 처럼 portable form 으로.