GIG

赴くままに技術を。

NvidiaのDeep Learning Quest(無料分)を受ける

すでにひとしきり広まった感があるDeep Learning。 Nvidiaがかなり本腰入れていて、それ向けの教育プログラムまである。

f:id:hermesian:20160504130503p:plain

どういうものかは知っておきたいので、無料枠で受けれる「ディープラーニング入門」を受講してみよう。実際AWS上に構築された環境を触りながらできるハンズオン形式で、有料のプログラムもAWSの利用料金ぐらいの値段みたい(とNvidia Deep Learning Day 2016 Springで紹介されていた)。

私たちは、あなたがあなたのアプリケーションは、研究者や開発者として必要な最高のどのフレームワークスーツを決める手助けを目的とした深い学習> のための最も一般的なソフトウェアフレームワークを見学します。この見学では、あなたのアプリケーションに一番適したディープラーニングフレーム> ワークを決定する事をゴールにします。ディープラーニングの予備知識は必要ありません。

たしかにDLフレームワークは乱立している印象がある。Software links « Deep Learningを見ると38種もあるのか。

起動に4分程度かかるとのこと。Jupyter Notebook形式なのね。 始まるとなんとタイマーが起動して、55分の間だけ利用できるとのこと。

f:id:hermesian:20160504130510p:plain

各DLフレームワークの採用基準も記載があった。 NVDLDでも下記のような比較がされてたけど、TheanoとTorch7の比較(性能面、機能面)があまり理解できていない。 これはもう使ってみないとわからない世界なのかも。 Lua言語の習得コスト考えるとTheanoとかPythonサポートしているものになりそうな印象。

GPUリソースをどうやって調達しようかな...。

Djangoアプリケーションのデプロイ

開発サーバでなく、製品版ではどうするかというと2通りの方法があるみたい。

  1. Apache Httpサーバ + mod_wsgi
  2. Nginx + Gunicorn

2.の方がパフォーマンスが優れているという話も見かけたけど、今回は1.を試してみる。 wsgiは"ウィスギィ"と読むのか。

検証環境として、Virtualbox上に立てたCentOS 7を使う。

 cat /etc/centos-release
CentOS Linux release 7.2.1511 (Core)

webブラウザから確認するため、VagrantfileにIPアドレスを固定するよう設定する。

  • Vagrantfile
...
  config.vm.network "private_network", ip: "192.168.33.10"
...
Python 3.5.1のインストール

デフォルトでインストールされているPythonのバージョンが2.7.5なので、3.5.1をインストールする。

# mkdir tmp
# cd tmp
# wget https://www.python.org/ftp/python/3.5.1/Python-3.5.1.tgz
# tar -xzf Python-3.5.1.tgz
# cd Python-3.5.1
# ./configure --enable-shared
# make
# make altinstall

インストールの確認をしたが、関連するライブラリのパスが通っていない...。 パスを通す。

# /usr/bin/python3.5 -V/usr/bin/python3.5: error while loading shared libraries: libpython3.5m.so.1.0: cannot open shared object file: No such file or directory
# echo "/usr/local/lib/python3.5" > /etc/ld.so.conf.d/python33.conf
# echo "/usr/local/lib" >> /etc/ld.so.conf.d/python33.conf
# ldconfig
Apache Httpサーバ およびmod_wsgiのインストール

tmpディレクトリのままでApache Httpサーバとmod_wsgiをインストールする。

# yum install httpd
# wget https://github.com/GrahamDumpleton/mod_wsgi/archive/4.5.2.tar.gz
# tar -xzf 4.5.2.tar.gz
# cd mod_wsgi-4.5.2/
# ./configure --with-python=/usr/local/bin/python3.5
# make
# make install
Djangoのインストール

pipのバージョンが古いかったので、アップグレードも実施。

# pip3.5 freeze
You are using pip version 7.1.2, however version 8.1.1 is available.
You should consider upgrading via the 'pip install --upgrade pip' command.
# /usr/local/bin/pip3.5 install --upgrade pip
# /usr/local/bin/pip3.5 install django
確認用プロジェクトで確認する

helloプロジェクトを作成。

# su - vagrant
$ cd ~
$ mkdir -p dev/python/django
$ cd dev/python/django/
$ django-admin startproject hello

マイグレーション

$ /usr/local/bin/python3.5 manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, sessions, contenttypes
Running migrations:
  Rendering model states... DONE
  Applying contenttypes.0001_initial... OK
  Applying auth.0001_initial... OK
  Applying admin.0001_initial... OK
  Applying admin.0002_logentry_remove_auto_add... OK
  Applying contenttypes.0002_remove_content_type_name... OK
  Applying auth.0002_alter_permission_name_max_length... OK
  Applying auth.0003_alter_user_email_max_length... OK
  Applying auth.0004_alter_user_username_opts... OK
  Applying auth.0005_alter_user_last_login_null... OK
  Applying auth.0006_require_contenttypes_0002... OK
  Applying auth.0007_alter_validators_add_error_messages... OK
  Applying sessions.0001_initial... OK

管理者アカウントを作っておいて、管理画面の表示も確認しよう。

$ /usr/local/bin/python3.5 manage.py createsuperuser
Username (leave blank to use 'vagrant'): admin
Email address: admin@email.com
Password:
Password (again):
Superuser created successfully.

前回はstaticフォルダにJavascriptやらCSSを入れて参照していたけど、管理画面のものはどこにあるのかなと思ったらそれをstaticフォルダに集めれとのこと。これをしないとあとで管理画面のスタイルが崩れて表示される。

collectstaticコマンド を実行するとSTATIC_ROOTで指定したディレクトリに格納される。

  • hello/settings.py
...
STATIC_ROOT = os.path.join(BASE_DIR, "static/")
...

それでもって

$ /usr/local/bin/python3.5 manage.py collectstatic
mod_wsgiの設定
oadModule wsgi_module modules/mod_wsgi.so

WSGIDaemonProcess hello python-path=/home/vagrant/dev/python/django/hello
WSGIProcessGroup hello
WSGIScriptAlias / /home/vagrant/dev/python/django/hello/hello/wsgi.py process-group=hello

<Directory /home/vagrant/dev/python/django/hello/hello>
    <Files wsgi.py>
        Require all granted
    </Files>
</Directory>

Alias /static /home/vagrant/dev/python/django/hello/static
<Directory /home/vagrant/dev/python/django/hello/static>
    Require all granted
</Directory>

apacheユーザがhelloプロジェクトにアクセスできるようにする。

$ sudo usermod -a -G vagrant apache
$ sudo chmod 775 -R ~/dev/python/django/hello/
Apache Httpサーバの起動

あとはApache Httpサーバを起動して、http://192.168.33.10/http://192.168.33.10/adminで開発用サーバと同じ画面が見れるはず。

# systemctl start httpd
# systemctl enable httpd

ただ1点気になったのが、Apache Httpサーバのエラーログに/はないと言われるのはなんでだろう。。

[wsgi:error] [pid 4116] Not Found: /

Django1.9+Bootstrap3でログイン表示を作る

認証・認可は、Djangoに限らず、Webフレームワークを使い出してまず外せない機能。

Django公式マニュアルを見てみると、機能としてデフォルトで持っていて、それを用途に応じて拡張していく方針とのこと。 Users, Groupモデル、パスワードをハッシュ化して保持して保持するといった提供されている。

1回やり方を確認しておけば何にでも応用できそうなのででBootstrap3を利用し、ログイン画面を表示してみる。

環境

環境としては、こちら。

項目 バージョン
Python 3.5.1
Django 1.9.5
jQuery v2.2.2
Bootstrap v3.3.6

Djangoの認証

Djangoで認証・認可の機能は、django.contrib.authで使用できる。これはプロジェクトを生成するときに元から含まれている。プロジェクト作成後、マイグレーション(python manage.py migrate)とすると認証・認可用のテーブルが作成される。

つくってみる

はじめにプロジェクトから作成する。 radishはただのプロジェクトの例なので、適宜変更してください。

$ django-admin startproject radish
$ python manage.py migrate

次にaccountsdashboardアプリを作成する。 accountsには認証・認可機能を含めで、dashboardには認証された後のリダイレクト先のアプリを含める想定。

$ python manage.py startapp accounts
$ python manage.py startapp dashboard

アプリを作ったら、忘れずsettings.pyINSTALLED_APPSに追記しておく。これを忘れると、後で出てくるテンンプレートが存在しないというエラーが発生するので、忘れずに。

  • radish/radish/settings.py
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',

    # local
    'accounts.apps.AccountsConfig',
    'dashboard.apps.DashboardConfig',
]
Bootstrapを配置する

JavascriptCSSのライブラリは、radish/staticフォルダ内に入れておく。するとsettings.pyの下記の記載に沿って、参照可能となる。

  • radish/radish/settings.py
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/

STATIC_URL = '/static/'

STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

jQueryやらBootstrapやらをインストールする。それぞれダウンロードするのが面倒であったので、Bowerで入れる。

  • radish/static/
$ bower init
...
(対話型でbower.jsonを作成)
...
$ bower install jquery -S
$ bower install bootstrap -S
トップ画面、ログイン画面、ログイン後画面(ダッシュボード画面)を作る

各画面共通で使うNavbarなどはbase.htmlに記述し、他の画面はそれを継承する。またそういう共通のHTMLはradish/templates配下に入れておく。しかし、このパスはDjangoが見つけてくれないので、またsettigs.pyに追記する。

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],  # 追記箇所
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

それではbase.html{% load staticfiles %}と書くと、下のように{% static xxx%}でjsやcssを利用できる。{% if user.is_authenticated %}~{% else %}で条件分岐しているところは、認証されている場合のみ有効にするメニュー表示である。また {% block container %}~{% endblock %}は、base.htmlを継承した方のHTMLが埋め込まれる箇所となっている。

{% load staticfiles %}

<!DOCTYPE html>
  <html lang="ja">
    <head>
      <meta charset="utf-8">
      <meta http-equiv="X-UA-Compatible" content="IE=edge">
      <meta name="viewport" content="width=device-width, initial-scale=1">

      <tile>{% block title %} Radish | {{ site_name }}{% endblock %}</tile>

      <!-- CSS -->
      <link href="{% static 'bootstrap/dist/css/bootstrap.min.css' %}" rel="stylesheet" />
      <link href="{% static 'bootstrap/dist/css/bootstrap-theme.min.css' %}" rel="stylesheet" />
      <link href="{% static 'font-awesome/css/font-awesome.css' %}" rel="stylesheet" />
  </head>
  <body>
    <nav class="navbar navbar-inverse navbar-fixed-top">
        <div class="container">
          <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
              <span class="sr-only">Toggle navigation</span>
              <span class="icon-bar"></span>
              <sapn class="icon-bar"></sapn>
              <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">Radish</a>
          </div><!-- /.navbar-header -->

          <div id="navbar" class="navbar-collapse collapse">
            {% if user.is_authenticated %}
              <ul class="nav navbar-nav navbar-right">
                  <li>
                      <a href="#">Dashboard</a>
                  </li>
                  <li>
                      <a href="#">Settings</a>
                  </li>
              </ul>
            {% else %}
              <form class="navbar-form navbar-right">
                  <button type="button" class="btn btn-primary"
                    onclick="location.href=&quot;{% url 'login' %}&quot;;">
                    Login</button>
              </form>
            {% endif %}
          </div><!-- /.navbar-collapse -->
        </div><!-- /.container -->
    </nav>

    {% block container %}
    {% endblock %}

    <hr/>
    <footer>
      <p>&copy; hermesian</p>
    </footer>

    <!-- JavaScript -->
    <script src="{% static 'jquery/dist/jquery.min.js' %}"></script>
    <script src="{% static 'bootstrap/dist/js/bootstrap.min.js' %}"></script>
  </body>
</html>

次にトップ画面home.htmlは下記。 これはBootstrapのjumbotronの例をそのまま利用。

{% extends 'base.html' %}

{% load staticfiles %}

{% block container %}
<!-- Main jumbotron for a primary marketing message or call to action -->
<div class="jumbotron">
    <div class="container">
      <h1>Radish</h1>
      <p>
          "Radish is a dashboard for collecting visualizing report."
      </p>
    </div>
</div>
<div class="container">
      <!-- Example row of columns -->
      <div class="row">
        <div class="col-md-4">
          <h2>Heading</h2>
          <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
          <p><a class="btn btn-default" href="#" role="button">View details »</a></p>
        </div>
        <div class="col-md-4">
          <h2>Heading</h2>
          <p>Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui. </p>
          <p><a class="btn btn-default" href="#" role="button">View details »</a></p>
       </div>
        <div class="col-md-4">
          <h2>Heading</h2>
          <p>Donec sed odio dui. Cras justo odio, dapibus ac facilisis in, egestas eget quam. Vestibulum id ligula porta felis euismod semper. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus.</p>
          <p><a class="btn btn-default" href="#" role="button">View details »</a></p>
        </div>
      </div>
  </div>
{% endblock %}

home.htmlのログインボタンで遷移する先は、accounts/tempalte/accounts/login.html<form>タグの下に{% csrf_token %}とあるのは、DjangoCSRF対策機能である。

{% extends 'base.html' %}

{% load staticfiles %}

{% block container %}
<div class="container">
  <div class="page-header">
      <h3>
        Login
      </h3>
  </div>
  <div class="row">
    <div class="col-md-4 col-md-offset-4">
        <div class="panel panel-default">
            <div class="panel-body">
                <form accept-charset="utf-8" role="form" action="{% url 'login' %}" method="post">
                    {% csrf_token %}
                    <fieldset>
                        <div class="form-group">
                            <input type="text" id="username" name="username" class="form-control"
                                   placeholder="Username" required autofocus>
                        </div>
                        <div class="form-group">
                            <input type="password" id="password" name="password" class="form-control"
                                   placeholder="Password" required>
                        </div>
                        {% if login_failed %}
                          <p class="text-danger">Sorry, that login was invalid.  Please try again.</p>
                        {% endif %}
                        <input class="btn btn-lg btn-success btn-block" type="submit" value="Log in">
                    </fieldset>
                </form>
            </div>
        </div>
    </div>
</div>
{% endblock %}

最後に認証後のdashboard画面dashboard/template/dashboard.html。といっても今回は空っぽ。

{% extends 'base.html' %}
ビューとルーティングを作る

accountsアプリ

  • radish/accounts/views.py

何かしらで認証されっぱなしの状態にならないように、logoutを最初に呼んで初期化してる。

import logging
from django.shortcuts import render_to_response, HttpResponseRedirect
from django.template import RequestContext
from django.contrib.auth import authenticate, login, logout

logger = logging.getLogger(__name__)


def login_view(request):

    #強制的にログアウト
    logout(request)
    username = password = ''

    login_failed = False

    if request.POST:
        username = request.POST['username'].replace(' ', '').lower()
        password = request.POST['password']
        user = authenticate(username=username, password=password)
        if user is not None:
            if user.is_active:
                login(request, user)
                return HttpResponseRedirect('/dashboard')
        else:
            login_failed = True

    return render_to_response('accounts/login.html',
                              {'login_failed': login_failed},
                              context_instance=RequestContext(request))

上で作ったビューをwebブラウザから/accounts/loginでアクセスできるよう設定する。

  • radish/accounts/urls.py
from django.conf.urls import url
from .views import login_view

urlpatterns = [
    url(r'^login/$', login_view, name='login'),
]

dashboardアプリ

  • radish/dashboard/views.py

@login_requiredをつけて、認証後のみアクセス可能なようにしている。

import logging

from django.shortcuts import render
from django.contrib.auth.decorators import login_required


@login_required
def index(request):
    return render(request, 'dashboard/index.html')
  • radish/dashboard/urls.py
from django.conf.urls import url
from .views import index

urlpatterns = [
    url(r'^$', index, name='dashboard'),
]
動作確認

ユーザを作成する。今回はスーパーユーザを造り、そのままそのアカウントでログインしてみる。

$ python manage.py createsuperuser
...
(対話的に作成)
...

動作確認として、開発サーバを起動$ python manage.py runserver、webブラウザからhttp://localhost:8000/にアクセスして、先ほど登録したスーパーユーザでログインし、NavbarにDashboard, Settingsというメニューが出ていることを確認する。

Djangoのフロー

DjangoフルスタックなWebフレームワークで、Ruby on RailsのようなDBマイグレーションができたり、管理GUIを簡単に作る機能があるなど、使えたら便利そう。

1) プロジェクトを作成する

$ django-admin startproject (プロジェクト名)

2) アプリケーションを作成する

$ python manage.py startpapp (アプリケーション名)

3) ビューを作成する

3)-1. (アプリケーション名)/views.pyを改修する
3)-2. (アプリケーション名)/urls.pyを改修する
3)-3. テンプレート(*.html)を作成する (js, cssは(プロジェクト名)/staticディレクトリ配下に入れる)

*テンプレート単体で確認できないのかな?

4) モデルを作成する

4)-1. (プロジェクト名)/(プロジェクト名)/settings.pyでデータベースを設定する
4)-2. (アプリケーション名)/models.pyを改修する
4)-3. (プロジェクト名)/(プロジェクト名)/settings.pyのINSTALLED_APPSを編集し、モデルを有効にする
4)-4. マイグレーションを実施する

$ python manage.py makemigrations (アプリケーション名)
$ python manage.py sqlmigrate (アプリケーション名) 0001  <= データベーススキーマを確認
$ python manage.py migrate

*ER図->DB--(リバース)-->モデル--(モデル修正)-->モデル'--(マイグレーション x n回)-->DB'の方がいきなりコードを書けないので、馴染める。

JacksonでLombokを使ったBeanにマッピングできない

同じ轍を踏まないようにメモ。

事象

JSONファイルから設定を読み込むことをしたく、Jacksonを使い、アクセッサーメソッドの記述を省力化しようとLombokを使った。そのとき下記のように記載するとアクセッサーメソッドがスネークケースになって(実際スネークケースになる設定というわけではなく、頭文字を大文字にして繋げる仕様で、"_"だからそれに対応できなかっただけのような気がする気がする...)、アンマーシャルすることができないエラーが発生する。

f:id:hermesian:20160207222514p:plain

import lombok.Getter;
import lombok.Setter;

public class Bean {

    @Getter
    @Setter
    private Parent1 _parent1;

    public class Parent1 {

        @Getter
        @Setter
        private String _child1;

        @Getter
        @Setter
        private String _child2;

        @Getter
        @Setter
        private String _child3;
    }
}
対策

属性の接頭辞には、"_"を使用しないこと。

f:id:hermesian:20160207222521p:plain

import lombok.Getter;
import lombok.Setter;

public class Bean {

    @Getter
    @Setter
    private Parent1 parent1;

    public class Parent1 {

        @Getter
        @Setter
        private String child1;

        @Getter
        @Setter
        private String child2;

        @Getter
        @Setter
        private String child3;
    }
}
バージョン

pom.xmlの内容は下記。

...以上、省略....
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.7.0</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.6</version>
        </dependency>
...以下、省略....

初段になりました

初めて審査なるものを受けました。 あいにくの雨。そして傘を忘れた...

審査は、術科試験と学科試験の2種。 ウェイトは不明だが、まれに学科で落ちることがあるとのことなので、術科にウェイトがあるような印象。

術科試験

一手座射が内容です。体配(執弓の姿勢、歩き方、坐しての回り方)が何よりも重要。 明らかに練習不足...。揖してからのモタつき、極め付けは射位を行き過ぎてしまいました。

学科試験

今年から学科の問題が公表されました(http://osaka-kyudo.jp/mondai_chiren_rengou.pdf)。 「A群、B群からそれぞれ1問、計2問を出題する。」を読んでいなかったため、「45分でこの量を書くのか...」と思い、キーワードを抑えることに集中していました。 終わった後、周りの方はほぼ15行びっしり記載されており、短すぎたかと焦りました(緊張すると震えてスラスラ書けない...)が、結果的には通ったようです。次は小論文などある程度の文量は書くトレーニングをし、そして硬筆の練習して臨みたいところ。

初心者弓道教室に参加して

初心者教室について

流山に越してから腰を据えて弓道を始めようと思い、まずは地域の弓道協会が主催する初心者教室に参加してみた。 計8回(5/30, 5/31, 6/6, 6/13, 6/14, 6/20, 6/21, 6/27)で先週がちょうど最終回だった。

  • 対象者は?

初心者でなくとも段を持っていない場合、様子をうかがえることから参加する方が良いと思う。 各地の道場における独自ルールもあると思うので。

課題

内省の意味を込めて、ここに記録しておく。

  • 足踏み
    • 左足の角度が開きすぎ
    • 幅が狭い
    • 胴が曲がっている(自分が正面であると思ったところから5cm後ろであった)
  • 弓構え
    • 手の内では指の「腹」でつかむ
  • 大三
    • 妻手は引かない
    • 肘を張る
  • 引分け
    • 左右に均等に引く(斜め後ろではなく)
  • 離れ
    • 射る瞬間に目をつぶることがある

その他

  • 弦を掛ける際は、順手
  • 矢番えの際は、気持ち前傾姿勢(仰け反って見えるときがある)