研究者の卵の卵

決して頭がいいとは言えない大学生が、日々おもったことや学んだことをつらつら書きます。人工知能や脳科学の話が多くなりそうです。

神経科学と確率 ~単一ニューロンからFEPまで~ 前編

はじめに

この記事は神経科学アドベントカレンダーの12月15日分の記事です.

もともと参加するかどうかすら結構迷ってたのですが,
わからないからやらない,というスピリットはあまりにもダサすぎるということで,
限られた知識の中から書けることを書いていきたいと思います.

確率論と神経科学は結構繋がりが深く,
単一ニューロンの発火ダイナミクスを解析するのにも使われますし,
最近注目を集めているFEP=自由エネルギー原理; Free-Energy Principle という脳の大統一原理を目指す理論でも
確率や情報理論のような道具がよく使われます. これは神経科学だからとかいう話ではなくて,単純に決定論的に動作しない対象を扱っていることが理由になっていると思います.

ほんとはひとつの記事でまとめるつもりだったのですが, かなり分量も多くまとめるスキルに乏しいので,前後編に分けて前編で単一ニューロンと確率の関わり, 後編でFEPについて書いていきたいと思います.

単一ニューロンの活動

まず,大きな神経ネットワークや生物システムそのものの話の前に,単一ニューロンの活動を確率で理解することを考えていきます. これは計算論的神経科学を勉強しようと思ったときに基礎的な話になってくるので, P.Dayanの著書 "Theoretical Neuroscience" やR.Rao先生によるCourseraコース "Computational Neuroscience" でも詳しく解説されています.

Neural Decoding

概説

まず,神経活動 (neuronal/neural activity)を観測した際に,それを引き起こした刺激 (stimulus/stimuli) が何であったかを予想することを考えていきます. 脳がエージェントが観測した情報をコンピュータのデジタル素子のように神経活動によって符号化していると考えたときに,
刺激を予想するのは神経活動からの情報の復号化であるという風に考え,これらは Neural Decoding と呼ばれています.

ただ,脳はコンピュータのように離散化された観測情報に対して決定的な応答を示すほど緻密に作られているわけではないようで,
殆どの場合「この活動なら絶対にこの刺激だ!」と言えるわけではないので,
そういう意味でneural decodingは確率的な手法を取るのが基礎的なやり方になっています.

当然そうでない場合もあり,そういう場合には刺激値が非線形なフィルタリング関数にかけられていると仮定し,
その結果として得られた神経応答 (neural/neuronal response) との関係からそのフィルタがどういうものなのかを調べよう,みたいなことも行われます. ただ,今回は確率の話と絡めた神経科学についての記事にしようと思っているので,そういう手法はまた別で記事にしたいと思います.

ということで,ここで知りたい値は神経活動 \mathbf{r}が与えられた際の刺激 sの条件付き確率分布なので,
 {\displaystyle P[s|r]}
であるということを念頭に置いて話を進めていきます.

この条件付き確率分布を見た時に脊髄 (spinal cord) はすぐに「ベイズの法則が使えるぞ!」と教えてくれますから,
とりあえずその直感に従ってみましょう.
 {\displaystyle P[s|r] = \frac{P[r|s]P[s]}{P[r]}} ここで,神経レスポンス \mathbf{r}が0でないことを仮定する必要がありますし,
逆に言うとこの方法で P[ s|r ]を知りたいのであれば r=0にならないような
 rの測り方を選ぶ必要があります. また,ベイズの法則を使ってdecodingを行おうとする時,どのような値についての知識が前提的に必要なのかを考える必要があります.
実際のところ,

  •  P(r)の分布
  •  P(s)の分布

の2者は必要不可欠になることが自明であると思います.
前者の方は比較的易しいはずです.
というのも,観測対象のニューロンはすでに手元にあるのだから,そのニューロンがどういう応答特性を持っているのかというのを,
何の前提条件もつけずに調べればいいのですから割と手に入ります.
どちらかというと問題になるのは後者の方でしょう.
後者は観測対象のニューロンが応答を示すと思われる文脈で可能なすべての刺激値の確率分布と言い換えると思います.
低次の,またはごく限定的な情報をコードしている細胞でない対象を扱う場合,これを予め得るというのは非常に難しくなるといえるでしょう.
ですから,実際に古典的な単一ニューロンに対するdecodingの研究では,
例えば一般物体のような複雑な図形の提示などは行われないことが多いようです.

Population Decoding of Wind Vector

確率論・ベイズ論的なneural decodingの例を示すために,ここでは有名なコオロギの尾毛器官を取り上げます.
コオロギの尾部には cerci と呼ばれる器官があり,それらから生えている細毛が風に当たって動くと細毛に接触しているニューロンが発火します.

これらの感覚神経はコオロギの体内にあるいくつかの介在ニューロンに軸索を伸ばしており,そこで細毛ニューロンが受け取った情報をもとに風がどの方向から吹いており,どこから危険が迫っているかについての情報を処理しています.

1991年にTheunissenとMillerがコオロギの尾毛に低い風速であらゆる角度から風を当てる実験1を行った結果,
たった4つの介在ニューロンで360度すべての角度情報を表現していることが明らかになりました.

f:id:arthurs_kurt:20191210094208p:plain
TheunissenとMillerによる風向のチューニングカーブ

上の図は横軸に当てた風の角度,縦軸にこれら介在ニューロンの発火率を取ってプロットしたもの(チューニングカーブ=tuning curves)です.
このグラフ上の発火率は各ニューロンの最大発火率によって正規化されていることに注意してください.

まず,確率やベイズを使わないdecodingの方法としては,単純にそれぞれのニューロンがある角度を担当しているという風に考えるのが直感的だと思います.
 a番目のニューロンのチューニングカーブを f_a(s)とすると,このチューニングカーブと実際の角度 sの関係は
 {\displaystyle f_a(s) = [\cos(s-s_a)]_+ = \max(0, \cos(s-s_a))}
と書くことができます.
 f_a(s)\simeq 1となる点においては右辺も 1となるので,これを使って a番目のニューロンが発火率のピークを示す角度 s_aを求めることができます.
上の図と照らし合わせると, s_aは1番目のニューロンからそれぞれ,だいたい45度,135度,225度,315度 となっていることがわかります.
つまり,1番目と3番目のニューロン,2番目と4番目のニューロンがそれぞれ対になって風向ベクトルの直交基底を成しているという見方もできるので,
 {\displaystyle f_a(s) = [\mathbf{v} \cdot \mathbf{c}_a ]_+ }
と書き直すこともできます.
 \mathbf{c}_a a番目のニューロンが発火ピークを見せる風向ベクトル, \mathbf{v}は実際の風向ベクトルです.
ですから,これら4つのニューロンの発火活動からdecodeできる風向ベクトルは
 {\displaystyle \mathbf{v} = \sum_{a=1}^4 f_a(s) \mathbf{c}_a }
という,各ニューロンによる風向ベクトル基底の線形結合によって表すことができます.

上記のような方法は "Vector Method" などと呼ばれ,非常に直感的に単一ニューロンレベルの活動から刺激を簡単に再構成できることが魅力的ですが,利用できるコンテキストが非常に限られたものになっているという短所もあります.
次に述べる確率論的なアプローチは,適用可能なコンテキストがより一般的なものになっています.

Optimal Decoding Methods

さぁ,こちらが本題になります.
遅いわな.

ここではベイズ推定=Bayesian InferenceとMAP推定=Maximum a Posteriori Inference; 事後確率最大推定,およびML推定=Maximum Likelihood Inference; 最尤推定で,上記と同じ刺激を同じ神経活動から再構成することを考えていきます.

以下では,真の刺激値を sニューロンの発火率を \mathbf{r} = (r_1, r_2, r_3, r_4)とします.
ここからは直接的に刺激値からニューロンの発火率へ写像を行うようなフィルタリング関数の存在は仮定しないので, r_iが最大の発火率で正規化されているという場合を必ずしも仮定する必要はありませんが,上記と同じ問題を考えているということを強調する目的で, r_iは上記の f_i(s)に対応していると考えます.

まずベイズ推定では何をするかというと,推定によって得られた刺激値の予測 s_{bayes}と真の刺激値 sの間の損失関数 L(s, s_{bayes})を考えます.
この損失関数を最小化するような \tilde{s}_{bayes}を与えられたどんな \mathbf{r}に対しても出力するような p[ s|\mathbf{r} ]の分布を得ることができれば,それはすなわち可能な限り正確なneural decodingに成功したと言うことができるよね,というのがベイズ推定の主張です.
では, s_{bayes}はどういう値であるべきかということですが, Lを二乗誤差とした場合は p[s|\mathbf{r}] の期待値とするのが良さそうです:
 {\displaystyle s_{bayes} = \mathbb{E}[p[s|\mathbf{r}]]}

次にMAP推定です.
そもそもベイズとかをやり始めた頃は,事前確率・事後確率・尤度といった言葉のニュアンスがきちんと掴めていませんでした.
基本的にすべての人間は僕よりも学習能力が高いようですが,万が一そういう人がいた場合のためにここで少し用語の整理をしておきます.
事前確率とは,「何もヒントが与えられていない状態での確率」と言い換えることができ,neural decodingの文脈では p[ s ] に相当します.
事後確率は,「ヒントが与えられたあとの確率」なので,ここでは p[s|\mathbf{r}]ということになります.

Neural decodingにおけるMAP推定の目的は,この事後確率を最大化するような s \mathbf{r}からのdecodingの結果とすることです.

ML推定はこれをもう一捻りしていて,尤度を最大化するような sを推定として選びます.
尤度というのは読んで字の如し,尤もらしさを表す指標です.
 P[\mathbf{r}|s] = \frac{P[s|\mathbf{r}]P[\mathbf{r}]}{P[s]}を, sの関数として見た時にこれを最大化する sを選びます.
つまり,  \mathbf{r}を与えられたとき,それを引き起こした刺激としてもっとも尤もらしい sを選ぶというわけです.


  1. “Representation of sensory information in the cricket cercal sensory system. II. Information theoretic calculation of system accuracy and optimal tuning-curve widths of four primary interneurons”. Theunissen and Miller. Journal of Neurophysiology (1991).

発火率の測り方

はじめに

最近,ずっとTheoretical Neuroscienceを読んで計算論的神経科学の勉強を深めています.
インプットばかりでは自分の力にはならないと思うので当然アウトプットが必要なんですが, その方法にも

  • 実際にプログラムを書いて実装してみる
  • 勉強したことをどこかで書き綴る

の2択ぐらいがあるんではないかと.
前者はCRCNSという,実際に研究で使われたデータセットアーカイブしているウェブサイトがあるのでそこからデータを落としてきていろいろ試すことができます.
後者はせっかくブログを書いているのでここをノートにしようかと思っています.

この分野に精通している方からしたら当然みたいなことを書いているかもしれませんが, まぁ備忘録ということで書かせていただければなぁと思っています.

ただし,参照している書籍が英語で書かれており, かつ私は日本語でこのブログの記事を書いているので, 日本語で何て言うのかわからないような単語は英語のまま書いたりするつもりです.

発火率の種類

まず前提として以下では,時間 Tにわたってニューロンの発火を観測することを考えます.
さらにその試行は, N回繰り返されるものとしましょう.

Firing rate

「発火率」を直訳すると"firing rate"になってしまうので,
発火率の一種としてこれを記すのは違和感たっぷりですが,書籍の中では"firing rate"と呼ばれている数値です.

時刻 tの関数として \mathsf{r}(t)と書くのですが,  \mathsf{r}(t)は言い換えると,時刻 tにおける発火の確率密度 p [t] です.
如何せん時間というのは連続なものですから,厳密な tに対して発火率を求めることは当然不可能です( \mathsf{r}(t) \simeq 0).
なので通常は, t \sim t + \Delta tの間での発火率を求めます.
試行1回に対してこの値を求めようとすると,「発火したか発火してないか」の2値になってしまうので, 複数回の試行の平均として求めます.

実験対象のニューロンの,時刻に依存する発火率の変遷などを見ることができます.

Spike-count rate

直訳すると「数え上げ発火率」とかでしょうか?
これは1回の試行についての値です.

時間 Tの試行全体での発火率を求めたいので,引数に時刻を取らない定数 rとして求められます.
ある試行中で n回発火があったとすると, r

 { \displaystyle
r = \frac{n}{T}
}

ということになります.

実験対象のニューロンが与えた刺激に対してどのくらい反応したかを,試行ごとに見ることができます.

Trial average rate

これは,「firing rateの時刻についての平均」とも言えますし,「spike-count rateの試行平均」とも言える値です.
前述のふたつの数値,firing rateとspike-count rateを, 前者は試行時間全体で, 後者は試行回数でそれぞれ割ると,どちらもTrial average rateという数値になります.

「このニューロンにこの刺激を与えたらたいていこのくらい反応する」というざっくりした様子を見ることができます.

発火率の測り方

一応,ここからが本題です.
なぜ「発火率の測り方」なんていうものを考える必要があるかというと, 発火率を時間の関数として記述すると,論ずることができる内容もかなり広がるからです. spike-count rateやtrial average rateは時間に依存しないので簡単に求めることができるのに対し, firing rateについては tを厳密に定めて \mathsf{r}(t)を求めることができません.
なので,時間の関数としての発火率を測るためにはいろいろ方法を工夫する必要があるよなぁ,というお話です.

発火率を図るためには,当然,発火のデータが必要です.
試しにプロットしてみたので,こちらを使ってみましょう.

f:id:arthurs_kurt:20190202135245p:plain
スパイクデータ

横軸が時間(秒)に対応していて, 3秒間の観測を想定しています.
縦軸は気にしないでください. このデータは,別に実際のニューロンを選んで観測したものではなく, 平均の発火率を70Hzとして確率論的にプロットしたものです.
これについても,もしかしたらそのうち記事を書くかもしれません.

時間をビンにわける方法

最も単純な方法は,試行時間(この場合は3秒)を, いくつかのビン(=Time bins)に分ける方法です.

ここでは,0.1秒のビン×30に分けるとします.
1つのビンの中でスパイクの回数をカウントし, その値をビンのサイズで割ることで,発火率を時間関数として記述します.

f:id:arthurs_kurt:20190202143522p:plain
Time binsによる計測
横軸は先ほどと同じで,時間(秒). 縦軸は,発火率(Hz)です.
スパイクのグラフと見比べてみると,うまく発火率が測れていることがわかると思います.

ただし,これはビン内では一定の発火率となっており, 得られる結果はビンのサイズに大きく左右されます.
不連続な関数として記述されるので,真に「時間によって変化する発火率」として表すことのできる指標ではないのかもしれません.

ちなみに,このビンサイズを試行時間と同じにすると, 上述のSpike-count Rateになります.

当然ながらSpike-count Rateと比べれば時間解像度はずいぶん高いのですが, 後述の方法ならばもっともっと時間解像度の高い \mathsf{r}(t)を求めることができます.

Rectangular window

試行時間をビンにわける方法は, ビンのサイズに依存すると同時に, ビンの位置にも依存しています.

こうしたビンの位置による任意性を排除するための方法としては, 一定の大きさ(たとえば前述のビンと同じ0.1秒)のウインドウを用意して, それを時間軸上でスライドさせていく方法があります.
 tを中心に置いたウインドウ内で観測されているスパイクの数を, ウインドウのサイズで割ったものを \mathsf{r}(t)とします. 下の図は,ウインドウサイズを \Delta t = 0.1とした場合のRectangular windowによる計測の結果です.

f:id:arthurs_kurt:20190202161009p:plain
Rectangular windowによる計測
計測結果を見ると,ビンの位置による任意性が除かれているのがわかると思います.
今回は,利用しているスパイクデータが, サンプリング周波数=1000Hzとしているので,かなりギザギザな見た目になっていますが, もう少し高いサンプリング周波数に対してこの方法で発火率を図れば,もう少し見た目も滑らかなグラフになります.

Gaussian window

上述のRectangular windowによる計測でも十分なのですが,もう少し踏み込んでみましょう.
当然のことですが, tにおける発火率を図るのに,  t t+\Delta tの発火を同等に扱うのは不自然な気もします.
ですので, tでの発火には大きめの重みをかけ,周辺に離れるに従って徐々にその重みを小さくしていくことを考えてみると, ガウス分布によるウインドウが尤もらしく見えます.
このようなウインドウをGaussian windowと呼びます.

Gaussian windowは,
 {\displaystyle
w(\tau) = \frac{1}{\sqrt{2\pi} \sigma_w} \exp( -\frac{\tau ^2}{2 \sigma ^2_w} )
}
という式で定義されます.

このウインドウ関数を用いて
 {\displaystyle {\mathsf r}(t) = \int^{\infty}_{-\infty} w(\tau) \rho (t-\tau) d\tau}
として発火率を求めます.
 \rho(z)は, zの瞬間にスパイクが発生していれば 1を,それ以外では 0を返します.
中身はディラックデルタ関数とかを使って定義されています.

この様なインテグラルをLinear filterと呼びます.
ちなみに,Rectangular windowも, r(\tau)に異なる関数を選択しているだけで, やっている処理はこれと同じで,線形フィルタリングです.

f:id:arthurs_kurt:20190202183345p:plain
Gaussian windowによる計測

Gaussian windowによって {\mathsf r}(t)を計測すると,このようになります.
使っているウインドウ関数が滑らかなのも相まって,グラフ自体もかなり滑らかになったのがわかると思います.

Alpha window

ガウスウインドウでは,遠くに離れるほど重みを減らそうというアイデアがありました.

さらにもう少し突き詰めたのが,Alpha windowです.
どういう風に突き詰めるかというと,離れるほど重みを減らすのは同じなのですが, ある時点での発火率には,その時点より前の発火しか加味しない というアイデアです.

ウインドウ関数には
 {\displaystyle w(\tau) = \mathsf{ReLU}(\alpha ^2 \tau \exp (- \alpha \tau))}
を用います.
ニューラルネットワークの活性化関数としてもおなじみ,ReLU(= Rectified Linear Unit)が出てきましたね.
ReLUは \mathsf{ReLU}(z) = \max (0, z)と書くこともできて,負の値はすべて0にしてくれる関数です.

実行した結果はこのようになります.

f:id:arthurs_kurt:20190203103157p:plain
Alpha windowによる計測

概形はGaussian windowによるものと似ていますね.
特徴としては,それより前の点でスパイクが観測されていない t = 0付近の点で \mathsf r (t) = 0になっていることです.
また,滑らかさはGaussianには劣るものの,そちらと比べると値の変動が激しく, より細かな特徴をとらえているように見えます.

さいごに

「発火率」そのものの種類と,発火率の時間関数の決め方を3種類まとめてみました.
実装も即席だったのでコードに誤りなどもあると思いますが,ご承知おきください.
コメントで指摘して下さればすぐに直します.

初めての国際会議@マレーシア科学大学

先日、12/11、12/12にマレーシアのUniversiti Sains Malaysiaで開催された国際会議 "International Conference on Creativity, Innovation and Invention in Digital Technology = CIIDT" に参加したので、そのときの記録を残したいと思います。

打診

夏休み、東大の某DL大好き研究室と幣高専の共同プロジェクトで開催された、高校生向けのディープラーニング入門講座にTAとして参加していた私は、最終日に研究室のボスに突然声をかけられました。

「国際会議に論文出さない?」

とのことだったのですが、実家が遠方で、サマースクールのために一時的に高専に戻っていただけだったので正直最初は若干悩みました。
ただ、このブログでも何度か触れている通り、実は私は研究者志望ですので、学部に編入する前に一応世界中の人が自分行った研究に触れられるように実績は積んでおこうということで承諾しました。
学会の名前だけ教えていただいて、現段階で出ている実験データを(もちろんボスから許可を得て)持ち出した私は実家に到着してからその学会の名前をググりました。

すると、まぁずいぶんと凝ったデザインのウェブページが出てくるではありませんか!
ちょっとテンションがあがったのでもう少し調べてみると、全然無名の会議だったので若干がっかりでした。
ただ、こちらも無名ではあるものの無事に査読に通って採択されると、学会での発表+学術誌への掲載も可能とのことだったので、実績にはなるだろうということで執筆を開始しました。

この段階でフルペーパー締め切りまで3週間

執筆

私は比較的英語が得意な方なので、できればいきなり英語で書きたかったのですが、ボスから「校正は日本語の原稿で行う」との指示があったので、しぶしぶ日本語で執筆を開始しました。

当然今まで書いた論文は一本だけなので、いろんな部分に修正指示が入りながらなんとか形にはなったので「よし、今からこれを全部英語に訳しましょう」の段階に入りました。
正直、訳す系のタスクはめちゃくちゃ苦手なので本当に二度手間だなぁと感じつつも、翻訳作業を行い、無事論文の提出を完了しました。

前日

実は、海外渡航自体初めてだったので、かなり緊張しながら準備を行っていました。

入国審査ゲートが最初の難関、なんて言われますが、マレーシアの入国審査はかなりザルで、指紋とってパスポートにスタンプ押してもらって終了でした。

前入りしたので初日は早朝から移動に費やし、ホテルにチェックイン後は適当に近くのスーパーで飯や飲み物を購入し、ホテルに持ち帰ってプレゼン資料の修正をしながらもぐもぐタイムを満喫しました。
テルチェックイン時にあまりにもホテルマンのなまった英語が聞き取れなかったので、夜中に葉巻を吸いに行くついでにホテルのフロントのお兄ちゃんたちと30分ぐらい雑談をして耳を慣らしました。
一人はマレー系、一人は中華系のお兄ちゃんたちだったのですが、ここで「マレーシア訛り」なるものは存在しないことに気が付きました。

しかも、公用語が英語の国なのである程度しっかりした英語を話すのかと思っていたら意外や意外、人によって文法の崩れ方がまちまちではありませんか。
ある程度マレーシア人の英語の癖はつかめたので、その日は午前1時ごろには就寝しました。

当日

引率していた教授(ボスは別の国際会議に参加してて来なかった)たちの昔の教え子のマレーシア人が、開催してる大学の准教授とのことで、朝からその先生に迎えに来ていただいて会場に乗り込みました。
USM、めちゃくちゃでかいですね。びっくりしました。
そしてメイン会場、ちっちゃいホールみたいなのを想定していたのですが、なんか国会議員とかが口喧嘩してる会議室みたいな感じの部屋でした。 割とでかめの机が部屋全体にU字に配置されていて各テーブルからはマイクが生えており、真正面には巨大なディスプレイ。
こんなに威厳のある部屋で無名カンファが開かれるなんて・・・と唖然としていました。

ただ、パラレルセッションで進んでいくので他にもサブホールが2つあり、その2つはかなり小さな部屋でした。
私が発表したのは小さいほうの部屋でした。

私と引率教授の片方、専攻科の先輩の3人が本学から発表を行ったのですが、私だけが一日目でした。

1年前に国内のJSAIの研究会に参加したときはド緊張で息あがりまくりだったのですが、今回は全然緊張しませんでした。
というか、マレーシアと日本では発表のテンションがだいぶ違っていて、みんなかなりラフに、オーディエンスのリアクションを見ながらフレキシブルに話してたので私もそれを真似ました。
時間制限はあったのですが、ある程度アドリブを入れてもぴったり終わらせる自信はあったので「ここは理解してくれてるな」「あれ?ここよくわかってないか?」とか、オーディエンスの顔色をうかがいながら無事にプレゼンを終わらせました。

QAセッションは少し自信なかったのですが、プレゼンで勢いづいたのか、思ったよりはちゃんと話せました。
質問の意図がわかりづらい場面とかもあったのですが、とりあえずこの辺かな?という話題で話し始めると、質問者の側も知りたいことを知るためにうまく話題を掘り下げようとしてくれるので、回答というよりは議論みたいになりはしましたけど無事にコミュニケーションも取れました。

やはりうまくいった一番の勝因は、前日にホテルマンと喋りまくったことだったと思います。
いかんせん訛りは本当に強いので、あれをやっていなければ質問を聞き取ることもできなかったと思います。

周りの演者たちの発表にも興味あったのですが、USMから参加してる演者たちの研究はほとんどサーベイばかりで少し退屈でした・・・。

最後に

本当に、ボスには感謝してます。

無名とはいえ、20歳で国際会議に参加して学術誌に論文を掲載できたという事実は、これから研究者を目指すキャリアの第一歩としては本当に好調な滑り出しだったと思います。

論文書いたりプレゼン作ったりする過程では、いろいろとストレスを感じたり他のことが手につかなくてイライラした場面もあったのですが、それを支えてくれた愛しきガールフレンドにも、精いっぱいの感謝を送りたいと思います。てか送りましたもうすでに。

あとは卒論書いて、大学入るまでに神経科学の知識を少しでも多くつけておくことを目標にしています。

自分にお疲れさまでした!

Pythonで機械翻訳 -'translate'パッケージ & Webスクレイピング-

はじめに

最近、卒業研究でPythonからフレーズ翻訳をするスクリプトを書かないといけない場面がありました。
いちばん安定していて間違いない方法はおそらくGoogle Translate APIを利用することだと思うのですが、 これには金がかかるという欠点があります。
無料でできる方法でちゃんと精度よく翻訳ができるスクリプトを書く方法をインターネッツで検索かけても、 実はそれほど出ていなかったり、情報が古くて実行できなかったりといろいろな問題がありました。 なので、改めてここで備忘録ついでに情報を残しておこうと思います。

translate パッケージ

あまり知られていないっぽいながらもラクな方法としては、 "translate"というパッケージをつかう、というのがあります。
pipでインストールできますし、condaとか使っててpipするのが嫌な人はソースを落としてきてsetup.pyを実行することでも利用できます。
私はconda利用者ですが、依存に問題がないことが確認できたらバンバンpipしちゃう人種の人間なので、pipでインストールしました。

$ pip install translate

以下のようにコードを書くと、簡単に翻訳ができます。

>>> from translate import Translator
>>>
>>> translator = Translator(from_lang = "ja", to_lang = "en")
>>> result = translator.translate("これはペンです。")
>>> result
'This is a pen.'

見た感じ、出力はGoogle翻訳と同じなので、どうやら何かしらの方法でGoogle翻訳を通して出力を行っているみたいですね。
ちなみに、他の翻訳プロバイダを試すこともできたりします。

>>> translator = Translator(provider = "microsoft", from_lang = "ja", to_lang = "de")

ただし残念ながら、上記のようにしてmicrosoft翻訳(?)をプロバイダに選択しても、 HTTPでクエリを投げるときにどうやらアクセスが拒否されるみたいです。
まぁGoogle翻訳の方が精度もいいので、基本的にはここには何も指定せずに実行するのがいいでしょう。

この方法で翻訳をするとき、かなりネックになってくるのが実行速度です。
みなさんも試してみるとわかると思いますが、「これはペンです」ぐらいの例文でも翻訳するのに1秒ほどかかります。
私に限らず、自然言語処理系の研究室で機械翻訳の必要が出てきてる時って基本的に大量のフレーズを一気に翻訳したい時だと思うので、 この方法はそういう人には全然おすすめできません。
時間かかってもいい人は別にいいと思うんですけどね。

Webスクレイピング

一見ごり押しですがかなり効果的な方法です。
BeautifulSoupとrequestsを利用してHTTPつかって直接Google翻訳のサイトにクエリを投げてしまいます。
あんまりWebスクレイピングとかやったことなかったのですが、Google翻訳のソースを見てみるとどうやら翻訳の結果は "result_box"というIDのボックス内に表示されているみたいです。
翻訳先言語の指定および投げたいフレーズはURLで指定できるので、直接取ってやろうぜ、というコンセプトです。
ちなみにBeautifulSoupとかrequestsとかはAnacondaでPythonをインストールすると最初からついてるみたいですね。
少なくとも私が試したときはそうでした。

>>> from bs4 import BeautifulSoup
>>> import requests
>>>
>>> target_url = "https://translate.google.com"
>>> params = {"hl":"en", "text":"これはペンです。"}
>>>
>>> r = requests.get(target_url, params = params)
>>> result = BeautifulSoup(r.text, "html.parser").find(id = "result_box").text
>>> result
'this is a pen.'

translateパッケージを使う場合と比べてこちらのほうが行数は増えますね。
もう少しきれいにまとめて実装できるのかもしれませんが、なんせコーダーとしてのスキルが結構低いので、 こういう書き方しかできないのはご了承ください。

個人的にちょっと気に入らないのが、http介して処理しているはずなのにこちらの方がtranslateパッケージを 使う場合よりもはるかに処理が速い点です。
translateパッケージの利点は行数が少なくなる点だから、そこは若干がんばってほしかった点ではありますね。

参考

imaharu.sakura.ne.jp

【論文メモ】"Dynamic Routing Between Capsules"

はじめに

ここ最近、いまさらながらG.Hinton博士の「Capsule」についての勉強をしています。
直接「カプセル」と日本語で指されることが多いこのアイデアは、 現在画像認識を中心としたさまざまなタスクで主流になっている、 Convolutional Neural Network (CNN)の弱点を改善するためにHinton博士が考案したものです。

まだ完全に理解したわけではないのですが、特に難しい理論でもないので、 理解出来たらChainerで試しに実装して公開してみるつもりです。
とりあえず現時点でちゃんと理解している部分だけをシェアしていきたいと思います。

CNNに対するHinton博士の文句

カプセルの存在意義を知るために、CNNの構造や特徴についておさらいしておく必要があるでしょう。
CNNは、1970年代に日本の研究者である福島邦彦先生が考案した「ネオコグニトロン」が源流になっているといわれています。
当時盛んに研究されていた「パーセプトロン」による単純なニューラルネットワークを用いたパターン検出は、 入力に存在するパターンの位置が微妙にずれたり、わずかに回転するだけで出力が変わってしまう非常にデリケートなものでした。
そこを解決するために考案されたネオコグニトロンは、特徴抽出を行うS層(CNNでは畳み込み層)と、その特徴量を一定の範囲でまとめるC層(CNNではプーリング層)を幾段も重ねることで、 パターンの位置変化に対する応答の不変性を獲得したモデルだったのです。

現在は少しずつその姿を変え、畳み込みニューラルネットワークとして機械学習の分野を席捲しているのです。

では、Hinton博士はそんなCNNのどこに対して苦言を呈しているのでしょうか?
それは、CNNではその処理によってオブジェクト間の空間的な関係の情報が失われることです。
これをもう少し詳しく説明してみましょう。

CNNの強みの一つは、さまざまな訓練データを繰り返し入力することで、 畳み込み層の各フィルタがそれぞれ、物体を認識するために重要な特徴量に反応するように自動的に学習していく点にあります。
例えば、手書き数字を認識するためによく訓練されたCNNのフィルタは、それぞれ「上のほうの曲線」とか「下の方の直線」といった形に反応するようになり、 その反応によって得られた特徴のマップが、さらに上位の層で処理されていくのです。
しかし、上位層に送られる前にこの特徴マップには「プーリング」の処理が入ります。
これによって、その特徴の位置が微妙に変化しても、同じような反応ができるようになっているのですが、 言い換えれば、「この特徴はこういうところになくてはならない」というマップの位置的な厳密性を下げる処理をしているのです。
これを多層にわたって繰り返していくのがCNNなので、結果、下の画像のような問題が起きてしまいます。

f:id:arthurs_kurt:20180929171445p:plain
顔であるかどうかを判定するためによく訓練されたCNNは、左のような画像でさえ顔であると認識してしまうおそれがある

「目に反応するフィルタ」も「口に反応するフィルタ」も共に上位層のプーリング処理によって位置的な厳密性が削られるので、 その位置関係はまったく考慮されずに情報が伝達してしまうわけです。

つまり、
オブジェクトがあるかないかや、どのあたりにあるべきかに対してはある程度厳密だが、オブジェクト間の位置関係についての重要な情報は無視されている
という点が、Hinton博士の呈したCNNに対する苦言です。

これは「学習に大量のデータが必要である」というCNNのよく知られた特徴を説明しているものでもあります。
オブジェクト間の位置関係が無視されているということは、まっすぐ向いている顔と傾いた顔をどちらも「顔」として認識するためには、 学習データにもまっすぐ向いた顔と傾いた顔が必要になるということです。
これは人間の持つ視覚機能とは大きく異なっていて、人間のパターン認識アルゴリズムを参考にしたニューラルネットワークらしからぬ欠点だといえるでしょう。

カプセルによる解決

カプセルは、こういった情報を失いやすいスカラー値の変わりに、ベクトルを保持する役割を持っています。
スカラー値は大きさしか持たないが、ベクトル値は大きさと向きを持つ。この当たり前の性質が、カプセルによるネットワークに大きな強みをもたらしてくれます。

従来のニューラルネットワークは、対象とする特徴が入力内に「どれぐらいあるっぽいか」をスカラー値で表現していました。
しかし、それでは上記のような問題がいくつか発生してしまいます。
カプセルは、その「どれぐらいあるっぽいか」をベクトルで表現するものです。
「あるっぽさ」をベクトルの長さによって表現し、それがどのような角度で存在しているのかをベクトルの向きによって示しているのです。

コンピュータ上で何かしらの画像を描画する際、アプローチの仕方にもよると思いますが、Instantiation Parameterというものが必要になるそうです。
ここでは、直訳して実体化パラメータとしておきましょうか。
例えば、「三角形の実体化パラメータ」は、x座標とy座標と、角度という3つのパラメータから構成されています。
この3つのパラメータが与えられれば、何をどこにどう描画するかを決めるには十分です。
さらに、「長方形の実体化パラメータ」が、三角形の実体化パラメータとの間にある一定の関係性を持っているとき、その2者をまとめて「家のパラメータ」とか「ヨットのパラメータ」とすることができるはずです。
カプセルによるニューラルネットワークは、 低レイヤーにおいてはこの三角形・長方形のパラメータを、高レイヤーにおいては家・ヨットのパラメータを それぞれカプセルという形で、 与えられた画像入力から求めるタスクを行うものであると言い換えることができるでしょう。

そしてこのカプセルネットワークを学習するということはすなわち、 各カプセルが必要なオブジェクトに反応するようになり、低層から高層へ、正しいカプセル間の結合が形成されることなのです。

カプセルの出力

では、ようやく具体的な理論に移っていこうと思います。

前項では、「オブジェクトがあるっぽさ」と書きましたが、具体的な言葉を使うと「確率」です。
つまり、0~1の間の値に収まる必要があるので、Hinton博士はSquashing関数という活性化関数を提案しています。
 { \displaystyle
\boldsymbol{v}_j = squash(\boldsymbol{s}_j) = \frac{\|\boldsymbol{s}_j\|^2}{1+\|\boldsymbol{s}_j\|^2} \frac{\boldsymbol{s}_j}{\|\boldsymbol{s}_j\|}
}
これを行うことで、短いベクトルは0に、長いベクトルは1に収束するように制限をかけます。 ここで \boldsymbol{s}_jは、 l+1番目の層内のカプセル jへの入力であり、 \boldsymbol{v}_jはそのカプセルの出力となるベクトルを表します。

では、この \boldsymbol{s}_jがどのように決定されるかというと、 l層目のカプセル iの出力 \boldsymbol{u}_iから求められます。
 l層目のカプセルの次元数から l+1層目のカプセルの次元数への変換には、重み行列 \boldsymbol{W}_{ij}が用いられます。
カプセル iの出力は単純に
 { \displaystyle
\hat{\boldsymbol{u}}_{j|i} = \boldsymbol{W}_{ij} \boldsymbol{u}_i
}
と求めることができます。
カプセルネットワークの学習においては、まず1つ、この重み行列を学習します。

さらに、この \hat{\boldsymbol{u}}_{j|i}から、  { \displaystyle
\boldsymbol{s}_j = \sum_i c_{ij} \hat{\boldsymbol{u}}_{j|i}
}
として、 \boldsymbol{s}_jを求めます。
このとき、 c_{ij}は、結合強度とよばれるパラメータで、ある低レイヤーカプセルの存在(たとえば鼻)が、高レイヤーのカプセル(たとえば顔)の存在に影響しているか否かを表現するものです。
この結合強度もカプセルネットワークの学習によって自動的に調整されるパラメータであり、その調整が「Dynamic Routing」です。

まとめると、 l番目の層のカプセル iから l+1番目の層のカプセル jへのベクトルの流れ方は、

  1.  { \displaystyle \hat{\boldsymbol{u}}_{j|i} = \boldsymbol{W}_{ij} \boldsymbol{u}_{i} }
  2.  { \displaystyle \boldsymbol{s}_j = \sum_i c_{ij} \hat{\boldsymbol{u}}_{j|i} }
  3.  { \displaystyle \boldsymbol{v}_j = squash(\boldsymbol{s}_j) }

となります。

カプセルネットワークの学習

カプセルネットワークの学習において調整されるパラメータは、ベクトルの次元変換時の重み行列と、 カプセル間の結合強度の2つであると説明しました。

重み行列 \boldsymbol{W}_{ij}は通常のニューラルネットワークにおける重みパラメータと同様のアルゴリズムで学習されます。
ここでは、Dynamic routingによる c_{ij}の学習を解説していこうと思います。

が、これも実は非常に簡単なアルゴリズムによるものです。
まず、結合強度 c_{ij}は、ソフトマックス関数によってあらわされます。
 { \displaystyle
c_{ij} = \frac{exp(b_{ij})}{\sum_k exp(b_{ik})}
}
ここで b_{ij}は、カプセル iとカプセル jが結びつくべきである確率を表しています。
つまり、カプセル iと次の層の各カプセルとの結合強度の和は1になるわけですね。
 c_{ij}の更新のためには、厳密には b_{ij}を更新することになるのですが、 ここでも新たに「合意(agreement)」という概念が表れます。
合意とは、「カプセル iとカプセル jを結合していいかどうか」を表す尺度です。

この値は、単純に \boldsymbol{v}_j \hat{\boldsymbol{u}}_{j|i}スカラー積によってあらわされます。
スカラー積、つまり内積は、2つのベクトルの長さの積に、さらにその2つのベクトルが成す角による余弦をかけて求められる値なので、 合意は \boldsymbol{v}_j \hat{\boldsymbol{u}}_{j|i}の類似度と解釈して間違いないと思います。

誤差逆伝播のようなアルゴリズムによって更新される \boldsymbol{W}_{ij}のような量とは違い、 この結合荷重はヘッブ則に基づく更新を行っているようですね。
 jの発火に iが貢献しているとき(=2者間の合意が大きい時)に更新しているということです。

ここで、前項のように学習の流れもまとめておきましょう。
ただし、学習開始前にあらかじめすべての i jの組み合わせについて b_{ij} \leftarrow 0としておきます。

  1.  { \displaystyle \boldsymbol{c}_i \leftarrow softmax(\boldsymbol{b}_i) }
  2.  { \displaystyle \boldsymbol{s}_j \leftarrow \sum_i c_{ij} \hat{\boldsymbol{u}}_{j|i} }
  3.  { \displaystyle \boldsymbol{v}_j \leftarrow squash(\boldsymbol{s}_j) }
  4.  { \displaystyle b_{ij} \leftarrow b_{ij} + \boldsymbol{v}_j \cdot \hat{\boldsymbol{u}}_{j|i} }

疑似言語方式で書きましたが、これを繰り返すことで正しく c_{ij}が更新されていきます。

さいごに

メモと言いつつかなり長くなってしまったことをお詫びしたいです。

まだ論文の前半を読んだにすぎませんが、この先は学習の方法等について記したものなので、 実装について書くときに一緒に説明してみようと思います。

脳のカラム構造と、情報処理の体系が似ている点と、 パラメータの更新がシナプス可塑性・ヘッブ法則に基づいている点で、非常に興味深いアルゴリズムだと思います。
回転している物体を認識するために、学習データに回転している画像を含ませる必要がない可能性があるという点においても、かなり希望を感じられるものですね。

初学者ですので、ご意見等、積極的にコメントいただけるとうれしいです!

高専について語ってみる

今まで書いた記事の中でトップレベルに、需要があるかどうかが微妙なテーマなのですが、他にネタがないので書いてみます。

高専とは?

まず、高専とはなんぞやというお話です。
Wikipediaによると

高等専門学校(こうとうせんもんがっこう)は、後期中等教育段階を包含する5年制(商船に関する学科は5年6か月)の高等教育機関と位置付けられている日本の学校 。一般には高専(こうせん)と略される。

だそうです。
Wikipediaの情報はあんまり正確ではないので、アンサイクロペディアの説明も載せておきましょうか。

高等専門学校(こうとうせんもんがっこう、英語:National Institute of Technology)とは、大卒並みに高い専門性を持ちながら大企業が安価に使える社畜を生産するために設置されている訓練所である。高校と同じく、中学校卒業後に入学する事ができる。略称は高専、NIT。

とのことです。

両者ともに書いていることなので書くまでもありませんが、「高専」は「高等専門学校」の略称です。
英語での名称は、数年前まで「〇〇 National College of Technology」でしたが、今は「National Institute of Technology, 〇〇 College」にパワーアップしています。
Collegeと呼ばれていたのが突然Instituteになっているわけですが、Instituteを冠する教育機関と言えば、アメリカの「Massachusetts Institute of Technology (マサチューセッツ工科大)」とか、スイスの「Swiss Federal Institute of Technology (スイス連邦工科大)」とか、国内の「Tokyo Institute of Technology (東工大)」とかがあります。
名前だけはこの辺の名門理工系大学と同列の扱いを受けているというわけですね。

ちなみに高専の修学年限は5年間です。
中学を卒業した人たちが入る学校で、大学2年生になる学年で卒業できます。
世間一般の生徒たちは、おそらく中学を卒業したら高校に入り、一般教養科目を中心に学びながら大学受験に向けた勉強をしていくものだと思いますが、その一方で、テクノロジーとかものづくりとかに興味を持った中学生たちは、高専に入って若いうちからかなり専門的な教育を受けます。

勉強内容

学科

高専にはいくつか学科が設けられていて、だいたい 機械・電気/電子・情報・建築/土木・化学 に関する学科が多いです。
中には、商船系の学科がある高専や、経済に関する学科もありますし、高専によっては情報系・電子系あたりが細分化されているような学校もあります。
あと、なんか学科を1つにするトレンドがあるみたいで、高知高専とかはもともと4学科ぐらいあったのを全部廃止して、「ソーシャルデザイン工学科」というのを設置したみたいです。
1、2年生の間はだいたいみんな共通する科目を勉強して、3年生で学びたい分野によってコース分けを受けるみたいですね。

一般教養

高校生が3年間で習う一般教養科目は、高専では2年でだいたい済ませてしまいます。
その代わり、文系科目はかなり少ないですし、理系でも進学校と比べると、内容は浅いです。
なんせ大学受験のための勉強をしないので、単元が進むスピードは速いですが、演習問題を解かされる量は大したことないわけです。

専門科目

高専教育の主役です。
これがなければ高専に入学する意味がありません。
1年生と2年生では、その分野の基礎的な専門知識をつけるための授業を受けます。
私が所属している高専情報工学科では、1年生では電気基礎、2年生では電気回路とC言語ぐらいしか、専門科目はありませんでした。
本格的に知識が深まり始めるのは3年生ごろで、うちはここでコンピュータアーキテクチャとか、2年生までに習ったC言語の知識を用いた応用プログラミングについて学びました。
情報系分野に興味があって高専に入ったため私はあんまりガチで勉強していませんでしたが、確か3年生では電子回路の授業も受けていた記憶があります。 4年生になると、さらに応用的な科目が増え、選択制のものが多くなります。
私はこの学年で「人工知能基礎」とか「システムプログラミング」を学びました。
システムプログラミングはちょっとおもしろいなーって感じの授業だったのですが、年間を通してLinuxマシン上でシェル(っぽいもの)の実装を目指す内容でした。
5年生では、一周回ってなぜかプログラムを書くような授業はなくなってしまいました。
高専は制度上、進学希望者も就職希望者も大抵が、5年の夏休みまでには進路が確定していることが多いので、後期は卒業単位が足りている人なんかはあまり授業は取らず、適当に遊んで卒論を書いて卒業、みたいな人が多いと思います。

工学実験

高専のパンフレットなんかでよく、ツナギを着たり眼鏡をかけたりして、測量をしたりよくわからない機械をさわったりパソコンをカタカタやっている人の写真を見ると思いますが、
あれはほぼ全部「工学実験」に取り組んでいる姿だと思っていただいて差支えないと思います。
どういうことをするかというと、主に授業で習った内容の実践みたいなものです。
私の所属先だと、情報工学科でも意外とプログラムを書くようなことはなく、電気回路を組んで特性測定をしたり、論理回路を作ったり、そういうことをやっていました。
大学でもそうだと思いますが、高専でも実験をしたら必ずレポートを提出する必要があります。
学校にもよると思いますがうちは手書きでした。
本格的にレポートを書かなければいけないのは3年生からなんですが、このときは年間を通して4テーマぐらいしか実習を行わず、各テーマに対して2回のレポート提出だったので合計で8本しか書いていません。
ただ、4年生に進級したとたんなぜか鬼になり、テーマ数が2週間に1つというペースになります。
なので、確か扱ったテーマ数は半期で7つとかだったように記憶しています。
で、実験が始まる前と終ったあとにそれぞれレポートの提出が義務付けられてますので、年間で提出するレポートは28本です。
さらに面倒なことに、各学期で2つ、内容がずば抜けて高度なテーマがあるのですが、それはなぜか1週間しか時間が割り当てられていません。
なので、この期間は本当に地獄でした。
再提出なんかも当然あったりするので、学期末が近づいてくると、要領が悪い学生は1週間で6つぐらい必死になってレポートを書いていたりもしていました。
真面目に文献を探しながらレポートを書く学生も一定数いますが、ある意味賢い学生は、先輩たちとコネクションを作っておいて、彼らのレポートをなんとか入手してそれを利用していることが多いようです。
全体的に地獄ですが、これで割と高専生はビシバシ鍛えられているらしく、大学や企業に入ってからはレポートの質の高さに太鼓判を押されることがよくあると聞いたことがあります。

卒業研究

高専の学びの集大成となるのが卒業研究です。
詳しいところはこちらも学校や学科によってまちまちですが、私が所属している高専情報工学科に限って言えば、
4年生の4月に各研究室の説明会みたいなのが開催されて、そのあとすぐに配属先の希望調査があります。
面談などは特になく、第n希望まで提出した各学生の成績ややる気なんかを総合的に見て、学科会議で教員たちが採用する学生を選びます。
先生によっては、あらかじめ3年生ぐらいのうちから研究室の見学に行っておいて、ちょっとしたコネクションというか、媚売りというか、そういう働きかけをしておくと、希望の研究室に入りやすくなったりします。

配属を受けてからは、4年生と5年生の計2年間、研究室に所属して卒業研究を進めていくことになります。
ここでは、2年間通して同じテーマを研究する人もいれば、4年生と5年生で別々のテーマに取り組む人もいます。
学生のモチベーションによっても研究のクオリティはまちまちで、スマホアプリの開発をやりました~(車輪の再発明)」みたいな人もいれば、問題に対する手法提案と、その評価実験にもとづいた本格的な「研究」をする人もいます。
大学と同様に、最終的には卒業論文を執筆して提出することを目標に取り組んでいきますが、本格的に取り組んでいる学生や進捗のいい学生は、外の学会に発表しに行ったり、コンテストの類に成果物を展示したり賞をもらったりするようなこともよくあります。
私は研究者志望ということもあり、開発というよりは研究寄りで取り組んでおり、4年次の終わりには人工知能学会さんが主催している小さな研究会で成果発表を経験しました。

高専のメリット

進路が決まりやすい

高専卒は実は、専門的な知識や技術は大卒並にある上に、年齢が若いこともあってかなり安い給料で手に入る労働力でもあるのです。
そのため、高専を卒業していれば就職難になることはまずなく、就職を希望している人は7割ぐらいが第一志望の企業に入りますし、就職浪人をする人間はほぼいません。
就職してからの企業からの評価もそれなりに高いことが多く、特に報告書(レポート)の書き方なんかは大卒よりも心得ていたりするので、そういった技術には定評があります。
実験や卒業研究も、基本的には一回ではできないようなレベルを要求される場合が多いので、ググり力というか、問題解決力みたいなのも高いんではないかと思います。

進学に関してもかなり楽で、私のように編入学という制度を使うと、高校からの進学ではかなり難易度が高い大学にもある程度楽に入ることができます。(当然、それなりに専門知識や実績は要求されることが多いですが)
これはおそらく学校にもよると思いますが、高専によったら、関関同立ぐらいの私立大学には名前を書くだけで入れたりすることもあるそうです。
こちらは就職ほど早くは決まりませんし、高望みすると第一志望で必ず入れるということはないのですが、
技科大、九州工業大、電通大東京農工大あたりは、推薦という制度があり、学力試験を受けることなく入れたりもします。
逆に、東大・京大を目指すと、ほぼ合格はできませんし、入れても1学年下げられるので、生涯修学年限がちょっと伸びちゃったりもします。
なぜか、私の高専からはことし、筑波大学を受験する人がめちゃくちゃ多かったのですが、最終的に一人しか受かりませんでした。

遠くに行かなくていい

これはあくまでプライベートのお話なのですが、高専には必ず学生寮が附属しています。
高専にもよりますが、多いところでは半数ぐらいが寮で暮らしているので、わざわざ遠くに行かなくても、友達の部屋でだべるとかいう行為は、寮の中で完結できてしまいます。
試験期間になると通学生にとってもこれはメリットになっていて、「ふだん通学に時間を使っていない→勉強がしっかりできている」というステータスを持つ寮の学生を、
研究室や図書館に召喚することで試験勉強を優位に進めることができます。

そもそも、寮がある時点でかなりのアドバンテージなので、早く独立したいけど勉強もしたいしお金も節約したい・・・という中学生は、高専を考えてみてはいかがでしょう。

高専のデメリット

多様性がない

名の知れた大学の学生や教員の方々と交流する機会があって、高専について雑談する機会があると、必ず言われるのが「高専には多様性がない」ということです。
高専生は大きく以下の2種類に分類できます。

  • 中学生の時点で工学に興味があった人
  • 工学にはもともと興味がないけど、就職率がいいので入ってきた人

高専の中でもレベルの高い、明石高専、奈良高専、木更津高専あたりになってくると、人口の影響もあって前者の割合が高くなってくるのですが、
閉鎖されたコミュニティで5年間過ごすと、世間に興味を示さなくなってしまいます。
基本的にずっと数式や自分の専門分野と向き合っていて、しかも趣味も大体みんな同じです。
アニメを見たり漫画を読んだり、車やバイクの話をしてはいるのですが、トレッキングが趣味です!ボルダリングが趣味です!ダンスが趣味です!みたいな人たちはいないので、そういう意味では多様性が全くありませんね。

大学では、構内で適当にすれ違った学生を捕まえて、自分の専門分野についての話題をおもむろに振るとドン引きされると思いますが、
高専ではそれをやると同調してきます。そういう感じです。

女子が少ない

これは男子にとっても女子にとっても死活問題です。
よく考えてください。高専の就学期間というのは、留年したりしない限り16歳~20歳です。
世間の人間は、青春を謳歌している年頃です。
そんな年代を、女子が少なくて多様性のない空間で過ごすと何が起こるかは想像に難くありませんね。
もちろん、そういったリスクを冒せるぐらいのメリットはあるのですが、いざ高専に入ってみると、青春できないことに対する精神的なダメージは思っていたよりも大きいです。

女子にとってももちろん、女子が少ないというのはある程度のダメージになりうると思います。
恋愛ができないとかいうことで悩むことはないかもしれませんが、やはりガールズトークの相手はいるんじゃないでしょうかね?私は男なのでわかりませんが。

もちろん、卒業して進学したり就職したりすると、ある程度女性のいる環境に置かれることになると思うのですが、そういった場所に行った時も、女性とのコミュニケーションの取り方を心得てない高専卒の人たちは少し苦労する場面もあるのかもしれません。
私は運よくクソかわいい彼女がいるのですが、それをクソかわいいと思っているのが高専生だけ、ということも普通にあり得ます。

まとめ

高専への進学を考えている中学生の皆さんと、高専生とこれからかかわるかもしれない一般人向けに書いてみました。
高専生はすごく変わった生き物ですが、社交性がまったくないわけではないので、仲良くなると面白いかもしれません。
それから、デメリットはいろいろ書きましたが、私は高専に来てよかったと思っています。
ちゃんと勉強するモチベーションがある人にとっては天国のような環境なので、専門的な分野について早く学びたいと思っている中学生の皆さんは、ぜひ高専への進学を検討してみてください。

Computational Neuroscience : Week2 を終えて

はじめに

少し遅ればせてしまいましたが、Week2を終えました。
実は、本格的にCourseraのコースを受講するのは初めてで、 このコースの本格性にかなり驚いたので、それも含めてまとめてみようと思います。

内容

Week1ではComputational Neuroscienceという学問分野がどのようなものなのかを軽く紹介するような内容だったので、週末の課題提出はありませんでした。
なので、かなり余裕をもってWeek2を始められるはずだったのですが、余裕がありすぎて逆に始めるのが遅れてしまいました。
追い打ちをかけるように、高専の方でも定期テストが近づいてきたり部活の引退試合があったりで、なかなかキャッチアップできませんでした。

Neural Encodingの簡単なモデル

Week2の内容は、Neural Encodingという手法についてでした。
手法の目的を、「ニューロンに与えられる刺激を基に、ニューロンが発火する確率分布を求めること」とし、そのために必要なアプローチを数学的に解説するというものでした。
最初に、与えられる刺激と発火確率分布の関係を定量化するためのモデルがいくつか紹介されました。
刺激関数を単純に定数倍したものや、何らかの「フィルタ関数」みたいなものを畳み込んだものなどが有効なようです。
さらにそこから、刺激関数を、時間軸だけでなく空間軸も持つものに拡張して視覚系における計算についても軽く解説していました。

フィルタ関数の決定

続いて、"じゃあそのフィルタ関数ってどうやって同定するねん!?"という話題に入っていきました。
ここでのフィルタ関数っていうのは、CNNにおける特徴フィルタと同じで、ニューロンが反応しやすい刺激の特徴を示すものなのです。
すなわち、フィルタ関数が決定できれば、それがそのままニューロンを発火させる信号になるわけです。

入力と発火の関係に手掛かりがない状態なので、入力としてガウス分布に基づいたホワイトノイズ信号を与えるという前提でいろいろ議論していました。
いちばんちゃんと解説していたのは、「Spike-triggered average」という方法で、アプローチはかなり簡単なものでした。
そのほかにも、多次元の刺激空間上で、ニューロンを発火させた刺激ベクトルがどういうグループを成しているのかを線形代数的に求めるアプローチや、
発火した場合としてない場合で、刺激関数の確率分布のKullback-Leibler距離が最大になるようにするという確率論的なアプローチでフィルタ関数を同定する方法も紹介されました。

課題提出

本当は、課題の提出期限は日本時間で月曜日の午前中だったのですが、
その日は前日から出かけていてずっと遊んでいたので、提出できませんでした。
ただ、週末のテスト提出は期限に間に合わなくてもペナルティはなく、最終的にコースが終了する日までにすべての課題を提出できればいいので、割とあっけらかんでした。

課題の内容は、授業内容の理解度を確認する選択形式の問題が2問ほどと、
PythonまたはMatlabを使って、与えられたデータセットからspike-triggered averageを求める問題でした。
具体的には、Pickle形式で、インデックスを時間軸にとった、ホワイトノイズの刺激のリストと発火したか否かのバイナリリストが渡されるので、
そのデータをPythonでいろいろいじって、spike-triggered averageを求めました。
それから最後に、なんか2問ぐらいありましたが、よく覚えていませんw

そこまで難易度は高くなかったです。
最後の2問で間違えてしまい、最終的には90%正答でしたが、80%以上正答していれば課題はクリアなので、とりあえずこれでWeek2は修了となります。

あと6週間ぐらい残ってますが、気長に頑張ってマスターしていきたいと思います。