[카테고리:] 생활코딩

  • gps 태그 앨범 제작(1/4)

    휴대폰으로 gps 태그를 포함하여 사진을 저장할 수 있다. 보통 사진을 너무 많이 찍는데 기억할만한 장소를 표시하고 싶다. 역시 구글링을 해보니 perl로 제작한 좋은 페이지를 찾았다.

    http://advent.perl.kr/2016/2016-12-06.html
    https://metacpan.org/pod/HTML::GoogleMaps::V3

    사진에 저장된 gps 태그를 보면 삼성 카메라 경우 각도+분+초로 되어있다. 이를 소수점으로 변환해야 한다. 공식은 (초/60 + 분)/60+각도다.

    하나 문제가 있는데 사진을 저장할 때 숫자로 저장하지 않아 뒤쪽 소수점을 다 날렸다. 사진 경로를 찾아 파일에 저장된 정확한 gps 위치를 기록해야 한다.

    가지고 있는 데이터베이스를 날릴 수 없어, id와 경로를 보고 위도, 경도를 업데이트 하기로 했다. 일단 위 식에 맞는 스크립트를 만들었다.

    #!/bin/bash
    
    #$1은 파일 경로. 데이터베이스에서 추출.
    #file 유무 확인
    if [ ! -f $1 ];then
    	echo "file is not there";
    	exit
    fi
    GpsLat=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLatitude.*Rational" | sed 's/ \{1,\}/ /g' | cut -d' ' -f4-)
    GpsLong=$(exiv2 -pa $1 2> /dev/null | grep -ae "Exif\.GPSInfo\.GPSLongitude.*Rational" | sed 's/ \{1,\}/ /g'| cut -d' ' -f4-)
    
    #echo $GpsLat;
    #echo $GpsLong;
    
    #GpsLat마지막 숫자
    GpsLatSec=$(echo $GpsLat | cut -d' ' -f3 | tr -d "\"")
    GpsLatMin=$(echo $GpsLat | cut -d' ' -f2 | tr -d "\'")
    
    GpsLongSec=$(echo $GpsLong | cut -d' ' -f3 | tr -d "\"")
    GpsLongMin=$(echo $GpsLong | cut -d' ' -f2 | tr -d "\'")
    
    #echo $GpsLatSec
    #echo $GpsLatMin
    
    GpsLatFloat=$(bc <<< "scale=4;($GpsLatSec/60+$GpsLatMin)/60")
    GpsLongFloat=$(bc <<< "scale=4;($GpsLongSec/60+$GpsLongMin)/60")
    
    #echo $GpsLatFloat
    #echo $GpsLongFloat
    
    #$Gps 인티저
    GpsLatInt=$(echo $GpsLat | cut -d' ' -f1 | tr -d "d-g");
    GpsLongInt=$(echo $GpsLong | cut -d' ' -f1 | tr -d "d-g");
    
    #echo $GpsLatInt
    #echo $GpsLongInt
    
    #전체 숫자.
    GpsLatFull=$(bc <<< "scale=4;$GpsLatFloat+$GpsLatInt");
    GpsLongFull=$(bc <<< "scale=4;$GpsLongFloat+$GpsLongInt");
    
    echo $GpsLatFull;
    echo $GpsLongFull;

    이제 데이터베이스를 내용을 파일로 출력하여 경로를 위 스크립트 인자로 넣어주면 된다.

  • 엑셀 정규 표현식

    엑셀에서 정규 표현식을 쓸 경우가 있다. 정규 표현식이 아니면 엄청 괴로울 수 있다. 고맙게도 선구자가 고민하여 공유했다. 감사합니다. 잘 쓰겠습니다. 위 사이트에서 가져온 코드다.

    Function RegexExecute(r As Range, p As String, Optional g As Boolean = False) As Variant     On Error GoTo ErrHandler
        
        Dim str As String, ptn As String
        str = CStr(r.Cells(1, 1).Value)
        ptn = CStr(p)
        
        Set regex = CreateObject("VBScript.RegExp")
        With regex
            .IgnoreCase = False
            .MultiLine = False
            .Global = g
            .Pattern = ptn
        End With          If regex.Test(str) Then         Set matches = regex.Execute(str)
            Dim temp As String
            temp = ""         For Each Match In matches
                temp = temp & Match
            Next
            RegexExecute = temp
            Exit Function
        End If
        
    ErrHandler:
        RegexExecute = CVErr(xlErrNA)
    End Function
    
    
  • Qlik 전 값 찾기

    속도, 시각을 알 경우, 가속도를 구해야 한다. peek 함수가 메모리에 저장된 현재 행 바로 전 값(-1)을 찾는다. 메모리에서 찾으므로 load 해야 한다.

    다음 속도, 시각 테이블을 Sheet1 엑셀 파일로 가지고 있다.

    시각	속도
    0.002	10
    0.004	10.5
    0.006	11
    0.008	11.5
    0.01	12
    0.012	12.5
    0.014	13
    0.016	13.5

    아래는 qlik이 자동으로 만든 코드이다. qlik을 잘 알면 더 깔끔하게 사용할 수 있으나, 지저분하지만 내 시간을 적게 사용한 아래도 괜찮다.

    [Sheet1]:
    LOAD
    	[시각],
    	[속도]
     FROM [lib://가속도분석/테스트.xlsx]
    (ooxml, embedded labels, table is Sheet1);

    사용자 지정 script를 추가한다. peek를 적용할 경우, order by를 명시해야 한다. 엄한 값을 갖는 경우도 있다.

    가속도tmp:
    
    load
    [시각] as [가속도.시각],
    [속도] as [가속도.속도],
    peek([가속도.속도]) as [가속도.전속도],
    peek([가속도.시각]) as [가속도.전시각]
    
    Resident [Sheet1]
    order by [시각] asc;
    
    drop Table [Sheet1];
    
    
    가속도:
    load
    [가속도.시각],
    [가속도.속도],
    ([가속도.전속도]/[가속도.전시각]) as [가속도.가속도]
    
    Resident [가속도tmp];
    
    drop Table [가속도tmp];

    데이터 뷰를 보면 다음 그림과 같다.

    그래프를 보면 예상대로 나온다.

  • linear approxmation

    python으로 데이터를 근사 함수로 바꾸는 명령이 있다. polyfit. 대박이다!

    Python 3.5.2 (default, Jul 10 2019, 11:58:48) 
    [GCC 5.4.0 20160609] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import numpy as np
    >>> x=np.arange(0,4)
    >>> y=np.array([0,1,1.9,3.1])
    >>> np.polyfit(x,y,1)
    array([ 1.02, -0.03])
    >>> np.polyfit(x,y,2)
    array([0.05, 0.87, 0.02])

    인터넷에서 구한 sine 데이터로 근사 함수를 구해봐야 겠다.

    #_*_ coding: utf-8 _*_
    import matplotlib
    matplotlib.use('Agg')
    
    import numpy as np
    from sklearn.preprocessing import PolynomialFeatures
    
    import csv 
    import tensorflow as tf
    import matplotlib.pyplot as plt 
    import pandas as pd
    
    from keras.models import Sequential
    from keras.layers import Dense
    from keras.layers import Dropout
    from keras.callbacks import ModelCheckpoint
    
    print ("Package Loaded")
    print ("데이터로 함수 근사하기")
    
    ipd = pd.read_csv("./sine.csv")
    print (ipd.head())
    print (ipd.shape)
    
    #column 선택.
    time=ipd.iloc[:,0].array
    sineValue=ipd.iloc[:,1].array
    #print(type(time))
    #print(time)
    #print(time)
    #print(sineValue)
    approxFunc = np.polyfit(time,sineValue,6, full=False)
    print(approxFunc)
    

    처음에 5,000개를 모두 시키니 애가 이상한 짓을 한다. 사인 웨이브 크기가 1이고 0.001 단위로 쪼갰다. 파랑색 선이 내가 예상한 그림인데 애가 작고 너무 티 안나게 그렸다. 오차를 줄이려 노력하다 보니 아무것도 아닌 그래프를 그렸다.

    이번에는 앞에 몇 개 잘랐다.

    tf-docker /home/tensorflow/tutorial/ItnSensor > cat sine.csv
    0,0.841470985
    0.001,0.873736397
    0.002,0.90255357
    0.003,0.927808777
    0.004,0.949402346
    0.005,0.967249058
    0.006,0.98127848
    0.007,0.991435244
    0.008,0.997679266
    0.009,0.999985904
    0.01,0.998346054
    0.011,0.992766189
    0.012,0.983268329
    0.013,0.969889958
    0.014,0.952683874
    0.015,0.931717983
    0.016,0.907075026
    0.017,0.878852258
    0.018,0.847161063
    0.019,0.812126509
    0.02,0.773886863
    0.021,0.73259304
    0.022,0.688408006
    0.023,0.64150614
    0.024,0.592072543
    0.025,0.540302306
    0.026,0.486399742
    0.027,0.430577581
    0.028,0.373056127
    0.029,0.314062391
    0.03,0.253829194
    0.031,0.192594249
    0.032,0.130599223

    이렇게 하면 좀 비슷하게 그린다. 입력으로 준 수치가 (0.032, 0.1305..)에서 끊어져 애는 끝까지 아래로 간다고 생각하나 보다.

    특정 부분을 보고 특징을 뽑아내야 하는데, 그냥 인공지능 하나 만들어서 하는게 낫다. 에러, 정확도가 얼마인지도 모르겠다.

  • CarpPole Deep Q Network 이해

    강아지 책에 나온 예제를 실행했다. 책 실행 환경과 내 그것이 달라 실행할 수 없었다. 나는 docker로 tensorflow를 사용한다. 그것도 cpu가 avx 등 을 지원하지 않아 직접 컴파일했다. openAi gym은 GUI 환경에서 실행되어 docker로 구동하기 힘들다. 데스크탑을 거실에 설치하여 다른 노트북에서 ssh로 접속하여 사용한다. 이런 모든 문제를 jypyter notebook로 해결했다. 전 글에 설명한대로 docker를 아래 명령으로 구동한다.

    docker run -it -v /run/user/1000:/run/user/1000 -v /dev:/dev -v /tmp/.X11-unix:/tmp/.X11-unix:ro --privileged --ipc=host --shm-size=256m --net=host -e DISPLAY=$DISPLAY -e XDG_RUNTIME_DIR=/run/user/1000 --runtime=nvidia -e LC_ALL=C.UTF-8 -v /home/now0930/tensorflow/:/home/mnt tensorflow/tensorflow:1.12.0-rc2-gpu-py3-keras /bin/bash

    jupyter notebook을 실행한다. uid 1000으로 실행하는 방법을 모르겠다.

    docker exec -w /home/mnt/gym vibrant_banach /usr/bin/xvfb-run -s "-screen 0 1400x600x24" jupyter notebook --allow-root

    책 코드를 실행하기 위해 아래와 같이 수정했다.

    import sys
    import gym
    import pylab
    import random
    import numpy as np
    from collections import deque
    from keras.layers import Dense
    from keras.optimizers import Adam
    from keras.models import Sequential
    from gym import wrappers
    
    EPISODES = 300
    
    
    # 카트폴 예제에서의 DQN 에이전트
    class DQNAgent:
        def __init__(self, state_size, action_size):
            self.render = False
            self.load_model = False
    
            # 상태와 행동의 크기 정의
            self.state_size = state_size
            self.action_size = action_size
            print("self.state_size는", self.state_size)
            print("self.action_size는", self.action_size)
            # DQN 하이퍼파라미터
            self.discount_factor = 0.99
            self.learning_rate = 0.001
            self.epsilon = 1.0
            self.epsilon_decay = 0.999
            self.epsilon_min = 0.01
            self.batch_size = 64
            #self.batch_size = 1
            self.train_start = 1000
    
            # 리플레이 메모리, 최대 크기 2000
            self.memory = deque(maxlen=2000)
    
            # 모델과 타깃 모델 생성
            self.model = self.build_model()
            self.target_model = self.build_model()
    
            # 타깃 모델 초기화
            self.update_target_model()
    
            if self.load_model:
                self.model.load_weights("./save_model/cartpole_dqn_trained.h5")
    
        # 상태가 입력, 큐함수가 출력인 인공신경망 생성
        def build_model(self):
            model = Sequential()
            model.add(Dense(24, input_dim=self.state_size, activation='relu',
                            kernel_initializer='he_uniform'))
            model.add(Dense(24, activation='relu',
                            kernel_initializer='he_uniform'))
            model.add(Dense(self.action_size, activation='linear',
                            kernel_initializer='he_uniform'))
            model.summary()
            model.compile(loss='mse', optimizer=Adam(lr=self.learning_rate))
            return model
    
        # 타깃 모델을 모델의 가중치로 업데이트
        def update_target_model(self):
            self.target_model.set_weights(self.model.get_weights())
    
        # 입실론 탐욕 정책으로 행동 선택
        def get_action(self, state):
            if np.random.rand() <= self.epsilon:
                return random.randrange(self.action_size)
            else:
                q_value = self.model.predict(state)
                #print("q_value는", q_value)
                #print("argamx(q_value)는", np.argmax(q_value[0]))
                #print("State는", state)
                return np.argmax(q_value[0])
    
        # 샘플 <s, a, r, s'>을 리플레이 메모리에 저장
        def append_sample(self, state, action, reward, next_state, done):
            self.memory.append((state, action, reward, next_state, done))
    
        # 리플레이 메모리에서 무작위로 추출한 배치로 모델 학습
        def train_model(self):
            if self.epsilon > self.epsilon_min:
                self.epsilon *= self.epsilon_decay
    
            # 메모리에서 배치 크기만큼 무작위로 샘플 추출
            mini_batch = random.sample(self.memory, self.batch_size)
            states = np.zeros((self.batch_size, self.state_size))
            next_states = np.zeros((self.batch_size, self.state_size))
            actions, rewards, dones = [], [], []
    
            for i in range(self.batch_size):
                states[i] = mini_batch[i][0]
                actions.append(mini_batch[i][1])
                rewards.append(mini_batch[i][2])
                next_states[i] = mini_batch[i][3]
                dones.append(mini_batch[i][4])
    
            # 현재 상태에 대한 모델의 큐함수
            # 다음 상태에 대한 타깃 모델의 큐함수
            target = self.model.predict(states)
            target_val = self.target_model.predict(next_states)
    
            # 벨만 최적 방정식을 이용한 업데이트 타깃
            for i in range(self.batch_size):
                #print("target은", target[i])
                if dones[i]:
                    target[i][actions[i]] = rewards[i]
                else:
                    target[i][actions[i]] = rewards[i] + self.discount_factor * (
                        np.amax(target_val[i]))
    
            self.model.fit(states, target, batch_size=self.batch_size,
                           epochs=10, verbose=0)
    
    
    if __name__ == "__main__":
        # CartPole-v1 환경, 최대 타임스텝 수가 500
        env = gym.make('CartPole-v1')
        env = wrappers.Monitor(env, "./gym-results-Cart", force=True, video_callable=lambda episode_id: episode_id%20==0)
    
        state_size = env.observation_space.shape[0]
        action_size = env.action_space.n
    
        # DQN 에이전트 생성
        agent = DQNAgent(state_size, action_size)
    
        scores, episodes = [], []
    
        for e in range(EPISODES):
            done = False
            score = 0
            # env 초기화
            #env = wrappers.Monitor(env, "./gym-results-Cart", force=True)
            state = env.reset()
            state = np.reshape(state, [1, state_size])
            #print("state reshape는",state)
    
            while not done:
                
                if agent.render:
                    env.render()
    
                # 현재 상태로 행동을 선택
                action = agent.get_action(state)
                # 선택한 행동으로 환경에서 한 타임스텝 진행
                next_state, reward, done, info = env.step(action)
                next_state = np.reshape(next_state, [1, state_size])
                # 에피소드가 중간에 끝나면 -100 보상
                reward = reward if not done or score == 499 else -100
    
                # 리플레이 메모리에 샘플 <s, a, r, s'> 저장
                agent.append_sample(state, action, reward, next_state, done)
                # 매 타임스텝마다 학습
                if len(agent.memory) >= agent.train_start:
                    agent.train_model()
    
                score += reward
                state = next_state
    
                if done:
                    # 각 에피소드마다 타깃 모델을 모델의 가중치로 업데이트
                    agent.update_target_model()
    
                    score = score if score == 500 else score + 100
                    # 에피소드마다 학습 결과 출력
                    scores.append(score)
                    episodes.append(e)
                    #pylab.plot(episodes, scores, 'b')
                    #pylab.savefig("./save_graph/cartpole_dqn.png")
                    print("episode:", e, "  score:", score, "  memory length:",
                          len(agent.memory), "  epsilon:", agent.epsilon)
    
                    # 이전 10개 에피소드의 점수 평균이 490보다 크면 학습 중단
                    if np.mean(scores[-min(10, len(scores)):]) > 490:
                        agent.model.save_weights("./save_model/cartpole_dqn.h5")
                        sys.exit()
    

    다음 내용을 수정했다.

    • 10 행: from gym import wrappers: wrappers 사용.
    • 120 행: env = wrappers.Monitor(env, “./gym-results-Cart”, force=True, video_callable=lambda episode_id: episode_id%20==0): 20번마다 동영상으로 저장. 여기를 설정하지 않으면 64번째 에피소드 동영상을 저장하고, 1,000번째 에피소드로 넘어간다. 학습 과정을 알 수 없다.

    cartPole-v1은 10초 동안 막대기가 넘어지지 않으면 끝나는 모델이다. 10초 전 막대기가 12도 넘게 기울어지면 끝난다. Q-learning은 아래 식으로 정의된다. \alpha 는 learning rate, \gamma 는 discount factor.

    Q(S_{t},A_{t})\leftarrow Q(S_{t},A_{t})+\alpha \left [R_{t+1}+\gamma\max_{a}Q(S_{t+1},a)-Q(S_{t},A_{t}) \right ]

    위 식에서 Q(S_{t},A_{t})R_{t+1}+\gamma \max_{a}Q(S_{t+1},a) 로 오차를 줄여 나간다. 오차는 MSE = ( 정답 – 예측 ) ^{2} = (R_{t+1} + \gamma Q(S_{t+1},A_{t+1}) - Q(S_{t},A_{t}) 로 정의한다. keras.fit에서 state에 따른 예측Q(S_{t},A_{t}) 과 정답인 target[i]로 학습한다. keras.fit을 부르기 전에 miniBatch 크기 모든 target[size]를 업데이트한다. print로 taget[i]값을 확인할 수 있다.

    episode: 73   score: 64.0   memory length: 2000   epsilon: 0.2699131774597243
    update전 target[20] [41.376812 37.715374]
    update후 target[20] [41.376812 40.977367]
    #action에 따른 정확한 Q 값을 수정.
    ##여기에서 무작위로 다시 뽑음.
    update전 target[20] [46.597427 39.114082]
    update후 target[20] [46.597427 42.882465]
    ...
    episode: 132   score: 419.0   memory length: 2000   epsilon: 0.009998671593271896
    update전 target[20] [113.11228 112.72044]
    update후 target[20] [113.11228 113.5387 ]
    update전 target[20] [109.97069 109.24642]
    update후 target[20] [109.97069 109.48601]
    update전 target[20] [112.96742 112.18164]
    update후 target[20] [112.92011 112.18164]
    # 132번 episode가 73번 episode보다 정답에 더 근접하여 업데이트 량이 줄었다.

    이렇게 10개 평균 score가 490 이상이면 학습을 중단한다. 적당한 Q 값을 찾는 문제라 value based Reinforce Learning이라 한다. 모델을 정의할 때 Q 값을 제한하지 않으려 activation을 linear로 설정했다.

    300번 학습 결과,스코어 vs 횟수.

    정책을 직접 근사하는 방법은 policy based Reinforce Learning인데, 마지막에 softmax 로 확율을 나오도록 해야 한다.

    Sutton & Barto 가 쓴 책을 보면 잘 이해가지 않는데, 직접 돌려 확인하면 이해했다 착각한다.