Webデータレポート

株式会社ルーターのデータレポートブログです

KDDIやオムロンがデータ流通事業に参入、データ取引市場は情報連携を巡り議論

KDDIオムロンがデータ流通事業に参入、データ取引市場は情報連携を巡り議論

http://business.nikkeibp.co.jp/atclbdt/15/258675/060200053/

日経ビッグデータより
 

データ販売サービスやデータ取引市場など、企業がビッグデータを入手する手段が多様化している。一方で、データ取引市場を巡っては、事業者間でサービスモデルを巡る議論が巻き起こっている。携携帯電話事業者で先陣を切って、データ販売サービスを始めたのはKDDIである。「KDDI IoTクラウド ~データマーケット~」を6月中旬から提供する。KDDIは「様々な産業にIoTサービスを提供してきたので、価値を出すにはどのデータをどのように分析をすればいいのかのノウハウを蓄積している」と説明する。

データマーケットプレイスが今後、様々な業界で立ちあがりそうです。通信、IoTなどのプレイヤーは当然として、インターネット事業者もデータの取得、販売にフォーカスいていく企業が増えてきそうです。

Amazon Alexa 、Amazon Echo、スマートスピーカーまとめ

スマートスピーカーとは

スマートスピーカーという領域がもりあがっています。日本ではまだ発売されていませんが、北米をはじめとする国では、Amazon Echoというスマートスピーカーが結構な台数販売されています。自社でのスマートスピーカーのR&Dがだいぶ進んだので中間報告。

Amazon EchoとAlexaの関係

Amazon Echoとは、Amazonが販売しているハードウェアのことで、Alexaとはその裏のプラットフォームを指します。なので、Amazon Alexa 対応のハードウェアはAmazon以外も販売できます。

前回のCESでは、家電メーカーがこぞってAlexa対応を発表していました。 http://scrum.vc/ja/2017/01/09/ces-2017/

Amazon Alexaなどの音声プラットフォームのことは「ボイスアシスタント」と呼ばれていたりします。ちょっとGoogleアシスタントに引っ張られている感ありますが、Amazon Echoを使ってる限りアシスタントという用途はちょっと違和感あります。「秘書感」はあんまりないです。

Amazon Alexaの競合に相当するもの

この辺を抑えておけば大丈夫かと思います。

Amazon Alexaにはスキルマーケットがある

Alexaはサードパーティがアプリを作るマーケットがあります。そのアプリを「スキル」と呼びます。そしてスキルストアがあります。 https://www.amazon.com/alexa-skills/b/ref=topnav_storetab_a2s?ie=UTF8&node=13727921011 ストアがあるということは、そこにランキングがあり、そこに新着があるということです。久しぶりですねこの響き。

ただ、今のところ無料アプリしかおいてないようです。無料か有料かのフラグがあるのでそのうち有料もあるのではないかと思います。

スキルの区分

スキルには3種類の区分があります。

flash briefing

ニュースを読み上げるだけのスキルです。What’s in the news? って聞くと、アレクサは今日のニュースを読み上げてくれますが、その際にインストールしたFlash Briefingスキルを上から順に読んでくれます。テキストをそのままAlexaに読ませてもいいのですが、独自に作ったmp3を流すことも可能です。コントロールは予め決められた枠内のみで機能します。

smart home

Alexa対応の家電を操作するスキルです。有名どころとしてはフィリップスのHueですね。 http://www2.meethue.com/en-us/friends-of-hue/amazon-alexa/ 他にも、IKEAが家電をAlexa(他音声アシスタント)対応するとのことです。 http://japanese.engadget.com/2017/05/24/ikea-tradfri-siri-alexa-google/

custom skill

IT業界の人達が一番興味があるのはこのカスタムスキルではないでしょうか。プログラマブルなのはこのカスタムスキルだけです。ユーザの音声をテキストに変換するのはAlexa側がやってくれるので、プログラマは音声を直接扱う必要はありません。簡単なスキルであれば、テキストを返すとAlexaが読み上げてくれます。チャットBOTを作るような開発ですね。

チャットbotと決定的に違うのは、URLを送りつけたり選択メニューを出せないということですが、URLを送りつけるチャットBOTはその時点で負けだと思っています(個人的の感想)。

まだまだR&Dフェーズですが、弊社ではスキルを複数作ってみております。コツや制限はいろいろありますが、「声と耳だけでコントロール」ってのはかなり便利です。殆どの対人コミュニケーションは会話です。

カスタムスキルは、ユーザ毎のプライベート領域もあるので、個人設定を保持することが可能です。ECサイトの認証トークンを保持しておけば、「○○買って」と言うだけで、配達するスキルは開発可能です。スクレイピングでやっちゃえばEC側に手を入れずにすぐにアレクサ対応可能です。

Amazon Echo単体の魅力

どこからでも聞けるマイク

どこからでも聞けなくちゃだめです。PCやスマホはあえて「前面の音のみ拾う」ことに特化ていました。マイクは7個ついています。 https://japan.cnet.com/article/35099774/

うるさくても拾えるマイク

スマートスピーカー自体が、スピーカーとマイクが接しています。大きめに音楽がなってる時でも、こちらの命令を受け取ってくれます。不思議でしかたないけど、絶対必要な機能です。

低価格

北米では180ドルで売られています。2万円くらい。大人が買う新しいインターネット端末としては安い。「いい音のBluetoothスピーカー」とみても安い。リビングと寝室に複数台買ってもいいですね。複数台のEchoがあっても、片方しか反応しないという賢さもあります。

Spotifyとの相性がいい

スピーカーですから当然音楽との相性はいいです。AlexaをSpotify のアカウントと連携しておくと、「play dirty work」って言うだけで、ブルゾンちえみのBGMが流れてきます。「play songos by babymetal」って言うとベビーメタルの曲がずらーっと流れてきます。「next(次)」「louder (もっと大きく)」「what’s plaing?(今の曲何?)」くらいのコマンドだけで、音楽は一通り楽しめます。

Spotify自体が音楽聞き放題では老舗で堅実なので、他の聴き放題とちがって「オルゴールバージョン」とかでごまかしてないのがめちゃくちゃありがたいですね。

iPodiTunes(実際にはgnutella)が音楽の聞き方を変えたみたいに、Amazon EchoとSpotifyの組み合わせは、一日の過ごし方を変えそうです。

一度でも声だけで音楽を操作することを経験すると曲送りで手を使うことが面倒に感じます。

経済産業省がビッグデータを活用した新経済指標を試験的に公開

経済産業省ビッグデータを活用した新経済指標を試験的に公開
 
日経ビッグデータより
 
経済産業省は今夏から、POS(販売時点情報管理)やSNSソーシャル・ネットワーキング・サービス投稿などのビッグデータを活用した新指標の試験的な公開を始める方向で検討している。経済統計の作成の効率化、公開の迅速化、データの詳細化に向けた開発を進めており、その成果を公開し、技術的な課題や利用者ニーズの検証を進める考えだ。

野村証券は、既存の経済統計指標を代替・補完する新指標の開発を試みた。ブログやTwitterのテキストを分析して指標化し、株価指数や為替などのデータも加えて、鉱工業生産指数を算出するモデルを開発した。テキスト分析においてはまず、約200のキーワードと鉱工業生産指数との相関を確認。「残業」など鉱工業生産指数と関連性が高いキーワードについては、「今日も残業だった」なら件数に加えて「今日は残業しなかった」なら除く処理をするなど、投稿の文脈も踏まえて判定して指標化し、精度を高めた。株価指数や為替などだけで鉱工業生産指数を推定するより、Twitterから得られたデータを加えた方が高い精度で推定できることも判明した。 

 

SNSデータなどを活用することにより今までに見えなかった経済指標が見えて、より精度の高い指標(事業者視点とユーザー動向視点)になっていくことが期待できそうですね!

実務で使う分析手法は5つで十分

山本ゆうごです。

実務で使う分析手法は5つで十分、マーケッターこそデータサイエンティスト候補 日経ビッグデータより

以下の5つで十分との記事。

  • クロス集計
  • ロジスティック回帰分析
  • 決定木分析
  • アソシエーション分析
  • クラスター分析(k-平均法)

今どきのAI感は薄いが、画像認識でもしないかぎり、確かにこれで収まるケースは多い。

また、事業KPIの分析では改善プランの立案をするので、「なぜだか分からないけどこういう予測モデルができました」だと、アクションプランを立てづらい。そうなると、結局はクロス集計で一つ一つの変数の相関を見たくはなる。

多くの場合は、クロス集計さえやってない状態で、データの収集と前処理ができてないケースがほとんどなので、まずはデータを集めるところから始めましょうというのが、毎度の結論になります。

マルコフ連鎖の文章生成について検証してみた

はじめまして。新入社員の松永です。

文章生成でブログ記事のようなものを自動作成できないか調べたところ、 DeepLearningを使わなくてもマルコフ連鎖Rubyでも手軽に文章生成ができるらしいことがわかったので、 果たしてどの程度の精度で自動生成が可能なのか検証してみました。

簡単な流れとしては、 Mecabで文章を形態素分析して単語単位に分解して辞書を作成。 作成した辞書に基づいて、マルコフ連鎖でランダムに文章を生成しています。

▼実装環境

マルコフ連鎖とは

文章を生成するときに、ある形態素に繋げられそうな形態素を選んで徐々に繋げていき文章を作成します。

例えば次の文章。

マルコフ連鎖 を 使って、文章 を 自動生成 します。」

このとき、「を」という形態素に繋がりそうな形態素は「使って」と「自動生成」ですね。 この繋がりそうな2つの形態素の中から、繋げる形態素を選ぶ作業を繰り返すことで文章を作成していきます。

ブログ記事の共通項目で文章生成

2件のブログの「インフルエンザとは」項目を形態素解析して文章生成してみました。

サンプル1:

インフルエンザとはインフルエンザウイルスが原因で起こる12月から4月に流行る感染症です。
急に起こる38~40℃の高熱、関節痛、頭痛が特徴的です。通常は、薬を使わなくても約1週間で治癒するとされていますが、高齢者や糖尿病などの持病のある方や小さな子どもがインフルエンザに感染すると、肺炎や脳症など合併症を起こすことがあるので注意が必要です。
インフルエンザワクチンの接種が重篤化を防ぐために有効とされています。
インフルエンザは学校保健安全法施行規則(平成24年施行)により出席停止となる伝染病の一つで、「発症後5日かつ解熱後2日(幼児は3日)を経過」するまで出席停止となります。職場などでもそれに倣って自宅待機となることが多いです。

「インフルエンザの症状・原因・治療 Doctors Me(ドクターズミー)」 https://doctors-me.com/doctor/respiratory/13

サンプル2:

インフルエンザは、毎年12月から1月にかけて猛威を振るいます。予防接種をしたり予防・対処法についての知識を得たりと、流行が本格化する前から注意を払っておく必要もあります。今回は、インフルエンザと普通の風邪との違い・検査方法・かかった場合の対処法や治療法について、医師・武井 智昭先生による監修記事で解説していきます。

「インフルエンザの症状~症状、かぜとの違い~|インフル・ニュース」 http://www.influ-news.info/influ/symptoms.html

結果

インフルエンザは、毎年12月から1月にかけて猛威を振るいます。インフルエンザワクチンの接種が重篤化を防ぐために有効とされています。インフルエンザは、薬を使わなくても約1週間で治癒すると、流行が本格化する前から注意を払っておく必要もあります。

まぁまぁそれらしい文章ができています。 しかしよくよく読んでみると文脈が成り立ってない部分があります。

Twitterのツイートで自動生成

次に、特定のアカウントの過去のツイートを200件形態素解析して文章生成してみます。

サンプル: 恋愛依存メンヘラ@bot @memememenhel https://twitter.com/memememenhel

結果

あなたの手の温もりで有りますように、少しでも、ほんの少しでも。私が手首を切ったの大丈夫だよって証明したくて手首を舐めてくれる気がないの知ってる癖に。離れられない。

手首切りたい死にたいが口癖です。

かなりそれっぽい。 文章としては少しおかしい部分もあるのですが、それがかえってポエム感に繋がっています。

▼まとめ

センテンス単位では文章としてまぁまぁそれらしい結果になっています。 しかし、よくみると文脈として成り立っていない場合があるので、長文や論理的な文章にはあまり向いていないのかなという印象を受けました。 多少文章が崩れても問題のないポエムのような文章には向いているかもしれません。

▼ソース

require 'natto'
require 'pp'
require 'enumerator'

$h = {}
# ----------------形態素解析
# ----------------辞書的なものの作成
def parse_text(text)
    mecab = Natto::MeCab.new
    text = text.strip
    # 形態素解析したデータを配列に分けて突っ込む
    # 先頭にBEGIN、最後にENDを追加
    data = ["BEGIN","BEGIN"]
    mecab.parse(text) do |a|
        if a.surface != nil
            data << a.surface
        end
    end
    data << "END"
    # p data
    data.each_cons(3).each do |a|
        suffix = a.pop
        prefix = a
        $h[prefix] ||= []
        $h[prefix] << suffix
    end
end

# ----------------マルコフ連鎖
def markov()
    p "markov"
    # ランダムインスタンスの生成
    random = Random.new
    # スタートは begin,beginから
    prefix = ["BEGIN","BEGIN"]
    ret = ""
    loop{
        n = $h[prefix].length
        prefix = [prefix[1] , $h[prefix][random.rand(0..n-1)]]
        ret += prefix[0] if prefix[0] != "BEGIN"
        if $h[prefix].last == "END"
            ret += prefix[1]
            break
        end
    }
    p ret
    return ret
end

str = ""
file_name = STDIN.gets

begin
    File.open(file_name,"r") do |file|
        file.each_line do |line|
            str += line.to_s
        end
        parse_text(str)
    end
end

#マルコフ連鎖で文章を自動生成
markov()

▼参考

Ruby形態素解析してマルコフ連鎖で文章生成 http://utsubo21.hatenablog.com/entry/2015/02/08/224155

生活音を機械学習してみた

音声認識というとどうしてもスピーチをテキストにするというソリューションが多いです。しかし用途がユーザーインターフェースに限られる。IOTのシーンではモノとモノが通信し合ってこそ、人間様が楽できるので、生活音を識別することをゴールとしたいと思います。

▼ 概要

今回は5種類のスズの音のサンプルを使って,2種類ずつどちらのスズか判別を行ってみたいと思います。

▼ 実装環境

▼ 用意するもの

Python機械学習ライブラリのscikit-learnを使います。
(参考: http://www.iandprogram.net/entry/2015/09/15/221518 )

UbuntuPythonをインストール
$ sudo apt-get install python2.7

pipをインストール
$ sudo apt-get install python-pip

Ubuntuにscikit-learnをインストール
$ sudo pip install scikit-learn

他にnumpyもインストールしておく。

▼ 教師データの作成

5種類のスズの音サンプルを用意します。

スズの名前 スズの音のタイプ
suzu01 一般的なスズ
suzu02 喫茶店のドアについてる感じ
suzu03 チリーン 風鈴みたいな
suzu04 シャン! クリスマスっぽい
suzu05 川の流れる音みたいな

音のサンプルを載せているWebサイトはたくさんありますが、 スズの音階がわからなかったりや同じスズを使っているけど鳴らし方だけ違ったりするサンプルが多く、教師データを作るのがなかなか難しい(正解ラベルが貼れない)。

人間が聞いて明らかに違うスズだとわかるものをサンプルとして使うことが望ましい。

5種類のスズの音サンプルは実際に聞いてみて明らかに違うものを用意する。今回用意したスズはスペクトログラムを書いてみると、その形状の違いから5つの異なるスズを使っていることがわかります。

f:id:webdatareport:20161106160556p:plainf:id:webdatareport:20161106160600p:plainf:id:webdatareport:20161106160603p:plainf:id:webdatareport:20161106160610p:plainf:id:webdatareport:20161106160613p:plain

サンプルだけではパターンが少ないので、機械学習するには十分ではありません。
そこで、スズの音にノイズ音を加えてデータを量産することに。

ノイズの名前 ノイズの内容
noise01 ハイヒールの足音
noise02 皮靴の足音
noise03 ドアが閉まる音
noise04 ドアノブをガチャガチャする音
noise05 ドアをノックする音
noise06 ドアが開く音
noise07 道路の環境音
noise08 人の笑い声
noise09 水洗トイレが流れる音
noise10 トイレットペーパーを回す音
noise11 TOTO音姫

5種類のスズの音に11種類のノイズを加えてデータを作成します。
さらに,ノイズの音量を10段階に設定することで更に多くの音声パターンを生成できる(5 × 11 × 10 = 550種類)。
今回はSoX (Sound eXchange) を使って,以下の手順でスズの音とノイズをミックスしていきます。
(参考:http://qiita.com/mountcedar/items/a04ebc4f8c27c226bbff)

ノイズ入りデータ作成手順 1. すべての音声データを一旦.wav形式に変換する 2. 5種類のスズの音を正規化 3. 11種類のノイズの音を正規化 4. 手順1と手順2からできた音声データをスズの音の長さに合わせて合成する。 その際, 新たに合成したノイズ入りのアウトプットファイルをスズの種類ノイズの種類音の段階(0~9).wav として保存する。

例:suzu03のwavファイルとnoise07のwavファイルを合成する。
$ sox -m suzu/suzu03.wav -v 0.2 noise/noise07.wav learning_sample/3_7_9.wav trim 0 suzu03_len
-m : --combine mixの略で2つのファイルを結合するためのオプション。
-v : 後ろの音ファイルの音量を調節をするオプション。(1より大:音量を上げる、1より小:音量を下げる)
trim : 音声を切り取るオプション。例では0秒目からsuzu03の音の長さ(suzu03_len)に合わせてクリッピングしている。

f:id:webdatareport:20161106160750p:plain f:id:webdatareport:20161106160824p:plain f:id:webdatareport:20161106160852p:plain f:id:webdatareport:20161106160906p:plain

スペクトログラムと波形図をそれぞれ見てみると、元々のsuzu03の画像と比較して、ノイズが入っていることが確認できます。

▼ MFCC (メル周波数ケプストラム係数)

音のデータから特徴量を抽出する方法としてMFCCを使います。 MFCCは人間の聴覚の特性にあわせて低周波部分は細かく,高周波部分は粗く調べる手法らしい(音声解析ではよく使われている)。 音の専門家じゃないので不明な点がありますが、音声データの一部分を取り出して、指定した次元のベクトルに集約して特徴量を抽出してくれます。
サンプル間で音の長さが違う場合でも、同じ長さのベクトルを用意することができるので、そのまま機械学習にかけられる。

MFCCの抽出手順は

  1. プリエンファシスフィルタで波形の高域成分を強調する
  2. 窓関数をかけた後にFFT高速フーリエ変換)して振幅スペクトルを求める
  3. 振幅スペクトルにメルフィルタバンクをかけて圧縮する
  4. 上記の圧縮した数値列を信号とみなして離散コサイン変換する
  5. 得られたケプストラムの低次成分がMFCC

(参考:http://aidiary.hatenablog.com/entry/20120225/1330179868)

#coding:utf-8
import wave
import numpy as np
import scipy.signal
import scipy.fftpack
import scipy.fftpack.realtransforms

def wavread(filename):
    wf = wave.open(filename, "r")
    fs = wf.getframerate()
    x = wf.readframes(wf.getnframes())
    x = np.frombuffer(x, dtype="int16") / 32768.0  # (-1, 1)に正規化
    wf.close()
    return x, float(fs)

def hz2mel(f):
    """Hzをmelに変換"""
    return 1127.01048 * np.log(f / 700.0 + 1.0)

def mel2hz(m):
    """melをhzに変換"""
    return 700.0 * (np.exp(m / 1127.01048) - 1.0)

def melFilterBank(fs, nfft, numChannels):
    """メルフィルタバンクを作成"""
    # ナイキスト周波数(Hz)
    fmax = fs / 2
    # ナイキスト周波数(mel)
    melmax = hz2mel(fmax)
    # 周波数インデックスの最大数
    nmax = nfft / 2
    # 周波数解像度(周波数インデックス1あたりのHz幅)
    df = fs / nfft
    # メル尺度における各フィルタの中心周波数を求める
    dmel = melmax / (numChannels + 1)
    melcenters = np.arange(1, numChannels + 1) * dmel
    # 各フィルタの中心周波数をHzに変換
    fcenters = mel2hz(melcenters)
    # 各フィルタの中心周波数を周波数インデックスに変換
    indexcenter = np.round(fcenters / df)
    # 各フィルタの開始位置のインデックス
    indexstart = np.hstack(([0], indexcenter[0:numChannels - 1]))
    # 各フィルタの終了位置のインデックス
    indexstop = np.hstack((indexcenter[1:numChannels], [nmax]))

    filterbank = np.zeros((numChannels, nmax))
    for c in np.arange(0, numChannels):
        # 三角フィルタの左の直線の傾きから点を求める
        increment= 1.0 / (indexcenter[c] - indexstart[c])
        for i in np.arange(indexstart[c], indexcenter[c]):
            i=int(i)
            filterbank[c, i] = (i - indexstart[c]) * increment
        # 三角フィルタの右の直線の傾きから点を求める
        decrement = 1.0 / (indexstop[c] - indexcenter[c])
        for i in np.arange(indexcenter[c], indexstop[c]):
            i=int(i)
            filterbank[c, i] = 1.0 - ((i - indexcenter[c]) * decrement)

    return filterbank, fcenters

def preEmphasis(signal, p):
    """プリエンファシスフィルタ"""
    # 係数 (1.0, -p) のFIRフィルタを作成
    return scipy.signal.lfilter([1.0, -p], 1, signal)

def mfcc(signal, nfft, fs, nceps):
    """信号のMFCCパラメータを求める
    signal: 音声信号
    nfft  : FFTのサンプル数
    nceps : MFCCの次元"""
    # プリエンファシスフィルタをかける
    p = 0.97         # プリエンファシス係数
    signal = preEmphasis(signal, p)

    # ハミング窓をかける
    hammingWindow = np.hamming(len(signal))
    signal = signal * hammingWindow

    # 振幅スペクトルを求める
    spec = np.abs(np.fft.fft(signal, nfft))[:nfft/2]
    fscale = np.fft.fftfreq(nfft, d = 1.0 / fs)[:nfft/2]

    # メルフィルタバンクを作成
    numChannels = 20  # メルフィルタバンクのチャネル数
    df = fs / nfft   # 周波数解像度(周波数インデックス1あたりのHz幅)
    filterbank, fcenters = melFilterBank(fs, nfft, numChannels)


    # 定義通りに書いた場合
    # 振幅スペクトルに対してフィルタバンクの各フィルタをかけ、振幅の和の対数をとる
    mspec = np.log10(np.dot(spec, filterbank.T))


    # 離散コサイン変換
    ceps = scipy.fftpack.realtransforms.dct(mspec, type=2, norm="ortho", axis=-1)

    # 低次成分からnceps個の係数を返す
    return ceps[:nceps]

#wavファイルと次元数を入れてMFCCを抽出
#   nfft:FFTのサンプル数 1024, 2048, 4096
#   nceps:MFCCの次元数 大体12次元が多い
#   ※ fs * cuttime >= nfft/2 を満たす値を与えなければいけない
def get_feature(wavfile,nfft,nceps):
    # 音声をロード
    wav, fs = wavread(wavfile)
    t = np.arange(0.0, len(wav) / fs, 1/fs)
    
    # 音声波形の中心部分を切り出す
    center = len(wav) / 2  # 中心のサンプル番号
    cuttime = 0.8         # 切り出す長さ [s]
    wavdata = wav[int(center - cuttime/2*fs) : int(center + cuttime/2*fs)]
    
    ceps = mfcc(wavdata, nfft, fs, nceps)
    return ceps.tolist()

先ほどミックスしたsuzu03とnoise07 (ノイズの音量レベル9) の3_7_9.wavをMFCCにかけてみる。
上記のコードに以下のコードを付け加えて、実際にMFCCを実行する。

if __name__ == "__main__":
    wavfile="learning_sample/3_11_9.wav"
    nfft=2048
    nceps=12
    tmp=get_feature(wavfile,nfft,nceps)
    print tmp

実行すると、

[-2.1340185367571975, -1.2788164503621682, 0.2980729758980935, -0.7116624981453882, 0.33237397666134955,
0.22739636812287548, 0.7001966634450906, -0.12020691819143244, -0.10969326122265541, -0.45330444421058963,
0.2237907950505698, 0.2439421042510435]

このように、音声のwavファイルから12次のベクトルを生成することができました。

SVMで判別

いよいよ、スズの音を判別してみます。
5種類のスズ (suzu01~05) を以下すべての組み合わせで判別します。
(ただし、すべてノイズ入りです。)

スズの組み合わせ スズの音番号のペアNo
suzu01, suzu02 (1, 2)
suzu01, suzu03 (1, 3)
suzu01, suzu04 (1, 4)
suzu01, suzu05 (1, 5)
suzu02, suzu03 (2, 3)
suzu02, suzu04 (2, 4)
suzu02, suzu05 (2, 5)
suzu03, suzu04 (3, 4)
suzu03, suzu05 (3, 5)
suzu04, suzu05 (4, 5)

全組み合わせにおいて、ノイズ11種類中10種類を学習データに、残り1種類を評価用データに使用するようにして、
学習時にないノイズであっても、スズの音を判別できるかを試しました。

学習用データ 200個
評価用データ 20個

今回は機械学習ではメジャーなSVM (Support Vector Machine) を使用します。
(参考:http://may46onez.hatenablog.com/entry/2016/02/19/152532)

svm.py

#coding:utf-8
from sklearn import svm
from sklearn.metrics import classification_report, accuracy_score
import sys
from mfcc import *
import glob
import csv
import random
import itertools
import numpy as np

if __name__ == "__main__":
    
    bell_nums = range(1,6)
    pairs = list(itertools.combinations(bell_nums,2))
    
    for pair in pairs:
        
        bell_num1=int(pair[0])
        bell_num2=int(pair[1])
        train_data = np.empty((0,12),float)
        train_label = np.array([])
        test_data = np.empty((0,12),float)
        test_label = np.array([])
        noise_nums = range(1,12)
        level_nums = range(0,10)
        random.shuffle(noise_nums)
        
        nfft = 2048  # FFTのサンプル数
        nceps = 12   # MFCCの次元数
        
        #鈴の音1
        for noise_num in noise_nums[0:10]:
            random.shuffle(level_nums)
            #学習用データを作成
            for level_num in level_nums[0:10]:
                files_name = glob.glob("learning_sample/%d_%d_%d.wav" % (bell_num1,noise_num,level_num))
                for file_name in files_name:
                    feature = get_feature(file_name,nfft,nceps)
                    if len(train_data) == 0:
                        train_data=feature
                    else:
                        train_data=np.vstack((train_data,feature))
                    train_label=np.append(train_label,bell_num1)
            #テストデータを作成
            file_name = "learning_sample/%d_%d_%d.wav" % (bell_num1,noise_num,level_nums[8])
            feature = get_feature(file_name,nfft,nceps)
            if len(test_data) == 0:
                test_data=feature
            else:
                test_data=np.vstack((test_data,feature))
            test_label=np.append(test_label,bell_num1)
    
        #鈴の音2
        for noise_num in noise_nums[0:10]:
            random.shuffle(level_nums)
            #学習用データを作成
            for level_num in level_nums[0:10]:
                files_name = glob.glob("learning_sample/%d_%d_%d.wav" % (bell_num2,noise_num,level_num))
                for file_name in files_name:
                    feature = get_feature(file_name,nfft,nceps)
                    if len(train_data) == 0:
                        train_data=feature
                    else:
                        train_data=np.vstack((train_data,feature))
                    train_label=np.append(train_label,bell_num2)
            #テストデータを作成
            file_name = "learning_sample/%d_%d_%d.wav" % (bell_num2,noise_num,level_nums[8])
            feature = get_feature(file_name,nfft,nceps)
            if len(test_data) == 0:
                test_data=feature
            else:
                test_data=np.vstack((test_data,feature))
            test_label=np.append(test_label,bell_num2)
            
    
        #特徴データをテキストに出力
        feature_train_data=np.hstack((train_label.reshape(len(train_label),1),train_data))
        feature_test_data=np.hstack((test_label.reshape(len(test_label),1),test_data))
        with open("feature_data/train_data.txt","w") as f:
            writer=csv.writer(f)
            writer.writerows(feature_train_data)
        with open("feature_data/test_data.txt","w") as f:
            writer=csv.writer(f)
            writer.writerows(feature_test_data)
                
        #識別機学習
        clf = svm.SVC()
        clf.fit(train_data,train_label)
        #推定
        test_pred = clf.predict(test_data)
        #print np.hstack((test_label.reshape(len(test_label),1),(test_pred.reshape(len(test_pred),1))))
        
        #結果算出
        score=accuracy_score(test_label, test_pred)
        print pair,score

svm.pyの中でmfcc.pyをインポートして特徴量抽出ができるように関数を呼び出しています。
train_datatest_dataは1列目にスズの音のラベル、2列目以降にMFCCで抽出した12次元の特徴量ベクトルが入っており、これをSVMの学習器に入れます。

▼ 結果

(1, 2) 1.0  
(1, 3) 1.0  
(1, 4) 1.0  
(1, 5) 1.0  
(2, 3) 1.0  
(2, 4) 1.0  
(2, 5) 1.0  
(3, 4) 1.0  
(3, 5) 1.0  
(4, 5) 1.0

1列目が判定したスズの音番号のペアNoで2列目が正答率になっています。
どのスズの組み合わせも100%の精度で判別することができました。

▼ まとめ

今回,SVM自体のチューニングは特にしていません。
前処理のMFCCによる特徴量抽出の時点でかなり上手く分類できてしまっているのだと思います。

モンスターBOXのモンスター名をTensorFlowで特定してみた

▼モンスター画像がたくさん転がってる国、日本

機械学習で何かと進化したのが画像認識。人間の顔の認識は古くから研究されつくされてる感もあるので、それとは別にソーシャルメディア上にアップされている画像を特定してみたいと思います。

特に日本だと、Twitterにゲームのキャプチャをアップしている人が多いから、ゲームのキャプチャを解析すれば、その人のレベル感が分かるし、誰と何を交換すればいいかなどの特定がしやすくなどいろいろ可能性は広がりそうです。

▼実装環境

ubuntu 14.04
python 2.7.6
opencv 3.1.0

▼モンスターBOXからモンスターを取り出す

機械学習ではいつも「この屏風からトラを取り出していただければ退治してみせましょう」というシーンに出くわします。今回もモンスターBOXのたくさん並んでいるモンスターを直接学習させても、パターンが膨大すぎる。だからモンスターアイコンだけを取り出したい。

今回はOpenCVの特徴点を取り出す方法を採用します。特徴点をピックアップするとその画像の中で「ごちゃごちゃしているところ」が特定できます。

特徴点を取り出すにもいろいろアルゴリズムがありますが、今回はFASTというアルゴリズムを使いました。
FASTの詳しい説明(http://www.vision.cs.chubu.ac.jp/CV-R/jpdf/RostenECCV2006.pdf

FASTで検出した特徴点をプロットすると、これが

f:id:webdatareport:20160701094750j:plain

こうなる

f:id:webdatareport:20160701094753j:plain

こんな感じに。
特徴点がモンスター部分に密集しています。
OpenCVには他にも特徴点アルゴリズムがありますが、このFASTが一番モンスター部分に密集してくれました。

この特徴点をヒストグラム化してみます。
X軸方向(横)のヒストグラムがこちら

f:id:webdatareport:20160701094755j:plain

 

山が5個できています。
この山の部分がモンスター部分で、谷が背景部分です。
谷部分で切り取ってあげればモンスター画像が綺麗にトリミングされているのではないか。

山谷部分がわかりやすくなるようグラフを平滑化します。
pandasで移動平均をとってみます。
参考(http://blanktar.jp/blog/2015/12/python-pandas-moving-average.html)

f:id:webdatareport:20160701094757j:plain

青い点は、ピーク解析を行って極小値であると判定された部分です。
SciPyでピーク点を検出することができます。
参考(http://org-technology.com/posts/scipy-peak-finding.html)

これだと両端のモンスター部分は切り取れないので
x座標の先頭と末端から、ピーク解析で得た極小値リストの最小値に一番近い座標をプロットしてみます。

f:id:webdatareport:20160701094759j:plain

うまく切り取れそう。
Y軸方向も同様に

f:id:webdatareport:20160701094800j:plain

試しに、プロットした座標に線を引いてみます。

f:id:webdatareport:20160701094802j:plain

思いのほか綺麗に境界線が引けています。

 

▼分類機作成

いよいよTensorFlowで分類機を作ってみます。
モデル生成~学習まで一通りこちらを参考にしました。
http://kivantium.hateblo.jp/entry/2015/11/18/233834

教師データはこちら(http://monst.appbank.net/monster/archives/1.html)のモンスター図鑑のモンスター画像を使用しました。
また手作業でモンスターの額を取り除いた画像用意して、枠周辺はあんまり気にするなということを教え込みたいなと。

使用した教師画像はこの2パターン。

f:id:webdatareport:20160701094805j:plain

f:id:webdatareport:20160701094806j:plain

それと先程トリミングした際に出た切れ端を負例画像として使用して、モンスターじゃない!ってことを教えます


ということで、使用した教師データは以下の通り。
正例画像:モンスター1981種 × 2枚=3962枚
負例画像:54枚

▼結果

Tensorflowで作った分類機にトリミングしたモンスター画像を入れて分類結果を返す一連の流れを試してみました。

f:id:webdatareport:20160701094750j:plain

トリミングした画像番号,モンスター番号,モンスター名
000,344,マチルダⅡ
001,1538,宇宙の伝達者 ナスカ
002,1226,通天大聖 孫悟空
003,1040,張飛 益徳
004,844,ヴィシャス
005,335,エール・ソレイユ
006,1739,黄泉津大神 イザナミ
007,1523,ハートの女王
008,1202,ロックガール ガーゴイル
009,1038,非天 阿修羅
010,736,レルネーの主 ヒュドラ
011,915,タランチュラス・ウェポン
012,1739,黄泉津大神 イザナミ
013,1472,ちゃす
014,1181,ヒーロー ドラえもん
015,1038,非天 阿修羅
016,563,黄泉津大神 イザナミ
017,1981,水瓶座黄金聖闘士 カミュ
018,1617,リリム
019,1464,灼夏の巨人 スルト
020,1139,護法善神 羅刹
021,1036,除夜を射る将軍 徳川吉宗
022,563,黄泉津大神 イザナミ
023,1965,白鳥星座の青銅聖闘士 氷河
024,1584,情熱の爆音シンガー エナ
025,1266,輝石の美将 雲母大佐
026,1040,張飛 益徳
027,900,MDT チェリーウィンガー
028,460,炎狼の赤ずきん ノンノ
029,1881,白馬の騎士 のび太

 

 

30枚中28枚が正解。教師データのバリエーションは大してないのですが、文字などのノイズが含まれた画像を分類機に入れても結構な精度で分類できていることがわかります。これだけ雑な学習でもまぁまぁ特定できてる。

▼まとめ

TensorFlow自体は、特にこれといったチューニングめいたものは使っておらず、ポイントは前処理。そして前処理に使ってるのは、OpenCVの特徴点抽出のみってところです。