Memo

メモ > 技術 > プログラミング言語: Python

■Python
■入門 以下が詳細で解りやすい Python入門 - @IT https://www.atmarkit.co.jp/ait/series/12963/ Pythonプログラミング入門 - Pythonプログラミング入門 documentation https://utokyo-ipp.github.io/ ■環境構築 主にVSCodeではじめるPython開発環境構築ガイド | DevelopersIO https://dev.classmethod.jp/articles/python-vscode-plugin/ ■応用 Pythonのアンダースコア( _ )を使いこなそう! - LSC PSD - Medium https://medium.com/lsc-psd/pythonic%E8%89%B2%E3%80%85-python%E3%81%AE%E3%82%A2%E3%83%B3%E3%83%80%E3%... AIエンジニアが気をつけたいPython実装のノウハウ・コツまとめ - Qiita https://qiita.com/sugulu/items/c0e8a5e6b177bfe05e99 【Python】いい書き方と悪い書き方を知って中級者を目指す - Qiita https://qiita.com/_masa_u/items/b21c493a82e8aba8993f Pythonのオブジェクト指向プログラミングを完全理解 - Qiita https://qiita.com/kaitolucifer/items/926ed9bc08426ad8e835 【2020年新人研修資料】ナウでヤングなPython開発入門 - Speaker Deck https://speakerdeck.com/stakaya/2020nian-xin-ren-yan-xiu-zi-liao-nauteyankunapythonkai-fa-ru-men 朝飯前に学べる!便利なPythonのヒント100選【前編】 - Qiita https://qiita.com/baby-degu/items/05cf809d4d992923020d 朝飯前に学べる!便利なPythonのヒント100選【後編】 - Qiita https://qiita.com/baby-degu/items/532bea7be058c35f61a8 全てがTypeScriptで動く「クラウド郵便 atena」を支える技術スタック https://zenn.dev/n1nc/articles/atena-system-architecture データ分析の基礎 - Qiita https://qiita.com/wooooo/items/24d1a4d6be5ab7bf023f Pythonのパッケージ管理の中級者の壁を超える stapy#98 - Speaker Deck https://speakerdeck.com/vaaaaanquish/pythonnopatukeziguan-li-nozhong-ji-zhe-nobi-wochao-eru-stapy-nu... 並列処理がとても苦手なPythonはプロセスを分けよう コードを書く時に意識したい2つのTipsと2つの落とし穴 - ログミーTech https://logmi.jp/tech/articles/329470 【AtCoder】Pythonで競プロをするときの注意点まとめ【競技プログラミング】 #Python - Qiita https://qiita.com/kemuniku/items/1f1537e1df2ac8180d9b ■数値を文字列と結合して表示
a = 10 print('a = ' + str(a))
■科学的表記法を使って数値を表現 Pythonコード内に「1e-3」のような表記が現れることがある これは科学的表記法を使って数値を表現したもの 「1e-3」は「1 * 10^-3」と同じで、その結果は 0.001 となる
1e0 = 1 1e1 = 10 1e-1 = 0.1 1e-2 = 0.01 1e-3 = 0.001
この表記法は、非常に大きな数値や非常に小さな数値を簡潔に表現するために使用される ■配列の計算 以下は計算できず、「TypeError: can only concatenate list (not "int") to list」のエラーになる
def double(x): return x + 1 numbers = [1, 2, 3] print(double(numbers))
以下のようにmapを使うと、それぞれの計算結果「[2 3 4]」を得られる
def double(x): return x + 1 numbers = [1, 2, 3] print(list(map(double, numbers)))
以下のようにnumpyを使っても、それぞれの計算結果「[2 3 4]」を得られる
import numpy as np def double(x): return x + 1 numbers = np.array([1, 2, 3]) print(double(numbers))
また以下のようにすると、計算結果「[5 7 9]」を得られる
import numpy as np def add(a, b): return a + b a_numbers = np.array([1, 2, 3]) b_numbers = np.array([4, 5, 6]) print(add(a_numbers, b_numbers))
Pythonのmap()でリストの要素に関数・処理を適用 | note.nkmk.me https://note.nkmk.me/python-map-usage/ PythonのNumPy配列の数値演算のやり方まとめ | HEADBOOST https://www.headboost.jp/python-numpy-array-calculations/ ■配列の内容をすべて表示
map_result = map(str, targets) result = ', '.join(map_result) print('[' + result + ']')
■配列の要素数を表示
print(len(targets))
■行列の計算 np.dot() によって行列の計算ができるが、与える配列の次元によって挙動が変わる 以下のとおりAとBが1次元配列の場合、以下のように計算される これは内積を求めている
import numpy as np A = np.array([1, 2, 3]) B = np.array([2, 4, 6]) result = np.dot(A, B) # 1*2 + 2*4 + 3*6 = 28 print(result) # 28
AとBが2次元配列の場合、以下のように計算される これは行列積を求めている
import numpy as np A = np.array([[1,1], [2,2], [3,3]]) B = np.array([[1, 2], [3, 4]]) result = np.dot(A, B) # A * B = C # |1 1| * |1 2| = |(1*1 + 1*3) (1*2 + 1*4)| = |4 6| # |2 2| |3 4| |(2*1 + 2*3) (2*2 + 2*4)| |8 12| # |3 3| |(3*1 + 3*3) (3*2 + 3*4)| |12 18| print(result) # [[ 4 6] # [ 8 12] # [12 18]]
AとBのどちらかがスカラの場合、以下のように計算される これは積を求めている
import numpy as np A = np.array([[1,1], [2,2], [3,3]]) B = 5 result = np.dot(A, B) # A * B = C # |1 1| * 5 = |(1*5) (1*5)| = | 5 5| # |2 2| |(2*5) (2*5)| |10 10| # |3 3| |(3*5) (3*5)| |15 15| print(result) # [[ 5 5] # [10 10] # [15 15]]
Aが2次元配列でBが1次元配列の場合、以下のように計算される
import numpy as np A = np.array([[1,1], [2,2], [3,3]]) B = np.array([7, 8]) result = np.dot(A, B) # A * B = result # |1 1| * |7 8| = |1*7 + 1*8| |15| # |2 2| |2*7 + 2*8| = |30| # |3 3| |3*7 + 3*8| |45| print(result) # [15 30 45]
numpy.dot の挙動 #Python - Qiita https://qiita.com/ao_log/items/64768b67153e8fb6820b ■map 【Pythonステップアップ!】高階関数mapの便利な使い方 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト https://www.sejuku.net/blog/24759 ■lambda Pythonのlambdaって分かりやすい - Qiita https://qiita.com/nagataaaas/items/531b1fc5ce42a791c7df ■画像 PythonでPowerPointの各ページを画像ファイルにする - Qiita https://qiita.com/natsutan/items/2487e24fe3f31569b40d ■クロスプラットフォームアプリ Pythonだけでクロスプラットフォームなアプリを作れるFletについて - Qiita https://qiita.com/NasuPanda/items/48849d7f925784d6b6a0 ■ゲーム 「ゲーム制作するなら、これだけは覚えておいたほうがいい」 プログラミングする上で重要な「対数」の考え方 - ログミーTech https://logmi.jp/tech/articles/326705 Pythonなら3Dゲームも作れる!まずは空間にモノを置いてみよう | 日経クロステック(xTECH) https://xtech.nikkei.com/atcl/nxt/column/18/02075/052400001/ ■数学 数学×Pythonプログラミング入門 - @IT https://atmarkit.itmedia.co.jp/ait/series/24243/ 統計・機械学習の理論を学ぶ手順 - Qiita https://qiita.com/kueda_cs/items/28008db6491c71ac5659 数学を楽しみながら独学できる本、究極の5冊 | 独学大全 | ダイヤモンド・オンライン https://diamond.jp/articles/-/301387 ■機械学習 Pythonでニューラルネットワークを書いてみよう:ニューラルネットワーク入門 - @IT https://atmarkit.itmedia.co.jp/ait/articles/2202/09/news027.html みんな、とにかくオセロAIを作るんだ - Qiita https://qiita.com/Nyanyan_Cube/items/1839732d7bdf74caff21 機械学習が独学できる日本語Youtube難易度別まとめ - Qiita https://qiita.com/fujimr_19xx/items/f85d08a260ef7e0df655 モナリザがトランプ大統領のように動き出すFirst Order Motion Modelを試してみる - Qiita https://qiita.com/jun40vn/items/722bd4675246eb7eac46 第1回 初めてのニューラルネットワーク実装、まずは準備をしよう ― 仕組み理解×初実装(前編):TensorFlow 2+Keras(tf.keras)入門 - @IT https://atmarkit.itmedia.co.jp/ait/articles/1909/19/news026.html Pythonで作る人工生命 | 日経クロステック(xTECH) https://xtech.nikkei.com/atcl/nxt/column/18/01996/ 【5分で解説】AI進化のきっかけになったTransformerとは!?Attention層とは?|スタビジ https://toukei-lab.com/transformer
■Windows上に開発環境を構築
■XAMPPでPythonを動作させるメモ Pythonディストリビューション使い分けのポイントを考えてみよう(Windows編):Python環境構築入門(1/3 ページ) - @IT https://atmarkit.itmedia.co.jp/ait/articles/2203/23/news027.html Windows環境へのPythonインストールは、上記のように複数の方法がある 後々のことを考えれば、Anacondaでインストールしておくのが無難か Python | Pythonのダウンロードとインストール https://www.javadrive.jp/python/install/index1.html 今回はAnacondaを使ってインストールした Anacondaのインストール | Python入門 https://www.javadrive.jp/python/install/index5.html Anaconda で Python 環境をインストールする - Qiita https://qiita.com/t2y/items/2a3eb58103e85d8064b6 【Python】非エンジニアWindowユーザー向けのAnacondaインストールの手順 https://tonari-it.com/python-anaconda-install/ ■コマンプロンプトで動作確認 コマンドプロンプトから、以下を実行してインストールを確認
>C:\Users\refirio\Anaconda3\python --version Python 3.7.3
以下のようにして直接命令を実行できる
>C:\Users\refirio\Anaconda3\python >>> print('Hello Python') Hello Python >>> quit()
hello.py を作成して以下の内容を記述
print("Hello! Python.")
以下のようにしてプログラムを実行
>C:\Users\refirio\Anaconda3\python hello.py Hello! Python.
■コマンプロンプトで動作確認(補足) 上で紹介したとおり、コマンドプロンプトから以下を実行してインストールを確認できる
>C:\Users\refirio\Anaconda3\python --version Python 3.7.3
Windowsの検索で「Anaconda Prompt」を検索して実行すると、パスの指定なしでも実行できる
>python --version Python 3.10.9
■CGIで動作確認 あらかじめ、XAMPPをインストールしておく C:\xampp\apache\conf\httpd.conf を編集し、Apacheを再起動する
AddHandler cgi-script .cgi .pl .asp ↓ AddHandler cgi-script .cgi .pl .asp .py
test.py を作成して以下の内容を記述
#!C:\Users\refirio\Anaconda3\python # -*- coding: utf-8 -*- print("Content-Type: text/html\n") print("Hello World")
以下のようにしてプログラムを実行 http://localhost/test/test.py ■文字化け対策 Python 3.x - Pythonにて文字化けが発生します|teratail https://teratail.com/questions/130659 PythonのCGIで日本語が文字化けしたときの対処法 - Qiita https://qiita.com/eleven-junichi2/items/f3fcb6abe7fe21a4d89a
#!/Users/refirio/Anaconda3/python # coding: utf-8 # -*- coding: utf-8 -*- import sys,io sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') print("Content-Type: text/html; charset=UTF-8\n") print("<!DOCTYPE html>") print("<html>") print("<head>") print("<meta charset=\"utf-8\">") print("<title>Python</title>") print("</head>") print("<body>") print("<h1>Python</h1>") print("<p>これはPythonの実行結果です。</p>") print("</body>") print("</html>")
■pip(Pythonのパッケージ管理システム) pipとpipenvとpoetryの技術的・歴史的背景とその展望 - Stimulator https://vaaaaaanquish.hatenablog.com/entry/2021/03/29/221715 Python - Pythonの「pip」と「pip3」は何が違う?|teratail https://teratail.com/questions/46066 PythonでOpenCVをはじめる(Windows10、Anaconda 2018.12、Python3.7.1、OpenCV4.0.0) - Qiita https://qiita.com/SatoshiGachiFujimoto/items/94da93f88578b87f6a89 Windowsの検索機能などから「Anaconda Prompt」を開く 以下のようにして、Pythonとpipのバージョンを確認できる
>python --version Python 3.7.3 >python -m pip -V pip 19.1.1 from C:\Users\refirio\Anaconda3\lib\site-packages\pip (python 3.7)
pipでライブラリをインストールした場合、以下のようにすればPythonプログラムの簡易な動作確認が
>python Python 3.7.3 (default, Apr 24 2019, 15:29:51) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32 Type "help", "copyright", "credits" or "license" for more information. >>> print('Hello!') Hello! >>> quit Use quit() or Ctrl-Z plus Return to exit >>> exit()
■Excelを操作 ※未検証 ゼロからはじめるPython(65) PythonでExcelを操作する二大手法を比較しよう | マイナビニュース https://news.mynavi.jp/article/zeropython-65/ PythonによるExcel自動化は何がスゴい?インストールからコードサンプルまで実践詳解 |ビジネス+IT https://www.sbbit.jp/article/cont1/46162 ■OpenCV PythonでOpenCVをはじめる(Windows10、Anaconda 2018.12、Python3.7.1、OpenCV4.0.0) - Qiita https://qiita.com/SatoshiGachiFujimoto/items/94da93f88578b87f6a89 Pythonを用いた画像処理(openCV,skimage) - Qiita https://qiita.com/taka_baya/items/453e429b466ffaa702c9
>pip install opencv-python Successfully installed opencv-python-4.1.1.26 >pip install opencv-contrib-python Successfully installed opencv-contrib-python-4.1.1.26 >python Python 3.7.3 (default, Apr 24 2019, 15:29:51) [MSC v.1915 64 bit (AMD64)] :: Anaconda, Inc. on win32 Type "help", "copyright", "credits" or "license" for more information. >>> import cv2 >>> cv2.__version__ '4.1.1' >>> exit()
インストールできたが、CGIからサンプルプログラムを実行するとエラーになった エラーの内容は以下のとおり
[Sun Sep 22 14:11:11.801745 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] End of script output before headers: test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.801745 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: ImportError: numpy.core.multiarray failed to import\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.802745 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: Traceback (most recent call last):\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.802745 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: File "C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py", line 5, in <module>\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.802745 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: import cv2\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.803737 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: File "C:\\Users\\refirio\\Anaconda3\\lib\\site-packages\\cv2\\__init__.py", line 3, in <module>\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.803737 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: from .cv2 import *\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/ [Sun Sep 22 14:11:11.803737 2019] [cgi:error] [pid 13672:tid 1960] [client ::1:52117] AH01215: ImportError: numpy.core.multiarray failed to import\r: C:/localhost/home/raspberrypi/public_html/cgi/opencv/test.py, referer: http://localhost/~raspberrypi/cgi/opencv/
エラーメッセージによると、numpy.core.multiarray を使えないらしい 以下を参考に numpy をアップデートすると大丈夫だった 【Pythonエラー対策】ImportError: numpy.core.multiarray failed to import | 西住工房 https://algorithm.joho.info/programming/python/numpy-core-multiarray-failed-to-import/
>pip install numpy --upgrade
なお、プログラム実行ディレクトリに、numpy.py を自身で作成していると、そちらが読み込まれる 結果的に正しいファイルを読み込めずにエラーになるので注意 ■OpenCV(バージョン3をインストール) 上記「OpenCV」の手順でインストールすると、4.1.1 がインストールされた 今回は本番環境に合わせて 3.4.3 にバージョンダウンするものとする 【Jupyter Notebook】OpenCVのインポートエラー解決メモ - Qiita https://qiita.com/yut-nagase/items/27b0a17e9e3074a95c6c 以下のようにしてアンインストール&インストールできた
>pip uninstall opencv-python >pip install opencv-python==3.4.3.18
なお、以下のバージョン指定だと「バージョンの指定が不十分」となる エラーメッセージをもとに、マイナーバージョンを指定する
>pip install opencv-python==3.4.3 Collecting opencv-python==3.4.3 ERROR: Could not find a version that satisfies the requirement opencv-python==3.4.3 (from versions: 3.4.2.16, 3.4.2.17, 3.4.3.18, 3.4.4.19, 3.4.5.20, 3.4.6.27, 3.4.7.28, 4.0.0.21, 4.0.1.23, 4.0.1.24, 4.1.0.25, 4.1.1.26) ERROR: No matching distribution found for opencv-python==3.4.3
■Jupyter Notebook ※未検証 【初心者向け】Jupyter Notebookの使い方!インスト…|Udemy メディア https://udemy.benesse.co.jp/development/python-work/jupyter-notebook.html ブラウザ上でプログラムを実行できるようになるらしい Googleの「Colaboratory」やAWSの「SageMaker Studio Lab」を使えば、同じような環境が提供される ■その他メモ 2020年5月におけるPython開発環境の選択肢 - Qiita https://qiita.com/nicco_mirai/items/80ba4b4bf9db11ac54c6 2020 年の Python パッケージ管理ベストプラクティス - Qiita https://qiita.com/sk217/items/43c994640f4843a18dbe
■Linux上に開発環境を構築
基本的に、Pythonは初めからインストールされている ■Raspberry Pi Raspberry Pi 上で開発するために諸々のツールを追加インストールした際のメモは RaspberryPi.txt を参照 ■CentOS CentOS7の場合、初めからPython2がインストールされている ただしPython3を使用したい場合、別途インストールする必要がある
# python --version Python 2.7.5
■CentOS7.7以降の場合 以下でインストールできる
# yum -y install python3 # python3 --version Python 3.6.8 # pip3 --version pip 9.0.3 from /usr/lib/python3.6/site-packages (python 3.6)
CentOS7.7でPython3.6をインストールしてみよう - DENET 技術ブログ https://blog.denet.co.jp/centos77python36/ ■CentOS7.7より以前の場合 以下でインストールできる
# yum install -y https://repo.ius.io/ius-release-el7.rpm # yum search python36 # yum install -y python36u python36u-libs python36u-devel python36u-pip
https://centos7.iuscommunity.org/ius-release.rpm は使えなくなっているので https://repo.ius.io/ius-release-el7.rpm を指定する Python 3 を CentOS 7 に yum でインストールする手順 | https://weblabo.oscasierra.net/python3-centos7-yum-install/ iusの最新リンクが変更になったので注意 - Qiita https://qiita.com/seal_qiita/items/981a9284ecd44e54af96 ■CentOS7でPython3.7を使う場合 現状Python3.7は提供されておらず、どうしても使いたければソースコードからインストールする必要があるみたい Python3.7とDjango3.0をインストールする(CentOS) - Qiita https://qiita.com/shiranon/items/889b9d32bea0df4b89dc ■その他メモ 【Python入門】subprocessを使ってコマンドを実行しよう! | 侍エンジニア塾ブログ(Samurai Blog) https://www.sejuku.net/blog/51090 subprocessの使い方(Python3.6) - Qiita https://qiita.com/caprest/items/0245a16825789b0263ad
■matplotlib(グラフ描画)
プログラミング言語Pythonおよびその科学計算用ライブラリである「NumPy」のためのグラフ描画ライブラリ matplotlibのめっちゃまとめ - Qiita https://qiita.com/nkay/items/d1eb91e33b9d6469ef51 以下はグラフを画像に出力する例
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt x = [1, 2, 3, 4, 5] y = [10, 11, 23, 45, 21] plt.figure(figsize=(4, 4), dpi=72) plt.plot(x, y) #plt.bar(x, y) plt.savefig('output/graph.png')
以下のようにして実行すると、outputフォルダ内にグラフの画像が出力される
> python graph.py
CLIでプログラムを実行すると画面に画像を表示できずにエラーとなる 「matplotlib.use('Agg')」と指定することで、画面ではなく画像に保存できるようになる なお「Agg」は「Anti-Grain Geometry engine」のことで、データを画像に描画するライブラリ 「plt.figure(figsize=(4, 4), dpi=72)」 は 「横4インチ×縦4インチ、解像度72」 の意味 これらを変更することで、画像の縦横比率や解像度が変わる matplotlibで作成したプロットを画像ファイルに保存する方法 - Qiita https://qiita.com/koichifukushima/items/e63e642431db92178188 matplotlib.use('Agg')するときの注意点 - みんなのふぃじー(はてなブログ版) http://fijixfiji.hatenablog.com/entry/2016/12/17/001226 Matplotlib - Linux のCLIでmatplotlibを動かしたい|teratail https://teratail.com/questions/166605 matplotlibで出力される画像のサイズを変更する https://www.solima.net/python/archives/179
■数式の表現
※Pythonとは直接関係しないが、数式を表現するためにMathJaxを使用する MathJax | Beautiful math in all browsers. https://www.mathjax.org/ mathjax.pdf http://www.eng.niigata-u.ac.jp/~nomoto/download/mathjax.pdf MathJax<Javascript<木暮 http://www.kogures.com/hitoshi/javascript/mathjax/index.html Github Pages で数式を 〜 MathJax v3 設定のポイント - Qiita https://qiita.com/memakura/items/e4d2de379f98ad7be498 お勧めのMathJax設定方法(構成や日本語表示など) - いっしきまさひこBLOG https://blog.masahiko.info/entry/2020/03/09/203814 以下は数式の例 \[x = -\frac{b}{a} \] \[x = \frac{-b\pm\sqrt{b^{2}-4ac}}{2a} \] \[\sum_{k=1}^{n} a_{k} = a_{1} + a_{2} + \dots + a_{n} \] \[\int_{-\infty}^{\infty} e^{-x^{2}} \, dx = \sqrt{\pi} \] \[f'(x) = \lim_{\varDelta x \to 0} \frac{ f(x+\varDelta x) - f(x) }{\varDelta x} \] \[\left\{ \begin{array}{l} x+y&=8\\ 2x+4y&=26 \end{array} \right. \] \[\begin{pmatrix} 1 & 2 \\ 11 & 12 \end{pmatrix} \] \[\frac{df}{dx} = \lim_{\Delta x \to 0} \frac{f(x+ \Delta x)-f(x)}{\Delta x} \]
■数学の復習
以下の書籍の勉強メモ やさしく学ぶ 機械学習を理解するための数学のきほん アヤノ&ミオと一緒に学ぶ 機械学習の理論と数学、実装まで https://www.amazon.co.jp/gp/product/B075GSMZDS 以下も参考になりそうなのでメモ 150 分で学ぶ高校数学の基礎 - Speaker Deck https://speakerdeck.com/e869120/150-fen-dexue-bugao-xiao-shu-xue-noji-chu 予備校のノリで学ぶ「大学の数学・物理」 - YouTube https://www.youtube.com/@yobinori ■総和 以下のような、1から100までの足し算があるとする \[1 + 2 + 3 + 4 + … + 99 + 100 \] 総和の記号を使うと、以下のように表現できる \[\sum_{i=1}^{100} i \] 何個足せばいいのかわからない場合、「n」を使って以下のように表現できる \[\sum_{i=1}^{n} i \] 同様に、以下のような式があるとする (式中の「(1)」や「(2)」は「1乗」「2乗」ではなく、「1番目」「2番目」の意味) \[E(\theta) = \frac{1}{2}((y^{(1)} - f_{\theta}(x^{(1)}))^{2} + (y^{(2)} - f_{\theta}(x^{(2)}))^{2} + … + (y^{(n)} - f_{\theta}(x^{(n)}))^{2}) \] これは以下のように表現できる \[E(\theta) = \frac{1}{2} \sum_{i=1}^{n} (y^{(i)} - f_{\theta}(x^{(i)}))^{2} \] ■関数 関数とは、数と数の間の関係を表すもの。値の変換装置 例えば「ある数を入力すると、2倍して1足した数が出力される」という変換装置があるとする \[出力 = 2(入力)+1 \] この場合、関数として記述すると以下のようになる \[f(x) = 2x + 1 \] 実際に値を当てはめて計算すると、以下のようになる \[f(1) = 2 \cdot 1 + 1 = 3 \] \[f(2) = 2 \cdot 2 + 1 = 5 \] \[f(-2) = 2 \cdot -2 + 1 = -3 \] \[f(0) = 2 \cdot 0 + 1 = 1 \] また関数の入力値と出力値をグラフ化することで「入力と出力の関係」を表すことができ、結果として直線や曲線が現れる ■微分 微分とは、小さな変化を見ること 関数のある点における傾きを調べたり、瞬間の変化を捉えることができるものとされる xが少し変化したとき、その変化量をΔxで表す Δは「デルタ」と読み、「微小な変化」の意味で使われる記号 ※ギリシャ語で差分は「διαφορa(diafora)」といい、この頭文字の大文字に由来している(実際は最後の「a」の上にコンマがある)  英語で言う「difference」のこと xの微細な変化を「x が x+Δx に変化した」と表し、横軸をx、縦軸をf(x)とすると、微細な変化量は以下のようになる \[\frac{ f(x + \Delta x) - f(x) }{\Delta x} \] これを平均変化度と言って Δf/Δx と表し、「f(x)をxで微分する」という意味になる 曲線の微細な変化を考える場合、平均変化度は曲線の接線となる。この接戦の傾きが微細な変化と言える Δ の代わりに d を使って df/fx と書くこともある(Δ は今のアルファベットで言えば D にあたるため) また df(x)/dx と書くこともあり、 さらに省略してf'(x)と書くこともある つまり、以下はどれも意味は同じ \[\frac{\Delta f}{\Delta x} \] \[\frac{df}{dx} \] \[\frac{df(x)}{dx} \] \[f'(x) \] x^2(xの2乗)を微分すると2xとなる(具体的な計算は、後述の「微分の計算」を参照) これは特定の点の傾きが分かる状態のもの(「xが1のときの傾きは2、xが2のときの傾きは4」という意味であり、「y = 2x」のような方程式を表しているわけでは無い) 具体的には ・「x = 0」のときの傾きは「2 * 0」なので「0」となる。これは「xが1増えてもyは増減しない」ので平面の状態 ・「x = -1」のときの傾きは「2 * -1」なので「-2」となる。これは「xが1増えたときyが2減る」ので右上がりの状態 ・「x = 1」のときの傾きは「2 * 1」なので「2」となる。これは「xが1増えたときyが2増える」ので右下がりの状態 この内容を前提として、もう少し具体的な内容で記載する 例えば「40秒で120m走行した車の速度」を求める場合、通常以下のように求める \[\frac{120m}{40s} = 3m/s \] ただしこれは平均速度であって、常に秒速3mの速度が出ていたわけではない ある時点における瞬間の速度は、それぞれで異なる値を取る 瞬間の変化量を求めるために、関数を「f(x)」、微小な数を「h」と置くとする ※一般的に、微分の数式では微細な数を「h」で表される 「h」が使われるようになった理由は「無難な文字が選ばれた」など色々な説があるが、よく分かっていないらしい https://bonyari-dtp.hatenablog.com/entry/2021/03/08/200000 このとき、関数「f(x)」の点「x」での傾きは以下のような式で表すことができる(左辺は「f(x)の微分」の意味を表す) \[\frac{d}{dx}f(x) = \lim_{h \to 0} \frac{ f(x + h) - f(x) }{h} \] 文字になると難しく感じるが、具体的な数字を代入してみるとイメージが付きやすい 例えば「10.0秒と10.1秒という0.1秒の間に、40.0mから40.6mに移動した」の場合、「x = 10」「h = 0.1」なので、 \[\frac{ f(10 + 0.1) - f(10) }{0.1} = \frac{ 40.6 - 40}{ 0.1 } = 6 \] となり、「傾き6」が速度となる なお「h = 0.1」はあくまでも例なので、実際は「限りなく0に近い数」となる ■微分の計算 計算の練習として、以下を微分してみる \[f(x) = x^{2} \] 微細な変化量を表す式において、変化量を「限りなく0に近い数」にすると、以下のように表すことができる \[\frac{df}{dx} = \lim_{x \to 0} \frac{ f(x + \Delta x) - f(x) }{\Delta x} \] f(x) は x^2 なので、置き換えると以下のようになる \[\frac{df}{dx} = \lim_{x \to 0} \frac{ (x + \Delta x)^{2} - x^{2} }{\Delta x} \] 式を展開する \[\frac{df}{dx} = \lim_{x \to 0} \frac{ x^{2} + 2x\Delta x + (\Delta x)^{2} - x^{2} }{\Delta x} \] 式を整理する \[\frac{df}{dx} = \lim_{x \to 0} \frac{ 2x\Delta x + (\Delta x)^{2} }{\Delta x} \] \[\frac{df}{dx} = \lim_{x \to 0} (2x + \Delta x) \] Δxを限りなく0に近づけると、Δxが消えて以下のようになる \[\frac{df}{dx} = 2x \] これで計算は完了 つまりxの2乗を微分すると2xになる 上の計算を踏まえて、以下に微分の性質を3つ示す。覚えておくと式の整理を効率よく行える 1つめ \[f(x) = x^{n} \] という式があるとき、これを微分すると以下のようになる \[\frac{d}{dx}f(x) = nx^{n-1} \] 2つめ 複数の関数や定数は以下のように扱える \[\frac{d}{dx}(f(x) + g(x)) = \frac{d}{dx}f(x) + \frac{d}{dx}g(x) \] \[\frac{d}{dx}(af(x)) = a\frac{d}{dx}f(x) \] 3つめ 「x」に関係のない定数aの微分は0になる \[\frac{d}{dx}a = 0 \] 以下計算例 \[\frac{d}{dx}5 = 0 \] \[\frac{d}{dx}x = \frac{d}{dx}x^{1} = 1\cdot x^{0} = 1 \] \[\frac{d}{dx}x^{3} = 3x^{2} \] \[\frac{d}{dx}x^{-2} = -2x^{-3} \] \[\frac{d}{dx}10x^{4} = 10\frac{d}{dx}x^{4} = 10\cdot 4x^{3} = 40x^{3} \] \[\frac{d}{dx}(x^{5} + x^{6}) = \frac{d}{dx}x^{5} + \frac{d}{dx}x^{6} = 5x^{4} + 6x^{5} \] ■偏微分 上で紹介した関数「f(x)」は変数が「x」しかない1変数関数だが、変数が2つ以上ある多変数関数も存在する 機械学習の最適化問題はパラメータの数だけ変数があるので、目的関数が多変数関数となる \[g(x_{1}, x_{2}, … , x_{n}) = x_{1} + x_{2}^{2} … + x_{n}^{n} \] 多変数関数を微分する場合、微分する変数だけに注目し、他の変数はすべて定数として扱うことにして微分する このような微分方法を偏微分という 例えば \[h(x_{1}, x_{2}) = x_{1}^{2} + x_{2}^{3} \] このように変数が2つある場合、3次元空間へのプロットとなる これを例えば「x2 = 1」に固定してみると、以下のように「h」は「x1」だけの関数になる \[h(x_{1}, x_{2}) = x_{1}^{2} + 1^{3} \] これで単純な二次関数となる 定数を微分するとすべて0になるので、「h」を「x1」で偏微分すると以下の結果になる(左辺は「h(x1, x2)の偏微分」の意味を表す) \[\frac{\partial}{\partial x_{1}}h(x_{1}, x_{2}) = 2x_{1} \] 同じ要領で「x1 = 1」に固定してみると、以下のように「h」は「x2」だけの関数になる \[h(x_{1}, x_{2}) = 1^{2} + x_{2}^{3} \] 「h」を「x2」で偏微分すると以下のようになる \[\frac{\partial}{\partial x_{2}}h(x_{1}, x_{2}) = 3x_{2}^{2} \] このように、微分したい変数のみに注目して、他の変数をすべて定数として扱うことで、その変数での関数の傾きを知ることができる 今回は2つの変数を持つ関数での例を挙げたが、変数がどれだけ増えたとしても同じ考え方が適用できる ■合成関数 例えば、以下のような2つの関数「f(x)」と「g(x)」があるとする \[f(x) = 10 + x^{2} \] \[g(x) = 3 + x \] このとき、「x」に適当な値を代入すると、それに対応する値が出力される \[f(1) = 10 + 1^{2} = 11 \] \[f(2) = 10 + 2^{2} = 14 \] \[g(1) = 3 + 1 = 4 \] \[g(2) = 3 + 2 = 5 \] 「x」には関数を代入することもできる \[f(g(x)) = 10 + g(x)^{2} = 10 + (3 + x)^{2} \] \[g(f(x)) = 3 + f(x) = 3 + (10 + x^{2}) \] 「f(x)」の中に「g(x)」が、もしくは「g(x)」の中に「f(x)」が使われているが、このように関数が複数組み合わさったものを合成関数と呼ぶ 例えば合成関数「f(g(x))」を「x」で微分することを考えてみる 解りやすくするために、いったん以下のように変数に置き換えてみる \[u = g(x) \] \[y = f(u) \] こうすると、以下のように段階的に微分できる \[\frac{dy}{dx} = \frac{dy}{du} \cdot \frac{du}{dx} \] つまり「y」を「u」で微分し、「u」を「x」で微分したものを掛けることで計算できる 実際に微分をすると以下のようになる \[\frac{dy}{du} = \frac{d}{du} f(u) \] \[\frac{dy}{du} = \frac{d}{du} (10 + u^{2}) = 2u \] \[\frac{du}{dx} = \frac{d}{dx} g(x) \] \[\frac{du}{dx} = \frac{d}{dx} (3 + x) = 1 \] それぞれの結果を掛けると、微分結果を得ることができる \[\frac{dy}{dx} = \frac{dy}{du} \cdot \frac{du}{dx} \] \[\frac{dy}{dx} = 2u \cdot 1 \] \[\frac{dy}{dx} = 2g(x) \] \[\frac{dy}{dx} = 2(3 + x) \] ■加法定理 以下の関係が成り立つ sin(A + B) = sinA cosB + cosA sinB sin(A - B) = sinA cosB - cosA sinB cos(A + B) = cosA cosB - sinA sinB cos(A - B) = cosA cosB + sinA sinB 加法定理の証明は、以下のページが解りやすい 加法定理 https://w3e.kanazawa-it.ac.jp/math/category/sankakukansuu/kahouteiri/henkan-tex.cgi?target=/math/cat... ■ベクトルと行列 ベクトルとは数を縦に並べたもの、行列とは数を縦と横に並べたもので、それぞれ以下のような形をしている \[a = \begin{bmatrix} 3 \\ 9 \end{bmatrix} , A = \begin{bmatrix} 6 & 3 \\ 8 & 10 \end{bmatrix} \] 慣習的にベクトルは小文字、行列は大文字のアルファベットを用いる(加えて、太文字で表すことが多い) ここでベクトルaは縦に2つの数が並んでおり、これは2次元ベクトルとなる 行列Aは縦横に2つの数が並んでおり、2×2(2行2列)のサイズの行列となる ベクトルを「列が1つしかない行列」と考えると、aは「2×1の行列」とみなすことができる \[A = \begin{bmatrix} 6 & 3 \\ 8 & 10 \end{bmatrix} , B = \begin{bmatrix} 2 & 1 \\ 5 & -3 \end{bmatrix} \] 行列は、それぞれ和差積の演算を定義することができる 和と差は単純に各要素ごとに足し算と引き算をすればいい \[A + B = \begin{bmatrix} 6 + 2 & 3 + 1 \\ 8 + 5 & 10 - 3 \end{bmatrix} = \begin{bmatrix} 8 & 4 \\ 13 & 7 \end{bmatrix} \] \[A - B = \begin{bmatrix} 6 - 2 & 3 - 1 \\ 8 - 5 & 10 + 3 \end{bmatrix} = \begin{bmatrix} 4 & 2 \\ 3 & 13 \end{bmatrix} \] 積は少し特殊で、左側の行列の「行」と右側の行列の「列」の要素を順番に掛けてから、それらを足し合わせる 行列同士の掛け算をする場合、左側にある行列の列数と、右側にある行列の行数が一致している必要がある \[AB = \begin{bmatrix} 6 * 2 + 3 * 5 & 6 * 1 + 3 * -3 \\ 8 * 2 + 10 * 5 & 8 * 1 + 10 * -3 \end{bmatrix} = \begin{bmatrix} 27 & -3 \\ 66 & -22 \end{bmatrix} \] また、以下のように行と列を入れ替える操作を転置と呼ぶ \[a = \begin{bmatrix} 2 \\ 5 \\ 2 \end{bmatrix} , a^{T} = \begin{bmatrix} 2 & 5 & 2 \end{bmatrix} \] ベクトル同士を掛ける場合、以下のように片方を転地してから積を計算することがある これはベクトル同士の内積を求めることと同じ \[a = \begin{bmatrix} 2 \\ 5 \\ 2 \end{bmatrix} , a^{T} = \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \] \[a^{T}b = \begin{bmatrix} 2 & 5 & 2 \end{bmatrix} \begin{bmatrix} 1 \\ 2 \\ 3 \end{bmatrix} \] \[a^{T}b = [ 2 * 1 + 5 * 2 + 2 * 3 ] \] \[a^{T}b = [ 18 ] \] ■ベクトルと内積 ※整理中。考え方や計算などに間違いがある可能性があるので注意 以下で具体例をもとに、ベクトルの性質を確かめる 2つの2次元ベクトルがあるとする \[a = (3, 1), b = (2, 3) \] aにおいて、斜辺の長さは \[\sqrt{3^{2} + 1^{2}} = \sqrt{10} (近似値は3.16227程度) \] となる またbにおいて、斜辺の長さは \[\sqrt{2^{2} + 3^{2}} = \sqrt{13} (近似値は3.60555程度) \] となる cosをもとに、ベクトルaとx軸の成す角度を求めると、 \[3 / 3.16227 = 0.94868... \] となり、このときの角度は18.43554...度となる(アークコサインでラジアンを求められるので、それを角度に変換する) またcosをもとに、ベクトルbとx軸の成す角度を求めると、 \[2 / 3.60555 = 0.55470... \] となり、このときの角度は56.30994...度となる(アークコサインでラジアンを求められるので、それを角度に変換する) よってベクトルaとbの成す角度は、 \[56.30994 - 18.43554 = 37.8744 \] となり、約38度となる これをもとに、公式を使ってベクトルaとbの内積を求めると \[a・b = |a|・|b|・cos\theta = 3.16227・3.60555・cos(37.8744) = 3.16227・3.60555・cos(38) = 3.16227 * 3.60555 * 0.78935 = 8.99994 \] となり、ベクトルaとbの内積は9となる 続いて、座標からも内積を求めてみる \[a = \begin{bmatrix} 3 & 1 \end{bmatrix}, b = \begin{bmatrix} 2 & 3 \end{bmatrix} \] 一方を転置して計算する \[a b^{T} = \begin{bmatrix} 3 & 1 \end{bmatrix} \begin{bmatrix} 2 \\ 3 \end{bmatrix} = \begin{bmatrix} 3 * 2 + 1 * 3 \end{bmatrix} = \begin{bmatrix} 9 \end{bmatrix} \] この場合も、値が9になることを確認できる つまりベクトル同士の掛け算において、片方を転置してから積を計算することで、ベクトル同士の内積を取ることができる 続いて、内積が何を求めているかを改めて考える まずはbの地点からベクトルaに対して垂直に線を引いた時の、その交点と原点の距離を求める 距離をxと置くと、以下のように求めることができる \[cos(37.8744) = x / 3.60555 \] \[0.78935 = x / 3.60555 \] \[x = 0.78935 * 3.60555 = 2.84604 \] 求められたxに、aの長さをかけたものが内積となる \[2.84604 * 3.16227 = 8.99994 \] この場合も、値が9になることを確認できる つまり内積とは「ベクトルbの終点からベクトルaに対して垂直に線を引いた時の、その交点と原点の距離」にベクトルaの長さをかけたもの ベクトルの内積というのは何を求めているのでしょうか。 - 内積を使って何が求ま... - Yahoo!知恵袋 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q14183393379 【数学】「内積」の意味をグラフィカルに理解すると色々見えてくる その1 #Python - Qiita https://qiita.com/kenmatsu4/items/a144047c1b49aa8c7eb0 以下はベクトルを図示するプログラム ベクトルaの長さは約3.16、ベクトルbの長さは約2.85 3.16×2.85=9.006 で、おおよそ9になる
import numpy as np import matplotlib matplotlib.use('Agg') # 描画バックエンドを 'Agg' に設定(画像ファイルとして保存するため) import matplotlib.pyplot as plt # ベクトルを Numpy 配列として定義 a = np.array([3, 1]) b = np.array([2, 3]) # ベクトル a と b の内積を計算 dot_product = np.dot(a, b) print(dot_product) # 9 # グラフのサイズを設定 plt.figure(figsize=(8, 6)) # ベクトル a と b をプロット plt.quiver(0, 0, a[0], a[1], angles='xy', scale_units='xy', scale=1, color='r', label=f'a = {a}') plt.quiver(0, 0, b[0], b[1], angles='xy', scale_units='xy', scale=1, color='b', label=f'b = {b}') # 内積のハイライト表示 # 簡単のために、ベクトル b をベクトル a に射影する # 射影 (dot_product_b_on_a) は a の縮小版 projection_length = dot_product / np.linalg.norm(a) ** 2 # a に対する b の射影の長さを計算 print(projection_length) # 0.8999999999999998 dot_product_b_on_a = projection_length * a # 射影ベクトルを計算 print(dot_product_b_on_a) # [2.7 0.9] plt.quiver(0, 0, dot_product_b_on_a[0], dot_product_b_on_a[1], angles='xy', scale_units='xy', scale=1, color='g', label='Projection of b on a') # ベクトル a に垂直な線を引く plt.plot([b[0], dot_product_b_on_a[0]], [b[1], dot_product_b_on_a[1]], color='purple', linestyle='--', label='Line perpendicular to vector a') normalized_a = a / np.linalg.norm(a) scaled_a = normalized_a * 9 plt.quiver(0, 0, scaled_a[0], scaled_a[1], angles='xy', scale_units='xy', scale=1, color='pink', label='Scaled a (Length 9)') # グラフの軸設定 plt.xlim(0, 10) plt.ylim(0, 10) plt.xlabel('X axis') # X軸ラベル plt.ylabel('Y axis') # Y軸ラベル plt.axhline(0, color='black', linewidth=0.5) # X軸 plt.axvline(0, color='black', linewidth=0.5) # Y軸 plt.grid(which='major', color='gray', linestyle='-', linewidth=0.5) # 主目盛線 plt.minorticks_on() plt.grid(which='minor', color='gray', linestyle=':', linewidth=0.5) # 補助目盛線 plt.legend() # 凡例表示 # グラフを画像として保存 plt.savefig('graph.png')
さらに別の側面から考察 行列との関係を考えてみる 以下のベクトルaとbがあるとする a = (3, 1), b = (2, 3) ベクトルaとbの内積は以下のように求められる 3*2 + 1*3 = 9 ベクトルaとbを2行2列の行列とみなし、そのまま行列の積を求めると以下のようになる
a * b = a |3 1| * |2 3| = |(3*2 + 1*0) (3*3 + 1*0)| = |6 9| |0 0| |0 0| |(0*2 + 0*0) (0*3 + 0*0)| |0 0|
bを転置して計算すると以下のようになる
a * b = a |3 1| * |2 0| = |(3*2 + 1*3) (3*0 + 1*0)| = |9 0| |0 0| |3 0| |(0*2 + 0*3) (0*0 + 0*0)| |0 0|
転置して計算することで9(内積の値)になることが確認できる (スカラーと行列は別ではあるが、1つの要素以外は0なので、9と言えなくはない…と思う) さらに別の側面から考察 少し極端な値のベクトルで考えてみる 以下ベクトルaとbの場合、 a = (5, 1), b = (0.1, 50) 内積は以下のようになる 5*0.1 + 1*50 = 0.5 + 50 = 50.5 コサインを使って求める場合、内積は以下のようになる ・ベクトルaの長さは、三平方の定理より5.1(5.09901951359)となる ・ベクトルbの長さは、三平方の定理より50(50.0000999999)となる ・コサインの値は 50.5 / (5.10 * 50.00) なので0.198(0.19803921568)となる ・よってコサインを使用した内積は 5.1 * 50 * 0.198 で、約50.5となる つまり、転置して計算した場合と同じ値を求められていることが判る 続いて「a・b = ab cos(θ)」を数学的に証明する 2つの2次元実ベクトルA, Bの長さをそれぞれa, bとし、それらの交点をθとする また、ベクトルAの角度をΦとする このとき、ベクトルA, Bは以下のように表すことができる A = (a1, a2) = (a cosΦ, a sinΦ) B = (b1, b2) = (b cos(θ+Φ), b sin(θ+Φ)) 一方を転置して積を求める。つまり内積を求めると以下のようになる a cosΦ・b cos(θ+Φ) + a sinΦ・b sin(θ+Φ) 共通要素のabをまとめると以下のようになる ab { cosΦ・cos(θ+Φ) + sinΦ・sin(θ+Φ) } 三角関数の加法定理によると、以下の関係が成り立つ 1. sin(A + B) = sinA cosB + cosA sinB 2. sin(A - B) = sinA cosB - cosA sinB 3. cos(A + B) = cosA cosB - sinA sinB 4. cos(A - B) = cosA cosB + sinA sinB この定理のうち、4を用いて式を変形する ab { cos(Φ - (θ+Φ)) } = ab { cos(Φ - θ - Φ) } = ab { cos(-θ) } コサインカーブをもとにすると、「cos(-θ) = cos(θ)」となる よって、最終的に以下のように変形できる = ab cos(θ) これにより、「一方を転置して積を求める。つまり内積を求める」という計算は、以下と等価となる ab cos(θ) これで以下の関係が求められた a・b = ab cos(θ) 内積(ベクトルの内積)とは?定義・公式・計算例・意味・英語訳【線形代数】 | k-san.link https://k-san.link/inner-product/ 以下メモ 行列の積(掛け算)を分かりやすく解説! - 「なんとなくわかる」大学の数学・物理・情報 https://www.krrk0.com/matrix-multiplication/ 行列の演算(和・定数倍・積)の定義と性質をわかりやすく丁寧に | 数学の景色 https://mathlandscape.com/matrix-cal/ 行列の掛け算について、その「意味」を教えてください。 - まず、(1行2... - Yahoo!知恵袋 https://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q11256265466 転置行列の意味が少しわかりました | 進化するガラクタ https://evolvingbook.com/2019/01/28/transposed-matrix/ 転置行列の意味・重要な7つの性質と証明 | 高校数学の美しい物語 https://manabitimes.jp/math/1046 「ルート2」を求める場合のJavaScript Math.sqrt(2) = 1.41421... 「cos(60)は0.5」を求める場合のJavaScript Math.cos(60 * Math.PI / 180) = 0.5 「0.5はcos(60)」を求める場合のJavaScript 180 / Math.PI * Math.acos(0.5) = 60 ■法線ベクトル 法線ベクトルとは、ある直接に垂直なベクトルのこと 例えば \[ax + by + c = 0 \] という直線があるとき、その法線ベクトルpは \[p = (a, b) \] となる ■指数・対数 指数とは、数の右上に記載して「その数を何乗するか」を表すもの 例えば以下のようなもの \[x^{3} = x \cdot x \cdot x \] \[x^{-4} = \frac{1}{x^{4}} = \frac{1}{x \cdot x \cdot x \cdot x} \] 指数は以下のような性質を持っており、これらは指数法則と呼ばれている \[a^{b} \cdot a^{c} = a^{b + c} \] \[\frac{a^{b}}{a^{c}} = a^{b - c} \] \[(a^{b})^{c} = a^{b + c} \] 上のように、指数は通常普通の数が使われるが、指数部が変数になっているものがある こようなものは指数関数と呼ばれ、以下のような関数の形をしている(「a > 1」の場合) \[y = a^{x} \] このような指数関数の逆関数として対数関数というものがあり、それを log を使って以下のように表す \[y = {log_{a}}x \] 逆関数とは、ある関数の「x」と「y」を入れ替えた関数のこと 逆関数のグラフの形は、もとの関数のグラフを時計回りに90度回転させて、左右方向に反転させた形になっている これは「a を y 乗すると x になる」と考えることができる また「a」の部分を「底」と呼ぶが、特にネイピア数(「e」という記号で表される 2.7182… という定数)を底としたものを自然対数と言い、 自然対数の場合は底を省略して単純に log または ln を使って以下のように表すことが多くある \[y = {log_{e}}x = log \ x = ln \ x \] この対数関数は以下のような性質を持っている \[log \ e = 1 \] \[log \ ab = log a + log b \] \[log \frac{a}{b} = log \ a - log \ b \] \[log \ a^{b} = b \ log \ a \] また、対数関数の微分もよく使われる 底を「a」とする対数関数の微分は以下のようになる \[\frac{d}{dx}log_{a}x = \frac{1}{x \ log \ a} \] 特に底が「e」の自然対数については、「log e = 1」という性質から、微分結果も以下のように簡潔なものになる \[\frac{d}{dx}log_{e}x = \frac{1}{x} \] ■代表値 平均値 … 変量の総和を個数で割ったもの。外れ値の影響を受けやすい 中央値 … 母集団の分布の中央にくる値。平均値に比べて外れ値の影響を受けにくい 最頻値 … 最も多い度数(頻度)を示す値。外れ値の影響はまず受けない ■標準偏差 標準偏差の意味と求め方 | AVILEN AI Trend https://ai-trend.jp/basic-study/basic/standard-deviation/ 統計学における分散とは?不偏分散との違いも! 例題でわかりやすく解説 | AVILEN AI Trend https://ai-trend.jp/basic-study/basic/variance/ 以下のデータがあるとする 名前: 得点 Aさん: 90点 Bさん: 80点 Cさん: 40点 Dさん: 60点 Eさん: 90点 平均は以下のように求められる \[(90 + 80 + 40 + 60 + 90) / 5 \\ = 72 \] 偏差(平均からの隔たりの大きさ)は以下のように求められる Aさん: 90 - 72 = 18 Bさん: 80 - 72 = 8 Cさん: 40 - 72 = -32 Dさん: 60 - 72 = -12 Eさん: 90 - 72 = 18 分散(データのばらつき具合)は以下のように求められる。偏差を2乗(マイナスの値を無くすため)し、すべてを足し合わせた値の平均を出している 偏差は個々の値を見るが、偏差ではデータ全体のばらつき具体を見ることができる 分散の値が大きければ、ばらつき具合が大きいということになる \[((90 - 72)^2 + (80 - 72)^2 + (40 - 72)^2 + (60 - 72)^2 + (90 - 72)^2) / 5 \\ = ((18)^2 + (8)^2 + (-32)^2 + (-12)^2 + (18)^2) / 5 \\ = (324 + 64 + 1024 + 144 + 324) / 5 \\ = 376 \] 分散は偏差を2乗した値の平均を取っているため、その数値はもとのデータとは単位が異なる そこで、平方根で本来のデータと単位を揃える この値を標準偏差と呼ぶ \[√376 \\ =19.3907194297 \] これで「平均点±19.39点の中に大体の人がいる」ということを求めらえる 正規分布(平均値と最頻値・中央値が一致し、それを軸として左右対称となっている確率分布)の場合、平均値±標準偏差中に観測データが含まれる確率は68.3%になる これが±標準偏差の2倍、3倍になるとさらに確率は上がる - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 範囲 範囲内に指定の数値が現れる確率 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 平均値±標準偏差 68.3% 平均値±(標準偏差×2) 95.4% 平均値±(標準偏差×3) 99.7% - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 各値について、平均値との差を標準偏差で割ると「平均が0、標準偏差が1」のデータになる(つまり「0±1の中に大体(7割ほど)のデータが存在する」となる) これを標準化と呼ぶ(X軸のスケールのみが小さくなる。機械学習の際、データを標準化して扱うことで処理が早くなる) Aさん: (90 - 72) / 19.39 = 0.93 Bさん: (80 - 72) / 19.39 = 0.41 Cさん: (40 - 72) / 19.39 = -1.65 Dさん: (60 - 72) / 19.39 = -0.62 Eさん: (90 - 72) / 19.39 = 0.93 ※平均は「0.93 + 0.41 - 1.65 - 0.62 + 0.93 = 0」となる 分散は「((0.93 - 0)^2 + (0.41 - 0)^2 + (-1.65 - 0)^2 + (-0.62 - 0)^2 + (0.93 - 0)^2) / 5 = 1.00096 = おおよそ1」となる 標準偏差は「1」となる(1の平方根は1) 標準化については以下も参照 機械学習でなぜ正規化が必要なのか - Qiita https://qiita.com/yShig/items/dbeb98598abcc98e1a57 【統計・機械学習】標準化(Standardization)と正規化(Normalization)とは?初心者向けにわかりやすく解説 | AI Academy Media https://aiacademy.jp/media/?p=1147 正規化・標準化を徹底解説 (Python 前処理 サンプルコード付き) https://www.codexa.net/normalization-python/ 【機械学習入門】正規化と標準化の特徴量のスケーリングの使い分け方法 https://www.hobby-happymylife.com/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0/no... 標準化した値を10倍して50を加えると、「平均が50、標準偏差が10」のデータになる。この値を偏差値と呼ぶ つまり、偏差値は以下のように求める ((得点 - 平均点) / 標準偏差) * 10 + 50 偏差値が50ということは、集団での平均値と一致するということになる 偏差値が60ということは、平均値±標準偏差なので、集団の中で上から約19.85%((100 - 68.3) / 2)のところに位置しているということになる 偏差値が70ということは、平均値±(標準偏差×2)なので、集団の中で上から約2.3%((100 - 95.4) / 2)のところに位置しているということになる 今回の場合、80点の偏差値は以下のようになる \[((80 - 72) / 19.39) * 10 + 50 \\ = 54.1258380609 \] 今回の場合、90点の偏差値は以下のようになる \[((90 - 72) / 19.39) * 10 + 50 \\ = 59.2831356369 \] ■標準偏差(実際の得点に近いデータで確認) 疑似偏差値計算 https://shade-search.com/sts/fsw/hensachi/test.cgi 作成された、以下の得点データで試す
0 0 6 8 10 10 11 13 15 17 18 18 18 20 21 21 21 22 22 22 23 23 23 24 24 24 25 25 25 25 26 26 26 26 26 27 27 27 27 27 28 28 28 29 30 31 31 31 31 32 32 32 32 32 32 33 33 33 34 34 34 34 34 34 35 35 35 35 36 36 36 36 36 36 37 37 37 38 38 38 38 38 39 39 39 39 40 40 40 41 41 41 41 41 41 41 41 41 42 42 42 42 42 42 43 43 43 43 43 43 43 43 44 44 44 44 44 44 45 45 46 46 46 46 46 46 46 46 46 46 47 47 47 47 47 47 47 47 47 47 47 47 48 48 48 49 49 49 49 49 50 50 50 50 50 50 50 50 51 51 51 51 51 51 51 52 52 52 52 52 52 53 53 53 53 53 54 54 54 54 54 54 54 55 55 55 55 55 55 55 55 56 56 56 56 56 56 57 57 58 58 58 58 59 59 59 59 59 59 59 60 60 60 61 61 62 62 62 62 62 63 63 63 63 63 63 63 64 64 64 64 64 65 66 66 66 66 66 67 67 67 67 67 67 67 68 68 68 69 69 69 69 69 69 70 70 70 70 70 71 71 71 72 72 73 73 74 74 74 75 75 77 77 77 77 77 78 79 79 79 79 79 79 79 80 80 81 82 82 82 83 83 84 85 87 87 90 91 96 96
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 得点エリア 人数 得点エリアの平均点 得点エリアの合計点 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 0〜9 4 4.5 18.0 10〜19 9 14.5 130.5 20〜29 31 24.5 759.5 30〜39 42 34.5 1449.0 40〜49 64 44.5 2848.0 50〜59 60 54.5 3270.0 60〜69 44 64.5 2838.0 70〜79 30 74.5 2235.0 80〜89 12 84.5 1014.0 90〜100 4 95.0 380.0 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 参考までに、得点エリアごとの人数をグラフにプロットするには以下のようになる
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt x = [ 0, 10, 20, 30, 40, 50, 60, 70, 80, 90] y = [ 4, 9, 31, 42, 64, 60, 44, 30, 12, 4] plt.figure(figsize=(4, 4), dpi=72) plt.plot(x, y) plt.savefig('output/graph.png')
偏差値は以下のようになる 得点合計 ... 14938 得点の平均 ... 49.7933333333333 標準偏差 ... 18.5568663542337 0点の偏差値 = (( 0 - 49.79) / 18.56) * 10 + 50 = 23.1734913793 24点の偏差値 = (( 24 - 49.79) / 18.56) * 10 + 50 = 36.1045258621 70点の偏差値 = (( 70 - 49.79) / 18.56) * 10 + 50 = 60.8890086207 96点の偏差値 = (( 96 - 49.79) / 18.56) * 10 + 50 = 74.8976293103 100点の偏差値 = ((100 - 49.79) / 18.56) * 10 + 50 = 77.0528017241 以下はサンプリングしたデータから標準偏差と偏差値を計算した場合 得点合計 = 14942 得点の平均=49.8066666666667 標準偏差 = 18.4979986905491 (疑似平均使用) 24点の偏差値 = 36.0489412404101 (疑似平均使用) 以下は全体の平均値のみ、オリジナルデータから得た場合 標準偏差 = 18.4980034958731 (オリジナルの平均使用) 24点の偏差値 = 36.0561528496371 (オリジナルの平均使用) 標準偏差の誤差 abs(18.4979986905491 - 18.5568663542337) = 0.0588676636845697 偏差値の誤差 abs(36.0489412404101 - 36.1003830921869) = 0.0514418517768078 ■最急降下法 最急降下法(さいきゅうこうかほう)もしくは勾配降下法(こうばいこうかほう)と呼ばれる ※整理中。以下を参考にメモを残しておきたい やる夫で学ぶ機械学習 - 単回帰問題 - - けんごのお屋敷 http://tkengo.github.io/blog/2016/01/04/yaruo-machine-learning2/ 最急降下法の概要 - Qiita https://qiita.com/Takayoshi_Makabe/items/ee467313c38b1879c097 \[g(x) = (x - 1)^{2} \] という二次関数のグラフがあるとき、最小値は x = 1 のときの g(1) = 0 である この式は単純なので簡単に求められるが、複雑な式の場合には以下のように求める方法がある まず、二次関数の増減表を求める 増減表を求めるためには関数を微分する \[\frac{d}{dx}g(x) = 2x - 2 \] 増減表は以下のようになる
x の範囲 … x<1 x=1 x>1 g(x) を微分したときの符号 … - 0 + g(x) の増減 … 減少 増加
例えば x = 3 からスタートして g(x) の値を小さくするためには、x を少しずつ左にずらしていけばいい(増減表から x > 1 の時は、グラフが左下がりになっているのがわかるため) x = -3 からだと、逆に右にずらしていけばいい つまり導関数の符号によって x をずらす方向が変わる(マイナスなら減少だから右にずらし、プラスなら増加だから左にずらす) このように微分して導関数を求めて、その符号によって x の位置をずらす、別の言い方をすると x を更新していくことで、最小値を求める x の更新を式にすると以下のようになる \[x := x - \eta \frac{d}{dx} g(x) \] これは「x を新しい x で定義していく」ということになり、つまりは計算で求めた x を次の計算に使うことになる この手法を最急降下法や勾配降下法という 微分式の前に付いている記号は「イータ」と読み、学習率と呼ばれる正の定数 学習率が小さければ、g(x) の最小値にたどり着くまでに何度も x を更新する必要があって時間がかかってしまう 逆に学習率を大きくすれば、速く g(x) の最小値にたどり着ける可能性があるが、x が定まらず発散してしまう可能性もある 具体的には g(x) の微分は 2x - 2 だから、x を更新する式は \[x := x - \eta (2x - 2) \] となる イータを1として x = 3 から始めて計算すると x := 3 - 1(2 * 3 - 2) = 3 - 4 = -1 x := -1 - 1(2 * -1 - 2) = -1 + 4 = 3 x := 3 - 1(2 * 3 - 2) = 3 - 4 = -1 となり、ループして求めることができない (1つ目の式で求められた「-1」を2つ目の式で使う。以降も同じように計算している) これが発散している状態 イータを0.1として計算すると x: = 3 - 0.1(2 * 3 - 2) = 3 - 0.4 = 2.6 x: = 2.6 - 0.1(2 * 2.6 - 2) = 2.6 - 0.3 = 2.3 x: = 2.3 - 0.1(2 * 2.3 - 2) = 2.3 - 0.2 = 2.1 x: = 2.1 - 0.1(2 * 2.1 - 2) = 2.1 - 0.2 = 1.9 となり、時間はかかるが正解には近づくことができている (1つ目の式で求められた「2.6」を2つ目の式で使う。以降も同じように計算している)
■数学とグラフ
[python]算数・数学?~関数と方程式~ - Qiita https://qiita.com/hiroyuki_mrp/items/d4194a6de594c2e0f56f ■基本のグラフ \[y = x \]
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt x = [0, 1, 2, 3, 4, 5, 6, 7, 8] # Xの範囲 y = x # Yの範囲 plt.figure(figsize=(8, 8), dpi=72) plt.axis('equal') # 縦横のメモリの大きさを揃える plt.xlim(-10, 10) # X軸は-10〜10の範囲を表示する plt.ylim(-10, 10) # Y軸は-10〜10の範囲を表示する plt.xticks(np.arange(-10, 10, 1)) # X軸のグリッド間隔を-10〜10の範囲で1刻みに設定する plt.yticks(np.arange(-10, 10, 1)) # Y軸のグリッド間隔を-10〜10の範囲で1刻みに設定する plt.grid(color='0.8') # 薄いグレーでグリッドを表示する plt.plot(x, y) plt.savefig('graph.png')
■1次関数 \[y = 2x + 3 \]
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt x = np.arange(-100, 100) y = 2 * x + 3 # 1次関数「y = 2x + 3」のグラフを描画 plt.figure(figsize=(8, 8), dpi=72) plt.axis('equal') plt.xlim(-10, 10) plt.ylim(-10, 10) plt.xticks(np.arange(-10, 10, 1)) plt.yticks(np.arange(-10, 10, 1)) plt.grid(color='0.8') plt.plot(x, y) plt.savefig('graph.png')
■2次関数 \[y = x^{2} + 1 \]
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt x = np.arange(-100, 100, 0.1) # 0.1刻みにしてグラフをなめらかにする y = x ** 2 + 1 # 2次関数「y = x^2 + 1」のグラフを描画 plt.figure(figsize=(8, 8), dpi=72) plt.axis('equal') plt.xlim(-10, 10) plt.ylim(-10, 10) plt.xticks(np.arange(-10, 10, 1)) plt.yticks(np.arange(-10, 10, 1)) plt.grid(color='0.8') plt.plot(x, y) plt.savefig('graph.png')
■3次関数 \[y = x^{3} + 4 \]
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt x = np.arange(-100, 100, 0.1) # 0.1刻みにしてグラフをなめらかにする y = x ** 3 + 4 # 3次関数「y = x^3 + 4」のグラフを描画 plt.figure(figsize=(8, 8), dpi=72) plt.axis('equal') plt.xlim(-10, 10) plt.ylim(-10, 10) plt.xticks(np.arange(-10, 10, 1)) plt.yticks(np.arange(-10, 10, 1)) plt.grid(color='0.8') plt.plot(x, y) plt.savefig('graph.png')
■連立方程式 2点 (3, 6) と (4, 12) を通る直線を求める ・「x = 3」のときに「y = 6」となる ・「x = 4」のときに「y = 12」となる なので、1次関数「y = ax + b」に当てはめて 6 = 3a + b 12 = 4a + b となる この連立方程式を解けばいい 以下はプログラムを使わずに解く例 b = 6 - 3a 12 = 4a + 6 - 3a a = 6 6 = 3 * 6 + b b = -12 y = 6x - 12 以下はプログラムを使って解く例 実行して 「ModuleNotFoundError: No module named 'sympy'」 のエラーになる場合、sympyをインストールする必要がある $ pip3.7 install sympy
from sympy import Symbol, solve a = Symbol('a') # 変数を定義(「a」を記号として扱う。通常int型とstr型は一緒に計算できない) b = Symbol('b') # 変数を定義(「b」を記号として扱う。通常int型とstr型は一緒に計算できない) exp1 = 3 * a + b - 6 exp2 = 4 * a + b - 12 ans = solve((exp1, exp2)) # 方程式の解を取得 print(ans) # 解を表示
以下は実行結果 $ python3.7 math.py {a: 6, b: -12}
■回帰による予測
以下の書籍の勉強メモ 最小二乗法を使って一次関数の式を求める やさしく学ぶ 機械学習を理解するための数学のきほん アヤノ&ミオと一緒に学ぶ 機械学習の理論と数学、実装まで https://www.amazon.co.jp/gp/product/B075GSMZDS この書籍のもとになったページが以下にある やる夫で学ぶ機械学習シリーズ - けんごのお屋敷 http://tkengo.github.io/blog/2016/06/06/yaruo-machine-learning0/ ■回帰の実践 click.csv
x,y 235,591 216,539 148,413 35,310 85,308 204,519 49,325 25,332 173,498 191,498 134,392 99,334 117,385 112,387 162,425 272,659 159,400 159,427 59,319 198,522
以下でグラフに配置して確認できる
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 学習データを読み込む train = np.loadtxt('click.csv', delimiter=',', dtype='int', skiprows=1) train_x = train[:,0] train_y = train[:,1] # プロット plt.plot(train_x, train_y, 'o') plt.savefig('graph.png')
以下で一次関数の学習データをプロットできる
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 学習データを読み込む train = np.loadtxt('click.csv', delimiter=',', dtype='int', skiprows=1) train_x = train[:,0] train_y = train[:,1] # 標準化を行う(データのスケールを揃えて学習が効果的に行われるようにする) mu = train_x.mean() sigma = train_x.std() def standardize(x): return (x - mu) / sigma train_z = standardize(train_x) # 更新用パラメータを初期化(初期値をランダムに設定する) theta0 = np.random.rand() theta1 = np.random.rand() # 予測関数(一次関数) def f(x): return theta0 + theta1 * x # 目的関数(二次関数。実際の値と予測値の二乗誤差の和の半分で、誤差関数とも呼ぶ) def E(x, y): return 0.5 * np.sum((y - f(x)) ** 2) # 学習率 ETA = 0.001 # 誤差の差分 diff = 1 # 更新回数 count = 0 # 誤差の差分が0.01以下になるまでパラメータ更新を繰り返す error = E(train_z, train_y) while diff > 0.01: # 更新結果を一時変数に保存 tmp_theta0 = theta0 - ETA * np.sum((f(train_z) - train_y)) tmp_theta1 = theta1 - ETA * np.sum((f(train_z) - train_y) * train_z) # パラメータを更新 theta0 = tmp_theta0 theta1 = tmp_theta1 # 前回の誤差との差分を計算 current_error = E(train_z, train_y) diff = error - current_error error = current_error # ログの出力 count += 1 log = '{}回目: theta0 = {:.3f}, theta1 = {:.3f}, 差分 = {:.4f}' print(log.format(count, theta0, theta1, diff)) # プロットして確認 x = np.linspace(-3, 3, 100) plt.plot(train_z, train_y, 'o') plt.plot(x, f(x)) plt.savefig('graph.png')
実行の際、以下のようなログが出力される
$ python3.7 regression1_linear.py 1回目: theta0 = 9.411, theta1 = 2.790, 差分 = 76035.5263 2回目: theta0 = 17.806, theta1 = 4.604, 差分 = 73024.5195 3回目: theta0 = 26.033, theta1 = 6.381, 差分 = 70132.7485 4回目: theta0 = 34.095, theta1 = 8.123, 差分 = 67355.4917 5回目: theta0 = 41.996, theta1 = 9.830, 差分 = 64688.2142 6回目: theta0 = 49.739, theta1 = 11.503, 差分 = 62126.5609 〜中略〜 389回目: theta0 = 428.985, theta1 = 93.443, 差分 = 0.0118 390回目: theta0 = 428.988, theta1 = 93.444, 差分 = 0.0113 391回目: theta0 = 428.991, theta1 = 93.444, 差分 = 0.0109 392回目: theta0 = 428.994, theta1 = 93.445, 差分 = 0.0105 393回目: theta0 = 428.997, theta1 = 93.446, 差分 = 0.0101 394回目: theta0 = 429.000, theta1 = 93.446, 差分 = 0.0097
「theta0 = 429.000」「theta1 = 93.446」と求められている これは予測関数「theta0 + theta1 * x」にある「theta0」と「theta1」の値を求めている つまり、予測関数は「429.000 + 93.446 * x」ということ プログラムの最後に以下を追加すると
print(f(standardize(100))) print(f(standardize(200))) print(f(standardize(300)))
実行時に以下も表示される つまり、個別に予測を表示できる
370.9672809730788 510.4700574222163 649.9728338713539
以下は詳細解説付きのコード(解説の都合上、一部プログラムも変更している)
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # データを読み込む(「click.csv」を「,」区切りの整数として読み込む。1行目は無視) train = np.loadtxt('click.csv', delimiter=',', dtype='int', skiprows=1) print(train) # [[235 591] # [216 539] # [148 413] # [ 35 310] # [ 85 308] # [204 519] # [ 49 325] # [ 25 332] # [173 498] # [191 498] # [134 392] # [ 99 334] # [117 385] # [112 387] # [162 425] # [272 659] # [159 400] # [159 427] # [ 59 319] # [198 522]] # 各0番目の要素(X座標)を抽出 train_x = train[:,0] print(train_x) # [235 216 148 35 85 204 49 25 173 191 134 99 117 112 162 272 159 159 59 198] # 各1番目の要素(Y座標)を抽出 train_y = train[:,1] print(train_y) # [591 539 413 310 308 519 325 332 498 498 392 334 385 387 425 659 400 427 319 522] # train_xの平均値を取得 mu = train_x.mean() print(mu) # 141.6 # train_xの標準偏差を取得 sigma = train_x.std() print(sigma) # 66.98537153737374 # 標準化(平均値との差を標準偏差で割って「平均が0、標準偏差が1」のデータにする)を行うための関数を定義 def standardize(x): return (x - mu) / sigma # 引数で渡されたxはnumpyの値なので、各値に対して計算が行われる # 標準化を行う(X軸のスケールを小さくする。標準化して扱うことで処理が早くなる) train_z = standardize(train_x) print(train_z) # [ 1.39433428 1.11069026 0.09554325 -1.59139223 -0.8449606 0.93154667 # -1.38239138 -1.74067856 0.46875906 0.73747445 -0.11345761 -0.63595975 # -0.36724436 -0.44188752 0.3045441 1.94669369 0.25975821 0.25975821 # -1.23310505 0.84197488] # 更新用パラメータを初期化(0〜1のランダムな数値を初期値に設定する) #theta0 = np.random.rand() #theta1 = np.random.rand() theta0 = 0.7248025635110643 # 解説の都合上、初期値を固定しておく theta1 = 0.36156516824075224 # 解説の都合上、初期値を固定しておく print(theta0) # 0.7248025635110643(0〜1のランダムな数値) print(theta1) # 0.36156516824075224(0〜1のランダムな数値) # 予測関数(一次関数) def f(x): return theta0 + theta1 * x # 目的関数(二次関数。実際の値と予測値の二乗誤差の和の半分で、誤差関数とも呼ぶ) def E(x, y): return 0.5 * np.sum((y - f(x)) ** 2) # 学習率 ETA = 0.001 # 誤差の差分 diff = 1 # 更新回数 count = 0 # ランダムな数値をもとに目的関数の誤差を確認 error = E(train_z, train_y) print(error) # 1931733.106949653(ランダムな数値を使用したので誤差が大きい) # 繰り返し1回目 if (diff > 0.01): # 目的関数の微分をもとに求めた式を使って取得した、更新結果を一時変数に保存 tmp_theta0 = theta0 - ETA * np.sum((f(train_z) - train_y)) tmp_theta1 = theta1 - ETA * np.sum((f(train_z) - train_y) * train_z) # パラメータを更新 theta0 = tmp_theta0 theta1 = tmp_theta1 print(theta0) # 9.293306512240843(正しい値に若干近づいた値) print(theta1) # 2.2239092232827655(正しい値に若干近づいた値) # 新しい値で目的関数の誤差を確認(誤差が若干減少した値) current_error = E(train_z, train_y) print(current_error) # 1855614.3975038927 # 前回の誤差との差分を計算 diff = error - current_error error = current_error print(diff) # 76118.70944576035 print(error) # 1855614.3975038927 # ログの出力 count += 1 log = '{}回目: theta0 = {:.3f}, theta1 = {:.3f}, 差分 = {:.4f}' print(log.format(count, theta0, theta1, diff)) # 1回目: theta0 = 9.293, theta1 = 2.224, 差分 = 76118.7094 # 繰り返し2回目 if (diff > 0.01): # 目的関数の微分をもとに求めた式を使って取得した、更新結果を一時変数に保存 tmp_theta0 = theta0 - ETA * np.sum((f(train_z) - train_y)) tmp_theta1 = theta1 - ETA * np.sum((f(train_z) - train_y) * train_z) # パラメータを更新 theta0 = tmp_theta0 theta1 = tmp_theta1 print(theta0) # 17.690440381996027(正しい値に若干近づいた値) print(theta1) # 4.0490063972239385(正しい値に若干近づいた値) # 新しい値で目的関数の誤差を確認(誤差が若干減少した値) current_error = E(train_z, train_y) print(current_error) # 1782509.9889521836 # 前回の誤差との差分を計算 diff = error - current_error error = current_error print(diff) # 73104.40855170903 print(error) # 1782509.9889521836 # ログの出力 count += 1 log = '{}回目: theta0 = {:.3f}, theta1 = {:.3f}, 差分 = {:.4f}' print(log.format(count, theta0, theta1, diff)) # 2回目: theta0 = 17.690, theta1 = 4.049, 差分 = 73104.4086 # 繰り返し3回目 if (diff > 0.01): # 目的関数の微分をもとに求めた式を使って取得した、更新結果を一時変数に保存 tmp_theta0 = theta0 - ETA * np.sum((f(train_z) - train_y)) tmp_theta1 = theta1 - ETA * np.sum((f(train_z) - train_y) * train_z) # パラメータを更新 theta0 = tmp_theta0 theta1 = tmp_theta1 print(theta0) # 25.919631574356107(正しい値に若干近づいた値) print(theta1) # 5.837601627686288(正しい値に若干近づいた値) # 新しい値で目的関数の誤差を確認(誤差が若干減少した値) current_error = E(train_z, train_y) print(current_error) # 1712300.5149791227 # 前回の誤差との差分を計算 diff = error - current_error error = current_error print(diff) # 70209.47397306096 print(error) # 1712300.5149791227 # ログの出力 count += 1 log = '{}回目: theta0 = {:.3f}, theta1 = {:.3f}, 差分 = {:.4f}' print(log.format(count, theta0, theta1, diff)) # 3回目: theta0 = 25.920, theta1 = 5.838, 差分 = 70209.4740 # 徐々に「前回の誤差との差分」が減っていることが分かる # さらに何度も実行されることにより、以下のように差分が減っていく # # 1回目: theta0 = 9.293, theta1 = 2.224, 差分 = 76118.7094 # 2回目: theta0 = 17.690, theta1 = 4.049, 差分 = 73104.4086 # 3回目: theta0 = 25.920, theta1 = 5.838, 差分 = 70209.4740 # 4回目: theta0 = 33.984, theta1 = 7.590, 差分 = 67429.1788 # 5回目: theta0 = 41.888, theta1 = 9.308, 差分 = 64758.9833 # 6回目: theta0 = 49.633, theta1 = 10.992, 差分 = 62194.5276 # 〜中略〜 # 389回目: theta0 = 428.984, theta1 = 93.443, 差分 = 0.0118 # 390回目: theta0 = 428.988, theta1 = 93.444, 差分 = 0.0114 # 391回目: theta0 = 428.991, theta1 = 93.444, 差分 = 0.0109 # 392回目: theta0 = 428.994, theta1 = 93.445, 差分 = 0.0105 # 393回目: theta0 = 428.997, theta1 = 93.446, 差分 = 0.0101 # 394回目: theta0 = 429.000, theta1 = 93.446, 差分 = 0.0097 # 394回目で、差分が0.01以下になった。これで「ほとんど誤差は発生しなくなった」とみなす # このときの値は theta0 = 429.000, theta1 = 93.446 となっている # つまり、求められた1次関数の式は # y = 429.000 + 93.446 * x # となる # この式をもとに予測することができる # # ただしxには標準化された値を渡す必要がある # 平均値 = 141.6, 標準偏差 = 66.98537153737374 # なので、xが100, 200, 300 のときの値は # # 100 = (100 - 141.6) / 66.98537153737374 = -0.62103111538 # y = 429.000 + 93.446 * (-0.62103111538) = 370.967126392 # よってx=100ならy=371 # # 200 = (200 - 141.6) / 66.98537153737374 = 0.87183214274 # y = 429.000 + 93.446 * 0.87183214274 = 510.46922641 # よってx=100ならy=510 # # 300 = (300 - 141.6) / 66.98537153737374 = 2.36469540087 # y = 429.000 + 93.446 * 2.36469540087 = 649.97132643 # よってx=100ならy=650 # # となり、求められた1次関数の式により予測ができていることを確認できる
以下メモ …だが、まだまだ理解を超えているので要勉強 予測データを関数として表すことができれば、与えられたデータをもとに予測を立てることができる シンプルな例として、今回の学習データは一次関数であると推測して実装する 一次関数の学習データは以下のように表すことができる \[y = ax + b \] この式を以下のように表すものとする \[f_{\theta}(x) = \theta_{0} + \theta_{1}x \] これが予測関数の元になっており、このシータ1とシータ2の値を求めることができれば正しい予測ができることになる そしてこれらの式において、 \[y = f_{\theta}(x) \] と一致するときが誤差のない状態となる これを変形すると \[y - f_{\theta}(x) = 0 \] と表すことができる 学習データが「n」個あるとして、学習データごとの誤差の和は以下のように表すことができる(この誤差の和が小さければ小さいほど正確な予測と言える) 左辺の E は、誤差を英語で表したときの「Error」の頭文字から取ったもの これが目的関数の元になっている なお、全体を2で割っているのは微分の計算を簡単にするため、2乗しているのは誤差が負の値になっても正確に算出するため \[E(\theta) = \frac{1}{2} \sum_{i=1}^{n} (y^{(i)} - f_{\theta}(x^{(i)}))^{2} \] このようなアプローチを最小二乗法と呼ぶ 標準化(学習データの平均を0、分散を1とする)は以下で行う 必須の処理ではないが、行っておくとパラメータの収束が早くなる 標準化については、このファイル内にある「数学の復習」の「標準偏差」も参照 \[z^{(i)} = \frac{x^{i} - \mu}{\sigma} \] 目的関数で E を小さくしていけば誤差が小さくなる ただし、適当に値を代入して求めるのは大変。このようなときは微分を使って求めていく この目的関数は \[f_{\theta}(x^{(i)}) \] を含んでいて、この値はシータ0とシータ1の2つのパラメーターを持っている つまりこの目的関数は、シータ0とシータ1の2つの変数を持つ2次関数になる よって普通の微分ではなく偏微分となり、更新式は以下のようになる \[\theta_{0} := \theta_{0} - \eta \frac{\partial E}{\partial \theta_{0}} \] \[\theta_{1} := \theta_{1} - \eta \frac{\partial E}{\partial \theta_{1}} \] これは最急降下法や勾配降下法と呼ばれるもの 分数の前に付いている記号は「イータ」で、学習率と呼ばれる正の定数 学習率の大小によって、最小値にたどり着くまでの更新回数が変わってくる 偏微分の計算を行うが、正攻法の微分は大変。よって合成関数の微分を使う。今回は以下のように定義する \[u = E(\theta) \] \[\nu = f_{\theta}(x) \] すると、以下のように段階的に微分できる \[\frac{\partial u}{\partial \theta_{0}} = \frac{\partial u}{\partial \nu} \cdot \frac{\partial \nu}{\partial \theta_{0}} \] これを計算すると、1つ目の値は \[\frac{\partial u}{\partial \nu} = \frac{\partial}{\partial \nu}(\frac{1}{2} \sum_{i=1}^{n} (y^{(i)} - \nu)^{2}) \] \[\frac{\partial u}{\partial \nu} = \frac{1}{2} \sum_{i=1}^{n} (\frac{\partial}{\partial \nu}(y^{(i)} - \nu)^{2}) \] \[\frac{\partial u}{\partial \nu} = \frac{1}{2} \sum_{i=1}^{n} (\frac{\partial}{\partial \nu}(y^{(i)2} - 2y^{(i)}\nu + \nu^{2})) \] \[\frac{\partial u}{\partial \nu} = \frac{1}{2} \sum_{i=1}^{n} (-2y^{(i)} + 2\nu) \] \[\frac{\partial u}{\partial \nu} = \sum_{i=1}^{n} (\nu - y^{(i)}) \] となる なお、3行目から4行目への変換時にカッコ内で行われている計算は ・「y^{(i)2}」はvで微分すると「0」になる ・「-2y^{(i)}v」はvで微分すると「-2y^(i)」になる ・「v^2」はvで微分すると「2v」になる ・それぞれを合わせて、「-2y^(i) + 2v」になる となる また2つ目の値は \[\frac{\partial \nu}{\partial \theta_{0}} = \frac{\partial}{\partial \theta_{0}}(\theta_{0} + \theta_{1}x) \] \[\frac{\partial \nu}{\partial \theta_{0}} = 1 \] になる これをかけ合わせると \[\frac{\partial u}{\partial \theta_{0}} = \frac{\partial u}{\partial \nu} \cdot \frac{\partial \nu}{\partial \theta_{0}} \] \[\frac{\partial u}{\partial \theta_{0}} = \sum_{i=1}^{n} (\nu - y^{(i)}) \cdot 1 \] \[\frac{\partial u}{\partial \theta_{0}} = \sum_{i=1}^{n} (f_{\theta}(x^{(i)}) - y^{(i)}) \] 引き続きシータ1についても微分してみる \[\frac{\partial u}{\partial \theta_{1}} = \frac{\partial u}{\partial \nu} \cdot \frac{\partial \nu}{\partial \theta_{1}} \] \[\frac{\partial u}{\partial \theta_{1}} = \frac{\partial \nu}{\partial \theta_{1}}(\theta_{0} + \theta_{1}x) \] \[\frac{\partial u}{\partial \theta_{1}} = x \] 微分する \[\frac{\partial u}{\partial \theta_{1}} = \frac{\partial u}{\partial \nu} \cdot \frac{\partial \nu}{\partial \theta_{1}} \] \[\frac{\partial u}{\partial \theta_{1}} = \sum_{i=1}^{n} (\nu - y^{(i)}) \cdot x^{(i)} \] \[\frac{\partial u}{\partial \theta_{1}} = \sum_{i=1}^{n} (f_{\theta}(x^{(i)}) - y^{(i)}) x^{(i)} \] 最終的に以下2つのパラメータの更新式を得ることができる これが更新式の元になっている \[\theta_{0} := \theta_{0} - \mu \sum_{i=1}^{n} (f_{\theta}(x^{(i)}) - y^{(i)}) \] \[\theta_{1} := \theta_{1} - \mu \sum_{i=1}^{n} (f_{\theta}(x^{(i)}) - y^{(i)})x^{(i)} \] 試行回数は一概には言えないが、今回は 10^-3 にしておく これらの内容をもとにプログラムを作成したものが先の内容となる 結果として \[\theta_{0} = 429.000 \] \[\theta_{1} = 93.446 \] という値を求められているが、つまりは求めたい1次関数は \[f_{\theta}(x) = \theta_{0} + \theta_{1}x \] \[f_{\theta}(x) = 429.000 + 93.446x \] \[y = 93.446x + 429.000 \] となる。具体的には xが100のときyは、93.446 * 100 + 429 = 9773.6 xが200のときyは、93.446 * 200 + 429 = 19118.2 xが300のときyは、93.446 * 300 + 429 = 28462.8 …だとおかしな値だが、もとのプログラムと同じく標準化の処理を加えると以下のようになる xが100のときyは370.9671010284257 xが200のときyは510.46967317686426 xが300のときyは649.9722453253028 ■回帰の実践(勉強中) 内容を単純化するため、学習データを「y = ax + b」ではなく「y = ax」にしてみる
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 学習データを読み込む train = np.loadtxt('click.csv', delimiter=',', dtype='int', skiprows=1) train_x = train[:,0] train_y = train[:,1] # 標準化を行う(データのスケールを揃えて学習が効果的に行われるようにする) mu = train_x.mean() sigma = train_x.std() def standardize(x): return (x - mu) / sigma train_z = standardize(train_x) # 更新用パラメータを初期化(初期値をランダムに設定する) theta = np.random.rand() # 予測関数(一次関数) def f(x): return theta * x # 目的関数(二次関数。実際の値と予測値の二乗誤差の和の半分で、誤差関数とも呼ぶ) def E(x, y): return 0.5 * np.sum((y - f(x)) ** 2) # 学習率 ETA = 0.001 # 誤差の差分 diff = 1 # 更新回数 count = 0 # 誤差の差分が0.1以下になるまでパラメータ更新を繰り返す error = E(train_z, train_y) while diff > 0.1: # パラメータを更新 theta = theta - ETA * np.sum((f(train_z) - train_y) * train_z) # 前回の誤差との差分を計算 current_error = E(train_z, train_y) diff = error - current_error error = current_error # ログの出力 count += 1 log = '{}回目: theta = {:.3f}, 差分 = {:.4f}' print(log.format(count, theta, diff)) # プロットして確認 x = np.linspace(-3, 3, 100) plt.plot(train_z, train_y, 'o') plt.plot(x, f(x)) plt.savefig('graph.png')
かなり下の方にグラフが表示されるが、傾きは意図したものになっている 標準化された内容において原点 (0, 0) を通る必要があるので、傾きだけで合わせるならこのようなグラフになる …ということのはず ■多項式回帰(重回帰)の実践 ※まだ検証中。大きな勘違いがある可能性がある 以下で多項式回帰(重回帰)を検証中
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 学習データを読み込む train = np.loadtxt('click.csv', delimiter=',', dtype='int', skiprows=1) train_x = train[:,0] train_y = train[:,1] # 標準化を行う(データのスケールを揃えて学習が効果的に行われるようにする) mu = train_x.mean() sigma = train_x.std() def standardize(x): return (x - mu) / sigma train_z = standardize(train_x) # 更新用パラメータを初期化(初期値をランダムに設定する) theta = np.random.rand(3) # 学習データの行列を作る def to_matrix(x): return np.vstack([np.ones(x.size), x, x ** 2]).T X = to_matrix(train_z) # 予測関数(列ベクトル) def f(x): return np.dot(x, theta) # 目的関数(二次関数。実際の値と予測値の二乗誤差の和の半分で、誤差関数とも呼ぶ) def E(x, y): return 0.5 * np.sum((y - f(x)) ** 2) # 学習率 ETA = 0.001 # 誤差の差分 diff = 1 # 更新回数 count = 0 # 誤差の差分が0.01以下になるまでパラメータ更新を繰り返す error = E(X, train_y) while diff > 0.01: # パラメータを更新 theta = theta - ETA * np.dot(f(X) - train_y, X) # 前回の誤差との差分を計算 current_error = E(X, train_y) diff = error - current_error error = current_error # ログの出力 count += 1 log = '{}回目: theta = {}, 差分 = {:.4f}' print(log.format(count, theta, diff)) # プロットして確認 x = np.linspace(-3, 3, 100) plt.plot(train_z, train_y, 'o') plt.plot(x, f(to_matrix(x))) plt.savefig('graph.png')
実行の際、以下のようなログが出力される
1回目: theta = [9.30220205 2.77489304 9.76441964], 差分 = 152581.1030 2回目: theta = [17.50386962 4.60251556 18.1524752 ], 差分 = 137373.5725 3回目: theta = [25.37374272 6.40522139 26.01357776], 差分 = 123765.8789 4回目: theta = [32.92899631 8.18277789 33.37728718], 差分 = 111587.5946 5回目: theta = [40.18587064 9.93499805 40.27153163], 差分 = 100686.5080 6回目: theta = [47.1597226 11.66173739 46.72269743], 差分 = 90926.6740 〜中略〜 791回目: theta = [405.71401902 95.10425227 23.29512797], 差分 = 0.0107 792回目: theta = [405.71683608 95.10405716 23.2935123 ], 差分 = 0.0105 793回目: theta = [405.71962911 95.10386371 23.29191041], 差分 = 0.0104 794回目: theta = [405.72239832 95.10367191 23.29032218], 差分 = 0.0102 795回目: theta = [405.72514391 95.10348175 23.2887475 ], 差分 = 0.0100 796回目: theta = [405.72786608 95.1032932 23.28718624], 差分 = 0.0098
thetaは「405.72786608」「95.1032932」「23.28718624」と求められている これは列ベクトルだが、求めたい関数は以下のように表すことができ、 \[{\theta}^{T}x = \theta_{0}x_{0} + \theta_{1}x_{1} + \theta_{2}x_{2} + … + \theta_{n}x_{n} \] 以下の等式が成立し、 \[f_{\theta}(x) = {\theta}^{T}x \] 結果的に予測関数は「405.72537805 + 95.10346544 * x + 23.28861321 * x^2」ということになる (現状かなり端折った内容になっているので、詳細は書籍を参照) プログラムの最後に以下を追加すると
print(f(to_matrix(standardize(100)))) print(f(to_matrix(standardize(200)))) print(f(to_matrix(standardize(300))))
実行時に以下も表示される つまり、個別に予測を表示できる
[355.64511094] [506.34110805] [760.84100797]
以下、メモ付きで検証中
import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 学習データを読み込む train = np.loadtxt('click.csv', delimiter=',', dtype='int', skiprows=1) print(train) # [[235 591] # [216 539] # [148 413] # [ 35 310] # [ 85 308] # [204 519] # [ 49 325] # [ 25 332] # [173 498] # [191 498] # [134 392] # [ 99 334] # [117 385] # [112 387] # [162 425] # [272 659] # [159 400] # [159 427] # [ 59 319] # [198 522]] train_x = train[:,0] print(train_x) # [235 216 148 35 85 204 49 25 173 191 134 99 117 112 162 272 159 159 59 198] train_y = train[:,1] print(train_y) # [591 539 413 310 308 519 325 332 498 498 392 334 385 387 425 659 400 427 319 522] # 標準化を行う(データのスケールを揃えて学習が効果的に行われるようにする) mu = train_x.mean() sigma = train_x.std() def standardize(x): return (x - mu) / sigma train_z = standardize(train_x) print(train_z) # [ 1.39433428 1.11069026 0.09554325 -1.59139223 -0.8449606 0.93154667 # -1.38239138 -1.74067856 0.46875906 0.73747445 -0.11345761 -0.63595975 # -0.36724436 -0.44188752 0.3045441 1.94669369 0.25975821 0.25975821 # -1.23310505 0.84197488] # 更新用パラメータを初期化(サイズが3の配列として、初期値をランダムに設定する) #theta = np.random.rand(3) theta = [0.52525576, 0.26226403, 0.01139251] print(theta) # [0.52525576 0.26226403 0.01139251] # 学習データの行列を作る # 多項式回帰に対応させるため、「(θ0) + (θ1)x + (θ2)x^2」の形式にする # つまり1行を1つの学習データとみなして「1 + (学習データ) + (学習データの2乗)」の形式にする # さらに、各学習データは縦方向で配列に連結する # 「T」で転置を行なう def to_matrix(x): return np.vstack([np.ones(x.size), x, x ** 2]).T X = to_matrix(train_z) print(X) # [[ 1. 1.39433428 1.94416809] # [ 1. 1.11069026 1.23363286] # [ 1. 0.09554325 0.00912851] # [ 1. -1.59139223 2.53252924] # [ 1. -0.8449606 0.71395842] # [ 1. 0.93154667 0.8677792 ] # [ 1. -1.38239138 1.91100592] # [ 1. -1.74067856 3.02996185] # [ 1. 0.46875906 0.21973506] # [ 1. 0.73747445 0.54386856] # [ 1. -0.11345761 0.01287263] # [ 1. -0.63595975 0.4044448 ] # [ 1. -0.36724436 0.13486842] # [ 1. -0.44188752 0.19526458] # [ 1. 0.3045441 0.09274711] # [ 1. 1.94669369 3.78961632] # [ 1. 0.25975821 0.06747433] # [ 1. 0.25975821 0.06747433] # [ 1. -1.23310505 1.52054807] # [ 1. 0.84197488 0.70892169]] # 予測関数(列ベクトル) # np.dot の挙動は https://qiita.com/ao_log/items/64768b67153e8fb6820b が参考になる # x には上で記載した X の値が格納されている。引数として渡されてくる。毎回固定の内容(上で記載した内容のまま) # theta にはパラメータの値が格納されている。具体的には「[0.52525576, 0.26226403, 0.01139251]」のような値が格納されている。徐々に最適化されて「[72.43856197 17.76450257 68.07431847]」のように変化し、最終的に「[405.72537805 95.10346544 23.28861321]」のような値になる def f(x): return np.dot(x, theta) # 目的関数(二次関数。実際の値と予測値の二乗誤差の和の半分で、誤差関数とも呼ぶ) def E(x, y): return 0.5 * np.sum((y - f(x)) ** 2) # 学習率 ETA = 0.001 # 誤差の差分 diff = 1 # 更新回数 count = 0 # 誤差の差分が0.01以下になるまでパラメータ更新を繰り返す error = E(X, train_y) print(error) # 1933525.9892911182 while diff > 0.01: # パラメータを更新 theta = theta - ETA * np.dot(f(X) - train_y, X) # 前回の誤差との差分を計算 current_error = E(X, train_y) diff = error - current_error error = current_error # ログの出力 count += 1 log = '{}回目: theta = {}, 差分 = {:.4f}' print(log.format(count, theta, diff)) # プロットして確認 x = np.linspace(-3, 3, 100) plt.plot(train_z, train_y, 'o') plt.plot(x, f(to_matrix(x))) plt.savefig('graph.png') # 検証 print(f(to_matrix(standardize(100)))) print(f(to_matrix(standardize(200)))) print(f(to_matrix(standardize(300))))
学習データは標準化と行列変換を経て X に格納される X の内容は以下のとおりで、これは以降変化しない [[ 1. 1.39433428 1.94416809] [ 1. 1.11069026 1.23363286] [ 1. 0.09554325 0.00912851] [ 1. -1.59139223 2.53252924] [ 1. -0.8449606 0.71395842] [ 1. 0.93154667 0.8677792 ] [ 1. -1.38239138 1.91100592] [ 1. -1.74067856 3.02996185] [ 1. 0.46875906 0.21973506] [ 1. 0.73747445 0.54386856] [ 1. -0.11345761 0.01287263] [ 1. -0.63595975 0.4044448 ] [ 1. -0.36724436 0.13486842] [ 1. -0.44188752 0.19526458] [ 1. 0.3045441 0.09274711] [ 1. 1.94669369 3.78961632] [ 1. 0.25975821 0.06747433] [ 1. 0.25975821 0.06747433] [ 1. -1.23310505 1.52054807] [ 1. 0.84197488 0.70892169]] 更新用パラメータはランダムに決定されて theta に格納される theta の内容は一例として以下のような値で、これはループによって最適化(更新)されていく [0.52525576, 0.26226403, 0.01139251] 10回最適化を行った段階では、以下のような値になる [72.43856197 17.76450257 68.07431847] 100回最適化を行った段階では、以下のような値になる [281.75465761 87.39699393 92.87228457] 最適化完了後(795回ループし、誤差が 0.01 以下になったとき)、以下のような値になる [405.72537805 95.10346544 23.28861321] これにより、求められた2次関数の式は y = 405.72537805 + 95.10346544 * x + 23.28861321 * x^2 となる xが100, 200, 300 のときの値は、「回帰の実践」のときと同様 100 = (100 - 141.6) / 66.98537153737374 = -0.62103111538 200 = (200 - 141.6) / 66.98537153737374 = 0.87183214274 300 = (300 - 141.6) / 66.98537153737374 = 2.36469540087 となるので、予測は以下のようになる y = 405.72537805 + 95.10346544 * (-0.62103111538) + 23.28861321 * (-0.62103111538 * -0.62103111538) = 355.645110936 y = 405.72537805 + 95.10346544 * (0.87183214274) + 23.28861321 * (0.87183214274 * 0.87183214274) = 506.34110805 y = 405.72537805 + 95.10346544 * (2.36469540087) + 23.28861321 * (2.36469540087 * 2.36469540087) = 760.841008005 よって x=100ならy=355 x=200ならy=506 x=300ならy=760 となる np.dotによる計算は、このファイル内の「Python > 行列の計算」にある「Aが2次元配列でBが1次元配列の場合」を参照 今回は、以下のような計算がされることになる
import numpy as np theta = [0.52525576, 0.26226403, 0.01139251] X = [[ 1, 1.39433428, 1.94416809], [ 1, 1.11069026, 1.23363286], [ 1, 0.09554325, 0.00912851], [ 1, -1.59139223, 2.53252924], [ 1, -0.8449606 , 0.71395842], [ 1, 0.93154667, 0.8677792 ], [ 1, -1.38239138, 1.91100592], [ 1, -1.74067856, 3.02996185], [ 1, 0.46875906, 0.21973506], [ 1, 0.73747445, 0.54386856], [ 1, -0.11345761, 0.01287263], [ 1, -0.63595975, 0.4044448 ], [ 1, -0.36724436, 0.13486842], [ 1, -0.44188752, 0.19526458], [ 1, 0.3045441 , 0.09274711], [ 1, 1.94669369, 3.78961632], [ 1, 0.25975821, 0.06747433], [ 1, 0.25975821, 0.06747433], [ 1, -1.23310505, 1.52054807], [ 1, 0.84197488, 0.70892169]] result = np.dot(X, theta) print(result)
result の内容は以下のとおり
[0.91308844 0.83060404 0.55041731 0.13674269 0.31178677 0.77945313 0.18447538 0.10325726 0.65069773 0.72486481 0.49564656 0.36307403 0.43047726 0.41158911 0.60618335 1.07897673 0.5941497 0.5941497 0.21917952 0.75415188]
先頭の 0.91308844 という値は、「theta」と「Xの1つめの要素」を使って以下のように求められている = (1 * 0.52525576) + (1.39433428 * 0.26226403) + (1.94416809 * 0.01139251) 次の 0.83060404 という値は、「theta」と「Xの2つめの要素」を使って以下のように求められている = (1 * 0.52525576) + (1.11069026 * 0.26226403) + (1.23363286 * 0.01139251) これを最後まで繰り返し、1次元配列の値を作っている ■メモ 以下なども参考になりそう 機械学習のパラメータチューニングを「これでもか!」というくらい丁寧に解説 - Qiita https://qiita.com/c60evaporator/items/ca7eb70e1508d2ba5359
■Pandas(データ解析支援)
データ解析を支援する機能を提供するライブラリ 以下でインストールできる
$ sudo pip3 install pandas
データ分析で頻出のPandas基本操作 - Qiita https://qiita.com/ysdyt/items/9ccca82fc5b504e7913a pandas の loc、iloc、ix の違い - python | コード7区 http://ailaby.com/lox_iloc_ix/ Pandasで速度に難がある場合、Polarsを使うといいらしい 詳細は、後述の「Polars(データ解析支援)」を参照 ■1次元のデータ構造
import pandas as pd label = ['a', 'b', 'c', 'd', 'e'] data = [1, 2, 3, 4, 5] s = pd.Series(data, index=label) # 行ラベル付きの1次元データ構造 # 内容をすべて表示 print(s)
実行すると以下の結果になる
$ python3 test.py a 1 b 2 c 3 d 4 e 5 dtype: int64
■2次元のデータ構造
import pandas as pd data = { 'col1': [1, 2, 3, 4, 5], 'col2': [2, 3, 4, 5, 6], 'col3': [3, 4, 5, 6, 7], } index_name = ['zero', 'one', 'two', 'three', 'four'] df = pd.DataFrame(data, index=index_name) # 行ラベル・列ラベル付きの2次元データ構造 # 内容をすべて表示 print(df) # ラベルによるデータ選択 print(df.loc['one', 'col2']) # 「one」行、「col2」列のデータを選択 print(df.loc['one':'three', :]) # 「one」から「three」行のすべての列のデータを選択 print(df.loc[['one', 'four'], ['col1', 'col3']]) # 「one」と「four」行の「col1」と「col3」列のデータを選択 # 位置番号によるデータ選択(一番号は0始まり / 結果は上と同じ) print(df.iloc[1, 1]) print(df.iloc[1:4, :]) print(df.iloc[[1, 4], [0, 2]])
実行すると以下の結果になる
$ python3 2.py col1 col2 col3 zero 1 2 3 one 2 3 4 two 3 4 5 three 4 5 6 four 5 6 7 3 col1 col2 col3 one 2 3 4 two 3 4 5 three 4 5 6 col1 col3 one 2 4 four 5 7 3 col1 col2 col3 one 2 3 4 two 3 4 5 three 4 5 6 col1 col3 one 2 4 four 5 7
■CSVファイルを読み込み
import pandas as pd # CSVファイルを読み込み df = pd.read_csv('sample.csv', index_col=0, encoding='shift-jis') # 次元をタプルに格納して返す print(df.shape) # 簡素な情報を出力する print(df.info()) # 最初の5行を表示 print(df.head()) # 最後の5行を表示 print(df.tail())
■Excelファイルを読み込み
import pandas as pd # Excelファイルを読み込み #excel = pd.read_excel('sample.xlsx', index_col=0) excel = pd.read_excel('sample.xlsx', index_col=0, engine='openpyxl') # 次元をタプルに格納して返す print(excel.shape) # 簡素な情報を出力する print(excel.info()) # 最初の5行を表示 print(excel.head()) # 最後の5行を表示 print(excel.tail())
「ImportError: Missing optional dependency 'xlrd'. Install xlrd >= 1.0.0 for Excel support Use pip or conda to install xlrd.」 のエラーになる場合、xlrdをインストールする必要がある
$ sudo pip3 install xlrd
インストールしても 「ValueError: Your version of xlrd is 2.0.1. In xlrd >= 2.0, only the xls format is supported. Install openpyxl instead.」 のエラーが表示される xlrd 2.0.0 からxlsxがサポートされなくなったらしい 対策に、openpyxlをインストールする
$ sudo pip3 install openpyxl
これでExcelファイルの読み込み時、「engine='openpyxl'」を指定すると読み込める
■Polars(データ解析支援)
※未検証。Pandasよりも高速らしい PandasからPolarsへ移行した方がいいのか #Python - Qiita https://qiita.com/inoshun/items/30e4e78cbf221bf11a86
■OpenCV(画像処理)
OpenCV(Open Source Computer Vision Library) 画像や動画を処理するのに必要な様々な機能を提供するライブラリ Pythonを用いた画像処理(openCV,skimage) - Qiita https://qiita.com/taka_baya/items/453e429b466ffaa702c9 Pythonで画像処理: Pillow, NumPy, OpenCVの違いと使い分け | note.nkmk.me https://note.nkmk.me/python-image-processing-pillow-numpy-opencv/ ■開発環境を構築 Windowsの場合は、このファイル内の「Windows上に開発環境を構築」を参照 Linuxの場合は、RaspberryPi.txt の「OpenCV」を参照 ■画像の読み込みと表示 保存の際に拡張子を「.png」にすればPNG形式で保存される 「.jpg」ならJpeg形式で保存される
import cv2 img = cv2.imread("sample.jpg") cv2.imwrite("output.png", img)
■画像のグレースケール変換
import cv2 img = cv2.imread("sample.png", 0) cv2.imwrite('gray.png', img)
import cv2 img = cv2.imread("sample.png") img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) cv2.imwrite("gray.png", img)
■画像の指定範囲の色を抽出
import cv2 import numpy as np img = cv2.imread("sample.png", 1) hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 取得する色の範囲を指定する lower_color = np.array([20, 50, 50]) upper_color = np.array([255, 255, 255]) # 指定した色に基づいたマスク画像の生成 img_mask = cv2.inRange(hsv, lower_color, upper_color) # フレーム画像とマスク画像の共通の領域を抽出する。 img_color = cv2.bitwise_and(img, img, mask=img_mask) cv2.imwrite("hsv.png", img_color)
■画像のエッジ部分を抽出
import cv2 import numpy as np # 白黒画像で画像を読み込み img = cv2.imread("sample.png", 0) # エッジ検出 canny_img = cv2.Canny(img, 50, 110) cv2.imwrite("canny.png", canny_img)
■画像のネガポジ変換
import cv2 img = cv2.imread("face.png") #img = 256 - img img = 0 - img cv2.imwrite("invert.png", img)
■画像のリサイズ
import cv2 # 画像を読み込み img = cv2.imread("sample.png") # リサイズ img = cv2.resize(img, (80, 80)) cv2.imwrite("resize.png", img)
■画像のトリミング
import cv2 # 画像を読み込み img = cv2.imread("sample.png") # トリミング x, y = 180, 240 w, h = 200, 60 img = img[y:y+h, x:x+w] cv2.imwrite("trimming.png", img)
■画像の特異点を抽出
import cv2 import numpy as np # 画像を読み込み img = cv2.imread("sample.png", 1) # 特異点を抽出 detector = cv2.ORB_create() keypoints = detector.detect(img) # 画像に特徴点を書き込み img_orb = cv2.drawKeypoints(img, keypoints, None) cv2.imwrite("orb.png", img_orb)
■画像のヒストグラムを可視化
import cv2 import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 画像を読み込み img = cv2.imread('sample.png') # ヒストグラムを可視化 color = ('b','g','r') for i,col in enumerate(color): histr = cv2.calcHist([img],[i],None,[256],[0,256]) plt.plot(histr,color = col) plt.xlim([0,256]) plt.savefig('histogram.png')
■輪郭抽出
import cv2 import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 画像を読み込んでリサイズ img = cv2.imread("face.jpg") img = cv2.resize(img, (200, 300)) # 色空間を二値化 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # グレースケールに変換 gray = cv2.GaussianBlur(gray, (7, 7), 0) # 平滑化 im2 = cv2.threshold(gray, 140, 240, cv2.THRESH_BINARY_INV)[1] # 二極化 # 画面左側に二値化した画像を描画 plt.subplot(1, 2, 1) plt.imshow(im2, cmap="gray") # 輪郭を抽出 cnts = cv2.findContours(im2, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)[0] # 抽出した枠を描画 for pt in cnts: x, y, w, h = cv2.boundingRect(pt) # 大きすぎたり小さすぎたり領域を除去 if w < 30 or w > 200: continue print(x,y,w,h) # 結果を出力 cv2.rectangle(img, (x, y), (x+w, y+h), (0, 255, 0), 2) # 画面右側に抽出結果を描画 plt.subplot(1, 2, 2) plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) plt.savefig("found.png", dpi=200)
実行時に 「npoints = 0 && (depth == cv_32f depth == cv_32s) in function 'pointsetboundingrect'」 のようなエラーになった場合、findContoursの「[1]」を「[0]」にすれば動作した Opencv 3.2から仕様が変わり、関数の戻り値の数が変わったとのこと Python - 輪郭抽出プログラムが実行されません|teratail https://teratail.com/questions/175238 ■顔認識
#!/Users/refirio/Anaconda3/python # coding: utf-8 # -*- coding: utf-8 -*- import sys import io import cv2 # 使用ファイルと入出力ディレクトリ IMAGE_FILE = "daughter.png" INPUT_PATH = "./inputs/" + IMAGE_FILE OUTPUT_PATH = "./outputs/" + IMAGE_FILE # ラインの色 COLOR_WHITE = (255, 255, 255) COLOR_RED = (0, 0, 255) # 画像ファイル読み込み image = cv2.imread(INPUT_PATH) # 画像をグレースケール変換 image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # カスケード分類器の特徴量を取得 face_cascade = cv2.CascadeClassifier("./haarcascades/haarcascade_frontalface_alt.xml") eye_cascade = cv2.CascadeClassifier("./haarcascades/haarcascade_eye.xml") # 画像の中から顔を検出 faces = face_cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=2, minSize=(50, 50)) if len(faces) > 0: # 検出した顔の座標を取得 for (face_x,face_y,face_w,face_h) in faces: # 検出した顔を囲む矩形の作成 cv2.rectangle(image, (face_x,face_y),(face_x + face_w,face_y + face_h), COLOR_WHITE, 2) # 検出した顔画像を取得 face_image = image[face_y : face_y + face_h, face_x : face_x + face_w] # 検出した顔画像をグレースケール変換 face_image_gray = image_gray[face_y : face_y + face_h, face_x : face_x + face_w] # 顔画像の中から目を検出 eyes = eye_cascade.detectMultiScale(face_image_gray, scaleFactor=1.1, minNeighbors=2, minSize=(20, 20)) if len(faces) > 0: # 検出した目の座標を取得 for (eye_x,eye_y,eye_w,eye_h) in eyes: # 検出した目を囲む矩形の作成 cv2.rectangle(face_image,(eye_x, eye_y),(eye_x + eye_w,eye_y + eye_h), COLOR_RED, 2) # 認識結果の保存 cv2.imwrite(OUTPUT_PATH, image) # 結果画面を表示 sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8') print("Content-Type: text/html; charset=UTF-8\n") print("<!DOCTYPE html>") print("<html>") print("<head>") print("<meta charset=\"utf-8\">") print("<title>Python</title>") print("</head>") print("<body>") print("<h1>Python</h1>") print("<img src=\"" + OUTPUT_PATH + "\" style=\"max-width: 500px; max-height: 500px;\">") print("</body>") print("</html>")
■skimage(画像処理)
skimageとは、画像処理に関するアルゴリズムを集めたライブラリ Pythonを用いた画像処理(openCV,skimage) - Qiita https://qiita.com/taka_baya/items/453e429b466ffaa702c9 ■画像の色の違いの部分を切り分け
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import cv2 from skimage import data, segmentation, color from skimage.future import graph # 画像を読み込み img = cv2.imread('sample.png', 1) #画像の色の違いの部分を切り分け labels = segmentation.slic(img, compactness=30, n_segments=400, start_label=0) out = color.label2rgb(labels, img, kind='avg', bg_label=0) plt.plot() plt.imshow(out) plt.savefig('rag.png')
■MeCab(形態素解析)
形態素解析とは、文章を意味を持つ最小単位(形態素)に分割し、各形態素に品詞情報などを付加する 英単語は単語の区切りが明確だが、日本語の形態素解析は容易ではない 代表的な形態素解析ライブラリとしてMeCabがある ■MeCabをインストール Raspberry Piでpythonからmecabを使う初期設定 - Qiita https://qiita.com/fujit33/items/fd1d09f3332c626c9379
$ sudo apt-get install mecab libmecab-dev mecab-ipadic-utf8 python-mecab $ sudo apt-get install swig $ sudo pip3 install mecab-python3 $ python3 Python 3.8.7 (default, Feb 7 2021, 00:21:33) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import MeCab >>> mecab = MeCab.Tagger() >>> print(mecab.parse("すもももももももものうち")) すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ の 助詞,連体化,*,*,*,*,の,ノ,ノ うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ EOS >>> exit()
■mecab-ipadic-NEologd を導入 MeCabは形態素解析を行うに当たり単語辞書を用いており、IPADICという単語辞書がよく用いられる mecab-ipadic-NEologd は、新しい語や固有表現を追加することで IPADICを拡張したMeCab用のシステム辞書 GitHub - neologd/mecab-ipadic-neologd: Neologism dictionary based on the language resources on the Web for mecab-ipadic https://github.com/neologd/mecab-ipadic-neologd
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git $ cd mecab-ipadic-neologd $ ./bin/install-mecab-ipadic-neologd -n -p /var/lib/mecab/dic/mecab-ipadic-neologd
Raspberry Pi 4 4B-32GB の環境ではインストールできた インストールに成功したら、以下のようにして辞書を指定できる
$ python3 Python 3.8.7 (default, Feb 7 2021, 00:21:33) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import MeCab >>> mecab = MeCab.Tagger("-d /var/lib/mecab/dic/mecab-ipadic-neologd") >>> print(mecab.parse("メイが恋ダンスを踊っている。")) メイ 名詞,固有名詞,人名,一般,*,*,M.A.Y,メイ,メイ が 助詞,格助詞,一般,*,*,*,が,ガ,ガ 恋ダンス 名詞,固有名詞,一般,*,*,*,恋ダンス,コイダンス,コイダンス を 助詞,格助詞,一般,*,*,*,を,ヲ,ヲ 踊っ 動詞,自立,*,*,五段・ラ行,連用タ接続,踊る,オドッ,オドッ て 助詞,接続助詞,*,*,*,*,て,テ,テ いる 動詞,非自立,*,*,一段,基本形,いる,イル,イル 。 記号,句点,*,*,*,*,。,。,。 EOS >>> exit()
Raspberry Pi 3 Model b+ の環境では以下のエラーになった メモリ不足のためインストールできないみたい 公式の解説によると4GBほどのメモリ空き容量が必要らしいが、今回の環境は1GB程度しかない
terminate called after throwing an instance of 'std::bad_alloc' what(): std::bad_alloc /home/pi/mecab-ipadic-neologd/bin/../libexec/make-mecab-ipadic-neologd.sh: 525 行: 23592 中止 ${MECAB_LIBEXEC_DIR}/mecab-dict-index -f UTF8 -t UTF8
mecab-ipadic-neologd/README.ja.md at master - neologd/mecab-ipadic-neologd - GitHub https://github.com/neologd/mecab-ipadic-neologd/blob/master/README.ja.md Vagrant上のVMへのmecab-ipadic-neologdのインストールが失敗する時 - Qiita https://qiita.com/comocc/items/bfa5c4fe3c84d31e8ae7 以下のようにすると、300MBほどサイズを削減できるとのこと 今回の環境ではこれでもインストールできなかった
$ ./bin/install-mecab-ipadic-neologd -n -y --ignore_adverb --ignore_interject --ignore_noun_ortho --ignore_noun_sahen_conn_ortho --ignore_adjective_std --ignore_adjective_verb --ignore_ill_formed_words -p /var/lib/mecab/dic/mecab-ipadic-neologd
以下のようにすると512MBほどのメモリ空き容量があればインストールできるとのこと ただしオススメしないとされている 今回の環境ではこれでもインストールできなかった
$ ./bin/install-mecab-ipadic-neologd -n -y --eliminate-redundant-entry -p /var/lib/mecab/dic/mecab-ipadic-neologd
今回はメモリ不足のため mecab-ipadic-NEologd を使えないようなので、標準の辞書を使う
■Janome(形態素解析)
Pythonで書かれた形態素解析ライブラリ pipでインストール可能なので、MeCabよりも手軽に扱うことができる ただし処理速度はMeCabに敵わない 内包辞書として mecab-ipadic-2.7.0-20070801 が使われている ■Janomeをインストール
$ pip3 install janome $ python3 Python 3.8.7 (default, Feb 7 2021, 00:21:33) [GCC 8.3.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from janome.tokenizer import Tokenizer >>> t = Tokenizer() >>> for token in t.tokenize("すもももももももものうち"): ... print(token) ... すもも 名詞,一般,*,*,*,*,すもも,スモモ,スモモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ も 助詞,係助詞,*,*,*,*,も,モ,モ もも 名詞,一般,*,*,*,*,もも,モモ,モモ の 助詞,連体化,*,*,*,*,の,ノ,ノ うち 名詞,非自立,副詞可能,*,*,*,うち,ウチ,ウチ >>> exit()
Welcome to janome's documentation! (Japanese) - Janome v0.4 documentation (ja) https://mocobeta.github.io/janome/ Python, Janomeで日本語の形態素解析、分かち書き(単語分割) | note.nkmk.me https://note.nkmk.me/python-janome-tutorial/ Janomeを使ってPythonで形態素解析 - Qiita https://qiita.com/charon/items/661d9a25b2233a9f8da4 ■最新の mecab-ipadic-NEologd を導入
$ git clone --depth 1 https://github.com/neologd/mecab-ipadic-neologd.git $ xz -dkv seed/*.csv.xz $ cat seed/*.csv > neologd.csv
作成された neologd.csv を作業フォルダに配置する 今回は janome ディレクトリで作業するものとする janome/neologd.csv 以下のプログラムで辞書をビルドする
from janome.dic import UserDictionary from janome import sysdic user_dict = UserDictionary('neologd.csv', 'utf8', 'ipadic', sysdic.connections) user_dict.save('neologd')
…が、Raspberry Pi 4 4B-32GB の環境では「MemoryError」となって処理が止まった JanomeでNEologd辞書を使う - Qiita https://qiita.com/_likr/items/0fc845f59b4ad685cc06
■機械学習
■機械学習とは 機械学習とは、人間の学習能力と同様の機能をコンピューター上で実現しようとする技術 人工知能における研究課題の一つ 一般的な識別プログラムを作る場合、画像データの画素を調べて 「赤色の要素が多ければリンゴ、黄色の要素が多ければレモン」 のように判定する。判定のルールは人間が決める 機械学習で判定する場合、人間が明確なルールを決めることは無い たくさんのリンゴとレモンの画像データを用意しておいて、それを識別器というプログラムに与える そうすることで、識別器が自動的に 「リンゴには赤色の要素が多く、レモンには黄色の要素が多い」 ということを学習する ■ニューラルネットワークとは ニューラルネットワークとは、人の神経を模したネットワーク構造のこと コンピュータに学習能力をもたせることにより、様々な問題を解決するためのアプローチ 人間の脳の中には、多数の神経細胞(ニューロン)が存在している 一つのニューロンは他の複数のニューロンから信号を受け取り、他のニューロンに対して信号を渡す 脳はこのような信号の流れによって、様々な情報を伝達している この仕組をコンピュータで再現したのがニューラルネットワーク ■ディープラーニング(深層学習)とは ニューラルネットワークを3層以上重ねたものを、一般に「ディープ・ニューラル・ネットワーク(DNN)」と呼ぶ このDNNを使った機械学習がディープラーニング(深層学習) ディープラーニングでは、大量のデータを学習することで、各ニューロン間の接続の重み付けのパラメーターを繰り返し調整する ■パーセプトロンとは 比較的単純な仕組みでありながら、現在の機械学習の基礎となっている人工ニューロン 入力層と出力層のみの2層からなる、単純パーセプトロンについて考える 3つの入力x1、x2、x3と1つの出力yがあるとする そして各入力値には、0または1の値を与えることにし、出力する値も0または1になるとする ここでは例えば、「新しいパソコンを買うかどうか」について考える 新しいパソコンを買う場合に出力yは1となり、買わない場合は0になる そして入力には、パソコンを購入してもいいかどうかを判断する要因を与えるものとする ・今が買い替えどきか(x1) ・手元に資金が十分にあるか(x2) ・現在セールをしているか(x3) これらの要素を考慮し、多数決で決めることになる ただしこの多数決は、平等に一票ずつが与えられるわけではない もしその人tの手元に資金がたくさんあるなら、x2の条件はそれほど重要ではない また、今使っているパソコンが故障した場合はx1の条件は重要になる つまり単純な多数決で判断できないため、パーセプトロンでも各入力に対する重み(W)というパラメーターを導入している x1、x2、x3に対する重みをW1、W2、W3としたとき、資金が多い人なら(W1=5、W2=2、W3=3)と重みを設定すると考えられるし、 すでにパソコンが壊れている人なら(W1=7、W2=2、W3=1)と重みを設定すると考えられる そして、パソコンを購入するかどうかを検討するプログラムは、閾値をbとしたとき、以下のように表現できる
if (x1 * W1) + (x2 * W2) + (x3 * W3) > b: # 買う else: # 買わない
このように重みや閾値を変化させることで、意思決定を明確化させることができる このパーセプトロンを複雑に組み合わせることで、より複雑な判断ができるようにする ■AI(人工知能)、機械学習、ディープラーニング(深層学習)の違い AI(人工知能): マシンによって再現される人間の知能 人間と同様の知能を実現させようという取り組みやその技術 機械学習: 人工知能を実現するためのアプローチ 特定のタスクをトレーニングにより実行できるようになるAI。人が特徴を定義する ディープラーニング(深層学習): 機械学習を実装するための手法 マシンが特徴を自動定義する 人工知能、機械学習、ディープラーニングの違いとは | NVIDIA https://blogs.nvidia.co.jp/2016/08/09/whats-difference-artificial-intelligence-machine-learning-deep... AI、機械学習、ディープラーニングの違いを説明できますか?機械学習と統計の違いは? (1/3):MarkeZine(マーケジン) https://markezine.jp/article/detail/29471
■scikit-learn(機械学習)
scikit-learn(サイキット・ラーン)は、Python向けの機械学習フレームワーク 様々なアルゴリズムに対応しており、すぐに機械学習を試せるようにサンプルデータも含まれている 機械学習でよく使われる他のライブラリ(PandasやNumPyなど)との親和性が高い BSDライセンスのオープンソースのため、無償で商用利用が可能 ■インストール
$ sudo pip3 install sklearn $ python3 Python 3.7.3 (default, Apr 3 2019, 05:39:12) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from sklearn.svm import LinearSVC >>> from sklearn.metrics import accuracy_score >>> exit()
機械学習のライブラリ!scikit-learnとは【初心者向け】 | TechAcademyマガジン https://techacademy.jp/magazine/17375 使用すべきアルゴリズムについても、上記ページで紹介されている 以下のプログラムでは、中小規模のクラス分類手法である Linear SVC を使用している
from sklearn.svm import LinearSVC from sklearn.metrics import accuracy_score # 学習用データと結果の準備 learn_data = [[0, 0], [1, 0], [0, 1], [1, 1]] learn_label = [0, 0, 0, 1] # アルゴリズムの指定(LinearSVC) clf = LinearSVC() # 学習用データと結果の学習 clf.fit(learn_data, learn_label) # テストデータによる予測 test_data = [[0, 0], [1, 0], [0, 1], [1, 1]] test_label = clf.predict(test_data) # 予測結果の評価 print(test_data, " の予測結果: ", test_label) print("正解率: ", accuracy_score([0, 0, 0, 1], test_label))
■インストール時にエラー インストール時に以下のようなエラーになることがあった
$ sudo pip3 install sklearn ERROR: Command errored out with exit status 1: /usr/local/bin/python3.8 /usr/local/lib/python3.8/site-packages/pip install
Python - pythonでscikit-learnがインストールできない|teratail https://teratail.com/questions/223561 Pythonの新しいバージョンに対応できていない可能性があるので、バージョンを下げて試す このときはPython3.8で上記エラーになったが、Python3.7だとインストールできた ■AnacondaのCGI環境で動作しないので試行錯誤中 Anaconda Prompt では動作するが、コマンドプロンプトやCGIだとscikitを認識できない? 以下の解説に習って「Add Anaconda to the system PATH environment variable」のチェックを外したが、それが問題になっているかも 【Python】非エンジニアWindowユーザー向けのAnacondaインストールの手順 https://tonari-it.com/python-anaconda-install/ 以下の記事では、チェックを入れるように案内されている Windows10でpythonを使う環境を作る?:AnacondaとPycharm - プロクラシスト https://www.procrasist.com/entry/2016/10/04/200000 チェックを入れて再インストールすると、コマンドプロンプトからは sklearn を呼び出せた …と思ったが、C:\Users\refirio\Anaconda3 の場所で実行するか否かによって違う? コマンドプロンプトでもアナコンダプロンプトでも同じ? ただしCGI経由だと以下のエラーになる Pythonのパスは #!/Users/refirio/Anaconda3/python から変える必要はないか
[Tue Sep 24 00:19:40.842477 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] End of script output before headers: sklearn.py [Tue Sep 24 00:19:40.842477 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] AH01215: Traceback (most recent call last):\r: C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py [Tue Sep 24 00:19:40.842477 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] AH01215: File "C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py", line 9, in <module>\r: C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py [Tue Sep 24 00:19:40.843483 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] AH01215: from sklearn.svm import LinearSVC\r: C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py [Tue Sep 24 00:19:40.843483 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] AH01215: File "C:\\localhost\\home\\raspberrypi\\public_html\\cgi\\sklearn.py", line 9, in <module>\r: C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py [Tue Sep 24 00:19:40.843483 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] AH01215: from sklearn.svm import LinearSVC\r: C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py [Tue Sep 24 00:19:40.843483 2019] [cgi:error] [pid 11380:tid 1900] [client ::1:50053] AH01215: ModuleNotFoundError: No module named 'sklearn.svm'; 'sklearn' is not a package\r: C:/localhost/home/raspberrypi/public_html/cgi/sklearn.py
以下、試行錯誤
pip list pip install sklearn pip install sklearn.svm pip install scikit-learn
【Python】アナコンダプロンプトだけでなくコマンドプロンプトでもPythonを使えるようにする|ぷんたむの悟りの書 https://punhundon-lifeshift.com/python_command_prompt anaconda 環境を設定しscikit-learnを実行する - Qiita https://qiita.com/KENOSIN/items/f9fef4da20cdd4489950 Pythonおよび機械学習勉強用のRaspberryPiの構築 - Qiita https://qiita.com/rhene/items/71b92c253d5ac2a4cc52 いったん諦めて、常に Raspberry Pi 環境で実行することにした ■Raspberry PiのCGI環境で動作しないので試行錯誤中
$ sudo pip3 install sklearn $ python3 Python 3.7.3 (default, Apr 3 2019, 05:39:12) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> from sklearn.svm import LinearSVC >>> from sklearn.metrics import accuracy_score >>> exit() $ python3 test.py この環境でも、コマンドラインからは呼び出せるが、CGI経由だと以下のエラーになる CGI経由の場合は環境変数がセットされないので、何らかの対策が必要? [Wed Sep 25 00:03:37.128014 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] AH01215: Traceback (most recent call last):: /var/www/cgi-bin/test/sklearn.py [Wed Sep 25 00:03:37.128256 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] AH01215: File "/var/www/cgi-bin/test/sklearn.py", line 5, in <module>: /var/www/cgi-bin/test/sklearn.py [Wed Sep 25 00:03:37.128320 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] AH01215: from sklearn.svm import LinearSVC: /var/www/cgi-bin/test/sklearn.py [Wed Sep 25 00:03:37.128409 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] AH01215: File "/var/www/cgi-bin/test/sklearn.py", line 5, in <module>: /var/www/cgi-bin/test/sklearn.py [Wed Sep 25 00:03:37.128469 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] AH01215: from sklearn.svm import LinearSVC: /var/www/cgi-bin/test/sklearn.py [Wed Sep 25 00:03:37.128578 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] AH01215: ModuleNotFoundError: No module named 'sklearn.svm'; 'sklearn' is not a package: /var/www/cgi-bin/test/sklearn.py [Wed Sep 25 00:03:37.143283 2019] [cgi:error] [pid 19171:tid 1952445472] [client 192.168.1.110:50839] End of script output before headers: sklearn.py
■scikit-learn(機械学習)でアヤメの分類
■アヤメの分類 pandas/iris.csv at master - pandas-dev/pandas - GitHub https://github.com/pandas-dev/pandas/blob/master/pandas/tests/data/iris.csv GitHub - kujirahand/book-mlearn-gyomu: Book sample (AI Machine-learning Deep-learning) https://github.com/kujirahand/book-mlearn-gyomu
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import accuracy_score # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") # アヤメデータをラベルと入力データに分離する y = iris_data.loc[:,"Name"] x = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) # 学習する clf = SVC() clf.fit(x_train, y_train) # 評価する y_pred = clf.predict(x_test) print("正解率 = " , accuracy_score(y_test, y_pred))
以下、勉強メモ train_test_split関数でデータ分割 - PyQ 1.0 ドキュメント https://docs.pyq.jp/python/machine_learning/tips/train_test_split.html iris.csv
SepalLength,SepalWidth,PetalLength,PetalWidth,Name 5.1,3.5,1.4,0.2,Iris-setosa 4.9,3.0,1.4,0.2,Iris-setosa 7.0,3.2,4.7,1.4,Iris-versicolor 6.4,3.2,4.5,1.5,Iris-versicolor 6.3,3.3,6.0,2.5,Iris-virginica 5.8,2.7,5.1,1.9,Iris-virginica
iris.py
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import accuracy_score # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") print("iris_test.csv") print(iris_data) # アヤメデータをラベルと入力データに分離する y = iris_data.loc[:,"Name"] x = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] print("y") print(y) print("x") print(x) # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) print("x_train") print(x_train) print("x_test") print(x_test) print("y_train") print(y_train) print("y_test") print(y_test)
以下のとおり実行
$ python3 iris_test.py iris_test.csv SepalLength SepalWidth PetalLength PetalWidth Name 0 5.1 3.5 1.4 0.2 Iris-setosa 1 4.9 3.0 1.4 0.2 Iris-setosa 2 7.0 3.2 4.7 1.4 Iris-versicolor 3 6.4 3.2 4.5 1.5 Iris-versicolor 4 6.3 3.3 6.0 2.5 Iris-virginica 5 5.8 2.7 5.1 1.9 Iris-virginica y 0 Iris-setosa 1 Iris-setosa 2 Iris-versicolor 3 Iris-versicolor 4 Iris-virginica 5 Iris-virginica Name: Name, dtype: object x SepalLength SepalWidth PetalLength PetalWidth 0 5.1 3.5 1.4 0.2 1 4.9 3.0 1.4 0.2 2 7.0 3.2 4.7 1.4 3 6.4 3.2 4.5 1.5 4 6.3 3.3 6.0 2.5 5 5.8 2.7 5.1 1.9 x_train SepalLength SepalWidth PetalLength PetalWidth 5 5.8 2.7 5.1 1.9 2 7.0 3.2 4.7 1.4 0 5.1 3.5 1.4 0.2 3 6.4 3.2 4.5 1.5 x_test SepalLength SepalWidth PetalLength PetalWidth 1 4.9 3.0 1.4 0.2 4 6.3 3.3 6.0 2.5 y_train 5 Iris-virginica 2 Iris-versicolor 0 Iris-setosa 3 Iris-versicolor Name: Name, dtype: object y_test 1 Iris-setosa 4 Iris-virginica Name: Name, dtype: object
■scikit-learn(機械学習)でワインの品質判定
Index of /ml/machine-learning-databases/wine-quality https://archive.ics.uci.edu/ml/machine-learning-databases/wine-quality/ GitHub - kujirahand/book-mlearn-gyomu: Book sample (AI Machine-learning Deep-learning) https://github.com/kujirahand/book-mlearn-gyomu 以下のプログラムで学習&評価できるが、正解率は6〜7割程度と低い
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score from sklearn.metrics import classification_report # データを読み込む wine = pd.read_csv("winequality-white.csv", sep=";", encoding="utf-8") # データをラベルとデータに分離 y = wine["quality"] x = wine.drop("quality", axis=1) # 学習用とテスト用に分割する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) # 学習する model = RandomForestClassifier() model.fit(x_train, y_train) # 評価する y_pred = model.predict(x_test) print(classification_report(y_test, y_pred)) print("正解率=", accuracy_score(y_test, y_pred))
以下のプログラムで確認すると、品質データの数には大きく偏りがあることが判る (品質の大半は5〜7で、2以下と10は存在すらしていない) なお結果のグラフは wine-count-plt.png に出力されるが、出力できるようにあらかじめパーミッションを調整しておく
import matplotlib.pyplot as plt import pandas as pd # ワインデータの読み込み wine = pd.read_csv("winequality-white.csv", sep=";", encoding="utf-8") # 品質データごとにグループ分けして、その数を数える count_data = wine.groupby('quality')["quality"].count() print(count_data) # 数えたデータをグラフに描画 count_data.plot() plt.savefig("wine-count-plt.png") plt.show()
以下のように、品質を3段階に再分類する これにより、正解率は9割以上になる 1, 2, 3, 4 → 0(悪い) 5, 6, 7 → 1(普通) 8, 9, 10 → 2(良い)
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.ensemble import RandomForestClassifier from sklearn.metrics import accuracy_score from sklearn.metrics import classification_report # データを読み込む wine = pd.read_csv("winequality-white.csv", sep=";", encoding="utf-8") # データをラベルとデータに分離 y = wine["quality"] x = wine.drop("quality", axis=1) # yのラベルを付け直す newlist = [] for v in list(y): if v <= 4: newlist += [0] elif v <= 7: newlist += [1] else: newlist += [2] y = newlist # 学習用とテスト用に分割する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) # 学習する model = RandomForestClassifier() model.fit(x_train, y_train) # 評価する y_pred = model.predict(x_test) print(classification_report(y_test, y_pred)) print("正解率=", accuracy_score(y_test, y_pred))
■scikit-learn(機械学習)で気象データを解析
気象庁|過去の気象データ・ダウンロード https://www.data.jma.go.jp/gmd/risk/obsdl/ 東京の10年分の平均気温を取得する 地点を選ぶ ... 東京 → 東京 項目を選ぶ ... 日別値 → 日平均気温 期間を選ぶ ... 2006年1月1日〜2016年12月31日 として「CSVファイルダウンロード」をクリック 余計な項目も含まれているので、以下のプログラムでデータを整形する
in_file = "data.csv" out_file = "temperature.csv" # CSVファイルを一行ずつ読み込み with open(in_file, "rt", encoding="Shift_JIS") as fr: lines = fr.readlines() # ヘッダをそぎ落として、新たなヘッダをつける lines = ["年,月,日,気温,品質,均質\n"] + lines[5:] lines = map(lambda v: v.replace('/', ','), lines) result = "".join(lines).strip() print(result) # 結果をファイルへ出力 with open(out_file, "wt", encoding="utf-8") as fw: fw.write(result) print("saved.")
以下のプログラムで平均を表示できる
import pandas as pd # PandasでCSVを読み込む df = pd.read_csv("temperature.csv", encoding="utf-8") # 日付ごとに気温をリストにまとめる md = {} for i, row in df.iterrows(): m, d, v = (int(row['月']), int(row['日']), float(row['気温'])) key = str(m) + "/" + str(d) if not(key in md): md[key] = [] md[key] += [v] # 日付ごとに平均を求める avs = {} for key in md: v = avs[key] = sum(md[key]) / len(md[key]) print("{0} : {1}".format(key, v)) # 11月3日の平均気温を表示 print(avs["11/3"])
以下のようにすれば、よりかんたんに平均を求めることができる
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import pandas as pd # CSVを読み込む df = pd.read_csv("temperature.csv", encoding="utf-8") # 月ごとに平均を求める g = df.groupby(['月'])["気温"] gg = g.sum() / g.count() # 結果を出力 print(gg) gg.plot() plt.savefig("average.png") plt.show()
以下のようにすれば、年ごとに30度超えの日数を表示できる
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt import pandas as pd # CSVを読み込む df = pd.read_csv("temperature.csv", encoding="utf-8") # 気温が30度超えのデータを調べる bool_30 = (df["気温"] > 30) # データを抜き出す over_30 = df[bool_30] # 年ごとにカウント count = over_30.groupby(["年"])["年"].count() # 結果を出力 print(count) count.plot() plt.savefig("over30.png") plt.show()
以下のようにすれば、過去6日の気温から翌日の気温を予測できる
from sklearn.linear_model import LinearRegression import pandas as pd import numpy as np import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 気温データ10年分の読み込み df = pd.read_csv('temperature.csv', encoding="utf-8") # データを学習用とテスト用に分割する train_year = (df["年"] <= 2015) test_year = (df["年"] >= 2016) interval = 6 # 過去6日分を学習するデータを作成 def make_data(data): x = [] # 学習データ(過去6日分の気温) y = [] # 結果(翌日の気温) temps = list(data["気温"]) for i in range(len(temps)): if i < interval: continue y.append(temps[i]) xa = [] for p in range(interval): d = i + p - interval xa.append(temps[d]) x.append(xa) return (x, y) train_x, train_y = make_data(df[train_year]) test_x, test_y = make_data(df[test_year]) # 直線回帰分析を行う lr = LinearRegression(normalize=True) lr.fit(train_x, train_y) # 学習 pre_y = lr.predict(test_x) # 予測 # 結果を図にプロット plt.figure(figsize=(10, 6), dpi=100) plt.plot(test_y, c='r') plt.plot(pre_y, c='b') plt.savefig('predict.png') plt.show()
■scikit-learn(機械学習)での最適なアルゴリズムやパラメータを探す
$ sudo pip3 install pytest $ sudo pip3 install cython
各アルゴリズムの正解率を比較 ただし2021年2月現在、実行すると以下のエラーになる
$ python3 algorithm.py Traceback (most recent call last): File "algorithm.py", line 5, in <module> from sklearn.utils.testing import all_estimators ModuleNotFoundError: No module named 'sklearn.utils.testing'
以下をインストールしても変化なし
$ sudo pip3 install sklearn.utils
以下は以前のメモ
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score import warnings from sklearn.utils.testing import all_estimators import warnings warnings.filterwarnings('ignore') # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") # アヤメデータをラベルと入力データに分離する y = iris_data.loc[:,"Name"] x = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] # 学習用とテスト用に分離する warnings.filterwarnings('ignore') x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) # classifierのアルゴリズム全てを取得する warnings.filterwarnings("ignore") allAlgorithms = all_estimators(type_filter="classifier") for (name, algorithm) in allAlgorithms: # 一部のアルゴリズムでエラーになるので除外(要調査) if name == "CheckingClassifier" or name == "ClassifierChain" or name == "MultiOutputClassifier" or name == "OneVsOneClassifier" or name == "OneVsRestClassifier" or name == "OutputCodeClassifier" or name == "VotingClassifier": continue # 各アリゴリズムのオブジェクトを作成 clf = algorithm() # 学習して、評価する clf.fit(x_train, y_train) y_pred = clf.predict(x_test) print(name, "の正解率 = " , accuracy_score(y_test, y_pred))
クロスバリデーション
import pandas as pd from sklearn.model_selection import KFold from sklearn.model_selection import cross_val_score import warnings from sklearn.utils.testing import all_estimators # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") # アヤメデータをラベルと入力データに分離する y = iris_data.loc[:,"Name"] x = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] # classifierのアルゴリズム全てを取得する warnings.filterwarnings("ignore") allAlgorithms = all_estimators(type_filter="classifier") # K分割クロスバリデーション用オブジェクト kfold_cv = KFold(n_splits=5, shuffle=True) for (name, algorithm) in allAlgorithms: # 一部のアルゴリズムでエラーになるので除外(要調査) if name == "CheckingClassifier" or name == "ClassifierChain" or name == "MultiOutputClassifier" or name == "OneVsOneClassifier" or name == "OneVsRestClassifier" or name == "OutputCodeClassifier" or name == "VotingClassifier": continue # 各アリゴリズムのオブジェクトを作成 clf = algorithm() # scoreメソッドをもつクラスを対象とする if hasattr(clf,"score"): # クロスバリデーションを行う scores = cross_val_score(clf, x, y, cv=kfold_cv) print(name,"の正解率=") print(scores)
最適なパラメータを探す
import pandas as pd from sklearn.model_selection import train_test_split from sklearn.svm import SVC from sklearn.metrics import accuracy_score from sklearn.model_selection import KFold from sklearn.model_selection import GridSearchCV # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") # アヤメデータをラベルと入力データに分離する y = iris_data.loc[:,"Name"] x = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) # グリッドサーチで利用するパラメータを指定 parameters = [ {"C": [1, 10, 100, 1000], "kernel":["linear"]}, {"C": [1, 10, 100, 1000], "kernel":["rbf"], "gamma":[0.001, 0.0001]}, {"C": [1, 10, 100, 1000], "kernel":["sigmoid"], "gamma": [0.001, 0.0001]} ] # グリッドサーチを行う kfold_cv = KFold(n_splits=5, shuffle=True) clf = GridSearchCV( SVC(), parameters, cv=kfold_cv) clf.fit(x_train, y_train) print("最適なパラメータ = ", clf.best_estimator_) # 最適なパラメータで評価 y_pred = clf.predict(x_test) print("評価時の正解率 = " , accuracy_score(y_test, y_pred))
■scikit-learn(機械学習)で言語を判定
利用されている文字コードが異なる言語を判定
import numpy as np from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score # Unicodeのコードポイント頻度測定 def count_codePoint(str): # Unicodeのコードポイントをアドレスとする配列を用意 counter = np.zeros(65535) for i in range(len(str)): # 各文字をUnicodeのコードポイントに変換 code_point = ord(str[i]) if code_point > 65535 : continue # 対応するアドレスの出現回数をインクリメント counter[code_point] += 1 # 各要素を文字数で割って正規化 counter = counter/len(str) return counter # 学習用データの準備 ja_str = 'これは日本語の文章です。' en_str = 'This is English Sentences.' th_str = '(タイ語の文章)' x_train = [count_codePoint(ja_str),count_codePoint(en_str),count_codePoint(th_str)] y_train = ['ja','en','th'] # 学習する clf = GaussianNB() clf.fit(x_train, y_train) # 評価用データの準備 ja_test_str = 'こんにちは' en_test_str = 'Hello' th_test_str = '(タイ語の文章)' x_test = [count_codePoint(en_test_str),count_codePoint(th_test_str),count_codePoint(ja_test_str)] y_test = ['en', 'th', 'ja'] # 評価する y_pred = clf.predict(x_test) print(y_pred) print("正解率 = " , accuracy_score(y_test, y_pred))
利用されている文字コードが同じ言語を判定 あらかじめ以下のファイルを用意しておく de, en , es からはじまるファイルの内容は、それぞれドイツ語、英語、スペイン語の内容にしておく train/de_cat.txt train/de_dog.txt train/de_elephant.txt train/en_cat.txt train/en_dog.txt train/en_elephant.txt train/es_cat.txt train/es_dog.txt train/es_elephant.txt test/de_lion.txt test/en_lion.txt test/es_lion.txt
import numpy as np from sklearn.naive_bayes import GaussianNB from sklearn.metrics import accuracy_score import glob # Unicodeのコードポイント頻度測定 def count_codePoint(str): # Unicodeのコードポイントをアドレスとする配列を用意 counter = np.zeros(65535) for i in range(len(str)): # 各文字をUnicodeのコードポイントに変換 code_point = ord(str[i]) if code_point > 65535 : continue # 対応するアドレスの出現回数をインクリメント counter[code_point] += 1 # 各要素を文字数で割って正規化 counter = counter/len(str) return counter # 学習データの準備 index = 0 x_train = [] y_train = [] for file in glob.glob('./train/*.txt'): # 言語情報の取得し、ラベルに設定 y_train.append(file[8:10]) # ファイル内の文字列を連結後、Unicodeのコードポイント頻度測定し、入力データに設定 file_str = '' for line in open(file, 'r'): file_str = file_str + line x_train.append(count_codePoint(file_str)) # 学習する clf = GaussianNB() clf.fit(x_train, y_train) # 評価データの準備 index = 0 x_test = [] y_test = [] for file in glob.glob('./test/*.txt'): # 言語情報の取得し、ラベルに設定 y_test.append(file[7:9]) # ファイル内の文字列を連結後、Unicodeのコードポイント頻度測定し、入力データに設定 file_str = '' for line in open(file, 'r'): file_str = file_str + line x_test.append(count_codePoint(file_str)) # 評価する y_pred = clf.predict(x_test) print(y_pred) print("正解率 = " , accuracy_score(y_test, y_pred))
■scikit-learn(機械学習)で数字を判定
■手書きの数字画像を表示 datasets.load_digits() で手書き数字のデータを参照できる digits.images ... 画像データの配列 digits.target ... データがどの数字を表すかのラベル
import matplotlib matplotlib.use('Agg') import matplotlib.pyplot as plt # 手書きデータを読み込む from sklearn import datasets digits = datasets.load_digits() # 15個連続で出力する for i in range(15): plt.subplot(3, 5, i+1) # 3行×5列の枠組みを用意し、i+1番目に表示する plt.axis("off") # 軸線を表示しない plt.title(str(digits.target[i])) # 見出し文字 plt.imshow(digits.images[i], cmap="gray") # 画像をグレースケールで表示する # 画像に保存する plt.savefig("output.png")
■手書きの数字を学習&判定 以下で学習させる
from sklearn.model_selection import train_test_split from sklearn import datasets, svm, metrics from sklearn.metrics import accuracy_score #from sklearn.externals import joblib import joblib # データを読み込む digits = datasets.load_digits() x = digits.images y = digits.target x = x.reshape((-1, 64)) # 二次元配列を一次元配列に変換 # データを学習用とテスト用に分割する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) # データを学習 clf = svm.LinearSVC() clf.fit(x_train, y_train) # 予測して精度を確認する y_pred = clf.predict(x_test) print(accuracy_score(y_test, y_pred)) # 学習済みデータを保存 joblib.dump(clf, "digits.pkl")
以下で判定させる 手書きの画像を number フォルダ内に 0.png 〜 9.png の名前で保存しておく ただし自分の手書き文字で試すと正解率は50%程度 ディープラーニングを用いた方法の方が制度が高くなるらしいので、引き続き要勉強
import cv2 #from sklearn.externals import joblib import joblib def predict_digit(filename): # 学習済みデータを読み込む clf = joblib.load("digits.pkl") # 自分で用意した手書きの画像ファイルを読み込む my_img = cv2.imread(filename) # 画像データを学習済みデータに合わせる my_img = cv2.cvtColor(my_img, cv2.COLOR_BGR2GRAY) my_img = cv2.resize(my_img, (8, 8)) my_img = 15 - my_img // 16 # 白黒反転する # 二次元を一次元に変換 my_img = my_img.reshape((-1, 64)) # データ予測する res = clf.predict(my_img) return res[0] # 画像ファイルを指定して実行 for i in range(10): n = predict_digit("number/" + str(i) + ".png") print("my" + str(i) + ".png = " + str(n))
■scikit-learn(機械学習)でスパムメールを判定
以下からスパムメールと通常メールを取得 GitHub - kujirahand/spam-database-ja: Spam database for Japanese https://github.com/kujirahand/spam-database-ja not-spam-sjis をもとに、以下の手順で文字コード変換をして not-spam-utf8 を作成する 複数ファイルのエンコードの変換 - EmEditor (テキストエディタ) https://jp.emeditor.com/text-editor-features/versatility/multiple-file-encoding-conversions/ 上記手順で作成した、「spam-utf8」「not-spam-utf8」以下を使用して進める 「spam-utf8」を「spam」として配置し、「not-spam-utf8」を「ok」として配置する また、以下のプログラムを作成する makedb_spamcheck.py
import os, glob import MeCab import numpy as np import pickle # ファイル名を定義 data_file = "./spamcheck-data.pickle" # 変数の準備 word_dic = {"__id": 0} # 単語辞書 files = [] # 読み込んだ単語データを追加する # MeCabの準備 tagger = MeCab.Tagger() # 指定したディレクトリ内のファイル一覧を読み込む def read_files(dir, label): # テキストファイルの一覧を得る files = glob.glob(dir + "/*.txt") for f in files: read_file(f, label) # ファイルを読み込む def read_file(filename, label): words = [] # ファイルの内容を読み込む with open(filename, "rt", encoding="utf-8") as f: text = f.read() files.append({ "label": label, "words": text_to_ids(text) }) # テキストを単語IDのリストに変換 def text_to_ids(text): # 形態素解析 word_s = tagger.parse(text) # 以下のような解析内容を得られるので、これを一行ずつ処理していく # # 友達 名詞,一般,*,*,*,*,友達,トモダチ,トモダチ # が 助詞,格助詞,一般,*,*,*,が,ガ,ガ # 遊び 名詞,一般,*,*,*,*,遊び,アソビ,アソビ # に 助詞,格助詞,一般,*,*,*,に,ニ,ニ # 来る 動詞,自立,*,*,カ変・来ル,基本形,来る,クル,クル words = [] # 単語を辞書に登録 for line in word_s.split("\n"): if line == "EOS" or line == "": continue word = line.split("\t")[0] params = line.split("\t")[1].split(",") hinsi = params[0] # 品詞 bunrui = params[1] # 品詞の分類 org = params[6] # 単語の原型 # 助詞・助動詞・記号・数字は処理しない if not (hinsi in ["名詞", "動詞", "形容詞"]): continue if hinsi == "名詞" and bunrui == "数詞": continue # 単語をidに変換 id = word_to_id(org) words.append(id) return words # 単語をidに変換 def word_to_id(word): # 単語が辞書に登録されているか if not (word in word_dic): # 登録されていないので新たにIDを割り振る id = word_dic["__id"] word_dic["__id"] += 1 word_dic[word] = id else: # 既存の単語IDを返す id = word_dic[word] return id # 単語の頻出頻度のデータを作る def make_freq_data_allfiles(): y = [] x = [] for f in files: y.append(f["label"]) x.append(make_freq_data(f["words"])) return y, x # 単語の出現頻度を取得 def make_freq_data(words): # 単語の出現回数を調べる cnt = 0 dat = np.zeros(word_dic["__id"], "float") for w in words: dat[w] += 1 cnt += 1 # 出現回数を出現頻度に直す dat = dat / cnt return dat # ファイルの一覧から学習用の単語頻出データベースを作る if __name__ == "__main__": read_files("ok", 0) read_files("spam", 1) y, x = make_freq_data_allfiles() # ファイルにデータを保存 pickle.dump([y, x, word_dic], open(data_file, "wb")) print("単語頻出データベース作成完了")
train_spamcheck.py
import pickle from sklearn.naive_bayes import GaussianNB from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score # ファイル名を定義 data_file = "./spamcheck-data.pickle" model_file = "./spamcheck-model.pickle" # データファイルの読込 data = pickle.load(open(data_file, "rb")) y = data[0] # ラベル x = data[1] # 単語の出現頻度 # 学習とテストを100回繰り返す count = 100 rate = 0 for i in range(count): # データを学習用とテスト用に分割 x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) # 学習する model = GaussianNB() model.fit(x_train, y_train) # 評価する y_pred = model.predict(x_test) acc = accuracy_score(y_test, y_pred) # 評価結果が良ければモデルを保存 if acc > 0.94: pickle.dump(model, open(model_file, "wb")) print(acc) rate += acc # 平均値を表示 print("----") print("平均=", rate / count)
test_spamcheck.py
import pickle import MeCab import numpy as np from sklearn.naive_bayes import GaussianNB # テストするテキスト test_text1 = """ 会社から支給されているiPhoneの調子が悪いのです。 修理に出すので、しばらくはアプリのテストができません。 """ test_text2 = """ 億万長者になる方法を教えます。 すぐに以下のアドレスに返信して。 """ # ファイル名を定義 data_file = "./spamcheck-data.pickle" model_file = "./spamcheck-model.pickle" label_names = ["OK", "SPAM"] # 単語辞書の読み込む data = pickle.load(open(data_file, "rb")) word_dic = data[2] # 学習済みモデルの読み込む model = pickle.load(open(model_file, "rb")) # MeCabの準備 tagger = MeCab.Tagger() # テキストがスパムかどうか判定する def check_spam(text): # テキストを単語IDのリストに変換し単語の頻出頻度を調べる zw = np.zeros(word_dic["__id"]) count = 0 s = tagger.parse(text) # 単語毎の回数を加算 for line in s.split("\n"): if line == "EOS": break params = line.split("\t")[1].split(",") org = params[6] # 単語の原型 if org in word_dic: id = word_dic[org] zw[id] += 1 count += 1 zw = zw / count # 予測 pre = model.predict([zw])[0] print("結果=", label_names[pre]) if __name__ == "__main__": print("テキスト1") check_spam(test_text1) print("テキスト2") check_spam(test_text2)
以下で単語頻出データ(spamcheck.pickle)を作成する
$ python3.7 makedb_spamcheck.py 単語頻出データ作成完了
以下で学習済みモデル(spamcheck-model.pickle)を作成する 評価結果が良いものをモデルとして保存する
$ python3.7 train_spamcheck.py 1.0 0.9777777777777777 1.0 〜中略〜 1.0 0.9777777777777777 0.9555555555555556 ---- 平均= 0.9911111111111102
以下でスパムか否かをテスト
$ python3.7 test_spamcheck.py テキスト1 結果= OK テキスト2 結果= SPAM
プログラム実行時に以下のようなエラーになる場合、サンプルデータが0件もしくは読み込みに失敗している可能性がある データファイルが正しく配置されているか確認する
$ python3.7 train_spamcheck.py Traceback (most recent call last): File "train_spamcheck.py", line 21, in <module> x_train, x_test, y_train, y_test = train_test_split(x, y, test_size=0.2) File "/usr/local/lib64/python3.7/site-packages/sklearn/model_selection/_split.py", line 2176, in train_test_split default_test_size=0.25) File "/usr/local/lib64/python3.7/site-packages/sklearn/model_selection/_split.py", line 1861, in _validate_shuffle_split train_size) ValueError: With n_samples=0, test_size=0.2 and train_size=None, the resulting train set will be empty. Adjust any of the aforementioned parameters.
■TensorFlow(ディープラーニング)
TensorFlow(テンソルフロー)は物体認識の分野で圧倒的な性能を示すようになり、 今は画像・音声・自然言語処理など、さまざまな分野で活用されている TensorFlow https://www.tensorflow.org/ Googleがオープンソースで公開している機械学習ライブラリで、機械学習やディープラーニングを実践できる Gmailでの迷惑メール除去にも使われているらしい スパムはいらない ―― TensorFlow を使って Gmail から新たに 1 億以上のスパム メッセージを除去 | Google Cloud Blog https://cloud.google.com/blog/ja/products/gcp/ridding-gmail-of-100-million-more-spam-messages-with-t... ■テンソル ディープラーニングの数学「スカラー・ベクトル・行列・テンソル」とは? | あぱーブログ https://blog.apar.jp/deep-learning/12121/ 「テンソル」「ベクトル」「行列」とは?ディープラーニングの情報整理のカラクリ 連載:図でわかる3分間AIキソ講座|ビジネス+IT https://www.sbbit.jp/article/cont1/63580 ディープラーニングでは、複雑なニューラルネットワーク上で膨大な数の数値がやりとりされる コンピュータではこれらの数値を扱うことができるが、数値の羅列だと人間には理解しづらく、技術の応用や発展も難しい そこで使われるようになったのが「テンソル(Tensor)」という数学的概念 基本的には「たくさんの数値を集めて、1つの情報として表現する」のがテンソル スカラーは単なる数値 スカラーを縦もしくは横に並べたものをベクトルという スカラーを縦横に並べたものを行列という 上記も含めて、スカラーを縦横斜めなど複数に並べたものをまとめて「テンソル」と呼ぶ これはプログラムの配列をイメージすると解りやすい 0次元テンソル … 0次元の配列(スカラー) 1次元テンソル … 1次元の配列(ベクトル) 2次元テンソル … 2次元の配列(行列) 3次元テンソル … 3次元の配列 4次元テンソル … 4次元の配列 X次元テンソル … X次元の配列 例えば2次元の配列なら「行列」という呼び方があるが、3次元以上になると決まった呼び方がない よって「3次元のテンソル」や「3階のテンソル」などと呼ぶ TensorFlowでは、グラフを構成するすべてのものをテンソルとして扱う ■TensorFlowのインストール
$ sudo apt install libatlas-base-dev $ sudo pip3 install tensorflow
Raspberry Pi 4 4B-32GB の環境ではインストールできた Raspberry Pi 3 Model b+ の環境では以下のエラーになったが、「sudo pip3 install tensorflow」を3回目でインストールに成功した
Looking in indexes: https://pypi.org/simple, https://www.piwheels.org/simple Collecting tensorflow Downloading https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv7l.whl (93.2MB) 85% |■■■■■■■■■■■■■■ | 79.8MB 2.3MB/s eta 0:00:06 THESE PACKAGES DO NOT MATCH THE HASHES FROM THE REQUIREMENTS FILE. If you have updated the package versions, please update the hashes. Otherwise, examine the package contents carefully; someone may have tampered with them. tensorflow from https://www.piwheels.org/simple/tensorflow/tensorflow-1.13.1-cp37-none-linux_armv7l.whl#sha256=25f4f... Expected sha256 25f4ff027beec1e568baf8e90a07bad59d354560533d6b37318b9efeb70beeb1 Got 4d215130b13d9606e91a2327383cf98e603e9e53294c2d68c59e8b5224e8a923
以下で動作確認
$ python3 Python 3.7.3 (default, Apr 3 2019, 05:39:12) [GCC 8.2.0] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import tensorflow as tf >>> sess = tf.Session() >>> hello = tf.constant('Hello.') >>> print(sess.run(hello)) b'Hello.' >>> exit()
Raspberry Pi 4 4B-32GB の環境では「import tensorflow as tf」を実行したときに以下の警告が表示されたが動作した
2021-02-06 14:47:10.086584: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory
Raspberry Pi 3 Model b+ の環境では「import tensorflow as tf」を実行したときに以下の警告が表示されたが動作した Pythonのバージョン次第で表示されないらしいが、いったんこのまま進める
WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.AUTO_REUSE is deprecated. Please use tf.compat.v1.AUTO_REUSE instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.AttrValue is deprecated. Please use tf.compat.v1.AttrValue instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.COMPILER_VERSION is deprecated. Please use tf.version.COMPILER_VERSION instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.CXX11_ABI_FLAG is deprecated. Please use tf.sysconfig.CXX11_ABI_FLAG instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.ConditionalAccumulator is deprecated. Please use tf.compat.v1.ConditionalAccumulator instead.
Raspberry PiにTensorFlowをインストールして基本的な分類サンプル実行まで試した - Qiita https://qiita.com/hidakanoko/items/5292ca79e3ff53867e40 RaspberryPiで機械学習TensorFlowセットアップ - Qiita https://qiita.com/totoshi/items/7eb690926eebafdb49ff Raspbian に公式対応した TensorFlow を入れてみたら警告が出たのでどうにかしてみたって話 - Qiita https://qiita.com/ktooi/items/48a8d18839cae7246c0b ■TensorFlowのインストール(CentOS7) 以下などを試したがインストールできず
# pip3 install tensorflow # pip3 install --upgrade https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.8.0-py3-none-any.whl # pip3 install tensorflow-gpu==2.4 # pip3 install tensorflow-gpu==1.14.0 # yum -y groupinstall "Base" "Development tools" # pip3 install tensorflow # yum -y install python3-devel # pip3 install tensorflow # pip3 install tensorflow-gpu==1.14.0 # pip3 install tensorflow==2.0.0b1
TensorFlow のインストール https://docs.vmware.com/jp/VMware-vSphere-Bitfusion/3.0/Example-Guide/GUID-1C053853-4D83-4D94-A6F3-D... 以下のエラーメッセージによると、「-std=gnu99」のオプションが問題になっているようだが対応方法が判らず
# pip3 install tensorflow==2.0.0b1 gcc -pthread -Wno-unused-result -Wsign-compare -DNDEBUG -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -m64 -mtune=generic -D_GNU_SOURCE -fPIC -fwrapv -fPIC -D_WIN32_WINNT=1536 -DGPR_BACKWARDS_COMPATIBILITY_MODE=1 -DHAVE_CONFIG_H=1 -DGRPC_ENABLE_FORK_SUPPORT=1 -DPyMODINIT_FUNC=extern "C" __attribute__((visibility ("default"))) PyObject* -DGRPC_POSIX_FORK_ALLOW_PTHREAD_ATFORK=1 -Isrc/python/grpcio -Iinclude -I. -Ithird_party/abseil-cpp -Ithird_party/address_sorting/include -Ithird_party/cares -Ithird_party/cares/cares -Ithird_party/cares/config_linux -Ithird_party/re2 -Ithird_party/boringssl-with-bazel/src/include -Ithird_party/upb -Isrc/core/ext/upb-generated -Isrc/core/ext/upbdefs-generated -Ithird_party/xxhash -Ithird_party/zlib -I/usr/include/python3.6m -c src/python/grpcio/grpc/_cython/cygrpc.cpp -o python_build/temp.linux-x86_64-3.6/src/python/grpcio/grpc/_cython/cygrpc.o -std=c++11 -std=gnu99 -fvisibility=hidden -fno-wrapv -fno-exceptions -pthread cc1plus: warning: command line option ‘-std=gnu99’ is valid for C/ObjC but not for C++ [enabled by default] 〜中略〜 Traceback (most recent call last): File "/tmp/pip-build-nppnb9ij/grpcio/src/python/grpcio/commands.py", line 286, in build_extensions build_ext.build_ext.build_extensions(self) File "/usr/lib64/python3.6/distutils/command/build_ext.py", line 448, in build_extensions self._build_extensions_serial() File "/usr/lib64/python3.6/distutils/command/build_ext.py", line 473, in _build_extensions_serial self.build_extension(ext) File "/usr/local/lib/python3.6/site-packages/setuptools/command/build_ext.py", line 202, in build_extension _build_ext.build_extension(self, ext) File "/usr/lib64/python3.6/distutils/command/build_ext.py", line 533, in build_extension depends=ext.depends) File "/usr/lib64/python3.6/distutils/ccompiler.py", line 574, in compile self._compile(obj, src, ext, cc_args, extra_postargs, pp_opts) File "/usr/lib64/python3.6/distutils/unixccompiler.py", line 129, in _compile raise CompileError(msg) distutils.errors.CompileError: command 'gcc' failed with exit status 1 ---------------------------------------- Command "/usr/bin/python3 -u -c "import setuptools, tokenize;__file__='/tmp/pip-build-nppnb9ij/grpcio/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /tmp/pip-dqgchcji-record/install-record.txt --single-version-externally-managed --compile" failed with error code 1 in /tmp/pip-build-nppnb9ij/grpcio/
-std=c99と-std=gnu99は同じ? - bugfix https://pneumaster.hatenadiary.org/entry/20081224/p1 ■足し算を行う
import tensorflow as tf # 定数を定義 a = tf.constant(100) b = tf.constant(30) # 演算を定義 add_op = a + b # セッションを開始する sess = tf.Session() # 式を評価する res = sess.run(add_op) print(res)
■データフローログ
$ sudo mkdir logs $ sudo chown smbuser. logs $ sudo chmod 0777 logs
プログラムを作成する
import tensorflow as tf # 定数を定義 a = tf.constant(10, name='10') b = tf.constant(20, name='20') c = tf.constant(30, name='30') # 演算を定義 add_op = tf.add(a, b, name='add') mul_op = tf.multiply(add_op, c, name='mul') # セッションを開始する sess = tf.Session() # 式を評価する res = sess.run(mul_op) print(res) # TensorBoardのためにグラフを出力 tf.summary.FileWriter('./logs', sess.graph)
プログラム実行後、tensorboard コマンドでデータフローグラフを表示できる
$ python3 test_mul_tb.py $ tensorboard --logdir=./logs 2021-02-06 15:06:32.558996: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all TensorBoard 2.0.2 at http://localhost:6006/ (Press CTRL+C to quit)
Raspberry Pi にGUIでアクセスし、ブラウザを起動して以下にアクセスすると「TensorBoard」が表示された http://localhost:6006/ Raspberry Pi 3 Model b+ の環境では以下のエラーになって動作しなかった
$ tensorboard --logdir=./logs WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.AUTO_REUSE is deprecated. Please use tf.compat.v1.AUTO_REUSE instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.AttrValue is deprecated. Please use tf.compat.v1.AttrValue instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.COMPILER_VERSION is deprecated. Please use tf.version.COMPILER_VERSION instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.CXX11_ABI_FLAG is deprecated. Please use tf.sysconfig.CXX11_ABI_FLAG instead. WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow/__init__.py:98: The name tf.ConditionalAccumulator is deprecated. Please use tf.compat.v1.ConditionalAccumulator instead. Traceback (most recent call last): File "/usr/local/bin/tensorboard", line 6, in <module> from tensorboard.main import run_main File "/usr/local/lib/python3.7/dist-packages/tensorboard/main.py", line 44, in <module> from tensorboard import default File "/usr/local/lib/python3.7/dist-packages/tensorboard/default.py", line 44, in <module> from tensorboard.plugins.interactive_inference import interactive_inference_plugin File "/usr/local/lib/python3.7/dist-packages/tensorboard/plugins/interactive_inference/interactive_inference_plugin.py", line 27, in <module> from grpc.framework.interfaces.face.face import AbortionError File "/usr/local/lib/python3.7/dist-packages/grpc/__init__.py", line 23, in <module> from grpc._cython import cygrpc as _cygrpc ImportError: /usr/local/lib/python3.7/dist-packages/grpc/_cython/cygrpc.cpython-37m-arm-linux-gnueabihf.so: undefined symbol: __atomic_exchange_8
■TensorFlowでアヤメの分類 TensorFlowでは、ラベルデータを「One-Hotベクトル」という形式で表す必要がある これは「1つだけHight(1)の状態で、他はLow(0)の状態であるようなビット列のことを指す」 iris.csv は「Pandas(データ解析支援)でアヤメの分類」で使用したものと同じ
import tensorflow as tf import pandas as pd from sklearn.model_selection import train_test_split # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") # アヤメデータをラベルと入力データに分離する y_labels = iris_data.loc[:,"Name"] x_data = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] # ラベルデータをone-hotベクトルに直す labels = { 'Iris-setosa': [1, 0, 0], 'Iris-versicolor': [0, 1, 0], 'Iris-virginica': [0, 0, 1] } y_nums = list(map(lambda v : labels[v] , y_labels)) # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split( x_data, y_nums, train_size=0.8) # アヤメデータの入力値(4次元)と出力値(3次元)を入れる場所を定義 x = tf.placeholder(tf.float32, [None, 4]) y_ = tf.placeholder(tf.float32, [None, 3]) # 重みとバイアスのための変数を定義 w = tf.Variable(tf.zeros([4, 3])) # 重み b = tf.Variable(tf.zeros([3])) # バイアス # ソフトマックス回帰を定義 y = tf.nn.softmax(tf.matmul(x, w) + b) # モデルを訓練する cross_entropy = -tf.reduce_sum(y_ * tf.log(y)) optimizer = tf.train.AdamOptimizer(0.05) train = optimizer.minimize(cross_entropy) # 正解率を求める predict = tf.equal(tf.argmax(y, 1), tf.argmax(y_,1)) accuracy = tf.reduce_mean(tf.cast(predict, tf.float32)) # 変数を初期化 init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) # 変数を初期化 init = tf.global_variables_initializer() sess = tf.Session() sess.run(init) # 学習を行う train_feed_dict = {x: x_train, y_: y_train} for step in range(300): sess.run(train, feed_dict=train_feed_dict) # テストデータで最終的な正解率を求める acc = sess.run(accuracy, feed_dict={x: x_test, y_: y_test}) print("正解率=", acc)
以下のとおり実行する
$ python3.7 iris.py 2021-02-20 12:43:47.841792: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory WARNING:tensorflow:From iris.py:25: The name tf.placeholder is deprecated. Please use tf.compat.v1.placeholder instead. WARNING:tensorflow:From iris.py:36: The name tf.log is deprecated. Please use tf.math.log instead. WARNING:tensorflow:From iris.py:37: The name tf.train.AdamOptimizer is deprecated. Please use tf.compat.v1.train.AdamOptimizer instead. WARNING:tensorflow:From iris.py:45: The name tf.global_variables_initializer is deprecated. Please use tf.compat.v1.global_variables_initializer instead. WARNING:tensorflow:From iris.py:46: The name tf.Session is deprecated. Please use tf.compat.v1.Session instead. 正解率= 0.96666664
「E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132」のエラーが表示されているが、実行に問題は無いようなのでいったん無視しておく Pythonおよび機械学習勉強用のRaspberryPiの構築 (RaspberryPi4 & Buster版 (RaspberryPi3も可)) - Qiita https://qiita.com/rhene/items/d370a3b3f05a7248bd79 Raspberry Pi 4 で機械学習系のパッケージを入れる(numpy, scipy, pandas, sklearn, matplotlib, tensorflow, keras) - 工作と競馬2 https://dekuo-03.hatenablog.jp/entry/2020/02/01/000000_1
■TensorFlow+Keras(ディープラーニング)
KerasはTensorFlowを簡単に使えるようにするためのライブラリだったが、使いやすかったのでTensorFlowに取り込まれた ■Kerasでアヤメの分類 モデル定義部分にある「Dense」というのは、全結合ニューラルネットワーク つまり「keras.layers.Dense」だけで1つのニューラルネットワークを表している 次の「keras.models.Sequential()」は、シーケンシャル(順番)にニューラルネットワークを追加するモデルを定義している 「Dense(10)」では、ユニット数が10個あるネットワークを作成している またこのモデルで最終的な出力は3次元なので、「Dense(3)」によって出力ユニット数を3次元にしている iris.csv は「Pandas(データ解析支援)でアヤメの分類」で使用したものと同じ
import tensorflow as tf #import tensorflow.contrib.keras as keras import tensorflow.keras as keras from sklearn.model_selection import train_test_split import pandas as pd import numpy as np # アヤメデータの読み込み iris_data = pd.read_csv("iris.csv", encoding="utf-8") # アヤメデータをラベルと入力データに分離する y_labels = iris_data.loc[:,"Name"] x_data = iris_data.loc[:,["SepalLength","SepalWidth","PetalLength","PetalWidth"]] # ラベルデータをone-hotベクトルに直す labels = { 'Iris-setosa': [1, 0, 0], 'Iris-versicolor': [0, 1, 0], 'Iris-virginica': [0, 0, 1] } y_nums = np.array(list(map(lambda v : labels[v] , y_labels))) x_data = np.array(x_data) # 学習用とテスト用に分割する x_train, x_test, y_train, y_test = train_test_split( x_data, y_nums, train_size=0.8) # モデル構造を定義 Dense = keras.layers.Dense model = keras.models.Sequential() model.add(Dense(10, activation='relu', input_shape=(4,))) model.add(Dense(3, activation='softmax')) # モデルを構築 model.compile( loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) # 学習を実行 model.fit(x_train, y_train, batch_size=20, epochs=300) # モデルを評価 score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
実行するとエラーになるようになっていたが、
$ python3 keras-iris.py 2021-02-06 15:24:33.126208: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory Traceback (most recent call last): File "keras-iris.py", line 2, in <module> import tensorflow.contrib.keras as keras ModuleNotFoundError: No module named 'tensorflow.contrib'
kerasの読み込み部分を以下のようにすれば実行できた バージョンアップによって読み込み方法が変わったのかもしれない
#import tensorflow.contrib.keras as keras import tensorflow.keras as keras
以下で実行できた
$ python3.7 keras-iris.py 2021-02-20 12:48:40.802940: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow_core/python/ops/resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. Train on 120 samples Epoch 1/300 120/120 [==============================] - 0s 1ms/sample - loss: 2.6795 - acc: 0.3583 Epoch 2/300 120/120 [==============================] - 0s 131us/sample - loss: 2.4687 - acc: 0.3583 Epoch 3/300 120/120 [==============================] - 0s 132us/sample - loss: 2.2803 - acc: 0.3583 〜中略〜 Epoch 298/300 120/120 [==============================] - 0s 143us/sample - loss: 0.1543 - acc: 0.9833 Epoch 299/300 120/120 [==============================] - 0s 142us/sample - loss: 0.1536 - acc: 0.9833 Epoch 300/300 120/120 [==============================] - 0s 143us/sample - loss: 0.1531 - acc: 0.9833 30/30 [==============================] - 0s 2ms/sample - loss: 0.1132 - acc: 0.9667 正解率= 0.96666664 loss= 0.11321666091680527
■学習メモ book-mlearn-gyomu/tf-iris.py at master - kujirahand/book-mlearn-gyomu - GitHub https://github.com/kujirahand/book-mlearn-gyomu/blob/master/src/ch5/iris/tf-iris.py book-mlearn-gyomu/keras-iris.py at master - kujirahand/book-mlearn-gyomu - GitHub https://github.com/kujirahand/book-mlearn-gyomu/blob/master/src/ch5/iris/keras-iris.py 【Pythonステップアップ!】高階関数mapの便利な使い方 | 侍エンジニア塾ブログ(Samurai Blog) - プログラミング入門者向けサイト https://www.sejuku.net/blog/24759 Pythonのlambdaって分かりやすい - Qiita https://qiita.com/nagataaaas/items/531b1fc5ce42a791c7df
■TensorFlow+Keras(ディープラーニング)で手書き数字の判定
■MNISTデータの利用 MNISTのデータは、白黒画像の手書き数字のデータセット 学習用の画像に6万枚、テスト用の画像に1万枚もの画像が用意されている sklearnのデータセットに比べると、質も量も大きなデータセット 以下のようにしてインストールする
$ sudo pip3 install keras
以下のようにして使用する
#import keras #from keras.datasets import mnist from tensorflow.keras.datasets import mnist from matplotlib import pyplot # MNISTのデータを読み込む (x_train, y_train), (x_test, y_test) = mnist.load_data() # データを 4x8 に出力 for i in range(0, 32): pyplot.subplot(4, 8, i + 1) pyplot.imshow(x_train[i], cmap='gray') # 画像に保存する pyplot.savefig("output.png")
初回実行時は、以下からMNISTデータのダウンロードが行われる メモリ不足になるとダウンロードに失敗することがあるらしいので注意する https://s3.amazonaws.com/img-datasets/mnist.npz ■多層パーセプトロン(Multilayer perceptron)で画像認識
# MLPでMNISTの分類問題に挑戦 #import keras #from keras.models import Sequential #from keras.layers import Dense, Dropout #from keras.optimizers import RMSprop #from keras.datasets import mnist import tensorflow.keras as keras from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout from tensorflow.keras.optimizers import RMSprop from tensorflow.keras.datasets import mnist import matplotlib.pyplot as plt # 入力と出力を指定 in_size = 28 * 28 out_size = 10 # MNISTのデータを読み込み (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train[0:in_size * 20] y_train = y_train[0:in_size * 20] X_test = X_test[0:in_size * 20] y_test = y_test[0:in_size * 20] # データを28*28=784の一次元配列に変換 X_train = X_train.reshape(-1, 784).astype('float32') / 255 X_test = X_test.reshape(-1, 784).astype('float32') / 255 # ラベルデータをone-hotベクトルに直す #y_train = keras.utils.np_utils.to_categorical(y_train.astype('int32'),10) #y_test = keras.utils.np_utils.to_categorical(y_test.astype('int32'),10) y_train = keras.utils.to_categorical(y_train.astype('int32'),10) y_test = keras.utils.to_categorical(y_test.astype('int32'),10) # MLPモデル構造を定義 model = Sequential() model.add(Dense(512, activation='relu', input_shape=(in_size,))) model.add(Dropout(0.2)) model.add(Dense(512, activation='relu')) model.add(Dropout(0.2)) model.add(Dense(out_size, activation='softmax')) # モデルをコンパイル model.compile( loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) # 学習を実行 hist = model.fit(X_train, y_train, batch_size=64, epochs=30, verbose=1, validation_data=(X_test, y_test)) # モデルを評価 score = model.evaluate(X_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0]) # # 学習の様子をグラフへ描画 # # 正解率の推移をプロット # plt.plot(hist.history['acc']) # plt.plot(hist.history['val_acc']) # plt.title('Accuracy') # plt.legend(['train', 'test'], loc='upper left') # plt.show() # # # ロスの推移をプロット # plt.plot(hist.history['loss']) # plt.plot(hist.history['val_loss']) # plt.title('Loss') # plt.legend(['train', 'test'], loc='upper left') # plt.show()
Raspberry Pi 3 Model b+ 環境では15分以上かかった Raspberry Pi 4 4B-32GB 環境では10分程度かかった また
X_train = X_train[0:in_size * 20] y_train = y_train[0:in_size * 20] X_test = X_test[0:in_size * 20] y_test = y_test[0:in_size * 20]
の処理を入れないと
X_train = X_train.reshape(-1, 784).astype('float32') / 255
部分で MemoryError のエラーになって処理が止まった ■学習結果の保存と読み込み 「学習を実行」の直後に以下の処理を記述すると、学習結果をファイルに保存できる
# 学習結果を保存 model.save_weights('mnist-mlp.h5')
またその後、「学習を実行」の処理の代わりに以下を記述すると、学習結果を読み込んで使用できる 学習には非常に時間がかかることがあるので、これにより処理時間を大幅に短縮できる
# 学習結果を読み込み model.load_weights('mnist-mlp.h5')
ただし、Raspberry Pi 4 4B-32GB 環境では以下のエラーになった
AttributeError: 'str' object has no attribute 'decode'
【Keras】エラー 'str' object has no attribute 'decode'について - Qiita https://qiita.com/Hiroki-Fujimoto/items/b078bfb680fb710c38c1 Python 3.x - 【機械学習】学習済みkerasモデルのロードが出来ない|teratail https://teratail.com/questions/306240 以下でh5pyをバージョン指定でインストールしてみる なお sudo でroot権限で実行しようとすると、「sudo: pip3.7: コマンドが見つかりません」のエラーになった
$ pip3.7 install h5py==2.10.0 $ pip3.7 show h5py Name: h5py Version: 2.10.0 Summary: Read and write HDF5 files from Python Home-page: http://www.h5py.org Author: Andrew Collette Author-email: andrew.collette@gmail.com License: BSD Location: /home/pi/.local/lib/python3.7/site-packages Requires: six, numpy Required-by: Keras, Keras-Applications
これで、以下で実行できるようになった
$ python3.7 keras-perceptron.py 2021-02-20 13:07:23.519644: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory Unable to init server: Could not connect: Connection refused Unable to init server: Could not connect: Connection refused (keras-perceptron.py:17547): Gdk-CRITICAL **: 13:07:28.524: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed (keras-perceptron.py:17547): Gdk-CRITICAL **: 13:07:28.527: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow_core/python/ops/resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. 10000/10000 [==============================] - 4s 438us/sample - loss: 0.4175 - acc: 0.9662 正解率= 0.9662 loss= 0.4175194102861721
最初以下でインストールしようとしたが、pip3.7 には影響しなかった(pip3 にのみ影響した) 一つの環境に複数のPythonのバージョンを同居させているための問題だと思われる
$ sudo pip3 install h5py==2.10.0 $ pip3 show h5py
■畳み込みニューラルネットワーク(Convolutional Neural Network)で画像認識 深層学習(ディープラーニング)の原理、CNN、RNN、LSTM,GANを図解で解説 | TickTack World http://gagbot.net/machine-learning/ml4 Convolutional Neural Network(CNN)は画像認識で実績のあるニューラルネットワーク
# CNNでMNISTの分類問題に挑戦 #import keras #from keras.models import Sequential #from keras.layers import Dense, Dropout, Flatten #from keras.layers import Conv2D, MaxPooling2D #from keras.optimizers import RMSprop #from keras.datasets import mnist import tensorflow.keras as keras from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Dropout, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.optimizers import RMSprop from tensorflow.keras.datasets import mnist import matplotlib.pyplot as plt # 入力と出力を指定 im_rows = 28 # 画像の縦ピクセルサイズ im_cols = 28 # 画像の横ピクセルサイズ im_color = 1 # 画像の色空間/グレイスケール in_shape = (im_rows, im_cols, im_color) in_size = 28 * 28 out_size = 10 # MNISTのデータを読み込み (X_train, y_train), (X_test, y_test) = mnist.load_data() X_train = X_train[0:in_size * 2] y_train = y_train[0:in_size * 2] X_test = X_test[0:in_size * 2] y_test = y_test[0:in_size * 2] # 読み込んだデータをの三次元配列に変換 X_train = X_train.reshape(-1, im_rows, im_cols, im_color) X_train = X_train.astype('float32') / 255 X_test = X_test.reshape(-1, im_rows, im_cols, im_color) X_test = X_test.astype('float32') / 255 # ラベルデータをone-hotベクトルに直す #y_train = keras.utils.np_utils.to_categorical(y_train.astype('int32'),10) #y_test = keras.utils.np_utils.to_categorical(y_test.astype('int32'),10) y_train = keras.utils.to_categorical(y_train.astype('int32'),10) y_test = keras.utils.to_categorical(y_test.astype('int32'),10) # CNNモデル構造を定義 model = Sequential() model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=in_shape)) model.add(Conv2D(64, (3, 3), activation='relu')) model.add(MaxPooling2D(pool_size=(2, 2))) model.add(Dropout(0.25)) model.add(Flatten()) model.add(Dense(128, activation='relu')) model.add(Dropout(0.5)) model.add(Dense(out_size, activation='softmax')) # モデルをコンパイル model.compile( loss='categorical_crossentropy', optimizer=RMSprop(), metrics=['accuracy']) # 学習を実行 hist = model.fit(X_train, y_train, batch_size=128, epochs=12, verbose=1, validation_data=(X_test, y_test)) # 学習結果を保存 #model.save_weights('mnist-cnn.h5') # 学習結果を読み込み #model.load_weights('mnist-cnn.h5') # モデルを評価 score = model.evaluate(X_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
以下のとおり実行
$ python3.7 keras-cnn.py 2021-02-20 13:17:35.353177: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory Unable to init server: Could not connect: Connection refused Unable to init server: Could not connect: Connection refused (keras-cnn.py:17621): Gdk-CRITICAL **: 13:17:40.334: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed (keras-cnn.py:17621): Gdk-CRITICAL **: 13:17:40.337: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow_core/python/ops/resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. Train on 1568 samples, validate on 1568 samples Epoch 1/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 1.5820 - acc: 0.4847 - val_loss: 1.0910 - val_acc: 0.6429 Epoch 2/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.6963 - acc: 0.7953 - val_loss: 0.5761 - val_acc: 0.8240 Epoch 3/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.4347 - acc: 0.8731 - val_loss: 0.4242 - val_acc: 0.8788 Epoch 4/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.3382 - acc: 0.9062 - val_loss: 0.3544 - val_acc: 0.8992 Epoch 5/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.2708 - acc: 0.9311 - val_loss: 0.3081 - val_acc: 0.9062 Epoch 6/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.2152 - acc: 0.9362 - val_loss: 0.2688 - val_acc: 0.9216 Epoch 7/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.1852 - acc: 0.9420 - val_loss: 0.2591 - val_acc: 0.9196 Epoch 8/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.1411 - acc: 0.9547 - val_loss: 0.2451 - val_acc: 0.9203 Epoch 9/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.1150 - acc: 0.9656 - val_loss: 0.2703 - val_acc: 0.9235 Epoch 10/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.0993 - acc: 0.9739 - val_loss: 0.2994 - val_acc: 0.9082 Epoch 11/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.0870 - acc: 0.9732 - val_loss: 0.2334 - val_acc: 0.9369 Epoch 12/12 1568/1568 [==============================] - 17s 11ms/sample - loss: 0.0682 - acc: 0.9777 - val_loss: 0.2361 - val_acc: 0.9324 1568/1568 [==============================] - 3s 2ms/sample - loss: 0.2361 - acc: 0.9324 正解率= 0.93239796 loss= 0.23608304721740436
Python - Kerasのto_categoricalを使おうとすると、no attributeのエラーが出てしまう。|teratail https://teratail.com/questions/277434 「学習結果を保存」の処理を有効にして学習結果を保存したあと、 「学習を実行」を「学習を実行」に変更すると、以下のように学習結果から処理を実行できる
$ python3.7 keras-cnn.py 2021-02-20 13:38:18.336257: E tensorflow/core/platform/hadoop/hadoop_file_system.cc:132] HadoopFileSystem load error: libhdfs.so: cannot open shared object file: No such file or directory Unable to init server: Could not connect: Connection refused Unable to init server: Could not connect: Connection refused (keras-cnn.py:17756): Gdk-CRITICAL **: 13:38:23.309: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed (keras-cnn.py:17756): Gdk-CRITICAL **: 13:38:23.312: gdk_cursor_new_for_display: assertion 'GDK_IS_DISPLAY (display)' failed WARNING:tensorflow:From /usr/local/lib/python3.7/dist-packages/tensorflow_core/python/ops/resource_variable_ops.py:1630: calling BaseResourceVariable.__init__ (from tensorflow.python.ops.resource_variable_ops) with constraint is deprecated and will be removed in a future version. Instructions for updating: If using Keras pass *_constraint arguments to layers. 1568/1568 [==============================] - 4s 2ms/sample - loss: 0.2332 - acc: 0.9381 正解率= 0.93813777 loss= 0.23319860234172368
★2021年2月にここまで再検証した
■TensorFlow+Keras(ディープラーニング)で写真に映った物体を認識
■CIFAR-10 CIFAR-10 and CIFAR-100 datasets https://www.cs.toronto.edu/~kriz/cifar.html 6万枚の画像にラベルを付けて公開しているサイト フルカラーだが、32px×32pxと小さなサイズの画像となっている ■CIFAR-10の画像を表示
from keras.datasets import cifar10 import matplotlib.pyplot as plt from PIL import Image # 画像データを読み込む (X_train, y_train), (X_test, y_test) = cifar10.load_data() plt.figure(figsize = (10, 10)) labels = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"] # 40個連続で出力する for i in range(0, 40) : im = Image.fromarray(X_train[i]) plt.subplot(5, 8, i + 1) plt.title(labels[y_train[i][0]]) plt.tick_params(labelbottom="off", bottom="off") plt.tick_params(labelleft="off", left="off") plt.imshow(im) plt.show() # 画像に保存する plt.savefig("output.png")
プログラムをはじめて実行したとき、以下のように画像のダウンロードが行われる Downloading data from https://www.cs.toronto.edu/~kriz/cifar-10-python.tar.gz 170500096/170498071 [==============================] - 107s 1us/step ■多層パーセプトロン(Multilayer perceptron)で画像認識
import matplotlib.pyplot as plt import keras from keras.datasets import cifar10 from keras.models import Sequential from keras.layers import Dense, Dropout num_classes = 10 im_rows = 32 im_cols = 32 im_size = im_rows * im_cols * 3 # データを読み込む (X_train, y_train), (X_test, y_test) = cifar10.load_data() X_train = X_train[0:im_size * 5] y_train = y_train[0:im_size * 5] X_test = X_test[0:im_size * 5] y_test = y_test[0:im_size * 5] # データを一次元配列に変換 X_train = X_train.reshape(-1, im_size).astype('float32') / 255 X_test = X_test.reshape(-1, im_size).astype('float32') / 255 # ラベルデータをOne-Hot形式に変換 y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) # モデルを定義 model = Sequential() model.add(Dense(512, activation='relu', input_shape=(im_size,))) model.add(Dense(num_classes, activation='softmax')) # モデルをコンパイル model.compile( loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) ## 学習を実行 #hist = model.fit(X_train, y_train, # batch_size=32, epochs=50, # verbose=1, # validation_data=(X_test, y_test)) # ## 学習結果を保存 #model.save_weights('cifar10-mlp.h5') # 学習結果を読み込み model.load_weights('cifar10-mlp.h5') # モデルを評価 score = model.evaluate(X_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
■畳み込みニューラルネットワーク(Convolutional Neural Network)で画像認識
import matplotlib.pyplot as plt import keras from keras.datasets import cifar10 from keras.models import Sequential from keras.models import load_model from keras.layers import Dense, Dropout, Activation, Flatten from keras.layers import Conv2D, MaxPooling2D num_classes = 10 im_rows = 32 im_cols = 32 in_shape = (im_rows, im_cols, 3) in_size = 32 * 32 # データを読み込む (X_train, y_train), (X_test, y_test) = cifar10.load_data() X_train = X_train[0:in_size * 5] y_train = y_train[0:in_size * 5] X_test = X_test[0:in_size * 5] y_test = y_test[0:in_size * 5] # データを正規化 X_train = X_train.astype('float32') / 255 X_test = X_test.astype('float32') / 255 # ラベルデータをOne-Hot形式に変換 y_train = keras.utils.to_categorical(y_train, num_classes) y_test = keras.utils.to_categorical(y_test, num_classes) ## モデルを定義 #model = Sequential() #model.add(Conv2D(32, (3, 3), padding='same', input_shape=in_shape)) #model.add(Activation('relu')) #model.add(Conv2D(32, (3, 3))) #model.add(Activation('relu')) #model.add(MaxPooling2D(pool_size=(2, 2))) #model.add(Dropout(0.25)) # #model.add(Conv2D(64, (3, 3), padding='same')) #model.add(Activation('relu')) #model.add(Conv2D(64, (3, 3))) #model.add(Activation('relu')) #model.add(MaxPooling2D(pool_size=(2, 2))) #model.add(Dropout(0.25)) # #model.add(Flatten()) #model.add(Dense(512)) #model.add(Activation('relu')) #model.add(Dropout(0.5)) #model.add(Dense(num_classes)) #model.add(Activation('softmax')) # ## モデルをコンパイル #model.compile( # loss='categorical_crossentropy', # optimizer='adam', # metrics=['accuracy']) # ## モデルを保存 #model.save('cifar10-cnn-model.h5') # モデルを読み込み model = load_model('cifar10-cnn-model.h5') ## 学習を実行 #hist = model.fit(X_train, y_train, # batch_size=32, epochs=50, # verbose=1, # validation_data=(X_test, y_test)) # ## 学習結果を保存 #model.save_weights('cifar10-cnn-weight.h5') # 学習結果を読み込み model.load_weights('cifar10-cnn-weight.h5') # モデルを評価 score = model.evaluate(X_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
■多層パーセプトロン(Multilayer perceptron)の学習結果から画像を判定
import cv2 import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.layers import Dense, Dropout num_classes = 10 labels = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"] im_size = 32 * 32 * 3 # モデルを定義 model = Sequential() model.add(Dense(512, activation='relu', input_shape=(im_size,))) model.add(Dense(num_classes, activation='softmax')) # 学習結果を読み込み model.load_weights('cifar10-mlp.h5') # OpenCVを使って画像を読み込む im = cv2.imread('test-car.jpg') # 色空間を変換してリサイズ im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB) im = cv2.resize(im, (32, 32)) plt.imshow(im) # 画像を出力 plt.show() # MLPで学習した画像データに合わせる im = im.reshape(im_size).astype('float32') / 255 # 予測する r = model.predict(np.array([im]), batch_size=32, verbose=1) res = r[0] # 結果を表示する for i, acc in enumerate(res): print(labels[i], "=", int(acc * 100)) print("---") print('予測した結果=', labels[res.argmax()])
以下の結果になる
$ python3 cifar10-mlp-judge.py 1/1 [==============================] - 0s 67ms/step airplane = 7 automobile = 89 bird = 0 cat = 0 deer = 0 dog = 0 frog = 0 horse = 0 ship = 0 truck = 2 --- 予測した結果= automobile
■畳み込みニューラルネットワーク(Convolutional Neural Network)の学習結果から画像を判定
import cv2 import numpy as np import matplotlib.pyplot as plt from keras.models import Sequential from keras.models import load_model from keras.layers import Dense, Dropout, Activation, Flatten from keras.layers import Conv2D, MaxPooling2D num_classes = 10 im_rows = 32 im_cols = 32 in_shape = (im_rows, im_cols, 3) in_size = 32 * 32 labels = ["airplane", "automobile", "bird", "cat", "deer", "dog", "frog", "horse", "ship", "truck"] im_size = 32 * 32 * 3 # モデルを読み込み model = load_model('cifar10-cnn-model.h5') # 学習結果を読み込み model.load_weights('cifar10-cnn-weight.h5') # OpenCVを使って画像を読み込む im = cv2.imread('test-car.jpg') # 色空間を変換してリサイズ im = cv2.cvtColor(im, cv2.COLOR_BGR2RGB) im = cv2.resize(im, (32, 32)) plt.imshow(im) # 画像を出力 plt.show() # CNNで学習した画像データに合わせる im = im.astype('float32') / 255 # 予測する r = model.predict(np.array([im]), batch_size=32, verbose=1) res = r[0] # 結果を表示する for i, acc in enumerate(res): print(labels[i], "=", int(acc * 100)) print("---") print('予測した結果=', labels[res.argmax()])
以下のとおり実行
$ python3 cifar10-cnn-judge.py 1/1 [==============================] - 0s 250ms/step airplane = 0 automobile = 99 bird = 0 cat = 0 deer = 0 dog = 0 frog = 0 horse = 0 ship = 0 truck = 0 --- 予測した結果= automobile
■TensorFlow+Keras(ディープラーニング)でカタカナを判定
■文字データベースのダウンロード etlcdb http://etlcdb.db.aist.go.jp/?lang=ja 画面上部の「DOWNLOAD」から利用申請できる 申請すると、すぐにメールアドレスにダウンロードリンクとパスワードが送られてくる 今回はダウンロードページから「ETL-1」をダウンロードする ダウンロードしたファイルを展開すると、「ETL-1」というフォルダの中に14個のファイルが作成される ■データベースを画像に変換
# ETL1Cのファイルを読み込む import struct from PIL import Image, ImageEnhance import glob, os # 出力ディレクトリ outdir = "png-etl1/" if not os.path.exists(outdir): os.mkdir(outdir) # ETL1ディレクトリ以下のファイルを処理する files = glob.glob("ETL1/*") for fname in files: if fname == "ETL1/ETL1INFO": continue # 情報ファイルは飛ばす print(fname) # ETL1のデータファイルを開く f = open(fname, 'rb') f.seek(0) while True: # メタデータ+画像データの組を一つずつ読む s = f.read(2052) if not s: break # バイナリデータなのでPythonが理解できるように抽出 r = struct.unpack('>H2sH6BI4H4B4x2016s4x', s) code_ascii = r[1] code_jis = r[3] # 画像データとして取り出す iF = Image.frombytes('F', (64, 63), r[18], 'bit', 4) iP = iF.convert('L') # 画像を鮮明にして保存 dir = outdir + "/" + str(code_jis) if not os.path.exists(dir): os.mkdir(dir) fn = "{0:02x}-{1:02x}{2:04x}.png".format(code_jis, r[0], r[2]) fullpath = dir + "/" + fn #if os.path.exists(fullpath): continue enhancer = ImageEnhance.Brightness(iP) iE = enhancer.enhance(16) iE.save(fullpath, 'PNG') print("ok")
■画像をリサイズしてバイナリにまとめる
import glob import numpy as np import cv2 import matplotlib.pyplot as plt import pickle # 保存先や画像サイズの指定 out_dir = "./png-etl1" # 画像データがあるディレクトリ im_size = 25 # 画像サイズ save_file = out_dir + "/katakana.pickle" # 保存先 plt.figure(figsize=(9, 17)) # 出力画像を大きくする # カタカナの画像が入っているディレクトリから画像を取得 kanadir = list(range(177, 220+1)) kanadir.append(166) # ヲ kanadir.append(221) # ン result = [] for i, code in enumerate(kanadir): img_dir = out_dir + "/" + str(code) fs = glob.glob(img_dir + "/*") print("dir=", img_dir) # 画像を読み込んでグレイスケールに変換しリサイズする for j, f in enumerate(fs): img = cv2.imread(f) img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) img = cv2.resize(img_gray, (im_size, im_size)) result.append([i, img]) # Jupyter Notebookで画像を出力 if j == 3: plt.subplot(11, 5, i + 1) plt.axis("off") plt.title(str(i)) plt.imshow(img, cmap='gray') # メモリ消費対策に読み込む数を制限 #print(str(j) + ' / ' + f) if j >= 99: break # ラベルと画像のデータを保存 pickle.dump(result, open(save_file, "wb")) plt.show() # 画像に保存する plt.savefig("output.png") print("ok")
■多層パーセプトロン(Multilayer perceptron)で学習
import numpy as np import cv2, pickle from sklearn.model_selection import train_test_split import keras # データファイルと画像サイズの指定 data_file = "./png-etl1/katakana.pickle" im_size = 25 in_size = im_size * im_size out_size = 46 # ア-ンまでの文字の数 # 保存した画像データ一覧を読み込む data = pickle.load(open(data_file, "rb")) # 画像データを0-1の範囲に直す y = [] x = [] for d in data: (num, img) = d img = img.reshape(-1).astype('float') / 255 y.append(keras.utils.np_utils.to_categorical(num, out_size)) x.append(img) x = np.array(x) y = np.array(y) # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) # モデル構造を定義 Dense = keras.layers.Dense model = keras.models.Sequential() model.add(Dense(512, activation='relu', input_shape=(in_size,))) model.add(Dense(out_size, activation='softmax')) # モデルをコンパイルして学習を実行 model.compile( loss='categorical_crossentropy', optimizer='adam', metrics=['accuracy']) model.fit(x_train, y_train, batch_size=20, epochs=50, verbose=1, validation_data=(x_test, y_test)) # モデルを評価 score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
正解率= 0.6391304135322571 loss= 1.788340950012207 ※読み込む画像を100に制限しているので、正解率は低い ■畳み込みニューラルネットワーク(Convolutional Neural Network)で学習
import numpy as np import cv2, pickle from sklearn.model_selection import train_test_split import keras from keras.models import Sequential from keras.models import load_model from keras.layers import Dense, Dropout, Flatten from keras.layers import Conv2D, MaxPooling2D from keras.optimizers import RMSprop from keras.datasets import mnist import matplotlib.pyplot as plt # データファイルと画像サイズの指定 data_file = "./png-etl1/katakana.pickle" im_size = 25 out_size = 46 # ア-ンまでの文字の数 im_color = 1 # 画像の色空間/グレイスケール in_shape = (im_size, im_size, im_color) # カタカナ画像のデータセットを読み込む data = pickle.load(open(data_file, "rb")) # 画像データを変形して0-1の範囲に直す y = [] x = [] for d in data: (num, img) = d img = img.astype('float').reshape(im_size, im_size, im_color) / 255 y.append(keras.utils.np_utils.to_categorical(num, out_size)) x.append(img) x = np.array(x) y = np.array(y) # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) ## CNNモデル構造を定義 #model = Sequential() #model.add(Conv2D(32, kernel_size=(3, 3), activation='relu', input_shape=in_shape)) #model.add(Conv2D(64, (3, 3), activation='relu')) #model.add(MaxPooling2D(pool_size=(2, 2))) #model.add(Dropout(0.25)) # #model.add(Flatten()) #model.add(Dense(128, activation='relu')) #model.add(Dropout(0.5)) # #model.add(Dense(out_size, activation='softmax')) #model.compile( # loss='categorical_crossentropy', # optimizer=RMSprop(), # metrics=['accuracy']) # ## モデルを保存 #model.save('katakana_cnn-model.h5') # モデルを読み込み model = load_model('katakana_cnn-model.h5') ## 学習を実行して評価 #hist = model.fit(x_train, y_train, # batch_size=128, # epochs=12, # verbose=1, # validation_data=(x_test, y_test)) # ## 学習結果を保存 #model.save_weights('katakana_cnn-weight.h5') # 学習結果を読み込み model.load_weights('katakana_cnn-weight.h5') # モデルを評価 score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
正解率= 0.7630434632301331 loss= 0.9600743656573089 ※読み込む画像を100に制限しているので、正解率は低い それでも多層パーセプトロンよりは向上している ※読み込む画像は800まで耐えられた 800の画像をもとに判定すると、正解率は以下になった 正解率= 0.9686141014099121 loss= 0.12908870187871482 ■畳み込みニューラルネットワーク(Convolutional Neural Network)の学習結果から画像を判定
import numpy as np import cv2, pickle from sklearn.model_selection import train_test_split import keras from keras.models import Sequential from keras.models import load_model from keras.optimizers import RMSprop from keras.datasets import mnist import matplotlib.pyplot as plt # データファイルと画像サイズの指定 data_file = "./png-etl1/katakana.pickle" im_size = 25 out_size = 46 # ア-ンまでの文字の数 im_color = 1 # 画像の色空間/グレイスケール in_shape = (im_size, im_size, im_color) # カタカナ画像のデータセットを読み込む data = pickle.load(open(data_file, "rb")) # 画像データを変形して0-1の範囲に直す y = [] x = [] for d in data: (num, img) = d img = img.astype('float').reshape(im_size, im_size, im_color) / 255 y.append(keras.utils.np_utils.to_categorical(num, out_size)) x.append(img) x = np.array(x) y = np.array(y) # 学習用とテスト用に分離する x_train, x_test, y_train, y_test = train_test_split(x, y, test_size = 0.2, train_size = 0.8, shuffle = True) # モデルを読み込み model = load_model('katakana_cnn-model.h5') # 学習結果を読み込み model.load_weights('katakana_cnn-weight.h5') # モデルを評価 score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0])
■TensorFlow+Keras(ディープラーニング)で画像を判定
■FlickrのAPIを使う
$ sudo pip3 install flickrapi
■Flickrから学習用の画像を取得する
# Flickrで写真を検索して、ダウンロードする from flickrapi import FlickrAPI from urllib.request import urlretrieve from pprint import pprint import os, time, sys # APIキーとシークレットの指定 key = '取得したAPIキー' secret = '取得したシークレットキー' wait_time = 1 # 待機秒数(1以上を推奨) # キーワードとディレクトリ名を指定してダウンロード def main(): go_download('ショートケーキ', 'cake') go_download('サラダ', 'salad') go_download('麻婆豆腐', 'tofu') # Flickr APIで写真を検索 def go_download(keyword, dir): # 画像の保存パスを決定 savedir = './images/' + dir if not os.path.exists(savedir): os.mkdir(savedir) # APIを使ってダウンロード flickr = FlickrAPI(key, secret, format='parsed-json') res = flickr.photos.search( text = keyword, # 検索語 per_page = 300, # 取得件数 media = 'photos', # 写真を検索 sort = 'relevance', # 検索語の関連順に並べる safe_search = 1, # セーフサーチ extras = 'url_q, license') # 検索結果を確認 photos = res['photos'] pprint(photos) try: # 1枚ずつ画像をダウンロード for i, photo in enumerate(photos['photo']): url_q = photo['url_q'] filepath = savedir + '/' + photo['id'] + '.jpg' if os.path.exists(filepath): continue print(str(i + 1) + ':download=', url_q) urlretrieve(url_q, filepath) time.sleep(wait_time) except: import traceback traceback.print_exc() if __name__ == '__main__': main()
実行すると images 内に画像が300個ずつ保存される ただし関係ない画像も保存されるので、手動で100個まで絞り込む 絞り込んだ画像は cleaned_images に保存するものとする ■画像Numpy形式に変換する
# 画像ファイルを読んでNumpy形式に変換 import numpy as np from PIL import Image import os, glob, random outfile = "photos.npz" # 保存ファイル名 max_photo = 100 # 利用する写真の枚数 photo_size = 32 # 画像サイズ x = [] # 画像データ y = [] # ラベルデータ def main(): # 各画像のフォルダを読む glob_files("./cleaned_images/cake", 0) glob_files("./cleaned_images/salad", 1) glob_files("./cleaned_images/tofu", 2) # ファイルへ保存 np.savez(outfile, x=x, y=y) print("保存しました:" + outfile, len(x)) # path以下の画像を読み込む def glob_files(path, label): files = glob.glob(path + "/*.jpg") random.shuffle(files) # 各ファイルを処理 num = 0 for f in files: if num >= max_photo: break num += 1 # 画像ファイルを読む img = Image.open(f) img = img.convert("RGB") # 色空間をRGBに img = img.resize((photo_size, photo_size)) # サイズ変更 img = np.asarray(img) x.append(img) y.append(label) if __name__ == '__main__': main()
実行すると cleaned_images 内の画像をもとに photos.npz に保存される
import numpy as np import matplotlib.pyplot as plt # 写真データを読み込み photos = np.load('photos.npz'); x = photos['x'] y = photos['y'] # 開始インデックス idx = 0 #idx = 100 #idx = 200 # pyplotで出力 plt.figure(figsize=(10, 10)) for i in range(25) : plt.subplot(5, 5, i + 1) plt.title(y[i + idx]) plt.imshow(x[i + idx]) plt.show() # 画像に保存する plt.savefig("output.png")
実行すると photos.npz の内容をもとに output.png に画像が表示される idx が 0 ならショートケーキの画像、100 にするとサラダの画像、200 にすると麻婆豆腐の画像が表示される ■画像をもとに学習する
import cnn_model import keras import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import train_test_split # 入力と出力を指定 im_rows = 32 # 画像の縦ピクセルサイズ im_cols = 32 # 画像の横ピクセルサイズ im_color = 3 # 画像の色空間 in_shape = (im_rows, im_cols, im_color) nb_classes = 3 # 写真データを読み込み photos = np.load('photos.npz') x = photos['x'] y = photos['y'] # 読み込んだデータをの三次元配列に変換 x = x.reshape(-1, im_rows, im_cols, im_color) x = x.astype('float32') / 255 # ラベルデータをone-hotベクトルに直す y = keras.utils.np_utils.to_categorical(y.astype('int32'), nb_classes) # 学習用とテスト用に分ける x_train, x_test, y_train, y_test = train_test_split( x, y, train_size=0.8) # CNNモデルを取得 model = cnn_model.get_model(in_shape, nb_classes) # 学習を実行 hist = model.fit(x_train, y_train, batch_size=32, epochs=20, verbose=1, validation_data=(x_test, y_test)) # モデルを評価 score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0]) # 学習結果を保存 model.save_weights('photos.h5')
正解率= 0.800000011920929 loss= 0.5151064833005269 正解率を上げるため、回転と反転を行って水増し学習する 300枚での学習だったが5760枚での学習となる ただし学習にかかる時間は何倍にもなる
# CNNでMNISTの分類問題に挑戦 import cnn_model import keras import matplotlib.pyplot as plt import numpy as np from sklearn.model_selection import train_test_split import cv2 # 入力と出力を指定 im_rows = 32 # 画像の縦ピクセルサイズ im_cols = 32 # 画像の横ピクセルサイズ im_color = 3 # 画像の色空間 in_shape = (im_rows, im_cols, im_color) nb_classes = 3 # 写真データを読み込み photos = np.load('photos.npz') x = photos['x'] y = photos['y'] # 読み込んだデータをの三次元配列に変換 x = x.reshape(-1, im_rows, im_cols, im_color) x = x.astype('float32') / 255 # ラベルデータをone-hotベクトルに直す y = keras.utils.np_utils.to_categorical(y.astype('int32'), nb_classes) # 学習用とテスト用に分ける x_train, x_test, y_train, y_test = train_test_split( x, y, train_size=0.8) # 学習用データを水増しする x_new = [] y_new = [] for i, xi in enumerate(x_train): yi = y_train[i] for ang in range(-30, 30, 5): # 回転させる center = (16, 16) # 回転の中心点 mtx = cv2.getRotationMatrix2D(center, ang, 1.0) xi2 = cv2.warpAffine(xi, mtx, (32, 32)) x_new.append(xi2) y_new.append(yi) # さらに左右反転させる xi3 = cv2.flip(xi2, 1) x_new.append(xi3) y_new.append(yi) # 水増しした画像を学習用に置き換える print('水増し前=', len(y_train)) x_train = np.array(x_new) y_train = np.array(y_new) print('水増し後=', len(y_train)) # CNNモデルを取得 model = cnn_model.get_model(in_shape, nb_classes) # 学習を実行 hist = model.fit(x_train, y_train, batch_size=64, epochs=20, verbose=1, validation_data=(x_test, y_test)) # モデルを評価 score = model.evaluate(x_test, y_test, verbose=1) print('正解率=', score[1], 'loss=', score[0]) # 学習結果を保存 model.save_weights('photos2.h5')
正解率= 0.9666666388511658 loss= 0.4047759254773458 ■オリジナル画像をもとに判定する
import cnn_model import keras import matplotlib.pyplot as plt import numpy as np from PIL import Image import matplotlib.pyplot as plt im_rows = 32 # 画像の縦ピクセルサイズ im_cols = 32 # 画像の横ピクセルサイズ im_color = 3 # 画像の色空間 in_shape = (im_rows, im_cols, im_color) nb_classes = 3 LABELS = ["ショートケーキ", "サラダ", "麻婆豆腐"] CALORIES = [344, 81, 256] # 保存したCNNモデルを読み込む model = cnn_model.get_model(in_shape, nb_classes) model.load_weights('photos2.h5') def check_photo(path): # 画像を読み込む img = Image.open(path) img = img.convert("RGB") # 色空間をRGBに img = img.resize((im_cols, im_rows)) # サイズ変更 #plt.imshow(img) #plt.show() # データに変換 x = np.asarray(img) x = x.reshape(-1, im_rows, im_cols, im_color) x = x / 255 # 予測 pre = model.predict([x])[0] idx = pre.argmax() per = int(pre[idx] * 100) return (idx, per) def check_photo_str(path): idx, per = check_photo(path) # 答えを表示 print(path, "は", LABELS[idx], "で、カロリーは", CALORIES[idx],"kcalです。") print("可能性は", per, "%です。") if __name__ == '__main__': check_photo_str('test_cake.jpg') check_photo_str('test_salad.jpg') check_photo_str('test_tofu.jpg')
test_cake.jpg は ショートケーキ で、カロリーは 344 kcalです。 可能性は 100 %です。 test_salad.jpg は サラダ で、カロリーは 81 kcalです。 可能性は 100 %です。 test_tofu.jpg は 麻婆豆腐 で、カロリーは 256 kcalです。 可能性は 97 %です。
■TensorFlow+Keras(ディープラーニング)で文章を分類
※未検証 以下で文章の分類を行っている まずはリンク先にある英語文章の分類から試したい Janomeも含めて試したい 日本語文章の分類ができるようになったら、実際のメールを元に「重要」「通常」「迷惑」などの分類を試したい Keras MLPの文章カテゴリー分類を日本語のデータセットでやってみる | cedro-blog http://cedro3.com/ai/keras-mlp-livedoor/ 数字画像の判定プログラムをベースに、バイナリデータを文章に差し替えれば文章認識に応用できるか …と思って以下をメモしたが、いったん上の方法を試す ただし「Kerasの使い方まとめ【入門者向け】」などは、試す内容に関わらず目を通しておきたい 【気温を予測してみよう!】機械学習の第一歩 | 底辺動物の雑記ブログ https://ashikapengin.com/2019/08/14/yosoku-kion/ Kerasのサンプルソースが何をやっているか読んでみる - It’s now or never https://inon29.hateblo.jp/entry/2017/06/23/183749 Kerasの使い方まとめ【入門者向け】 https://sinyblog.com/deaplearning/keras_how_to/ TensorFlowを使ってテキスト分類をしてみる。 - どん底から這い上がるまでの記録 https://www.pytry3g.com/entry/tensorflow_basic_text_classification 挑戦! word2vecで自然言語処理(Keras+TensorFlow使用):ディープラーニング習得、次の一歩(1/2 ページ) - @IT https://www.atmarkit.co.jp/ait/articles/1801/30/news139.html PythonライブラリKerasを用いたAI(ディープラーニング)による文書分類とモデルの評価 | 知のマイニング https://software-data-mining.com/python%E3%83%A9%E3%82%A4%E3%83%96%E3%83%A9%E3%83%AAkeras%E3%82%92%E...
■機械学習メモ
■日本語処理 機械学習のための日本語前処理 - Qiita https://qiita.com/Qazma/items/0daf927e34d22617ddcd ■ディープラーニングで「娘が写っている」「娘が写っていない」「暗くて不明」を判定 定点撮影で撮りためたものから学習用データを作成する 2019年10月1日時点から、「娘が写っている」「娘が写っていない」「暗くて不明」を仕分けていく それぞれ100枚ずつ画像を用意する 10月16日くらいまででデータが揃った …が、実際に試すと正解率は6〜7割程度 チューニングでどの程度改善できるかは不明
■Windowsアプリケーション
※未検証 【Python】PythonでGUI(デスクトップ)アプリを作ってみる@Windows - SEワンタンの独学備忘録 https://www.wantanblog.com/entry/2020/07/14/224611 Pythonでデスクトップアプリを作成する時に使えるライブラリ4選【アプリの配布方法も解説】 https://sync-g.co.jp/sjobs/python-desktop/ 【超入門】Pythonによるデスクトップアプリの作り方と配布方法|エンジニアブログ https://engineer-life.dev/python-desktop-app/ ゼロからはじめるPython(46) Pythonでデスクトップアプリ作成入門 - Tkinterで肥満判定ツールを作ろう | TECH+(テックプラス) https://news.mynavi.jp/techplus/article/zeropython-46/
■2017年2月時点のメモ
■インストール http://refirio.org/view/358 2017年2月の時点で、この方法でPython+MySQLを動作させることができた(Bottleフレームワークは未検証) ただし今ならVer3でいいかも。 2018年なら、以下も参考にできそう 2018年のPythonプロジェクトのはじめかた - Qiita https://qiita.com/sl2/items/1e503952b9506a0539ea ■「import urllib」でエラー 「import urllib.request」となっている箇所を「import urllib」にして、 「urllib.request.urlretrieve」となっている箇所を「urllib.urlretrieve」にしたら何故か動いた。 Ver3から命令が整理されているらしい。 ■pip(Pythonのパッケージ管理システム)
>python -m pip -V … pipのインストールを確認 pip 8.1.1 from C:\Python27\lib\site-packages (python 2.7)
■Beautiful Soup インストール
>python -m pip install beautifulsoup4
HTMLの解析
# coding: UTF-8 # ライブラリの取り込み from bs4 import BeautifulSoup # 解析したいHTML html = """ <html> <body> <h1>スクレイピングとは</h1> <p>Webページを解析すること。</p> <p>任意の箇所を抽出すること。</p> </body> </html> """ # HTMLを解析する soup = BeautifulSoup(html, 'html.parser') # 任意の部分を抽出する h1 = soup.html.body.h1 p1 = soup.html.body.p p2 = p1.next_sibling.next_sibling # 要素のテキストを表示する print "h1 = " + h1.string print "p = " + p1.string print "p = " + p2.string # 完了 print "OK"
簡単なクロール
# coding: UTF-8 # ライブラリの取り込み from bs4 import BeautifulSoup import urllib # ダウンロード res = urllib.urlopen("http://stocks.finance.yahoo.co.jp/stocks/detail/?code=usdjpy") # HTMLを解析する soup = BeautifulSoup(res, 'html.parser') # 任意の部分を抽出する price = soup.select_one(".stoksPrice").string # 要素のテキストを表示する print "usd/jpy = " + price # 完了 print "OK"

Advertisement