다차원 Arrays를 표현하는 PyTorch 클래스
numpy-like operations: numpy의 ndarray와 사실상 동일 (== Tensorflow의 Tensor).
PyTorch의 tensor는 GPU에 올려서 사용이 가능함
x_data.device
>>> device(type = 'cpu')
if torch.cuda.is_availabel():
x_data_cuda = x_data.to('cuda') # GPU로 올리기
x_data_cuda.device
>>> device(type = 'cuda', index = 0)
torch.tensor
vs torch.Tensor
torch.Tensor
torch.tensor
torch
: 텐서를 생성하는 라이브러리
torch.autograd
: 자동미분 기능을 제공하는 라이브러리
torch.nn
: 신경망을 생성하는 라이브러리
torch.multiprocessing
: 병럴처리 기능을 제공하는 라이브러리
torch.utils
: 데이터 조작 등 유틸리티 기능 제공
torch.legacy
(./nn/.optim): Torch로부터 포팅해온 코드
torch.onnx
: ONNX(Open Neural Network Exchange)
(참고: 이수안컴퓨터연구소 - 파이토치)
import torch
a = torch.Tensor([[1, 2],
[3, 4]])
print(a[1, 1])
>>> tensor(4.)
공식문서
(3-D tensor) if dim == 2
파이썬 코드(2-D tensor)
import torch
A = torch.Tensor([[1, 2],
[3, 4]])
output = torch.gather(A, 1, torch.tensor([[0],
[1]]))
print(output)
>>> tensor([[1.],
>>> [4.]])
reshape()
과 동일하게 텐서의 크기(size)나 모양(shape)을 변경import torch
A = torch.Tensor([[1, 2],
[3, 4]])
output = torch.gather(A, 1, torch.tensor([[0],
[1]]))
print(output.view(2, 1))
print(output.view(1, 2))
print(output.view(-1, 2)) # -1: ,2에 맞춰 자동으로 조정
>>> tensor([[1.],
>>> [4.]])
>>> tensor([[1., 4.]])
>>> tensor([[1., 4.]])
torch.view
vstorch.reshape
reshape()
:reshape
은 가능하면 input의view
를 반환하고, 안되면contiguous
한 tensor로 copy하고 view를 반환한다.view()
:view
는 기존의 데이터와 같은 메모리 공간을 공유하며 stride 크기만 변경하여 보여주기만 다르게 한다. 그래서contigious
해야만 동작하며, 아닌 경우 에러가 발생함.
contiguous
란
- arrow(), view(), expand(), transpose() 등의 함수는 새로운 Tensor를 생성하는 게 아니라 기존의 Tensor에서 메타데이터만 수정하여 우리에게 정보를 제공함. 즉 메모리상에서는 같은 공간을 공유함.
- 하지만 연산 과정에서 Tensor가 메모리에 올려진 순서(메모리 상의 연속성)가 중요하다면 원하는 결과가 나오지 않을 수 있고 에러가 발생함. 그렇기에 어떤 함수 결과가 실제로 메모리에도 우리가 기대하는 순서로 유지하려면 .contiguous()를 사용하여 에러가 발생하는 것을 방지할 수 있다.
(참고: Hello Subinium!)
import torch
A = torch.Tensor([[[1, 2],
[3, 4]]])
print(A.size())
A = A.squeeze()
print(A.size())
>>> torch.Size([1, 2, 2])
>>> torch.Size([2, 2])
import torch
A = torch.Tensor([[[1, 2],
[3, 4]]])
print(A.size())
A = A.unsqueeze(dim = 3) # dim = 3 -> A.size([1, 2, 2, <여기에 추가>]) (dim = -1 한것과 같음)
print(A)
print(A.size())
>>> torch.Size([1, 2, 2])
>>> tensor([[[[1.],
>>> [2.]],
>>>
>>> [[3.],
>>> [4.]]]])
>>> torch.Size([1, 2, 2, 1])
stack()
: 새로운 차원으로 주어진 텐서들을 붙이는 것cat()
: 주어진 차원을 기준으로 주어진 텐서들을 붙이는 것(concatenate)import torch
a = torch.tensor([1, 2])
b = torch.tensor([3, 4])
ab_stack = torch.stack([a, b])
ab_cat = torch.cat([a, b])
print(ab_stack)
print(ab_cat)
>>> tensor([[1, 2],
>>> [3, 4]])
>>> tensor([1, 2, 3, 4])
(참고: 파이토치KR 커뮤니티)
split()
: n개씩 나눠지게 하는 것chunk()
: n개로 나누는 것import torch
a = torch.tensor([1, 2, 3, 4, 5, 6])
a_split = torch.split(a, 3)
a_chunk = torch.chunk(a, 3)
print(a_split)
print(a_chunk)
>>> (tensor([1, 2, 3]), tensor([4, 5, 6]))
>>> (tensor([1, 2]), tensor([3, 4]), tensor([5, 6]))
transpose()
: 두 개의 차원을 transpose 시킬 수 있다.permute()
: 모든 차원에 대해 transpose 시킬 수 있다.a = torch.tensor([i for i in range(24)]).view(2, 3, -1)
b = a.transpose(0, 1) # 0번째와 1번째 transpose (최대 두 차원만 변경 가능)
c = a.permute(2, 1, 0) # 모든 차원에 대한 transpose (모든 차원 변경 가능)
print(a.size())
print(b.size())
print(c.size())
>>> torch.Size([2, 3, 4])
>>> torch.Size([3, 2, 4])
>>> torch.Size([4, 3, 2])
log1p
, rad2deg
, clamp
, sin
, log
, floor
, exp
, .....argmax
, all
, mean
, median
, norm
, sum
equal
, isclose
, isinf
, isnan
, sort
, argsort
:작은 수부터 차례로 index 반환, .....cov
, cumsum
, diff
, ....torch.einsum
: 다양한 연산 함수에 대해 통일된 표기법으로 연산시켜주는 함수einsum형태:
Result = einsum("dimension notation of A, dimension notation of B,...->Result Dimension", A, B, ...)
ex) transpose
import torch
A = torch.tensor([[1,2], [4,5]])
R = torch.einsum("ij->ji", A)
print(A)
print(R)
>>> tensor([[1, 2],
>>> [4, 5]])
>>> tensor([[1, 4],
>>> [2, 5]])
mm
, mataul
, dot
, bmm
, qr
, matrix_rank
, ...torch.mm
vs torch.matmul
vs torch.bmm
vs torch.mul
torch.matmul
(@
)은 torch.mm
과는 달리 broadcast를 지원한다.torch.matmul
은 1차원일 때 내적을 수행한다.torch.mul
은 성분곱 연산이다.autograd
관련 작업들을 두 패키지를 통해 진행할 수 있음requires_grad
와 같은 방식으로 진행할 수 있음torch.nn
은 attribute를 활용해 state를 저장하고 활용하고,torch.nn.functional
로 구현한 함수의 경우에는 인스턴스화 시킬 필요 없이 사용이 가능weight
값들을 직접 선언 안함softmax
, one_hot
import torch
from torch import nn
linear = nn.Linear(10, 20) # 10 -> 20
a = torch.randn((3, 10))
output = linear(a)
print(a.size())
print(output.size())
>> torch.Size([3, 10])
>> torch.Size([3, 20])
nn.Module
클래스는 nn 모듈의 Base 클래스임.Module
은 다른 Module
를 여러 개 포함할 수 있다(더욱 큰 딥러닝 모델이 됨)__init__
와 forward
로 구성됨.# nn.Module 기본 구성
import torch
from torch import nn
class Add(nn.Module): # nn.Module 상속받음
def __init__(self):
super().__init__()
def forward(self, a, b):
output = torch.add(a, b)
return output
add = Add()
a, b = torch.tensor([10]), torch.tensor([15])
print(add(a, b))
>>> tensor([25])
# nn.Sequential
import torch
from torch import nn
class Add(nn.Module):
def __init__(self, num):
super().__init__()
self.num = num
def forward(self, x):
output = torch.add(x, self.num)
return output
cal = nn.Sequential(Add(1), Add(2), Add(4)) # (1 + 1) (2 + 2) (4 + 4)
x = torch.tensor([1])
print(cal(x))
>>> tensor([8])
# nn.Sequential
import torch
from torch import nn
class Add(nn.Module):
def __init__(self, num):
super().__init__()
self.num = num
def forward(self, x):
output = torch.add(x, self.num)
return output
cal = nn.ModuleList([Add(1), Add(2), Add(4)]) # []
x = torch.tensor([1])
print(cal[1](x))
>>> tensor([3])
Python List
vs Pytorch ModuleList
__setattr__
이라는 특수 메서드가 호출됨.__setattr__
메서드는 '값'의 타입을 체크해서 만약 모듈이면 submodule로 등록하고 아니면 무시하고 넘어가게 됨.Python List
로 값을 저장하면 list에 포함된 어떠한 module들도 저장이 되지 않음# nn.Sequential
import torch
from torch import nn
class Add(nn.Module):
def __init__(self, num):
super().__init__()
self.num = num
def forward(self, x):
output = torch.add(x, self.num)
return output
cal = nn.ModuleDict({'one': Add(1), 'two': Add(2), 'three': Add(4)}) # {}
x = torch.tensor([1])
print(cal['three'](x))
>>> tensor([5]
parameters()
)에 추가됨(torch.Tensor 클래스와의 차이점)import torch
from torch import nn
from torch.nn.parameter import Parameter
class Linear(nn.Module): # 선형변환
def __init__(self, in_features, out_features):
super().__init__()
self.W = Parameter(torch.empty((out_features, in_features)))
self.b = Parameter(torch.empty(out_features))
def forward(self, x):
output = torch.addmm(self.b, x, self.W.T)
return output
x = torch.Tensor([[1, 2],
[3, 4]])
linear = Linear(2, 3)
print(linear(x))
## gradient를 계산하는 함수인 grad_fn가 생성됨
>> tensor([[-1.3925e+31, 2.9512e+04, 9.5367e-06],
>>> [-1.3925e+31, 5.9024e+04, 1.9073e-05]], grad_fn=<AddmmBackward0>)
Gradient 계산 | 값 업데이트 | 모델 저장시 값 저장 | |
---|---|---|---|
Tensor | ❌ | ❌ | ❌ |
Parameter | ⭕ | ⭕ | ⭕ |
Buffer | ❌ | ❌ | ⭕ |
class Model(nn.Module):
def __init__(self):
super().__init__()
self.parameter = Parameter(torch.Tensor([7])) # PARAMETER
self.tensor = torch.Tensor([7]) # TENSOR
self.register_buffer('buffer', torch.Tensor([7]), persistent=True) # BUFFER
m = Model()
print(m.state_dict())
>>> OrderedDict([('parameter', tensor([7.])), ('buffer', tensor([7.]))])
import torch.nn as nn
class Model(nn.Module):
def __init__(self):
super(Model, self).__init__()
self.layer_A = nn.Linear(2, 5)
self.layer_B = nn.Linear(5, 10)
self.layer_C = nn.Linear(10, 1)
self.relu = nn.ReLU()
def forward(self, x):
output = self.layer1(x)
output = self.relu(output)
output = self.layer2(output)
output = self.relu(output)
output = self.layer3(output)
return output
model = Model()
print(model.state_dict())
>>>
for name, module in model.named_parameters():
print(name, module)
print("-" * 30)
>>>
print(model.get_parameter('layer_A.weight'))
>>>
for name, module in model.named_modules():
print(name, module)
print("-" * 30)
>>>
print(model.get_submodule('layer_A'))
>>> Linear(in_features=2, out_features=5, bias=True)
model.buffers()
: 모델 이름은 생략, buffer만 가져옴model.get_buffer()
: 모델의 특정 module에 있는 버퍼를 가져옴<코드 생략>
hook(module, input, ouput)
hook(module, input)
hook(module, grad_input, grad_output)
tensor_hook(grad)
import torch
from torch import nn
def pre_hook(module, input):
print('forward 시작!!')
def hook(module, input, output):
return output + 10000 #output 값에 10000 더해서 반환
linear = nn.Linear(2, 3)
linear.register_forward_pre_hook(pre_hook)
linear.register_forward_hook(hook)
print(linear(torch.Tensor([[1, 2], [3, 4]])))
>>> tensor([[ 9999.2549, 10000.6816, 9999.8857],
>>> [ 9997.7803, 10000.9023, 9999.5381]], grad_fn=<AddBackward0>)
nn.module
에서 모델 맨 위 module에 어떤 함수를 적용하면, 그 아래에 존재하는 모든 module에 해당 함수를 적용함(nn.Module에서 내부적으로 이를 지원). 그러나 nn.Module에 이미 구현되어 있는 method가 아닌 custom method를 모델에 적용하고 싶다면, apply함수를 사용해야 함.import torch
from torch import nn
@torch.no_grad()
def init_weights(m):
print(m)
if type(m) == nn.Linear:
m.weight.fill_(1.0) # m모듈의 weight(parameter)를 1.0으로 채우는 함수
print(m.weight)
net = nn.Sequential(nn.Linear(2, 2), nn.Linear(2, 2))
print(net.apply(init_weights)) # apply가 적용된 module을 return해줌
>>>
$ nvidia-smi
GPUtil.showUtilization()
torch.cuda.empty_cache()
: 사용하지 않는 공간을 확보해줌gc.collect()
: 조각모음