$ yarn install
$ npx textlint README.md
ImageNet Classification with Deep Convolutional Neural Networks
2012年のILSVRCというImageNetを用いた画像分類コンペで圧勝したモデル。
2012年までは人間が画像から特徴量を設計し、それを用いて分類を行っていたが、AlexNetが2012年のILSVRCで圧勝したことにより機械によって特徴量を抽出できることが示された。また当時、畳み込み演算を含む大規模なCNNを学習することはコストの面で難しかったが、GPUに最適化された畳み込み演算の実装を行うことで学習時間を短縮した。
- ReLU
- GPUによる並列計算
- ネットワークの中の一部のみでGPU間の通信を行うことで、計算を効率化した。
- ReLUと輝度の正規化の組み合わせが良かった。
- Overlapping Pooling
- プーリング層でダウンサンプルする領域を少しずつ被せることで過学習しにくくなった
- Dropoutで過学習を防いだ。
- 水平移動や反転などのData Argumentationによって教師データを増やした。
ImageNetの2011年秋の版で事前学習したAlexNetを2012年のILSVRCでfine tuningすると、テストデータにおいてエラー率は15.3%となった。
中間層をひとつでも取り除くとネットワークの性能が低下するので、ネットワークの深さは非常に重要である。教師データを増やさずにネットワークを大きくしたり、教師なしの事前学習でさらなる性能が得られるかもしれない。
画像は論文より引用
5層の畳み込み層と3層の全結合層からなる。
Deep Residual Learning for Image Recognition
Microsoft Researchが2015年に提案したモデル。
当時、画像認識において一般にCNNの層数を増やすことでより高次元の特徴を獲得することは知られていたが、単純に層を重ねるだけでは性能が悪化していく勾配消失問題があった。ResNetではshortcut connection
という機構を導入し、手前の層の入力を後ろの層に直接足し合わせることで、この勾配消失問題を解決した。
画像は論文より引用
図の左側がbuilding block
と呼ばれ、右側がbottleneck building block
と呼ばれる。この構造によって勾配がより手前の層まで伝わるようになった。
ILSVRCという毎年開催されていたImageNetを用いた画像分類コンペにおいて、2014年以前はせいぜい20層程度(VGGが16か19層、GoogleNetが22層)のモデルで競っていた。しかしResNetは152もの層を重ねて学習させることに成功し、2015年のILSVCRで優勝した。
2017年に提案された自然言語処理のモデル。コンピュータビジョンのモデルではないものの、この論文で提案されたTransformerというアーキテクチャが後発のコンピュータビジョンのモデルに大きな影響を与えたので、ここで取り上げる。
当時、Seq2SeqのモデルではRNNやCNNと併用してAttentionを用いるものがあった。しかし、この論文ではRNNやCNNを排除してAttentionのみのTransformerというアーキテクチャを提案した。RNNを排除してAttentionや全結合層を用いることによって並列化が可能になって学習にかかる時間が削減された。さらに精度も向上し、入力と出力の文章離れた位置にある任意の依存関係を学習しやすくなった。
- Scaled Dot Product Attention
- まず、embeddingされた入力ベクトル(sequence_length, d_model)に対して、Query、Key、Valueを計算する。これらは入力ベクトルをそれぞれ重み行列Wq(d_model, d_q)、Wk(d_model, d_k)、Wv(d_model, d_v)で写像して得られる。この論文ではself-attentionを用いるのと、全く同じ構造のレイヤーを複数重ねるので、d_q、d_k、d_v、d_modelは全て等しい。
- 各Queryと各Keyの内積にsoftmax関数を適用し、QueryとKeyの関連度を計算する。さらにこれをValueとの内積をとることで、各Queryと類似度の高いKeyに対応するValueほど重く重みづけされたValueの重み付き和が得られる。これは、入力のある部分に対して他のどの部分が重要になるかを抽出する操作とみなすことができる。
- QueryとKeyの内積をで割っているのは、が大きくなったときにQueryとKeyの内積が大きくなり、softmaxの勾配が極端に小さくなっていまうのを防ぐためである。
Scaled Dot Product AttentionはPyTorchを用いて次のように実装できる。
class ScaledDotProductAttention(nn.Module):
def __init__(self, d_model: int) -> None:
"""
Args:
d_model: embedded vector length
"""
super().__init__()
self.d_k: int = d_model
self.w_q = nn.Linear(d_model, d_model, bias=False)
self.w_k = nn.Linear(d_model, d_model, bias=False)
self.w_v = nn.Linear(d_model, d_model, bias=False)
self.out = nn.Linear(d_model, d_model, bias=False)
def forward(self, x: torch.Tensor, mask: Optional[torch.BoolTensor] = None) -> torch.Tensor:
"""
Args:
x: input tensor [batch_size, sequence_length, d_model]
Returns:
out: torch.Tensor [batch_size, sequence_length, d_model]
"""
query, key, value = self.w_q(x), self.w_k(x), self.w_v(x)
query /= math.sqrt(self.d_k)
attn_weight = torch.bmm(query, key.transpose(-2, -1))
if mask is not None:
attn_weight = attn_weight.masked_fill(mask, -1e9)
attn_weight = functional.softmax(attn_weight, dim=-1)
attn = torch.matmul(attn_weight, value)
out = self.out(attn)
return out
- Multi Head Attention
- 各単語に対して1組の次元のQuery、Key、Valueを持たせるのではなく、それらを種類の異なる重みベクトルにより写像したもので種類の異なるAttentionを計算する。それぞれのQuery、Key、Valueから構成されるAttention機構はheadと呼ばれ、それぞれで異なる部分空間から有益な情報を抽出することができる。 これによって、アンサンブルのような効果が得られる
Multi Head Attentionは、Scaled Dot Product Attentionの実装を少し改変する事で実装できる。計算効率のため、各headに分割されたQuery, Key, Valueをそれぞれまとめて保持する。Query、Key、Valueのテンソルの形状は(batch_size, num_head, sequence_length, dim_per_head)のようになる。
class MultiHeadAttention(nn.Module):
def __init__(self, d_model: int, num_head: int) -> None:
"""
Args:
d_model: embedded vector length
"""
super().__init__()
assert d_model % num_head == 0, f"d_model({d_model}) must be dividible by num_head({num_head})"
self.d_k: int = d_model
self.num_head: int = num_head
self.dim_per_head: int = d_model // num_head
self.w_q = nn.Linear(d_model, d_model, bias=False)
self.w_k = nn.Linear(d_model, d_model, bias=False)
self.w_v = nn.Linear(d_model, d_model, bias=False)
self.out = nn.Linear(d_model, d_model, bias=False)
def forward(
self, x: torch.Tensor, mask: Optional[torch.BoolTensor] = None
) -> torch.Tensor:
"""
Args:
x: input tensor [batch_size, sequence_length, d_model]
Returns:
out: torch.Tensor [batch_size, sequence_length, d_model]
"""
batch_size: int = x.size()[0]
query: torch.Tensor = self.w_q(x)
key: torch.Tensor = self.w_k(x)
value: torch.Tensor = self.w_v(x)
# [batch_size, sequence_length, d_model] -> [batch_size, sequence_length, num_head, dim_per_head] -> [batch_size, num_head, sequence_length, dim_per_head]
query = query.view(batch_size, -1, self.num_head, self.dim_per_head).transpose(1,2)
key = key.view(batch_size, -1, self.num_head, self.dim_per_head).transpose(1,2)
value = value.view(batch_size, -1, self.num_head, self.dim_per_head).transpose(1,2)
query /= math.sqrt(self.d_k)
attn_weight = torch.matmul(query, key.transpose(2, 3))
if mask is not None:
attn_weight = attn_weight.masked_fill(mask, -1e9)
attn_weight = functional.softmax(attn_weight, dim=-1)
attn = torch.matmul(attn_weight, value)
# [batch_size, num_head, sequence_length, dim_per_head] -> [batch_size, sequence_length, num_head, dim_per_head] -> [batch_size, sequence_length, d_model]
attn = attn.transpose(1, 2).contiguous().view(batch_size, -1, self.d_k)
out = self.out(attn)
return out
- Positional Encoding
WMT 2014 English-German、 WMT 2014 English-Frenchというデータセットで英語からドイツ語、フランス語への翻訳タスクを行った。結果は英語-ドイツ語翻訳タスクではBLEUスコア28.4、英語-フランス語翻訳タスクではBLEUスコア41.8でstate-of-the-artを達成した。
Attentionベースのモデルに期待しており、これをテキスト以外に画像、動画、音声などで活用できるようなAttentionを研究する予定だ。
画像は論文より引用
- DecoderのMasked Multi Head Attentionは、対象単語より左の単語のみに依存するように、softmaxの入力値を一部マスクしている。
- Multi Head AttentionやFeed ForwardにはResidual構造がある。