본문 바로가기

~2023

[CS231n] Lecture 8. Deep Learning Software

728x90
반응형

목차

1.  CPU vs GPU

2.  Deep Learning Frameworks

    2.1  Pytorch

3. Static vs Dynamic Graphs

 


1. CPU vs GPU

CPU와 GPU에 대해 이야기를 하자면 왼쪽 그림은 CPU 칩의 모습이고 오른쪽 그림은 GPU의 모습이다.

위 그래프는 x축은 모델, y축은 연산에 소요된 시간인데 성능이 하드웨어 크기에 비례하는 것인지 GPU(빨, 주)가 CPU(파)보다 훨씬 적은 시간이 소요됐다. 64~76배 차이가 있는데 무조건 GPU를 쓰는게 좋다는 것을 알 수 있다.

강의에서 말하기를 CPU에서는 병목 현상(bottleneck)이 발생할 수 있기 때문에 GPU를 사용하는게 좋고 데이터는 CPU에 저장하며, 모델은 GPU에서 작동하는 것이 좋다고 한다.

 

2. Deep Learning Frameworks

2.1 Pytorch

Pytorch는 (전) Facebook (현) Meta에서 만든 딥러닝 프레임워크이다.

과거에는 Tensorflow를 많이 사용했지만 최신 논문 정보 반영과 연산이 직접적으로 잘 보인다는 장점 등으로 인해 대부분의 사람들이 Pytorch를 사용하며 오픈 소스 및 자료도 풍부해졌다.

그래서 이 챕터에서는 pytorch를 활용한 코드 구현 방법을 소개하려고 한다.

 

Pytorch에는 Tensor, Variable, Module이 있다.

  • Tensor: 연산 단위, 다차원 배열 - numpy array (GPU에서만 작동)
  • Variable: 노드로서 데이터 및 기울기 저장
  • Module: Network에 있는 하나의 Layer

 

위에서부터 첫 번째 블록은 2개의 레이어(x, y)를 가진 네트워크를 정의하고 해당 레이어의 가중치를 초기화한다.

두 번째 블록에서 torch.mm()과 torch.clamp()로 forward를 수행해 예측값 y_pred를 구하고 y_pred와 y 값으로 loss를 연산한다. 참고로 torch.mm()은 행렬곱을 수행하는 메소드이고 torch.clamp()는 매개변수로 min 또는 max를 넘겨 받아 해당 값보다 크거나 작은 값을 0으로 만든다. 따라서 torch.clamp(min=0)은 0보다 작은 값을 0으로 만들라는 의미로 relu 함수와 동일하게 작동한다. 그리고 pow()은 제곱을 해주는 메소드이다.

세 번째 블록은 가중치에 대한 기울기를 구하고 네 번째 블록에서 가중치 w1, w2를 업데이트한다.

 

위에 이미지처럼 torch 연산으로 기울기 값을 구할 수 있지만 autograd의 Variable을 사용하면 하나의 메소드로 모든 연산을 수행할 수 있다.

따라서 위에 이미지와 모든 것이 동일하지만, 세 번째 backpropagation 부분에서 w.grad.data.zero_()와 loss.backward()를 해주면 메소드 내에서 알아서 연산을 수행해주며 가독성도 훨씬 좋다.

 

이번에는 가중치 w1, w2를 torch.nn을 통해 layer로 관리하는 코드를 봐보자.

위에 예시에서는 w1, w2를 만들어 기울기를 각각 구하고 업데이트를 수행해줬는데 nn을 사용해 모델 가중치를 param으로 관리하면서 코드가 가독성이 높아지고 짧아진 걸 볼 수 있다.

 

위 update 부분에서 for loop문을 사용하기도 하고 $w = w - lr * gradient$ 수식을 그대로 사용하는데 torch.optim으로 최적화 함수를 객체화해 가독성을 향상시키고 코드를 짧게 만들었다.

 

그래서 최종적으로 우리가 잘 알고, 많이 배포되어 있는 형태의 코드를 만들 수 있다.

 

그리고 파이토치의 DataLoaders를 통해 데이터셋을 쉽게 불러올 수 있다.

또한 미니배치, 셔플, 멀티스레딩등을 간편하고 효율적으로 지원한다.

해당 코드와 같이 하나의 model class로 model을 구현하고, DataLoader로 minibatch를 추출한 뒤 Optimizer를 사용하여 학습을 수행하는 형태가 가장 기본적이다.

 

torchvision이라는 모듈을 통해 alexnet, vgg16, resnet101을 간편하게 불러와 사용할 수 있다.

 

 

3. Static vs Dynamic Graphs

TensorFlow가 사용하는 Static그래프와 PyTorch가 사용하는 Dynamic그래프의 장단점과 특징에 관해 소개하려고 한다.

 

각각의 코드를 보면 구성을 알 수 있다.

Static Graph는 첫번째로 그래프를 구성을 한 후, 두번째로 해당 그래프를 계속 반복적으로 동작하는 방식인 반면에, Dynamic Graph는 forward pass마다 새로운 그래프를 정의한다.

즉, TensorFlow는 정적으로 계산 그래프를 생성하여 계산 그래프를 한 번만 생성하여 계속 이용하고,
PyTorch는 동적으로 계산 그래프를 생성한다. 따라서 계산이 필요할 때마다 매 번 그래프를 새로 생성한다.

 

Static Graph의 첫번째 장점은 그래프 최적화이다.

이는 일부 연산을 합치거나 재배열시켜 가장 효율적인 연산을 하도록 최적화하는것이다.

위의 예를 보면 conv와 relu가 반복적으로 진행되는걸 합쳐서 진행을 하는데,  이는 합쳐도 같은 연산을 하기때문에 코드는 더 효율적일것이다.

 

Static Graph의 첫번째 장점은 직렬화이다.

Static Graph는 메모리 내에 네트워크 구조를 저장하기 때문에 원본코드 없이도 그래프를 다시 불러올 수 있다.

Dynamic Graph는 그래프 구성과 실행의 과정이 얽혀있기 때문에 모델 재사용을 위해선 항상 원본코드가 필요하다는 단점이 있다.

 

Dynamic graph의 장점은 깔끔한 코드이다.

첫번째 예시로는 가정어구 (Conditional) 이다.

위와 같은 z > 0 일때 w1을 곱해주고 이외에는 w2를 곱해주는 식이 있다.

Dynamic 그래프로는 if문과 같은 제어문을 통해 일반적인 코드를 작성하듯이 간편하게 계산 그래프를 생성 할 수 있다.

하지만 Static 그래프로는 첫번째로 그래프가 생성시 모든 조건을 미리 고려해서 한번에 넣어줘야하고, tf자체에서 제공하는 특별한 연산자를 사용해야한다.

즉,  python 문법으론 불가능하고 반드시 특수한 tensorflow 연산자가 필요하다. 위에서는  tensorflow버전의 if문인 tf.cond를 사용했다. 이는 해당 연산자에 대해 새로 알아야 되며, 코드가 직관적이지 않다는 단점이 있다.

 

두번째 예시로는 반복연산 (Loops) 이다.

위와같이 반복연산을 하는 식이 존재한다. 이때 Dynamic 그래프로는 for문을 통해 간편하게 표현할 수 있다.

하지만 Static 그래프로는 함수형 프로그래밍처럼 미리 기능에 대한 선언을 함수로 해두어야한다,

위에서는 tf.foldl를 사용한것을 볼 수 있다.

 

마지막으로 Dynamic Graph가 사용되는곳이다.

순환신경망, 재귀신경망 그리고 module로 구성된 network를 쉽게 유동적으로 컨트롤 할 수 있다는 장점이 있다.

728x90
반응형