Fedora 23でchainerインストール


今,Fedora 23はgccのバージョンが5.3.1なので,そのままchainerをインストールしようとすると,コンパイルエラーが発生する.

原因は,以下の2点

  • CUDAがgcc 4.9までしか対応していないこと.
  • enumの扱いが変わったこと.

CUDAのgcc対応

コードを見ると,

/usr/local/cuda/include/host_config.h

の115行目に,GCCのバージョンが4.9より大きいとエラーになるような #error が書かれている.
仕方ないので,これをコメントアウトして次のようにするとコンパイルが通るようになる.

#error -- unsupported GNU version! gcc versions later than 4.9 are not supported!
   ↓
//#error -- unsupported GNU version! gcc versions later than 4.9 are not supported!

enumの扱い

元々enumはint型として扱えていたが,それができなくなっている.なので,

typedef enum enum_etype{
    a = 1
    b = 2,
    c = 3
} Etype;

int main(){
    Etype x = 0;
}

のようなコードはコンパイルエラーになる.これを防ぐにはgccのオプションに"-fpermissive" をつければ良い.

なので,chainerをインストールする際に,

alias g++="g++ -fpermissive"
pip install chainer

としたらいけた.正しいやり方かどうかわからないけど.

caffeのビルドでハマるとき


自分用メモです.

fedora22でCaffeのビルド時に,cblas関連のリンカエラーが出る場合.

CaffeのデフォルトのBLASライブラリはAtlasですが,何故かうまくいかないので,OpenBLASを使うように変更する.
やり方は,cmakeの時にBLASをAtlasからOpenに切り替える.

Pythonでbool値の引数をargparse


引数にTrue/Falseの値を渡してargparseでパースして使いたい.
ということでメモ.

ぐぐったらこういうやり方が出てきた.

def parse():
    parser = argparse.ArgumentParser(description='Argparseのテスト')
    parser.add_argument('--version', action='version', version='%(prog)s 1.0')

    parser.add_argument('--force', dest='force', action='store_true')
    parser.add_argument('--no-force', dest='force', action='store_false')
    parser.set_defaults(force=False)

    params = parser.parse_args()

    return vars(params)

この --force/--no-force の指定で force の値が True/False になる.デフォルトはFalse.

ただ,これだと

python hoge.py --force --no-force

みたいに両方指定することも可能なのでまずい.

そこで,mutually_exclusive_groupを使って,

def parse():
    parser = argparse.ArgumentParser(description='Argparseのテスト')
    parser.add_argument('--version', action='version', version='%(prog)s 1.0')

    group = parser.add_mutually_exclusive_group()
    group.add_argument('--force', action='store_true')
    group.add_argument('--no-force', action='store_false')
    parser.set_defaults(force=False)

    params = parser.parse_args()

    return vars(params)

とすることで,両方指定した時にエラーを出すことが出来る.

OpenCV 3.0.0-alphaでSIFT/SURFを使う


OpenCV 3.0を入れて,SIFTを使おうと思ったところ見当たらなかったのでメモ.
そもそも SIFT が入っている nonfree.hpp が見当たらなかった.
opencvのgitのログを見ると,31df47b 2014-08-11 の時点で,nonfreeとfeatures2dの一部がopencv_contrib/xfeatures2dへ移動したと書いてある.

なので,別途 opencv_contrib を落としてきて opencv と一緒にビルドしてインストールする必要がある.
ビルド時にCMAKEにopencv_contrib内のmodulesのパスを渡す.

手順は以下のとおり.

git clone https://github.com/Itseez/opencv.git
git clone https://github.com/Itseez/opencv_contrib.git

mkdir opencvbuild
cd opencvbuild
cmake -DOPENCV_EXTRA_MODULES_PATH=../opencv_contrib/modules ../opencv/
make
sudo make install

これでOKなはず. cmake-gui を使う場合は, OPENCV_EXTRA_MODULES_PATH を一覧から探して,Valueに opencv_contrib/modules へのパスを書く.

が,手元の環境では cudalegacy がコンパイルできないっぽい.
ひとまず BUILD_opencv_cudalegacy のチェックを外してコンパイル.

さらに,xfeatures2Dの test, perf_test がコンパイルエラーになるので,
BUILD_PERF_TESTS と BUILD_TESTS もチェックを外した.

環境は,gcc4.8,CUDA6.0です.

ちなみに,これでインストールすると,
これまでのOpenCVで nonfree/nonfree.hpp だったものは,
opencv2/xfeatures2d/nonfree.hpp になります.
なので,これまで

#include <opencv2/nonfree/nonfree.hpp>

と書いていたものは,

#include <opencv2/xfeatures2d/nonfree.hpp>

に書き換えることでコンパイルが通ります.

pep8準拠に


Python では, pep8 というコーディング規約(?)があって,
pep8 コマンドで,コードがそれに準拠しているかをチェックできる.

vim の syntastic と組み合わせると,ファイルを保存するたびに pep8 が実行され,
規約違反があった場合 vim の画面内の当該箇所に印がつく.
また,その行にカーソルを持って行くと,画面の一番下に,
どういう違反があるかが表示される.

例えば,変数名が短すぎる,関数名が hoge_hige() の形になっていない,コメント(docstring)がない,1行が長すぎるなど.

ひとまず自分の書いてるライブラリでエラーができるだけなくなるよう頑張る.

syntasticを使ってPythonのコードスタイルチェック


vimのプラグイン syntastic を入れると,pep8を使ったコードスタイルのチェックができる.

syntastic のインストールはNeoBundleを使って,

NeoBundle "syntastic"

を.vimrc に追記してから :NeoBundleInstall すればOK.

pep8についてはこの記事がわかりやすい.
要はPythonのコードスタイルチェッカー.

インストールはpipを使って

pip install pep8

でOK.

コマンドラインから生で使う方法は

python -m pep8 -v hoge.py

という感じで,pythonのコードをチェックできる.
docstringがないとか,行が長すぎるとか,変数が多すぎるとか色々言われる.

syntasticとpep8がインストールされていれば,
vimを使って python のコードを保存した時点でチェックが走り,
vim のバッファ内でどの部分がおかしいかが可視化される.

指摘された行にカーソルを持って行くと,
一番下に,どう悪いのかが表示される.

これを使ってプログラムを綺麗に書くようにしよう.

scikit-imageでの画像データの扱い


Pythonでの機械学習ライブラリとしては有名な scikit-learn があるが,
画像処理ライブラリは scikit-image がある.

最近Pythonでの画像処理の勉強をしていて気になったので,
scikit-image での画像の型の扱いについてメモ.

scikit-image ライブラリでは,画像の読み込みは,サブモジュールの skimage.data を使い,

import skimage.data

img = skimage.data.imread("lenna.jpg")

のように書く.

この時,読み込まれた画像は,uint8の型のarrayになっていて,
値は 0〜255 の間の整数値となる.

例えばグレースケール化したいと思った時,skimage.color.rgb2gray という関数を使うが,
これを行なうと,

import skimage.color
gimg = skimage.color.rgb2gray(img)

結果の gimg は,float64 型になっていて,
値は 0.0〜1.0 の浮動小数点型となる.

画像処理においては, 0.0〜1.0 の間の浮動小数点数として扱うのが,
メモリは食うけど便利.

この辺りの型の変換を行なうのが,

skimage.img_as_bool(img)
skimage.img_as_ubyte(img)
skimage.img_as_int(img)
skimage.img_as_uint(img)
skimage.img_as_float(img)

の関数.

それぞれ,
skimage.img_as_bool(img):
bool型 (True / False の2値)

skimage.img_as_ubyte(img):
uint8型(読み込んだ時の状態.[0,255]の範囲)

skimage.img_as_int(img):
int16型(uint8の[0,255]が[0,32767]にマップされる.負の値も格納可.)

skimage.img_as_uint(img):
uint16型([0,65535]の範囲)

skimage.img_as_float(img):
float64型(uint8の[0,255]が[0.0,1.0]にマップされる.負の値も格納可.)

となる.
なお,この範囲は, skimage.dtype_limits(img) によってタプルで取得可能.

C++11の機能によるparallel_for


C++11からは,std::threadというのが追加され,マルチスレッドプログラミングが標準で使えるようになった.

その機能を使って,std::for_each的な処理をマルチスレッド化したいなと思って調べたら以下のページが見つかった.

A parallel for using std::thread? | stackoverflow

やり方について色々議論があるけど,最後に出ている次のようなコードが良さそう.

template<typename Iterator, class Function>
void parallel_for(const Iterator& first, const Iterator& last, Function&& f, const int nthreads = 1, const int threshold = 1000)
{
    const unsigned int group = std::max(std::max(ptrdiff_t(1), ptrdiff_t(std::abs(threshold))), ((last-first))/std::abs(nthreads));
    std::vector<std::thread> threads;
    Iterator it = first;
    for (; it < last-group; it += group) {
        threads.push_back(std::thread([=,&f](){std::for_each(it, std::min(it+group, last), f);}));
    }
    std::for_each(it, last, f); // use calling thread while we wait for the others
    std::for_each(threads.begin(), threads.end(), [](std::thread& x){x.join();});
}

これは次のように利用できる.

std::vector<double> data={1,2,3,4,5};
for_each(data.begin(), data.end(), [](const int& i){
    // i を使った処理
});

という感じで使える.

typedefをテンプレート化したい(エイリアステンプレートというらしい)


template <typename T>
class A{
    T i;
};

みたいなクラスがあった時に,たとえばclass Aをstd::shared_ptrでくるんだ型をtypedefしたい.
普通に考えると,

template <typename T>
typedef std::shared_ptr<A<T>> SharedA<T>;

って書けばいいように思うけど,これはまだサポートされてないらしい.

調べてみると,

C++でtemplate typedef | bettamodokiのメモ
typedef テンプレート | Microsoft Developer Network
typedefテンプレート | ぼく用あれこれまとめ@wiki

と,「C++0xではできるようになる」という感じの色んな記事が見つかる.

ではと思い,上の記事を -std=c++11 オプションをつけてコンパイルしてみたが通らず….

調べた結果,これはエイリアステンプレートというもので実現されているらしい.

How to typedef a template class? | stackoverflow

これによると,書き方は

template <typename T>
using SharedA = std::shared_ptr<A<T>>;

でいいらしい.実際書いてコンパイルしてみたら通った.

staticメンバ関数メモ


staticメンバ関数はクラスを指定した呼び出ししか出来ないと思ってた.

class A{
    public:
        static int getX(){ return x; }
    private:
        static int x;
};
int A::x=0;

int main(){
    int i = A::getX();
    return 0;
}

しかし,まぁ当然だけどインスタンスからも呼べた.

int main(){
    A a;
    int i = a.getX();
    return 0;
}

それだけ.