読者です 読者をやめる 読者になる 読者になる

備忘録 blog

Docker/Machine Learning/Go

HaskellにおけるHTMLのテンプレートエンジンを調査する

haskell html

HaskellはWebフレームワークだけでもYesod, Snap, Happstackといった重厚長大型のフレームワークに加え、軽量なもの/API向けのものでもSpock, Scotty, Servantなど乱立しているが、Template Engineとて例外ではない。Blaze-html, shakespeare, mustache, stache, ede, lucid, heistなどこれもまた様々存在し、特にSpockやScottyといったフレームワークではテンプレートエンジン選択の自由度が高いので、どれを使おうかと思い、調べたのでここにメモを残す。

Template Engine

stackoverflow.com

stackoverflowでも何を使えばよいか、議論となっている。

stache

stache: Mustache templates for Haskell

Mustacheという汎用テンプレートエンジンのhaskell実装の1つ。 ただMustache自体の仕様として記法が簡潔でよいのだが、if文の分岐がBooleanのTrue/Falseしかできないなど、少し凝ったことをしづらい面がある。 ただAesonのインスタンスをそのまま渡せるのは心強く、Viewに送りたいデータを新しいデータ型として定義し、deriveJSONを呼んでおけば、あとはテンプレートにそのインスタンスを渡すだけでよいというのは手軽である。

記法は以下のような形。

Hi, {{name}}! You have:
{{#things}}
  * {{.}}
{{/things}}

こうすると、things配列の要素が.のところに順々に出力される。

Mustache

mustache: A mustache template parser library.

これも上と同じMustacheの実装。Data.AesonのValueを渡せるのはよいが、Maybe型の値のデータをみたとき、Nothingの時の値は空白が入っていることを期待したらnullが入っているというのはstacheと異なる点。そういった点で、stacheの時と同じmustacheファイルに対して同じ挙動を示すというわけではなかった。下の記事によれば、

Mustache templates in Haskell - Tutorials

it again makes simple things complex using Aeson's Value (good) and at the same time introducing its own Value type (with conflicting names of constructors and naturally not so numerous instances).

とのことで、Mustacheを使うぐらいであればstacheを使ったほうがよさそう。

ede

ede: Templating language with similar syntax and features to Liquid or Jinja2.

Mustache風味のHTMLベースのテンプレートエンジンだが、こちらのほうが表現力が高い。

qiita.com

こちらもData.AesonのValue型をObject型に変換し、それをテンプレートに代入してrenderしてくれる機構が備わっているので、テンプレートに与えたいデータをデータ型で用意しておけばよいのは変わらない。

--Unwrap a Value to an Object safely.
fromValue :: Value -> Maybe Object

記法はこんな感じ。

<div class="checkbox">
  {% for chara in characters %}
    <label class="checkbox-inline">
      <input name="chara" value="{{chara.value.name}}" type="checkbox">
      {{chara.value.name}}
    </label>
  {% endfor %}
</div>

if文では、比較演算子if-elif-elseと複数の条件で分岐させることもできるので、View側で凝ったことをすることも容易。

lucid

lucid: Clear to write, read and edit DSL for HTML

一方でこちらはhaskellの記法でHTMLを記述するDSL

ただSpockで使う場合、テンプレートを書き換えるごとにコンパイルしなおさなければならない。ede, stacheの場合は別ファイルで呼び出すので、コンパイルをし直す必要はないが、記法が誤っている場合は実行時エラーとなる。そう考えるとCompile時にValidateしてくれるlucidや、特にshakespeareではリンクのバリデーションも施してくれるので、これらのほうが型安全であると考えられる。

HTMLテンプレート?Lucidを使ってみた

Haskellの文法そのままなので、例えばリストの要素を列挙したい場合では

div_ [class_ "container"] do $
  h1_ [] "List"
  ul_ [class_ "list-group"] $
    mapM_ (li_ []) ["a", "b"]

などと書くことで、["a"], ["b"]の中身がliタグに囲まれて列挙される。

blaze-html

blaze-html: A blazingly fast HTML combinator library for Haskell

広く使われるHTMLライブラリではあるのですが、先述のLucidはこちらの改良版と言うか、blaze-htmlの問題点を解決したライブラリである。チュートリアルより、

import Text.Blaze.Html5 as H
import Text.Blaze.Html5.Attributes as A

userInfo :: Maybe User -> Html
userInfo u = H.div ! A.id "user-info" $ case u of
    Nothing ->
        a ! href "/login" $ "Please login."
    Just user -> do
        "Logged in as "
        toHtml $ getUserName user
        ". Your points: "
        toHtml $ getPoints user

記法はこんな感じで、これの何が問題かというと、下記のブログによればいくつかあるのだが、div, id, head, mapといった要素はbaseとconflictしているのでqualifiedして呼ばなければならないし、AttributeとElementの名前がコンフリクトするものがあるので、そうするとAやらHやらを頭に付けなければならない。結果としてコードが見にくくなってしまうのだ。それよりかは、Lucidのようにすべてsuffixに_をつけるほうが統一性があり、見栄えも良さそうだ。

Lucid: templating DSL for HTML

shakespeare

shakespeare: A toolkit for making compile-time interpolated templates

yesodで使われているテンプレートエンジン。hamletはこれにdeprecateされた。拡張子としては.hamletがHTML、.juliusがjs, .luciusCSSに対応している。 記法はこんな感じ。

<div .container>
  <h1> All Posts

  <div .jumbotron>
    <ul>
      $forall Entity id post <- allPosts
        <h4>
          <li>
            <a href=@{PostDetailsR id}>#{blogPostTitle post}

タグは閉じないで、インデントで親子関係を示す。HTMLに近い記法ができる一方でコンパイル時に変数が確実に埋め込まれる。たとえば@{}では型付きのURLが埋め込まれるため、それが有効なURLかどうかコンパイル時にバリデートされる。これがリンク切れを起こさない秘訣だ。変数の代入は#{}を使う。このとき、hamletではXSS attackを防ぐために適切にエスケープしてくれる。

制御構文は$から始まる行に記述し、if, elseif, forall, caseなど場合分けや、Maybe型への対応なども充実している。hamletはQuasiquotesでコード内部に埋め込むこともできるし、外部ファイルに記述することもできる。外部ファイルの場合はTemplateHaskellで参照され、コンパイル時に組み込まれる。

上記はyesodの場合で、これはscreencastから持ってきた例だが、yesodと無関係に使うこともできる。

www.yesodweb.com

sites.google.com

heist

heist: An Haskell template system supporting both HTML5 and XML.

snapというフレームワークで採用されているテンプレートエンジン。これは実際には試していないので、ウェブ上の例を見てみよう。

<bind tag="special">special-id</bind>
<div id="${special}">very special</div>

<bind tag="message">some text</bind>
<p><message/></p>

snapframework.com

heistの特徴となる主なタグはbindapplyで、bindはその名の通り変数を束縛し、 applyは<apply template="nav"/>のようにすると部分テンプレートを代入することができるらしい。Haskellからどう呼び出すかというと、公式サイトの例をみると

factSplice :: Splice Snap
factSplice = do
    input <- getParamNode
    let text = T.unpack $ X.nodeText input
        n = read text :: Int
    return [X.TextNode $ T.pack $ show $ product [1..n]]

というコードに対して、bindSplice "fact" factSplice templateStateとすると、<fact>タグにfactSpliceがbindされるので、<fact>5</fact>120になるとのことだ。

シェルコマンドでよく使う引数を書き留める

linux shell

TL;DR

シェルコマンドの中で、しばしば自分が使っていて便利な引数、毎回検索するも忘れてしまって前回打ったコマンドをback-i-searchで探そうとするも見つからなくて困るものなどを記す。

diff

diff -y -B -b -i -W 200

  • -y : 結果を2行に表示
  • -W 200: 各行の幅を表示
  • -B : 空行を無視
  • -b : 空白スペースを無視
  • -i : 大文字・小文字の違いを無視

sort

sort -n -r -k 3,3

  • -n : 数値順に評価
  • -r : 逆順にする
  • -k : 並び替えるフィールドを指定する。上記の例だと3フィールド目。

tr

標準入力から標準出力へ、文字を変換・削除するなどして流し込むコマンド。

tr -d '\n'

  • -d : 引数の文字を削除する

less

less -N -S -s +F

  • -N : 行番号を付ける
  • -S : 長い行を折り返さず、1行で表示
  • -s : 空行を1行にまとめる
  • +F : 更新をリアルタイムに見る

qiita.com

qiita.com

time

/usr/bin/time -p -o FILE [cmd]

  • /usr/bin/time : シェル組み込みのtimeではなく、GNU timeを使う
  • -p : 互換性のある出力にする
  • -o FILE : 出力のファイル名を指定する

du

フォルダの容量を表示する

du -h --max-depth=2 [dir]

  • -h : サイズの接尾辞が付く
  • --max-depth : 再帰的に探索するディレクトリの深さの上限を指定する

tar

tar czvf file.tar.gz file tar xzvf file.tar.gz

  • c : 圧縮する
  • x : 解凍する
  • z : gzipにする
  • v : ファイル一覧を出力する
  • f : fの引数のアーカイブファイルを使う
  • j : bzip2にする

curl

curl -H 'Content-Type:application/json' -d "{\"session\": \"test\"}" -u user:pass [url]

  • -H : header
  • -d : パラメータをつける
  • -u : BasicAuthのユーザー情報

qiita.com

ps

プロセスを見る。

ps aux

  • a : 自分以外のプロセスも見る
  • u : ユーザー名が出る
  • x : 端末を持たないプロセスも見る

convert

ImageMagickのコマンド。identifyもそうだが、パッケージ名とコマンド名が一致しないので注意。

タイル状に切り抜く時のコマンド。

convert -crop 64x64 +repage in.png out.png

こうすると、64x64でタイル状に左上から切り取ってくれる。ただし、割り切れずに端数がでる場合は端数サイズのファイルが出力されてしまうし、出力ファイル名はout-1.png,out-2.pngのようになるので、sortするときに文字順で並べるとout-1.png,out-10.png,out-11.png...のように並んで困ることになる場合もある。

Imagemagick - code snippets

xargs

xargs -P 22 -n 2 -t -I {} [cmd]

  • -P : 指定した個数のプロセスを立ち上げて並列実行
  • -n : cmdに渡す引数の個数
  • -t : コマンドの実行内容を表示
  • -I : [cmd]の部分に引数で渡した{}を使うと、その部分にxargsで渡される引数が入る。
    • -i : -iも-Iと同様で、引数を省略すると自動で{}が採用されるが、deplecated.

orebibou.com

d.hatena.ne.jp

ただしxargsからパイプでファイルに書き込みたいと思って、> output.txtなどと書いても、プロセスを並列化していると複数のプロセスから同時に書き込まれるので、1つのプロセスから書き込まれる内容が別々の行にばらけてしまうことがある。そういった諸々の問題が面倒なので、下のコマンドを使うこともある。

parallel

xargsより高性能に並列処理を行ってくれるコマンド。このGNU parallelは、apt-getなどで別途導入する。

bicycle1885.hatenablog.com

GNU Parallel

シェルスクリプト(bash)

bash -x hoge.sh

  • -x : 実行するコマンドも同時に出力する
  • -c : 引数の文字列をシェルコマンドとして実行する

shellscript.sunone.me

モニタリングツール

htop

プロセスをモニタリングするtopコマンドの拡張で、見やすい。 htop 上でキーをたたくと、表示様式を変更することができる。F1キーをたたけばヘルプが見られる。

  • u : ユーザーを限定してプロセスを表示
  • H : ユーザープロセスのスレッドを隠すか表示させるかをトグルする
  • l : lsofで開いているファイルを読む
  • s : straceで読んだシステムコールを読む

iostat

ioの状況を表示するコマンド

bmon

ネットワークアダプタの状況を表示するコマンド

その他

80 Linux Monitoring Tools for SysAdmins - Server Density Blog

入出力制御

qiita.com

Haskellで参考にしたもの

haskell

Web Framework

Scotty / Spock

Rubyで言う所のSinatraのような軽量フレームワークhaskell版。ScottyよりSpockの方が、waiに準拠している上に機能も充実していて良いらしい。

Spockの紹介記事は以下。

qiita.com

ScottyをHerokuで動かしてみたサンプルアプリは

github.com

Yesod

Yesodのすごいところは、shakespeareのおかげでビューにまで型付きの制約があるところで、このおかげでリンク切れとか起きないらしい。(もしリンクが切れるようなことがあれば、それはコンパイルが通らない。)

またketerと言うデプロイマネージャーは、ローカルでコンパイルして、実行に必要なファイルをすべてまとめてサーバーにscpし、ダウンタイム0でデプロイしてくれるようにできるらしい。とても便利。

公式のScreecastsには、わずか40分程度!で簡単なブログを組み立てる動画が見られる。

HTMLエスケープやXSSを防ぐ機構についてはライブラリが面倒を見てくれるため、我々はそういったことに気をつかうことなく安心してWebアプリを書くことができる。

www.yesodweb.com

Other

Web/Comparison of Happstack, Snap and Yesod - HaskellWiki

テンプレートエンジンについては記事を書きました。

sharply.hatenablog.com

DB操作をする

YesodのDatabase.Persistentが、sqlite, mongoDB, postgresSQLなどのDBとのアダプターとなって、マイグレーションを自動でやってくれるとか便利。

www.yesodweb.com

qiita.com

rf0444.hatenablog.jp

http://blog.fujimuradaisuke.com/post/26887032662/haskell-de-json-web-api
blog.fujimuradaisuke.com

Libraries

d.hatena.ne.jp

http://haskell-distributed.github.io/

実際にこれを使って分散処理を書くのがやりやすいかというと、やはりもう少しダイナミックに型を扱える言語の方が書きやすいのかもしれない。

チュートリアル

1. Getting Started

  • IntervalMap

区間を保持する構造のhaskellにおける実装。

github.com

Haskell IntervalMap

  • Aeson

Template Haskellを用いて、dataの定義からderiveJSONするのがスマートそうな気がします。

qiita.com

Data.AesonでJSONを扱う | saito's memo

文字列型

bicycle1885.hatenablog.com

qiita.com

Blaze.ByteString.Builder

Other

例えばm [a] => [m a]にする関数が何かを知りたいと思った時、Hoogle で検索するのが便利そうです。初心者なのでコンパイルが通らない時に型の帳尻合わせをしたくなるので、そういった時に重宝しました。

Hoogle

github.com

React-Nativeで便利なUIライブラリ

javascript React

tl;dr

React-NativeでiOSAndroidのネイティブアプリを作る際、自分が使った中で便利だったUIに関するライブラリをいくつか紹介する。

探し方や導入方法など

github.com

ここにReact-nativeに関連する様々な情報がまとまっており、その中にライブラリも多数収録されている。

依存がjavascriptだけのものはnpm install --saveすればよい。一方でコンパイル時に組み込まなければならないものは、GithubのReadmeなどに説明があると思うが、最近ではrnpmを使う、あるいはreact-native link <packagename>といったコマンドでプロジェクトに自動で組み込んでくれるようになっているので、手動で各ファイルに追記するよりミスを防げるので安全であると言えよう。

react-native-gifted-chat(旧 react-native-gifted-messenger)

github.com

いわゆるL○NE風のチャット画面を誰でも容易に作ることのできるライブラリ。ここにあるようにデザインはもうすでに整っているので、あとはチャットに表示させるメッセージをどこかから引っ張ってくるだけでよい。

React-native-gifted-messenger時代のものだが、簡単なチャットアプリの作り方は以下のQiitaの記事が参考になる。

qiita.com

react-native-vector-icons

github.com

FontAwesomeをはじめとしてFoundation, MaterialIcons, Octionsなど様々なベクターアイコンがバンドルされたライブラリ。

例えばアイコンを表示させたかったら、以下のようなタグを挿入すればよい。

<Icon name="rocket" size={30} color="#900" />

クオリティの高いアイコンが多数揃っているので、必要なアイコンはきっと見つかるはずだ。

react-native-action-button

github.com

Twitterの公式アプリの右下にある感じのボタンと、それを押すと複数のボタン選択肢が開いてくれるような、触っていて楽しいライブラリ。

これとreact-native-vector-iconsを組み合わせると、ボタンのアイコンを自作せずともきれいなベクターアイコンを使えるので便利。

react-native-sglistview

github.com

React NativeにはListViewという実装があり、何らかのデータソースから得られたデータをリスト形式で表示してくれるものであるが、その実装ではスクロールするにつれてメモリ使用量が線形で増え、利用可能なメモリを使い潰すと考えられる。その解決策として、SGListViewを用いることを提案している。スクロールするたびに内部のビューをflushしてくれるので、メモリを節約できるとのこと。

記法はListViewで実装していた部分をそのままSGListViewで置き換えればよく、導入も容易である。ただしアルファ版のため、skepticallyに使うようにとNoticeに書いてあるので注意。

react-native-grid-view

github.com

ListViewに対して、1つの列に複数のアイテムを置くことができるという点が優れている。ライブラリ自体の説明は乏しいが、Exampleを参考に改変しながら実装するとよいと思われる。サムネイルから選択させるような画面を作るときに向いているだろう。

react-native-router-flux

github.com

React NativeではNavigatorでのルーティングがデフォルトとなっており、Sceneと呼ばれる一つ一つの画面をスタックにpop/pushしていくことで、階層的なルーティングをサポートしている。

一方でそもそもAndroidiOSの間では画面遷移の制御や、TabBarやNavBarといったネイティブコンポーネントの違いがあり、その違いをうまく吸収してくれるようなルーターを使いたいと思う。

そこでここで取り上げるのが、fluxの考え方を取り入れたreact-native-router-fluxだ。公式のExampleをみてみると、

    return <Router>
      <Scene key="root">
        <Scene key="login" component={Login} title="Login"/>
        <Scene key="register" component={Register} title="Register"/>
        <Scene key="home" component={Home}/>
      </Scene>
    </Router>

Routerを上記のように定義すると、それぞれのコンポーネントではActions.Key(PARAM)によってpropsにPARAMを代入した状態で、Keyで指定したSceneへの遷移を呼び出せるほか、Actions.pop()と書くとその前のSceneに戻ることができる。

こうすることでまずルーティングを直感的に記述でき、それぞれの遷移も(ライブラリのActionsをそのコンポーネントに依存しない形で呼び出すので少し気持ち悪いように見えるかもしれないが)Keyを指定するだけで手軽に書けるので便利である。

またこのままだとナビゲーションバーが上に出るので、それがうっとうしい場合は<Scene key="root" hideNavBar>とすると、ナビゲーションバーを消すことができる。またそれぞれのSceneで、pop可能なとき、画面の左部中央をスワイプすると勝手にpopされてしまう。この挙動が邪魔な場合は、その挙動が発生してほしくないScene上で例えば<Scene key="home" component={Home} panHandlers={null}/>などとして、panHandlersをnullにすることで、スワイプによる画面遷移を防ぐことができる。

参考:

twins-tech.hatenablog.com

PRML 3.4-3.6 メモ

線形回帰モデルの流れ

3章では、 {y=w^{T}x}に対して、 yと決定変数tの間に加えられるガウスノイズの精度パラメータとしてβ、モデルパラメータwの事前確率分布を期待値0の、分散 {\alpha^{-1} I}の等方的ガウス分布としてαという2つのハイパーパラメータを導入している。ここで、ベイズ線形回帰ではwを周辺化していたが、今度はハイパーパラメータについても同様に事前分布を導入して周辺化したいが、完全に解析的に周辺化することは難しい。そのため、wに関して得られた周辺尤度を最大にするようにハイパーパラメータの値を定めるという近似について議論し、αとβの意味づけについて考える。

3.4 ベイズモデル比較

  • モデルパラメータの値を含んだ同時確率から、それを積分して周辺化することで、パラメータに依存しない確率が手に入れられる。

モデルの事後分布 {p(M_i|D) \propto p(M_i) p(D|M_i)}を計算するにあたって、事前分布 {p(M_i)}が全iに対して等しいとすると、 {p(D|M_i)}の項をモデルエビデンス=データから見たモデルの好みが重要である。それぞれのモデルの事後分布が分かると、全体の予測分布は混合分布で与えられる。

{ \displaystyle
p(t|x, D) = \sum p(t|x, Mi, D)p(M_i|D)
}

これは多峰性の分布となるが、近似するためにここから尤もらしいモデルを1つ選択しよう。

{ \displaystyle
p(D|M_i) = \int p(D|w,M_i)p(w|M_i)
}

この時、モデルエビデンスパラメータの事後確率を選ぶ際の正規化係数そのものになっている。

別の解釈を与える

モデルエビデンスに別の解釈を与える。パラメータの事前分布と事後分布が図3.12の時、事前分布の話は1で幅がΔWpriorだと、その高さは1/ΔWpriorとなるから、このことからp(D)を表現できる。この対数をとると、 {\ln{p(D|w_{MAP})}}が尤もらしいパラメータ wMAPによるフィッティング度で、 Δpos/Δpriを含む項が複雑さに対するペナルティであり、事前分布より事後分布が強くフィットするほど、ペナルティが増える。=これにより、過学習を防ぐことが可能となっていると考えられる。

M個のパラメータに対して、同じ比を持つならばM倍のペナルティがかかる。これが、パラメータ数が増えるにつれてペナルティが増えていることを示している。

カルバックライブラーダイバージェンス

期待ベイズ因子を求める際にKL-Divを用いる。式3.73の情報学的な解釈としては、真の分布 {p(D|M_1)}に対して偽の分布 {p(D|M_2)}を用いた時に必要な追加情報量の平均である。ここで、その2つの分布が一致するならば、必要となる情報量は0になるためにカルバックライブラーダイバージェンスも0になるということも直感的にわかる。

  • 変則事前分布は、先の解釈で言うところの正規化係数が定義できないので、適用できない。
  • 適切な極限をとって近似するほかない。

3.5 エビデンス近似

3.3より線形関数モデルでは、モデルパラメータwの事前確率分布を期待値0の、分散 {\alpha^{-1} I}の等方的ガウス分布を考えることとした。ここでβを決定変数に加えられるガウスノイズの精度パラメータとすると(このβは尤度関数に顕に現れる)、この時にwの事後分布は正規分布 { N (w|M_N,S_N)} で表現される。 これの対数尤度をとると、係数にαとβが現れる形になる。背後に仮定したガウス分布のαとβに対して、対数尤度を最大にするような値を求めるのが本節の目的である。

3.5 エビデンス近似 - 詳細

ハイパーパラメーターα、βに対しても事前分布を導入する。パラメータを周辺化して得られる周辺尤度関数を最大化することを、エビデンス近似と呼ぶ。

周辺尤度関数を最大にするようなα、βを選択すればよい。ではその周辺尤度関数を計算してみよう。重みwを周辺化すれば、αとβの式にできる。

演3.17,演3.18をとくと、演3.19は自明に導けて、エビデンス関数の(対数)表式を求められる。

これを最大化するα、βを求めたい。αは(3.92)から導かれる。βも同様に導かれて、(3.95)から導かれる。αとβはそれぞれに関する陰関数であるため、繰り返しによって計算する。

3.5.3 有効パラメータ数-αの意味づけ

基底関数の変換行列Φの固有値λ,αを用いて、

{ \displaystyle
\gamma = \sum(\frac{\lambda}{\lambda + \alpha})
}

で表される。固有値が正だから、 {\frac{\lambda}{\lambda + \alpha}}は0~1の値をとる。1となるものの和=個数がγであるから、1となるものはどういうものだろうか。

パラメータwiが最尤推定値に近いもの。このパラメータはデータに制約されるから、well-determinedパラメータと呼ばれる。このパラメータは、回帰への相関が高いパラメータに対応している。

一方で0に近い場合、 {y=w^{T} \phi(x)}に対して特徴量空間で値が動きにくくなることから、尤度関数の感度は悪くなっている。

思うに、実際には理想的にw_iの値がくっきり最尤推定値に近いものと0に近いもので別れることはなく、 {\frac{\lambda}{\lambda + \alpha}}が0.5になるようなものも得られるだろうが、その時γはパラメーターの寄与相当数(0.5のものが2つあれば、1相当になるとみなす)という形で捉えればよいのではなかろうか。

ハイパーパラメーターαはそもそも事前分布の分散として与えたものであるから、α=0であれば事前分布を導入してないことになるのでα=0の時は最尤推定に一致するし、α!=0の時はMAP推定の結果で最頻値が与えられると考えられる。

3.5.3 有効パラメータ数-βの意味づけ

βは、回帰関数周りでの目標関数の残差分散だが、ここではデータ数がN-γ、つまりwell-determinedでないパラメータの個数ととなっている。これは分散の最尤推定値と不偏推定量の関係で見たように、自由度が関係している。

ベイズ推定では、γ個のパラメータがデータによって決まっていると考えられるため、総パラメータ数Mに対してM-γ個のパラメータは事前分布に従っている。ここから、γ個のパラメータ=自由度が、最尤推定バイアス補正に用いられていると考えるのが相当である。

データ点に関する陰的な和でΦTΦが表現されることが期待できるようなN>>Mの状況では、すべてのパラメータがwell-determinedとなり、γ=Mとなる。この時αとβは容易に書き下せる。αが正則化項、βがデータ依存の誤差項に対応していることは、事前確率分布を期待値0の、分散 {\alpha^{-1} I}の等方的ガウス分布を考え、βを決定変数に加えられるガウスノイズの精度パラメータとしていたことから直感的にわかる。

固定された基底関数の限界

線形モデルの欠点は、以下である。

  • 基底関数を、観測する前に固定していること。

これに対する対処策は以下である。

  • データベクトルは、本質的な次元数は入力空間よりも小さい非線形多様体上に分布していること。
    • 後述
  • 局所的な基底関数を用いれば良い
  • 目標変数がデータ多様体中のほんの少数の方向にしか依存しないこと

パラメータの隠れ変数, 連続への拡張

周辺化することで、パラメータwはいわば隠れ変数となる。この隠れ変数が離散的であるとしたのがEMアルゴリズムによるE,M過程によるαとβの最適化であり、連続的であるとした時に主成分分析を行うのが12章の流れである。

データベクトルは、本質的な次元数は入力空間よりも小さい非線形多様体上に分布していることの直感的な議論としては、下章で示されている例としては手書き数字において、変化するのは垂直方向と水平方向、回転という3自由度しかないので、実効次元は3次元となる。この時、画素が文字位置の非線形関数であり、平行移動と回転のパラメタが潜在変数である。

KerasでLSTMを使ってテスト駆動開発してみた

deeplearning ruby on rails

tl;dr

Kerasという機械学習フレームワークのサンプルにあるLSTMを使い、テストコードを生成して、それをもとにテスト駆動開発してみた。

Kerasを試してみる

以前、紹介記事を書いたのでそちらを参照していただけると幸いです。

sharply.hatenablog.com

また、MLPを使った文の分類については以下の記事をご参照ください。

sharply.hatenablog.com

ソースコードを生成してみる

Kerasのexamplesに含まれているlstm_text_generation.pyを使って、文を生成してみることにチャレンジしてみたいと思います。ここではLSTMという構造が使われていますが、LSTMについては別の記事で少し紹介したので、そちらとその参考ページを参照いただけたら幸いです。

sharply.hatenablog.com

さて、元のコードではニーチェの文書をそのLSTMに学習させています。CPUマシンで計算させるとそれなりにまともな文章が出力されるまでとんでもなく時間がかかるのですが、例えば17イテレータでこんな文章が出力されました。

----- diversity: 1.0 ----- Generating with seed: "on as religion, art and ethics are so un" on as religion, art and ethics are so untorjuse of the nationar is the greater and repalsife man who law, it was supposed at the inplanatine, sole--of the whole poom befole this chacal we have sight of the are the divine patter. of the bits in the end, and the good and despriating the otherse, consequem and gratprouble autional enemat.--and a thing world agaits this difficeetis: the must is the greater of to the morality. one who are in

何のこっちゃといった感じですが、これは"on as religion, art and ethics are so un"をシード、つまりこの文字列から始まる文として、その続きをLSTMに予測させたものです。ご覧の通りそんなに精度よく文が生成されるわけではないのですが、今回はここにRuby on Rails5のソースコードのうち、テストコードだけを読ませてみたいと思います。

$ git clone https://github.com/rails/rails.git
$ cd rails
$ more `find . | grep _test.rb` > all_test.rb

これだけ抽出するだけでも5MBぐらいになり、5MB程度でも非力なCPUマシンでは1イテレータに10時間ほどかかってしまう見込みが出たので、splitコマンドを使って1MBずつに切り分けて、そのなかで最初のファイルを入力として指定してみます。さて、ちゃんとテストコードらしいコードを出力してくれるのでしょうか。結果はこのようなものがみてとれました。

----- diversity: 0.5 (9イテレータ目)
  def test_create_with_conditions_should_be_shared_with_conditions_on_conditions_on_many_and_limit_with_logs_target_with_propore_the_save
    comment = comment.projects.first
    assert_equal 1, post.all.merge!(:includes => :posts.id).post
    assert_equal 2, post.tags.belongs.size
  end

  def test_attribute_mattring_table_name_uniqueness_with_can_be_should_return_name
    column = companies(:f

----- diversity: 1.0 (9イテレータ目)
equal startup, sponsor.sponsorable
  end

  test 'string withdenv = write ci nect('restraction is instance_destroying peoples- ta/se body face
  def test_precision_sql_from_select_view(*arging using attributet") do
      connection.project_id = forkal
      assert_equal 'w, sole
      assert posts(@connection.insert_line_it(with_serialize, default_end) 
    assert_equal 0, parent.id

    \wifhoun data s iv� ssopeltriv"
      end

----- diversity: 0.5 (16イテレータ目)
    car = car.create!(bulbs: [first_name])
    assert_equal 0, account.where("name = ?', ['author'], :interest.first_name: 'sting'
    end
  end

  def test_bould_name_prefixed_association_loading_with_belongs_to_and_on_association
    assert_equal 1, account.where("credit_limit = 10").to_a
    assert_equal 1, companies(:first_firm).clients_of_firm.reload.size
  end

  def test_no_collection_using_primary_key
        with_example_t

中には駄目そうなのもあり、diversityが高いほど駄目になっていますが、diversity=0.5で見た目では実行できそうなコードをピックアップすることができました。関数名がスネークケースで単語マシマシみたいになっていて英語的には破綻していますが、それでもちゃんとRubyで実行できそうなコードになっているのがわかります。

それではテスト駆動開発ということで、このテストに通りそうなコードを書いてみたいと思います。上のコードで、小文字と大文字を今回同一視しているのでその部分だけを修正してテストコードを作り、それをパスできるコードを書きます。

require 'test/unit'
require "active_record"

ActiveRecord::Base.establish_connection(
  adapter:   'sqlite3',
  database:  ':memory:'
)

class InitialSchema < ActiveRecord::Migration
  def self.up
    create_table :comments do |t|
      t.string :name
      t.integer :project_id
    end
    create_table :projects do |t|
      t.string :name
      t.integer :comment_id
    end
    create_table :posts do |t|
      t.string :name
    end
  end
end

InitialSchema.migrate(:up)

class ActiveRecord::Relation
  def post
    1
  end
end

class Symbol
  def id
    self.__id__
  end
end

class Comment < ActiveRecord::Base
  has_many :projects
end

class Project < ActiveRecord::Base
  belongs_to :comment
end

class Post < ActiveRecord::Base
  def self.tags
    Tag.all
  end
end

class Tag < ActiveRecord::Base
  def self.belongs
    [0,1]
  end
end

class TestSample < Test::Unit::TestCase
  def setup
    @comment = Comment.new
  end

  def test_create_with_conditions_should_be_shared_with_conditions_on_conditions_on_many_and_limit_with_logs_target_with_propore_the_save
    comment = @comment.projects.first
    assert_equal 1, Post.all.merge!(:includes => :posts.id).post
    assert_equal 2, Post.tags.belongs.size
  end
end

では、これを実行してみます。

$ ruby test_spec.rb 
Loaded suite test_spec
Started
.

Finished in 0.009579296 seconds.
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
1 tests, 2 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
104.39 tests/s, 208.78 assertions/s

テストに通ったので、うまくいったといえそうです。

近い将来、人工知能がまだプログラムは組めないけれど、仕様書からテストコードぐらいは生成できるようになった過渡期が訪れたとき、我々人類はこのようにして、機械によって生成されたテストコードをパスするためのプログラムを書くだけの存在になってしまうかもしれませんね。

プロセスあたりのメモリ使用量を知りたい

linux software

tl;dr

それぞれのプロセスがどのぐらいのメモリを使用しているかを知りたい。

コマンドで確認する

システム全体のメモリ使用量を確認する

  • cat /proc/meminfo

linuxではデバイスもプロセスもファイルとして扱えるので、catできる。

MemTotal:        8073996 kB
MemFree:          333772 kB
MemAvailable:    4262036 kB
Buffers:          600280 kB
Cached:          3386552 kB
SwapCached:            0 kB
Active:          4668596 kB
Inactive:        2382920 kB
Active(anon):    3061940 kB
Inactive(anon):   286724 kB
Active(file):    1606656 kB
Inactive(file):  2096196 kB
Unevictable:           0 kB
Mlocked:               0 kB

enakai00.hatenablog.com

  • free -tm
             total       used       free     shared    buffers     cached
Mem:          7884       6293       1591        260        470       3368
-/+ buffers/cache:       2454       5430
Swap:         2054          0       2054
Total:        9939       6293       3646

上のを高級な表示にした感じ。linuxではbuffersとcachedは、メモリが足りない時は開放するようになるので、buffers/cacheの値を見るとよい。

  • vmstat

仮想メモリの統計を得る。メモリに関してはfreeと同じような感じだが、cpuやswap, ioの状況も見ることができる。

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 2  0      0 2911928 490096 2719356    0    0    48    44  356   16  8  2 87  3  0

またvmstat [sec]として秒数を引数に渡すと、その秒数ごとの出力を得ることができる。

プロセスごとのメモリ使用量を確認する。

用語を以下のように置くことにする。

  • VSS: 仮想メモリの使用量
  • RSS: 物理メモリの使用量(共有メモリの使用量を含める)
  • PSS: 物理メモリの使用量(共有メモリの使用量をプロセス間で等分する)
  • USS: 物理メモリの使用量(共有メモリの使用量を除く)

使用量というのは実際にはページ単位で使われているかであって、Linuxでは4KBを1ページとしているため最小単位は4KBとなる。HugePagesを使えば、より粒度の大きいページを使うことができて、そうすることでページ表へのアクセスを減らすことができ、場合によっては高速化できる。

ここで検知したいのはvirtual memoryで確保した領域ではなく、実際に使われている領域がどのぐらいかということにある。そのため最低でもRSS、欲を言えばそれより細かい粒度での情報が欲しい。

  • ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root         1  0.0  0.0  35840  5612 ?        Ss   12:43   0:02 /usr/lib/systemd/systemd

これによってRSSは分かるが、結局それは正しい実使用量ではない。

Virtual Threads: Understanding memory usage on Linux

それは先述のように共有ライブラリの使用量が含まれており、reservedなメモリ使用量を全て表示しているからだ。C,C++のソフトウェアに関してはgdb, valgrindなどのデバッガを使えばよいとしている。

  • top/htop
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU  %MEM     TIME+ COMMAND
 3296 root      20   0 2330052 981008 162780 S 35.43 12.15 102:10.74 firefox                                 
 1959 root      20   0 3283584 575640  43724 S 6.954 7.130   6:17.59 dropbox    

topコマンドよりhtopコマンドの方が視覚的にわかりやすいプロセス毎のメモリ/cpu使用率などを表示してくれる。RESがタスクが使用しているスワップされていない物理メモリ、SHRにタスクが利用している共有メモリの総量が載っているので、USS=RES-SHRでとりあえず計算することは可能。

  • pmap -x {procid}
3296: firefox
START               SIZE     RSS     PSS   DIRTY    SWAP PERM MAPPING
00007f4d21e00000  11264K   9320K   9320K   9320K      0K rw-p [anon]
00007f4d23400000  10240K   8120K   8120K   8120K      0K rw-p [anon]
00007f4d23e50000      4K      0K      0K      0K      0K ---p [anon]
00007f4d23e51000   8192K     20K     20K     20K      0K rw-p [anon]
00007f4d24651000      4K      0K      0K      0K      0K ---p [anon]
00007f4d24652000   8192K     12K     12K     12K      0K rw-p [stack:22843]
00007f4d24e52000      4K      0K      0K      0K      0K ---p [anon]
00007f4d24e53000   8192K     12K     12K     12K      0K rw-p [stack:22673]
00007f4d25653000   7860K    428K    428K      0K      0K r--p /usr/share/fonts/truetype/ipamp.ttf
00007f4d25e00000   5120K      0K      0K      0K      0K rw-p [anon]
00007f4d26700000  22528K   9512K   9512K   9512K      0K rw-p [anon]
00007f4d27e00000   5120K   2252K   2252K   2252K      0K rw-p [anon]
00007f4d28c00000   1024K    816K    816K    816K      0K rw-p [anon]
00007f4d28df7000   6092K   2572K    335K      0K      0K r--p /usr/share/fonts/truetype/ipagp.ttf

pmapを使うことでRSSに加え、PSSもわかった。

  • smem
 PID User     Command                         Swap      USS      PSS      RSS 
 1093 hoge     /usr/lib32/skype/skype             0   172280   175262   182704 
 1050 hoge     /usr/bin/dropbox                   0   193672   195052   207152 

それぞれのプロセスのUSS, PSS, RSSを表示してくれる。python2製。

stackoverflow.com

上のStackOverflowによれば、smemでは下の計算式で求められている。

USS = sum of /proc/<pid>/smaps Private_clean + Private_dirty
PSS = sum of /proc/<pid>/smaps Pss
RSS = sum of /proc/<pid>/smaps Rss

smapsで得られる共有メモリの部分には、共有ライブラリだけでなく例えばforkした子プロセスでは、物理メモリのデータをCopy On Write(実際にメモリが書き換えられた時点で複製する)ようにしているので、そのときに共有されている物理メモリについても含まれている。そのためUSSだけがそのプロセスが実際に使うメモリ量とはならないし、RSSであっても共有ライブラリの分のメモリを含んでいる以上、同様となる。

dtrace

さてSolarisMac OS XFreeBSDにはdtraceというコマンドがある。これは動的にシステムをトレースするソフトウェアであるが、残念ながらlinuxには搭載されていない。

以下のツールは、dtraceの代替として紹介されている。それぞれを紹介したい。これを用いて、メモリを確保するようなシステムコールがいつどれだけ発行されたかをたどることができる。

stackoverflow.com

  • sysdig

Sysdig | Home

csysdigでncurseによるインタラクティブモニタリングをすることが可能となっている。そう、sysdigで表示される謎の出力をいちいちgrepしたり、引数をつけて呼び出す必要はないのだ。

最初に開いた画面でできることはたとえば以下がある。

f:id:sharply:20160622151129p:plain

F2を押すと、Viewを変更できる。例えば何らかのプロセスによってopenしているファイルのリスト(lsof)であったり、Systemcallのリストであったり。

Enterキーで選択されている行に限定して詳しく見ることができる。BackSpaceキーで戻れる。例えばSystemCallのリストで、Systemcallを選んでEnterを押すと、そのSystemcallを読んだプロセスが表示される。

F5を押すと、readwriteイベントを見ることができる。F6を押すと、本家sysdigの出力を垣間見ることができる。

なお、実行するにはsuperuser権限で実行しなければならない。

stap とかいうどこかで聞いたことの有るような細胞名のコマンドで呼び出すこのツールは、Systemtap Scriptと呼ばれるスクリプトファイルに従ってカーネルに対する探索を行うことが可能である。

sourceware.org

がまだ詳しくわかっていない...

  • strace

実際にシステムコールがどのタイミングで走っているかについてはstraceで検知することが可能である。プロセスにアタッチして、そのプロセスにおけるシステムコールを確認することもできる。

blog.livedoor.jp

straceを使うと、このような形で呼ばれたシステムコールと戻り値をみることができる。それをもとにmmapbrkがどれだけメモリ確保したかを累算することができるが、いかんせん、これが内部で呼んでいるシステムコールptraceは遅いので、実用性という面では厳しい。

brk(NULL)                               = 0x2156000
brk(0x2188000)                          = 0x2188000
mmap(NULL, 1000000000004096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
brk(0x38d7ea6df0000)                    = 0x2188000
mmap(NULL, 1000000000135168, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
mmap(NULL, 134217728, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_NORESERVE, -1, 0) = 0x7f73a4490000
munmap(0x7f73a4490000, 62324736)        = 0
munmap(0x7f73ac000000, 4784128)         = 0
mprotect(0x7f73a8000000, 135168, PROT_READ|PROT_WRITE) = 0
mmap(NULL, 1000000000004096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) = -1 ENOMEM (Cannot allocate memory)
exit_group(0)                           = ?

さいごに

今回の記事については、素人同然の立場でまとめた備忘録ですので、Linuxにおけるメモリの使用方法について不正確な記述が多いおそれがあります。ご注意下さい。

References

sisidovski.hatenablog.com

gntm-mdk.hatenadiary.com

Memory Flame Graphs

qiita.com

qiita.com

Linuxトラブルシューティング探偵団 番外編(3):SystemTapで真犯人を捕まえろ! (1/4) - @IT

d.hatena.ne.jp

th0x4c.github.io