【IT Text自然言語処理の基礎】第4章演習問題を解いてみた

# 本記事の概要
この記事では「IT Text 自然言語処理の基礎」（オーム社）の **第4章「系列に対するニューラルネットワーク」** に付いている演習問題を詳しく解説します。

書籍にも略解はありますが、解説が省略されていたりします。
略解でわからなくなったときは、この記事を参考にしてもらえればと思います！

# 問1
> 式$(4.18)$を導出せよ．
> ```math
> \frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{h}_{t-1}} = \boldsymbol{W}_{hh}^\top\text{diag}(f'(\boldsymbol{a}_t))\tag{4.18}
> ```

式$(4.15)$（$\boldsymbol{h}_t=\boldsymbol{f}(\boldsymbol{a}_t)$）より、$\boldsymbol{h}_t$は$\boldsymbol{a}_t$の関数なので、連鎖律を使って式$(4.18)$の左辺を分解します（地道に各成分について連鎖律を適用し、行列計算すれば確かめられます）。

```math
\frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{h}_{t-1}} = \frac{\partial \boldsymbol{a}_t}{\partial \boldsymbol{h}_{t-1}} \frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{a}_{t}}\tag{A}
```

まずは$\displaystyle\frac{\partial \boldsymbol{h}\_t}{\partial \boldsymbol{a}\_{t}}$を求めにいきましょう。

```math
\begin{align}
\frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{a}_{t}} 
&= \frac{\partial \boldsymbol{f}(\boldsymbol{a}_t)}{\partial \boldsymbol{a}_{t}}
\end{align}
```
です（$\boldsymbol{f}$はベクトル値関数で、$\boldsymbol{f}=(f_1,f_2,\cdots,f_d)=(f,f,\cdots,f)$）。
右辺ベクトル微分を書き下すと次のような行列になります（$a_t^{(i)}$は$\boldsymbol{a}_t$の第$i$成分を表す）。

```math
\frac{\partial \boldsymbol{f}(\boldsymbol{a}_t)}{\partial \boldsymbol{a}_t}
= \begin{pmatrix}
\frac{\partial f(a_t^{(1)})}{\partial a_t^{(1)}} & \cdots & \frac{\partial f(a_t^{(d)})}{\partial a_t^{(1)}}\\
\vdots & \ddots & \vdots\\
\frac{\partial f(a_t^{(1)})}{\partial a_t^{(d)}} & \cdots & \frac{\partial f(a_t^{(d)})}{\partial a_t^{(d)}}\\
\end{pmatrix}
```

この行列の非対角成分（$i\ne j$）について見ると、必ず0になります。
（$\boldsymbol{a}_t$の各成分$a_t^{(1)},\cdots,a_t^{(d)}$は互いに独立なので）

対角成分は残るので、結局

```math
\frac{\partial \boldsymbol{f}(\boldsymbol{a}_t)}{\partial \boldsymbol{a}_t}
= \begin{pmatrix}
\frac{\partial f(a_t^{(1)})}{\partial a_t^{(1)}} & \cdots & O\\
\vdots & \ddots & \vdots\\
O & \cdots & \frac{\partial f(a_t^{(d)})}{\partial a_t^{(d)}}\\
\end{pmatrix}
= \text{diag}(f'(\boldsymbol{a_t}))\tag{B}
```

となります。

次は$\displaystyle\frac{\partial \boldsymbol{a}\_t}{\partial \boldsymbol{h}\_{t-1}}$を求めにいきましょう。ベクトル微分の各成分を書き下すと

```math
\begin{align}
\frac{\partial \boldsymbol{a}_t}{\partial \boldsymbol{h}_{t-1}}
&= \begin{pmatrix}
\frac{\partial a_t^{(1)}}{\partial h_{t-1}^{(1)}} & \cdots & \frac{\partial a_t^{(d)}}{\partial h_{t-1}^{(1)}}\\
\vdots & \ddots & \vdots\\
\frac{\partial a_t^{(1)}}{\partial h_{t-1}^{(d)}} & \cdots & \frac{\partial a_t^{(d)}}{\partial h_{t-1}^{(d)}}
\end{pmatrix}
\end{align}\tag{C}
```

です。ここで$\boldsymbol{a}_t$の定義を思い出すと、

```math
\boldsymbol{a}_t= \boldsymbol{W}_{hx}\boldsymbol{x}_t + \boldsymbol{W}_{hh}\boldsymbol{h}_{t-1}+\boldsymbol{b}_h
```

なので、この第$i$成分は次のようになります（※$(A)_{i,:}$は行列$A$の$i$行目のベクトルを表す）。

```math
a_t^{(i)} = (\boldsymbol{W}_{hx})_{i,:}\boldsymbol{x}_t + (\boldsymbol{W}_{hh})_{i,:}\boldsymbol{h}_{t-1} + b_h^{(i)}
```
よって、

```math
\frac{\partial a_t^{(i)}}{\partial  h_{t-1}^{(j)}} = (\boldsymbol{W}_{hh})_{i,j}
```
と$(\text{C})$から

```math
\begin{align}
\frac{\partial \boldsymbol{a}_t}{\partial \boldsymbol{h}_{t-1}}
&= \begin{pmatrix}
(\boldsymbol{W}_{hh})_{1,1} & \cdots & (\boldsymbol{W}_{hh})_{d,1}\\
\vdots & \ddots & \vdots\\
(\boldsymbol{W}_{hh})_{1,d} & \cdots & (\boldsymbol{W}_{hh})_{d,d}
\end{pmatrix}
= \boldsymbol{W}_{hh}^\top
\end{align}
\tag{D}
```
したがって$(\text{A})$に$(\text{B})(\text{D})$を代入して

```math
\frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{h}_{t-1}} = \frac{\partial \boldsymbol{a}_t}{\partial \boldsymbol{h}_{t-1}} \frac{\partial \boldsymbol{h}_t}{\partial \boldsymbol{a}_{t}}
= \boldsymbol{W}_{hh}^\top\text{diag}(f'(\boldsymbol{a_t}))
```


# 問2
> RNNでは，各位置の隠れ状態ベクトルを順番に計算する必要があるため，そのままでは計算の並列化が困難である．GPUなどのハードウェアでRNNの並列計算を実現するために，どのような実装上の工夫が行われているのか，調査して説明せよ．

略解では「ミニバッチに含まれる系列の長さを揃える。」とされています。

系列の長さを揃えてあげれば、1バッチぶん計算する際にまとめて計算することができます。
揃っていないと逐次処理することになります。

# 問3
> LSTMにおいて位置$t$の忘却ゲート$\boldsymbol{f}\_t$が完全に開いているとき，つまり$\boldsymbol{f}\_t=1$に固定されているとき，$\boldsymbol{c}\_t$を$\boldsymbol{c}\_{t-1}$で偏微分せよ．また，その結果からLSTMが勾配消失問題を緩和できる理由を説明せよ．

$\boldsymbol{c}_t$は式$(4.24)$より

```math
\boldsymbol{c}_t = \boldsymbol{f}_t \odot \boldsymbol{c}_{t-1} + \boldsymbol{i}_t \odot \boldsymbol{g}_t\tag{4.24}
```

で、問題の条件$\boldsymbol{f}_t=1$を代入すると

```math
\boldsymbol{c}_t = \boldsymbol{c}_{t-1} + \boldsymbol{i}_t \odot \boldsymbol{g}_t
```

よって
```math
\frac{\partial \boldsymbol{c}_t}{\partial \boldsymbol{c}_{t-1}} = 1
```
です。よってこのとき$\boldsymbol{c}_{t-1}$の勾配は、

```math
\frac{\partial L}{\partial \boldsymbol{c}_{t-1}} = \frac{\partial L}{\partial \boldsymbol{c}_{t}}
\frac{\partial \boldsymbol{c}_t}{\partial \boldsymbol{c}_{t-1}} = \frac{\partial L}{\partial \boldsymbol{c}_{t}}
```

となり、勾配消失の心配がなくなることがわかります。

# 問4
> 画像処理で用いられるCNNと自然言語処理で用いられるCNNの類似点および相違点を説明せよ．

#### 類似点
略解にある通り「入力の特定のパターンに反応するフィルタが学習される」ですね。

畳み込み計算は内積計算なので、フィルタのパターンと入力のパターンが類似していれば大きな値が出力されます。

#### 相違点
画像データではフィルタを縦にも横にも動かして畳み込み計算をするのに対し、文章のような系列データでは一方向にしか動かしません。