chainer.links.Linearを使って離散コサイン変換


ざっとググったところ出てこなかったこともあり、メモ。
離散コサイン変換(Discrete Cosine Transform, DCT)をchainer.links.Linearクラスを使って作成してみました。

離散コサイン変換とは、高速フーリエ変換(Fast Fourier Transform, FFT)の親戚で、FFTの実数部を引き出すのと同じ意味合いになります。(詳しい解説は他の方の説明に頼ります)

以下の関数DCT(wave)を使うと、scipy.fftpack.dct(wave)と同じ結果が返ってくることを確認しました。
モジュールのimportは、Chainerのチュートリアルに準じて行っています。

DCT.py
def DCT(wave):
    num_base = np.size(wave.data[0,:])
    lDCT = L.Linear(num_base,num_base)
    for n in range(num_base):
        for k in range(num_base):
            lDCT.W.data[k,n] = 2*np.cos(np.pi*k*(2*n+1)/(2*num_base))
    lDCT.b.data[:] = 0.0
    return lDCT(wave)

私がはまった点は、
・Linearに渡すのはVariable形式
・np.array([[入力ベクトル]])のように、次元を2次元にして渡す
という点です。
これを使うとDCTを使ったChainや誤差関数を作れる(はず)です。(まだ未使用です)

(追記:2016年2月4日)
逆離散コサイン変換(Inverse DCT, IDCT)も作ってみました。
Scipyのドキュメントより、scipy.fftpack.dct(wave)はデフォルトでType2を返します。
この場合逆変換はType3を使用すればよいので、実装は以下の通りとしました。

IDCT.py
def IDCT(wave):
    num_base = np.size(wave.data[0,:])
    lIDCT = L.Linear(num_base,num_base)
    for n in range(num_base):
        for k in range(num_base):
            if(n==0):
                lIDCT.W.data[k,n] = 0.0
            else:
                lIDCT.W.data[k,n] = 2*np.cos(np.pi*(k+0.5)*n/num_base)
    lIDCT.b.data[:] = wave.data[0,0]
    return lIDCT(wave)

このIDCTの注意点は、バッチ処理には使えない(!)ということです。
よりよい実装があればよいのですが。。