Non-engineer memoblog

エンジニアではない人間のメモブログ(備忘録とアウトプット欲のために)

Kerasの学習メモ

しばらく時間が立ってしまいましたが、改めてKerasを学習して忘れないうちにメモ。

今回はAIスタートアップで就業している方にいろいろ教えてもらえて細かい部分がとても参考になった。

モデル読み込みと利用

以前に別途作成したモデル hoge.h5 を読み込みして使おうとしたら、

ValueError: No model found in config file.

と怒られてしまった。エラーそのままググってみると、

Unable to load model from .h5 file · Issue #6937 · keras-team/keras · GitHub
Python - kerasのモデルのload_modelでエラー(ValueError: Unknown initializer: weight_variable)(112052)|teratail

で書かれていることを参考に、

# 以前のコード
model.save_weights(hdf5_file)

model.save(hdf5_file)

に変更してから再度学習 → エラーが消えて動いた(ほんとにこれが原因だったのだろうか?)

batch_sizeについて

history = model.fit(X, y, batch_size=8, nb_epoch=3, validation_split=0.1)

以前にbatch_sizeのことがいまいち分からなかったのでメモ。
st-hakky.hatenablog.com

サラッと読むと↑の記事では、batch_sizeは一度に計算する量だけど、

512だと学習速度をあげたかったのかなという気持ちが見えます。

自分だけで読んでいたら↑の記述の感覚がよく分からなかった。よくよく読んで見ると

1epochの計算速度が変わります(ここでいっているのは、学習の収束の速さなどではなく、単純に計算速度の話です)。パラメーターの更新の回数というのが、ミニバッチのサイズが小さいほど多くなるので、これは当然と言えば当然です。

ミニバッチ単位でデータを読みとり、それを使うとなると、これはミニバッチのサイズが大きければ大きいほど、メモリの使用量を食います。

と記載あり、わかったような分からなかったような気でいましたが、要するにパラメータ更新という計算リソース上のオーバーヘッドがごっそり減るか否かということだとわかった。また分散も少なくなることから、batch_sizeを多くした方が良さそうな感じもしていたけど、

メモリがないとかえって遅くなる

ということを教えてもらえた。

あとはこのあたりを少し。

model.compile(loss='binary_crossentropy',optimizer='rmsprop',metrics=['accuracy'])
  • 最適化は計算リソースの制約があればSGDを使用する
  • acc と loss など数値の見かた
  • Google Colaboratoryの利用方法(超基礎)
  • metricsは主に以下2つがある
    • binary_accuracy → 2クラス
    • categorical_accuracy → 多クラス(マルチクラス)

などなど。

趣味としての概要記事超入門

Pythonの超々初歩的なコーディングで長いことハマってしまい、メンターの方に質問を投げているが世間はGWなので、レスが来るまでに良く分かっていなかったことなどをググってみたりしているメモです。

Inside of Deep Learningディープラーニングの性能改善手法 一覧)

改善方法が文字多め!!でまとまっててとても読みやすかった神記事でした。
Inside of Deep Learning (ディープラーニングの性能改善手法 一覧) - Qiita

ドロップアウト/Batch Normalization

記事やTwitterなどでよく見かけるけどキーワードでしたが、良く分かっていなかったのでした。
今更聞けないディープラーニングの話【ユニット・層・正則化・ドロップアウト】 - HELLO CYBERNETICS
Dropout:ディープラーニングの火付け役、単純な方法で過学習を防ぐ - DeepAge
Batch Normalization:ニューラルネットワークの学習を加速させる汎用的で強力な手法 - DeepAge

転移学習/Zero-Shot Learning

ゼロショット学習は、ワンショットとも言われるらしく、文字通り1度だけで「これは別クラスの対象物である」と認識できるような学習方法らしく、DARPAロボティクスチャレンジのような認識タスクに応用できそうなものみたいですね。
転移学習とは|機械学習とディープラーニングとの関係性と必要スキル|フリエン
転移学習:機械学習の次のフロンティアへの招待 - Qiita
Zero-Shot Learning with Semantic Output Codesを読んだ - EchizenBlog-Drei

転移学習は、以前にDeepMindが発表したDNC(Differentiable neural computers)と同じようなもの?と思いながらでしたが、重み付けが最適にチューニングされている転移学習と実際にメモリ保持しているDNCといった感じでしょうか・・・??
DNC (Differentiable Neural Computers) の概要 + Chainer による実装 - Qiita



QRNN

RNN + LSTMよりも強力
LSTMを超える期待の新星、QRNN - Qiita
【Python】QRNNでカオス時系列データ予測【Keras】 - Qiita
QRNNでLSTM(深層学習を用いた時系列分析)をスピードアップ | GMOインターネット 次世代システム研究室

CapsNet

CNNの問題点を解消できる可能性を秘めた超期待のネットワーク?
CapsNetについての調べ - Qiita
深層学習を根底から覆すカプセルネットワークの衝撃 - WirelessWire News(ワイヤレスワイヤーニュース)

Group Normalization(GN)

Batch Normalizationの限界を補う代替案らしいですが、Batch Normalizationですら理解できていないのに・・・
Facebook AI Proposes Group Normalization Alternative to Batch Normalization
[1803.08494] Group Normalization


・・・・と、なんかリンク貼るだけになってしまったのですが、CapsNetとGroup Normalization以外は1年以上前の出来事や手法の話であって、なんだかバトル系少年漫画のインフレを見ているかのようです。改善手法 一覧記事があったおかげで何となくの雰囲気をつかむことができた。

文字で雰囲気は感じる(理解できるとは言っていない!)ことができるけれども、さすがにもう少しベクトルとか行列とかコードとか数学とか数学とか・・・などの素養を理解しないと雰囲気を楽しむことすら大変になりそうだと感じてきている。

ということで以前に購入した 、
みんなのAI講座 ゼロからPythonで学ぶ人工知能と機械学習 | Udemy
こちらはニューラルネットワークバックプロパゲーションまでは分かりやすく解説されていたけど、ベクトルとか行列とかはほとんど取り扱っていなかったので、比較的新しめの動画コンテンツでそのあたりを取り扱っていないか物色しました(そしてセール購入)・・・

www.udemy.com
www.udemy.com

※Udemyっていつもセールやっているんだけどこれ大丈夫なんだろうか・・・

ある意味、非エンジニアが雰囲気をつかむために学習コンテンツを見るというのすごく効率の良い情報収集だと感じている。聴覚と視覚を両方使用できるし、また目線を大きく移動させることなく図やイラストを画面で遷移させながら、実際にコードと動く結果が確認できる(それをコピペすれば自分の環境でも動くはずであろうものが)。これを電車に乗りながら可能なのは強力だなーと。

ただこれは学習と言えるのかかなり疑問なので自分はコンテンツ(ここでは機械学習記事など)を楽しむための予習というか情報収集という位置づけでとらえている。

逆に言えば実際の技術職の方は以下の記事を見るように
qiita.com
実際にビジネスに落とし込むことの壮絶さがわかる。

Turing Complete FM

話変わって、最近はlld(リンカ)のオリジナル開発者のUeyama RuiさんのPodcastがすごく面白い。
turingcomplete.fm

自分もアンケートに25%しか理解できない(もっと分からないですがw)と回答しました(笑)

ただこの辺はLinux概要(ただし2.4~2.6系)をほんの少し勉強したことがあることで、雰囲気を楽しめる。そのおかげで15. CERNでのソフトウェアエンジニアリングのような話を聞けたり、やっぱりある程度の知識はコンテンツを楽しむために重要だと思う。それと、Ruiさん(Google)がFacebookコンパイラチームのリクルーターに招待された会食に行ったら、後ろの席の同僚も来てたとかいう裏話が聞けるのもw

[追記]
久しぶりにLinux入門記事を見てみようとしたら、有料会員じゃないと見れなくなっていた・・・
tech.nikkeibp.co.jp

MONOistのこっちはまだ閲覧できるみたい
monoist.atmarkit.co.jp

Django2.0入門(その2)

Django2.0の環境が整ったため、さっそくDjangoプロジェクトを作成。
淡々とメモをしていますが、かなり躓き試行錯誤しながらやっていました。。。
(コピペではなく写経していたので、タイポとエラーと戦いつつ)

以下の学習コンテンツを参考
www.udemy.com
最初にもお伝えしましたが、この学習コンテンツは口頭での解説も分かりやすいので、初心者にはかなりオススメです。


setting.pyを編集

$ cd /home/hogeuser/projects/mircroblog/mircroblog/
$ sudo vim settings.py

settings.py

# 33行目辺りに blog を追加
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'blog',
]

# 107行目辺りを以下のように編集
LANGUAGE_CODE = 'ja'
TIME_ZONE = 'Asia/Tokyo'

models.pyを編集

from django.db import models


class Blog(models.Model):
    '''
    - データを保存する場合は django.models だと「 ***Field() 」という形になることが多い
    - コードには記載が無いが、django内部的にIDがインクリメントで保存されている(PK:プライマリキー)
    '''

    # 文字列を保存する「models.CharField(max_length=保存する文字数)」
    content = models.CharField(max_length=140)

    # 日付を「post_date」に保存(「auto_now_add=True」で投稿したときに1度だけ日時を返す)
    post_date = models.DateTimeField(auto_now_add=True)
    # models.DateTimeField(auto_now=True) <-- 更新するたびに日時を上書きする

マイグレーションファイルを作成

$ python manage.py makemigrations

# DBをマイグレートする
$ python manage.py migrate


admin.pyの編集

$ cd blog/
$ sudo vim admin.py

admin.py

from django.contrib import admin

# 「models.py」で作成したBlogクラスをモジュールとしてインポート
from blog.models import Blog

# Blogクラスを継承 → アドミンサイトに登録
admin.site.register(Blog)


ListViewを作成

from django.shortcuts import render

# 汎用ビューのListViewをインポートする
from django.views.generic import ListView

# BlogListViewを作成したモデル「models.py」に関連付ける必要があるためにBlogモデルをインポートする
from .models import Blog

# ListViewクラスを継承したBlogListViewクラスを作成(クラス名は「App-nameListView」?みたいにする)
class BlogListView(ListView):
    # BlogListViewクラスをBlogモデルに関連付ける
    models = Blog

blog_list.html を作成

####### blog_list.html ##########
<html>
<head>
    <title>MicroBlog</title>
</head>
<body>

<h1>MicroBlog</h1>

<!-- 以下の<div>内にデータが入る -->
<div>

    <!-- {%}: プログラム的な命令を記述する(表示されない) -->
    <!-- 以下の「object_list」は「class Blog(models.Model):」のobjectのこと(idが降られてる1つ1つの記事) -->
    {% for blog in object_list %}
        <div>
            <!-- 二重 : 値を表示するための記述(表示される) -->
            {{ blog.content }}<br>
            {{ blog.post_date }}
        </div>
    <!-- PythonのインデントをHTML内で表現するために書く{%}内に「endhoge」 と書く -->
    {% endfor %}  

</div>

</body>
</html>


DetailViewを作成

###### views.py内に追記する ######

from django.shortcuts import render

# 汎用ビューのListViewをインポートする
from django.views.generic import ListView

# 汎用ビューのDetailViewをインポートする
from django.views.generic import DetailView

# BlogListViewを作成したモデル「models.py」に関連付ける必要があるためにBlogモデルをインポートする
from .models import Blog


# ListViewクラスを継承したBlogListViewクラスを作成
class BlogListView(ListView):
    # BlogListViewクラスをBlogモデルに関連付ける
    model = Blog

class BlogDetailView(DetailView):
    model = Blog


urls.pyを編集

###### urls.py内に追記 ######

from blog.views import BlogDetailView

urlpatterns = [
    #path(‘<URL>‘, views(関数), ニックネーム),  <--末尾に「,」を付ける(リスト[]のため)
    path(‘’, BlogListView.as_view(), name=“index”),

    #path(‘<pk ←IDのこと >‘, views(関数), ニックネーム),  <--末尾に「,」を付ける(リスト[]のため)
    path(‘<int:pk>’, BlogDetailView.as_view(), name=“detail”),

    path(‘admin/’, admin.site.urls),
]
<html>
<head>
<title>MicroBlog</title>
</head>
<body>

<h1>MicroBlog</h1>

<!-- 以下の<div>内にデータが入る -->
<div>

    <h2>{{ object.content}}</h2>
    <p>{{ object.post_date }}</p>

</div>

</body>
</html>

base.htmlを作成

<!-- 「block body」と「endblock」の記述が重要  -->

<html>
<head>
<title>MicroBlog</title>
</head>
<body>

<h1>MicroBlog</h1>

<!-- 以下の<div>内にデータが入る -->
<div>

    <!-- 以下の「block body」は以下の部分(base.html)は上書きされますよというもの-->
    <!-- もし上書きされなかったら「block body」と「endblock」の間のベーステンプレが表示される-->
    {% block body %}
        <p>base.html</p>
    {% endblock %} 

</div>

</body>
</html>

テンプレファイルを作成

# テンプレ化させたいHTMLファイルの一番上に以下の記述を行う
{% extends “base.html” %}

{% block body %}

{% endblock %}


# たとえばblog_list.html内特有の記述(表示)をベースとなるテンプレ(base.html)に統合させたい場合は以下。
{% extends “base.html” %}

{% block body %}

    # 以下に特有の記述をコピペする    
    {% for blog in object_list %} 
        <div>
            {{ blog.content }}<br>
            {{ blog.post_date }}
        </div>
    {% endfor %}  

{% endblock %}

# それ以外は「base.html」に記載があるので全て削除


# blog_detail.html内特有の記述(表示)を「base.html」に統合。そして、それ以外の記述は全て削除
{% extends “base.html” %}

{% block body %}
    <h2>{{ object.content}}</h2>
    <p>{{ object.post_date }}</p> 
{% endblock %}


'''
Bootstrapをダウンロードして、「index.html」を「base.html」に全てコピペ(上書き)する。
そしたら、main contents箇所を削除(divは残す)
さらにfooterも削除(ただし残しても良い)
'''

Bootstrapを追加していく

日本語も美しく表示できるBootstrapテーマのRINを追加していく(学習コンテンツでは別のテーマを使用していましたが)
rinhoshizo.la

Bootstrap自体の知識もあんまりないので、結構は大変だった。。。


Bootstrapを修正

# base.htmlの一番上に以下を追記する

{% load static %}

<!DOCTYPE html>
<html lang=“en”>

'''
プログラム的に内容が変更されない静的なファイル(CSSとか画像とか)を保存されているフォルダへ自動的にPATHを通してくれる記述。
'''
    
# 以下のように加筆をしていく

<!-- Bootstrap core CSS -->
<link href=“{% static ‘vendor/bootstrap/css/bootstrap.min.css’ %}” rel=“stylesheet”>

<!-- Custom styles for this template -->
<link href=“{% static ‘css/clean-blog.min.css’ %}” rel=“stylesheet”>

<!-- Bootstrap core JavaScript -->
<script src=“{% static ‘vendor/jquery/jquery.min.js’ %}“></script>

<script src=“{% static ‘vendor/bootstrap/js/bootstrap.bundle.min.js’ %}“></script>

<!-- Custom scripts for this template -->
<script src=“{% static ‘js/clean-blog.min.js’ %}“></script>


'''
これは「settings.py」の一番下に記述されて言う「STATIC_URL = /static/」の記述以降に
 /static/vendor/bootstrap/css/bootstrap.min.css  となるように記述がされる
 この「STATIC_URL = /static/」の「/static/」の箇所を修正するだけで、AWSから配信する際のPATHの変更が簡単になる
'''

# 「“{% static 〜〜」 の記述を有効にするために、「settings.py」の一番下へ追記

STATIC_URL = ‘/static/’
STATICFILES_DIRS = (
    os.path.normcase(os.path.join(BASE_DIR, “assets”))
)

BASE_DIRについて

#「BASE_DIR」とは「/home/hogeuser/projects/microblog/microblog」のことで、

    microblog/   # <--- つまりはこいつのこと
    ├── assets
    ├── blog
    │   ├── __init__.py
    │   ├── admin.py
    │   ├── apps.py
    │   ├── forms.py
    │   ├── migrations
    │   ├── models.py
    │   ├── templates
    │   ├── tests.py
    │   └── views.py

'''
つまりは「os.path.normcase(os.path.join(BASE_DIR, “assets”))」は、
/home/hogeuser/projects/microblog/microblog/assets」のように
「assets」ディレクトリのPATHを通すという記述。
Djangoはフルパスで指定する必要があるため、「os.path.join」でプログラム的にパスを作成している
'''

テンプレファイルについて

'''
現在はBlogクラスを作った場合は、
「blog_list」や「blog_detail」や「blog_hoge」などのファイルを探すという決まりがある。

しかし色々と別のフォルダを作ってそこにファイルを置きたい場合は、
「settings.py」の「TEMPLATES」の「‘DIRS:’」にPATHを記述する必要がある。
'''

# 例: microblog/templatesというフォルダを作り、その中にあるファイルを見つけて欲しい場合

TEMPLATES = [
    {
        ‘BACKEND’: ‘django.template.backends.django.DjangoTemplates’,
        ‘DIRS’: [
            os.path.normpath(os.path.join(BASE_DIR, “templates”))
        ],
        ‘APP_DIRS’: True,

    # 〜〜 中略 〜〜

    },
]

・・・・・とこんな感じで淡々と進めて行きました。


いろいろやっている内に学習コンテンツそのままですが、こんな感じで出来上がりました!!

まずは一覧表示

ログインしないと作成や編集削除ができない状態。
f:id:coffeedog:20180430221525p:plain

ログイン画面

f:id:coffeedog:20180430221537p:plain
ユーザー名とパスワードを入力
f:id:coffeedog:20180430221545p:plain

新規作成画面へ遷移

f:id:coffeedog:20180430221655p:plain

編集と削除の画面

f:id:coffeedog:20180430221551p:plain


と・・・ここまでやってきましたが、ここまで言って見えた景色は

基礎力がないとこのあと太刀打ちできねぇ_:(´ཀ`」 ∠):

・・・というところで、次回からPythonの基本的なコーディングと、そのあとにマイクロフレームワークのFlaskから出直そうと思っています。

Django2.0入門以前(その1)

以前にDjangoチュートリアルを試してみて、途中で撃沈(つまりハマって挫折)してたりしましたが、この度Django2.0になったことで再度トライしてみることに。

環境

  • Python3.6
  • Windows10
  • Virtualbox(ゲストCentOS7 )


とはいえチュートリアルとかドキュメント類を読めないヘタレ庶民なので、
ここは分かりやすい学習コンテンツをぱく参考にチャレンジ。

以下の学習コンテンツを参考
www.udemy.com

  • Microblogを作っていく
  • (初心者としては)説明がしっかりしていてテンポもよく非常に分かりやすかった
  • Python入門が省かれていてすぐにDjango学習に進むことができるのが良かった
  • 当然、これだけで使いこなせるわけではない

他のはPython入門やその他基礎にコンテンツを割いているので、何もかも初めての人にはそっちのがいいかもです。


環境構築

CentOS7にTeraTermでアクセスし、install.shを作成

# まずはupdate
sudo yum update -y
sudo yum install -y vim git wget nginx

# Pyenvのインストール
sudo yum -y install gcc zlib-devel bzip2 bzip2-devel readline readline-devel sqlite sqlite-devel openssl openssl-devel
sudo curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash
sudo echo 'export PATH="~/.pyenv/bin:$PATH"' >> ~/.bash_profile
sudo echo 'eval "$(pyenv init -)"' >> ~/.bash_profile
sudo echo 'eval "$(pyenv virtualenv-init -)"' >> ~/.bash_profile
source ~/.bash_profile

# Python3.6のインストール
pyenv install 3.6.4
pyenv global 3.6.4
pyenv rehash

# pipとDjangoのインストール
sudo yum -y install python-devel
sudo yum install -y https://centos7.iuscommunity.org/ius-release.rpm
sudo yum -y install python-pip
sudo pip install --upgrade pip
sudo pip install django

うまくいけば、Django2.0の環境が整うため、さっそくDjangoプロジェクトを作成。

$ mkdir projects
$ cd projects/

# microblogというプロジェクトを作成
$ django-admin startproject mircroblog
$ cd mircroblog/

# blogというアプリを作成
$ ./manage.py startapp blog

ここまで実行したらローカルサーバーを起動してアクセスしますが、
その前にVirtualbox(CentOS7 )へのアクセスなので settings.py を編集。

sudo vim /home/hogeuser/microblog/microblog/settings.py

ALLOWED_HOSTS = ['CentOS7 のIPアドレス']

のように設定。

それと selinux

sudo setenforce 0

そしたら改めてローカルサーバーを起動

# Djangoのローカルサーバーを起動
$ python manage.py runserver CentOS7 のIPアドレス:8000

Performing system checks...

System check identified no issues (0 silenced).
April 29, 2018 - 16:55:28
Django version 2.0.4, using settings 'microblog.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.

IPアドレス:8000 にアクセスすると
f:id:coffeedog:20180429203038p:plain

こんな画面がでれば成功です!
firewall や selinux をオフにするやらでハマっていましたが、まずは一安心です。

Raspberry Pi3 でOpenCV3+Python3(背景差分による動体検出)

  • Python3.5.3
  • OpenCV3.3
  • Raspbian Strech

使ったもの

www.logicool.co.jp

以前に参考にしていたこちらはOpenCV2.4 + Python2.7なので、
tatsu-zine.com

新しく以下の学習コンテンツを参考
www.udemy.com

  • 環境の構築(OpenCVの導入)
  • 画像/動画の入出力
  • トラックバー / マウスイベント
  • 色空間/グレースケールへの理解
  • 平滑化/エッジの検出などの畳み込み処理
  • 2値化
  • 特徴点の抽出
  • 色検出、オプティカルフローなどの物体追跡
  • パーティクルフィルターの理論と実装

取り扱っていない内容

  • 機械学習
  • カメラモデル
  • SIFT/SURFなどのライセンス上商用利用しにくいもの
import cv2
import numpy as np

cv2.namedWindow("img", cv2.WINDOW_NORMAL)
cv2.resizeWindow("img", 1200, 800)
cap = cv2.VideoCapture("my_video.mkv")
ret, frame = cap.read()
h, w, ch = frame.shape
frame_back = np.zeros((h,w,ch), dtype=np.float32)
while True:
    ret, frame = cap.read()
    if ret == False:
        break
    frame_diff = cv2.absdiff(frame.astype(np.float32), frame_back)
    cv2.accumulateWeighted(frame, frame_back, 0.1)
    cv2.imshow("img", frame_diff.astype(np.uint8))
    if cv2.waitKey(10) == 27:
        break

cv2.destroyAllWindows()

実行結果

f:id:coffeedog:20180430000227j:plain
f:id:coffeedog:20180430000254j:plain

ダンボーが闇落ちしただけで10秒ほどで処理が落ちました。

PC上で実行すると普通に差分がとれて、動体検出ができましたので、
Raspberry Piのオーバークロックで、少しでも処理能力の向上を図ってみることに。

以下の記事を参考にさせていただきました!
ラズベリーパイのCPUクロックと電圧をいじってみる – EZなBlog
Raspberry Pi3 CPUクロック周波数を固定にする方法 | ある計算機屋さんの手帳

sudo vim /boot/config.txt

以下のように編集

force_turbo=1
arm_freq=1300

over_voltage=5

# ついでにGPUメモリも128 から 320へ変更
gpu_mem = 320

CPUガバナーの設定を変更

# 1.3GHz動作(固定)
sudo cpufreq-set -g performance
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_cur_freq
1300000

ちゃんと1.3GHzに設定されました。

また、オーバークロックによるCPU損傷を少しでも軽減させるためにファン付きケースに入れてみる。
5in1 アップデート!アクリル Raspberry Pi Model B+ Raspberry Pi 2/3 Model B 専用アクリル・ケース+ファン+ スイッチ付きケーブル+クーラー2個+HDMI to VGA ケーブル(Black/黒)


rebootしてから、再度実行・・・・・



してみましたが、とくに実行結果はからわず、ダンボーが闇落ち後、数秒で落ちました。。。


次は2値化処理などで負荷を軽減させる処理を加えてみたいと思います。

Pythonデータサイエンス入門以前のメモ(その2)

前回の続き。学習コンテンツを眺めながら自分用のメモを記していく。
www.udemy.com

PandasのDataFrameについて

# 以下はお決まり。
import numpy as np
import pandas as pd

# pd.Seriesとpd.DataFrameは良く使うので「Series」「DataFrame」の単語のみで使えるようにインポートする
from pandas import Series, DataFrame

# DataFrameを新規に作るには、DataFrame(hoge) とする(下の方で出て来る)。
## NFLのデータをサンプルとして使用。

import webbrowser
website = 'http://en.wikipedia.hogehoge'
webbrowser.open(website)

## クリップボードから読み込むことが可能。

nfl_frame = pd.read_clipboard()

# nfl_frameには「表(table)」が格納されているためnotebook上に「表(table)」が表示される
# 列(カラム)の名前が「.columns」で確認できる。

nfl_frame.columns

# 個別の列(カラム)にアクセスする場合は、角括弧[ ] に列名(カラム名)を記述する。

# nfl_frame['First Season'] とすると以下のDataFrameが返ってくる。
    0    1960
    1    1920
    2    1921
    3    1966
    4    1996
    5    1950
    Name: First Season, dtype: int64

'''
「.Team」のように「.」の後に列名(カラム名)でもOK。ただしFirst Seasonは2単語のスペース有りだから角括弧でなければならない
'''

# nfl_frame.Team とすると以下のDataFrameが返ってくる。
    0       Dallas Cowboys
    1        Chicago Bears
    2    Green Bay Packers
    3       Miami Dolphins
    4     Baltimore Ravens
    Name: Team, dtype: object

## 複数のカラム(列)のみを抽出してDataFrameを作る

nfl_frame[['Team', 'First Season']]

'''
上記のようにすると「Team」と「First Season」の2列のDataFrame(表:Table)ができる。
特定のいくつかのカラムのみを抽出し「新しいDataFrame」を作る(元のDataFrameを上書きしないで済む)。
'''

DataFrame(nfl_frame,columns=['Team','First Season','Total Games'])

'''
上記のようにすると、「Team」「First Season」「Total Games」の3列名でのDataFrame(表:Table)ができる。
'''

## さらに新しい列(カラム)を追加できる。「Stadium」を追加。

DataFrame(nfl_frame,columns=['Team','First Season','Total Games','Stadium'])

# ただし、「Stadium」には何もデータが無いのでデータの箇所は「NaN(Null)」になる。

## notebookが縦に長くなるため、「.head()」を使うと先頭から○○行だけを表示できる。

# nfl_frame.head(3)  とすると、先頭(1行目)から、3行目までの表(Table)が表示される。

# 「.tail()は逆の下から○○行」

## indexの番号でアクセス「 .ix[] 」

'''
nfl_frame.ix[3] とすると、インデックス番号3(0から数えて4番目)のDataFrameにアクセスできる。

データを挿入するには、nfl_frame['Stadium'] = "Levi’s Stadium" とすると列全体に値を代入できる。

「Levi’s Stadium」に「’」があるので、全体は「”」にする。

ただし、上記だと列すべて「Levi’s Stadium」なので、nfl_frame["Stadium"] = np.arange(6) とすることで、0から5の数字が連番で代入される。

ただし「np.arange()」の引数と「列」の長さを合わせる用に注意
'''

## PandasのSeriesをDataFrameに追加する

#Seriesで「Levi’s Stadium」「AT&T Stadium」を作成して、そのindex番号を4番と0番に指定。
stadiums = Series(["Levi’s Stadium","AT&T Stadium"],index=[4,0])

# stadiums には以下が格納されている。
    4    Levi’s Stadium
    0      AT&T Stadium
    dtype: object

# その「stadiums」を先ほどのDataFrame(nfl_frame)に代入すると、

nfl_frame['Stadium']=stadiums

# nfl_frame の「列Stadium」の0番目は「AT&T Stadium」、4番目は「Levi’s Stadium」のデータが挿入されている(他は全て「Nan」)。

### 列を消す

'''
del nfl_frame['Stadium'] とすると、列Stadiumを列ごと削除できる。
PythonのDict型からDataFrameを作れる
'''

# 以下のようなPythonのDictを「変数data」に格納する。

data = {'City':['SF','LA','NYC'],
        'Population':[837000,3880000,8400000]}

# city_frame = DataFrame(data) とすると、DataFrameが作成されて「city_frame」に代入。
# city_frame には以下のようなデータフレームが格納されている。
        City 	Population
    0	SF  	837000
    1	LA  	3880000
    2	NYC 	8400000

Pandasのindexについて

# まず、PandasのSerieseを以下のように作成する。my_ser = Series([1,2,3,4],index=['A','B','C','D'])
 
# そのSerieseから、indexだけを取り出す。

my_index = my_ser.index

# my_index には以下のようにindexだけが格納されている。

Index(['A', 'B', 'C', 'D'], dtype='object')

# my_index[2] とすれば、3番目(0から数える)のindexを取り出せる。
'C'

# Pythonのスライスも可能(3番目以降を全て~)。
    my_index[2:]
    Index(['C', 'D'], dtype='object')

# ただしPandasは、indexの値を変更は不可(データの堅牢性のため)。

my_index[0] = 'Z'

TypeError: Indexes does not support mutable operations

# 上記のように「Z」を代入しようとするとエラーになる。

## Pandasのindexの変更について

# 簡単なSeriesを作り、「ser1」に代入。

ser1 = Series([1,2,3,4],index=['A','B','C','D'])

# ser1 は以下のようになっている。
    A    1
    B    2
    C    3
    D    4
    dtype: int64

# Pandasの「.reindex()」を使って、indexを変更。

ser2 = ser1.reindex(['A','B','C','D','E','F'])

# ser2 は以下のようになっている。
    A     1
    B     2
    C     3
    D     4
    E   NaN # 自動的にnullが入る
    F   NaN # 自動的にnullが入る
    dtype: float64

# 以下は値(Value)に、0、5、10のインデックスを付けている。

ser3 = Series(['USA','Mexico','Canada'],index=[0,5,10])

# ser3 は以下のようになっている。
    0        USA
    5     Mexico
    10    Canada
    dtype: object

# 一気に「NaN(Null)」を埋めてくれる「ffill(forward fill)」というものがある。

# ser3.reindex(range(15),method='ffill') とすると以下のようになる。
    0        USA
    1        USA # 自動的にUSAが入る
    2        USA # 自動的にUSAが入る
    3        USA # 自動的にUSAが入る
    4        USA # 自動的にUSAが入る
    5     Mexico
    6     Mexico # 自動的にMexicoが入る
    7     Mexico # 自動的にMexicoが入る
    8     Mexico # 自動的にMexicoが入る
    9     Mexico # 自動的にMexicoが入る
    10    Canada
    11    Canada # 自動的にCanadaが入る
    12    Canada # 自動的にCanadaが入る
    13    Canada # 自動的にCanadaが入る
    14    Canada # 自動的にCanadaが入る
    dtype: object


## reshapeを使ってDataFrameを作ってみます。

#「randn」は正規分布の乱数で5行5列のDataFrameを作る。Cをわざと抜いてindex名を代入。列名(カラム)を代入。
dframe = DataFrame(randn(25).reshape((5,5)),  
                    index=['A','B','D','E','F'],  
                    columns=['col1','col2','col3','col4','col5'])  

# dframe は以下のようになっている。
	col1  	 col2   	col3   	col4   	col5  
A	0.650892	1.571965	1.726236	-0.423697	0.110843
B	1.037495	0.037039	-1.368314	-1.041347	1.337007
D	-1.289793	0.652301	0.548770	0.636829	-0.349049
E	-0.573696	0.108592	0.863125	-0.109940	-0.577262
F	1.160227	-0.546492	1.172700	0.071298	1.222122


## Cが抜けているため以下のように値(データ)は「NaN(Null)」なる。

new_index = ['A','B','C','D','E','F']
dframe2 = dframe.reindex(new_index)

# dframe は以下のようになっている。
    	col1  	 col2   	col3   	col4   	col5  
    A	0.650892	1.571965	1.726236	-0.423697	0.110843
    B	1.037495	0.037039	-1.368314	-1.041347	1.337007
    C	NaN     	NaN    	NaN    	NaN    	NaN
    D	-1.289793	0.652301	0.548770	0.636829	-0.349049
    E	-0.573696	0.108592	0.863125	-0.109940	-0.577262
    F	1.160227	-0.546492	1.172700	0.071298	1.222122


## 「ix」を使うと、素早く「Reindex(再インデックス化)」が可能
dframe.ix[new_index, new_columns]

	col1  	 col2   	col3   	col4   	col5     col6   
A	0.650892	1.571965	1.726236	-0.423697	0.110843	NaN
B	1.037495	0.037039	-1.368314	-1.041347	1.337007	NaN
C	NaN     	NaN    	NaN    	NaN    	NaN          NaN
D	-1.289793	0.652301	0.548770	0.636829	-0.349049	NaN
E	-0.573696	0.108592	0.863125	-0.109940	-0.577262	NaN
F	1.160227	-0.546492	1.172700	0.071298	1.222122	NaN

SerieseやDataFrameの行や列を削除について

### お約束
import numpy as np
from pandas import Series,DataFrame
import pandas as pd

ser1 = Series(np.arange(3),index=['a','b','c'])

# ser1 とすると以下のようになる。
    a    0
    b    1
    c    2
    dtype: int64

## Serieseのindexを消すには「.drop()」を使用

# ser1.drop('b') とすると以下のようになる。
    a    0
    c    2
    dtype: int64


## DataFrameの場合

#「reshape」で3行3列のDataFrameを作成。index名を代入(都市の略称)。列名(カラム)を代入。
dframe1 = DataFrame(np.arange(9).reshape((3,3)),
                    index=['SF','LA','NY'], 
                    columns=['pop','size','year'])

# dframe1 とすると以下のようになる。

    	pop	size	year
    SF	0	1	2
    LA	3	4	5
    NY	6	7	8

## DataFrameのindexを指定して行を削除(axis=0が省略されている。「axisは軸」)

# dframe1.drop('LA')  とすると以下のようになる。

    	pop	size	year
    SF	0	1	2
    NY	6	7	8

# ただし大元のDataFrameの値が削除(変更)されたのではなく、index「LA」の行が削除されたDataFrameが生成されて返ってきているだけ。

## DataFrameの列(カラム)を削除することも可能(その場合、列の軸を示す、axis=1が必要。「axisは軸」)

dframe1.drop('year',axis=1)

    	pop	size
    SF	0	1
    LA	3	4
    NY	6	7

SerieseやDataFrameからデータを取り出す

import numpy as np
from pandas import Series,DataFrame
import pandas as pd

ser1 = Series(np.arange(3),index=['A','B','C'])

# 分かりやすい数値にするため各要素を2倍。
ser1 = 2*ser1

# ser1 とすると以下のようになる。
    A    0
    B    2
    C    4
    dtype: int64

ser1['B'] ### 2 が返ってくる
ser1[1] ### 2 が返ってくる

ser1[0:3]    # 数字の添え字で範囲も指定可能。
    A    0
    B    2
    C    4
    dtype: int64

ser1[['A','B','C']]  # ABCの文字列のindexをリスト形式で与えることも可能。
    A    0
    B    2
    C    4
    dtype: int64


# 論理式を与えることも可能。
ser1[ser1>3]
    C    4
    dtype: int64

# 条件に合った場所の値を変更できます。
ser1[ser1>3] = 10

# ser1 とすると以下のようになる。
    A     0
    B     2
    C    10  # 10に書き換わった。
    dtype: int64

## DataFrameの場合

#「reshape」で5行5列のDataFrameを作成。index名を代入(都市の略称)。列名(カラム)を代入。
dframe = DataFrame(np.arange(25).reshape((5,5)),  
                    index=['NYC','LA','SF','DC','Chi'],
                    columns=['A','B','C','D','E'])

# dframe とすると以下のようになる。
    	A	B	C	D	E
    NYC	0	1	2	3	4
    LA	5	6	7	8	9
    SF	10	11	12	13	14
    DC	15	16	17	18	19
    Chi	20	21	22	23	24


# 列(カラム)の名前で選択(ここでは「列B」)
dframe['B']
    NYC     1
    LA      6
    SF     11
    DC     16
    Chi    21
    Name: B, dtype: int64

# リストで複数のカラムを選択可能(「列B」と「列E」を選択)
dframe[['B','E']]
    	B	E
    NYC	1	4
    LA	6	9
    SF	11	14
    DC	16	19
    Chi	21	24


# 論理式を与えることも可能(「列C」で値が「8」より大きい「行」を表示)
dframe[dframe['C']>8]

    	A	B	C	D	E
    SF	10	11	12	13	14
    DC	15	16	17	18	19
    Chi	20	21	22	23	24


# 真偽値(ブーリアン)をそのまま表示することも可能。
dframe> 10

    	A	B	C	D	E
    NYC	False	False	False	False	False
    LA	False	False	False	False	False
    SF	False	True	True	True	True
    DC	True	True	True	True	True
    Chi	True	True	True	True	True


# 「ix」を使うと「行」のデータを縦(列ではない)のように表示する。
dframe.ix['LA']
    A    5
    B    6
    C    7
    D    8
    E    9
    Name: LA, dtype: int64


# 「ix」には「数字」の添え字も渡せる(ここでは2番目の行。つまり「LA」と同じ)。
dframe.ix[1]
    A    5
    B    6
    C    7
    D    8
    E    9
    Name: LA, dtype: int64

Pythonデータサイエンス入門以前のメモ(その1)

こちらの学習コンテンツを眺めながら自分用のメモを記していくことに。
www.udemy.com

Numpy入門以前

# 2行4列のリストの場合は、(2, 4)の感じでタプルを返す 
np.shpae() 

# こんな感じ「 dtype('int64') 」で格納されているデータの「データ型」を返す(Numpyは全て同じ型でなければならない)。
np.dtype() 

# array([0., 0., 0., 0., 0.,])
np.zeros(5)  

# 引数にタプルを渡すと、5行5列の1の2次元配列ができる
np.ones((5,5))  

#空っぽの3行4列の2次元配列を作れる。
np.empty((3, 4)) 

#Numpyのアライを返す。array([0, 1, 2, 3, 4])

np.arange(5) 

# Python2だと割り算が割れないので最初に記述する。
from __future__ import division 

'''
arrというアレイから、
 - slice_arr = arr
 - slice_arr[:] = 99 

をすると、もとの「arr」にも99が入ってしまいます。

その場合、
 - slice_arr = arr.copy() 
 - 引数なしで.copy()

をすれば、大元の「arr」の値は上書きされない。
'''

# arr[0, 1, 2, 3, 4, 5, 6, 7, 8] の配列を .reshape((3, 3)) とすると、3行3列の2次元配列にリシェイプされる。
np.reshape() 

# arr.Tとすると行と列を入れ替えできる。TはTranspose。arr.transpose()でも同じ結果。転置のティーと覚える。

# 平方根(√)を計算する。2なら「1.4142」、3なら「1.732050」
np.sqrt() 

# アレイA, アレイBのアレイ要素同士の足し算ができる
np.add(A, B) 

# アレイA, アレイBのそれぞれ大きい方の要素を返す(ごっちゃになる選抜)
np.maximum(A, B) 


# このように書くことでnotebook上にそのまま描画できるらしい
import matplotlib.pyplot as pyplot
%matplotlib inline

Numpyアレイ続き

A = np.array([1, 2, 3, 4])
B = np.array([1000, 2000, 3000, 4000])
condition = np.array([True, True, False, False])
anser = [(a if cond else b) for a,b,cond in zip(A,B,conditon)]
anser2 = np.where(condition, A, B)

#  [1, 2, 3000, 4000] をリストの形で返す。(ただしコレだと多次元アレイに対応できないらしい)。
「anser」 

# array([   1,   2, 3000, 4000]) をNumpyアレイの形で返す。(「np.where」は1次元のアレイだが多次元にも対応なのでコレの方が良い)。
「anser2」 

# アレイを足し算する(引数なしだと、全部の要素の合計)。
arr.sum() 

# 0を引数にとると、行方向に「列」の合計値を返す。
arr.sum(0)

# アレイの平均値
arr.mean() 

# アレイの標準偏差
arr.std()

# 分散値
arr.var()

# アレイの要素がソートされる(デフォルトでは小さい値順になる)。
np.any()
np.all()
np.sort()


# 「np.unique()」で重複しているものを省いたアレイを返す。
gorillas = np.array(['kiyo', 'syaba', 'anii', 'nene', 'kiyo' 'haoko', 'syaba'])
np.unique(gorillas)
 
# array(['kiyo', 'syaba', 'anii', 'nene', 'haoko'])
np.in1d() 

'''
1つ目の引数にとったアレイが、2つ目の引数に入っているかを個別に判定(bool値を返す)
'''

### Numpyアレイの保存

'''
arr = np.arange(5) で array([0, 1, 2, 3, 4]) の1次元アレイを作り、その後に、np.save('my_array', arr)とすることで、「.npy」の拡張子でNumpyアレイをファイルとして保存することができる。

np.load('my_array.npy')とすると保存したNumpyアレイを返すことができる。
'''

# ジップ形式でアレイを保存することが可能(拡張子は「.npz」)
np.savez('ziparrays.npz', x=arr1, y=arr2)

'''
「ziparrays.npz」というファイル名で、さらにXとして「arr1」をジップ保存、yとして「arr2」をジップ保存している。
zipArr = np.load('ziparrays.npz') とすれば読み込みできる。

さらに、zipArr['x'] とすることで、さきほど「x=arr1」としたarr1のアレイを返すことができる。
'''

# テキストでアレイを保存
arr = np.array([[1,2,3,4],[5,6,7,8]])

# 第3引数の「delimiter」で区切り文字を指定
np.savetxt('my_test_text.txt', arr, delimiter=',') 

# MacとLinuxなら「!」をつけるとコマンドが使える。
!cat my_test_text.txt  

# 以下のようにすることで読み込みする。
np.loadtxt('my_test_text', delimiter=',') 


'''
Pandasのシリーズについて
np.arrayとpd.Seriesの違いは、インデックスに番号(連番)が付いていること。ちなみに、pd.Series.valuesでシリーズのデータだけを取り出せて、中身は、Numpyのアレイが返ってくる。
'''

ww2_cas = Series([8700000,4300000,3000000,2100000,400000],
     index=['USSR','Germany','China','Japan','USA'])

# ww2_cas には以下が格納されている。
    USSR       8700000
    Germany    4300000
    China      3000000
    Japan      2100000
    USA         400000
    dtype: int64

# indexを数字から文字列に変更すれば、文字列のindex指定でアクセスできる。

# 400000が返ってくる
ww2_cas['USA']

# 以下のように4000000以上の数字のものを抽出もできる。
ww2_cas[ww2_cas>4000000] とすると以下が返ってくる。
    USSR       8700000
    Germany    4300000
    dtype: int64

### Pythonの辞書型に変換もできる。
# ww2_dict = ww2_cas.to_dict() とすると、ww2_dict には以下が格納されている。
        {'China': 3000000,
         'Germany': 4300000,
         'Japan': 2100000,
         'USA': 400000,
         'USSR': 8700000}

# 上記の辞書をもとに、PandasのSeriesを作ることができる。

# WW2_Series = Series(ww2_dict) とすると、

    # WW2_Seriesには以下が格納されている。
        China      3000000
        Germany    4300000
        Japan      2100000
        USA         400000
        USSR       8700000
        dtype: int64

## indexを追加することができる(Argentinaを追加)。

countries = ['China','Germany','Japan','USA','USSR','Argentina']
obj2 = Series(ww2_dict,index=countries)

    # obj2には以下が格納されている。
        China        3000000
        Germany      4300000
        Japan        2100000
        USA           400000
        USSR         8700000
        Argentina        NaN # アルゼンチンは死者数を入れていないため。
        dtype: float64

# ちなみにnullデータがあるかどうかを確認可能。 pd.isnull(obj2) とすると、nullがあればTrueが返ってくる。

### Pd.Seriesには、名前を付けらる。

obj2.name = '第二次世界大戦の死傷者'

    # obj2には以下が格納されている。
        China        3000000
        Germany      4300000
        Japan        2100000
        USA           400000
        USSR         8700000
        Argentina        NaN
        Name: 第二次世界大戦の死傷者, dtype: float64

# indexに名前を付けることも可能
obj2.index.name = 'Countries'

    # obj2には以下が格納されている。
        Countries
        China        3000000
        Germany      4300000
        Japan        2100000
        USA           400000
        USSR         8700000
        Argentina        NaN
        Name: 第二次世界大戦の死傷者, dtype: float64

Raspberry PiへROS (Robot Operating System)のインストールと実行

興味があったのでROSを学習してみよう、ということでインストールと動作の実行を行って見たいと思います。

※最初にRaspberry Pi3(Raspbian)へのインストールを行おうとしましたが、なぜか途中でうまくいかなくなったためRaspberry Pi2にて正式対応のUbuntuへインストール。


以下の記事と書籍を参考にしました。
ラズパイで動くロボット「GoPiGo」をつかって遠隔見守りロボットを作ろう(1) 開発準備編 (1/6):CodeZine(コードジン)
ROSではじめるロボットプログラミング―フリーのロボット用「フレームワーク」 (I・O BOOKS)

wicd-cursesのインストール

※Ubuntu14.04 LTSはMicroSDに転送済み

$ sudo apt-get update 
$ sudo apt-get wicd-curses 
$ sudo reboot 
$ sudo wicd-curses  

すんなり起動ができず、いったんapt-get dist-upgradeをなど試しているうちに起動しました。

公式サイトに従ってROS Indigoのインストール

$ sudo update-locale LANG=C LANGUAGE=C LC_ALL=C LC_MESSAGES=POSIX 
$ sudo sh -c 'echo "deb http://packages.ros.org/ros/ubuntu trusty main" > /etc/apt/sources.list.d/ros-latest.list' 
$ sudo apt-key adv --keyserver hkp://ha.pool.sks-keyservers.net --recv-key 0xB01FA116 
$ sudo apt-get update 
$ sudo apt-get install ros-indigo-ros-base -y  

rosdepのインストールと初期化

$ sudo apt-get install python-rosdep 
$ sudo rosdep init 
$ rosdep update  

ROSの環境変数をシステムに反映/rosinstallのインストール

$ echo "source /opt/ros/indigo/setup.bash" >> ~/.bashrc 
$ source ~/.bashrc 
$ sudo apt-get install python-rosinstall  

ここまでも良くわからない失敗などを繰り返し、なんとかインストール完了。

Hello worldを実行

import rospy

rospy.init_node('hello_world_node')
rospy.loginfo('hello world')
rospy.spin()

実行

$ python hellow_world.py  

ファイルがありませんとエラー発生。

パーミッションを変更

$ chmod u+x hellow_world.py  

再度実行したらきちんと'hello world'が表示されました。

ワークスペースディレクトリを作成

$ mkdir -p ~/catkin_ws/src 
$ cd ~/catkin_ws/  

ROSの起動

ここでもう1つターミナルを立ち上げる。

$ roscore 
... logging to /home/ubuntu/.ros/log/71ba861e-f35d-11e6-b4a0-0022cffb11db/roslaunch-ubuntu-1318.log 
Checking log directory for disk usage. This may take awhile. 

~中略~ 

setting /run_id to 71ba861e-f35d-11e6-b4a0-0022cffb11db 
process[rosout-1]: started with pid [1343] 
started core service [/rosout]


きちんと起動されました。

ROSワークスペースの作成

$ mkdir -p ~/catkin_ws/src 
$ cd ~/catkin_ws/src/ 
$ catkin_init_workspace 
$ catkin_make  

CMake Error: your CXX compiler: "CMAKE_CXX_COMPILER-NOTFOUND" was not found. Please set CMAKE_CXX_COMPILER to a valid compiler path or name.

catkin_makeでエラー発生。

g++ をインストール

$ sudo apt-get install g++  

再度実行

$ catkin_make 

#### Running command: "make -j4 -l4" in "/home/ubuntu/catkin_ws/build"  

きちんとビルドされました。


その他の実行は以下(長くなってきたため...)

$ source ~/catkin_ws/devel/setup.bash 
$ vim ~/.bashrc 

#source /opt/ros/indigo/setup.bash 
source ~/catkin_ws/devel/setup.bash 

$ echo $ROS_PACKAGE_PATH 

/home/ubuntu/catkin_ws/src:/opt/ros/indigo/share:/opt/ros/indigo/stacks 

$ cd ~/catkin_ws/src 
$ catkin_create_pkg ros_start rospy roscpp std_msgs 
$ cd ~/catkin_ws 
$ catkin_make 
$ source ~/catkin_ws/devel/setup.bash 
$ roscd ros_start 
$ cd ~/catkin_ws/src/ros_start 
$ mkdir scripts 
$ cd scripts  

Pubkisherの作成

Subscriberの作成

パーミッションを変更

$ chmod 755 talker.py listener.py 

ここでさらにもう1つターミナルを立ち上げて(計3つ)実行

$ roscore 
$ rosrun ros_start talker.py 
$ rosrun ros_start listener.py  

以下のようにポーリングっぽいループ処理が走りました!

[INFO] [WallTime: 1487159069.768171] I heard hello. world 1487159069.77 
[INFO] [WallTime: 1487159069.868088] I heard hello. world 1487159069.87 
[INFO] [WallTime: 1487159069.968091] I heard hello. world 1487159069.97 
[INFO] [WallTime: 1487159070.068077] I heard hello. world 1487159070.07 
[INFO] [WallTime: 1487159070.168078] I heard hello. world 1487159070.17 
[INFO] [WallTime: 1487159070.268178] I heard hello. world 1487159070.27  

.....という形で一応、動作できたっぽいです。ココに到達するまですんなりうまくいかないところもあり、試行錯誤したのでとりあえずホッとしました。

Raspberry Pi3環境によるOpenCVの実行

Raspberry Pi3にOpenCV3.1をインストールします。
※既にPython3やpipはインストール済み

参考にさせていただいた記事
www.pyimagesearch.com
a244.hateblo.jp

まずはopencv-3.1.0とopencv_contrib-3.1.0のダウンロード

$ wget -O opencv-3.1.0.zip https://github.com/opencv/opencv/archive/3.1.0.zip 
$ wget -O opencv_contrib-3.1.0.zip https://github.com/opencv/opencv_contrib/archive/3.1.0.zip  

上記記事を参考にし、pyenvの仮想環境で構築しようとするとmakeを実行までは成功するもその後のinstallでなぜか失敗。仮想環境とPython2系を選択肢から外して行うことで何とか成功(ただし2回ビルドエラーになる)。

もろもろ格闘して以下を実行

$ make -j4 
$ sudo make install 
$ sudo ldconfig  

…なんどもやり直しによる長時間の待ち時間を経て、インストール完了しました。ビルド自体は2時間かからないくらい。

さっそくOpenCVHello world(?)であるLena sampleを実行(Haar-cascade Detection)

$ python3 facedetect.py

f:id:coffeedog:20170212231324p:plain

正常に検出(ただしGUI環境だとメモリが少なく途中でフリーズ)。
とりあえず、今後はカメラモジュールと組み合わせて何かを処理していきたいと思います。

Raspberry Pi3環境によるTensorFlowのインストールと実行

TensorFlowをRaspberry Piに対応したいと思います。Googleも今後はRaspberry Piと連携していくみたいです。

まずはTensorFlowのインストール

※既にPython3やpipはインストール済み

以下の記事を参考にしました。

参考にさせていただいた記事
qiita.com
github.com

以下を実行

$ wget https://github.com/samjabrahams/tensorflow-on-raspberry-pi/releases/download/v0.12.1/tensorflow-0.12.1-cp34-cp34m-linux_armv7l.whl 
$ sudo pip3 install tensorflow-0.12.1-cp34-cp34m-linux_armv7l.whl

すんなりインストール完了しました。

動作テスト(hello, tensorflow!)

さっそくHello worldを実行

pi@raspberrypi:~ $ python3
Python 3.4.2 (default, Oct 19 2014, 13:31:11) 
[GCC 4.9.1] on linux
>>> # hello-tf.py
... import tensorflow as tf
>>> import multiprocessing as mp
>>> 
>>> core_num = mp.cpu_count()
>>> config = tf.ConfigProto(
...     inter_op_parallelism_threads=core_num,
...     intra_op_parallelism_threads=core_num )
>>> sess = tf.Session(config=config)
>>> 
>>> hello = tf.constant('Hello, tensorflow!')
>>> print(sess.run(hello))
'Hello, tensorflow!'
>>> 
>>> a = tf.constant(10)
>>> b = tf.constant(32)
>>> print(sess.run(a+b))
42

問題なく実行できました。適当に引っ張ってきた画像(サイ)をお借りして試しにサンプル実行をしてみます(以下記事を参考)。
arkouji.cocolog-nifty.com
f:id:coffeedog:20170216111300j:plain

$ python3 classify_image.py --image_file rhino01.jpg
W tensorflow/core/framework/op_def_util.cc:332] Op BatchNormWithGlobalNormalization is deprecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization(). 
triceratops (score = 0.91139) 
warthog (score = 0.00875) 
hippopotamus, hippo, river horse, Hippopotamus amphibius (score = 0.00297)

91%でトリケラトプスと認識してます。まさかのサイは圏外。

別の画像(サイ)をお借りして試しにサンプル実行。
f:id:coffeedog:20170216111426j:plain

$ python3 classify_image.py --image_file rhino02.jpg 
W tensorflow/core/framework/op_def_util.cc:332] Op BatchNormWithGlobalNormalization is deprecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization(). 
triceratops (score = 0.85796) 
hippopotamus, hippo, river horse, Hippopotamus amphibius (score = 0.01660) 
Indian elephant, Elephas maximus (score = 0.01387)

85%でトリケラトプスと認識してます。カバは出てきますがサイはまたも圏外。

つぎはキリンの画像で実行
f:id:coffeedog:20170216111902j:plain

$ python3 classify_image.py --image_file giraffe01.jpg
W tensorflow/core/framework/op_def_util.cc:332] Op BatchNormWithGlobalNormalization is deprecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization(). 
cheetah, chetah, Acinonyx jubatus (score = 0.17464) 
zebra (score = 0.05517) 
hyena, hyaena (score = 0.05437)

17%でチーターと認識してます。全体的にかなり低い精度です。

別の画像(キリン)をお借りして試しにサンプル実行。
f:id:coffeedog:20090804000000j:plain

$ python3 classify_image.py --image_file giraffe02.jpg 
W tensorflow/core/framework/op_def_util.cc:332] Op BatchNormWithGlobalNormalization is deprecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization(). 
cheetah, chetah, Acinonyx jubatus (score = 0.32205) 
hyena, hyaena (score = 0.27464) 
African hunting dog, hyena dog, Cape hunting dog, Lycaon pictus (score = 0.01903)

32%でチーターと少し精度が上がったものの、かなり低い数値。

今度は動物ではなくTensorFlowのロゴをお借りして試しにサンプル実行。
f:id:coffeedog:20170216111911j:plain

$ python3 classify_image.py --image_file tensorflow.jpg 
W tensorflow/core/framework/op_def_util.cc:332] Op BatchNormWithGlobalNormalization is deprecated. It will cease to work in GraphDef version 9. Use tf.nn.batch_normalization(). 
Band Aid (score = 0.64480) 
cash machine, cash dispenser, automated teller machine, automatic teller machine, automated teller, automatic teller, ATM (score = 0.05389) 
sunscreen, sunblock, sun blocker (score = 0.01263)

64%でバンドエイドと認識。その他5%でキャッシュディスペンサーと認識してます。ある意味イケるのかと期待しましたが、全くだめでした。

とはいえドンピシャでハマると結構良い精度で認識するものもあるようなので、機会があれば得手不得手の画像や角度を見極めて見たいと思います。

Windows/Mac環境によるTensorFlowの動作テスト

Windows環境によるTensorFlowの動作テスト

参考にさせていただいた記事

yaju3d.hatenablog.jp

qiita.com

Download and Setup  |  TensorFlow


以下を実行

pip install --upgrade https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-0.12.0rc0-cp35-cp35m-win_amd64.whl  

エラー

Collecting tensorflow-gpu==0.12.0rc0 from https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-0.12.0rc0-cp35-cp35m-win_amd64.whl
Downloading https://storage.googleapis.com/tensorflow/windows/gpu/tensorflow_gpu-0.12.0rc0-cp35-cp35m-win_amd64.whl (32.5MB)
100% |################################| 32.5MB 32kB/s
Requirement already up-to-date: wheel>=0.26 in c:\users\owner\anaconda3\lib\site-packages (from tensorflow-gpu==0.12.0rc0)
Requirement already up-to-date: protobuf==3.1.0 in c:\users\owner\anaconda3\lib\site-packages (from tensorflow-gpu==0.12.0rc0)
Requirement already up-to-date: six>=1.10.0 in c:\users\owner\anaconda3\lib\site-packages (from tensorflow-gpu==0.12.0rc0)
Requirement already up-to-date: numpy>=1.11.0 in c:\users\owner\anaconda3\lib\site-packages (from tensorflow-gpu==0.12.0rc0)
Collecting setuptools (from protobuf==3.1.0->tensorflow-gpu==0.12.0rc0)
Using cached setuptools-31.0.0-py2.py3-none-any.whl
Installing collected packages: tensorflow-gpu, setuptools
Found existing installation: tensorflow-gpu 0.12.0rc0
Uninstalling tensorflow-gpu-0.12.0rc0:
Successfully uninstalled tensorflow-gpu-0.12.0rc0
Found existing installation: setuptools 23.0.0
Cannot remove entries from nonexistent file c:\users\owner\anaconda3\lib\site-packages\easy-install.pth

以下を参考にエラー対応
h-piiice16.hatenablog.com


記事中引用

調べてみるとsetuptoolsがコンフリクトしているのが問題らしくconda removeでsetuptoolsをリムーブすれば大丈夫かと思いいろいろ試行錯誤してみたもののうまく行かず…

とありましたが、そのままremoveでとりあえず動作。

Successfully installed setuptools-31.0.0 tensorflow-gpu-0.12.0rc0

インストール完了。


MNISTチュートリアルWindows CPU実行)

参考にさせていただいた記事

TensorFlow : ML 初心者向けの MNIST (コード解説) – TensorFlow

PyCharm上で実行

Successfully downloaded train-images-idx3-ubyte.gz 9912422 bytes.
Extracting /tmp/data/train-images-idx3-ubyte.gz

・・・・・・・・・・・・

0.9172

91%の精度(90%くらいだと精度が悪いようです)。

WARNING:tensorflow:From ...in <module>.: initialize_all_variables (from tensorflow.python.ops.variables) is deprecated and will be removed after 2017-03-02.
Instructions for updating:
Use `tf.global_variables_initializer` instead.

※今年の3月までに変数初期化命令を global_variables_initializer に変える必要があり(以下参考)。

qiita.com

一応Mac上でも動作確認(Jupyter Notebook上で実行)

今度はWindowsGPU環境でMNISTのExpertsをテスト(Jupyter Notebook上で実行)


結果は99.2%(計算には2分かからないくらい)。

step 400以降はずっと96%~100%を行ったり来たり。step 8700で94%になってしまいましたが、その後は安定して98%前後でした。

Pythonを学習してみる

年末から新年にかけて

をやってみました。とりあえず以前にドットインストールでPython2.7(旧版)をさらっとやったことがありましたが、あんまり覚えていかったので再度復習(現在はPython3対応で一部プレミアム版のみ)。

また、Udemyの方の講座(Python3入門)は結構前に1800円くらいで購入してずっとやっていなかったのですが、この機会に初歩的な文法を学ぶことに。

その他にもUdemyは年末にキャンペーンをしていたので

といかにもミーハーな講座を購入しました。

みんなのAI講座

3層パーセプトロン誤差逆伝播法の基本的なイメージがつかめて、初心者にも分かりやすい内容でした。またscikit-learnにも触れており、機械学習をツールとして利用したい人には良い講座だと思います。ただしコードの説明はかなりあっさりしているのと、数学などには殆ど触れないので実際にいろいろと試すには独自に数学やテクニックを学んでいく必要があるように感じます。

実践 Python データサイエンス

NumpyやMatplotlib、Pandasなどの各種ライブラリやJupter-Notebookなど取り扱っている講座になっています。この講座もscikit-learnを取り扱ってました。データサイエンスや統計をイメージするのにうってつけの講座のような気がします(そしてまだ半分も終わっていない)。

Python機械学習

こちら講座もscikit-learnを利用して機械学習のかなり基本的なところから、初心者からすれば少し実践的なところまで網羅しているので機械学習のイメージを掴むには良さそう(これもまだ全然終わっていない)。

ArduinoでRover超入門

ArduinoでRoverを超入門した話(というほどのモノでもないですが)。

構成

  • Arduino UNO x 1
  • Arduino用モバイルバッテリー
  • 超音波センサ x 1
  • マイクロサーボ x 1

マイクロサーボ9g SG−90: パーツ一般 秋月電子通商 電子部品 ネット通販
超音波距離センサー HC−SR04: センサ一般 秋月電子通商 電子部品 ネット通販

  • モータードライバ x 2
  • その他もろもろ

モータードライバはSN754410NE(2つあれば4輪駆動が可能)
akizukidenshi.com

Rover本体側のパーツ

マイコンカーベース板 - aitendo
モータホルダ - aitendo
ホイール付きタイヤ - aitendo
DC減速型モータ - aitendo
電池ボックス 単3×4本 リード線・フタ・スイッチ付: パーツ一般 秋月電子通商 電子部品 ネット通販

大変だったこと

通常の単3電池4本だと、パワーが足りずめちゃくちゃ遅いか、駆動ができない状態に。。。プログラムやパーツの重量の原因なのは重々承知でしたが、ちまたのRover動画などを拝見してるとめちゃくちゃスムーズに動いていて・・・

そんな時、ニッケル単3電池が出力強いよと知り合いが言っていたので、ためしに変更してみましたところ、

なんと!!(ギリギリではありますが)まともに動くようになりました!!
vimeo.com
(1.5Vから1.2Vの電池へ交換なのになぜなんだぜ??)

その他大変だったこと

  • ジャンパワイヤの配線が大変でしたし、結果すんごい汚い状態で接続(ちまたの完成形では恐ろしいほどにみんな綺麗で無駄がない)
  • 各モーター(4個)それぞれにコンデンサを1つだけ半田付けしましたが、これが結構難しくて大変でした(本当は2つずつ付けたかった)
  • バッテリーボックスをジャンパワイヤ接続できるようにコンタクタなどを買ったですが、どうしてもうまくカシめることができずに知り合いにカシめてもらいました。

プログラム

#include<Servo.h>

//アナログピンをデジタルピンとして代用
#define MOTOR_A1 14
#define MOTOR_A2 15
#define MOTOR_B1 17
#define MOTOR_B2 16

#define MOTOR_C1 6
#define MOTOR_C2 7
#define MOTOR_D1 12
#define MOTOR_D2 13

Servo myservo;

int motor_speed = 255;   //回転速度(0~255段階)

const int trigPin = 2;   //HC-SR04のトリガーを2pin
const int echoPin = 4;   //HC-SR04のエコーを4pin
unsigned long duration;  //距離(HC-SR04)
int cm;                  //距離(cmへ変換)

void setup()
{
    pinMode(MOTOR_A1, OUTPUT);
    pinMode(MOTOR_A2, OUTPUT);
    pinMode(11, OUTPUT);

    pinMode(MOTOR_B1, OUTPUT);
    pinMode(MOTOR_B2, OUTPUT);
    pinMode(3, OUTPUT);

    pinMode(MOTOR_C1, OUTPUT);
    pinMode(MOTOR_C2, OUTPUT);
    pinMode(9, OUTPUT);

    pinMode(MOTOR_D1, OUTPUT);
    pinMode(MOTOR_D2, OUTPUT);
    pinMode(10, OUTPUT);

    //HC-SR04の設定
    pinMode(trigPin, OUTPUT);
    pinMode(echoPin, INPUT);
    Serial.begin(9600);

    //SG90の設定
    myservo.attach(5);
    //SG90を横に取り付けたため初期値90に設定
    myservo.write(90);
}

void loop() {
    motor_foward();
    conflict_control();
}

//---距離検出-------------------------------------
void detect_sonor()
{
    //pinをOUTPUTに設定(パルス送信のため)
    pinMode(trigPin, OUTPUT);
    //LOWパルスを送信
    digitalWrite(trigPin, LOW);
    delayMicroseconds(5);
    //HIGHパルスを送信
    digitalWrite(trigPin, HIGH);
    //10uSパルスを送信してHC-SR04を起動
    delayMicroseconds(10);
    digitalWrite(trigPin, LOW);

    //入力パルスの長さを測定
    duration = pulseIn(echoPin, HIGH);

    //パルスの長さを半分に分割
    duration = duration / 2;
    //cmに変換
    cm = int(duration / 29);

    //シリアルコンソールに表示
    Serial.print(cm);
    Serial.print("cm");
    Serial.println();

    delay(100);
}

//---衝突回避-------------------------------------
void conflict_control()
{
    detect_sonor();
    if (cm <= 20) {
        motor_stop();
        motor_back();
        motor_stop();
        //左方確認
        myservo.write(165);
        delay(500);
        detect_sonor();
        if (cm <= 20) {
            //右方確認
            myservo.write(10);
            delay(500);
            detect_sonor();
            if (cm <= 20) {
                //前方向を向く
                myservo.write(90);
                delay(500);
                motor_back();
                motor_stop();
                //左方確認(再)
                myservo.write(165);
                delay(500);
                detect_sonor();
                if (cm <= 20) {
                    //右方確認(再)
                    myservo.write(10);
                    delay(500);
                    detect_sonor();
                    if (cm <= 20) {
                        //前方
                        myservo.write(90);
                        delay(500);
                        //方向転換(180度)
                        motor_left();
                        delay(2000);
                        motor_foward();
                    } else {
                        //前方
                        myservo.write(90);
                        delay(500);
                        motor_left();
                        motor_foward();
                    }
                } else {
                    //前方
                    myservo.write(90);
                    delay(500);
                    motor_left();
                    motor_foward();
                }
            } else {
                //前方
                myservo.write(90);
                delay(500);
                motor_left();
                motor_foward();
            }
        } else {
            //前方
            myservo.write(90);
            delay(500);
            motor_right();
            motor_foward();
        }
    }
}

//---前進-------------------------------------
void motor_foward()
{
    digitalWrite(MOTOR_A1, HIGH);
    digitalWrite(MOTOR_A2, LOW);
    analogWrite(11, motor_speed);

    digitalWrite(MOTOR_B1, HIGH);
    digitalWrite(MOTOR_B2, LOW);
    analogWrite(3, motor_speed);

    digitalWrite(MOTOR_D2, HIGH);
    digitalWrite(MOTOR_D1, LOW);
    analogWrite(9, motor_speed);

    digitalWrite(MOTOR_C2, HIGH);
    digitalWrite(MOTOR_C1, LOW);
    analogWrite(10, motor_speed);
}

//---後退-------------------------------------
void motor_back()
{
    digitalWrite(MOTOR_A1, LOW);
    digitalWrite(MOTOR_A2, HIGH);
    analogWrite(11, motor_speed);

    digitalWrite(MOTOR_B1, LOW);
    digitalWrite(MOTOR_B2, HIGH);
    analogWrite(3, motor_speed);

    digitalWrite(MOTOR_D2, LOW);
    digitalWrite(MOTOR_D1, HIGH);
    analogWrite(9, motor_speed);

    digitalWrite(MOTOR_C2, LOW);
    digitalWrite(MOTOR_C1, HIGH);
    analogWrite(10, motor_speed);

    delay(500);
}

//---左旋回-------------------------------------
void motor_left()
{
    digitalWrite(MOTOR_A1, HIGH);
    digitalWrite(MOTOR_A2, LOW);
    analogWrite(11, 255);

    digitalWrite(MOTOR_B1, LOW);
    digitalWrite(MOTOR_B2, HIGH);
    analogWrite(3, motor_speed);

    digitalWrite(MOTOR_D2, HIGH);
    digitalWrite(MOTOR_D1, LOW);
    analogWrite(9, motor_speed);

    digitalWrite(MOTOR_C2, LOW);
    digitalWrite(MOTOR_C1, HIGH);
    analogWrite(10, motor_speed);

    delay(1000);
}

//---右旋回-------------------------------------
void motor_right()
{
    digitalWrite(MOTOR_A1, LOW);
    digitalWrite(MOTOR_A2, HIGH);
    analogWrite(11, motor_speed);

    digitalWrite(MOTOR_B1, HIGH);
    digitalWrite(MOTOR_B2, LOW);
    analogWrite(3, motor_speed);

    digitalWrite(MOTOR_D2, LOW);
    digitalWrite(MOTOR_D1, HIGH);
    analogWrite(9, motor_speed);

    digitalWrite(MOTOR_C2, HIGH);
    digitalWrite(MOTOR_C1, LOW);
    analogWrite(10, motor_speed);

    delay(1000);
}

//---停止-------------------------------------
void motor_stop()
{
    analogWrite(11, 0);
    analogWrite(3, 0);

    analogWrite(9, 0);
    analogWrite(10, 0);

    delay(500);
}

普通の人なら簡単にできそうなことかもですが、結構(かなり)大変でしたが、動いてよかった!!

OpenCV入門以前

以前に、実践OpenCV 2.4 for Pythonという書籍を購入していたにもかかわらず、ほとんど読まずに積読状態。。せっかくだから入門下準備を整えてむることに。ちなみに、こちら既に絶版のようでAmazon中古価格が7000円超え。

書籍のバージョンは

なのですが、Python3.5、OpenCV 3.1 をインストールしました。

余談ですが、Visual Studio2015にインストールしようとしたため、CmakeやらCUDA対応やらやたら時間がかかったあげく、C++では実行できましたが、Pythonのやり方があんまりよくわからず、素直にAnacondaでインストールし直しました。

参考にさせていただいたのはこちらの記事
nixeneko.hatenablog.com
qiita.com

> conda install -c menpo opencv3

あっさりインストール完了。Visual Studioへの道はなんだったのか。

とりあえずOpenCVチュートリアルのメッシを表示させる。

import numpy as np
import cv2

img = cv2.imread('messi5.jpg',0)

cv2.imshow('image',img)
cv2.waitKey(0)
cv2.destroyAllWindows()

f:id:guzuzu:20170120223435p:plain

お、きちんと表示されました。