[main_skill] M1에서 배우는 파이토치 1편

coing_by_hotpack·2023년 1월 25일
0

Deeplearning

목록 보기
1/1
post-thumbnail

Pytorch와 친해지기

0. 참고한 강의 영상

메타코드 딥러닝 6시간완성 1편

이론 파트는 다 수강한 상태!

1. Macbook Air M1에서 Pytorch MPS(윈도우에서 쓰이는 cuda) 설치

  1. 딥러닝을 공부할 개발환경에서 아래의 커멘드를 입력
    conda install -c pytorch pytorch

  2. Python 환경에서 아래의 커멘드를 입력 후 True를 확인하기

import torch

device = torch.device('mps:0' if torch.backends.mps.is_available() else 'cpu')

print (f"PyTorch version:{torch.__version__}") # 1.12.1 이상
print(f"MPS 장치를 지원하도록 build 되었는지: {torch.backends.mps.is_built()}") # True 여야 합니다.
print(f"MPS 장치가 사용 가능한지: {torch.backends.mps.is_available()}") # True 여야 합니다.

!python -c 'import platform;print(platform.platform())'

필자의 경우 아래와 같이 출력

PyTorch version:1.12.1
MPS 장치를 지원하도록 build 되었는지: True
MPS 장치가 사용 가능한지: True
macOS-13.0-arm64-arm-64bit

설치가 잘 됐는지는 이후 학습과정을 통해서 확인할 수 있어서 패스~

2. 클론코딩

2-1. tensor와 list 비슷하지만 다르다

ls1 = [1,2]
ls2 = [3,4]

tor1 = torch.tensor([1,2])
tor2 = torch.tensor([3,4])

print(ls1 + ls2)
print(tor1 + tor2)
print(tor1 * tor2)

[1, 2, 3, 4]
tensor([4, 6])
tensor([3, 8])

리스트 형태의 값의 연산과 텐서 형태의 값의 연산은 다른 형태로 진행된다

2-2. 처음 마주한 matmul 함수

print(sum(tor1 + tor2))

print(tor1.dot(tor2))
print(torch.dot(tor1, tor2))

print(torch.matmul(tor1, tor2)) 
print(torch.matmul(tor1.view(1,-1), tor2)[0]) 

matmul 은 shape을 맞추고 행렬 곱을 계산하기 위한 함수

viewmatmul을 하기 위해 맞춰주는 함수. 최근에는 업글되서 위에 처럼 진행한다고 함.

행렬 곱은 스칼라 곱과 다르다는 점만 안다면 이해가 쉽다

2-3. torch.where

data = torch.randn(4,3)
print(data)
print(torch.where(data>0, torch.ones(data.shape), torch.zeros(data.shape)))

data > 0이라는 조건을 넣어줬을 때 텐서의 각 원소마다 그 값이 참이면 텐서의 원소 위치에 torch.ones를 반환하고 그렇지 않으면 data의 그 위치에 torch.zeros를 보여주는 함수

tensor([[-1.2605, 1.2107, -0.7283],
[-1.6908, 0.4007, -2.2820],
[-1.7402, 0.5828, -0.9733],
[-0.4130, -0.4026, 0.2520]])
tensor([[0., 1., 0.],
[0., 1., 0.],
[0., 1., 0.],
[0., 0., 1.]])

2-4. numpy와 호환이 가능하다

numpy 를 배우다보면 딥러닝에서 자주 쓰인다고 했는데 직접 써보니 torch 와 호환성이 좋아보임

a = torch.ones(5)
print(a)

b = a.numpy()
print(b)

a = torch.from_numpy(b)
print(a)

텐서를 넘파이로, 넘파이를 텐서로 바꾸는 함수가 존재

2-5. GPU(mps)를 써보자

M1 GPU를 쓸 수 있도록 지원해준 mps를 어떻게 쓸까?

x = torch.tensor([1,1]).cuda()
print(x)

위 방식대로 M1 로컬환경에서 실행하면 당연히 오류가 뜬다. 우리는 cuda가 동작하지 않아서

x = torch.tensor([1,1]).to("mps")
print(x)

x = x.cpu()
print(x)

그래서 cuda() 대신에 to("mps") 를 사용한다!

  • 구매한지 1년이 넘어가서야 드디어 GPU를 써본다

cpu() 함수는 GPU 연산이 필요없는 계산에서 활용

여기서 주의해야 할 점은 GPU로 계산한 객체와 CPU로 계산한 객체는 서로 연산이 불가능하다는 점이다.

x = torch.tensor([1,1]).to("mps")
y = torch.tensor([0.5, 0.1])

print(x + y)

RuntimeError: Expected all tensors to be on the same device, but found at least two devices, mps:0 and cpu!

x는 mps로 계산하고 y는 cpu로 계산한 값이기 때문에 서로 연산이 불가능

2-5. Computational Graph (오차역전파를 계산하기 위해서는?)

이론상으로 노드에서 노드로 이어지는 계산을 수행한 후 예측값을 수정하기 위해 진행하는 오차역전파에서 gradient를 얻기 위해서 torch 에서는 설정해줘야 하는 것이 있다

a = torch.tensor([2.], requires_grad=True)
b = torch.tensor([1.], requires_grad=True)

함수에서 볼 수 있는 requires_grad 를 True로 설정해야 한다는 것

a = torch.tensor([2.], requires_grad=True)
b = torch.tensor([1.], requires_grad=True)

c = a + b
d = b + 1
e = c * d

c.retain_grad() # gradient를 계산할 수 있는 자격(?)을 주고
d.retain_grad()
e.retain_grad()

e.backward(retain_graph=True) # gradient를 계산하면

print(a.grad) 
print(b.grad)
print(c.grad)
print(d.grad)
print(e.grad) # grad를 구할 수 있다

retain_grad() 가 없이 c, d, e 값을 확인해보면 grad를 적용할 수 없는 None값이 출력될 것

따라서, retain_grad() 를 부여하고 역전파를 실행하여 grdient를 계산하면 grad를 얻을 수 있다.

여기서 주의해야 할 점은 역전파를 계속 수행하게 되면 grad값이 너무 커지는 현상이 발생하여 좋은 학습에 방해가 된다! 따라서 grad 값을 0으로 초기화하는 작업이 필요

a.grad.zero_()

항상 backward() 가 끝나면 넣어주도록 하자

이제 grad가 필요없어진 상황에선 아래와 같이 변수에 grad 성질을 제거한다

a.requires_grad = False
a = a.detach()

2가지 방법 중 아무거나 활용해도 된다

profile
코딩은 핫팩빨

0개의 댓글