AIがヒカキンブンブンじゃんけんに勝てるのかをTensorFlowで検証してみた

彼に年収や人格で負けているなら、
せめてじゃんけんくらい勝たせてほしいですよね。

ということで、
今回はTensorFlowを使って、画像分類器で
ヒカキンブンブンじゃんけんに勝たせるAIをつくります。

準備するもの

ヒカキンブンブンじゃんけんに勝たせるAIのつくり方

じゃんけんをAIに学習させる

まずは、じゃんけんの画像が入っているzipファイルをダウンロードします。

!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps.zip \
    -O /tmp/rps.zip

!wget --no-check-certificate \
    https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps-test-set.zip \
    -O /tmp/rps-test-set.zip

`
–2022-09-19 05:51:56– https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps.zip
Resolving storage.googleapis.com (storage.googleapis.com)… 172.217.194.128, 142.251.10.128, 142.251.12.128, …
Connecting to storage.googleapis.com (storage.googleapis.com)|172.217.194.128|:443… connected.
HTTP request sent, awaiting response… 200 OK
Length: 200682221 (191M) [application/zip]
Saving to: ‘/tmp/rps.zip’

/tmp/rps.zip 100%[===================>] 191.38M 40.7MB/s in 4.7s

2022-09-19 05:52:02 (40.7 MB/s) – ‘/tmp/rps.zip’ saved [200682221/200682221]

–2022-09-19 05:52:02– https://storage.googleapis.com/laurencemoroney-blog.appspot.com/rps-test-set.zip
Resolving storage.googleapis.com (storage.googleapis.com)… 172.217.194.128, 142.251.10.128, 142.251.12.128, …
Connecting to storage.googleapis.com (storage.googleapis.com)|172.217.194.128|:443… connected.
HTTP request sent, awaiting response… 200 OK
Length: 29516758 (28M) [application/zip]
Saving to: ‘/tmp/rps-test-set.zip’

/tmp/rps-test-set.z 100%[===================>] 28.15M –.-KB/s in 0.1s

2022-09-19 05:52:02 (204 MB/s) – ‘/tmp/rps-test-set.zip’ saved [29516758/29516758]
`

zipを解凍して/tmp/ディレクトリに保存します。

import os
import zipfile

local_zip = '/tmp/rps.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/')
zip_ref.close()

local_zip = '/tmp/rps-test-set.zip'
zip_ref = zipfile.ZipFile(local_zip, 'r')
zip_ref.extractall('/tmp/')
zip_ref.close()

学習用のじゃんけんの画像を
グーチョキパーに分類します。

rock_dir = os.path.join('/tmp/rps/rock')
paper_dir = os.path.join('/tmp/rps/paper')
scissors_dir = os.path.join('/tmp/rps/scissors')

print('total training rock images:', len(os.listdir(rock_dir)))
print('total training paper images:', len(os.listdir(paper_dir)))
print('total training scissors images:', len(os.listdir(scissors_dir)))

rock_files = os.listdir(rock_dir)
print(rock_files[:10])

paper_files = os.listdir(paper_dir)
print(paper_files[:10])

scissors_files = os.listdir(scissors_dir)
print(scissors_files[:10])

total training rock images: 840 total training paper images: 840 total training scissors images: 840 ['rock01-027.png', 'rock05ck01-108.png', 'rock05ck01-090.png', 'rock01-040.png', 'rock02-108.png', 'rock02-022.png', 'rock01-060.png', 'rock07-k03-061.png', 'rock06ck02-032.png', 'rock03-069.png'] ['paper05-114.png', 'paper03-099.png', 'paper06-011.png', 'paper07-053.png', 'paper03-040.png', 'paper07-040.png', 'paper05-082.png', 'paper07-116.png', 'paper01-041.png', 'paper07-035.png'] ['scissors04-034.png', 'testscissors01-033.png', 'testscissors03-058.png', 'testscissors01-087.png', 'testscissors03-044.png', 'testscissors01-040.png', 'scissors04-080.png', 'scissors03-069.png', 'testscissors03-088.png', 'scissors04-038.png']

プロットします。

%matplotlib inline

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

pic_index = 2

next_rock = [os.path.join(rock_dir, fname) 
                for fname in rock_files[pic_index-2:pic_index]]
next_paper = [os.path.join(paper_dir, fname) 
                for fname in paper_files[pic_index-2:pic_index]]
next_scissors = [os.path.join(scissors_dir, fname) 
                for fname in scissors_files[pic_index-2:pic_index]]

for i, img_path in enumerate(next_rock+next_paper+next_scissors):
  img = mpimg.imread(img_path)
  plt.imshow(img)
  plt.axis('Off')
  plt.show()

学習します。

import tensorflow as tf
import keras_preprocessing
from keras_preprocessing import image
from keras_preprocessing.image import ImageDataGenerator

TRAINING_DIR = "/tmp/rps/"
training_datagen = ImageDataGenerator(
      rescale = 1./255,
        rotation_range=40,
      width_shift_range=0.2,
      height_shift_range=0.2,
      shear_range=0.2,
      zoom_range=0.2,
      horizontal_flip=True,
      fill_mode='nearest')

VALIDATION_DIR = "/tmp/rps-test-set/"
validation_datagen = ImageDataGenerator(rescale = 1./255)

# 学習データをつくる
train_generator = training_datagen.flow_from_directory(
    TRAINING_DIR,
    target_size=(150,150),
    class_mode='categorical',
  batch_size=126
)

# 検証データをつくる
validation_generator = validation_datagen.flow_from_directory(
    VALIDATION_DIR,
    target_size=(150,150),
    class_mode='categorical',
  batch_size=126
)

# ニューラルネットワークを定義する
model = tf.keras.models.Sequential([
    tf.keras.layers.Conv2D(64, (3,3), activation='relu', input_shape=(150, 150, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(128, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dropout(0.5),
    tf.keras.layers.Dense(512, activation='relu'),
    tf.keras.layers.Dense(3, activation='softmax')
])

# 要約
model.summary()

# ニューラルネットワークをコンパイルする
model.compile(loss = 'categorical_crossentropy', optimizer='rmsprop', metrics=['accuracy'])

# 学習する
history = model.fit(train_generator, epochs=25, steps_per_epoch=20, validation_data = validation_generator, verbose = 1, validation_steps=3)

model.save("rps.h5")

学習が終わりました。

ヒカキンとじゃんけんをして、AIに勝たせる

これでファイルをアップロードして、ヒカキンに勝つ手を出力します。

import numpy as np
from google.colab import files
from keras.preprocessing import image

uploaded = files.upload()

for fn in uploaded.keys():
  path = fn
  img = image.load_img(path, target_size=(150, 150))
  x = image.img_to_array(img)
  x = np.expand_dims(x, axis=0)

  images = np.vstack([x])
  classes = model.predict(images, batch_size=10)
  hikakin_result = np.array(classes[0])
  paper = np.array([1, 0, 0])
  rock =  np.array([0, 1, 0])
  scissors =  np.array([0, 0, 1])
  if hikakin_result[0] == paper[0]:
    print("✌")
  if hikakin_result[1] == rock[1]:
    print("🖐")
  if hikakin_result[2] == scissors[2]:
    print("✊")

上記を実行しましょう。
10回戦じゃんけんをしてみます。

Round 1

AIは✊を出しました。
よって、Round 1はAIの勝ち。

Round 2

AIは🖐を出しました。
よって、Round 2はAIの勝ち。

Round 3

AIは🖐を出しました。
よって、Round 3はあいこ。

Round 4

AIは✊を出しました。
よって、Round 4はAIの負け。

AIはパーを出されると弱いのでしょうか。

Round 5

3度目の正直なるか。

AIは✌を出しました。
よって、Round 5はAIの勝ち。

ようやく、パーに勝つことができました。

Round 6

AIは🖐を出しました。
よって、Round 6はAIの勝ち。

Round 7

AIは✌を出しました。
よって、Round 7はAIの勝ち。

Round 8

AIは✌を出しました。
よって、Round 8はAIの負け。

流石に、ぶれてるとダメでした。

Round 9

AIは✌を出しました。
よって、Round 9はAIの勝ち。

Round 10

AIは🖐を出しました。
よって、Round 10はAIの負け。

結果

RoundAIヒカキン
1
2
3
4
5
6
7
8
9
10

AIは 70% の確率でヒカキンブンブンじゃんけんに勝てる


ディープテックのマガジンはこちら『DeepMagazine』

https://deep-recommend.com/magazine