独学でプログラミングとかやってみる 〜ITとかの勉強レポート〜

ボクが勉強したプログラミングやIT関連の情報を記事にしていきます。機械学習や深層学習なども取り扱います。

Oculus GoのゲームをUnityで作る★その1

Oculus GoのゲームをUnityで組んでみる

コントローラ取得

Unityでゲームを作るのに必ず必要なことがあります。 それはコントローラからの入力をスクリプトで取得することです。 まず、コントローラ入力を取得する方法を調べたのでメモとして書いておきます。

元の記事 https://qiita.com/ry-kgy/items/2b783b969c874ef4cc64

バックボタン

バックボタン入力取得

OVRInput.Get(OVRInput.Button.Back)

トリガー

トリガーを押した入力の取得

OVRInput.GetDown(OVRInput.Button.PrimaryIndexTrigger)

トリガーを離した入力の取得

OVRInput.GetUp(OVRInput.Button.PrimaryIndexTrigger)

タッチパッド

クリックの入力取得

OVRInput.Get(OVRInput.Button.PrimaryTouchpad)

Up方向の入力取得

OVRInput.Get(OVRInput.Button.Up)

Down方向の入力取得

OVRInput.Get(OVRInput.Button.Down)

Left方向の入力取得

OVRInput.Get(OVRInput.Button.Left)

Right方向の入力取得

OVRInput.Get(OVRInput.Button.Right)

位置

位置の取得

Vector2 vector = OVRInput.Get(OVRInput.Axis2D.PrimaryTouchpad)

次回簡単な実装に挑戦

入力系統は以上ですので、あとはUnityでシンプルなゲームを作っていきたいと思います。 アンドロイドでビルドすれば動作するようなので、 次回以降は実際にゲームを組み、Oculus Go実機での動作確認を進めていきます。

OpenCVの基本操作の一部

OpenCVPythonで操作する基本的な話をメモ的に記載します。

ヒストグラム

import cv2
import matplotlib.pyplot as plt

img = cv2.imread("画像データのPath")

#カラー画像の場合
color_list = ["blue", "green", "red"]
for i,j in enumerate(color_list):
    hist = cv2.calcHist([img], [i], None, [256], [0, 256])
    plt.plot(hist, color = j)

#グレースケール画像の場合
img_gray = cv2.imread("画像データのPath", 0)
hist2 = cv2.calcHist([img_gray], [0], None, [256], [0,256])
plt.plot(hist2)

#ヒストグラムの均一化
img_eq = cv2.equalizeHist(img)
hist_e = cv2.calcHist([img_eq], [0], None, [256], [0, 256])
plt.plot(hist_e)

γ変換

画面を明るくしたり暗くしたりする処理

import numpy as np

#明るくするにはgamma > 1
gamma = 1.5
gamma_cvt = np.zeros((256, 1), dtype=np.uint8)
for i in range(256):
    gamma_cvt[i][0] = 255 * (float(i)/255) ** (1.0/gamma)
    
img_gamma = cv2.LUT(img, gamma_cvt)

#暗くするにはgamma < 1
gamma = 0.4
gamma_cvt = np.zeros((256, 1), dtype=np.uint8)
for i in range(256):
    gamma_cvt[i][0] = 255 * (float(i)/255) ** (1.0/gamma)
    
img_gamma = cv2.LUT(img, gamma_cvt)

以上、簡単な操作の一部でした。

MacでC++をコンパイルする

調べて忘れるのももったいないので、 メモとして記載します。

g++を使ってコンパイルを行います。 ターミナルに

$gcc --help

と入力して一覧が出てくれば準備は整っています。 例えば、「main.cpp」というファイルをコンパイルするには、

#a.outというファイルが出力される
$g++ main.cpp

#helloというファイルが出力される
$g++ -o hello main.cpp

出力されたファイルを実行するときは

#a.outを実行する場合
$./a.out

#helloを実行する場合
$./hello

以上のように入力すればOKです。

PythonでOpenCVを使ってみた

画像を開く、保存する

import cv2
img = cv2.imread("画像ファイルPath")
cv2.imwrite("保存ファイルPath", img)

動画を開く、保存する

import cv2
video = cv2.VideoCapture("動画ファイルPath")
if cap.isOpened() == False:
    sys.exit()
ret, frame = cap.read()
h, w = frame.shape[:2]
fourcc = cv2.VideoWriter_fourcc(*"XVID")
dst = cv2.VideoWriter("保存ファイルPath", fourcc, 30.0, (w,h))

リサイズ

import cv2
img = cv2.imread("画像ファイルPath")
size = (300, 200) #変更後のサイズを指定する
img_resize = cv2.resize(img, size)

以上の簡単な操作を行いました。

フルスクラッチで単回帰分析をやってみる

機械学習の理解を深める

Pythonにはsklearnという便利な機械学習ライブラリがあります。 ただ、内部の計算に触れることは大事だと思うのです。 というわけで今回は単回帰分析をsklearnを使わずに実装します。

計算の準備

計算式の確認をします。 単回帰なのでパラメータは一つです。 パラメータをaとすると、


a = \dfrac{\displaystyle{\sum_{n=1}^{N}}x_{n}y_{n}}
{\displaystyle{\sum_{n=1}^{N}}x_{n}^{2}}

上記のようになります。
簡単な計算式ですので、簡単に実装できます。例えば、pandasのデータフレームを使えば、 次のように実装できると思います。

xx = x * x
xy = x * y
a = xy.sum() / xx.sum()

簡単にパラメータが求められます。 データからの予測値は


result = ax

上記の式で求めることができます。 実際にデータを扱うときはすこしデータに手を加えて、 値から平均を引いた値を使って計算しやすくするなどの工夫をしたほうがいいと思います。

TensorFlowでMNISTを使ってみる

今回やったこと

TensorFlowのチュートリアルを今回やってみました。 MNISTというかなり有名な数字画像の識別問題をやってみます。

どうやったか?

チュートリアルに倣ってsoftmaxと勾配降下法を使いました。 ミニバッチでランダムにサンプルを選んで学習させてマシンへの負担を減らしています。

PythonでのコードはTensorFlowのチュートリアルにあるので省略します。

結果は92%の識別精度が出ました!
特別なことを特にしていないのにすごい精度ですね。 99%以上の精度を出す方法もあることが知られていますが、 それはDeepLearningを使っているそうです。
MNISTは何回かコード書いて遊んでますが、TensorFlowを使うとコーディング楽ですね。

DeepQ-NetworkでOpenAI Gymに挑戦!

DeepQ-Networkとは

一言で言うと多層のQネットワークです。 Qネットワークに隠れ層を追加して多層化したもので、 今回はExperience Replayというアルゴリズムを使って実装していきます。 メモリにステート、アクション、次のステート、次のアクションを記録していきます。 メモリの上限を超えたら端から消していくDouble Ended Queueと呼ばれる構造を使いたいと思います。

今回はカートポールというOpenAI Gymの有名なゲームに挑戦します。

Pythonでサクサクと実装していきます。 コードを全部載せると長いので省略して書いていきます。

#Q-Networkのクラス
class QNetwork:
    def __init__(self,learning_rate=0.01,state_size=4,action_size=2,hidden_size=10,name="QNetwork"):
        with tf.variable_scope(name):
            self.inputs_ = tf.placeholder(tf.float32,[None,state_size],name="inputs")
            self.actions_ = tf.placeholder(tf.int32,[None],name="actions")
            one_hot_actions = tf.one_hot(self.actions_,action_size)
            self.targetQs_ = tf.placeholder(tf.float32,[None],name="target")
            self.fc1 = tf.contrib.layers.fully_connected(self.inputs_,hidden_size)
            self.fc2 = tf.contrib.layers.fully_connected(self.fc1,hidden_size)
            self.output = tf.contrib.layers.fully_connected(self.fc2,action_size,activation_fn=None)
            self.Q = tf.reduce_sum(tf.multiply(self.output,one_hot_actions),axis=1)
            self.loss = tf.reduce_mean(tf.square(self.targetQs_-self.Q))
            self.opt = tf.train.AdamOptimizer(learning_rate).minimize(self.loss)
#MemoryObjectのクラス
from collections import deque
class Memory:
    def __init__(self,max_size=2000):
        self.buffer = deque(maxlen=max_size)
        
    def add(self,experience):
        self.buffer.append(experience)
        
    def sample(self,batch_size):
        idx = np.random.choice(np.arange(len(self.buffer)),size=batch_size,replace=False)
        return [self.buffer[i] for i in idx]
#Experience Memory
env.reset()
state,reward,done,_ = env.step(env.action_space.sample())
memory = Memory(max_size=memory_size)

for i in range(pretrain_length):
    action = env.action_space.sample()
    next_state,reward,done,_ = env.step(action)
    
    if done:
        next_state = np.zeros(state.shape)
        memory.add((state,action,reward,next_state))
        
        env.reset()
        state,reward,done,_ = env.step(env.action_space.sample())
    else:
        memory.add((state,action,reward,next_state))
        state = next_state

隠れ層は64個、トレーニング回数は2000回とします。
トレーニングが完了したらいつものように、ゲームを実行してみます。

ゲームのスコアは199.0でした!
最大スコアが200なのでうまく学習してくれたことがわかります。 強化学習は面白いですね!