
다차원 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.Tensortorch.tensor.png)
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.viewvstorch.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, sumequal, 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.multorch.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-smiGPUtil.showUtilization()torch.cuda.empty_cache() : 사용하지 않는 공간을 확보해줌gc.collect() : 조각모음