pytorch의 tensor는 numpy의 ndarry와 비슷한 구조를 가진다. 실제로 numpy와 tensor간의 변환이 가능하며 둘이 메모리를 공유하기 때문에 어느 한쪽을 수정하면 같이 변하는 특징이 있으며 GPU에서 실행할 수 있다는 특징이 있다.
import torch
input = [[1, 2],[3, 4]]
input_data = torch.tensor(input)
print(input_data)
import torch
print('random 생성')
print(torch.rand(2,2))
print('정규분포를 따르는 tensor')
print(torch.randn(2,2))
print('0 tensor')
print(torch.zeros(2,2))
print('1 tensor')
print(torch.ones(2,2))
import torch
input = [[1, 2],[3, 4]]
## 32bit
input_data = torch.tensor(input, dtype=torch.float)
print(input_data)
input_data = torch.tensor(input, dtype=torch.double)
print(input_data)
input_data = torch.tensor(input, dtype=torch.long)
print(input_data)
import torch
x = torch.rand(2,2)
print(f'x : {x}\n')
y = torch.ones_like(x)
print(f'y : {y}\n')
z = torch.zeros_like(y)
print(f'z : {z}\n')
t = torch.rand_like(z)
print(f't : {t}')
import torch
x = torch.rand(2,6)
print(x,'\n')
print(x.size())
print(x.shape)
import torch
x = torch.rand(2,6)
y = torch.rand(2,6)
#1
print(f"{x + y}\n")
#2
print(f"{torch.add(x,y)}\n")
#3
print(f"{x.add(y)}\n")
#4 ( 결과를 out으로 내보낼 수 있다. )
result = torch.empty_like(x)
torch.add(x, y, out=result)
print(f"{result}\n")
import torch
x = torch.rand(2,6)
y = torch.rand(2,6)
print(f'{x}\n{y}\n')
#1
print(f"{x - y}\n")
#2
print(f"{torch.sub(x,y)}\n")
#3
print(f"{x.sub(y)}\n")
#4 ( 결과를 out으로 내보낼 수 있다. )
result = torch.empty_like(x)
torch.sub(x, y, out=result)
print(f"{result}\n")
import torch
x = torch.rand(2,6)
y = torch.rand(2,6)
print(f'{x}\n{y}\n')
#1
print(f"{x / y}\n")
#2
print(f"{torch.div(x,y)}\n")
#3
print(f"{x.div(y)}\n")
#4 ( 결과를 out으로 내보낼 수 있다. )
result = torch.empty_like(x)
torch.div(x, y, out=result)
print(f"{result}\n")
import torch
x = torch.rand(2,6)
y = torch.rand(2,6)
print(f'{x}\n{y}\n')
#1
print(f"{x * y}\n")
#2
print(f"{torch.mul(x,y)}\n")
#3
print(f"{x.mul(y)}\n")
#4 ( 결과를 out으로 내보낼 수 있다. )
result = torch.empty_like(x)
torch.mul(x, y, out=result)
print(f"{result}\n")
import torch
x = torch.rand(2,3)
y = torch.rand(3,2)
print(f'{x}\n{y}\n')
#1
print(f"{torch.mm(x,y)}\n")
#2
print(f"{torch.matmul(y)}\n")
#3 ( 결과를 out으로 내보낼 수 있다. )
result = torch.empty(2,2)
torch.mm(x, y, out=result)
print(f"{result}\n")
import torch
x = torch.rand(2,2)
print(f"x : {x}\n")
print(x.sum())
print(f"axis=0 : {x.sum(axis=0)}")
print(f"axis=1 : {x.sum(axis=1)}")
print(f"선두에 있는 차원부터 계산 : {x.sum(axis=(0, 1))}")
print(f"item()으로 python 숫자로 변환 : {x.sum().item()}")
x.add_()와 같이 연산결과를 피연산자에 저장한다. _를 사용하는 것에 주의한다.
import torch
x = torch.rand(2,2)
print(x)
x.add_(2)
print(x)
x.div_(2)
print(x)
import torch
x = torch.randn(2,2)
print(x)
print('첫번째 행 : ',x[0])
print('첫번째 열 : ',x[:,0])
print('첫번째 열 : ',x[...,0])
numpy에서의 reshape의 기능, -1로 자동 조정기능도 똑같이 존재한다.
import torch
x = torch.randn(2,2)
print(f"x\n{x}\nx size\n{x.shape}\n")
y = x.view(4)
print(f"y\n{y}\ny size\n{y.shape}\n")
z = y.view(2,-1)
print(f"z\n{z}\nz size\n{z.shape}")
import torch
x = torch.randn(3,2,1,3)
print(x.shape)
y = x.squeeze()
print(y.shape)
차원의 크기가 1인 부분을 축소시켜준다.
import torch
z = torch.rand(2,2)
print(z)
y = z.unsqueeze(dim=1)
print(y.shape)
x = z.unsqueeze(dim=0)
print(x.shape)
stack
import torch
x = torch.ones(2,2)
y = torch.zeros(2,2)
z = torch.rand(2,2)
result = torch.stack([x, y, z])
print(result)
print(result.shape)
import torch
x = torch.ones(2,2)
y = torch.zeros(2,2)
result1 = torch.stack([x, y])
result2 = torch.cat([x,y])
print(result1.shape)
print(result2.shape)
stack과 같은 결과를 보여주기 위해선 차원을 증가하고 수행해야한다.
import torch
x = torch.ones(2,2)
y = torch.zeros(2,2)
x = x.unsqueeze(dim=0)
y = y.unsquuuze(dim=0)
result = torch.cat([x, y], dim=0)
print('cat : ', result.shape)
import torch
x = torch.rand(2,6)
print(x)
y,z = torch.chunk(x, 2, dim=1)
print(y)
print(z)
import torch
x = =torch.rand(2,6)
y,z = torch.split(x, 3, dim=1)
print(y)
print(z)
tensor가 cpu상에 있다면, numpy와 메모리를 공유하기 때문에 한쪽이 변하면 다른쪽도 변한다.
import torch
import numpy as np
x = torch.ones(2,2)
y = x.numpy()
print(x)
print(y)
x.add_(1)
print(x)
print(y)
import torch
import numpy as np
x = np.ones([2, 2])
y = torch.from_numpy(x)
print(x)
print(y)
np.add(x, 1, out=x)
print(x)
print(y)
.to 메소드를 사용해 cpu,gpu등 장치로 옮길 수 있다.
import torch
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)
x = torch.rand(1)
y = x.to(device)
print(y.device)
z = torch.rand(3)
print(z.to("cpu",dtype=torch.double))
대표적인 구성요소 | 설명 |
---|---|
torch | 텐서를 생성 |
torch.autograd | 자동미분을 제공하는 라이브러리 |
torch.nn | 신경망 생성 |
torch.multiprocessing | 병렬처리 기능 제공 라이브러리 |
torch.utils | 데이터 조작 등 다양한 유틸리티 제공 |
torch.onnx | Open Neural Network Exchange, 다른 프레임워크간 모델 공유 |
신경망 학습시, 역전파(backpropagarion)를 통해 매개변수(가중치)는 손실함수의 변화도(gradient)에 따라 조정된다. 변화도를 계산하기 위해 pytorch에는 자동미분엔진이 내장되어 있다.
data : tensor형태의 데이터
grad : data가 거쳐온 layer에 대한 미분값 저장
grad_fn : 미분값을 계산한 함수에 대한 정보 저장
requires_grad : True설정시 연산을 추적할 수 있음
.backward() : 자동으로 gradient를 계산하며 .grad에 저장된다.
.detach() : 연산기록으로부터 분리
with torch.no_grad(): : gradient를 업데이트 하지 않는다. 평가할때 사용한다.
Function클래스 : Autograd 구현에 중요한 클래스
import torch
x = torch.zeros(2, 2, requires_grad=True)
print(x)
y = x + 2
print(y)
z = y * 3
print(z)
import torch
x = torch.zeros(2,2)
print(x.requires_grad)
#in-place방식
x.requires_grad_(True)
print(x.requires_grad)
import torch
data = torch.ones(2, 2, requires_grad = True)
w = torch.randn(2, 3)
b = torch.randn(3)
z = torch.mm(data, w) + b
out = z.sum()
print(out)
print(data.grad)
out.backward()
print(data.grad)
import torch
data = torch.ones(2, 2, requires_grad=True)
w = torch.randn(2, 3)
b = torch.randn(3)
z = torch.mm(data, w) + b
out = torch.sum(z,axis=0)
print(out)
#스칼라 값이 아니면 오류가 나는데, 해결방법으로 벡터를 지정할 수 있다.
v = torch.tensor([0.1,0.5,0.01])
out.backward(v)
print(data.grad)
gradient의 업데이트를 하지 않는다.
import torch
data = torch.ones(2, 2, requires_grad=True)
print((data + 1).requires_grad)
with torch.no_grad():
print((data + 1).requires_grad)
연산기록으로 분리하여 내용물은 같지만, require_grad가 다른 tensor
import torch
data = torch.ones(2, 2, requires_grad=True)
print(data.requires_grad)
x = data.detach()
print(x.requires_grad)
print(data.eq(x).all())
두 패키지가 제공하는 기능은 비슷하지만 사용하는 방법에 차이가 있다.
nn패키지는 가중치(weight), 편향(bias) 값들이 내부에서 자동 생성되는 layer,
따라서 직접 선언해주지 않는다.
nn.functional은 weight나 bias를 직접 선언하여 외부에서 만든 값을 사용한다.
import torch
import torch.nn
##layer.weight로 값을 확인할 수 있으며 실행때마다 달라진다.
layer1 = nn.Conv2d(in_channels=3, out_channels=10, kernel_size=3, stride=2, padding=0, dilation=1)
layer2 = nn.Conv2d(in_channels=3, out_channels=10, kernel_size(3,5), stride(2,1), padding=(2,1))
input = torch.randn((100,3,28,28))
output1 = layer1(input)
output2 = layer2(input)
print(output1.size())
print(output2.size())
import torch
import torch.nn.functional as F
filter_ = torch.randn(10,3,5,5)
input = torch.randn((100,3,28,28))
conv = F.conv2d(input,filter_,padding=1)
print(conv.shape)
torch에는 데이터를 처리하기 위해 torch.utils.data.DataLoder와 torch.utils.data.Dataset의 두가지 요소를 제공한다. dataset은 미리 준비된 데이터셋을 불러 올 수 있으며, 가지고 있는 데이터와 라벨을 저장하고, dataloader는 dataset을 데이터에 쉽게 접근할 수 있도록 iterable(반복가능객체)로 만든다.
from torchvision import datasets
import torchvision.transforms as transforms
# dataloader의 인자로 들어갈 transform을 미리 정의함
# Compose 를 통해 리스트안에 순서대로 전처리 진행
# 대표적으로, torchvision은 PIL형태로만 입력을 받기 때문에, tensor로 변환해야함(totensor)
transform = transforms.Compose([transforms.ToTensor(),
transforms.Normalize(mean=(0.5,),std=(0.5,))])
train_data = datasets.FashionMNIST(
root="/content/",
train=True,
download=True,
transform=transform
)
test_data = datasets.FashionMNIST(
root="/content/",
train=False,
download=True,
transform=transform
)
from torch.utils.data import DataLoader
#데이터를 불러올 때 batch, 셔플여부, num_workers(데이터 불러올때 몇개의 코어로 할것인지)
train_loader = DataLoader(train_data, batch_size=8, shuffle=True )
test_loader = DataLoader(test_data, batch_size=8, shuffle=False)
#필요에 따라 데이터셋을 배치사이즈만큼 반복할 수 있다.
data_iter = iter(train_loader)
images, labels = data_iter.next()
print(images.shape, labels.shape)
import matplotlib.pyplot as plt
import torch
torch_image = torch.squeeze(images[0])
print(torch.shape)
image = torch_image.numpy()
print(image.shape)
label = labels[0].numpy()
print(label)
labels_map = {
0: "T-shirt",
1: "Trouser",
2: "Pullover",
3: "Dress",
4: "Coat",
5: "Sandal",
6: "Shirt",
7: "Sneaker",
8: "Bag",
9: "Ankle Boot"
}
plt.title(labels_map[int(label)])
plt.imshow(image,"gray")
plt.show()
torch.nn패키지를 사용하여 신경망을 생성하는데, nn.Module을 상속받아 해당 모듈의 계층들과 output을 반환하는 forward메소드를 포함한다.
import torch.nn as nn
class MyNet(nn.Module):
def __init__(self):
super(MyNet,self).__init__()
import torch
import torch.nn as nn
#cuda를 사용할 수 있는지 확인
device = "cuda" if torch.cuda.is_available() else "cpu"
print(f"device is {device}")
#conv로 연습
class MyNet(nn.Module):
def __init__(self):
super(MyNet,self).__init__()
#input = (1,1,28,28)
self.conv1 = torch.nn.Sequential(
nn.Conv2d(in_channels=1,out_channels=10, kernel_size=3, stride=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2, stride=2))
self.conv2 = torch.nn.Sequential(
nn.Conv2d(in_channels=10,out_channels=15,kernel_size=3,stride=1),
torch.nn.ReLU(),
torch.nn.MaxPool2d(kernel_size=2,stride=2))
self.fc1 = nn.Linear(15 * 7 * 7, out_features=100,bias=True)
torch.nn.init.xavier_uniform_(self.fc1.weight)
self.fc2 = nn.Linear(100, out_features=64,bias=True)
torch.nn.init.xavier_uniform_(self.fc2.weight)
self.fc3 = nn.Linear(64, out_features=10,bias=True)
torch.nn.init.xavier_uniform_(self.fc1.weight)
def forward(self,x):
out = self.conv1(x)
out = self.conv2(out)
#첫번째 차원은 그대로두고 나머지를 알아서
out = out.view(out.size(0),-1)
out = self.fc1(out)
out = self.fc2(out)
out = self.fc3(out)
return out
net = MyNet().to(device)
batch_size = 100
epoch_num = 15
learning_rate = 0.005
loss_f = torch.nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.Adam(net.parameters(),lr=0.05)
data = torchvision.datasets(root='/m_data/',
train=True,
transfrom= transforms.ToTensor(),
download=True)
data_loader = DataLoader(dataset=data,
batch_size=batch_size,
shuffle=True,
)
for epoch in range(epoch_num):
avg_cost = 0
for x,y in data_loader:
x = x.to(device)
y = y.to(device)
#모델 매개변수의 변화도를 재설정한다. 기본적으로 변화도는 더해지기 때문에
#중복계산을 막기위해 0으로 설정
optimizer.zero_grad()
hypo = net(x)
cost = loss_f(hypo,y)
cost.backward()
optimizer.step()
avg_cost += cost / total_batch