数値解析系

2021年3月30日 (火)

Yolov3で駐車場空き状況把握をトライ中

なんか急に、そういうものを調べようということになりまして。

というのも、会社で「駐車場の空き状況を把握できないか」という話が出ました。

やり方は色々とあるのですが、最も手っ取り早い方法を試すことに。

それは、汎用の物体検出手法を使って「車」を検出させて、その数・位置から空き状況を把握する、というもの。

そこで以前、最新の物体検出YOLO v3 (Keras2.2.0+TensorFlow 1.8.0)を独自データで学習できるようにしてみた: EeePCの軌跡でも紹介したYolov3を使ってみました。

20210326_173609

幸い、我が家のすぐ横が駐車場なので、それを利用させてもらいます。

タイムラプス撮影を行い、その後、その写真で車の数をカウントさせるというところまでを実行。

元のコードをちょっと書き換えて、バウンディングボックスの中心点と、その中に数を表示するようにしました。

Yolo_20210326_170236

で、結果はこの通り。見えにくいですが、赤い丸の中に数字が書かれてます。

実は側面からなので、ちょっとカウントしづらい環境でしたが、まあまあ正確なカウントと位置把握はできたんじゃないかと。

と、思いきや、よく見ると奥の車はダブルカウントしてますね。

やっぱり、正面 or 背面から撮影しないと、うまくいかなさそうです。

まあ、プロトタイプができたので、これをもって社内に売り込もうかと。

定点観察なので、駐車場枠の中のアスファルト路面が見えるか見えないかでやるのが、一番確実な気もします。あるいは、Yoloなどとそれを組み合わせて、精度を上げるというのもありかもしれませんね。

なお最近、社内外でこのYolov3がよく使われてます。

Yoloの最新版はv5なのですが、あちらは商用利用に難ありだったりするので、手軽なv3に人気があるようです。で、私の以前書いた上の記事がマニュアルとしてよく使われてると聞いてます。

実際、SSDよりYoloの方が検出数や精度が高く、かつ速いですからね。

Google Colabを使うという手もあるんですが、手軽な反面、業務用ではやや手を出しにくい(Google Drive上に業務データを置くことになるので)という事情もあって、オンプレで利用したいという声が多いですね。そうなると、オンプレ上での活用が進んでいるYolov3に人気が集まる、ということのようです。

実は実業務で物体検出を使ったことがなかったのですが、これを機にいろいろと活用してみましょうかね。


今すぐ試したい! 機械学習・深層学習(ディープラーニング) 画像認識プログラミングレシピ

2021年2月27日 (土)

Raspberry Pi × 画像認識 で「後出しじゃんけん機」作ってみた

久しぶりの、Raspberry Piネタです。

今日は、どちらかというと「教育用」なネタです。

Raspberry Piと画像認識を応用した「後出しじゃんけん機」なるものを作ってみました。

なんじゃそら?という名前ですが、簡単に言うと、

(1) グー、チョキ、パー をラズパイカメラで撮影して記録 (各30枚づつくらい)

(2) 上の写真を用いて深層学習(CNN)を実施

(3) できたモデルを使い、カメラで撮影した「手」を推論する

(4) 推論結果に対し、勝つ手の画像を表示する

……という、Raspberry Piを使った一種のAIです。

これ、要するに、身近なもので画像認識AIを体感しよう!って趣旨の工作&プログラムです。

通常なら、Raspberry PiとPCを組み合わせるところですが、この両者の行き来が煩わしいので、学習用のデータ取りから学習、そして推論までを、すべてRaspberry Pi上でできるようにしてます。

まず、準備ですが、以下の3つのコードをコピペして持って行ってください。

「1_camera.py」


import glob
import time
import os
import io

# for Raspberry Pi
import RPi.GPIO as GPIO
import picamera

GPIO.cleanup()

#for Raspberry Pi
GPIO.setmode(GPIO.BCM)
port1 = 17 # gu
port2 = 27 # choki
port3 = 22 # pa

GPIO.setup(port1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(port2, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)
GPIO.setup(port3, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

count = 1
flag = 0

# File remove
file_list = glob.glob('./data/0_gu/*')
for file in file_list:
    os.remove(file)
file_list = glob.glob('./1_choki/*')
for file in file_list:
    os.remove(file)
file_list = glob.glob('./data/2_pa/*')
for file in file_list:
    os.remove(file)

print('Ready!')

try:
    while True:
        sc = str(count)
        ssc = sc.zfill(4)
        #GPIOの17,27,22がオンになったら、画像を取り込んで認識を開始
        if GPIO.input(port1):
            label = '0_gu'
            flag = 1
        elif GPIO.input(port2):
            label = '1_choki'
            flag = 1
        elif GPIO.input(port3):
            label = '2_pa'
            flag = 1
            
        if flag ==1 :
            print(ssc + ':' + label)
            with picamera.PiCamera() as camera:
                    camera.resolution = (12896)
                    camera.start_preview()
                    camera.capture('./data/'+label+'/'+label+ssc+'.jpg')
            count +=1
            flag = 0

        time.sleep(0.01)

except KeyboardInterrupt:
    GPIO.cleanup()

「2_train.py」


#!/usr/bin/env python
# -*- coding: utf-8 -*-

import os
import sys
import numpy as np
import tensorflow as tf
import matplotlib.pyplot as plt

import keras
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
from keras.callbacks import ModelCheckpoint

# ======= hypter param =====
batch_size = 10
epochs = 50
# ==========================

path=os.getcwd()+'/data/'

class_count = 0
folder_list=os.listdir(path)

for folder in folder_list:

  class_count = class_count+1

NUM_CLASSES = class_count
IMAGE_SIZE = 28

# Loss
def plot_history_loss(fit):
    # Plot the loss in the history
    axL.plot(fit.history['loss'],label="loss for training")
    axL.plot(fit.history['val_loss'],label="loss for validation")
    axL.set_title('model loss')
    axL.set_xlabel('epoch')
    axL.set_ylabel('loss')
    axL.legend(bbox_to_anchor=(10), loc='lower right'borderaxespad=1fontsize=10)

# Accurascy
def plot_history_acc(fit):
    # Plot the loss in the history
    axR.plot(fit.history['acc'],label="loss for training")
    axR.plot(fit.history['val_acc'],label="loss for validation")
    axR.set_title('model accuracy')
    axR.set_xlabel('epoch')
    axR.set_ylabel('accuracy')
    axR.legend(bbox_to_anchor=(11), loc='upper right'borderaxespad=1fontsize=10)

if __name__ == '__main__':

    count=0
    folder_list = sorted(os.listdir(path))

    train_image = []
    train_label = []
    test_image = []
    test_label = []
    X = []
    Y = []

    label = 'label.txt'
    
    f = open(label, 'w')
    for folder in folder_list:
        subfolder = os.path.join(path,folder)
        file_list = sorted(os.listdir(subfolder))

        filemax = 0

        i = 0

        for file in file_list:

            i = i + 1

            img = img_to_array(load_img('./data/' + folder + '/' + file,target_size=(28,28)))
            X.append(img)
            Y.append(count)
        
        label_name = folder + ' ' + str(count) + '\n'
        f.write(label_name)

        count +=1

    X = np.asarray(X)
    Y = np.asarray(Y)
    X = X.astype('float32')
    X = X / 255.0

    Y = np_utils.to_categorical(Y, NUM_CLASSES)

    train_image, test_image, train_label, test_label = train_test_split(X,Y,test_size=0.20)
    
    f.close()
    print(u'画像読み込み終了')

    input_shape = (IMAGE_SIZE, IMAGE_SIZE, 3)

    model = Sequential()
    model.add(Conv2D(32,kernel_size=(3,3),
                     activation='relu',
                     padding='same'
                     input_shape=input_shape))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Conv2D(64, (3,3), activation='relu'padding='same'))
    model.add(MaxPooling2D(pool_size=(2,2)))

    model.add(Flatten())
    model.add(Dense(512activation='relu'))
    model.add(Dropout(0.5))
    model.add(Dense(NUM_CLASSES, activation='softmax'))

    model.compile(loss=keras.losses.categorical_crossentropy,
                  optimizer=keras.optimizers.Adadelta(),
                  metrics=['accuracy']
                  )

    chkpt = './model_28.h5'
    cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss'verbose=1
                            save_best_only=Truemode='auto')

    history = model.fit(train_image, train_label,
              batch_size=batch_size,
              epochs=epochs,
              verbose=1,
              validation_data=(test_image, test_label),
              callbacks=[cp_cb],
              )

    model.summary()

    score = model.evaluate(test_image, test_label, verbose=0)

    fig, (axL, axR) = plt.subplots(ncols=2figsize=(10,4))

    plot_history_loss(history)
    plot_history_acc(history)

    fig.savefig('./loss_acc.png')
    plt.close()

「3_atdashi.py」


#!/usr/bin/env python

import os
import sys
import numpy as np
import tensorflow as tf

import keras
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
import time

import RPi.GPIO as GPIO
import picamera

i = 0
label_name = []

label = 'label.txt'

f = open(FLAGS.label,'r')
for line in f:
  line = line.rstrip()
  l = line.rstrip()
  label_name.append(l)
  i = i + 1

NUM_CLASSES = i
IMAGE_SIZE = 28

if __name__ == '__main__':
    test_image = []
    
    # model read
    model = load_model('./model_28.h5')
    model.summary()
    
    # for Raspberry Pi

    GPIO.cleanup()

    #for Raspberry Pi
    GPIO.setmode(GPIO.BCM)
    port1 = 24 # switch

    GPIO.setup(port1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    print('Ready!')
    try:
        while True:
            if GPIO.input(port1):
                with picamera.PiCamera() as camera:
                    camera.resolution = (12896)
                    camera.start_preview()
                    camera.capture('./tmp.jpg')
                
                img = img_to_array(load_img('./tmp.jpg' , target_size=(28,28)))
                test_image.append(img)
                test_image = np.asarray(test_image)
                test_image = test_image.astype('float32')
                test_image = test_image / 255.0
    
                predictions = model.predict_classes(test_image)
    
                print(label_name[predictions[0]], u'です。')
                
                test_image = []
            
            time.sleep(0.01)

    except KeyboardInterrupt:
        GPIO.cleanup()

事前に、TensorFlow、Keras、numpyなどのライブラリをpip3コマンドで取り込んでおいてください。

(なお、TensorFlowは1.14、kerasは2.2.4 を推奨)

で、Raspberry Piの回路図は以下の通り。4つのタクトスイッチを使います。

Atdasi01

ちょっとわかりにくいですが、各タクトスイッチにつながる線で、黒は「GPIO24」、青は「GPIO17」、黄は「GPIO27」、緑は「GPIO22」、そして赤は「3.3V」につながってます。

あ、Raspberry Pi用のカメラも当然、つないでおきます。

で、先の3つのプログラムコードを、一つのフォルダに入れます。

Atdashi02

また、同じフォルダ内に「data」という名前のフォルダを作り

Atdashi03

その下に、上のような「グー」「チョキ」「パー」に当たる3種類のフォルダを作っておきます。

Img_0159

で、我が家のRaspberry Piで組んでみました。

Img_0164

こんな感じに、4つのタクトスイッチとつないでます。

なお、カメラは5インチ液晶の裏に両面テープで張り付けておきました。

これで、準備完了です。

(1) グー、チョキ、パー をラズパイカメラで撮影して記録 (各30枚づつくらい)

まず、自分の手を使って、「グー」「チョキ」「パー」の手を集めます。

Raspberry Pi上でターミナルを開き、

> python3 1_camera.py

と入力し、実行。

ターミナル上に「Ready!」と表示されたら、準備完了です。撮影を開始します。

Raspberry Piのカメラの前で「グー」「チョキ」「パー」の3種類の手を構えて、先の回路図にあるボタン「グー」「チョキ」「パー」で、手にあったものを選んで押します。

Img_0162

すると以下のような感じに、各フォルダ内に画像がたまっていきます。

Atdashi04

各ラベルごとに、20~30枚づつくらい撮影してください。

なお、合計が100枚を超えると、Raspberry Pi 3B+ではメモリーが飛ぶっぽいです(うちは飛びました)。

(2) 上の写真を用いて深層学習(CNN)を実施

(1)で教師データができたので、学習を実行します。同じフォルダ内で、

> python3 2_train.py

と実行します。

デフォルトでは、50エポックほど流れます。大体5分くらいで終わります。

なお、この50エポック内の最良のモデルのみが保存される仕組みになっているため、学習が終わればそのまま(3)へと移行します。

が、その前に、学習の状況を確認しておきましょう。

作業フォルダー中に、「loss_acc.png」という画像ファイルができているはずです。

Loss_acc

その名の通り、Loss(損失)値とAccuracy(精度)値のグラフが出てきます。Loss値は0に近いほど、Accuracyは1に近いほど、高精度なモデルができている目安になります。

が、よく見るとどちらも2色あります。これは、学習用データでの検証値(Train)と、評価用データでの検証値(Val)となります。

簡単に言うと、上の画像のようにLoss、Accuracy共に、この両者がほぼ同じところに収束していれば、学習としてはまずまずです。

これがTrainとValとが離れていると、いわゆる”過学習”と呼ばれる状態になります。その場合は汎用性が落ちているので、パラメータを変更するなり、(1)からやり直すなりして、再学習する必要が出てきます。

(例えば、batchの値を10→20に変えてみる 等)

単純に、何も変えずにもう一度実行するだけでよくなることもあります。何度実行しても改善されないときのみ、パラメータをいじるか、あるいは写真の撮り直しを実行してみてください。

グラフを確かめてから、(3)へ行きます。

(3) できたモデルを使い、カメラで撮影した「手」を推論する

ここでは、「3_atodashi.py」を使います。

> python3 3_atodashi.py

と実行したのち、

Img_0163

こんな感じに、カメラの前で手を構えます。

もし、写真のようにチョキを出しているときに、プロンプト上で

 > 2_choki

と表示されたら、推論成功です。

グーやパーだと勘違いしていたら、学習に失敗している可能性があります。

(1)か、(2)あたりからやり直してください。

あるいは、手が近すぎる or 遠すぎることもあります。何度か実験した経験での話ですが、ちょっと動かしてみると、精度が上がる距離がどこかにあることが多いです。

さて、画像認識としてはここまでで終了ですが、これではまだ「後出しじゃんけん機」ではありませんね。

(4) 推論結果に対し、勝つ手の画像を表示する

Raspberry Piに後出しじゃんけんをさせるために、「3_atodashi.py」を以下のコードに置き換えます。


#!/usr/bin/env python

import os
import sys
import numpy as np
import tensorflow as tf
import cv2

import keras
from keras.utils import np_utils
from keras.models import Sequential
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
import time

import RPi.GPIO as GPIO
import picamera

i = 0
label_name = []

label = 'label.txt'

f = open(label,'r')
for line in f:
  line = line.rstrip()
  l = line.rstrip()
  label_name.append(l)
  i = i + 1

NUM_CLASSES = i
IMAGE_SIZE = 28

if __name__ == '__main__':
    test_image = []
    
    # model read
    model = load_model('model_28.h5')
    model.summary()
    
    # for Raspberry Pi

    GPIO.cleanup()

    #for Raspberry Pi
    GPIO.setmode(GPIO.BCM)
    port1 = 24 # switch

    GPIO.setup(port1, GPIO.IN, pull_up_down=GPIO.PUD_DOWN)

    print('Ready!')
    try:
        while True:
            if GPIO.input(port1):
                with picamera.PiCamera() as camera:
                    camera.resolution = (12896)
                    camera.start_preview()
                    camera.capture('./tmp.jpg')
                
                img = img_to_array(load_img('./tmp.jpg' , target_size=(28,28)))
                test_image.append(img)
                test_image = np.asarray(test_image)
                test_image = test_image.astype('float32')
                test_image = test_image / 255.0
    
                predictions = model.predict_classes(test_image)
    
                print(label_name[predictions[0]], u'です。')

                #後出し処理
                if predictions[0] == 0# 「グー」だった時
                    reac = "pa.png" # 「パー」を返す
                elif predictions[0] == 1# 「チョキ」だった時
                    reac = "gu.png" # 「グー」を返す
                else# 残り、すなわち「パー」だった時
                    reac = "choki.png" # 「チョキ」を返す

                img = cv2.imread(reac)
                cv2.imshow("reaction",img)
                key = cv2.waitKey(1000
                cv2.destroyAllWindows()
                
                test_image = []
            
            time.sleep(0.01)

    except KeyboardInterrupt:
        GPIO.cleanup()

「#後出し処理」というコメント行がある後ろ当たりに、その後出しじゃんけんの処理が追加されてます。

また、画像表示にはOpenCVを用いてますので、pip3コマンドでOpenCVをインストールしておいてください。

> pip3 install python-opencv

で、このほかに画像が3枚、つまり、グー、チョキ、パーの画像をそろえる必要があります。

私はいらすとやで落としましたが、なんでもいいです。

Atodashi05

こんな感じに「グー」「チョキ」「パー」それぞれ「gu.png」「choki.png」「pa.png」として、Raspberry Pi上のプログラムコードの入った同じフォルダに入れておいてください。

で、この状態で(3)と同様に動かすと、推論の直後に、Raspberry Piが勝つと思う手を表示してきます。

Img_0205

こんな具合です。

(3)でそこそこの精度が出るモデルであれば、正しい「勝ち手」を出してくれるはずですね。

はい、以上が「後出しじゃんけん機」を作るまで、です。

(2)で使う「Train.py」という学習用コードを読めばわかる通り、28×28の画像で学習、推論させてます。この解像度じゃないと、Raspberry Piでは学習できません。

かなり低い解像度ですが、案外この解像度でも、じゃんけんくらいは認識できるようです。

もっとも、一筋縄ではいかないところもありますね。背景に依存しちゃったり、あるいは過学習で現実の手をうまく認識しなかったり……その辺りは、トライアンドエラーで実験してみるのがよいかと思います。

今回入れてませんが、Grad‐Camを使ったりして、モデルの確からしさを調べるのもいいですね。実際、会社にある同じコードでは、Grad-Camを組み込んでます。

どちらかというと、画像認識の理屈よりも、それを実際に使ってみてノウハウっぽいものを学ぶというのが狙いのプログラムコード。やってみると、思ったよりも精度は出ることもあるし、思い通りにいかないこともあります。

もちろん、ここに書いただけでは不十分な話が多いです。パラメータまで含めたら、一介のブログ記事では書ききれないほどいろいろあります。

このほか、精度におけるカメラと手の距離の依存性が高いので、HC-SR04などの距離センサーと組み合わせて撮影させてみるなど、電子工作の題材にもぴったりですね。

とまあ、我ながらうまい仕掛けを作ったものだと思っていたんですが。

これを作り上げた後に、「人気ブロガーからあげ先生のとにかく楽しいAI自作教室」(日経BP)という本にも、同じようにじゃんけんの手を学習させるというコードがあることが判明。

で、Kindle版で購入してみてみたんですが……あちらはRaspberry Pi上ではなく、しかも画像セットはあらかじめ準備されたものを使用、かつ、Google Colab上で動かすというものでした。いやはや、幸いにもこちらのやってることとは、かぶってませんでしたね。

まあ、似たようなことは皆さん、考えるものですね。

ちなみにこの本、画像だけでなく、自然言語など、幅広いカテゴリーの話が載っていたりと、なかなか面白い本です。買って損はありません。

著者のからあげ氏のブログは、Raspberry Pi関係のコードではとてもお世話になってますね。私もよく、参考にさせてもらってます。

以上、「画像認識を体で覚える」仕組みを作ってみた、というお話でした。


人気ブロガーからあげ先生のとにかく楽しいAI自作教室

2021年1月 4日 (月)

高精度な手足、身体の姿勢推定API「MediaPipe」を使って体の姿勢を数値化させてみる

一年ほど前に紹介した「PoseNet」がありますが。


Googleの「PoseNet」を試してみた: EeePCの軌跡


あれがさらに高精度、高密度になった「MediaPipe」なるものが、いつの間にか登場してます。


少し前から気になってたんですが、休みに入り、ようやくそれを実験する機会を得ました。


で、参考にしたのは以下のサイト。


CPUだけで顔・手・ポーズのリアルタイム検出を行う | cedro-blog


ここで紹介されたコードで、一発で動きました。


やったことといえば、


(1) pipコマンドで「MediaPipe」をインストールする。


  > pip install mediapipe


  (ほかにも、numpy、OpenCV、PILLOWも必要です)


(2) Githubから、コードを一式ダウンロードしておく。


サイトはこちら:GitHub - cedro3/mediapipe: MediaPipeのPythonパッケージのサンプルです。2020/12/11時点でPython実装のある4機能(Hands、Pose、Face Mesh、Holistic)について用意しています。


(3) WebカメラのついたPCなら、そのままコマンドで実行。


  > python sample_face.py


  (コードは4種類で、「sample_face.py」「sample_hand.py」「sample_holistic.py」「sample_pose.py」から選択。大体、どれがどういうコードかは、名前からわかるかと思います。)


こんな感じの結果が出ます。


Mediapipe03


Mediapipe02


いやあ、なかなか高精度ですね。


これ、GPUを使ってないようですが、うちの環境(Ryzen 5 4600H 6コア)で20~30fpsは出ます。


さて、姿勢推定をさせたなら当然、各々の座標が抜き出したくなるものですが、上で入手したコードのうち、「sample_holistic.py」という、顔も手も身体もすべて出力させているコードを参考にします。


このコードの中の「landmark_x」「landmark_y」という配列があるんですが、これが座標情報だとわかります。


で、じーっとこのコードを解読すると、例えば191行目から始まる「draw_hands_landmarks()」という関数207行目あたりを見ると、この中ではどうやらlandmark_point.x[2]、landmark_point.y[2]が親指の座標なんだなぁと読めますね。[]野中の数字が0だと「手首1」、1だと「手首2」(右か左かは不明)、10だと「中指・第2関節」……という具合に、解読できそうです。


顔の座標を読み出したければ、299行目から始まる「draw_face_landmarks()」を見れば、目や鼻、口の座標を拾えそうです。


かなり地味で忍耐が必要な作業になりそうですが、このコードを流用すれば、姿勢の数値化はどうにかできそうです。


とまあ、かなりいい感じのMediaPipe。これでPoseNetとはおさらばか……と思いきや。


実は欠点が一つあります。それは、1体しか読みだせないということ。


PoseNetは10人まで同時に読み込めましたが、こちらは一番大きな人物のみ姿勢推定を行うことしかできません。


このため、複数の人の動きをトレースすることは不可能。あくまでも一人だけの詳細な動きを読み出すためのコードのようです。


ベテランの作業姿勢と新入社員の姿勢とを比べる、といったことくらいならできそうですね。


今すぐ試したい! 機械学習・深層学習(ディープラーニング) 画像認識プログラミングレシピ


2020年12月31日 (木)

2020年まとめ

今年も、いろいろありましたね……

何といっても今年は新型コロナ禍の年。コロナで始まり、コロナで終わる。いや未だに、先が見えておりません。だからというわけではありませんが、どちらかというと今年は、私にとってあまりいいことはなかったですね……

このブログにとっては、毎日更新をやめた年でもあります。

とはいえ、やはりまとめができるほどの出来事が満載。今年を振り返ってみます。

【1月】

画像異常検知のデモ機「AIビー玉選別機」を作ってみた: EeePCの軌跡

さて今年は、いきなりRaspberry Pi工作から始まりました。

昨年末に買ったRaspberry Pi 4を使ってますが、結局今年は、Raspberry Pi 3B+をよく使った年でした。

それはともかく、いわゆる画像異常検知にトライしたこの事例。社内でも、使われつつあります。

【2月】

プロジェクター買いました: EeePCの軌跡

2月はせいぜい、これくらいですかねぇ。プロジェクターを買いました。

結論から言うと、ほとんど使ってません。家ではまるで使い道がないですね、これ。

【3月】

このあたりからコロナ禍が猛威を振るい、学校が休みになったり、外出自粛が叫ばれたり、インフラもないのに在宅勤務が推奨されたり……などなど、ストレスマッハな時期がはじまります。

そんな中でも、地道に活動しておりました。

 Raspberry Pi Camera V1.3の「互換カメラ」買ってみた: EeePCの軌跡

ブログが13年目に入る3月9日の記事がこれ。Raspberry Piカメラの互換品を安く手に入れたというお話。

このカメラ自体、今でも使っていて重宝してますが、そんな話題とは裏腹に、しれっとこの記事の最後に「毎日更新をやめます宣言」をしております。

ちょうど12年目のこの日を境に、自身の活動を中心とした記事のみを乗せようと心がけてます。

当ブログをhttps化しました: EeePCの軌跡

さて、このブログもう一つの大きな変化点は「https化」。

あまり意味があるような、ないような変化点ですが、ブラウザによってはかなりうっとおしい警告が出るため、切り替えてみました。

今ではほとんどセキュリティ警告が出なくなっているはずです。

 Ankerのロボット掃除機”Eufy”買ってみた: EeePCの軌跡

こんなものも買いました。

自動掃除機です。2万円以下で、わりと賢い掃除機を入手。週1で2階をせっせと掃除しております。これは良い買い物でした。

おかげさまで、コロナ太りが捗り過ぎて、夏の健康診断に引っかかるというおまけが付いてきましたが。

【4月】

子供の春休みが、終わりません。そんな4月には、こんなものを買ってます。

iPad用トラックパッド・キーボード付きケース買ってMacBookっぽく使えるか試してみた: EeePCの軌跡

結局、ほとんど使ってないのですが、iPad用キーボードです。トラックパッド付。

iPadOS 13がリリースされて、iPadがトラックパッド対応したため購入。

といってもうちにはMacBook Airがあるので、どうしてもそちらにいってしまいます。

使い勝手は、やはりクラムシェル端末には敵いませんね。

小説家になろう 第8回ネット小説大賞 一次選考に2作品が選ばれました: EeePCの軌跡

で、そんなMacBook Airの成果というべきものがこれ。

今年もなんとか1次通過しました。しかも、2作品。相変わらず、2次は全滅しましたが……

来年はもっと、飛躍できないかなぁ。

なお今年はブログ上のネームを、この「小説家になろう」にそろえて「ディープタイピング」としました。Twitterも同じく。ようやく発音可能な名前になりましたね。

特に記事にはしてませんが、この4月頃から会社でZoomをよく使うようになります。今ではすっかりZoom使いです。

【5月】

サーマルセンサー「AMG8833」とRaspberry Piで非接触体温計っぽいものを作ってみた: EeePCの軌跡

コロナ禍ということで、こういうものを作ってみました。

非接触体温計……っぽいもの。頑張れば使えそうなやつです。お値段も5000円ほどと、お手軽なセンサーです。

この記事ですが、このブログの今年のアクセス数トップ記事になっておりますね。

それにしても今年は、久しぶりにRaspberry Piをよく使った年です。

【6月】

6月は、あまり実りのない月でしたね。健康診断に引っかかったことくらいでしょうか?

が、こんな出来事がありました。

Apple ID詐欺……やられかけました……: EeePCの軌跡

Appleっぽい詐欺サイトに誘導されかけました。

特に実害はなさそうでしたが、警戒してすぐにApple IDのパスワードを変更してます。

そういえば周りにも、Facebookを乗っ取られた人がいました。世の中が乱れると、なぜかこういう輩が暗躍するようです。こういう時期、要注意ですね。

【7月】

コロナ禍がややおさまった名古屋 大須へ行って参りました: EeePCの軌跡

すごく久しぶりの大須探訪記です。長男と2人で、行ってきました。

コロナ禍でどうなっていることかと心配でしたが、ここは相変わらずでしたね。

といっても、細かい店がいくつか閉店(または閉店予告)しておりました。大須と言えども、やはり爪痕はあるようです。

長男と共に、大須の雰囲気を満喫した夏でした。

クラムシェル端末風に使えるタッチパッド付iPadキーボードケースを買ってみた: EeePCの軌跡

性懲りもなく、こんなものを購入。

最新版のiPad向けの商品を買ったため、サイズが合いませんが、何とか無理やり使ってレビュー。

使用感は、悪くありませんね。ただし、やはりMacBook Airには敵わず、結局これも使わずじまい。

【8月】

ミラー型ドライブレコーダー購入: EeePCの軌跡

ドライブレコーダーを買いました。

ルームミラーを電子ミラー化 & 後方カメラ付きというもので、今どきの煽り運転対策には最適。

夜でも後方を確認しやすくなりました。これは買いです。

【9月】

Surface Goがようやく実用形態に: EeePCの軌跡

今年はついに、Surfaceを買いました。

やはり、Zoomやらを使っていると、この手の軽くて起動が速い端末が欲しくなります。

スマホ世代には、ピッタリなWindows端末ですね。おすすめです。

ららぽーと東郷へ行ってきました: EeePCの軌跡

一方、うちの近所に馬鹿でかいショッピングモールが誕生です。

50km圏内をカバーする目的で作られたこのショッピングモール、SIMフリーiPhoneが調達できる店が、まさか徒歩圏内にできようとは思ってもいませんでした。

が、私にとってのこのショッピングモール最大のインパクトはヴィレッジヴァンガードが入っていること。

福袋入手は、ここで決まりです。

【10月】

久しぶりにEeePC 1000H-Xを起動してみた: EeePCの軌跡

ふと見つけた32ビットOSの話題につられて、久しぶりにEeePC 1000H-Xを起動してみました。

バッテリーは完全に死んでますが、本体はまだ生きてます。

とはいえ、さすがにもう遅いですね……12年前の、しかも最底辺のPCですからね。

Tensorflow.js + WebGLで顔検出してくれるWebアプリ: EeePCの軌跡

顔検出のWebアプリの紹介です。マスク顔でもこの通り、検出可能。

何気に、私の顔が出ております(ただしマスク付き)。

【11月】

Raspberry Pi + 磁気センサーで ドアの開閉をセンシングしてみた: EeePCの軌跡

ドアセンサー、作ってみました。会社のトイレIoTの要望に応えての工作です。

いかにもRaspberry Piらしい(?)電子工作ですね。

3COINSのBluetoothイヤホン買ってみた: EeePCの軌跡

瞬発的なアクセス数としては、今年一番バズった記事です。

3COINSで買ったBluetoothイヤホン。

1500円という金額にしては、とても使いやすく音質も悪くないです。

もっとも、ノイズキャンセリングがあるわけではないので、外ではそれなりの音質。

おまけに、よく途切れることがあります。室内でも時々、ぶちぶちと切れますね。安定性はいまいち。

でもまあ、1500円ですから、これ。そう思えば妥当かと。

ゲーム&ウォッチ型スーパーマリオ復刻版ゲーム: EeePCの軌跡

ところで、11月はいろいろなものを買った月です。その一つがこれ。スーパーマリオ35周年記念で、ゲーム&ウォッチ型のゲーム機。

ちなみに、スーパーマリオ1の方はクリアしました。

3年ぶりにiPhoneを購入!iPhone 12 グリーンをららぽーと東郷で入手!: EeePCの軌跡

で、今年最高額の買い物は、これ。

iPhone 12です。128GBで、色はグリーン。

これまでiPhone 5c以降、様々なカラバリモデルが出ましたけど、白・黒以外を買ったのはこれが初めてです。

画面サイズも6.1インチと、我が家では最大サイズのiPhone。おかげでとても見やすいです。

【12月】

11月はガジェット購入祭り的な月でしたが、その余波は12月にも残ります。

Amazon Echo Show 5買ってみた: EeePCの軌跡

とうとう買ってしまいました、Amazon Echo show 5。家電リモコンなどはつけてませんが、音楽再生に使ってます。

音声認識は高いですが、Googleに比べると、あまり遊び心がないですね。真面目です。はい。

と、本年のガジェットな買い物はこれで終わるはずだったんですが……

 ドスパラのゲーミングノート「GALLERIA GR1650TGF-T」を購入!: EeePCの軌跡

やっぱり、無理でした。

フィニッシュは、こいつが飾りました。これが今年2番目の買い物(ちなみに3番目はSurface Go)。

ゲーミングノートPCではコスパ最高と謳われたドスパラのGALLERIA GR1650TGF-Tを、メインPCとして購入。

スマホやSurface Goのおかげで起動時間の速さに慣れすぎてしまい、HDDオンリーのデスクトップ機ではやはり使い物にならないことがしばしば。とうとう勢い余って購入。

おかげさまで、すごく快適です。起動も使い勝手もよくなり、机の上も広くなっていいことづくめ。

Ryzenの6コアも、なかなかいいです。

もっと早くこうするべきだったかと。

ただ、その副産物として、Surface Goを使わなくなりましたが……

しかし、これで快適なら、プロセッサ性能の向上ぶりが段違いといわれるM1チップ搭載のMacBookなど手に入れようものなら、どうなることか……次は、Apple Siliconかな?よだれが止まりません。

久しぶりに、PC界隈が活気づいた年ですね。振り返ればiPhoneよりも、こっちの方がインパクト大きいです。

◇◇◇

とまあ、コロナ禍で外出も控えめなこの年でしたが、それでも振り返ると案外、いろいろとありましたね。

個人的には、あまり良い年ではありませんでしたね。ブログにはほとんど書いてませんが、裏ではいろいろトライしては、成果を残せずという事柄が多いです。

うーん、どうしてこうなった……振り返れば、今年はブログ開設以来初めてヴィレッジヴァンガードの福袋を買わなかったからでしょうか?あんなもの(?)にジンクスがあるとは思いたくないのですが……

その反動で、来年はもうちょっと、羽ばたきたいところです。叶うでしょうか、そんな願望。

と、まずは、ヴィレヴァン福袋を買うところからスタートですね。

今年の更新は、これでおしまいとなります。

来年も、よろしくお願いいたします。皆様、よいお年を。

エンスカイ 鬼滅の刃 2021年 カレンダー壁掛け B3サイズ

2020年12月27日 (日)

VGG16のファインチューニングコード

このブログでも2016年以降、ディープラーニングネタをいくつか投入しておりますが。

そういえば、最近は基本となりつつある「ファインチューニング」ってやつを紹介してませんね。

てことで、VGG16を用いたファインチューニングのコードを、載せておきますね。

【学習用コード】(vgg16_ft_train.py)


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import cv2
import numpy as np
import tensorflow as tf
import tensorflow.python.platform
import keras
from keras.utils import np_utils
from keras.models import Sequential,Model
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D,GlobalAveragePooling2D,Input
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
from keras.callbacks import ModelCheckpoint
from keras.applications.vgg16 import VGG16

path=os.getcwd()+'/data/'
checkDir=os.getcwd()+'/checkpoints/'
if not os.path.exists(checkDir):
os.mkdir(checkDir)
class_count = 0
folder_list=os.listdir(path)

for folder in folder_list:
class_count = class_count+1

label_filenm = './label.txt'
NUM_CLASSES = class_count
IMAGE_SIZE = 224
batch_size = 64
epochs = 200
count=0
folder_list = sorted(os.listdir(path))

train_image = []
train_label = []
test_image = []
test_label = []
X = []
Y = []
f = open(label_filenm, 'w')
for folder in folder_list:
subfolder = os.path.join(path,folder)
file_list = sorted(os.listdir(subfolder))
filemax = 0
i = 0
for file in file_list:
i = i + 1
img = img_to_array(load_img('./data/' + folder + '/'
+ file,target_size=(224,224)))
X.append(img)
Y.append(count)
label_name = folder + ' ' + str(count) + '\n'
f.write(label_name)
count +=1

X = np.asarray(X)
Y = np.asarray(Y)
X = X.astype('float32')
X = X / 255.0
Y = np_utils.to_categorical(Y, NUM_CLASSES)

train_image, test_image, train_label, test_label = train_test_split(X,Y,test_size=0.10)
f.close()
print(u'画像読み込み終了')

input_tensor = Input(shape=(IMAGE_SIZE, IMAGE_SIZE, 3))

base_model = VGG16(weights='imagenet', include_top=False, input_tensor = input_tensor)

x = base_model.output
x = GlobalAveragePooling2D()(x)
x = Dense(1024, activation='relu')(x)
x = Dropout(0.5)(x)
predictions = Dense(NUM_CLASSES, activation='softmax')(x)
model = Model(inputs=base_model.input,outputs=predictions)

for layer in base_model.layers:
layer.trainable = False

model.compile(loss='categorical_crossentropy',
optimizer=keras.optimizers.Adagrad(lr=0.01, epsilon=None, decay=0.0),
metrics=['accuracy']
)
chkpt = os.path.join(checkDir, 'model_.{epoch:02d}-{val_loss:.2f}.h5')
cp_cb = ModelCheckpoint(filepath = chkpt, monitor='val_loss', verbose=1,
save_best_only=True, mode='auto')

model.fit(train_image, train_label,
batch_size=batch_size,
epochs=epochs,
verbose=1,
validation_data=(test_image, test_label),
callbacks=[cp_cb],
)
model.summary()
score = model.evaluate(test_image, test_label, verbose=0)

【推論用コード】(vgg16_ft_app.py)


#!/usr/bin/env python
import os
import sys
import numpy as np
import tensorflow as tf
import keras
from keras.utils import np_utils
from keras.layers import Dense,Dropout,Flatten
from keras.layers import Conv2D,MaxPooling2D
from keras.preprocessing.image import array_to_img,img_to_array,load_img
from keras import backend as K
from sklearn.model_selection import train_test_split
from keras.models import load_model
import cv2
import math
from PIL import Image
path=os.getcwd()+'/analysis/'
file_list=os.listdir(path)
i = 0
label_name = []
label_filenm = './label.txt'
f = open(label_filenm,'r')
for line in f:
line = line.rstrip()
l = line.rstrip()
label_name.append(l)
i = i + 1
NUM_CLASSES = i
IMAGE_SIZE = 224
test_image = []
path=os.getcwd()+'/analysis/'
outpath = os.getcwd() + '/visible/'
if not os.path.exists(outpath):
os.mkdir(outpath)
file_list=os.listdir(path)
def Grad_Cam(input_model, x, layer_name):
    X = np.expand_dims(x, axis=0)
X = X.astype('float32')
preprocessed_input = X / 255.0
    predictions = model.predict(preprocessed_input)
class_idx = np.argmax(predictions[0])
class_output = model.output[:, class_idx]
    conv_output = model.get_layer(layer_name).output
grads = K.gradients(class_output, conv_output)[0]
gradient_function = K.function([model.input], [conv_output, grads])
    output, grads_val = gradient_function([preprocessed_input])
output, grads_val = output[0], grads_val[0]
    weights = np.mean(grads_val, axis=(0, 1))
cam = np.dot(output, weights)
    cam = cv2.resize(cam, (224, 224), cv2.INTER_LINEAR)
cam = np.maximum(cam, 0)
cam = cam / cam.max()
    jetcam = cv2.applyColorMap(np.uint8(255 * cam), cv2.COLORMAP_JET)
jetcam = cv2.cvtColor(jetcam, cv2.COLOR_BGR2RGB)
jetcam = (np.float32(jetcam) + x / 2)
    return jetcam
model = load_model('model.h5')
model.summary()
for file in file_list:
img = img_to_array(load_img('./analysis/' + file, target_size=(224,224)))
test_image = np.asarray(img)
test_image = test_image.astype('float32')
test_image = test_image / 255.0
test_image = test_image.reshape((1,) + test_image.shape)
    y_prob = model.predict(test_image) 
pred = y_prob.argmax(axis=-1)
value_pred = max(model.predict(test_image)[0])
    gdst = Grad_Cam(model, img, 'block5_pool')
gcnt_filenm = outpath + 'gradcam_' + label_name[pred[0]] + '_' + file
cv2.imwrite(gcnt_filenm, gdst)

 

    print(u'ファイル : ', file, u'は ', label_name[pred[0]], u'です。 ' , value_pred)

コードの行間が妙に空いてるところがありますが、いくら直してもココログが勝手に空けちゃうんです。

なんかこのブログ、どんどんと使いにくくなって……申し訳ありません、あらかじめ、ご了承願います。

使い方ですが、

【準備】

(1) Windows版Pythonをインストール (おすすめはpython 3.7.9の64ビット版)

    このサイトが便利 : 非公式Pythonダウンロードリンク - Python downloads

   パスを通すオプションがあるので、それをチェックしてインストールしてください。

(2) Windows PowerShellを開く。(以下、コマンドはすべてWindows PowerShellで実行)

(3) pipコマンドで、tensorflow 1.14.0、keras 2.2.4、OpenCV (最新版)、PILLOWを入れておく。

【学習】

(1)「data」フォルダを作り、その中にラベルごとのフォルダを複数作って、画像を入れる

      (inu、neko、……のように、半角英数で名前を付けてください)

(2) 上の学習用コードをテキストエディタなどで張り付けて保存(以下、ファイル名は「vgg16_ft_train.py」)。

(3) コマンドで、「python vgg16_ft_train.py」を実行。

(4) 終了したら、「checkpoints」フォルダ内にある一番最後のファイルを上のフォルダに移動し、「model.h5」と名前を変えておく。

【推論】

(1) 上の推論用コードをテキストエディタなどで張り付けて保存(以下、ファイル名は「vgg16_ft_app.py」)。

(2)  コマンドで「python vgg16_ft_app.py」を実行。

こんな感じの結果が出れば、OK。

Vgg16_01

ちなみに、Grad Camを入れてるので、「visible」フォルダにヒートマップが出力されます。

Vgg16_02

注目部位が赤くなるってやつです。

いつも使うお城のデータセットでやってみたんですが……なんかちょっと妙な感じ。なぜだか、お城そのものよりも周囲に色がついてますね。

それはともかく、一応動きました。

会社では、かなり使ってますね、VGG16。ResNet50だの、InceptionV3だのとより深層のモデルもあるんですが、VGG16ベースの方がなぜか精度、汎用性が高い印象。

最近は、新規ネットワークで学習させるより、既存のモデルをベースにファインチューニングする方が増えましたね。

あ、ところで、モデルを流用して学習させる方法には「転移学習」と「ファインチューニング」という言葉があって、それぞれちょっと意味が異なります。

ものの本によれば、

・転移学習とは、ベースモデル部分をそのまま使い、結合層以降を学習すること。

・ファインチューニングとは、ベースモデル部分の一部も再学習すること。

という意味のようです。

で、ここに載せたコードは、厳密には「転移学習」と呼ぶのがふさわしいみたいなのですが、そういうのも含めてファインチューニングと呼んでいる節があるので、いつの間にか私もまとめてファインチューニングと呼んでますね。

まあ、いずれにせよ、この数年でディープラーニングも随分と簡単、一般化したものだと感じます。様々な分野の製品検査や効率化に、使われ始めてますね。

で、このコードが、うちの新メインPCであるGALLERIAで動いてます。

これを使ってなにか、やらかしたいですねぇ……できれば、Raspberry Piも使って。現在、思案中です。


人気ブロガーからあげ先生のとにかく楽しいAI自作教室

2020年11月 3日 (火)

運転診断をしてくれるサービス「DRIVE CHART」

最近社内で、ドライブレコーダーの映像を使って運転診断できないか?という相談を持ち掛けられました。

で、調べたら出てきたのがこの記事。

危険運転を可視化するAIドラレコサービス「DRIVE CHART」帝都自動車交通グループのタクシー737台に導入へ | ロボスタ

すでにそういう運転診断サービスがありました。昨年の6月に始まったようですが、それを今年、帝都自動車交通グループが自社のタクシー737台の運転診断に用いているという話です。

ちなみにこのDRIVE CHARTというサービスは、初期投資に5万円(ドラレコ含む)、月額3千円ほどで導入できるようです。

外だけでなく、運転手の状態監視もできるみたいですね。

まあ、正直言うと、自社の車に導入したくないシステムではありますね。なんだか窮屈です。

本当なら、危険を察知してその場で回避してくれる仕組みの方がありがたいですよね。とても5万じゃ導入できないでしょうけど。


【令和最新型】ドライブレコーダー 前後カメラ 高画質 32Gカード付き 1080PフルHD 2カメラ 170度広角 LED信号機対策 スーパーナイトビジョン 操作簡単 上書き機能 WDR技術 防犯カメラ Gセンサー搭載/駐車監視/動体検知/ループ録画/高速起動/緊急録画/高温保護/ドラレコ 車載カメラ 暗視機能 日本語説明書付き

2020年11月 2日 (月)

くら寿司でのRaspberry Pi + Coralによるエッジ端末活用事例

英文のサイトですが、翻訳などを用いてお読みください。

Kura Sushi | Coral

くら寿司では皿のカウントなどをするエッジAI端末として、Raspberry Pi + Coralを用いているようです。

回転ずしって、会計の際には店員さんが皿を数えて、それで金額を確定しますが、それをリアルタイムにカウントしているようですね。

Raspberry Piにつけられたカメラにより画像認識でその商品のカウントを行っているようですが、特徴は、その処理を端末内で行っているということ。

通常なら、オンプレのサーバーかクラウドを使うところですが、すべての店舗のデータを処理しようものなら、回線やサーバーに相当な負荷がかかります。

回線に負荷かけちゃいけませんよね、海鮮物を扱うだけに。

冗談はともかく、その解決策として、このエッジ端末にたどり着いたようです。

私も、エッジ端末としてのRaspberry Piにかなり期待してます。今まさに、Raspberry Piを使った取り組みを仕掛けようとしてますけど、お手軽でそこそこの処理能力のあるこの端末、なかなか侮れません。

そういえば私、くら寿司にまだ行ったことがないんですよね……ちょうどいい場所になくて、行く機会がないだけなんですけど。せっかくなので、今度探して行ってみましょうかね。

I-O DATA Raspberry Pi メインボード Bluetooth(R) Wi-Fi対応モデル Raspberry Pi 3 model B 安心の1年間ハードウェア保証 UD-RP3

2020年10月25日 (日)

Tensorflow.js + WebGLで顔検出してくれるWebアプリ

結構たくさんの顔をdetectしてくれるやつです。

https://terryky.github.io/tfjs_webgl_app/dbface/

物体検出なので、結構重いです。が、さほど速いとは思えないSurface Go 1で動かしても、2、3 fpsはいけます。

Facedetect01

こんな感じに、マスク付きでもOK。こいつ、なかなかヤバイです。

本気を出せば、これくらいの顔検出をさせることも可能。ええ……やっぱり、ヤバイです。

ほかにも、以下のリンクからHand PoseなどのWebアプリを試すことができます。

tfjs_webgl_app

お手軽に物体検出、姿勢検出をさせてみたい方は、ぜひ。

TensorFlowはじめました3 Object Detection ─ 物体検出 (NextPublishing)

2020年8月16日 (日)

”ScratchでAIを学ぼう”を買ってみた

以下の記事を見まして、

「ScratchでAIを学ぼう」はScratchで動かしながら強化学習を理解できる凄い本 - karaage. [からあげ]

つい買ってしまったのがこちら。

Img_4159

はい、タイトルの通り、ScratchでAIを学ぶという本です。

といっても、PythonにScikit-learn、Kerasなどで機械学習系はある程度組める私が、何故Scratchなどという微妙な言語によるAI解説本に手を出したのか?

実はこの本で扱うAIというのが、「強化学習」なんです。

教師あり、なし学習というのはいろいろとやってきましたけど、強化学習って、使う機会がなかったんですよね。

てことで、これに飛びついたというわけです。

Img_4160

いわゆるQ学習のアルゴリズムが書かれてます。ああ、こういう原理なわけねぇ……思わず納得です。

中学生向けの数学で理解できるレベルと書かれてますが、確かにそうですね。中学レベルの数学です。

が、そこはやはり”機械学習”の一種ですから、パラメータチューニングやらの大変さはあります。

なによりも、強化学習の題材が一番の課題。

ところがこの本から3つのサンプルコードにアクセスでき、あらかじめ組まれた強化学習コードを読み込むところからスタートできます。動かしつつ体感でき、理屈を後付けで覚えるという私のスタイルにピッタリな本です。

で、最初のプログラムコードは、2択のゲームです。

Qst04

穴が二つあって、「左」「右」のボタンをクリックすると、ある確率でダイヤが出ます。

ところがその左右の確率が不均質で、20回クリックするうちに当りをつけて、なるべく多くのダイヤを出すというのがこのゲームのルール。

それを、人間、強化学習で交互に行います。

Qst05

で、まずは人間の結果。

20回中、ダイヤは7個でした。案外、ムズイ。

Qst07

で、今度はAIの出番。

Qst06

結果はこちら。倍近い大差をつけられました。あーあ……

この強化学習というのが、学習しながらゲームを解いているわけですが、これが意外と、人間が勝つことが困難なほど上手く学習してくれます。

しばらく、パラメータをいじりながら遊んでみました。

Qst02

このコードの解説と動作原理は、本の中に書かれてます。詳しくは、本をお買い上げください。お値段、2090円。

今のところ、あまり使い道が思いつかない強化学習ですが、いずれはモノにしたいですね。

ScratchでAIを学ぼう ゲームプログラミングで強化学習を体験

2020年5月25日 (月)

ゲームを作り出すAI!?NVIDIAが「GameGAN」でパックマンを再現!

パックマンって、誕生から40年を迎えるんですね。

それはともかく、そのパックマンをエピソードのみから再現するというAIをNVIDAが作り出したと宣伝しております。

誕生 40 周年を迎えるパックマンを、NVIDIA の研究者たちが AI で再現 | NVIDIA

そのAIはずばり「GameGAN」というそうです。GAN(Generative Adversarial Network、敵対的生成ネットワーク)のゲーム版といったところのようです。

そのGameGANにパックマンの5万エピソードを放り込んで学習させて、ゲームエンジン無しにパックマンを再現したんだそうです。

ええ、もう、何言ってるのかわかりませんね……

で、できたものはこちらの動画。

これを見る限り、ゲームを作った、というより、ゲーム動画を作ったというところでしょうかね……

どちらにしても、たいしたものです。

いずれスペースハリアーやアフターバーナーなんかも作り出しちゃうんでしょうかね?

レトロアーケード <パックマン>

より以前の記事一覧

当ブログ内検索

スポンサード リンク

ブログ村

無料ブログはココログ