🤖 AI/ML

텐서

Tensor

다차원 배열. 딥러닝의 기본 데이터 구조. TensorFlow, PyTorch에서 연산 단위.

📖 상세 설명

텐서(Tensor)는 다차원 배열(Multi-dimensional Array)을 일반화한 수학적 개념으로, 딥러닝과 과학 컴퓨팅의 기본 데이터 구조입니다. 스칼라(0차원), 벡터(1차원), 행렬(2차원)을 포함하며, 3차원 이상의 고차원 데이터까지 표현합니다. PyTorch와 TensorFlow 같은 딥러닝 프레임워크에서 모든 데이터와 연산은 텐서 단위로 이루어집니다.

텐서라는 용어는 원래 물리학과 수학에서 좌표 변환에 대해 특정 방식으로 변환되는 객체를 지칭했습니다. 머신러닝에서는 이 개념을 빌려와 다차원 숫자 배열을 표현하는 데 사용합니다. 2015년 TensorFlow의 등장과 함께 이 용어가 대중화되었고, PyTorch, JAX, MLX 등 현대 딥러닝 프레임워크 모두 텐서를 핵심 자료구조로 채택하고 있습니다.

텐서의 핵심 속성으로는 형태(Shape), 데이터 타입(dtype), 디바이스(device)가 있습니다. Shape은 각 차원의 크기를 나타내며 (배치크기, 채널, 높이, 너비)처럼 표현됩니다. dtype은 float32, float16, int64 등 데이터 정밀도를 결정하고, device는 CPU나 GPU(cuda) 등 연산이 수행되는 하드웨어를 지정합니다. 텐서 연산은 브로드캐스팅, 인덱싱, 슬라이싱 등 NumPy와 유사한 문법을 지원하면서도 GPU 가속과 자동 미분을 제공합니다.

2024-2025년 실무에서는 mixed precision training(FP16/BF16)과 양자화(INT8, INT4)가 표준이 되어 텐서 연산 효율성이 크게 향상되었습니다. NVIDIA의 Tensor Core, Apple의 Neural Engine, Google의 TPU 모두 텐서 연산에 최적화된 하드웨어입니다. 또한 Triton, torch.compile() 같은 JIT 컴파일러가 텐서 연산을 자동으로 최적화하여 성능을 극대화합니다.

💻 코드 예제

PyTorch 텐서의 기본 사용법입니다.

# PyTorch 텐서 기초
# pip install torch

import torch

# 다양한 방법으로 텐서 생성
zeros = torch.zeros(3, 4)           # 3x4 영행렬
ones = torch.ones(2, 3, 4)          # 2x3x4 일행렬
rand = torch.rand(3, 3)             # 0~1 균등분포
randn = torch.randn(3, 3)           # 표준정규분포
arange = torch.arange(0, 10, 2)     # [0, 2, 4, 6, 8]

# 리스트/NumPy에서 변환
from_list = torch.tensor([[1, 2], [3, 4]])
import numpy as np
from_numpy = torch.from_numpy(np.array([1.0, 2.0, 3.0]))

# 텐서 속성 확인
print(f"Shape: {rand.shape}")       # torch.Size([3, 3])
print(f"Dtype: {rand.dtype}")       # torch.float32
print(f"Device: {rand.device}")     # cpu

# GPU로 이동 (CUDA 사용 가능시)
if torch.cuda.is_available():
    gpu_tensor = rand.to('cuda')
    print(f"GPU Device: {gpu_tensor.device}")  # cuda:0

# 텐서 연산
a = torch.tensor([[1, 2], [3, 4]], dtype=torch.float32)
b = torch.tensor([[5, 6], [7, 8]], dtype=torch.float32)

print(f"덧셈: {a + b}")
print(f"행렬곱: {a @ b}")  # 또는 torch.matmul(a, b)
print(f"요소별 곱: {a * b}")

# 형태 변환
c = torch.arange(12)
print(f"원본: {c.shape}")           # [12]
print(f"reshape: {c.reshape(3, 4).shape}")   # [3, 4]
print(f"view: {c.view(2, 6).shape}")         # [2, 6]
print(f"unsqueeze: {c.unsqueeze(0).shape}")  # [1, 12]

# 자동 미분 (딥러닝의 핵심)
x = torch.tensor([2.0, 3.0], requires_grad=True)
y = x ** 2 + 2 * x + 1
loss = y.sum()
loss.backward()
print(f"기울기 (dy/dx): {x.grad}")  # [6.0, 8.0]

TensorFlow 텐서와 실전 활용 예제입니다.

# TensorFlow 텐서 기초
# pip install tensorflow

import tensorflow as tf

# 텐서 생성
zeros = tf.zeros([3, 4])
ones = tf.ones([2, 3, 4])
rand = tf.random.uniform([3, 3])
constant = tf.constant([[1, 2], [3, 4]])

# 텐서 속성
print(f"Shape: {rand.shape}")
print(f"Dtype: {rand.dtype}")

# 딥러닝 모델에서의 텐서 흐름 예시
# 이미지 배치: [batch_size, height, width, channels]
batch_images = tf.random.normal([32, 224, 224, 3])

# 컨볼루션 레이어 시뮬레이션
conv_layer = tf.keras.layers.Conv2D(64, (3, 3), padding='same')
output = conv_layer(batch_images)
print(f"입력: {batch_images.shape}")  # (32, 224, 224, 3)
print(f"출력: {output.shape}")        # (32, 224, 224, 64)

# Mixed Precision (FP16) 예시
tf.keras.mixed_precision.set_global_policy('mixed_float16')
print(f"Global Policy: {tf.keras.mixed_precision.global_policy()}")

# 텐서 타입 변환
float_tensor = tf.cast(constant, tf.float32)
int_tensor = tf.cast(rand * 10, tf.int32)

# GPU 메모리 확인
gpus = tf.config.list_physical_devices('GPU')
print(f"사용 가능한 GPU: {len(gpus)}개")

📊 성능 & 비용

2025년 1월 기준 텐서 연산 성능 비교입니다.

하드웨어 FP32 TFLOPS FP16 TFLOPS 메모리 가격(대략)
NVIDIA H100 67 1,979 80GB HBM3 $30,000+
NVIDIA A100 19.5 312 80GB HBM2e $10,000+
NVIDIA RTX 4090 82.6 165 24GB GDDR6X $1,600
Apple M3 Max ~14 ~28 128GB 통합 $3,000+

데이터 타입별 메모리 사용량:

데이터 타입 비트 사용 사례 메모리 절감
float32 (FP32) 32bit 기본 학습 기준
float16 (FP16) 16bit Mixed Precision 50%
bfloat16 (BF16) 16bit LLM 학습 50%
int8 8bit 양자화 추론 75%

🗣️ 실무에서 이렇게 말하세요

💬 회의에서
"GPU 메모리 부족 문제는 텐서 데이터 타입을 BF16으로 변경하고 gradient checkpointing을 적용해서 해결했습니다. 배치 사이즈를 32에서 64로 늘려도 OOM이 발생하지 않습니다."
💬 면접에서
"텐서의 contiguous 여부가 성능에 중요합니다. transpose나 permute 후에는 메모리 레이아웃이 non-contiguous가 되는데, 이 상태로 연산하면 속도가 저하되므로 필요시 .contiguous()를 호출합니다."
💬 기술 토론에서
"torch.compile()이 나오면서 텐서 연산이 자동 최적화됩니다. Triton 커널로 컴파일되어 수동 CUDA 최적화 없이도 2배 이상 빨라지는 경우도 있어요. 다만 dynamic shape이 많으면 컴파일 오버헤드가 있습니다."

⚠️ 흔한 실수 & 주의사항

CPU-GPU 텐서 혼합 연산

CPU 텐서와 GPU 텐서를 직접 연산하면 에러가 발생합니다. 연산 전에 모든 텐서가 같은 device에 있는지 확인하고, .to(device)로 통일하세요.

in-place 연산의 부작용

a.add_(b) 같은 in-place 연산은 자동 미분 그래프를 손상시킬 수 있습니다. 특히 requires_grad=True인 텐서에서 주의가 필요합니다.

올바른 접근법

텐서 생성 시 device와 dtype을 명시적으로 지정하세요. 메모리 프로파일링 도구(torch.cuda.memory_summary())를 활용하여 메모리 누수를 조기에 발견하세요.

🔗 관련 용어

📚 더 배우기