Machine Learning은 즐겁다! Part 3

Machine Learning은 즐겁다! Part 3

출처 : 기계학습(Machine Learning, 머신러닝)은 즐겁다! Part 3

딥러닝(Deep Learning)에 관한 의미는?

이번에는 딥러닝을 사용해 사진 속에서 객체를 인식하는 프로그램을 작성하는 법에 대해 알아봄

- Google Photos에서 사진 속에 포함된 객체를 기반으로 원하는 사진을 검색할 수 있는 법

Google에서는 사진에 태그가 지정되지 않아도 원하는 사진을 검색할 수 있음

- 이 웹툰은 3살짜리 아이는 새의 사진을 쉽게 인식할 수 있어도, 50년 이상 최고의 컴퓨터 과학자들은 컴퓨터로 객체를 인식하는 방법을 알아내기 위해 노력했으나 불가능했다는 것을 알려줌

- 지난 몇 년 사이, 우리는 딥 컨볼루션 신경망(deep convolutional neural networks)을 사용해 객체 인식에 대한 접근방법을 발견

심플하게 시작

새의 사진을 인식하는 방법을 배우기 전, 손으로 쓴 숫자 "8"과 같은 좀 더 심플한 것을 인식하는 방법

Part 2에서는 단순한 뉴련을 많이 연결함으로써 신경망이 어떻게 복잡한 문제를 해결할 수 있는지에 대해 배움

- 또한 Machine Learning이라는 아이디어는 동일한 일반 알고리즘을 다른 데이터로 재사용해 다른 종류의 문제를 해결할 수 있음

- 필기체를 인식하기 위해 위의 신경망을 수정해 '8'만을 인식하게 만들어 볼 것

- Machine Learning은 데이터가 있을 때, 그것도 아주 많이 있을 때 잘 동작. 그렇기에 손으로 쓰여진 필기체 '8'이 정말 많이 필요

- 다행히 연구자들이 이와 같은 목적을 위해 필기체 숫자의 MNIST 데이터 세트 (MNIST data set of handwritten numbers)를 만들었음. MNIST는 하나 당 18x18 픽셀 크기의 이미지로 60,000개의 필기체 숫자 이미지들을 제공

MNIST 데이터 세트에 있는 여러가지 8 이미지

생각해보면 모든 것은 그저 숫자일 뿐입니다

우리의 neural으로 이미지를 처리하려고 하는데... 어떻게 이미지를 공급해야 하는가?

→ neural은 숫자를 입력으로 사용, 컴퓨터에서 이미지는 각각의 픽셀이 얼마나 어두운지를 나타내는 숫자 그리드

우리의 neural에 이미지를 공급하기 위해서는 18x18 픽셀 이미지를 324개의 숫자들의 배열로 생각

324개의 입력을 처리하기 위해, 우리의 신경망이 324개의 입력 노드를 갖도록 변경

neural에는 두개의 출력이 있음

1) 이미지가 '8일 가능성

2) 이미지가 '8'이 아닐 가능성

- 인식하려는 개별 객체에 대해 별도의 출력을 가짐으로써, 우리는 neural을 이용해 객체를 그룹으로 분류할 수 있음

이제 우리의 neural은 훨씬 커졌으나(3개 대신 324개의 입력) 모든 최신 컴퓨터는 순식간에 수백 개의 노드가 있는 neural을 처리할 수 있음

이제 neural을 '8'과 '8'이 아닌 이미지로 훈련시켜서 이를 구분할 수 있게 하는것이 남음

만약 '8'을 제공할 때 그 이미지가 '8'일 확률은 100%이고 '8'이 아닐 확률은 0%가 되어야 함

훈련 데이터

훈련이 끝나면 '8'이라는 그림을 꽤 높은 정확도로 인식할 수 있는 neural을 갖게 될 것

편협한 생각

- 픽셀을 neural에 제공하는 것만으로도 이미지 인식을 제작하는데 정말 효과적

Machine Learning은 마술인가요?

→ 실제로 그렇게 간단하지 않습니다

일단 우리의 '8' 인식기가 글자가 이미지 중간에 있는 단순한 이미지에서는 잘 작동

하지만 문자가 이미지의 중심에 완벽하게 맞지 않으면 전혀 동작하지 않음

그 이유는 우리 neural이 '8'이 완벽하게 중심에 있는 패턴만을 배웠기 때문... '8'이 중심에서 벗어난 것이 무엇인지 전혀 알 수 없음. 단지 하나의 패턴만 알고 있음

이런 것은 현실세계에서 무쓸모. 현실세계의 문제는 결코 명확하고 단순하지 않음. 따라서 우리는 '8'이 완벽하게 중심에 있지 않은 경우에도 neural을 동작시킬 방법을 알아내야 함

무차별 대입(Brute Force) 아이디어 #1 : 슬라이딩 윈도우(Sliding Window)로 찾기

우리는 이미 이미지의 중앙에 위치한 '8'을 찾을 수 있는 프로그램을 만듬

그렇다면 이미지를 작은 섹션으로 나누어 '8'을 찾을 때까지 한번에 한 섹션씩 모두 스캔하는 방법은?

→ 이 접근 방식을 슬라이딩 윈도우(sliding window)라고 함

- 또한 이것은 무차별 대입(brute force) 솔루션

- 일부 제한된 경우에는 잘 동작하지만 실제로는 매우 비효율적. 다양한 크기의 객체를 찾기 위해 같은 이미지를 계속해서 확인해야 하기 때문

무차별 대입(Brute Force) 아이디어 # 2 : 더 많은 데이터와 딥 신경망(Deep Neural Net)

이미지 안에 여러 크기의 다른 위치에 있는 '8'에 대한 더 많은 데이터로 훈련시키는 것은 어떨까?

- 이를 위해 새로운 훈련 데이터를 수집할 필요 없이 스크립트를 작성해 이미지내의 여러 다른 위치에 있는 '8' 이미지를 생성하면 됨

- 이미 가지고 있는 훈련 이미지의 다른 버전을 만들어 합성 훈련 데이터(Synthetic Training Data)를 만듬

- 이러한 테크닉을 통해 우리는 훈련 데이터를 무한정 공급 가능

- 데이터가 많을수록 당연히 neural이 해결하기가 어려워짐. 하지만 네트워크를 더 크게 만들어 더 복잡한 패턴을 배울 수 있도록 함으로써 이를 보완할 수 있음

- 신경망을 크게 만들기 위해서 단지 노드의 레이어를 중첩하면 됨

- 전통적인 신경망(traditional neural network)보다 더 많은 계층(layers)을 가지고 있기 때문에 우리는 이것을 "딥 신경망(deep neural network)"이라고 부름

- 이 아이디어는 1960년대 말부터 있었지만 최근까지도 이러한 대규모 neural을 훈련하는 것은 너무 느렸음

- 그리나 일반적인 컴퓨터 프로세서 대신에 (매트릭스 곱셈을 정말 빠르게 하기 위해 고안된) 3D 그래픽 카드를 사용하는 방법을 알게 되면서 대규모 neural으로 작업하는 것이 갑자기 실용적이 되었음

- 실제로 오버워치를 플레이할 때 사용하는 것과 완전하게 동일한 NVIDIA GeForce GTX 1080 그래픽 카드를 사용해 neural을 매우 빠르게 훈련시키는 것이 가능

- 그러나 이것이 솔루션이 되는 것이 아님

- 두 가지 경우가 완전히 다른 객체라고 보고 그림의 위쪽에 있는 '8'을 인식하도록 neural을 훈련시키는 것과 아래쪽에 있는 '8'을 별도로 인식하도록 훈련시키는 것은 말이 되지 않음

- '8'이 어느 위치에 있더라도 추가적인 훈련 없이 같은 것이라고 인식할 만큼 현명한 neural을 만들 방법은..?

그 해결책이 바로 컨볼루션(Convolution) 입니다

인간인 우리는 사진에 계층 구조 또는 개념 구조(hierarchy or conceptual structure)이 있음을 직관적으로 알 수 있음

원작자의 아드님 사진.. 귀엽다

인간으로서 우리는 이 그림에서 계층구조를 즉시 인식

땅은 잔디와 콘크리트로 덮혀 있음

한 아이가 있음

이 아이는 bouncy horse에 앉아 있음

bouncy horse는 잔디 위에 있음

- 가장 중요한 것은, 우리는 아이가 어떤 면(surface) 위에 있더라도 아이라는 개념을 인식할 수 있음. 우리는 아이가 나타날 수 있는 모든 가능한 면(surface)에 대해서 아이라는 개념의 인식을 다시 배울 필요는 없음

*surface : 계층 구조의 하나의 계층 또는 레이어 의미

그러나 당장 우리의 neural은 이런 일을 할 수 없음

- 현재는 이미지의 다른 부분에 있는 '8'을 서로 완전히 다른 것이라 인식, 가능한 모든 위치에서 각 객체를 식별하는 것을 모두 다시 학습해야 한다는 뜻

- 우리는 '8'이 그림에서 어디에 나타나더라도 '8'이라는 이동 불변성(translation invariance)을 우리의 신경망이 이해하도록 해야 함

- 컨볼루션(Convolution)이라 부르는 프로세스를 사용해 이 작업을 수행할 것

- 컨볼루션은 컴퓨터 과학과 생물학에서 부분적으로 영감을 받은 아이디어

컨볼루션(Convolution)의 동작 방식

우리의 신경망에 전체 이미지를 한 개의 그리드로써 전체 이미지를 공급하는 대신에, 객체는 그림의 어디에서 나타나더라도 동일한 것이라는 아이디어를 활용해서 훨씬 더 똑똑한 방법을 사용할 것

Step 1: 이미지를 중첩된 이미지 타일들로 나누기

앞선 슬라이딩 윈도우 검색과 유사하게, 원본 이미지 전체에 슬라이딩 윈도우를 적용해서 각 결과를 별도의 작은 그림 타일로 저장

이렇게 해서, 원본 이미지를 동일한 크기의 작은 이미지 타일 77개로 변환

Step 2: 각 이미지 타일을 작은 신경망에 제공(feed)하기

앞서 우리는 '8'인지 확인하기 위해 하나의 이미지를 신경망에 제공

여기서도 똑같은 작업을 할 것임. 다만 각 개별 이미지 타일에 대해 이 작업을 수행할 것

한번에 한개의 타일에 대해 77번 반복

하지만 한 가지 중요한 변화가 있음 : 우리는 동일한 원본 이미지의 모든 단일 타일에 대해 동일한 신경망 가중치(same neural network weights)를 유지할 것

- 다시 말해서, 모든 이미지 타일을 동일하게 취급

- 어떤 타일에 무엇인가 흥미로운 것이 나타나면, 그 타일을 흥미있는 것이라고 표시할 것

Step 3: 각 타일에 대한 결가를 새로운 배열에 저장하기

원본 타일의 배열 형태를 버리고 싶지는 않음. 따라서 각 타일을 처리한 결과를 원본 이미지에 대한 동일한 배열 형태로 그리드에 저장

다시 말해서, 하나의 큰 이미지로 시작해서 원래 이미지의 어느 부분이 가장 흥미로운지를 기록한 조금 크기가 작아진 배열을 얻게 됨

Step 4: 시료 채취하기

Step 3의 원본 이미지의 어느 부분이 흥미로운지를 나타내는 배열을 얻은 것. 그러나 이 배열도 여전히 너무 큼

- 배열의 크기를 줄이기 위해서 맥스-풀링(max pooling)이라는 알고리즘을 사용해 시료 채취

우리는 결과 배열을 2x2 정사각형으로 나누어 각각에서 가장 큰 숫자만을 취합

- 각 2x2 사각형 격자(square grid)를 구성하는 4개의 입력 타일에서 흥미로운 것을 찾으면, 가장 흥미로운 것도 유지할 수 있다는 것

- 이를 통해 가장 중요한 부분을 유지하면서도 배열의 크기를 줄일 수 있음

마지막 Step: 예측하기

지금까지 커다란 이미지의 크기를 상당히 작은 배열로 줄임

- 이 배열은 결국 숫자들의 집합일 뿐. 따라서 이제 우리는 이 작은 배열을 다른 신경망에 제공할 입력으로 사용할 수 있을 것

- 최종신경망이 이미지가 일치하는지 또는 일치하지 않는지를 결정해줄 것. 앞선 컨볼루션 단계(Step)들과 구분하기 위해 이를 완전히 연결된 망(fully connected network)라 부르겠음!

정리하자면, 시작에서부터 끝까지 전체 5단계의 경로(popeline)는 다음과 같음

더 많은 단계를 추가하기

우리의 이미지 처리 경로(popeline)는 다음고 같은 일련의 단계들로 이루어짐: 컨볼루션(convolution) 맥스-풀링(max-pooling), 그리고 마지막 완전히 연결된 망(fully-connected network)

- 현실 세계의 문제를 해결할 때는 이러한 단계를 원하는만큼 많이 조합하고 반복할 수 있음!

- 2개, 3개 또는 심지어 10개의 컨볼루션 레이어를 가질 수 있음

- 데이터의 크기를 줄이고 싶다면 어느 단계에서나 max-pooling을 실행하면 됨

- 기본 아이디어는 큰 이미지로 시작해서 마지막으로 하나의 결과가 나올 때까지 단계적으로 반복해서 데이터를 압축해 가는 것

- 더 많은 컨볼루션 단계를 가져갈수록, 당신의 신경망은 학습을 통해 더욱 복잡한 형상을 인식할 수 있음

- ex) 첫 번째 컨볼루션 단계에서는 날카로운 모서리를 인식하는 법을 배울 수 있고, 두 번째 컨볼루션 단계에서는 이 날카로운 모서리에 대한 지식을 사용해서 부리를 인식할 수 있으며 세 번째 단계에서는 부리에 대한 지식 등을 사용해서 전체 새를 인식할 수도 있을 것

딥 컨볼루션 망

- 위 그림은 224x224 픽셀 이미지에서 시작해서 컨볼루션과 맥스 풀링을 두번 적용한 다음 컨볼루션을 추가로 3번 더 적용, 그리고 다시 맥스 풀링을 적용한 다음 두 번의 완전히 연결된 망의 단계(layers)를 적용

- 최종 결과는 이미지가 1000개의 범주 중 하나로 분류되는 것

정확한 신경망 구축하기

그런데 이미지 분류기(image classifier)가 잘 동작할 수 있도록 어떤 단계들을 결합해야 하는지 어떻게 알 수 있을까요?

→ 많은 실험과 테스트를 통해서만 답을 얻을 수 있음. 해결하려는 문제에 대한 최적의 구조와 매개 변수를 찾기까지 어쩌면 100개의 신경망을 훈련시켜야 할 수도 있음. Machine Learning에는 많은 시행 착오가 뒤따름

새 분류기 만들기

이제 우리는 사진이 새인지 아닌지를 결정할 수 있는 프로그램을 작성할 수 있음

항상 그렇듯이 시작하기 위해서는 데이터가 필요. 무료 CIFAR10 데이터 세트에는 6,000장의 새 사진과 52,000장의 새가 아닌 사진이 포함되어 있음. 그러나 더 많은 데이터를 얻기 위해 12,000장의 새 사진이 있는 Caltech-UCSD Birds-200-2011 데이터 세트도 추가할 것

합친 데이터 세트에 있는 새들 사진 중 일부:

52,000장의 새가 아닌 사진 중 일부:

이 데이터 세트는 우리의 목적에 맞게 잘 동작하겠지만, 72,000개의 저해상도 이미지는 현실 세계의 애플리케이션에 사용하기에는 여전히 작은 데이터. Google 수준의 성능을 원한다면 수백만 개의 고해상도 이미지가 필요. Machine Learning에서 더 나은 알고리즘을 사용하는 것보다 더 많은 데이터를 보유하는 것이 언제나 더 중요. 이는 현재 Google이 무제한 사진 저장 용량을 제공하는 이유

새 분류기를 만들기 위해 TFLearn을 사용

- TFlearn은 단순화 된 API를 제공하는 Google의 TransorFlow 딥러닝 라이브러리의 래퍼(wrapper)

- 이를 이용하면 신경망 계층을 정의하는데 단 몇 줄의 코드만 작성하면 되는 수준으로 컨볼루션 신경망을 위한 네트워크 작성을 쉽게 할 수 있음

신경망을 정의하고 훈련시키기 위한 코드:

# -*- coding: utf-8 -*- """ Based on the tflearn example located here: https://github.com/tflearn/tflearn/blob/master/examples/images/convnet_cifar10.py """ from __future__ import division, print_function, absolute_import # Import tflearn and some helpers import tflearn from tflearn.data_utils import shuffle from tflearn.layers.core import input_data, dropout, fully_connected from tflearn.layers.conv import conv_2d, max_pool_2d from tflearn.layers.estimator import regression from tflearn.data_preprocessing import ImagePreprocessing from tflearn.data_augmentation import ImageAugmentation import pickle # Load the data set X, Y, X_test, Y_test = pickle.load(open("full_dataset.pkl", "rb")) # Shuffle the data X, Y = shuffle(X, Y) # Make sure the data is normalized img_prep = ImagePreprocessing() img_prep.add_featurewise_zero_center() img_prep.add_featurewise_stdnorm() # Create extra synthetic training data by flipping, rotating and blurring the # images on our data set. img_aug = ImageAugmentation() img_aug.add_random_flip_leftright() img_aug.add_random_rotation(max_angle=25.) img_aug.add_random_blur(sigma_max=3.) # Define our network architecture: # Input is a 32x32 image with 3 color channels (red, green and blue) network = input_data(shape=[None, 32, 32, 3], data_preprocessing=img_prep, data_augmentation=img_aug) # Step 1: Convolution network = conv_2d(network, 32, 3, activation='relu') # Step 2: Max pooling network = max_pool_2d(network, 2) # Step 3: Convolution again network = conv_2d(network, 64, 3, activation='relu') # Step 4: Convolution yet again network = conv_2d(network, 64, 3, activation='relu') # Step 5: Max pooling again network = max_pool_2d(network, 2) # Step 6: Fully-connected 512 node neural network network = fully_connected(network, 512, activation='relu') # Step 7: Dropout - throw away some data randomly during training to prevent over-fitting network = dropout(network, 0.5) # Step 8: Fully-connected neural network with two outputs (0=isn't a bird, 1=is a bird) to make the final prediction network = fully_connected(network, 2, activation='softmax') # Tell tflearn how we want to train the network network = regression(network, optimizer='adam', loss='categorical_crossentropy', learning_rate=0.001) # Wrap the network in a model object model = tflearn.DNN(network, tensorboard_verbose=0, checkpoint_path='bird-classifier.tfl.ckpt') # Train it! We'll do 100 training passes and monitor it as it goes. model.fit(X, Y, n_epoch=100, shuffle=True, validation_set=(X_test, Y_test), show_metric=True, batch_size=96, snapshot_epoch=True, run_id='bird-classifier') # Save model when training is complete to a file model.save("bird-classifier.tfl") print("Network trained and saved as bird-classifier.tfl!")

- Nvidia GeForce GTX 980 Ti 또는 그 상위 제품과 같이 충분한 RAM을 갖춘 좋은 그래픽 카드로 훈련시키면, 1시간 이내에 훈련을 완료할 수 있음

- 훈련을 시킬수록 정확도는 높아짐. 첫 번째 훈련 후에 75.4%의 정확도를 얻었음

- 단 10회 훈련한 후 이미 91.7%까지 올라감

- 50회 정도 지나면 95.5%의 정확도에 이르렀고, 추가 훈련을 도움이 되지 않았기 때문에 멈춤

- 이제 우리의 프로그램은 이미지에서 새를 식별할 수 있음!

Neural 테스트하기

이제 우리는 훈련된 neural을 만들었고 바로 사용할 수 있음! 하나의 이미지 파일이 새인지 아닌지를 예ㅡㄱ하는 간단한 스크립트 확인

- 그러나 우리 neural이 얼마나 효과적인지를 실제로 확인하기 위해서는 아주 많은 이미지로 테스트해야 함

- 유효성 검사를 위해 15,000개의 이미지를 포함한 데이터 세트를 만듬, 우리의 neural에 이 15,000개의 이미지를 실행해보니, 95% 수준으로 정확한 대답 예측

정확도 95%는 얼마나 정확한 것일까?

- 우리의 neural은 95% 정확하다고 할 수 있음 그런데 95%라는 것은 다른 의미로 볼 수도 있음

만약 훈련 이미지의 5%가 새이고 나머지 95%가 새가 아닌 경우 어떻게 될까?

- 매번 "새가 아니다"라고 추측하는 프로그램이 있다면 이것은 95% 정확한 것이 됨

- 그러나 이것은 100% 쓸모 X

- 평균적인 정확도보다 숫자를 좀 더 자세히 들여다 볼 필요가 있음.

- 분류 시스템이 실제로 얼마나 좋은지 판단하기 위해서, 우리는 실패한 시간의 비율이 아니라 어떻게 실패했는지를 면밀히 조사해야 함

우리의 예측을 "맞다"와 "틀리다"로 생각하는 대신, 다음의 네 가지 범주로 나누어 봄

1) True Positives : 우리의 neural이 올바르게 식별한 새들 사진

2) True Negatives : "새가 아니다"라고 올바르게 식별한 이미지들

3) False Positives : 새라고 생각했지만 실제 새가 아닌 이미지들

4) False Negatives : 정확하게 새로 인식하지 못한 이미지들

15,000개 이미지의 유효성 검사 세트를 사용해서, 우리의 예측이 각 카테고리별로 어떻게 분류되는지 알아봄

왜 결과를 이런 식으로 세분화해야 할까?

→ 모든 실수가 같은 원인으로 발생하지 않기 때문

- ex) MRI 이미지로부터 암을 찾아내는 프로그램을 작성했다고 상상, 우리가 암을 찾아낸 경우에 false negatives보다 false positives가 더 나음

평균적인 정확도를 보는 대신 Precision과 Recall 계산

- 위 결과는 우리가 97% 정확도로 "새"를 추측했음을 보여줌

- 그러나 데이터 세트에서 실제 새의 90%만 발견했다는 사실도 알 수 있음, 바꿔 말하자면 우리는 모든 새를 발견하지 못할 수도 있지만, 발견했을 때는 꽤 확실하게 맞출 수 있음

from http://kwonjeong.tistory.com/13 by ccl(A) rewrite - 2021-09-09 17:26:14