딥러닝 프레임워크는 굉장히 많다. 대표적인 것은 keras, Tensorflow, PyTorch가 있다.
그 중 가장 많이 사용되는 것은 pytorch와 tensorflow를 사용한다.
두 프레임워크의 가장 큰 차이점은 computational graph의 사용이다. computational graph란 연산과정을 그래프로 표현한 것이다. backward propagation을 위해 현재 있는 데이터들을 그래프로 표현해야하는데, tensorflow는 graph를 그려놓은 다음 실행 시점에 사용되는 static graph를 사용하고, pytorch는 실행 시점에 그래프를 정의하는 dynamic computation graph를 사용한다.
Numpy + AutoGrad + Funtion
autograd 패키지는 Tensor로 수행한 모든 연산에 대하여 자동-미분(Autimatic differentiation) 기능을 제공합니다. autograd는 실행 시점에 정의되는(define-by-run) 프레임워크입니다. 이것은 코드가 어떻게 실행되는가에 따라서 역전파(backprop)가 정의됨을 의미합니다. 즉 반복마다1 역전파가 달라질 수 있다는 것을 의미합니다.
출처 : http://taewan.kim/trans/pytorch/tutorial/blits/02_autograd/
import numpy as np
n_array = np.arange(10).reshape(2,5)
print(n_array)
print("ndim :", n_array.ndim, "shape :", n_array.shape)
import torch
t_array = torch.FloatTensor(n_array)
print(t_array)
print("ndim :", t_array.ndim, "shape :", t_array.shape)
nd_array_ex = np.array(data)
tensor_array = torch.from_numpy(nd_array_ex)
tensor_array
tensor data type
numpy like operations
# array to tensor
data = [[3, 5, 20],[10, 5, 50], [1, 5, 10]]
x_data = torch.tensor(data)
# list slicing
x_data[1:]
x_data[:2, 1:]
# flatten
x_data.flatten()
# ones_like
torch.ones_like(x_data)
# tensor to numpy
x_data.numpy()
# shape
x_data.shape
# data type
x_data.dtype
# pytorch의 tensor는 GPU에 올려서 사용가능
x_data.device
if torch.cuda.is_available():
x_data_cuda = x_data.to('cuda')
x_data_cuda.device
tensor_ex = torch.rand(size=(2, 3, 2))
tensor_ex
tensor_ex.view([-1, 6])
tensor_ex.reshape([-1,6])
# view는 copy가 아닌 메모리 공유
a = torch.zeros(3, 2)
b = a.view(2, 3)
a.fill_(1)
a
b
# reshape은 copy
a = torch.zeros(3, 2)
b = a.t().reshape(6)
a.fill_(1)
a
b
tensor_ex = torch.rand(size=(2, 1, 2))
tensor_ex.squeeze()
tensor_ex = torch.rand(size=(2, 2))
tensor_ex.unsqueeze(0).shape
tensor_ex.unsqueeze(1).shape
tensor_ex.unsqueeze(2).shape
n1 = np.arange(10).reshape(2,5)
n2 = np.arange(10).reshape(5,2)
t1 = torch.FloatTensor(n1)
t2 = torch.FloatTensor(n2)
t1 + t1
t1 - t1
# 행렬곱셈 함수는 dot이 아닌 mm사용
n2 = np.arange(10).reshape(5,2)
t2 = torch.FloatTensor(n2)
t1.mm(t2)
t1.matmul(t2)
t1.dot(t2)
# dot은 vector연산 됨
a = torch.rand(10)
b = torch.rand(10)
a.dot(b)
a
# mm은 vector연산 안됨
a = torch.rand(10)
b = torch.rand(10)
a.mm(b)
# mm은 broadcasting 지원 안함
a = torch.rand(5,2, 3)
b = torch.rand(5)
a.mm(b)
# matmul은 broadcasting 지원함
a = torch.rand(5,2, 3)
b = torch.rand(3)
a.matmul(b)
# matamul연산은 아래와 같음
a[0].mm(torch.unsqueeze(b,1)).squeeze()
a[1].mm(torch.unsqueeze(b,1))
a[2].mm(torch.unsqueeze(b,1))
a[3].mm(torch.unsqueeze(b,1))
a[4].mm(torch.unsqueeze(b,1))
import torch
import torch.nn.functional as F
tensor = torch.FloatTensor([0.5, 0.7, 0.1])
h_tensor = F.softmax(tensor, dim=0)
h_tensor
y = torch.randint(5, (10,5))
y_label = y.argmax(dim=1)
y_label
torch.nn.functional.one_hot(y_label)
import itertools
a = [1, 2, 3]
b = [4, 5]
list(itertools.product(a, b))
tensor_a = torch.tensor(a)
tensor_b = torch.tensor(b)
torch.cartesian_prod(tensor_a, tensor_b)
# 미분 시 backward 사용
# y = w^2
# z = 10y + 50
# z = 10w^2 + 50
w = torch.tensor(2.0, requires_grad=True)
y = w**2
z = 10*y + 50
z.backward()
w.grad
# 편미분은 external_grad 인자
# Q = 3a^3 = b^2
# dQ/da = 9a^2
# dQ/db = -2b
a = torch.tensor([2., 3.], requires_grad=True)
b = torch.tensor([6., 4.], requires_grad=True)
Q = 3*a**3 - b**2
external_grad = torch.tensor([1., 1.])
Q.backward(gradient=external_grad)
a.grad
b.grad
pytorch project template
따라서 OOP + 모듈 = 프로젝트 형식의 구현 필요
템플릿 : https://github.com/victoresque/pytorch-template
<Custom model 개발>
nn.Module
- Container
named_children vs named_modules
둘다 모델 내부의 module을 출력해준다.
named_children은 한 단계 아래의 submodule까지만 표시하고,
named_modules는 자신에게 속하는 모든 submodule들을 표시해준다.
get_submodules
내가 원하는 특정 모듈만 가져올 때 사용
Parameter
nn.Module안에 미리 만들어진 tensor들을 보관할 때 사용
Parameter는 tensor의 subclass로, Module사용시 자동으로 parameter라는 학습가능한 매개변수로 저장된다. 학습가능한 매개변수는 pytorch의 auto grad로 역전파시 업데이트 될 수 있다.
일반 tensor는 그렇지 않다.
Buffer
일반적인 Tensor는 Parameter와 다르게 gradient를 계산하지 않아 값도 업데이트 되지 않고, 모델을 저장할 때 무시된다.
하지만 Parameter로 지정하지 않아서 값이 업데이트 되지 않는다 해도 저장하고싶은 tensor가 있을 때, buffer에 tensor를 등록해주면 모델을 저장할때 Parameter뿐만 아니라 buffer로 등록된 tensor들도 같이 저장된다.
- "Tensor"
- ❌ gradient 계산
- ❌ 값 업데이트
- ❌ 모델 저장시 값 저장
- "Parameter"
- ✅ gradient 계산
- ✅ 값 업데이트
- ✅ 모델 저장시 값 저장
- "Buffer"
- ❌ gradient 계산
- ❌ 값 업데이트
- ✅ 모델 저장시 값 저장
hook
패키지화된 코드에서 다른 프로그래머가 custom 코드를 중간에 실행시킬 수 있도록 만들어놓은 인터페이스.
<pytorch hook>
apply
모델에 무언가를 적용하려면 모델을 구성하는 전체 모듈에 모두 적용이 되어야하는데, custom 함수를 모델에 적용하고 싶을 때 apply 사용한다.
apply 를 통해 적용하는 함수는 모델의 모든 module들을 순차적으로 입력받아서 처리한다.
apply 함수는 일반적으로 가중치 초기화(Weight Initialization)에 많이 사용된다.
pytorch를 얼렁뚱땅 사용하고 있었는데, 이번 과제를 하면서 공식문서를 정독하고, 다양한 operation을 직접 사용, 비교해보며 확실한 개념을 잡을 수 있었다. 잊어버리지 않게 자주 사용하자!