- MNIST 데이터셋: 고등학생과 인구조사국 직원 등이 쓴 손글씨를 이용해 만든 데이터로 구성되어 있습니다. 7만 개의 글자 이미지에 각각 0부터 9까지 이름표를 붙인 데이터셋이다.
이미지를 인식하는 원리
MNIST 데이터는 텐서플로의 케라스 API를 이용해 간단히 불러올 수 있습니다.
X = 이미지 데이터
Y = 이미지에 0 ~ 9를 붙인 이름표
학습에 사용될 부분: X_train, y_train
테스트에 사용될 부분: X_test, y_test
케라스의 MNIST 데이터는 총 7만 개 이미지 중 6만 개를 학습용으로 1만 개를 테스트용으로 미리 구분.cmap='Gray' 옵션을 지정해 흑백으로 출력
이 이미지는 가로 28 x 세로 28 = 총 784개의 픽셀로 이루어져 있습니다. 각 픽셀은 밝기 정도에 따라 0부터 255까지 등급을 매깁니다. 흰색 배경이 0이라면 글씨가 들어간 곳은 1~255의 숫자 중 하나로 채워져 긴 행렬로 이루어진 하나의 집합으로 변환됩니다.
다음 코드로 확인할 수 있습니다.
이제 이것을 속성을 담은 데이터를 딥러닝에 집어넣고 클래스를 예측하는 문제로 전환시킵니다. 28 x 28 = 784개의 속성을 이용해 0 ~ 9의 클래스 열 개 중 하나를 맞히는 문제가 됩니다. 이제 주어직 가로 28, 세로 28의 2차원 배열을 784개의 1차원 배열로 바꾸어 주어야 합니다. reshape(총 샘플 수, 1차원 속성의 개수) 형식으로 지정합니다. 총 샘플 수는 앞서 사용한 X_train.shape[0]을 이용하고, 1차원 속성의 개수는 이미 살펴본 대로 784개입니다.
`
케라스는 데이터를 0 ~ 1사이의 값으로 변환한 후 구동할 때 최적의 성능을 보입니다. 따라서 현재 0 ~ 255 사이의 값으로 이루어진 값을 255로 나누어 0 ~ 1사이의 값으로 바꾸어야 합니다. 이를 정규화라고 합니다.
정규화를 위해 값들을 실수형으로 바꾸어야 합니다.
X_test에도 마찬가지로 이 작업을 적용합니다.
딥러닝의 분류 문제를 해결하려면 원-핫 인코딩 방식을 적용해야합니다. 즉, 0 ~ 9의 정수형 값을 갖는 현재 형태에서 0 또는 1로만 이루어진 벡터로 값을 수정해야 합니다.
np_utils.to_categorical() 함수를 이용해 [5]를 [0,0,0,0,0,1,0,0,0,0]으로 바꾸는 것과 같은 과정을 진행할 것입니다. to_categorical(클래스, 클래스의 개수) 형식으로 지정합니다.
: 입력된 이미지에서 다시 한 번 특징을 추출하기 위해 커널(슬라이딩 윈도)을 도입하는 기법입니다.
예시
입력된 이미지가 다음과 같은 값을 가지고 있다고 하자.
여기에 2 x 2 커널을 준비합니다. 각 칸에는 가중치가 들어 있습니다.
커널을 맨 왼쪽 윗칸에 적용해보겠습니다.
적용된 부분은 원래 있던 값에 가중치의 값을 곱합니다. 그 결과를 합하면 새로 추출된 값은 2가 됩니다.
( 1 x 1 ) + ( 0 x 0 ) + ( 0 x 0 ) + ( 1 x 1 ) = 2
이 커널을 한 칸씩 옮겨 모두 적용해 보자.
정리하면 다음과 같다.
컨볼루션(합성곱) 층
컨볼루션 층을 만들면 입력 데이터가 가진 특징을 대략적으로 추출해서 학습을 진행할 수 있습니다. 이런 커널을 여러 개 만들 경우 여러 개의 컨볼루션 층이 만들어집니다.
케라스에서 컨볼루션 층을 추가하는 함수는 Conv2D() 입니다.
1. 첫 번째 인자: 커널을 몇 개 적용할지 정합니다. 여기서는 32개의 커널을 적용했습니다.
2. kernel_size: 커널의 크기를 정합니다. kernel_size = (행, 열) 형식으로 정하며, 여기서는 3 x 3 크기의 커널을 사용하게 끔 정했습니다.
3. input_shape: Dense 층과 마찬가지로 맨 처음 층에는 입력되는 값을 알려 주어야 합니다. input_shape = (행, 열, 색상 또는 흑백) 형식으로 정합니다. 만약 입력 이미지가 색상이면 3, 흑백이면 1을 지정합니다. 여기서는 28 x 28 크기의 흑 백 이미지를 사용하도록 정했습니다.
4. activation: 사용할 활성화 함수를 정의합니다.
이어서 컨볼루션 층을 하나 더 추가해 보겠습니다.
맥스 풀링, 드롭아웃, 플래튼
: 컨볼루션 층을 통해 이미지 특징을 도출해도 그 결과가 여전히 크고 복잡하면 이를 다시 한 번 축소해야 한다. 이 과정을 풀링(pooling) 또는 서브 샘플링(sub sampling)이라고 합니다.
: 맥스 풀링(max pooling): 정해진 구역 안에서 최댓값을 뽑아냄.
: 평균 풀링(average pooling): 평균 값을 뽑아냄
맥스 풀링의 예
다음과 같은 이미지가 있다.
맥스 풀링을 적용하면 다음과 같이 구역을 나눕니다.
그리고 각 구역에서 가장 큰 값을 추출합니다.
이 과정을 거쳐 불필요한 정보를 간추립니다. 맥스 풀링은 MaxPooling2D() 함수를 사용해서 다음과 같이 적용할 수 있습니다.
pool_size를 통해 풀링 창의 크기를 정합니다.
드롭아웃, 플래튼
: 과적합을 효과적으로 피하는 과정을 도와주는 기법중 가장 효과가 큰 것이 드롭아웃(drop out) 기법입니다. 드롭아웃은 은닉층에 배치된 노드 중 일부를 임의로 꺼 주는 것입니다.
랜덤하게 노드를 꺼 주면 과적합을 방지할 수 있습니다. 케라스를 이용해 25%의 노드를 꺼봅시다.
이런것들을 앞에서 Dense() 함수를 이용해 만들었던 기본 층에 연결해보자. 이때 주의할 점은 컨볼루션 층이나 맥스 풀링은 주어진 이미지를 2차원 배열인 채로 다루기 때문에 이를 1차원 배열로 바꾸어 주어야 활성화 함수가 있는 층에서 사용할 수 있습니다. Flatten() 함수를 사용해 2차원 배열을 1차원으로 바꾸어 줍니다.
컨볼루션 신경망 실행하기
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout, Flatten, Conv2D, MaxPooling2D
from tensorflow.keras.callbacks import ModelCheckpoint,EarlyStopping
: 자연어 처리는 사람이 말하는 음성이나 텍스트를 컴퓨터가 인식하고 처리하는 것을 말합니다.
텍스트의 토큰화
: 입력할 텍스트가 준비되면 이를 단어별, 문장별, 형태소별로 나눌 수 있는데 이렇게 작게 나누어진 하나의 단위를 토큰이라고 합니다. 그리고 이 과정을 토큰화하고 합니다.
케라스가 제공하는 text 모듈의 text_to_word_sequence() 함수를 사용해보자.
결과는 다음과 같습니다.
Bag-of-Words 라는 방법은 같은 단어끼리 따로따로 가방에 담은 후 각 가방에 몇 개의 단어가 들어있는지 세는 기법입니다. 단어의 빈도수를 알면 텍스트에서 중요한 역할을 하는 단어를 파악할 수 있습니다.
케라스의 Tokenizer() 함수를 사용하면 단어의 빈도수를 쉽게 계산할 수 있습니다.
텍스트 전처리 함수 중 Tokenizer() 함수를 불러옵니다.
전처리하려는 세 개의 문장을 docs라는 배열에 지정합니다.
토큰화 함수인 Tokenizer()를 이용해 전처리하는 과정을 다음과 같습니다.
word_counts는 단어의 빈도수를 계산해 주는 함수입니다. 출력 결과는 다음과 같습니다.
순서를 기억하는 OrderedDict 클래스에 담겨 있는 형태로 출력되어 있습니다. document_count() 함수를 이용하면 총 몇 개의 문장이 들어 있는지도 셀 수 있습니다.
또한, word_docs() 함수를 통해 각 단어들이 몇 개의 문장에 나오는지 세어서 출력할 수도 있습니다. 순서는 랜덤입니다.
각 단어에 매겨진 인덱스 값을 출력하려면 word_index() 함수를 사용하면 됩니다.
단어의 원-핫 인코딩
: 단어가 문장의 다른 요소와 어떤 관계를 가지고 있는지 알아보는 방법입니다.
예시
다음과 같은 문장이 있다.
각 단어를 모두 0으로 바꾸어 주고 원하는 단어만 1로 바꾸어 주는 것이 원-핫 인코딩이다. 이를 수행하기 위해 먼저 단어 수만큼 0으로 채워진 벡터 공간으로 바꾸자.
각 단어가 배열 내에서 해당하는 위치를 1로 바꾸어서 벡터화할 수 있습니다.
이러한 과정을 케라스로 실습해보자. 먼저 토큰화 함수를 불러와 단어 단위로 토큰화하고 각 단어의 인덱스 값을 출력해보자.
texts_to_sequences() 함수를 사용해서 토큰의 인덱스로만 채워진 새로운 배열을 만들어주자.
1 ~ 6의 정수로 인덱스되어 있는 것을 0과 1로만 이루어진 배열로 바꾸어 주는 to_categorical() 함수를 사용해 원-핫 인코딩 과정을 진행하자. 배열 맨 앞에 0이 추가되므로 단어 수보다 1이 더 많게 인덱스 숫자를 잡아 주는 것에 유의하자.
단어 임베딩
: 단어 임베딩은 주어진 배열을 정해진 길이로 압축시킵니다.
단어 임베딩은 각 단어 간의 유사도를 계산함.
단어 간 유사도는 오차 역전파를 이용한 최적의 유사도를 계산하는 학습 과정을 거친다. Embedding() 함수를 사용해 간단히 할 수 있다. Embedding() 함수를 적용해 딥러닝 모델을 만들 수 있다.
- Embedding(16, 4)는 입력될 총 단어 수는 16, 임베딩 후 출력되는 벡터 크기는 4로 하겠다는
의미 입니다.
- Embedding(16, 4, input_length=2) 라고 하면 총 입력되는 단어 수는 16개이지만 매번 두 개씩
만 넣겠다는 의미입니다.
텍스트를 읽고 긍정, 부정 예측하기
영화 리뷰를 딥러닝 모델로 학습해서 각 리뷰가 긍정적인지 부정적인지를 예측하는 것입니다. 먼저 짧은 리뷰 열 개를 불러와 긍정이면 1이라는 클래스를, 부정적이라면 0이라는 클래스로 지정합니다.
토큰화 과정을 진행합니다.
토큰에 지정된 인덱스로 새로운 배열을 생성합니다.
리뷰 데이터마다 토큰 수가 다릅니다. 딥러닝 모델에 입력하려면 학습 데이터의 길이가 동일해야 합니다. 이처럼 길이를 똑같이 맞추어 주는 작업을 패딩(padding) 과정이라고 합니다. 케라스의 pad_sequences() 함수를 사용하면 원하는 길이보다 짧은 부분은 숫자 0을 넣어서 채워주고, 긴 데이터는 잘라서 같은 길이로 맞춰줍니다.
실습| 영화 리뷰가 긍정적인지 부정적인지를 예측하기
from tensorflow.keras.preprocessing.text import Tokenizer
from tensorflow.keras.preprocessing.sequence import pad_sequences
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense,Flatten,Embedding
from tensorflow.keras.utils import to_categorical
from numpy import array
# 텍스트 리뷰 자료를 지정합니다.
docs = ["너무 재밌네요","최고예요","참 잘 만든 영화예요","추천하고 싶은 영화입니다","한번 더 보고싶네요","글쎄요","별로예요","생각보다 지루하네요","연기가 어색해요","재미없어요"]