Contents
Denoising Autoencoder(DAE)とは
Denoising Autoencoder(DAE、デノイジングオートエンコーダ)は生成モデルであるオートエンコーダの一種で、基本的にノイズがかかった画像データからノイズを除去することを目的としたモデルです。ここでは、DAEについてオートエンコーダの基本的なところから解説していきます。
本記事は簡単なニューラルネットワークの基本知識は頭に入っている方を読者として想定しています。
1. オートエンコーダとは
1.1 オートエンコーダの基本的構造
まず、オートエンコーダについて簡単に説明します。オートエンコーダは入力データを圧縮(エンコード)して潜在空間表現に変換し、その後、圧縮された情報から元のデータを再構成(デコード)することを目的としたニューラルネットワークです。生成モデルとしてだけではなく、勾配消失や過学習を避けるためにも用いられます。
オートエンコーダは主に入力を圧縮するエンコーダ部分と圧縮した情報を再構成するデコーダ部分の二つからできています。
エンコーダ、デコーダはそれぞれ基本的にニューラルネットを用いて構成されています。学習は入力データとモデルの出力が近くなるように行われます。
1.2 オートエンコーダの種類
オートエンコーダには様々な種類があり、DAEもその一種です。いくつか簡単に紹介します。
- Variational Autoencoder (VAE)
これは生成モデルで最も有名なモデルです。潜在変数に確率分布を用いているため、潜在変数から入力と少し異なるデータを生成することができます。誤差逆伝播法を使うためにリパラメトリゼーショントリックという手法が用いられています。 - Denoising Autoencoder (DAE)
このあと説明する、ノイズ除去を目的としたオートエンコーダです。 - Convolutional Autoencoder (CAE)
エンコーダ部分とデコーダ部分に線形層ではなく畳み込み層を用いたモデルです。こちらは空間的な情報を保持したまま圧縮することができます。
2. Denoising Autoencoder(DAE)
2.1 DAEの概要
では、DAEについて見ていきましょう。基本はオートエンコーダなので同じようなエンコーダ-デコーダ構造をとっています。異なる点は「入力データにノイズを加えたデータを用いる」というところです。加えるノイズにはガウシアンノイズやごま塩ノイズなど様々なものがあります。
ノイズが加わったデータを訓練データとして与えますが、出力画像とノイズの載っていない綺麗な画像との誤差を最小化するようにモデルを学習させます。
このように学習することでノイズのかかった画像から綺麗な画像を生成することができるようになることに加え、ノイズをかけたデータに対して学習を行っているため汎化性能が通常のオートエンコーダより高くなります。
2.2 DAEの実装
では、概要が分かったところで実装してみましょう。実装は簡単で、入力データにノイズをかけ、出力データと綺麗なデータの誤差を最小化するように学習すればいいだけです。
まずMNISTデータをロードして、データローダーを作成します。
今回は畳み込み層を使わず、画像を平坦にして線形層で学習させます。
# オートエンコーダの定義
class DAE(nn.Module):
def __init__(self):
super(DAE, self).__init__()
# Encoder
self.encoder = nn.Sequential(
nn.Linear(28 * 28, 128),
nn.ReLU(True),
nn.Linear(128, 64),
nn.ReLU(True),
nn.Linear(64, 32),
nn.ReLU(True)
)
# Decoder
self.decoder = nn.Sequential(
nn.Linear(32, 64),
nn.ReLU(True),
nn.Linear(64, 128),
nn.ReLU(True),
nn.Linear(128, 28 * 28),
nn.Sigmoid()
)
def forward(self, x):
x = self.encoder(x)
x = self.decoder(x)
return x
定義自体は普通のオートエンコーダと同じであることがわかります。
# モデル、損失関数、オプティマイザの定義
model = DAE()
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
損失関数、オプティマイザを定義したら学習させます。
# トレーニングループ
num_epochs = 10
for epoch in range(num_epochs):
for data in train_loader:
img, _ = data
# ノイズの追加
noisy_img = img + 0.5 * torch.randn(img.shape)
noisy_img = torch.clamp(noisy_img, 0., 1.)
# 順伝播
output = model(noisy_img)
loss = criterion(output, img)
# 逆伝播と最適化
optimizer.zero_grad()
loss.backward()
optimizer.step()
print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')
学習させ、ノイズ除去した画像を綺麗な画像と見比べてみましょう。
少なめのデータで学習させましたが、割といいかんじにノイズ除去できていることがわかります。少しぼやけていますが、もっと多くのデータを使ってエポック数も増やしたりすればさらに精度がよくなりそうですね。