プレゼンテーションZENを読んだ
学生時代に研究室の教員から「これくらいは流石に読んでるよな?」と煽られたにも関わらず読んでなかった「プレゼンテーションZEN」を読みました。
ZENは「禅」を指しています。その名の通りこの本ではプレゼンが成功する方法ではなく、良いプレゼンをするための考え方やアプローチが書かれています。
ここでは、読んでいて心に刺さった点を幾つか挙げます。
プレゼンテーションの主役は自分
当たり前ですが、プレゼンの主役はPowerPointではありません。話をする自分自身です。そもそもPowerPointで全てを説明できるとしたらスピーカーは不要です。それに下で述べるようにPowerPointはテキストを詰め込むツールとしては適切ではありません。 人がプレゼンを行う際には、必ずその人にしか伝えられないアイディア、経験があります。PowerPointやKeynoteなどのプレゼンテーションツールは、スピーチを引き立たせるための補助的な役割でしかないのです。
この考え方に立つことで、スライドを作るアプローチが劇的に変わると思います。「情報を載せなきゃ」というマインドで作るスライドと、「自分が話したいことをどうやって引き立たせるか」というマインドで作るスライドではきっと完全に違うものが出来上がるでしょう。
悪しき習慣のスライデュメント
本の中で著者は「スライドはシンプル」にと何回も説いています。スライドはスライドとして、資料は資料として用意するべきである、と。そして、スライドと資料が混ざったものを「スライデュメント」(Slide + Document)と呼び、それは非常に中途半端で良くないものであると主張しています。スライデュメントとは、スライド一面が大量の文字で埋め尽くされたり、箇条書きで埋まったりしているようなスライドのことを指しています。
しかし、現在ビジネスの場ではこの「スライディメント」が多く見られます。むしろPowerPointを使ってプレゼンする際の基本的な形とさえなっています。著者はこれを「一石二鳥だと思っている人がいるかもしれないが、二兎追う者は一兎も得ずである」とバッサリ切り捨てています。たしかに、PowerPointのスライドは、詳細を事細かに書けるようにはなっていませんし、文字を詰め込んだところで聴衆から読めなくなってしまっては意味がありません。詳細を伝えたいならWordなどで資料を作成して、それを後で読んでもらえばいいのです。
「究極的に何が言いたいのか」を考え抜く
自分が聴衆として聞く場合を想像するとわかると思いますが、100%の集中力でプレゼンを聞き続けるなんてことは不可能です。だいたいどこかで集中力が切れます。 だからこそ、準備の段階で「自分はプレゼンを通して聴衆に何を伝えたいのか」を考え抜き、それが伝わるような構成でプレゼンテーションを組まなければなりません。プレゼンを作る際には、「聴衆はたった自分のプレゼンの中でたった1つのことしか記憶に残らない」というつもりで作るべきなのです。
プレゼンを作っているとついつい色んなことをスライドに書きすぎてしまいますが、可能な限り削るべきです。ZENでは、プレゼンの準備に必要なのは「抑制」であると説いています。伝えたいことを詰め込みすぎて、聴衆の集中力が切れてしまったら最後、そのプレゼンは誰の記憶にも残らないものとなってしまいます。可能な限りシンプルに行くべきなのです。
上記に書いたのはまさにプレゼンテーションにおける禅のような考え方や姿勢でしたが、この本にはスライドを作る際のデザインの原則や、スピーチの場において必要なことなど、実践的なこともかなり載っています。スライドのサンプルもかなり多いです。今後も何かとプレゼンをする機会はあるので、この本を参考にして、禅のような精神で鍛錬を積みたいと思います。
GoogleCalendarAPIを使ってGoogleCalendarの予定を取得する
お題通りです。+ α程度の情報は載せていますが、基本的には公式のQuickStart通りに進めました。言語はPythonです。
Step1: Google Calendar APIを有効にする
自分のGoogleアカウントでGoogle Developers Consoleにログインします。初めての場合は「規約に同意して進む」みたいな画面が出るので、一通り確認して進みます。
認証が終わると自動的にAPIを使うためのProjectが作成されます。 「認証情報の追加」というメニューが出てきますが、APIを使うのに必要なのはClient IDなので「クライアントID」と書かれたリンクをクリックして次に進みます。
OAuth同意画面に飛ばされるので、必須項目のサービス名を記入して次へ。(他に記入できる項目があれば記入してください) アプリケーションの種類と名前(適当でもいいです)を入力して「作成」ボタンを押すとクライアントIDとシークレットキーが作成されます。
こんな感じです。右端のダウンロードのマークをクリックしてjsonファイルをダウンロードし、client_secret.jsonという名前にリネームしてプログラムを置く予定のフォルダに保存します。
Step2: Pythonライブラリのインストール
pipで入れるだけ。
pip install --upgrade google-api-python-client
Step3: サンプルスクリプトを動かす
サンプルのスクリプトquickstart.py
が公開されているので、これをコピーします。
Step4: 実行
あとはpythonで叩くだけ。
python quickstart.py
ブラウザが立ち上がって、Googleアカウントの認証をできればOK。 サンプルのスクリプトは、実行したタイミングから未来の予定10件を取得するようにできています。
補足
これだけだとちょっと寂しすぎるので、少しだけ補足を。
認証情報の保管
quickstart.py
実行時にブラウザを使って認証を行いましたが、これは最初だけです。2回目以降は普通にAPIが使えます。
この時の認証情報が$HOME/.credentials/
以下に保存されています。
APIの仕様
こちらのサイトに使えるメソッドが載っています。
予定の書き込み
quickstart.py
では、予定の読み込みの例しか載っていません。
書き込みの例を簡単に紹介します。やることは主に3つ程度です。
1. SCOPEの変更
quickstart.py
の20行目
SCOPES = 'https://www.googleapis.com/auth/calendar.readonly'
この最後のreadonlyを省きます。
2. 認証情報を削除
このままだと上記のreadonly権限での認証情報が残ってしまっているため、Permission Deniedで弾かれます。 $HOME/.credentials以下の認証情報ファイルを削除します。
3. イベントを挿入するソースコードを記述
quickstart.py
でイベントを取得している箇所を、以下のような感じに書き換えます。
event = { 'summary': 'Sample Event from Python', 'start': { 'dateTime': '2017-04-28T09:00:00', 'timeZone': 'Asia/Tokyo', }, 'end': { 'dateTime': '2017-04-29T19:00:00', 'timeZone': 'Asia/Tokyo', }, 'recurrence': [ 'RRULE:FREQ=DAILY;COUNT=2' ], } calendarId = 'xxxxxxx@gmail.com' # 自分のカレンダーID(例えば、メールアドレス名)を入れる event = service.events().insert(calendarId=calendarId, body=event).execute()
FGO英霊クラス判定器
久しぶりの更新になりました. 2016年は定期的に更新しようと意気込んでたにも関わらず,完全放置になってしまっていました. 今年の目標は「技術に対して積極性を持つこと」「精神的な余裕を持つこと」です.去年は修論のために専門の技術を追いかけるのに精一杯だったので,今年はより多方面に関心を持って過ごしたいと思います.
ということで2017年ブログ第1弾は「FGO英霊クラス判定」にしました. 概略を言うとFate Grand/Order(FGO)というスマホゲームのキャラがどのクラスに属するかを機械学習で識別しよう,という試みです.
実装時の言語はpythonで,深層学習ライブラリのKerasと,機械学習・確率統計で誰もがお世話になるであろうライブラリScikit-Learnを使用します.ツール・ライブラリのインストールについてはこの記事では触れません.
注:このブログではFGOのキャラクター名を例に出して説明するため,Fate作品の(多少の)ネタバレに繋がる恐れがあります.これからFate作品を楽しもうと思っている方は,お気をつけください.
動機
画像系の深層学習に触れてみようと思ったのがきっかけでした.研究では音声・言語を扱っていたんですが,画像方面には全く縁がなかったので.
画像分野の深層学習研究では,近年CNN(Convolutional Neural Network)によるオブジェクト認識のタスクにおいて著しい発展が見られています.試しに調べてみるとアニメ画像におけるキャラクター認識というのは結構やられていて,ラブライブやごちうさのキャラクター認識を行ったという記事が見つかります.
この記事では,キャラクター認識ではなくキャラクター属性認識をしようと思います.スマホゲームのFate Grand/Orderにスマホゲームに登場する英霊(キャラクター)の属するクラスの認識です.単純なキャラクター認識よりも難易度が高そうであるのと,Twitterのアイコンなどを使って自分がどのクラスに属するかを推定する,といったアプリケーションへの応用が見込めることが大きな理由です.
システムの概略図としては次のような形になっています.キャラクターの画像を学習済みのVGGnet(CNNの一つ)に入力することでその中間層から特徴量を抽出し,それを用いてRandom Forestなどの識別モデルの学習を行います. ここは機械学習に馴染みのない人にとっては聞きなれない単語だらけだと思いますが,後ほど説明します.
タスク設計
最初にFGOについてです.Fate作品,ゲームの内容については特にこの記事と関係が無いので触れません. 大事なのは登場するキャラクターが歴史,神話上に登場する過去の英雄(英霊)で,基本的に7つのクラスのどれかに割り当てられていることです.
7つのクラスは次のとおりです.
- セイバー(剣)
- アーチャー(弓)
- ランサー(槍)
- ライダー(騎)
- キャスター(術)
- アサシン(殺)
- バーサーカー(狂)
これに加えて,エクストラクラスというのが存在します.なので,正確には全部で8クラス存在します.
例えば,次のイラストはアーサー王であり,セイバーのクラスに属しています.(「性別・・・」とかそういうツッコミは無しです.)
それぞれの英霊は自身に由来のあるクラスに属することが多いです. またイラストでも,剣を持っていたり弓を持っていたりと,それなりの特徴を備えています.
一方で例外もあります.
このキャラクターは弓を持っていないですがアーチャーのクラスに属します. (詳細はFate stay/nightを見てください)
今回のゴールは、英霊の画像を入力してその英霊のクラスを推定するシステムを作ることです. 各キャラクターとそれが属するクラスの関係は曖昧ですが,その曖昧さを機械学習の仕組みを利用してモデル化することを目的とします.
データ収集・前処理
最初に画像の収集です.公式のゲームイラストを実際のゲームや攻略サイトなどから集めました.FGOではキャラクターのイラストが立ち絵固定のため,アニメのように1コマ1コマを学習データにするということができません.各キャラクターごとに進化後のイラストが3枚存在するためそれも収集し,以下の500枚程度の画像が集まりました.
クラス | 枚数 |
---|---|
セイバー | 76 |
アーチャー | 69 |
ランサー | 85 |
ライダー | 64 |
キャスター | 96 |
アサシン | 72 |
バーサーカー | 69 |
エクストラ | 28 |
かなり少ないですが他に集める手段となると創作二次絵などになってしまうため,とりあえずこのデータのみを使います. 本当でしたら数千〜数万枚のイラストが必要なところです.
使用するニューラルネットは入力の画像サイズが固定で,224x224になっている必要があります.そのため集めたデータをニューラルネットに入力できる形に整形する前処理を行います.次の三つの処理を行いました.
1.枠のトリミング 持ってきた画像には,外側の枠に英霊のクラスや,ゲーム内でのランク(星の数),強さなどキャラクターの画像以外の情報が含まれています. そのため,上下の枠をトリミングしキャラクターのみが映るようにします.
2.キャラクターのトリミング 使用するニューラルネットは入力画像が正方形でないといけないため,1でトリミングした画像を、横幅に合わせてトリミングします.この際,画像の下側は多少見切れてしまいます.
3.リサイズ 224x224に画像をリサイズします.
左が元画像,右がトリミング・リサイズを行った画像です.
特徴量抽出
Convolutional Neural Network(CNN)という,画像系で近年素晴らしい性能を叩き出しているニューラルネットワークを用います. CNNの説明はこの記事が分かりやすかったので気になる人は参照してください. 今回はCNNを学習モデルとしてではなく,特徴量抽出器として用います.オブジェクト認識で用いられているCNNは,その中間層の出力が物体を識別するのに有効な特徴を持つことが知られています. そこで,学習済みのCNNに画像を入力した際の中間層の値を抽出し,それを画像の特徴量とします. 特徴量とはその名の通りデータの特徴を表すベクトルになります.
学習済みのCNNに,VGGnetというニューラルネットワークを用います.ILSVRC2014というオブジェクト識別,分類のコンテストにて非常に良い性能を叩き出したニューラルネットワークです.ILSVRCは,ある画像が入力された際にそこに映っている物体(オブジェクト)が用意された1000カテゴリ(クラス)のどれであるかを当てるタスクです.
VGGnet
VGGnetについて簡単に説明します.最初のシステム概略図でちらっと登場しましたが,VGGnetは以下のような構造をとっています.VGGnetに限らずCNNは畳み込み層(Convolution Layer)とプーリング層(Pooling Layer)の繰り返しによって構成されます.Conv1, Pool7などと書かれた枠がそれに相当します.ざっくり説明すると,畳み込み層,プーリング層によって画像の様々な構造(例:「斜めの線を持つか?」)を捉えることができます. その後,全結合層(Fully-Connected Layer)を複数配置します.FC14~16がそれに相当します.FC16で,入力画像は1000カテゴリのどれか,という最終的な結果が出力されます. プーリング層は学習によってパラメータが変化しないため,層としてカウントされないようです.そのため畳み込み層(Conv)と全結合層(FC)の数をニューラルネットワークの層の数としています.この例は,16層のVGGnetを表しています.
VGGnetを用いた特徴量抽出
Keras版VGGnetの学習済みモデルはこちらから入手しました.ついでに重みも取ってきます. これを用いて,画像データから特徴量を抽出します.以下その際のソースコードです.
# モデルの読み込み model = vgg16_keras.VGG_16('vgg16_weights.h5') # コンパイル sgd = SGD(lr=0.1, decay=1e-6, momentum=0.9, nesterov=True) model.compile(optimizer=sgd, loss='categorical_crossentropy') # 最終層の手前のフルコネクション層.4096ユニット. get_fc15_layer_output = K.function([model.layers[0].input, K.learning_phase()], [model.layers[-5].output]) # 画像の読み込み img = cv2.resize(cv2.imread(image_file, cv2.IMREAD_COLOR), (224, 224)).astype(np.float32) # 平均値を引く img[:,:,0] -= 103.939 img[:,:,1] -= 116.779 img[:,:,2] -= 123.68 img = img.transpose((2,0,1)) img = np.expand_dims(img, axis=0) # 中間層の値を出力 fc15_layer_output = get_fc15_layer_output([img, 0])[0]
Kerasで中間層の値を取り出す関数は上記のようにK.function
を使って設計することができます.
今回はFC15という最終層の2つ手前,4096ユニットの全結合層から特徴量を抽出しました.
識別モデルの作成
上で抽出した特徴量を用いて,識別モデルを学習します.ある英霊画像の特徴量Xが入力された際に,その英霊の属するクラスYを出力するモデルとなります.学習・識別にはRandomForestを用いました.RandomForestは弱識別器(決定木と呼ばれる)を複数作成し,その結果を統合して値を出力する手法です.動作が非常に軽くて使いやすいのが魅力ですかね.
今回ですが,いきなり8クラスは難しそう(というか難しかった)ので,セイバー,ランサー,アーチャーの3クラスで識別を行いました. この3クラスにした理由は,どのクラスの英霊のイラストも,そのクラスを象徴する武器が描かれているためです. セイバークラスの英霊はだいたい剣を持っている,ランサークラスの英霊はだいたい槍を持っている,アーチャークラスの英霊はだいたい弓を持って・・・いないかもしれませんが持っている人もいます.まあそういった特徴的な画像を用いないと識別が困難だろうという予想のもと選びました.他のクラスは,ライダーなのに剣を持っているとか,ややこしいのが多かったのでそもそも難しそうなんですよね.
学習データは上記の画像計230枚でした.このデータセットを20分割し,19個をモデルの学習用,1個を性能を確認するためのテスト用として,20分割交差検定を行いました.最終的な精度は20回テストした平均の精度を採用します.
コードは以下のとおりです.
import numpy as np import os from sklearn.cross_validation import KFold import sys from data_loader import DataLoader from rf_trainer import RandomForestTrainer if __name__ == '__main__': # 対象クラス train_servant = ['saber', 'archer', 'lancer'] data_loader = DataLoader('config.ini') trainer = RandomForestTrainer() X = [] # データ Y = [] # ラベル # 学習データ読み込み for name in train_servant: x, y = data_loader.get_servant_feature(name) X += x Y += y # K分割交差検定 n_folds = 20 kf = KFold(len(X), n_folds=n_folds) total_score = 0 for train_index, test_index in kf: model = trainer.train(np.array(X)[train_index], np.array(Y)[train_index]) score = trainer.predict(model, np.array(X)[test_index], np.array(Y)[test_index]) total_score += score print("Score: %s" % round(total_score / n_folds, 3))
DataLoader,RandomForestTrainerは自作のクラスで以下のようになっております.
# -*- coding: utf-8 -*- import glob import numpy as np import os import ConfigParser class DataLoader: def __init__(self, config_file): self.servants = { 'saber': 0 , 'archer': 1, 'lancer': 2, 'rider': 3, 'caster': 4, 'assassin': 5, 'berserker': 6, 'extra': 7 } cfg = ConfigParser.SafeConfigParser() cfg.read(config_file) self.data_root_dir = cfg.get('Data', 'root_dir') self.feature_type = cfg.get('Data', 'feature_type') self.data_ext = cfg.get('Data', 'data_ext') def get_servant_feature(self, servant_class_name): """サーヴァントのクラスを指定してデータを取ってくる params - servant_class_name: 7騎のうちのどれか """ if not servant_class_name in self.servants.keys(): print("Error! There is no servant"); return None, None X = [] Y = [] servant_data_dir = os.path.join(self.data_root_dir, servant_class_name) file_pattern = '%s/*_%s.%s' % (servant_data_dir, self.feature_type, self.data_ext) data_files = glob.glob(file_pattern) for data_file in data_files: data = np.loadtxt(data_file) X.append(data) Y.append(self.servants[servant_class_name]) return X, Y
# -*- coding: utf-8 -*- from sklearn.ensemble import RandomForestClassifier from sklearn.externals import joblib class RandomForestTrainer: def __init__(self): self.model = RandomForestClassifier() def train(self, train_data, train_label, output_dir_path=None): self.model.fit(train_data, train_label) if not output_dir_path is None: joblib.dump(model, output_dir_path) return self.model def predict(self,model, test_data, test_label): score = self.model.score(test_data, test_label) return score
検証
上記のスクリプトを実行して得られた結果,正解率は残念ながら33.1%程度でした.低い.ほぼチャンスレートですね.
一応,試しに使ってみます.3クラスに属する英霊の画像は学習で使ってしまったので,他のクラスの英霊がもし3クラスのどれかに割り当てられるとしたら・・・という想定でテストを行います.
保存したモデルを読み込み,画像から得られた特徴量をモデルに入力して出力のクラスを得ます.出力されるのは0〜2の数字で,各クラスに対応しています.
import numpy as np from sklearn.ensemble import RandomForestClassifier from sklearn.externals import joblib model = joblib.load('model_path') # modelの保存場所 data = np.loadtxt('feature_vector_path') # 特徴量の保存場所 model.predict(data) # 識別 # 0→セイバー,1→アーチャー,2→ランサー
例1
まずは主人公のパートナーであるマシュ・キリエライト.このキャラクターはエクストラクラスに属します.
data = np.loadtxt('data/feature/extra/0000_fc15.dat') # パスはデータの場所 model.predict(data) # => array([1])
アーチャー判定が出ました.ふむ.剣っぽいものを持っているのでどっちかっていうとセイバーらしさがあると思うんですけどね.
例2
続いて2例目.これは直感に合致した例です. バーサーカーの同じキャラなんですが,進化状態によって持っている武器が違います. 左は弓を持ち,右はそれに加えて剣を持っています.
data = np.loadtxt('data/feature/berserker/0062_fc15.dat') # 左の絵 model.predict(data) # => array([1]) data = np.loadtxt('data/feature/berserker/0063_fc15.dat') # 右の絵 model.predict(data) # => array([0])
左の絵はアーチャー,右の絵はセイバーに分類されました.おぉ,それっぽい.
例3
続いて3例目,このキャラクターはアサシンのクラスなんですが,剣を持っています. セイバーに分類されてほしいところ・・・.
data = np.loadtxt('data/feature/assassin/0041_fc15.dat') model.predict(data) # =>array([1])
アーチャーでした.難しい・・・・・.
考察
上手く行かなかった理由について少し検討を行いました. 学習データが少ないのは自明なのですが,そもそも学習に用いている特徴量が識別に有効なものになっているかを調べます.
学習に用いた4096次元の特徴量はそのままでは簡単な比較ができないため,主成分分析(PCA:Principal Component Analysis)を用いて2次元に圧縮し,可視化してみました.PCAはデータ分析でよく使われる手法で,データ群をまとめてその主成分,そのデータをよく表現する成分を取り出します.
学習に用いた特徴量が識別的なものであれば,PCAを行った結果クラスごとにある程度分布が分かれているような図が得られるはずです.
ソースコードと可視化の結果です.
# -*- coding: utf-8 -*- """PCAでFC15特徴量を2次元に圧縮,プロットする""" import glob import numpy as np import matplotlib import matplotlib.pyplot as plt from sklearn.decomposition import PCA from data_loader import DataLoader if __name__ == '__main__': servants = [ 'saber', 'archer', 'lancer', 'rider', 'caster', 'assassin', 'berserker', 'extra' ] X = [] Y = [] data_loader = DataLoader('config.ini') for name in servants: x, y = data_loader.get_servant_feature(name) X += x Y += y N = 2 # 圧縮する次元数 pca = PCA(n_components=N) pca.fit(X) saber = np.array([x for i, x in enumerate(X_pca) if Y[i] == 0]) archer = np.array([x for i, x in enumerate(X_pca) if Y[i] == 1]) lancer = np.array([x for i, x in enumerate(X_pca) if Y[i] == 2]) fig, ax = plt.subplots() ax.plot(saber[:,0], saber[:,1], 'b.', label='saber') ax.plot(archer[:,0], archer[:,1], 'r.', label='archer') ax.plot(lancer[:,0], lancer[:,1], 'g.', label='lancer') ax.set_title("PCA for fgo") ax.legend(numpoints=1) # 表示 plt.show()
プロットした点が各データ,色がクラスを表しています.x軸とy軸が2次元に圧縮した際の各データの値です.
わー,見事にバラバラ.もちろん次元圧縮しているのでこの図が特徴量の全てを語っているわけではないのですが,ここまで混ざっていると識別は困難ですね.
まとめ
ということで,この記事ではFGOのキャラクターのクラス識別を取り上げました.手始めに3クラスで試しましたが,精度は全然ダメです.識別精度は上げるには,データ量を増やすこと,特徴量についてより良いものを検討すること,の2種類が課題として挙げられるでしょうか.特に後者については,実物のオブジェクト認識タスクで学習したCNNではなく,アニメ画像等で学習したCNNを用いるなどの工夫が必要かもしれません.いずれ8クラスへの拡張,アプリケーションの開発なども取り掛かりたいと思います.
PythonでMySQL(Mac,Ubuntu)
Mini Tips.
MySQL-pythonを使用します.
Mac(Yosemite)
pipでインストールするだけ
pip install MySQL-python
Ubuntu(14.04)
こちらも同様
sudo pip install MySQL-python
と思ったらなにやらエラーが
EnvironmentError: mysql_config not found ---------------------------------------- Cleaning up... Command python setup.py egg_info failed with error code 1 in /tmp/pip_build_fukuoka/MySQL-python Storing debug log for failure in /home/fukuoka/.pip/pip.log
libmysqlclient-dev
がないらしい
sudo apt-get install libmysqlclient-dev sudo pip install MySQL-python
実行テスト
次のようなテーブルをサンプルとして扱います
mysql> desc goods; +-------+-------------+------+-----+---------+----------------+ | Field | Type | Null | Key | Default | Extra | +-------+-------------+------+-----+---------+----------------+ | id | int(11) | NO | PRI | NULL | auto_increment | | name | varchar(10) | YES | MUL | NULL | | +-------+-------------+------+-----+---------+----------------+ mysql> select * from goods; +----+-------+ | id | name | +----+-------+ | 2 | chair | | 1 | desk | | 3 | pc | +----+-------+
"""mysql_test.py""" # -*- coding: utf-8 -*- import MySQLdb connection = MySQLdb.connect(db="test",user="goods") cursor = connection.cursor() sql = "select * from goods" cursor.execute(sql) # 1行だけ取得 first_row = cursor.fetchone() print first_row print "=" * 10 # (残り全行取得) result = cursor.fetchall() for row in result: print row cursor.close() connection.close()
実行結果
python mysql_test.py (2L, 'chair') ========== (1L, 'desk') (3L, 'pc')
Reveal.js + Markdownで簡単にプレゼン資料を用意する
プレゼン資料を用意するの毎回時間かかるし結構めんどくさいなー。って思ってたらReveal.jsなるものを見つけたので、早速使ってみました。 少し前に流行ってた?みたい。
導入
本家のgithubが丁寧に書かれているのでそれに従ってセットアップ。外部からMarkdownファイルを読み込めるようにしたいため、Node + Grantのフルセットアップを行います。
git clone https://github.com/hakimel/reveal.js.git cd reveal.js npm install
grunt serve
でhttp://localhost:8000にアクセスするとスライドが見れます
Markdownの埋め込み
body
のdiv class="reveal"
内で以下のように記述することで、md/test.md
を読み込んでくれます。
<body> <div class="reveal"> <!--ここから! --> <!-- Any section element inside of this container is displayed as a slide --> <div class="slides"> <section data-markdown="md/test.md" data-separator="---$" data-separator-vertical=">>>$" data-transition="zoom"> <script type="text/template"> </script> </section> </div> <!--ここまで! --> </div>
test.mdは以下
# これはReveal.jsのテストです Hello, reveal.js! --- ## Reveal.js& Markdownで ## スライド作り *** * Markdownでスライドを作ります * index.htmlにファイル名を指定して埋め込みます * たのしい✌('ω'✌ )三✌('ω')✌三( ✌'ω')✌ >>> ## ここは補足ページなどになります --- ## 利点 * とにかくMarkdownがラク * Markdown大好きマンには嬉しい * 動きがかっこいい --- ## あなたもRevealjs + Markdownでプレゼン作成のストレスを軽減しよう!
テーマの変更
メタタグのtheme
を変更することでスライドのテーマを変更できます。
<link rel="stylesheet" href="css/theme/serif.css" id="theme">
各種設定
section
タグのdata-transition
を変えることでスライドの遷移方法を変えることができます。
<section data-markdown="md/test.md"
data-separator="---$"
data-separator-vertical=">>>$"
data-transition="zoom">
data-separator ページ送りを正規表現で表します。上記例だと
---改行
でページ送りができます。data-separator-vertical 縦方向のページ送りの正規表現を指定します。
data-transition ページ遷移のアクションを指定します。
デモ
本家デモ
Juliusによる音素アライメント(音素セグメンテーション) on MacOSX(Yosemite)
オープンソースの汎用大語彙連続音声認識エンジン、Juliusを用いて音声認識ではなく強制音素アライメントを行います。 音素アライメントとはある音声ファイルに含まれる音素(分節音)の開始・終了時間を自動認識する技術となります。
事前に必要な物
Homebewを使っていれます.
- portaudio
brew install --universal portaudio
- flex
brew install flex
Julius本体のインストール
Julius
こちらから最新版のJuliusをダウンロード。今回は4.3.1。
解凍・コンパイル
tar xvzf julius-4.3.1.tar.gz cd julius-4.3.1/ env CFLAGS='-arch i386' LDFLAGS='-arch i386' ./configure --disable-mac-universal make sudo make install
単語・音素セグメンテーションキットのダウンロード
githubから落としてきます
git clone git@github.com:julius-speech/segmentation-kit.git
segmentation-kit/
直下にあるsegment_julius.pl
を修正します。segment_julius.plの45~50行目のelse文の箇所を変えます。
## julius executable if ($^O =~ /MSWin/){ $juliusbin=".\\bin\\julius-4.3.1.exe"; } else { $juliusbin="./bin/julius-4.3.1"; }
$juliusbin="./bin/julius-4.3.1";
ここのパスをインストールしたjuliusの実行場所を確認し、変更します。
$which julius > /usr/local/bin/julius
## julius executable if ($^O =~ /MSWin/){ $juliusbin=".\\bin\\julius-4.3.1.exe"; } else { $juliusbin="/usr/local/bin/julius"; }
動作確認
segmentation-kit/wav
フォルダにあるsample.wav
、sample.txt
を使用します。ちなみにwavファイルは16kHzである必要があるようです(変えられるのかな?)。
sample.txt
のテキストはこんな感じ。ひらがなで書きます。
きょーわいいてんきだ
wavファイルと書き起こしのtxtファイルを用意し、segment_julius.pl
を実行します。
perl segment_julius.pl wav/sample.wav wav/sample.txt
実行された音素アライメントの結果がwav/sample.labに書き出されます。
0.0000000 0.2425000 silB 0.2425000 0.3325000 ky 0.3325000 0.5725000 o: 0.5725000 0.6925000 w 0.6925000 0.7725000 a 0.7725000 0.8925000 i 0.8925000 0.9925000 i 0.9925000 1.0825000 t 1.0825000 1.1825000 e 1.1825000 1.2825000 N 1.2825000 1.4025000 k 1.4025000 1.4525000 i 1.4525000 1.5125000 d 1.5125000 1.6125000 a 1.6125000 2.0525000 silE
参考
http://shower.human.waseda.ac.jp/~m-kouki/pukiwiki_public/24.html#cb2d81f0
音声認識 Julius 4.2.3 + Mac OSX Mountain Lion 10.8.4 でビルドする方法 - Qiita
ダッシュで2015年を振り返る
気がついたら12月31日で、こたつで紅白を見ている自分に気がついたので、ささーっと2015年を振り返ってみようと思います。お酒を飲みながら書いている間に完全に私的備忘録になっちゃったけどまあそれはそれで。
月別振り返り
1月
新年早々卒論がゲシュタルト崩壊を起こしていました。Twitterを振り返ると1月3日に卒論発表会の原稿を出して「よいお年を!』などと呟いてます。なんだか大変そうです。
2月
卒論を出し終わって平穏な月でした。学生最後のサークル合宿に行ったり、卒業旅行で富山に行ったりしました。バイト先ではRails+knockoutjsを学んでフロントエンドがっつり開発マンになっていました。
3月
大学生最後の春休み、旅行やらバイトやら飲み会やらで充実した日々を過ごす傍学会の原稿を書くなどしていました。旅行で台湾に行ったのですが、初海外でした。現地の人みんな日本語で話しかけてくれるので海外きた感あんまなかったけど、初海外は初海外です。
4月
大学院生になったという実感はあまりなく、授業をまた受けるようになったというくらいでした。Twitterを遡ると小川一水「天冥の標」シリーズにどハマりしていました。個人的な今年一番のヒットはこれです。いつかブログにまとめたいなとか思ったりします。
5月
5月は月末の学会準備に追われていました。学会では函館に行き、初めて発表をしました。函館は先生にご馳走になったお寿司が美味しかったし、一人で見た函館山からの夜景はとてもきれいでした。学会サイコー。
6月
学会が終わった反動からか、ゆるゆるな一ヶ月を過ごしていました。有意義だったことといえば、前期途中から始まったFSNLP勉強会に参加し出して、古き良き自然言語処理周りのお勉強をしたことですかね。
7月
(大学院)1年生なので、そこそこ試験勉強とかレポートに追われていたようです。月末に行ったKURAND SAKEマーケットの日本酒飲み放題がとても美味しかったことを覚えています。
8月
研究室にいるロボットのデモを行うことになり、その開発に追われていました。Java力の復活。以前のBloggerからはてなBlogに移行したのもこの時期だったような。あとこの時期はプロコンをやり始めて、毎週Atcorderに取り組んでいました。最近やってないなあ。
9月
インターンで2週間大阪に行っていました。インターン自体よりも2週間会社の寮で一人、という非日常で生き生きしていました。週末は京都や大阪を観光したし、期間限定社会人を全力で満喫しましたね。
10月
スケジュール帳とか見返してみてもあんまり予定ないですね・・・何してたんだろ?
11月
開発系ではtmuxを知り開発効率が格段に上がった月でした。もっと早くに知っておきたかった。月末に社会人の友人を訪ねて山梨旅行に行ったりしました。紅葉にはちょっと遅かったけど、昇仙峡は綺麗だったし、ワインは美味しかったし良い息抜きになりました。今年は息抜きしてばっかですね。
12月
なう。今年は忘年会をあまりしていません。「忘年会」って語感から一年を忘れるための行事かと思いきや、ネットを調べると「一年を忘れないための会」とか、「嫌なことを忘れる会」とか色んな意見があってちょっとわからなくなりました。まあ、忘れたいことを銘々に忘れればいいんじゃないでしょうか?
分野別振り返り
研究
卒論もなく、修論もない修士一年という立場を利用してかなり自由に色んなことをさせてもらいました。その分進捗がgg... 来年は修論が書けるようにがんばらねば。
趣味
ボードゲーム
ボードゲームにより一層はまった年でした。ゲームマーケットに2回共参加して散財し、幾つかボードゲーム会にも顔を出したりしました。購入したのはパーティーゲーム系が多く、中でも「私の世界の見方」は4年越しに手に入れることができて満足でした。
ミステリ・SF
今年は去年以上に本が読めなくなってしまいました。電車の中で寝てしまうというのが主な原因です。 一番のヒットは上にも書いた小川一水「天冥の標」。全10巻まであって最近9-1が出たのですが、新刊が楽しみでなりません。他にSFだと法条遥「リライブ」、スタニスワフ・レム「ソラリス」が面白かったですかね。 ミステリで一番は「戦場のコックたち」。
開発
去年アルバイトでRailsの開発をするようになって、それはそれで実装力はついたのですが、今年は「より綺麗なコードを書く」ということを意識して開発に臨めた一年だったかなと思います。周りの方々の影響って大きい。 また、いろんな組織の中での大きなプロジェクト開発に携わる機会が多かったため、そういった保守性がいかに大事であるか、というのを認識できたというのもあります。
まとめ
良いお年を!