2019년 6월 23일 일요일

우분투 USB 부팅 이미지 리사이즈 방법

이 글은 우분투 USB 부팅 이미지를 리사이즈 방법을 간략히 공유한다.
보통, 테스트용으로 우분투 등 리눅스 부팅 이미지를 만든 후, 좀 더 큰 메모리 SD 카드(256, 512 GB)로 이미지를 복사해 옮겨가고 싶을 때 사용한다. 이 글은 다음 레퍼런스를 참고하였다.

2019년 6월 18일 화요일

고정밀 GNSS와 ROS 연동하기

이 글은 고정밀 GNSS(Global Navigation Satellite System), IMU(Inertial Measurement Unit)와 ROS(Robot Operating System)를 연동하는 것에 대한 내용을 간단히 요약한 것이다. 여기서 사용한 GNSS센서는 3DM GX5이다.
3DM-GX5-45(high performance integrated multi-constellation GNSS receiver)

이 제품은 GPS, GLONASS, DeiDou, Galileo를 활용한 GNSS receiver이며, 정밀한 AHRS(Attitude and Heading Reference System) 값을 얻을 수 있다.
AHRS data

이 센서는 가격이 3~400백만원 수준이며, 드론, 로봇틱스 등 다양한 분야에 활용되고 있다. 이 센서는 가격이 상대적으로 저렴한? 편이라 한다. 다만, ROS 우부투, 리눅스 기반 작업을 할 때는 문서화가 잘 안되어 있어, 삽질이 좀 필요하다. 윈도우 버전은 설치 프로그램도 함께 제공하는 등 상대적으로 작업이 쉽다.
GNSS 사용 사례

이 글은 다음 링크를 참고하였다.
머리말
제품 제조사는 ROS 드라이버 패키지를 다음 링크에서 제공하고 있다.
이 패키지는 인터페이스 드라이버, ROS node가 제공되며, MIP SDK(Software Development Kit)를 통해 GNSS 장치와 연결해 사용한다. 

ROS 패키지 빌드 및 실행 
현재 ROS 버전이 HYDRO, INDIGO 일 경우에는 다음과 같이 3DM-GX5-45 ROS 패키지를 다운로드하고 설치해보자. 

DISTRO={hydro|indigo}
cd ~/catkin_ws
rosdep update
rosdep check --from-paths src/microstrain_3dm_gx5_45/ --rosdistro=$DISRO
rosdep install --from-paths src/microstrain_3dm_gx5_45/ --ignore-src --rosdistro=$DISTRO --simulate
rosdep install --from-paths src/microstrain_3dm_gx5_45/ --ignore-src --rosdistro=$DISTRO
catkin_make
source devel/setup.bash

만약, ROS가 최신 MELODIC 버전이라면 github에서 소스코드를 다운로드한 후 다음과 같이 빌드해서 ROS 패키지를 설치해야 한다.
cd ~/catkin_ws/src
git clone https://github.com/ros-drivers/microstrain_mips.git
cd ..
catkin_make -j1

참고로, 패키지 정보는 다음과 같이 정의되어 있다.

제대로 빌드되었다면, 패키지가 설치되며, 다음 명령을 통해 microstrain_mips 패키지를 확인할 수 있다.
rospack list-names
ROS 패키지 리스트

이제 센서와 컴퓨터를 USB로 연결해 본다. 센서와 USB에 연결된 포트 이름은 상황에 따라 동적으로 할당되므로, 다음 명령을 이용해 센서에 연결된 USB serial port 이름 리스트를 먼저 확인하고 적절한 포트 이름을 지정해야 한다. 
dmesg | grep tty

연결된 포트는 아래 명령으로 좀 더 자세한 정보를 확인할 수 있다.
ls -l /dev/ttyACM0

센서 정보는 다음 명령을 통해 확인할 수 있다.
cd ~/catkin_ws/devel/lib/microstrain_mips
./GX4-45_Test /dev/ttyACM0 115200

GNSS 센서와 연결상태 확인

이제 다음과 같이 ROS node를 실행해 본다. 참고로, 아래 글의 파라메터를 확인해 적절한 값을 입력해야 동작한다. 예를 들어, 포트이름을 정확히 입력하지 않으면 센서의 ROS node는 실행되지 않을 것이다.
rosrun microstrain_mips microstrain_mips_node _port:=/dev/ttyACM0 _device_setup:=true

이렇게 실행된 결과 다음과 같은 토픽 데이터를 얻을 수 있다. 
각 topic data 를 살펴보면 다음과 같다.
  • rostopic echo /imu/data
microstrain_mips_node가 생성한 ROS 토픽
참고로, IMU 데이터 구조는 ROS IMU Sensor Driver 에 설명되어 있다. Accelerometers, Gyroscopes, Magnetometers, Orientation로 구성되어 있으며, IMU데이터에서 많이 사용하는 Orientation은 quaternion 형태로 출력된다.
imu/data (sensor_msgs/Imu) 토픽은 quaternion orientation 추정값을 포함하고, imu/data_raw (sensor_msgs/Imu) 토픽은 accelerometer, gyroscope 데이터를 포함한다. imu/msg (sensormsgs/MagneticField)는 magnetometer 데이터를 포함한다.  
  • rostopic echo /gps/fix

  • rostopic echo /nav/odom

  • rostopic echo /nav/status

ROS node 에서 생성된 데이터가 제대로 출력되는 것을 확인할 수 있다.

3DM-GX5-45 패키지 기능 및 파라메터
다음은 센서 ROS 패키지에서 제공하는 서비스이다.
이 패키지에서 사용하는 파라메터 중 주요한것을 살펴보면 다음과 같다. 이 파라메터는 ROS node 실행 시 _parameter:=value 형식으로 설정할 수 있다.
  • port (string, default: /dev/ttyACM0): Serial port - Linux only
  • baud_rate (int, default: 115200): Baud rate of serial connection
  • device_setup (bool, default: true): If true, puts device in idle mode and configures the device.If false, skips configuration. Important: the configuration parameters below are not effective unless this flag is true.
  • dynamics_mode (int, default: 1): Vehicle dynamics mode 0x01=Portable, 0x02=Automotive, 0x03=Airborne
  • declination_source (int, default: 2): Possible declination sources: 0x01=Node, device reports magnetic north, 0x02=Internal World Magnetic Model, 0x03=Manual (see declination parameter)
  • gps_frame_id (string, default: wgs84): Value for the frame_id field in the header of the NavSatFix message published on the gps/fix topic
  • imu_frame_id (string, default: base_link): Value of the frame_id field in the header of the Imu message publised in the imu/data topic
  • odom_frame_id (string, default: wgs84): Value of the frame_id field in the header of the Odometry message published on the nav/odom topic
  • odom_child_frame_id (string, default: base_link): Value of the child_frame_id field in the Odometry message published on the nav/odom topic.
  • publish_gps (bool, default: true): Sets if ~gps/fix should be advertised/published or not. Note - to maximize performance you may want to only publish the Odometry messages
  • gps_rate (int, default: 1): Target update (publishing) rate for gps/fix messages. See update [[#rates] Update Rates] below.
  • imu_rate (int, default: 10): Target update (publishing) rate for imu/data messages. See update [[#rates] Update Rates] below.
  • odom_rate (int, default: 10): Target update (publishing) rate for nav/odom messages. See update [[#rates] Update Rates] below.
여기서 data update rate는 Hz 단위이다. 데이터 packet rate는 base_rate/decimation 이다. 3DM-GX4-45의 경우, 다음 rate에서 테스트되었다.
  • GPS - base rate = 4 Hz
  • IMU - base rate = 500 Hz
  • Filter - base rate = 500 Hz
Odometry 메시지는 현재 pos.position인 longitude(x), latitude(y)와 ellipsoid height(z)값을 리턴해 준다. pose.covariance와 twist.covariance는 position와 attitude의 대각성분(diagonal element)를 포함하고 있다.

Nav Status 메시지 통신 프로토콜은 다음과 같다. 
  • filter_state
    • 0x00 – Startup
    • 0x01 – Initialization (see status flags)
    • 0x02 – Running, Solution Valid
    • 0x03 – Running, Solution Error (see status flags)
  • dynamics mode
    • 0x01 – Portable (device default)
    • 0x02 – Automotive
    • 0x03 – Airborne
  • status_flags
    • See device documentation
Nav Sat Fix 메시지는 다음과 같다. Position co-variance는 수평, 수직 정확도를 기반으로 대각성분을 채운다. status.status 필드는 LLH() position data "valid flag"-1이다.
  • 0x0001 – Latitude and Longitude Valid
  • 0x0002 – Ellipsoid Height Valid
  • 0x0004 – MSL Height Valid
  • 0x0008 – Horizontal Accuracy Valid
  • 0x0010 – Vertical Accuracy Valid
  • E.g., if all valid, then the status.status field should be 30.
함께 제공되는 mip_sdk_user_functions은 C함수 API로 RS232를 통해 센서와 명령+데이터를 입출력할 때 사용한다.

마무리
이 글에서는 고정밀 GNSS와 ROS를 연동하는 방법을 간단히 소개하였다. GNSS와 LiDAR 데이터를 연계하면, 실시간으로 하나의 좌표계안에 정합된 스캔 데이터 점군을 획득할 수 있다. 이는 로보틱스, 자율주행차와 같이 실시간으로 공간정보를 획득해야 할 때 매우 유용한 기술이다. 

레퍼런스




2019년 6월 8일 토요일

인공지능과 미디어아트 플랫폼

이 글은 인공지능과 미디어아트의 관계를 다룬 내용을 간략히 소개한다.

인공지능, 특히 딥러닝 기술이 무르익어가는 단계에서 여러 분야에 대한 응용 노력이 많아지고 있다. 물론 예술 분야도 예외가 아니어서, 인공지능 기술이 예술 플랫폼에서 여러가지 사례로 활용되고 있다.

예술 분야에서도 인공지능을 이용한 플랫폼이 개발되었는 데, RUNWAY는 그 중 하나이다. 이 플랫폼을 이용하면, 머신러닝 환경을 설치하고, 딥러닝 모델 패키지를 설치하는 노력이 훨씬 줄어든다.

이 플랫폼을 이용하면, CNN, OBJECT DETECTION, CAPTION, GAN 등 다양한 모델을 클릭 몇번으로 다운로드하여, JAVASCRIPT 등 다양한 방식으로 본인의 어플리케이션과 연결해 미디어아트를 연출할 수 있다. 
기본 제공 딥러닝 모델

객체 인식 

얼굴 특징 인식

실시간 인식된 얼굴 특징 벡터

각 분야의 특성이 접목된 이런 머신러닝 플랫폼은 앞으로 점차 많아질 것이다.

2019년 6월 5일 수요일

벨로다인 LiDAR 기반 SLAM 하기

이 글은 LiDAR(Light Detection and Ranging) 기반으로 SLAM 하는 방법을 간략히 설명한다. 슬램은 임의의 위치에서 상대적 거리를 측정할 수 있는 센서를 이용해 실시간으로 지도를 생성하는 기술이다. 이 기술은 무인자율차 등 실시간으로 2, 3차원 지도를 생성해야할 때 사용한다.
실시간 SLAM(Simultaneous localization and mapping) 기반 3D 맵(LOAM)

이 글에서 SLAM을 활용해 보기 위해서 저가의 VLP16 벨로다인 센서를 사용한다. 참고로, 이 방법은 우분투 ROS 환경에서 실행된다. 여기서 사용하는 환경은 ROS melodic 버전을 사용하였으며, 오드로이드 우분투 18.04 기반이다(이전 설치 글 참고). 우분투, 벨로다인 LiDAR 드라이버, ROS, RViz 설치 방법은 다음 링크를 참고하길 바란다.
이 글에서는 SLAM의 원리를 다루지는 않는다. SLAM의 이론적 설명은 다음 링크를 참고한다.
SLAM은 대부분 ROS 패키지를 사용하므로, 이전 글 참고해 미리 설치해 놓어야 한다.

LOAM SLAM
우선 SLAM 에서 잘 알려진 LOAM(Laser Odometry and Mapping) 방식 SLAM을 만들어보자. 다음과 같이 github에서 소스코드를 받고, 순서대로 빌드해 본다(링크1, 링크2 참고).

$ cd ~/catkin_ws/src/
$ git clone https://github.com/laboshinl/loam_velodyne.git
$ cd ~/catkin_ws
$ catkin_make -DCMAKE_BUILD_TYPE=Release
$ source ~/catkin_ws/devel/setup.bash

참고로, 오드로이드, 라즈베리파이 같이 램 용량이 적은 컴퓨터에서는 컴파일 에러가 발생한다. 이 경우, 부록에 설명된 방법대로 스왑 용량을 설정해 컴파일 빌드하면 된다(컴파일이 몇시간 걸릴 수 있다).

이제 roscore를 실행하고, 다음 명령을 실행한다.
roslaunch loam_velodyne loam_velodyne.launch

LOAM SLAM을 이용해 회사 사무실을 LiDAR로 스캔해 본 결과는 다음과 같다.

점군이 모여있는 부분은 회사에 설치된 파티션이고, 그 외에 점들이 흩어져 있는 부분들은 천장 및 바닥이다. 파티션의 경계선은 뚜렷하게 표시된 맵이 생성되지만, 아직 좌표계, 캘리브레이션, IMU 등을 제대로 설정하지 않은 상황이라, SLAM 맵 정확도가 높지는 않아 보인다. 또한, 창쪽 유리가 반사되어 노이즈가 생기는 것을 확인할 수 있다.

참고로, VLP16의 스캔 수직범위는 크지 않아, 360도 스캔을 위해서는 스캐너를 회전시켜야 한다. 아래 영상은 LiDAR를 회전시켜 360도로 점군을 획득해 맵을 생성하는 예이다.

LOAM SLAM

참고로, 다음 명령을 이용해 미리 획득된 데이터를 플레이하거나 읽을 수 있다.
rosbag play ~/Downloads/velodyne.bag 
roslaunch velodyne_pointcloud VLP16_points.launch pcap:="$HOME/Downloads/velodyne.pcap"

LeGO LOAM
LeGO LOAM 링크를 방문해, 다음과 같이 소스를 다운로드후 빌드를 준비한다.
wget -O ~/Downloads/gtsam.zip https://github.com/borglab/gtsam/archive/4.0.0-alpha2.zip
cd ~/Downloads/ && unzip gtsam.zip -d ~/Downloads/
cd ~/Downloads/gtsam-4.0.0-alpha2/
mkdir build && cd build
cmake ..
sudo make install

다음과 같이 소스를 빌드한다.
cd ~/catkin_ws/src
git clone https://github.com/RobustFieldAutonomyLab/LeGO-LOAM.git
cd ..
catkin_make -j1

다음과 같이 ROS 패키지 실행한다.
roslaunch lego_loam run.launch


만약, 벨로다인에서 저장된 ROS bag 파일이 있다면, 다음 명령을 이용해 재생하여 rviz에 데이터를 표시할 수 있다. 참고로, LeGO 웹사이트에서 샘플 데이터 bag 파일을 다운로드 할 수 있다.
rosbag play *.bag --clock --topic /velodyne_points /imu/data

실행결과는 다음과 같다.
LeGO LOAM

LOAM이나 LeGO이외에도 여러가지 SLAM방식이 존재한다. 그러므로, 응용 목적에 따라 적합한 것을 사용해야 한다.
HDL graph SLAM

부록: 오드로이드 cc1plus internal compile 에러 솔류션
오드로이드는 내부 램 용량이 작은 임베디드 컴퓨터이기 때문에 컴파일 시 cc1plus internal compile error 가 발생될 수 있다. 이 경우, 터미널에서 다음과 같이 설정한다.

dd if=/dev/zero of=/swapfile bs=1024 count=4194304
chown root.root /swapfile
chmod 0600 /swapfile
mkswap /swapfile
swapon /swapfile

설정된 스왑 디스크 크기를 확인해 본다.
free -m

이렇게 해도 안된다면, 컴파일 시 make -j 옵션 대신 make 를 사용한다(관련 링크).

참고로, 임베디드 장치는 메모리 크기가 2~4G이며 스왑은 구성되어 있지 않다. 이 경우, 컴파일 프로세스에서 g++: internal compiler error: Killed (program cc1plus) 오류가 발생한다. 이 오류는 메모리가 부족하여 발생하므로, 스왑을 추가하여 문제를 해결할 수 있다(링크 참고).

레퍼런스

오드로이드 우분투 기반 벨로다인 라이다와 ROS 설치, 연결 및 설정

로버나 드론 기반에서 LiDAR를 연결해 스캔하고 데이터를 처리하고자 할 때, 라즈베리파이, 오드로이드(ODROID)와 같은 임베디드 컴퓨터를 사용해야 하는 경우가 있다.

이 글은 오드로이드에 연결된 벨로다인 VLP16을 이용해 스캔 데이터를 ROS RVIZ로 처리하는 방법을 간략히 정리한다. 참고로, 지난번 글에서는 윈도우에서 VPL16 LiDAR 설정 방법을 다루었었다. 이 내용을 진행하기 전에 우분투는 오드로이드에 설치되어 있었다(설치방법 참고 링크).
Velodyne VLP16 ROS RViz 실행 모습(오드로이드)

ROS 벨로다인 LiDAR VPL16 설정 및 패키지 설치
벨로다인 설정 및 설치 방법은 아래 글을 참고하였다.
LiDAR 이더넷 연결 단계는 다음과 같다. 
  1. LiDAR 파워 연결
  2. LiDAR와 오드로이드 간 이더넷 케이블 연결
  3. 오드로이드 WiFi 끄기
  4. Networks Connections 실행. edit를 선택해 IPV4 설정 탭 선택. "Method"를 "Manual"로 변경
  5. add를 선택해 IP 주소 필드에 192.168.1.70 설정
  6. Netmask는 255.255.255.0, Gateway는 0.0.0.0 설정
  7. Routes > Use this connection only for resources on its network 선택 (for WiFi connection)
  8. OK > save 선택
IPv4 setting

Routes setting

LiDAR 설정단계는 다음과 같다.
  1. 터미널에서 다음 명령 입력. sudo ifconfig eth0 192.168.3.100
  2. LiDAR IP 주소에 고정 라운트를 추가함. IP주소는 제품 CD 케이스에 포함되어 있음 (참고로 벨로다인 VLP16 라이다에 기본 설정된 IP는 192.168.1.201 임). sudo route add 192.168.XX.YY eth0 
  3. LiDAR 설정 체크를 위해, 인터넷 브라우저에 192.168.XX.YY 입력해 세부 설정 화인

VLP16 ROS 패키지를 다음과 같이 설치한다. 참고로 VERSION은 melodic이다.
  1. sudo apt-get install ros-VERSION-velodyne
  2. cd ~/catkin_ws/src/ && git clone https://github.com/ros-drivers/velodyne.git
  3. rosdep install --from-paths src --ignore-src --rosdistro YOURDISTRO -y
  4. cd ~/catkin_ws/ && catkin_make
제대로 설치가 되면, 다음과 같이 터미널에서 ROS를 실행한다.
source ~/.bashrc
roscore
ROS 실행된 모습

터미널에서 다음과 같이 velodyne VLP16 노드와 토픽을 실행한다.
roslaunch velodyne_pointcloud VLP16_points.launch
rosnode list
rostopic echo /velodyne_points

velodyne pointcloud node 실행 후 rosnode list 결과

rostopic echo 실행 결과

rviz 를 다음과 같이 실행한다.
rosrun rviz rviz -f velodyne

RViz에서 다음과 같이 Point Cloud 토픽 데이터를 볼 수 있도록 설정한다.
  1. RViz > display > Add 선택 후 Point Cloud2 선택 확인
  2. Topic 필드에 Point Cloud2 탭에서 "/velodyne_points" 입력 후 확인
설정 후 다음 같이 벨로다인에서 획득한 포인트 클라우드를 확인할 수 있다.

RViz 실행 모습

추신 - 요즘 오랜만에 시간이 나서 1년동안 쌓여 있던 장비와 컨텐츠들을 꺼내 쌓인 먼지를 털고 기억을 떠올려가며 정리한다. 회사가 정출연이라 직업은 연구하는 것인데, 여기 저기서 행정으로 인터럽트가 걸리고, 정신차려보면 몇년이 흘러 있는 경우가 많음. 브랜드 기술력 쌓으며 연구하기 정말 어려운 환경. - 넌센스

추신 - 시스템 안전성 테스트를 위해 2019년 6월 5일부터 현재(6월 17일)까지 LiDAR를 실행해 보았다. 아직 잘 동작하고 있다.

부록: VeloView 설치 및 실행
다음 링크를 참고해 VeloView를 설치하고 실행한다. 단, VeloView 설치 파일은 아직 64비트만 지원하고 있어, 직접 소스코드를 빌드해야 한다. 이 경우, QT4 패키지 업데이트 부분이 있는 데, 이는 오드로이드의 EGL과 Segmentation fault를 유발한다. 이 경우, 여기를 참고해 QT를 다시 설정해야 한다.
레퍼런스

Keras와 CoLab을 활용한 간단한 딥러닝 모델 훈련, 모델 저장 및 재사용

딥러닝 개발은 코딩보다는 딥러닝 환경 설과 데이터 구축에 많은 노력이 들어간다. 예를 들어, 딥러닝 환경설정은 무한 삽질로 빠지는 경우가 있다. 우분투, 텐서플로우(tensorflow), 케라스(keras) 등의 설정은 GPU와 궁합이 잘 맞지 않을 경우 우분투부터 여러번 설치해야 할 수 있다. 딥러닝 학습 모델에 필요한 데이터셋을 모으고 라벨링하는 작업은 정말 피곤한 일이다. 이후, 라벨링 된 데이터셋을 얻은 후에도 딥러닝 모델 학습에 맞게 구조화하는 작업도 귀찬은 것이다. Keras는 이런 일을 단순화시켜주는 기능을 제공한다.

이 글에서는 딥러닝 환경설정은 구글의 CoLab을 사용해 삽질을 하지 않는다. Keras의 ImageDataGenerator는 수집한 데이터 파일들을 폴더에 다음과 같이 넣어 두면, 폴더명을 라벨로 사용해 각 데이터 파일에 라벨링을 자동으로 처리한다.
trainset/cats
         /dogs
testset/cats
         /dogs
이 글은 CNN모델을 학습할 때 좀 더 손쉬운 학습 데이터를 준비, 훈련, 저장 및 재사용 방법을 간략히 정리한다. CNN모델 소스코드는 이 링크를 참고하였다. CNN모델 자체에 대한 설명은 여기를 참고한다.

머리말
이 글은 데이터 준비 및 훈련 방법에만 초점을 맞추기 위해, Cat, Dog 이미지 데이터를 사용한다. 딥러닝 도구는 keras의 CNN을 사용할 것이다.

데이터 준비
우선 다음 압축파일을 다운로드 받는다. 이 파일 안에는 구글에서 얻은 고양이와 개 이미지 파일들을 훈련용 8000개, 테스트용 2000개 가지고 있다.
CoLab 서버에 훈련 데이터셋을 업로드하기 위해, 압축파일을 풀고 dataset 폴더를 별도 zip 파일으로 압축한다. 참고로, 이 데이터셋 구조는 다음 그림과 같다.
딥러닝 데이터셋 구조

CoLab에 접속해 python3 파일을 하나 새로 만든다.
그리고, 다음과 같이 CoLab의 파일 업로드 함수를 이용해 CoLab 서버에 압축한 zip파일을 전송한다.

from google.colab import files
uploaded = files.upload()

참고로 CoLab은 우리가 구글에서 임시로 빌려쓰는 클라우드 서버기 때문에 사용하지 않고 일정 시간이 지나면 자동으로 끊어지고 업로드한 데이터도 사라질 수 있다. 그래서, 학습한 모델은 바로 로컬에 다운로드받거나 구글 드라이브에 옮겨 놓는 것이 좋다. 

다음 명령을 CoLab에서 실행해, 업로드한 압축파일을 푼다. 라벨링은 압축 해제된 폴더 이름에 따라 ImageDataGenerator의 flow_from_directory함수에서 자동으로 처리될 것이다.

!unzip dataset.zip

코딩 및 실행
CoLab 을 열고, 다음과 같이 코딩하고 실행한다. 참고로, 이 딥러닝 모델의 구조는 Data(64, 64, 3)-Conv(64, 64, 3)-MaxPooling(2, 2)-Conv-MaxPooling(2, 2)-Flatten-Dense(128)-Dense(1) 이다.

# Importing the Keras libraries and packages
from keras.models import Sequential
from keras.layers import Convolution2D
from keras.layers import MaxPooling2D
from keras.layers import Flatten
from keras.layers import Dense

# Initialising the CNN
classifier = Sequential()

# Step 1 - Convolution
classifier.add(Convolution2D(32, 3, 3, input_shape = (64, 64, 3), activation = 'relu'))  # Convolution2D(filter number, filter row, filter col, input_image(x, y, channel), activate function)

# Step 2 - Pooling
classifier.add(MaxPooling2D(pool_size = (2, 2)))  # max pooling row, col

# Adding a second convolutional layer
classifier.add(Convolution2D(32, 3, 3, activation = 'relu'))
classifier.add(MaxPooling2D(pool_size = (2, 2)))

# Step 3 - Flattening
classifier.add(Flatten())  # 2D -> 1D network

# Step 4 - Full connection
classifier.add(Dense(output_dim = 128, activation = 'relu'))   # Dense(output weight link number, activation function)
classifier.add(Dense(output_dim = 1, activation = 'sigmoid'))

# Compiling the CNN
classifier.compile(optimizer = 'adam', loss = 'binary_crossentropy', metrics = ['accuracy'])

# Part 2 - Fitting the CNN to the images

from keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale = 1./255,
                                   shear_range = 0.2,
                                   zoom_range = 0.2,
                                   horizontal_flip = True)

test_datagen = ImageDataGenerator(rescale = 1./255)

training_set = train_datagen.flow_from_directory('training_set',
                                                 target_size = (64, 64),
                                                 batch_size = 32,
                                                 class_mode = 'binary')

test_set = test_datagen.flow_from_directory('test_set',
                                            target_size = (64, 64),
                                            batch_size = 32,
                                            class_mode = 'binary')

classifier.fit_generator(training_set,
                         samples_per_epoch = 8000,
                         nb_epoch = 25,
                         validation_data = test_set,
                         nb_val_samples = 2000)

그럼 다음과 같이 모델이 훈련되는 것을 확인할 수 있다.
학습된 결과

분류 예측
구글에서 얻은 고양이나 강아지 사진을 random.jpg 로 저장하고, 앞서 파일을 올린 방식과 같이 CoLab 서버에 파일 업로드한다. 그리고, 다음 코드를 CoLab에 입력해 실행해 본다.

import numpy as np
from keras.preprocessing import image
test_image = image.load_img('random.jpg', target_size = (64,64))
test_image = image.img_to_array(test_image)
test_image = np.expand_dims(test_image, axis = 0)
result = classifier.predict(test_image)
training_set.class_indices
if result[0][0] >= 0.5:
  prediction = 'dog'
else:
  prediction = 'cat'
print(prediction)

그럼, 다음과 같이 훈련된 딥러닝 모델이 적용 예측 결과가 표시될 것이다.
예측 결과

훈련된 딥러닝 모델 저장
이제 훈련된 딥러닝 모델을 다음 명령을 이용해 저장한다.
from keras.models import load_model

classifier.save('DL_CNN_cat_dog.h5')

from google.colab import files
files.download('DL_CNN_cat_dog.h5')  # from colab to browser download

훈련된 딥러닝 모델 불러와 사용하기
저장된 딥러닝 모델은 다음과 같이 간단히 로딩해 사용할 수 있다.
from keras.models import load_model
model = load_model('DL_CNN_cat_dog.h5')

똑같은 예측 소스코드로 실행해 보면 동일한 결과를 확인할 수 있다.
import numpy as np
import matplotlib.pyplot as plt

from keras.preprocessing import image
test_image1 = image.load_img('random4.jpg', target_size = (64,64))
test_image2 = image.img_to_array(test_image1)
test_image2 = np.expand_dims(test_image2, axis = 0)
result = model.predict(test_image2)
training_set.class_indices
if result[0][0] >= 0.5:
  prediction = 'dog'
else:
  prediction = 'cat'

origin_image = image.load_img('random4.jpg')
plt.imshow(origin_image)
print('  => predict = ', result[0][0], ', class = ', prediction)

로딩된 모델을 이용한 예측 결과

참고로 저장된 모델은 스마트폰, 웹 기반 앱에서 로딩해 사용할 수 있다. 관심이 있다면 다음 링크를 참고한다.


이 예제의 폴더 구조만 약간 변경하면 다양한 분야에서 CNN기반 딥러닝 모델 학습을 할 수 있다.

레퍼런스

오드로이드 XU4 우분투와 ROS, RVIZ 설치하기

오드로이드(ODROID)는 개발용으로 자주 사용되는 임베디드 컴퓨터로 라즈베리파이와 비슷한 크기를 가지나 성능은 훨씬 좋다.

이 글은 오드로이드에 로버 기반 LiDAR 스캔 장치를 개발하고 데이터를 획득해 볼 생각으로 진행한 우분투와 ROS(Robot Operating System)설치 방법을 간략히 정리한다.

참고로 NVIDIA, 라즈베리파이에 ROS 설치 후 비전을 개발하는 방법은 여기를 참고하길 바란다.

오드로이드 연결
다음 그림과 같이, 모니터 HDMI, 키보드, 마우스 및 WiFi 동글을 연결한다.

우분투 설치
다음 링크를 참고하여, 우분투 18.04를 설치한다.
설치 순서는 다음과 같다.
  1. ODROID 사이트에서 제공하는 우분투 이미지 다운로드
  2. 7-Zip 이용해 우분투 이미지 압축 해제
  3. Win32 Disk Imager와 이미지를 이용해 micro SD 메모리 부팅 드라이브 만들기
  4. micro SD 메모리를 오드로이드 슬롯에 삽입
  5. 오드로이드 파워 켜기
  6. 오드로이드 WiFi 동글 삽입 후 WiFi 설정
  7. 오드로이드 우분투 날짜 설정 
  8. 터미널창에서 다음 명령 이용해 우분투 업데이트 및 설치
$ sudo apt update
$ sudo apt upgrade
$ sudo apt dist-upgrade
$ sudo reboot
업데이트 중에 다음 같은 lock 파일 에러가 나올 수 있다.
E: Could not get lock /var/lib/apt/lists/lock - open (11: Resource temporarily unavailable)

이 경우, rm 명령을 실행해 lock 걸린 해당 파일을 삭제한다. 
sudo rm /var/lib/apt/lists/lock

재부팅하면 우분투가 설치된다. 이제 여러 패키지를 설치할 수 있다.
$ sudo apt install smplayer


3차원 그래픽 성능은 다음과 같이 확인한다. 
$ glmark2-es2
$ es2gears

webglsamples.org 사이트를 방문하면 webgl 예제로 성능을 테스트할 수 있다. 


ROS 설치
다음 링크를 참고해 ROS를 설치한다. ROS 버전은 melodic 이다.
오드로이드는 GPU가 없으므로 OpenGL 관련 패키지 실행시 에러가 있다. 이는 임베디드 보드에서 ROS의 RViz 사용 시 고질적인 GL 관련 에러를 발생한다. 이 문제를 해결하기 위해서 다음 명령을 우분투 터미널에서 입력한다(관련 링크). 

sudo -s
wget -O /usr/local/bin/odroid-utility.sh https://raw.githubusercontent.com/mdrjr/odroid-utility/master/odroid-utility.sh
chmod +x /usr/local/bin/odroid-utility.sh
odroid-utility.sh

오드로이드 유틸리티 쉘을 실행해 나오는 화면에서 6번 화면을 선택해 업데이트한다. 

내장된 Embedded GL인 EG를 사용해야 하므로, 이에 맞게 GUI로 사용되는 QT를 다시 업데이트해야 한다. 다음 명령을 터미널에 입력해 실행한다(관련 링크).

sudo apt update && sudo apt upgrade
sudo apt install libfbclient2 libodbc1 libpq5 libsybdb5 libgles2-mesa-dev libxext-dev libinput-dev libxkbcommon-dev
wget https://dn.odroid.com/5422/ODROID-XU3/Ubuntu/qt5.9.5_armhf_bionic.tar.gz
tar xvfz qt5.9.5_armhf_bionic.tar.gz
cd qt5.9.5_armhf_bionic/
sudo dpkg -i *.deb

제대로 설치되었다면, 다음 명령을 실행했을 때 QT 3D 그래픽 창을 볼 수 있다. 
DISPLAY=:0.0 /usr/lib/arm-linux-gnueabihf/qt5/examples/opengl/hellogles3/hellogles3


참고로, 디스크 용량을 절약하려면, 다운로드한 파일들을 다음처럼 삭제다.
cd ..
rm -rf qt5.9.5_armhf_bionic*

ROS와 RVIZ 실행
다음 명령을 실행한다.
source ~/.bashrc
roscore

이제 터미널 창을 하나 더 띄우고, 다음 명령을 실행한다. 혹시 GL관련 에러가 있다면, ROS RVIZ Troubleshooting 페이지를 참고해 "export LIBGL_ALWAYS_SOFTWARE=1" 명령어를 이용하여 하드웨어 가속기를 OFF한다. 
rosrun rviz rviz

그럼 다음과 같이 오드로이드 우분투 환경에서 RVIZ 화면을 확인할 수 있다.


ROS 상세한 사용법은 다음 튜토리얼 및 레퍼런스를 참고한다.
기타, ROS 관련 3D 이미지 비전은 이 링크를 참고한다.