AI VIDEO BRIEFING

파이토치 입문 핵심 7가지 개념 — 텐서와 자동미분부터 커스텀 신경망, 불확실성, 배포까지

텐서와 자동미분에서 시작해 선형회귀와 다층 퍼셉트론, CNN과 RNN, 커스텀 손실함수, 불확실성 모델링, TorchServe 배포까지 파이토치의 핵심을 코드 흐름을 따라 한 줄기로 꿰어 정리한다.

파이토치를 일곱 가지 개념으로 정리하면 이렇게 된다 영상 대표 이미지

핵심 메시지

  • 파이토치 텐서는 넘파이 배열과 비슷하지만 GPU 연산에 최적화돼 있고, 그래디언트 정보를 함께 담을 수 있다는 점이 결정적으로 다르다.
  • requires_grad를 켜면 파이토치가 연산을 추적해 계산 그래프를 만들고, backward 한 줄로 연쇄법칙을 자동 적용한다. 사용자는 순전파만 정의하면 된다.
  • 그래디언트는 덮어쓰이지 않고 누적된다. 이는 버그가 아니라 설계이며, 그래서 zero_grad로 초기화하는 습관이 필요하다.
  • nn.Module을 상속하고 forward만 정의하면 CNN, 잔차 블록, 인코더-디코더까지 어떤 구조든 만들 수 있다. forward 안에 반복문과 조건문을 써도 그래디언트는 흐른다.
  • torch.distributions를 쓰면 가중치를 확률분포로 다루는 베이지안 신경망처럼 불확실성까지 학습하는 모델을 만들 수 있다.

쉽게 이해하기

영상은 파이토치를 일곱 개의 개념으로 나눠 설명한다. 출발점은 텐서다. 텐서는 벡터와 행렬을 일반화한 다차원 배열로, 넘파이 배열과 문법이 비슷해 원소별 덧셈이나 곱셈을 그대로 쓸 수 있다. 차이는 GPU 연산에 최적화돼 있다는 점, 그리고 그래디언트 정보를 저장할 수 있다는 점이다.

텐서 다루기에서 특히 강조되는 것은 전치와 행렬곱, 브로드캐스팅, 배치 행렬곱이다. 모양이 다른 텐서끼리 연산하면 파이토치가 작은 쪽을 자동으로 늘려 맞추는데, 편리한 만큼 의도치 않은 오류가 끼어들 수 있으니 항상 염두에 두라고 당부한다. 배치 행렬곱은 10개의 3×4 행렬과 10개의 4×5 행렬을 한 번에 곱해 10×3×5를 얻는 식으로 동작하며, 트랜스포머의 어텐션에서 어떤 쌍이 서로 관련이 높은지 병렬로 계산할 때 바로 이 연산이 쓰인다.

두 번째 축은 자동미분이다. requires_grad를 켠 텐서에 연산을 하면 파이토치가 어떤 변수가 어떤 변수에서 파생됐는지를 기록한 계산 그래프를 만든다. backward를 부르면 그래프를 거꾸로 훑어 연쇄법칙을 적용하고 결과를 각 텐서의 grad에 채워 넣는다. 영상은 dw/dz, dz/dy, dy/dx가 각각 10, 1, 4일 때 곱해서 40이 나오는 예를 손으로 따라가며, 실제로는 backward 한 줄이면 같은 40을 얻는다는 것을 보여 준다.

여기서 자주 헷갈리는 지점이 그래디언트 누적이다. 같은 입력 텐서에 대해 서로 다른 출력을 두 번 역전파하면 grad 값이 3과 2로 각각 덮어쓰이는 것이 아니라 5로 더해진다. 여러 번의 순전파에 걸쳐 그래디언트를 합칠 수 있게 하려는 의도적 설계이며, 원치 않는다면 zero_grad로 직접 비워야 한다. 이 성질은 나중에 GPU 메모리를 늘리지 않고 배치 크기를 키우는 그래디언트 누적 기법으로 다시 활용된다.

개념이 갖춰지면 실습으로 넘어간다. 면적과 연식으로 집값을 예측하는 선형회귀에서 데이터는 정규화하고, 입력과 정답은 상수로 두고 가중치와 편향에만 requires_grad를 켠다. 예측을 만들고 평균제곱오차로 손실을 구한 뒤 backward를 부르고, 학습률만큼 가중치를 빼는 것이 한 스텝이다. 학습이 끝나면 면적 가중치는 양수, 연식 가중치는 음수로 수렴해 상식과 맞아떨어진다. 지그재그 모양의 데이터에는 직선으로는 부족하므로 nn.Sequential에 선형 층과 ReLU를 번갈아 쌓은 다층 퍼셉트론을 쓴다.

후반부는 확장이다. 이미지에는 합성곱 층으로 지역 특징을 뽑고 평탄화한 뒤 선형 층을 거쳐 로짓을 만들고, 소프트맥스로 확률분포로 바꿔 교차 엔트로피로 학습한다. nn.Module을 상속해 forward만 정의하면 LeNet 같은 구조도, 출력을 원래 입력에 다시 더하는 잔차 블록도 그대로 표현된다. 시퀀스에는 GRU와 인코더-디코더 구조를 쓰는데, forward 안에 반복문과 조건문을 넣어 교사 강요를 구현해도 그래디언트는 문제없이 흐른다. 여기에 손실함수와 활성화 함수 선택, Dataset과 DataLoader, 그래디언트 클리핑과 학습률 스케줄러, 그리고 가중치를 분포로 다루는 베이지안 신경망까지 이어진다. 마지막으로 텐서보드와 wandb를 이용한 관측, TorchServe를 이용한 배포 절차를 다루고, 파이토치 라이트닝과 Accelerate, Optuna, ONNX, scikit-learn 등 함께 익히면 좋은 라이브러리 목록으로 마무리한다.

주요 인사이트

  • 파이토치의 설계 철학은 '순전파만 쓰면 나머지는 알아서 한다'로 압축된다. 사용자는 입력을 출력으로 바꾸는 계산 그래프만 정의하고, 역전파와 그래디언트 전달은 프레임워크가 맡는다.
  • 수학적으로 미분이 안 되는 연산도 파이토치 안에서는 흐른다. torch.max는 원소별로 비교해 큰 값 쪽으로 그래디언트를 보내고, torch.where는 조건에 따라 두 입력 중 하나에서 값을 가져오며 의존성 그래프를 양쪽으로 나눈다.
  • 브로드캐스팅은 편의 기능이자 버그의 온상이다. 모양이 다른 텐서를 더했을 때 에러 대신 조용히 확장된 결과가 나오므로, 의도한 모양인지 매번 확인하는 습관이 필요하다.
  • 그래디언트 누적이 기본값이라는 점을 이해하면 zero_grad는 외워야 할 주문이 아니라 자연스러운 귀결이 된다. 같은 성질이 큰 배치를 흉내 내는 기법으로도 쓰인다.
  • 모델이 하나의 값만 내놓아야 할 이유는 없다. 평균과 로그 분산을 함께 출력하게 하면, x가 커질수록 분산이 커지는 데이터에서 예측 구간이 벌어지는 모습까지 학습된다.

자주 묻는 질문

넘파이 배열 대신 파이토치 텐서를 쓰는 이유가 뭔가요?

문법은 비슷하지만 파이토치 텐서는 GPU 연산에 최적화돼 있고, 그래디언트 정보를 함께 저장할 수 있습니다. 이 그래디언트 정보가 자동미분의 토대가 됩니다.

zero_grad는 왜 매번 불러야 하나요?

파이토치에서 그래디언트는 덮어쓰이지 않고 grad 속성에 더해지기 때문입니다. 영상의 예에서 같은 입력에 대해 두 번 역전파하면 3과 2가 더해져 5가 됩니다. 여러 순전파의 그래디언트를 합칠 수 있게 한 의도적 설계이므로, 원치 않으면 직접 비워야 합니다.

커스텀 모델을 만들려면 무엇을 구현해야 하나요?

nn.Module을 상속하고 부모 생성자를 호출한 뒤, 생성자에서 초기화한 학습 파라미터는 파이토치가 자동으로 추적합니다. 그다음 forward 함수를 재정의해 입력이 출력으로 바뀌는 단계를 적으면 되고, 미분 가능한 연산이기만 하면 어떤 파이토치 함수든 쓸 수 있습니다.

원문과 출처

이 글은 원본 영상의 자막을 바탕으로 한국어 독자를 위해 요약했습니다. 전체 맥락과 최신 정보는 원문에서 확인하세요.

YouTube 원본 영상 보기 ↗

관련 AI 소식