
Outline
この記事について
DeepMind が Nature に投稿した論文
Hybrid computing using a neural network with dynamic external memory
で使用されている “Differentiable Neural Computing (DNC)” について解説します。ロジックの説明がメインですが、Python – Chainer による実装例も紹介します。
Differentiable Neural Computing (DNC)とは
sequential data を Neural Net で処理したいという欲求は昔からあるようで、一番スタンダードなものは Recurrent Neural Net (RNN) です。しかし、RNN には”勾配消失問題”というものがありまして、それを克服したモデルが Long Short Term Memory (LSTM) と呼ばれています。何が short で何が long なのかというと、入力されたデータは、出力されるまで Neural Net の内部にとどまっているわけです。これはある意味で “Memory” のようなものと考えてもよさそうです。しかし、入力から出力までの”短時間”しか記憶ができない。なので、”short term momory” と呼ばれます。「この short term memory の記憶できる時間が長くなりましたよ」という意味で、Long Short Term Memory と名付けられているようです。そうすると、本当に long な Meomory は学習機内部ではなくて外部にあってもいいかもしれない、そんな気がしてきます。そういう思いから生まれた、かどうかは分かりませんが、Differentiable Neural Computing (DNC) とは、学習機の外部に Memory を用意してやって、Memory の使用法まで含めて学習させてしまうというものです。”Differentiable”の意味ですが、back propagation で学習させようと思うと、微分を計算できることが必要になります。ですので、外部 Memory に対する操作も含めて”微分計算が可能であること”という意味です。
ロジック解説
DNC の全体像
DNC の構成要素は、本体である Controller と外部 Memory です。論文によると、全体としてのデータの流れは下図のように表すことができます。
DNC は sequential data を扱いますので、現在の time-step を $t$ と表しています。前 step は $t-1$、次 step は $t+1$ となり、図中の添え字 $t$ は、それぞれの変数がどの time-step で生成されたものであるかを表しています。
それでは、データの流れを順を追って見ていきましょう。図中に(1)~(4)の番号が振ってありますので、この順で追ってください。
(1) : “Data Set” より 入力データ $x_t$ が入力されます。これに、前 step での Memory からの出力 $\boldsymbol{r}_{t-1}$ とを合わせた $\boldsymbol{\chi}_t=[\boldsymbol{x}_t, \boldsymbol{r}_{t-1}]$ を Controller への入力とします。
(2) : Controller からの出力 $\boldsymbol{h}_t$ が得られますので、これを2つのルートに振り分けます。ひとつは、”Out Put” に向けての $\boldsymbol{v}_t$、もう1つは Memory を制御するための “interface vector” $\boldsymbol{\xi}_t$ です。論文中では、これらは $\boldsymbol{h}_t$ の線形変換 $\boldsymbol{v}_t=W_y \boldsymbol{h}_t$ と、$\boldsymbol{\xi}_t=W_{\xi} \boldsymbol{h}_t$ として書かれています。
(3) : “interface vector” $\boldsymbol{\xi}_t$ をもとに Memory へのデータの書き込みが行われ Memory の状態が更新されます。また、Memory からの読み出しも行われ、”read vector” $\boldsymbol{r}_t$ が得られます。
(4) : “read vector” $\boldsymbol{r}_t$ は、 “Out Put”への出力に加算される一方で、次 step での Controller への入力へと回されます。
(5) : Controller からの出力と、Memoryからの出力を合成し”Out Put” へ $\boldsymbol{y}_t = \boldsymbol{v}_t + W_r \boldsymbol{r}_t$ を出力します。
以上、(1)~(5) をもって、1 step が完了します。
Controller としては、多次元の入力を受け取り、多次元の出力を返す学習機なら何でもよいのですが、(Recurrent) Neural Net や LSTMなどを使うことが多いようです。(Recurrent) Neural Net や LSTM の解説は他にゆずるとして、この記事では、DNC の最大の特徴である「外部 Memory の読み書き」について解説していきます。
外部 Memory の読み書きについて
それでは、外部 Memory の読み書きについて解説しましょう。面倒なので、以下では単に Memory と呼ぶことにします。
Memory の構造
まずは、Memory の構造について把握しておきましょう。
Memory としては $N$ × $W$ の行列を用います。つまり、address が $1$~$N$ まで振られていて、各 address に $W$ 次元の数値ベクトルを格納できる slot があると考えます。Memory の状態は刻々と更新されていきますので、time-step $t$ での Memory を表す行列を $M_t$ と書くことにします。ただし、行列の次元 $N$ × $W$ は固定されているものとし、常に、$N$ は memory slot の総数 (address の総数)、$W$ は slot の長さ(格納する数値ベクトルの次元)とします。
interface vector の詳細
「全体のデータの流れ」でも述べた通り、Controller による Memory の操作は
“interface vector” $\boldsymbol{\xi}_t$ を通して行われます。一口で Memory の操作といっても、読み込み/書き込み/addressの指定など、複数のタスクが考えられますので、$\boldsymbol{\xi}_t$ は機能別に各 component に分解されます。
\begin{align}
\boldsymbol{\xi}_t = \Big[ \boldsymbol{k}_t^{r, 1},...,\boldsymbol{k}_t^{r, R}, \; \hat{\beta}_t^{r, 1},...,\hat{\beta}_t^{r, R}, \; \boldsymbol{k}_t^w, \; \hat{\beta_t}^w, \hat{\boldsymbol{e}}_t, \; \boldsymbol{\nu}_t, \; \hat{f}_t^1,...,\hat{f}_t^R, \; \hat{g}_t^a, \; \hat{g}_t^w, \; \hat{\boldsymbol{\pi}}_t^1,...,\hat{\boldsymbol{\pi}}_t^R \Big]
\end{align}
‘$\hat{}$’ 記号がついているものは、さらに scale 変換をかけます。種類が多くてややこしいので、いったんまとめます。( , )内の値は、(次元, 個数)です。
・”read key” $(W, R) \; :\; \boldsymbol{k}_t^{r, 1},…,\boldsymbol{k}_t^{r, R}$
・”read strength” $(1, R) \; : \; \beta_t^{r, 1},…,\beta_t^{r, R} \;\;\big(\beta_t^{r, i}=\text{oneplus}(\hat{\beta}_t^{r, i})\big)$
・”write key” $(W, 1) \; : \; \boldsymbol{k}_t^w$
・”write strength” $(1,1) \; : \; \beta_t^w=\text{oneplus}(\hat{\beta}_t^w)$
・”erase vector” $(W, 1) \; : \; \boldsymbol{e}_t=\sigma(\hat{\boldsymbol{e}}_t)$
・”write vector” $(W, 1) \; : \; \boldsymbol{\nu}_t$
・”free gate” $(1, R) \; : \; f_t^1,…,f_t^R \;\; \big(f_t^i=\sigma(\hat{f}_t^i)\big)$
・”allocation gate” $(1, 1) \; :\; g^a_t=\sigma(\hat{g}^a_t)$
・”write gate” $(1, 1) \; :\; g^w_t=\sigma(\hat{g}^w_t)$
・”read mode” $(3, R) \; : \; \boldsymbol{\pi}_t^1,…,\boldsymbol{\pi}_t^R \;\; \big(\boldsymbol{\pi}_t^i=\text{softmax}(\hat{\boldsymbol{\pi}}_t^i)\big)$
スケール変換に用いる関数は、
\begin{align}
& \text{oneplus}(x) = 1+\text{log}(1+e^x) \in [1, \infty) \\
& \sigma(x) = \frac{1}{1+e^{-x}} \in [0, 1] \\
& \text{softmax}(\boldsymbol{x}) = \frac{e^\boldsymbol{x}}{\sum_ie^{x_i}} \in [0, 1]
\end{align}
と定義されています。$\text{oneplus}(x)$、 $\sigma(x)$、$\text{exp}(x)$ の引数にベクトル値を取る場合は、成分ごとの作用を意味しますので注意してください。
ここでは、定義を羅列しただけなので、何もわからないと思います。以下、これらの component をどのように使って Memory を制御していくか、順に解説していきます。
先に進む前に、1点だけ説明を加えておきます。$R$ は Memory からの読み出しの回数を表しています。論文中の DNC では、1 step のうちで Memory からの読み出しを複数回行う設定となっていて、その回数が $R$ です。対して、書き込みは、1 step に1回のみの設定です。また、interface vector の次元は、$W$ と $R$ で決まっていて、$WR+3W+5R+3$ となることも分かるかと思います。
Memory の読み書き手順(概要)
Memory の読み書きには、読み書き対象となる Memory slot の address を指定する必要があります。ただし、back propagation による学習が可能であるためには、微分可能性、少なくとも演算の連続性が必要となります。よって、特定のひとつの address だけを指定するのではなく、幅を持たせて、どの address を重点的に読み込む/書き込むかの重みづけを行います。以後、この重みを、”read/write weighting”と呼ぶことにしますが、これらをどう求めていくかがポイントになります。
“read/write weighting” を求めてしまえば、読み込み/書き込みの演算自体は単純です。詳細は後に回しますが、概要をつかんでおきましょう。まず、読み込みの場合を考えてみます。今、”read weighting” $\boldsymbol{w}^r_t$ が得られたとします。このベクトルの次元は、Memory slot の総数と同じ $N$ です。各成分は対応する address の Memory slot にある情報をどれだけ”強く”読み込むかを表しています。すなわち、読みだされる情報は、Memory 行列と重みベクトルの積として、$M_t^T\boldsymbol{w}^r_t$と表されます。先にも述べましたが、論文中では 1 step で読み出しを $R$ 回行う設定なので、”read weighting” も $R$ 個 $\{\boldsymbol{w}_t^{r,i}\}_{i=1,…,R}$ 構成されます。また、読み出しによる増幅など防ぐため、自然な要請として
\begin{align}
& 0 \leqq \boldsymbol{w}_t^{r,i}[n] \leqq 1 \;\; (n=1,2,...,N)\\
& \sum_{n=1}^N \boldsymbol{w}_t^{r,i}[n] \leqq 1 \;\; (i=1,2,...,R)
\end{align}
を課すものとします。
同様に、書き込みの場合も考えてみましょう。”write weighting” $\boldsymbol{w_t^w}$ が得られたとします。また、書き込みたい情報を表すベクトル $\boldsymbol{\nu}_t$ も得られているとします。$\boldsymbol{w_t^w}$の次元は$N$で、各成分は対応する Memory slot にどれだけ”強く” $\boldsymbol{\nu}_t$ を書き込むかを意味します。つまり、Memory 行列 $M_{t-1}$ に、行列 $\boldsymbol{w_t^w}\boldsymbol{\nu}_t^T$ を加算することで書き込みを行い Memory を更新します。各成分に
\begin{align}
& 0 \leqq \boldsymbol{w}_t^w[n] \leqq 1 \;\; (n=1,2,...,N)\\
& \sum_{n=1}^N \boldsymbol{w}_t^w[n] \leqq 1
\end{align}
を課す点は同様です。
Memory の読み書き手順(詳細)
論文中では、Memory への読み書き自体も含めて以下の4つの手順を踏んでいます。
①write weighting の更新
②Memory への書き込み
③read weighting の更新
④Memory からの読み込み
以下、このステップにそって解説していきますが、実装例でも、この順で処理をまとめていますので、参考にしてください。
尚、前 time-step での read/write weighting $\{\boldsymbol{w}_{t-1}^{r,i}\}_{i=1,…,R}$ / $\boldsymbol{w}_{t-1}^{w}$は得られているものとします。
①write weightingの更新
書き込み先の address の選択には2つの方法があり、write weighting は2つの要素から構成されます。つまり、(1) interface vector を通して入力された “key” をもとに書き込み先 slot を選択、(2)前 time-step までの読み出し状況をもとに使用済みの情報が残っている slot を選択、の2つです。
まずは、(1)から見ていきましょう。
interface vector $\boldsymbol{\xi}_t$ 中の “write key” $\boldsymbol{k}_t^w$ を各 Memory slot に保持されている情報と照合し類似度を計算します。また、weighting の peak の鋭さを調整するパラメータとして “write strength” $\beta_t^w$ も使用します。
この計算は、read weighting を求めるところでも共通なので、$N$×$W$ 行列 $M$、$W$ 次ベクトル $\boldsymbol{k}$、スカラー値 $\beta$ に対して、以下の演算を定義しておきます。
\begin{align}
\mathcal{C}(M, \boldsymbol{k}, \beta)[n] = \frac{\text{exp}\big(\mathcal{D}(\boldsymbol{k}, M[n,:])\beta \big)}{\sum_m\text{exp}\big(\mathcal{D}(\boldsymbol{k}, M[m,:])\beta \big)}
\end{align}
ここで、$\mathcal{D}$ は2つのベクトル間の距離で、とりかたはいろいろ考えられますが、論文に合わせてコサイン類似度
\begin{align}
\mathcal{D}(\boldsymbol{u}, \boldsymbol{v}) = \frac{\boldsymbol{u} \cdot \boldsymbol{v}}{||\boldsymbol{u}|| \; ||\boldsymbol{v}||}
\end{align}
としておきます。$\beta \rightarrow \infty$ の極限で $\mathcal{C}$ は鋭いピークがひとつだけ立ちます。
さて、ここで定義した演算を用いて、(1)の方法による write weighting は
\begin{align}
\boldsymbol{c}_t^w=\mathcal{C}(M_{t-1}, \boldsymbol{k}_t^w, \beta_t^w)
\end{align}
と計算されます。
次に(2)の方法による計算です。多少ややこしいですが、以下の順で求めていきます。
(2)-1. “retention vector” $\boldsymbol{\psi}_t$ の構成
前 time-step $t-1$ で情報を読み出した Memory slot は、使用済み slot として書き込みに利用したいと思うのは自然でしょう。しかし、今後も必要な情報が保持されている場合は、上書きしてはいけません。このように、前 time-step で読み込みを行った Memory slot を本当に開放して良いかどうかのフラグ(実際には0~1の連続値なので重み)が “free gate” $f_t^i\;(i=1,…,R)$ です。すなわち、$f_t^i \boldsymbol{w}_{t-1}^{r,i}$ を成分単位で考えて、「$f_t^i w_{t-1}^{r,i}$ $\simeq 1$ $\Leftrightarrow f_t^i \simeq 1$ and $w_{t-1}^{r,i}\simeq 1$」 ならば読み込み済みかつ開放OKなので上書きします。また、「$f_t^i w_{t-1}^{r,i}$ $\simeq 0$ $\Leftrightarrow f_t^i \simeq 0$ or $w_{t-1}^{r,i}\simeq 0$」 ならば 前 time-step で読み込まれていない、または、読み込み済みだったとしても解放フラグが立っていないので上書き不可となります。今、各回の読み込みごとに考えていましたが、全 $R$ 回をひっくるめての使用中(上書き不可)フラグである “retention vector” $\boldsymbol{\psi}_t$を
\begin{align}
\boldsymbol{\psi}_t = \prod_{i=1}^R\big(1-f_t^i\boldsymbol{w}_{t-1}^{r, i}\big)
\end{align}
で定義します。積は成分ごとの積をとります。1からの差を求めた後で積を計算していますので、$R$ 回のうち1度でも上書き可と判断された memory slot は上書き可と判断されます。一方で、使用中(上書き不可) $\psi_t \simeq 1$ と判断されるのは、$R$ 回全てについて上書き不可と判断されたときに限られます。
(2)-2. “usage vector” $\boldsymbol{u}_t$ の構成
(2)-1では、使用中フラグ(正しくは重み)としての $\boldsymbol{\psi}_t$ を考えましたが、前 time-step での読み込みについてしか考えていませんでした。実際には、書き込みが行われた場合には使用中の度合いが高まるはずですし、直前 time-step より前の time-step での状況も考えるべきです。これらを踏まえて、各 Memory slot の使用中度合いを表す重み “memory usage vector” $\boldsymbol{u}_t$ を以下の更新式で定義します。
\begin{align}
\boldsymbol{u}_t &= \big(\boldsymbol{u}_{t-1} + \boldsymbol{w}_{t-1}^w - \boldsymbol{u}_{t-1} \circ \boldsymbol{w}_{t-1}^w \big) \circ \boldsymbol{\psi}_t \\
\boldsymbol{u}_0 &= 0, \;\; \boldsymbol{w}_0^w = 0
\end{align}
$\circ$は成分ごとの積を表します。(…)内第3項目は $\boldsymbol{u}_t$ の各成分が $1$ を超えないように調整するための補正です。$u_t = 1$ に達すると書き込みによる重みの更新は停止しますし、もし $u_t > 1$ となってしまっても更新により値を減少させます。
(2)-3. “allocation weighting” の構成
使用中度合い $\boldsymbol{u}_t$ に基づいて、書き込みを行う Memory slot の address を決めます。基本的には、使用中度合いが低いところに書き込む訳ですが、傾斜をつけます。まず、$\boldsymbol{u}_t$ の成分を値が小さい順に並べた時の index からなるベクトルを $\boldsymbol{\phi}_t$ とします。つまり、
\begin{align}
\boldsymbol{u}_t[\boldsymbol{\phi}_t[1]] \leqq \boldsymbol{u}_t[\boldsymbol{\phi}_t[2]] \leqq
\boldsymbol{u}_t[\boldsymbol{\phi}_t[3]] \leqq \cdots \leqq
\boldsymbol{u}_t[\boldsymbol{\phi}_t[N]]
\end{align}
です。これを用いて、”allocation weighting” $\boldsymbol{a}_t$ を
\begin{align}
\boldsymbol{a}_t[\boldsymbol{\phi}_t[n]] = \big(1-\boldsymbol{u}_t[\boldsymbol{\phi}_t[n]]\big) \prod_{m=1}^{n-1}\boldsymbol{u}_t[\boldsymbol{\phi}_t[m]]
\end{align}
で定義します。積は成分ごとの積をとります。基本的には、$1-\boldsymbol{u}_t$ なので使用済み(書き込み可)の度合いを表す重みとなっています。
以上、(1)と(2)の結果を統合し、write weighting $\boldsymbol{w}_t^w$ を
\begin{align}
\boldsymbol{w}_t^w = g_t^w\big(g_t^a\boldsymbol{a}_t+(1-g_t^a)\boldsymbol{c}_t^w\big)
\end{align}
として更新します。ここで、$g_t^a$ と $g_t^w$ は interface vector $\boldsymbol{\xi}_t$ を通して入力されていたものです。それぞれ、「使用済みフラグ or “key”のどちらに基づいて書き込みを行うか」、「そもそも書き込みを行うか」を制御する gate として働きます。
②Memory への書き込み
write weighting の更新が完了しましたので、Memory に書き込みを行います。ただし、書き込みと同時に古い情報の消去も行います。どの Memory slot を対象とするかの重みづけは、”write weighting” $\boldsymbol{w}_t^w$ で行います。書き込まれるデータは “write vector” $\boldsymbol{\nu}_t$、slot 内のデータをどのようなパターンで消去するかは、erase vector $\boldsymbol{e}_t$ で与えられ、この2つは interface vector を通して入力されています。
Memory 行列 $M_{t-1}$ の消去・書き込みによる更新は以下の式に従って行われます。
\begin{align}
& M_t[n,s] = M_{t-1}[n,s] \big(1-\boldsymbol{w}_t^w[n] \boldsymbol{e}_t[s] \big) + \boldsymbol{w}_t^w[n] \boldsymbol{\nu}_t[s] \\
& \Leftrightarrow M_t = M_{t-1} \circ \big(1-\boldsymbol{w}_t^w \boldsymbol{e}_t^T \big) + \boldsymbol{w}_t^w \boldsymbol{\nu}_t^T
\end{align}
③read weightingの更新
読み込み先の address の選択にも2つの方法があります。つまり、
(1) interface vector を通して入力された “key” をもとに読み込み先 slot を選択、(2)書き込み順に従って slot を選択、の2つです。
(1)については、write weighting の時と同じように “read key” $\{\boldsymbol{k}_t^{r,i}\}_{i=1,2,..,R}$ と “read strength” $\{\beta_t^{r,i}\}_{i=1,2,..,R}$ を用いて、
\begin{align}
\boldsymbol{c}_t^{r, i} = \mathcal{C}\big(M_t, \boldsymbol{k}_t^{r,i}, \beta_t^{r,i}\big) \;\; (i=1,2,...,R)
\end{align}
と計算します。
(2)はやや長いですが、順に説明していきます。
説明の便宜上(2)-2 →(2)-1の順で解説しますが、実装する際は(2)-1 →(2)-2の流れです。
(2)-2. “precedence weighting” の構成
precedence weighting $\boldsymbol{p}_t$ を以下の更新式で定義します。
\begin{align}
& \boldsymbol{p}_0 = 0 \\
& \boldsymbol{p}_t = \Big(1-\sum_{n=1}^N \boldsymbol{w}_t^w[n]\Big)\boldsymbol{p}_{t-1} + \boldsymbol{w}_t^w
\end{align}
$\boldsymbol{w}_t^w$ はすでに①で更新が完了していることに注意してください。②で”強く”書き込みが行われた場合は、$\sum \boldsymbol{w}_t^w \simeq 1$ となるので、前 time-step の情報 $\boldsymbol{p}_{t-1}$ は消去され、現 time-step でどこに書き込みが行われたかが保存されます。書き込みが行われなかった場合は、最後に行われた書き込みの重みが保持され続けます。また、$\boldsymbol{p}_t[n] \leq 1$、$\sum_n \boldsymbol{p}_t[n] \leq 1$ であることはすぐにわかります。
(2)-1. “temporal link matrix” の構成
Memory slot への書き込み順を表す $N$ × $N$ 行列 $L_t$ を構成します。成分単位でみたときに $L_t[n, m] \simeq 1$ であることは 「Memory $M_t$ において slot ‘n’ にある情報は slot ‘m’ にある情報 の次に書き込まれたものである」という関係が表現できるように、更新式を以下で与えます。
\begin{align}
& L_0[n,m]=0 \\
& L_t[n,n]=0 \\
& L_t[n,m]=\big(1-\boldsymbol{w}_t^w[n]-\boldsymbol{w}_t^w[m]\big)L_{t-1}[n,m] + \boldsymbol{w}_t^w[n]\boldsymbol{p}_{t-1}[m]
\end{align}
対角成分は意味をなさないため $0$ で固定します。$0 \leqq L_t[n,m] \leqq 1$ および、$\sum_m L_t[n,m] \leqq 1$ はすぐに確かめられます。$\sum_n L_t[n,m] \leqq 1$ は確かめようとしましたが、示せませんでした。示せた方がおられましたら、コメントいただけると助かります。
(2)-3. “forward/backward weighting” の構成
Memory への書き込み順を考慮した forward/backward weighting $\{\boldsymbol{f}_t^i\}_{i=1,..,R}$ / $\{\boldsymbol{b}_t^i\}_{i=1,..,R}$をやや荒っぽいですが
\begin{align}
&\boldsymbol{f}_t^i[n]=\sum_{m=1}^NL_t[n,m]\boldsymbol{w}_{t-1}^{r,i}[m] \; \Leftrightarrow \; \boldsymbol{f}_t^i=L_t\boldsymbol{w}_{t-1}^{r,i} \\
&\boldsymbol{b}_t^i[m]=\sum_{n=1}^N\boldsymbol{w}_{t-1}^{r,i}[n]L_t[n,m] \; \Leftrightarrow \; \boldsymbol{b}_t^i=L_t^T\boldsymbol{w}_{t-1}^{r,i} \\
\end{align}
で構成します。$\sum_n L_t[n,m] \leqq 1$ が成り立つならば、$0\leqq \boldsymbol{f}_t^i[n] \leqq 1$ および $\sum_n\boldsymbol{f}_t^i[n]\leqq1$ が成立します。$\boldsymbol{b}_t^i$ についても同様です。
以上、(1)~(2)を統合して、read weighting $\{\boldsymbol{w}_t^{i,r}\}_{i=1,…,R}$ を更新します。
\begin{align}
\boldsymbol{w}_t^{r,i}=\boldsymbol{\pi}_t^i[1]\boldsymbol{b}_t^i + \boldsymbol{\pi}_t^i[2]\boldsymbol{c}_t^i + \boldsymbol{\pi}_t^i[3]\boldsymbol{f}_t^i \;\; (i=1,2,...,R)
\end{align}
$\{\pi_t^i\}_{i=1,…,R}$ は interface vector を通して入力されています。
④Memoryからの読み込み
Memory からの読み出しは簡単です。読み出し結果の “read vector” $\{\boldsymbol{r}_t^i\}_{i=1,..,R}$ は
\begin{align}
\boldsymbol{r}_t^i[s] = \sum_{n=1}^N \boldsymbol{w}_t^{r,i}[n]M_t[n,s] \; \Leftrightarrow \; \boldsymbol{r}_t^i = M_t^T\boldsymbol{w}_t^{r,i} \;\; (i=1,2,...,R)
\end{align}
と計算されます。
以上をもって、time-step $t$ の Memory 読み書きが完了します。
Pyhthon – Chainer による実装例
上で説明したロジックの python による実装例を紹介します。オリジナルのコードは、
DNC (Differentiable Neural Computers) の概要 + Chainer による実装
にあるものです。上の解説と比較しやすいように処理を関数にまとめたり、変数名を変えたりしていますが、内容はほぼ同じものです。
ひとつ注意しておきたいのですが、全体像で示した Controller からの出力 $\boldsymbol{h}_t$ は、論文では Controller の最終的な出力だけでなく、hidden layer の出力もすべて統合しているように見えます。しかし簡単のため、ここで使う Controller は 2層程度の簡単なものに限り、hidden layer の出力は Controller の外には取り出しません。
DNC の実装
import numpy as np
import chainer
from chainer import functions as F
from chainer import links as L
from chainer import optimizers, Chain, Link, Variable
# controller of DNC
class SimpleLSTM(Chain):
def __init__(self, d_in, d_hidden, d_out):
super(SimpleLSTM, self).__init__(
l1 = L.LSTM(d_in, d_hidden),
l2 = L.Linear(d_hidden, d_out),
)
def __call__(self, x):
return self.l2(self.l1(x))
def reset_state(self):
self.l1.reset_state()
class DNC(Chain):
def __init__(self, X, Y, N, W, R):
self.X = X # input dimension
self.Y = Y # output dimension
self.N = N # number of memory slot
self.W = W # dimension of one memory slot
self.R = R # number of read heads
self.d_ctr_in = W*R+X # input dimension into the controller
self.d_ctr_out = Y+W*R+3*W+5*R+3 # output dimension from the controller
self.d_ctr_hidden = self.d_ctr_out # dimension of hidden unit of the controller
self.d_interface = W*R+3*W+5*R+3 # dimension of interface vector
self.controller = SimpleLSTM(self.d_ctr_in, self.d_ctr_hidden, self.d_ctr_out)
super(DNC, self).__init__(
l_ctr = self.controller,
l_Wy = L.Linear(self.d_ctr_out, self.Y),
l_Wxi = L.Linear(self.d_ctr_out, self.d_interface),
l_Wr = L.Linear(self.R * self.W, self.Y),
)
self.reset_state()
def reset_state(self):
# initialize all the recurrent state
self.l_ctr.reset_state() # controller
self.u = Variable(np.zeros((self.N, 1)).astype(np.float32)) # usage vector (N, 1)
self.p = Variable(np.zeros((self.N, 1)).astype(np.float32)) # precedence weighting (N, 1)
self.L = Variable(np.zeros((self.N, self.N)).astype(np.float32)) # temporal memory linkage (N, N)
self.Mem = Variable(np.zeros((self.N, self.W)).astype(np.float32)) # memory (N, W)
self.r = Variable(np.zeros((1, self.R*self.W)).astype(np.float32)) # read vector (1, R * W)
self.wr = Variable(np.zeros((self.N, self.R)).astype(np.float32)) # read weighting (N, R)
self.ww = Variable(np.zeros((self.N, 1)).astype(np.float32)) # write weighting (N, 1)
# utility functions
def _cosine_similarity(self, u, v):
# cosine similarity as a distance of two vectors
# u, v: (1, -) Variable -> (1, 1) Variable
denominator = F.sqrt(F.batch_l2_norm_squared(u) * F.batch_l2_norm_squared(v))
if (np.array_equal(denominator.data, np.array([0]))):
return F.matmul(u, F.transpose(v))
return F.matmul(u, F.transpose(v)) / F.reshape(denominator, (1, 1))
def _C(self, Mem, k, beta):
# similarity between rows of matrix Mem and vector k
# Mem:(N, W) Variable, k:(1, W) Variable, beta:(1, 1) Variable -> (N, 1) Variable
N, W = Mem.shape
ret_list = [0] * N
for i in range(N):
# calculate distance between i-th row of Mem and k
ret_list[i] = self._cosine_similarity(F.reshape(Mem[i,:], (1, W)), k) * beta
# concat horizontally because softmax operates along the direction of axis=1
return F.transpose(F.softmax(F.concat(ret_list, 1)))
def _u2a(self, u):
# convert usage vector u to allocation weighting a
# u, a: (N, 1) Variable
N = u.shape[0]
phi = np.argsort(u.data.flatten()) # u.data[phi]: ascending
a_list = [0] * N
cumprod = Variable(np.array([[1.0]]).astype(np.float32))
for i in range(N):
a_list[phi[i]] = cumprod * (1.0 - F.reshape(u[phi[i]], (1, 1)))
cumprod *= F.reshape(u[phi[i]], (1, 1))
return F.concat(a_list, 0)
# operations of the DNC system
def _controller_io(self, x):
# input data from the Data Set : x (1, X) Variable
# out-put from the controller h is split into two ways : v (1, Y), xi(1, W*R+3*W+5*R+3) Variable
chi = F.concat([x, self.r], 1) # total input to the controller
h = self.l_ctr(chi) # total out-put from the controller
self.v = self.l_Wy(h)
self.xi = self.l_Wxi(h)
# interface vector xi is split into several components
(self.kr, self.beta_r, self.kw, self.beta_w,
self.e, self.nu, self.f, self.ga, self.gw, self.pi
) = F.split_axis(self.xi, np.cumsum(
[self.W*self.R, self.R, self.W, 1, self.W, self.W, self.R, 1, 1]), 1) # details of the interface vector
# rescale components
self.kr = F.reshape(self.kr, (self.R, self.W)) # read key (R, W)
self.beta_r = 1 + F.softplus(self.beta_r) # read strength (1, R)
# self.kw : write key (1, W)
self.beta_w = 1 + F.softplus(self.beta_w) # write strength (1, 1)
self.e = F.sigmoid(self.e) # erase vector (1, W)
# self.nu : write vector (1, W)
self.f = F.sigmoid(self.f) # free gate (1, R)
self.ga = F.sigmoid(self.ga) # allcation gate (1, 1)
self.gw = F.sigmoid(self.gw) # write gate (1, 1)
self.pi = F.softmax(F.reshape(self.pi, (self.R, 3))) # read mode (R, 3)
def _up_date_write_weighting(self):
# calculate retention vector : psi (N, 1)
# here, read weighting : wr (N, R) must retain state one step former
psi_mat = 1 - F.matmul(Variable(np.ones((self.N, 1)).astype(np.float32)), self.f) * self.wr # (N, R)
self.psi = Variable(np.ones((self.N, 1)).astype(np.float32))
for i in range(self.R):
self.psi = self.psi * F.reshape(psi_mat[:,i],(self.N,1)) # (N, 1)
# up date usage vector : u (N, 1)
# here, write weighting : ww (N, 1) must retain state one step former
self.u = (self.u + self.ww - (self.u * self.ww)) * self.psi
# calculate allocation weighting : a (N, 1)
self.a = self._u2a(self.u)
# calculate write content weighting : cw (N, 1)
self.cw = self._C(self.Mem, self.kw, self.beta_w)
# up date write weighting : ww (N, 1)
self.ww = F.matmul(F.matmul(self.a, self.ga) + F.matmul(self.cw, 1.0 - self.ga), self.gw)
def _write_to_memory(self):
# erase vector : e (1, W) deletes information on the Memory : Mem (N, W)
# and write vector : nu (1, W) is written there
# write weighting : ww (N, 1) must be up-dated before this step
self.Mem = self.Mem * (np.ones((self.N, self.W)).astype(np.float32) - F.matmul(self.ww, self.e)) + F.matmul(self.ww, self.nu)
def _up_date_read_weighting(self):
# up date temporal memory linkage : L (N, N)
ww_mat = F.matmul(self.ww, Variable(np.ones((1, self.N)).astype(np.float32))) # (N, N)
# here, precedence wighting : p (N, 1) must retain state one step former
self.L = (1.0 - ww_mat - F.transpose(ww_mat)) * self.L + F.matmul(self.ww, F.transpose(self.p)) # (N, N)
self.L = self.L * (np.ones((self.N, self.N)) - np.eye(self.N)) # constrain L[i,i] == 0
# up date prcedence weighting : p (N, 1)
self.p = (1.0 - F.matmul(Variable(np.ones((self.N, 1)).astype(np.float32)), F.reshape(F.sum(self.ww),(1, 1)))) * self.p + self.ww
# calculate forward weighting : fw (N, R)
# here, read wighting : wr (N, R) must retain state one step former
self.fw = F.matmul(self.L, self.wr)
# calculate backward weighting : bw (N, R)
self.bw = F.matmul(F.transpose(self.L), self.wr)
# calculate read content weighting : cr (N, R)
self.cr_list = [0] * self.R
for i in range(self.R):
self.cr_list[i] = self._C(self.Mem, F.reshape(self.kr[i,:], (1, self.W)), F.reshape(self.beta_r[0,i],(1, 1))) # (N, 1)
self.cr = F.concat(self.cr_list, 1) # (1, N * R)
# compose up-dated read weighting : wr (N, R)
bcf_tensor = F.concat([
F.reshape(F.transpose(self.bw), (self.R, self.N, 1)),
F.reshape(F.transpose(self.cr), (self.R, self.N, 1)),
F.reshape(F.transpose(self.fw), (self.R, self.N, 1))
], 2) # (R, N, 3)
self.pi = F.reshape(self.pi, (self.R, 3, 1)) # (R, 3, 1)
self.wr = F.transpose(F.reshape(F.batch_matmul(bcf_tensor, self.pi), (self.R, self.N))) # (N, R)
def _read_from_memory(self):
# read information from the memory : Mem (N, W) and compose read vector : r (W, R) to reshape (1, W * R)
# read weighting : wr (N, R) must be up-dated before this step
self.r = F.reshape(F.matmul(F.transpose(self.Mem), self.wr), (1, self.R * self.W))
def __call__(self, x):
self._controller_io(x) # input data is processed through the controller
self._up_date_write_weighting()
self._write_to_memory() # memory up-date
self._up_date_read_weighting()
self._read_from_memory() # extract information from the memory
self.y = self.l_Wr(self.r) + self.v # compose total out put y : (1, Y)
return self.y
使用例
使用例も載せますが、DNC (Differentiable Neural Computers) の概要 + Chainer による実装にあるものと内容は同じです。
固定長の one-hot ベクトルをランダムな個数入力し、入力完了後に、出力として入力データを echo させます。echo させたデータと入力データの2乗誤差を loss として、1セットの入力ごとに学習を行います。学習が終了したら、次セットの one-hot ベクトルを入力します。
import dnc
import numpy as np
import chainer
from chainer import functions as F
from chainer import links as L
from chainer import optimizers, Chain, Link, Variable
def onehot(x, n):
ret = np.zeros(n).astype(np.float32)
ret[x] = 1.0
return ret
X = 5
Y = 5
N = 10
W = 10
R = 2
model = dnc.DNC(X, Y, N, W, R)
optimizer = optimizers.Adam()
optimizer.setup(model)
n_data = 10000 # number of input data
loss = 0.0
acc = 0.0
acc_bool = []
for data_cnt in range(n_data):
loss_frac = np.zeros((1, 2))
# prepare one pair of input and target data
# length of input data is randomly set
len_content = np.random.randint(3, 6)
# generate one input data as a sequence of randam integers
content = np.random.randint(0, X-1, len_content)
len_seq = len_content + len_content # the former is for input, the latter for the target
x_seq_list = [float('nan')] * len_seq # input sequence
t_seq_list = [float('nan')] * len_seq # target sequence
for i in range(len_seq):
# convert a format of input data
if (i < len_content):
x_seq_list[i] = onehot(content[i], X)
elif (i == len_content):
x_seq_list[i] = onehot(X-1, X)
else:
x_seq_list[i] = np.zeros(X).astype(np.float32)
# convert a format of output data
if (i >= len_content):
t_seq_list[i] = onehot(content[i - len_content], X)
model.reset_state() # reset reccurent state per input data
# input data is fed as a sequence
for cnt in range(len_seq):
x = Variable(x_seq_list[cnt].reshape(1, X))
if (isinstance(t_seq_list[cnt], np.ndarray)):
t = Variable(t_seq_list[cnt].reshape(1, Y))
else:
t = []
y = model(x)
if (isinstance(t, chainer.Variable)):
loss += (y - t)**2
acc_bool.append(np.argmax(y.data)==np.argmax(t.data))
if (np.argmax(y.data)==np.argmax(t.data)): acc += 1
if (cnt+1==len_seq):
# training by back propagation
model.cleargrads()
loss.grad = np.ones(loss.shape, dtype=np.float32)
loss.backward()
optimizer.update()
loss.unchain_backward()
# print loss and accuracy
if data_cnt < 50 or data_cnt >= 9950:
print('(', data_cnt, ')', acc_bool, ' :: ', loss.data.sum()/loss.data.size/len_content, ' :: ', acc/len_content)
loss_frac += [loss.data.sum()/loss.data.size/len_seq, 1.]
loss = 0.0
acc = 0.0
acc_bool = []
test 結果
10000回繰り返した時の結果です。
[ ]内の bool 値は、出力べクトルで最大値を1に、その他を0に振り直したものが、入力値と一致するかを bool 値で表したものです。
・最初の20回の結果
( 0 ) [True, False, False] :: 0.197543557485 :: 0.3333333333333333
( 1 ) [False, False, False, False] :: 0.209656882286 :: 0.0
( 2 ) [True, False, False] :: 0.172263367971 :: 0.3333333333333333
( 3 ) [False, True, True] :: 0.185363880793 :: 0.6666666666666666
( 4 ) [True, True, True, True] :: 0.157090616226 :: 1.0
( 5 ) [False, False, False, False, False] :: 0.191528530121 :: 0.0
( 6 ) [True, False, False, False, False] :: 0.175649337769 :: 0.2
( 7 ) [False, False, False, True, True] :: 0.173387451172 :: 0.4
( 8 ) [True, False, True, True] :: 0.150813746452 :: 0.75
( 9 ) [False, True, False] :: 0.163899072011 :: 0.3333333333333333
( 10 ) [False, False, False, False, False] :: 0.183468780518 :: 0.0
( 11 ) [True, False, True, False] :: 0.152743542194 :: 0.5
( 12 ) [False, False, True, False] :: 0.170574557781 :: 0.25
( 13 ) [False, True, False, True, False] :: 0.161617393494 :: 0.4
( 14 ) [False, False, False, False] :: 0.168220555782 :: 0.0
( 15 ) [False, False, False] :: 0.167814588547 :: 0.0
( 16 ) [False, True, False, False] :: 0.158575570583 :: 0.25
( 17 ) [False, False, False, False] :: 0.165678012371 :: 0.0
( 18 ) [False, False, False] :: 0.165241924922 :: 0.0
( 19 ) [False, True, False] :: 0.143808253606 :: 0.3333333333333333
・最後20回の結果
( 9980 ) [True, True, True, True] :: 0.000208107382059 :: 1.0
( 9981 ) [True, True, True, True, True] :: 0.000164349582046 :: 1.0
( 9982 ) [True, True, True, True, True] :: 0.000122650777921 :: 1.0
( 9983 ) [True, True, True] :: 0.000181751077374 :: 1.0
( 9984 ) [True, True, True, True, True] :: 0.000318505689502 :: 1.0
( 9985 ) [True, True, True, True, True] :: 0.00023639023304 :: 1.0
( 9986 ) [True, True, True, True, True] :: 0.000988183766603 :: 1.0
( 9987 ) [True, True, True, True, True] :: 0.000226851813495 :: 1.0
( 9988 ) [True, True, True] :: 0.000401457709571 :: 1.0
( 9989 ) [True, True, True, True] :: 0.000256504747085 :: 1.0
( 9990 ) [True, True, True, True, True] :: 0.000165695995092 :: 1.0
( 9991 ) [True, True, True, True] :: 0.000123940082267 :: 1.0
( 9992 ) [True, True, True, True, True] :: 0.000351718552411 :: 1.0
( 9993 ) [True, True, True, True] :: 0.000147357559763 :: 1.0
( 9994 ) [True, True, True, True] :: 0.000173216045368 :: 1.0
( 9995 ) [True, True, True, True] :: 0.000108330522198 :: 1.0
( 9996 ) [True, True, True, True] :: 0.00016659933608 :: 1.0
( 9997 ) [True, True, True] :: 0.000255667418242 :: 1.0
( 9998 ) [True, True, True] :: 0.000280433737983 :: 1.0
( 9999 ) [True, True, True, True, True] :: 0.000443447269499 :: 1.0
完璧に正解しています。20回分しか載せていませんが、最後の100回中でFalseは0回でした。ただし、他の手法と比較まではしていないので、DNC だからこそなのかは不明です。
今回はロジックの紹介が目的だったのでここまでとします。
参考URL
・Chainerの実装例はこのページのものを使わせていただきました
DNC (Differentiable Neural Computers) の概要 + Chainer による実装
・今回はGPU、バッチ処理などは考えてませんでしたが下のページが参考になるかと思います
(Chainer) DNC(Differentiable Neural Computers)で文字列の学習&生成
・Tensor Flowでの実装もあるようです
https://github.com/Mostafa-Samir/DNC-tensorflow
・LSTMの解説はここがわかりやすいです
- JuliaでPyPlot.jl (matplotlib) を使ったヒストグラムのアニメーションを効率的に作成する
- 栄養素多次元ベクトル間の類似度を計算する
- Kerasのbackendが、思い通りならない時のメモ
- scikit-learnでSVMのパラメータを調節してみた話
- matplotlibでよく使う手続き
- Djangoのモジュールをインタープリタで読み込む
- PythonでRandom Forestを使う
- 文字と濁点・半濁点が分かれていて,それらを結合したい時
- NLTKを使って情報利得を計算
- PythonとTkinterを使ってプログラミング
- pythonのunix-time <-> datetime の変換
- Pythonの-mオプションを使えばフィルターの管理が楽
- doctest.testfile()を使ってドキュメント兼テストコードを作成
- カレントディレクトリをwebサーバで公開
- ニコニコ生放送のコメントを取得する
- tkinterを使ったアプリケーションをcx_freezeで実行ファイルにする
- ネスト解消のためのポリモーフィズムについて
- Google+で見かけたコメントに,「Pythonでリストの何番目の要素が最大/最小か求める簡単な方法は?」というのがあった.真っ先に思いついたのが1行目のコードなのだけれど,2行目の方がより良いかな?
- 日本語を含むUnicodeのJSON文字列を得る.
- Pythonでテストする際には何を使っているか?
- JSON変換するクラス
- FlaskでBlueprintを使ってControllerを別に分けてみる
- Pyramidで遊ぶ
- Pythonでconstant
- プログラミングの師匠募集
- ドミニオン圧縮プレイをモンテカルロ法で分析
- Pythonでテストを書いてプロファイル取ったりカバレッジ調べたり
- Pythonにおける例外のメッセージ
- 使ってないポートを取得する Python版
- 文字から Unicode を算出する
- どうやって情報収集してますか?
- Google App Engineのwebapp.RequestHandlerはputとdeleteを受けるときパラメータを取得できない
- 空のディレクトリに.gitkeepを配置するコマンドラインツール
- php でも ruby でも python でも perl でも動く Hello World
- amazon linux上で、python2.7用にMySQL-pythonをコンパイル・インストール
- # 文字列の文字コードを返す関数
- ImportError: cannot import nameを解消する
- JSON の整形
- pythonインタプリタ起動時に良く使うmoduleをimportする
- IPython起動時にスクリプトを自動的に読み込む
- UNIXでPython,Ruby,Perl,Node.jsのバージョン管理環境構築
- unicodeとdecodeとencodeについて実験した
- エロ動画フォルダからサムネイルをopencvで楽に作る
- appcfg.pyでデプロイしたファイルをダウンロードする
- OS X LionでPython開発環境を作成
- Django+MongoDB開発環境整備 (書き途中)
- List 操作メモ書き
- 引数のデフォルト値はimmutableなものにする
- すっと頭に再帰が浮かぶようになりたい
- Google App Engineのpythonのバージョンが噛み合わない問題について
- Pythonで数値計算
- 辞書のキーにタプルを使って、複数キー項目
- Pythonでflatten
- Xcode用自動ビルドバージョンインクリメントスクリプト
- Pythonでtest.pyを作るな!
- ファイル監視にwatchdogがかなり便利な件
- Flask on dotCloud でハマったところ
- easy_installでインストールしたパッケージを削除する方法
- pythonbrewでの複数バージョン&ライブラリ管理メモ
- Python de BDD (Lettuceで)
- CentOS 5.4 に Python 2.7.3 を install
- pip のコマンド/オプションのタブ補完を有効にする
- boto で S3 アップローダー
- 「オープンソースで学ぶ社会ネットワーク分析」におけるpythonコマンド
- 一度だけ評価するプロパティ
- SQLAlchemy ORM でクエリ生成の高速化
- Django の django-admin.py でパスを通しても command not found の時
- Django でデコレータを使って View への preprocess を実装してみる
- Pythonで関数合成
- Sublime Text で pythonbrew
- Paver を使ったスクリプティング – コマンド定義編
- Paver 応用編 – プロジェクトに組み込む
- Paver を使ったスクリプティング – ファイル操作編
- Paver を使ったスクリプティング – 外部コマンド編
- VPC with a Single Public Subnet Only を boto で自作
- 指定時間内に関数が終了しなかったら何かするデコレータ
- はじめてのDjangoで躓いた箇所まとめ
- BitbucketのOAuth:access token取得まで
- python でモック – mox の使い方
- Djangoのコマンド補完設定
- Python の Singleton
- すごく簡単なアルゴリズムがphpで書けなくてつらい
- Unix Domain Socket サーバーを作る
- プログラミングの学習に役立つウェブサイト
- DMMのAPIを叩くクラス
- letを作ってLet’s 1行プログラミング
- Setup modern Python environment with Homebrew
- Pygments.rb を使う
- Mailmanのwithlistコマンドによる一括設定変更
- ハイフン区切り形式の MAC アドレスを取得する -1 liner 編-
- Zsh上で使用頻度の高いコマンド一覧を表示する
- Python で複素数を扱う
- PyQt4導入
- 重み付け乱択
- Pythonのキーワード引数も含めてmemoizeしたい
- Ubuntuで個人環境にpythonパッケージをインストール
- pythonでUTF8のテキスト処理
- NLTKを使って文書分類用データをサクッと作る
- 最速最強Webサーバーアーキテクチャ
- 「Sublime Text 2で全角スペースをハイライト表示するプラグインを作る」に設定でオンオフ出来るようにしてみた。
- SublimeLinterにD言語(他の任意の言語)を追加してハイライト出来るようにする
- pythonの文法チェック
- defaultdictを使って,ネストされた辞書を作る
- SQLAlchemy BaseModel
- Python で Amazon CloudFront の Signed URL を発行する
- PyOpenCL Version 2012.2の話 第1弾
- TortoiseHgのファイルビューをもう少し改造してみる
- Docutils と Ruby で快適ドキュメント生活
- numpyの練習1
- スクリプト言語で実行可能なファイルを作る
- パラメトリックとノンパラメトリックの狭間
- bing search apiの使い方
- Flaskのカスタマイズについて
- PyOpenCLでアプリケーション(PIL & PyOpenGL)
- pytestを実戦投入してみた
- いとも簡単にMac OS XにSciPyをインストールする
- 実務でRandomForestを使ったときに聞かれたこと
- gaffer + fabric で簡単デプロイ環境
- Theano の 基本メモ
- 実行スクリプトからの相対パスでファイルにアクセスする.
- CoffeeScriptとJavaScriptやPythonやRubyの文法の比較
- これ知らないプログラマって損してんなって思う汎用的なツール
- 【まとめ】これ知らないプログラマって損してんなって思う汎用的なツール 100超
- Python での shift_jis と shift_jis_2004 について
- リストの中のインスタンスのもつ値で検索
- 日時 ⇔ 文字列
- ファイルの更新を検知して、自動的にCoffeeやSassをコンパイルしたり、ブラウザをリロードしたりするスクリプト
- curlを捨ててhttpieを使おう
- 都道府県のリストをサクッと出力するだけのCLIツール
- Python でホスト名を取得する
- MinGWでVimをビルド。(+lua,+python)
- 複数の辞書のマージ方法いろいろ
- LinuxでPythonをビルドするときの –enable-shared オプションについて
- pythonで二分探索
- Qiita API の Python ラッパーを作った
- Haskellソース編集後、保存と同時にghciにロードするSublime Text 2プラグイン
- botの一部の機能として自動フォローやランダムツイート
- kobitonote.py – Kobitoで編集したアイテムをEvernoteに同期保存
- Command Line で使用しているツールまとめ vol.5
- Flaskを1ヶ月間使ってみた感想
- Pythonのfeedparserをつかってみる。
- Pythonで文字列 <-> 日付(date, datetime) の変換
- Qiitaの投稿をGitHubにバックアップ
- Pythonプログラムのプロセス名を設定する
- Xcodeプロジェクト内のクラスの依存関係を図示する
- Python スクリプト実行中にシェルを起動する
- SQLAlchemyでINNER JOINする方法
- pymongoで正規表現
- Windows + Python 3.3 で watchdog をインストールする
- プログレスバー表示させたいなぁ
- Pythonでconfig.iniを使う
- Twistedを利用してお手軽にDNSサーバーを構築する
- 今流行りのエディタSublimeText2を使って、AOJで競技プログラミングを楽しもう
- PythonでN-Gram
- Parse.com REST APIを使ったAPN(remote notification)を試した
- Apache + mod_wsgi で複数の WSGIPythonPath を設定する
- クラスにバインディングしてYAMLの読み書き
- SublimeText2とSublimeLinter – Python3の構文チェック –
- Pinaxの概要について簡単なまとめ #djangoja
- アクセサを一つのメソッドにまとめる
- PythonのPILで書き出したGIF画像をつなげて動画GIFを作る
- Pythonで画像をWavelet変換するサンプル
- TheanoをMac OS Xにhomebrewでinstallする方法
- BitbucketのPrivate repositoryをタダでCIする
- Python3.3 + mod_wsgi3.4 をさくらVPS(CentOS)にインストールした時に少しハマったので振り返りメモ
- [Python2]日付文字列→UnixTime→日付文字列
- Install Theano on Ubuntu 12.04
- Vim (with python) で json を整形
- tweepy2導入
- PyramidのテンプレートをMakoに切り替える
- propertyを使うときはobjectを継承したクラス (new-style class) を使う
- redis-pyの使い方 辞書とか
- コマンドラインからtwitter投稿
- 標準入力の受け取りのその1
- Python – MP3ファイルにタグづけ
- ファイルを保存した瞬間ユニットテストを実行
- Python – Django css・jsをコンプレス
- requestsが便利
- リスト内に特定の要素があるかでif分岐
- Pythonの辞書 初心者向けガイド
- fabricのお役立ちコンテキストマネージャ
- FlaskでLast-Modifiedを設定する最も簡単な方法
- Flaskのrequest.argsでパラメータの処理について
- ブラウザでPython:Brythonのすすめ
- MeCab解析済みの結果を読み取るcorpus readerを書いた
- PythonでCIDR表記を変換
- multiprocessingで並列処理
- ログ監視スクリプト
- Ubuntu12.04にPython3.3をインストール
- 今更 virtualenv を使ってみる
- lxmlでブロークンなXMLをパースする
- 永続性が必要な時は hash() を使うな!
- Fabricタスクの途中で実行ユーザーを切り替えたいときはsettingsコンテキストマネージャ
- pythonからfluentdを使う
- Vimのpython3で日本語表示するの面倒くさすぎワロタwww
- MochaでブラウザテストをするためのWebサーバ
- 行数あたりの価値が高いコード
- Python で日付の計算
- コマンドラインで XLSX を CSV に変換する
- ファイルの中身を簡単な暗号化(Python)
- Pythonで文字列からさくっと文字の出現頻度を数えるには?
- GAE/Pyのdev_appserver.pyで外部(localhost以外)から接続可能にするには
- RubyとPythonじゃデフォルト引数の値が評価されるタイミングが違うんだぜ
- Python 3の print() で UnicodeEncodeError を回避するデコレータ
- Google Calendar から日報を生成する
- MeCab 使ってよみがなを取ってくる
- PyCharm での type hinting を使いこなす
- Django – Apache mod_wsgi virtualhost デプロイ
- ブラウザで保存したファイルをダウンロード元サイト別にフォルダ分け
- BitBucket に Sphinx ドキュメントを push したら自動的にウェブサーバーに反映するようにしてみた
- Sublime Text 2でPythonの開発環境を整える
- SciPyとmatplotlibのインストール(Python)
- Twistedを利用してメールサーバーを立てる
- SciPy+matplotlibで3D散布図を作成(Python)
- CentOS 6.x x86_64 Python-2.7.4 rpmパッケージ作成
- pythonの例外でstack traceを表示する
- lambdaでif-elifを楽に書く
- Python, SciPy, matplotlibのインストール(Windows)
- Python 3の正規表現で \d を使うな!
- CentOS6.4でPython2.7.3でApacheでmod_wsgiでDjango
- f2pyを使ってfortranでpythonのモジュールを書く
- ネットワークインタフェースに振られた IPv4 アドレスをコードで取得する (Linux)
- sphinx+mathjaxでマクロをusepackageみたいに読み込む
- iPythonでオートフォーマットされた出力の改行場所を変える
- Python3.3.1 in BottleでGoogle Custom Search APIを使って検索するだけのアプリケーションを作る
- Pythonでリフレクション
- pythonでhtml中の相対リンクを絶対リンクに書き換える(lxml)
- Pythonスクリプトからjarファイル中のクラスを直接importする
- class sklearn.naive_bayes.MultinomialNB(alpha=1.0, fit_prior=True, class_prior=None)のメモ
- pythonの軽量framework, Bottle
- GAE上でのTwilio
- リプ爆撃
- Twilogから過去ツイートを取ってきてbotを作り、昔の自分をTLに再現させるでござるの巻(その1)
- Macを使うにあたっての落とし穴回避(Linuxユーザ向け?)
- PyQCheckというPythonでQuickCheckが行えるライブラリをPyPIに登録した。
- multiprocessing vs threading
- MacにPythonをインストールするときのメモ
- Webアプリケーションのパフォーマンス測定ツールFunkload…
- python データーを圧縮してsqliteへ書き込む
- Zabbix APIをたたく (1.8, 2.0)
- emacs-jediのinstall
- Twilogから過去ツイートを取ってきてbotを作り、昔の自分をTLに再現させるでござるの巻(その2)
- テストデータはsetUpで宣言するべき幾つかの理由
- pythonをはじめるためのリンク
- a()とa.__call__()は等価ではない
- Python で簡易 SMTP サーバを立てる
- ログを色つけて見やすくする君
- 【LDAP環境構築:7】 Pythonでユーザー追加・検索・変更・削除まで
- classの__str__を、lambdaを使ってもっと簡単に書こう!
- MacにDjangoをインストール
- ChaSenのインストール
- CPythonからJavaのクラスを呼び出す(Py4J)
- テキストファイルのエンコーディングを自動判定して処理する
- pythonのsqlite3 に日本語(マルチバイト文字列)を格納する
- pythonのsqlite3でインメモリDBをセーブ/ロードする
- Python+FlaskなwebアプリをJenkinsでウイーン
- pyramidチュートリアル メモ (bankaccount)
- ローカルのipアドレスを取得
- macbook air Mid2013 にインストールしたアプリや開発環境のメモ(php,ruby,node.js,python など)
- PySideのスロットを定義する際の注意
- はてなブックマークのお気に入りユーザーで、既にアクティヴではないユーザーを調べる
- フォーマット文字列内での波括弧のエスケープ
- Pythonの数値計算ライブラリ NumPy入門
- PySideのスロットを定義する際の注意(2)
- vim7.3(+python2.4)をソースからインストール(Gundo.vimに対応)
- PythonからMySQLを使う
- コンソールへの出力を上書きしてゆく方法
- Pythonzとvirtualenvでクリーンなpython環境
- WEBブラウザからコマンドを実行する君作った
- ATND APIをPythonで叩くときのtips
- pytestを使ってカバレージとか取りながら分割実行してテスト実行時間を短縮する
- Pythonのクラス定義のファイルの場所を知る。
- encodeするのがめんどくさい
- はじめてのpython① pythonbrewで環境構築&HelloWorld!!
- Google Cloud Messaging for Chrome を使ってサーバからChrome拡張にメッセージを送る
- Pythonでコマンドライン引数にサブコマンドを指定する
- WEBブラウザから検索やコマンド実行をする君2
- 多重ループを一気に抜ける
- Pythonでgitのコミットログをパースしてみよう!
- Pythonで再帰的にファイル・ディレクトリを探して出力する
- 『Macで日本語ファイルをgitにコミットするのやめて><』とりあずMacとLinuxで互換性のない日本語ファイルを探すスクリプト書いた
- Flaskで大きいアプリケーションを作るときのTips
- 1分でVim+Pythonのテスト環境をつくる
- 深イイ意味など全くない並列処理 in Python
- 電波状況が悪い時にiPadにファイルを転送する
- matplotlibでstacked histogram (積み上げヒストグラム) を書く
- pipでtweepyをインストールしてAPI1.1に対応させて使う
- python2.7.3のcsvモジュールを使う時の文字エンコード
- Pythonで”coding: utf-8″ 書くの面倒くさいのでShellscriptでなんとかする
- Pythonで関数合成と適用的な
- pythonでフォルダ内のファイル名をrenameして整理したメモ
- 【作業メモ】Amazon Linuxにmatplotlibとnumpy入れるまで
- Appiumを使ってスマートフォンアプリのテストを自動化する – Python編
- matplotlibで欲しいグラフの書き方がわからない時はgalleryを見ると便利
- web2pyのadminのpassword
- PIL(Python Imaging Library)で、点を描画するサンプル。
- Mac OS Marvericks にHomebrewを使ってpyenv,pythonの環境設定を行うメモ
- PIL(Python Imaging Library)で、画像をセピア調に変換する
- PySide – モードレスダイアログを表示中にバックグラウンドで何らかの処理を行う
- Python用ケムインフォマティクスツールRDKitのインストール
- バックアップにBakthatいいんじゃね?
- Pythonのreduceを使うとちょうはかどる話
- Pythonにおける継承の基本的なお話(初心者向け)
- Pythonの古いクラスと新しいクラスの話
- unittest.mock
- MySQL Workbench の mwb ファイルから sql ファイルに自動変換
- ipythonの便利な使い方
- Propertyデコレータを使う?
- MySQLの全DBに対してmysqldumpするスクリプト
- pyramidチュートリアル メモ (single_file_tasks)
- Sublime Text 2で任意のテキストを常にハイライト表示するプラグインを作る
- 時間計測
- [python] lassieでWebページのメタデータをサクっととってくる
- オブジェクトの属性を取得
- classをクロージャーっぽく動的に宣言する
- MySQLdbの優雅な使い方
- PythonのiteratorとRubyのEnumeratorを比較してみた
- ImportError: No module named と言われた時の対応方法
- LXCをブラウザで操作できるLXC Web Panelが素晴らしかった件
- 非エンジニア向けのMercurial入門
- blogの更新を監視して結果をtwitterに投げたり、interviewsの回答を催促したり
- Pythonのモジュール例外の表示を分かりやすくする
- CentOS 6.4 で python から MySQL につなぐ
- EmacsのPython開発環境構築メモ
- Pythonでオブジェクトの内部構造を知る方法
- HMAC 方式を使用してハッシュ値を生成する。
- MySQLdbでイテレータ
- Bottle を使用したウェブアプリケーション(1)
- IPythonのデバッガー(ipdb)の使い方
- Pythonの例外クラスのインスタンスを直接、例外クラスの引数にするな!
- lambdaを使う例
- ベータ分布をPythonで書く
- Python 3のsorted関数と比較関数
- Pythonでバイナリファイルを作成する
- AKBメンバーのGoogle+ IDを一気に取得する
- サクラエディタでスクリプトをデバッグする
- Python3.3.1 + Bottle でWebアプリケーション(1) – テンプレートエンジンをjinja2に変更する
- botで天気予報をtweet
- 値が空だったら初期化したい(python)
- 【失敗】Stack OverflowのClone AskbotをCentOS6.4にインストール
- redis.pyのConnectionPoolの実装よんだ
- リスト内包表記でifの判定
- Gmailの件名をtwitterに投稿
- 標準入力で受け取ったりとかコマンドライン操作からGmailの送信
- python 現在時刻取得
- scikit-learnのParallelで並列処理
- 時系列顧客ロイヤリティの算出
- matplotlibでグラフを動的に生成して、reporlabでPDFに埋め込む
- Pythonで逆アセンブラする
- OpenCV2.4(+python)を手っ取り早くOS Xにインストールしてサンプルを試してみる
- AKB48 Google+投稿をゲットする
- eggパッケージのインストールとアンインストール
- すぐにできるページランク計算(全行コメント解説つき)
- MeCabをPython3上から使えるようにする
- matplotlibやpylabで論文向きの白黒のグラフをプロットする
- pythonモジュールの一覧表示
- djangoコマンドの二重起動を防止する
- Scipyでの疎行列の扱い
- OptParserの使い方
- pycharmのショートカット
- Pythonで単語の数え上げとかするならCounterを使うと便利なはなし
- 1分でPython&CSSセレクタによるスクレイピングを実現する
- web アプリケーションで matplotlib の図を表示する
- MacでPython環境構築メモ
- pythonのfluentdではまりどこ??
- pythonのSimpleHTTPServer
- fabric でエラー時のロールバック処理をする
- RubyとPythonとPerlで正規表現の速さを比べてみた(2013年版)
- ランダム文字列生成(Python)
- Python for Data Analysis Chapter 2
- Python for Data Analysis Chapter 3
- Python for Data Analysis Chapter 4
- virtualenvごとにPYTHONPATHを切り替える
- Mac(Mountain Lion)にPython環境を構築
- matplotlibのインストール(Python 3.3.2)
- py2exeとsetuptoolsの連携
- Mountain Lion環境への「virtualenv」と「pythonz」のインストール手順 + 利用方法
- urllib.parse.quote関数使用時の注意
- GoogleAppEngine/PythonでDjangoを使う方法
- 三角関数とか使ったメモ
- OSXでのCython実行方法メモ
- 今どきのPythonのライブラリ自作からPyPIへの登録
- 実行時間とかメモリ使用量とか気にしてみようと思ったから
- pythonbrewでPythonインストールしてFlaskをWSGIサーバで動かすまで
- Python で画像フォーマット
- Pythonのクラスで__eq__などを汎用的に実装する
- Mac に matplotlib をインストールする手順
- Python3をさくらサーバー(FreeBSD)にインストール
- ファイルの削除にrmコマンドは使わないようにした
- ruby は インスタンス変数の確認に instance_variable_defined? を使う
- twitter利用時間をを基準にざっくりと推定睡眠時間を計算する
- Djangoのモデルでchoice属性で値を限定しているフィールドの「名前」を取得する方法
- watchmedo(watchdog)を使ってエディタでファイルを保存する度にテストを実行する時の設定
- Celeryの非同期処理中に起きたエラーをメールで通知
- Pythonライブラリのダウンロード数表示バッジを生成
- virtualenvでpython
- randintに気をつけよう
- Pythonで日本語メールを送る方法をいろいろ試した
- MarvericksにしてPILのインストールがコケる件
- Django管理サイトのチューニング
- AnacondaでPython3.3
- MacOSX Mavericks(10.9)にhomebrewを使ってDjangoの開発環境を整える
- Python 3.3でmatplitlibとpylabを使おうとしたら RuntimeError: Python is not installed as a frameworkというエラーが発生したときの解決方法
- GensimPy3を使って小説家になろうのトピックモデルを解析
- `return self`でメソッドチェーン
- Python3.3.1でcChardetとpython3-chardetを使ったメモ
- pythonのデフォルトエンコーディングをutf-8に変更する
- utf-8を含む文字列を含む配列をprintしたときに文字化けする問題
- importについて
- TOPIX の時系列を表示する
- zip関数の挙動を少し試した
- django の dumpdata コマンドの代替
- scikit-learnでCross Validation
- TOPIXの時系列を pickle, csv, Excel形式で保存する
- 機械学習ライブラリ SHOGUN入門
- Python初歩からの学習メモ1
- Python初歩からの学習メモ2
- #python pythonの日本語のシンタックスエラー回避
- python-sphinxで表を書く時は csv-table を使った方が便利
- リスト操作とか競技プログラミングで使ったりした私用メモ
- Python3.4からpipが標準インストーラに!?
- rauthでTwitterAPIにアクセスするのが簡単すぎて、僕にも彼女が…
- ダミーデータファイルを作る
- Mac OS Xで複数バージョンのPythonを利用する(1)複数Verインストール編
- Mac OS Xで複数バージョンのPythonを利用する(2)利用編
- 不均衡データにおけるsampling
- “__slots__“を使ってメモリを節約
- pythonで日時の差分を秒単位で出す方法
- PythonでStateモナド
- 【募集】プログラミングのスキル交換をしませんか
- Supervisorで簡単にデーモン化
- Pythonでlet式を使う
- AWS コマンドラインインターフェイス(Python/awscli)をMac OS Xで利用する手順
- Pythonのパッケージ管理ツールez_setupの覚書
- sitecustomize.py を使わず usercustomize.py を使おうね
- ローカルのGAEを同一LAN内のiPhoneのブラウザから確認する方法
- はじめてのPython 素数に0, 1をくっつけて返すスクリプト
- PythonでCSVの読み書き
- easy_installのインストール
- Pelican ブログのインストール方法
- PythonでNetCDFの読み書き
- テキストファイルから指定した文字列を含む行を出力する
- pythonメモ:easy_installが使えないとき
- ベイズ線形回帰(PRML§3.3)の図版再現
- ラテン語文解析プログラムを書くことを目的としたラテン語学習(前編)
- MongoEngineでMongoDBを触ってみる基礎編
- Translate Toolkitで翻訳ツールを作る
- Pythonでカバレッジを調べる
- たぶん1分くらいでできる形態素解析とtfidf(テストコードつき)
- ChatWork API を叩く PHP と Python のサンプル
- LXCをPythonから操作する
- sympyで運動方程式
- APSchedulerで少し進んだジョブスケジューリング
- IntelliJ IDEAのPythonプラグインからもvirtualenvが使える
- Pythonのクラスメンバのスコープまとめ
- Keynoteに美しくスニペットを貼る
- ラテン語文を合成音声で読み上げる技術
- SphinxでPythonドキュメントを自動的にビルド
- b-Bit MinHashを使ったサイトのカテゴリ分類
- とにかく簡単に JSON データを確認したい
- 第16回オフラインリアルタイムどう書くの問題をPythonで解いてみた
- DJangoメモ:はじめから(準備編)
- Pythonでニュース速報(嫌儲)のスレッド一覧を取得してみる。
- scipyとか使ってみる
- scipyでフィルタ作成
- numpyでハミング符号
- ὑμήνπτερόν
- feedparserで自動的にねこ画像を拾ってくる
- pyOpenGLでシェーダープログラミング
- DJangoメモ:はじめから(モデル設定編)
- DJangoメモ:はじめから(管理画面を使う編) myハマりポイント
- pythonのunittestのassertXXX一覧
- 秒速でねこ画像を集めてネコヒルズ族を目指す
- ScipyでICA
- Docker で Google AppEngine 開発
- 最小お釣問題について考える
- DJangoメモ:はじめから(管理画面をもっと編集編)
- Python でテスト
- AnsibleのPython APIを試す。
- Pythonのインストール(Windows)
- DJangoメモ:はじめから(ビューを作る編)
- ConfigParserモジュールの使い方
- [Python] virtualenvとは何か
- Python の subprocess で出力を受け取るときは communicate() を使おう
- はてブのホッテントリのタイトルを要約してWebの今を見つめる
- DJangoメモ:はじめから(テンプレートからビューを作る編)
- Python3.3でナイーブベイズを実装する
- Python3.3でナイーブベイズを実装する
- 犬派と猫派の勢力図をGoogleChartAPIでグラフ化して決着をつける
- Python3.3で実装したナイーブベイズをBing APIで取得したWebページで学習。文章を分類させる
- 【cocos2d-x 3.0】binding-generatorでScript Bindingを自動化する方法
- iOS実機のSSL通信をプロキシによって傍受したり改ざんする方法
- DJangoメモ:はじめから(エラー画面設定編)
- 少しのコードでWebPayを導入する Python Ver.
- カレントディレクトリをドキュメントルートとしてHTTPサーバを立てる
- DJangoメモ:はじめから(URLConfの単純化と分割)
- AnsibleでPython(正確にはJinja2)の文法を生かしたスマートな条件文の書き方集
- MacOSXにSphinxをインストール
- Ansibleを導入したい人の為のくどきポイント
- DJangoメモ:はじめから(フォーム処理)
- DJangoメモ:はじめから(汎用ビューの使用)
- FlaskとPILImageを使ってリサイズした画像をResponseする
- Python3.3で実装したナイーブベイズ分類器を利用して、文章と文字列中の語の共起頻度から、類似度を計算する
- herokuでDJangoページを公開:準備編 myハマりポイント
- Pythonライブラリ・Botoで素敵にAWSを管理する
- Pythonメモ:pipコマンドが使えないとき
- FlaskからWebPayを導入する
- SublimeTextに実績機能をつけた
- pythonでもっとも簡単に音声合成する方法
- Python Jinja2
- PythonでLeapMotionを使ってみる
- 今週のアルゴリズム:最短経路の計算!(Ruby/Python/C#/VB/Goでpermutation iterator)
- 今週のアルゴリズム:最短経路の計算!(PHP/Python/Ruby/HSPでnext_permutation、Perlでpermutation iterator)
- scikit-learnでtf-idfを計算する
- CMake+SWIGで簡単にC/C++の多言語バインディングを実現する
- JavaScriptでもジェネレーター関数
- Mac OS X 開発環境構築メモ
- pandasメモ
- herokuでDJangoページを公開:実践編
- 30C3 CTF オンライン予選大会の PyExec 問題紹介
- wxPythonをMacOSXにインストールする際に「”〜.pkg”は壊れているため開けません。」のメッセージが出たときの対処法
- python3でtwitter
- Twitterでつぶやく
- Twitter-Pythonの使い方
- numpyで行列の斜めのやつを取得する
- python の map オブジェクトを list にした後は何も残らない
- PythonとPHPで文字列分割をして配列の最後の要素を取得
- Google App Engine for PythonでTweet(API1.1)
- pythonでmarkdownを扱う
- Matplotlibによるヒストグラム透明重ね書き
- Pythonで標準出力をnon-blockingにする
- 1分で実現できる!関数の実行結果をmemcachedにキャッシュするデコレータ
- pythonクイズ
- ワンライナーWebサーバを集めてみた
- X-SendFileを用いて静的ファイルをサーブ
- herokuでDjangoブログ:ログイン実装
- Command Line で使用しているツールまとめ vol.8
- APIでできること vol.1
- 変数の変数名を文字列で取得する。
- pyrtm と RTM CLI を使う
- スコープでリソースを破棄するいろいろなやりかた
- Django:参考資料
- どうやってコードを書けばいいのかな? というときに役立つかもしれない howdoi
- SQLAlchemy で独自の Composite Value を作る
- networkxでグラフを描く
- Twitter の OAuth ログインを自動化するスクリプト
- ファイルをzip圧縮して別のサーバにバックアップする
- boto を使って Amason S3 に指定のフォルダをアップロードするスクリプト
- argparseの使い方とoptparseとの違い
- Coverallsで “coverage unknown” になった時の対処法
- pythonでflatten
- Python 再帰の上限の参照と変更
- pythonでホームディレクトリの取得
- Pythonのスタイルを自動で整形させるVimプラグイン
- Tornado + nginx の時のIPの取得方法
- Python3でImportError: No module named ‘xxxxx’
- ScraperWikiを使ってWEBサイトからデータを定期的に取得する
- Scikit-learnでPCA
- Scikit-learnでIsomap
- メモ:Vagrant環境でCGI(試行錯誤中)
- Python 3.4 から標準ライブラリに入る Enum 型が今からでも便利
- SQLAlchemy で Enum を使う
- Django Templateのif-elseを短く書く
- Macでpyenv+virtualenv
- LINQのPython実装 “linqish”の紹介
- Numpyで行列の連結
- Scipyでデータをnormarizeする
- reportlabで画像追加メモ
- django-celery で Amazon SQS を使ってみた
- 環境構築手順書: Ubuntu + Apache2 + Python + Pyramid
- Path API を叩く PHP / Python / Ruby のサンプル
- Pythonメモ(自分用):配列
- 【python】web開発準備(仮想環境の構築)
- Python版のConfluence API用モジュールを使ってみます。
- PythonでYouTubeの動画を自動的に検索&ダウンロードする
- Pythonメモ:現在の月を取得
- sqlalchemyでgroup_byしてsum
- 僕とcpとSubprocessと
- Pythonの進化計算ライブラリDeap
- Scikit-learnでハイパーパラメータのグリッドサーチ
- 泥沼の記憶(CSV)をワンライナーで処理する
- pipで既にインストールされているパッケージをuser環境(非su)でアップデートする
- 2D plot in matplotlib
- 今日の株式取引は?
- 東証1部上場銘柄の名前と証券コードを取得する
- python で redmine の更新を hipchat へ流す
- Bottle0.13+jPlayer2.5で自分だけのミュージックプレイヤーを作ろう!
- Ruby と Python の仮想環境操作を統一する
- CentOS に Python2.7, Python3を入れたメモ
- anyenvで開発環境を整える
- pythonで文字列ゼロ埋め、文字列からある文字をカウントする
- Pythonで正規表現使うとき
- pythonにおける相対urlの処理
- pythonで文字列が数字かどうかを確認する
- pythonにswitchはないけれど
- Python と node.js のテストライブラリを簡単に比較してみた
- Webアプリ開発実践:Djangoでシフト作成ページを作ろう!(はじめに)
- numpyで作成した行列の可視化
- Pythonメモ:オブジェクトの持つ属性を知りたいとき
- supervisorでulimitを設定する

Androidに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Pythonに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Swiftに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。

Unityに関する現役のエンジニアのノウハウ・トレンドのトピックなど技術的な情報を提供しています。コード・プログラムの丁寧な解説をはじめ、初心者にもわかりやすいように写真や動画を多く使用しています。