MATHGRAM

主に数学とプログラミング、時々趣味について。

【低レベルプログラミング】docker による実行環境構築とハローワールド 【その1】

めっちゃお久しぶりです.

エンジニアとして強くなるために低水準言語をちゃんと理解したくなり, 最近低レベルプログラミングを購入しました.

低レベルプログラミング

低レベルプログラミング

初心者には割と敷居が高い印象を受けましたが,知らない単語は調べつつ読み進めています.

そして忘れないためにも,この本から学んだことを記録として残していこうと思います.

シリーズ化しますので続いてなかったら挫折したか死んだかのどっちかだと思ってください.

本記事の内容は全て以下のレポジトリに push していますので,適宜参考にしてみてください.

また,この記事の本文も上のレポジトリに push しています. もし間違いや読みにくい文章等がございましたら issue を立てるなり PR を上げるなりしていただけると泣いて喜びます.

よろしくお願いします.

目次

  1. docker を用いた実行環境構築
  2. 簡単なアセンブリを書いてハローワールド

本記事では実行環境構築に焦点をあて, アセンブリの詳細な解説は次の記事で行います.

1. docker を用いた実行環境構築

この本ではDebian GNU\Linux 8.0の環境を推奨されていますが, いつも触っている Macbook で実行したいので Docker を使って環境を整えます.

まずは Dockerfile を作成します. 書籍の実行環境となるべく揃えたいのでイメージはdebian:8を使用しましょう.

C 言語のコンパイラである gcc 等も後々必要になるようですが,最初はミニマムで進めていこうと思います.

FROM debian:8

RUN apt-get update \
  apt-get install -y binutils nasm gdb \
  apt-get install -y vim

それではこの Dockerfile から docker イメージを作成しましょう.

$ docker build -t low-level-programming .

これでイメージが作成されました. 以上で実行環境構築は終了です.
ホントに docker は最高ですねー

2. 簡単なアセンブリを書いてハローワールド

早速ハローワールドを出力するアセンブリを書いてみましょう. と,言っても書籍のコード丸写しです.

元コードは書籍の p28 のリスト 2-4 です.

section .data
message: db 'hello, world!', 10

section .text
global _start

_start:
  mov rax, 1
  mov rdi, 1
  mov rsi, message
  mov rdx, 14
  syscall

  mov rax, 60
  xor rdi, rdi
  syscall

現状,高級言語しか知らない自分には本当に何が書いてあるかわからないです笑

冒頭でも書きましたが,このコードの解説は次の記事で行います.

では,アセンブル*1して実行してみましょう.

先ほど作った実行環境にアセンブリを保存しているワーキングディレクトリをマウントします.

$ docker run -it -v $(pwd):/work low-level-programming bash

あとはコンパイルして実行するのみです.

$ cd work
$ nasm -felf64 hello.asm -o hello.o
$ ld -o hello hello.o
$ ./hello

はい,以下のようにちゃんとハローワールドが出力できましたね.

root@97e9cd2fd7da:/work# ./hello
hello, world!

まとめ

  • 手を動かすために docker で実行環境を整えました.
  • アセンブリhello, world!を出力しました.

以上です.

次回は本記事で書いたハローワールドを読み解いていきます.

参考

本記事の内容は以下の記事を大いに参考にしています. 有益な記事ありがとうございました.

書籍「低レベルプログラミング」アセンブリ実行 Docker 環境の構築

1: アセンブラ機械語コンパイルすること

t-SNEの結果をplotlyで3D可視化する

前回のplotlyの記事で実践編は暇あったら書きます的なこと言ったのですが,今回はそれに当たる内容です.

内容量はかなり少なく薄いですが,plotlyの使用例程度に思ってくれると有難いです.

t-SNEとは

t-SNEとは,皆さまご存知の通り次元圧縮の手法ですね.高次元データを人間が認知できる次元まで綺麗に落とし込める手法なので使っている人は多いのではないでしょうか.

今回はplotlyの使い方を重視した記事なので,理論の話はしませんが需要があったらまとめますね.一応参考になる資料をここにまとめておきます.

論文:
https://lvdmaaten.github.io/publications/papers/JMLR_2008.pdf

参考サイト:
理論とか置いといてt-sneをアプリケーションとして使う人は読むべき
高次元のデータを可視化するt-SNEの効果的な使い方 - DeepAge

ざっと理論の概要を知りたい人はこちらで.
t-SNE を用いた次元圧縮方法のご紹介 | ALBERT Official Blog

実践してみる

上のt-SNE を用いた次元圧縮方法のご紹介 | ALBERT Official Blogでやってることをpythonに移植する流れでやりたいと思います.

データセットcoil-20を使用し,sklearnに実装されているtsneを用います.

まずは3D

まずは3次元まで落とし込んでみましょう.

import os
import numpy as np
import cv2
from sklearn.manifold import TSNE
from sklearn import preprocessing

import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()

# 画像の前処理.標準化やらL2正規化やら.
def preprocess_image(path, size):
    img = cv2.imread(path, cv2.IMREAD_GRAYSCALE)
    resized = cv2.resize(img, (size, size), cv2.INTER_LINEAR).astype("float")
    normalized = cv2.normalize(resized, None, 0.0, 1.0, cv2.NORM_MINMAX)
    timg = normalized.reshape(np.prod(normalized.shape))
    return timg/np.linalg.norm(timg) 

ROOT = "./coil-20-proc"
ls = os.listdir(ROOT)

# 名前からラベルを持って来ます.
obj_ls = [name.split("_")[0] for name in ls]

ALL_IMAGE_PATH = [ROOT+"/"+path for path in ls]

# 全画像に対して前処理する
preprocess_images_as_vecs = [preprocess_image(path, 32) for path in ALL_IMAGE_PATH]

# tsneを実行
tsne = TSNE(
    n_components=3, #ここが削減後の次元数です.
    init='random',
    random_state=101,
    method='barnes_hut',
    n_iter=1000,
    verbose=2
).fit_transform(preprocess_images_as_vecs)

たったこれだけで次元削減できてしまいます.sklearnに感謝です.

さて,現在tsneという変数に次元削減後のarrayが入っているのでコイツをplotlyを用いて可視化してみます.

# 3Dの散布図が作れるScatter3dを使います.
trace1 = go.Scatter3d(
    x=tsne[:,0], # それぞれの次元をx, y, zにセットするだけです.
    y=tsne[:,1],
    z=tsne[:,2],
    mode='markers',
    marker=dict(
        sizemode='diameter',
        color = preprocessing.LabelEncoder().fit_transform(obj_ls),
        colorscale = 'Portland',
        line=dict(color='rgb(255, 255, 255)'),
        opacity=0.9,
        size=2 # ごちゃごちゃしないように小さめに設定するのがオススメです.
    )
)

data=[trace1]
layout=dict(height=700, width=600, title='coil-20 tsne exmaple')
fig=dict(data=data, layout=layout)
offline.iplot(fig, filename='tsne_example')

こんな感じで出力されます.グリグリ動かしてみてください.とても綺麗に分離できていることがわかります.尚,円形にplotされていることに関する考察などは先のブログでされているので是非参考にしてみてください.

2Dもやってみる.

ほぼ上と同じようにtsneを実行し,Scatter2dを用いて可視化してみます.

# tsneには2dまで落とし込んだarrayが入っている想定です.

trace = go.Scatter(
    x=tsne[:,0],
    y=tsne[:,1],
    mode='markers',
    marker=dict(
        sizemode='diameter',
        color = preprocessing.LabelEncoder().fit_transform(obj_ls),
        colorscale = 'Portland',
        line=dict(color='rgb(255, 255, 255)'),
        opacity=0.9,
        size=4
    )
)

data=[trace]
layout=dict(height=800, width=800, title='coil-20 tsne exmaple 2D')
fig=dict(data=data, layout=layout)
offline.iplot(fig, filename='tsne2D_example')

f:id:ket-30:20170705035109p:plain:w500:h500

この世の生データに比べたらかなり綺麗に分かれていますが,若干バラついてる部分も見受けられますね.やはり3Dと2Dでは元のデータに対する説明量が違いますので,この程度の差は出てしまいます.

内容としては以上です.

あとがき

plotlyは最近かなり使っているのですが,せっかく使っているのに実践編として記事にできてない状況になっています・・・.これからは,今回くらいの内容の薄さでもいいやぁって開き直って記事の更新頻度を上げていきたいと思います.

次はディリクレ分布を可視化してみようと思います.よろしければそちらも是非.

以上です.

matplotlib使いづらくない?plotlyで可視化しようよ

pythonでグラフを可視化する時,matplotlib使いづらくないですか?覚えにくいし,毎回ググってる気がします.

あとデザインもダサいので全然好きになれません.(デザインに関してはseabornを使えば綺麗ですが,結局matplotlibで書くことになるので覚えづらいことには変わりないです・・・)

ただしmatplotlib画像の表示には強いです.そういう時は僕も使います.

プロmatplotliberの方がこの記事を見てくださって,「お前は何もわかっていない.こんなに素晴らしくグラフをかけるんじゃ」って言われたら素直に土下座します.煽り気味のタイトルで本当に申し訳ないです.

そんなこんなで今回は,割と覚えやすくてデザインもよく,3Dの作図にも強い可視化ライブラリ,plotlyを紹介します.

いきなりですがplotlyではこんな作図ができます.

Note: おそらくスマホではうまく表示されませんのでPCで確認お願いします!

追記: PCでも数字のメモリが [?] になってしまう時があるようです.ちゃんと表示させたいときは更新などをして対処お願いします.申し訳ありません.

ご覧の通り,マウスホバーで詳細を表示できたり,グラフを動かせたり3Dの作図もかなりいい感じにできるのでみなさんも使ってみてください.

アジェンダ

  1. Usage
  2. Basic Charts
    1. Scatter Charts (散布図)
    2. Line Charts (折れ線グラフ)
    3. Bar Charts (棒グラフ)
  3. Statistical and Seaborn-style Charts
    1. Error Bars (誤差付き折れ線グラフ)
    2. Box Plots (箱ひげ図)
    3. Histograms (ヒストグラム)
    4. 2d Histograms (二次元ヒストグラム)
    5. 2d Density Plots
  4. Scientific Charts
    1. Heatmaps
    2. Dendrograms (階層クラスタ)
  5. 実践(暇できたら適当にやっていきます.)

目次に書いたもの以外でもたくさん機能はあるのですが,あんまり使わなそうだなぁと個人的に思ったものは紹介していません.DocumentにGoです.

また最後に実践編として分析例をいくつか載せていく予定です.実践編は随時追加予定なので自分のやりたい分析と近いものがあれば参考にしてみてください.

最後に注意事項.
以下で表示しているグラフは全て画像なので,動かせません.注意してください

もちろんみなさんのローカル環境ではグリグリ動かせるグラフができますのでご安心を.

あと最後の最後におまけなんですが,atomhydrogenを使えばatom内で分析がゴリゴリできます.

f:id:ket-30:20170527212818p:plain

実は僕jupyterもそこまで好きじゃないんで,同志がいたら使ってみてくださいね.

1. Usage

まずはinstall.pipで簡単にいけます.

$ pip install plotly

この記事を見ている多くの方は既にinstallしていると思いますが,pandasやらjupyterやらまぁその辺は入れといてください.

※ ここから下は,plotlyの基本的な書き方の説明です.コードを読む方が早いって方は読まなくて大丈夫です.

さて肝心の作図の方法ですが,だいたいのグラフは以下の流れで作成できます.

  1. オフラインで動くように設定する.
  2. traceを作成する.
  3. layoutを定義する.
  4. iplot, もしくはplotで作図する.

1個ずつ言葉を確認していきましょう.

まず結構重要なオフラインの設定です.

plotlyはアカウントを作って,サーバー上にグラフを保存することができます.一番最初に掲載した,3Dの動くグラフもサーバー上に保存されているグラフをお借りしているものです.

しかし僕の場合はオフラインで事足ります.というかほとんどのユーザーはオフラインで満足なはず.ですので以下のようにimportしましょう.

import plotly.offline as offline
offline.init_notebook_mode()

ここの仕組みについてはあまり考える必要ないと思います.僕も知りません.

お次はtraceです.

traceは作図で一番重要なデータや作図方法の情報が入ったものです.具体的な例を示します.

# 注意: 色々省いているのでこれだけでは動きません! 
import plotly.offline as offline
import plotly.graph_objs as go

trace = go.Scatter(
    x = np.array(setosa[columns[1]]),
    y = np.array(setosa[columns[2]]),
    name = "setosa",
    mode = "markers",
    marker = dict(size=10, color="rgba(255, 0, 255, 0.5)"))

ここではScatter(散布図)を使いtraceを作っています.見てわかるように,この時点でxyなどにデータを与えています.またmarkerの部分で点の大きさや色なども指定しています.plotlyではこのtraceを基本単位として扱います.

次はlayoutについて.

先ほどはデータ点そのものについて色や大きさなどを指定しました.layoutではグラフのタイトルや軸の名前など,ひとつ粒度の大きい部分のデザインを定義していきます.具体的な例は以下です.

layout = go.Layout(
    title='Iris sepal length-width',
    xaxis=dict(title='sepal legth(cm)'),
    yaxis=dict(title='sepal width(cm)'),
    showlegend=True)

最後にiplotです. iplotplotの違いはjupyter内で作図をするかどうかの違いなので,基本的にiplotを使います.

先ほど作った,tracelayoutを辞書で囲んであげてiplotします.ちなみに辞書で情報を整理されたものを,plotlyではfigureと呼んでいるみたいです.

fig = dict(data=data, layout=layout)
offline.iplot(fig, filename="example")

以上が主な作図方法の流れです.

2. Basic Charts

2.1 Scatter Charts (散布図)

Simple Scatter Plots

散布図です.1個目なのでIrisデータ使いましょう.

まずはラベルなしでplotしてみます. 教師なし学習とかを想像しながら見てくださいね.

グラフはこんな感じになります. f:id:ket-30:20170521153357p:plain

サンプルコード

Usageでも紹介した通り,

  1. traceを作成する.
  2. layoutを定義する.
  3. iplot, もしくはplotで作図.
    の流れです.

Style Scatter Plots

次はラベルつきでplotしてみます. 教師データを意識してください.

f:id:ket-30:20170521160938p:plain

versiclorvirginicaがガッツリ混ざっていますね.3種類に分類するとき,この特徴量だけでは足りないことが見て取れます.

サンプルコード

Usageでも紹介した通り,

  1. traceを作成する.
  2. layoutを定義する.
  3. iplot, もしくはplotで作図.
    の流れです.

2.2 Line Charts (折れ線グラフ)

折れ線グラフは時系列データを扱うときに使います.
基本的には散布図と同様にScatterを使い,modelinesを与えるだけです.

f:id:ket-30:20170521162955p:plain

サンプルコード

Usageでも紹介した通り,

  1. traceを作成する.
  2. layoutを定義する.
  3. iplot, もしくはplotで作図.
    の流れです.

2.3 Bar Charts (棒グラフ)

棒グラフはカテゴリカル分布の作図や,
それぞれのクラスに属するデータ数を可視化するときに使います.

以下の例では,手書き数字データセットのdigitsを用いてそれぞれの数字にいくつのデータがあるか調べています.

f:id:ket-30:20170521172122p:plain

今回の例ではほとんど同数なので問題ありませんが,
データ数に偏りがあった場合は重み付けなどしないといけませんからね.
この棒グラフの可視化も分析には重要なstepです.

サンプルコード

Usageでも紹介した通り,

  1. traceを作成する.
  2. layoutを定義する.
  3. iplot, もしくはplotで作図.
    の流れです.

3. Statistical and Seaborn-style Charts

3.1 Error Bars

Error Barsとは誤差付き折れ線グラフのことです.ここで紹介しているのは厳密に言うとBasic Continuous Error Barsですが,まあ気にしないでください.多分こっちの方が使います.

使いどころはベイズ線形回帰などがパッと思いつくところです.ベイズ線形回帰だと確率が見えないから微妙かな.まぁいつか何かで実践して載せるつもりです.いつかね!

以下の図とサンプルコードは本家のDocumentをoffline ver.に書き換えただけのほぼ同じものです.

f:id:ket-30:20170522235157p:plain

サンプルコード

  1. traceを作成する.
  2. layoutを定義する.
  3. iplot, もしくはplotで作図.
    の流れです.

3.2 Box Plots (箱ひげ図)

有名な図ですけど,自分で作図したことはほとんどないです.

これも本家のDocumentをoffline に書き換えただけです.申し訳ない.

f:id:ket-30:20170523000145p:plain

サンプルコード

  1. traceを作成する.
  2. layoutを定義する.
  3. iplot, もしくはplotで作図.
    の流れです.

3.3 Histograms

きました,定番のヒストグラムです.めっちゃ使います.

棒グラフと似てますけど違いますからねー.

まずは正規分布から適当にデータをサンプリングして最もシンプルなヒストグラムを生成してみましょう.

こんな感じになります.

f:id:ket-30:20170523002714p:plain

若干きもいヒストグラムになっちゃいました.

サンプルコード

import plotly.offline as offline
import plotly.graph_objs as go
offline.init_notebook_mode()

import numpy as np

x = np.random.randn(500)
data = [go.Histogram(x=x)]

offline.iplot(data, filename='basic histogram')

しかし,分析しているときは何かしらのデータを比較していることも多いですよね.

1つのデータごとに1つずつヒストグラムを作るのはダサいです.

ってことで多分こういうグラフの方が一般的に使うのかなと思います.

f:id:ket-30:20170523004712p:plain

若干ずらして表示してくれるので見やすいですね.

サンプルコード

3.4 2d Histgrams

2つのヒストグラムを使って作図します.次の図は2次元正規分布を無理やり離散に書き換えたものと考えるとわかりやすいかもしれません.

f:id:ket-30:20170527174157p:plain

カウントした総数で正規化すればこのままの状態で確率分布になります.

こういうグラフ見てると周辺化したくなってきますよね.

サンプルコード

3.5 2d Density Plots

2D Histogramと似てますが,こちらは連続データを扱うときに使います.

irisデータに含まれるsetosaのsepal lengthとsepal widthを使って分布を確認してみましょう.

f:id:ket-30:20170521202709p:plain

ちょっとデータが少ないですね.しかもこの多次元データは2次元正規分布に従うというより,正の相関を持ったデータっぽいですね.

多次元正規分布の作図として適してないかもしれませんが,まぁこういうことも作図して初めてわかるときもあるよってことで許してください.

サンプルコード

4 Scientific Charts

4.1 Heatmaps

お次はヒートマップです.3種類の変数の関係性を見たいときに使います. Qiitaのこちらの記事がseabornに含まれているわかりやすいデータを用いているので,こちらと同様にグラフを作ってみましょう.

f:id:ket-30:20170527163923p:plain

色の濃さは乗客数を表しているので,乗客数と年月の相関を確認することができます.パッと見ただけで,12月は帰省などで多いのかな?や,1955年付近には何があったのだろう?と分析の目処を立てることができますね.

また模様の違いがはっきり出ている方が,その変数は特徴量として大きな情報を持っていると判断することもできます.つまり特徴量選択の際にも使うことができます.

サンプルコード

4.2 Dendrograms

主に階層的クラスタリングで使うDendrograms,いわゆる系統樹の紹介です.階層的クラスタリングってなんやねんって方は,こちらを参考にして見てください.

ヒートマップと組み合わせて用いることが多いのですが,そこに関してはseabornの方が簡単にできるような気がしてます.とりあえずここで紹介するのは基本的なDendrogramsってことで許してください.

一応階層クラスタリングを簡単に説明すると,それぞれのデータごとに"キョリ"を計算し,近いものから同じグループとして結合していく手法です."キョリ"の計算方法は色々あるので,それは別の記事で書こうかと.できたらリンク貼りますねー.

結果的にはこんな図ができます.

f:id:ket-30:20170527173110p:plain

サンプルコード

系統樹figure_factoryを用いて作図するのですが,Layoutを扱う際に,若干の注意が必要です.コメントで書いておきましたので,そちらを参考にして見てください.

実践編

暇できたら書く

まとめ

少なくともmatplotlibよりは覚えやすいし,デザイン的にかっこいいグラフが作れると僕は思っています.

またplotlyの真髄は3Dの作図なので,3Dグラフのまとめもすぐに書きますね.

以上です.