PyTorch와 TensorFlow는 현재 사용되는 머신러닝 라이브러리 중 가장 많이 사용되는 라이브러이다.
둘 다 굉장히 훌륭하고 유용한 라이브러리이고, 공통적인 부분도 많지만 차이점도 존재한다.
가장 큰 차이점은 Computational graphs 방식이다.
- TensorFlow: Static graphs
- PyTorch: Dynamic computation graphs
TensorFlow는 Define and Run 방식으로,
그래프를 먼저 정의한 후에 실행시점에 데이터를 feed하여 실행시키는 방식이다.
반면 PyTorch는 Define by Run 방식으로, (Dynamic Computational Graph, DCG)
실행을 하면서 그래프를 생성해가는 방식이다.
Define by Run의 장점은, 결과를 즉시 확인 가능하다는 것이다.
즉, 좀 더 파이썬스럽다고 할 수 있다.
cf) Pythonic code: 유지가 쉽고 명확하고 간결한 코드
그에 반에 TensorFlow는 제품성과 확장성의 장점이 있다.
PyTorch의 가장 큰 특징은 numpy + AutoGrad 이다.
- numpy
Pytorch에서 사용되는 tensor는 기본적으로 numpy의 ndarray와 같은 구조이다.
따라서, 기존의 numpy의 문법들을 대부분 PyTorch에서 사용할 수 있다. (예를 들어 slicing, flatten, ones_like, shape 등)data = [[1,2,3],[...]] # tensor 생성 x_data = torch.tensor(data) # Slicing x_data[1:] x_data[:2, 1:] # flatten() x_data.flatten() # 1D로 바꿔줌. # ones_like() torch.ones_like(x_data) # x_data 형태, 원소는 1인 tensor 생성. # numpy() x_data.numpy() # ndarray 타입으로 바꿔줌. # shape, dtype x_data.shape x_data.dtype
또한, pytorch는 GPU에 올려서 사용 가능하다.
x_data.device # device(type='cpu') if torch.cuda.is_available(): x_data_cuda = x_data.to('cuda') x_data_cuda.device # device(type='cuda', index=0)
- tensor handling
tensor_ex = torch.rand(size=(2,3,2))
view: tensor의 shape를 변환(reshape와 동일)
tensor_ex.view([-1, 6]) # tensor_ex가 (2,3,2) 형태이므로 [-1, 6]에서 -1 index는 2를 의미
cf) view와 reshape의 차이
- view: 기존의 값들의 메모리 주소만 형태에 맞춰서 불러옴(메모리 보장 O)
- reshape: 메모리 보장을 하지 않고 copy를 해서 형태를 변환함
view를 디폴트로 사용하는 것을 추천!squeeze: 차원의 개수가 1인 차원을 삭제(압축)
unsqueeze: 차원의 개수가 1인 차원을 추가# unsqueeze(i), 여기에서 i는 dimension 혹은 axis를 의미 [ [1,2], unsqueeze(0) => [ [ [1,2], [3,4] ] <= squeeze() [3,4] ] ] [ [1,2], unsqueeze(1) => [ [ [1,2] ], [3,4] ] <= squeeze() [ [3,4] ] ] [ [1,2], unsqueeze(2) => [ [ [1],[2] ], [3,4] ] <= squeeze() [ [3],[4] ] ] # (2,2) 행렬이 각각 (1,2,2), (2,1,2), (2,2,1)로 변환!
- 행렬의 연산은 dot이 아닌 mm을 이용
dot은 양쪽 모두 벡터일 때 사용가능 하므로, 행렬 곱을 할 때에는 mm 연산을 이용한다.n1 = np.arange(10).reshape(2,5) t1 = torch.FloatTensor(n1) n2 = np.arange(10).reshape(5,2) t2 = torch.FloatTensor(n2) t1.mm(t2) # 행렬곱 # t1.matmul(t2)로도 행렬곱 연산 가능 # mm 연산과 matmul 연산의 차이는 broadcasting 지원 # mm: broadcasting 지원 X # matmul: broadcasting 지원 O
cf) nn.functional 모듈을 통해 다양한 수식 변환 지원
ex. sotmax, argmax, one_hot, ...import torch import torch.nn.functional as F tenor = torch.FloatTensor([0.5, 0.7, 0.1]) h_tensor = F.softmax(tensor, dim=0) # h_tensor => tensor([0.3458, 0.4224, 0.2318]) y = torch.randint(5, (10,5)) y_label = y.argmax(dim=1) F.one_hot(y_label) # 원핫 인코딩
- AutoGrad
Pytorch의 핵심은 자동 미분 지원! (backward 함수 사용)w = torch.tensor(2.0, requires_grad = True) # 미분 대상에 포함! y = w ** 2 z = 10 * y + 25 z.backward() w.grad # 실제로는 requires_grad에 직접 주지 않고, #Linear과 같은 함수 이용 시, 자동으로 reqires_grad가 True
requires_grad = True는 autograd하는 모든 연산을 추적한다.
예를 들어 신경망의 매개변수 a와 b, 오차 Q를 다음과 같이 있다고 가정하면
신경망을 학습할 때, 아래와 같이 매개변수들에 대한 오차의 변화도를 구해야한다.a = torch.tensor([2., 3.], requires_grad=True) b = torch.tensor([6., 4.], requires_grad=True) Q = 3*a**3 - b**2
Q에 대해서 .backward()를 호출할 때, autograd는 계산된 변화도를 각 a, b텐서의 .grad 속성(attribute)에 저장한다.
Q는 vector이기 때문에, gradient 인자(argument)를 명시적으로 전달하여야 하는데, gradient는 Q와 같은 shape의 텐서이며, Q 자기 자신에 대한 변화도를 나타낸다. (dQ/dQ = 1)external_grad = torch.tensor([1., 1.]) Q.backward(gradient=external_grad)