2019년 5월 18일 토요일

구글 코랩(Colab)으로 딥러닝 해 보기

최근, 사내 핸즈온 행사로 IoT로 딥러닝하기를 하면서 많은 사람들이 환경 설정으로 애를 먹는 상황을 경험해 보았다. 딥러닝 환경을 구축은 여러가지 방법이 있다.

1. 우분투 기반
2. 아나콘다 기반
3. 도커 이미지 기반
4. 아마존 웹 서비스 기반

물론, 아래로 갈 수록 설치할 필요가 없고 쉬워진다.

이날 핸즈온은 도커로 미리 준비된 keras-full 로 진행한 것이었는 데, 문제는 연구원의 공식 컴퓨터 실임에도 불구하고 열악해 빠진 사내 방화벽, 무선, 인터넷 환경이 이었다(이건 직접 경험해 보지 않으면 상상 되지 않을 것이다). 도커부터 이미지 설치까지 미리 공지했었으나, 이 상황에서 평소에도 매우 바쁘신 분들이 열정만 갖고 오셔서 다운로드 하시려 함. 결국 본의아니게 시켜 좌절 경험시켜 드려 마음 한켠 짐이 생겨 버렸다.

이런 말도 안되는 환경에서 설치한다는 것은 네트워크 전문가 십만명이 와도 불가능한 것이다.

잠깐 머리에 스쳐간 4번 카드는 제일 편하지만, 개인적으로 AWS 옵션이 켜져 몇 달동안 계속 돌아가는 바람에 계정에 락이 걸려 버렸다(아마존 나쁘다).

그래서, 구글신에게 물어보기로 함.

공짜로 딥러닝 라이브러리 설치 않하고 사용할 수 있는 방법은 없나요?

구글신이 말씀하시길 코랩이 공짜고 AWS보다 좋다 하여, 당장 시작해보았다.

코랩은 colaboratory의 약자로 구글에서 제공하는 클라우드 기반 개발 도구이다. 쥬피터 노트북과 매우 비슷하다. 아래 링크를 클릭하면 바로 경험해 볼 수 있다.


여기서 나타나는 창의 메뉴 중 새 PYTHON 3 노트 메뉴를 클릭해 소스파일을 하나 생성해 본다.

모든 라이브러리가 설치되어 있지 않겠지 싶어, 그리 기대하지 않고 LSTM 코드(링크) 입력하고 돌렸음. 너무 과했나 싶었는 데, 어~ 잘 돌아가네.
아무 문제 없이 돌아간 LSTM

구글 드라이브와 연동되는 코랩


게다가 구글 드라이브와 연동되어 소스코드도 자동 저장해 준다. 클라우드 서버 랩 12기가, 디스크 50기가도 공짜다 (감동의 물결 T.T~).

물론, 이 공간도 다 차면 AWS처럼 돈 달라 하겠지만, 일단 딥러닝 핸즈온 강의할 때 환경 설정 개고생 안해도 된다. 참고로, 코랩은 미리 만들어 놓은 개발 튜토리얼과 영상을 제공한다(정말 인자하시다).

사람이란 간사하다. 얼마전까지 내 PC에서 딥러닝 환경 만들어야 그것들(G사, A사 포함)에 종속되지 않는다고 떠들어 댔건만.. 구글신 고마워요.


2019년 4월 20일 토요일

2019년 4월 17일 수요일

Docker 윈도우 방화벽 문제

Docker 윈도우 방화벽 문제 해결과 관련된 몇몇 검색한 링크 남긴다. 이 경우 이미지가 다운로드 되지 않는다.
보통 이런 문제는 방화벽이 철저한 회사나 기관에서 도커 사용할 때 발생한다.
참고로 좋은 도커 설치 영상이 있어 링크를 남긴다.
도커 설치

2019년 4월 2일 화요일

ABB 로봇 제어하기

이 글은 ABB 로봇 제어하는 기본 명령어와 기능을 간략히 정리한다.

ABB는 산업용 로봇으로 C언어와 유사한 개발언어로 로봇을 제어할 수 있다.
개발은 로봇 스튜디오 프로그램이나 비쥬얼 스튜디오 같은 개발 도구로 코딩할 수 있다.
로봇 스튜디오는 특히 시뮬레이션이 가능해서, 코딩된 프로그램을 미리 3차원 공간에서 테스트할 수 있다.

로봇 스튜디오 클랩프 시뮬레이션 모습(Clamp Claw Vacuum)

코드를 직접 다음 처럼 생긴 펜던트로 터치해서 입력하는 방법도 있으나 매우 불편하다. 보통, 코딩된 프로그램을 USB로 담아서 ABB 로봇암을 제어하는 컴퓨터에 전송한 후에 로봇을 동작시킨다. 
로봇암 제어 모습

다음 사이트에서 다양한 개발 예제와 SDK(Software Development Kit)를 다운로드할 수 있다. 

프로그래밍을 하지 않고 로봇암을 제어하기 위해서는 라이노에서 실행되는 그래스호퍼 애드인이 필요하다. 여기에 다음과 같은 HAL 을 설치하면, 라이노에 그려진 툴패스를 따라서 로봇암이 제어된다. 

2019년 2월 9일 토요일

간단한 도커 기반 케라스 LSTM 딥러닝 모델 학습 및 데이터 예측

이 글은 도커를 기반으로 케라스를 이용한 LSTM 학습 및 예측 방법을 간단히 따라해 보고, 사용방법과 코드를 익힙니다. 작년 가을부터 쌓여있던 연구행정일 어느 정도 정리되어, 쌓아 둔 글들 중 케라스 기반 LSTM과 관련 내용들을 하나씩 정리하도록 하겠습니다. 딥러닝 모델에 대한 내용은 아래 링크 참고 바랍니다.

머리말
텐서플로우, 케라스를 사용하는 방법은 크게 다음과 같습니다.
  1. 텐서플로우 및 케라스 직접 설치, 사용
  2. 아나콘다 설치 후 텐서플로우 및 케라스 설치, 사용
  3. AWS와 같은 클라우드 기반 미리 설치된 텐서플로우, 케라스 설치 및 사용
각각이 장단점 있죠.

우선, 1, 2번 같은 경우, 직접 본인 컴퓨터에서 설치부터 시작해 사용까지 경험해 본다는 측면에서 공부하기 좋으나, 수많은 관련 라이브러리 버전 의존성을 맞춰주고, 하나가 업데이트되면 다른 라이브러리 의존성이 깨져 재설치해야 하는 등 번거로움이 많은 방법입니다.

3번 같은 경우, 클라우드 제공 사이트에 회원 가입 후 몇몇 설정 클릭질만 해 주면 쉽게 사용할 수 있으나, 왠지 내공있어야 하는 일들은 남이 대신 해 주는 것 같고, 사용량이 많아지면, 업체에서 과금을 할 것이기 때문에 번거로운 점이 있습니다.

딥러닝 라이브러리 사용 편의성과 과금을 피해가는 방법 중 하나가 이 글에서 제안하는 도커를 이용한 딥러닝 라이브러리 사용 방법입니다.

도커는 사전 설치된 이미지가 있으면 다운로드 받아 컨테이너에 실행하면 되므로, 라이브러리 종속성 문제나 과금에 자유롭죠. 다만, 수많은 이미지 중 안정적인 버전을 찾기가 쉽지 않은 문제가 있습니다.

이 글에서는 Kitematic 을 사용해 딥러닝 라이브러리 설치된 이미지를 검색하고, 이를 사용해 LSTM을 실행해 보도록 하겠습니다. 도커에 대한 설명은 아래 링크 참고 바랍니다.

Kitematic 이용한 도커 딥러닝 라이브러리 이미지 설치
Kitematic은 도커 이미지 원클릭 설치를 제공한다. 그래픽 사용자 인터페이스 (GUI)에서 앱 컨테이너를 제어할 수 있어 매우 편리하다. Kitematic은 다음 링크에서 다운로드 받을 수 있다.
Kitematic (2019년 4월 도커 버전과 Kitematic 버전이 서로 문제를 일으켜서, 도커 이미지 다운로드 안되는 현상있음. 이 경우, https://github.com/docker/kitematic/releases 에서 Kitematic 0.17.3 버전을 다운로드 받아 실행해 볼것)

Kitematic 사이트에서 프로그램을 다운로드 설치한 후 실행하면 다음과 같이 도커 이미지를 검색할 수 있다. 본인은 keras로 검색하였다. 
keras 검색 결과(Kitematic)

이 글에서는 keras-full 이미지를 설치해 사용한다. 참고로, 다른 이미지들은 jupyter notebook이 안되거나, 몇몇 keras 관련 라이브러리가 설치되어 있지 않아, 이 글의 LSTM 예제를 따라하기 어렵다.

keras-full 이미지 설치는 매우 간단해, 'CREATE'버튼을 클릭하면 된다. 이후, 이미지를 다운로드하고, 도커 컨테이너에 설치하는 과정은 자동적으로 진행된다. 

설치 후 keras-full 이미지는 왼쪽 컬럼에 표시된다. 해당 이미지를 선택하고, 상단의 start 툴바 버튼을 클릭하면 실행된다. 웹이 지원되는 이미지는 WEB PREVIEW 탭이 다음 그림과 같이 보여진다. 이 탭의 문서 툴바 버튼을 클릭하면 쥬피터 노트북이 실행될 것이다. 

케라스 기반 LSTM 사용하기 
쥬피터 노트북 실행되면, 암호를 묻는다. 이 이미지의 노트북 암호는 'keras'이다.

입력 후 로긴하면 다음과 같은 창을 볼 수 있다.

여기서, New 버튼을 이용해 python3 소스 파일을 하나 만들어 본다.

실습할 LSTM 소스코드는 keras에서 실행된다. 이 코드는 여객기 탑승자 수를 날짜별로 저장한 스프레드시트 파일을 읽어, 딥러닝 모델 학습한 후 예측 모델을 만든다. 그리고, 예측 모델과 실제 값을 비교한 결과를 그래프로 출력한다.

다음 LSTM 소스코드를 복사해 붙여넣기를 한다. 참고로, 이 소스코드 내용은 Machine Learning Mastery LSTM 링크를 방문하면 좀 더 상세한 설명을 확인할 수 있다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# LSTM for international airline passengers problem with regression framing
import numpy
import matplotlib.pyplot as plt
from pandas import read_csv
import math
from keras.models import Sequential
from keras.layers import Dense
from keras.layers import LSTM
from sklearn.preprocessing import MinMaxScaler
from sklearn.metrics import mean_squared_error
# convert an array of values into a dataset matrix
def create_dataset(dataset, look_back=1):
 dataX, dataY = [], []
 for i in range(len(dataset)-look_back-1):
  a = dataset[i:(i+look_back), 0]
  dataX.append(a)
  dataY.append(dataset[i + look_back, 0])
 return numpy.array(dataX), numpy.array(dataY)
# fix random seed for reproducibility
numpy.random.seed(7)
# load the dataset
dataframe = read_csv('international-airline-passengers.csv', usecols=[1], engine='python', skipfooter=3)
dataset = dataframe.values
dataset = dataset.astype('float32')
# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)
# split into train and test sets
train_size = int(len(dataset) * 0.67)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
# reshape into X=t and Y=t+1
look_back = 1
trainX, trainY = create_dataset(train, look_back)
testX, testY = create_dataset(test, look_back)
# reshape input to be [samples, time steps, features]
trainX = numpy.reshape(trainX, (trainX.shape[0], 1, trainX.shape[1]))
testX = numpy.reshape(testX, (testX.shape[0], 1, testX.shape[1]))
# create and fit the LSTM network
model = Sequential()
model.add(LSTM(4, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=1, verbose=2)
# make predictions
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
# calculate root mean squared error
trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))
# shift train predictions for plotting
trainPredictPlot = numpy.empty_like(dataset)
trainPredictPlot[:, :] = numpy.nan
trainPredictPlot[look_back:len(trainPredict)+look_back, :] = trainPredict
# shift test predictions for plotting
testPredictPlot = numpy.empty_like(dataset)
testPredictPlot[:, :] = numpy.nan
testPredictPlot[len(trainPredict)+(look_back*2)+1:len(dataset)-1, :] = testPredict
# plot baseline and predictions
plt.plot(scaler.inverse_transform(dataset))
plt.plot(trainPredictPlot)
plt.plot(testPredictPlot)
plt.show()

이 코드를 실행하기 위해서는 아래 링크에서 비행기 탑승자 수 CSV(,) 데이터파일을 미리 소스코드 폴더에 다운로드해 넣어야 한다.


이 데이터셋에서 67%는 훈련용, 나머지 33%는 테스트 검증용으로 사용한다.
LSTM 소스코드를 쥬피터 노트북에서 실행한 결과는 다음과 같다.

...
LSTM 학습 및 테스트 결과 그래프(청색: 원본 데이터, 적색: 훈련 데이터, 녹색: 테스트 예측 데이터)

결과 그래프에서 보여지는 것처럼, LSTM은 원본 데이터와 유사한 패턴으로, 향후 데이터를 예측해 내는 것을 확인할 수 있다.

소스코드 설명
이 코드는 LSTM 모델을 이용해 시퀀스로 배열된 시계열 데이터를 예측하는 것이다. 이런 기법은 다양한 분야에 사용될 수 있다. 주요 코드만 확인해 본다.

다음은 데이터셋을 로딩하는 코드이다.
# load the dataset
dataframe = pandas.read_csv('international-airline-passengers.csv', usecols=[1], engine='python', skipfooter=3)
dataset = dataframe.values
dataset = dataset.astype('float32')

이후 0에서 1 값으로 데이터를 정규화한다.
# normalize the dataset
scaler = MinMaxScaler(feature_range=(0, 1))
dataset = scaler.fit_transform(dataset)

데이터세트에서 67%는 훈련용, 33%는 테스트용으로 분리한다.
# split into train and test sets
train_size = int(len(dataset) * 0.67)
test_size = len(dataset) - train_size
train, test = dataset[0:train_size,:], dataset[train_size:len(dataset),:]
print(len(train), len(test))

LSTM 모델 입력은 현재 주어진 시간(T) 승객수이며, 출력 Y는 다음 시간(T + 1)의 승객수가 되도록 한다. 이 배열을 numpy.array 형 dataX, dataY로 리턴하는 함수를 만든다.
# convert an array of values into a dataset matrix
def create_dataset(dataset, look_back=1):
dataX, dataY = [], []
for i in range(len(dataset)-look_back-1):
a = dataset[i:(i+look_back), 0]
dataX.append(a)
dataY.append(dataset[i + look_back, 0])
return numpy.array(dataX), numpy.array(dataY)

참고로, 이 함수를 호출하면 다음과 같이, 첫번째 데이터의 Y는 두번째 데이터의 X가 된다.
X Y
112 118
118 132
132 129
129 121
121 135

이제, 입력 데이터셋을 LSTM 모델 학습에 맞게 행렬 모양으로 변환하고, LSTM 시퀀스 모델을 생성해, trainX, trainY 데이터를 입력한다.
# create and fit the LSTM network
model = Sequential()
model.add(LSTM(4, input_shape=(1, look_back)))
model.add(Dense(1))
model.compile(loss='mean_squared_error', optimizer='adam')
model.fit(trainX, trainY, epochs=100, batch_size=1, verbose=2)

다음 코드를 이용해 학습된 모델을 예측한 출력값을 얻는다. 그리고, 원본 데이터 trainY와 훈련용 데이터셋 예측값 trainPredict, 테스트용 데이터 예측값 testPredict 편차를 RMSE로 확인한다. 참고로, 본인 컴퓨터에서는 각각 RMSE가 22.92, 47.53 이었다.
# make predictions
trainPredict = model.predict(trainX)
testPredict = model.predict(testX)
# invert predictions
trainPredict = scaler.inverse_transform(trainPredict)
trainY = scaler.inverse_transform([trainY])
testPredict = scaler.inverse_transform(testPredict)
testY = scaler.inverse_transform([testY])
# calculate root mean squared error
trainScore = math.sqrt(mean_squared_error(trainY[0], trainPredict[:,0]))
print('Train Score: %.2f RMSE' % (trainScore))
testScore = math.sqrt(mean_squared_error(testY[0], testPredict[:,0]))
print('Test Score: %.2f RMSE' % (testScore))

나머지 코드는 원본 데이터, 학습 데이터, 테스트 데이터를 그래프로 출력하는 코드이다.

마무리
이 글은 좀 더 간편한 방식으로 딥러닝 모델을 학습하고 테스트할 수 있는 도커 이미지를 이용해, 간단한 LSTM 모델을 케라스 기반으로 실행해 보았다. 도커를 이용하면, 라이브러리 종속성 문제로 삽질할 필요 없이, 딥러닝 모델 개발 본연의 목적에만 집중할 수 있고, 사용량이 많아지면 과금되는 클라우드 플랫폼을 사용할 필요도 없다.

참고로 설명한 LSTM코드는 매우 일반적인 패턴 학습 모델이므로, 약간만 수정하면, 다양한 예측 모델에 사용할 수 있다.

레퍼런스

2019년 2월 2일 토요일

인공지능 기반 미디어아트

이 글은 인공지능 기반 미디어아트 기술, 동향 및 사례에 대해 정리한 슬라이드를 공유합니다.

이 슬라이드는 딥러닝부터 시작해, 관련 다양한 오픈소스 도구를 보여줍니다. 아울러, 딥러닝을 몰라도 간단히 사용할 수 있는 서비스 제공 웹사이트를 나열하고, 해외 최신 인공지능 기반 미디어아트 사례들을 공유합니다.






2019년 1월 6일 일요일

라즈베리파이 기반 딥러닝 객체 인식 개발 방법

이 글은 어느 분이 블로그로 문의한 내용도 정리할 겸 라즈베리파이 기반 딥러닝 객체 인식 개발 방법에 대한 내용을 간단히 요약해 공유한다.


사실, 이와 관련된 자료는 구글링을 하면 꽤 많이 검색된다. 참고로, OpenCV를 이용해 파이썬 기반에서 객체를 인식하는 방법도 유용하다.

머리말
비전에서 객체 인식이란 다음과 같이 특정 이미지에서 원하는 객체 종류, 위치와 크기를 얻는 것이다.
객체 인식은 다음과 같이 다양한 분야에서 사용된다.

객체 인식에서 유명한 방법인 YOLO는 매우 빠른 방식으로 객체 탐색을 할 수 있다.

YOLO 알고리즘을 간단히 설명하면 다음과 같다.

image = readImage()
cells = 검색 셀 범위 설정
index = 0
for cell in cells
   maxPrediction = 0.0
   for region in cell.region
      cell_image = image.getRegionImage(region)
      prediction[index] = prediction(cell_image)
      if(maxPrediction < prediction[index])
         maxPrediction = prediction[index]
         region = cell.grow(region)
      else
         index++
         break   

의사코드는 다음과 같다.


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
#this is an Image of size 140x140. We will assume it to be black and white (ie only one channel, it would have been 140x140x3 for rgb)
image = readImage()

#We will break the Image into 7 coloumns and 7 rows and process each of the 49 different parts independently
NoOfCells = 7

#we will try and predict if an image is a dog, cat, cow or wolf. Therfore the number of classes is 4
NoOfClasses = 4
threshold = 0.7

#step will be the size of step to take when moving across the image. Since the image has 7 cells step will be 140/7 = 20
step = height(image)/NoOfCells

#stores the class for each of the 49 cells, each cell will have 4 values which correspond to the probability of a cell being 1 of the 4 classes
#prediction_class_array[i,j] is a vector of size 4 which would look like [0.5 #cat, 0.3 #dog, 0.1 #wolf, 0.2 #cow]
prediction_class_array = new_array(size(NoOfCells,NoOfCells,NoOfClasses))

#stores 2 bounding box suggestions for each of the 49 cells, each cell will have 2 bounding boxes, with each bounding box having x, y, w ,h and c predictions. (x,y) are the coordinates of the center of the box, (w,h) are it's height and width and c is it's confidence
predictions_bounding_box_array = new_array(size(NoOfCells,NoOfCells,NoOfCells,NoOfCells))

#it's a blank array in which we will add the final list of predictions
final_predictions = []

#minimum confidence level we require to make a prediction
threshold = 0.7

for (i<0; i<NoOfCells; i=i+1):
 for (j<0; j<NoOfCells;j=j+1):
  #we will get each "cell" of size 20x20, 140(image height)/7(no of rows)=20 (step) (size of each cell)"
  #each cell will be of size (step, step)
  cell = image(i:i+step,j:j+step) 

  #we will first make a prediction on each cell as to what is the probability of it being one of cat, dog, cow, wolf
  #prediction_class_array[i,j] is a vector of size 4 which would look like [0.5 #cat, 0.3 #dog, 0.1 #wolf, 0.2 #cow]
  #sum(prediction_class_array[i,j]) = 1
  #this gives us our preidction as to what each of the different 49 cells are
  #class predictor is a neural network that has 9 convolutional layers that make a final prediction
  prediction_class_array[i,j] = class_predictor(cell)

  #predictions_bounding_box_array is an array of 2 bounding boxes made for each cell
  #size(predictions_bounding_box_array[i,j]) is [2,5]
  #predictions_bounding_box_array[i,j,1] is bounding box1, predictions_bounding_box_array[i,j,2] is bounding box 2
  #predictions_bounding_box_array[i,j,1] has 5 values for the bounding box [x,y,w,h,c]
  #the values are x, y (coordinates of the center of the bounding box) which are whithin the bounding box (values ranging between 0-20 in your case)
  #the values are h, w (height and width of the bounding box) they extend outside the cell and are in the range of [0-140]
  #the value is c a confidence of overlap with an acutal bounding box that should be predicted
  predictions_bounding_box_array[i,j] = bounding_box_predictor(cell)

  #predictions_bounding_box_array[i,j,0, 4] is the confidence value for the first bounding box prediction
  best_bounding_box =  [0 if predictions_bounding_box_array[i,j,0, 4] > predictions_bounding_box_array[i,j,1, 4] else 1]

  # we will get the class which has the highest probability, for [0.5 #cat, 0.3 #dog, 0.1 #wolf, 0.2 #cow], 0.5 is the highest probability corresponding to cat which is at position 0. So index_of_max_value will return 0
  predicted_class = index_of_max_value(prediction_class_array[i,j])

  #we will check if the prediction is above a certain threshold (could be something like 0.7)
  if predictions_bounding_box_array[i,j,best_bounding_box, 4] * max_value(prediction_class_array[i,j]) > threshold:

   #the prediction is an array which has the x,y coordinate of the box, the height and the width
   prediction = [predictions_bounding_box_array[i,j,best_bounding_box, 0:4], predicted_class]

   final_predictions.append(prediction)

print final_predictions

prediction함수는 딥러닝으로 훈련된 모델을 사용한다. 훈련 모델을 얻기위해서는 훈련 데이터를 미리 준비해야 한다. 준비 순서는 다음과 같다.
훈련 데이터 획득
이 단계를 수행하기 위해서는 객체 당 100개 정도 수준의 데이터가 필요하다. 가능한 예측해야할 데이터와 비슷한 자료가 필요하다.

라벨링(labeling) - 주석달기
labelImg와 같은 도구를 이용해 이미지에 테두리 상자를 그리고, 라벨을 달아 놓는다. 사실 딥러닝 소스코드는 그리 어렵지 않은 수준이지만, 라벨링 작업은 매우 노동집약적이고 힘든 작업이다. 딥러닝 소스코드는 사실 이런 데이터가 된다. 

모델학습
보통 GPU가 달린 컴퓨터를 이용해 학습을 시킨다. 이미 CNN과 같이 딥러닝 이미지 인식용 모델은 공개된 것이 많다. 예제도 많으니 이런 것들을 사용해 학습시킨다. 
훈련에 필요한 데이터 량을 줄이는 것도 필요하다. 이와 관련된 링크를 참고한다. 미리 훈련된 모델은 여기서 찾을 수 있다.

혹시, 텐서플로우나 케라스를 설치하지 않았고, 설치하는 데 힘들다면, 다음과 같이 이미 만들어진 도커 이미지를 사용할 수도 있다. 사용방법은 여기를 참고한다.

sudo nvidia-docker run -p 8000:8000 -v `pwd`:data docker.nanonets.com/pi_training -m train -a ssd_mobilenet_v1_coco -e ssd_mobilenet_v1_coco_0 -p '{"batch_size":8,"learning_rate":0.003}' 

학습된 모델 설명은 여기서 얻을 수 있다.

라즈베리파이 딥러닝 실행 속도 개선
딥러닝 모델은 32비트 float 실수형 가중치로 구성된 행렬로 볼 수 있다. 딥러닝 모델 중 유명한 AlexNet은 크기만 거의 200MB이다. 이 행렬을 로딩해 실시간으로 계산한다는 것은 라즈베리파이 같은 임베디드 컴퓨터에서는 쉽지 않다. 

이런 이유로 32비트 float을 양자화해 8비트 정수로 변환시켜 사용한다. 이 결과로 딥러닝 모델 크기는 75%가 줄어든다. 
양자화 셀 스크립트는 다음과 같다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
curl -L "https://storage.googleapis.com/download.tensorflow.org/models/inception_v3_2016_08_28_frozen.pb.tar.gz" |
  tar -C tensorflow/examples/label_image/data -xz
bazel build tensorflow/tools/graph_transforms:transform_graph
bazel-bin/tensorflow/tools/graph_transforms/transform_graph \
--in_graph=tensorflow/examples/label_image/data/inception_v3_2016_08_28_frozen.pb \
  --out_graph=/tmp/quantized_graph.pb \
  --inputs=input \
  --outputs=InceptionV3/Predictions/Reshape_1 \
  --transforms='add_default_attributes strip_unused_nodes(type=float, shape="1,299,299,3")
    remove_nodes(op=Identity, op=CheckNumerics) fold_constants(ignore_errors=true)
    fold_batch_norms fold_old_batch_norms quantize_weights quantize_nodes
    strip_unused_nodes sort_by_execution_order

라즈베리파이 설정
라즈베리파이에 카메라를 설치한다. 

카메라에서 이미지를 가져오는 코드는 다음과 같이 매우 간단하다.

import picamera, os
from PIL import Image, ImageDraw
camera = picamera.PiCamera()
camera.capture('image1.jpg')
os.system("xdg-open image1.jpg")

딥러닝 모델을 다운로드한다.

sudo nvidia-docker run -v `pwd`:data docker.nanonets.com/pi_training -m export -a ssd_mobilenet_v1_coco -e ssd_mobilenet_v1_coco_0 -c /data/0/model.ckpt-8998

라즈베리파이에 텐서플로우와 모델을 설치한다.

1
2
3
4
5
6
7
8
sudo apt-get install libblas-dev liblapack-dev python-dev libatlas-base-dev gfortran python-setuptools libjpeg-dev
sudo pip install Pillow
sudo pip install http://ci.tensorflow.org/view/Nightly/job/nightly-pi-zero/lastSuccessfulBuild/artifact/output-artifacts/tensorflow-1.4.0-cp27-none-any.whl
git clone https://github.com/tensorflow/models.git
sudo apt-get install -y protobuf-compiler
cd models/research/
protoc object_detection/protos/*.proto --python_out=.
export PYTHONPATH=$PYTHONPATH:/home/pi/models/research:/home/pi/models/research/slim

이제 모델을 실행해 이미지에서 객체를 인식해 보자.
python ObjectDetectionPredict.py --model data/0/quantized_graph.pb --labels data/label_map.pbtxt --images /data/image1.jpg /data/image2.jpg

라즈베리파이에서 이미지 인식 성능은 다음과 같다. 예를 들어, raster RCNN은 초당 34.52 예측을 할 수 있다.

NanoNets 기반 예측
나노넷(NanoNets)은 앞의 준비과정보다 좀 더 단순하게 객체 인식을 할 수 있도록 해 준다. 나노넷은 GPU같이 값비싼 하드웨어가 필요없이 라즈베리파이 같은 장치에서도 사용하기 좋다.

다음은 나노넷의 간단한 예제이다.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import picamera, json, requests, os, random
from time import sleep
from PIL import Image, ImageDraw

#capture an image
camera = picamera.PiCamera()
camera.capture('image1.jpg')
print('caputred image')

#make a prediction on the image
url = 'https://app.nanonets.com/api/v2/ObjectDetection/LabelFile/'
data = {'file': open('image1.jpg', 'rb'), \
    'modelId': ('', 'YOUR_MODEL_ID')}
response = requests.post(url, auth=requests.auth.HTTPBasicAuth('YOUR_API_KEY', ''), files=data)
print(response.text)

#draw boxes on the image
response = json.loads(response.text)
im = Image.open("image1.jpg")
draw = ImageDraw.Draw(im, mode="RGBA")
prediction = response["result"][0]["prediction"]
for i in prediction:
    draw.rectangle((i["xmin"],i["ymin"], i["xmax"],i["ymax"]), fill=(random.randint(1, 255),random.randint(1, 255),random.randint(1, 255),127))
im.save("image2.jpg")
os.system("xdg-open image2.jpg")

나노넷에 대한 상세한 내용은 다음 링크를 참고한다.



마무리
이 글에서는 라즈베리파이에서 딥러닝 모델을 실행해 객체 인식 탐색하는 방법을 알아보았다.
이 글의 코드는 다음 링크를 참고하길 바란다.


이 글에 대한 좀 더 상세한 내용은 다음 링크를 참고하길 바란다.

레퍼런스
1. Raspberry Pi: Deep learning object detection with OpenCV
2. How to easily Detect Objects with Deep Learning on Raspberry Pi