chainer 利用時のハマりどころ

chainerという機械学習フレームワークを使っていて,いくつか引っかかったところがあったのでメモしておく. 基本はエラーメッセージさえ読んだら解決する.

カスタム訓練・テストデータを用意する時

chainer.datasets.tuple_dataset.TupleDataset を使って画像データとラベルデータを紐付けるまでは良かったが trainer.run() で以下のようなエラーメッセージが出る.

    return xp.concatenate([array[None] for array in arrays])
TypeError: string indices must be integers

文字列の添字には整数を使用しなければいけないというエラーメッセージだが,最初どこが悪いのか良くわからなかった.

デバッグすると,ラベルの連結処理で死んでるということが分かった.

結局,ラベルをファイルから読み込んでリストに追加するという前処理をしていたのだが,そのときにラベルを string のままリストにしたのが悪く,np.int32で キャストすると上手く動いた.

配列の扱い

trainer.run() の時には特別意識する必要は無いが,学習済みのモデルに対してある入力に対する出力が欲しい時にひっかかった.

ValueError: numpy and cupy must not be used together
type(W): <class 'cupy.core.core.ndarray'>, type(x): <class 'numpy.ndarray'>, type(b): <class 'cupy.core.core.ndarray'>

numpycupy を同時に使うなというエラーメッセージで,gpu使っているのに numpy.ndarray を使おうとした時に遭遇する. これは注意していればそこまで問題ではない.

ubuntu上でisoファイルを書き込む

検索ワードが悪いのもあるが,あまり引っかからなかったためメモ.

環境

手順

  1. 標準で入っている Disk (gnome-disk-utility) を起動
  2. 認識のされている USB のタブに移り
  3. パーティションイメージのリストアをクリック
  4. リストアするイメージに iso ファイルを選択
  5. リストアを開始

Kac's counting formula

Kac-rice formula 関連の日本語記事が無かったので自分の理解を深めることを兼ねて記事を書こうと思います.

ここでは,参考文献 [1] の記述の順番通りに話を進めます.最初は Kac's counting formula から.

準備

実軸上の区間 \( I \) がある.ここで,次のような滑らかな関数を考える.
\[
f_0,f_1,...,f_N:I\rightarrow \mathbb{R}
\]

また, \( k>0 \) に対し同じ確率空間  (\Omega, \mathcal{A}, {\bf P} ) のおいて平均0, 分散 \( v_k > 0 \) のそれぞれ独立している正規分布に従う確率変数 \(X_k\) が与えられたとき,次の線形結合 \(F(t)\) を作ることができる.
\[
F(t)=F_\omega(t)=\sum_{k=0}^{N}X_k(\omega)f_k(t)
\]

Dirac's delta function approximation

任意の  \epsilon に対して  \delta_\epsilon: \mathbb{R} \rightarrow \mathbb{R} を定義する.

\[
\delta_\epsilon(y)= \begin{cases}
\frac{1}{2\epsilon}, |y|<\epsilon \\
0, otherwise
\end{cases}
\]


このとき,任意の \( C^1 \) 級関数 \( f:\mathbb{R} \rightarrow \mathbb{R} \) に対して次の式が成り立つ.

\[
\lim_{ \epsilon \rightarrow 0 } \int_{ \mathbb{R} } \delta_{ \epsilon(t) } f(t) = f(0)
\]

\(I\) の区間において, \(F\) の値が \(0\) から \(\epsilon \) の間に存在している数を数える関数を \( Z_\epsilon (F, I) \) とすると次のように定義できる.

\[
Z_\epsilon(F,I):=\int_I \delta_\epsilon (F(t))|F'(t)|dt
\]

convenient の定義

1. 次の条件を満たす時,\( C^1 \) 級関数 \( f:[a,b] \rightarrow \mathbb{R} \) は convenient という

  •  f(a)\cdot f(b) \neq 0
  •  f の全ての0は非退化である. (例: \( f(t)=0 \) なら \( f'(t)\neq0 \) )

2.  C^1 級関数  F: \mathbb{R} \rightarrow \mathbb{R} proper で全ての零点において非退化であるなら,  Fconvenient という


命題 (Kac's counting formula)

区間  I 上において f=0 の数は  Z(F, I) で表される.

1. \( C^1 \) 級関数 \( F: [a,b] \rightarrow \mathbb{R} \) が convenient ならば次の式が成り立つ
\[ Z(F, [a,b] )= \lim_{\epsilon \rightarrow 0} Z_\epsilon (F, [a, b]) \]
2. \( C^1 \) 級関数  F:\mathbb{R} \rightarrow \mathbb{R}convenient ならば次の式が成り立つ.
\[ Z(F, \mathbb{R} )= \lim_{\epsilon \rightarrow 0} Z_\epsilon (F, \mathbb{R}) \]
3. 1., 2.のような F に対して,\( \nu \) を  F=0 の数, \( \kappa < \infty \) を臨界点の数とするとどんな \epsilon に対しても次の式が成り立つ.
\[ Z_\epsilon (F, I) \leq \nu + 2 \kappa \]

証明

1.  Fconvenient なので,有限個の零点  \tau_1 < ... < \tau_\nu を持つ.  F の臨界点の集合  C はコンパクトであり, F の零点集合と互いに素である.
よって,
\[ \epsilon_0 := \min_{x \in C} |F(x)| > 0. \]
 \epsilon \in (0, \epsilon_0) を固定すると,
\[ \int_{a}^{b} \delta_\epsilon (F(t))|F'(t)|dt = \frac{1}{2 \epsilon} \int_{ |F|< \epsilon } |F'(t)|dt. \]
開集合  {|F| < \epsilon } の連結成分は,臨界点集合と互いに素であり, |F(c)|=|F(d)|=\epsilon となるような開区間 \( (c, d) \subset
[a,b] \) である.そのように取った区間 F'(t) の値は次のようになる.
\[ |F(d)-F(c)|=\int_c^d|F'(t)|dt = 2\epsilon. \]

 0 \leq i \leq \nu においてある零点  \tau_i は,ある開区間  (c_i, d_i) に含まれると考えることができる(次のイメージ図を参照).
f:id:t-tatsukawa:20170626020931p:plain

よって
\[ \int_a^b \delta_\epsilon (F(t))|F'(t)|dt = \frac{1}{2 \epsilon} \sum_{i=1}^\nu \int_{c_i}^{d_i} |F'(t)|dt = \nu = Z(F, [a, b]). \]

2.  Fproper なので, |t|>a で |F(t)|>1のようなコンパクト区間 \( [-a, a] \) が存在する.この  F の制約は convenient であり,
\[ Z(F, [-a, a])=Z(F,\mathbb{R}). \]
次に, \epsilon \in (0, 1)とすると,
\[ \int_\mathbb{R} \delta_\epsilon(F(t))|F'(t)|dt=\int_{-a}^{a}\delta_\epsilon(F(t))|F'(t)|dt. \]

よって,
\[ \lim_{\epsilon \rightarrow 0} \int_\mathbb{R} \delta_\epsilon (F(t))|F'(t)|dt=\lim_{\epsilon \rightarrow 0} \int_{-a}^{a} \delta_\epsilon(F(t))|F'(t)|dt=Z(F, [-a,a])=Z(F,\mathbb{R}). \]

3.  F は有限個の臨界点を持つため,ロルの定理よりどんな  c \in \mathbb{R} に対して, F(t)=c となるような有限個の解を持つ.
\epsilon > 0 を固定すると,集合  {|F|<\epsilon} の連結成分は, |F(a)|=|F(b)|=\epsilon であるような区間  (a, b) に到達する. |F(t)|=\epsilon は有限個の解を持つため, {|F|<\epsilon} の有限個の成分は次のように表される.
\[ J_l=(a_l,b_l), l=1,...,L. \]
よって,
\[ \int_I \delta_\epsilon (F(t))|F'(t)|dt=\frac{1}{2 \epsilon} \sum_{l=1}^L \int_{J_l} |F'(t)|dt. \]

 k_l J_l 上の  F(t)turning point の数とする.
ある J_l において  F(t)turning point を含まないなら  F(a_l)F(b_l)<0 かつ  J_l は固有の零点を持つ.
\[ \sum_{l=1}^L \int_{J_l} |F'(t)|dt=2 \epsilon. \]

ここで  L_0, L_1 を次のように定義する.
\[ L_0 := \{l=1, ..., l; J_l \text{は turning point を含まない} \} \]
\[ L_1 := \{l=1, ..., l; J_l \text{は turning point を含む} \} \]

上の議論から  |L_0|=\nu,  |L_1| \leq \kappa が言える.よって,

\[ \frac{1}{2\epsilon} \sum_{l=1}^L \int_{J_l} |F'(t)|dt = \frac{1}{2\epsilon} \sum_{l\in L_0} \int_{J_l} |F'(t)|dt+\frac{1}{2\epsilon} \sum_{l\in L_1} \int_{J_l} |F'(t)|dt\\
=\nu+\frac{1}{2\epsilon} \sum_{l \in L_1} \int_{J_l} |F'(t)|dt. \]

 l \in L_1 の開区間の中で  Fturning point を次のように置く.
\[ t_1 < ... < t_{k_l} \]

よって,
\[ \int_{J_l}|F'(t)|dt=|F(a_l)-F(t_1)|+F(t_1)-F(t_2)|+...+|F(t_{k_l})-F(b_l)| \leq 2\epsilon (k_l + 1). \]

なので,
\[ \frac{1}{2\epsilon} \sum_{l\in L_1} \int_{J_l} |F'(t)|dt \leq \sum_{l\in L_1} (2k_l + 1) \leq \kappa + |L_1| \leq 2\kappa. \]


参考文献

[1] ON THE KAC-RICE FORMULA


余談

久しぶりに hatenablog に記事を書いたが,数式の記法がややこしい上によくわからない状態で正しくレンダリングされない問題があり,かなり辛い感じを受けた.
`\[ \eta \]|`が上手く表示されないっぽい.

DjangoでのSQL操作のメモ

マイグレーションの作成

python3 manage.py makemigrations

マイグレーションの実行

python3 manage.py migrate

マイグレーションSQL文を吐く

python3 manage.py sqlmigrate (アプリ名) (バージョン番号)

データベースへのログイン

python3 manage.py dbshell

テーブル構築でエラー吐いた時

  1. テーブルを消す
  2. 最新の一つ前のマイグレーションまでのSQLを実行する
  3. migrateする

…めちゃくちゃ非効率で嫌なので他に良い方法ないかなぁ…

predicateの記述法

c++の理解が浅すぎるので迂闊なことは書けないですが自分へのメモ。

std::sortやstd::transformを使っているとpredicateを指定する状況が自然に生まれてきます。

predicateは関数オブジェクトで表すことができます。関数オブジェクトは()をオーバーロードしたクラスで表すことができます。途中で関数ポインタとの違いが分からなくなって
[*1]を参考にしました。インライン化に関しての理解が浅いので後で[*2]を読みます。

ところでlambda式が評価されるとclosure objectになります[*3]。closure objectは一種の関数オブジェクトになります。よってpredicateはlabmda式で表すことができます。

サンプルコード

int main() {
    auto compare = [](const std::complex<float> &a, const std::complex<float> &b) -> bool {
        if(abs(a) == abs(b)) {
            if(a.real() == b.real()) return a.imag() > b.imag();
            return a.real() > b.real();
        } else {
            return abs(a) > abs(b);
        }
    };

    std::vector<std::complex<float>> seq;
    seq.push_back(std::complex<float>(0.5f, 1.0f));
    seq.push_back(std::complex<float>(0.5f, 0.3f));
    seq.push_back(std::complex<float>(4.2f, -1.0f));
    seq.push_back(std::complex<float>(0.0f, -2.0f));
    seq.push_back(std::complex<float>(2.0f, 0.0f));
    seq.push_back(std::complex<float>(-2.0f, 0.0f));

    std::priority_queue<std::complex<float>, std::vector<std::complex<float>>, decltype(compare)> queue(compare);
    for(auto element : seq) {
        queue.push(element);
    }
    
    std::sort(seq.begin(), seq.end(), compare);

    std::cout << "std::sort" << endl;
    for(auto element : seq) {
        std::cout << element.real() << ',' << element.imag() << std::endl; 
    }

    std::cout << "std::priority_queue" << endl;
    for(; !queue.empty(); queue.pop()) {
        auto element = queue.top();
        std::cout << element.real() << ',' << element.imag() << std::endl; 
    }
}

出力

std::sort
4.2,-1
2,0
0,-2
-2,0
0.5,1
0.5,0.3
std::priority_queue
0.5,0.3
0.5,1
-2,0
0,-2
2,0
4.2,-1

参考文献

clang_completeでopencvの補完を出すようにする

vimの情報を追っていないのでclang_completeが流行っているのかも定かではないけど自分へのメモ。

開発しているディレクトリに.clang_completeというファイルを作る。中身は下のような感じで。*は適宜変える。

-I/*/opencv/*/include/opencv
-I/*/opencv/*/include/opencv2
-I/*/opencv/*/include
-I/*/usr/local/include
-I.
-DLRVTRACK_WITH_OPENCL

っていうかhelp開いてconfigurationの所見たら書いてるのでhelp開く癖つけましょう(自分への戒め)

4. Configuration *clang_complete-configuration*

Each project can have a .clang_complete at his root, containing the compiler
options. This is useful if you're using some non-standard include paths or
need to specify particular architecture type, frameworks to use, path to
precompiled headers, precompiler definitions etc.

Note that as with other option sources, .clang_complete file is loaded and
parsed by the plugin only on buffer loading (or reloading, for example with
:edit! command). Thus no changes made to .clang_complete file after loading
source file into Vim's buffer will take effect until buffer will be closed and
opened again, reloaded or Vim is restarted.

Compiler options should go on individual lines (multiple options on one line
can work sometimes too, but since there are some not obvious conditions for
that, it's better to have one option per line).

Linking isn't performed during completion, so one doesn't need to specify any
of linker arguments in .clang_complete file. They will lead to completion
failure when using clang executable and will be completely ignored by
libclang.

Example .clang_complete file: >
-DDEBUG
-include ../config.h
-I../common
-I/usr/include/c++/4.5.3/
-I/usr/include/c++/4.5.3/x86_64-slackware-linux/

Code Thanks Festival B

12月14日(日)、Code Thanks Festival B日程に参加してきました。

勉強会と被ってた & テスト期間が先週まで続いていた & レポートがやばかったのでほとんど準備らしい準備はできずに参加しました。

問題

A問題

int main() {
    ios_base::sync_with_stdio(0);
    int A, B;
    cin >> A >> B;
    cout << max(A, B) << endl;
}

B問題

int main() {
    ios_base::sync_with_stdio(0);

    int A, B, C;
    cin >> A >> B >> C;
    int D = max(A+B, A*B);
    cout << max(D*C, D+C) << endl;
}

C問題

int main() {
    ios_base::sync_with_stdio(0);

    int N, ans = 0;
    cin >> N;
    vector<int> v(N);
    for(int i = 0; i < N; i++) {
        cin >> v[i];
    }
    int a;
    for(int i = 0; i < N; i++) {
        cin >> a;
        if(v[i] / 2 < a) {
            ans++;
        }
    }

    cout << ans << endl;
}

D問題

int d[1001];

int main() {
    ios_base::sync_with_stdio(0);
    
    int N, T, A;
    cin >> N >> T;
    int ans = 0;
    for(int i = 0; i < N; i++) {
        cin >> A;
        for(int j = 1; ; j++) {
            if(j * A > T) break;
            d[j*A]++;
            ans = max(ans, d[j*A]);
        }
    }
    cout << ans << endl;
}

E問題

typedef pair<int,int> P;

int R, C, N;
int field[50][50];
bool ok[50][50];
int x[4] = {0, 1, 0 , -1};
int y[4] = {1, 0 , -1, 0};

int main() {
    ios_base::sync_with_stdio(0);

    P s, g;
    cin >> R >> C;
    cin >> s.first >> s.second;
    cin >> g.first >> g.second;
    s.first--, s.second--;
    g.first--,g.second--;

    cin >> N;

    memset(field, -1, sizeof field);
    int r, c, h, w;
    for(int i = 0; i < N; i++) {
        cin >> r >> c >> h >> w;
        r--, c--;
        for(int y = 0; y < h; y++) {
            for(int x = 0; x < w; x++) {
                ok[r+y][c+x] = true;
            }
        }
    }
    

    for(int i = 0; i < R; i++) {
        for(int j = 0; j < C; j++) {
            field[i][j] = -1;
        }
    }


    queue<P> que;
    if(ok[s.first][s.second]) {
        field[s.first][s.second] = 0;
        que.push(s);
    }
    for(; !que.empty(); que.pop()) {
        P p = que.front();

        if(p.first == g.first && p.second == g.second) {
            cout << "YES" << endl;
            return 0;
        }

        for(int i = 0; i < 4; i++) {
            int ny = p.first + y[i];
            int nx = p.second + x[i];

            if(0 <= nx && nx < C && 0 <= ny && ny < R && ok[ny][nx] && field[ny][nx] < 0) {
                field[ny][nx] = field[p.first][p.second] + 1;
                que.push(make_pair(ny,nx));
            }
        }
    }


    cout << "NO" << endl;

}

F問題

const long long MOD = 1000000007;
long long dp[1001];

int main() {
    ios_base::sync_with_stdio(0);

    string X, S, T;
    cin >> X >> S >> T;

    int ans = 0;

    dp[0] =1;

    for(int i = 0; i < X.size(); i++) {
        bool f = true;
        for(int j = 0; j < S.size(); j++) {
            if(X[i+j]!=S[j]) {
                f = false;
                break;
            }
        }
        if(f) {
            (dp[i+S.size()] += dp[i]) %= MOD;
        }
        f = true;
        for(int k = 0; k < T.size(); k++) {
            if(X[i+k]!=T[k]) {
                f = false;
                break;
            }
        }
        if(f) {
            (dp[i+T.size()] += dp[i]) %= MOD;
        }
    }

    cout << dp[X.size()] << endl;
}

G問題

int dp[501][501];

bool solve(int n, int p) {
    if(dp[n][p] != -1) return dp[n][p];
    if(n <= p) return dp[n][p] = true;
    bool res = false;
    for(int i = 1; i <= min(n, p); i++) {
        if(!solve(n-i, i+1)) {
            res = true;
            break;
        }
    }

    return dp[n][p] = res;
}

int main() {
    int N, P;
    cin >> N >> P;
    for(int i = 0; i <= N; i++) for(int j = 0; j <= N; j++) dp[i][j]=-1;
    cout << (solve(N, P) ? "first" : "second") << endl;
}

H問題

解いてない

所感

  • 結果的にamazonカード9000円分と焼肉権を頂いたので行って良かったなと思います。

f:id:t-tatsukawa:20141225182728j:plain

  • DP比較的得意な方とか思っていたけど2人で勝敗を決める系のDP書いたことが無くて撃沈したのが辛かった。
  • 叙々苑の焼き肉弁当美味しかったです。
  • 結構Twitterのフォロワーが沢山いて焦った。
  • 懇親会は完全に音ゲーマーのためのイベントと化していた。あの雰囲気には入れないなぁ。
  • スタッフの皆さんありがとうございました。