분류 전체보기 (317)

반응형

MAC OS 환경변수 설정하기

 

텍스트 파일이 자동으로 실행됨MAC Os에서 터미널이 실행될 때, ~/.zshrc 라는 텍스트 파일이 자동으로 실행됨

예를들어, 홈폴더 아래 anaconda/bin 폴더를 PATH 환경변수에 추가하고 싶은 경우, 아래 문구를 ~/.zshrc 에 넣어주면된다.

export PATH="/Users/username/anaconda3/bin:$PATH"

 

또는 Linux 와 같이 /etc/profile 또는 ~/.bash_profile 에 환경 변수를 넣는것도 좋은 방법이다. 이후에 ~/.zshrc 파일을 열고

source /etc/profile
source ~/.bash_profile 

 

문구를 쓰면 위 텍스트 파일을 터미널을 열면 자동으로 명령 실행하기 때문에 환경변수로 반영된다.

반응형
반응형

하둡과 응용 프레임워크 2) 하둡 실행 환경 (YARN, Tez, Spark)

이전 포스팅에서 Map reduce 프레임워크의 한계에 대해 설명하고, 이를 보완하기 위하여 YARN, Tez, Spark 등이 사용된다는 것에 대해 간단하게 언급하였다. 하둡 아키텍쳐에 대해 다시 remind 를 해보자. 

 

Hadoop architecture

위 그림과 같이 데이터가 node 에 분산되어 저장되어있고, task 가 data node 에 할당되어 처리를 한 후에, 이 결과를 merge 하는 것이 하둡이 어떤 job 을 실행하는 방법이다. 이것이 이전 포스팅에서 언급한 '계산을 데이터로 보내는 것' (computation to data) 의 개념이라고 볼 수 있다. 이러한 방법은 불가능한 것을 가능할 수 있고, 무엇보다 더욱 효율적으로 (빠르게) job 을 처리할 수 있다. 병렬적으로 수행할 수 있고, 데이터의 이동이 최소화되기 때문이다. 하지만 문제는, MapReduce execution framwork 는 Map reduce paradigm 을 구현할 수 있는 application 에만 유용하다. 어떤 application 이 map reduce 를 통해 구현할 수 없는 경우에 문제가 생긴다. 이를 보완하기 위하여 YARN, Tez, Spark 등이 사용된다. 

 

Next Generation Execution Framworks

 

 

YARN 은 기본적인 Hadoop 의 execution engine 이다. 이 위에 YARN 위에서 동작하는 HBase 와 같은 application 이 있다. 또한 YARN 위에서는 Tez 와 Spark 와 같은 다른 framework가 올라갈 수도 있다. Pig 나 Hive 같은 application 은 TEZ 와 Spark (Hive 의 경우 TEZ와 Spark 모두 이용) 위에서 동작한다. 또한 Spark 는 YARN 없이도 동작할 수 있는 execution framework 이다. 

 

Tez 의 특징은 dataflow graph 를 지원하고, custom data type 을 지원한다. 따라서 맵 리듀스 프레임워크에서 처럼 모든 데이터의 입출력이 key-value pair 로 이루어져야하는 제약이 없다. Tez 를 활용하는 것의 장점은 자원을 효율적으로 관리하고 복잡한 태스크를 DAG (directed acyclic graph) 를 활용해서 실행할 수 있다는 것이다.  

 

Hive on Tez example 

Hive 는 backend execution engine 으로 Tez 를 이용하는 것을 지원한다. 예를 들어 아래 코드를 보자.

SELECT a.vendor, COUNT(*), AVG(c.cost) FROM a 
JOIN b ON (a.id = b.id)
JOIN c ON (a.itemid = c.itemid)
GROUP BY a.vendor

1) Original Hadoop MapReduce 를 사용한 해법

위의 쿼리는 여러개의 map reduce job 으로 나뉘어진다. 하나의 map reduce job 이 다른 job 의 인풋이 되고, 이것들이 조합이 되어 최종적인 쿼리의 결과를 가져올 수 있다. 

 

2) Tez 를 사용한 해법

Tez 를 사용하면 조금 더 간단하게 같은 작업을 수행할 수 있다. original map reduce 만을 사용했을 때와의 차이점은 intermediate map task 가 없다는 것이다. map reduce 의 경우 원래는 결과를 hdfs 에 저장하도록 되어있는데, 그러지 않고 데이터를 재사용함으로써 graph 를 간편화할 수 있고 이를 통해 효율적으로 같은 job을 수행할 수 있는 것이다. 

 

Spark 의 경우 advanced DAG execution engine 이며 cyclic data flow 를 지원한다. 또한 in-memory computing 을 지원한다. 우선 데이터 처리를 memory 위에서 할 수 있기 때문에 매우 빠르고, DAG 사이에 데이터 공유도 가능하다는 장점이 있다. 또한 Java, Scala, Python, R 언어를 지원하기 때문에 범용성이 높은 execution engine 이라고할 수 있다. 예를 들어 Spark python interface 를 통해 Logistic regression 을 수행하는 코드를 확인해보자. 

points = spark.textFile(...).map(parsePoint).cache()
w = numpy.random.ranf(size = D) # current separating plane 
for i in range(ITERATIONS):
  gradient = points.map(
  	lambda p: (1 / (1 + exp(-p.y*(w.dot(p.x)))) - 1) * p.y * p.x 
    ).reduce(lambda a, b: a + b)
  w -= gradient
print "Final separating plane: %s" % w

original map reduce 는 iterative data process 에 적용하기 매우 힘들다는 단점이 있었다. 바로 위 코드에서 iteration 이 등장하는데, 같은 데이터셋을 이용해서 gradient 를 여러번 반복해서 구해서 weight 를 업데이트하는 logistic regression 의 training 과정이다. 우선 같은 데이터셋을 여러번 반복해서 사용하기 때문에 .cache() 함수를 통해 데이터를 RAM 에 저장시킨다.  위 코드는 spark 공식 홈페이지의 예제 (http://spark.apache.org/examples.html)인데 original map reduce 와 100배 정도의 속도차이가 난다고 한다. 이러한 이유로 in-memory computing 이 가능한 경우 선호된다. 이 링크에서는 다양한 Spark 예제를 확인할 수 있다. 또한 spakr 는 Machine learning 을 위한 라이브러리도 제공하기 때문에 이를 직접 구현하지 않고도, high-level interface 를 사용할 수도 있다 (https://spark.apache.org/docs/2.1.0/ml-classification-regression.html).

 

References

코세라 - Hadoop Platform and Application Framework 강의를 참고하였습니다. 

반응형
반응형

Docker 를 통한 Hive 실습환경 구축 및 간단 예제

 

본 포스팅에서는 Hive 핵심정리 (다융 두 저, 에이콘 출판사) 의 3장 예제를 Docker 를 이용해 실습해 보았다. 

 

1. Docker 설치 

2. Apache Hive 2.3.2 docker container 다운로드 (https://github.com/big-data-europe/docker-hive)

3. "docker-compose.yml" 파일에서 코드 샘플 경로 마운팅 (C:\workspace\HiveBook\HiveEssentials-master\scripts 을 container 의 /HiveBook 폴더로 마운트) 샘플 코드는 Hive 핵심정리 (에이콘 출판사) 샘플코드 (https://github.com/willddy/HiveEssentials)를 활용하였음.

 

- 샘플코드를 container 에 mount 하기 위해서는 아래 hive-server 에서 volumes 으로 경로를지정하면됨

version: "3" 

services: 
  namenode: 
    image: bde2020/hadoop-namenode:2.0.0-hadoop2.7.4-java8 
    volumes: 
      - namenode:/hadoop/dfs/name 
    environment: 
      - CLUSTER_NAME=test 
    env_file: 
      - ./hadoop-hive.env 
    ports: 
      - "50070:50070" 
  datanode: 
    image: bde2020/hadoop-datanode:2.0.0-hadoop2.7.4-java8 
    volumes: 
      - datanode:/hadoop/dfs/data 
    env_file: 
      - ./hadoop-hive.env 
    environment: 
      SERVICE_PRECONDITION: "namenode:50070" 
    ports: 
      - "50075:50075" 
  hive-server: 
    image: bde2020/hive:2.3.2-postgresql-metastore 
    env_file: 
      - ./hadoop-hive.env 
    environment: 
      HIVE_CORE_CONF_javax_jdo_option_ConnectionURL: "jdbc:postgresql://hive-metastore/metastore" 
      SERVICE_PRECONDITION: "hive-metastore:9083" 
    ports: 
      - "10000:10000" 
    volumes: 
      - C:\workspace\HiveBook\HiveEssentials-master\scripts:/HiveBook 
  hive-metastore: 
    image: bde2020/hive:2.3.2-postgresql-metastore 
    env_file: 
      - ./hadoop-hive.env 
    command: /opt/hive/bin/hive --service metastore 
    environment: 
      SERVICE_PRECONDITION: "namenode:50070 datanode:50075 hive-metastore-postgresql:5432" 
    ports: 
      - "9083:9083" 
  hive-metastore-postgresql: 
    image: bde2020/hive-metastore-postgresql:2.3.0 
  presto-coordinator: 
    image: shawnzhu/prestodb:0.181 
    ports: 
      - "8080:8080" 

volumes: 
  namenode: 
  datanode:

 

4. hive-server 실행

docker-compose up -d
docker-compose exec hive-server bash

 

docker-compose up -d 는 각각의 docker-compose.yml 에 위치한 container 를 background 실행하는 명령어

 

The docker-compose up command aggregates the output of each container (essentially running docker-compose logs -f). When the command exits, all containers are stopped. Running docker-compose up -d starts the containers in the background and leaves them running.

 

Command Line Interface (cli) 에서 실행

 

1. beeline으로 실행하기

 

/opt/hive/bin/beeline -u jdbc:hive2://localhost:10000

 

2. hive 로 실행하기

hive

 

Hive cli 의 경우 하이브 클라이언트는 하이브가 설치된 동일한 장비여야한다. 하지만 비라인의 경우 하이브 서버를 JDBC 커넥션으로 연결하고 클라이언트와 동일 장비에 하이브 라이브러리를 설치할 필요가 없다. 따라서 비라인은 하둡 클러스터 바깥에서 원격으로 실행할 수 있다. 이외의 다양한 hive client 들에 대한 설명은 https://cwiki.apache.org/confluence/display/Hive/HiveServer2+Clients에서 찾아볼 수 있다. 

 

예를 들어, beeline 으로 실행하면 아래와 같은 명령어와 함께 beeline 커맨드가 실행된다.

 

Connecting to jdbc:hive2://localhost:10000 
Connected to: Apache Hive (version 2.3.2) 
Driver: Hive JDBC (version 2.3.2) 
Transaction isolation: TRANSACTION_REPEATABLE_READ 
Beeline version 2.3.2 by Apache Hive 
0: jdbc:hive2://localhost:10000>

 

sample code 를 mounting 했기 때문에 아래 경로에서 파일을 확인할 수 있다.

 

/HiveBook/Chapter_03/employee.txt

더보기

Michael|Montreal,Toronto|Male,30|DB:80|Product:DeveloperLead
Will|Montreal|Male,35|Perl:85|Product:Lead,Test:Lead
Shelley|New York|Female,27|Python:80|Test:Lead,COE:Architect
Lucy|Vancouver|Female,57|Sales:89,HR:94|Sales:Lead

Table 생성 및 데이터 삽입

CREATE TABLE employee
(
  name string,
  work_place ARRAY<string>,
  sex_age STRUCT<sex:string,age:int>,
  skills_score MAP<string,int>,
  depart_title MAP<STRING,ARRAY<STRING>>
)
ROW FORMAT DELIMITED
FIELDS TERMINATED BY '|'
COLLECTION ITEMS TERMINATED BY ','
MAP KEYS TERMINATED BY ':';

--Verify tables creations run in Beeline
!table employee

--Load data
LOAD DATA LOCAL INPATH '/HiveBook/Chapter_03/employee.txt' OVERWRITE INTO TABLE employee;

--Query the whole table
SELECT * FROM employee;

반응형
반응형

하둡  플랫폼과 응용 프레임워크 - Hadoop Basic module

 

하둡은 Doug Cutting and Mike Cafarella 에 의해 2005 년에 만들어졌다. 하둡의 핵심 아이디어는 '데이터를 계산하는 것' (data to computation)이 아니라 '계산을 데이터로 보내는 것' (computation to data) 이다.  Hadoop 의 핵심은 다음과 같다. 

 

Scalability : 어떠한 클러스터 환경에서도 적용 가능하다. 

Reliability : 분산 환경에서의 근본적인 가정은 Hardware 의 고장이 자주 생긴다는 것이다.  이것은 당연한 것이고, Hadoop 은 이를 핸들링하는 방법을 제공한다. (이를 Resilence 라고 부르기도한다.)

 

Hadoop distributed file system (HDFS) 와 Map reduce framework 는 기존의 google 의 computing system 과 file system 을 기반으로 만들어졌다. 

 

Hadoop 의 기본 모듈

 

1. Hadoop Common : 다른 module 이필요한 library, utility 를 갖고 있다. 

2. Hadoop Distributed File system : big data 를 클러스터에 분산해서 저장할 수 있는 파일 시스템이다. 

3. Hadoop YARN : 클러스의 resource management platform 이다. 

4. Hadoop MapReduce :  hadoop 의 분산 컴퓨팅 프레임워크다. 

 

HDFS

: Distributed, scalable, and portable file system written in Java for the Hadoop framework. 

 

일반적인 window, linux file system 은 C나 C++ 로 쓰여져있는데, HDFS 는 hadoop framework 를 위해 Java 로 만들어진 file system 이다. 각각의 HDFS 는 GB 에서 PB 에 이르는 매우 큰 파일을 저장한다. Data node 를 Replication 함으로써 reliability 를 확보한다. 

 

Hadoop 1.0 vs Hadoop 2.0

 

 

 

Hadoop 2.0 에서 바뀐 점은 YARN 이라는 cluster resource management 모듈이 생긴 것이다. 또한 Global manager 가 아니라 per application manager 로 바뀌었다.YARN 은 Map reduce 에 한정되지 않게 hadoop cluster 을 강화시키기 위한 목적으로 scalability 와 관련이 있다. YARN 은 cluster의 resource 를 capacity, guarantees, fairness 와를 기준으로 활용도를 향상시키도록 만든다. Hadoop 2.0에서는 Map reduce 뿐 아니라 graph process 나 iterative modeling 과 같은 다양한 프로그래밍 방법을 적용할 수 있다. 

 

 

 

Hadoop "Zoo" 

 

 

HDFS 와 Map reduce 에 대해서는 어떤것인지 다루었다. 그런데 그 위에서 작동하는 Oozie, Pig, Hive 는 무엇인가? 이러한 Hadoop eco system 은 Google 의 기술 스택에서 출발했다. Chubby, MapREduce, MySQL Gateway, Bigtable 과 같은 구글의 original 기술 스택을 기반으로 hadoop eco system 이 발전했다. 아래는 구글과 페이스북의 데이터 관련 기술 Stack 의 예시이다. 

 

 

 

맵리듀스와 하둡 execution environment

 

맵리듀스는 Job tracker, task tracker 로 나뉘며, Job tracker 는 master node (name node) 에 task tracker 는 data node 에서 실행된다. HDFS 환경에서 맵리듀스의 한 가지 장점은 실제 computation 이 각각의 data node 에서 그 node 에 있는 data 를 통해서 처리되기 때문에 data 이동을 최소화할 수 있다는 것이다. 또한 하나의 노드에 fitting 이 되지 않는 데이터를 처리할 수 있다. (맵리듀스 관련 이전 포스팅 보기) 하지만 맵리듀스는 Java 를 기반으로 규약에 맞게 프로그래밍을 한 후에 job 을 submission 하는 방식으로 구동되기 때문에 매번 이러한 프로그램을 만들어야한다는 부담이 있다. 따라서 맵 리듀스를 내부적으로 구현한 어플리케이션이 등장했다. 하지만 또 문제는 맵리듀스 만으로 해결할 수 없는 문제가 있을 수 있다는 것이다. 대부분의 데이터 프로세싱이 맵리듀스 방법을 통해 해결 가능했으나, 아닌 문제도 많았다. 

 

예를 들어 다음과 같다. 

 

1) Interactive data exploration : 탐험적 데이터 분석을 하는 경우 데이터로부터 결과를 구하는 작업을 여러분 수행한다. 그때마다 Map reduce 방법을 이용해서 데이터를 불러오는 것은 비효율적이다.  

2) Iterative data processing : 데이터 프로세싱을 반복적으로 수행하는 경우도 마찬가지로 맵리듀스 방법이 적절하지 못하다. 이와 같은 상황에서 메모리에 데이터를 불러온 후에 이를 통해 프로세싱을 하는 편이 더욱 효율적일 것이다. 

 

이러한 문제점을 해결하고자 나온 것이 YARN, Tez, Spark 와 같은 next generation execution framework 이다. 이러한 프레임워크에서는 task 의 복잡한 Directed acyclic graph (DAG) 를 지원하고, data 의 in memory processing 을 지원한다. 다음 포스팅에서는 YARN, Tez, Spark 를 다루어보려고한다.

 

References

코세라 - Hadoop Platform and Application Framework 강의를 참고하였습니다. 

반응형
반응형

[딥러닝강의] GPU 와 딥러닝 소프트웨어

Deep Learning Frameworks (https://analyticsindiamag.com/evaluation-of-major-deep-learning-frameworks/)

CPU vs. GPU

 

왜 딥러닝에서 CPU 가 아닌 GPU 를 사용할까? GPU 의 원래 목적은 그래픽을 rendering 하는 것이다. GPU 를 만드는 회사는 크게 NVIDIA 와 AMD 로 나뉜다. 여러 커뮤니티에서 NVIDIA 와 AMD 중에 무엇이 더 나은지 논쟁을 한다. 하지만 딥러닝 측면에서는 NVIDIA 의 GPU 가 더욱 좋다. AMD GPU 는 딥러닝 목적으로 사용하기 힘들다. 따라서 딥러닝에서 GPU 를 말하면 대부분 하나의 회사 NVIDIA 의 GPU 를 의미한다. 

 

Rendering 이란?

평면인 그림에 형태·위치·조명 등 외부의 정보에 따라 다르게 나타나는 그림자 색상 농도 등을 고려하면서 실감나는 3차원 화상을 만들어내는 과정 또는 그러한 기법을 일컫는다. 즉, 평면적으로 보이는 물체에 그림자나 농도의 변화 등을 주어 입체감이 들게 함으로써 사실감을 추가하는 컴퓨터그래픽상의 과정이 곧 렌더링이다. [네이버 지식백과] 렌더링 [rendering] 

 

CPU 와 GPU 의 차이

CPU 와 GPU 의 차이

1) 코어의 종류와 숫자

 

CPU 는 GPU 보다 더 적은 코어를 갖고 있지만 각각의 코어가 GPU 보다 더 강력한 컴퓨팅 파워를 갖고 있다. 따라서 CPU 는 순차적인 작업 (Sequential task) 에 더 강점이 있다. 반면 GPU 는 CPU 보다 코어수는 많지만 각각의 코어가 GPU 보다 더 성능이 낮기 때문에 병렬적인 작업 (Paralell task) 에 더 강점이 있다. 현재 PC 에서 사용되는 CPU 의 코어는 보통 4~10개 정도이며 hyperthreading 기술을 통해 thread 를 2배 정도 늘릴 수 있다. 예를 들어 8 코어 16 threads CPU 의 경우, 병렬적으로 16개의 task 를 수행할 수 있다는 뜻이다. 반면, 예를 들어 NVIDIA 의 Tital XP GPU 의 경우 3840 코어를 갖고 있다. 또 최근 출시된 2080 TI 의 경우 4,352 개의 코어를 갖고 있다. threading 을 감안하더라도 CPU와 GPU 의 코어 수의 차이는 200 배 이상이다. 

 

2) 메모리

 

CPU 와 GPU 의 중요한 차이 중 하나는 바로 메모리를 어떻게 사용하는지에 관한 것이다. CPU 는 캐시 메모리가 있지만 대부분의 시스템과 공유된 메모리를 사용한다. PC 의 경우 8GB, 16GB RAM 이 일반적인 메모리의 종류이다. GPU 의 경우 시스템과 메모리를 공유할 수도 있지, 이 경우 GPU 와 메모리 사이의 Bottleneck 이 생기기 때문에 성능이 낮아진다. 따라서 GPU 는 GPU card 내에 자체의 메모리가 존재한다. 예를 들어 Tital XP GPU 의 경우 12 GB 의 메모리를 갖고 있다. 

 

CPU 의 강점은 갖는 것은 여러가지 일 (음악 감상, 영화 감상, 딥러닝, 게임 등)을 할 수 있으며, 순차적인 처리를 빠르게 할 수 있다는 것이다. 반면, GPU 는 여러가지 일을 다 잘하진 못해도 병렬화를 할 수 있다면, 이를 빠르게 처리할 수 있다. 병렬화 가능한 일 중 하나가 바로 행렬 곱 (Matrix multiplication) 이다. 

 

병렬화 가능한 행렬곱

행과 열의 곱을 각각의 GPU 코어에서 처리 후 이를 합친다면 순차적으로 처리하는 것보다 더 빠르게 수행할 수 있을 것이다. GPU 를 이용한 프로그래밍을 하는 방법은 NVIDIA 의 CUDA 라이브러리를 사용하는 것이다. CUDA 를 이용하면 C, C++ 등의 언어로 GPU 프로그래밍을 할 수 있다. 또한 CUDA 보다 high-level API 로 cuBLAS, cuDNN 등 이 있다. high-level API 의 경우 CUDA 를 기반으로 행렬 연산, 딥러닝 등을 구현하는 것에 초점을 맞추어져 있기 때문에 이러한 작업들에 GPU 를 더욱 쉽게 이용할 수 있다. 하지만 CUDA 를 사용한 프로그래밍은 구현하기가 쉽지 않다. 예를 들어 캐시 메모리와 같은 메모리 계층 구조를 잘 이용하지 않으면 효율적인 코드를 작성하기 어렵다. 

 

따라서 딥러닝을 위해서 CUDA 코드를 처음부터 작성해서 이용하지 않는다. 먼저 NVIDIA 에서 CUDA 를 활용하기 위한 high-level API (cuDNN) 를 만들어 놓았기 때문에 이를 이용하면 되기 때문이고, 또한 cuDNN 을 활용한 다양한 딥러닝 프레임워크들이 이미 나와있기 때문이다. 

 

딥러닝 프레임워크

이름 단체
Caffe2 Facebook
PyTorch Facebook
TensorFlow Google
CNTK Microsoft
Paddle Baidu
MXNet Amazon

최근 딥러닝 프레임워크는 빠르게 생겨나고 있다. Tensorflow (Keras) 와 PyTorch 가 최근 가장 많이 사용되는 딥러닝 라이브러리가 볼 수 있다. 최근 MXNet 기반 Computer Vision toolkit 인 GluonCV 도 ICCV 에서 발표되는 등 많은 발전이 있는듯하다. GluonCV 는 컴퓨터 비전 분야의 State-of-the-art 를 사용하기 쉽게 만든 MXnet 의 high-level 라이브러리로 볼 수 있다. 

 

딥러닝 프레임워크를 사용하면 우리는 딥러닝을 효율적으로 구현할 수 있다. 상세하게는 아래와 같은 장점이 있다. 

 

1) 딥러닝 모델을 쉽게 만들 수 있다

2) Gradient 를 빠르게 구할 수 있다.

3) GPU 이용을 쉽게하고 효율적으로 동작할 수 있다 (cuDNN, cuBLAS 를 wrapping 해서 구현 → 효율 좋음). 

 


파이토치 (Pytorch)

 

파이토치 (https://pytorch.org/) 도 위와 같은 이유로 사용되는 대표적인 딥러닝 프레임워크 중 하나이며 최근 많은 인기를 얻고 있다. 파이토치가 인기를 얻게 된 이유는 기술을 단순화 시켜서 사용하도록 만든 사용 편리성과 함께, '동적 계산 그래프 (Dynamic computational graph)' 를 사용한다는 점이다. 텐서플로우의 경우 정적 계산 그래프 (Static computational graph) 으로 한 번 모델을 만든 후, 여러번 돌리는 방식인 반면, 동적 계산 그래프트는 한 번의 forward path 마다 새로운 그래프를 다시 그린다. 

 

cs231n lecture 8. Deep Learning Software

 

동적 계산 그래프 (Dynamic computational graph)

 

동적 계산 그래프는 어떤 장점을 가질까? 동적 계산 그래프는 복잡한 아키텍쳐를 구축할 때 더욱 유연하다. 예를 들어, RNN 을 활용한 Image captioning 의 경우 input 에 따라 output sequence (텍스트) 의 길이가 달라진다. 따라서 computational graph 가 input 이미지에 따라 동적으로 변한다는 것이다. 이 경우 forward path 마다 구조가 바뀌는 것이 더 효율적이므로 동적 계산 그래프가 더욱 적합하다. 

 

image captioning (https://towardsdatascience.com/image-captioning-in-deep-learning-9cd23fb4d8d2)

이와 비슷한 Visual Question Answering (VQS) 분야에 Neuromodule 도 동적 계산 그래프가 적합한 예이다. Neuromodule 은 "이미지" 와 "질문" 두 가지를 입력하면 답변을 위한 custom architecture 를 만들고 답을 출력하고자 하는 모델이다. 예를 들어, 고양이 사진을 주고 "고양이의 색깔은?" 과 같은 질문을 던지는 것이다. 이 경우에도 마찬가지로 네트워크가 동적으로 구성되어야 할 것이다. 어떤 사진을 주고 "이 이미지에서 고양이의 수가 강아지의 수보다 많은가?" 라는 질문을 던지면 앞선 네트워크와는 다르게 구성되어야 한다. 이처럼 동적 계산 그래프를 활용하면 다양한 네트워크를 구성할 수 있다. 

 

파이토치는 연구를 위한 목적으로 만들어진 라이브러리이다. 그래서 요청에 따라 빠르게 응답해야하는 프로덕트 용으로는 적합하지 않을 수 있다. 하지만 Open Neural Network Exchange (https://onnx.ai/) 라는 새로운 프로젝트가 나오면서 이런 제약이 줄어들고 있다. onnx 는 머신러닝 모델의 interoperability 를 위한 프로젝트로 모델을 ONNX Format 로 export 한 후 다른 환경에서 import 할 수 있도록 한다. 이를 활용하면 파이토치 모델을 프로덕션용 Caffe2 모델로 변환해서 배포할 수 있다. ONNX Format 은 파이토치 외에도 CNTK, MXNet, 텐서플로, 케라스, Scikit-Learn 에도 활용할 수 있다. 

 

파이토치의 설치

 

환경 : Ubuntu 16.04, Jupyter Lab (with JupyterHub), Python 3.8, Cuda 

 

1) 파이썬 가상 환경 (virtual environment) 생성 & Jupyter Lab 등록

 

 

conda create --name pytorch python==3.8
source activate pytorch
pip install ipykernel
python -m ipykernel install --name pytorch

 

2) CUDA version check 

 

nvcc --version 


nvcc: NVIDIA (R) Cuda compiler driver
Copyright (c) 2005-2017 NVIDIA Corporation
Built on Fri_Sep__1_21:08:03_CDT_2017
Cuda compilation tools, release 9.0, V9.0.176

 

3) Install Pytorch 

 

pytorch 홈페이지에서 환경을 클릭하면 설치할 수 있는 커맨드를 출력해준다. CUDA 9.0 을 사용하고 있는데, CUDA 9.2 를 선택해서 나온 커맨드로 설치해도 무방한듯 하다. 

 

https://pytorch.org/

 

conda install pytorch torchvision cudatoolkit=9.2 -c pytorch

 

설치 완료 후 주피터 랩에서 pytorch kernel 을 실행 후, import pytorch 로 임포트가 잘 되는 것을 확인하자. 

 

Reference

 

반응형
반응형

Hadoop MapReduce 파이썬 구현 (단어 빈도수 세기)

 

Map-Reduce 란?

 

본 포스팅에서는 하둡이 분산처리를 하는 방법인 맵리듀스를 파이썬으로 구현하는 방법을 간단하게 다루겠습니다. 하둡은 자바로 코딩되어 있지만 파이썬, C++ 등의 언어를 이용해서 하둡을 이용할 수 있습니다. 가장 간단하게는 파이썬 코드를 Jython 을 이용해 자바의 jar 파일로 만드는 것인데, 이것은 매우 불편합니다. 특히, Jython 에서 제공하지 않는 파이썬의 기능, 패키지를 이용할 때 문제가 됩니다. 그래서 하둡에서는 standard input, standard output 을 인터페이스로해서 파이썬과 같은 다른 언어에서도 하둡을 이용하는 방법을 제공하고 있습니다. 이번 포스팅에서는 파이썬으로 맵리듀스 코드를 구현하고 테스트 해보는 것을 정리하였습니다. 맵리듀스의 프로세스는 아래와 같습니다. 

 

출처 -  http://www.admin-magazine.com/HPC/Articles/MapReduce-and-Hadoop

 

맵 리듀스는 기본적으로 Split -> Map -> Shuffle -> Reduce 의 절차를 갖습니다. 여기서 Split-Map을 합쳐서 맵 태스크, Shuffle-Reduce 를 합쳐서 리듀스 태스크라고도 부릅니다. Split 은 인풋데이터를 쪼개서 인풋을 키-쌍 값으로 만들어주는 작업이고, Map 은 키-쌍 값을 인풋으로 받아 list(키-값 쌍)을 내보냅니다. Shuffle 에서는 list(키-값 쌍) 을 인풋으로 받아 키-값 쌍을 내보내고 Reduce 에서는 Shuffle 의 결과인 키-값 쌍 입력으로 받아 마지막으로 list(키-값 쌍) 을 내보냅니다. 

 

Map-Reduce 의 인풋/아웃풋

 


 Input Output 
 Split  텍스트  <k1, v1>
 Map  <k1, v1>  list (<k2, v2>)
 Shuffle  list (<k2, v2>)  <k2, list(v2)>
 Reduce  <k2, list(v2)>  list (<k3, v3>)

 

단어 빈도수 세기 예제

 

맵 리듀스는 왜 필요할까요? 예를 들어, 100개의 문서가 있을 때, 이 문서들에서 단어의 빈도수를 세는 프로그램을 작성한다고 해봅시다. 그런데 문서의 크기가 각각 1TB 라서 500GB 램을 갖는 하나의 컴퓨터에서 실행할 수 없다고 해봅시다. 만약, 분산 컴퓨팅에 대한 학습이 안 되어있는 프로그래머라면, 우선 메모리가 충분하지 않으므로 문서의 일부만 불러와서 단어수를 세고, 결과를 어딘가에 저장하고, 메모리에서 지우는 것을 반복하는 것을 생각해볼 수 있을 것입니다. 물론 이것도 좋은 해법이겠지만, 단점은 시간이 오래걸린다는 것입니다. 만약 충분한 수의 컴퓨터가 있다면 문서의 총 크기는 100TB 이므로, 예를 들어, 각각 500GB 의 메모리를 갖는 200개의 컴퓨터를 활용해서 문제를 해결하고자 하는 것이 분산 컴퓨팅이고 분산컴퓨팅에 사용되는 유명한 방법이 바로 맵리듀스라고 할 수 있습니다.

 

단어 빈도수 세기 예제에서의 자료 구조 흐름

 

인풋데이터

We hold these truths to be self-evident. Governments long established should not. Such has been the patient. .....

 

Splitting 결과 (<k1, v1>)

(0, We hold these truths to be self-evident, ..)

(138, Governments long established should not ...)

(256, Such has been the patient ...) 

 

이렇게 나눠진 문서는 각 노드에 정해진 양만큼 할당이 됩니다. 맵 태스크가 하는 일은 이 키-값 쌍을 인풋으로 받아 다음과 같은 리스트를 만들어주는 것입니다. 총 100개의 문장이라면 다음과 같은 100개의 리스트가 생깁니다. 

 

Map 결과 (list (<k2, v2>))

('We' : 1, 'hold' : 1 ...) 

('Government' : 1, 'long' : 1 ...)

('Such' : 1, 'has', 1 ...)

 

맵 태스크의 결과는 문장별 단어의 빈도수를 갖고 있는 리스트입니다 (여러번 단어가 나오더라도 각각 1을 같습니다.). 이를 키-값 쌍으로 변화하기 위해 셔플링 (Shuffling) 을 수행합니다. 셔플링은 각 단어별로 문장 내에서 찾은 빈도수의 리스트를 갖고 있습니다. 

 

Shuffle 결과 (<k2, list(v2)>)

('We' : [1,1,1])

('Government : [1,1,1])

('Such' : [1,1,1])

 

리듀스 태스크는 셔플링의 결과 키-값 쌍을 입력으로 받아 최종 결과를 출력합니다. 

 

Reduce 결과 (list (<k3, v3>))

('We' : 100)

('Government' : 10)

 

파이썬 Mapper 

 

Map Task 는 인풋 데이터를 적절히 쪼갠 후, 여러 개의 키-값 쌍 (key-value pair) 으로 만드는 과정입니다. 단어 수를 세는 문제에서는 먼저 텍스트를 라인 단위로 나눈 후 (스플릿), 각 라인별로 단어를 쪼개서 출력합니다. Map task 를 실습해보기 위해 hadoop.txt 라는 샘플 텍스트 파일을 만든 후 아래와 같이 실행하였습니다. 

#!/usr/bin/env python
"""mapper.py"""

import sys

# input comes from STDIN (standard input)
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()
    # split the line into words
    words = line.split()
    # increase counters
    for word in words:
        # write the results to STDOUT (standard output);
        # what we output here will be the input for the
        # Reduce step, i.e. the input for reducer.py
        #
        # tab-delimited; the trivial word count is 1
        print ('%s\t%s' % (word, 1))

hadoop.txt
0.00MB

cat hadoop.txt | python mapper.py

MapReduce       1
framework.      1
The     1
idea    1
is      1
based   1
on      1
the     1

 

위와 같이 (단어, 1) 의 키-값 쌍이 아웃풋으로 나오게 됩니다. 이제 이 아웃풋을 리듀서에 전달하면 됩니다. 참고로 이 Mapper 가 실제 hadoop 에서 실행될 때, 아웃풋이 셔플 단계에 의해 sorting 되고 적절한 수의 노드에 나누어서 전달 됩니다. 나누어서 전달할 때도 랜덤하게 나누는 것이 아니라 sorting 된 채로 나누어지기 때문에 효율을 최대화할 수 있는 방법으로 데이터를 전달합니다. 하지만 본 포스팅에서 이 부분은 다루지 않습니다. 이 부분은 하둡에 의해 제어되며, 프로그래머는 코드를 통해 맵리듀스의 각 프로세스의 데이터 구조 프로토콜에 맞게 아웃풋을 내주기만 하면됩니다.  

 

파이썬 Reducer 작성

 

Reduce task 는 map task 의 output 을 input 으로 받아 원하는 결과를 집계해주는 작업입니다. 실제로 hadoop 에서는 reduce task 는 shuffle 과 reduce 로 나뉩니다. reduce 작업에 사용되는 노드는 하나일 수도 있지만, 여러개의 노드를 사용하기도 합니다. 이러한 작업이 복잡해보이지만 분산해서 처리하는 일은 hadoop 에서 제어하는 부분에 속합니다. 즉, 코드를 작성하는 사람은 코드의 로직에만 집중하면됩니다. 

#!/usr/bin/env python
"""reducer.py"""

from operator import itemgetter
import sys

current_word = None
current_count = 0
word = None

# input comes from STDIN
for line in sys.stdin:
    # remove leading and trailing whitespace
    line = line.strip()

    # parse the input we got from mapper.py
    word, count = line.split('\t', 1)

    # convert count (currently a string) to int
    try:
        count = int(count)
    except ValueError:
        # count was not a number, so silently
        # ignore/discard this line
        continue

    # this IF-switch only works because Hadoop sorts map output
    # by key (here: word) before it is passed to the reducer
    if current_word == word:
        current_count += count
    else:
        if current_word:
            # write result to STDOUT
            print ('%s\t%s' % (current_word, current_count))
        current_count = count
        current_word = word

# do not forget to output the last word if needed!
if current_word == word:
    print ('%s\t%s' % (current_word, current_count))

 

우선 코드가 잘 작동하는지 알아보기 위해 mapper 의 아웃풋을 '키' 인 단어를 기준으로 아래와 같이 정렬합니다.  

cat hadoop.txt | python mapper.py | sort -k 1

(Figure 1
(typically      1
1).     1
Adobe,  1
Amazon  1
Amazon, 1
An      1
An      1
Apache  1
Automatic       1
Because 1
Elastic 1
Google  1
Google  1
Hadoop  1

 

다음으로 위 명령어의 아웃풋을 piping 을 통해 reducer 에 전달한 후, '값' 인 빈도수를 기준으로 내림차순 정렬하면 최종 결과를 얻게 됩니다. 

cat hadoop.txt | python mapper.py | sort -k1,1 | python reducer.py | sort -k 2 -r

to      8
MapReduce       8
is      7
that    6
in      6
and     6
a       6
on      5
reduce  4
can     4
be      4
are     4
map     3
by      3
The     3
which   2

 

본 포스팅에서는 파이썬을 통해 맵리듀스 코드를 작성하는 방법을 포스팅하였습니다. 하지만 이는 분산 컴퓨팅은 아닙니다. 다음 포스팅에서는 이러한 파이썬 맵리듀스 코드를 하둡으로 실행해서 분산 처리하는 방법 대해 다루어보겠습니다. 

 

References

반응형
반응형

Wallpaper 콜렉션 사이트


마이크로소프트의 좋은 배경화면들을 무료로 받을 수 있는 사이트를 알게되어 공유합니다 (https://wallpaperhub.app/). 이 사이트가 좋은점은 다양한 기기에 맞는 해상도로 사진들을 다운로드를 받을 수 있습니다. 콜렉션 페이지에 가면 Microsoft 의 서피스 랩탑 등 다양한 기기의 디폴트 배경화면 콜렉션을 볼 수 있습니다. 서피스 Wallpaper 에 좋은 사진들이 많은듯합니다. 



반응형
반응형


Scikit-learn Gradient Boosting 모델 예측값이 매번 달라지는 문제와 해결


아래 코드는 k-fold cross-validation 을 통해 best parameter 를 찾은 후, test set 에 대해 예측하는 코드이다. 이 코드에서 random_state=2020 을 지정하지 않으면, GridSearchCV 를 통해 구한 best parameters set이 매번 달라졌다. 즉 이말은 Gradient Boosting Tree 가 fitting 할 때마다 달라진다는 뜻이다. 


def cv_and_prediction(x_vars, name, model=False): train_x = metadata_valid[x_vars] train_y = metadata_valid["case"] test_x = metadata_test[x_vars] test_y = metadata_test["case"] model = GradientBoostingClassifier(random_state=2020) param_test = { "n_estimators": range(50, 100, 25), "max_depth": [1, 2, 4], "learning_rate": [0.0001, 0.001, 0.01, 0.1], "subsample": [0.7, 0.9], "max_features": list(range(1, len(x_vars), 2)), } gsearch = GridSearchCV( estimator=model, param_grid=param_test, scoring="roc_auc", n_jobs=4, iid=False, cv=5, ) gsearch.fit(train_x, train_y) print(name) print("Best CV Score", gsearch.best_score_) print("Best Params", gsearch.best_params_) model = GradientBoostingClassifier(**gsearch.best_params_) model.fit(train_x, train_y) metadata_test[name] = model.predict_proba(test_x)[:, 1] return model


왜 이런문제가 발생하는가 ?


Decision trees can be unstable because small variations in the data might result in a completely different tree being generated. This problem is mitigated by using decision trees within an ensemble.


The problem of learning an optimal decision tree is known to be NP-complete under several aspects of optimality and even for simple concepts. Consequently, practical decision-tree learning algorithms are based on heuristic algorithms such as the greedy algorithm where locally optimal decisions are made at each node. Such algorithms cannot guarantee to return the globally optimal decision tree. This can be mitigated by training multiple trees in an ensemble learner, where the features and samples are randomly sampled with replacement.


구글링을 통해 문제가 발생할 수 있을만한 원인을 찾았다. 


1. 우선 Decision tree 를 적합하는 방법은 heuristic algorithm (greedy algorithm) 이다. 왜냐하면 optimal 한 decision tree 를 찾는 것은 np-complete 문제이기 때문이다. 하지만 직접적인 문제는 아닌듯하다. greedy 한 방법으로 tree 를 만들더라도 매번 같은 greedy 한 방법을 이용하면 같은 tree 가 생성되기 때문이다.


2. Gradient Boosting 과 같은 ensemble 방법에서는 매 iteration 마다 subsample 을 만들어서 negative gradient 를 예측하는 모델을 만들어서 합치게 되는데 이 때, subsample 이 random 하게 설정되기 때문에 매 번 모형이 달라지고 이로 인해 예측 값이 조금씩 달라지게 된다.  


정확한 원인이 무엇이든 Gradient boosting tree 를 만드는 것에는 randomness가 있으며 reproducible 한 코드를 작성하고 싶으면 GradientBoostingClassifier(random_state=2020) 와 같이 random_state 를 지정해야한다. 


참고

https://scikit-learn.org/stable/modules/tree.html#tree

반응형
반응형

구글 번역기는 하나의 긴 문장을 두 개의 문장으로 쪼개주기도 한다.

 

임상 정보 기반 위험도 평가부는 임상 정보와 유전체 정보에 따른 위험도를 산출하는 모듈로, 유전체/가족력 정보를 통해 대상자를 몇 가지 표현형 (phenotype) 으로 나눈 후, 각 표현형의 나이에 따른 유방암 발생 확률에 임상 정보를 통해 추정한 상대 위험도 (relative risk)를 곱하는 방법을 통해 위험도를 산출한다. 

 

The clinical information-based risk assessment unit is a module that calculates the risk according to clinical information and genomic information. After dividing the subject into several phenotypes through genome / family history information, the risk of breast cancer according to the age of each phenotype and clinical It is calculated by the squared relative risk estimated from the information.

 

빠르게 영문 번역해야할 일이 있어 번역기의 도움을 받았는데 정말 좋은 것 같다. RNN seq to seq 의 개념에서 마침표를 하나의 단어로 인식한다면 기술적으로 불가능한것은 아니겠지만 어떻게 트레이닝을 했을지 정말 놀랍다. 

반응형
반응형


[딥러닝 강의] [1] 데이터 기반 이미지 분류 (Data-driven Image Classification)

이미지 분류 개요
이미지 분류는 컴퓨터 비전 분야의 주요 문제이다. 사람은 고양이를 보고 고양이라고 쉽게 분류할 수 있지만, 컴퓨터에게는 매우 어려운 문제이다. 사람은 고양이를 실체가 있는 물체로 인식하는 반면 컴퓨터에게는 0~255 사이의 숫자로 표현되기 때문이다. 이미지 분류의 문제는 이러한 사람과 컴퓨터의 사물을 보는 차이에서 온다. 예를 들어, 고양이를 관측한 위치 (viewpoint variation), 빛 (Illumination), 고양이의 자세 (deformation), 가림 (Occlusion), 고양이의 종류 (Intraclass variation) 등에 따라 컴퓨터에게 고양이는 상당히 다르게 인식된다. 단지 고양이 뿐만이 아니다. 여러 물체를 인식하고 이를 분류하는 문제는 매우 challenging 하다고 할 수 있다. 

그림. 사람과 컴퓨터의 이미지 인식 차이


딥러닝 이전 시대에 이미지를 분류하기 위하여 다양한 시도들이 있어왔다. 대표적으로 사진으로부터 고양이의 귀, 고양이의 눈, 고양이의 코가 '존재한다는 정보' 를 얻는 알고리즘을 만들고 이를 통해 고양이임을 판단하고자 한 방법이 시도되었다. 이를 규칙 기반 방법 (Rule-based approach) 하지만 이러한 방법의 문제는 1) 불안정하다는 것 (고양이의 귀, 코는 종에 따라 다르고, 자세와 위치에 따라 다르게 인식된다.) 과 2) 규칙을 만드는 것이 어렵다는 것이다. 예를 들어, 말해 고양이가 아니라 사진으로부터 개나 트럭을 분류해내고 싶으면 어떨까? 클래스마다 사람이 새로운 규칙을 만들어주어야한다. 즉 이러한 방법은 확장성 (scalability) 이 떨어진다. 

데이터 기반 방법
이러한 문제를 해결하기 위해 제시된 것이 데이터 기반 방법 (Data-driven approach) 이다. 데이터 기반 방법은 사람이 직접 알고리즘을 만드는 것이 아니라 데이터를 기반으로 모델을 만들어 문제를 해결하고자 하는 방법이다. 결론부터 말하면 이미지 분석에 있어 데이터 기반 방법은 규칙 기반 방법보다 거의 모든 측면에서 효과적이다. 또한 사람이 학습하는 방법과도 비슷하다. 

그림. Rule-based approach vs. Data-driven approach


데이터 기반 방법은 수많은 이미지와 레이블 (ex. 개, 고양이 등) 이 있는 데이터셋을 통해 모델을 학습 (training) 한다. 이 때, 모델을 학습하는 것을 머신 러닝 (Machine Learning) 이라고 말한다. 이렇게 학습된 머신러닝 모델은 새로운 이미지를 인풋으로 받아 그 이미지의 레이블을 예측 (prediction or test) 한다. 즉, 이미지를 분류하는 모델을 만드는 방법 중 데이터 기반 방법을 머신러닝이라고 하며, 머신러닝 모델은 데이터셋을 통해 이미지를 학습하는 과정과 새로운 이미지를 예측하는 과정이 있다. 머신러닝 모델의 학습을 위한 데이터셋은 직접 웹 등으로부터 수집할 수 있다. 또한 ImageNet, CIFAR 등 공개된 질 좋은 데이터셋도 있기 때문에 누구나 직접 머신러닝 모델을 구축해볼 수 있다. 예를 들어, CIFAR-10 데이터셋은 10개의 클래스, 50000개의 트레이닝셋, 10000개의 테스트셋으로 구성된다.  


그림. CIFAR-10 데이터셋


이미지 분류를 위한 첫 번째 알고리즘 : Nearest neighbor

데이터 기반 모델의 첫 번째 간단한 예시로 nearest neighbor (NN) 방법을 살펴보자. KNN 방법은 먼저 학습 데이터셋을 저장한 후에, 예측 단계에서는 투입된 이미지와 가장 가까운 데이터의 레이블을 통해 예측 하는 방법이다. 그러면 이미지와 이미지의 가까운 정도 (distance) 는 어떻게 구할 수 있을까? 다양한 지표 (metric) 이 있지만 그 중 한 가지인 L1 distance 는 다음과 같다.


$$ d_1 (I_1, I_2) = \sum_{p} | I_1^p - I_2^p | $$


L1 distance 를 distance metric 으로 사용하는 nearest neighbor 을 파이썬 코드로 아래처럼 구현할 수 있다. 


import numpy as np

class NearestNeighbor(object):
  def __init__(self):
    pass

  def train(self, X, y):
    """ X is N x D where each row is an example. Y is 1-dimension of size N """
    # the nearest neighbor classifier simply remembers all the training data
    self.Xtr = X
    self.ytr = y

  def predict(self, X):
    """ X is N x D where each row is an example we wish to predict label for """
    num_test = X.shape[0]
    # lets make sure that the output type matches the input type
    Ypred = np.zeros(num_test, dtype = self.ytr.dtype)

    # loop over all test rows
    for i in xrange(num_test):
      # find the nearest training image to the i'th test image
      # using the L1 distance (sum of absolute value differences)
      distances = np.sum(np.abs(self.Xtr - X[i,:]), axis = 1)
      min_index = np.argmin(distances) # get the index with smallest distance
      Ypred[i] = self.ytr[min_index] # predict the label of the nearest example

    return Ypred


위 코드를 사용해서 테스트셋에 대한 성능을 평가한 결과 38.6 % 정도의 성능을 보인다. 우선, 임의로 찍은 수치 (10 %) 보다 성능이 좋기 때문에 모델을 만드는데 큰 노력을 들이지 않았다는 점을 감안해 괜찮은 수치이다. 하지만 state-of-the-art 인 Convolutional Neural Network 기반 모델의 성능 (95 %) 과 비교하면 매우 낮다. 


L1 외에도 다양한 metric 을 쓸 수 있다. 예를 들어, L2 distance 는 다음과 같다.


$$ d_2 (I_1, I_2) = \sqrt{\sum_{p} ( I_1^p - I_2^p )^2} $$



L1 L2 distance 의 차이

L1 과 L2 는 p-norm 계열의 distance measure 이다. 그러면 L1 과 L2  의 차이는 L2 distance 는 L1 distance 를 사용하는 것보다 차이가 큰 것에 더 관대하지 않다는 것이다. 즉, L1 이 아닌 L2 distance 를 쓴다는 것은 여러개의 dimension 에서 적당한 차이를 보이는 것보다 하나의 dimension 에서 큰 차이를 보이는것에 더 페널티를 많이준다는 의미다. 


K-nearest neighbor 

nearest neighbor (NN) 은 단점이 많은 알고리즘이다. 먼저, NN 은 단 하나의 label 만 prediction 에서 고려하기 때문에 안정성이 떨어지는 결과를 보여준다. 한 마디로 성능이 떨어진다. 이를 보완하기 위해 k-nearest neighbor (KNN) 를 활용할 수 있다. 이 방법은 테스트 (또는 예측) 단계에서 인풋과 가까운 순으로 총 k 개의 데이터의 레이블을 구한 후, 가장 빈번하게 나오는 레이블로 예측하는 방법이다. 이렇게 여러개로부터 가장 빈번하게 나오는 것을 예측 결과로 하는 것을 머신러닝에서는 voting 이라고 부른다. 


그림.  k-nearest neighbor


위 그림을 보면 NN 대신에 K-nearest neighbor 을 사용하면 어떤 장점이 있는지 확인할 수 있다. NN 에는 이상치 (outlier) 를 중심으로 섬과 같은 지역 (decision boundary) 가 생긴다는 것을 볼 수 있다. 하지만 KNN 의 경우, 이상치에 더 둔감하다. NN 의 경우 이상치에 민감하기 때문에 트레이닝 데이터에 국한된 규칙을 배울 가능성이 높다. KNN 을 사용하면 처음 보는 데이터 (unseen data) 대한 성능 (generalization)이 높을 것임을 짐작할 수 있다. 그리고 처음 보는 데이터를 올바르게 예측하는 것이 머신러닝 방법을 사용한 예측 모델링의 주요 목적이다. K-nearest neighbor 를 실제로 사용할 때  한가지 고려 사항은 k 를 어떻게 정하냐는 것이다. k 가 높으면 물론 좋겠지만 그만큼 테스트 단계에서의 계산량이 매우 많아진다는 단점이 있다. 


Validation set 을 통한 Hyperparameter tuning

K-nearest neighbor 에서 우리가 정해야할 것은 kdistance function 이다. 이를 알고리즘 자체의 파라미터, hyperparameter 라고 한다. 그리고 이를 조정하는 방법을 hyperparameter tuning 이라고 한다. 머신러닝에서 hyperparameter tuning 을 하는 주 방법은 여러번 해봐서 가장 좋은것을 찾는 것이다. 이것은 별다른 아이디가 없을 때 좋은 방법이다. 하지만 hyperparameter 를 찾는데 테스트셋을 사용할 수는 없다. 머신러닝에서 테스트셋은 성능을 평가하는 것 이외에 다른 목적으로 쓰일 수 없다. 만약 테스트셋으로 hyperparameter tuning을 하면 모델이 테스트셋에 과적합 (overfitting) 되며, 다른 처음보는 데이터에 적용했을 때 상당히 성능이 떨어지는 문제를 겪게 된다. 테스트셋은 반드시 모델 구축이 끝난 후, 단 한 번 평가 되어야 한다.  따라서 방법은 트레이닝 셋의 일부를  hyperparameter tuning 을 위하여 분할하여 사용하는 것이다. 이를 validation set 이라고 부른다. validation set 을 통한 hyperparameter tuning 은 머신러닝에서 중요한 개념 중 하나이다. Validation set 을 통한 Hyperparameter tuning 을 아래와 같은 파이썬 코드로 구현해볼 수 있다. 


# assume we have Xtr_rows, Ytr, Xte_rows, Yte as before
# recall Xtr_rows is 50,000 x 3072 matrix
Xval_rows = Xtr_rows[:1000, :] # take first 1000 for validation
Yval = Ytr[:1000]
Xtr_rows = Xtr_rows[1000:, :] # keep last 49,000 for train
Ytr = Ytr[1000:]

# find hyperparameters that work best on the validation set
validation_accuracies = []
for k in [1, 3, 5, 10, 20, 50, 100]:
  
  # use a particular value of k and evaluation on validation data
  nn = NearestNeighbor()
  nn.train(Xtr_rows, Ytr)
  # here we assume a modified NearestNeighbor class that can take a k as input
  Yval_predict = nn.predict(Xval_rows, k = k)
  acc = np.mean(Yval_predict == Yval)
  print 'accuracy: %f' % (acc,)

  # keep track of what works on the validation set
  validation_accuracies.append((k, acc))


Nearest neighbor  잘 작동할까?


nearest neighbor 은 매우 이해하기 쉬운 알고리즘인 반면 여러 단점이 존재한다. 


1) 현실적인 단점은 NN은 테스트 단계에서 시간이 오래걸린다는 것이다. 모든 n 개의 트레이닝 데이터에 대해서 distance 를 구해야하기 때문에 O(n) 의 복잡성을 갖는다. 따라서 현실의 어플리케이션에 적용하기는 매우 어렵다. (NN 의 테스트 단계에서의 계산 복잡성을 줄이기 위해 Approximate Nearest Neighbor (ANN) 도 연구가 활발히 이루어지고 있는 분야이다. ANN 을 구현한 FLANN 라는 것도 있다. 기본 아이디어는 kdtree 나 k-means 알고리즘 등을 통해 데이터 인덱싱을 먼저 수행하여 테스트 단계에서 조회할 데이터를 줄이는 것이다.) 


2) NN 우리의 물체의 유사성에 대한 인식 (perceptual similarity) 과 부합하지 않는 결과를 내놓을 수 있다. 아래 그림은 모두 original 데이터와 L2 distance 를 기준으로 같은 유사성을 보이도록 이미지를 변환한 것이다 예를 들어 우리가 original 과 shifted 이미지를 인식할 때, 피사체의 위치에 차이만 있을 뿐 물체에는 아무런 차이가 없다. 하지만 단지 물체가 옆으로 이동한 것만으로도 상당한 distance 가 생기게 된다는 것이다. 


그림. 원본 이미지와  같은 L2 distance 를 갖는 이미지 모음


Raw-pixel 을 이용한 모델은 왜 실패하는가?


왜 이런 문제가 생길까? 문제는 물체의 특성이 아닌 각 픽셀을 기준으로 차이를 비교한다는 것이다. 물론 픽셀이 이미지의 특성을 반영하지만, 픽셀 값의 많은 부분이 물체 인식과 크게 관련이 없다. 아래 그림은 CIFAR-10 데이터셋에 t-SNE 를 적용해 이미지를 2차원으로 표현한 것이다. 이렇게 고차원을 저차원으로 바꾸는 것을 dimension reduction 또는 embedding 이라고도 부른다.  고차원 데이터를 공간상에 표현하는 것이 힘들기 때문에 이와 같이 저차원으로 바꾸어 표현하고자 한 것이다. 이상적으로는 CIFAR의 10개의 클래스에 맞게 군집화 되어야한다. 하지만 그림을 자세히 살펴보면 물체에 인식과 관련있는 특성 뿐 아니라 배경, 또는 색깔 등에 큰 영향을 받는다는 것을 알 수 있다. 즉, 픽셀은 물체에 대한 인식 뿐 아니라 불필요한 것까지 표현한다. 따라서 raw-pixel 을 기준으로 nearest neighbor 을 적용 하는 것은 적절하지 않은 방법이다. 단지, nearest neighbor 뿐 아니라 raw-pixel 을 output 으로 direct mapping 하는 대부분의 머신러닝 알고리즘은 같은 이유로 이미지 데이터에 효과적으로 적용되기 어렵다. 어떻게 이미지를 '우리의 인식과 관련 있는 특성' 으로 요약할 수 있을지에 관한 것이 representation learning 이며, 이것은 딥러닝 (deep learning) 의 핵심 아이디어이다.  


그림. CIFAR-10 의 tSNE를 통한 2차원 임베딩


Summary

  • 데이터 기반 이미지 분류의 기본 개념 1) 이미지-레이블 데이터셋을 통해 모델 학습 2) 새로운 데이터에 대해 예측
  • Nearest Neighbor 을 통해 이미지 분류 하는법 + Validation set 을 통해 hyperparameter tuning 하는 방법  
  • training, validation, test set 의 개념. test set 은 모든 프로세스에서 반드시 한 번만 사용되어야 한다.
  • Raw-pixel 에 을 output 으로 direct mapping 해서 모델을 만드는 것이 실패하는 이유 (인식과 표현의 차이)

참고


반응형

'Soft skills > Lecture' 카테고리의 다른 글

[딥러닝강의] [2] GPU 와 딥러닝 소프트웨어  (2) 2020.02.07
반응형