こんにちはKeita_Nakamoriです。
データサイエンティスト育成講座、連休のおかげで久々に手がつけられました。
主に確率分布、推定、検定の話でした。苦手な分野なので地道に理解しながら牛歩のごとく進めました。
スクリプトメモ
次回は再びNumpyやらPandasの使い方になるのでさらっと行けたら良いなと思います。
流行の科学技術を勝手に追いかけるブログ 人工知能 仮想現実 ブロックチェーン
東洋インタレスト出版
Python関係です
こんにちはKeita_Nakamoriです。
データサイエンティスト育成講座、連休のおかげで久々に手がつけられました。
主に確率分布、推定、検定の話でした。苦手な分野なので地道に理解しながら牛歩のごとく進めました。
次回は再びNumpyやらPandasの使い方になるのでさらっと行けたら良いなと思います。
こんにちはKeita_Nakamoriです(^o^)
小学生向けにPythonの学習用にとJetson Nanoを久々に引っ張り出して有効活用しようと思いつきました。
Linux用のAnaconda3をイントールしようとしましたが無理なようなのであきらめてVScodeをインストールしようと思います。
まじめにやるならVScode本体をビルドしてからインストールしますが、下手をすると1時間くらいかかるので今回はビルド済みのパッケージをダウンロードしてインストールしました。
curlを使用するので
$sudo apt-get install curl
してから
$curl -L https://github.com/toolboc/vscode/releases/download/1.32.3/code-oss_1.32.3-arm64.deb -o code-oss_1.32.3-arm64.deb
そして
$sudo dpkg -i code-oss_1.32.3-arm64.deb
VScodeを立ち上げてみます。
$code-oss
インストールしたてのときはメニューがないので表示するための設定をします
Restartするよう警告がでるの、Restartボタンをクリックする。
これでメニューバーが追加されたはずです。
左端にあるExtensions でpythonをインストールします。
pylintも入れたいですが、現状ではpip3すら入っていない状態ですので入れます。
$sudo apt install python-pip python3-pip
$pip3 install pylint
これで VScodeでpython開発ができます。\(^o^)/
こんにちは、Keita_Nakamori(´・ω・`)です。
「東京大学のデータサイエンティスト育成講座」を参考に学習を進めています。
pythonで色々と実行していきますので、章ごとにスクリプトのメモを残していこうと思います。※ 我流でやっていますので本書の中身とは異なります。
第一章はpythonの基礎的な操作方法なので、なれている方にとっては読み飛ばして良いところです。
無名関数(ラムダ式)の復習くらいですかね。ああ、そんなのもあったな程度です。高階関数 イテレーター ジェネレータ デコレーターなどは出てきません。
基本、なくてもデータサイエンスでは困りません。
スクリプトメモ
前回は、数値の出力まででしたので、今回はリアルタイムプロットに挑戦します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# -*- coding: utf-8 -*- import smbus import math from time import sleep from time import perf_counter import time import matplotlib.pyplot as plt #mpu6050のデバイスアドレス(決まっている) DEV_ADDR = 0x68 ACCEL_XOUT = 0x3b ACCEL_YOUT = 0x3d ACCEL_ZOUT = 0x3f TEMP_OUT = 0x41 GYRO_XOUT = 0x43 GYRO_YOUT = 0x45 GYRO_ZOUT = 0x47 PWR_MGMT_1 = 0x6b PWR_MGMT_2 = 0x6c # sudo i2cdetect 0 : Error: Could not open file `/dev/i2c-0' or `/dev/i2c/0' # sudo i2cdetect 1 : I will probe file /dev/i2c-1 # エラーの出ない方がバス番号(0 か 1) # コネクションオブジェクトを取得 bus = smbus.SMBus(1) # write_byte_data(アドレス, コマンド, 1バイトの値) # スリープを解除 多分(最初はスリープしている) bus.write_byte_data(DEV_ADDR, PWR_MGMT_1, 0) # make plot times = [0 for i in range(60)] axs = [0 for i in range(60)] time = 0 ax = 0 # initialize matplotlib plt.ion() plt.figure() li_x, = plt.plot(times, axs) # need " , " #li_y, = plt.plot(times, ays) # need " , " #li_z, = plt.plot(times, azs) # need " , " #plt.xlim(-1,1) plt.ylim(-2,2) plt.xlabel("time") plt.ylabel("ax,ay,az") plt.title("ax,ay,az real time plot") def read_word(adr): high = bus.read_byte_data(DEV_ADDR, adr) low = bus.read_byte_data(DEV_ADDR, adr+1) val = (high << 8) + low return val def read_word_sensor(adr): #2バイトデータから 1ワードデータへデコードする val = read_word(adr) if (val >= 0x8000): return -((65535 - val) + 1) else: return val def get_temp(): # 温度を算出する temp = read_word_sensor(TEMP_OUT) x = temp / 340 + 36.53 # data sheet(register map)記載の計算式. return x def getGyro(): # 3軸 角速度を算出する x = read_word_sensor(GYRO_XOUT)/ 131.0 y = read_word_sensor(GYRO_YOUT)/ 131.0 z = read_word_sensor(GYRO_ZOUT)/ 131.0 return [x, y, z] def getAccel(): # 3軸 加速度を算出する x = read_word_sensor(ACCEL_XOUT)/ 16384.0 y= read_word_sensor(ACCEL_YOUT)/ 16384.0 z= read_word_sensor(ACCEL_ZOUT)/ 16384.0 return [x, y, z] # Define initial time t_init = perf_counter() while perf_counter() - t_init < 60.0 : t = perf_counter() - t_init # 3軸 加速度を算出し出力する ax, ay, az = getAccel() print ('{0:4.3f}, {1:4.3f}, {2:4.3f}, {3:4.3f}' .format(t, ax, ay, az)) #最新のデータを追加すると同時に最初のデータを削除する times.append(t) times.pop(0) axs.append(ax) axs.pop(0) #ays.append(ax) #ays.pop(0) #azs.append(ax) #azs.pop(0) # 区間プロットする li_x.set_xdata(times) li_x.set_ydata(axs) plt.xlim(min(times), max(times)) plt.draw() # plt.ion()に対応 (plt.show()ではない) plt.pause(0.01) sleep(0.02) |
できました! 以上です。
こんにちは、加速度センサーのMPU-6050を買ったので、試運転してみます。
使用するピンは 1 , 3 , 5 , 6 です。
MPU-6050の電源電圧は 3.3[V] ですが、GY-521に3.3[V]のレギュレータICが載っていて、I2Cバスのプルアップ抵抗が 3.3[V] へ繋がっているので、5[V]電源の Arduino に直接つないで使うことが出来ます。
という記述を見つけましたが、おとなしく+3.3Vに接続します。
ラズパイの設定でSSH,VNC,I2C,SPIとか全部 有効にします。
ターミナルで >ifconfigして アドレスを確認します。
192.168.10.xxx
ウィンドウズマシン上でVNC Viewerから新規コネクト作成で192.168.10.114します。
このとき、重要なのは ユーザーネームは自分で設定したIDではなくて pi です!!で、パスワードは自分で設定したやつです。
非常に紛らわしいですね。毎回詰まります。
$ gpio readall
すると、GPIOの一覧が確認できます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
+-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | | | 3.3v | | | 1 || 2 | | | 5v | | | | 2 | 8 | SDA.1 | ALT0 | 1 | 3 || 4 | | | 5v | | | | 3 | 9 | SCL.1 | ALT0 | 1 | 5 || 6 | | | 0v | | | | 4 | 7 | GPIO. 7 | IN | 0 | 7 || 8 | 1 | ALT5 | TxD | 15 | 14 | | | | 0v | | | 9 || 10 | 1 | ALT5 | RxD | 16 | 15 | | 17 | 0 | GPIO. 0 | IN | 0 | 11 || 12 | 0 | IN | GPIO. 1 | 1 | 18 | | 27 | 2 | GPIO. 2 | IN | 0 | 13 || 14 | | | 0v | | | | 22 | 3 | GPIO. 3 | IN | 0 | 15 || 16 | 0 | IN | GPIO. 4 | 4 | 23 | | | | 3.3v | | | 17 || 18 | 0 | IN | GPIO. 5 | 5 | 24 | | 10 | 12 | MOSI | ALT0 | 0 | 19 || 20 | | | 0v | | | | 9 | 13 | MISO | ALT0 | 0 | 21 || 22 | 0 | IN | GPIO. 6 | 6 | 25 | | 11 | 14 | SCLK | ALT0 | 0 | 23 || 24 | 1 | OUT | CE0 | 10 | 8 | | | | 0v | | | 25 || 26 | 1 | OUT | CE1 | 11 | 7 | | 0 | 30 | SDA.0 | IN | 1 | 27 || 28 | 1 | IN | SCL.0 | 31 | 1 | | 5 | 21 | GPIO.21 | IN | 1 | 29 || 30 | | | 0v | | | | 6 | 22 | GPIO.22 | IN | 1 | 31 || 32 | 0 | IN | GPIO.26 | 26 | 12 | | 13 | 23 | GPIO.23 | IN | 0 | 33 || 34 | | | 0v | | | | 19 | 24 | GPIO.24 | IN | 0 | 35 || 36 | 0 | IN | GPIO.27 | 27 | 16 | | 26 | 25 | GPIO.25 | IN | 0 | 37 || 38 | 0 | IN | GPIO.28 | 28 | 20 | | | | 0v | | | 39 || 40 | 0 | IN | GPIO.29 | 29 | 21 | +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+ | BCM | wPi | Name | Mode | V | Physical | V | Mode | Name | wPi | BCM | +-----+-----+---------+------+---+---Pi 3B--+---+------+---------+-----+-----+ |
$ sudo i2cdetect -y 1
すると、I2Cが接続されているのが確認できます。
1 2 3 4 5 6 7 8 9 |
0 1 2 3 4 5 6 7 8 9 a b c d e f 00: -- -- -- -- -- -- -- -- -- -- -- -- -- 10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 40: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- 60: -- -- -- -- -- -- -- -- 68 -- -- -- -- -- -- -- 70: -- -- -- -- -- -- -- -- |
では、加速度を取得してみましょう。ベタ貼りしてみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 |
# -*- coding: utf-8 -*- import smbus import math from time import sleep import time DEV_ADDR = 0x68 ACCEL_XOUT = 0x3b ACCEL_YOUT = 0x3d ACCEL_ZOUT = 0x3f TEMP_OUT = 0x41 GYRO_XOUT = 0x43 GYRO_YOUT = 0x45 GYRO_ZOUT = 0x47 PWR_MGMT_1 = 0x6b PWR_MGMT_2 = 0x6c bus = smbus.SMBus(1) bus.write_byte_data(DEV_ADDR, PWR_MGMT_1, 0) def read_word(adr): high = bus.read_byte_data(DEV_ADDR, adr) low = bus.read_byte_data(DEV_ADDR, adr+1) val = (high << 8) + low return val def read_word_sensor(adr): val = read_word(adr) if (val >= 0x8000): return -((65535 - val) + 1) else: return val def get_temp(): temp = read_word_sensor(TEMP_OUT) x = temp / 340 + 36.53 # data sheet(register map)記載の計算式. return x def getGyro(): x = read_word_sensor(GYRO_XOUT)/ 131.0 y = read_word_sensor(GYRO_YOUT)/ 131.0 z = read_word_sensor(GYRO_ZOUT)/ 131.0 return [x, y, z] def getAccel(): x = read_word_sensor(ACCEL_XOUT)/ 16384.0 y= read_word_sensor(ACCEL_YOUT)/ 16384.0 z= read_word_sensor(ACCEL_ZOUT)/ 16384.0 return [x, y, z] while 1: ax, ay, az = getAccel() gx, gy, gz = getGyro() print ('{0:4.3f},{0:4.3f},{0:4.3f},{0:4.3f},{0:4.3f},{0:4.3f},' .format(gx, gy, gz, ax, ay, az)) |
ちゃんと動いていますね。
数値データをグラフ化して見ましょう。
動的にmatplotlibを利用する必要がありますので、ちょっと考えなくてはなりません。
こんにちは Keita_Nakamoriです。(´・ω・)
台風19号が接近し、レベル4の避難命令が出ましたので最寄りの小学校へ避難しております。ひまです。
無名関数を使うときはlambda(ラムダ)と書きます。
def xxx(a, b): に相当します。
通常の関数で言うところの return a*b に相当します。
xxx関数を定義したとして、xxx(5,8) のように引数を2つ渡すことに相当します。
以上より、通常の関数では
1 2 3 4 |
def xxx(a,b): return a*b xxx(5,8) |
のところを
一行で (lambda a,b : a*b)(5,8)
と書けるのです。
書いているうちに台風が去っていきました。お家に帰りましょう。(´・ω・)
前回、myproject管理フォルダ内のurls.pyを編集しましたが、今回は
car_motorbikeアプリケーションフォルダ直下に、同じくurls.pyを新規作成して、下記スクリプトを書きます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
from django.urls import path # 追加モジュール 今回は同じ階層にある # さらにアプリケーションと同じ階層(.)なので viewsは被らない。 # よって、基本構文で良い from . import views app_name = 'carbike' # 追加した # urlパターンをリストで作っておく urlpatterns = [ path('', views.index, name='index'), # predictアドレス 後ほどviewsにpredictメソドを定義するために # views.py へ def predict(): を追加する path('predict/', views.predict, name='predict'), ] |
1.当該スクリプトで使用するモジュールであるviews.py は 当該urls.pyと同層になるので
from . import views
という不思議なインポート記述になります。
viewsモジュールはまだ作成していませんので実行すると当然エラーになりますが、あとで作成しますので心配いりません。
2.そして、画像を入力したときにvvc16_predct.pyを走らせて予測結果を返す画面である predict画面を定義します。
urlpatternsリストにリスト要素として
path(‘predict/’, views.predict, name=’predict’)
を追加します。これで urlのツリー構造として /carbike/predict が定義されたことになります。
views.predictメソドはこれから作成しなければなりませんので、現時点ではエラーが出ます。
3.なお、このcar_motorbike/urls.pyスクリプトは myproject/urls.py から呼び出されるものなので、これから myproject/urls.py の方を改良していきます。
ルーティングというやつです。
ではここから car_motorbike/urls.py へルートをつなげていきます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
from django.contrib import admin # includeメソドを追加で読み込む from django.urls import path, include urlpatterns = [ path('admin/', admin.site.urls), # 追加urlパターン carbikeというフォルダを見に来たら、carbike.indexを呼び出す # path('carbike/', carbike.index), # 追加urlパターン carbikeというフォルダを見に来たら、 # car_motorbike.urls.pyの中にあるルーティングを読みに行く path('carbike/', include('car_motorbike.urls')), ] |
1.include関数を新たにインポートして 、先程作成した car_mortorbike/urls.pyを参照するようリストurlpatternsにリスト要素としてpath(‘carbike/’, include(‘car_motorbike.urls’))を追加します。
2.これで、ブラウザ上のurl指定に/carbikeが追加されたとき、car_motorbike.urlsスクリプトを見に行くことになります。
先程、car_motorbike/urls.py 内で views.predictメソドを記述しましたが、それの実体をここで定義します。とりあえずルーティングが正しく行われて表示されるか確認したいので、実行内容としてはテキストを出力するだけの最低限にしてテストしてみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
from django.shortcuts import render # 追加モジュール from django.http import HttpResponse def index(request): # webサイトのindex.html に相当する部分 # 仮のリターンを作っておく return HttpResponse('hello_world') def predict(request): # webサイトのpredict.html に相当する部分 # 仮のリターンを作っておく return HttpResponse('show predictions here') |
では python manage.py runserver して ブラウザで動作チェックをしましょう。
1.http://127.0.0.1:8000/ を入力すると
>[21/Sep/2019 15:53:08] “GET / HTTP/1.1” 404 2032
トップページは作っていませんから、404エラーで問題ありません。
2.http://127.0.0.1:8000/carbike を入力すると
>[21/Sep/2019 15:53:17] “GET /carbike/ HTTP/1.1” 200 11
200と出ていますのでちゃんと認識しています。
3.http://127.0.0.1:8000/carbike/predict
>[21/Sep/2019 15:53:30] “GET /carbike/predict/ HTTP/1.1” 200 21
と 200が帰ってくるのでこちらも正常に動作しています。
Web Application: 第10回 HTMLでかっこよくする
こんにちは Keita_Nakamori(´・ω・)です。
さて、前回まででTensor Flow を使ったスクリプトを書いてきましたが、これをwebアプリとしてアクセスできるようにDjangoを組み込んでいきます。
$ pip install Django
django-2.2.5 が入りました
djangoでは大項目としてプロジェクト名、小項目としてアプリケーション名があります。後々ひとつのプロジェクトの下に複数のアプリケーションを作っていくことになります。
では、myprojectというプロジェクトを作ります
$ django-admin startproject myproject
これでmyprojectというプロジェクトフォルダが生成されました。
フォルダの下層にはmange.pyという管理用のpythonファイルと、プロジェクト名と同じ名称で設定用のmyproject設定フォルダが生成されます。
Web Server Gateway Interface (WSGI; ウィズギー)
webサーバーとwebアプリ(またはwebフレームワーク)を接続するためのインターフェース定義。
WSGIはこれまでFastCGI, mod_python, CGIなど様々なインターフェース定義が乱立している中で最終的にpythonにおける最有力規格となったインターフェース定義。python webフレームワークで有力なFlaskとかBottletoとかDjangoが採用しているので、かなり盤石。
管理スクリプトmanage.pyを使ってmyprojectプロジェクト全体フォルダから
$ python manage.py runserver
とランサーバー指令をコマンドプロンプトに打つと
1 2 3 4 5 6 7 8 9 10 11 |
Watching for file changes with StatReloader Performing system checks... System check identified no issues (0 silenced). You have 17 unapplied migration(s). Your project may not work properly until you apply the migrations for app(s): admin, auth, contenttypes, sessions. Run 'python manage.py migrate' to apply them. September 21, 2019 - 09:35:13 Django version 2.2.5, using settings 'myproject.settings' Starting development server at http://127.0.0.1:8000/ Quit the server with CTRL-BREAK. |
と出るので、http://127.0.0.1:8000/がサーバーとして動き出します。
実際にブラウザのURLバーにこれをコピペすると、インストールが完了しましたとお祝いの言葉を頂戴できます。
強制終了は CTRL-BREAKと書いてありますが、control+c のことです。
hello worldと表示するwebアプリケーションを作ってみましょう。
runserverしっぱなしの場合はctl+cで一旦止めておきます。
myproject プロジェクトフォルダに戻ってみたら、db.sqlite3 というデータベースが生成されていました。まだカラのようで容量は0KBです。
つづきまして、アプリケーションのフォルダを作りましょう。
スタートアップですがstartup ではなくて startappなので要注意です。
$myproject>python manage.py startapp car_motorbike
これでmyprojectプロジェクトフォルダ直下に car_motorbikeアプリケーションフォルダが生成されました。
現在のフォルダ構成をおさらいすると、
そして、car_bikeアプリケーションフォルダの中には、各種pythonスクリプトが新しく生成されました。今後はここを弄っていくことになります。
VScodoで構造を見てみると、まだ何も弄ってないのにこれだけのファイル数になります。ではviews.pyを開いて編集していきましょう。
オリジナルは下記のような2行のコードです。
1 2 |
from django.shortcuts import render # Create your views here. |
アクセスが来たときに hello_worldとレスポンスを返すためのHttpRespose関数をインポートして使用します。
1 2 3 4 5 6 7 8 |
from django.shortcuts import render # 追加モジュール from django.http import HttpResponse def index(request): # webサイトのindex.html に相当する部分 return HttpResponse('hello_world') |
これはまだ、呼び出されたときの挙動を定義しただけですので、このindex(request)関数を呼び出すためのスクリプトが別途必要です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
"""myproject URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/2.2/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path urlpatterns = [ path('admin/', admin.site.urls), ] |
(google翻訳すると スクリプト部分まで和訳されて意味不明でした。)
myproject URL設定
urlpatternsリストはURLをビューにルーティングします。 詳細については、以下を参照してください。
https://docs.djangoproject.com/en/2.2/topics/http/urls/例:
1.インポートの追加:
from my_app import views
2. urlpatternsにURLを追加します:
1.インポートを追加します:
2. URLをurlpatternsに追加します:
1. include()関数をインポートします:
2. urlpatternsにURLを追加
イメージが全然わきませんね。
機能ビューの
をやってみます。
公式サイトに従ってインポートをfrom car_motorbike import views としてしまうとあとあとcar_motorbike以外のアプリを作成して時に form xxx import viewsというようにかぶってしまうので、ここではimport car_motorbike.views as carbike として被らないようにします。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
# 追加モジュール import car_motorbike.views as carbike # 拡張子.pyは省略する '''以下のようなインポートの仕方だとwebページの変数がすべてviewsになってしまい被る from car_motorbike import views ''' urlpatterns = [ path('admin/', admin.site.urls), # 追加urlパターン carbikeというフォルダを見に来たら、carbike.indexを呼び出す path('carbike/', carbike.index), ] |
Keita_Nakamoriです。TensorFlowに疲れてきました。
早くwebアプリの部分にいきたい・・・。
今回は、転移学習を試してみます。学習済みのCNNであるVGG16を使って、その後ろに中間層と全結合層をマニュアルで挿入して最終的にsoftmax関数を通して結果を出力します。
中間層は256node、全結合層は2クラスしかないので2nodeです。
前回まで、import keras をして kerasを使用していましたが、今どきはTensorFlowのクラスとして存在しているので使ってみます。
というのもfrom keras.models import Modelでエラーが出てしまいどうしようもないので調べていたら見つけました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
import numpy as np import matplotlib.pyplot as plt # keras は tensorflowのクラスとして存在する from tensorflow import keras from tensorflow.keras.models import Sequential, Model from tensorflow.keras.layers import Dense, Dropout, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.optimizers import SGD, Adam from tensorflow.python.keras.utils import np_utils from tensorflow.python.keras.applications import VGG16 # 出力結果のクラスを定義 classes = ["car", "motorbike"] num_classes = len(classes) # クラス数を定義 # 画像サイズを定義(VGG16に合うように) image_size = 224 # npyデータを読み込み、訓練用・検証用データに分割する X_train, X_test, y_train, y_test = np.load( "./image_files_224.npy", allow_pickle=True ) # one hot エンコーディング y_train = np_utils.to_categorical(y_train, num_classes) y_test = np_utils.to_categorical(y_test, num_classes) # ここで入力データの正規化を行う X_train = X_train.astype("float") / 255.0 X_test = X_test.astype("float") / 255.0 # VGG16モデルを定義する model = VGG16(weights='imagenet', include_top=False, input_shape=(image_size,image_size,3)) # 以降のニューラルネットワーク層を定義する。top_model # VGG16の出力がSequentialで出てくるので、追加する全結合層もシーケンシャルで作成しておく。 top_model = Sequential() top_model.add(Flatten(input_shape=model.output_shape[1:])) top_model.add(Dense(256, activation='relu')) top_model.add(Dropout(0.5)) top_model.add(Dense(num_classes, activation='softmax')) # VGG16と追加層を結合する # VGG16の出力を追加層の入力に入れる。 model = Model(inputs=model.input, outputs=top_model(model.output)) # モデルのサマリーを確認する model.summary() # トレーニングしないようにパラメータをフリーズ(固定化)する # 必ずcompileの前に入れる for layer in model.layers[:15]: layer.trainable = False # オプティマイザーを定義する opt = Adam(lr=0.0001) model.compile(loss='categorical_crossentropy', optimizer=opt,metrics=['accuracy']) # 訓練をする history = model.fit(X_train, y_train, batch_size=32, epochs=17) # 評価する score = model.evaluate(X_test, y_test, batch_size=32) print('Test loss:', score[0]) print('Test accuracy:', score[1]) # モデルを保存する model.save("./vgg16_trans.h5") # 可視化する loss = history.history['loss'] nb_epoch = len(loss) plt.plot(range(nb_epoch), loss, marker='.', label='loss') plt.legend(loc='best', fontsize=10) plt.grid() plt.xlabel('epoch') plt.ylabel('loss') plt.show() |
スクリプト内の# モデルのサマリーを確認する model.summary() までを実行するとニューラルネットワークの構造が確認できます。
最後に、sequential (Sequential) (None, 2) が新しく生成されました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
Model: "model" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) [(None, 224, 224, 3)] 0 _________________________________________________________________ block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 _________________________________________________________________ block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 _________________________________________________________________ block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 _________________________________________________________________ block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 _________________________________________________________________ block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 _________________________________________________________________ block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 _________________________________________________________________ block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 _________________________________________________________________ block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 _________________________________________________________________ block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 _________________________________________________________________ block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 _________________________________________________________________ block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 _________________________________________________________________ sequential (Sequential) (None, 2) 6423298 ================================================================= Total params: 21,137,986 Trainable params: 21,137,986 Non-trainable params: 0 _________________________________________________________________ |
VGG16層 全結合2層 17エポックまでやってみましたが、数十分かかってしまいました。流石のディープさです。
しかし、結果は素晴らしいい。トレーニング100% テスト99%の精度。
そして、モデルファイルである192MB のvgg16_trans.h5 ファイルも上手く生成できていました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
600/600 [==============================] - 226s 376ms/sample - loss: 0.2884 - acc: 0.8750 Epoch 2/17 600/600 [==============================] - 241s 402ms/sample - loss: 0.0544 - acc: 0.9833 Epoch 3/17 600/600 [==============================] - 1048s 2s/sample - loss: 0.0109 - acc: 0.9983 Epoch 4/17 600/600 [==============================] - 235s 392ms/sample - loss: 0.0085 - acc: 0.9967 Epoch 5/17 600/600 [==============================] - 252s 421ms/sample - loss: 0.0012 - acc: 1.0000 Epoch 6/17 600/600 [==============================] - 242s 403ms/sample - loss: 4.5241e-04 - acc: 1.0000 Epoch 7/17 600/600 [==============================] - 235s 391ms/sample - loss: 3.2469e-04 - acc: 1.0000 Epoch 8/17 600/600 [==============================] - 235s 391ms/sample - loss: 1.6192e-04 - acc: 1.0000 Epoch 9/17 600/600 [==============================] - 227s 378ms/sample - loss: 1.1878e-04 - acc: 1.0000 Epoch 10/17 600/600 [==============================] - 228s 380ms/sample - loss: 4.5246e-05 - acc: 1.0000 Epoch 11/17 600/600 [==============================] - 228s 381ms/sample - loss: 1.3106e-04 - acc: 1.0000 Epoch 12/17 600/600 [==============================] - 234s 390ms/sample - loss: 6.3007e-05 - acc: 1.0000 Epoch 13/17 600/600 [==============================] - 229s 382ms/sample - loss: 2.4614e-05 - acc: 1.0000 Epoch 14/17 600/600 [==============================] - 230s 383ms/sample - loss: 3.7191e-05 - acc: 1.0000 Epoch 15/17 600/600 [==============================] - 229s 381ms/sample - loss: 3.3313e-05 - acc: 1.0000 Epoch 16/17 600/600 [==============================] - 235s 392ms/sample - loss: 3.7981e-05 - acc: 1.0000 Epoch 17/17 600/600 [==============================] - 230s 383ms/sample - loss: 7.3269e-06 - acc: 1.0000 200/200 [==============================] - 67s 333ms/sample - loss: 0.0636 - acc: 0.9900 |
では、転移学習済みのvgg16_trans.h5モデルをロードして、Anacondaプロンプトからサンプル画像を入力することによってcar なのか motorbikeなのか予測してみましょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
import numpy as np import matplotlib.pyplot as plt from PIL import Image import sys # keras は tensorflowのクラスとして存在する from tensorflow import keras from tensorflow.keras.models import load_model '''トレーニング済みなので 不要 from tensorflow.keras.layers import Dense, Dropout, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.optimizers import SGD, Adam from tensorflow.python.keras.utils import np_utils from tensorflow.python.keras.applications import VGG16 ''' # 出力結果のクラスを定義 classes = ["car", "motorbike"] num_classes = len(classes) # クラス数を定義 # 画像サイズを定義(VGG16に合うように) image_size = 224 # 画像ファイルをコマンドラインの第2引数から開く image = Image.open(sys.argv[1]) # 画像ファイルをRGBに変換する image = image.convert('RGB') # 画像を同じサイズに揃える image = image.resize((image_size, image_size)) # RGB値をnumpy配列に変換する data = np.asarray(image) # データを正規化する data = data / 255.0 # リストにappendしてnumpy配列にする X = [] X.append(data) X = np.array(X) # VGG16_transモデルをロードする model = load_model('./vgg16_trans.h5') # VGG16_transモデルにデータを入れて予測結果を返す # スコアが配列で帰ってくるので[0]番目をつける result = model.predict([X])[0] # 最も大きい数字を採用する predicted = result.argmax() percentage = int(result[predicted] * 100) # プリントする print(classes[predicted], percentage) print('==== script is done ====') |
1.車の画像データの一つをcar1.jpgにリネームしてdjangoaiフォルダ直下に移動します。
(djangoai) C:\Users\keita\anaconda_projects\djangoai>python vgg16_predict.py car1.jpg
結果:car 100
2.次にバイクの画像データの一つをbike1.jpgにリネームしてdjangoaiフォルダ直下に移動します。
(djangoai) C:\Users\keita\anaconda_projects\djangoai>python vgg16_predict.py motorbike1.jpg
結果:motorbike 100
3.試しにビキニ画像データを入力してみましたが・・・バイク100%になりました。(笑)
Web Application: 第8回 はじめてのwebアプリ
オックスフォード大学のVisual Geometry Groupが作った、畳み込み13層+全結合3層の 合計16層のニューラルネットワークです。
VGG16の入力データの画像サイズは 224 x 224 である必要がありますので generate_inputdata.pyを改造して224×224のnpyデータを生成するgenerate_inputdata_224.pyを作りましょう。
また、それだと元々150角サイズが224角サイズになるわけですから、容量が増えてしまいます。(実際に600MBから1300MBに増えました。)
そこで、このスクリプトでは正規化するのをやめて、浮動小数点が発生するのを防ぎ容量を落とします。
代わりに、VGG16をやる直前に正規化を行う方針でいきます。
変更した部分は
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 |
from PIL import Image # image operation import os # get file list import glob # image treatment import numpy as np # culculation from sklearn.model_selection import train_test_split # split data # initialize parameters classes = ['car', 'motorbike'] # define 2 classses num_classes = len(classes) # the number of classes image_size = 224 # pixels of width or height # read images and cnvert numpy array X = [] # ready to make list Y = [] # ready to make list # numbering and for index, class_label in enumerate(classes): # create class_label directories (car or motorbike) photos_dir ='./' + class_label # search jpeg fileb and create files object files = glob.glob(photos_dir + '/*.jpg') for i, file in enumerate(files): # open image files as instance image = Image.open(file) # convert image into RGB value data image = image.convert('RGB') # align to the same size (just in case) image = image.resize((image_size, image_size)) # convert RGB value into numpy array data = np.asarray(image) # do not normalize # so, data object nees to be normalize other script later #data = data / 255.0 # append value to list X.append(data) Y.append(index) # convert list into numpy array X = np.array(X) Y = np.array(Y) # split data (training and test) X_train, X_test, y_train, y_test = train_test_split(X, Y) # replace 1 variable xy =(X_train, X_test, y_train, y_test) # save values as npy file np.save('./image_files_224.npy', xy) |
では、データができたところでVGG16モデルを作成しましょう。
モジュール追加:from keras.applications import VGG16
ロードデータ名変更;
正規化操作の追加:
モデル定義の変更
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import numpy as np import tensorflow as tf import keras import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras.optimizers import SGD, Adam from keras.utils import np_utils from keras.applications import VGG16 # initialize parameters classes = ['car', 'motorbike'] # define 2 classses num_classes = len(classes) # the number of classes image_size = 224 # pixels of width or height # load npy file # need 'allow_pickle=True' X_train, X_test, y_train, y_test = np.load('./image_files_224.npy', allow_pickle=True) # one hot encording y_train = np_utils.to_categorical(y_train, num_classes) y_test = np_utils.to_categorical(y_test, num_classes) # normalize X_train = X_train.astype('float') / 255.0 X_test = X_train.astype('float') / 255.0 # define model model = VGG16( weights='imagenet', include_top=False, input_shape=(image_size,image_size, 3) ) print('Model loaded') model.summary() |
input_1 (InputLayer) (None, 224, 224, 3)について
1枚の224 x 224 サイズの画像データにつき、 RGBの3枚に分解されたデータが入力データとし入ります。
まだ何枚のデータが入ってくるかわかりませんのでNoneになっています。
畳み込み2回 プーリング1回 畳み込み2回 プーリング1回 畳み込み3回・・・、で 16層あるのだそうですがどういう数え方をしたら16になるかは理解できていません・・・。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
Model loaded Model: "vgg16" _________________________________________________________________ Layer (type) Output Shape Param # ================================================================= input_1 (InputLayer) (None, 224, 224, 3) 0 _________________________________________________________________ block1_conv1 (Conv2D) (None, 224, 224, 64) 1792 _________________________________________________________________ block1_conv2 (Conv2D) (None, 224, 224, 64) 36928 _________________________________________________________________ block1_pool (MaxPooling2D) (None, 112, 112, 64) 0 _________________________________________________________________ block2_conv1 (Conv2D) (None, 112, 112, 128) 73856 _________________________________________________________________ block2_conv2 (Conv2D) (None, 112, 112, 128) 147584 _________________________________________________________________ block2_pool (MaxPooling2D) (None, 56, 56, 128) 0 _________________________________________________________________ block3_conv1 (Conv2D) (None, 56, 56, 256) 295168 _________________________________________________________________ block3_conv2 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_conv3 (Conv2D) (None, 56, 56, 256) 590080 _________________________________________________________________ block3_pool (MaxPooling2D) (None, 28, 28, 256) 0 _________________________________________________________________ block4_conv1 (Conv2D) (None, 28, 28, 512) 1180160 _________________________________________________________________ block4_conv2 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_conv3 (Conv2D) (None, 28, 28, 512) 2359808 _________________________________________________________________ block4_pool (MaxPooling2D) (None, 14, 14, 512) 0 _________________________________________________________________ block5_conv1 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv2 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_conv3 (Conv2D) (None, 14, 14, 512) 2359808 _________________________________________________________________ block5_pool (MaxPooling2D) (None, 7, 7, 512) 0 ================================================================= Total params: 14,714,688 Trainable params: 14,714,688 Non-trainable params: 0 _________________________________________________________________ |
ひとまず、できていました。このあと、全結合層を後ろに追加していくことになります。それは次回!
Web Application: 第7回 VGG16を使った転移学習