과제 6. 인터프리터와 역전파 학습(Interpreter & Autograd) 구현하기

   

  • 제출기한 : 6월 8일 월요일 11:59pm
  • 주의: 채점은 스크립트로 자동으로 이루어지기에 폴더 이름이 잘못되면 0점을 받게 됩니다.

제출 방법

아래 두 가지를 하나의 압축 파일(학번_hw6.zip)에 담아 Uclass 과제 게시판에 업로드해주세요.

  1. 프로젝트 디렉토리 — 학번을 이름으로 하는 프로젝트 디렉토리 (예: 202448015/)
  2. 실행 화면 캡처dune test 실행 결과 화면, hw6_screenshot.png
    • 캡처 화면에는 모든 테스트 케이스의 통과 결과가 모두 보여야 합니다.

      코드 파일만 제출하거나 실행 화면이 누락된 경우 감점될 수 있습니다.

과제 진행 시 어려운 점이 있으면 온라인 강의실 게시판을 이용해 질문하세요. 게시판을 통해 하기 어려운 질문이라면 아래 TA 이메일을 통해 문의하시기 바랍니다.

  • TA 이메일: seongminkim16@gmail.com

   

과제 소개

마지막 관문입니다! 우리는 앞선 과제들을 통해 수학 엔진(HW4), 파서(HW3), 차원 검사기(HW5)를 모두 구축했습니다. 그러나 이 코드 트리(AST)들은 어떻게 평가되고 실행되어 훈련되는 것일까요?

이번 최종 과제에서는 AST 노드들을 순회하며 실제 텐서 값을 넣고 연산을 수행하는 명령어 처리기(Interpreter)와 기울기를 타고 내려와 파라미터를 업데이트하는 역전파(Autograd/Backward) 코어를 스스로 100% 통합 및 완성합니다.

   

평가 코어 (Evaluation in Interpreter)

우리가 파싱한 노드 하나를 볼 때마다 실제로 무언가 액션을 실행해서 OCaml 상의 값(Value)을 만들어 내야 합니다. eval env expr 시스템은 주어진 expr트리 형태를 따라 밑바닥부터 파고 들어간 뒤 연산들을 돌려줍니다.

예를 들어 Forward (m, x) AST 노드를 만났다면?

  1. 내부에 있는 모델 트리 m을 먼저 평가해 실제 행렬 세트 값 (VModel)을 뽑아냅니다.
  2. 텐서 트리 x를 평가해 입력 텐서 값 (VTensor)을 뽑아냅니다.
  3. 두 스칼라 덩어리를 forward_model 이라는 순전파 함수에 태워 최종 예측값 벡터를 도출합니다!

   

순전파 레이어 (Forward Pass)

코드 안에 존재하는 forward_model (m: model_val) (x: vec) 함수를 구현해야 합니다. m이 선형 회귀(MLinear (w, b)) 일 때는 HW4에서 구현한 mat_vec_mul과 벡터 덧셈 연산을 이용해 $W \times x + b$ 수식을 OCaml로 표현하세요. 이 과정이 곧 딥러닝 1사이클에서의 예측값 추론 과정입니다.

   

역전파 최적화 루프 (Backward Pass & SGD)

오차를 계산했다면 이젠 가중치들을 역추적하여 깎아내야(Gradient Descent, SGD) 합니다! backward_model m x dy lr 함수에 출력부에서의 오차 미분값(dy)이 첫 인자로 진입합니다.

A. 연쇄 법칙 (Chain Rule for Linear Layer)

MLinear 층을 지날 때:

  1. 입력 기울기(Input gradient)인 $dx$ 는 수식 $dx = W^T \cdot dy$에 의해 계산되어 이전 층으로 반환(Return)해줘야 합니다.
  2. 가중치 기울기(Weight gradient)인 $dW$ 는 $dy \cdot x^T$(외적)에 의해 도출됩니다.
  3. 편향 기울기는 그대로 $db = dy$ 입니다.

B. 파라미터 업데이트의 불변성 딜레마

OCaml은 순수 함수 기반이라 MLinear 안의 행렬 데이터를 덧씌울 수 없습니다. 따라서 가중치를 빼기 연산한 새로운 $\text{new_W} = W - lr \cdot dW$ 모델 노드 자체를 아예 새롭게 통보하여 반환하는 형식으로 뼈대를 개조해야 합니다. (이 함수는 dx새로 업데이트된 Model 쌍을 반환해야 합니다!)

   

예제 프로그램

아래의 TensorLang 코드는 간단한 모델의 학습 전후 예측값을 비교하는 프로그램입니다.

let m = seq (linear 2 4) (linear 4 1) in
let x = tensor [1.0; 0.5] in
let y = tensor [1.0] in
let pred_before = forward m x in
let m2 = train m x y 100 0.01 in
let pred_after = forward m2 x in
(pred_before, pred_after)

모든 구현이 완벽하게 끝났다면 제공된 필기체(MNIST) 훈련 데이터셋과 테스트 셋을 돌려 정확도 테스트를 실행해 보실 수 있습니다!

let x_train = load_x "train_digits.csv" in
let y_train = load_y "train_digits.csv" in
let x_test  = load_x "test_digits.csv" in
let y_test  = load_y "test_digits.csv" in

let m = seq (linear 64 32) (seq relu (linear 32 10)) in
let trained_m = train m x_train y_train 50 0.1 in

accuracy trained_m x_test y_test

이 과제에서 만든 신경망 엔진은 생각보다 정교해서 간단한 인식 작업을 훌륭히 수행합니다.

   

테스트 및 실행

구현을 마쳤다면, 터미널(Terminal)에서 아래 커맨드를 입력하여 코드의 정합성을 확인합니다.

dune test