728x90
반응형

 지금까지 이미지 분류 모델을 만들고, 학습까지 시켜보았다. 지난 포스트에서는 학습 과정을 보며, 학습이 제대로 이루어졌는지를 평가하고, 최적의 epochs를 결정하는 방법에 대해 공부해보았다.

 그러나, 지금 같이 데이터의 양이 작고, epochs가 상대적으로 적은 경우엔 학습이 완전히 끝난 후 그래프를 그려서 학습 과정을 살필 수 있었지만, 만약에 epochs가 1,000 이거나 데이터의 크기가 1,000만 개를 가뿐히 넘겨 학습 시간이 길어지는 경우라면, 이전에 했던 방법으로 접근해서는 안된다.

 이때, 등장하는 개념이 바로 조기 종료다.

 

 

조기 종료(Early Stopping)

0. 선행 코드

# Import module
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import (Dense, BatchNormalization, Dropout, Flatten)
from tensorflow.keras.datasets.mnist import load_data

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Dataset 준비
(train_images, train_labels), (test_images, test_labels)= load_data()

# 무작위로 샘플 추출
np.random.seed(1234)
index_list = np.arange(0, len(train_labels))
valid_index = np.random.choice(index_list, size = 5000, replace = False)

# 검증셋 추출
valid_images = train_images[valid_index]
valid_labels = train_labels[valid_index]

# 학습셋에서 검증셋 제외
train_index = set(index_list) - set(valid_index)
train_images = train_images[list(train_index)]
train_labels = train_labels[list(train_index)]

# min-max scaling
min_key = np.min(train_images)
max_key = np.max(train_images)

train_images = (train_images - min_key)/(max_key - min_key)
valid_images = (valid_images - min_key)/(max_key - min_key)
test_images = (test_images - min_key)/(max_key - min_key)





# 모델 생성
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28], name="Flatten"))
model.add(Dense(300, activation="relu", name="Hidden1"))
model.add(Dense(200, activation="relu", name="Hidden2"))
model.add(Dense(100, activation="relu", name="Hidden3"))
model.add(Dense(10, activation="softmax", name="Output"))





# 모델 컴파일
opt = keras.optimizers.Adam(learning_rate=0.005)
model.compile(optimizer = opt,
              loss = "sparse_categorical_crossentropy",
              metrics = ["accuracy"])

 

 

 

 

1. 검증 손실 값과 과대 적합

  • 조기 종료를 이해하기 위해선 이전에 만들었던 그래프를 다시 한번 봐야 한다.

  • 위 그래프는 훈련 셋과 검증 셋의 손실 값(Loss)과 정확도(Accuracy)를 시각화한 것이다.
  • 검증 셋의 손실 값(val_loss, 녹색)은, 쭉 감소하다가 갑자기 손실 값이 증가하게 된다.
  • 이는 모델이 학습 셋에 지나치게 최적화되어, 학습 셋이 아닌 다른 데이터 셋을 이상하게 출력하는 과대 적합(Overfitting) 현상이 발생하여, 일어나는 현상이다.
  • 조기 종료는 검증 셋의 손실 값이 최소가 되는 순간(최적의 모델) 학습을 멈춤으로써, 이러한 과대 적합을 멈추는 아주 간단하면서도 강력한 규제 방법 중 하나다.
  • 참고: "Tensorflow-3.2. 이미지 분류 모델(2)-검증 셋(Validation set)"
  • 조기 종료는 이전 "Tensorflow-3.3. 이미지 분류 모델(3)-모델 생성"에서 잠깐 언급하고 넘어갔던, "스트레치 팬츠(Stretch pants) 방식"을 위한 도구 중 하나다.

 

 

 

 

2. 콜벡(callbacks)

  • 콜벡(callbacks)은 학습 과정에서 영향을 주거나, 발생한 통계 데이터를 출력해주는 함수들의 집합이다.
  • 대표적인 callbacks 함수는 이전 포스트에서 우리가 다뤘던 history로, 워낙 유용하다 보니 자동으로 적용되어 있다.
  • callbacks 함수는 Sequential이나 .fit() 메서드에 전달 가능하다.
  • 조기 종료는 이 callbacks 안에 포함되어 있다.

2.1. 조기 종료

  • 조기 종료는 다음과 같은 방법으로 사용할 수 있다.
early_stop = keras.callbacks.EarlyStopping(monitor="val_loss", min_delta=0, patience=10, restore_best_weights=True)
history = model.fit(train_images, train_labels,
                    epochs=1000,
                    batch_size=5000,
                    validation_data=(valid_images, valid_labels),
                    callbacks=[early_stop])
  • keras.callbacks.EarlyStopping()의 중요 파라미터는 다음과 같다.
  1. monitor: 관찰할 값 - 일반적으로 검증 손실 값인 var_loss를 사용하며, 간간히 var_acc가 사용되기도 한다.
  2. min_delta: 개선 기준 최소 변화량 - 개선되고 있다고 판단할 수 있는 최소 변화량으로 변화량이 min_delta보다 작다면 개선이 없다고 판단한다.
  3. patience: 정지까지 기다리는 epochs - 당장 최솟값이 나왔다 할지라도, 이 값이 학습을 하다 보면, 더 떨어질 수도 있다. 그러므로, patience에 정해진 epochs만큼 학습을 더 실시하고, 그동안 개선이 없다면, 학습을 멈춘다.
  4. restore_best_weights: 최선 값이 발생한 때로 모델 가중치 복원 여부 - False로 돼 있다면, 학습의 마지막 단계에서 얻어진 모델 가중치가 사용된다.
  • val_loss는 증감을 반복하므로, epochs를 조금 줘서 기다리도록 하자.
  • 위 코드를 실행하면 다음과 같은 결과가 나온다.
Epoch 1/1000
11/11 [==============================] - 2s 177ms/step - loss: 1.5362 - accuracy: 0.4834 - val_loss: 0.4362 - val_accuracy: 0.8714
Epoch 2/1000
11/11 [==============================] - 1s 55ms/step - loss: 0.3673 - accuracy: 0.8928 - val_loss: 0.2479 - val_accuracy: 0.9252
Epoch 3/1000
11/11 [==============================] - 1s 55ms/step - loss: 0.2225 - accuracy: 0.9336 - val_loss: 0.1759 - val_accuracy: 0.9436
Epoch 4/1000
11/11 [==============================] - 1s 61ms/step - loss: 0.1550 - accuracy: 0.9539 - val_loss: 0.1353 - val_accuracy: 0.9560
Epoch 5/1000
11/11 [==============================] - 1s 55ms/step - loss: 0.1185 - accuracy: 0.9649 - val_loss: 0.1108 - val_accuracy: 0.9640

...

Epoch 19/1000
11/11 [==============================] - 1s 54ms/step - loss: 0.0032 - accuracy: 0.9997 - val_loss: 0.0786 - val_accuracy: 0.9806
Epoch 20/1000
11/11 [==============================] - 1s 51ms/step - loss: 0.0026 - accuracy: 0.9999 - val_loss: 0.0841 - val_accuracy: 0.9794
Epoch 21/1000
11/11 [==============================] - 1s 52ms/step - loss: 0.0024 - accuracy: 0.9998 - val_loss: 0.0831 - val_accuracy: 0.9794
Epoch 22/1000
11/11 [==============================] - 1s 60ms/step - loss: 0.0017 - accuracy: 1.0000 - val_loss: 0.0800 - val_accuracy: 0.9798
Epoch 23/1000
11/11 [==============================] - 1s 51ms/step - loss: 0.0013 - accuracy: 1.0000 - val_loss: 0.0845 - val_accuracy: 0.9792
  • epochs를 1000으로 지정하였으나, val_loss가 최솟값을 찍었기 때문에 epoch 23에서 학습을 정지하였다.
  • 조기 종료를 사용하면, 별도의 과정 없이, 손쉽게 최적의 epochs를 찾아낼 수 있으므로, 오차 역전파법을 찾아내 지금의 딥 러닝을 있게 한 1등 공신 중 한 명인 제프리 힌턴은 조기 종료를 "훌륭한 공짜 점심(beautiful free lunch)"이라고 불렀다고 한다.
  • 이외에도 콜벡에는 학습 중간에 자동 저장을 하는 ModelCheckPoint나 학습률을 스케쥴링하는 LearningRateSchedule 등 유용한 기능이 많다. 관심 있는 사람은 다음 아래 사이트를 참고하기 바란다.
    (keras.io/ko/callbacks/)
 

Callbacks - Keras Documentation

Usage of callbacks 콜백은 학습 과정의 특정 단계에서 적용할 함수의 세트입니다. 학습 과정 중 콜백을 사용해서 모델의 내적 상태와 통계자료를 확인 할 수 있습니다. 콜백의 리스트는 (키워드 인수

keras.io

 

 

[참고 서적]

 

 

  지금까지 조기 종료(Early stopping)와 콜백에 대해 알아보았다. 다음 포스트에서는 최종 과정인 모델 평가와 모델 저장 및 불러오기에 대해 학습해보도록 하겠다.

728x90
반응형
728x90
반응형

 이전 포스트에서 모델을 학습시키는 것에 대해 알아보았다. 기존 포스팅에서는 학습을 시키고, 이를 가만히 기다리기만 했었는데, 이 학습 과정에서 발생하는 Log를 분석할 수 있다면, 언제 학습을 멈춰야 할지, 과적합이 발생하였는지 등을 정보다 정확히 알 수 있다. 이번 포스팅에서는 학습과정을 확인하는 방법에 대해 알아보도록 하겠다.

 

 

학습과정 확인(History)

0. 이전 코드 정리

# Import module
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import (Dense, BatchNormalization, Dropout, Flatten)
from tensorflow.keras.datasets.mnist import load_data

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Dataset 준비
(train_images, train_labels), (test_images, test_labels)= load_data()

# 무작위로 샘플 추출
np.random.seed(1234)
index_list = np.arange(0, len(train_labels))
valid_index = np.random.choice(index_list, size = 5000, replace = False)

# 검증셋 추출
valid_images = train_images[valid_index]
valid_labels = train_labels[valid_index]

# 학습셋에서 검증셋 제외
train_index = set(index_list) - set(valid_index)
train_images = train_images[list(train_index)]
train_labels = train_labels[list(train_index)]

# min-max scaling
min_key = np.min(train_images)
max_key = np.max(train_images)

train_images = (train_images - min_key)/(max_key - min_key)
valid_images = (valid_images - min_key)/(max_key - min_key)
test_images = (test_images - min_key)/(max_key - min_key)
# 모델 생성
model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28], name="Flatten"))
model.add(Dense(300, activation="relu", name="Hidden1"))
model.add(Dense(200, activation="relu", name="Hidden2"))
model.add(Dense(100, activation="relu", name="Hidden3"))
model.add(Dense(10, activation="softmax", name="Output"))
# 모델 컴파일
opt = keras.optimizers.Adam(learning_rate=0.005)
model.compile(optimizer = opt,
              loss = "sparse_categorical_crossentropy",
              metrics = ["accuracy"])
# 모델 학습하기
history = model.fit(train_images, train_labels,
                    epochs=100,
                    batch_size = 5000,
                    validation_data=(valid_images, valid_labels))
  • 이전 포스팅에서는 model.fit()을 따로 다른 변수에 담지 않았으나, 이번 포스팅에서는 이들을 history라는 변수에 담고, 이를 분석해보도록 하겠다.

 

 

 

 

1. History

  • model.fit()을 실시하여, 학습을 시작하게 되면, 다음과 같은 Log가 출력되게 된다.
history = model.fit(train_images, train_labels,
                    epochs=100,
                    batch_size=5000,
                    validation_data=(valid_images, valid_labels))
Epoch 1/100
11/11 [==============================] - 2s 182ms/step - loss: 1.5596 - accuracy: 0.4747 - val_loss: 0.4669 - val_accuracy: 0.8640
Epoch 2/100
11/11 [==============================] - 1s 57ms/step - loss: 0.3706 - accuracy: 0.8902 - val_loss: 0.2654 - val_accuracy: 0.9182
Epoch 3/100
11/11 [==============================] - 1s 55ms/step - loss: 0.2260 - accuracy: 0.9337 - val_loss: 0.1824 - val_accuracy: 0.9416
Epoch 4/100
11/11 [==============================] - 1s 51ms/step - loss: 0.1626 - accuracy: 0.9514 - val_loss: 0.1369 - val_accuracy: 0.9562
Epoch 5/100
11/11 [==============================] - 1s 52ms/step - loss: 0.1198 - accuracy: 0.9642 - val_loss: 0.1176 - val_accuracy: 0.9624

...

Epoch 96/100
11/11 [==============================] - 1s 52ms/step - loss: 2.8271e-05 - accuracy: 1.0000 - val_loss: 0.1096 - val_accuracy: 0.9788
Epoch 97/100
11/11 [==============================] - 1s 57ms/step - loss: 2.7180e-05 - accuracy: 1.0000 - val_loss: 0.1100 - val_accuracy: 0.9790
Epoch 98/100
11/11 [==============================] - 1s 56ms/step - loss: 2.6393e-05 - accuracy: 1.0000 - val_loss: 0.1101 - val_accuracy: 0.9790
Epoch 99/100
11/11 [==============================] - 1s 50ms/step - loss: 2.5213e-05 - accuracy: 1.0000 - val_loss: 0.1103 - val_accuracy: 0.9792
Epoch 100/100
11/11 [==============================] - 1s 51ms/step - loss: 2.4920e-05 - accuracy: 1.0000 - val_loss: 0.1106 - val_accuracy: 0.9792
  • model.fit()는 History 객체를 반환하며, 이 것이 바로 fit()을 실행하면 반환되는 출력 Log이다.
  • 출력되는 값은 model.compile을 할 때, metrics를 어떻게 지정하느냐에 따라 달라진다.
  • 가장 일반적으로 사용되는 accuracy를 넣고, validation data를 넣으면, loss, accuracy, val_loss, val_acc가 출력되게 된다.
  • 이는 매 에포크마다의 모델을 평가하는 점수라고 할 수 있으며, 그 뜻은 다음과 같다.
  1. loss: 훈련 셋 손실 값
  2. accuracy: 훈련 셋 정확도
  3. val_loss: 검증 셋 손실 값
  4. val_acc: 검증 셋 정확도
  • 만약 검증 셋을 추가하지 않는다면 val_loss, val_acc가 출력되지 않으며, metrics에서 accuracy를 지정하지 않는다면, accuracy도 출력되지 않는다.

 

 

 

 

2. History 데이터를 다뤄보자.

# history를 출력시켜보자.
>>> history
<tensorflow.python.keras.callbacks.History at 0x20f001a1d00>
  • history를 출력시켜보면, <tensorflow.python.keras.callbacks.History at ~~~~~>와 같은 이상한 문자가 출력된다. Python에서는 이를 객체라 부르며, 해당 객체에 다양한 함수를 이용하여 학습과정에서 발생한 다양한 정보를 볼 수 있다.
  • 예를 들어, history.epoch를 입력하면, 전체 epoch를 list로 출력하며, history.params 입력 시, 훈련 파라미터가 반환된다.
  • 우리에게 필요한 것은 history.history로, 이 데이터는 한 에포크가 끝날 때마다 훈련 셋과 검증 셋을 평가한 지표들이 모여 있는 것이다.
# history.history는 각 지표들이 담겨있는 dictionary다
>>> type(history.history)
dict

# history.history의 생김새는 다음과 같다.
>>> history.history
{'loss': [1.1046106815338135,
  0.32885095477104187,
  0.2113472819328308,
  0.1513378769159317,
  0.11605359613895416,
  0.09276161342859268,
  
...

  0.9787999987602234,
  0.9789999723434448,
  0.9789999723434448,
  0.979200005531311,
  0.979200005531311]}
  • 데이터를 파악하기 쉽도록 DataFrame의 형태로 바꿔서 보자.
history_DF = pd.DataFrame(history.history)
history_DF

  • 적합한 epoch를 알기 위해 해당 데이터를 시각화해보자.
  • index는 epoch와 동일하다.
# 꺾은선 그래프를 그리자.
# 그래프의 크기와 선의 굵기를 설정해주었다.
history_DF.plot(figsize=(12, 8), linewidth=3)

# 교차선을 그린다.
plt.grid(True)

# 그래프를 꾸며주는 요소들
plt.legend(loc = "upper right", fontsize =15)
plt.title("Learning Curve", fontsize=30, pad = 30)
plt.xlabel('Epoch', fontsize = 20, loc = 'center', labelpad = 20)
plt.ylabel('Variable', fontsize = 20, rotation = 0, loc='center', labelpad = 40)

# 위 테두리 제거
ax=plt.gca()
ax.spines["right"].set_visible(False) # 오른쪽 테두리 제거
ax.spines["top"].set_visible(False) # 위 테두리 제거

  • 시각화를 해서 4개 지표의 변화 추이를 보았다.
  • 위 그래프의 결과를 해석해보면 다음과 같다.
  1. 훈련 셋과 검증 셋의 그래프가 비슷한 형태를 보였다. 이는 과적합(Overfitting)이 되지 않았다는 것을 의미한다.
  2. 훈련 셋, 검증 셋의 Accuracy는 1을 향해 상승하였다. loss는 0을 향해 하강하는 형태를 보였다. 이는 안정적으로 학습을 하고 있는 것을 의미한다.
  3. 훈련 셋, 검증 셋의 Accuracy와 loss는 epoch 20부터 수렴하기 시작했다.
  4. 검증 셋의 loss는 epoch가 20을 넘는 순간부터 소폭 증가하는 형태를 보였다.
  5. 검증 셋의 손실 값이 최저값을 약 epoch 20에서 달성하였으므로, 모델이 완전히 수렴하였다고 할 수 있다.
  • 기존에 epochs을 100으로 설정하였으나, loss와 accuracy가 수렴한 지점을 볼 때, 이는 과하게 큰 값임을 알 수 있다. epochs를 30으로 줄여서 다시 학습을 해보도록 하자.
  • epoch가 불필요하게 큰 경우, 리소스의 낭비가 발생하기도 하지만, 과적합(Overfitting)이 될 위험이 있으므로, 적합한 epoch에서 학습을 해주는 것이 좋다.
  • epoch가 커지면 커질수록 훈련 셋의 성능은 검증 셋의 성능보다 높게 나온다. 검증 셋의 손실(var_loss)의 감소가 아직 이루어지고 있는 상태라면, 모델이 완전히 수렴되지 않은 상태라 할 수 있으므로, 검증 셋 손실의 감소가 더 이상 이루어지지 않을 때 까진 학습을 해야 한다.

 

epochs를 30으로 하여 다시 학습해보자.

history = model.fit(train_images, train_labels,
                    epochs=30,
                    batch_size=5000,
                    validation_data=(valid_images, valid_labels))
history_DF = pd.DataFrame(history.history)
# 꺾은선 그래프를 그리자.
# 그래프의 크기와 선의 굵기를 설정해주었다.
history_DF.plot(figsize=(12, 8), linewidth=3)

# 교차선을 그린다.
plt.grid(True)

plt.legend(loc = "upper right", fontsize =15)

plt.title("Learning Curve", fontsize=30, pad = 30)
plt.xlabel('Epoch', fontsize = 20, loc = 'center', labelpad = 20)
plt.ylabel('Variable', fontsize = 20, rotation = 0, loc='center', labelpad = 40)

# 위 테두리 제거
ax=plt.gca()
ax.spines["right"].set_visible(False) # 오른쪽 테두리 제거
ax.spines["top"].set_visible(False) # 위 테두리 제거

  • 위 그래프를 보면 검증 셋이 연습 셋 보다 더 빠르게 0과 1로 다가가는 것으로 오해할 수 있으나, 훈련 셋의 지표는 epoch 도중에 계산되고, 검증 셋의 지표는 epoch 종료 후 계산되므로, 훈련 곡선을 왼쪽으로 소폭(에포크의 절반만큼) 이동시켜야 한다.
  • 혹시나 해서 하는 말이지만, 모델이 생성된 후에 다시 학습을 하려면, 커널을 재시작해서 모델의 파라미터를 초기화시키고 학습해야 한다. Tensorflow는 이미 학습이 되어 파라미터가 생긴 모델을 재학습 시키면, 기존의 파라미터를 감안하여 학습을 하게 된다.

 

 

[참고 서적]

 

 

 지금까지 모델 학습 과정에서 발생한 history 객체를 이용해서, 학습 셋과 검증 셋의 지표들을 시각화하고, 과적합이 발생하였는지, 적합한 epochs이 얼마인지 탐색해보았다.

 간단하게 검증 셋과 학습 셋의 그래프가 비슷한 경향을 보이면 과적합이 일어나지 않고 있다는 것을 의미하며, 0과 1에 수렴하지 못한다면, 하이퍼 파라미터가 주어진 데이터셋에 맞지 않다는 것을 의미한다. 또한 epochs가 수렴 이후에도 지속되는 경우, 연습 셋에 과적합 될 수 있으므로, 적당한 epochs를 설정하는 것이 중요하다.

 그러나, 꼭 위 방법처럼 epoch를 갱신해서 다시 학습을 해줘야 하는 것은 아니다. 다음 포스트에서는 epoch가 아직 남았더라도, 조건을 만족하면 알아서 학습을 멈추는 조기 종료에 대해 알아보도록 하겠다.

728x90
반응형
728x90
반응형

 지난 포스트에서 Tensorflow에서 왜 Keras를 사용하는지와 Keras의 코드 흐름이 어떻게 흘러가는지를 알아보았다. 지금까지의 Tensorflow 과제에서는 진행 과정을 큰 시야에서 보았다면, 이번 포스트부턴 디테일하게 각 부분이 어떻게 흘러가는지를 보도록 하겠다.

 

 

MNIST Dataset

 LeCun 교수가 만든 MNIST Dataset은 머신러닝 학습에서 가장 기본적으로 사용되는 데이터로, Tensorflow, Pytorch와 같은 수많은 딥러닝 라이브러리의 예제에서 해당 데이터를 다루는 것을 볼 수 있다.

 이번 학습에서는 MNIST 데이터에서 가장 대표적인 데이터인 손으로 쓴 숫자를 분류하는 모델을 만들어보도록 하겠다.

# Import Module
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras.layers import (Dense, BatchNormalization, Dropout)
from tensorflow.keras.datasets.mnist import load_data

import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
# Import Dataset
(train_images, train_labels), (test_images, test_labels)= load_data()
  • 해당 코드를 처음 실행한다면, Dataset이 다운로드 된다.
  • 때문에 인터넷이 안 되는 환경에서는 해당 데이터를 다운로드할 수 없으므로, 외부망에서 미리 다운로드를 하여 가상 환경을 반입하도록 하자.
  • 데이터가 어떻게 생겼는지 보도록 하자.
# Dataset의 모양
>>> train_images.shape
(60000, 28, 28)

>>> train_labels.shape
(60000,)

>>> test_images.shape
(10000, 28, 28)

>>> test_labels.shape
(10000,)
  • train set은 총 60,000개, test set은 10,000개의 Data로 이루어져 있으며, 각각 28*28의 형태로 구성되어 있다.
  • Label Data는 각 Row가 무슨 숫자인지를 의미한다.
  • 이미지 데이터이므로, 이미지가 어떻게 생겼는지 봐보자.
def show_images(dataset, label, nrow, ncol):

    # 캔버스 설정
    fig, axes = plt.subplots(nrows=nrow, ncols=ncol, figsize=(2*ncol,2*nrow))
    ax = axes.ravel()

    xlabels = label[0:nrow*ncol]

    for i in range(nrow*ncol):

        image = dataset[i]
        ax[i].imshow(image, cmap='gray')
        ax[i].set_xticks([])
        ax[i].set_yticks([])
        ax[i].set_xlabel(xlabels[i])

    # 빈 칸 없이 꽉 채우기
    plt.tight_layout()
    plt.show()
show_images(train_images, train_labels, 4, 5)

  • 이미지 데이터의 모습은 위와 같다. 아래에 있는 숫자는 각 Data에 해당하는 Label을 붙인 것이다.
  • 실제 데이터인 텐서의 모습은 다음과 같다.
>>> print(train_images[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   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   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   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   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   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   3  18  18  18 126 136 175  26 166 255 247 127   0   0   0   0]
 [  0   0   0   0   0   0   0   0  30  36  94 154 170 253 253 253 253 253 225 172 253 242 195  64   0   0   0   0]
 [  0   0   0   0   0   0   0  49 238 253 253 253 253 253 253 253 253 251  93  82  82  56  39   0   0   0   0   0]
 [  0   0   0   0   0   0   0  18 219 253 253 253 253 253 198 182 247 241   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0  80 156 107 253 253 205  11   0  43 154   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0  14   1 154 253  90   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 139 253 190   2   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0  11 190 253  70   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  35 241 225 160 108   1   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0  81 240 253 253 119  25   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0  45 186 253 253 150  27   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0   0  16  93 252 253 187   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 249 253 249  64   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0   0   0  46 130 183 253 253 207   2   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0   0   0  39 148 229 253 253 253 250 182   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0   0   0  24 114 221 253 253 253 253 201  78   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0   0   0  23  66 213 253 253 253 253 198  81   2   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0   0   0  18 171 219 253 253 253 253 195  80   9   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0  55 172 226 253 253 253 253 244 133  11   0   0   0   0   0   0   0   0   0   0   0   0   0   0]
 [  0   0   0   0 136 253 253 253 212 135 132  16   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   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   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   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0   0]]
  • 이미지를 어떻게 텐서로 만드는 가에 대해 의문이 들 수 있는데, 위 데이터와 실제 사진을 비교해보면 굉장히 단순한 원리로 만들어졌음을 알 수 있다.
  • 위 텐서에서 0에 가까울수록 사진에서는 검게 나왔으며, 숫자가 최댓값인 255에 가까울수록 희게 나온 것을 알 수 있다.
  • 즉, 흑백 사진의 텐서화는 색의 농도로 나타나는 것을 알 수 있다.
  • 만약, 이 것이 칼라 사진인 경우, RGB 총 3개의 채널(Channel)에 대해 각 색의 농도를 행렬로 만들어, 3차원 배열로 만들면, 텐서가 생성된다.

 

 

 

 다음 포스트에서는 검증셋(Validation set)에 대해 자세히 알아보고, 검증셋을 직접 추출해보도록 하겠다.

728x90
반응형

+ Recent posts