docomoの雑談対話APIのエンドポイントが変わって動かなくなっていた件

日本語でそれっぽい雑談対話を生成してくれてチャットボットとかで使われているであろうdocomoの雑談対話APIにアップデートがあったらしい。

よって今まで動いていたエンドポイントから404が返ってくるようになってしまった。

これからは/naturalChatting/v1/dialogueで終わるエンドポイントへ切り替えなければならないのと、

今まではAPIKEYを指定するだけでリクエストができていたがこれからは事前にユーザー登録を行ってappIdを入手する必要がある。

ということでこちらに新しい仕様があるのでPythonでサンプルを書いてみた

import requests
import os
import json

docomo_key = "{ docomo api key }"


def registration(config_path,key):
    regist = "https://api.apigw.smt.docomo.ne.jp/naturalChatting/v1/registration?APIKEY={key}"\
        .format(key=key)
    data = {
        "botId": "Chatting",
        "appKind": "Smart Phone"
    }
    res = requests.post(regist, json=data)
    res_json = res.json()

    with open(config_path, "w") as f:
        json.dump(res_json, f)

def conversation(key,app_id,speech):
    url = "https://api.apigw.smt.docomo.ne.jp/naturalChatting/v1/dialogue?APIKEY={key}" \
        .format(key=key)
    data = {
        "botId": "Chatting",
        "appId": app_id,
        "voiceText":speech,
        "language":"ja-JP"
    }
    res = requests.post(url, json=data)
    res_json = res.json()
    return res_json["systemText"]["utterance"]

def main():
    # appIdを取得して.cacheディレクトリに入れる
    cache = os.path.join(os.environ["HOME"],".cache")
    dialog = os.path.join(cache,"dialog.json")
    if not os.path.exists(cache):
        os.mkdir(cache)

    if not os.path.exists(dialog):
        registration(dialog,docomo_key)

    with open(dialog,"r") as f:
        config = json.load(f)

    app_id = config["appId"]

    text = "こんにちは"

    res = conversation(docomo_key,app_id,text)

    print(res)

if __name__ == "__main__":
    main()

 

今までdocomoの雑談対話APIで動いていたチャットボットとか結構いたのではないだろうか。それらが動かなくなっているとおもうので対応を頑張ってもらいたい

[symfony] ControllerでJsonを返す

PHP、SymfonyでJsonを返すAPIを作ろうとしていたら思ったより難しかったのでメモ

ORMapperはDoctrineです。

 

Jsonを返すためにはアクションメソッド内でSerializerを利用する必要があります。

コンストラクタでシリアライザを初期化してあとはResponseクラスに入れて返すと無事にJsonが返却できます

class TodoController extends Controller
{
    private $encoders;
    private $normalizers;

    private $serializer;

    public function __construct()
    {
        $this->encoders = array(new XmlEncoder(), new JsonEncoder());
        $this->normalizers = array(new ObjectNormalizer());
        $this->serializer = new Serializer($this->normalizers, $this->encoders);
    }
    /**
     * @Route("/", name="todo_index", methods="GET")
     */
    public function index(TodoRepository $todoRepository): Response
    {

        $items = $todoRepository->findAll();
        $jsonContent = $this->serializer->serialize($items, 'json',['json_encode_options' => JSON_UNESCAPED_SLASHES]);
        $res =  new Response($jsonContent);
        $res->headers->set('Content-Type','application/json');
        return $res;
    }
}

 

[Unity] 動的にテクスチャにお絵かきする

お絵かき機能のあるゲームを作成する必要があったので調べました。

こちらが非常にわかりやすいですが少々バグとUnityのアップデートがあったので方法をメモします。

Unityでテクスチャにお絵描きしよう – おもちゃラボ http://nn-hokuson.hatenablog.com/entry/2016/12/08/200133

 

まず、Cubeオブジェクトを配置し、カメラに写るようにします。

Cubeオブジェクトの名前を「cube_draw」とし、インスペクタからBoxColliderをRemoveComponentし、新たにMeshColliderを追加します。これは後ほど登場するRayHitからUV値を取得するtextureCoordがBoxColliderだと常に(0,0)になってしまうのを防ぐためです。

続いてテキトーな画像を1つ用意し、テクスチャとしてCubeに貼り付けます。この時、「Advanced」->「Read/Write Enabled」にチェックをいれます。

最後に適当なMonoBehaviourに以下のようなコードを書きます。

public class SceneManager : MonoBehaviour {

	private Renderer renderer;
	private Texture2D drawTexture;
	private Color[] textureBuffer;

	private int brushSize = 10;
	// Use this for initialization
	void Start () {
		        
		this.renderer = GameObject.Find("cube_draw").GetComponent<Renderer>();
		var bodyTexture = (Texture2D)this.renderer.material.mainTexture;
		var bodyPixels = bodyTexture.GetPixels();
		this.textureBuffer = new Color[bodyPixels.Length];
		bodyPixels.CopyTo(this.textureBuffer,0);
		        
		this.drawTexture = new Texture2D(bodyTexture.width,bodyTexture.height,TextureFormat.RGBA32,false);
		this.drawTexture.filterMode = FilterMode.Point;
		this.drawTexture.SetPixels(this.textureBuffer);
		this.drawTexture.Apply();
		this.renderer.material.mainTexture = this.drawTexture;
	}
	
	// Update is called once per frame
	void Update () {
		if (Input.GetMouseButton(0))
		{
			// Screenのマウスの位置から空間に向けてレイ(光線)を放つ
			var ray = Camera.main.ScreenPointToRay(Input.mousePosition);
			// 光線が何かのオブジェクトにヒットしたなら
			RaycastHit hit;
			if (Physics.Raycast(ray, out hit))
			{
				// UV値からテクスチャのどの部分にヒットしたのかを計算
				var hitPoint = new Vector2(hit.textureCoord.x * drawTexture.width, hit.textureCoord.y * drawTexture.height);

				// brushSize分のピクセルを塗りつぶす
				for (int x = (int) (hitPoint.x - brushSize / 2); x < hitPoint.x + brushSize; x++)
				{
					for (int y = (int) (hitPoint.y - brushSize / 2); y < hitPoint.y + brushSize; y++)
					{
						if (x >= 0 && y >= 0)
						{
							this.textureBuffer.SetValue(Color.black, (int) x + drawTexture.width * (int) y);
						}
					}
				}

			}

			// テクスチャを適用
			this.drawTexture.SetPixels(this.textureBuffer);
			this.drawTexture.Apply();
			this.renderer.material.mainTexture = this.drawTexture;
		}
	}
}

コードの解説としては、MainCameraのScreenPointToRayメソッドによってカメラから擬似的な光線を照射し、ヒットしたオブジェクトを返します。その後、textureCoordによってヒットした場所のテクスチャUV値を取得します。最後にその部分周辺のピクセル値を書き換えることでお絵かきを実現できます。

 

コンピュータの中で音量はどう扱われるか

音声情報処理の研究室にいたはずなのに理解がとても曖昧だったので調べたことのメモ

当方、学習中の身です。間違いがあったらご指摘ください。

 

音量の話。人は音の大きさについて自然と「うるさい」と思ったり「静かだ」と思うわけで、うるさい音量というのは確かに存在します。しかしながら、その「うるさい音量」は具体的にどれ位の数で表すことができるのか、さらにはコンピュータの中でサンプリングされた音はどのようなスケールで扱われるのか、詳細を教えてくれるところはあまりありません。今回はそんな話について調べたことをまとめます。

自然界での音量

まずは自然界の話。よくオスプレイとかの騒音を騒音計を使って騒音レベルを計測している映像をニュースとかで見ますが、その時使われる単位として「デシベル(dB)」があります。これは音に限った単位ではなく、電気回路等では電圧利得などの単位として使われます。利得とはすなわち、入出力の比であり、入力に対してどれだけの出力を得ることができたか。そのような指標で調べたい時、dBが使われます。ではデシベル音量に関しては何の比率なのでしょうか。音量は「ある基準音圧」に対し、「対象の音圧」がどれぐらいの比率かで表されます。基準音圧は人間の耳で聞こえる最小の音圧です。つまり、自然界で聞こえる音量(dB)とは、人間が聞こえる最小の音圧に対し、どれぐらいの音圧を持っているかの比率で表されます。音量の式を下記に示します。

なぜ20logなのかですが、利得は元々電力から来ているそうで、電力の時は10logを使っていたが電圧になおすために変換した結果だそうです。

下記参考文献によると、デシベルで表すことによってこの音はどれぐらいの音と同じぐらいかを知ることができます。

120デシベル ・飛行機のエンジンの近く
110デシベル ・自動車の警笛(前方2m)・リベット打ち
100デシベル ・電車が通るときのガードの下
90デシベル ・犬の鳴き声(正面5m)・騒々しい工場の中・カラオケ(店内客席中央)
80デシベル ・地下鉄の車内・電車の車内・ピアノ(正面1m)
70デシベル ・ステレオ(正面1m、夜間)・騒々しい事務所の中・騒々しい街頭
60デシベル ・静かな乗用車・普通の会話
50デシベル ・静かな事務所・クーラー(屋外機、始動時)
40デシベル ・市内の深夜・図書館・静かな住宅の昼
30デシベル ・郊外の深夜・ささやき声
20デシベル ・木の葉のふれあう音・置時計の秒針の音(前方1m)

dBデシベルの話し 音の大きさ http://www.geocities.jp/fkmtf928/dB_sound.html

まとめるとデシベル音量は相対値であり、人間の聞こえる最小音圧に対し、どれぐらいの音圧があるかで表されるということです。

参考文献

dBデシベルの話し 音の大きさ http://www.geocities.jp/fkmtf928/dB_sound.html

コンピュータでの音量

では自然界ではなく、デジタルの世界。コンピュータでの音量の扱い方を見ていきます。

音というのは空気の振動であり、波形です。コンピュータはデジタル回路なので波形のような連続値を扱うことはできません。そこでサンプリングを行なうことによって波形を離散データとして扱います。一定時間(周期)ごとにマイクに入る電圧を記録し、音をデータとして保存します。電圧を記録するとき、どのぐらいの細かさ(分解能)で記録するかを「量子化ビット」と呼びます(下図縦軸)。この量子化ビットが8bitならば(signedの場合)-128〜+128までの数値で記録することができます。16bitならば-32768〜32767までの数値で記録することができます。量子化ビット数が大きければ大きいほどより分解能が高く、細かいマイク電圧の変化を記録できるので鮮明に音を記録できます。一方、データサイズが大きくなってしまう問題もあります。

ではこのビットで記録された音の大きさは何デシベルぐらいなのでしょうか。サンプリングされたデータの大きさは量子化ビットの数によって変わってしまうので量子化ビット8bitで記録された音声の大きさと量子化ビット16bitで記録された音声の大きさを、データで直接比較することはできません。そこで何かしらの変換をかけて、デシベルに直せると比較できて便利そうです。

ビットからデシベルへの変換

先程も述べたように、音量というものは基準からの比率です。自然界では基準は「人間が聞こえる最小音量」でしたが、コンピュータの世界では「記録すべき最大音量」が基準となります。なのでコンピュータで音量は「最大音量からどれぐらい小さいか」の比率で表されます。以下量子化ビット数16bitで解説をします。16bit量子化でunsignedの場合、0〜最大65535までの数値で音を表現できます。ではこの値の範囲は最大でどれ位の利得を表現できるかを計算すると、最大利得は96.3dBとなります。つまり、デシベルスケールになおすと0dB〜96.3dBまでの範囲で音を表現することができます。これをダイナミックレンジと呼びます。

音波形の音量はすなわち振幅の大きさです。しかし波形はマイナスの方向にも言ってしまうので、正しく音量を得るために波形の絶対値をとります。さらに、その平均値をとると、だいたい下図赤線の値となり、音の大きさを得ることができます(マイナスをなくすために2乗する場合もあります)。音量は基準からの比率であり、今回の基準は最大音量ですので下図の式のようになり、デシベル音量を得ることができます。ダイナミックレンジを見ると、16bit量子化では0〜-96.3dBまでの値を得ることができます。マイナスの方向に向かっているのは最大値を基準としているからであり、自然界で扱われるデシベルと逆のスケールになっていますがコンピュータでは一般的なようです。

参考文献

あちゃぴーの自転車通勤: dB(デシベル)とbit(ビット)の関係について http://achapi2718.blogspot.jp/2011/12/dbbit.html

まとめ

まとめると、量子化ビットAbitな音声信号のサンプル値Bのダイナミックレンジとデシベル音量は以下の式で表すことができます。対数のおかげで、処理時間がかかる除算を減算へと変化させることができ、プログラムからも扱いやすそうです。

[論文読み]音声認識に向けた超高齢者音声のコーパス構築

メタデータ

概要

高齢者向け音声認識精度の向上を目指して、高齢者の音声コーパスを集め、認識実験をした研究。

102名の高齢者にJNAS(若者向け音素バランスコーパス)とS-JNAS(高齢者向け音素バランスコーパス)を読んでもらい、感情ラベルや認知症スケール(HDS-R)などのラベルもつけた。(102名中11名が認知症傾向)

音声認識器Kaldiにより比較実験。

結果、若者の学習データ(JNAS)に若者の評価データ(JNAS)を使うとWordErrorRateがGMM(2.79)、DNN(2.34)。

若者の学習データ(JNAS)に高齢者の評価データ(S-JNAS)を使うとWordErrorRateがGMM(6.79)、DNN(3.41)。

高齢者の学習データ(S-JNAS)に高齢者の評価データ(S-JNAS)を使うとWordErrorRateがGMM(4.05)、DNN(3.41)。

何故か今回収集したコーパスは学習に使っていない模様

年代に合わせた音響モデル作成の必要性を確認

知見

やはり、高齢者には高齢者専用の音響モデルで音声認識をしたほうが精度が高くなる。

若者の音響モデルで高齢者の声を認識しようとすると認識率が低下する。

高齢者は加齢とともに、調音器官の筋肉が衰えて、音声が不明瞭になり、音声認識に影響を及ぼす。