Riverside Learning LABO(Skill/Idea/Code)

よりよいシステムのため工学系と人間系の学習下書きメモ

開発 WEBブラウザ開発環境 Colaboratory

深層学習や機械学習をブラウザor自マシンで試すためのノウハウがまとまっている
サンプルプログラムを利用し、実際に体験しながら機械学習をを学習する解説書。

キーワード
Python機械学習、深層学習、自然言語処理、Jupyter Notebook、
形態素解析ディープラーニングOpenCV

Googleアカウントがある方はいかにアクセスするとpythonの実行環境が手に入る。
(というか環境を構築する必要がない。
ブラウザ上でpythonのコードを記述、ブラウザの実行ボタンを押すと、実行結果がブラウザで確認できる。)
colab.research.google.com

開発 Pythonによるスクレイピング-02

pythonを使ってスクレイピングを試す.
開発環境はWindowsの中にDocker imageのUbuntuを構築して試す.
開発環境準備についてのメモ


# docker imagesの実行中の一覧を取得commitコマンドで保存する
$ docker ps
$ docker commit CONTAINER ID REPOSITORY/TAG
例)
$ docker commit 80a09241ae94 mlearn/jpall


#保存したdocker imageの一覧を開く
$ docker images
例)
REPOSITORY TAG IMAGE ID CREATED SIZE
mlearn jpall 80a09241ae94 11 hours ago 442MB
continuumio/miniconda3 latest 1284db959d5d 2 weeks ago 409MB
hello-world latest e38bc07ac18e 2 months ago 1.85kB


#実環境のsmapleフォルダをVMマッピングして保存したdocker imageを起動
$ docker run -i -t -v /c/Users/Fujitsu/Documents/sample:/sample mlearn:init /bin/bash
(base) root@xxxxxxxxxxxxxx:/# cd sample


#pip3を使ったbeautifulsoup4ライブラリインストール
#1.python がインストール済みであること
Windows環境手順1.ダウンロード先:https://bootstrap.pypa.io/get-pip.py よりget-pip.pyを任意のディレクトリに保存する
#2.保存したディレクトリで下記コマンドを実行する
python3 get-pip.py
#3 pipコマンドでURL解析用のライブラリをインストールする
pip3 install beautifulsoup4


#実行中のdocker imageが表示される
$ docker ps
例)
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
f7cc38d403a8 mlearn:jpall "/usr/bin/tini -- /b…" 40 seconds ago Up 39 seconds pensive_murdock

#表示されたdocker imageにはattach可能、表示されない場合はstartから必要
$ docker attach f7cc38d403a8
or
$ docker start f7cc38d403a8
$ docker attach f7cc38d403a8

#後は ?????????.pyにpythonスクリプトを配置すれば、スクレイピングを試せる
(base) root@xxxxxxxxxxxxxx:/# cd sample
(base) root@2f5ccabba444:/sample# python3 ?????????.py

開発 Pythonによるスクレイピング-01

pythonを使ってスクレイピングを試す.
開発環境はWindowsの中にDocker imageのUbuntuを構築して試す.
開発環境準備についてのメモ

準備1
Windows7,Windows8.1
Docker toolboxをダウンロード
取得元:https://docs.docker.com/toolbox/
参考 :Docker for Windows のインストール — Docker-docs-ja 1.13.RC ドキュメント

windows10
Docker Platformをダウンロード
取得元:www.docker.com
参考 :Dockerコンテナ テクノロジでアプリケーションをスピーディーに提供

準備2
デスクトップからTerminal.lnkを起動
Docker\Docker Quickstart Terminal.lnk"

## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/

準備3
docker run hello-world
hello-worldイメージがダウンロードされて画面上にhello worldが表示される


参考

プログラミング作法5

第5章 デバッグ
・コーディングと同じ時間をデバッグにかけ過ちから学ぶ
(またバグを見つけたら同じ過ちを犯さないような方法、
再び発生したときの突き詰める方法を学ぶ)
・やみくもにデバッガを使うよりもプリント文とチェックコードの方が融通が利く
・おなじみのパターンを見つける (見慣れた問題かどうかのチェック)
・最新の変更点のチェック (最後に何を変更したか)
・同じ間違いを繰り返さない (同じ間違いが他の場所にないか)
デバッグは今すぐ放置せずに行う
スタックトレースを取得する
・打つ前に読んでみる (印刷してみる、休憩してみる)
・自分のコードを他人に説明してみる
・バグを再現できるようにする
・分割統治する (可能性の範囲を狭めていく)
・誤作動を特定の数値パターンから検証する
・出力表示でバグの検索範囲を狭める
・自己検証コードを記述する (問題の発生前に行うのがポイント)
・ログファイルを出力する
・作図する (度数分布図など)
・ツールを使う (diff、grep など)
・記録を取る (何を行ったのか)
・デバッガによって思い込みではない動作による検証ができる
・対象コードやバージョンを間違えている場合も往々にしてある
メモリリークが原因の場合
・極めて稀にライブラリやハードによる原因という場合もある
・再現性の難しいバグでは逆に動的に変化する部分やメモリが怪しい
・他人のバグのときは受け取る側に分かりやすいテストケースで知らせる

プログラミング作法4

第4章 インターフェイス


設計において解決すべき課題。これらが決まったら仕様としてまとめる。
インターフェイス (提供するアクセスやサービス)
・情報の隠蔽 (可視、プライベート)
・リソース管理 (割り当て、解放)
・エラー処理 (検出、報告、報告手段、復旧措置)
・面倒な入力解析プログラムで入力例を付ける
・一度しのぎのはずのプログラムが、その後も使われることは多い
・原則としてライブラリルーチンはエラー発生時に死んではならない


よいインタフェースを作るための留意点。優れたインターフェイスはシンプルで普遍的で整然としており、予測可能で堅牢、更には変化に対応できている。実装が隠蔽されポインタからしかアクセスできないようなもののことを不透過型(opaque type)という。
・実装の詳細を隠蔽する
・直交性のあるプリミティブなセットを選択する
・ユーザに内緒で何かをしない (インタフェースの拡大を含む)
・同じことはどこでも同じように実行する (一貫性と規則性)


リソース管理での要点。ポイントは解放を割り当てと同じレイヤで行う点。マルチスレッドなどではプログラムが再入可能(reentrant)である必要がある。
・初期化/生成
・状態管理
・共有とコピー
・後始末/破棄


strtok は処理の目印として NULL をデータに書き込むので多重呼び出しができない。(スレッドセーフでない。)
・標準関数のエラー処理までをラッパーとして包んで提供する
・勝手に終了はしないようにする(ログに残すなど)
・エラー検出を低いレベルで行い、処理は高いレベルで行う
(呼び出し側で対処するということ)
・例外は例外的な状況でのみ使う
・エラー情報をユーザには分かりやすく伝える (エラー + 正しい方法)
C/C++ では atexit で正常終了直前の制御を取得できる

NaN (Not a Number : 非数) IEEE 浮動小数点数の返す特殊なエラー値

プログラミング作法3

第3章 設計と実装

データ構造が決まればアルゴリズムもすんなり決まることが多い。(データ構造によって全体像が定義されるから。)そのためにもシンプルなアルゴリズムとデータ構造を選択することが重要になる。そして、プロトタイプ(捨てるためのプログラム)を有効的に使う。

アルゴリズムの異なる言語による実装の違いと性能差について。C はソースが長くなるが高速、C++Java はソースはすっきりするが速度面で C に劣る。

プログラミング作法2

第2章 アルゴリズムとデータ構造
安定した結果を出すには一定の経験を積むしかない
不慣れな分野に取り組むときは、その分野で既に何が解明されているのかを調べないと、
優れた手法のあることに気付かずに、下手なやり方で苦労することになる。


・逐次検索(sequential search)はデータが少なければ十分実用(逐次検索は線形検索(linear search)ともいう)
・もう少し多い場合は二分検索(binary search)を使う(バイナリサーチではデータが事前にソートされている必要がある)
・汎用的なソート手法としてクイックソートがある (C.A.R Hoare/1960)(ある値を選択して以上/以下に分割し、それを再帰的に行う。
しかし値が全て同じなら n の 2 乗に比例する時間がかかるANSI C なら qsort や bsearch が用意されている、Java の例もあり)

O 記法(O-notation)による、実行時間を n の関数に見立てた計算量(complexity)の算出。
これだけではなく最悪のケースと期待される動作の把握が必要になる。以下に重要となるケースを挙げる。

    • -

記法 名称 例
O(1) 定数 配列インデックス
O(logn) 対数 二分検索 (段階ごとに半分)
O(n) 1 次 文字列比較
O(nlogn) nlogn クイックソート
O(n2) 2 次 単純なソート手法
O(n3) 3 次 行列乗算
O(2n) 指数 集合分割問題 (全ての可能性の評価)

    • -

・巡回セールスマン問題等の指数的アルゴリズムの問題は近似値で代用されることが多い
・配列は要素数が可変だったり膨大なときには別のデータ構造を検討する
・アロケートを 1 バイトずつではなくある程度まとめて行う
・memcpy よりも memmove の方が安全でおすすめ*1
・リストは頻繁に順序の変更されるときに向く
・書式文字列を引数に取るという方法
・ルートからリーフまでの個々の経路がほぼ同じ長さのツリーをバランス木(balanced tree)という
再帰が最終的に自分自身の呼び出し結果の返すことを末端再帰(tail recursion)という
・間順走査(in-order traversal)は部分木を左から右へ行く中間で処理の行うことをいう
・降順走査(post-only traversal)は子を訪れてから現在のノードに対する処理の行うことをいう
・ハッシュをうまく使えばルックアップや挿入、削除が一定時間で可能になる
・ハッシュの配列サイズはルックアップ作業が O(1) になるような大きさにする
・ASCII 文字用のハッシュ関数の乗数には 31 と 37 が適している


アルゴリズムの使用では、まず使えそうなアルゴリズムとデータ構造の吟味し、その上でどの程度の量のデータを処理するのか考え、更にライブラリや言語の機能で使えるものがないか考える。それでも適当なものがなければ、短い実装を書くかどこかから拝借する。


あくまで高度なテクニックに頼るのは上記を行って、なおかつ性能の問題が出たときにする。ほとんど場合、配列、リスト、ツリー、ハッシュで対処できる。

*1:重複アドレスでも上書きしない

プログラミング作法1

第1章 スタイル
基本原則は簡潔性、明両性、一般性
低レベル階層の仕組みを理解するのは有益だ


・よいスタイルは習慣の問題である
・グローバルには分かりやすい名前、ローカルには短い名前
(インデックスの i,j、ポインタの p,q、文字列の s,t など)
・関連性のあるものは統一した命名をする
(queue、Q、Queue などと併用しない、bool を返す is・ など 関数には能動的な名前(動詞 + 名詞)を付ける)
・名前を的確にする
・構造が分かるようにインデントする
・自然な式を使う
(条件式を否定演算(!)ではなく、肯定となるように記述)
・カッコを使って式の曖昧さをなくす
(優先度の高いオペランド同士をくっつけて書く)
・複雑な式を一文にまとめず分割する
・明快に書く (小賢しいコードを書かない)
・副作用に注意する
・インデントとブレースのスタイルを統一する
(作業内容が常に同じ方法なら、それが違うだけで注目できる)
・言語の慣用句によって一貫性を確保する
(gets ではなく fgets を使う、strlen は \0 を含めず strcpy は含む、
多分岐に else-if を使う (可能性の高いものから記述))
落下シーケンスのcase文はきちんとbreakしよう
・関数マクロはなるべく使わない (C++ ならインライン関数で代替)
・マクロの本体と引数はカッコに入れる
マジックナンバーには名前を付ける (原則として 0/1 以外の全て)
・数値はマクロではなく定数として定義する
(define ではなく enum や const にする)
・整数より文字定数を使う
(0 をヌルポインタなら (void*)0 や NULL 、文字列終端なら \0 で区別、
0 はリテラルの数字 0 で使う)
・オブジェクトサイズは言語に計算させる
(sizeof(array)/sizeof(array[0]))
・当り前のことをいちいちコメントにしない
・関数、グローバル変数、定数定義、構造体・クラスメンバにはコメント
・悪いコードではコメントを付けるのではなく書き直す
・(修正があっても)コードと矛盾しないコメントを維持する
・あくまでも明快に、混乱を招かないコメントにする
(難問を増やすのがコメントの目的ではない)

疑似コード

疑似コードでロジックを設計


利点
疑似コードは言語に依存せずに、処理の流れ
作成するべき部品群を記述できる.


捕捉
仕様を満たすため、特に性能を満たすためには
ロジックまで十分検討されていることが必要である
核心部分はできるだけ半永久的にメンテする意識を
持ったものが設計し作成することで品質が上がる