본 포스팅은 다음 과정을 정리 한 글입니다.
Custom and Distributed Training with TensorFlow
지난 시간 리뷰
안녕하세요.
지난 Custom Models, Layers and Loss Functions with TensorFlow 과정에서는 Functional API에 대한 배경 지식과 손실 함수 및 레이어와 같은 TensorFlow의 여러 가지를 Customize 하는 방법을 배웠습니다.
이번 과정에서는 학습 모델을 customize 하는 것과 TensorFlow의 일부 기본 기능을 override 하는 방법에 대해 자세히 살펴보고자 합니다. 살펴보기 전에 먼저 기본 구성 요소에 대해 조금 더 깊이 들어가 봅시다.
이번 주에는 네트워크 훈련에 사용되는 두 가지 핵심 구성 요소를 살펴보겠습니다.
먼저 Tensor에 대해 살펴보겠습니다. 그런 다음 TensorFlow가 학습을 최적화 할 때 그라디언트를 사용하는방법에 대해 알아보겠습니다.
여러분은 곧 TensorFlow가 TensorFlow로 명명된 이유를 알게 될 것입니다. Tensor (텐서)는 무엇일까요?
Tensor는 수학의 개념으로, 기본적으로 유연한 데이터 구조로, 아래 그림처럼 다양한 방식으로 데이터를 저장할 수 있습니다.
기억해야 할 중요한 용어는 텐서의 차원이며 텐서가 궁극적으로 나타내는 데이터 유형에 큰 영향을 미칠 수 있습니다.
단일 값 또는 스칼라 (scalar)는 차원이 없는 텐서로 볼 수 있습니다.
벡터는 여기에서 볼 수 있는 수평 1, 2, 3 또는 수직 1, 2, 3과 같이 값이 단일 차원(1차원)으로 표현되는 텐서입니다.
행렬은 벡터와 비슷하지만 각 차원은 1보다 큽니다. 아래 예시처럼 3x3행렬은 텐서이기도 합니다. 차원의 수와 각 차원의 값에 관계없이 텐서는 이들 각각을 설명할 수 있는 일반적인 데이터 구조입니다.
예를 들어, 텐서는 큐브로 시각화할 수 있는 3x3x3 텐서와 같은 3차원을 가질 수 있습니다. 이것은 일반적으로 사용되고 있습니다. 텐서는 단순히 데이터를 저장하는 매우 유연한 방법입니다.
TensorFlow에서 코딩할 때 수학적 텐서의 기본 개념을 구현하는 텐서 객체를 만들 수 있습니다. 가장 쉬운 방법은 tf.Variable 또는 tf.constant를 사용하는 것입니다.
앞으로 텐서라고 말할 때는 수학에 존재하는 텐서의 일반적인 의미가 아니라 TensorFlow의 텐서 객체를 말하는 것입니다.
이름에서 알 수 있듯이 tf.Variable을 사용할 때 텐서가 수정될 수 있습니다. 즉, "hello"값을 저장하면 "goodbye"값을 저장하도록 변경할 수 있습니다.
변수의 값을 수정할 수 있는 경우 변경 가능하다고 말합니다.
Mutable은 객체가 변경될 수 있다고 말하는 소프트웨어 엔지니어링 방식입니다.
그러나 tf.constant를 사용하면 변경이 불가능하므로 변경할 수 없습니다.
tf.constant가 1,2,3,4,5,6 값을 가지고 있다면, 하나를 0으로 바꾸거나 텐서 끝에 다른 숫자 7을 추가할 수 없습니다.
다른 값 세트를 저장하려는 경우 새 tf.constant를 만들어야 합니다.
TensorFlow에서 텐서 데이터 유형을 관리하는 객체는 종종 텐서의 대문자 T로 표시되며 두 가지 기본 속성이 있습니다.
텐서의 shape(모양)과 텐서에 저장된 type(데이터 유형)입니다.
텐서 객체를 만들 때 각 차원에 필요한 단위 수를 지정합니다. 예를 들어, 여기에서 이 텐서에는 1차원에 두 개의 유닛이 있습니다. 두 개의 값을 저장할 수 있으며 이 경우 4, 6이 있습니다. 여기에 shape를 추가로 작성해줘야 합니다.
입력의 차원을 알고 있는 경우 대부분의 연산은 알려진 모양의 텐서를 생성하지만 경우에 따라 그래프 실행 시간에만 모양을 찾을 수 있습니다.
텐서가 사용하는 또 다른 속성은 데이터 유형이며, 텐서를 나타내는 데 사용되는 데이터의 종류를 나타냅니다.
예를 들어, 정수, 부동 소수점 숫자, 문자열이 있습니다.
아래 예제에서 데이터 유형은 32 비트 정수인 int32입니다.
이제 TensorFlow Keras 모델에서 tf 변수가 어떻게 사용되는지 살펴보겠습니다.
Sequential API를 사용하여 작은 Dense layer를 가진 모델을 만듭니다.
모델을 만들 때 모델링 된 변수 속성을 호출하여 내부 변수가 어떻게 보이는지 확인할 수 있습니다.
여기에서 내부 변수 중 두 가지를 볼 수 있습니다. 또한 변수의 모양과 데이터 유형을 확인할 수도 있습니다.
첫 번째 tf 변수의 이름은 'density_1/kernel:0'이며 해당 레이어의 가중치 행렬을 유지하는 데 사용됩니다.
커널이라는 용어는 신경망 계층의 가중치를 나타내는 또 다른 단어입니다.
shape=(1, 1) 이므로 2차원입니다. 각 차원은 길이가 1입니다. 데이터 유형은 float32이고 임의로 초기화된 값을 갖습니다.
두 번째 tf 변수의 이름은 'density_1/bias:0'이며 이 레이어의 bias값을 저장합니다.
길이가 1 단위 인 하나의 차원이 있습니다. 데이터 유형도 float32이고 초기 값은 0입니다.
가중치와 bias는 모두 여기서 무작위로 초기화되지만 훈련 후 해당 값은 훈련 데이터에 맞게 변경됩니다.
tf.Variable을 사용하여 나만의 텐서를 만들 수 있으며 사용할 때 주의해야 할 사항이 있습니다. V는 대문자입니다.
아래 예제 텐서의 예제가 있습니다.
데이터 유형 또는 dtype은 초기 값에서 파생되며 이 경우 dtype은 int32로 자동 설정됩니다.
데이터 유형이 int32가 아닌 다른 유형을 가져야 하는 경우도 있을 수 있습니다.
예를 들어, 데이터 유형이 float32가 되도록 할 수 있습니다. 매개 변수 dtype을 tf.float32로 설정을 해주면 됩니다. 텐서는 이제 float32의 dtype임을 알 수 있습니다.
한 가지 중요한 점은 tf.float32를 두 번째 매개변수로 전달하기만 하면 안 되고 "dtype=tf.float32" 형태로 전달해야만 합니다.
세 번째 예를 보면 tf.float32만 넣었을 때 에러는 안 나지만 dtype=int32로 설정되어 있는 것을 확인할 수 있습니다.
그리고 여기에 tf.Variable을 사용할 때 염두에 두어야 할 다른 것이 있습니다.
텐서의 모양은 초기 값에 의해 설정됩니다.
아래 예제를 살펴보겠습니다. 길이 4의 벡터가 있습니다.
tf.Variable에서 shape에 대한 매개변수를 통해 벡터를 행렬로 변경할 수는 없습니다.
[1, 2, 3, 4]라는 1차원 벡터를 2차원 벡터로 변경하려고 tf.Variable([1, 2, 3, 4], shape=(2,2))를 해도 변경되지 않고 아래와 같이 에러가 나는 것을 볼 수 있습니다.
초기에 설정된 shape은 명시적으로 제공된 shape 값과 호환되지 않습니다. 텐서가 특정 shape을 갖기를 원한다면 초기 값을 줄 때 해당 값을 list의 형태로 만들어서 전달해야 합니다.
예를 들어 list [1, 2]와 list [3, 4]가 다시 큰 list안에 속해 있는 것을 볼 수 있습니다. 이 것을 넣으면 shape=(2, 2)인 텐서를 만들 수 있습니다.
shape를 tf.TensorShape(None)와 같게 설정하면 결과 텐서의 shape는 알 수 없습니다. 따라서 변수는 어떤 shape이든 배열로 업데이트할 수 있습니다.
string이 지원되기 때문에 원하는 경우 코끼리와 같은 간단한 문자열 값을 텐서에 저장할 수 있습니다.
허수, 복소수의 경우 학적 표기법에 사용되는 문자 i가 아닌 소문자 j를 사용하여 허수를 나타낼 수 있습니다.
tf.complex64 데이터 유형을 사용하여 복소수 텐서에 저장할 수 있습니다.
다음은 소수를 포함하는 1차원 배열 or 벡터의 예입니다. dtype=tf.int32입니다.
마지막으로 4,9,16,25를 텐서로 저장하는 2x2 행렬입니다.
첫 번째 함수 매개 변수는 두 개의 목록을 포함하는 목록으로 전달됩니다. 이는 이제 두 개의 행이 있음을 의미합니다. 각 내부 목록에는 두 개의 값이 있으며 이는 두 개의 열이 있음을 나타냅니다. 그리고 이것이 tf.Variable의 shape이 2x2 텐서라는 것을 아는 방법입니다.
마찬가지로 tf.constant를 사용하여 텐서를 생성할 수 있으며 상수는 소문자 c입니다.
첫 번째 텐서는 tf.constant로 설정하고 1,2,3 list를 전달하며 list의 내용으로 채워진 1차원 텐서를 얻습니다.
tf.Variable과 다른 tf.constant의 중요한 기능 중 하나는 tf.constant내에 shape 매개변수를 사용하여 1차원 입력 변수의 형태를 변경할 수 있다는 것입니다.
두 번째 tensor는 shape 매개 변수를 사용하여 1차원 텐서를 2x3 행렬로 재구성하여 텐서를 얻었습니다.
마지막 예에서는 단일 스칼라 값을 초기 값으로 사용하여 2x3 행렬로 구성된 텐서를 얻는 예제입니다. 텐서의 모든 위치에 복사할 값으로 모두 -1이 들어가게 된 것을 확인할 수 있습니다. shape에 설정된 대로 2x3 텐서가 모두 -1로 채워진 텐서가 생성되었습니다.
Tensor는 더하기, 빼기, 곱하기와 같은 많은 연산을 지원합니다. 다음으로 이러한 수학적 연산 중 몇 가지를 살펴보겠습니다.
먼저 두 개의 텐서가 같은 차원을 가지고 있다면 더할 수 있습니다.
아래 예제를 보면 [1, 2], [3, 4]를 더하면 1과 3, 2와 4를 각각 더해 [4, 6]이 되는 것을 볼 수 있습니다.
비슷하게, tf.square는 제곱을 얻기 위한 연산으로 25의 값을 가지는 텐서를 반환합니다.
reduce_sum은 텐서 내의 모든 값을 더한 결과를 반환합니다. [1, 2, 3]은 6이 됩니다. 결과는 차원이 없는 shape, 즉 scalar가 됩니다.
tf.reduce_sum 연산은 입력 형태를 1차원 벡터에서 0차원 스칼라로 줄입니다.
일반적인 수한 연산을 더 쉽게 작성하기 위해 TensorFlow 객체로 작업하는 경우 tf.add 함수 대신 더하기 기호를 사용할 수 있습니다.
tf.square(2)와 tf.square(3)는 모두 텐서 객체를 생성하므로 더하기 기호를 사용하여 이 두 개를 더하여 값 13을 가지는 텐서를 얻을 수 있습니다.
이 것은 tf.add(tf.square(2), tf.square(3))과 동일합니다. 소프트웨어 엔지니어링에서는 이를 연산자 오버 로딩이라고 합니다.
파이썬의 더하기 기호는 두 개의 정수 또는 부동 소수점을 추가하기 때문입니다.
TensorFlow 오버로드를 사용하면 더하기 기호를 사용하여 텐서 객체도 처리할 수 있습니다.
이제 텐서가 무엇인지, TensorFlow의 API를 사용하여 이를 조작하는 방법에 대한 몇 가지 기본 사항을 살펴보았습니다.
다음 시간에는 기본적이지만 강력한 python함수와 텐서와 함께 사용할 수 있는 방법을 살펴보겠습니다.
댓글