이번 포스팅에서는 TensorFlow Keras의 손실함수 중에서 다중분류 문제(multiclass classification problem) 에 대한 딥러닝 모델을 훈련할 때 사용하는 손실함수에 대해서 소개하겠습니다. 

 

(1) 손실함수란 무엇인가? 

(2) 문제 유형별 Keras의 손실함수는 무엇이 있나? 

(3) 교차 엔트로피(Cross Entropy) 란 무엇인가?

(4) sparse_categorical_crossentropy() vs. categorical_crossentropy() 비교

 

 

 

(1) 손실함수란 무엇인가? 

 

 기계학습(Machine Learning), 딥러닝(Deep Learning) 은 손실함수(Loss Function)을 통해서 학습합니다. 손실함수는 다른 이름으로 비용함수(Cost Function)라고도 합니다. 

 

 손실함수는 특정 알고리즘이 주어진 데이터를 얼마나 잘 모델링하는지를 측정하는 방법입니다. 만약 학습모델을 사용해 예측한 값(predicted value)이 참 값(true value, actual value)과 차이가 많이 날 경우 손실함수의 값은 매우 커지게 되며, 손실함수 값이 작을 수록 알고리즘이 주어진 데이터를 잘 모델링했다고 평가할 수 있습니다. 

 

 기계학습, 딥러닝에서는 손실함수의 손실값(loss value)을 점점 작게 해서 최소의 손실 값을 찾아가는 최적화 함수(optimization function)을 사용해서 데이터로 부터 모델을 학습하게 됩니다. 최적화 함수에 대해서는 별도의 포스팅을 통해서 나중에 소개하도록 하겠습니다. 

 

 

 

(2) 문제 유형별 Keras의 손실함수는 무엇이 있나? 

 

 모든 문제에 공통으로 적용할 수 있는 만능의 손실함수는 없습니다. 각 문제 유형(예: 회귀, 분류)과 데이터 형태(y label 이 정수, onehot encoded), 미분 계산의 용이성, 이상치(outliers)의 포함 정도 등에 따라서 사용하는 손실함수는 달라집니다. 

 아래의 표는 TensorFlow Keras의 문제 유형(problem types) 별로 마지막층의 활성화 함수(last layer's activation function)와 손실함수/클래스를 표로 정리한 것입니다.

 

이번 포스팅에서 다루고자 하는 TensorFlow Keras의  sparse_categorical_crossentropy()와 categorical_crossentropy() 손실함수는 다중분류 문제(multiclass classification problem)에 사용하는 손실함수입니다. 

 

 

[ TensorFlow Keras의 손실 함수, 손실 클래스 (Loss Functions, Loss Classes) ]

TensorFlow Keras Loss Functions, Loss Classes

 

 

 

(3) 교차 엔트로피(Cross Entropy) 란 무엇인가?

 

교차 엔트로피 개념은 정보이론(information theroy)에서 나왔습니다. 교차 엔트로피(Cross Entropy)는 동일한 근간의 사건의 집합(over the same underlying events set)에서 뽑은 두 개의 확률 분포 p와 q에서 만약 집합에 사용된 코딩 체계가 실제 확률분포 p보다 추정 확률 분포 q에 최적화되어 있는 경우 집합으로 부터 뽑힌 사건을 식별하는데 필요한 평균 비트 수를 측정합니다.

 

위의 정의는 위키피디아(https://en.wikipedia.org/wiki/Cross_entropy) 에서 인용한 것인데요, 무슨 말인지 잘 이해하기 힘들지요? 아래의 유튜브 링크는 "Hands-on Machine Learning with Scikitlearn, Keras & TensorFlow" 책의 저자인 Aurelien Geron 님께서 "Entropy, Cross Entropy, KL Divergence"에 대해서 소개해주고 있는 영상인데요, 이걸 참고하시면 이해하는데 훨씬 쉬울거예요. 

 

 

이 정의는 다시 확률분포 q로 부터의 p의 차이인 Kullback-Leibler Divergence  Dkl(p||q) 로 공식화(be formulated)될 수 있습니다. 이산형 확률분포와 연속형 확률분포일 경우별로 교차엔트로피를 구하는 수식은 아래의 내용을 참고하세요. 

 

 

교차 엔트로피는 기계학습과 최적화에서 손실 함수를 정의하는 데 사용될 수 있습니다. 참 확률 p(i)는 정답 레이블이고, 주어진 분포 q(i)는 현재 모델의 예측 값입니다. 언어 모델을 예로 들면, 훈련 데이터셋을 기반으로 언어모델을 생성한 다음, 교차 엔트로피를 테스트 세트에서 측정하여 모델이 테스트 데이터를 예측하는 데 얼마나 정확한지 평가합니다. 이 언어모델 예에서 p는 모든 말뭉치에서 단어의 실제 분포이고, q는 모델에 의해 예측된 단어의 분포입니다. 

 

y(i) 를 실제의 참 값(actual true value), y_hat(i)를 모델이 예측한 값(predicted value)라고 했을 때, 분류 문제의 교차 엔트로피는 아래와 같은 수식으로 표현할 수 있습니다. (이진분류의 경우 y(i)가 0 또는 1 의 값을 가짐). 아래 수식을 보면 알 수 있듯이, 이진분류문제의 교차 엔트로피 손실함수는 실제 값이 0이면 아래 수식의 왼쪽 부분이 없어지고, 실제 값이 1이면 아래 수식의 오른쪽이 없어집니다. 따라서 만약 이진분류 모델이 실제 값을 틀리게 예측하고 또 예측확률값이 높을 수록 교차 엔트로피 손실함수 값이 더 커지게끔 설계되어 있습니다. (틀렸으면 벌을 주는데, 더 확신을 가지고 틀렸으면 더 큰 벌을 주는 개념). 

Cross Entropy Loss for Classification Problem

 

 

 

(4) sparse_categorical_crossentropy() vs. categorical_crossentropy() 비교

 

(4-1) 다중분류 문제(multiclass classification problem) 에 사용하는 함수 중에서 y label 의 형태에 따라서, 

 - tf.keras.losses.sparse_categorical_crossentropy(): y label 이 정수 (integer) 

 - tf.keras.losses.categorical_crossentropy(): y label 이 one-hot encoded 

를 선택해서 사용하면 됩니다.

아래의 화면캡쳐한 코드 예시를 보면 y label의 형태가 어떻게 다른지 금방 알 수 있을 거예요. 

 

(4-2) 또 하나 차이점이 있다면, 문제의 유형(problem types)에 따라서, 

 - tf.keras.losses.sparse_categorical_crossentropy(): multiclass single-label classification 만 가능

 - tf.keras.losses.categorical_crossentropy(): multiclass single-label classification, multiclass multilabel classification 둘다 사용 가능

하다는 차이점이 있습니다.  

multiclass single-label classification 문제는 다중 클래스 중에서 관측치는 단 한개의 클래스에만 속하는 문제(예: MNIST의 이미지 숫자 분류)를 말하며, multiclass multilabel classification 문제는 관측치가 여러개의 클래스에 속할 수 있는 문제(예: 음악 장류 분류, 영화 장르 분류 등)를 말합니다. 

 

Keras: sparse_categorical_crossentropy vs. categorical crossentropy

 

 

 

[ Reference ]

* TensorFlow 손실함수 (Loss Functions/ Classes)
   : https://www.tensorflow.org/api_docs/python/tf/keras/losses

* Keras 손실함수 (Loss Functions/ Classes): https://keras.io/api/losses/

* Cross Entropy: https://en.wikipedia.org/wiki/Cross_entropy

* Keras sparse_categorical_crossentropy()
   : https://www.tensorflow.org/api_docs/python/tf/keras/metrics/sparse_categorical_crossentropy

* Keras categorical_crossentropy()
   : https://www.tensorflow.org/api_docs/python/tf/keras/metrics/categorical_crossentropy

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

지난번 포스팅에서는 TensorFlow 의 tf.constant() 로 텐서를 만드는 방법(https://rfriend.tistory.com/718)을 소개하였습니다. 이번 포스팅에서는 TensorFlow 의 변수 (Variable) 에 대해서 소개하겠습니다. 

 

(1) TensorFlow 변수(tf.Variable)는 무엇이고, 상수(tf.constant)는 무엇이 다른가? 

(2) TensorFlow 변수를 만들고(tf.Variable), 값을 변경하는 방법 (assign)

(3) TensorFlow 변수 연산 (operations)

(4) TensorFlow 변수 속성 정보 (attributes)

(5) 변수를 상수로 변환하기 (converting tf.Variable to tf.constant)

 

 

(1) TensorFlow 변수(tf.Variable)는 무엇이고, 상수(tf.constant)와는 무엇이 다른가? 

 

 텐서플로의 튜토리얼의 소개를 보면 "변수는 프로그램 연산에서 공유되고 유지되는 상태를 표현하는데 사용을 권장("A TensorFlow variable is the recommended way to represent shared, persistent state your program manipulates.") 한다고 합니다. 말이 좀 어려운데요, 변수와 상수를 비교해보면 금방 이해가 갈 것입니다. 

 

 텐서플로 변수(Variable)는 값의 변경이 가능(mutable value)한 반면에, 상수(constant)는 값의 변경이 불가능(immutable value)합니다. 변수는 값의 변경이 가능하고 공유되고 유지되는 특성 때문에 딥러닝 모델을 훈련할 때 자동 미분 값의 back-propagations 에서 가중치를 업데이트한 값을 저장하는데 사용이 됩니다. 변수는 초기화(initialization)가 필요합니다. 

 

TensorFlow Variable, 변수

 

 

 

(2) TensorFlow 변수를 만들고(tf.Variable), 값을 변경하는 방법 (assign)

 

TensorFlow 변수는 tf.Variable(value, name, dtype, shape) 의 메소드를 사용해서 만들 수 있습니다. 

 

import tensorflow as tf
print(tf.__version__)
#2.7.0


## After construction, the type and shape of the variable are fixed.
v = tf.Variable([1, 2])
print(v)
#<tf.Variable 'Variable:0' shape=(2,) dtype=int32, numpy=array([1, 2], dtype=int32)>

 

 

변수의 값을 변경할 때는 assign() 메소드를 사용합니다.  assign_add(), assign_sub() 를 사용해서 덧셈이나 뺄셈 연산을 수행한 후의 결과로 변수의 값을 업데이트 할 수도 있습니다. 

 

## The value can be changed using one of the assign methods.
v.assign([3, 4])

print(v)
#<tf.Variable 'Variable:0' shape=(2,) dtype=int32, numpy=array([3, 4], dtype=int32)>


## The value can be changed using one of the assign methods.
v.assign_add([10, 20])

print(v)
#<tf.Variable 'Variable:0' shape=(2,) dtype=int32, numpy=array([13, 24], dtype=int32)>

 

 

 

tf.Variable(value, shape=tf.TensorShape(None)) 처럼 shape 매개변수를 사용하면 형태(shape)를 정의하지 않은 상태에서 변수를 정의할 수도 있습니다. 

 

## The shape argument to Variable's constructor allows you to 
## construct a variable with a less defined shape than its initial-value
v = tf.Variable(1., shape=tf.TensorShape(None))

print(v)
#<tf.Variable 'Variable:0' shape=<unknown> dtype=float32, numpy=1.0>


v.assign([[1.]])
#<tf.Variable 'UnreadVariable' shape=<unknown> dtype=float32, 
#numpy=array([[1.]], dtype=float32)>

 

 

 

(3) TensorFlow 변수 연산 (operations)

 

변수는 텐서 연산의 인풋(inputs to operations)으로 사용될 수 있습니다. 아래 예에서는 변수와 상수간 원소 간 곱과 합을 구해보았습니다. 

 

## Variable created with Variable() can be used as inputs to operations. 
## Additionally, all the operators overloaded for the Tensor class are carried over to variables. 
w = tf.Variable([1., 2.])
x = tf.constant([3., 4.])

## element-wise product
tf.math.multiply(w, x)
# <tf.Tensor: shape=(2,), dtype=float32, numpy=array([3., 8.], dtype=float32)>



## element-wise addition
w + x
# <tf.Tensor: shape=(2,), dtype=float32, numpy=array([4., 6.], dtype=float32)>

 

 

 

(4) TensorFlow 변수 속성 정보 (attributes)

 

텐서플로의 변수에서 이름(name), 형태(shape), 데이터 유형(dtype), 연산에 이용되는 디바이스(device) 속성정보를 조회할 수 있습니다. 

 

## Attributes
v = tf.Variable([1., 2.], name='MyTensor')
print('name:', v.name)
print('shape:', v.shape)
print('dtype:', v.dtype)
print('device:', v.device)

# name: MyTensor:0
# shape: (2,)
# dtype: <dtype: 'float32'>
# device: /job:localhost/replica:0/task:0/device:CPU:0

 

 

 

(5) 변수를 상수로 변환하기 (converting tf.Variable to tf.constant)

 

변수를 상수로 변환하려면 tf.convert_to_tensor(Variable) 메소드를 사용합니다. 

 

## converting tf.Variable to Tensor
c = tf.convert_to_tensor(v)

print(c)
# tf.Tensor([1. 2.], shape=(2,), dtype=float32)

 

 

 

[ Reference ]

* TensorFlow Variable: https://www.tensorflow.org/api_docs/python/tf/Variable

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

데이터 전처리를 하다보면 필요에 맞게 데이터 형태, 구조를 변경하는 일이 빈번하게 생깁니다. 이번 포스팅에서는 텐서의 형태를 변환, 재구조화, 전치하는 방법을 소개하겠습니다. 

이미 numpy (https://rfriend.tistory.com/345 , https://rfriend.tistory.com/289)에 익숙한 분이라면, 사용법이 비슷하기 때문에 그리 어렵지 않게 금방 이해할 수 있을 거예요. 

 

(1) tf.reshape(): 텐서의 형태 변환 

(2) tf.transpose(): 텐서의 행과 열 전치

 

 

TensorFlow reshape, transpose

 

 

(1) tf.reshape(): 텐서의 형태 변환

 

먼저, 0~11까지 12개의 원소를 가지는 벡터(vector) 로 텐서를 만들어보겠습니다. 

 

t1 = tf.constant(range(12))

print(t1)
# tf.Tensor([ 0  1  2  3  4  5  6  7  8  9 10 11], 
#.          shape=(12,), dtype=int32)


tf.rank(t1) # rank 1
# <tf.Tensor: shape=(), dtype=int32, numpy=1>

 

 

 

위의 벡터 (12,) 형태를 가지는 텐서 t1을, 행렬 (3, 4) 형태를 가지는 텐서로 tf.reshape(tensor, shape, name=None) 메소드를 사용해서 변환(reshape)해보겠습니다. 

 

## reshaping a shape of Tensor from (12,) to (3, 4)
t2 = tf.reshape(t1, [3, 4]) 

print(t2)
# tf.Tensor(
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]], shape=(3, 4), dtype=int32)


tf.rank(t2) # rank 2
# <tf.Tensor: shape=(), dtype=int32, numpy=2>

 

 

 

tf.reshape(tensor, shape) 의 shape 란에 원하는 형태를 [ ] 안에 콤마로 구분해서 넣어주면 됩니다. 이번에는 rank 3 을 가지는 (2, 2, 3) 형태의 텐서로 형태를 변환해보겠습니다. 

 

## reshaping a Tensor with a shape of (12,) to (2,2,3)
t3 = tf.reshape(t1, [2, 2, 3])

print(t3)
# tf.Tensor(
# [[[ 0  1  2]
#   [ 3  4  5]]
#  [[ 6  7  8]
#   [ 9 10 11]]], shape=(2, 2, 3), dtype=int32)


tf.rank(t3) # rank 3
# <tf.Tensor: shape=(), dtype=int32, numpy=3>

 

 

tf.reshape(tensor, shape) 의 shape 에 '-1' 이 들어있으면, 숫자가 기입된 부분의 축을 변환하고 난 후에, "남은 축의 형태는 원래 텐서의 총 크기와 같도록 알아서 추정"해준다는 뜻입니다. 

 

아래 예에서는 원래 텐서 t1 이 (12,) 형태였으며, tf.reshape(t1, [-1, 3]) 으로 재구조화시켰더니 (4, 3) 형태의 텐서로 변환되었네요. 

 

## If one component of shape is the special value -1, 
## the size of that dimension is computed 
## so that the total size remains constant.
t4 = tf.reshape(t1, [-1, 3])


print(t4)
# tf.Tensor(
# [[ 0  1  2]
#  [ 3  4  5]
#  [ 6  7  8]
#  [ 9 10 11]], shape=(4, 3), dtype=int32)


tf.rank(t4) # rank 2
# <tf.Tensor: shape=(), dtype=int32, numpy=2>

 

 

특히, tf.reshape(tensor, [-1]) 처럼 shape 에 [-1] 은 1차원의 벡터인 1-D 텐서로 변환을 한다는 뜻입니다. 

아래 예에서 텐서 t4 는 (4, 3) 형태를 가지는 행렬이었는데요, tf.reshape(t4, [-1]) 해주었더니 (12,) 의 형태를 가지는 1차원의 벡터로 변환이 되었습니다. 

 

## In particular, a shape of [-1] flattens into 1-D. 
## At most one component of shape can be -1.
t5 = tf.reshape(t4, [-1])

print(t5)
# tf.Tensor([ 0  1  2  3  4  5  6  7  8  9 10 11], 
#           shape=(12,), dtype=int32)


tf.rank(t5) # rank 1
# <tf.Tensor: shape=(), dtype=int32, numpy=1>

 

 

 

tf.reshape(tensor, []) 의 [ ] 는 텐서를 1개의 원소를 가지는 스칼라(scalar) 로 변환합니다. 

 

## tf.reshape(t, []) reshapes a tensor t with one element to a scalar.
t6 = tf.constant([5])

print(t6) # rank 1, vector
# tf.Tensor([5], shape=(1,), dtype=int32)


t7 = tf.reshape(t6, [])
print(t7) # rank 0, scalar
# tf.Tensor(5, shape=(), dtype=int32)


tf.rank(t7) # rank 0
# <tf.Tensor: shape=(), dtype=int32, numpy=0>

 

 

 

(2) tf.transpose(): 텐서의 행과 열 전치

 

tf.transpose(tensor)는 텐서의 행과 열의 위치를 전치(transpose) 시켜 줍니다. 

아래의 예에서는 shape=(3,4) 의 텐서를 shape=(4,3)의 텐서로 행과 열을 전치시켜주었습니다. 행과 열이 전치를 시키기 전과 후에 어떻게 바뀌었는지 살펴보면 금방 이해하실 수 있을 거예요. 

 

print(t2)
# tf.Tensor(
# [[ 0  1  2  3]
#  [ 4  5  6  7]
#  [ 8  9 10 11]], shape=(3, 4), dtype=int32)


t8 = tf.transpose(t2)

print(t8)
# tf.Tensor(
# [[ 0  4  8]
#  [ 1  5  9]
#  [ 2  6 10]
#  [ 3  7 11]], shape=(4, 3), dtype=int32)

 

[ Reference ]

- tf.reshape(): https://www.tensorflow.org/api_docs/python/tf/reshape

- tf.transpose(): https://www.tensorflow.org/api_docs/python/tf/transpose

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

딥러닝 모델을 훈련하고 예측하는데 사용하는 TensorFlow 프레임웍의 이름은 Tensor + Flow (텐서를 흘려보냄) 에서 유래했습니다. 텐서(Tensor)는 텐서플로의 가장 기본이 되는 자료 구조인 만큼 만드는 방법과 속성정보 조회하는 방법을 알아둘 필요가 있겠습니다. 

 

이번 포스팅에서는 

 

(1) 텐서의 정의

(2) 텐서 만들기

     - (2-1) tf.constant([mat1, mat2, mat3])

     - (2-2) tf.stack([mat1, mat2, mat3])

     - (2-3) tf.convert_to_tensor([mat1, mat2, mat3])

(3) 텐서의 속성정보 조회하기

     - (3-1) Tensor.dtype : 텐서 데이터 유형

     - (3-2) Tensor.shape : 텐서 형태

     - (3-3) Tensor.rank : 텐서 차수(rank), 텐서를 구성하는 벡터의 개수, 랭크

     - (3-4) Tensor.device : 텐서 생성 디바이스 (CPU, GPU)

 

하는 방법에 대해서 소개하겠습니다. 

 

 

 

(1) 텐서의 정의

 

 TensorFlow의 자료 구조에는 0차원의 스칼라(scalar), 1차원의 벡터(vector), 2차원의 행렬(matrix), 3차원 이상의 텐서(tensor) 가 있습니다. 텐서플로에서 텐서는 벡터와 행렬, 그리고 3차원 이상의 고차원의 배열을 모두 아우르는 일반화된 데이터 구조를 말합니다.

 텐서플로는 파이썬 객체를 텐서(Tensor)로 변환해서 행렬 연산을 수행합니다. 텐서플로는 먼저 tf.Tensor 객체의 그래프(graph) 를 생성하는 것에서 시작하여, 각 텐서가 어떻게 계산되는지를 구체화하고, 이 그래프의 부분들을 실행하여 원하는 최종 결과를 도출합니다. 

 텐서는 데이터 유형(a data type, 예: float32, int32, string) 과 데이터 형태 (shape) 의 속성을 가집니다. 

 

TensorFlow data types: scalar, vector, matrix, tensor

 

 

(2) 텐서 만들기

 

그럼, (2, 3) 의 shape 을 가지는 3개의 배열을 가지고, 3차원인 (3, 2, 3) 형태의 텐서를 만들어보겠습니다. 

 

     - (2-1) tf.constant([mat1, mat2, mat3])

     - (2-2) tf.stack([mat1, mat2, mat3])

     - (2-3) tf.convert_to_tensor([mat1, mat2, mat3])

 

import tensorflow as tf
tf.__version__
#2.7.0


## input matrix (list of list)
mat1 = [[1, 2, 3], [4, 5,  6]]
mat2 = [[7, 8, 9], [10, 11, 12]]
mat3 = [[13, 14, 15], [16, 17, 18]]

 

 

(2-1) tf.constant([mat1, mat2, mat3])

 

## A tf.Tensor represents a multidimensional array of elements.

## (1) tf.constant(): Creates a constant tensor from a tensor-like object.
tensor1 = tf.constant([mat1, mat2, mat3])

tensor1
# <tf.Tensor: shape=(3, 2, 3), dtype=int32, numpy=
# array([[[ 1,  2,  3],
#         [ 4,  5,  6]],

#        [[ 7,  8,  9],
#         [10, 11, 12]],

#        [[13, 14, 15],
#         [16, 17, 18]]], dtype=int32)>

 

 

 

(2-2) tf.stack([mat1, mat2, mat3])

 

## tf.stack(): Stacks a list of rank-R tensors into one rank-(R+1) tensor.
tensor2 = tf.stack([mat1, mat2, mat3])

 

 

 

(2-3) tf.convert_to_tensor([mat1, mat2, mat3])

 

텐서를 만들 때 데이터 유형(dtype), 텐서 이름(name)의 속성정보를 설정할 수 있습니다. 

 

## tf.convert_to_tensor(): Converts the given value to a Tensor.
tensor3 = tf.convert_to_tensor([mat1, mat2, mat3])

# tensor3 = tf.convert_to_tensor([mat1, mat2, mat3], 
#                                dtype=tf.int64, 
#                                name='my_first_tensor')

 

 

 

(3) 텐서의 속성정보 조회하기

 

     - (3-1) Tensor.dtype : 텐서 데이터 유형

     - (3-2) Tensor.shape : 텐서 형태

     - (3-3) Tensor.rank : 텐서 차수(rank), 텐서를 구성하는 벡터의 개수, 랭크

     - (3-4) Tensor.device : 텐서 생성 디바이스 (CPU, GPU)

 

# A tf.Tensor has the following properties:
# - a single data type (float32, int32, or string, for example)
# - a shape

## The DType of elements in this tensor.
tensor3.dtype
# tf.int64


## Returns a tf.TensorShape that represents the shape of this tensor.
tensor3.shape
# TensorShape([3, 2, 3])


## rank of this tensor.
tf.rank(tensor3)
# <tf.Tensor: shape=(), dtype=int32, numpy=3>


## The name of the device on which this tensor will be produced, or None.
tensor3.device
# /job:localhost/replica:0/task:0/device:GPU:0

 

 

[ Referece ]

- tf.Tensor(): https://www.tensorflow.org/api_docs/python/tf/Tensor

- tf.constant(): https://www.tensorflow.org/api_docs/python/tf/constant

- tf.stack(): https://www.tensorflow.org/api_docs/python/tf/stack

- tf.convert_to_tensor(): https://www.tensorflow.org/api_docs/python/tf/convert_to_tensor

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 Python Tensorflow와 numpy 모듈을 사용하여 

  (1) 행렬 원소 간 곱 (matrix element-wise product)

  (2) 행렬 곱 (matrix multiplication) 

하는 방법과 연산 방법을 소개하겠습니다. 

얼핏보면 둘이 비슷해보이지만, 전혀 다른 연산으로서 주의가 필요합니다. 

 

 

tensorflow, numpy, element-wise product, matrix multiplication

 

 

 

먼저, TensorFlow와 numpy  모듈을 불러오고, 예제로 사용할 2차원 행렬(matrix)을 만들어보겠습니다. 

 

import numpy as np
import tensorflow as tf
print(tf.__version__)
#2.7.0


## matrix
x = tf.constant([[1, 2], [3, 4]])

print(x)
# tf.Tensor(
# [[1 2]
#  [3 4]], shape=(2, 2), dtype=int32)


y = tf.constant([[0, 10], [20, 30]])

print(y)
# tf.Tensor(
# [[ 0 10]
#  [20 30]], shape=(2, 2), dtype=int32)

 

 

 

(1) 행렬 원소 간 곱 (matrix element-wise product)

 

## [TensorFlow] matrix element-wise product
tf.math.multiply(x, y)

# <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
# array([[  0,  20],
#        [ 60, 120]], dtype=int32)>

 

## [numpy] matrix element-wise produce
np.array(x) * np.array(y)

# array([[  0,  20],
#        [ 60, 120]], dtype=int32)

 

 

 

(2) 행렬 곱 (matrix multiplication) 

 

## matrix multiplication using tf.matmul()
tf.matmul(x, y)

# <tf.Tensor: shape=(2, 2), dtype=int32, numpy=
# array([[ 40,  70],
#        [ 80, 150]], dtype=int32)>

 

## [numpy] matrix multiplication using np.dot()
np.dot(x, y)

# array([[ 40,  70],
#        [ 80, 150]], dtype=int32)



## [numpy] matrix multiplication using np.matmul()
np.matmul(x, y)

# array([[ 40,  70],
#        [ 80, 150]], dtype=int32)

 

 

 

참고로, TensorFlow 의 텐서를 numpy의 array 로 변환하려면 numpy() 메소드를 사용하면 됩니다. 

 

## casting tensor to numpy's array
tf.matmul(x, y).numpy()

# array([[ 40,  70],
#        [ 80, 150]], dtype=int32)

 

 

이번 포스팅이 많은 도움이 되었기를 바랍니다. 

행복한 데이터 과학자 되세요!  :-)

 

728x90
반응형
Posted by Rfriend
,

이번 포스팅에서는 파일 형태의 이미지 데이터를 TensorFlow와 Keras 메소드를 사용하여


(1) 웹에서 압축 이미지 파일을 다운로드하여 압축을 해제하고,

(2) 폴더 이름을 확인하고 폴더 밑에 있는 파일 이름을 리스트로 만들기

(3) 이미지 파일을 로딩하여 시각화하고 라벨 이름 출력하기


를 해보겠습니다.



  (1) 웹에서 압축 이미지 파일을 다운로드하여 압축 해제하기


먼저 TensorFlow 와 객체지향 파일시스템 경로(object-oriented filesystem paths)를 관리할 때 사용하는 pathlib 모듈을 importing 하겠습니다.



import tensorflow as tf

import pathlib

import os


print(tf.__version__)

[Out] 2.4.0-dev20200913

 



이제 준비가 되었으니 https://storage.googleapis.com 의 예제 이미지로 압축되어 저장되어 있는 'flower_photos.tgz' 압축 파일을 Keras의 get_file() 메소드를 사용하여 가져와서 압축을 풀어(untar = True)보겠습니다.



flowers_root = tf.keras.utils.get_file(
    'flower_photos',
    'https://storage.googleapis.com/download.tensorflow.org/example_images/flower_photos.tgz',
    untar=True)




이러면 압축이 풀린 파일이 '.keras/datasets/flower_photos 라는 폴더에 저장되어 있습니다. 이를 pathlib.Path() 메소드로 Mac, Linux, Windows OS에 상관없이 경로를 인식할 수 있도록 PurePath로 만들어주었습니다.


* source: https://docs.python.org/3/library/pathlib.html




print(flowers_root)

[Out] /Users/xxx/.keras/datasets/flower_photos


flowers_root = pathlib.Path(flowers_root)

flowers_root

[Out] PosixPath('/Users/xxx/.keras/datasets/flower_photos')

 



저는 Mac OS 에서 작업을 했는데요, Mac OS에서 숨겨진 폴더, 파일을 보려면 Finder 에 커서를 가져다대고 'Shift + Command + .' 을 동시에 눌러주면 됩니다. 그러면 아래의 화면 캡쳐처럼 '/.keras/datasets/flower_photos/' 경로에 다운로드 후 압축해제한 이미지 파일들이 들어있음을 눈으로 직접 확인할 수 있습니다.






  (2) 폴더 이름을 확인하고 폴더 밑에 있는 파일 이름을 리스트로 만들기


다음으로, root directory 밑에 있는 하위 디렉토리와 파일 이름들을 모두(flowers_root.glob("*") ) 가져다가 for loop 으로 순회하면서 하나씩 차례대로 출력해서 확인해보겠습니다.


위의 화면캡쳐에서 숨겨진 폴더, 파일을 눈으로 봤던 것과 동일하게 하위 폴더에는 'roses', 'sunflowers', 'daisy', 'dandelion', 'tulips' 폴더와 'LICENSE.txt' 텍스트 파일이 들어있군요.



# The root directory contains a directory for each class.
for item in flowers_root.glob("*"):
    print(item.name)


[Out]

roses sunflowers daisy dandelion tulips LICENSE.txt




이제 TensorFlow.Dataset.list_files() 메소드를 사용해서 각 꽃 이름 폴더 ('roses', 'sunflowers', 'daisy', 'dandelion', 'tulips' 폴더) 밑에 있는 이미지 파일 이름(jpg 포맷) 들의 리스트를 만들어보겠습니다.


그리고 이중에서 3개만 가져와서(take(3)) 하나씩 차례대로 '전체 경로/파일이름'을 출력해보겠습니다.



# The files in each class directory are examples:
list_ds = tf.data.Dataset.list_files(str(flowers_root/'*/*'))


for f in list_ds.take(3):
    print(f.numpy())


b'/Users/xxx/.keras/datasets/flower_photos/daisy/4440480869_632ce6aff3_n.jpg' b'/Users/xxx/.keras/datasets/flower_photos/daisy/1879567877_8ed2a5faa7_n.jpg' b'/Users/xxx/.keras/datasets/flower_photos/sunflowers/969913643_9d5cd2fe45_m.jpg'

 




  (3) 이미지 파일을 로딩하여 시각화하고 라벨 이름 출력하기


이제 이미지 파일이 준비가 되었으니 TensorFlow.keras.preprocessing.image 메소드를사용하여 꽃 이미지 3개를 크기가 (250, 250)인 이미지로 변환하여 로딩하고, matplotlib 모듈로 시각화(plt.imshow(img))해보겠습니다. ( tf.Tensor() 파일을 f.numpy() 로 변환하여 로딩)


이때 TensorFlow.strings.split(f, os.sep)[-2] 로 '전체 경로/파일이름' 리스트에서 뒤에서 부터 두번째에 위치한 라벨을 파싱해서 가져와서 이미지를 시각화할 때 라벨도 같이 출력을 해보겠습니다.


해바라기(sunflowers), 장미(roses), 민들레(dandelions) 이 차례대로 시각화되었네요.



from tensorflow.keras.preprocessing import image
import matplotlib.pyplot as plt

for f in list_ds.take(3):
    img = image.load_img(f.numpy(), target_size=(250, 250))
    label = tf.strings.split(f, os.sep)[-2]
    print(label.numpy())
    plt.imshow(img)
    plt.show()




* Reference: https://www.tensorflow.org/guide/data?hl=en



많은 도움이 되었기를 바랍니다.

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요.



728x90
반응형
Posted by Rfriend
,

딥러닝, 머신러닝을 공부하다 보면 예제로 활용할 수 있는 데이터를 마련하거나 찾기가 어려워서 곤란할 때가 있습니다. 특히 라벨링이 된 이미지, 영상, 음성 등의 데이터의 경우 자체적으로 마련하기가 쉽지 않습니다. 


이번 포스팅에서는 딥러닝, 기계학습을 하는데 활용할 수 있도록 공개된 데이터셋을 TensorFlow Datasets 에서 다운로드하고 fetch 하는 방법을 소개하겠습니다. 


TensorFlow 데이터셋은 아래의 두 곳에서 다운로드 할 수 있습니다. 

(Many many thanks to TensorFlow team!!! ^__^)

  • TensorFlow Datasets : https://www.tensorflow.org/datasets
  • TensorFlow Datasets on GitHub : https://github.com/tensorflow/datasets



  (1) TensorFlow 2.0 과 TensorFlow Datasets 라이브러리 설치


cmd 명령 프롬프트 창에서 pip install 로 TensorFlow 2.0 과 TensorFlow DataSets 라이브러리를 설치합니다. 


(* CPU 를 사용할 경우)


$ pip install --upgrade pip

$ pip install tensorflow

$ pip install tensorflow_datasets

 



(* GPU를 사용할 경우)


$ pip install tensorflow-gpu

 




  (2) tensorflow 와 tensorflow_datasets 라이브러리 import 후 Dataset 로딩하기


TensorFlow v2와 tensorflow_datasets 라이브르러를 import 하겠습니다. 



import tensorflow.compat.v2 as tf

import tensorflow_datasets as tfds

 



TensorFlow v2 부터는 PyTorch처럼 Eager 모드를 지원합니다. Eager모드와 Graph 모드를 활성화시키겠습니다. 



# tfds works in both Eager and Graph modes

tf.enable_v2_behavior()



TensorFlow Datasets에 등록된 모든 공개 데이터셋 리스트를 조회해보겠습니다. 양이 너무 많아서 중간은 생략했는데요, 아래에 카테고리별로 리스트를 다시 정리해보았습니다. 



# Tensorflow Datasets Lists

tfds.list_builders()

['abstract_reasoning', 'aeslc', 'aflw2k3d', 'amazon_us_reviews', 'arc', 'bair_robot_pushing_small', :

-- 너무 많아서 중간 생략 ^^; --

   :
 'wmt18_translate',
 'wmt19_translate',
 'wmt_t2t_translate',
 'wmt_translate',
 'xnli',
 'xsum',
 'yelp_polarity_reviews']





Audio, Image, Object Detection, Structured, Summarization, Text, Translate, Video 의 8개 범주로 데이터셋이 구분되어 정리되어 있습니다. (* link: https://www.tensorflow.org/datasets/catalog/overview)


 Audio

 Image

 groove

librispeech

libritts

ljspeech

nsynth

savee

speech_commands

abstract_reasoning

aflw2k3d

arc

beans

bigearthnet

binarized_mnist

binary_alpha_digits

caltech101

caltech_birds2010

caltech_birds2011

cars196

cassava

cats_vs_dogs

celeb_a

celeb_a_hq

cifar10

cifar100

cifar10_1

cifar10_corrupted

citrus_leaves

cityscapes

clevr

cmaterdb

coil100

colorectal_histology

colorectal_histology_large

curated_breast_imaging_ddsm

cycle_gan

deep_weeds

diabetic_retinopathy_detection

div2k

dmlab

downsampled_imagenet

dsprites

dtd

duke_ultrasound

emnist

eurosat

fashion_mnist

flic

food101

geirhos_conflict_stimuli

horses_or_humans

i_naturalist2017

image_label_folder

imagenet2012

imagenet2012_corrupted

imagenet_resized

imagenette

imagewang

kmnist

lfw

lost_and_found

lsun

malaria

mnist

mnist_corrupted

omniglot

oxford_flowers102

oxford_iiit_pet

patch_camelyon

pet_finder

places365_small

plant_leaves

plant_village

plantae_k

quickdraw_bitmap

resisc45

rock_paper_scissors

scene_parse150

shapes3d

smallnorb

so2sat

stanford_dogs

stanford_online_products

sun397

svhn_cropped

tf_flowers

the300w_lp

uc_merced

vgg_face2

visual_domain_decathlon 

 Object Detection

coco

kitti

open_images_v4

voc

wider_face 

 Structured

 amazon_us_reviews

forest_fires

german_credit_numeric

higgs

iris

rock_you

titanic

 Summarization

aeslc

big_patent

billsum

cnn_dailymail

gigaword

multi_news

newsroom

opinosis

reddit_tifu

scientific_papers

wikihow

xsum 

 Text

 blimp

c4

cfq

civil_comments

cos_e

definite_pronoun_resolution

eraser_multi_rc

esnli

gap

glue

imdb_reviews

librispeech_lm

lm1b

math_dataset

movie_rationales

multi_nli

multi_nli_mismatch

natural_questions

qa4mre

scan

scicite

snli

squad

super_glue

tiny_shakespeare

trivia_qa

wikipedia

xnli

yelp_polarity_reviews

 Translate

flores

para_crawl

ted_hrlr_translate

ted_multi_translate

wmt14_translate

wmt15_translate

wmt16_translate

wmt17_translate

wmt18_translate

wmt19_translate

wmt_t2t_translate

 Video

bair_robot_pushing_small

moving_mnist

robonet

starcraft_video

ucf101




  (3) CIFAR 100 데이터셋을 로컬 디스크에 다운로드 하고 로딩하기 

       (download & load CIFAR 100 dataset)


딥러닝을 활용한 이미지 분류 학습에 많이 사용되는 예제 데이터셋인 CIFAR 100 Dataset 을 로컬 디스크에 다운로드해보겠습니다. 


[ CIFAR 10 이미지 시각화 (예시) ]




cifar_builder = tfds.builder("cifar100")

cifar_builder.download_and_prepare()





CIFAR 100 데이터셋은 ./tensorflow_datasets/cifar100/3.0.0. 폴더 밑에 다운로드되어 있습니다. train, test 데이터셋 레코드와 label 데이터, dataset과 image에 대한 JSON 데이터셋이 로컬 디스크에 다운로드 되었습니다. 





  (4) 데이터셋의 속성 정보 조회하기 (Datasets Attributes)


cifiar_builder.info 로 데이터셋의 속성을 조회해보면 아래와 같습니다. 아래의 JSON 속성 정보를 참고해서 필요한 정보를 참조할 수 있습니다. 



print(cifar_builder.info)

[Out]:

tfds.core.DatasetInfo( name='cifar100', version=3.0.0, description='This dataset is just like the CIFAR-10, except it has 100 classes containing 600 images each. There are 500 training images and 100 testing images per class. The 100 classes in the CIFAR-100 are grouped into 20 superclasses. Each image comes with a "fine" label (the class to which it belongs) and a "coarse" label (the superclass to which it belongs).', homepage='https://www.cs.toronto.edu/~kriz/cifar.html', features=FeaturesDict({ 'coarse_label': ClassLabel(shape=(), dtype=tf.int64, num_classes=20), 'image': Image(shape=(32, 32, 3), dtype=tf.uint8), 'label': ClassLabel(shape=(), dtype=tf.int64, num_classes=100), }), total_num_examples=60000, splits={ 'test': 10000, 'train': 50000, }, supervised_keys=('image', 'label'), citation="""@TECHREPORT{Krizhevsky09learningmultiple, author = {Alex Krizhevsky}, title = {Learning multiple layers of features from tiny images}, institution = {}, year = {2009} }""", redistribution_info=, )




CIFAR 100 데이터셋의 100개 라벨을 인쇄해보겠습니다. 위의 JSON 정보를 참고해서 features["label"].names 로 속성값을 조회할 수 있습니다. 



# label naems

print(cifar_builder.info.features["label"].names)


[Out]: 
['apple', 'aquarium_fish', 'baby', 'bear', 'beaver', 'bed', 'bee', 'beetle', 'bicycle', 'bottle', 'bowl', 'boy', 'bridge', 'bus', 'butterfly', 'camel', 'can', 'castle', 'caterpillar', 'cattle', 'chair', 'chimpanzee', 'clock', 'cloud', 'cockroach', 'couch', 'crab', 'crocodile', 'cup', 'dinosaur', 'dolphin', 'elephant', 'flatfish', 'forest', 'fox', 'girl', 'hamster', 'house', 'kangaroo', 'keyboard', 'lamp', 'lawn_mower', 'leopard', 'lion', 'lizard', 'lobster', 'man', 'maple_tree', 'motorcycle', 'mountain', 'mouse', 'mushroom', 'oak_tree', 'orange', 'orchid', 'otter', 'palm_tree', 'pear', 'pickup_truck', 'pine_tree', 'plain', 'plate', 'poppy', 'porcupine', 'possum', 'rabbit', 'raccoon', 'ray', 'road', 'rocket', 'rose', 'sea', 'seal', 'shark', 'shrew', 'skunk', 'skyscraper', 'snail', 'snake', 'spider', 'squirrel', 'streetcar', 'sunflower', 'sweet_pepper', 'table', 'tank', 'telephone', 'television', 'tiger', 'tractor', 'train', 'trout', 'tulip', 'turtle', 'wardrobe', 'whale', 'willow_tree', 'wolf', 'woman', 'worm']



print(cifar_builder.info.features["coarse_label"].names)

[Out]:
['aquatic_mammals', 'fish', 'flowers', 'food_containers', 'fruit_and_vegetables', 'household_electrical_devices', 'household_furniture', 'insects', 'large_carnivores', 'large_man-made_outdoor_things', 'large_natural_outdoor_scenes', 'large_omnivores_and_herbivores', 'medium_mammals', 'non-insect_invertebrates', 'people', 'reptiles', 'small_mammals', 'trees', 'vehicles_1', 'vehicles_2']





  (5) Train, Validation Set 분할하여 불러오기



# Train/ Validation Datasets

train_cifar_dataset = cifar_builder.as_dataset(split=tfds.Split.TRAIN)

val_cifar_dataset = cifar_builder.as_dataset(split=tfds.Split.TEST)


print(train_cifar_dataset)

[Out]: 
<DatasetV1Adapter shapes: {coarse_label: (), image: (32, 32, 3), label: ()}, types: {coarse_label: tf.int64, image: tf.uint8, label: tf.int64}>


print(val_cifar_dataset)

[Out]: 
<DatasetV1Adapter shapes: {coarse_label: (), image: (32, 32, 3), label: ()}, types: {coarse_label: tf.int64, image: tf.uint8, label: tf.int64}>



# Number of classes: 100

num_classes = cifar_builder.info.features['label'].num_classes


# Number of images: train 50,000 .  validation 10,000

num_train_imgs = cifar_builder.info.splits['train'].num_examples

num_val_imgs = cifar_builder.info.splits['test'].num_examples


print("Training dataset instance:", train_cifar_dataset)

Training dataset instance: <DatasetV1Adapter shapes: {coarse_label: (), image: (32, 32, 3), label: ()}, types: {coarse_label: tf.int64, image: tf.uint8, label: tf.int64}>





  (6) 데이터셋 전처리 (크기 조정, 증식, 배치 샘플링, 검증 데이터셋 생성)


* code reference: Hands-on Computer Vision with TensorFlow 2 by Eliot Andres & Benjamin Planche

(https://www.amazon.com/Hands-Computer-Vision-TensorFlow-processing-ebook/dp/B07SMQGX48)



import math


input_shape = [224, 224, 3]

batch_size = 32

num_epochs = 30


train_cifar_dataset = train_cifar_dataset.repeat(num_epochs).shuffle(10000)

 

def _prepare_data_fn(features, input_shape, augment=False):

    """

    Resize image to expected dimensions, and opt. apply some random transformations.

    - param features: Data

    - param input_shape: Shape expected by the models (images will be resized accordingly)

    - param augment: Flag to apply some random augmentations to the images

    - return: Augmented Images, Labels

    """

    input_shape = tf.convert_to_tensor(input_shape)

    

    # Tensorflow-dataset returns batches as feature dictionaries, expected by Estimators. 

    # To train Keras models, it is mor straightforward to return the batch content as tuples. 

    image = features['image']

    label = features['label']

    

    # Convert the images to float type, also scaling their values from [0, 255] to [0., 1.]

    image = tf.image.convert_image_dtype(image, tf.float32)

    

    if augment:

        # Randomly applied horizontal flip

        image = tf.image.random_flip_left_right(image)

        

        # Random B/S changes

        image = tf.image.random_brightness(image, max_delta=0.1)

        image = tf.image.random_saturation(image, lower=0.5, upper=1.5)

        image = tf.clip_by_value(image, 0.0, 1.0) # keeping pixel values in check

        

        # random resize and random crop back to expected size

        random_scale_factor = tf.random.uniform([1], minval=1., maxval=1.4, dtype=tf.float32)

        scaled_height = tf.cast(tf.cast(input_shape[0], tf.float32) * random_scale_factor, tf.int32)

        scaled_width = tf.cast(tf.cast(input_shape[1], tf.float32) * random_scale_factor, tf.int32)

        

        scaled_shape = tf.squeeze(tf.stack([scaled_height, scaled_width]))

        image = tf.image.resize(image, scaled_shape)

        image = tf.image.random_crop(image, input_shape)

    else:

        image = tf.image.resize(image, input_shape[:2])

        

    return image, label



import functools


prepare_data_fn_for_train = functools.partial(_prepare_data_fn, 

                                              input_shape=input_shape,

                                              augment=True)


train_cifar_dataset = train_cifar_dataset.map(prepare_data_fn_for_train, num_parallel_calls=4)



# batch the samples

train_cifar_dataset = train_cifar_dataset.batch(batch_size)

train_cifar_dataset = train_cifar_dataset.prefetch(1)



# validation dataset (not shuffling or augmenting it)

prepare_data_fn_for_val = functools.partial(_prepare_data_fn,

                                           input_shape=input_shape,

                                           augment=False)


val_cifar_dataset = (val_cifar_dataset

                     .repeat()

                    .map(prepare_data_fn_for_val, num_parallel_calls=4)

                    .batch(batch_size)

                    .prefetch(1))



train_steps_per_epoch = math.ceil(num_train_imgs / batch_size)

val_steps_per_epoch = math.ceil(num_val_imgs / batch_size)




많은 도움이 되었기를 바랍니다. 

이번 포스팅이 도움이 되었다면 아래의 '공감~'를 꾹 눌러주세요. :-)



728x90
반응형
Posted by Rfriend
,