[Pytorch] practice

윤형준·2022년 8월 24일
0
post-thumbnail

Day1 실습

Pytorch를 다루는데 꼭 필요한 tensor에 대한 개념과 선형 모델로 간단한 데이터 모델을 예측하는 모델을 만들어보자

Tensor manipulation

  • python의 numpy 패키지와 pytorch는 vector, matrix, tensor를 쉽게 다룰 수 있는 많은 함수와 자료구조를 제공합니다. 따라서 공학과 인공지능을 공부하기 위해서 필수적으로 알아두어야 하는 라이브러리들입니다. 간단한 선형 인공지능 모델을 다루기 전에 많이 쓰이고 유용한 함수들을 먼저 공부해봅시다.

텐서 조작하기 레퍼런스

  1. 텐서의 차원과 형태 관련
X, Y        # Tensors
X.dim()  # 차원을 출력
X.shape, X.size() # 텐서의 모양을 출력
import torch
X =torch.rand(3,4, 5)

print('X.dim()', X.dim())
print('X.shape', X.shape)
print('X.size()', X.size())
X.dim() 3
X.shape torch.Size([3, 4, 5])
X.size() torch.Size([3, 4, 5])

그렇다면 shpae과 size()의 차이는??

  • shape은 변수이고 size()는 메서드이다.
  1. Mul 과 Matmul의 차이
X.matmul(Y) # 행렬 곱 (내적)
X.mul(Y)    # X*Y 와 동일. 각 원소 별로 곱하는 연산.
X = torch.rand(3,2,5)
Y = torch.rand(3,5,3)

D = X.matmul(Y) # 행렬 곱 (내적)
print(D)
print(D.shape)
# X.mul(Y)    # X*Y 와 동일. 각 원소 별로 곱하는 연산.
tensor([[[1.7955, 1.2414, 1.4892],
         [1.4453, 1.0660, 1.0680]],

        [[1.5991, 1.2970, 1.6333],
         [1.0118, 1.4612, 0.9563]],

        [[0.4231, 0.7838, 1.0513],
         [0.8023, 1.0286, 1.2409]]])
torch.Size([3, 2, 3])
  1. Broadcasting

X의 shape이 [100,1,20] 이고, Y가 [100,40,20] 일때, 크기가 다르기 때문에 원소별 연산 (예; +, * 등) 적용이 불가한 것처럼 보이지만, numpy와 pytorch는 broadcasting을 지원하여, X의 두번째 차원 1인 경우, Y의 두번째 차원인 40에 맞춰 X의 값들을 반복 복제하는 식으로 자동으로 크기를 조절하여 연산이 가능하도록 만들어줍니다. 매번 복제하는 코드를 명시적으로 구현할 필요 없이, 매우 편리하게 응용될 수 있지만, 의도치 않게 broadcasting이 되면 디버깅을 할때 오류를 잡는 것이 어려워 질 수 있으므로 꼭 주의하여 사용 것이 좋습니다.

  1. view() (numpy의 경우는 reshape())

텐서의 shape를 바꿔야할 경우 사용합니다. 매우 자주 쓰이는 함수이므로 꼭 알아두세요!

X.shape
X.view(3,10).shape
torch.Size([3, 10])
  1. axis개념

많은 함수에서 매개변수로 요구되는 개념입니다. 다차원 텐서에 해당 함수 연산을 어떤 축으로 적용 할지를 결정하는데 사용합니다.\ 예; np.concaternate((A1,B1),axis = 0) 이런식으로 함수의 매개변수 중 하나로 자주 등장합니다. \ \ 참고자료> http://taewan.kim/post/numpy_sum_axis/ \

  1. squeeze & unsqueeze

특정 차원이 1인 경우 축소시키거나 차원을 확장시킬 때 사용합니다. 자주 등장하므로 알아두면 좋습니다.

torch.squeeze(X) # X: [100,1,20] => [100,20]
  1. type casting

컴퓨터는 여러가지 자료형(int,float,uint8 등)이 있지만 type이 같지 않으면 수치적인 문제가 발생할 수 있기 때문에 항상 유의하는 것이 좋습니다. 따라서 자료형이 무엇인지 그리고 어떻게 바꾸는지 알고 있어야 합니다.

  1. concatenate

두 개 이상의 텐서들을 지정된 축으로 쌓아서 더 큰 텐서를 만드는 함수. 하나의 텐서로 합치기 위한 입력 텐서들은 concatenate하는 축을 제외하고는 모두 같은 크기를 가져야 합니다.


1일차 실습

선형 모델 f(x)=Wx+b에 대해서, 주어진 데이터를 제일 잘 표현하는 learnable parameter인 Weight W와 Bias b를 찾는 방법의 예제 입니다. 이 실습에서는 parameter 탐색을 하는 다양한 방법 중 가장 Naive한 방법으로 찾는 예제를 보여줍니다.

먼저 필요한 라이브러리들을 import합니다.

W와 b를 찾는다(최적화한다.)

from __future__ import print_function, division
import os
import torch
import pandas as pd
from skimage import io, transform
import numpy as np
import warnings
warnings.filterwarnings("ignore")

다음의 그래프는 지난 시험의 결과를 토대로 서로 다른 학생의 공부시간과 성적의 관계를 모아놓은 표입니다.

Q1) study time과 Grade 각각을 torch.FloatTensor로 작성하시고, shape는 [7, 1], dimension은 2로 만들어 보세요.

Q2) 위에서 만든 x_train과 y_train이 잘 만들어졌는지 시각화 해보세요.

시각화 참고 링크

![스크린샷 2022-08-24 오후 5.00.16](무제.assets/스크린샷 2022-08-24 오후 5.00.16.png)

이번에는 GDrive와 Colab의 csv 파일을 읽어오는 법과 외부 인터넷 페이지 상의 csv 파일을 읽어오는 법에 배워보도록 하겠습니다.

하단의 링크에는 health_data.csv 파일이 들어있습니다. 이 파일을 다운받은 후 google drive의 가장 기본 디렉토리인 "내 드라이브"로 옮겨주세요.

https://drive.google.com/file/d/1C1_Sh2Rw5St58NLvDer62cJd-bvUvUcs/view?usp=sharing

Colab과 Gdrive 모두 google에서 제공하는 서비스이므로 2개를 연동시킬 수 있습니다.

하단의 링크를 참조하시면 친절한 설명이 되어있습니다.

https://starrykss.tistory.com/1029

from google.colab import drive
drive.mount('/content/gdrive')  Mounted at /content/gdrive

Mounted at /content/gdrive

gdrive와 colab을 연동시켰다면 gdrive에서 csv 파일을 가져와 사용해봅시다.

import pathlib
path = pathlib.Path('/content/gdrive/My Drive/health_data.csv') 

data_file = pd.read_csv(path)
data_file.head()

![스크린샷 2022-08-24 오후 5.13.35](무제.assets/스크린샷 2022-08-24 오후 5.13.35.png)

이 데이터는 정제가 되지 않아 데이터가 불완전 한 상태입니다. NaN은 숫자로 표현 불가한 값으로 최적의 Weight W와 Bias b 를 찾는데 방해가 됩니다. 이런 데이터들을 모두 제거하는 전처리 작업을 해봅시다.

Q3) 우선 데이터셋 안에 NaN 혹은 null이 있는지 체크합니다.

pd.isnull(data_file)
  • Isnull 함수를 활용하여 결측값을 체크 했는데 모든 셀에 대해서 False True 형태로 출력 됨

![스크린샷 2022-08-24 오후 5.20.28](무제.assets/스크린샷 2022-08-24 오후 5.20.28.png)

정답

data_file.isnull()

Q4)미완성 되어 있는 행을 제거해보세요.

(힌트1) pandas의 dropna()이용

(힌트2) axis에 대한 개념을 모르겠다면 tensor manipulation 부분으로 가서 다시 공부해보세요!

data_file = pd.read_csv(path).dropna(axis=0)
data_file.head()
  • pandas의 dropna()를 이용했고 axis=0을 주어 결측값이 있는 행을 없앴다.
  • 결측값이 있는 열을 없애고 싶다면 axis=1을 주면 된다.

![스크린샷 2022-08-24 오후 5.26.15](무제.assets/스크린샷 2022-08-24 오후 5.26.15.png)

정답

data_file = data_file.dropna(index=0).reset_index(drop=True)
data_file.head()

Q5) csv 파일은 아직 pytorch에서 사용할 수 있는 텐서의 형태가 아니므로 tensor의 형태로 바꿔보세요

height = 
weight = 

![스크린샷 2022-08-24 오후 6.23.34](무제.assets/스크린샷 2022-08-24 오후 6.23.34.png)

이런식으로 하면 되지 않을까 생각했는데 실패 ㅠㅠ

정답

height = torch.tensor(data_file.height)
weight = torch.tensor(data_file.weight)

Q6) 공부시간과 성적 그래프를 입력할 때 처럼 shape와 dimension을 맞춰주시고, 자료형은 float 타입으로 변환시켜보세요

(힌트) .view() 함수이용, shape = (50, 1), dimension = 2

x_train = height.view([height. shape[0] ,1]).float()
y_train = weight.view([weight. shape[0] ,1]).float()

Q7) 랜덤으로 만든 데이터를 기존 데이터에 추가해봅시다. x_train dataset의 경우 145부터 190사이의 랜덤한 숫자 50개, y_train dataset의 경우 45부터 85 사이의 랜덤한 숫자 50개를 생성하여 concatenate를 시킵니다.

(힌트) 랜덤 생성 함수 torch.rand()함수 사용, concatenate의 경우 torch.cat()함수를 사용합니다. axis도 데이터의 형태에 맞게 사용하시면 됩니다.

x_train = torch.cat((torch.rand(50.1)*45+145,x_train). axis = 0)
y_train = torch.cat((torch.rand(50.1)*45+145,y_train). axis = 0)

![스크린샷 2022-08-25 오전 1.29.36](무제.assets/스크린샷 2022-08-25 오전 1.29.36.png)

  • why not

Q8) training data가 잘 등록이 되었는지 matplotlib 함수를 통해 시각화 해보세요.

%matplotlib inline
import matplotlib.pyplot as plt

x = x_train
y = y_train

plt.scatter(x,y)
plt.show()

Q9) 이번에는 아래의 파란선처럼 data에 잘 표현하는 직선(y=Wx+by = Wx + b)을 찾으려합니다. x와 y는 데이터셋으로부터 주어진 데이터들이기 때문에 W와 b를 결정하면 됩니다. 기계가 학습하는 방법과 관련된 것을 수업에서 다루지 않았기 때문에, 가장 간단한 방법인 랜덤하게 W와 b를 바꿔가면서 training dataset을 가장 잘 fitting하는 파라메터들을 찾아봅시다.

Q10) 총 50000번 W, b 값을 바꾸어 training dataset에 가장 잘 fitting 하는 W, b 값을 찾아봅시다. W, b가 가질 수 있는 모든 값을 다 시도해보는 것은 무한한 가능성이 있어서 어마어마하게 많은 시간을 이용해야 합니다. 이번 실습과 같이 작은 문제에서는 적용할 수 있을지 모르겠지만 조금만 차원이 늘어나도 실용적이지 않게 됩니다. 따라서, 이번에는 복잡한 방법이 아니라 Try & Error를 통한 가장 간단한 방법을 시도해 봅시다. 랜덤으로 *실수*를 생성하여 W, b에 할당 합니다. 그렇게 정해진 W, b를 이용하여 y의 예측을 시도할 수 있습니다.

hypothesis=Wx+b

현재 구한 직선 (Hypothesis)이 데이터에 잘 fitting 되었는지 확인하는 방법으로는 Error ∣hypothesis−y∣의 합으로 구하며 이를 loss라고 명명합니다. 일반적으로는 L2 loss라 하여 간단히 (hypothesis−y)2를 사용하나, 본 예제에서는 데이터에 거짓 데이터(Outlier)들이 많이 포함되어 있어, 거짓 데이터에 강인하다고 알려진, L1 loss ∣hypothesis−y∣를 사용합니다. 이전에 구했던 loss의 값보다 더 작은 loss가 나올 경우 min_loss에 현재의 loss를, min_W과 min_b에는 현재 W와 b를 저장합니다.

50000번을 반복하여 생성된 직선을 matplotlib으로 시각화하여 얼마나 현재 training dataset에 얼마나 잘 fitting 되었는지 확인하여보세요.

(힌트) 랜덤으로 숫자를 생성하는 함수로는 torch.rand() 함수를 사용하고, 적당히 크기와 오프셋을 조정해주세요. ([출력범위] = 크기*[입력범위] + 오프셋)

(힌트) 파이썬의 기초가 약하여 if문, for문 같은 문법을 간단하게 공부하고 싶으시다면 wikidoc(https://wikidocs.net/book/1 : jump to python)을 참고하시면 도움이 될것입니다.

(+α\alpha) |hypothesis - y|의 값들을 모두 더하는 가장 쉬운 방법은 for문을 사용하는 것이지만, 가장 짧게 작성할 수 있는 방법은 벡터화하여 연산하는 방법입니다. https://ooyoung.tistory.com/141 벡터화와 관련된 간단한 설명이 되어있는 링크이며 벡터화를 시키지 않아도 문제를 푸는데는 지장이 없습니다.

#답안 작성

#문제를 푸는데 필요한 변수들이며 필요할 경우 추가 혹은 삭제하셔도 무방합니다.
iter = 50000 #loss값을 구하는 횟수로 총 50000번 
weight_max = 100 #'[입력범위]'로 random값의 weight 범위 제한 목적 ( -50 < weight < 50 )
bias_max = 150 #오프셋으로 random값의 bias 범위 제한 목적 (-150 < bias < 0)
min_loss = 1000000 #업데이트 된 가장 작은 값의 loss 저장 
min_W = 0 
min_b = 0

#dataset
x = x_train
y = y_train

def loss_fn(hypo, GT):
  return sum(abs(hypo - GT))

# [Do it yourself] 위의 변수들을 활용하여 문제를 풀어주세요.
for i in range(iter):
  W = 
  b = 
  hypothesis = 
  
  cur_loss = loss_fn(hypothesis,y)

  ... 

  if cur_loss < min_loss:
    ...

최종적으로 data에 직선을 잘 fitting 시켰는지 시각화 해봅시다

# 직선 시각화
%matplotlib inline
import matplotlib.pyplot as plt
import numpy as np

x = x_train
y = y_train

plt.scatter(x, y)

t = np.arange(140.,190.,0.001)

plt.plot(t, min_W*t+min_b)
plt.xlabel('height (cm)')
plt.ylabel('weight (kg)')
plt.show()

대략 아래와 같은 결과를 얻으셨다면 Day1의 실습은 마무리가 된 것입니다.

profile
매일 조금씩 성장하는 개발자

0개의 댓글