Stimulator

機械学習とか好きな技術話とかエンジニア的な話とかを書く

なんかホームページを作った

- 7月10日(金) -

突然学部生の1人がゼミ終わりに

「ばんくしさんWebの知識あります!?」

から入って

「Webサイト作って勝負しませんか」

と言い出したのでその日にサーバとドメインを取った.

Webの知識はJavascriptを少し書いた事ある程度だったが何か始まった.

- 7月11日(土) -

Julia言語の勉強会に出てLTした.

懇親会ではJuliaの話も機械学習の話もできて良かった.

とても楽しかった.


- 7月12日(日) -

フォロワーと蕎麦を食べに言ってカラオケをして晩御飯はお酒を飲んだ.

とても楽しかった.


- 7月13日(月) -

月曜日は大学で実験のTAがある.

めちゃくちゃ大変だった.


- 7月14日(火) -

なんかPython書きたいしDjangoとかいうの使う事にした.


- 7月15日(水) -

午前から演習のTAと午後実験TAが被る最悪の日だった.

完全に厄日だった.


- 7月16日(木) -

台風が来るとの事だったのでおうちの片付けとかをした.

日曜日に仲の良いフォロワーが泊まりに来るとの事なのでトイレや風呂も掃除した.

綺麗な部屋はサイコー!


- 7月17日(金) -

研究室でゼミがあるので大学行った.

学部生のサイトを見せてもらうと既に広告が貼ってあってちょっと引いた.


- 7月18日(土) -

今、午前3時でなんかWebサイトができたので公開した.

http://vaaaaanquish.jp

PHPとかPythonDjango,bootstrapとjsとでなんか書いた.



- 今後の予定 -

何も公開してないGitとかにコンテンツが天から降ってきて欲しい.

後輩のWebサービスも許可してもらえたらいずれ紹介したい.

あと何か問題ありそうだったら言って欲しい感じのやつです.よろしくお願いします.

MacにJuliaしてSublimeTextする

OS X Yosemite 10.10.3にプログラミング言語"Julia"を導入して、Sublime Text 2の環境を整える話。

- はじめに -

Juliaは科学数値計算向けに開発されている言語です。
MatlabやR、Octave、numpy、scipyのような記述でかつ高速に処理を行えます。
http://julialang.orgにもあるように他言語に比べてとにかく早いです。めっちゃ早いです。

最近では、電脳戦の将棋AI等にも使われ、少しずつ認知度が上がってます。
私は機械学習を専攻していますが、Pythonで設計してJuliaで実験するのが日常になっています。

Juliaの構文以外で好きなところして

  • 早い > 嬉しいです
  • Juliaの中身がJuliaで書かれている > いざという時なんとかなります
  • Python連携 > Pythonのコードやライブラリを呼び出したり、Pythonからの移行が非常に楽です。

この辺が気に入って書いています。
後以下の記事とかを暇潰しに読んでいたところハマりました。


- Juliaのインストール -

参考:https://github.com/staticfloat/homebrew-julia/

Macにhomebrewをインストールしておいて

$ brew update
$ brew install gfortran
$ brew tap staticfloat/julia
$ brew install julia

起動した
f:id:vaaaaaanquish:20150519061826p:plain

- エラーと解決策 -

- brew update

brewのアップデートでエラーが出て

error: Your local changes to the following files would be overwritten by merge:
    Library/Formula/boost.rb
Please, commit your changes or stash them before you can merge.
error: Your local changes to the following files would be overwritten by merge:
    Library/Formula/boost-python.rb
    Library/Formula/gflags.rb
    Library/Formula/glog.rb
    Library/Formula/lmdb.rb
    Library/Formula/protobuf.rb
    Library/Formula/snappy.rb
    Library/Formula/szip.rb
Please, commit your changes or stash them before you can merge.
Aborting
Error: Failure while executing: git pull -q origin refs/heads/master:refs/remotes/origin/master

この前機械学習ライブラリのCaffeを入れた時に書き換えたのでgit mergeできないと怒られた。
強制的に上書きして解決した。

$ cd $(brew --prefix)
$ git fetch origin
$ git reset --hard origin/master

これで行けるでしょって思ったら

error: Your local changes to the following files would be overwritten by merge:
    opencv.rb
Please, commit your changes or stash them before you can merge.
Aborting
Error: Failed to update tap: homebrew/science

scienceの中身も書き換わっていたので、/usr/local/Library/Taps/のscienceのバックアップを取ってからtap

$ cd /usr/local/Library/Taps/homebrew
$ mv homebrew-science/ homebrew-science-bak/
$ brew tap homebrew/science

brew update上手くいきました。

- install gfortran

あとgfortranのインストール時にもエラーが出た

Error: No available formula for gfortran 
GNU Fortran is now provided as part of GCC, and can be installed with:
  brew install gcc

gccの中に入ってるからgccインストールすれば良いとの事。gccは以前入れていたのでスルーした。
入っていなければエラー通り

$ brew install gcc

多分大丈夫。

- Sublime Textでbulid -

Command+bでビルドしたいので、[Tools]>[Bulid System]>[New Build System](日本語だと[ツール]>[ビルドシステム]から[ビルドシステムの追加])を選択。よしなに設定を書いた。

{
    "cmd": ["julia", "$file"],
    "selector": "source.julia"
}

 

- Packageのインストール -

Package Installerが導入されているなら、いつものCommand+Shift+PでInstall Packageを選択し

を入れると吉っぽい。

(他にもIJuliaのPackageもあったけどST3にしか対応してないので入れてない)

- テスト -

1linerのHello World(Fizzbuzz)
GitHub - vaaaaanquish/Julia_1liner_helloworld_fizzbuzz: show title

println([(x==0) ? "Hello, World!" : (x%3==0) && (x%5==0) ? "FizzBuzz" : (x%3==0) ? "Fizz" : (x%5==0) ? "Buzz" : x for x in 0:20])

 

- まとめ -

問題なく動いてハッピー。
Juliaにコード規約とかそれ関連のSTPackageとかできないかなと思う日々である。

LOGICOOL Bluetooth マルチデバイス キーボード ブラック k480をつかう

タイトル通りです。誕生日にびーきゃぷ(@beepcap)さんからもらったものです。

www.amazon.co.jp

レビューみたいな感じです。
ちなみに前の前のキーボードが壊れ、研究室のゴミ箱にあったキーボードを使っていた人が書いています。

見た目です。

f:id:vaaaaaanquish:20150321233658j:plain:w400

良いです。

ちょうど横になったiPad miniiPhoneが入ります。
端末を立てる所はゴムっぽい素材なので結構安定して立ちます。

キータッチも好きです。
少しキーが小さいですが、僕は指が大きくないので十分に感じます。
打鍵は可もなく不可もなくといった感じ。すぐ慣れました。
見た目は薄い感じですが、この見た目からすると打鍵感と音が強めだと思います。

見た目に反してそこそこの重量があるので安定して活動できます。

Bluetoothも良好です。
有線と無線どちらも使えれば最高でしたが、プログラミング等特に大きな不満なく活動出来ています。

端末切り替えも良い感じです。3つの端末を切り替える事ができて、WindowsLinuxOS XAndroidiOSで試して、切り替え時のペアリングは高速で良好、cmdやctrlもあり、長時間使っていないと自動で切断もしてくれます。

色んなマシンを使うので、このキーボードから手を離さず全ての動作が出来てとても快適になりました。L字デスクの端にあるMacbookに対してすらこのキーボードを使っています。


唯一の不満はキーボードが平面すぎる事でした。調整できません。

f:id:vaaaaaanquish:20150321233741j:plain:w400

少し斜めになってるのが好きなんですよね。
でもよくデスクを見渡して見ると、目の前にKORGシンセサイザーの名器「X50」がありました。

f:id:vaaaaaanquish:20150321233720j:plain:w400

この隙間に・・・

f:id:vaaaaaanquish:20150321233710j:plain:w400

ピッタリ!!

最高の角度になりました。

今ではこれ一つで活動しています。
外出時にも良さそうで、iPadとこれだけ持って出て軽いコーディングぐらいならできるなあとか思っています。



かなり気に入ってるので記事にしました。
キー配列や端末数を考慮したハイエンドモデルが色々出たら俺は買うぞって感じでした。

ありがとうbeepcap!ありがとうLogicool


(マウスも似たようなマルチデバイスで使えるやつあると良いなあ・・・)

Deep LearningとConvolutional Neural Network

- はじめに -

前回機械学習ライブラリであるCaffeの導入記事を書いた。今回はその中に入ってるDeep Learningの一種、Convolutional Neural Network(CNN:畳み込みニューラルネットワーク)の紹介。

CNNは今話題の多層ニューラルネットDeep Learningの一種であり、画像認識等の分野に大きな成果をもたらしています。

まあCNNすごい。本当、画像認識系だと一強といった感じ。
実装経験もあるのでよしなに書いてみようという記事。


追記:2018-10-24
この記事は2014年終盤、Deep Learningに関連するネット記事も数個しかなく、各論文でもCNNに関する理解が分かれていたような時期に、大学生であった筆者が書いた記事です。概念の理解の助けになるよう残していますが、正しくない箇所も後々多く出てくるかと思います。考慮の上、お読み頂ければと思います。


- ニューラルネットとは -

Deep Learningは、脳の神経回路網を模したニューラルネットワークを多層にしたものである。
ニューラルネットワークもとい機械学習の目的は回帰や分類、次元削減等である。


f:id:vaaaaaanquish:20150125220403p:plain:h300:w400


データから読み取れる「複雑な関数」を得る事ができれば、例えば今流行りの「分類で言うとこれは人だ」とか「今あるデータの傾向から未来を予測」のような事ができる。

その仕組みは死ぬほど大雑把に言うと、"関数の足し算"である。
フーリエ変換で音をsin波の組み合わせで表現できるように、複雑な関数を複数のニューロンが持つ活性化関数を用いて表現する。


f:id:vaaaaaanquish:20150125220611p:plain:h100:w200


ニューラルネットを構成する「ニューロン(Neuron)」は、1つ1つがある関数(活性化関数)を持つ。
それぞれのニューロンが持つ活性化関数は"パラメータ"が少しずつ違い、同じ形ではない。
重みを持ったノードでニューロン同士つなぎ合わせる事で、複雑な関数を表現する事ができる。


f:id:vaaaaaanquish:20150125220632p:plain:h300:w500



- 多層ニューラルネットワーク -

ニューラルネットは、多層にする事で「表現力を上げる」事ができる。
ニューラルネットが出来る事に次元削減がある。言葉の通り問題の次元を減らす事が可能である。

以下の図のように、二次元にデータが分布していた時、そのデータの特徴を得る事が出来れば、その特徴は一次元の分布としても見ることができる。語弊覚悟で言うと特徴抽出、次元削減とも言える。


f:id:vaaaaaanquish:20150125221815p:plain


これは二次元以上にも同じ事が言える。機械学習における次元とは問題の条件であったりするので、10000次元等の複雑な問題を簡単な視点にする事が出来る。


次元削減を複数回行って簡単化し、最後は分類や回帰の問題を解く。これが多層ニューラルネットワークである。

- Deep Learning -

多層ニューラルネットの考え方は、ニューラルネットの元始となるパーセプトロンが出て来た当初から存在していた。多層ニューラルネットは理論上どんな関数でも表現でき、今回のテーマのCNNも、日本人研究者である福島邦彦先生が1982年にネオコグニトロン*1として発表されたものが元になっている。

では何故その昔から存在する多層ニューラルネットワークが今話題なのか。
その理由として以下の3つ、ハードウェアと学習技術、次元削減がある。

  • ハードウェア性能の向上

前述の通り、ニューロンには活性化関数があり、それぞれのニューロン毎にパラメータが違う。
ニューラルネットは「学習」と呼ばれる作業によって、そのパラメータを調整し、関数の表現に至る。
学習は、データを入力しニューラルネットの出力から得た誤差を後ろ向きに伝搬しパラメータを微調整、次のデータを入力し出力から得た誤差を…という微調整作業の繰り返しである。誤差逆伝播*2


f:id:vaaaaaanquish:20150126052041p:plain

この"繰り返し計算する"作業というのはコンピュータの最も得意とする分野である。しかし、コンピュータにも限界がある。ニューラルネットの規模を大きくすれば精度を見込めるが、その反面で大きなニューラルネット、多層に繋げたニューラルネットの学習を処理できるマシンがなかった。それらの計算は、微分計算等が含まれ非常に複雑だったことも計算量増加に繋がっている。
ハードウェアの登場はとても大きいと言える。

  • "学習"技術の向上

先ほど学習として挙げた誤差逆伝播法は、多層のニューラルネットでは難しいという問題があった。*3
多層ニューラルネットで誤差を伝搬していくと、出力に近い層では正しく調整できるが、入力に近い層では誤差が拡散してしまい上手く調整できなかった。


      f:id:vaaaaaanquish:20150126052152p:plain

後述するが、そこを上手く学習するための手法が多く提案され、その結果にDeep Learningがある。

  • 次元削減

前述したように、Deep Learningは次元削減を繰り返すで問題の特徴を捉える。この作業はその他の機械学習器を使う際、画像であればSIFTやHOGといった"別のアルゴリズム"を用いて行っていた。そして、問題に応じてこの特徴量設計が上手く噛み合わないと、いくら機械学習器自体の精度が高くても良い結果が出ない。それらはノウハウを用いて、ある意味手動で設計する必要があった。

Deep Learnigでは、その多層構造によって次元削減を行う事になる。これにより、特徴抽出の部分をニューラルネット構造1つで調整する事が可能であり、かつ得られる特徴量はその問題に適した形であるので、主題となる分類問題や回帰問題を上手く解決する事が出来る。


f:id:vaaaaaanquish:20150126052310p:plain


- Deep Learningにおける学習技術 -

学習手法では、データの取り方や誤差逆伝播法のアルゴリズム、活性化関数の工夫等様々な研究が出てきた。
中でもDrop outやpre-trainingがブレイクスルーのきっかけだと言える。

Drop outは学習する時に、一部のニューロンを無いものとする。Drop outすることで、誤差を拡散させずに上手く学習する事が出来るようになる(接続を無いものとするDrop Connect等もある)。

      f:id:vaaaaaanquish:20150126052855p:plain


Dropoutの実装と重みの正則化 - もちもちしている

  • pre-training

pre-training(事前学習)は、ある次元削減可能なニューラルネットモデルを事前に学習させておき、ある程度良い初期パラメータにしてから多層に繋げる手法である。pre-trainingによって、多層ニューラルネット全体を誤差逆伝播法で調整する際、良いパラメータから学習を始められるので、残念なパラメータに陥り抜け出せないという事が少なくなる。pre-trainingではRBMやAuto Encoder等のニューラルネットモデルが使われている。


f:id:vaaaaaanquish:20150126053048p:plain


研究が活発になり、RBMモデルを使ったDBM(Deep Boltzmann machines)やらCNN、DNN、RNN…技術の組み合わせや種類で様々なDeep Learningがあり、それらがごちゃごちゃになったネット記事が複数ある状況が今といった感じ。

- CNNにおける学習 -

CNNは前述のpre-trainingとは少し違った方法によって、その精度を確立する。

例として画像認識タスクを考える。
多層ニューラルネットワークの問題として勾配の更新が上手くできない問題(Vanishing gradient problem)を挙げたが、他に移動や歪みに対する柔軟性、汎用性に欠けるといった問題があった。ニューラルネットは、固定的な画像に対してはその画素入力から正しい応答を行うよう学習できる。しかし、ニューロン同士の接続が多さから、画素がズレるとその1つの入力の誤差が出力に影響を及ぼす事になる。それらのどちらの問題にも対応し、汎用性を高く考えられたのが、Convolutional Neural Network、CNNである。

- 局所受容野 -

画像のズレ等の入力が出力に影響し、そこから得られる誤差が学習の精度を下げているなら、その誤差が全てのニューロンに伝搬するのを止めてしまおうという考え方がある。多層ニューラルネットにおける層同士の接続を制限する"局所受容野"を用いる。

      f:id:vaaaaaanquish:20150126053545p:plain:h250:w300

図のように、層ごとに接続の制限を行う。中間層は左層の一部の局所的なデータを入力としている。局所的なデータを入力とするが、次の層(右層)でデータ全体を反映する事が可能となっている。さらに、逆向きに誤差の伝搬する際には、全てのニューロンに誤差が影響しない事が分かる。誤差の影響範囲を狭める事で、前述したVanishing gradient problemにも対応する形となる。局所受容野をオーバラップする(中間層-左層の接続でに関して被る部分がある)事で、データの欠損やズレがある場合でも、他ニューロンとの競合によって解決する事が出来る。

さらに、"共有重み"(Tied Weight)と呼ばれるテクニックを用いる。図のように局所受容野のノードの重みを共有する。更新する際に用いる伝搬誤差はそれぞれの誤差の和となる。

      f:id:vaaaaaanquish:20150126054639p:plain

この局所受容野を複数用いる事で、画像に移動、歪みが発生しても、それぞれ移動不変性を持った局所受容野の結果から統合的にデータを用いる事となり、高精度の認識が可能となる。

画像認識におけるCNNでは、この局所受容野をフィルタやウィンドウと捉え、重みを持たせる。この重みフィルタ(≒共有重みを持つノード群)をシフトしていく事で層の出力を決定する形を取る。実装の際には、様々あるが、下図のようなフィルタ処理となる場合が多い。

f:id:vaaaaaanquish:20150126055121p:plain
この局所受容野による処理を複数行う。先程同様フィルタ処理として表現すると以下のような図となる。
f:id:vaaaaaanquish:20150126055246p:plain
フィルタをかけたものを特徴マップと呼ぶ。それらは共有重みを持つ局所受容野(フィルタ)によって複数生成される。多層にする場合は前層の"特徴マップ"から同じ座標に対してフィルタをかけ足し合わせる。これがCNNが"畳み込みニューラルネットワーク"と呼ばれる所以でもある。数式で表すと畳み込み演算である事がよく分かる(要出典)。
f:id:vaaaaaanquish:20150126055215p:plain

- プーリング -

局所受容野によって、画像の移動不変性や誤差拡散の抑制を得た。しかし、図を見ても分かるように、畳み込み処理によって特徴マップは増えていくことになる。特徴マップが局所受容野のスケール次第で小さくなるとは言えるが、マップが増える計算時間は大きい。さらに以下の図のように、局所受容野のフィルタを1ピクセルずつ移動させる実装であれば、特徴を検出できるのに対して、2ピクセルの移動であれば検出できない可能性がある。1ピクセル毎に移動し計算を行うと計算時間が増加してしまう。そこで、CNNでは、プーリングと呼ばれるテクニックを用いる。

プーリングは、画像で言うところの低画像化である。ニューラルネットの層の間に非線形な低画像化処理を挟み、少ないニューロンで次の層へ入力する。この処理によって、移動不変性を確実なものとするだけでなく、畳み込み演算における計算の削減を行う事が出来る。

f:id:vaaaaaanquish:20150126055504p:plain

プーリングには平均をとるaverage poolingや最大値をとるmax poolingがあり、CNNにおいてそれぞれの効果や使い方が数多く研究されている。

- Convolutional Neural Network -

CNNでは、局所受容野による畳み込み演算とプーリングを交互に繋げ、最後に主題に合わせて全接続の3層ニューラルネットSVMを接続する。

f:id:vaaaaaanquish:20150126055607p:plain

最後、誤差逆伝搬法を適応し全体の調整をする事で精度を出す。

上記したような手法によって、今までのニューラルネットの問題を解決し、高精度でしっかり学習が行える素晴らしいDeep Learningである。

- まとめ -

  • ニューラルネットの誤差拡散を防げるDeep Learning
  • 人が設計していた特徴抽出の部分もやってくれるDeep Learning
  • Dropout,pre-trainingすごい
  • CNNはpre-trainingを使わずに実現(おかげで早い)
  • CNNは局所受容野で誤差拡散を防ぎ移動不変性を得る
  • CNNはプーリングよるニューロン削減を行っても学習できる

 

- あとがき -

CNN、面白い程精度が出るので研究室で改造するのが暇潰しになる。
あと、特徴マップとかも出力してみると興奮する。畳み込みは理に適ってて好き。
研究者も多くなってきたので、今後発展しそうな予測から記事にした。

多分こんな感じの発表をゼミや勉強会でするとマサカリ以前に見向きもされないとか思いながら書いた。
CNNとかフィルタ処理として捉えすぎると線形な機械学習器である事を同時に説明しづらいし、ちゃんとニューラルネットから学習や関数における工夫、実装ノウハウ的な部分まで次は書きたい。

最近は転移学習で別の問題を解いてからやると良いとか(ほぼpre-trainingに感じる)、学習の更新がそもそもとか色々あって、結局どこに落ち着くのかとかも見てて面白い。


 

Mac OS X 10.9.5でCaffeする

※注意:この記事はMac OS 10.9が最新だった頃に書かれたものです。2015/6/15に諸事情で再インストールを行いましたがformulaの書き換えが不必要、変更になったりその他ファイルの書き方が変わったりとインストール自体は楽になっています。日々変更があるようですので、記事内同様のエラー等で無い限り最新の別記事を参照した方が良いと思われます。
//--はじめに--

巷で「CaffeをインストールすればConvolution Neural Networkを誰でも簡単に作れる!」「CaffeはDeep Learningの基準!」みたいな意見を見るようになった。機械学習の難しい数式を理解しなくても、高速で最高精度の特徴抽出、認識が出来て、その上、出力や重みの可視化、ネットワーク構成の図まで作れる。つよい。

Caffeは、現GoogleのYangqing Jia氏が作成した。その精度もさることながら、OSSとしての開発速度が驚異的。専用のコミュニティやGithub上での最新アルゴリズムの実装、チュートリアルやドキュメントも完備、ネットワーク構造図も出力出来る事から最近では論文でも実装をCaffeで行ったものがあり"学習済のモデルデータ"まで配布している所もある。

現状強いのはCNN(Convolution Neural Network)で、色んな技術がforkされている。マジでGithub見ているだけでも面白い。本体はCUDAを用いた分散実装で少し読みにくいが、出力等を簡単に制御出来るようになっているし、何よりめっちゃ速い。

いたせりつくせりである

Pylearn2やTheano、sklearnに並ぶ機械学習ライブラリ。CNNで論文書くなら使いたいみたいな感じ。

//--面倒くさがりバイバイ--

素晴らしいライブラリだけあって準備が大変。正直「何が"簡単にCNN出来ます"じゃw」となる。
Linux,Unixではhomebrewやpip、Anaconda等といったパッケージ管理がまず必須。自分でソースファイルをコンパイルしても良いが諸準備が多いのでパス周りがごちゃごちゃにならないようにした方が良い。
加えて公式HPで前準備して欲しいと言っているのはこちら

  • CUDA library
  • BLAS (provided via ATLAS, MKL, or OpenBLAS)
  • OpenCV (>= 2.4)
  • Boost (>= 1.55, although only 1.55 and 1.56 are tested)
  • glog, gflags, protobuf, leveldb, snappy, hdf5, lmdb
  • その他rapper

多い。加えて数値計算ライブラリであるnumpyやscipyも必須となる。
全部書くと大変なので、今回はnumpy,scipy,OpenCVは既にインストールされている、パッケージ管理としてbrewとpipを導入している前提で記事を書く。

//--環境--

CaffeではLinux,Unixでの使用を推奨している。
今回の環境はOS X 10.9.5
10.8では簡単に出来てYosemiteだと難しいらしい(要出典)。
Linuxは次の記事で書く。
OS Xではバージョン毎にコンパイラや標準ライブラリが違ったりするので「今のバージョン」や「コンパイラに何を使っているか」を把握しておく必要がある。

//--CUDA library--

NVIDIAが提供するGPGPUが使えたりするライブラリ。これのおかげで速い。
CUDA Downloads
公式ページ(上リンク)から自分のOSに合ったpkgをダウンロード、pkgインストーラを開いて規約を読みつつよしなにインストールする。
Macだととりあえず1つしかpkgがないから選択肢なし。

//--BLAS--

Basic Linear Algebra Subprograms:ベクトルと行列に関する基本線型代数操作を実行するライブラリAPI
オープンソースの移植性の高い最適化BLAS実装としてATLAS、Intel MKS等がある。
CaffeではATLAS、MKL、OpenBLASの3つに対応している。すごい。
標準はATLASであるが、CaffeコミュニティではOpenBLASにするとRun Testにおけるエラーが減ったという書き込みもあるのでどちらがいいかは微妙。

今回はATLASで導入。
http://sourceforge.net/projects/math-atlas/files/Stable/
ここからソースを落としてきて展開する。ディレクトリ内に移動して

$ mkdir build
$ cd build
$ ../configure
$ make

インストール完了。

//--周辺パッケージ群--

glog, gflags, protobuf, leveldb, snappy, hdf5, lmdb。必要な周辺パッケージ群。

左から、ログ取り、コマンドラインのフラグ処理、データの構造化、軽量データベース、圧縮、ファイルの階層構造操作、RAM(インメモリ)上でのデータベース操作用のライブラリ。どれも素晴らしいので1つ1つ見てても面白い。

$ for x in snappy leveldb gflags glog szip lmdb homebrew/science/opencv; do brew install $x; done
$ brew install --with-python protobuf
$ brew install hdf5

これで終わり。ありがとうhomebrew。

//--boost、boost-python--

Boostの一種で恐ろしく簡単にPythonコードを書けるようになる。
C++でもよく使われるが本当にありがたい。以下でインストール

$ brew install --build-from-source boost boost-python

 

//--諸パッケージ群インストールにおけるエラー--

boost,boost-python,protobufでエラーが出た。

  • boostインストール時のリンクエラー
Error: You must `brew link boost' before boost-python can be installed

boostはC++でも触ったのでそれかも。リンク貼れないらしい。brewをアップデート。

$ brew update
$ brew upgrade

リンクの上書き。

$ brew link boost
$ brew link --overwrite boost

エラーが止まらない。

Error: Could not symlink include/boost/accumulators
/usr/local/include/boost is not writable.

しょうがないのでboostのリンクファイルを消す。バックアップを取ってから

$ sudo rm -r /usr/local/include/boost
$ brew link --overwrite boost

Yeah.

Linking /usr/local/Cellar/boost/1.57.0... 119 symlinks created

 

Error: The `brew link` step did not complete successfully
The formula built, but is not symlinked into /usr/local
Could not symlink lib/libboost_python.a
Target /usr/local/lib/libboost_python.a
already exists. You may want to remove it:
rm '/usr/local/lib/libboost_python.a'

To force the link and overwrite all conflicting files:
brew link --overwrite boost-python

To list all files that would be deleted:
brew link --overwrite --dry-run boost-python

既にあるから消すかリンク変えてねと。特に使う予定もないのでバックアップを取って消してOverwriteでbrewリンクへ。

$ rm /usr/local/lib/libboost_python.a
$ brew link --overwrite boost-python

Yeah.

Linking symlinks created

 

  • protobufでも同じリンクエラー

同様にrmで削除してからoverwriteしてbrewリンクへ。

Error: Permission denied

が出たらアクセス権限がないので一時的に権限を変更。

$ sudo chown -R $USER /usr/local

Yeah.

Linking symlinks created

 

//--周辺パッケージとコンパイラ--

エラーが治っても問題はある。このままではmake all出来ない。
OS Xでは10.9以降でgccではなくclangをデフォルトコンパイラとして使用している。
clangではlibc++を標準ライブラリとして利用しているが、CUDAやOpenCVでCUDAを使う場合はlibstdc++が必要になる。gccにしても良いが、Macでのgccを他のライブラリのインストールで使って大変だったので、今回はclangで切り抜ける。

$ for x in snappy leveldb protobuf gflags glog szip boost boost-python lmdb homebrew/science/opencv; do brew edit $x; done

連続で周辺パッケージのformulaを開く。
デフォルトだとVimで開かれるので、普段Vim使ってない人はaで挿入編集モード、escで抜けて、Shift+Zを2回で保存して終了、ぐらいで大丈夫。
def installの部分に毎回以下を付け加える。

def install
# ADD THE FOLLOWING:
ENV.append "CXXFLAGS", "-stdlib=libstdc++"
ENV.append "CFLAGS", "-stdlib=libstdc++"
ENV.append "LDFLAGS", "-stdlib=libstdc++ -lstdc++"
# The following is necessary because libtool likes to strip LDFLAGS:
ENV["CXX"] = "/usr/bin/clang++ -stdlib=libstdc++"

連続で表示されるので全て書き換え終わったら

$ for x in snappy leveldb gflags glog szip lmdb homebrew/science/opencv; do brew uninstall $x; brew install --build-from-source --fresh -vd $x; done

でリビルドしておく。
protobufに関しては古いものをアンインストールして再度インストールしておく。

$ brew uninstall protobuf; 
$ brew install --build-from-source --with-python --fresh -vd protobuf

 

//--boost、boost-pythonのバージョン--

boostのバージョンが高い(1.56以上)と後に行うCaffeのテストを通せない。こんな感じでエラーが出ることになる。

$ make runtest
...
[ FAILED ] 3 tests, listed below
caffe::FloatCPU
caffe::DoubleCPU

初期化が上手く出来ていないものだと考えられる。boostのバージョンを下げる。

$ brew edit boost
$ brew edit boost-python

で開いて両者のboostのformulaの部分を以下のように変更

class BoostPython < Formula
homepage "http://www.boost.org"
url 'https://downloads.sourceforge.net/project/boost/boost/1.55.0/boost_1_55_0.tar.bz2'
sha1 'cef9a0cc7084b1d639e06cd3bc34e4251524c840'
head "https://github.com/boostorg/boost.git" 
revision 2

変更したら再度インストールしなおしておく。

$ brew uninstall boost
$ brew uninstall boost-python

アンインストールしてから

$ brew install --build-from-source --fresh -vd boost boost-python

 

//--Git clone--

ライブラリ本体をダウンロードしておく。
https://github.com/BVLC/caffeGitHub - BVLC/caffe: Caffe: a fast open framework for deep learning.
ここから。Git cloneしても良いしzipでクレしても良いのでもらう。

//--Python等rapper周りの導入--

展開したCaffeのルートディレクトリに移動して周辺のパッケージをインストールする。

$ sudo pip install -r /path/to/python/requirements.txt

Caffeのバージョン毎にrequirements.txtの場所が違うので注意する。
コンパイラに「無いよ!」と言われたら検索して適宜変更する。
あとnumpy、scipyをインストールしておかないとダメ。

//--Caffeのコンパイル--

いよいよCaffeコンパイル。公式ではMakefileのconfigを作れとあるが、サンプルが用意されているのでコピーする。
Caffeのルートディレクトリ内で

$ cp Makefile.config.example Makefile.config

Makefile.configのサンプルを見ると、「色々バージョンやOSに合わせて修正してね」という部分があるので修正する。エディタでMakefile.configを開いて

GPUは使わない(使いたい場合コンパイラを変更しないといけないので)のでコメントアウトを外す
# CPU-only switch (uncomment to build without GPU support).
CPU_ONLY := 1
OSXではClang++!!と言われているので書き換え
# To customize your choice of compiler, uncomment and set the following.
# N.B. the default for Linux is g++ and the default for OSX is clang++
CUSTOM_CXX := clang++

BLAS等の設定もあるが、ATLASの場合はデフォルトなので特に修正しなくて良い。
コンパイルはmakeファイル。Caffeのルートディレクトリ内で

$ make clean
$ make all

エラーがでなければOK

//--テスト--

Caffeディレクトリ内で

$ make test
$ make runtest

エラーが出ばければOK

[----------] Global test environment tear-down
[==========] 457 tests from 98 test cases ran. (17037 ms total)
[ PASSED ] 457 tests.

Yeah.

//--感想--

めっちゃつらい

//--これから--

これだけじゃ楽しくCNNするには程遠いのでLinuxでの導入やSublimeTextからCaffe動かして遊べるような記事をいずれ気が向いたら書く。

「パッケージ管理にAnacondaを使うと楽やで」と言う人も居るが、複数回の更新やパス関連を考えるとbrewさまさまといった感じ。pipでも良いとは思う。

サンプルも使い方もGithubに沢山上がっているので暇はしない。

//--参考--

メインで参考にしたのは公式と公式コミュニティのGit Q&Aとこちらのブログ。

DeepLearningライブラリ「Caffe」の実行環境をOSX10.9で作る - モノクロタイム
最高にCOOLだったので筆者をTwitterでフォローするなどした。

Random Forest for kazoo04 recognition

 

- 挨拶 - 

 みなさんこんにちは。Kazoo04 Advent Calender 7日目を担当します、@vaaaaanquish ことばんくしです。よろしくお願いします。突然ですがみなさん、

 

"みなさん、かずー氏好きですか?"

 

…そうですね。まあまあですね。今回はそんなKazoo04に捧げる記事を書いていきたいと思います。技術的、専門的な難しい内容は全然出てこないので気軽にどうぞ。

 

 - 背景 -

  「Kazoo04に会ってみたい」ここ数年、このようなワードがインターネットを闊歩するようになりました。人類の歴史、インターネットの歴史から見ても、ここまでKazoo04が切望された時代はおそらく初めてなのではないでしょうか。これは、Kazoo04によって生み出された言葉やクラスタが世界に多大な影響を与えた証拠であると言えるでしょう。しかしながら、Kazoo04は一個人であり、人の身。神ではありません。Kazoo04は複数存在せず、その身は多忙を極めています。地球上に存在する70億人からKazoo04を見つける事、それは宇宙に広がる星々から彗星を見つけるに等しいと言えるでしょう。

 

 "もし、街中でKazoo04とすれ違ってしまっていたら?"

 

そうです。みなさんもKazoo04と会うチャンス、Kazoo04チャンス*1を常に与えられているのです。しかし、みなさんがそのKazoo04チャンスを逃さないようにするには街に繰り出し、常にKazoo04を意識し、認識する必要があるのです。

 

 

- 近年の物体認識技術について -

  私は"機械学習"を研究テーマとし活動しています。近年では、画像に写ったモノを認識するタスク、"一般物体認識"、"特定物体認識"の分野においても機械学習がホットなワードとなっています。例として、最近発表されたGoogleの一般物体認識技術のいくつかを見てみましょう。

 

Google MapsのStreet Viewの画像認識アルゴリズムがCAPTCHAのほとんどを解読 - TechCrunch

こちらでは、ストリートビューに写っている街区番号画像から数値を解読したり、有名なCAPTCHAの認識を行っています。今話題のニューラルネット"Deep Learning"の一種を使い、その精度は90%を超えています。

 

Research Blog: A picture is worth a thousand (coherent) words: building a natural description of images

こちらは、写真からの物体検出、シーン認識ですね。人がモーターバイクに乗った画像を入力にニューラルネット(Deep Learning)によって「A person riding a motorcycle on a dirt road」という文章を生成しています。

 

 このような研究成果は、身の回りにも溢れ始めています。

Research Blog: Improving Photo Search: A Step Across the Semantic Gap

 こちらでは、Google+Picasaに投稿した画像をニューラルネット(Deep Learning)を用いて画像認識、シーン認識によってラベル付けを行っています。Google+のアカウントがあれば、画像を投稿し"dog"や"car"で検索する事で結果を得られます。

 

このように、機械学習を用いて画像内に写っている物を分類(認識)する技術が多く研究されており、その精度は年々向上しています。Googleは多くの企業や大学教授を買収し結果を出し、Facebookは個人識別の"Deep Face"*2Microsoftも画像ラベル付けと"Project Adam"*3を発表しています。

 

 

- 機械学習 -

 機械学習の学習器は、以下の様に多くのデータを用いてパラメータを調整し、望みの解を出せるような学習を行います(教師あり学習の場合)。

 

f:id:vaaaaaanquish:20141207163844p:plain

 

 

- kazoo04識別問題 -

 GoogleFacebookみたいに学習した学習器を使ってこんな事が出来ればいいよね。

 

f:id:vaaaaaanquish:20141207164159p:plain

 

 

- kazoo04データ少ない問題 -

 機械学習では主に"大量のデータ"を用いて"学習"を行うと説明しました。データは正解情報を持つポジティブデータと、誤答であるネガティブデータを必要とします。ネガティブデータは背景っぽい画像や適当な人画像データセットから用意できました。必要なのはポジティブデータ。Kazoo04を認識する上で必要なデータ…そう、Kazoo04の写真です。まずはインターネットでKazoo04の画像を検索してみました。

 

f:id:vaaaaaanquish:20141207164244j:plain

キレそうです。

 

そこで私は裏ルートを使用しました。

なんと偶然にも私はKazoo04と大学が同じ!なんとなんと偶然にもKazoo04と研究室が同じ!ということで、研究室の画像サーバを漁って、Kazoo04の画像をスクレイピングする作業を決死の手動で行いました。

 ここだけの話、Kazoo04はシャイなのか研究室カメラの写真が少なかったです。とても困りました。「大学生にもなって"俺写真写るの嫌いなんだよ"とか言ってたのかなアイツwwキモww」と思いました。

 画像の少なさには、画像を歪ませたり回転、位置変更、大きさ変更によって学習データを増やし、誤差にも強い学習を行う方法(Over Sampling,Data Augmentation,Elastic Distortion,...etc)を利用しました。一般的には固定的なロゴ認識に強くなったり不均衡データを補強するものが多いですが、Kazoo04の画像の少なさが目立ったので採用しました。後輩がちょうど研究しているので、参考資料も多かった上、この辺りはOpenCVやImageライブラリを適当に使ってよしなに書けますからね。後は、株式会社ウサギィに行った際にKazoo04を盗撮する等してデータを増やしました。

 そんなこんなで私のKazoo04フォルダには、合宿先で浴衣なKazoo04やフットサルで汗を流すKazoo04、歪んだKazoo04、逆さのKazoo04がもうKazooKazooしました。まさにKa動物園04ってね。

 

f:id:vaaaaaanquish:20141207164340j:plain

 

 

- RandomForest -

学習器には"RandomForest"を用います。何故数ある学習器の中からRandomForestを選ぶかと言うと、


Random Forest とその派生アルゴリズム - Sideswipe

Kazoo04が紹介しているからです!

 あのKazoo04が紹介している学習器が精度出ない訳ありません。Kazoo04が良いと言えば良い。Kazoo04がYesと言えばYesなのです。

  RadomForestは「決定木を沢山作って多数決を取る」機械学習アルゴリズムの一種です。Kazoo04も紹介しているように、学習が高速で精度がよく、ノイズに対しても強い等の特徴を持った学習器です。ありがたい事に、OpenCVPython機械学習ライブラリとして有名なscikit-learn*4に実装されており、使いやすさの点でも強力な機械学習器の一つです。今回はscikit-learnのRandomForestクラスを使いました。

 

 - 特徴量設計 -

 機械学習の生成モデル(学習器)にデータを入れる際に、生のデータ(画像であればRGB値)をそのまま入力すると、計算量が膨大かつ学習が難しくなってしまうという問題が知られています。そこで画像の特徴をベクトル量として抽出してから入力にするのが一般的です。今回は、

・メインとなるのは"Kazoo04"か"そうじゃないか"の二値分類であること

・人間でありかつKazoo04の顔である事を判断すること

・実装が面倒なのでライブラリとかで適当に出来ること

を考えてSURF特徴量*5HOG特徴量*6を利用しました。特徴点抽出と勾配の特徴抽出でなんとかしてみましょう。SURFはOpenCVHOG特徴量はPythonのImageライブラリに入っているのでそれを利用します。

 

 

- 学習まとめ -

 特徴抽出をおこなったあとscikit-learnが対応している入力形式にします。大きさを調整したりリスト形式にしたりよしなにしてやります。後はscikit-learnのRandomForestモデルを設定、入力して学習させます。今回のパラメータは大体こんな感じ。

f:id:vaaaaaanquish:20141207164926p:plain

今回の学習構造を書くとこう。 本来は主成分分析を用いたりもしますが、少し面倒なのでこう。

 

f:id:vaaaaaanquish:20141207165001p:plain

 

 

- 画像認識と矩形検出 -

 学習し終わった学習器によって実際の画像からKazoo04を認識させます。では、Google検索で出てきたKazoo04が写っている写真を利用してやってみます。

方法としてはこう。

f:id:vaaaaaanquish:20141207165029p:plain

1.RandomForest入力サイズの窓を作り特徴量を取って検出

2.人が写っていると判断したら赤枠で囲む

3.窓を少しずつ移動させる

4.Kazoo04っぽさを判別するため赤枠の中をさらにRandomForestで走査

を繰り返しします。この方法は、物体の大きさ変化に弱くなることが考えられますが、今回はスケール変化のみで対応しました。

 

 

- 結果 - 

 以上の方法でなんとなくそれとなく適当にPythonで書いてみました。その結果がこちらです。今回は、株式会社ウサギィ様がHTML Japan Cap2014で表彰された際の写真をお借りしました。

 

これが

f:id:vaaaaaanquish:20141207165449j:plain

こう

f:id:vaaaaaanquish:20141207165134j:plain

 

走査するスケールを大きくはしましたが、赤枠が沢山出てしまっています。k-meansを使って沢山集まっている部分をまとめます。平均をとるイメージでこう

f:id:vaaaaaanquish:20141207165553j:plain

 

良い感じですね。ではもう一枚。

f:id:vaaaaaanquish:20141207165840j:plain

そしてこう

f:id:vaaaaaanquish:20141207165902j:plain

 

細かい走査の際に顔部分も自動で切り取ってみます。顔画像をメインでスクレイピングしたので顔の部分はお手の物です。

f:id:vaaaaaanquish:20141207165938p:plain

ああ…Kazoo04…///

 

 そんなこんなでKazoo04を自動で認識し、切り取る事が出来ました。いくつか研究室の画像をテスト画像にして試しましたが、大体Kazoo04でした。細身でメガネでクールなヘアスタイルの同期が居なかった事に感謝ですね。1日講義受けながら適当に書いたら、案外すんなり出来たので良かったなといった感じです。画像のスクレイピングとラベル付けには二日掛けました。後、自分の写真も入れまくって、角度次第でKazoo04と認識される場所が10%くらいある事もわかりました。愛ゆえにKazoo04に近付いている証拠かも知れませんね。

 

 

- 反省 -

 せっかくなのでとことん、しっかり解説しようとか思いましたが、研究が忙しかったので断念しました。Webサービスにしようと思った手前手持ちに公開できるサーバがなかったり、図編集のソフトが死んで手書きにしたり、結果相当に精度が良かった画像だけブログに載せたり、グダグダなAdvent Calenderの足を引っ張る方になってしまいました。Kazoo04の画像が少なかったのと、特徴量設計が甘かったのは痛かったのか、メガネで細身な人が5~10%程でKazoo04になってしまったのも悔しいです。この手のプロジェクトによくありがちな「学習用のデータを作っている時に飽きる」現象も体験し、これやってる暇があったら研究するよなと強く思いました。こんなことばかりやってるからいつもKazoo04に怒られるんですね。精進します。

 

 

- おわりに -

 なんかまあちゃんとデータとか特徴とか分かってればライブラリ使って気軽に教師あり学習が行える世の中になってしまいました(ありがたい)。今回TeX数式を入れるのが面倒それなりに分かりやすいように書いたつもりですが、機械学習だけでなく情報工学は物理やら数学やらの塊みたいな感じです。自分の研究室でこんなゼミ発表したら数式で頭の先からひざまで殴られるレベルです。機械学習に関しては、このような記事が出る程に、様々な知識を要し複雑化しているとも感じます。


機械学習をこれから始める人に押さえておいてほしいこと - Qiita

それでも、この分野に興味を持ってもらえればと思いもあって、少しだけ考えて書きました。最新の研究では、ここに書いたものを応用した沢山の面白い技術が出てきています。他にも機械学習界隈の成長は著しく、ニュースサイト等でも多く見られるようになっています。一緒に超絶楽しい最適化をやってくれる人、機械学習使って面白い事をやってくれる人が増える事をそれなりに想ってます。

 

 

 

 

P.S.

くろていは"Kazoo04"として殆ど認識されませんでした。おわり。

*1:かずー氏に会える機会の総称

*2:参考 http://research.preferred.jp/2014/03/face-verification-deepface-and-pyramid-cnn/

*3:参考 http://www.itmedia.co.jp/news/articles/1407/15/news039.html

*4:機械学習Pythonライブラリ、SVMからDeep Learning、Random Forestまで充実している 

*5:画像から特徴点を探し出しベクトル量にする手法

*6:エッジのヒストグラムを用いてベクトル量にする手法

stochastic average gradientな話

//---はじめに---

 こんにちは。Machine Learning Advent Calendar 2013の11日目を担当することになりました@vaaaaanquishです。今回は大学で研究している進捗としてstochastic average gradient(SAG)についてまとめていきたいと思います。「前年度も誰かがやってたような・・・」と思った方はきっと記憶違いです。よろしくお願いします。

 

//---SAG---

 SAGはNIPS2012で発表*1されたオンラインアルゴリズム最適化手法の一つです。その名の通り更新時に確率的勾配の「Average」を取るアルゴリズムです。このような平均化されたアルゴリズムは、averaged stochastic gradient descent*2やSample Average Approximation*3のように昔から数多くの研究が行われていました(図書館で論文を読みあさっている時に偶然知りました)。今回紹介するSAGでは、ある条件の下で計算のコストが定数オーダー線形収束する事の証明が成されています。要するにとても早いです。とてもすごい。

 

//---SGとFG---

 NIPS2012の論文では、IntroductionとしてStochastic Gradient(SG)Full Gradient(FG)の比較を行っています。なぜなら、SAGが実質これら2つの良いとこ取りのようなアルゴリズムであるからです。

 FGは損失関数の和等を最小にしたい時、有限のサンプルの平均から最適化します。所謂「バッチアルゴリズム」です。FGはそのアルゴリズム上、凸な問題と一定のステップサイズを考えた時、k回の更新によって{\mathcal{O}(\rho^{k})}で線形収束します({\rho}<1)。しかしながら、全てのサンプルを見る為に、毎回計算にかかるコストが一定で大きいというデメリットがあります。

 それに対してSGは、サンプルの中から一様に(確率的に)データを選び更新を行う「オンラインアルゴリズム」です。こちらは全てのデータを見る訳ではないので計算コストが小さくなります。収束もFGのようにはいかずとも{\mathcal{O}(1/k)}が期待できます。

 SAGは、より強い仮定のもとで、これらFGの収束とSGの計算コストを最適に取り込み、より高速な最適解への収束を可能にしたアルゴリズムです。

 

//---The SAG method---

 SAGの反復は以下のようにして行われます。

 {x^{k+1}=x^{k}-\frac{\alpha}{n}\displaystyle\sum_{i=1}^{n}y^{k}_{i}}

 {y_{i}^{k}=f^{'}_{i}(x^{k}) \;\;\;\;\;\;\;\;\;\; (i=i_{k}) \\                y_{i}^{k-1}                             (oterwise)}

 上式の{f_{i}}は有限のデータ、{i_{k}}はランダムな訓練例です。一見上の式だけ見るとFGのように見えますが、実際はオンラインアルゴリズムのようにランダムな訓練例によって更新されます。しかし、更新の際に使うGradientは、その時点までに見てきたデータを復元し、その平均を用います。

 つまり、ランダムに選ばれた訓練例を記憶しておいて、それらの平均を取って更新に利用すれば、回数を重ねる毎に見るサンプルデータが増え、徐々にFGで得られるようなFullGradientに近似されるといった考え方になります。

 実装の際には、「現在の(平均化された)Gradient」に加えて「今まで見たデータを復元出来る情報」を保持しておく必要があります。これは、同じ次元のベクトルとして保存しておけば良いので、やたらメモリを食う等という事もありません。さらに、最初の数回SGを回すと高い収束率を維持することが出来ます[要出典]。

 

//---強い仮定---

 SAGは、どんな最適化問題に対しても良い性能を発揮する事が保証されている訳でもありません。主な条件としては「問題がStrongly Convex(強凸)」「二回微分可能である(≒リプシッツ連続)」があります。前者は機会学習等では満たされない条件ですが、正則化項の追加によってほとんどの問題で解決する事が可能でしょう。後者は簡単な話急傾斜になるような問題で無い事が求められます。

 

//---Results---

 以下は論文内での実験の結果です。

f:id:vaaaaaanquish:20131207233940j:plain

 見て分かるように、SAGの良い収束速度を示しています(自分が実装した訳ではないので一概には言えませんが)。Objective mlnus OptimumもTest Logistic Lossもどちらも成果を出しているという事で素晴らしいですね。問題によっては、SGの倍以上の性能を出せるというならば、色々な所で実装される日も近いのではないでしょうか。

 

//---SAGとこれから---

 そもそも今平均化されたオンラインアルゴリズムが話題となる理由として、深層学習等の学習器の発展があると考えています。私もニューラルネットを学び、DeepLearningを知り、応用を考えてこのようなアルゴリズムを勉強し始めました。様々な最適化問題に簡単に実装出来るようになる事がこのアルゴリズムの発展にも繋がると考えています。さらには、他のFOBOSのようなオンラインアルゴリズムでも似たような平均化手法が使えたり、もしかしたらSAGが非効率になるような物も見つかるのかも・・・。楽しみですね。私自身実装して実験している最中ですが、気になったという方は一度試してみてはいかがでしょうか。

 (「勉強会で証明を解説します」という時は連絡してくれると嬉しいです///)

 

//---おわりに---

 以上で私のMachine Learning Advent Calendar 2013記事を終了します。ほぼ「卒論に向けてのメモ」状態で申し訳ない気持ちでいっPythonです。内容の薄い記事ですが、このような機会を提供してくれたnaoya_tさん、紹介して頂いたkazoo04さんに感謝しております。今後大学院で学会等にも発表者として参加出来るよう精進して行きたいと思います。先輩方の意見と記事を楽しみに残り少ない2013年を過ごしたいと思います。少し早いですが、良いお年を。

 

//---参考---