けの〜のブログ

ガッキーでディープラーニングして教育界に革命を起こす

Udacity始めました

一通りinputも終わったので実装経験と2周目ということでUdacityのオンラインコースを受講し始めました!

 

今回は実装に重点を当てて取り組んでいけたらと思います。

実装はgithubに上げて行く予定です!

 

今興味ある分野はAI×Roboticsということでゴリゴリ実装できるよう頑張るぞー!

動画から画像を切り出す

extractframes.py

import cv2
import os

def extract_frames(input_file, output_directory):
    '''
    extract frames from a video and save them in jpg
    input_file: file path of a video ここに動画データを格納する 形式はmp4
    output_directory: file path where frames will be saved  画像の保存先をここに入れる
    '''
    # TODO: rewrite this!
    try:
        os.makedirs(output_directory)
    except:
        pass

    vidcap = cv2.VideoCapture(input_file)

    success,image = vidcap.read()
    count = 0
    success = True

    while success:
        print('reading a frame: ', count)
        success,image = vidcap.read()

        output_file_path = os.path.join(output_directory, '{}.jpg'.format(count))
        cv2.imwrite(output_file_path, image)

        count += 1

if __name__ == '__main__':
    extract_frames('videos/0.mp4', 'frames/0')
extractface.py

import cv2
import glob
import os

OUTPUT_IMAGE_SIZE = (128, 128)
# CASCADE_PATHは自分のどこに"haarcascade_frontalface_alt.xml"があるかのpathを通す
CASCADE_PATH = '/usr/local/opt/opencv/share/OpenCV/haarcascades/haarcascade_frontalface_alt.xml'
cascade = cv2.CascadeClassifier(CASCADE_PATH)

def extract_faces(input_directory, output_directory):
    '''
    extract faces from frames and save them in jpg (128 * 128)
    input_directory: file path to where frames are stored (will be created by extractframes.extract_frames())
    output_directory: file path where faces will be saved
    '''

    # TODO: rewrite this!
    try:
        os.makedirs(output_directory)
    except:
        pass

    frame_files = glob.glob('{}/*'.format(input_directory))
    cnt = 0

    for frame_file in frame_files:
        try:
            print('processing {}'.format(frame_file))

            image = cv2.imread(frame_file)
            image_gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
            image_h, image_w = image.shape[:2]
            face_rect_min_size = int(min(image_h, image_w) / 4)
            facerect = cascade.detectMultiScale(image_gray, scaleFactor=1.1, minNeighbors=1, minSize=(face_rect_min_size, face_rect_min_size))

            if not len(facerect) == 1:
                continue

            rect = facerect[0]

            x, y = rect[0], rect[1]
            w, h = rect[2], rect[3]

            cv2.imwrite(os.path.join(output_directory, '{}.jpg'.format(cnt)), cv2.resize(image[y:y+h, x:x+w], OUTPUT_IMAGE_SIZE))
            cnt += 1
        except Exception as e:
            # TODO: rewrite this!
            print(e)
main.py

import extractface
import extractframes
from pathlib import Path
import glob

def get_faces_from_video(input_file):
    # TODO: replace this!
    name = input_file.replace('videos/', '').replace('.mp4', '')

    # get frames from video
    extractframes.extract_frames(input_file = 'videos/{}.mp4'.format(name), output_directory = 'frames/{}'.format(name))

    # get faces from frames
    extractface.extract_faces(input_directory = 'frames/{}'.format(name), output_directory = 'faces/{}'.format(name))


if __name__ == '__main__':
    for file_name in glob.glob('videos/*'):
        get_faces_from_video(file_name)

Cycle GAN Unpaired Image to Image Translation

前回の記事で解説したPix2PixGANの発展形

Pix2PixGANではある画像Xとある画像Yがセットとなっており、XからYへの変換を学ぶためのGANであった。

 

しかしこのようにある画像Xに直接対応する画像Yが存在するデータ群を揃えることは難しい。

 

そこで考案されたのがCycleGANである。

ある種類の画像xのデータの集合をドメインXと呼ぶ(ガッキーの写真の集合はガッキードメイン)

またある画像yのデータの集合をドメインYと呼ぶ(女性の写真の集合は女性ドメイン)

このドメインXからドメインYへの写像、変換を行うのがCycleGANである。

つまり、ガッキーと同じポーズをしている女性の画像がなくても、変換を学ぶということである。

 

このためにまず元来のGANのように、ターゲットとなるデータの集合と分布が同じようになるようにGeneratorを学習させ、

さらにGeneratorが作った画像を元の画像に直すものを学習させ、データが矛盾しないようにする。

 

具体的にどのようなことを行なっているか??

XとYというのは対となる画像でーたセットではないが、XドメインとYドメインの間の関係を学習させようという試み。

個々のinput xがうまくYドメインのy dataのように変換されるためにcycle consistantという考えを用いている。

イメージとしては

英語の文章をフランス語に翻訳するというときに、翻訳されたフランス語を再度英語に翻訳し直し、その英語が元の文章の意味を保っているか??という工夫である。

 

 

Generatorについて

 

 

 

Discriminatorについて

 

 

損失関数について

 

 

実装について

 

 

 

参考

https://www.slideshare.net/DeepLearningJP2016/dlharmonic-networks-deep-translation-and-rotation-equivariance

元の論文

[1703.10593] Unpaired Image-to-Image Translation using Cycle-Consistent Adversarial Networks

 

 

Pix2Pix Image to Image Translation

画像変換などのタスクではどのようなものを損失関数とするかが大きな課題であった。

"現実のものと見分けがつかないような画像を作る"

という目標を達成してくれるのが

GAN(generative adversarial network)であった。

 

Pix2Pixのこの論文では

GANのモデルがデータを作り出すモデルを学習するように、conditional GAN がconditionalなgenerative modelを学習する。

Conditional GANは image to image transitionの問題に対しての良いアプローチのように思われる

ある入力に対して、ある出力を返すように設定する。

 

Pix2Pixの論文では

様々な種類の問題において、Conditional GANが良い結果を出したこと、

良い結果を出すためのフレームワークを提示したことが意義のあることだとしている。

 

これまでの先行研究ではpixelごとに分類や回帰していたがこれにより構造的な関係が考慮されていなかった。

Conditinal GANは構造的な関係も学習する。

これまでのConditional GANと異なりPix2Pixは様々なタスクに対応できる。

またGeneratorに"U-net" の構造を用いて

DiscriminatorにPatchGANを用いている。

Conditional GANは image xとノイズzからoutput yを作り出す

U-netとはbottle netを通さずにoutputへ通すもの

Patch GANはある領域ごとにDiscriminatorを舐めて行き、平均をとるというもの。

少ない数のパラメーターで行える。

元の論文

[1611.07004] Image-to-Image Translation with Conditional Adversarial Networks

 

 

GANについて DCGAN,CycleGAN

ネット上で参考にした情報のまとめ

 

ネット上で参考にした記事を備忘録的に記録しました

https://elix-tech.github.io/ja/2017/02/06/gan.html

http://tech-blog.abeja.asia/entry/everyday_gan

 

 

GAN(Generative Adversarial Net)について

概要

訓練データを学習しそれらのデータと似たような新しいデータを育成するモデルのことを生成モデルと呼びます。別の言い方をすると、訓練データの分布と生成データの分布が一致するように学習していくようなモデルです。GANはこのような生成モデルの一種です。

 

通常、モデルが持つパラメータ数に対して訓練データの量が圧倒的に大きいため、モデルは重要な特徴を捉えることを求められます。

 

GAN以外にもVAE(Variational Autoencoder)などあります。GANは学習が不安定だが他の手法に比べてくっきりとした画像が生成される傾向があるようだ。

 

GANの仕組み

GANではGeneratorとDiscriminatorという二つのネットワークが存在する。

Generatorは訓練データと同じようなデータを生成しようとします。一方、discriminatorはデータが訓練データから来たものか、それとも生成モデルから来たものかを識別します。

紙幣の偽造者と警察の関係のように、お互いが偽札を作るため、偽札を見破るために技量を上げていく、という例え話がよくされるらしい。

Discriminatorが、与えられたデータが訓練データなのか生成データなのか見分けられなくなルような状態ではDiscriminatorの正答率は50%になるようだ。

 

GANのObjectiveについて

具体的にどのように学習を行うか。

ガッキーの画像について考えていきたいと思う。

xというのがガッキーの画像データ(Discriminatorが訓練データと判定しなければいけないデータ)で、xはある確率分布P data(x)に従っているとする。

 

zはノイズを表す、このzは何らかの事前に決めた分布 Pzに従う要素。

Generatorはzを入力として、偽物を作り出す。

f:id:keno-lasalle-kagoshima:20171218134406p:plain

DiscriminatorはD(x)=1

GeneratorはD(G(z))=1

またDiscriminatorはD(G(z))=0

を出力するように学習する。

学習時はDiscriminatorとGeneratorを交互に更新していく。

Discriminatorがうまく分類できるようになるとD(x)は大きくなり、また偽物だとバレてD(G(z))は小さくなる。

逆にGeneratorがうまく偽物を作れるようになるとD(G(z))は大きくなる。

この学習で良い偽物を作れる理由を述べたいと思います。 以下 pzG(z)から誘導される確率分布pg(x) と書くことにすると、 良い偽物が作れるようになる理由は、この最適化問題の global optimum が pg(x)pdata(x)が一致する時だからです。以下でそれを確認します。

まず、G を固定した際、最良の DG は以下のように計算できます。 objective L

L(G,D)=pdata(x)log(D(x))dx+pz(z)log(1D(G(z)))dz=pdata(x)log(D(x))+pg(x)log(1D(x))dx

と書き直せますが、f(x)=alog(x)+blog(1x) の最大値は x=a/(a+b)で取るから

DG=pdatapdata+pg

となります。これを用いてちょっと計算すると

maxDL(G,D)=Expdata[log(pdatapdata+pg)]+Expg[log(pgpdata+pg)]=log(4)+2JS(pdata||pg) .

ここで JS は Jensen-Shannon divergence。JS は pdata=pg となる際に最小値を取るので、上式はこの時に最小となります。

以上をまとめれば、objective L を min max 最適化をしていけば、 確率分布が一致するという意味で G は対象の data を良く模倣できるようになる、というのが理論的な根拠となります。

DCGAN(Deep Convolutional GAN)について

CNN(Convolutional Neural Network)を用いたモデル

CNNを使ったGANで最初に高解像度画像の生成に成功したのはLAPGANらしいが、何段にも分けて画像を生成する必要があったらしい。

DCGANでは一発で高解像度画像を生成することに成功したようだ。

 

またGANは学習が難しいことが知られているが、学習をうまく進めるための様々なテクニックが紹介されているようだ。

poolingをやめる

全結合層ではなくglobal average poolingを行いDiscriminatorで出力する(安定性は増すが収束が遅くなるようだ)

Batch Normalizationを使う

各層でのデータ分布を正規化することで学習を速くしたりパラメーターの初期化をそれほど気にしなくてもよくなる。過学習を防ぐ効果もあるようだ。

Generatorの出力層とdiscriminatorの入力層には適用しないようにする。

 

参考記事

https://elix-tech.github.io/ja/2017/02/06/gan.html

http://tech-blog.abeja.asia/entry/everyday_gan

 

 

 

remoteの動かし方 備忘録

 cd #ディレクトリ
 vim 〇〇.pem #ここにパーミッションキーを入れて
 chmod 600 〇〇.pem #これで認証して
   ssh -i key.pem ubuntu@address #これでリモートに接続
 nvidia-smi #性能確認
 exit; #退出
   ls -lht #一覧表示
 ps au #実行中のファイルを表示
 scp -i ○.pem ○.py ubuntu@address #ローカルのファイルをリモートにコピー
 nohup python3 ○.py & #リモート上で実行(接続が切れても実行を続ける)
 kill PID number #実行を止める





Efficient Methods and Hardware for Deep Learning

近年モデルサイズが大きくなっており、学習にかかる時間やエネルギーが大量に必要となってしまう。

またスマホなどへのアプリケーションもメモリの関係から難しくなる。

 

そこでどのようなアルゴリズムを用いたら効率化、省エネ化できるかということが検討されている。

Pruning

ニューロンの90%を不活性化してまた学習し直しても精度が落ちずにできるようである。

重みの値が小さいものを除くらしい。

人間のシナプスの数も生まれた時50trilionあって、一歳の時には1000trillionになるが、青年期になると500trillionになるようだ。

 

Weight Sharing

重みで1,98,1.88,2.12,2.03

のような重みは2で表す

ということにより必要なビット数を少なくすることができる。

重みの更新の際にも傾きを大体の数で表して更新するということもあるようだ。

 

Huffman coding

 

Squeeze net

1×1の畳み込み層を使い、全結合層を無くしパラメーターの数を少なくする

 

Quantization

重みの分布から最大値、最小値を考慮しbit数を決める

 

重みを学習させたら推測の際には-1,0,1 を使う

 

GPUも改良が進んでいるみたい