2024. 4. 17. 18:00ㆍ@dev.formegusto
새로운 라이브러리나 기술을 사용함에 있어서 공식 문서나 블로그 등을 참고하는 것은 어느덧 일상이 되었습니다. 과거에는 전체적인 배경을 파악하고 코드로 접근하는 이해를 진행했었는데, 언젠가부터는 실용적인 측면에 비중이 커져서 코드 중심의 빠른 학습의 습관이 생겼는데요. 프로그래밍 언어를 사용한 소통이 많이 익숙해졌구나 하면서 뿌듯하다가도 비효율적인 활용을 하고 있다는 것을 깨닫게 되는 시점에는 이론으로 다시 돌아오더라구요. 아무래도 저는 느리지만 확실한 방법이 어울리는 편인 것 같습니다. 🐢🐢
🧺 Learning Point
- Mechanism Perspective
- Complexity of Image Data
- Statistical based model mechanism
- Neural Network based model mechanism
- Conclusion
지난 시간에는 머신러닝과 딥러닝의 차이를 역사와 모델 유형 관점에서 살펴보았었는데요. 이번 시간에는 머신러닝의 통계적인 성격과 딥러닝의 신경망 기술에 기반한 코드 중심의 접근으로 차이점을 알아볼게요. fruits 360 데이터를 활용한 과일 분류기를 목표로, 통계 및 신경망 모델의 전처리, 학습 그리고 평가, 각 단계를 독립적으로 진행해 보면서 이들의 모델 제작 메커니즘은 어떤 차이를 보이는지 확인해 보도록 하겠습니다. 👩🏻🌾🧑🏻🌾👨🏻🌾
🍑 Mechanism Perspective
Subject | Statistical | Neural Network |
데이터셋 크기 | 작은 데이터셋에서 훈련 가능 | 대량의 데이터 필요 |
과정 | 전문가의 개입을 보다 요구 | 환경 및 과거로부터 스스로 학습 |
성능 | 짧은 훈련 시간 및 낮은 정확도 | 긴 훈련 시간 및 높은 정확도 |
모델링 | 비교적 간단하고 선형적 상관 관계 | 비선형 및 복잡한 상관 관계 형성 |
해석 인사이트 | 화이트박스 모델 | 블랙박스 모델 |
위 도표는 "Model Type Perspective"에서 소개해 드렸던 통계와 신경망 모델의 차이를 나타내는 자료인데요. 공통의 주제를 가지는 특징들로 그룹화해 보았어요. 각 행의 주제를 수집, 전처리, 학습 그리고 평가로 구성된 인공지능 모델의 일반적인 제작 프로세스 상에 두어 어느 단계와 연관성을 가지는지 확인해 볼게요.
수집 | 전처리 | 학습 | 평가 |
데이터셋 크기 | |||
과정 | |||
성능 | |||
모델링 | |||
해석 인사이트 |
각 주제는 세부적으로 들여다보면 모든 단계와 연관성을 가지겠지만, 단어가 주는 강한 느낌을 기준으로 정리해 보았어요. 그 중에서도 전처리부터 평가까지, 가장 많은 영역을 포함하는 "과정"에서 이야기하는 "전문가의 개입"과 "자가 학습"의 의미를 깊이 생각해 보았는데요.
통계 모델의 "전문가의 개입"은 특징 간의 상관관계를 명확하게 밝혀내어, 출력을 실제값과 근사하도록 하는 전반적인 통계 모델 제작 프로세스를 이야기합니다. 이들은 알고리즘별로, 특정 추론 프로세스에 크게 의존하고 있기 때문에 데이터의 구조와 복잡도 등의 한계를 극복하기 위한 분석과 전처리 작업이 깊이 있게 진행되며, 여기에는 통계 및 컴퓨터 과학 등의 폭 넓은 지식을 요구합니다.
신경망 모델의 "자가학습"은 입력을 통과시킨 신경망의 출력을 실제값과 근사시키는 방향으로 지속적인 가중치 업데이트를 진행하는 신경망의 기술적 특징을 이야기합니다. 데이터 도메인 및 신경망 지식의 이해도를 바탕으로 특정 구조에 얽매이지 않은 모델을 구성할 수 있으며, 입력 데이터에 대한 높은 수용성과 학습력을 자랑합니다. 하지만 여기에는 높은 연산량과 대용량 데이터 등과 같은 고수준의 요구사항들이 수반됩니다.
저희의 핵심 관심사는 모델에게 데이터를 학습시키는 데에 인력이 얼마나 개입하는가에 있는데요. 이는 제작 프로세스상에 있는 모든 작업 메커니즘에 영향을 주는 주제이기 때문에, 동일한 목적을 가진 통계 및 신경망 모델을 각각 제작해 보면 그 차이를 효과적으로 체험해 볼 수 있을 것 같습니다.
제가 준비한 데이터는 kaggle에서 제공 중인, 여러 가지 과일의 다각도 이미지를 포함한 fruits 360 입니다. 모델 제작에 앞서, 다음 섹션에서는 통계와 신경망의 공통 과제인 데이터 배경지식을 파악하기 위한 분석을 진행해 보겠습니다.
🍎 Complexity of Image Data
인공지능 분야에서 말하는 데이터는 특징과 정답으로 구분되어 있습니다. 마치 우리가 상황과 생김새를 통해 어떠한 사건 혹은 사물을 인지하는 것 처럼 인공지능 모델은 특징의 패턴을 학습하여 높은 정확도의 예측 및 판단을 목표로 하는데요.
여기서 데이터의 복잡성은 정답을 규정짓는 특징의 관계 해석 난이도를 이야기합니다. 특징이 많은 고차원, 관계가 난해한 비선형성 등의 심화 원인을 가지고 있는데요. 그렇다면 fruits 360 데이터의 대분류, 이미지 데이터는 어떤 복잡성을 가지고 있을까요?
matplotlib의 mpimg.imread를 사용하여 이미지를 불러올게요. 하나의 이미지는 (100, 100, 3)의 형태를 가지고 있으며, (세로, 가로, RGB) 표현으로 공간이 구성되어 있다는 것을 알 수 있습니다.
값이 입력될 수 있는 픽셀이라는 공간의 조합으로 하나의 이미지가 완성되는데요. 단색 혹은 단순 패턴의 이미지는 선형 회귀를 통한 픽셀 위치에 따른 값의 추론이 가능한 분포를 가지고 있지만, fruits 360의 데이터는 시도하기도 어려울 만큼 각 픽셀에 다양한 값이 비선형적으로 분포해 있는 것을 알 수 있습니다.
또한, 각 색상 채널의 상관관계는 다양한 특징을 발생시킵니다. 대표적으로, 색조(Hue), 명도(Saturation) 그리고 채도(Value)가 있겠는데요. 그 밖에도 피사체의 형태와 위치 같은 공간적 요소와 빛과 그림자 그리고 질감과 같은 시각적 요소 등의 고수준의 정보도 포함합니다.
이와 같이, 이미지 데이터는 피사체 표현 강도에 따라 복잡성이 높아지는 데이터입니다. 이러한 복잡성은 인공지능 역사 속에서 다양한 인사이트와 챌린지를 제공하는 중요한 역할을 해왔고, 주요 논문들에서는 이미지 데이터가 제시하는 한계에 도전하는 모습을 빈번히 확인할 수 있습니다.
이미지 데이터의 활용은 아주 복잡하지만 성장은 확실하게 챙겨줄 것 같은 느낌이 오네요. 넥스트 레벨을 꿈꾸는 분들은 꼭 한번 경험해 보는 것이 좋겠죠? 이제 준비가 되셨다면 본격적으로 통계 모델부터 인공지능 기술을 활용한 과일 분류기를 제작해보도록 하겠습니다. 🍀🍀
🍌 Statistical based model mechanism
통계는 일반적으로 행과 열로 이루어진 행렬 형태의 데이터를 사용하여 진행됩니다. 평면의 공간 내에서 특징 간의 상관관계를 밝혀내는 것이 주요 목표 인데요. 이는 대부분 통계 모델의 기초가 됩니다.
하지만 현재 fruits 360 데이터는 (세로, 가로, RGB)로 구성된 입체적인 형태를 가지고 있어요. 이는 통계 모델이 요구하는 데이터 형태로는 적절하지 않으며, 원활한 메커니즘의 진행을 위해서는 전처리를 진행해 줘야 합니다.
img.flatten()
# or
img.reshape(-1)
가장 간단한 접근법은 데이터를 Flat하게 만드는 방법이 있습니다. (세로, 가로, RGB) 구조의 데이터를 (값) 구조의 형태로 변경해 주는 것인데요. numpy의 reshape 혹은 flatten 메서드를 통해 (100, 100, 3) 형태의 데이터를 (30,000) 형태의 데이터로 변환시킬 수 있습니다.
import cv2
# Grayscale
gray_img = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
# Binaryization
threshold = 128
_, binary_img = cv2.threshold(img, threshold, 1, cv2.THRESH_BINARY)
binary_img = np.mean(binary_img, axis=2).round().astype(np.uint8)
색상 채널을 단순하게 만드는 방법도 있습니다. OpenCV의 cvtColor 메서드를 활용하여 무채색의 표현으로 변환하는 Grayscale 혹은 threshold 메서드를 활용하여 피사체의 유의미한 색상이 포함된 위치만을 기록하는 Binaryization 등을 수행할 수 있죠.
from sklearn.decomposition import PCA
from sklearn.manifold import TSNE
# Flattening
flat_imgs = imgs.reshape(len(imgs), -1)
# Principal Component Analysis
pca = PCA(n_components=2)
pca_imgs = pca.fit_transform(flat_imgs)
# t-SNE(t-distributed Stochastic Neighbor Embedding)
tsne = TSNE(n_components=2)
tsne_imgs = pca.fit_transform(flat_imgs)
차원축소(Dimension Reduction) 방법론들을 사용할 수도 있어요. 이는 고차원의 데이터를 저차원의 데이터로 변환하는 기술들을 이야기 하는데요. 대표적으로, 데이터의 분산을 이용하는 PCA(Principal Component Analysis)나 확률 분포를 이용하는 t-SNE(t-distributed Stochastic Neighbor Embedding)가 있습니다.
from sklearn.neighbors import KNeighborsClassifier
from sklearn.svm import SVC
from sklearn.ensemble import RandomForestClassifier
이제 본격적으로 학습을 진행해 보도록 할까요? 전처리 데이터는 Flat, Grayscale, PCA 그리고 모델은 KNN(K-Neighbor Nearest)과 SVM(Support Vector Machine) 그리고 RandomForest를 사용하겠습니다.
def imgs_split(imgs):
return train_test_split(imgs, labels, test_size=0.25, shuffle=True)
def evaluation_score(y_true, y_pred):
accuracy = accracy_score(y_true, y_pred)
precision = precision_score(y_true, y_pred, average=None)
recall = precision_score(y_true, y_pred, average=None)
def fit(model, imgs):
X_train, X_test, y_train, y_test = imgs_split(imgs)
# Learning Performance
timer.start()
model.fit(X_train, y_train)
learning_time = timer.end()
# Prediction Performance
timer.start()
y_pred = model.predict(X_test)
prediction_time = timer.end()
# Evaluation
scores = evaluation_score(y_test, y_pred)
return learning_time, prediction_time, scores
# Usage
knn = KNeighborsClassifier(n_neighbors=10)
fit(knn, flat_imgs)
다양한 데이터와 모델의 학습 및 평가 프로세스를 정형화하기 위한 함수를 위와 같이 작성해 주었고, 평가의 요소는 학습 및 예측 속도 그리고 정확도(Accuracy), 정밀도(Precision), 재현율(Recall)의 분류 지표입니다. 각 모델의 평가 결과와 개선 방식을 비교하고 적절한 모델을 선택하도록 할게요.
학습을 무사히 진행해 주셨다면 평가 결과 비교를 진행해 보도록 하겠습니다. 우선은 구조에 큰 변화를 주지 않은 Flat 및 Grayscale 데이터를 사용한 케이스의 분류 성능이 매우 우수한 것을 확인할 수 있습니다. 반면에 속도 측면의 성능은 모델별로 상이하네요. 각 모델의 동작 방식을 분석하여, 이를 개선할 수 있는 요소를 찾아보도록 하겠습니다.
SVM의 학습은 클래스를 나누는 결정 경계(Decision Boundary)를 찾기 위하여, 서포트 벡터(Support Vector)와 마진(Margin), 그리고 커널(Kernel) 함수를 이용한 연산이 진행됩니다. 해당 방식은 기본적으로 연산 비용이 많이 드는 방식으로, 데이터의 차원과 수량의 증가는 높은 연산 비용으로 이어지게 되며, 이는 예측의 과정에서도 활용되어 예측 속도에도 영향을 주게 됩니다.
이어서, KNN은 주어진 학습 데이터의 거리를 측정하여 K개의 이웃을 찾아 그룹을 형성하는 연산을 진행합니다. SVM과 마찬가지로, 학습 과정의 연산을 예측에서도 활용한다는 공통의 특징을 가지고 있는데요. 그래서 Flat-Gray-PCA 순으로 개선되는 속도의 추세가 SVM과 유사한 것을 확인할 수 있습니다. 그러나 SVM 보다는 단순한 방식을 사용하기 때문에, 차원과 수량에 비교적 적은 영향을 받습니다.
하지만 SVM은 통계 모델 중에서도 데이터에 대한 높은 학습력을 가지고 있으며, 불안정한 KNN의 분류 성능에 비해 SVM은 높은 유지력을 위 시각화에서 확인할 수 있습니다. 분류 성능을 유지하고, 속도를 개선할 수 있다는 점에서는 SVM은 적절한 PCA 하이퍼파라미터를 설정하는 방향으로 개선을 진행하여 KNN 보다 우수한 모델 제작할 수 있겠네요.
아직 살펴보지 않은 RandomForest는 여러 개의 의사 결정 트리(Decision Tree)를 학습하고, 이들의 예측을 결합하여 최종 예측을 결정하는 앙상블(Ensemble) 학습 방식을 사용합니다. 예측의 과정에서 학습 연산의 재사용이 아닌 생성된 의사 결정 트리 경로를 사용하기 때문에 앞서 살펴본 모델들과는 다른 세상을 살고 있으며, 데이터의 형태가 예측 속도에는 큰 영향을 끼치지 않는 것을 확인할 수 있습니다.
단점이 될 수도 있는 학습 속도는 scikit-learn 에서 제공하는 RandomForest 생성자의 의사 결정 트리의 개수를 조절하는 데에 사용되는n_estimators 매개변수를 통해 개선을 진행할 수 있습니다. 분류 성능을 유지하는 선까지 수량을 낮추는 방식으로 말이죠.
종합적으로, Flat과 Grayscale을 입력 데이터 사용했을 때 나타나는 높은 성능과 실용적인 측면에서 예측 속도의 중요성 그리고 데이터의 구조를 유지하며 개선을 진행할 수 있다는 점을 고려했을 때, 통계 모델에서 fruits 360 데이터에 적합한 모델은 RandomForest로 결론 지을 수 있겠네요. 🥳🥳
🍊 Neural Network based model mechanism
현대 딥러닝 기술의 주요 개념인 신경망은 1957년에 프랑크 로젠블라트 님이 발표하신 "The Perceptron: A Probabilistic Model for Information Storage and Organization in the Brain"에서 인간의 뇌가 정보를 저장하고 조직하는 방식을 모델링하기 위한 퍼셉트론을 배경으로 성장해 왔습니다.
때문에 오늘날의 다양한 신경망 알고리즘은 인지과학으로부터 많은 영감을 받아 탄생했는데요. 그 중에서도 합성곱 신경망(Convolution Neural Network, CNN)은 시각적 수용 영역(Receptive Field)의 접근을 통해 발전한 기술로, 컴퓨터 비전(Computer Vision, CV) 분야에서 큰 주목을 받고 있습니다.
CV의 주요 관심사인 이미지 및 비디오 데이터는 평면 데이터로부터 색상 그리고 시간의 요소를 포함하며 차원이 확장되는 특징을 가지고 있는데요. CNN은 주요 레이어인 합성곱층(Convolution Layer)과 풀링층(Pooling Layer)을 통해 시각 데이터의 패턴을 탐지하고 인식하며, 이는 매우 효과적인 인식 및 분류 작업을 가능케 해주었습니다.
🍳 Convolution Neural Network Guide
- Convolution Layer
- Pooling Layer
- Let's cnn.fit()!
저희의 fruits 360을 활용한 과일 분류기 모델 생성에도 좋은 성과를 가져다 줄 것으로 기대하는데요. Tensorflow를 활용한 개념 이해부터 학습까지, 진행해 보도록 하겠습니다. 😎😎
🍒 Convolution Layer
합성곱층은 CNN 기술의 전체적인 배경을 설명하는 아주 중요한 요소입니다. 필터(Filter) 혹은 커널(Kernel)이라고 불리는 가중치 갱신에 영향을 주는 수용 영역의 형태와 이에 대한 움직임을 설명하는 스트라이드(Stride)를 기반으로 동작하는데요. Tensorflow에서는 입력 데이터 차원에 따라 Conv1D, Conv2D 그리고 Conv3D로 구분한 생성자를 제공합니다.
from tensorflow.keras import layers
conv_layer = layers.Conv2D(filters=1, kernel_size=(3, 3), strides=1)
input_shape = (None, 8, 8, 1)
conv_layer.build(input_shape)
현재 저희가 다루고 있는 정적 이미지 데이터는 (batch_size, height, width, channels) 형태의 입력을 받는 Conv2D에 적합한 형태를 갖추고 있습니다. 이에 사용되는 매개변수인 filters와 kernel_size는 (...kernel_size, input_channels, filters) 형태의 가중치와 (filters) 크기를 가지는 편향 구성에 사용되며, strides는 입력 데이터에 대한 가중치 및 편향 연산의 움직임을 정의합니다.
input_data = np.arange(1, 65).reshape(1, 8, 8, 1).astype(np.float32)
weight = np.arange(1, 10).reshape(3, 3, 1, filters).astype(np.float32)
bias = np.array([2]).astype(np.float32)
conv_layer.set_weights([weight, bias])
output_data = conv_layer(input_data)
# ... visualization
원활한 설명을 위하여 합성곱층 객체의 가중치와 편향을 단순한 수치 행렬 데이터로 구성 해보았는데요. 입력 데이터를 레이어에 통과시켜보겠습니다.
출력결과가 어떤 느낌으로 다가오시나요? 우선 값이 아닌 형태적인 관점에서 보았을 때 (8, 8)의 행렬이 (6, 6)의 형태로 변화한 것을 확인할 수 있습니다. 이는 (3, 3)형태의 가중치 행렬이 입력 데이터를 (1, 1)의 움직임으로 슬라이딩 윈도우 연산을 수행했기 때문인데요.
각 윈도우 지역 내에서는 가중치 행렬과의 요소별 곱 그리고 총합을 편향과 합하는 연산이 진행됩니다. 여기에 학습이라는 개념을 적용하면 지역적 특징 추출의 작업이 수행되는 것으로 볼 수 있겠는데요. 이러한 특징 때문에 합성곱층의 출력 데이터를 Feature Map 이라고 부르기도 합니다.
다수의 채널을 가지는 입력 데이터에서는, 채널별로 독립적인 수용 영역을 포함한 특징 추출로 수행됩니다. 그리고 이 후에 결과를 합산한 데이터가 출력됩니다.
하지만 이러한 방식은 가장자리와 내부 데이터 간의 슬라이딩 적용 영역 차이 때문에 특징 추출의 불균형을 일으킵니다. 이럴 때는 입력 데이터 모서리 주변에 일정한 값을 추가하여 출력 데이터의 형태를 조절하는 패딩(padding) 기법을 사용하여 보완할 수 있는데요. 생성자의 padding 매개변수를 "same"으로 설정하는 것으로 적용할 수 있습니다.
수용 영역을 제어하는 모습이 물체의 정체를 감지하기 위하여 구석구석 형태를 살펴보는 행위처럼 느껴지지 않나요? 합성곱층의 유연한 입력 데이터 구조 적응력은 전처리에 대한 부담을 해소하여 특징 손실 줄일 수 있게 해주며, 픽셀 간의 상관관계를 형성하고 있는 시각 데이터 학습에 대한 다양한 설계 방향성을 제시 해줍니다.
🫐 Pooling Layer
합성곱층의 메커니즘은 매우 섬세하게 진행된다는 것을 알 수 있는데요. 분명한 장점이지만, 모델의 연산량 및 훈련 데이터의 특징을 너무 과하게 학습하는 과적합(Overfitting)의 가능성을 증가시키는 단점을 동반합니다.
Window Operation | Feature | |
최대 풀링 (Max Pooling) | 최대값 | 활성 데이터 강조 |
평균 풀링 (Average Pooling) | 평균값 | 부드럽고 균일한 정보 형성 |
이에 대응할 수 있는 해결책으로는 풀링층이 있습니다. 합성곱층과 유사하게 풀링 영역의 형태와 움직임을 설정하여 슬라이딩 윈도우를 진행하는데요. 개별 윈도우를 대표하는 값을 추출하여 입력 데이터의 공간 해상도를 감소시키는 메커니즘을 가지고 있으며, 윈도우 공간 내에서 진행되는 연산에 따라 최대 풀링과 평균 풀링으로 구분되어 집니다.
# 최대 풀링
max_pool = layers.MaxPooling2D(pool_size=(2, 2), strides=1, padding="valid")
# 평균 풀링
avg_pool = layers.AveragePooling2D(pool_size=(2, 2), strides=1, padding="valid")
Tensorflow에서도 해당 분류를 채택하여 MaxPooling 및 AveragePooling 생성자를 제공하는데요. 주요 매개변수로는 풀링 윈도우 영역의 크기를 정의하는 pool_size가 있으며, 합성곱층과 마찬가지로 움직임을 정의하는 strides와 형태 조절을 위한 padding이 있습니다.
풀링층을 통과한 데이터는 크기가 축소되어 다음 레이어의 연산량을 개선하고 특징 일반화를 통해 과적합을 방지하여 모델의 성능을 최적화 하는데에 기여합니다.
🥗 Let's cnn fit()!
합성곱 신경망의 개념은 흥미롭게 보셨나요? 이제 배운 내용을 토대로 모델을 설계해 보도록 할 건데요. 앞서 말씀드린 것 처럼, Conv2D 생성자가 요구하는 입력 데이터의 형태는 fruits 360 데이터 집합의 형태와 같으며, 이에 따라 데이터에 대한 전처리를 진행하지 않고 신경망 설계에만 집중해 볼 수 있겠습니다.
from tensorflow.keras import layers, models
cnn.add(layers.Conv2D(filters=1, kernel_size=(2, 2), activation='relu'))
cnn.add(layers.Flatten())
cnn.add(layers.Dense(label_count))
신경망 설계는 간단히 "훈련 데이터가 정답 까지 도달하는 길을 꾸며주는 작업"으로 보시면 될 것 같아요. 머리에 도화지를 펼쳐보시고, 고차원의 이미지 데이터가 출력 단계의 라벨 데이터까지 도달하는 길을 떠올려보면, 학습을 위한 합성곱층과 출력층 그리고 층간의 형태를 맞춰주기 위한 Flat 전처리의 지점들을 상상해 볼 수 있습니다. 그러면 위와 같이 Convolution - Flatten - Fully Connected 의 레이어 구성을 도출 시킬 수 있겠네요.
이와 같은 신경망 구성에서는 Convolution을 지나 형성된 Feature Map이 Flat하게 펼쳐지고 Fully Connected를 지나 입력 데이터가 어느 라벨에 적절한지에 대한 정보가 측정된 배열 데이터가 최종적으로 출력되게 됩니다. 모델은 이러한 흐름을 기반으로 학습과 예측을 진행하죠.
# ... update model's hyper parameter or layer configuration
# Compile Model
cnn.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True))
# Learning Performance
timer.start()
history = cnn.fit(X_train, y_train, epochs=10,
callbacks=[tf.keras.callbacks.EarlyStopping(
patience=3,
monitor="loss",
restore_best_weights=True
)])
learning_time = timer.end()
# Prediction Performance
timer.start()
y_pred = np.argmax(cnn.predict(X_test), axis=1)
prediction_time = timer.end()
# Evaluation
scores = evaluation_score(y_test, y_pred)
신경망의 길을 더 꾸며보겠습니다. 합성곱층을 중심으로 하이퍼파라미터 혹은 레이어 구성에 변화를 주는 실험을 통하여 통계 모델에서와 동일한 평가 지표를 사용한 결과를 확인하고, 적절한 설정을 적용하는 방향으로 성능을 늘려가보도록 하겠습니다.
첫 번째 실험은 filters 값에 따른 성능 변화를 관찰하였습니다. filters의 증가는 향상된 특징 추출의 강도와 분류 성능을 나타내어, 학습량의 감소 추세를 Epochs Count 자료를 통해 확인할 수 있었는데요. 하지만 연산량과 함께 증가하는 학습 및 예측 속도 시간도 고려해야하기 때문에 무작정 높은 값 보다는 안정적인 예측 성능을 보이는 구간의 최솟값을 선택할 수 있겠습니다.
다음으로는 kernel_size에 변화를 주었습니다. 슬라이딩 횟수가 줄어들어 속도가 개선될 것 같았지만, 오히려 커널의 연산 범위와 함께 가중치 학습량의 증가로 성능이 저하되었으며, 불안정한 분류 성능도 확인되었습니다. 피사체의 형태가 뚜렷한 fruits 360 데이터에서는 kernel_size를 작게 가져가는 섬세한 특징 추출 방식이 적절한 것 같네요.
cnn.add(layers.Conv2D(filters=16, kernel_size=2, activation='relu'))
그러면 Conv2D의 설정을 분류지표의 성능의 안정성을 고려하였을 때, 위 코드와 같이 구성할 수 있겠는데요. 다음으로는 추가 레이어를 통한 성능 개선을 진행할 수 있는지 알아보도록 하겠습니다.
Layer | Constructor | Code |
Convolution | Conv2D | C |
MaxPooling | MaxPooling2D | M |
AveragePooling | AveragePooling2D | A |
Flatten | Flatten | F |
Fully Connected | Dense | D |
합성곱층의 결과를 개선해 수 있는 추가 레이어를 찾아보도록 할 것 인데요. 시각화 커뮤니케이션을 위하여 레이어를 코드로 정의하여 표시 하겠습니다. 예시로, Convolution - MaxPooling - Flatten - Fully Connected 의 경우에는 CMFD로 표기됩니다.
이미 초기에 도출한 간단한 신경망 구성에서 효과적인 분류 성능을 보여줬었네요. 그러면 레이어의 깊이를 더하는 구성은 제외할 수 있겠습니다. 다음의 문제는 속도를 개선하는 것인데 최대 풀링층을 추가한 형태가 눈에 띄네요.
이에 따라, CMFD, CAFD 형태의 신경망의 추가적인 실험으로 풀링층의 pool_size 변화에 따른 성능 변화를 지켜봤는데요. 일반화의 범위를 적당한 선까지 지켜준다면, 분류 성능을 유지하면서도 학습 및 예측 속도를 개선시킬 수 있는 모습을 확인할 수 있네요.
# Set Layer Configuration
cnn = models.Sequential()
cnn.add(layers.Conv2D(filters=16, kernel_size=2, activation='relu'))
cnn.add(layers.MaxPooling2D(pool_size=8))
cnn.add(layers.Flatten())
cnn.add(layers.Dense(label_count))
# Compile Model
cnn.compile(optimizer='adam',
loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True))
# Start Learning
cnn.fit(X_train, Y_train, epochs=20,
callbacks=[tf.keras.callbacks.EarlyStopping(
patience=3,
monitor="loss",
restore_best_weights=True
)])
속도 개선의 효과가 더욱 큰 최대풀링층을 택하여, Convolution - MaxPooling - Flatten - Fully Connected의 구성으로 레이어 구성을 마무리할 수 있겠네요. 저는 여기에 안정적인 분류 성능을 위하여 epochs 값도 충분히 올려놓은 형태로 최종 CNN 모델을 완성시켰습니다. 🥳🥳
🍇 Conclusion
지금까지 과일 분류기라는 공통의 목적을 가진 통계 및 신경망 기반 모델의 학습 과정을 살펴보았습니다. 모든 모델이 멋진 성능과 속도를 갖추게 되었는데, 그 중에서도 통계 기반 모델의 놀라운 성과가 돋보이는데요. 이번 섹션에서는 2개의 모델 제작 메커니즘을 다시 떠올려보며, 차이점을 중심으로 회고해보도록 하겠습니다.
우선, 전처리 작업을 떠올려보도록 할게요. 통계 모델은 원활한 학습을 진행하기 위한 입력 데이터의 제한을 가지고 있었습니다. 그래서 데이터 구조에 변화를 주는 Flat과 무채색 변환을 통해 색상 채널을 축소하는 Grayscale 그리고 보다 고수준의 차원 축소를 위한 PCA의 전처리를 진행했는데요.
신경망 모델에서는 이미지라는 주제에 적절한 기술을 선택해서 특별한 전처리를 진행하지 않았습니다. 합성곱 신경망의 높은 입력 수용성 덕분에 도메인의 배경과 통계 분석 능력 등의 폭 넓은 지식을 요구하는 전처리에 대한 부담을 해소할 수 있었죠.
Conv2D(filters="?", kernel_size="?")
하지만 성능 개선의 작업에서 하이퍼파라미터와 레이어 구성에 대한 폭 넓은 경우의 수에 대응하기 위한 다양한 시도가 진행되었습니다. 핵심 레이어의 기초 개념과 평가 결과에 의존 했으며 학습이 오래걸린다는 특징을 가지고 있기 때문에 많은 시간이 소요되었습니다.
통계 모델은 학습 과정에서 도출된 유의미한 통계적 자료들이 데이터의 크기 혹은 하이퍼파라미터 등과 같은 개선 요소를 빠르게 찾아내는 데에 기여해주었습니다. 이는 결과의 근거가 명확하지 않은 신경망과 비교되는 통계 모델의 장점을 보여줍니다.
Kaggle | Flat | Grayscale | PCA | Learning | Time | Indicator | Etc | |
Statistical | ||||||||
CNN |
결과적으로 통계 모델은 전체 메커니즘에 인력의 지식이 적극 동원되어야 합니다. 반면에 신경망 모델은 대부분의 과정을 선택 사항으로 두고 프로세스를 진행할 수 있었는데요. 물론, 일반적인 상황은 아닙니다. 저희가 실험에서 도출한 결론들은 fruits 360 데이터의 조건이 적절했기에 가능했던 일이죠.
신경망 기반 모델도 수량과 복잡도가 적절하지 않은 데이터를 만나면 통계 모델과 같은 전처리와 분석을 진행해 주어야 하며, 블랙박스 모델이라는 특성 상 그 이상의 지식을 요구하게 될 수도 있습니다.
하지만 인공지능의 실용화가 중요한 현대에서는 변칙적인 실제 환경에 적응할 수 있는 신경망 기반 모델의 자가 학습 가치를 아주 크게 보고 있어요. 그래서 단점들을 보완하기 위한 데이터 증강(Data Augmentation) 및 설명가능한 인공지능(Explainable AI, XAI) 등과 같은 기술들이 연구되고 있습니다.
또한, fruits 360 데이터에서는 통계 모델이 더욱 뛰어난 성능을 보여준 것을 기억하시나요? 신경망 모델의 한계는 통계 모델과의 융합을 통해서도 방법을 찾고는 합니다. 이러한 동향과 결과를 보았을 때, 아직 딥러닝의 신경망 기술은 머신러닝의 개념을 완전히 대체하지 못하며, 오늘날의 저희가 머신러닝과 딥러닝을 독립적인 개념으로 부르는 근본적인 이유일지 모르겠네요. 🧐🧐
"머신러닝과 딥러닝의 차이가 뭐야?" 라는 질문에서부터 시작한 "섬세한 머신러닝과 딥러닝의 차이점" 시리즈는 모두 마무리 되었습니다. "Chaos: Machine Learning? Deep Learning?" 에서는 인공지능의 기초적인 이론을 친숙하게 다루었으며, "Mechanism Perspective" 에서는 코드와 결과를 중심으로 이야기를 써 내려갔는데요.
이론은 가볍게 이해하고, 코드와 결과 중심의 세부적인 이해를 선호하는 저의 공부 습관을 담아보았어요. 다소 포괄적인 머신러닝과 딥러닝의 차이점이라는 주제가 조심스러웠지만, 나름 탄탄하고 딥러닝의 장점이 편향되지 않는 방향으로 작성하기 위해 노력해 보았습니다. 다음에 또 새로운 주제로 만나요. 오늘 하루도 수고하셨습니다. 😌😌
'@dev.formegusto' 카테고리의 다른 글
ABC부터 시작하는 블록체인 (1) Bitcoin Paper Review (0) | 2024.06.05 |
---|---|
섬세한 머신러닝과 딥러닝의 차이점 (1) Chaos: Machine Learning? Deep Learning? (0) | 2024.02.21 |
Typescript로 구현해 보는 KMeans (4) KMeans With UI Interaction (1) | 2024.02.07 |
Typescript로 구현해 보는 KMeans (3) KMeans++ with Typescript (0) | 2024.01.17 |
Typescript로 구현해 보는 KMeans (2) KMeans and KMeans++ Difference (1) | 2024.01.10 |