본문 바로가기
두두 IT/딥러닝

02. tensor 다루기

by DoDo's 2026. 5. 26.
반응형

1. Tensor(텐서)의 개념과 상태 조회

Tensor는 파이토치에서 데이터를 저장하고 연산하는 기본 자료구조입니다. NumPy의 ndarray와 사용법이 매우 유사하지만, GPU 가속 연산자동 미분 기능이 추가되어 있다는 강력한 장점이 있습니다.

⚠️ 주의: PyTorch의 Tensor는 숫자 데이터 타입만 지원합니다. (문자열 불가)

📊 텐서의 핵심 상태 조회 메서드

  • tensor.shape 또는 tensor.size(): 텐서의 형태(구조)를 반환합니다.
  • tensor.ndim 또는 tensor.dim(): 텐서가 몇 차원(Rank)인지 반환합니다.
  • tensor.numel(): 텐서 안에 들어있는 전체 원소의 개수를 반환합니다.
  • tensor.dtype: 데이터의 타입(예: torch.float32)을 알려줍니다.
  • tensor.type(): 텐서 객체의 정확한 클래스 타입을 문자열로 반환합니다.
  • tensor.device: 현재 텐서가 저장된 메모리의 위치(cpu, cuda, mps)를 나타냅니다.

2. 다양한 텐서 생성 방법

① 원하는 값이나 특정 자료구조로 생성

  • torch.tensor(데이터, dtype=...): 리스트나 넘파이 배열을 바탕으로 텐서를 생성합니다.
  • 직접 클래스로 생성 (기본 데이터 타입 고정):
    • torch.FloatTensor(): float32 (실수형, 딥러닝에서 가장 기본)
    • torch.LongTensor(): int64 (정수형, 주로 인덱스나 라벨에 사용)

② 규칙이 있는 특수 텐서 생성

  • 특정 값 채우기: * torch.zeros(*size): 0으로 가득 찬 텐서
    • torch.ones(*size): 1로 가득 찬 텐서
    • torch.full(size, fill_value): 지정한 값으로 가득 찬 텐서
  • 기존 텐서 본따기 (_like):
    • torch.zeros_like(target_tensor): 다른 텐서와 모양(Shape)과 타입(Dtype)이 완벽히 똑같고 값만 0, 1, 지정값으로 채워진 텐서를 만듭니다.
  • 수치 범위 지정:
    • torch.arange(start, end, step): 수열 생성 (인덱싱 리버스 용도로 step에 음수 사용 불가)
    • torch.linspace(start, end, steps): 시작부터 끝까지 동일한 간격으로 steps 개수만큼 생성

③ 난수(Random) 기반 생성

  • torch.rand(*size): 0 ~ 1 사이의 균등분포 실수
  • torch.randn(*size): 평균 0, 표준편차 1인 표준정규분포 실수
  • torch.randint(low, high, size): 지정 범위 내의 정수 난수
  • torch.randperm(n): 0부터 $n-1$까지의 정수를 무작위로 섞은 배열 생성 (데이터 셔플 및 인덱스 섞기에 애용)

3. 핵심 조작 기법 (인덱싱, 모양 변경, 병합)

① Indexing & Slicing 특징

  • NumPy와 거의 같지만, 슬라이싱 시 간격(Step)에 음수를 쓸 수 없습니다.
  • 🔄 역순(Reverse) 조회가 필요할 때는: .flip(dims=[축번호]) 함수를 사용해야 합니다.
  • 조건에 맞는 값만 추출하는 Boolean Indexing이나 .masked_select(조건) 기능도 지원합니다.

② Shape(형태) 변경: reshape() vs view()

  • 두 함수 모두 원소 개수를 유지하며 모양을 바꿉니다. 한 축에 -1을 넣으면 컴퓨터가 알아서 계산합니다.
  • ⚠️ 중요 (참조 관계): 변환된 텐서의 값을 바꾸면 원본 텐서의 값도 같이 바뀝니다. 원본을 지키려면 .clone()을 붙여서 복사본을 만들어야 합니다.

③ Dummy 축(차원) 늘리기와 줄이기

  • 늘리기: tensor.unsqueeze(dim=축번호) 또는 tensor[None, :]를 사용해 크기가 1인 차원을 강제로 끼워 넣습니다.
  • 줄이기: tensor.squeeze()를 사용해 크기가 1인 더미 차원들을 전부 제거하거나 특정 축만 골라 제거합니다.

④ 텐서 합치기: torch.cat()

  • torch.cat([A, B, ...], dim=축번호): 지정한 축을 기준으로 텐서들을 이어 붙입니다.
  • ⚠️ 조건: 합치려는 기준 축을 제외한 나머지 모든 축의 크기(Size)가 완벽히 같아야 합니다.

4. 연산 및 장치(Device) 할당

① 디바이스 이동: CPU ↔ GPU

파이토치는 연산을 수행할 하드웨어를 직접 지정할 수 있습니다. 모델과 데이터가 같은 하드웨어 장치에 있어야만 연산이 가능합니다.

Python
 
# 내 컴퓨터 환경에 맞는 최적의 가속 장치 자동 지정 규칙
device = 'cuda' if torch.cuda.is_available() else 'mps' if torch.backends.mps.is_available() else 'cpu'

t = torch.tensor([1, 2, 3], device=device) # 생성 시 지정
t_cpu = t.to("cpu")                       # 생성 후 이동

② 원소별(Element-wise) 연산과 브로드캐스팅

  • 사칙연산과 비교 연산은 기본적으로 자리가 같은 원소끼리 계산됩니다.
  • 만약 두 텐서의 모양이 다르더라도, 특정 축의 크기가 1인 경우 파이토치가 자동으로 데이터를 복사해 모양을 맞춰 연산해 주는데, 이를 브로드캐스팅(Broadcasting)이라고 합니다.

③ 행렬곱 연산

  • 일반 행렬곱: @ 연산자 또는 torch.matmul(A, B)를 사용합니다.
  • 배치 행렬곱 (torch.bmm): 3차원 텐서가 입력되었을 때, 0번 축(Batch)은 그대로 두고 뒤의 1번, 2번 축끼리만 행렬곱을 수행합니다.

5. 자동 미분 시스템 (Autograd)

딥러닝의 핵심인 역전파(Backpropagation) 시 가중치(Weight)의 미분계수(기울기)를 자동으로 구해주는 시스템입니다.

[Image diagram of PyTorch Autograd computational graph and backward pass]

🔄 역전파가 일어나는 메커니즘

  1. requires_grad=True: 이 옵션이 켜진 텐서는 파이토치가 "미분해야 하는 대상(가중치)"으로 인지하고 추적하기 시작합니다.
  2. grad_fn (도함수 저장): 이 변수를 가지고 연산(식)을 수행하면, 결과 텐서에 미분 공식 엔진인 grad_fn이 자동으로 장착됩니다.
  3. .backward(): 최종 오차(Loss) 점수에서 .backward()를 호출하면, 장착되어 있던 grad_fn들이 역순으로 실행되며 미분 값을 계산합니다.
  4. .grad: 계산이 완료되면 처음 requires_grad=True를 켰던 변수의 .grad 속성에 최종 미분 결과(기울기)가 저장됩니다.

🚫 torch.no_grad() (미분 엔진 끄기)

  • with torch.no_grad(): 블록 안에서 일어나는 모든 연산은 grad_fn을 만들지 않고 미분 추적을 하지 않습니다.
  • 이유: 모델을 학습시킬 때가 아닌, 완성된 모델로 테스트(평가)나 추론을 할 때는 미분 계산이 필요 없으므로 메모리와 가속도를 아끼기 위해 필수적으로 사용합니다.

🧹 x.grad = None (기울기 초기화)

  • 파이토치는 .backward()를 할 때마다 기존에 계산해 둔 .grad 값에 새로운 값을 더해서 누적하는 성질이 있습니다.
  • 따라서 새로운 미분 계산(새로운 학습 라운드)을 하기 전에는 반드시 x.grad = None (또는 과거 방식의 zero_grad())을 통해 기존에 쌓인 기울기를 깨끗이 비워주어야 연산이 꼬이지 않습니다.
반응형