정리노트

Deep Learning (3)_ Pytorch 본문

AI/Deep Learning

Deep Learning (3)_ Pytorch

Krex_Kim 2022. 4. 20. 22:03

앞선 포스팅에서 간단한 Neural Network구조인 MLP를 다루었는데, 

그 단순한 모델인데도 각 Activation의 Gradient부터 일일이 가중치를 Update하는 일까지 꽤 복잡한 과정을 거친 것을 확인할 수 있었다. 그렇다면 모든 딥러닝을 구현할때 이런과정을 거쳐야할까?

 

아니다.

 

파이썬에는 Pytorch, Tensorflow, Keras같은

Deep Neural Network를 구현하는 훌륭한 오픈소스 Framework가 있고, 실제 모델을 구현하는 단계에서는 이런 Framework를 잘 구성해주면 복잡한 과정을 거치지 않아도 비교적 단순하게 모델을 구현할 수 있다.

시간이 지날 수록 pytorch 사용량이 많아지고 있음을 알 수 있다

 

이번 포스팅에서는 바로 이 pytorch Deep Learning Framework에대해서 자세히 다뤄보도록 하겠다.

.

 

 

◆목차

With & Without Pytorch (Shallow Neural Network)

torch.Tensor

 ○ Torch Data Type

 ○ Tensor Operation

Autograd 
 ○ with torch.no_grad():

 ○ Avoiding in-Place Operation in Autograd

◎ nn.Module

 

 

 

 

 

 With & Without Pytorch (Shallow Neural Network)

같은 Shallow Neural Network를


하나는 Numpy,

다른 하나는 Pytorch 패키지로 구현해보면서

Pytorch 프레임워크의 일반적인 구조를 살펴보도록 하자.

 

보통 크게, 인공지능을 구현할때

1, Data Preprocessing(전처리)

2, Data Pipelining

3, Modeling

4, Training

정도의 단계를 거치는데, 지금 이야기 하려는 단계는 Modeling, Training이다.

 

먼저 아래와같이 Neural Network 모델을 구현해보자.

왼쪽은 Pytorch없이 Numpy로만 구현한 모델이고,

오른쪽은 Pytorch로 구현한 모델이다.

 

Numpy로 구현한 모델에서는

training 코드에서 Back Propagation의 Gradient값을 일일이 구현해 주어야 하므로

Foward Pass에서 Return 값으로

첫번째 레이어의 Output값 a1,

두번째 최종레이어의 Output값 a2 값까지

모조리 반환해야 training코드를 짤 수 있다.

 

그러나 Pytorch에서는

parameter을 tracking하여 자동으로 Gradient값을 찾아주는 Auto Gradient 기능 덕분에

Gradient값을 일일이 구현할 필요없어지고,

Forward Pass에서도 최종 결과값인 a2만 반환해주면 된다.

 

Pytorch로 모델을짤때는 nn.Module이라는 클래스를 상속하여 사용하는데,

https://pytorch.org/docs/stable/nn.html

 

torch.nn — PyTorch 1.11.0 documentation

Shortcuts

pytorch.org

 

nn.Module안에 Deeplearning을 구축하는데 필요한 Submodule이 다 들어 있어서,

원할때 편하게 꺼내쓰면 되는 구조로 되어있다.

 

 

아래는 Numpy로 구축한 모델의 Training 과 Pytorch로 구축한 모델의 Training과정을 비교해 놓은 것이다.

 

구현한 모델로 Training을 할때,

Numpy로 구현한 모델은 일일이 Gradient값을 구해서 기입해주고, update해줘야하는 반면,

Pytorch로 구현한 모델은 Autograd 기능덕분에 backward() 메서드만 호출해주면 Optimizer에 따라 Gradient 값에따른 Backpropagation을 진행해준다.

 

 

같은 트레이닝 과정이지만 pytorch 프레임워크에서 짰을때 가독성이 좋고 속도도 훨씬 빠르다.

Pytorch는 GPU가속을 사용할 수 있도록 디자인 되어있기 때문에, Data Pipelining만 잘해주면 엄청난 속도로 수많은 데이터를 처리할 수 있다.

 

 

◎ torch.Tensor

Linear Algebra에서 다루는 Tensor개념처럼, PyTorch텐서역시 여러차원의 Array로 이루어져있으며,

Numpy의 거의 모든 기능이 지원되고, 추가로 GPU Accelearion이 가능하다.

 

 

 

○ Torch Data Type

아래 링크에서 Torch에 쓰이는 Data Type을 확인할 수 있다.

https://pytorch.org/docs/stable/tensors.html

 

torch.Tensor — PyTorch 1.11.0 documentation

Shortcuts

pytorch.org

 

Default Data Type은 32bit floating point이다.

 

 

○ Tensor Operation

Tensor의 Operation은 Numpy와 매우 비슷해서, Numpy연산에 익숙한 사람이라면 금방 따라갈 수 있을 것이다.

 

아래는 torch에서 사용하는 Tensor연산에대해 가볍게 정리해둔 것이니,

혹시라도 모르는게 있다면 한번쯤 참조해보면 좋을 듯 하다.

 

- Accessing Elements

Torch의 Default Data Type은 32bit floating point라서, 정수를 기입해도 실수형 자료형을 Return하는 것을 볼 수 있다.

항상 Tensor값을 반환하며, tensor가 아니라 그냥 안에들어있는 데이터를 보고싶으면 item()메서드를 사용한다.

 

- Slicing

Numpy, Pandas 패키지를 써본 사람이라면 익숙한 슬라이싱.

Numpy와 다를게 없다.

 

indexing Number : 순서

  =>    0부터시작 : 1부터시작

 

 

- Negative Slicing

음의 인덱싱도 Numpy, Pandas와 똑같다

 

 

- Shape & Transpose

 

 

 

- Sum

특정 차원에 있는 모든 Elements를 더하는 Method로,

keepdim 파라미터를 이용해 차원을 유지할지 결정한다.

(유지하지 않는다면 차원이 줄어든다.)

dimension 에 대한 정의가 없다면 모든 값이 더해진 0차원 텐서가 된다

 

dim에 대한 정의를

2차원 텐서인 경우 0,1 (또는 -1,-2)로 할 수 있으며,

3차원 텐서의 경우 0,1,2까지 할 수 있다.

 

위 그림에서 예시는 0(열), 1(행)에대한 sum을 진행한 그림으로, keepdim 파라미터로 차원을 유지하는 그림을 확인할 수 있다. -> tensor([6. , 5.]) 이 아니라 tensor([[6.] , [5.]])

 

 

- Mean

mean() 메서드도 sum()에서와 비슷한데, 특정차원, 혹은 모든 차원에 대해서 평균을 반환할 수 있다.

0인경우가 열, 1인경우가 행에대한 평균.

3차원 텐서인경우 2까지 사용가능하다.

 

- Max

0인경우가 열, 1인경우가 행에대한 평균 

3차원 텐서인경우 2까지 사용가능하다.

 

 

 

 

- Bianry Operation

 

 

 

- Inner Product

 

 

 

 

 

 

으레, Torch로 모델을 구현하다보면

차원의 수와 shape를 맞추주려고 아래 그림 처럼 씨름하게되기 마련인데, 이때 쓰기 유용한 Operation으로

view, squeeze/unsqueeze이 있다.

 

- View

예시를 보면 이해가 쉬울것이다

 

 

 

- Squeeze / Unsqueeze

아래의 broadcasting 수동버전으로 생각해두면 될 듯하다

 

- Broadcasting

Broadcasting은, Tensor연산과정에서 서로다른 차원개수의 텐서를

차원수를 맞춰주며 연산가능하도록 하는 기능으로,

이에대한 설명은 아래 블로그에 자세히 나와있다

https://mclearninglab.tistory.com/85

 

Pytorch docs 요약] Broadcasting Semantics

원본 BROADCASTING SEMANTICS 많은 pytorch operation은 NumPy Broadcasting Semantics 을 지원한다. 짧게 말해, PyTorch operation이 broadcast를 지원하면, 그 텐서 매개변수들은 자동적으로 (데이터를 복사하지..

mclearninglab.tistory.com

Pytorch가 Broadcasting을 지원하려면, 아래조건을 만족해야한다.

각 텐서의 끝자락부터의 순서로

1, 텐서차원이 같거나,

2, 1이거나

3, 차원이 없거나.

위 예시를 보면, (2,3,3)크기의 텐서인 X는,

(1,1,3) , (1,3) , (3) 사이즈의 텐서와의 연산에서 Broadcasting이 가능한 것을 알 수있다.

 

X 가 (2,3), Y가 (2)인 텐서이고,

이때 X의 마지막 차원인 3과 Y의 마지막 차원인 2가 서로 다르기 때문에 Broadcasting이 지원이 안되는 모습을 볼 수 있다. -> X를 Transpose하여(3,2)로 만들어준다면, 아까전 예시처럼 Broacasting이 가능해진다.

 

- ndarray, tensor

Numpy의 ndarray와 Pytorch의 Tensor끼리 왔다갔다 하는 메서드이다.

 

*단, 여기서 만약에 데이터가 Cuda device에 할당되어있다면 작동하지 않을 수도 있다..

이럴경우 할당된 데이터를 다시 해제 시키도록 해야하는데,

아래처럼 진행해주면 된다.

연산과정에서 X,Y와 함께 avg_cost까지 CUDA GPU에 할당된 상황이다.

'cuda' Device에 할당되어 있을시 다시 cpu로 detach해주고 numpy로 바꿔주어야 한다.

 

 

 

 

 Autograd

Neural Network의 노드와 레이어 개수가 많아질 수록, 계산해야하는 Gradient는 무한히 많아진다.

글 시작부에서, Pytorch Framework에서는 Gradient를 계산해줄 때, 일일이 기입해주지 않아도 자동으로 Gradient를 계산해주고, 이를 Tracking해준다고 언급하였다.

 

 

이 기능을 Pytorch의 'Autograd'기능이라고 한다.

 

아래 블로그에 Auto_grad내용이 잘 정리되어있으니 참조

https://blog.naver.com/PostView.nhn?blogId=je_un&logNo=222298692213

 

[Pytorch] Autograd

위의 동영상과 사이트를 보며 정리한 포스팅 입니다. Autograd 텐서의 모든 연산에 대해 자동 미분을 제공...

blog.naver.com

require_grad=True가 되어있을때, 파라미터 Value를 Tracking할 수 있고,

Backward() 메서드를 입력만해주면 Tracking된 Value를 기반으로 Gradient를 알아서 계산해준다. 

자세한 설명은 위 블로그에 잘 정리가 되어있어서, 궁금하다면 한번 꼭 읽어보길 바란다.

 

 

○ with torch.no_grad():

https://go-hard.tistory.com/64

 

model.eval()과 with torch.no_grad()

pytorch 프레임워크에서 Train을 하거나 evaluation or Test를 수행할 때 자주 사용하게 되며, 함수간의 차이가 존재한다. 혼동하기 쉬우니 구분해서 사용하기 바랍니다. model.eval()  will notify all your la..

go-hard.tistory.com

Gradient는 Training과정의 Back Propagation을 하기 위해서 필요한 것이기 때문에,

Forward Propagation, 즉, 모델 자체의 Prediction값을 테스트하고 싶을때는 굳이 필요하지 않고 계산 속도만 저해할 뿐인 기능이 된다.

 

딥러닝 코드들을 보면 

이렇게 선언해놓고 그 안에서 코딩이 구현된 경우가 많은데,

require_grad를 False로 바꿔주는 기능이라고 생각하면 된다. (그렇기때문에 with 안에서는 Backward()는 불가능하다)

 

○ Avoiding in-Place Operation in Autograd

in-place Operation란, tensor의 값을 바꿀 때, 해당 메모리에 값을 Copy하여 바꾸는 것이 아닌, 직접 메모리에 접근하여 값을 바꾸는 Operation을 의미한다.

앞서 Autograd의 핵심은 Parameter Value를 Tracking하여 그 변화량을 알아내는 것이라고 언급하였다.

이 Autograd가 제대로 동작하기 위해서는, in-place Operation을 사용하지 말아야한다. (구체적인 이유는 알수없지만)

무려 Pytorch 오피셜

아래 예시처럼 inplace Operation가 아닌, 별도의 메모리를 Copy하여 사용하도록 모든 연산을 진행시켜야 Autograd가 제대로 작동된다.

...0하나 만드는 것도 따로마스크를 만들어서 진행해주는게 좋다

 

 

 

◎ nn.Module

포스팅 앞부분에서도 언급했듯,

pytorch는 모델을 구성할 때, nn.Module를 상속받아 사용한다.

 

이 내용에 대해서는 아래 블로그에 잘 정리되어있다

https://daebaq27.tistory.com/60

 

[Pytorch] nn.Module & super().__init__()

우리는 pytorch에서 각자 레이어 혹은 모델을 구성할 때, nn.Module을 상속받는다. 왜 상속을 받을까? 또 상속받을 때, super().__init__()은 왜 해주는 것일까? 해당 코드를 작성함으로써 어떤 속성을 갖게

daebaq27.tistory.com

class 클래스이름(nn.Module):

  def __init__(self):

     super(클래스이름,self).__init__()

 

를 클래스 선언과 함께 해주는게 국룰인데 이걸 하는 이유까지 위 블로그에 잘 나와있다.

nn.module은 클래스를 Submodule화 하여 Parameter Tracking을 진행하는 것으로 알고있는데 (아마 맞을거임)

super().__init()__을 해주는 이유도, 바로 이 클래스를 modules화 해주기 위해서 초기화 해주는 것이다.

 

nn.Module의 특징

 

 

 

 

-> Training 

nn.Module을 상속받아 구성한 모델을 Training하는 과정은

보통 아래와같은 3단계를 거친다.

 

1, initialization.. 

Optimizer를 설정해주고, Learning rate를 결정한다.

 

 

2, Forward

Class의 forward() method에 input값을 넣어 Forward Propagation한다

 

3, Backward

loss를 설정해 준 후,

Autograd의 힘을 빌려서 loss의 Gradient값을 도출한다. 그리고 Optimizer.Step()을 이용해 이를 Propagation시켜준다.

 

 

.... 그 복잡한 과정이 3단계로 요약됐다..

 

 

 

 

Comments