2018년 12월 27일 목요일

직접 간단히 만들어보는 블록체인과 가상화폐


이 글은 블록체인 동작 메커니즘 이해하고자 하는 싶은 분을 위해 핵심 개념만 간단히 개발하는 과정을 공유한다.

좀 더 자세한 내용은 아래 링크를 참고한다.

우선 요구사항을 정해보자
블록체인 개발전에 블록체인 개념을 내포하는 몇가지 요구사항을 정의해야 한다.
  • 가상화폐: 가치 교환을 위한 디지털 가치 보관 수단
  • 지갑: 개인이나 조직 가상화폐를 보관하는 전자 계정
  • 트랜잭션: 데이터의 변화를 기록한 단위
  • 블록: 트랜잭션을 기록한 단위. 데이터 변조를 막기 위해 해쉬 암호화 사용
  • 마이닝: 블록을 관리하는 컴퓨팅 소모 자원에 대한 대가 지급
  • 스마트 계약: 상호간 거래시 계약 불이행을 방지하기 위한 수단

간단히 만들어 보는 블록체인 
우선 요구사항을 바탕으로 아키텍처를 디자인해보자.

요구사항에 해당하는 객체를 모두 클래스화한다. 그리고, 각 클래스간 관계를 디자인한다. 예를 들어, 코인과 화폐는 서로 관계가 있다.

코인은 가치를 보관하는 개념이다. 트랜잭션은 쌍방간의 계약중 하나이며, 가치의 변경을 담는 역할이다. 블록은 트랜잭션의 변화를 기록한다. 블록은 링크드리스트(linked list) 자료구조로 정의된다. 블록의 위변조는 해쉬값으로 알 수 있다. 블록체인은 블록을 생성하고 관리한다. 스마트계약은 트랜잭션을 발생시킨다.

이를 디자인하면 다음과 같다.
클래스 디자인(UML)

앞의 디자인을 반영해 중요한 부분만 코딩하면 다음과 같다.
 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
class coin
{
public:
   double value = 0;
}

class wallet
{
public:
   string accountAddress;
   coin coin;
}

class transaction
{
public:
   string fromAcccount, toAccount;
   coin trasnferValue;
   string calculateHash() {return SHA256(this)};
}

class block
{
public:
   const int MAX_BLOCK_TRANSCTION 40
   int countTransaction = 0;
   transaction[MAX_BLOCK_TRANSACTION];
   block* previousBlock = NULL;
   block* nextBlock = NULL;

   int insertTransaction(transaction& t);
   string calculateHash();
}

class blockChain
{
public:
   block* createGenesisBlock();
   coin* miningBlock(int hash, block& block);
   block* insertBlock(block* b);
}

class smartContract
{
public:
   void setScript(string code);
   bool execute();

private:
   string code;
   python contractScript;
}
style by hilite

마무리
이 글은 블록체인과 스마트 계약 구현 원리를 이용해 보기 위해 간단히 아키텍처를 디자인해보고, 코드로 구현해 보았다. 사실, 이외 여러 기능과 구성요소가 필요하나, 다양한 블록체인 플랫폼의 핵심적인 내용은 비슷하다. 좀 더 상세한 내용은 다음 레퍼런스를 참고하길 바란다. 

레퍼런스

2018년 12월 16일 일요일

Blue Z IoT 오픈소스 프로젝트

이 글은 BlueZ IoT 오픈소스 프로젝트를 간략히 설명한다. 

Bluz는 Arduino처럼 작동하지만 Bluetooth LE (BLE) 통신 기능이 내장된 개발 키트이다. 이 BLE 연결을 통해 장치는 REST API를 통해 전 세계 어느 곳에서나 하드웨어에 액세스할 수있게 해주는 Particle 클라우드와 통신할 수 있다. 
BluZ 개념도

함수를 호출하고, 변수를 가져오고, 이벤트를 게시 또는 구독하고, 웹 훅을 트리거하고, 웹 IDE를 통해 무선으로 프로그래밍 할 수 있다. 

Bluz는 배터리 수명이 긴 무선 애플리케이션에 이상적이다. BLE를 사용하면, bluz는 몇 달 또는 몇 년 동안 코인 셀 배터리로 지속될 수 있으며, 모두 클라우드에 연결되어 액세스 할 수 있다. 

Bluz는 Arduino에서 사용되는 것과 동일한 언어인 Wiring으로 프로그래밍되어 있으므로 많은 호환 가능한 개발 키트가 사용 가능하다.

레퍼런스는 아래 링크를 참고한다.

2018년 12월 10일 월요일

마이크로소프트 딥러닝 인공지능 도구

몇 년사이에 마이크로소프트사의 딥러닝 인공지능 도구가 크게 발전한 것 같다. 물론 오픈소스 기반인데다 무료라 사용하기 어렵지 않다.

이 글은 대표적인 이 회사의 인공지능 도구를 소개한다.

  • Azure Notebooks: 쥬피터 노트북 기반 다양한 프로젝트를 무료로 개발할 수 있음
  • Custom Vision: 딥러닝 모델 관련 설정 및 코딩 없이, 손쉽게 이미지를 업로드하면 딥러닝 모델을 개발할 수 있음
  • Caption Bot: 비전 딥러닝 모델을 이용한 간단한 서비스로 이미지를 올리면, 자동으로 객체과 상호관계를 인식해 설명을 해줌










2018년 11월 18일 일요일

아마존 AWS 딥렌즈(DeepLens) 사용기

이 글은 연구용으로 2018년 여름에 구매했던 아마존 AWS 딥렌즈(DeepLens)의 간단한 사용기이다. 가격은 겨우 $249로 아마존에서 판매하고 있다. 연말이 되어서야 아래한글 연구행정 문서질을 어느정도 정리하고, 드디어 지금 시간이 있어 딥렌즈 꺼내놓고 사용법을 정리한다.

이 글은 다음과 같이 딥렌즈 장치 설정에서 카메라에서 실시간 객체 인식 예제를 생성하는 방법까지 설명한다. 참고로, 딥렌즈에는 객체인식, 표정인식, 제스춰인식 등 다양한 예제를 제공하고 있으며, 각 인식 모델은 사용자가 학습한 모델로 대치할 수 있다. 그러므로, 다양한 분야에서 딥러닝 모델을 개발하고 적용하는 것이 가능하다. 
웹에서 딥러닝 기반 객체 인식 결과 확인

딥렌즈 장치에서 직접 딥러닝 객체 인식 결과 확인

개요
딥렌즈는 아마존에서 개발한 딥러닝 기반 비전용 카메라이다.


딥렌즈를 이용하면, 미리 훈련된 신경망 모델을 클릭만 해서 딥렌즈에 적용하여, 다양한 비전 프로젝트를 손쉽게 진행할 수 있다. 이미 아마존에는 다양한 최신 신경망 모델이 업로드되어 있어, 적용에 그리 어렵지 않다.

딥렌즈 스펙
딥렌즈 스펙은 다음과 같다. 운영체제는 우분투 16.04를 사용하며, 딥러닝 연산을 위해 Gen9을 사용한다.

Hardware
Intel Atom® processor
Gen9 graphics
Ubuntu 16.04 LTS
106 GFLOPS performance
Dual band Wi-Fi
4 MP camera with MJPEG
H.264 encoding at 1080p resolution
Storage
8 GB RAM
16 GB memory
32 GB SD card
Inputs / Outputs
2 USB ports
Micro HDMI
Audio out
Software
AWS Greengrass pre-configured
Cl-DNN (compute library for deep neural networks)
좀 더 상세한 제품 내용은 개발자 가이드라인을 살펴본다.

셋업
딥렌즈를 구입한 후, 다음 영상을 참고해 셋업한다.

딥렌즈는 AWS를 사용하므로, 설정을 위해서는 먼저 AWS에 가입해야 한다. 가입 후 AWS에 로그인을 한다. 다음은 이후 주요 딥렌즈 설정 순서이다. 

1. 컴퓨터에서 AWS 콘솔(console)에 로그인 후 AWS services의 Find Services에서 AWS DeepLens를 검색.

2. Register device 버튼을 선택해 딥렌즈 장치를 생성함. 이름을 입력하고, 딥렌즈에서 사용할 패키지 사용 권한(permission)을 획득한 후, 장치 접속 인증서를 생성함.

3. 웹페이지에 나타나는 순서대로, 딥렌즈 전원 버튼을 눌러 전원을 켬. 잠시 후 중간 LED가 깜빡깜빡 거리는 reset 상태가 될 것임.

4. 딥렌즈 장치 바닥에 표시된 장치 WiFi SSD를 컴퓨터의 WiFi로 설정하고, 표시된 암호를 입력해 딥렌즈 장치와 연결함. 이후, 계속 다음 버튼을 클릭함.

5. 이후, 딥렌즈 장치 설정 콘솔 열기(Open AWS DeepLens console) 버튼 페이지가 표시됨. 버튼을 클릭함. 나타나는 콘솔 페이지에서, 사용할 WiFi를 설정하고, 방금전 생성한 장치 접속 certificate 압축파일을 선택, 딥렌즈 장치 및 SSH 터미널 접속에 사용할 암호 등을 입력하고, 계속 진행함.

*주의: 참고로, 기존 딥렌즈 장치를 삭제한 후, 이 과정을 다시 진행할 경우, 장치 등록이 안되는 경우가 발생할 수 있음. 이 경우, 딥렌즈 장치 후면의 모니터 micro HDMI, 마우스 및 키보드 USB 단자를 연결해 우분투로 아까 입력한 암호를 이용해 로그인해야 함. 이후, 우분투에 앞서 설정한 WiFi 접속된 SSID 네트워크 연결을 삭제하고, 다시 장치 설정을 reset해야 함(장치 뒷면에 작은 홀이 있는 데, 이를 20초간 바늘 같은 것으로 누르고 있으면 reset상태가 됨). 이후, 앞의 과정을 다시 시작하면 설정이 잘 될 것임.


6. 딥렌즈 장치 내 패키지 업데이트 등이 모두 끝나면, 장치 등록(registration)이 성공하였다는 메시지가 AWS DeepLens 콘솔 페이지에 아래와 같이 표시됨.

정상 등록된 딥렌즈 장치

딥러닝 모델 설치
이 예제에서는 객체를 탐지하는 CNN 모델을 적용할 것이다. 이 모델은 이미 훈련되어 있으며, 딥렌즈에 설치하면, 바로 실행할 수 있다. 다음 영상을 참고하자.

딥렌즈 예제 프로젝트 생성 방법

주요 단계는 다음과 같다.

1. Create new project 버튼 클릭

2. Project type 선택. 이 경우, Object detection 프로젝트를 선택하였음.

3. Create 버튼 클릭

4. AWS 클라우드에 생성된 Object-detection 프로젝트를 Deploy to device 버튼을 클릭해 딥렌즈 장치로 전송함

5. Deploy 중인 상태는 다음 그림과 같이 청색으로 표시됨

6. Deploy 완료하면 다음 그림과 같이 녹색으로 바뀜

7. Deploy 완료된 프로젝트를 선택해, Project output을 확인해 보면, MQTT 로 토픽을 받을 수 있는 링크가 있음. Copy 한 후, 표시된 AWS IoT console 페이지에서 해당 토픽 링크를 붙여 넣어 봄

그럼, 다음과 같이, 객체 인식이 된 결과를 토픽단위로 확인할 수 있음

8. Project output 에서 View the video output을 선택함. 여기서, 설명된 내용과 같이 딥렌즈 장치에서 video server certification 파일을 생성하고, 이를 크롬 브라우저의 보안 인증서로 등록해야 함. 이를 위해, 딥렌즈 장치의 우분투에 로긴해서 해당 파일을 생성하여, 파일을 접속할 컴퓨터에 복사해 와야 함. 본인의 경우, SSH로 원격 접속해서 해당 파일을 생성하지 않고, 장치의 우분투에 직접 로긴해 파일을 생성하고 크롬에 등록하였음(인증서 등록시 별도 암호는 설정하지 않았음).
Video Server 인증서를 크롬에 등록한 후 Video output 페이지 접속한 화면

9. Video output(https://172.30.22:4000) 페이지에 접속하면, 다음과 같은 프로젝트 실행되고 있는 결과를 원격으로 확인할 수 있음



이외 다른 프로젝트를 생성하여, deploy하면 다음과 같은 다양한 딥러닝 결과물을 확인할 수 있다. 
제스쳐 인식 결과
사진에서 페인팅 결과

직접 훈련한 딥러닝 모델도 임포트할 수 있다.
다양한 딥러닝 프레임웍에서 훈련된 모델을 가져오는 화면

참고로, 딥렌즈 장치에서 직접 카메라 스트리밍을 보고싶다면, mplayer를 설치(링크)하고, 다음과 같이 우분투에 로긴해서 명령을 입력하면 된다. 
mplayer -demuxer lavf /opt/awscam/out/ch1_out.h264

딥러닝 결과를 확인하고 싶다면, 다음과 같이 입력하면 된다. 만약, 화면의 질이 않좋다면, -cache 8092 옵션으로 캐쉬 크기를 조정해 본다. 
mplayer -demuxer lavf -lavfdopts format=mjpeg:probesize=32 /tmp/results.mjpeg

SSH 접속 방법
참고로, 딥렌즈에 설치된 우분투로 직접 접속하지 않고, 컴퓨터에서 원격으로 접속해 딥렌즈 소프트웨어를 설치하거나 특정 명령을 실행할 수 있다. 이 경우, SSH 방식으로 터미널 접속해야 한다. 이를 위해 PuTTY 란 프로그램을 다운로드 받아 설치한다.
사용 방법은 아래 링크를 참고한다.

다음은 PuTTY를 이용해 딥렌즈 장치에 접속하는 장면이다.  

TTY 터미널로 접속하면, 다음과 같이 딥렌즈 장치의 우분투 운영체제에 패키지를 설치하고, 유지관리를 손쉽게 할 수 있다.
터미널 접속 화면

참고로, 딥렌즈에서 실행되는 프로세스는 ps -ef 로 확인하거나, 다음과 같이 htop 유틸리티를 설치해 확인해 볼 수 있다.
sudo apt-get install htop

AWS에서 기본으로 설치한 딥렌즈 지원용 프로세스들을 확인해 볼 수 있다.

마무리
지금까지 딥렌즈 사용법을 간단히 살펴보았다. 딥렌즈는 아마존에서 챌린지를 개최하여 다양한 활용 사례들을 발굴하고 있다.

딥렌즈 성능은 그리 크게 좋지는 않다(HW스펙 참고). 이 정도 스펙은 세그먼테이션, 다중객체 인식을 실시간으로 돌리는 쉽지 않다. 다만, AWS와 연동성이 좋아, 딥러닝 모델을 쉽게 선택해 사용해 볼 수 있어 편의성은 높다. 그래서, 딥러닝 비전 교육 도구로써는 괜찬다고 생각한다.

딥러닝 플랫폼이 처음 나올때만해도, 텐서플로 같은 패키지를 설정하는 데만 많은 시간이 걸렸지만, 최근 나오는 딥러닝 도구는 이런 과정 없이 바로 사용할 수 있게 사용 편의성을 높여가고 있다. 점차 딥러닝 사용자의 저변이 넓어지고, 사용하기 쉬워지고 있다.

딥러닝이 특별한 사람들만 사용하는 기술처럼 보이지만, 아마존, 마이크로소프트와 같이 대기업 소프트웨어가 손쉽게 딥러닝 기술을 사용할 수 있는 도구를 출시하고 있어, 조만간 대중화되리라 생각한다. 그때는 누구나 드래그 드롭으로 딥러닝을 개발하고, 응용 프로그램을 만들 수 있을 것이다.

레퍼런스

2018년 11월 3일 토요일

간단한 BIM 기반 스마트 계약 개발하기

이 글에서는 BIM 기반 스마트 계약을 개발할 때, 어떤 방식으로 진행하는 지를 간략히 설명한다.

스마트 계약 개발 절차
개발은 보통 요구사항 정의, 분석, 설계, 개발 및 테스트로 진행된다.  요구사항 정의 시 사용되는 방법 중 하나가 유스케이스 분석이다. 유스케이스 분석을 통해, 실제 사용 사례와 시나리오를 정리한다.

유스케이스 정의
BIM의 경우 제일 큰 이슈 중 하나가 디지털 모델 변경이 다수 관계자간에 진행되어, 모델의 신뢰성 보장이 어렵다는 것이다. 신뢰성 보장을 위해서는 모델에 대한 이슈 발생과 처리 시 과정을 추적할 수 있어야 한다. 이슈 관리 이력을 분산원장(블록체인)에 저장해, 모델 변경 이력을 추적할 수 있도록 하고, 모델에 대한 신뢰성을 확보한다. 그래서, 유스케이스를 BIM 협업 상황에서 모델 변경 관련된 모델링 이슈 이력 관리로 한다. 모델 변경 시 관련 트랜잭션 정보는 다음과 같이 가정한다.

1. BIM file URL = resource_type://address+directory
2. Issue No = IS###
3. Issue reason = enum {element_collision, element_missing, invalid_data, etc}
4. Sender = email
5. Receiver = email
6. Date = YYYY/MM/DD
7. State = enum {open, progress, solved, close}

구현해 보기
앞의 유스케이스를 스마트 계약으로 구현해 보면 다음과 같다.

pragma solidity ^0.4.0;
contract BIM_modeling_issue {
    struct Issue {
        uint no;
        string url;
        uint reason;
        string sender, receiver;
        string date;
        uint state;
    };
    Issue[] issues;

    /// Create a issue
    function BIM_modeling_issue(uint8 num) public {
        issues.length = num;
    }

    function findIssueBySender(string sender) public Issue returns (Issue _is) {
        for(uint8 i = 0; i < issues.length; i++)
        {
            if(issues[i].sender == sender) { 
               _is = issues[i];
            }
        }
    }
}



BIM 모델링 이슈 데이터를 관리하는 Issue 구조체를 정의하고, issues 배열을 만든다. sender가 생성한 issue를 찾는 findIssueBySender라는 간단한 함수를 만들어 보았다. 이 스크립트는 Solidity 계약 개발을 지원하는 REMIX등에서 실행할 수 있다.


레퍼런스
Welcome to Remix documentation!
Create Your First Smart Contract In Ethereum With Ganache And Remix IDE
Build Your First Ethereum Smart Contract with Solidity — Tutorial


2018년 10월 31일 수요일

Google 에서 제안하는 어린이 코딩 도구

집에서도 할 수 있는 코딩 방법 중 구글에서 제안한 유용한 도구를 설명한 사이트가 있어 잠깐 소개한다. 코딩에 흥미를 갖게 하는 도구들이 소개되어 있는 데, 어린이들도 쉽게 할 수 있는 것들이라 부모와 충분히 함께 할 수 있다.

코드짐(Code Gym)
구글에서 제공하는 오픈소스 코딩 도구로 그리기, 음악, 그래픽 패턴등을 코딩을 통해 만들고 즐길 수 있다.

블로키(Blockly)
코딩으로 재미있는 다양한 그림을 만들 수 있는 도구이다.

Made with Code
코딩으로 다양한 게임과 스토리를 만드는 도구이다. 설명이 잘 되어 있어, 따라하는 데 그리 어렵지 않다.

MIT 앱 인벤터(app inventor)
스마트폰에 실행되는 앱을 블록 코딩 방식으로 만들 수 있다. MIT에서 개발되었으며, 오픈소스이다.


2018년 9월 21일 금요일

딥러닝 훈련용 대용량 이미지의 하둡 파일 준비 방법

이 글은 딥러닝 훈련용 이미지 데이터 준비 방법을 간단히 설명한다.

학습용 빅데이터 준비 순서
우선, 학습할 데이터 목적을 분명히 정한다. 훈련할 딥러닝 모델 종류에 따라 데이터 구조 및 형식이 적절히 변환되어야 할 수 있다. 훈련 및 검증 데이터 크기가 얼마 정도가 되어야 하는 지 결정한다. 대략 학습용 데이터를 준비하는 순서는 다음과 같다.

1. 학습용 빅데이터 활용 목적 결정
2. 빅데이터 형식, 구조 및 크기 결정
3. 빅데이터 수집 방법 결정
4. 빅데이터 관리 방법 결정
5. 빅데이터 수집
6. 빅데이터 정리
7. 빅데이터 라벨링 및 주석 작업
8. 작업된 데이터 품질 확인
9. 훈련 및 검증용 빅데이터 준비

이제 딥러닝 훈련용 하둡 데이터 준비 방법을 간단히 살펴보자.

딥러닝 훈련용 하둡 데이터
빅데이터중에 멀티미디어 데이터는 하둡파일로 저장해 관리하는 것이 편리하다. 비전과 관련된 많은 딥러닝 예제에서는 하둡파일인 HDF5를 사용한다. 참고로 하둡파일 구조는 다음 링크를 참고한다.
딥러닝에 필요한 데이터는 매우 많은데, 예를 들어, ImageNet에 있는 학습 데이터는 거의 2 백만 개 이미지이다. 이런 상황에서 모든 이미지를 메모리로 로드하고, 이미지 전처리를 적용한 후, 네트워크에 전달하여 훈련, 검증 또는 테스트하는 것은 현명하지 않다.

하나의 HDF5 파일에 많은 수의 이미지를 저장하고, 일괄적으로 데이터를 로딩할 수 있다. HDF5는 데이터를 관리, 조작, 압축 및 저장하는 기능을 제공한다. 이 글에서는 개와 고양이 이미지를 HDF5로 저장 및 로딩해본다.

이미지 및 레이블 지정
먼저 모든 이미지에 대한 레이블을 지정해야 한다. 각 고양이 이미지에 label = 0을 지정하고, 각 강아지 이미지에 label = 1을 지정한다. 그리고, 학습 모델 가중치가 특정한 학습 시기에 편중되지 않도록 데이터를 임의로 뒤집고 섞어야 한다. 데이터 세트는 훈련용 60%, 검사 20), 테스트 20%로 나눈다. 아래 예제는 machinelearninguru.com 을 참고하였다.

from random import shuffle
import glob
shuffle_data = True  # shuffle the addresses before saving
hdf5_path = 'Cat vs Dog/dataset.hdf5'  # address to where you want to save the hdf5 file
cat_dog_train_path = 'Cat vs Dog/train/*.jpg'

# read addresses and labels from the 'train' folder
addrs = glob.glob(cat_dog_train_path)
labels = [0 if 'cat' in addr else 1 for addr in addrs]  # 0 = Cat, 1 = Dog

# to shuffle data
if shuffle_data:
    c = list(zip(addrs, labels))
    shuffle(c)
    addrs, labels = zip(*c)
    
# Divide the hata into 60% train, 20% validation, and 20% test
train_addrs = addrs[0:int(0.6*len(addrs))]
train_labels = labels[0:int(0.6*len(labels))]

val_addrs = addrs[int(0.6*len(addrs)):int(0.8*len(addrs))]
val_labels = labels[int(0.6*len(addrs)):int(0.8*len(addrs))]

test_addrs = addrs[int(0.8*len(addrs)):]
test_labels = labels[int(0.8*len(labels)):]
HDF5 파일 생성
h5py 및 PyTables 같은 HDF5 형식을 생성하는 함수가 있다.

이미지를 저장하기 위해 각 이미지 데이터 세트마다 배열 구조를 정의해야 한다. 보통, 데이터 IMAGE_HEIGHT, IMAGE_WIDTH, image_depth 이다. 배열을 만들 때 데이터 유형은 dtype이다.

하둡파일 생성방법은 테이블 방식과 h5py 함수를 이용해 직접 생성하는 방식이 있다.

테이블 방식은 empty 배열을 생성하는 create_earray 를 사용할 수 있다. 여기에 데이터를 추가 할 수 있다. 레이블은 create_array를 사용하는 것이 더 편리하다. 배열 dtype을 설정하려면 uint8에 대해 tables.UInt8Atom()과 같은 테이블 dtype을 사용할 수 있다. create_earray 및 create_array 메소드 첫 번째 속성은 데이터 그룹을 작성하여 데이터를 관리 할 수있는 데이터 그룹 이다. 그룹은 HDF5 파일 폴더와 비슷하다.

h5py 방식은 create_dataset을 사용하여 배열을 만든다. 배열을 정의 할 때는 정확한 크기를 결정해야한다. 레이블에 create_dataset을 사용해 즉시 레이블을 지정할 수 있다. numpy 유형을 사용하여 배열의 dtype을 직접 설정할 수 있다.

아래는 테이블을 이용해 하둡파일을 생성한다.
import numpy as np
import tables

data_order = 'tf'  # 'th' for Theano, 'tf' for Tensorflow
img_dtype = tables.UInt8Atom()  # dtype in which the images will be saved

# check the order of data and chose proper data shape to save images
if data_order == 'th':
    data_shape = (0, 3, 224, 224)
elif data_order == 'tf':
    data_shape = (0, 224, 224, 3)

# open a hdf5 file and create earrays
hdf5_file = tables.open_file(hdf5_path, mode='w')

train_storage = hdf5_file.create_earray(hdf5_file.root, 'train_img', img_dtype, shape=data_shape)
val_storage = hdf5_file.create_earray(hdf5_file.root, 'val_img', img_dtype, shape=data_shape)
test_storage = hdf5_file.create_earray(hdf5_file.root, 'test_img', img_dtype, shape=data_shape)

mean_storage = hdf5_file.create_earray(hdf5_file.root, 'train_mean', img_dtype, shape=data_shape)

# create the label arrays and copy the labels data in them
hdf5_file.create_array(hdf5_file.root, 'train_labels', train_labels)
hdf5_file.create_array(hdf5_file.root, 'val_labels', val_labels)
hdf5_file.create_array(hdf5_file.root, 'test_labels', test_labels)
이제 이미지를 하나씩 읽어 전처리하고 저장한다.
# a numpy array to save the mean of the images
mean = np.zeros(data_shape[1:], np.float32)

# loop over train addresses
for i in range(len(train_addrs)):
    # print how many images are saved every 1000 images
    if i % 1000 == 0 and i > 1:
        print 'Train data: {}/{}'.format(i, len(train_addrs))

    # read an image and resize to (224, 224)
    # cv2 load images as BGR, convert it to RGB
    addr = train_addrs[i]
    img = cv2.imread(addr)
    img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_CUBIC)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # add any image pre-processing here

    # if the data order is Theano, axis orders should change
    if data_order == 'th':
        img = np.rollaxis(img, 2)

    # save the image and calculate the mean so far
    train_storage.append(img[None])
    mean += img / float(len(train_labels))

# loop over validation addresses
for i in range(len(val_addrs)):
    # print how many images are saved every 1000 images
    if i % 1000 == 0 and i > 1:
        print 'Validation data: {}/{}'.format(i, len(val_addrs))

    # read an image and resize to (224, 224)
    # cv2 load images as BGR, convert it to RGB
    addr = val_addrs[i]
    img = cv2.imread(addr)
    img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_CUBIC)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # add any image pre-processing here

    # if the data order is Theano, axis orders should change
    if data_order == 'th':
        img = np.rollaxis(img, 2)

    # save the image
    val_storage.append(img[None])

# loop over test addresses
for i in range(len(test_addrs)):
    # print how many images are saved every 1000 images
    if i % 1000 == 0 and i > 1:
        print 'Test data: {}/{}'.format(i, len(test_addrs))

    # read an image and resize to (224, 224)
    # cv2 load images as BGR, convert it to RGB
    addr = test_addrs[i]
    img = cv2.imread(addr)
    img = cv2.resize(img, (224, 224), interpolation=cv2.INTER_CUBIC)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

    # add any image pre-processing here

    # if the data order is Theano, axis orders should change
    if data_order == 'th':
        img = np.rollaxis(img, 2)

    # save the image
    test_storage.append(img[None])

# save the mean and close the hdf5 file
mean_storage.append(mean[None])
hdf5_file.close()
HDF5 파일 읽기
데이터가 HDF5 파일에 올바르게 저장되었는지 확인해야한다. 이를 위해 임의의 크기의 배치로 데이터를 로드하고 처음 다섯번째 배치의 첫 번째 이미지를 출력해 본다. 또한 각 이미지의 레이블을 확인한다.
import tables
import numpy as np

hdf5_path = 'Cat vs Dog/dataset.hdf5'
subtract_mean = False

# open the hdf5 file
hdf5_file = tables.open_file(hdf5_path, mode='r')

# subtract the training mean
if subtract_mean:
    mm = hdf5_file.root.train_mean[0]
    mm = mm[np.newaxis, ...]

# Total number of samples
data_num = hdf5_file.root.train_img.shape[0]
이제 배치 목록을 만들고, 순서를 섞는다. 그리고, 각 배치의 모든 이미지를 한번에 로딩한다.
from random import shuffle
from math import ceil
import matplotlib.pyplot as plt

# create list of batches to shuffle the data
batches_list = list(range(int(ceil(float(data_num) / batch_size))))
shuffle(batches_list)

# loop over batches
for n, i in enumerate(batches_list):
    i_s = i * batch_size  # index of the first image in this batch
    i_e = min([(i + 1) * batch_size, data_num])  # index of the last image in this batch

    # read batch images and remove training mean
    images = hdf5_file.root.train_img[i_s:i_e]
    if subtract_mean:
        images -= mm

    # read labels and convert to one hot encoding
    labels = hdf5_file.root.train_labels[i_s:i_e]
    labels_one_hot = np.zeros((batch_size, nb_class))
    labels_one_hot[np.arange(batch_size), labels] = 1

    print n+1, '/', len(batches_list)

    print labels[0], labels_one_hot[0, :]
    plt.imshow(images[0])
    plt.show()
    
    if n == 5:  # break after 5 batches
        break

hdf5_file.close()

이 코드를 이용해, 배치로 로딩한 이미지 데이터셋을 이용한 딥러닝 모델 훈련, 검증을 할 수 있을 것이다. 이와 관련된 코드는 machinelearningrugu.com에서 제공한 Github페이지에서 확인할 수 있다.

만약 텐서플로우 레코드 형식인 TFRecords 로 처리하려면, 이 링크를 참고하라.


참고 - 딥러닝 데이터 취득 센서 스펙 
무인자율차 등에 사용하는 데이터 취득용 센서는 환경에 따라 취득할 수 있는 데이터 종류, 여건 등이 다르다. 아래 표는 이를 정리한 것이다.
센서 스펙(Distributed Deep Learning with Hadoop and TensorFlow)

참고 - 딥러닝 데이터 취득 센서 스펙 
머신러닝 플랫폼은 사용하는 레이어에 따라 여러가지가 될 수 있다. Flux는 데이터 저장, 학습, 시뮬레이션, 관리까지 아우르는 플랫폼이다. 시뮬레이션 및 센서 데이터 교환을 위해 ROS를 사용하고 있다.


참고 - 딥러닝 모델 데이터 종류
빅데이터를 저장하고 훈련 시 필요한 데이터를 딥러닝 모델에 공급하기 위해 데이터 형식을 구조화해야 한다. 데이터 구조는 앞서 설명한 바와 같이, 훈련, 검증 및 테스트로 구분하고, 각 데이터셋을 배치방식으로 로딩하기 위해 배치단위로 저장된다. 각 데이터는 학습 모델에 입력될 수 있는 데이터 구조로 정규화되어 저장되며, 이때 라벨 정보가 함께 있어야 한다.

데이터 활용 목적에 따라 취득될 수 있는 데이터 종류는 다음과 같다.

1. 이미지 형식
이 데이터 형식은 카메라로 얻은 사진, 동영상 뿐 아니라 신호 등 시공간 이미지 데이터 등을 모두 포함한다. 이미지는 RGB 픽셀 단위, 정수나 실수로 표현된 신호값 등으로 구성될 수 있다.
이미지는 프레임으로 구분되며, 프레임은 스트리밍(streaming) 가능한 형식으로 표현된다. 저장된 동영상 파일 포맷을 읽기 위해서는 포맷 해석을 위한 코덱(codec)이 필요하다. 보통, OpenCV같은 라이브러리는 이미지 영상 데이터를 읽고 쓸 수 있다.
신호같은 데이터는 행렬 형식으로 이미지를 만들고 저장할 수 있다.

2. 텍스트 형식
텍스트 형식은 이미지 보다는 구조나 포맷이 간단하고, 읽고 쓰기가 편리하다. 텍스트 형식은 훈련용, 검증용 데이터셋 종류와 갯수를 구분할 수 있는 헤더 정보를 정의한다.

3. 점군(포인트 클라우드) 형상
점군은 대용량 데이터로 수백만개 이상 포인트가 포함된 구조이다. 수백만개 점군을 직접 훈련용 데이터로 사용할 수는 없으니, 세그먼테이션하여 분리된 점군을 적절히 샘플링하여, 3차원 grid 형식으로 저장한다. 이때 voxel 구조 등을 사용하기도 한다.

기타 수치, 벡터 데이터, 관계 위상 정보 등이 있다.


레퍼런스
  1. Saving and loading a large number of images (data) into a single HDF5 file
  2. Distributed Deep Learning with Hadoop and TensorFlow
  3. How to Prepare a Photo Caption Dataset for Training a Deep Learning Model (Keras)
  4. Faster R-CNN Use Caffe Framework with Video
  5. Capturing and processing video from a webcam
  6. Scripts to extract CNN features from video frames with Keras, github
  7. Real-time object detection with deep learning and OpenCV
  8. Deep Learning Tutorial to Calculate the Screen Time of Actors in any Video (with Python codes)
  9. How to run Object Detection and Segmentation on a Video Fast for Free with R-CNN
  10. How to (quickly) build a deep learning image dataset
  11. Image Classification using Convolutional Neural Networks in Keras (simple)
  12. Simple Image Classification using Convolutional Neural Network — Deep Learning in python.
  13. Building powerful image classification models using very little data
  14. How to build a Neural Network with Keras
  15. A Tutorial on How to Feed Your Own Image Data to Tensorflow
  16. 컨볼루션 신경망 모델 만들어보기
  17. 학습 모델 보기/저장하기/불러오기

2018년 9월 17일 월요일

케라스 기반 이미지 인식 딥러닝 모델 구현

오랜만에 급한 일이 약간 처리되어, 쌓아 둔 케라스(Keras) 기반 딥러닝 자료를 정리한다. 이 글은 Inception, VGG등 대표적인 딥러닝 모델을 설명하고, 케라스 기반 VGG 딥러닝 구현 예제를 소개한다. 이 예제에서는 구글에서 얻은 건축 이미지와 3D 이미지 예측 정확도를 간단히 테스트해본다.

이미지넷 인식 딥러닝 모델
이미지넷 객체 인식 딥러닝 모델은 이미지넷 ImageNet Large Scale Visual Recognition Competition(ILSVRC) 대회를 통해 크게 발전되었다. 2014년 대회에서는 1000개 이미지 분류 문제가 있었고, 이를 위해, 이미지넷의 120만장 학습 이미지와 5만장 validation set, 10만장 test set을 사용할 수 있다. 
이 대회는 ground truth 와 가장 높은 확률로 예측된 클래스가 서로 일치하는 지 확인하는 top-1 정확도, 가장 높은 확률로 예측된 5개 클래스안에 ground truth 존재 여부를 확인하는 top-5 error rate로 순위를 매긴다.
Top-1 accuracy deep learning model(https://arxiv.org/abs/1605.07678) 

10 Testing Results (Review: ResNet — Winner of ILSVRC 2015 (Image Classification, Localization, Detection))

이미지 인식 문제에서 높은 정확도를 가진 모델 중 대표적인 것만 간략히 살펴본다. 

  • LENET5: 1994년 개발된 모델로 컨볼루션 뉴럴네트워크 사용함. 이 모델은 1988년부터 Yann LeCun이 개발되어 LeNet5으로 이름지어짐. 이 모델은 컨볼루션 레이어 3개를 사용하여, 이미지 특징 벡터를학습하였음. 이 당시에는 GPU가 없어, 대용량 계산 시간을 줄이기 위해 희소 연결 행렬을 사용하였음 

  • AlexNet: 딥러닝 대부 중 한명인 Geoffrey E. Hinton제자인 2012년 Alex Krizhevsky가 발표한 이미지넷의 이미지 인식 정확도를 극적으로높인 첫번째 딥러닝 모델. Top 5 test error가 15.4%로 2위 모델보다(26.2%) 정확도가 매우 높음. 5개 컨볼루션 레이어와 3개 fully connected 레이어 사용함. 이 모델에서 ReLu(Rectified Linear Unit), over fitting 방지를 위한 Dropout 기법이 적용됨. GPU를 NVIDIA GTX 580 사용하였음


  • Xception: 이미지 넷에서 0.945 정확도로 top-5 validation 획득한 모델. 입력 이미지는 299x299임
  • VGG: 2014년 옥스포드 VGG 그룹에서 개발된 딥러닝 모델. 알렉스넷의 커널 크기를 11에서 3x3으로 줄였고, 성능을 높임. 19층 레이어를 쌓음. 이미지넷 정확도를 92.3%로 개선. 층이 깊어 역전파 될 때 그레디언트가 작아져 해가 수렴되지 않은 문제(gradient vanishing)가 있었음 



  • ResNet: 2015년 이미지넷 ILSVRC에서 3.6% 에러율로 1등 차지한 모델. 참고로 인간 분류 오차가 5~10%임. 알렉스넷과 같은 전통적인 순차 네트워크와는 달리, ResNet은 exotic architecture로 네트워크 내에서 네트워크를 구조화한 모델임. 이런 구조는 마이크로 구조라는 블럭 빌딩 세트 집합으로 구성됨. residual block을 이용해 gradient vanishing문제 해결
Residual block(ResNet)

  • Inception: 2015년 이미지넷에서 우승. VGG의 계산 시간/성능을 개선한 모델. 다양한 필터와 1x1 풀링(pooling) 기법 등 사용해 전체적으로 네트워크 연결을 줄임. 컨볼루션 필터을 쪼개어 연산수를 낮게 만듬. 이를 통해, 핵심적인 연산은 밀도있게 처리함

  • DenseNet: 2016년 개발된 모델. 해를 좀 더 효과적으로 찾고 수렴시키기 위해, 역전파를 순차적으로 하는 것이 아닌 건너뛸수 있도록 네트워크 망을 개선함



객체 인식 딥러닝 모델
R-CNN(2013), FAST R-CNN(2015), FASTER R-CNN(2015), YOLO 등은 이미지 속 다양한 객체 경계를 탐색하는 모델이다. 이 문제는 경계 탐색 작업과 객체 분류 작업으로 구성된다.
아래 링크에 이와 관련된 모델 및 구조가 설명되어 있다.

케라스 설치 및 사용 방법
아래 링크를 참고해 케라스를 설치하고 실행되는 지 확인해 본다.

케라스 기반 VGG 딥러닝 모델 구현
케라스는 MXNet, Deeplearning4j, Tensorflow, Theano, 와 같은 다양한 딥러닝 프레임웍을 기능적으로 캡슐화한 딥러닝 프레임웍이다. 모델링이 직관적이고 간편해 많이 사용된다. 

케라스에는 VGG, ResNet, Inception V3, MobileNet 등 다양한 딥러닝 모델이 이미 구현되어 있어, 가져다 사용하기만 하면 된다. 

이 글에서는 VGG 딥러닝 모델을 케라스로 간단히 구현해 본다. 우선, 케라스, numpy, matplotlib 등은 설치되어 있다고 가정한다. VGG 모델은 이미 이미지넷이 훈련된 모델을 다운받아 사용한다. VGG로 이미지를 인식하는 코드는 다음과 같다.

from keras.models import Sequential 
import keras
import numpy as np
from keras.applications import vgg16, inception_v3, resnet50, mobilenet

#VGG 모델을 로딩함
vgg_model = vgg16.VGG16(weights='imagenet')

from keras.preprocessing.image import load_img
from keras.preprocessing.image import img_to_array
from keras.applications.imagenet_utils import decode_predictions
import matplotlib.pyplot as plt

filename = '/home/ktw/tensorflow/door1.jpg'
# 이미지 로딩. PIL format
original = load_img(filename, target_size=(224, 224))
print('PIL image size',original.size)
plt.imshow(original)
plt.show()

# PIL 이미지를 numpy 배열로 변환
# Numpy 배열 (height, width, channel)
numpy_image = img_to_array(original)
plt.imshow(np.uint8(numpy_image))
plt.show()
print('numpy array size',numpy_image.shape)

# 이미지를 배치 포맷으로 변환
# 데이터 학습을 위해 특정 축에 차원 추가
# 네트워크 형태는 batchsize, height, width, channels 이 됨
image_batch = np.expand_dims(numpy_image, axis=0)
print('image batch size', image_batch.shape)
plt.imshow(np.uint8(image_batch[0]))

# 모델 준비
processed_image = vgg16.preprocess_input(image_batch.copy())

# 각 클래스 속할 확률 예측
predictions = vgg_model.predict(processed_image)
 
# 예측된 확률을 클래스 라벨로 변환. 상위 5개 예측된 클래스 표시
label = decode_predictions(predictions)
print(label)

구글에서 검색해 얻은 문, 창문과 같은 건축 실내 요소 이미지들을 저장해 놓고, 입력해 얻은 결과는 다음과 같다. sliding door로 인식된 결과를 확인할 수 있다.


다른 테스트를 위해, 3D 모델링에서 캡쳐한 이미지의 인식 정확도를 확인해 보았다. 
VGG딥러닝 모델에서 유사한 클래스가 인식된 것을 확인할 수 있다. 다만, 이미지넷에 올라온 객체가 본인이 제시한 이미지와는 상이한 부분이 있어 정확도가 높지는 않다. BIM과 같은 3D모델에서 캡쳐한 이미지가 유사하게 인식되나, 마찬가지로 정확도가 그리 높지는 않다. 

테스트해본 결과를 보면, 정확도를 높이기 위해서는 목적에 맞는 훈련용 데이터 확보와 처리가 필수적이라는 것을 알 수 있다. 딥러닝 모델은 훈련된 데이터셋에 대한 부분만 정확도 높게 예측할 뿐이다. 

레퍼런스