실습 · 연습문제 2개
설정에서 객체 만들기: registry 패턴 config-registry
실험마다 모델 코드를 고치는 대신, 설정 파일(TOML·YAML)에 type과 인자를 적고 코드가 그 설정에서 객체를 만들게 하면 실험의 차이가 설정 파일의 diff로 남는다. 이 문제에서는 PyTorch 없이 그 뼈대를 만든다.
Registry 클래스의 두 메서드를 완성한다.
register(name)— 클래스(또는 함수)를name으로 등록하는 decorator를 반환한다. decorator는 받은 객체를 그대로 돌려준다. 이미 등록된 이름이면KeyError를 낸다(두 모듈이 같은 이름을 쓰는 사고를 막는다).build(cfg)— dictcfg에서 객체를 만든다.cfg["type"]으로 등록된 클래스를 찾고, 나머지 키를 키워드 인자로 넘겨 호출한다.- 등록되지 않은
type이면KeyError를 내고, 메시지에 등록된 이름들을 정렬해 포함한다(오타를 바로 찾을 수 있게). - 인자 값이
"type"키를 가진 dict이면 그 값도 먼저build한다. 인자 값이 list이면 원소마다 같은 규칙을 적용한다(중첩 설정). - 받은
cfg를 바꾸지 않는다. 같은 설정으로build를 두 번 호출해도 결과가 같아야 한다.
reg = Registry()
@reg.register("linear")
class Linear:
def __init__(self, d_in, d_out): ...
@reg.register("seq")
class Seq:
def __init__(self, layers): ...
model = reg.build({"type": "seq", "layers": [{"type": "linear", "d_in": 3, "d_out": 8},
{"type": "linear", "d_in": 8, "d_out": 1}]})
state_dict 비교와 접두사 정리 state-dict-diff
체크포인트를 불러올 때 가장 흔한 문제는 이름 불일치다. 다른 코드가 저장한 state_dict에는 module.이나 model. 같은 접두사가 붙어 있거나, 층 이름이 바뀌었거나, shape이 다른 텐서가 섞여 있다. strict=False로 그냥 불러오면 오류 없이 일부만 로드되므로, 로드 전에 무엇이 어긋나는지 먼저 확인해야 한다.
state_dict는 이름(문자열)에서 배열로 가는 dict다. 이 문제에서는 PyTorch 대신 NumPy 배열을 쓴다. 두 함수를 완성한다.
strip_prefix(state_dict, prefix)—prefix로 시작하는 키에서만 접두사를 떼어 낸 새 dict를 반환한다. 다른 키는 그대로 둔다. 원본 dict를 바꾸지 않는다. 예:{"module.fc.weight": W},"module."→{"fc.weight": W}.diff_state_dict(expected_shapes, state_dict)— 모델이 기대하는{이름: shape}과 불러온 state_dict를 비교해 다음 세 목록을 담은 dict를 반환한다. 각 목록은 이름을 정렬한 list다."missing": 모델에는 있는데 state_dict에 없는 이름"unexpected": state_dict에는 있는데 모델에 없는 이름"shape_mismatch": 양쪽에 다 있지만 shape이 다른 이름
diff_state_dict({"fc.weight": (2, 3), "fc.bias": (2,)},
{"fc.weight": np.zeros((3, 3)), "head.bias": np.zeros(1)})
# {"missing": ["fc.bias"], "unexpected": ["head.bias"], "shape_mismatch": ["fc.weight"]}
세 목록이 모두 비어 있어야 strict=True 로드가 성공한다.