#はじめに
生成系のディープラーニングであるGANの勉強をしています。
GANって身近に何か活用する手段がないのかと思考を巡らせていたところ、思い付きました。
AI(ここではGAN)に美女とは何かを学ばせ、AIが定義する美女の写真を出力させてみようと。
美を追求する皆様に読んでいただければと思います。
※たいした示唆はないので、あらかじめご容赦ください。
GANをまじめに勉強するのであれば、別の記事の方がいいです。
#美とは
美しさとは何か。
有名な説に平均顔仮説が知られています。
複数の顔画像を足し合わせると魅力的な顔になるという仮説です。
なぜ魅力的になるか色んな説があるのですが、
例えば、平均化すると左右対称な顔になるが、左右対称性は生理学的な安定性を表すからだとか、
平均から外れることは突然変異(有害なことが多い)の可能性があり避ける傾向にあるからだとか
平均化することで肌がすべすべになるからとかです。
本当かよ
ということで、実際に見てみると
【引用】平均顔は美人顔? | 美容整形|大塚美容形成外科 横浜院 公式
確かに、美しい。
主張しすぎない控え目そうなところがまたグッドです。
でも、平均顔仮説には反論もあるようで、
実際には一般人の顔写真を平均化するよりも、芸能人の顔を平均化した方がより魅力的に感じるとか
やっぱり特徴のない平均顔は魅力的といえど、最も魅力的な顔は生まれないとか言われているみたいです。
じゃあ、アプローチを変えて、平均化などせずにAIに魅力的な顔そのものを学ばせて、美女をそのまま生成させればよいのではないか。
ということで、やってみます。
#写真の収集
まずはAIに学ばせる美女の写真を集めました。
特定のワードで検索してヒットした画像を集めました。
「美女」とか「美人」とかの言葉に加え、このサイトを参考に日本の人が美女と感じる人約55人の名前も検索対象としました。
1ワードにつき400件抽出したので、データ数は22,000件となりました。
ちなみに、どんな画像が抽出されたというと・・・
こんなのとか
・・・あれ、一部想定外の画像が含まれました。
この辺はまじめに手作業で削除してしまいます。
結局、1.4万件くらいのデータ数になりました。
1.4万枚も美女の画像を見せられたら、心のないAI君といえど、さすがに美女とは何か感じ取ってくれることでしょう。
#参考:検索語リスト
search_words = ["美人 顔","美女","橋本環奈","石原さとみ","北川景子","新垣結衣","佐々木希","深田恭子","沢尻エリカ",
"新木優子","綾瀬はるか","桐谷美玲","広瀬すず","長澤まさみ","柴咲コウ","本田翼","比嘉愛未","山本美月",
"浜辺美波","白石麻衣","堀北真希","中条あやみ","川口春奈","有村架純","吉岡里帆","木村文乃","菅井友香",
"菜々緒","永野芽郁","ローラ","戸田恵梨香","鈴木えみ","齋藤飛鳥","長谷川潤","上戸彩","黒木メイサ","新川優愛",
"波瑠","広瀬アリス","今田美桜","小松菜奈","大政絢","西野七瀬","二階堂ふみ","生田絵梨花","清野菜名",
"土屋太鳳","小芝風花","貴島明日香","西内まりや","小坂菜緒","与田祐希","松岡茉優"]
収集方法についてはこちらを参考にしてください。
Pythonで画像を収集する方法
#実装
美女生成用コードは下記の通りです。
Google Colab上で実装しています。
※長いので別記事にしました。
#コードの解説
実装コードの中身をご説明します。
###美女を生み出すAI
美女を生み出すAIです。
人間でいうと、メイクアップアーティストとか美容師みたいなもんだとイメージしていただければと思います。
class Generator(nn.Module):
def __init__(self, z_dim=20, image_size=64):
super(Generator, self).__init__()
# ...
return out
128ピクセルサイズの美女を生み出します。
###本物の美女か偽物の美女かを判断するAI
本物の美女の画像か美女を生み出すAIが作った画像かを見分けるAIです。
この人は自分では美女を生み出すことはせず、あくまでも出来上がったものに対して口を挟むだけです。
そういう意味では、美容評論家とかファッション評論家みたいなイメージをしていただければと思います。
class Discriminator(nn.Module):
def __init__(self, z_dim=20, image_size=64):
super(Discriminator, self).__init__()
# ...
return out
###本物の美女を呼び出す
美女を連れてくる人が必要です。
たくさんの知り合いの美女の中から数人ずつ呼び出しては、美容評論家に紹介します。
パリピーみたいな人をイメージをしていただけばと思います。
class ImageTransform():
"""画像の前処理クラス"""
# ...
class GAN_Img_Dataset(data.Dataset):
"""画像のDatasetクラス。PyTorchのDatasetクラスを継承"""
# ...
# ファイルリストを作成
train_img_list = glob.glob(folder+"/*")
# Datasetを作成
mean = (0.5,)
std = (0.5,)
train_dataset = GAN_Img_Dataset(
file_list=train_img_list, transform=ImageTransform(mean, std))
# DataLoaderを作成
batch_size = 16
train_dataloader = torch.utils.data.DataLoader(
train_dataset, batch_size=batch_size, shuffle=True)
batch_sizeが一度に呼び出す美女の数です。
今回はカラーの美女のため、多すぎ注意です。
欲張ると、美容評論家が評論をやめてクラッシュしてしまいます。
###評論会
メイクアップアーティストと美容評論家が戦います。
メイクアップアーティストによって美しくなった美女たちとパリピーが連れてきた美女たち
美容評論家は彼女らの美貌の中の真実を見抜くことができるのでしょうか。
# モデルを学習させる関数を作成
def train_model(G, D, dataloader, num_epochs):
# ...
return G, D
# ネットワークの初期化
def weights_init(m):
# ...
# 初期化の実施
G.apply(weights_init)
D.apply(weights_init)
print("ネットワークの初期化完了")
# 学習・検証を実行する
# 時間がかかる
num_epochs = 300
G_update, D_update = train_model(
G, D, dataloader=train_dataloader, num_epochs=num_epochs)
#ビーナスたちの生誕
いよいよ、検証です!
出でよ美人たち!
import torchvision
# 美女を可視化する
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 入力の乱数生成
batch_size = 16 #今回は16人
z_dim = 40
fixed_z = torch.randn(batch_size, z_dim)
fixed_z = fixed_z.view(fixed_z.size(0), fixed_z.size(1), 1, 1)
# 画像生成
G_update.eval()
fake_images = G_update(fixed_z.to(device))
fig = plt.figure(figsize=(25, 16))
fake_images = torchvision.utils.make_grid(fake_images, nrow=8, padding=1)
plt.imshow(fake_images.cpu().detach().numpy().transpose((1,2,0)))
どうですか!
新たな美女たちがここに誕生しました。
えっ、好みじゃない?ちょっと怖い・・・?
人のタイプはそれぞれですからね
好きな人は好きだと思いますよ
美少女コンテストの実装
美少女コンテストを実装しましょう。
50人の候補の中から、1番美容評論家の評価が高かった美女が優勝です。
# 美少女コンテスト
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
# 入力の乱数生成
batch_size = 50 #参加者は50人
z_dim = 20
fixed_z = torch.randn(batch_size, z_dim)
fixed_z = fixed_z.view(fixed_z.size(0), fixed_z.size(1), 1, 1)
# 美女の生成
G_update.to(device)
G_update.eval()
fake_images, am1, am2 = G_update(fixed_z.to(device))
# 評論
D_update.to(device)
D_update.eval()
d_out_fakes, _, _ = D_update(fake_images)
beauty_num = np.argmax(nn.Sigmoid()(d_out_fakes).cpu().detach().numpy())
# 優勝者の表示
fig = plt.figure(figsize=(15, 6))
plt.imshow(fake_images[beauty_num].cpu().detach().numpy().transpose((1,2,0)))
栄えある美少女コンテスト受賞者は・・・
おおお、お?
目はパッチリ、口元はちょっとこわい感じ、服装はAKBっぽい??
審査員の好みが反映された結果となりました。
#最後に
ここまで読んでいただきありがとうございました。
人気ランキング上位の有名人の画像をもとに自分だけの美女をつくってみました。
「最近だと非常に高精度な顔画像を生成できるようになっている中、何だこの精度は!?」とおしかりを受けるかもしれませんが、お許しください。
ただ、使った画像データは手作業で選択したといえど、結構なゴミが混じっているので、思ったより顔っぽくなってびっくりしました。
別の記事を調べている中では、画像データを20万枚くらい使って、精密な顔画像を書いている人もいました。※リンクはこちら
純粋にデータ数を増やせば、納得いく結果が得られるのでしょうか。
GANに使える顔画像のデータセットとして有名なものにCelebAデータセットというものが有名だそうです。
※【参考】CelebAデータセット
この辺も勉強のため、どこかでチャレンジしてみたいと思います。
あと、GANを実行するにはコンピュータのスペックがかなり必要なこともわかりました。
今回の128ピクセル画像の生成では100エポックの学習に12時間くらいかかっています。
データ数を増やすとなると、Colab環境では厳しいかもしれませんが、これも勉強ついでにどこかでチャレンジしてみます。
以上、家で暇つぶしで書きました。
失礼しました!