※ 본 내용은 stanford에서 제공하는 cs231n 강의, 강의자료를 바탕으로 작성하였습니다.
Lecture 8에서는 CPU/GPU 및 deep learning 관련 software, framework를 다루고 있다.
Tensorflow와 Pytorch에 대해 주로 다루고 있다.
※해당 내용은 변화가 빠른 내용이다보니 2017년의 강의 내용이 글을 쓰는 현재 시점과는 차이가 있을 수 있다.
<CPU/GPU>
CPU와 GPU의 대표적인 차이는 cores의 수이다.
CPU는 일반적으로 최대 10개 정도의 core를 갖는다면, GPU의 cores 수는 1000단위로 그 차이는 매우 크다.
따라서 간단한 연산을 병렬로 처리하기에 GPU가 유리하다.
대표적으로 matrix multiplication이나 convolution 연산 등을 떠올릴 수 있고, 모두 deep learning에서 흔하게 쓰이는 연산이다.
다만 개별 core의 성능은 CPU가 훨씬 빠르다.
또한 GPU는 GPU 만의 메모리를 갖고, CPU와 GPU 간의 데이터 이동은 병목현상을 유발할 수 있다는 점도 기억해두어야 한다.
<Deep Learning Frameworks>
기본적으로 deep learning framework는 다음과 같은 편리함을 제공한다.
- 계산 그래프를 구현
- Gradients의 계산을 자동으로 제공
- GPU 상에서 동작하기에 최적화되어 있음
● TensorFlow
2-layer NN을 구현하는 코드를 통해 tensorflow 코드의 기본적인 동작에 대해 살펴보겠다.
기본적으로 tensorflow는 computational graph의 구조를 작성(①, ②)하는 코드와 실제 계산을 동작시키는 코드(③)가 구분된다.
(※ tf 최근 버전의 경우, Session을 이용하지 않는 것으로 알고 있다.)
① Computational graph의 구조 작성
파란색 사각형으로 표시된 ① 영역은 computational graph를 구현한다.
변수를 tf.~의 자료형으로 선언하는 것을 제외하고는 어떠한 연산을 수행하는지 어렵지 않게 알 수 있을 것이다.
변수를 numpy 등이 아니라 tf.~로 선언함으로써 GPU 상에서 다룰 수 있게 된다.
x, y의 경우 placeholder, w1, w2의 경우 Variable로 선언되어 있는데,
이는 w1과 w2는 update가 빈번하게 이뤄지는 변수이기 때문이다.
한 번 graph에 제공되면 그 값이 유지되는 x, y와 다르게 w1, w2는 매번 update되고, 이를 매번 CPU에서 제공하는 것은 큰 overhead를 유발한다(둘의 메모리가 다르기 떄문에, 이동으로 인한 overhead).
따라서 해당 변수를 Variable로 선언하여, GPU 상에서 업데이트가 이뤄지도록 한다.
② Optimizer
Optimizer를 통해서 NN의 train을 매우 간단하게 구현할 수 있다.
Optimizer의 종류를 선언해주고, optimizer가 어떠한 노드를 최적화할 것인지 전달해주면 자동으로 optimization을 수행한다. 정확히는 weight의 update를 자동으로 수행한다.
어떠한 parameter를 training할 것인지도 알아서 판단하므로(엄밀히는 trainalbe하게 선언된 변수를 찾아서 train),
특정 node의 값을 optimize하라는 코드만 작성해도 필요한 parameter를 최적화한다.
③ Training
실제로 계산을 수행할 때는 Session을 생성하고, session을 run 시켜서 계산이 이뤄진다.
즉, 앞선 코드는 구조만을 작성하는 코드이다.
생성한 sess를 실행시키고, 실제 그래프 구조에 적용될 값들을 전달한다.
이 시점에서 w1, w2에 할당될 random 값이 결정된다(global_variable_initializer)).
이 후의 for문이 training을 반복하는 코드이다.
sess.run([loss, updates], feed_dict = values)
loss 노드와 updates 노드를 수행시키면 loss가 계산되기 까지의 computation graph의 노드가 모두 동작하고, updates 노드를 수행시키면 optimization(gradient descent)가 수행된다.
- High-Level wrapper
자주 쓰이는 layer 들은 보다 high-level로 제공되기도 한다.
앞선 코드와 동일한 역할을 수행하는 코드이며, tf.layers.dense layer를 이용하여 구현할 수도 있다.
Keras
Keras는 훨씬 더 직관적인 high-level wrapper를 구현한다.
매우 직관적이기 때문에 코드만으로 이해하는 것에 어려움은 없다.
그 외에도 다양한 high-level wrappers가 존재한다.
●PyTorch
Abstraction
기본적으로 Pytorch에는 three levels of abstraction이 있다.
- Tensor : ndarray를 다루는 자료형이고, GPU 상에서 다뤄진다.
- Varaiable : 계산 그래프의 각 노드이다. Data 뿐만 아니라 gradient도 같이 node에 저장한다.
- Module : State나 learnable weights를 저장하는 layer이다.
PyTorch의 코드는 조금 더 numpy 형식과 비슷하고, 이해하기 쉽다.
변수를 선언하고(①), 선언한 변수를 통해 필요한 값을 계산한다(②).
'backward()'를 호출하면 해당 노드를 계산하는 데 사용된 노드들의 gradient가 계산되어 각 노드(Variable)에 저장된다.
그 값을 이용해서 업데이트를 수행하면 된다(③).
Own Autograd
직접 class를 구현하고, backward 연산을 구현해주면 해당 class도 backward()의 역전파 과정에서 자동으로 gradient가 계산된다.
loss.backward()를 호출하면 ReLU() layer의 backward()도 호출이 된다.
PyTorch는 nn을 통해서 higher-level wrapper를 제공한다.
마찬가지로 직관적이기 때문에 코드만으로 쉽게 이해가 가능하다.
PyTroch에서는 nn.Module을 상속해서 새로운 modules를 define할 수 있다.
forward()만 작성해주면 backward()는 autograd를 통해 계산된다.
실제로 PyTorch 코드를 작성할 때는 위와 같이 하나의 module class로 구현하는 경우가 많다고 한다.
PyTorch도 마찬가지로 optimization을 간단하게 해주는 기능을 제공한다.
사용할 Optimizer에 업데이트할 parametres와 learning rate를 제공한 후, step()을 호출하면 각 노드에 저장된 grad값을 이용하여 자동으로 업데이트를 수행한다.
DataLoader는 dataset을 wrap하여 minibatch를 제공하고, shuffle해주는 등의 과정을 간편하면서 효율적으로 동작하도록 해준다.
코드를 통해 활용법을 쉽게 이해할 수 있다.
실제 PyTorch로 코드를 짜는 경우 최종적으로 위와 같은 형태를 자주 보게 될 것이라고 한다.
(하나의 module class로 model을 구현하고, DataLoader로 minibatch를 추출하며 Optimizer를 사용하여 학습을 수행하는 형태)
● Static(TensorFlow) vs Dynamic Graphs(PyTorch)
TensorFlow는 정적으로 계산 그래프를 생성한다. 즉, 계산 그래프를 한 번만 생성하여 계속 이용한다.
PyTorch는 동적으로 계산 그래프를 생성한다. 계산이 필요할 때마다 매 번 그래프를 새로 생성한다.
Static의 장점
- 계산 그래프 최적화
먼저 static 방식의 장점은 그래프의 최적화가 가능하다는 것이다.
같은 연산을 수행하더라도 계산이 조금 더 빠르도록 구조를 바꾸는 등으로 최적화를 수행할 수 있다.
한 번 생성 후 계속 사용할 것이므로, optimization 과정이 조금 걸리더라도 그럴 가치가 있다.
- 직렬화(Serialization)
한 번 생성된 그래프가 계속 사용되므로, 코드가 없더라도 그래프를 직렬화하여 사용할 수 있다.
반면 dynamic 방식은 매 생성마다 코드가 필요하다.
-> 뒤에도 다룰 내용이지만, dynamic 방식은 if문과 같은 일반적인 프로그래밍 구조로 그래프를 생성할 수 있기 때문에 코드가 항상 필요하다.
Dynamic의 장점
- Conditional
바로 위에서 다룬 내용이다.
매번 그래프를 새로 생성하기 때문에 if문과 같은 제어문을 일반적인 코드를 작성하듯이 사용하여 계산 그래프를 생성할 수 있다.
반면 tensroflow는 일반적인 코드와는 다르게 if문을 사용하는게 아니라 TF 자체에서 제공하는 특별한 operator를 사용해야 한다. -> 해당 operator에 대해 새로 알아야 되며, 코드가 직관적이지 않다.
'Computer Vision > cs231n' 카테고리의 다른 글
[Lec 10] Recurrent Neural Networks, RNN (0) | 2022.01.19 |
---|---|
[Lec 9 ]CNN Architectures (0) | 2022.01.17 |
[Lec 7] Training Neural Networks, Part2 (0) | 2022.01.15 |
[Lec6] Training Neural Networks, Part 1 (0) | 2022.01.10 |
[Lec5] Convolutional Neural Network (0) | 2022.01.09 |