DenoisingAutoEncoderでアニメ顔の特徴を抽出してみた
Sponsored Links
皆さんこんにちは
お元気ですか。私は人生元気に仲良くフリーダムに生きています。
本日はDenoisingAutoEncoder(DAE)を使って実験してみたいと思います。
DeepLearningの重みは可視化できます。他のブログで掲載されている
可視化について殆ど、MNISTだったので、今回試しに、
アニメ顔の特徴を抽出してみました。
データセット
今回の実験ではanimeface-character-datasetを使います。
Tile化して表示させるのが面倒だったので、Finderのスクリーンショットで
お許し下さい。
※7/13追記:animeface-character-datasetはanimeface-character-datasetから手に入ります。
ソースコード
Chainerを使って記載しました。大部分のDAEのコードは
Implementation of stacked denoising autoencoder using BriCA1 and Chainer.を参考にしました。ありがとうございます。
AnimeFaceの読み込み
#coding:utf-8 import cv2 import glob import numpy as np class AnimeFaceDataset(object): def __init__(self,folder,reshape_size=28): self.data_list = self.image_read(folder,reshape_size) def image_read(self, folder,reshape_size): data_list = [] for file in glob.glob(folder): image = cv2.resize(cv2.cvtColor(cv2.imread(file),cv2.COLOR_BGR2GRAY),(reshape_size,reshape_size)) data_list.append(np.reshape(image,reshape_size * reshape_size) / 255.0) return np.array(data_list,dtype=np.float32) def getImages(self): return self.data_list
DenoisingAutoEncoder
#coding:utf-8 from chainer import Variable, FunctionSet, optimizers, cuda import chainer.functions as F import numpy as np class DenoisingAutoEncoder(object): def __init__(self, input_size, hidden_size): self.model = FunctionSet( encode = F.Linear(input_size, hidden_size), decode = F.Linear(hidden_size, input_size) ) self.use_cuda = False self.optimizer = optimizers.Adam() self.optimizer.setup(self.model.collect_parameters()) def encode(self,x): return F.sigmoid(self.model.encode(x)) def decode(self,x): return F.sigmoid(self.model.decode(x)) def cost(self, x, loss_param): if self.use_cuda: x = cuda.to_gpu(x) lost_x = x * np.random.binomial(1, 1 - loss_param,len(x[0])) x_variable = Variable(lost_x) t_variable = Variable(x) y = self.encode(x_variable) z = self.decode(y) return F.mean_squared_error(z, t_variable) def train(self, x, loss_param): self.optimizer.zero_grads() loss = self.cost(x, loss_param) loss.backward() self.optimizer.update() return float(cuda.to_cpu(loss.data)) def predict(self, x): x_variable = Variable(x) y_variable = self.model.encode(x_variable) return cuda.to_cpu(y_variable) def getWeight(self): return self.model.encode.W
実行
#coding:utf-8 import AnimeFaceDataset import DenoisingAutoEncoder import numpy as np import Visualize import cv2 reshape_size = 50 animeFaceDataset = AnimeFaceDataset.AnimeFaceDataset("./animeface-character-dataset/thumb/*/*.png",reshape_size=reshape_size) data = animeFaceDataset.getImages() batch_size = 64 N = len(data) n_epoch = 70 visualize = Visualize.Visualizer() for loss_param in [0.0,0.1,0.2,0.3,0.5]: dae = DenoisingAutoEncoder.DenoisingAutoEncoder(reshape_size * reshape_size,500) for epoch in range(1, n_epoch+1): print('epoch', epoch) if epoch == 1: tile = visualize.convert(dae.getWeight(), reshape_size, (20,20)) cv2.imwrite("./training_result/weight_tile_t_%f_%d.png" % (loss_param,0), tile) perm = np.random.permutation(N) sum_loss = 0.0 for i in xrange(0, N, batch_size): x_batch = data[i:i+batch_size] sum_loss = sum_loss + dae.train(x_batch, loss_param=loss_param) print sum_loss / N tile = visualize.convert(dae.getWeight(), reshape_size, (20,20)) cv2.imwrite("./training_result/weight_tile_t_%f_%d.png" % (loss_param,epoch), tile)
Visualizer
こちらは、Theano tutrialを参考にして作成しました。
#coding:utf-8 import numpy as np import cv2 class Visualizer(object): def __init__(self): pass def scale_to_unit_interval(self,ndar, eps=1e-8): ndar = ndar.copy() ndar -= ndar.min() ndar *= 1.0 / (ndar.max() + eps) return ndar def convert(self,weights,size,tile_size = (10,10)): tile = np.zeros((tile_size[0] * size, tile_size[1] * size),dtype='uint8') tile_images = [] for weight in weights: tile_image = self.scale_to_unit_interval(weight) tile_image = np.reshape(tile_image,(size,size)) * 255 tile_images.append(tile_image) cnt = 0 for height_index in xrange(tile_size[0]): for width_index in xrange(tile_size[1]): height = height_index * size width = width_index * size tile[height:height+size,width:width+size] = tile_images[cnt] cnt = cnt + 1 return tile
特徴量抽出結果
初期状態
欠損率0.0
欠損率0.1
欠損率0.3
欠損率0.5
誰が誰かというのはわかりませんが顔ということはわかりますね。
色々おもしろいことをやっている人は沢山いますので、様々な画像をかけてみると良いかもしれません。