2017年08月07日

アイドルに関するデータ取得~分析:3.1 フォロワーのプロフィール文分析

久々に更新。今回はアイドルアカウントのフォロワーの方々のプロフィール文で使用されている単語の頻度を集計し、wordcloudで可視化してみました。

初めはwindows+Rで格闘してたんですが、全角・半角・英数・文字コードの処理系がRは相当面倒でしたので、pythonをbash on Ubuntu on windowsで使いました。スクリプトは以下のサイトを参考にしました。ありがとうございます。
Word Cloudで文章の単語出現頻度を可視化する。[Python]
スクリプト実行の下準備として①形態素解析用の辞書のダウンロード、②日本語フォントのダウンロードを行いました。

①形態素解析用の辞書はmecab-ipadic-NEologdを使いました。こちらの辞書は新語を週2回のペースで追加更新されているとのことで、とても高性能な辞書として至る所で使われているそうです。私の方でもその威力を試してみました。まずデフォルトのmecabの辞書で{木村拓哉,℃-ute,岡井千聖,梁川奈々美}の4単語を形態素解析にかけてみます。

木村 名詞,固有名詞,人名,姓,*,*,木村,キムラ,キムラ
拓哉 名詞,固有名詞,人名,名,*,*,拓哉,タクヤ,タクヤ
℃- 名詞,サ変接続,*,*,*,*,*
ute 名詞,固有名詞,組織,*,*,*,*
岡井 名詞,固有名詞,人名,姓,*,*,岡井,オカイ,オカイ
千聖 名詞,固有名詞,人名,名,*,*,千聖,チヒロ,チヒロ
梁川 名詞,固有名詞,人名,姓,*,*,梁川,ハシカワ,ハシカワ
奈々美 名詞,固有名詞,人名,名,*,*,奈々美,ナナミ,ナナミ

対して、mecab-ipadic-NEologdを使った場合は、

木村拓哉 名詞,固有名詞,人名,一般,*,*,木村拓哉,キムラタクヤ,キムラタクヤ
℃-ute 名詞,固有名詞,人名,一般,*,*,℃-ute,キュート,キュート
岡井千聖 名詞,固有名詞,人名,一般,*,*,岡井千聖,オカイチサト,オカイチサト
梁川奈々美 名詞,固有名詞,人名,一般,*,*,梁川奈々美,ヤナガワナナミ,ヤナガワナナミ

完璧。。素晴らしいですね。。。。

②matplotlib.pyplotで図を出力するときに日本語のフォントが必要だったので、以下のコマンドで新しく日本語フォントをダウンロードしました。

sudo apt-get install fonts-noto-cjk fonts-noto-hinted

スクリプトで、辞書とwordcloudのフォントパスを指定する部分は以下のように書き換えています。
辞書指定部分
t = mc.Tagger(''-d /usr/lib/mecab/dic/mecab-ipadic-neologd'')
wordcloudのフォントパス指定部分
font_path="/usr/share/fonts/opentype/noto/NotoSansCJK.ttc"

下準備は以上で終わりです。
ではwordcloudの結果です。※1つの図に同じ単語がいくつか出てるのは処理をどこかで失敗してるのかも。

・モーニング娘。
MorningMusumeMgProfile.png

・℃-ute
Cute_upfrontProfile.png

・JUICE=JUICE
JuiceJuice_ufProfile.png

・アンジュルム
angerme_upfrontProfile.png

・カントリー・ガールズ
countrygirls_ufProfile.png

・こぶしファクトリー
kobushifac_ufProfile.png

・つばきファクトリー
tsubakifac_ufProfile.png

・Berryz工房
Berryz_koboProfile.png


どのグループも結構同じ単語({ハロプロ,好き,ちゃん,さん,大好き,フォロー,アイドル,垢,アンジュルム,年,モーニング娘。,中,℃-ute,無言,ハロヲタ,世代,こと,応援}など)が出てます。プロフィールに推しメンの名前を書いている方がかなり多く、それに関連して{好き,ちゃん,さん,大好き}などが上位に出ています。
Twitterっぽいワードは{フォロー,垢,無言}でしょうか。多分{垢}の意味はヲタク用垢という意味でつかわれています。無言は、無言フォロー=Twitter上で絡んだことがないアカウントをいきなりフォローすることを指します。{世代}という言葉も重要です。ご自身の年令を、{同い年のメンバー名 + 世代}という風に表している方が多いです。年令が想像できるワードは他にも{大学生}とか{JK}とかがありました。

各グループの特徴を見るために、単語の発生頻度の上位50のうち、他のグループの単語の発生頻度上位50に含まれない単語があるかを見てみましたが、どのグループも含まれない単語がない(=ユニークな単語がない)という結果になりました。このブログの以前の記事でハロプロヲタの方々は複数のグループをフォローしていると言いましたが、その影響だと思います。他のグループをフォローしていないヲタクのプロフィールに絞ってやるとよかったのかも。

48グループのメンバーの方のアカウントもやってみました。

・松井珠理奈さん
170721_JURINA38GFollowersProfile.png
気になるワードがありました。プロレス(←中央下黄色く"推し"の"推"と"し"の間にあります)、新日本プロレス(中央の黄色の乃木坂の下にあります)。それぞれ出現数は1944(40位),675(151位)。松井さんはプロレスが好きだそうで、プロレスの仕事をしてらっしゃいます。プロレスコミュニティから松井珠理奈さんをフォローされているようです。

・鎌田菜月さん
nacky_k829FollowersProfile.png
{推し}の下に将棋という文字があります。趣味が将棋とのことで、将棋コミュニティからフォローされているようです。Twitterのヘッダーの画像も将棋でした。そういえば乃木坂にも将棋のお仕事をしている方がいらっしゃった気がします。あらゆるジャンルにアイドルがいる、とても素晴らしいことだと思います。

・髙畑結希さん
takahatayuki718FollowersProfile.png
松井珠理奈さんと鎌田菜月さんの時より、メンバー名が現れているような気がします。フォロワーのDD度が高いのかもしれません。
松井さん、鎌田さん、高畑さんの3人を対象にしましたが、傾向として総選挙の順位が高い方ほど、AKBと一見関係なさそうなワードが出てきてそうな気がします(松井さん3位、鎌田さん44位、高畑さん78位)。渡辺麻友さんとかどういうワードが出てくるんでしょう。次の課題にします。
posted by 石田泰浩 at 02:47| Comment(0) | アイドル | 更新情報をチェックする

2017年06月17日

℃-ute。ありがとう。

ラストコンサート in さいたまスーパーアリーナ ~Thank you team℃-ute~を見てきました。
チケットはファンクラブ先行抽選、e+先行抽選、ローチケ先行抽選、チケットぴあ先行抽選で全て落選していたのですが、沖縄のFCツアーで同室だった方が私がチケットを持っていないことを知って、Twitterで定価で譲ってくれる方を探してくれて、しかもその方に料金を先払いしてくださって確保していただきました。本当にteam℃-ute(℃-uteファンの総称)は優しい方が多い。。感動しました。。

会場はステージが見えない席(いわゆる音席)ですらチケットはソールドアウト。グッズを買うために前日からさいたまスーパーアリーナに並んだ強者が100名程おり、当日のグッズ列は3000人以上並んだそうです。現場で話した知り合いは、7時から並んで購入できたのが13時だったと言っていました。私は到着が遅かったので断念(しかしほとんどがFC通販で買えるので、まあOK)。

ラストコンサートはこれまで参加したライブの全て(パフォーマンス、演出、盛り上がり、楽しさ)を塗り替えるものでした。解散コンサートではなく、夢のステージでのコンサートという気持ちでメンバーもファンもライブを楽しんでいたんだと思います(それでもやはり最後であることに感極まって涙を流すメンバーを見て私は泣いてしまったのですが)。最後にウエディングドレスで現れた彼女たちを見て娘が嫁に行くときの父親の気持ちがわかった気がしました。サプライズで現れた道重さゆみさんが℃-uteのことを「アイドルを超えたとてつもないすごい者たち」と表現されてましたが、本当にそう思います。

ハロー!プロジェクトのYouTubeオリジナル番組のハロステでラストコンサートの裏側が紹介されています(41分20秒~。)。

ステージを降りた後の映像(45分15秒~)は、初めて見ましたが、、なんというか、、泣けますね。

応援できたのは半年という短い期間ですが、本当に幸せでした。メンバーの皆様には感謝の言葉しかありません。

矢島舞美さん
こんなに美人さんで性格の良さがにじみ出て、愛された方は知りません。メンバーからもファンからも心から「舞美ちゃんには幸せになってほしい」と口を揃えて言ってしまうほど、天使のような女性です。初めての握手会で「また来ます」とお伝えした時に「待ってる!」と笑顔で言われた時のドキドキは忘れません。SSAでの舞美さんの思い出曲、「まっさらブルージーンズ」も感動的で何度も録画した映像を見返しています。このコンサートの演出で一番鳥肌が立ちました。今後矢島さんは女優さんとして次のステージに進まれるとのことですので、舞台などの現場があれば職場の方々を誘って必ず見に行きます。

中島早貴さん
パフォーマンスが抜群にかっこいいです。「Danceでバコーン」の可動域は言わずもがな、「The Curtain Rises」の間奏のダンスとかかっこよくて大好きでした。春ツアーは何度も見に行きましたが、中島早貴さんの回替わり演出(「ベーグルにハム&チーズ」→「私が本気を出す夜」)を実は1番楽しみに見に行ってました。中島さんの歌声・煽りもかなり好きでした。「情熱エクスタシー」とか「いざ、進め!Steady go!」とか。そういえば、「いざ、進め!Steady go!」は生で聴けなかったなあ。「君の戦法」は恐ろしくかわいい中島早貴さんが見れます。今後中島さんも矢島さんと同じく女優さんとしての道を進みますが、現場があれば絶対見に行きます。あと島島(矢島さんと中島さんのお2人を指す愛称)バスツアー絶対やってください。本当に楽しみにしています。

鈴木愛理さん
初めて参加したナルチカでこんなに可愛い女性いるのかと思いました。しかも可愛いだけじゃなくて、歌・ダンスが抜群にうまくて、最強のアイドルだと思っています。そんな彼女ですが、℃-ute史を学ぶと、エースとしてプレッシャーの中で戦ってきた、強い女性ということがわかります。沖縄に参加したときにも「SHOCKを初めてファンの前で披露したときの景色が、今まで見た景色の中で一番嫌な景色だった」と涙ながらに語る鈴木さんを見ていたので、SSAでSHOCKを歌う姿を見てうるっときました。今後鈴木さんはソロで歌手活動を続けるとのこと。その決意を聞いて私も含め、周りのteam℃-uteは本当に喜んでいました。鈴木さんの現場には行って応援し続けますので、その時はよろしくお願いします(何をだ)。

岡井千聖さん
普段バラエティ番組に出ているおバカな岡井さんからは想像できないほど、ライブの岡井さんって本当にかっこいいんです。歌声がパワフルでロックで力強くて。「Midnight Temptation」の君の本性と、「嵐を起こすんだ Exceiting Fight」の太陽に近づけないと、「愛はまるで静電気」のまあナンセンスな議論とか何度巻き戻して聞いたことか。鈴木さんとのツインボーカルの「悲しきヘブン」は、世間一般のアイドルの域に収まらない、本当にかっこいい曲です(またこれも℃-ute史を学べばわかりますが鈴木さんと岡井さんが共に認め合うライバル関係で、その2人が見つめあって歌うっていうことも、この曲の良さなんですよ)。SSAでは岡井さんメインの曲である「僕らの輝き」が聴けたのが本当に嬉しかったです。この曲は岡井さんメインの曲で、私が℃-uteの歌の中で一番好きな曲。生で一度も聞けてなくて、歌ってほしいなあと思っていたんですが、ギターがジャラーーーン!となった瞬間、ぶるっと震え、「千聖ー!!!」と叫びました。応援できた期間は半年という短い間でしたが、岡井千聖さんを知れて本当によかったなあと思います。バラエティに進む岡井さんですが、会える機会はあるのかなあ。もしファンクラブ企画やってくれのであれば、地球の裏側でも行きます。岡井さん、よろしくお願いします。

萩原舞さん
人類の末っ子、萩原さん。メンバーとのやり取りを見てると本当に可愛がられてるなあと私はいつもニッコニコで見てました。これもまた℃-ute史で重要ですが、変声期を迎えて歌が上手く歌えなくなってしまった彼女。ライブは口パクで参加させてくれてくれとマネージャーさんに頼んだ時期もあったそうですが、頑張って歌い続けてくれました。℃-uteの歌唱メンは矢島さん鈴木さん岡井さんですが、中島さんと萩原さんのメイン曲って本当にteam℃-uteは大好きなんですよね。「Everyday絶好調」「Shines」「都会っ子」「大きな愛でもてなして」(新規だからメイン曲じゃない曲も入ってるかもですが)。萩原さんは芸能界を引退されますが、我々ファンは舞ちゃんが幸せになることを祈っています。


最後に今年参加した現場を振り返ってみます。
握手会2回
ナルチカ3回
ひなフェス1回
春ツアー11回
沖縄FCバスツアー1回(3日)
シリイベ3回
CD発売記念イベント6回
ラジオ公録1回
ディナーショー1回
ラストコンサート1回
----
計30回

初現場が1月28日の握手会だったことを考えると、そこから解散までが20週間なので、1週間に1.5回のペースで現場入りしています。かなり楽しませてもらいましたし、℃-uteの皆さんもかなり大変なスケジュールをこなしてくれたんだなあと思います。同じセトリの公演をこんなに繰り返し行くこともないんだろうなあ。

本当に楽しかったし幸せでした。℃-uteさん、本当にありがとう。
DCMkpSIUQAAH_4F.jpg
写真はラストコンサート前に岡井さんヲタで写真を撮りましょうと呼びかけがあったので、そこに混ぜてもらったときの写真。

---
解散と同時に中島早貴さん、鈴木愛理さん、岡井千聖さんがinstagramを始めました。instagramに興味ゼロだった私ですが、そのことを知った10秒以内にinstagramのアカウントを作っていました。ちょろいですね、ヲタクって。

となると、instagramの分析がしたくなったのですが、instagram APIの利用が許可制で、その審査が厳しいことがわかって断念。そもそもクローリング目的だと駄目っぽいですね(こちらの記事参照)。色々とアイデアがあったんですが。。
posted by 石田泰浩 at 02:00| Comment(0) | ℃-ute | 更新情報をチェックする

2017年06月04日

アイドルに関するデータ取得~分析:2.1 アイドルの顔認識

℃-uteファン歴半年のド新規なのですが、先日バスツアーに参加しました。
初日はお昼にメンバー5人との6ショット。バスガイドさん姿がとても神々しく、一生の思い出になりました。夜はディナートークショーにカラオケ大会。ロマモが生で聴けて岡井千聖さんファンとして心から感動しました。前半ラストのultra soulもとても盛り上がり、ウルトラソウル!のタイミングの会場全体で全力ジャンプは最高でした。後半ラストchoo choo trainでも会場全体で踊りが発生して、こんな楽しいカラオケは今後ないだろうなあと思います。
2日目は朝はシーサーの色塗りで中島早貴さん、鈴木愛理さんが降臨。シーサーにサインを入れてもらい、お二人が見回る中色を塗っていきます。皆さんシーサーの色を見れば推しメンがわかるような色塗りをしていました。私も緑多めに塗りました。ランチでは岡井千聖さん、萩原舞さんのトークショー。お二人はお互いの恥ずかしい動画を公開しあって、会場を沸かせました。夕方は矢島舞美さんが琉球の姫に扮し、演奏+歌を聞かせてくれました。夜はミニライブ。個人的にはズンタカマーチ、ハエ男、ひょっこりひょうたん島が聴けて嬉しかったです。
最終日はファンのつ℃い。抽選会の後、メンバーへのサプライズで、各メンバーのファン代表2人ずつがメッセージを読み上げる企画がありました。順番は萩原舞さんからだったのですが、、一瞬で泣いてしまいました。というのも沖縄に行く前日にメンバーの方々が解散後のご自身の活動についてブログを書かれていて、矢島舞美さん、中島早貴さん、鈴木愛理さん、岡井千聖さんについては芸能界に残るとのことだったのですが、萩原舞さんは芸能界を引退されるとのことを述べており、萩原舞さんのファン代表の方の言葉は非常に胸に刺さりました。メンバーからファンへのメッセージもファンへの愛に溢れて、その言葉を聞けて本当に幸せな気持ちになれました。バスツアーで泣いちゃったので、さいたまスーパーアリーナは私は絶対泣くんだろうなあと思います。


さて、今回はGWにアイドルの顔認識に取り組んだのでその備忘録(Twitterのアイドルアカウントの分析は別で進めています)。以下はこれまでにアイドルを対象に顔認識に取り組まれた方々。

私のお題はもちろん℃-uteさん。

手順は次の通りです。
1.画像の収集
2.画像加工
3.ラベル付け
4.モデル学習

かけた時間の比率は0.5:0.5:8:1ぐらいだと思います。スクリプトを公開してくださっている方のおかげで、ラベル付け以外はそれほど苦労しませんでした。


1.画像の収集
Twitterから℃-uteメンバーの写真を取得しました。対象アカウントがTwitterに上げた画像をスクレイピングで取得していきます。アカウントは℃-ute STAFF@Cute_upfront
画像取得は以下のサイトを参考にいたしました。ありがとうございます。
こちらで紹介されているスクリプトの19-25行目の認証関係と、
32-36行目のところを
SCREEN_NAMES = '''Cute_upfront'''
としただけ。

こちらのスクリプトを実行し、Cute_upfrontアカウントがTwitterにあげた画像700枚を収集できました。
scraping.PNG


2.画像加工
画像から顔の部分を切り取ります。顔の抽出にはGoogle Cloud Vision APIを使ってみたかったので、これを利用し、顔の座標特定。OpenCVを組み合わせて切り取り。
画像加工はこちらのサイトを参考にいたしました。ありがとうございます。

こちらで紹介されているスクリプトを複数の画像で実行できるように少し変更しました。
・imagesで画像ファイル名取得
・for文でimages全てを画像加工

#!/usr/bin/python
#coding:utf-8
import cv2
import os
import sys
import base64
import json
import requests
import glob
#import subprocess
# APIのURL

# APIキー
api_key = ''
#画像ファイル名取得
images = glob.glob('*.jpg')
#画像の数だけ実行
for input in images:
    print input
    #リクエスト用のデータ作成
    with open(input, 'rb') as image:
        base64_image = base64.b64encode(image.read())
        data = {
            'requests': [{
                'image': {
                    'content': base64_image,
                },
                'features': [{
                    'type': 'FACE_DETECTION',
                    'maxResults': 10,
                }]
                
            }]
        }
        # リクエスト送信
        header = {'Content-Type': 'application/json'}
        response = requests.post(api_url + api_key,  json.dumps(data))#, header)
        # 分析結果の取得
        if response.status_code == 200:
            #print response.text
            json_response = json.loads(response.text)
            # 顔認識の結果が含まれていれば切り出す
            if json_response['responses'][0].has_key('faceAnnotations'):
                # 認識できた顔の数だけループ
                for i, face in enumerate(json_response['responses'][0]['faceAnnotations']):
                    # 顔画像位置
                    vertices = [(v.get('x', 0.0), v.get('y', 0.0)) for v in face['fdBoundingPoly']['vertices']]
                    #print vertices
                    # 顔画像の切り出し
                    src = cv2.imread(input)
                    dst = src[int(vertices[0][1]):int(vertices[2][1]), int(vertices[0][0]):int(vertices[2][0])]
                    dst = cv2.resize(dst, (112,112))
                    # 顔画像の出力パスを作成
                    root, ext = os.path.splitext(input)
                    face_image_path = root + '_face' + str(i) + ext
                    # 顔画像の出力
                    cv2.imwrite(face_image_path , dst)
            else:
                print u'顔が認識されませんでした'
        else:
            print 'Http response error'

プログラムを画像が入ったフォルダに入れて動かすと、顔の切り出しが完了です。
VisionAPIによる前処理後.PNG


3.ラベル付け
目と手を使って振り分けました。左は岡井千聖さん、右は中島早貴さんです。
label.PNG

教師なしで似てる顔を分類してくれるGooglePhotoに全て入れれば大分楽できるなとは思いながらも、自力で3-4日かけて泥臭くやりました(ニコニコしながら)。この作業は好きな写真じゃなかったらなかなか辛いと思います。結果、メンバーごとに以下のフォルダに写真を分け終わりました。
memberfolder.PNG


4.モデル学習
TensorFlowを使いました。

こちらで紹介されているスクリプトを参考にしました。ありがとうございます。
訓練データ・テストデータの画像とラベルの一覧ファイル(train.txtとtest.txt)は下画像の通りに準備(1列目に画像ファイルのパス、2列目にラベル(矢島さんであれば0、中島さんであれば1、鈴木さんであれば2、岡井さんであれば3、萩原さんであれば4とした))。訓練データとテストデータの比率は877枚:218枚です。
train_test.PNG

NUM_CLASSESは5(メンバーの数)に変更。また、tensorflowのバージョン移行に対応して、少し修正しました。


#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import cv2
import numpy as np
import tensorflow as tf
import tensorflow.python.platform

NUM_CLASSES = 5
IMAGE_SIZE = 112
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3

flags = tf.app.flags
FLAGS = flags.FLAGS
flags.DEFINE_string('train', 'train.txt', 'File name of train data')
flags.DEFINE_string('test', 'test.txt', 'File name of test data')
flags.DEFINE_string('train_dir', 'メンバーのフォルダを置いたディレクトリ', 'Directory to put the training data.')
flags.DEFINE_integer('max_steps', 200, 'Number of steps to run trainer.')
flags.DEFINE_integer('batch_size', 10, 'Batch size'
                     'Must divide evenly into the dataset sizes.')
flags.DEFINE_float('learning_rate', 1e-4, 'Initial learning rate.')

def inference(images_placeholder, keep_prob):
    """ 予測モデルを作成する関数

    引数: 
      images_placeholder: 画像のplaceholder
      keep_prob: dropout率のplace_holder

    返り値:
      y_conv: 各クラスの確率(のようなもの)
    """
    # 重みを標準偏差0.1の正規分布で初期化
    def weight_variable(shape):
      initial = tf.truncated_normal(shape, stddev=0.1)
      return tf.Variable(initial)

    # バイアスを標準偏差0.1の正規分布で初期化
    def bias_variable(shape):
      initial = tf.constant(0.1, shape=shape)
      return tf.Variable(initial)

    # 畳み込み層の作成
    def conv2d(x, W):
      return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    # プーリング層の作成
    def max_pool_2x2(x):
      return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                            strides=[1, 2, 2, 1], padding='SAME')
    
    # 入力を112x112x3に変形
    x_image = tf.reshape(images_placeholder, [-1, 112, 112, 3])

    # 畳み込み層1の作成
    with tf.name_scope('conv1') as scope:
        W_conv1 = weight_variable([5, 5, 3, 32])
        b_conv1 = bias_variable([32])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    # プーリング層1の作成
    with tf.name_scope('pool1') as scope:
        h_pool1 = max_pool_2x2(h_conv1)
    
    # 畳み込み層2の作成
    with tf.name_scope('conv2') as scope:
        W_conv2 = weight_variable([5, 5, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

    # プーリング層2の作成
    with tf.name_scope('pool2') as scope:
        h_pool2 = max_pool_2x2(h_conv2)

    # 全結合層1の作成
    with tf.name_scope('fc1') as scope:
        W_fc1 = weight_variable([7*7*64, 1024])
        b_fc1 = bias_variable([1024])
        h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
        # dropoutの設定
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

    # 全結合層2の作成
    with tf.name_scope('fc2') as scope:
        W_fc2 = weight_variable([1024, NUM_CLASSES])
        b_fc2 = bias_variable([NUM_CLASSES])

    # ソフトマックス関数による正規化
    with tf.name_scope('softmax') as scope:
        y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

    # 各ラベルの確率のようなものを返す
    return y_conv

def loss(logits, labels):
    """ lossを計算する関数

    引数:
      logits: ロジットのtensor, float - [batch_size, NUM_CLASSES]
      labels: ラベルのtensor, int32 - [batch_size, NUM_CLASSES]

    返り値:
      cross_entropy: 交差エントロピーのtensor, float

    """

    # 交差エントロピーの計算
    cross_entropy = -tf.reduce_sum(labels*tf.log(logits))
    # TensorBoardで表示するよう指定
    tf.scalar_summary("cross_entropy", cross_entropy)
    return cross_entropy

def training(loss, learning_rate):
    """ 訓練のOpを定義する関数

    引数:
      loss: 損失のtensor, loss()の結果
      learning_rate: 学習係数

    返り値:
      train_step: 訓練のOp

    """

    train_step = tf.train.AdamOptimizer(learning_rate).minimize(loss)
    return train_step

def accuracy(logits, labels):
    """ 正解率(accuracy)を計算する関数

    引数: 
      logits: inference()の結果
      labels: ラベルのtensor, int32 - [batch_size, NUM_CLASSES]

    返り値:
      accuracy: 正解率(float)

    """
    correct_prediction = tf.equal(tf.argmax(logits, 1), tf.argmax(labels, 1))
    accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
    tf.scalar_summary("accuracy", accuracy)
    return accuracy

if __name__ == '__main__':
    # ファイルを開く
    f = open(FLAGS.train, 'r')
    # データを入れる配列
    train_image = []
    train_label = []
    for line in f:
        # 改行を除いてスペース区切りにする
        line = line.rstrip()
        l = line.split()
        # データを読み込んで112x112に縮小
        print(l[0])
        img = cv2.imread(l[0])
        #img = cv2.resize(img, (112, 112))
        # 一列にした後、0-1のfloat値にする
        train_image.append(img.flatten().astype(np.float32)/255.0)
        # ラベルを1-of-k方式で用意する
        tmp = np.zeros(NUM_CLASSES)
        tmp[int(l[1])] = 1
        train_label.append(tmp)
    # numpy形式に変換
    train_image = np.asarray(train_image)
    train_label = np.asarray(train_label)
    f.close()

    f = open(FLAGS.test, 'r')
    test_image = []
    test_label = []
    for line in f:
        line = line.rstrip()
        l = line.split()
        img = cv2.imread(l[0])
        #img = cv2.resize(img, (112, 112))
        test_image.append(img.flatten().astype(np.float32)/255.0)
        tmp = np.zeros(NUM_CLASSES)
        tmp[int(l[1])] = 1
        test_label.append(tmp)
    test_image = np.asarray(test_image)
    test_label = np.asarray(test_label)
    f.close()
    
    with tf.Graph().as_default():
        # 画像を入れる仮のTensor
        images_placeholder = tf.placeholder("float", shape=(None, IMAGE_PIXELS))
        # ラベルを入れる仮のTensor
        labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
        # dropout率を入れる仮のTensor
        keep_prob = tf.placeholder("float")

        # inference()を呼び出してモデルを作る
        logits = inference(images_placeholder, keep_prob)
        # loss()を呼び出して損失を計算
        loss_value = loss(logits, labels_placeholder)
        # training()を呼び出して訓練
        train_op = training(loss_value, FLAGS.learning_rate)
        # 精度の計算
        acc = accuracy(logits, labels_placeholder)

        # 保存の準備
        saver = tf.train.Saver()
        # Sessionの作成
        sess = tf.Session()
        # 変数の初期化
        sess.run(tf.initialize_all_variables())
        # TensorBoardで表示する値の設定
        summary_op = tf.merge_all_summaries()
        summary_writer = tf.train.SummaryWriter(FLAGS.train_dir, sess.graph_def)
        
        # 訓練の実行
        for step in range(FLAGS.max_steps):
            for i in range(len(train_image)/FLAGS.batch_size):
                # batch_size分の画像に対して訓練の実行
                batch = FLAGS.batch_size*i
                # feed_dictでplaceholderに入れるデータを指定する
                sess.run(train_op, feed_dict={
                  images_placeholder: train_image[batch:batch+FLAGS.batch_size],
                  labels_placeholder: train_label[batch:batch+FLAGS.batch_size],
                  keep_prob: 0.5})

            # 1 step終わるたびに精度を計算する
            train_accuracy = sess.run(acc, feed_dict={
                images_placeholder: train_image,
                labels_placeholder: train_label,
                keep_prob: 1.0})
            print "step %d, training accuracy %g"%(step, train_accuracy)

            # 1 step終わるたびにTensorBoardに表示する値を追加する
            summary_str = sess.run(summary_op, feed_dict={
                images_placeholder: train_image,
                labels_placeholder: train_label,
                keep_prob: 1.0})
            summary_writer.add_summary(summary_str, step)

    # 訓練が終了したらテストデータに対する精度を表示
    print "test accuracy %g"%sess.run(acc, feed_dict={
        images_placeholder: test_image,
        labels_placeholder: test_label,
        keep_prob: 1.0})

    # 最終的なモデルを保存
    save_path = saver.save(sess, "model.ckpt")


終わるまで30分ぐらいだったかと思います。最後にコマンドラインで以下を実行。

tensorboard --logdir (スクリプトを実行したディレクトリ)

実行後以下にアクセスすると、tensorboard(モデルの精度、学習過程をグラフで見せてくれる)が見れるようになります。


tensorboard.PNG


画像は訓練データの的中精度です(一度ガクンと精度が落ちてるところがありますが、原因調査までは至れていません)。訓練データについては80ステップ程で精度100%まで達していました。

最後にテストデータの精度をチェック。

#!/usr/bin/env python 
#! -*- coding: utf-8 -*-
import sys
import numpy as np
import tensorflow as tf
import cv2


NUM_CLASSES = 5
IMAGE_SIZE = 28
IMAGE_PIXELS = IMAGE_SIZE*IMAGE_SIZE*3

def inference(images_placeholder, keep_prob):
    """ モデルを作成する関数

    引数: 
      images_placeholder: inputs()で作成した画像のplaceholder
      keep_prob: dropout率のplace_holder

    返り値:
      cross_entropy: モデルの計算結果
    """
    def weight_variable(shape):
      initial = tf.truncated_normal(shape, stddev=0.1)
      return tf.Variable(initial)

    def bias_variable(shape):
      initial = tf.constant(0.1, shape=shape)
      return tf.Variable(initial)

    def conv2d(x, W):
      return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')

    def max_pool_2x2(x):
      return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],
                            strides=[1, 2, 2, 1], padding='SAME')
    
    x_image = tf.reshape(images_placeholder, [-1, 28, 28, 3])

    with tf.name_scope('conv1') as scope:
        W_conv1 = weight_variable([5, 5, 3, 32])
        b_conv1 = bias_variable([32])
        h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)

    with tf.name_scope('pool1') as scope:
        h_pool1 = max_pool_2x2(h_conv1)
    
    with tf.name_scope('conv2') as scope:
        W_conv2 = weight_variable([5, 5, 32, 64])
        b_conv2 = bias_variable([64])
        h_conv2 = tf.nn.relu(conv2d(h_pool1, W_conv2) + b_conv2)

    with tf.name_scope('pool2') as scope:
        h_pool2 = max_pool_2x2(h_conv2)

    with tf.name_scope('fc1') as scope:
        W_fc1 = weight_variable([7*7*64, 1024])
        b_fc1 = bias_variable([1024])
        h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
        h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, W_fc1) + b_fc1)
        h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

    with tf.name_scope('fc2') as scope:
        W_fc2 = weight_variable([1024, NUM_CLASSES])
        b_fc2 = bias_variable([NUM_CLASSES])

    with tf.name_scope('softmax') as scope:
        y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2)

    return y_conv

if __name__ == '__main__':
    test_image = []
    for i in range(1, len(sys.argv)):
        img = cv2.imread(sys.argv[i])
        img = cv2.resize(img, (28, 28))
        test_image.append(img.flatten().astype(np.float32)/255.0)
    test_image = np.asarray(test_image)

    images_placeholder = tf.placeholder("float", shape=(None, IMAGE_PIXELS))
    labels_placeholder = tf.placeholder("float", shape=(None, NUM_CLASSES))
    keep_prob = tf.placeholder("float")

    logits = inference(images_placeholder, keep_prob)
    sess = tf.InteractiveSession()

    saver = tf.train.Saver()
    sess.run(tf.global_variables_initializer())
    saver.restore(sess, "model.ckpt")

    for i in range(len(test_image)):
        accr = logits.eval(feed_dict={ 
            images_placeholder: [test_image[i]],
            keep_prob: 1.0 })[0]
        pred = np.argmax(logits.eval(feed_dict={ 
            images_placeholder: [test_image[i]],
            keep_prob: 1.0 })[0])
        print pred,accr


テストデータの精度は75%ぐらいでした。パラメータチューニングをしない状態でそれぐらいの精度出るんですね。明日は春ツアー千秋楽@名古屋で朝早いので半端ですが、今回はここで終わり!
続きを読む
posted by 石田泰浩 at 02:31| Comment(0) | アイドル | 更新情報をチェックする