るぴブロ

備忘録とかです(*'ω'*)

2021年 あけました!

あけましておめでとうございます!!
今年もよろしくお願い致します🙇🏻‍♂️
皆様にとってより良い一年になります様に😊

今年の干支は「牛」🐄

f:id:rupic:20210101004504j:plain
昨年に引き続き干支シリーズ化していくみたいですw

今年の目標

無理せずこつこつと!!

  • 今年も xAI Meetup 盛り上げていきたい!
    • オンラインでのハンズオンはハードル高いけどやってみたいですね
  • もちろんふくてんもイベントしていければ!
  • 産業医の先生に怒られるので、今年こそ痩せないとww
  • 何か新しい特技を増やしたい
  • 月一はブログ更新

今年ものんびり楽しいことをやっていけると良いな😊

2020年を振り返って

今年も残すところあと2日。
最近中々ブログも書けていないので年の最後くらいはまとめようと思います。

Private

今年も一年、家族全員大きなケガも病気もなく健康に過ごせました。
来年も健やかな一年を過ごせます様に。


ようこそプラド
子供が小さかったのでここ何台かはずっとミニバンだったのだけれど、ようやく嫁からのOKが出たので念願のSUVに!!
11月に注文したルーフラックがまだ来ないけど大事に乗ろうw


可愛い眼鏡が見つかった
大名の蒲池眼鏡でMASAHIRO MARUYAMA のアシンメトリーな眼鏡を発見!!
嫁に踏まれて他界したRaybanの眼鏡も喜んでくれてると思う(しらんけど

仕事

今の会社で働かせてもらって十数年たつのですが、社内でも他の人と違った業種なのもあり同じ会話が出来る人がいない事がすごくストレスで、数年前から自分がこの会社にいる事に違和感を感じ、2019年末から転職を考え始めていました。
ありがたいことに数社の方にお声がけ頂き転職をしようとした矢先にコロナウイルスが流行り始め一時見送りという形に・・・。
そんな中、昨年よりお手伝いさせて頂いていた次世代事業室という部署に異動になり業務内容も今までとはまた違ったものになりました。忙しいけどとても充実した日々を過ごせているのかなと。
来年も自分に出来る事はしっかりやっていこうと思います。

コミュニティ

xAI Meetup #1
今年の初めに「xAI Meetup」 というAIを手段としてもっと身近にもっと手軽に色々な人に利用してもらう事を目的にしたコミュニティを立ち上げました。
オンラインでのコミュニティ活動は機材や環境等を考えると中々億劫になってしまいしばらく休止していましたが、周りの皆様のご協力もあり何とかオンラインでのイベントにも参加する事が出来ました!

xTech ゆるっとLT: xAI Meetup and AR_Fukuoka
ARコンテンツ作成勉強会主催の吉永さんよりお声がけ頂き、合同でLT会を開催しました。
異分野ではあるけども、xR と AI はとても親和性が高く皆さんのお話を聞く事で様々なヒントが得られたとても素敵な会になったと思いました。

togetter.com tks-yoshinaga.hatenablog.com

speakerdeck.com

www.slideshare.net www.slideshare.net


Open Source Conference 2020 Online/Fukuoka
こちらも吉永さんよりお声がけ頂き、エンジニアフレンドシティ枠で参加する事に!
xAI 運営メンバーの加藤さんと共同登壇させて頂きました。
準備段階からの加藤さんのすごさが半端なかったっすwww

event.ospn.jp www.youtube.com

www.slideshare.net


エンジニアフレンドシティ福岡フェスティバル2020
こちらは、オルターブース松本さんよりお声がけ頂き、今年のテーマである「New Engineers Life」の中でも現在注目を集めている「NoCode」について対談形式でお話するというもの。
セカンドファクトリー清水さんのファシリテーションのもとあっという間の45分でした。

efc.fukuoka.jp www.youtube.com

www.slideshare.net

まとめ

今年はコロナウイルスで人と会いにくい環境になってしまった中で「新しい働き方」「新しい生活の仕方」「新しい人との接し方」など変化の多い年になったと思いますが、公私ともにオンライン/オフラインでたくさんの人に出会えた事、助けて頂いた事は本当に感謝しかありません。
コミュニティ活動も来年は少しづつ活動を再開していきたいと思っていますので来年もよろしくお願いいたしますm(__)m

それでは皆さま良いお年を…

ResNetを使ってみよう!

すごく久しぶりの投稿です。
5月から所属部署の変更があり、バタバタしてましたw(今もですが)

せっかく前回、Machine Learning のHello World をやったので、流行り(?)の ResNet を使ってみましょう。

rupic.hatenablog.com

ResNet

ResNet (Residual Network) は Microsoft Research の Kaiming He さんが2015年に考案したニューラルネットワークのモデルらしい。

2014年の画像認識の分野でトップを争う ImageNet コンペティションにおいて、1位だった GoogLeNet は 22層。ところが、翌年には GoogLeNet スゲーってなってたとこに、まさかの 152層 が出てきて(゚д゚)フォォォァァァァァァァォァオァオァオアオアォアォアア!ってなったみたいです。

ResNet の特徴

  • とにかく層が深い
     → いろんな論文にも書いている通り、CNN では学習における層の深さはとても大事らしい。
  • ショートカット用のルートがある
     → すごく長いニューラルネットワークの入力層に近いノードでは、色々あって勾配消失が発生し学習が止まったり、速度が低下したりしてしまうらしく、それを解決する為の方法との事。

ResNet の弱点

  • すごく強いマシンが欲しい
     → 我が家のマシンは GPU GeForce Quadro P6000 / メモリ 64G ですが、それでも入力が大きいと 152層はしんどいです。
  • 学習に時間がかかる
     → 11class、152層、50 Epoc とかでも5~6時間くらいかかる。
       待っている間は何もしたくなくなる事もあるかもしれない。

en.wikipedia.org



とりあえず、メモ程度ですが学習用のコードを...。
参考にさせて頂いた無限ノック。

github.com

main.py

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf
from tensorflow.keras.models import Sequential,Model
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D, Input, BatchNormalization, concatenate, AveragePooling2D, Add, SeparableConv2D
from tensorflow.keras import optimizers
from tensorflow.keras.callbacks import ModelCheckpoint, LearningRateScheduler, ReduceLROnPlateau, CSVLogger, TensorBoard
from tensorflow.keras.preprocessing.image import ImageDataGenerator, array_to_img, img_to_array

# 好きなモデルを呼び出す
import ResNet152 as resnet

import seaborn as sns
import csv
import os
import numpy as np
import matplotlib.pyplot as plt
import json
import collections as cl
import argparse
import codecs
from datetime import datetime

def PrintLog(log):
    print(log,file=codecs.open('./Log/print.log','a','utf-8'))
    print(log)

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
physical_devices = tf.config.experimental.list_physical_devices('GPU')
if len(physical_devices) > 0:
    for k in range(len(physical_devices)):
        tf.config.experimental.set_memory_growth(physical_devices[k], True)
        print('memory growth:', tf.config.experimental.get_memory_growth(physical_devices[k]))
else:
    print("Not enough GPU hardware devices available")


PATH = r'D:\datasets\original'

train_dir = os.path.join(PATH, 'train')
validation_dir = os.path.join(PATH, 'validation')

# 学習用のサブディレクトリがクラスになる

class_names = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K']
class_names.sort()

train_dirs = []
validation_dirs = []
for name in class_names:
    train_dirs.append(os.path.join(train_dir, name)),
    validation_dirs.append(os.path.join(validation_dir, name))

num_tr = []
for trdir in train_dirs:
    num_tr.append(len(os.listdir(trdir)))

num_val = []
for valdir in validation_dirs:
    num_val.append(len(os.listdir(valdir)))

total_train = 0
for numtr in num_tr:
    total_train += numtr


total_val = 0
for numval in num_val:
    total_val += numval


PrintLog("--images-----------------------")
for i in range(len(class_names)):
    PrintLog('class : {} images'.format(class_names[i]))
    PrintLog('        total training   {}'.format(num_tr[i]))
    PrintLog('        total validation {}'.format(num_val[i]))


PrintLog("-------------------------------")
PrintLog("Total : images")
PrintLog(("        training   ", total_train))
PrintLog(("        validation ", total_val))


num_classes = 11
channel = 3
batch_size = 11

epochs = 50
IMG_WIDTH = 1080
IMG_HEIGHT = 1080


# 写真のセンターをいい感じに切り出す
def crop_center(pil_img, crop_width, crop_height):
    img_width, img_height = pil_img.size
    return pil_img.crop(((img_width - crop_width) // 2,
                        (img_height - crop_height) // 2, 
                        (img_width + crop_width) // 2, 
                        (img_height + crop_height) // 2))

# 写真の縦の長さで正方形に切り出す
def crop_max_square(pil_img):
    return crop_center(pil_img, min(pil_img.size), min(pil_img.size))

def preprocess(x):
    im = array_to_img(x)
    im_new = crop_max_square(im)    
    return img_to_array(im_new)

# 学習データセットに変化をつける
train_image_generator = ImageDataGenerator(
                        rescale=1./255,
                        rotation_range=5,
                        width_shift_range=.15,
                        height_shift_range=.15,
                        zoom_range=0.5,
                        brightness_range=[0.3,1.0],
                        preprocessing_function=preprocess
                        ) # 学習データのジェネレータ

train_image_generator.mean = np.array([123.68/255,116.779/255,103.939/255], dtype=np.float32).reshape((1,1,3))

# 必要な大きさにリサイズする
train_data_gen = train_image_generator.flow_from_directory(batch_size=batch_size,
                                                           directory=train_dir,
                                                           shuffle=True,
                                                           target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                           classes=class_names,
                                                           class_mode='categorical')


# 検証データをクロップ
validation_image_generator = ImageDataGenerator(rescale=1./255, preprocessing_function=preprocess) # 検証データのジェネレータ
validation_image_generator.mean = np.array([123.68/255,116.779/255,103.939/255], dtype=np.float32).reshape((1,1,3))

val_data_gen = validation_image_generator.flow_from_directory(batch_size=batch_size,
                                                              directory=validation_dir,
                                                              shuffle=False,
                                                              target_size=(IMG_HEIGHT, IMG_WIDTH),
                                                              classes=class_names,
                                                              class_mode='categorical')

# クラスをJsonに書き出しとく
dic = cl.OrderedDict()
for class_index in train_data_gen.class_indices:
    dic[class_index] = cl.OrderedDict({"index":train_data_gen.class_indices[class_index],"name":class_index})

with open('./model/class_map.json','w') as fw:
    json.dump(dic,fw,indent=2)


#モデルの作成
model = resnet.ResFunction(IMG_HEIGHT, IMG_WIDTH, channel, num_classes)

#ラーニングレートを可変にする
def lr_schedule(epoch):
    lr = 1e-3
   
    if epoch > 44:
        lr *= 1e-6
    elif epoch > 39:
        lr *= 1e-5
    elif epoch > 34:
        lr *= 1e-4
    elif epoch > 29:
        lr *= 1e-3
    elif epoch > 24:
        lr *= 1e-2
    elif epoch > 19:
        lr *= 1e-1

    PrintLog('Next Epoc: {}, Learning rate: {}'.format(epoch + 1, lr))
    return lr


# ADAM オプティマイザーと binary cross entropy 損失関数を選択
# 各学習エポックの学習と検証の精度を表示するために、metrics 引数を渡す
decay=1e-6
momentum=9e-1

model.compile(optimizer=optimizers.SGD(lr_schedule(0), momentum=momentum, decay=decay, nesterov=True),
              loss='categorical_crossentropy',
              metrics=['accuracy'])

# modelのネットワークレイヤーを見たい場合の関数
with open('./Log/network_layer','a') as f:
    model.summary(print_fn = lambda x: f.write(x + '\r\n'))

# モデルの学習

# ImageDataGenerator クラスの fit_generator メソッドを使用して、ネットワークを学習します。
# CallBackにモデル補正用のメソッドを指定してラーニングレートを調整する
save_dir = os.path.join(os.getcwd(), 'saved_models')
model_name = 'ResNetv152_model.{epoch:03d}.h5'
if not os.path.isdir(save_dir):
    os.makedirs(save_dir)
filepath = os.path.join(save_dir, model_name)

checkpoint = ModelCheckpoint(filepath=filepath,
                             monitor='val_accuracy',
                             verbose=1,
                             save_best_only=False)

lr_scheduler = LearningRateScheduler(lr_schedule)

#各エポックの結果をcsvへ保存する
csv_logger = CSVLogger(filename='./Log/training.log',
                       separator=',',
                       append=True)

callbacks = [checkpoint, lr_scheduler, csv_logger]

history = model.fit(
    train_data_gen,
    epochs=epochs,
    validation_data=val_data_gen,
    validation_steps=total_val // batch_size,
    steps_per_epoch=total_train // batch_size,
    callbacks=callbacks
)

#モデルを保存
model.save('./model')

#Confusion_Matrixを出力
Y_pred = model.predict(val_data_gen)
y_pred = np.argmax(Y_pred, axis=1)

PrintLog('\r\nConfusion Matrix\r\n')

cm = tf.math.confusion_matrix(val_data_gen.classes, y_pred)
PrintLog(cm)
sns.heatmap(cm, annot=True, fmt='d', cbar=False, cmap='Blues')
plt.savefig('./model/confusion_matrix.png')

# 学習結果の可視化
epochs_range = range(epochs)

acc = history.history['accuracy']
val_acc = history.history['val_accuracy']

loss = history.history['loss']
val_loss = history.history['val_loss']

plt.figure(figsize=(8, 8))
plt.subplot(1, 2, 1)
plt.plot(epochs_range, acc, label='Training Accuracy')
plt.plot(epochs_range, val_acc, label='Validation Accuracy')
plt.legend(loc='lower right')
plt.title('Training and Validation Accuracy')

plt.subplot(1, 2, 2)
plt.plot(epochs_range, loss, label='Training Loss')
plt.plot(epochs_range, val_loss, label='Validation Loss')
plt.legend(loc='upper right')
plt.title('Training and Validation Loss')
plt.savefig('./model/figure.png')
plt.show()

ResNet152.py

from __future__ import absolute_import, division, print_function, unicode_literals

import tensorflow as tf
from tensorflow.keras.models import Sequential,Model
from tensorflow.keras.layers import Dense, Dropout, Activation, Flatten, Conv2D, MaxPooling2D, Input, BatchNormalization, concatenate, GlobalAveragePooling2D, Add, SeparableConv2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator

def ResFunction(IMG_HEIGHT, IMG_WIDTH, channel, num_classes):

    def ResBlock(x, in_f, f_1, out_f, stride=1, name="res"):
        res_x = Conv2D(f_1, [1, 1], strides=stride, padding='same', activation=None, name=name + "_conv1")(x)
        res_x = BatchNormalization(name=name + "_bn1")(res_x)
        res_x = Activation("relu")(res_x)

        res_x = Conv2D(f_1, [3, 3], strides=1, padding='same', activation=None, name=name + "_conv2")(res_x)
        res_x = BatchNormalization(name=name + "_bn2")(res_x)
        res_x = Activation("relu")(res_x)

        res_x = Conv2D(out_f, [1, 1], strides=1, padding='same', activation=None, name=name + "_conv3")(res_x)
        res_x = BatchNormalization(name=name + "_bn3")(res_x)
        res_x = Activation("relu")(res_x)

        if in_f != out_f:
            x = Conv2D(out_f, [1, 1], strides=1, padding="same", activation=None, name=name + "_conv_sc")(x)
            x = BatchNormalization(name=name + "_bn_sc")(x)
            x = Activation("relu")(x)

        if stride == 2:
            x = MaxPooling2D([2, 2], strides=2, padding="same")(x)
        
        x = Add()([res_x, x])
        x = Activation("relu")(x)

        return x
        
    
    inputs = Input((IMG_HEIGHT, IMG_WIDTH, channel))
    x = inputs
    
    x = Conv2D(64, [7, 7], strides=3, padding='same', activation=None, name="conv1")(x)
    x = BatchNormalization(name="bn1")(x)
    x = Activation("relu")(x)
    x = MaxPooling2D([5, 5], strides=3, padding='same')(x)

    x = ResBlock(x, 64, 64, 256, name="res2_1")
    x = ResBlock(x, 256, 64, 256, name="res2_2")
    x = ResBlock(x, 256, 64, 256, name="res2_3")

    x = ResBlock(x, 256, 128, 512, stride=2, name="res3_1")

    # 各ブロックの繰り返し数
    for i in range(7):
        x = ResBlock(x, 512, 128, 512, name="res3_{}".format(i + 2))

    x = ResBlock(x, 512, 256, 1024, stride=2, name="res4_1")
    for i in range(35):
        x = ResBlock(x, 1024, 256, 1024, name="res4_{}".format(i + 2))

    x = ResBlock(x, 1024, 512, 2048, stride=2, name="res5_1")
    x = ResBlock(x, 2048, 256, 2048, name="res5_2")
    x = ResBlock(x, 2048, 256, 2048, name="res5_3")

    # 一つ上の層の出力に合わせて
    x = GlobalAveragePooling2D()(x)
    #x = Flatten()(x)
    x = Dense(num_classes, activation='softmax', name="fc")(x)

    model = Model(inputs=inputs, outputs=x)

    return model

Hello World of Machine Learning!!

こんばんは。
会社から帰って家の事して色々してるといつもこの時間になってしまいますね。

福岡県ではコロナウイルスの感染者が 12 人に増えてしまいました💦
しっかり食べて、しっかり寝て、適度に運動して、うがい手洗いもして、出来るだけ人が集まるところは避けながらコロナに負けない生活習慣を心掛けたいです。

さて、先日までに Windows マシンの機械学習環境の構築をやっていきましたが、どうしてもやらないといけない事があって(ジャンプを読みたくて)動作確認をしてませんでしたので動作確認をしていきたいと思います。

rupic.hatenablog.com

機械学習Hello World → MNIST の画像分類

機械学習はじめまして!な方用として良く使われる MNIST 。
様々な Hello World の中でもトップクラスの感動を得られますw
※個人的に一番感動したのは Lチカでした

MNIST

Mixed National Institute of Standards and Technology database
28x28 ピクセルの手書き数字画像のデータセットで 6,0000 個のトレーニングデータと 1,0000 個のテストデータが収容されています。

詳しく知りたい方は以下の記事で確認してみてください。

udemy.benesse.co.jp

なにするの?

Tensorflow のチュートリアルにある、 MNIST の6,0000 個のトレーニングデータを学習して機械学習モデルを作成し、テストデータを用いてモデル精度を確認します。 www.tensorflow.org

学習モデルを作成する

Anaconda Prompt 等で Tensorflow-gpu 2.1.0 をインストールします。

pip install tensorflow-gpu==2.1.0

f:id:rupic:20200327004400p:plain

main.py

# 必要なライブラリをインポートする
import tensorflow as tf
from tensorflow.keras import datasets, layers, models

# MNIST データセットをダウンロード
(train_images, train_labels), (test_images, test_labels) = datasets.mnist.load_data()

# データ数、縦px、横px、チャンネル(グレースケール:1、カラー:3)
train_images = train_images.reshape((60000, 28, 28, 1))
test_images = test_images.reshape((10000, 28, 28, 1))

# ピクセルの値を 0~1 の間に正規化
train_images = train_images / 255.0
test_images = test_images / 255.0

# モデルを作成
model = models.Sequential()
# 畳み込み:活性化関数 relu → 入力 x が x<=0 であれば 0 を、x>0 であれば x を返す
model.add(layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)))
# 出力をダウンスケール
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))
model.add(layers.MaxPooling2D((2, 2)))
model.add(layers.Conv2D(64, (3, 3), activation='relu'))

# 3x3x64 次元のテンソル → 576個の要素を持つ1次元のベクトルに変換
model.add(layers.Flatten())
# 全結合層 
model.add(layers.Dense(64, activation='relu'))
# softmax関数 → 0~1 の範囲で値を算出
model.add(layers.Dense(10, activation='softmax'))

# モデルの概要を出力
model.summary() 

# モデルをコンパイル
# optimizer:最適化アルゴリズム
# loss:損失関数 (スパースなマルチクラス分類交差エントロピー関数)
# metrics:評価関数
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 学習開始 epoc は学習回数
model.fit(train_images, train_labels, epochs=5)

#モデルを保存
model.save('./model')

# テストデータを用いて精度の確認
test_loss, test_acc = model.evaluate(test_images,  test_labels, verbose=2)

print(test_acc)

f:id:rupic:20200327014028p:plain
model.summary() の表示内容
f:id:rupic:20200327005802p:plain
実行するとすごい勢いで文字が流れていきます

f:id:rupic:20200327013647p:plain
指定 学習回数(5 epoch) が終了すると、テストデータを用いて精度を確認

最後に

言語系の Hello World と違ってデータセットを準備したり、少し長めのコードを書く必要がありますが、実際に動かした時の感動は中々なものですね。
もっと精度を上げるには学習の回数を変えてみたり、レイヤーを変えてみたり、最適化アルゴリズムを変えてみたり、学習レートを調整してみたり、データを可視化してみるのもいいですね…。調整出来る箇所が多いですが、色々と試してみてどんな変化があるか見てみるといいかもしれません😊

Windows 10 に CUDA + cuDNN をインストール

こんばんは。
昨日に引き続き PC の設定のお話です。
今日は NVIDIAGPU開発環境である CUDA と CUDA を使って Deep Learning の計算を高速で行うためのライブラリである cuDNN をインストールしていきますたいと思います!!
特にハマりポイントはないと思うのでさくっと入れていきます。

CUDAってなに?

CUDA(Compute Unified Device Architecture:クーダ)とは、NVIDIAが開発・提供している、GPU向けの汎用並列コンピューティングプラットフォーム(並列コンピューティングアーキテクチャ)およびプログラミングモデルである[3][4][5]。専用のC/C++コンパイラ (nvcc) やライブラリ (API) などが提供されている。なおNVIDIAGPUにおいては、OpenCL/DirectComputeなどの類似APIコールは、すべて共通のGPGPUプラットフォームであるCUDAを経由することになる[6]。 【Wikipedia引用】

www.nvidia.co.jp

要は、NVIDIA が開発している GPU 上でプログラミングをするためのソフトウェアプラットフォームで、例えば複雑で計算量の多い処理を並列処理したい時に、GPU を使って無駄なく効率的に処理をする為のものだと思ってます。

CUDA のほかにも OpenCL っていう GPGPU(GPUによる汎用計算) があるんですが、NVIDIA の性能を最大限活かす為に CUDA が作られてるだろうから NVIDIAGPU を利用しているのであれば、CUDA を利用する方がいいのではないかと思います。

www.khronos.org

CUDA Toolkit のダウンロード

CUDA の最新版は 10.2 ですが、Tensorflow 2.1 の環境に合わせて 10.1 をインストールしたいと思います。

www.tensorflow.org


以前のバージョンはこちらのアーカイブからダウンロードしましょう。

developer.nvidia.com

f:id:rupic:20200324005057p:plain
自身の環境にあったものをダウンロードしてください

CUDA Toolkit のインストール

f:id:rupic:20200324005157p:plain
特にこだわりがなければそのままOKで

f:id:rupic:20200324005305p:plain
同意して続行します

f:id:rupic:20200324005424p:plain
カスタムでインストールしたいものだけに絞る事も出来ますがそのままいきます

f:id:rupic:20200324010009p:plain
完了です。次へをクリックしましょう

f:id:rupic:20200324010043p:plain
このまま閉じます

システム環境変数の設定 PATH

自動で PATH が追加されていることを確認します。

f:id:rupic:20200324011534p:plain

システム環境変数の設定 CADA_PATH

自動でCUDA_PATH と CUDA_PATH_V10_1 が追加されていることを確認します。

f:id:rupic:20200324010447p:plain

インストールの確認

f:id:rupic:20200324012222p:plain
nvcc にパスが通ってることを確認

cuDNN ってなに?

CUDA をつかって Deep Learning の計算を高速で行うためのライブラリ
様々なフレームワークに対応しています。

対応一覧
https://www.arcbrain.jp/support/NVIDIA/Deep_Learning/Frameworks/#Another_Frameworks

cuDNN のダウンロード

ダウンロードするにはユーザー登録が必要です。
必ず CUDA と同じバージョンに対応した cuDNN をインストールしてください

ダウンロードリンク
https://developer.nvidia.com/rdp/cudnn-download

f:id:rupic:20200324013111p:plain
Download cuDNN をクリック
f:id:rupic:20200324013153p:plain
アカウントがなければ Join で作成しましょう

f:id:rupic:20200324014246p:plain
バージョンに注意!

f:id:rupic:20200324014325p:plain
自身の環境にあったものをクリックしてダウンロード

cuDNN のインストール

ダウンロードした『cudnn-10.1-windows10-x64-v7.6.5.32.zip』を解凍したフォルダの中にある『cuda』フォルダを開きます。

先ほどインストールした CUDA のディレクトリに中身のフォルダ毎コピペしちゃいましょう。
CUDA Toolkit のインストールディレクトリは変更してなければ以下

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1

f:id:rupic:20200324015406j:plain

システム環境変数の設定 CUDNN_PATH

CUDNN_PATHを追加

C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v10.1

f:id:rupic:20200324015548p:plain
環境変数の追加

インストールの確認

f:id:rupic:20200324015830p:plain
cudnn64_7.dll にパスが通っている事を確認

インストール完了

お疲れさまでした。
これでCUDA と cuDNN のインストールは完了です。

Windows Tarminal に Anaconda Prompt を表示する

こんばんは。
新しい PC に機械学習環境の構築を時間のある時にぼちぼちやってます。

rupic.hatenablog.com

会社で使ってる機械学習用マシンも最近新調したので、最近同じような事を何度もやってます😅
今回は Python のインストール → Anaconda Prompt をWindows Tarminal に追加をやっていきます。

Python のインストール

こちらは Anaconda をインストールしましょう。

Anaconda

Anaconda は Continuum Analytics って会社が提供している Python と conda というパッケージマネージャーを含む Python ディストリビューション
以下のサイトからインストーラーをダウンロードしてインストールします。

www.anaconda.com

f:id:rupic:20200322221234j:plain

f:id:rupic:20200322221249p:plain
PythonWindows の環境を選択

基本的にインストーラーの指示に従ってインストールすればOKです。
インストールの確認は Anaconda Prompt から以下を入力して Python のバージョンを確認で OK でしょう。

python -V

f:id:rupic:20200322224535p:plain
インストールされてますね

Python のライブラリをインストールしたり、仮想環境を作成したりする際に Anaconda Prompt を利用するんですが、起動するのに Windows メニューからアイコンをクリックするのが面倒なので、僕は Windows Tarminal に入れています。

Windows Tarminal

コマンドプロンプトだったり、Power Shell だったり、Cloud Shellだったり、似たようなコマンドラインツールが多いですよね。
そんなコマンドラインツール達を一括管理してくれるのが、Windows Tarminal !! これは便利ですね!!
ちなみに現在は Preview v0.9 ですが、正式版に備える予定の全機能が実装されているそう。

www.atmarkit.co.jp

github.com

インストール

Windows Store からインストールしましょう。

www.microsoft.com

システム要件

f:id:rupic:20200322222554p:plain

呼び出し

Win + R → 『wt』と入力して Enter で Windows Terminal が起動します。

f:id:rupic:20200322225236p:plain
コマンドプロンプト『cmd』を呼び出す感じでいいですね

f:id:rupic:20200322225419p:plain
Power Shell が起動しましたね

ちなみにタブの所にある『∨』をクリックすると、コマンドプロンプトや Azure Cloud Shell が選択できます。
Ctrl + Shift + 数字キーで切り替え可能です。
Windows Tarminal の機能は色々あるんですが、そこは本線から外れてしまいますので適宜ggって下さい。

Anaconda Prompt を追加する

タブの所にある『∨』をクリックして Setting をクリックすると Setting.json が開きます。
※ Ctrl + ,でも OK です。

Setting.json
 guid:一意のキー
 name:表示名
 commandline:呼び出すコマンドラインツール

// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation

{
    "$schema": "https://aka.ms/terminal-profiles-schema",

    "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",

    "profiles":
    {
        "defaults":
        {
            // Put settings here that you want to apply to all profiles
        },
        "list":
        [
            {
                // Make changes here to the powershell.exe profile
                "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
                "name": "Windows PowerShell",
                "commandline": "powershell.exe",
                "hidden": false
            },
            {
                // Make changes here to the cmd.exe profile
                "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
                "name": "cmd",
                "commandline": "cmd.exe",
                "hidden": false
            },
            {
                "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
                "hidden": false,
                "name": "Azure Cloud Shell",
                "source": "Windows.Terminal.Azure"
            }
        ]
    },

    // Add custom color schemes to this array
    "schemes": [],

    // Add any keybinding overrides to this array.
    // To unbind a default keybinding, set the command to "unbound"
    "keybindings": []
}

既存の設定をコピーする

f:id:rupic:20200323000536j:plain
Power Shell の設定をコピペする

guid を変更する

一意になれば良いので、末尾の文字を変更すれば OK

 変更前:"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
 変更後:"guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44b9}",          ※16進で記載です

表示名を変更する

好きな名前にするといいと思う

 変更前:"name": "Windows PowerShell",
 変更後:"name": "Anaconda Prompt",

コマンドを変更する

Anaconda Prompt を呼び出す為のコマンドを変更する

Windows メニューから Anaconda プロンプトを右クリック→その他→ファイルの場所を開く
f:id:rupic:20200323005556j:plain
② Anaconda プロンプトを右クリック→プロパティ
f:id:rupic:20200323005843j:plain
③ リンク先をコピー
f:id:rupic:20200323005919j:plain
④ メモ帳などに張り付けて不要な部分を削除する
f:id:rupic:20200323010356j:plain
⑤ ④を Setting.json の commandline に張り付け
f:id:rupic:20200323010637p:plain

確認してみる

Win + R → 『wt』で Windows Tarminal 呼び出し(呼び出しが楽!!)

f:id:rupic:20200323010840p:plain
Anaconda Prompt が増えてる!!
f:id:rupic:20200323011006p:plain
しっかり動きますね

余談

よく見ると先ほど追加した Anaconda Prompt には アイコンがないんですよね。
Setting.json で設定できるプロパティが色々ある様で、どうやら icon に何かしら設定すれば良さそうです。

プロパティ一覧 github.com

// To view the default settings, hold "alt" while clicking on the "Settings" button.
// For documentation on these settings, see: https://aka.ms/terminal-documentation

{
  "$schema": "https://aka.ms/terminal-profiles-schema",

  "defaultProfile": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",

  "profiles": {
    "defaults": {
      // Put settings here that you want to apply to all profiles
    },
    "list": [
      {
        // Make changes here to the powershell.exe profile
        "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44bf}",
        "name": "Windows PowerShell",
        "commandline": "powershell.exe",
        "hidden": false
      },
      {
        // Make changes here to the cmd.exe profile
        "guid": "{0caa0dad-35be-5f56-a8ff-afceeeaa6101}",
        "name": "cmd",
        "commandline": "cmd.exe",
        "hidden": false
      },
      {
        "guid": "{b453ae62-4e3d-5e58-b989-0a998ec441b8}",
        "hidden": false,
        "name": "Azure Cloud Shell",
        "source": "Windows.Terminal.Azure"
      },
      {
        "guid": "{61c54bbd-c2c6-5271-96e7-009a87ff44b9}",
        "name": "Anaconda Prompt",
        "commandline": "cmd.exe /K C:\\Users\\rupic\\anaconda3\\Scripts\\activate.bat",
        "backgroundImage": "C:\\Users\\rupic\\OneDrive\\画像\\anaconda.png",
        "colorScheme": "Solarized Light",
        "useAcrylic": true,
        "icon": "ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png",
        "hidden": false
      }
    ]
  },

  // Add custom color schemes to this array
  "schemes": [],

  // Add any keybinding overrides to this array.
  // To unbind a default keybinding, set the command to "unbound"
  "keybindings": []
}

f:id:rupic:20200323014153p:plain
自分の好きな様に改造してみるといいかもです

Macbookpro 入院 → 代替え機購入

こんばんは!
愛用している Macbookpro のキーボードの調子が宜しくなく久しぶりのブログです😢
どう調子が悪いかというとキー入力する際にキーを押した際にがチャタリングしている様な動作をするんです。。。
例えば『こんにちは』と入力しようとすると『こおおんにちはああ』みたいに不特定のキーが連続して入力されるような状態でコーディングはおろか通常のWEB検索すら困難ですw

これはあかんと思い Apple サポートに問い合わせたところ無償での修理をしてくれることに。
それは助かるのですが修理が完了するまでに最短で 7 営業日かかるところ、現在コロナの影響で部品が届かない事が考えられるため納期不明と…。
納期不明って💦
AzureにVM立ててiPadからーと考えましたが、メイン機として使うにはそこそこ辛いと思うのでここは代替え機を準備する事にしました。

f:id:rupic:20200321010925p:plain
こちらです。

仕様


ノートPCにしては珍しいメカニカルキーボードを採用しているモデルでキーの打鍵感がしっかりしていて入力しやすい。
残念ポイントはキーピッチを広く取りすぎてキー配列がちょっと使いずらいところと、メーカー製PCでは相変わらずのWindows 10 Homeなところ。 テンキー無くせばいいのになと思うけどゲーム用途と考えるとゲーム操作に影響の出ないキーはずらしちゃいますよねw

でも動作も軽快だし、使いやすいのでしばらくはこのマシンをガンガン使っていこうと思う。
せっかくGPUつんでるんだし、VR ヘッドマウント欲しいなぁ・・・。
と思いつつ、機械学習環境のセットアップしながらまたブログを書いていこうと思います。

Ink Recognizerを使ってみよう ( Cognitive Services 復習 )

こんばんは!
コロナウイルスの影響で各地のイベントは自粛ムード…
我が家は出来るだけ人が多い所を避けて、前々から嫁に頼まれてたやつをDIYしています。

さて、勉強会も中々開催できないので、時間がある時に Microosoft Azure のサービスで一番好きな Cognitive Services について不定期でのんびりブログに書いていこうと思います。

Cognitive Services

Microsoft の提供するサービスである、 Cognitive Services は人間の認知する機能の一部(見たり、聞いたり、話したり、意思決定したり、検索したり)を機械で擬似的に再現したサービスで Web API として利用できる AI パーツ。

2020.02.26 現在のサービス一覧 (27 Services ※5 preview)

  • 決定:よりスマートな意思決定をすばやく行う
  • 言語:非構造化テキストから意味を取り出す
    • Immersive Reader(preview):音声や視覚的な合図を使用して、あらゆる能力の読み手がテキストを理解できるようにする
    • Language Understanding自然言語を解釈する機能を提供
    • QnA Maker:ナレッジベースから質疑応答を、会話形式で行うことができる
    • Text Analytics:センチメント、キー フレーズ、名前付きエンティティを検出
    • Translator Text:60 を超えるサポート言語を検出し、リアルタイムで翻訳
  • 音声:音声処理をアプリやサービスに統合する
  • 視覚:画像、ビデオ、デジタル インク内のコンテンツを識別し、分析する
    • Computer Vision:画像内のコンテンツを分析
    • Custom Vision:ビジネス上のニーズに合うよう画像認識をカスタマイズ
    • Face:イメージ内の人物とその感情を検出して識別
    • Form Recognizer(preview):ドキュメントからテキスト、キーと値のペア、テーブルを抽出
    • Ink Recognizer(preview):デジタル インクや手書き入力を認識し、一般的なシェイプの位置特定
    • Video Indexer:ビデオのビジュアルとオーディオ チャネルを分析し、そのコンテンツにインデックスを設定
  • 検索:World Wide Web から探しているものを見つける
    • Bing Autosuggest:インテリジェントな先行入力機能が追加され、ユーザーはよりすばやくクエリを入力する
    • Bing Custom Search:検索結果に広告が表示されないカスタムの検索エンジンを作成
    • Bing Entity Search:名前付きエンティティを識別して分類し、それに基づいて検索結果を探す
    • Bing Image Search:さまざまな画像検索オプションをアプリに追加
    • Bing News Search:アプリをニュースの検索リソースに変更
    • Bing Spell Check:ユーザーが単語の切れ目、スラング、名前、同音異義語、ブランドを識別して修正
    • Bing Video Search:高度なビデオ検索機能をアプリに追加
    • Bing Visual Search:ユーザーが画像を使用して検索
    • Bing Web Search:安全で広告なしの、位置認識機能を備えた検索をユーザーが利用できるようにし、Web の検索結果、画像、ニュース、ビデオ、ビジュアルから関連情報を表示

Ink Recognizer

初回となる今回は、タイトル通り Ink Recognizer API についてです。

手書きの文字、図形、インク ドキュメントのレイアウトなどのデジタル インク コンテンツを認識できる AI サービス

ちょっと何言ってるかわかりませんね。

要は Ink Recognizer API を使用すると、アプリケーション内の手書きコンテンツを簡単に認識する事ができるんです。
あぁ、OCRかw と思われる方もいらっしゃるかと思いますが(僕もそう思いました)、タブレットPCなどにペンや手書きで書いた文字の軌跡を時間軸で並べ渡してあげる事で、図形や文字を認識してくれるというものらしいです。

f:id:rupic:20200224220125p:plain

できる事

手書き認識

63 の主要な言語とロケールの手書きコンテンツを認識

docs.microsoft.com

レイアウト認識

コンテンツを手書き領域、段落、行、単語、箇条書きに分割します。 これにより、お使いのアプリケーションでそのレイアウト情報を使用して、リストの自動書式設定や図形の配置などの追加機能を構築

図形認識

一般的な幾何学図形を認識

docs.microsoft.com

図形とテキストの認識

どのインク ストロークが図形または手書きコンテンツに属しているかを認識し、それらを個別に分類

価格

現在 Preview 中なので価格設定は変わる事があるかもしれませんが以下となっています。

こちら、200 ストロークの要求で 1 トランザクションでして、例えば『石橋裕太』という文字の場合、合計 37 ストロークという感じだと思います。
なので Free プランでも十分に楽しめるかと!!

実際に使ってみる

Azure Portal で Ink Recoognizer のリソースを作成

f:id:rupic:20200226173943p:plain
全てのサービス>AI+Machine Learning>Cognitive Services (検索する方が早いw)

f:id:rupic:20200226174200p:plain
Ink Recognizer のリソースを作成

f:id:rupic:20200226174234p:plain
必要事項を良い感じに入力してください

f:id:rupic:20200226174320p:plain
キーとエンドポイント>キー1をコピーしとく

サンプルコード

github.com

こちらのコードをローカルに git clone して VS Code で開きます。

git clone https://github.com/Azure-Samples/cognitive-services-REST-api-samples
cd SampleCode\cognitive-services-REST-api-samples\javascript\InkRecognition\javascript-app\src
code .

f:id:rupic:20200226174833p:plain
coonfig.js の SUBSCRIPTION_KEY にキー1を貼付け

あとは sample.html を開けば良いのですが、ここまで来て気づいた事としてペンで入力出来る端末がない事でしたww (Macbookなのでタッチついてない…)
とりあえず、App Service に GitHub からデプロイして iPad で動作を確認してみましょう。

動作を確認

f:id:rupic:20200226194847p:plain
左側:ペンで書いた文字、右側:Response JSON

Request
ストローク毎にポイントが時系列順で渡されてますね

{
  "version": 1,
  "language": "ja-JP",
  "strokes": [
    {
      "id": 63,
      "points": "48.6895,163.1115,47.3666,163.1115,46.0437,162.1193,46.0437,161.8015,45.3822,161.4630,45.3822,161.1452,46.7052,160.4682,50.0125,159.8145,55.9656,158.8198,63.2416,157.4891,73.1635,156.4943,83.0854,155.1843,91.6843,153.8511,100.2833,152.8589,105.5750,152.2026,108.2208,152.2026,109.5437,152.2026,109.5437,152.2026,108.2208,152.8589,106.8979,154.1896"
    },
    {
      "id": 64,
      "points": "78.4552,159.1582,78.4552,158.8198,77.7937,159.1582,77.1322,160.1504,76.4708,162.4552,75.8093,166.0932,74.4864,171.3797,71.8406,177.0021,67.2104,184.2937,61.9187,191.5671,55.9656,200.1687,48.6895,206.7677,44.0593,211.7338,40.0906,215.0515,37.4447,216.3641,36.1218,216.7025,36.1218,216.0256"
    },
    {
      "id": 65,
      "points": "65.8875,197.1895,65.8875,196.1973,65.8875,195.8588,65.8875,196.8510,65.8875,198.8406,67.2104,203.1323,68.5333,207.7625,70.5177,212.3901,73.1635,216.0256,74.4864,218.6895,75.8093,220.6765,77.1322,221.9865,77.7937,222.6427,78.4552,222.9812"
    },
    {
      "id": 66,
      "points": "74.4864,199.8328,73.1635,198.8406,73.1635,198.8406,74.4864,198.8406,77.1322,198.1843,83.0854,197.5073,88.3770,196.5151,94.3302,195.5410,99.6218,195.2026,102.9291,196.1973,104.2520,197.1895,105.5750,198.1843,105.5750,199.8328,104.9135,201.8171,103.5906,204.1245,101.6062,206.7677,100.2833,209.4291,99.6218,211.0776,98.2989,213.7208,96.9760,215.7078,96.3145,217.0203"
    },
    {
      "id": 67,
      "points": "85.7312,219.0073,83.0854,219.0073,82.4239,219.0073,83.0854,219.3458,85.0697,219.3458,89.7000,217.6947,96.9760,216.3641,102.9291,215.7078,104.2520,215.7078"
    },
    {
      "id": 68,
      "points": "115.4968,171.3797,115.4968,171.0619,114.1739,170.4030,114.1739,170.0671,115.4968,169.7287,118.1427,168.7365,124.0958,168.0802,131.3718,167.4239,136.6635,166.0932,140.6322,165.0984,141.2937,164.7806,140.6322,164.7806,137.3250,164.4447,134.0177,163.4500,131.3718,161.8015,130.0489,160.1504,129.3875,158.1635,129.3875,156.8328,129.3875,156.4943,129.3875,157.1713,129.3875,159.8145,129.3875,167.0854,128.7260,174.6948,128.0645,182.9604,128.0645,191.2286,128.0645,199.1739,128.0645,205.1193,128.0645,210.0854,128.7260,213.0645,129.3875,214.3771,129.3875,214.3771,129.3875,214.0593"
    },
    {
      "id": 69,
      "points": "131.3718,176.3458,131.3718,176.3458,130.7104,176.0254,130.0489,176.0254,129.3875,176.3458,129.3875,177.3380,128.0645,179.3250,128.0645,181.6323,125.4187,186.5984,122.1114,190.5723,118.8041,193.8719,116.1583,196.8510,114.1739,198.5021,112.8510,198.8406,112.1895,197.5073"
    },
    {
      "id": 70,
      "points": "129.3875,175.6895,128.0645,175.0332,127.4031,174.6948,126.7416,174.6948,128.0645,174.6948,129.3875,175.6895,132.6947,177.9969,135.3406,179.9813,138.6479,181.9682,141.2937,183.6167,142.6166,184.2937"
    },  ...長いので省略
  ]
}

Response
こちらは alternates の recognizedString に候補となる文字列が帰ってきてたり、一致率が一番高い文字列がわかったり、文字のある場所が座標として帰ってきてますね

{
  "recognitionUnits": [
    {
      "alternates": [
        {
          "category": "inkWord",
          "recognizedString": "右"
        },
        {
          "category": "inkWord",
          "recognizedString": "后"
        },
        {
          "category": "inkWord",
          "recognizedString": "谷"
        },
        {
          "category": "inkWord",
          "recognizedString": "厄"
        },
        {
          "category": "inkWord",
          "recognizedString": "名"
        },
        {
          "category": "inkWord",
          "recognizedString": "古"
        },
        {
          "category": "inkWord",
          "recognizedString": "百"
        },
        {
          "category": "inkWord",
          "recognizedString": "召"
        },
        {
          "category": "inkWord",
          "recognizedString": "不"
        }
      ],
      "boundingRectangle": {
        "height": 70.79000091552734,
        "topX": 36.119998931884766,
        "topY": 152.1999969482422,
        "width": 73.43000030517578
      },
      "category": "inkWord",
      "class": "leaf",
      "id": 4,
      "parentId": 3,
      "recognizedText": "石",
      "rotatedBoundingRectangle": [
        {
          "x": 38.619998931884766,
          "y": 149.52999877929688
        },
        {
          "x": 109.52999877929688,
          "y": 152.1999969482422
        },
        {
          "x": 106.83000183105469,
          "y": 224.0399932861328
        },
        {
          "x": 35.90999984741211,
          "y": 221.3699951171875
        }
      ],
      "strokeIds": [
        63,
        64,
        65,
        66,
        67
      ]
    },
    {
      "alternates": [
        {
          "category": "inkWord",
          "recognizedString": "槗"
        },
        {
          "category": "inkWord",
          "recognizedString": "楿"
        },
        {
          "category": "inkWord",
          "recognizedString": "橎"
        }, ...長いので省略
  ]
}

f:id:rupic:20200226200825p:plain
認識した文字列と場所をCanvas上に反映させるとこんな感じになります

f:id:rupic:20200226200936p:plain
ちなみにこんな図形を書いてみると…
f:id:rupic:20200226201007p:plain
良い感じに図形の形や場所などを認識してくれます

まとめ

  • Ink Recognizer API を使用すると、アプリケーション内の手書き文字を良い感じに認識してくれる!
  • 認識精度はかなり高めだと思う ※ヘナヘナな文字でもしっかり認識してくれて嬉しいw
  • 会員登録とか紙に文字で書いた後に PC に入力するっていう感じの業務は置き換え可能かも?
  • Macboook + iPad ある時は AppService にデプロイしなくても SideCar 使えば良かったんだと後から気付きましたw(泣
  • あ、Surface Pro 買えば良いのか(白目

f:id:rupic:20200226201646p:plain
SideCar で iPad を液タブとして使えるの忘れてたw

AR Fukuoka リアルタイム手書き数字認識AIを作って遊ぼうに参加してきました!

こんにちは → こんばんは!!
今日はエンジニアカフェでこちらに参加、少しだけお手伝いしてきました😊

xr-fukuoka.connpass.com

f:id:rupic:20200215131833p:plain エンジニアカフェでイベント開催すると黒板にイラストつきな紹介を書いてくれてるんですが、何気にこれ嬉しいですよね!!

今回イベントに参加しながらブログを書いているので、ちょっと長めになっちゃってます🙇🏻‍♂️

イベントの雰囲気

f:id:rupic:20200215132053p:plain
師匠によるいつもの挨拶

f:id:rupic:20200215132206p:plain
IST 甲斐さんから今日やることのご紹介

ディープラーニングとは

f:id:rupic:20200215133007p:plain
ガッキーは可愛いので正義

本日のお題

Tensorflow + Keras + Opencv を利用して、PCのカメラで撮影した手書き文字をリアルタイムで認識

  • 難しい事はさておいて、ざっくり説明すると Tensorflow はゲームのハード、Keras がゲームソフト

まずはMNISTで遊んでみよう

MNISTをKerasで使える形にする

import numpy as np
from keras.datasets import mnist
from keras.utils import np_utils

#MNISTデータセット呼び出し
(X_train, y_train), (X_test, y_test) = mnist.load_data()

#データの正規化
X_train = np.array(X_train)/255.
X_test = np.array(X_test)/255.

#CNNに入れるために次元を追加
X_train = np.expand_dims(X_train, axis=-1)
X_test = np.expand_dims(X_test, axis=-1)

#ラベルのバイナリ化
y_train = np_utils.to_categorical(y_train)
y_test = np_utils.to_categorical(y_test)

モデルの構築

from keras.layers import Input, Dense, Conv2D, MaxPooling2D
from keras.models import Model
from keras.layers.core import Flatten

inputs = Input(shape=(28,28,1)) #入力層

conv1 = Conv2D(16, (3, 3), padding='same', activation='relu')(inputs) #畳込み層1
pool1 = MaxPooling2D((2, 2))(conv1)
conv2 = Conv2D(32, (3, 3), padding='same', activation='relu')(pool1) #畳込み層2
pool2 = MaxPooling2D((2, 2))(conv2)

flat = Flatten()(pool2) #全結合層に渡すため配列を一次元化
dense1 = Dense(784, activation='relu')(flat) #全結合層

predictions = Dense(10, activation='softmax')(dense1) #出力層

model = Model(inputs=inputs, outputs=predictions) #モデルの宣言(入力と出力を指定)

モデルのコンパイル、学習実行

model.compile(optimizer="sgd", loss="categorical_crossentropy", metrics=["accuracy"])
hist = model.fit(X_train, y_train, batch_size=16, verbose=1, epochs=1, validation_split=0.9)

学習結果の評価

score = model.evaluate(X_test, y_test, verbose=1)
print("正解率(acc):", score[1])

モデルを保存

model.save("MNIST_test.h5")

作成されたモデルの確認

f:id:rupic:20200215135707p:plain
モデルが作成された!

f:id:rupic:20200215140253p:plain

作成した学習モデルを利用して評価する

from keras.models import load_model
import cv2
import numpy as np

model = load_model("mnist.h5") # 学習済みモデルをロード

Xt = []
img = cv2.imread("6.jpg", 0)
img = cv2.resize(img,(28, 28), cv2.INTER_CUBIC)

Xt.append(img)
Xt = np.array(Xt)/255
Xt = np.expand_dims(Xt, axis=-1)

result = model.predict(Xt, batch_size=1)
print(result[0])

画像加工処理をやってみよう

OpenCVを利用して、撮影している画像をリアルタイムにKerasで認識できる形に加工する

f:id:rupic:20200215140837p:plain
こんなイメージ。分かり易い!

f:id:rupic:20200215142807p:plain
皆さん真剣に聴かれてますね!

まずはOpenCVを使って画像を表示してみる

f:id:rupic:20200215143715p:plain
界隈では有名人な Lenna さんの画像を利用

import cv2

#Lennaを召喚する呪文:0→グレースケール、1→カラー
image = cv2.imread('Lenna.png',1)
#testウインドウにLennaを召喚
cv2.imshow('test',image)
#何かしら操作があるまで待つ:0なので無限に待つよ
cv2.waitKey(0)
#ウインドウを破棄する
cv2.destroyAllWindows()
#Macの人は以下を入れとかないとエラー
cv2.waitKey(1)

f:id:rupic:20200215144434p:plain
実行するとこんな感じですね!美人さんです。

teratail.com

読み込んだ画像をグレーに変えてみる

*方法は簡単。2行ほど追記するだけ!

#グレースケールに変換
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

#グレー用のウインドウを追加
cv2.imshow('gray',gray)

f:id:rupic:20200215150328p:plain
先ほどのカラーとグレースケールのLennaさんが表示されます。

次は画像に資格の枠を表示する

  • OpenCV は画像の左上を原点として座標を指定します。
  • 以下のコードを追加
#四角を表示する
cv2.rectangle(image,(50,50),(100,100),(255,0,0))

f:id:rupic:20200215150924p:plain
こんな感じに枠が表示されますね

画像に文字を書く

#(窓,書き込む文字列,座標,フォント,サイズ,色,太さ,線の種類)
cv2.putText(image,'Hello World',(0,30),cv2.FONT_HERSHEY_SIMPLEX,1,(255,255,255),1,cv2.LINE_AA)

f:id:rupic:20200215151804p:plain
日本語などの2バイト文字を表示する為には少し工夫が必要

画像を二値化→白黒反転→ブラーをかける

#大津の方法で二値化する
_, th = cv2.threshold(gray,0,255,cv2.THRESH_OTSU)
#白黒反転
th = cv2.bitwise_not(th)
#ブラーを書ける
th = cv2.GaussianBlur(th,(9,9),0)

f:id:rupic:20200215152420p:plain
二値化した画像

f:id:rupic:20200215152538p:plain
白黒反転した画像

f:id:rupic:20200215152650p:plain
ブラーをかけた画像

画像をトリミング

th = th[50:150,50:150]

f:id:rupic:20200215153043p:plain
指定したサイズにトリミングした画像

画像を縮小

#50 x 50 にトリミング
th = cv2.resize(th,(50,50),cv2.INTER_CUBIC)

f:id:rupic:20200215153226p:plain
指定サイズに縮小する

MNISTの中身をみてみよう

ここまでの内容を合体させて、先ほど利用したMNISTの中身の画像をOpenCVを利用して見てみましょう

from keras.datasets import mnist
import cv2

#MNISTを画像部分だけロード
(X_train,_),(_,_) = mnist.load_data()
#X_trainの100番目を取得して表示
cv2.imshow('mnist',X_train[100])

cv2.waitKey(0)
cv2.destroyAllWindows()
cv2.waitKey(1)

f:id:rupic:20200215154008p:plain
指定した配列番号のもじが表示される

PC内臓のカメラの画像を表示する

  • PCのカメラにアクセスする為には、ご利用の環境によって段階を踏まないといけません。
    ① どのカメラを利用するか指定する
    ② カメラから画像を読み込む
    ③ カメラの画像を表示する
    ④ カメラを開放する

静止画

import cv2

#①カメラを指定
cap = cv2.VideoCapture(0)
#②カメラから画像を読み込む
ret,frame = cap.read()
#③カメラの画像を表示する
cv2.imshow('frame',frame)

cv2.waitKey(0)

#④カメラを開放する
cap.release()
cv2.waitKey(1)

cv2.destroyAllWindows()
cv2.waitKey(1)

f:id:rupic:20200215160523p:plain
油断してるとおかしな顔が取れるので気をつけてください

動画

  • OpenCVでは静止画をひたすら撮影→表示し続ける事で動画となるという思想なので以下で動画に対応できます
  • 終了判定がないと無限に動画が表示されてしまうので、今回はキーボードのQが入力されると終了するっていうコードに、静止画コードの②と③を変更します。
while(True):
    ret,frame = cap.read()
    cv2.imshow('frame',frame)

    #キーボードのQが押されたら終了させる
    k =  cv2.waitKey(1) & 0xFF
    if  k == ord('q'):break

動画の中心に四角を表示する

f:id:rupic:20200215162925p:plain
考え方はこちらです

while (True):
    ret,frame = cap.read()

    #サイズでかいとき対策として半分にする
    h,w,_=frame.shape[:3]
    frame = cv2.resize(frame, (int(w/2), int(h/2)))
    
    #画像の形(高さ,幅,チャンネル数)
    h,w,_=frame.shape[:3]
    #y軸の中心点を取得
    h_center=h//2
    #x軸の中心点を取得
    w_center=w//2
    
    cv2.rectangle(frame,(w_center-71,h_center-71),(w_center+71,h_center+71),(255,0,0))

リアルタイム手書き数字認識を作成する

  • ここまでくれば色々な事に応用できますね😊
  • 本日の本題であるリアルタイム文字認識を作成してみましょう!!
  • コツはPCのInカメラを利用した時に自分の動きが左右反転してしまうので、frame = cv2.flip(frame,1)で反転してあげると良い

完成コード

import cv2
from keras.models import load_model
import numpy as np

#学習モデルを読み込む
model = load_model('mnist.h5')

#カメラを指定する
cap = cv2.VideoCapture(0)

while (True):
    #判定用データを格納する変数
    Xt = []
    Yt = []
        
    ret,frame = cap.read()

    #サイズでかいとき対策として半分にする
    h,w,_=frame.shape[:3]
    frame = cv2.resize(frame, (int(w/2), int(h/2)))
    
    #画像の形(高さ,幅,チャンネル数)
    h,w,_=frame.shape[:3]
    #y軸の中心点を取得
    h_center=h//2
    #x軸の中心点を取得
    w_center=w//2
    
    cv2.rectangle(frame,(w_center-31,h_center-31),(w_center+31,h_center+31),(255,0,0))
    
    #トリミング(y,x)なので注意
    im=frame[h_center-30:h_center+30,w_center-30:w_center+30]
    #グレースケール化
    im=cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    #二値化
    _,im =cv2.threshold(im,0,255,cv2.THRESH_OTSU)
    #白黒反転
    im=cv2.bitwise_not(im)
    #ブラーをかける
    im=cv2.GaussianBlur(im,(9,9),0)
    #28 x 28 にリサイズする
    im=cv2.resize(im,(28,28),cv2.INTER_CUBIC)
    
    Xt.append(im)
    Xt = np.array(Xt)/255
    Xt = np.expand_dims(Xt,axis=-1)
    #Xtと学習したデータを比較して判定結果を返す
    result = model.predict(Xt,batch_size=1)
    
    #画面の反転
    frame = cv2.flip(frame,1)
    
    for  i in range(10):
        #小数点以下第二位までで四捨五入
        r = round(result[0,i],2)
        #OpenCVで表示できる型に変換
        r  = "{0:0.2f}".format(r)
        #その数字が何かと一致する確率をセットで格納
        Yt.append([i,r])
        #Ytをソートする
        Yt = sorted(Yt,key=lambda x:(x[1]))
    
    #判定結果の上位1番目を画面上に表示する
    cv2.putText(frame,'1st:'+str(Yt[9]),(10,50),cv2.FONT_HERSHEY_SIMPLEX,0.8,(255,255,255),1,cv2.LINE_AA)
    
    cv2.startWindowThread()
    cv2.imshow("frame",frame)
    cv2.imshow("debug",im)
    key = cv2.waitKey(30) & 0xFF
    if key ==ord('q') :
        break

#カメラを開放する
cap.release()
#フリーズ対策としてwaitKeyで挟む
cv2.waitKey(1)
cv2.destroyAllWindows()
cv2.waitKey(1)

f:id:rupic:20200215171908p:plain
完成!!!
f:id:rupic:20200215172659p:plain
画面キャプチャはこんな感じ

まとめ

  • 甲斐さんの説明がめっちゃ丁寧だし分かり易いし感動!!!!
  • やっぱりガッキーは可愛い
  • ブログ書きながらは忙しすぎてしんどい事が判明w
  • いち早くビール飲みたい

祝 xAI Meetup #1 開催しました

こんばんは!
2月7日(金)はxAI Meetupの記念すべき第一回の開催でした!

f:id:rupic:20200209110603j:plain

xai.connpass.com

xAI Meetupって?

f:id:rupic:20200209105814p:plain

  • 参加してくれた全員にAIという物をもっと身近に感じてもらいたい。
  • もっと簡単なものだと知ってもらいたい。
  • そして、目的としてのAIではなく、手段としてのAIを体験してもらいたい。
  • AI開発のプロ達とAIを使う方達が交流する事で、それぞれのレイヤーの方達に気づきがあれば。

そんな想いで2019年末に立ち上げたコミュニティです。

xai.connpass.com

会場の様子

f:id:rupic:20200209110519j:plain
大盛況!!

タイムテーブル

f:id:rupic:20200209111220p:plain
スピーカー陣も内容も豪華!!

セッション

既にブログにまとめて頂いているのでこちらをご覧ください🙇🏻‍♂️
本当に有難う御座います!!

木村さんのブログ

showm001.hatenablog.com

うしまるさんのブログ

usimaru.net

Twitter まとめ

togetter.com

Welcom to xAI Meetup

石橋裕太

参加頂ける全ての人のAIに対する『わからない』を解決する事で、AIというものをもっと身近に感じてもらいたいという事、xAIでこれからやっていきたい事をお話しさせて頂きました。

www.slideshare.net

Alibaba Cloud ET Brain

知念裕子さん

知念さんはAribaba Cloud のMVPアワードを受賞されており、Aribaba CloudのAIサービスであるET Brainについてご紹介頂きました!!
中でもET City Brainはリアルタイム都市データを利用した事故渋滞検出なんかできて、すごく気になるサービスだと思いました。

jp.alibabacloud.com

RC Car x AI

山田美穂さん

急遽登壇をお願いしたのにも関わらず、快諾して頂き有難う御座います🙇🏻‍♂️
RC Car(ラジコン)にラズパイとカメラを搭載し、人間がコントローラーで運転した内容を学習させてコースを自動走行させてみたお話しです!
めっちゃ興味あるのでうちの財務大臣に稟申しよう。。。(切実

speakerdeck.com

テキスト書き起こし&読み上げLINE ボット

松本典子さん

いつも思うのは松本さんってAIに関わらず、テクノロジーを利用する人たちの理想の姿だと思うんです。
すごい技術も限られた人たちだけが使えるってのは本当の意味で普及したと言えないと思うので、こんな風にもっとみんなが自然と技術を利用できる事ができる様になれば幸せだなと思います。

www.slideshare.net

資本論 x AI

阿久沢崇さん

資本論!!!!
AI開発の導入は儲かる事を考える事が大前提です。
機械学習を利用した案件は比較的シンプルなものが多く、エンジニアの方も企画〜プロジェクトに関わっていく事で無駄な手戻りをなくす事が出来るので是非!
資本論については池上彰先生の著書がわかりやすくておすすめです!!!

池上彰の講義の時間 高校生からわかる「資本論」

池上彰の講義の時間 高校生からわかる「資本論」

www.slideshare.net

Container x AI

加藤司さん

AIの利用を想定したインフラ周り+ガ●ダムをCustom Visionで判定するお話し。
機械学習を利用したプロジェクトというと一般的にモデル開発の方に注目しがちですが、しっかりとしたインフラが基盤にあってからこそ成り立つと思います。

www.slideshare.net

まとめ

f:id:rupic:20200209110803j:plain
記念撮影
記念すべき第一回開催は大盛況で幕を閉じました!!!!

今回、平日夜の勉強会開催にも関わらず、connpassでイベントをアップしてすぐに満席になり、キャンセル待ちも発生するというなんともありがたいと思うと同時に、この分野の勉強会には皆さん興味があるのだと驚きました。
次回ももっと楽しんで頂ける様にイベントを企画したいと思います!!

参加して頂いた皆様、運営、登壇して頂いた皆様、本当に有難う御座いました!
これからもよろしくお願い致します🙇🏻‍♂️

Fukuoka.NET #18 ~ようこそ令和2年~ 開催しました

こんばんは。
水曜、木曜と久々の高熱で死んでましたが、点滴と栄養ドリンクといっぱいの睡眠で復活しました僕ですw
年に 1 〜 2 回くらいしか風邪ひかないので久々にしんどかったです😢

本日、1月17日(金) は今年初のふくてんでした㊗️

場所はエンジニアカフェのメインホールをお借りしての開催です! fukuten.connpass.com 資料はこちら fukuten.connpass.com

あけましておめでとうございます

f:id:rupic:20200118013534p:plain
ゆる〜とオープニング

ふくてんはまず始めに自己紹介タイムがあります!

誰かの前で何かを話す事はすごくドキドキしますが、それが自己紹介だったとしても自身がつくし、なおかつ参加者同士の属性がわかるとお互いに話すきっかけになったりしていいですよね😊

f:id:rupic:20200118013934p:plain
自己紹介タイムです

今回初参加の方が3名ほどいらっしゃいました!
なんとも嬉しい限りです!ありがとうございます(^^)

タイムテーブル

f:id:rupic:20200118015730p:plain
20分 * 3、10分 * 1、LT * 1 ですね!

改めてC#でできることを振り返る

オルターブース 松村さん f:id:rupic:20200118015609p:plain

いまC#でできることをまとめたお話。
その中でも端末に .NET Core Runtime をインストールしなくても実行可能な
Self contained deployment
Windows Sandbox を起動し、実際に.NET Core Runtime が インストールされていない環境で動作する事を確認できる Demo は参加者の反応も良かったと思う。

www.slideshare.net

既にお兄さんのブログも公開されてますので詳細はこちらです! tsubalog.hatenablog.com

ML.NETのお話し

トヨタ自動車九州 石橋

f:id:rupic:20200118022248p:plain
木村さんの写真お借りました!ありがとうございます!!

タイトルをつけ忘れた事にセッション始まってから気づくなんて何とも申し訳ないw
『今すぐ試せる!既存のソリューションにML.NETで機械学習を実装してみよう!!』 的な感じでしょうか。 ML.NETの紹介と、Visual Studio 2019 から Model Builder を利用した画像分類の Demo をさせて頂きました😊
資料はこちら

Ml.NET from ru pic
www.slideshare.net

xAI Meetup #1 はこちら! xai.connpass.com

.NET Frameworkで​C# 8って使える?​YESとNO!

ジェイエムテクノロジー ジョニーさん f:id:rupic:20200118023257p:plain

『新規開発なのに .NET Framework 4.x? もう2020年ですよ!』と、現在.NET Framework の新規開発案件を担当されているジョニーさん😢
C# 8.0 の新機能 + .NET Framework でもC# 8.0 を利用する為に試行錯誤された内容を発表されていました!ジョニーさんすごいなぁ😲

f:id:rupic:20200118023701p:plain
C# 8.0 互換性表

Serverless Framework で C# を使ってみる

オルターブース 木村さん

f:id:rupic:20200118024706p:plain
木村さんは1月からオルターブースさんにJoinされました㊗️

木村さんは前職で主にperlPHPpythonといったいわゆるスクリプト系言語での開発をされていらっしゃったとの事で、C#はハンズオン程度で利用したことがある程度。

これからは業務で使うことが増えていくので、しっかりC#自体を勉強すると共に、最新動向もキャッチアップしていかないといけません。そのためには登壇を申し込み、それに向けて必死でネタを仕込むというのが一番です(スパルタですが)。

さすがすぎます🥰

今回は、ServerlessFramework で C# を使ってみてアレコレハマったところや、解決できたところを非常に丁寧にわかり易くご紹介して頂きました!!

www.slideshare.net

しかも誰よりも早くブログも書いて頂きました!
ありがとうございます😊
showm001.hatenablog.com

Xamarin で人生が変わった話

放浪軍師さん

f:id:rupic:20200118030932p:plain
放浪軍師さんのLT!!

f:id:rupic:20200118031222p:plain
放浪軍師さんをggると確実に1つの時代を気付き上げてきた感じが伝わりますね

というのはおいといて、
元々放浪軍師さんの努めてらっしゃった会社はゴリゴリの vb6 開発をされていたみたいで、独学でXamarin を勉強し始めたとの事。
その内容をブログに上げながら学習していたがそもそも何をどうしていいのかすらわからない。
勤めている会社と意見が合わず色々揉めてたりしている中、そんな時に軍師さんを助けてくれたのがコミュニティやブログを購読してくれてた方達だったそうで、Xamarin をどんどん覚えて行くうちに最終的には転職までしちゃいました!というサクセスストーリーでした😊

コツコツと愚直に何かができる人の事は必ず誰かが見れくれているし、認めてくれるんだなと感動しました㊗️いい話が聞けて良かったー!本当ありがとうございました!!

次回の JXUG は以下から申し込み可能です! jxug.connpass.com

まとめ

今年初めてのふくてんは参加人数は少ないながらも内容は濃かった様な気がします。っていうか自分的にすごく楽しかった!!
本当はもっと .NET を使ってらっしゃる企業さんとかあると思うので是非そんな方達ともお話ししてみたいなと思うけどそんな方にどうアプローチしていいものか、今の自分には思いつかないのでどなたかご紹介ください。

次回のふくてんは2月20日(木) 19:00 〜 開催です!

fukuten.connpass.com

お待ちしてます😊

2020年!開けましたので…

あけましておめでとうございます!
今年もよろしくお願い致します🙇🏻‍♂️
皆様にとってより良い一年になります様に😊

f:id:rupic:20200101005359p:plain
今年は年男なので、嫁が書いてくれたw

今年の目標

  • xAI Meetup を盛り上げるべく色々企画する
  • 毎月ふくてんを開催
  • 積極的に登壇する
  • 今年は北九州でもイベント開催できたらいいな
  • ブログ月3で書く
  • 長女のランドセルを全力で探す
  • 自転車再開して体重を減らす

色々やりたいけど楽しむ事が一番だと思うので、のんびり頑張ります😊