입력한 데이터의 묶음
묶음대로 결과물이 나온다
100개 데이터를 한꺼번에 묶어서 ( 배치를 만들어서 ) 입력을 했으면,
거기에 대한 결과물이 100개가 한꺼번에 나온다.
Loss도 배치를 사용하는 상황에 대해서 대응을 해줘야 한다.
N
건의 배치에 대한 loss를 각각 구한 다음
그 값을 모두 더해서 평균을 내면 된다.
import tensorflow as tf
import matplotlib.pyplot as plt
%matplotlib inline
from tensorflow.keras import datasets
mnist = datasets.mnist
(x_train, y_train), _ = mnist.load_data()
print('x_train의 shape : {} ' .format(x_train.shape))
print('y_train의 shape : {} ' .format(y_train.shape))
~~>
x_train의 shape : (60000, 28, 28)
y_train의 shape : (60000,)
TRAIN_IMAGE_COUNT = x_train.shape[0]
x_train = x_train.reshape(TRAIN_IMAGE_COUNT, -1)
x_train.shape
~~>
(60000, 784)
y_train = tf.one_hot(y_train, 10)
y_train = y_train.numpy() # Tensor 배열을 ndarray 화 시키기
y_train
~~>
array([[0., 0., 0., ..., 0., 0., 0.],
[1., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
...,
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 0., 0.],
[0., 0., 0., ..., 0., 1., 0.]], dtype=float32)
y_train.shape
~~>
(60000, 10)
✨ 각 알고리즘 ( CNN, RNN, ANN )등을 사용할 때 마다 받아 들일 수 있는 데이터의 형상( shape )이 상이 하기 때문에 언제나 데이터의 shape을 확인하고 전처리 할 수 있도록 해야한다.
✨ 정답 데이터( t ) 같은 경우에는 텐서플로우나 파이토치 등의 프레임워크를 사용할 때는 딱히 신경을 쓰지 않아도 좋다. 단 t의 형상에 따라서 사용되어지는 loss 함수의 종류는 달라질 수 있다.
✨ 예를 들어 턴서플로우에서 t가
One Hot Encoding이 안되어 있는 경우 :
sparse categorical crossentropy
를 사용
One Hot Encoding이 되어 있는 경우 :categorical crossentropy
를 사용
이진 분류 :binary crossentropy
를 사용하는 등의 확인은 필요하다.
import numpy as np
train_size = x_train.shape[0] # 전체 훈련 데이터셋 크기(60,000개)
batch_size = 10 # 미니 배치의 사이즈 ( 10개를 1묶음으로 )
batch_mask = np.random.choice(train_size, batch_size) # train_size에서 batch_size 만큼의 정수를 무작위로 추출
batch_mask
~~>
array([37931, 28671, 19284, 36379, 27742, 22532, 54126, 56638, 24002,
45051])
x_batch = x_train[batch_mask] # batch_mask에 위치한 데이터 추출하기
y_batch = y_train[batch_mask] # 정답 데이터도 동일한 batch_mask를 이용해서 추출
👉 위의 코드에서는 y라고 되어있지만 실제로는 t( 정답 )이다.
version 1
def cross_entropy_error(y, t):
# 만약에 데이터가 1개만 들어온다면 - 1차원 배열 형태로 데이터가 들어오는 경우 -> 배치를 사용하지 않는 경우
if y.ndim == 1: # y가 1차원 배열 : 배치가 없는 경우
t = t[np.newaxis, :]
y = reshape(1, -1) # 두 방식은 같은 것 편한 것으로 사용하면 된다.
batch_size = y.shape[0] # N을 구한 것
# 배치마다의 loss를 합한 다음 batch_size로 나누어 준다 -> loss의 평균
delta = 1e-7
return -np.sum(t * np.log(y+delta)) / batch_size
version 2
def sparse_cross_entropy_error(y, t):
if y.dim == 1:
t = t.reshape(1, t.size) # size : 스칼라 원소의 개수
y = y.reshape(1, y.size)
delta = 1e-7
batch_size = y.shape[0]
return -np.sum(np.log(y[np.arrange(batch_size), t] + delta)) / batch_size
np.log(y[np.arange(batch_size), t])
batch_size = 5
t = [2, 7, 0, 9, 8] # OHE이 안되어 있는 상태
np.arange(batch_size) : [0, 1, 2, 3, 4] # batch_size 크기의 배열이 생성 됨
y[[0, 1, 2, 3, 4], [2, 7, 0, 9, 8]]
y[np.arange(batch_size), t] : y[0, 2]
y[1, 7]
y[2, 0]
y[3, 9]
y[4, 8]
💡 y는 현재 batch_size가 5이기 때문에 5개의 배치 데이터에 대한 소프트맥스의 결과물
👉 y는 이차원 배열이 된다.
y가
y = [
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
]
이라면...
y[0, 2]의 경우 살펴보기
1. np.log(y[np.arange(batch_size), t])
2. np.log(y[0, 2])
3. np.log(0.8)
y[1, 7]
y[2, 0]
y[3, 9]
y[4, 8]
💡 batch가 없고, OHE이 되어있으면?
💡 batch가 없고, OHE도 안되어 있으면?
✨ y는 신경망의 추론단계( 순전파 )를 지났기 때문에 항상 softmax가 적용된 결과물
클라스가 3개면 y의 결과물은 3개, 배치가 없는 경우 (3, )
t = np.array([1])
y = np.array([0.1, 0.7, 0.2])
print(t.size)
print(y.size)
print(t.reshape(1, t.size))
print(y.reshape(1, y.size))
~~>
1
3
[[1]]
[[0.1, 0.7, 0.2]]
batch_size = 5
sel = np.array([1, 3, 4])
t = np.array([2, 7, 0])
y = np.array([
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 3.0, 0.0, 0.0],
[0.9, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 0.0, 10],
[0.1, 0.05, 0.8, 0.05, 0.0, 0.0, 0.0, 0.0, 8, 0.0]
])
y[sel, t]
~~>
array([0.8, 0. , 0.1])