数式表示ライブラリ(Mathjax)を Ver 3.x に載せ替えた

はじめに

数式をWebに書くには Mathjax.js が便利ですよね。 v2系よりも描画が速くなった(速度 3割増し?)とのことのなので、今後はv3系を使う予定です。 乗り換えの際に、inlineでの記述がうまくできなくてかなり悩んでいました。一応解決したので備忘録です。

設定への影響

v2系⇒v3系で、configの書き方が変更になっていた。

config値を指定する script をヘッダとかフッタなどに記述します。 その際に v2系で指定していた script type は指定してはいけない。

<script>
MathJax = {
  tex: {inlineMath: [['$', '$'], ['\\(', '\\)']]}
};
</script>

config を無事に取り込めるようになったので、インライン表示も可能になりました。

ブロック記述 \$\$~\$\$ インライン記述 \$~\$ インライン記述(\displaystyle)
ここから>$$ \int_0^\pi\sin x $$<ここまで ここから>$\int_0^\pi\sin x$<ここまで ここから>$ \displaystyle \int_0^\pi\sin x$<ここまで
ここから>$$ \sum_{i=1}^{n}a_i x^i $$ ここから>$ \sum_{i=1}^{n}a_ix^i $<ここまで ここから>$ \displaystyle \sum_{i=1}^{n}a_ix^i $<ここまで
ここから>$$ \frac{1-x}{x} $$<ここまで ここから>$ \frac{1-x}{x} $<ここまで ここから>$ \displaystyle \frac{1-x}{x} $<ここまで

以前から気になっていたこと

キャレット「^」が本文中でも反応してしまう。

はてなブログ独自現象?)
Mathjax Blockなし⇒x_1 + y2 + y^3 (Blockなしでも y2 が反応している。期待と異なる反応)
Mathjax Blockあり⇒$ x_1 + y^2 + y^3 $ (期待するとおりの表示)

原因

数式 y=x^2 のキャレット(^)がMathjaxに渡る前に展開され、y=x<sup>2</sup> として渡される。このためMathjaxではキャレットとして認識できず、mjx-container を展開しない。

回避方法

  • キャレットをエスケープする⇒(\^)
    簡単だけど既存の式を修正する必要がある。

  • 特定のタグの中(pとかdivとか)だとsup化に反応しないので、段落全体をタグで囲む。


タグなし: $ y=x2 $

pタグあり: $ y=x^2 $

divあり: $ y=x^2 $
tableタグあり: $ y=x^2 $

Mathjax以外の数式記述方法

https://render.githubusercontent.com を使うと Mathjax.js を使わなくとも、imageとして数式を張り付けることができます。 GitHubなどで便利そう。

記述例

<img src="https://render.githubusercontent.com/render/math?math=x=(x_1, x_2, ..., x_m)^T \in \mathbb{R}^m" />

出力例

参考

はてなブログで書いたコードブロックに行番号を表示する

はじめに

はてなブログのコードブロックにも行番号を表示したいですよね。ということで、先人のブログを参考に設定してみました。

参考にしつつ更新したところ

各コードブロックの開始番号を変えたい

つまり、そのまま指定すると ↓こんな感じで1から始まるじゃないですか。

import pandas as pd

それを、↓ こんな感じで特定の数字、10とか100とかから表示したいです。

import pandas as pd

実装に対する考え方

先のjavascriptでは、行番号はcssのcounterを使用しています。ですので、コードブロックの外部から、css変数を与えて制御することで実現できます。

 <div style="counter-set: linenumber 99">
 ```python
 import pandas as pd
 ```
 </div>

何故そうするのか?

動かない例

markdownの場合は以下の書式となるようですが、はてなブログのコードブロックはその書き方に対応していません。

5.7 コードブロックに行番号を表示する (*) | R Markdown クックブック

 ```{r, attr.source='.numberLines'}
 if (TRUE) {
   x <- 1:10
   x + 1
 }
 ```

はてなブログの場合

はてなブログのコードブロックでもシンタックスハイライト用に指定できるファイルタイプも多くありますが、属性指定とかはできません。このためコードブロックのファイルタイプの記述ははそのまま保持したうえで、属性に相当する情報を与える必要があります。

ソースコードを色付けして表示する(シンタックスハイライト) - はてなブログ ヘルプ

記事中に複数のコードブロックを埋め込むことを考えると、ある程度スコープを意識した記述ができることも必要です。そのために記事本文中で該当コードブロックを divタグで囲み、style を用いて css変数を操作することにより、目的とする制御が可能となります。

参考

数式の書き方(Mathjax 覚え書き)

はじめに

MathjaxはLatexで数式を表現するパッケージです。Ver2系とVer3系が出回っていますが特にこだわりが無ければVer3系を使用するのが良いでしょう。処理速度も改良されていますし、最新メンテナンスによりセキュリティ的にも堅牢と言えます。利用の際には予めMathjax.js を読み込んでおく設定をしておきます。はてなブログの場合は「ヘッダ」に script を設定しておくと手間もなく良い感じです。

早引き用に、よく使うものを集めておく

いつも使うけど利用頻度が低いとすぐに忘れてしまう、、そんな私への備忘録です。

数式 書き方 用途
$ x^{i+1} $ x^{i+1}
x\^{i+1}
上付き(読み方:キャレット)
状況に応じてエスケープ(\)を添える⇒(\^)
$ w_2 $ w_2 下付き
$\frac{1}{x}$ \frac{1}{x} 分数
$ \nabla $ \nabla ベクトルの微分演算(読み方:ナブラ)
ユニコードでも表現可能(∇)
$ \partial $ \partial 偏微分を表現する(読み方:ラウンドディー、ディー)
ユニコードでも表現可能(∂)
$ \left[ ... \right] $ \left[ ... \right] 大きい括弧
$ \approx $ \approx 大よそ等しい

参考

本家

より詳細には本家のサイトを参照すると良いです。

多めに見たいとき

より広くまとめている人のサイトも参考になります。

深層学習 day1 Section5(誤差逆伝搬法)

このページは Study-AI の実装演習レポートです。

1. 要点まとめ

  • 勾配誤差の計算には、数値微分を用います。
$$ \nabla E=\frac{\partial E}{\partial W}=\left[\frac{\partial E}{\partial w_1}...\frac{\partial E}{\partial w_M}\right] $$
  • 数値微分とは、
    プログラムで微小な数値を生成し擬似的に微分を計算する手法です。
$$ \frac{\partial E}{\partial w_m}\approx\frac{E(w_m+h)-E(w_m-h)}{2h} $$

各パラメータ$ W_m $ それぞれについて$ E(W_m+h) $や$ E(W_m-h) $を計算するためには、順伝播の計算を繰り返し行う必要があり負荷が大きい。
即ち、計算量が非常に多くなります。このデメリットに対応するために、誤差伝播法を利用します。

  • 誤差逆伝播法とは、
    算出された誤差を、出力層側から順に微分し、前の層へと伝播されます。最小限の計算で各パラメータでの微分値を解析的に計算する手法です。 計算結果(=誤差)から微分を逆算することで、不要な再帰的計算を避けて微分を算出できます。

2. 実装演習

問題 誤差逆伝播法では不要な再帰的処理を避けることができる。既に行った計算結果を保持しているソースコードを抽出せよ。

  • 1_3_stochastic_gradient_descent.ipynb

(解答)

    # 出力層でのデルタ
    delta2 = functions.d_mean_squared_error(d, y)
    # b2の勾配
    grad['b2'] = np.sum(delta2, axis=0)
    # W2の勾配
    grad['W2'] = np.dot(z1.T, delta2)
    # 中間層でのデルタ
    #delta1 = np.dot(delta2, W2.T) * functions.d_relu(z1)

    ## 試してみよう
    delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)

問題 次の数式に該当するソースコードを探せ

  • 1_3_stochastic_gradient_descent.ipynb

(数式)

$$ \frac{\partial E}{\partial y} $$

(解答)

delta2 = functions.d_mean_squared_error(d, y)

(数式)

$$ \frac{\partial E}{\partial y} \frac{\partial y}{\partial u} $$

(解答)

delta1 = np.dot(delta2, W2.T) * functions.d_sigmoid(z1)

(数式)

$$ \frac{\partial E}{\partial y} \frac{\partial y}{\partial u} \frac{\partial u}{\partial w^{(2)}_{ji}} $$

(解答)

grad['W1'] = np.dot(x.T, delta1)

3. 確認テストなどの考察

  • 記号の読み方に気を付けましょう。講師からの訂正がなくとも前後の文脈から判断することが必要です。その意味や意図を理解することが大切です。
    $ \nabla $:ナブラ ナブラ - Wikipedia
    $ \partial $:ディー ∂ - Wikipedia

4. 関連記事

深層学習 day1 Section4(勾配下降法)

このページは Study-AI の実装演習レポートです。

1. 要点まとめ

勾配下降法は、重みやバイアスを調整しながらニューラルネットワークを学習させる手法であり、次の3手法があります。

手法 特徴
勾配下降法
(GD;Gradient Descent)
学習に全データを使用する。
メモリ使用量が大きく、局所解に陥りやすい。
確率的勾配下降法
SGD;Stochastic Gradient Descent)
学習にランダムに抽出したサンプルを使用する。
オンライン学習ができる。メモリに使用量が少ないが、外れ値の影響を受けやすい。
ミニバッチ勾配下降法
(MSGD;inibatch SGD
学習にランダムに分割したデータの集合を使用する。
確率的勾配法のメリットを損なわず、計算機の計算資源を有効活用できる。

学習を進める際に、学習率 $ \varepsilon $ を与えます。

  • 学習率 $ \varepsilon $ が大きすぎると、最小値にいつまでもたどりつかず、発散してしまいます。
  • 学習率 $ \varepsilon $ が小さいと、発散することはないが収束するまでに時間がかかってしまいます。 また、局所解にもつかまりやすくなります。

収束性を向上させるためのアルゴリズムには、さまざまな種類が考案されており、主に次のものが使われます。

  • Momentum
  • AdaGrad
  • Adadelta
  • Adam

2. 実装演習

問題 ファイル 1-3 から勾配下降法が行われている場所を抜き出せ

  • 1_3_stochastic_gradient_descent.ipynb

(数式)

$$ W^{(t+1)}=W^{(t)}-\varepsilon\nabla E_t $$

(解答)

# 学習率
learning_rate = 0.07

   :(中略)

    # パラメータに勾配適用
    for key in ('W1', 'W2', 'b1', 'b2'):
        network[key]  -= learning_rate * grad[key]

問題 オンライン学習とは?

(解答)
学習データが入ってくるたびに都度、パラメータを更新し学習を進める方法です。一方、バッチ学習は一度にすべての学習データを使ってパラメータを更新する方法です。

問題 この数式の意味を図に書いて説明せよ

(数式)

$$ W^{(t+1)}=W^{(t)}-\varepsilon\nabla E_t $$

(解答)
エポックを回すたびに、前回データに誤差修正を差し引いたものを、次のエポックの入力とします。これを誤差が収束するまで繰り返します。

flowchart LR
  subgraph "重みW"
  subgraph E0["エポック t"]
    t[t 回目]:::CNone -.- W0(("W<sup>(t)</sup>"))
  end
  subgraph E1["エポック t+1"]
    t1[t + 1 回目]:::CNone -.- W1(("W<sup>(t+1)</sup>"))
  end
  subgraph E2["エポック t+2"]
    t2[t + 2 回目]:::CNone -.- W2(("W<sup>(t+2)</sup>"))
  end
  end
E0 -- "W<sup>(t+1)</sup>=W<sup>(t)</sup>-ε∇E<sub>(t)</sub>" --> E1
E1 -- "W<sup>(t+2)</sup>=W<sup>(t+1)</sup>-ε∇E<sub>(t+1)</sub>" --> E2
classDef CNone fill:None,stroke-width:0px;

3. 確認テストなどの考察

  • 学習率は、人手で適切な値を試行して求める必要があります。(ハイパーパラメーターとして与えます)
  • 学習データとして画像を使用する場合、jpegpngを直接用いることはできず、bmpに伸張する必要があります。このため、少ないメモリでオンライン学習が可能なアルゴリズムが求められます。

4. 関連記事

深層学習 day1 Section3(出力層)

このページは Study-AI の実装演習レポートです。

1. 要点まとめ

出力層は、分類であれば各クラスに属する確率など、人間が欲しい最終的な結果を出力します。 機械学習において、この出力層の結果と目的変数の値を比較し、どれくらい合っているかを算出するために誤差関数を使用します。

活性化関数は、中間層と出力層とで利用される目的が異なります。 値の強弱については次の違いがあります。

  • 中間層:しきい値の前後で信号の強弱を調整します
  • 出力層:信号の大きさ(比率)はそそままに変換します

分類問題にて確率出力とする場合、出力層の出力は0~1の範囲とし、さらに総和を 1となるように調整します。

出力層で使用される関数の種類

回帰二値分類多クラス分類
活性化関数恒等写像 $$ f(u)=u $$ シグモイド関数 $$ f(u)=\frac{1}{1+e^{-u}} $$ ソフトマックス関数 $$ f(i,u)=\frac{e^{u_i}}{\sum_{k=1}^Ke^{u_k}} $$
誤差関数平均二乗誤差関数 $$ E_n(w)=\frac{1}{2}\sum_{i=1}^{I}(y_n - d_n)^2 $$ 交差エントロピー誤差関数 $$ E_n(w)=-\sum_{i=1}^{I}d_i\log y_i $$

恒等写像

恒等写像は、入力値を加工せず、そのまま出力します。

シグモイド関数

(数式)

$$ f(u)=\frac{1}{1+e^{-u}} $$

(コード)

def sigmoid(u):
    return 1 / (1 + np.exp(-u))

ソフトマックス関数

ソフトマックス関数はシグモイド関数を多次元用に汎化したものです。
(数式)

$$ f(i,u)=\frac{e^{u_i}}{\sum_{k=1}^{K}e^{u_k}} $$

(コード)

def softmax(u):
  return np.exp(u) / np.sum(np.exp(u)) 

平均二乗誤差関数

回帰問題では平均二乗誤差関数を用います。
(数式)

$$ \eqalign{ E_n(w)&=\frac{1}{2}\sum_{j=1}^I(y_j-d_j)^2 \\ &=\frac{1}{2}||(y-d)||^2 } $$

(コード)

def mean_squared_error(y, d):
    return np.mean(np.square(y - d)) / 2

問題 ・なぜ引き算ではなく2乗するか述べよ
・式の1/2はどういう意味を持つか述べよ

(解答)

  • 2乗する理由
    引き算を行うだけでは、各ラベルの誤差で正負方向の値が発生し、全体の誤差を正しく表すのに都合が悪い。2乗してそれぞれのラベルでの誤差を正の値になるようにする。
  • 1/2する理由
    実際にネットワークを学習するときに行う誤差逆伝搬の計算で、誤差関数の微分を用いるが、その際の計算式を簡単にするため。本質的な意味はない。

交差エントロピー誤差関数

分類問題であれば、交差エントロピー誤差関数を用います。
(数式)

$$ E_n(w)=-\sum_{i=1}^{I}d_i\log y_i $$

(コード)

def cross_entropy_error(d, y):
    return -np.sum(np.log(y[np.arange(bach_size), d] + 1e-7)) / bach_size

対数の結果が0になることを回避するために、極めて小さい値として1e-7を与えます。

2. 実装演習

問題 ソフトマックス関数のコードについて処理を説明せよ

  • common/functions.py より抜粋
# ソフトマックス関数
def softmax(x):  
    if x.ndim == 2:                                # 次元数が2の場合
        x = x.T                                    # xを転置
        x = x - np.max(x, axis=0)                  # オーバーフロー対策として上限値を元に全体を補正する
        y = np.exp(x) / np.sum(np.exp(x), axis=0)  # ソフトマックス関数の本体
        return y.T                                 # 再度、転置して配列を元に戻す

    x = x - np.max(x)                              # オーバーフロー対策として上限値を元に全体を補正する
    return np.exp(x) / np.sum(np.exp(x))           # ソフトマックス関数の本体

問題 交差エントロピー誤差関数のコードについて処理を説明せよ

  • common/functions.py より抜粋
# クロスエントロピー
def cross_entropy_error(d, y):
    if y.ndim == 1:                                # 次元数が1の場合
        d = d.reshape(1, d.size)                   # ベクトルに変形
        y = y.reshape(1, y.size)                   # ベクトルに変形
        
    # 教師データがone-hot-vectorの場合、正解ラベルのインデックスに変換
    if d.size == y.size:
        d = d.argmax(axis=1)                       # インデックス最大値を取得
             
    batch_size = y.shape[0]                        # バッチサイズを取得
    return -np.sum(np.log(y[np.arange(batch_size), d] + 1e-7)) / batch_size # 関数本体

3. 確認テストなどの考察

  • ソフトマックス関数はシグモイド関数を汎化したものであるが、グラフとして描画させた様子は、ReLU関数に類似する。
  • 計算しやすくするために、配列の転置や次元数調整などのトリックを使用する。
  • 対数の計算にて、結果を-∞/∞になることを回避するため、ゼロ値に対し極小値を与えるトリックを使用する。

4. 関連記事

深層学習 day1 Section2(活性化関数)

このページは Study-AI の実装演習レポートです。

1. 要点まとめ

活性化関数とは、ニューラルネットワークにおいて、次の層への出力の大きさを決める【非線形の関数】のことです。入力の値によって、次の層への信号のON/OFFや強弱を定める働きを持ちます。 非線形な関数は「加法性」や「斉次性」を持ちません。

活性化関数の種類

  • 中間層用の活性化関数
  • 出力層用の活性化関数

2. 実装演習

ステップ関数

(数式)

$$ f(x)= \begin{cases} 1 (x \gt 0) \\ 0 (x \le 0) \end{cases} $$

(コード)

def step_function(x):
  if x > 0:
    return 1
  else:
    return 0

(グラフ)

(課題)
0~1間の値を表現できず、線形分離可能なものしか学習できなかった。

シグモイド関数

(数式)

$$ f(u) =\frac {1}{1+e^{-u}} $$

(コード)

def sigmoid(u):
  return 1/(1 + np.exp(-u))

(グラフ)

(課題)
大きな値では出力の変化が微小なため、勾配消失問題を引き起こすことがあった。

ReLU関数

現在、最も使われている活性化関数。
(数式)

$$ f(x)= \begin{cases} x (x \gt 0) \\ 0 (x \le 0) \end{cases} $$

(コード)

def relu(x):
    return np.maximum(0, x)

(グラフ)

3. 確認テストなどの考察

  • 実装演習において「relu」関数の定義実体は、commonパッケージ内にて定義されています。
  • ステップ関数において、本レポートの中では、入力が「ゼロ」の場合は出力も「ゼロ」として数式を訂正しています。(等号記号の扱いを訂正)
  • シグモイド関数において、本レポート中では、関数 f の入力は u に揃えています。
  • グラフ表現には今回は Chart.js (v3.6.2) を利用しています。関数を視覚的に表現することは理解を助けるのに効果的と考えます。

4. 関連記事