[Week 1]PyTorch 기초 사용법
pytorch의 tensor와 tensor 연산, torch.nn을 활용한 모델 구축을 다룹니다.
Tensor
import torch
t = torch.tensor([2, 3, 4], dtype=torch.int32)
print(t.float().dtype()) # torch.float32
print(t.dim()) # 1
print(t.size()) # or t.shape -> torch.Size([3])
print(t.numel()) # 3 (number of element)
torch.sum(t) # 모든 요소의 합
torch.prod(t) # 모든 요소의 곱
torch.mean(t) # 평균
torch.var(t) # 표본 분산
torch.std(t) # 표본 표준편차
- (참고)표본 표준편차의 경우 표본으로 계산한 값이기 때문에 n이 아닌 n-1로 나누어야한다 - 자유도 개념
q = torch.empty(5) # 초기화 되지 않은 텐서 생성(쓰레기 값 들어감)
q.fill_(3.0) # fill_ 언더바 넣어야함
q.float() # tensor의 dtype casting 가능
# CPU tensor
x = torch.IntTensor([1,2,3])
x = torch.FloatTensor([1, 2, 3])
x.to(device='cuda') # cuda, 즉, GPU 메모리로 텐서를 옮기며 gpu 사용
x.cuda()
x.to('cpu') # 텐서를 다시 cpu로 옮겨옴
x.cpu()
x = torch.tensor([1, 3])
y = x.clone() # tensor 복사
z = x.detach() # 마찬가지로 복사하지만 계산 그래프에서 제외된 채 복사됨
t = torch.tensor([[1, 2, 3],
[4, 5, 6]])
print(t[1, :])
print(t[1, ...]) # ...으로도 : 과 같은 역할을 수행할 수 있다.
파이썬 리스트는 slicing
시 내부 값을 복사하여 새로운 메모리 공간에 리스트를 생성하지만, numpy의 배열이나 pytorch의 텐서들은 기존과 동일한 메모리 공간을 공유한다(얕은 복사).
이런 경우 slicing
으로 인해 tensor가 연속적으로 할당되어 있지 않을 수 있다.
t.is_contiguous() # 연속적인지 확인 가능
# (2, X) 형태로 변경(-1을 적으면 해당 차원에 적절한 값으로 자동 부여됨)
t.view(2, -1) # 불연속일 시 view 메서드는 오류 발생
t.contiguous().view(2, -1) # 연속으로 변경 후 view 적용 가능
t.reshape(2, -1) # 불연속이라도 사용 가능(이 경우 자동으로 복사가 일어남)
# 복사 된 경우 수정 시 원본 tensor에 영향 X
t.flatten(1, 2) # 1번째 부터 2번째 차원까지 평탄화 수행
t.transpose(1, 2) # 1, 2 차원의 축을 교환
t.squeeze() # 채널이 1개인 차원을 없애고 압축
t.unsqueeze(dim=1) # dim 1에 채널 1인 차원 추가
t = torch.tensor([[1, 2, 3]]) # 1x3
t.expand(4, 3) # 4x3 형태로 변경
# 기존 t의 메모리를 공유하며 확장된 것도 전부 view이다
# 수정 시 반복된 텐서들과 원본 텐서까지 영향이 간다
t.repeat(2, 3) # 2x9로 복사
# 기존 텐서의 값을 기반으로 새로운 텐서를 생성한다
# in-place 방식의 산술연산
a.add_(b) # _있는 함수는 a 텐서의 값을 업데이트한다
a.sub_(b)
a.mul_(b)
a.div_(b)
$L_p$ norm 노름
\[\|x\|_p = \left(\sum_{i=1}^{n}\left(|x_i|^p\right)^{\frac{1}{p}} \right)\]유사도
두개의 1-D Tensor(Vector) 가 얼마나 유사한지에 대한 측도
맨해튼 유사도
\[\begin{aligned} \text{Manhattan Distance} &= \sum_{i=1}^n|x_i-y_i| \\ \text{Manhattan Similarity} &= \frac{1}{1 + \text{Manhattan Distance}} \end{aligned}\]- 유사도의 최댓값은 1이다.
유클리드 유사도
\[\begin{aligned} \text{Euclidean Distance} &= \sqrt{\sum_{i=1}^n|x_i-y_i|^2} \\ \text{Euclidean Similarity} &= \frac{1}{1 + \text{Euclidean Distance}} \end{aligned}\]코사인 유사도
두 벡터가 이루는 각도에 cosine
값을 취해 유사도를 평가한다.
\[\begin{aligned} \text{Cosine Similarity} &= cos(\theta) \\ &= \frac{\mathbf{x} \cdot \mathbf{y}}{\|x\|_2\cdot\|y\|_2} \end{aligned}\]벡터가 평행이면 유사도가 1, 수직이면 0의 유사도를 갖게 된다.
상관 관계 분석 수식
\[r_{xt} = \frac{\sum_{i=1}^n{(x_i-\bar{x})(t_i-\bar{t})}}{\sqrt{\left(\sum_{i=1}^n{(x_i-\bar{x})^2}\sum_i^n{(t_i - \bar{t})^2} \right)}}\]x와 t가 함께 변하는 정도를 각각 변하는 정도에 나누는 것
np.corrcoef(x, t)
최소 0.5 이상일때부터 상관관계가 존재한다고 볼수 있음
torch.nn 으로 신경망 모델 구축
데이터 전처리
from sklearn.model_selection import train_test_split # sklearn을 활용한 데이터 분할
x_train, x_test, t_train, t_test = train_test_split(x, t, test_size=0.2, random_state=42)
from sklearn.preprocessing import StandardScaler # sklearn을 활용한 데이터 표준화
scaler = StandardScaler()
x_train = scaler.fit_transform(x_train)
x_test = scaler.transform(x_test)
from torch.utils.data import Dataset, DataLoader
class IrisDataset(Dataset): # CustomDataset 클래스 생성 가능
def __init__(self, features, labels):
self.features = features
self.labels = labels
def __len__(self): # 데이터 길이 반환
return len(self.features)
def __getitem__(self, idx): # 특정 idx 데이터 반환 메서드까지 오버라이딩 필수
return self.features[idx], self.labels[idx]
train_dataset = IrisDataset(x_train, t_train)
test_dataset = IrisDataset(x_test, t_test)
batch_size = 4 # 배치 크기를 4로 설정
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False)
nn.Module
nn.Module
을 상속받는 모듈이나 모델을 만들 수 있다. forward
순전파 함수를 구현해주어야한다.
class Model(nn.Module):
def __init__(self):
super().__init__()
self.linear = nn.Linear(3, 5)
# TODO: 생성자 만들기
def forward(self, x):
y = self.linear(x)
# TODO: 순전파 구현하기
return y
model = Model()
# GPU 설정
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model.to(device)
x = x.to(device)
y = y.to(device)
# 손실함수 및 optimizer 생성
loss_function = nn.MSELoss() # Mean Squared Error
# nn.BCELoss()는 binary cross entropy loss
optimizer = optim.SGD(model.parameters(), lr = 0.01)
for epoch in range(num_epochs):
for batch_features, batch_labels in train_loader:
outputs = model(batch_features)
loss = loss_function(outputs, batch_labels) # input으로 손실값까지 계산
optimizer.zero_grad() # 이전 단계에 계산된 값 초기화
loss.backward() # 기울기 계산
optimizer.step() # parameter 업데이트
예측(테스트)
예측 시에는 gradient 계산이 불필요하며, 정규화를 했다면 예측 후 정규화 해제 작업이 필요하다.
# 표준화시 fit_transform으로 훈련 데이터에 따라 정규화를 하며 scaler_x에 정규화 파라미터를 저장하였다.
# 이를 test에도 적용하기 위해 transform 함수를 사용한다.
test_scaled = scaler_x.transform(test_data.reshape(-1, 1))
test_tensor = torch.tensor(test_scaled, dtype=torch.float32).view(-1, 1).to(device)
model.eval() # dropout, batch norm 같은 걸 평가모드로 전환
with torch.no_grad(): # grad 계산 방지
predictions_scaled = model(test_tensor)
predictions = scaler_t.inverse_transform(predictions_scaled.cpu().numpy())
댓글남기기