初心者データサイエンティストの備忘録

調べたことは全部ここに書いて自分の辞書を作る

【読書記録】<弱さ>のちから(鷲田清一)

はじめに

 私はこれまで学校や会社、家庭になじめない人生を送ってきました。周りの人にとって簡単にできることが、自分にとっては難しく感じるのです。
 そういった経験の積み重ねや大学受験の失敗により、18歳のときに心の病を発症してしまいました。心の病とは厄介なもので、発症から10年以上経っていますが、完全に回復していません。サラリーマンになってからは休職や時短勤務も経験しました。
 そんな中、哲学者の鷲田清一さんが書いた「<弱さ>のちから」という本の存在を知りました。自分は間違いなく「弱い」人間だと感じている私にとって、興味を惹かれるタイトルでした。本記事では、本書を読んだ私の感想を書こうと思います。

「<弱さ>のちから」とは

 私は本書を読み、「<弱さ>のちから」とは「社会規範に縛られた人を開放するちから」という風に解釈しました。まずは、「<弱さ>のちから」を私がなぜこのように解釈したのかについて述べようと思います。
 本書では、「からだにじぶんを委ねられなくなったことが、わたしたちのいちばん危ういところなのかもしれない」と問題提起しています。なぜ、からだにじぶんを委ねられなくなったかというと、人は他人や社会の影響を強く受ける生き物だからです。社会の多くの人が持つ論理に流されてしまって、じぶんのからだが悲鳴をあげても無視してしまう、現代はそんな状況であるという問題提起を鷲田さんはしています。
 実際私も「勉強はできるべきだ」や「給料は高いほうが良い」という社会規範的な考え方に強固に支配されてきましたし、今も支配されています。しかし、この考え方のせいで身体が悲鳴をあげても、その悲鳴を無視し心の病になってしまいました。
 この問題に対して、鷲田さんは以下のような解決策を提示しています。

じぶんが乱れうること、じぶんをほどくということが、ほんとうの自由だとしたら。そういう自由を他者の存在の<弱さ>が劈(ひら)いてくれる

 ここでいう「じぶんが乱れうること」「じぶんをほどくということ」は、じぶんが固定観念のように持っている社会規範的な考え方を揺るがせること、という風に私は解釈しました。このように人を縛る社会規範を揺るがせる力を<弱さ>は持っている、なので「<弱さ>のちから」とは本書においては「社会規範に縛られた人を開放するちから」と解釈できるのではないかと私は考えました。
 ここまでの議論は抽象的で分かりにくかったと思うので、もう少し具体的に「<弱さ>のちから」について述べようと思います。
 私は大学生の頃、多様な子どもが集まる塾でアルバイトをしていました。その中には不登校になったり、発達障害を持っていたり、家庭が荒れていたりといった生きづらさを抱えている子どもが多くいました。誤解を恐れずに言えば、そのような子どもたちは社会的な<弱さ>を持っています。
 私はそのような子どもに教員という立場で関与していましたが、私が持っている社会規範的な考え方は通用しませんでした。そのような環境で子どもたちに関わっていく中で、私の「勉強はできなければいけない」という考え方に若干の変化が生じました。子どもが持つ<弱さ>は「勉強ができなければいけない」という考え方に耐えることができず、それゆえ私が生きてきた生き方と異なる生き方を一緒に模索する必要に迫られたからです。
 以上のように、自分が固定観念的に持っている社会規範と異なる文化を持つ人々と接することで、自分の固定観念が乱され、自由になる契機となる、ということを鷲田さんは言いたいのだと思います。このことを鷲田さんは下記のように述べています。

ケアにあたるひとがケアを必要としているひとに逆にときにより深くケアされ返すという反転が。より強いとされる者がより弱いとされる者に、かぎりなく弱いとおもわれざるをえない者に、深くケアされるということが、ケアの場面ではつねに起こるのである。

弱い立場は相対的

 ここからは私の感想です。
 <弱さ>というものは絶対的な概念ではなく、相対的な概念であると思います。したがって、どのような人でも他者との関係性において「弱い」立場にもなりうるし、「強い」立場にもなりうると思います。
 例えば、私は会社では出世コースから完全に外れ、仕事ができない「弱い」奴だと思われています。しかし、前述した塾ではややもすれば優位な立場になってしまう教員として働いていました。このような環境ではどちらかと言えば「強い」立場になるのではないかと思います。
 したがって、自分が社会規範に縛られていると感じ、そこから自由になりたいと思うのであれば、自分よりも「弱い」立場のいる人がいる環境を探し、その環境に行けば良いと思います。そのうえで、「弱い」立場にいる人を深く知り、ケアすることで、自分を縛る社会規範に乱れが生じ、そこから自由になる契機を掴めると私は考えます。
 また、自分が「弱い」立場にいると感じる人は、自分と接する人の価値観を乱しに行けば良いのです。それによって社会規範の縛りから抜け出せることができ、助かる人もいると思います。「弱い」人はある種の啓蒙活動ができる人である、と開き直れば良いと思います。

「弱い」「強い」が生む分断

 「強い」者が「弱い」者を差別するという構造は、日本のどこでも見られることだと思います。ネットでは低所得・独身・病気持ちの男性を差別的に表現する「弱者男性」という嫌な言葉もあります。
 このように、人を「弱い」「強い」で分類し、同じ分類の人としか関係を持たないという考え方で生きていくと、社会が「弱い」グループと「強い」グループに分断されていきます。社会の分断が進むということは、人々の間で互いを尊重するという考え方が喪失されていくということでもあります。そのような社会で生きていくことは、正直私にはしんどいです。したがって、私は社会が分断されていくことに抵抗を感じます。もっと「強い」人と「弱い」人が深い交流をすることができれば、分断は防げると思います。

私はどうするべきか

 私は現在、会社では「弱い」立場で生きています。そのことに対して、私は強い悲しみを覚えてきました。実際、周囲から「その年齢でそのクラスかよ」と飲み会で馬鹿にされて辛い思いをしたこともあります(注:自分が所属する会社では「クラス」というもので給料が決まる)。しかし、本書を読み、「弱い」立場にもそれ独特のちからがあると気付くことができました。
 一方で、私が社会規範から自由になるために、自分が持つ固定観念を消化する必要もあります。これについては、自分がケアする側になれる環境を探し、そこで「弱い」立場の人をケアすること、深く知ることによって消化していきたいと思います。

【読書記録】<弱さ>のちから(鷲田清一)

はじめに

 私はこれまで学校や会社、家庭になじめない人生を送ってきました。周りの人にとって簡単にできることが、自分にとっては難しく感じるのです。
 そういった経験の積み重ねや大学受験の失敗により、18歳のときに心の病を発症してしまいました。心の病とは厄介なもので、発症から10年以上経っていますが、完全に回復していません。サラリーマンになってからは休職や時短勤務も経験しました。
 そんな中、哲学者の鷲田清一さんが書いた「<弱さ>のちから」という本の存在を知りました。自分は間違いなく「弱い」人間だと感じている私にとって、興味を惹かれるタイトルでした。本記事では、本書を読んだ私の感想を書こうと思います。

「<弱さ>のちから」とは

 私は本書を読み、「<弱さ>のちから」とは「社会規範に縛られた人を開放するちから」という風に解釈しました。まずは、「<弱さ>のちから」を私がなぜこのように解釈したのかについて述べようと思います。
 本書では、「からだにじぶんを委ねられなくなったことが、わたしたちのいちばん危ういところなのかもしれない」と問題提起しています。なぜ、からだにじぶんを委ねられなくなったかというと、人は他人や社会の影響を強く受ける生き物だからです。社会の多くの人が持つ論理に流されてしまって、じぶんのからだが悲鳴をあげても無視してしまう、現代はそんな状況であるという問題提起を鷲田さんはしています。
 実際私も「勉強はできるべきだ」や「給料は高いほうが良い」という社会規範的な考え方に強固に支配されてきましたし、今も支配されています。しかし、この考え方のせいで身体が悲鳴をあげても、その悲鳴を無視し心の病になってしまいました。
 この問題に対して、鷲田さんは以下のような解決策を提示しています。

じぶんが乱れうること、じぶんをほどくということが、ほんとうの自由だとしたら。そういう自由を他者の存在の<弱さ>が劈(ひら)いてくれる

 ここでいう「じぶんが乱れうること」「じぶんをほどくということ」は、じぶんが固定観念のように持っている社会規範的な考え方を揺るがせること、という風に私は解釈しました。このように人を縛る社会規範を揺るがせる力を<弱さ>は持っている、なので「<弱さ>のちから」とは本書においては「社会規範に縛られた人を開放するちから」と解釈できるのではないかと私は考えました。
 ここまでの議論は抽象的で分かりにくかったと思うので、もう少し具体的に「<弱さ>のちから」について述べようと思います。
 私は大学生の頃、多様な子どもが集まる塾でアルバイトをしていました。その中には不登校になったり、発達障害を持っていたり、家庭が荒れていたりといった生きづらさを抱えている子どもが多くいました。誤解を恐れずに言えば、そのような子どもたちは社会的な<弱さ>を持っています。
 私はそのような子どもに教員という立場で関与していましたが、私が持っている社会規範的な考え方は通用しませんでした。そのような環境で子どもたちに関わっていく中で、私の「勉強はできなければいけない」という考え方に若干の変化が生じました。子どもが持つ<弱さ>は「勉強ができなければいけない」という考え方に耐えることができず、それゆえ私が生きてきた生き方と異なる生き方を一緒に模索する必要に迫られたからです。
 以上のように、自分が固定観念的に持っている社会規範と異なる文化を持つ人々と接することで、自分の固定観念が乱され、自由になる契機となる、ということを鷲田さんは言いたいのだと思います。このことを鷲田さんは下記のように述べています。

ケアにあたるひとがケアを必要としているひとに逆にときにより深くケアされ返すという反転が。より強いとされる者がより弱いとされる者に、かぎりなく弱いとおもわれざるをえない者に、深くケアされるということが、ケアの場面ではつねに起こるのである。

弱い立場は相対的

 ここからは私の感想です。
 <弱さ>というものは絶対的な概念ではなく、相対的な概念であると思います。したがって、どのような人でも他者との関係性において「弱い」立場にもなりうるし、「強い」立場にもなりうると思います。
 例えば、私は会社では出世コースから完全に外れ、仕事ができない「弱い」奴だと思われています。しかし、前述した塾ではややもすれば優位な立場になってしまう教員として働いていました。このような環境ではどちらかと言えば「強い」立場になるのではないかと思います。
 したがって、自分が社会規範に縛られていると感じ、そこから自由になりたいと思うのであれば、自分よりも「弱い」立場のいる人がいる環境を探し、その環境に行けば良いと思います。そのうえで、「弱い」立場にいる人を深く知り、ケアすることで、自分を縛る社会規範に乱れが生じ、そこから自由になる契機を掴めると私は考えます。
 また、自分が「弱い」立場にいると感じる人は、自分と接する人の価値観を乱しに行けば良いのです。それによって社会規範の縛りから抜け出せることができ、助かる人もいると思います。「弱い」人はある種の啓蒙活動ができる人である、と開き直れば良いと思います。

「弱い」「強い」が生む分断

 「強い」者が「弱い」者を差別するという構造は、日本のどこでも見られることだと思います。ネットでは低所得・独身・病気持ちの男性を差別的に表現する「弱者男性」という嫌な言葉もあります。
 このように、人を「弱い」「強い」で分類し、同じ分類の人としか関係を持たないという考え方で生きていくと、社会が「弱い」グループと「強い」グループに分断されていきます。社会の分断が進むということは、人々の間で互いを尊重するという考え方が喪失されていくということでもあります。そのような社会で生きていくことは、正直私にはしんどいです。したがって、私は社会が分断されていくことに抵抗を感じます。もっと「強い」人と「弱い」人が深い交流をすることができれば、分断は防げると思います。

私はどうするべきか

 私は現在、会社では「弱い」立場で生きています。そのことに対して、私は強い悲しみを覚えてきました。実際、周囲から「その年齢でそのクラスかよ」と飲み会で馬鹿にされて辛い思いをしたこともあります(注:自分が所属する会社では「クラス」というもので給料が決まる)。しかし、本書を読み、「弱い」立場にもそれ独特のちからがあると気付くことができました。
 一方で、私が社会規範から自由になるために、自分が持つ固定観念を消化する必要もあります。これについては、自分がケアする側になれる環境を探し、そこで「弱い」立場の人をケアすること、深く知ることによって消化していきたいと思います。

色々な勾配降下法

はじめに

 近年、ニューラルネットワークは分類精度の高さや様々なタスクへの応用が可能であることから、幅広い領域で使われています。私の場合、セキュリティ領域でニューラルネットワークを用いています。  ところが、ニューラルネットワークはその複雑な構造から、誤った使い方をされてしまうことがあります。誤った使い方を防ぐためには、その基礎理論を学ぶことが重要だと私は考えています。私の場合、なっとく!ディープラーニングという本を通じて、ニューラルネットワークの理論を学んできました。
 本記事では、本書で学んだ勾配降下法という手法について説明します。本記事より詳しい内容を確認したい方は、本書の第8章をご覧ください。

勾配降下法

 勾配降下法とは、最適化問題を解く方法の一つです。ニューラルネットワークにおいては、モデルの出力と真のラベル間の損失関数を最小にするようなパラメータを推定することが求められます。このとき、勾配降下法が使われます。  勾配降下法の基本的なパラメータ更新式は、(1)式のようになります。


\begin{eqnarray}
\omega _ {(n+1)} = \omega _ {(n)} - \eta \dfrac{\partial L}{\partial \omega}(\omega _ {(n)} ) \tag{1}
\end{eqnarray}

です。ただし、\omega _ {(n+1)}は更新後のパラメータ、\omega _ {(n)}は更新前のパラメータ、\etaは学習率、Lは損失関数です。 \dfrac{\partial L}{\partial \omega}(\omega _ {(n)} )によって更新の方向が、 \etaによって更新の大きさが決まります。なお、今回の実装においては損失関数は二乗誤差とします。

色々な勾配降下法

 勾配降下法は、一回の更新に用いるデータの個数や、データの選び方に応じて名前が変わります。各手法の名前をまとめたものが、表1です。

表1:勾配降下法の種類

実装

 表1に記載の勾配降下法をJuliaで実装しました。 github.com

 正確にエポック数などを揃えて比較したわけではないですが、1回の更新に用いるデータの個数が多い(=バッチサイズが大きい)ほど学習にかかる時間が短いように感じました。

まとめ

 本記事では様々な勾配降下法を「1回の更新に用いるデータの個数」と「1回の更新に用いるデータの選択の仕方」の2観点を用いて整理しました。また、Juliaでこれらの勾配降下法を実装し、バッチサイズが大きいほど学習にかかる時間が短くなることを確認しました。

ニューラルネットワークのドロップアウト

目次

はじめに

 近年、ニューラルネットワークは分類精度の高さや、様々なタスクへの応用が可能であることから、幅広い領域で使われています。私の場合、セキュリティ領域でニューラルネットワークを用いています。
 ところが、ニューラルネットワークはその複雑な構造から、誤った使い方をされてしまうことがあります。誤った使い方を防ぐためには、その基礎理論を学ぶことが重要だと私は考えています。私の場合、なっとく!ディープラーニングという本を通じて、ニューラルネットワークの理論を学んできました。
 本記事では、本書で学んだドロップアウトという手法について説明します。本記事より詳しい内容を確認したい方は、本書の第8章をご覧ください。

ドロップアウトの概要

 ドロップアウトとは、ニューラルネットワークにおける過学習を防ぐための仕組みです。ニューラルネットワークに含まれる重みをランダムに0にすることによって、より頑健なニューラルネットワークを構築することができます。
 本記事では、まず過学習を起こすニューラルネットワークを構築します。その後、学習の過程にドロップアウトを入れることによって、過学習が抑制されることを示します。なお、本記事を執筆する過程で書いたJuliaのコードはGitHubで公開しています。

問題設定

 MNISTデータセットの分類器を、三層のニューラルネットワークを用いて構築します。画像が28×28=784個の特徴量を持っているので、入力層が784個、隠れ層は300個、出力層は0から9の10個のニューラルネットワークを構築します。

過学習を起こすニューラルネットワーク

 まずは、ドロップアウトを入れずに学習を進めたニューラルネットワークを構築します。このとき、横軸にイテレーション、縦軸に学習データとテストデータに対する最小二乗誤差(Mean Square Error:MSE)をとった図が図1です。

図1:ドロップアウトを入れないニューラルネットワークイテレーションとMSEの関係

 図1を見ると、学習データのMSEは単調減少しているのに対し、イテレーションが15を超えたあたりからテストデータのMSEが増加し、その後減少していないことがわかります。これは、ニューラルネットワークが学習データの特徴を捉えすぎることにより、テストデータの分類がうまくいかなくなっている状態です。
 ニューラルネットワークは、その表現力の高さから、過学習を起こしやすいことが知られています。

ドロップアウトを入れたニューラルネットワーク

 ドロップアウトを入れて学習を進めたニューラルネットワークを構築します。このとき、横軸にイテレーション、縦軸に学習データとテストデータに対するMSEをとった図が図2です。

図2:ドロップアウトを入れたニューラルネットワークイテレーションとMSEの関係

 図2を見るとわかるように、学習データとテストデータのMSEが両方とも単調減少しています。これはドロップアウトを入れたことにより、過学習が抑制されているからです。

まとめ

 ニューラルネットワーク過学習を抑制するドロップアウトについて、簡単に説明しました。また、ドロップアウトを入れずに学習を進めたニューラルネットワークと、ドロップアウトを入れて学習を進めたニューラルネットワークのMSEの変化を比較しました。これにより、過学習を防ぐ手立てとしてドロップアウトが有効な場合があることが示されました。

「ハンチバック」と「普通になりたいという気持ち」

はじめに

 芥川賞を受賞した「ハンチバック」を読みました。本作は、先天性ミオパチーという病気に罹患している作者、市川沙央さんによって書かれた本です。主人公も同じ病気に罹患しており、小説では(恐らく)市川さんの心象風景が描かれています。
 私が本作を手に取った理由は、市川さんが他人事ではないからです。社会で生きる上で何らかのハンディキャップを抱えているという点で、市川さんと私には共通点があります。そのハンディキャップをどのように小説に落とし込んでいるのかということに興味を持ち、本作を手に取りました。

社会への批判

 本作は、健常者優位な社会への批判で満ち溢れています。私はこの世の中を健常者優位と思ったことはありませんが、障害を持つ人から見たらそうなのだと思います。社会への批判を真正面から描くことで、結果的に健常者である読者は障害者と健常者という対立的な視点を持つことになります。その視点により、私たちにとって快適な社会は、障害者にとって全く快適ではないという当たり前の現実に私たちは気付かされます。

妊娠と中絶はしてみたい

 本作が芥川賞を受賞した後、作者の市川さんには批判がいくつも届いたそうです。そのうちの一つに本作の主人公がTwitterでつぶやいた『妊娠と中絶はしてみたい』という言葉に対する批判があります。『妊娠と中絶はしてみたい』という言葉に対して「気持ち悪い」とか「生命を軽視している」といった批判です。
 確かに、『妊娠と中絶はしてみたい』という言葉をその字義通りに受け取ると、ギョッとします。しかし、これは「普通の人になりたい」という気持ちの比喩だと私は思いました。ここでいう普通の人というのは、本作でいえば健常者であり、健常者から性の対象とされる人のことを指すと、私は思いました。「普通の人になりたい」という気持ちをセンセーショナルに表現したものが、『妊娠と中絶はしてみたい』という言葉だと私は解釈しています。
 このことをよく書き表していると感じた文章は下記です。

私はあの子たちの背中に追い付きたかった。産むことはできずとも、堕ろすところまでは追い付きたかった。

私と本作の関係性

 本記事の「はじめに」で、私は社会で生きる上でのハンディキャップを抱えていると書きました。私自身は障害を持っていませんが、社会に対して生きづらさは常に感じています。私は幼い頃から、人と同じように振舞えないことにコンプレックスを抱いていました。そのコンプレックスは今でも抱えていますし、周囲と比べて劣等感を非常に感じながら生きています。その気持ちを一言で表すと「普通の人になりたい」なんです。 「普通の人」に強い憧れを持ちながら、それを一生実現できないだろうと思うやるせなさは、それを経験した人にしかわからないと思います。
 とはいえ、私の「普通の人になりたい」は周囲から植え付けられたものでもあると感じています。身体障害のような目に見えて「普通の人ではない」という状態ではありません。ある意味気持ち次第で「普通の人になれる」という意味では、私の方が気楽だと思います。

終わりに

 ここまで書いてきて、その人にとっての「普通の人」というのは、「その人にとって理想の人」と言い換えられるかもしれないと私は思いました。市川さんにとっての理想の人は背骨が曲がっていない人、私にとっては勉強ができて、所属するコミュニティでうまく振舞える人を「普通の人」と言っている感があります。そう考えると、自分のことを「普通ではない弱者」と捉える視点とは別の視点を持つことができるかもしれないと思いました。  

 

git pushしたときに403エラーが出たときの対処法

はじめに

 先日GitHubのリモートリポジトリにgit pushしようとしたら、ユーザー名とパスワードを求められました。その上、正しいと思われるユーザー名とパスワードを入力したにも関わらず、

The requested URL returned error: 403

というエラーが出ました。
 本記事では、このエラーの対処法についてまとめようと思います。

確認事項

 ググったところ、このエラーが出たときに確認すべき事項が少なくとも4個あるようです。 その確認事項とは下記の通りです。

  1. git configが正しく設定されているか?
  2. Windows資格情報が設定されてしまっているか?
  3. アクセストークンは発行しているか?
  4. SSH通信でリモートリポジトリとやり取りしようとしているか?

これらについて、下記に私が参考にしたWEBサイトを載せておきます。2024/1/15時点の私の環境(Windows 10, git version 2.28.0)では、下記のWEBサイトを一つずつ確認していくことで解消できました。

参考WEBサイト

git configが正しく設定されているか?」と「Windows資格情報が設定されてしまっているか?」

 確認事項の1, 2は一つのQiitaの記事にまとまっていました。 qiita.com

アクセストークンは発行しているか?

 確認事項の3は下記をご覧ください。pushする際に求められる「パスワード」は実は「パスワード」ではなく、「アクセストークン」ですよという罠。 fantastech.net

SSH通信でリモートリポジトリとやり取りしようとしているか?

 確認事項の4は下記をご覧ください。

trios.pro

まとめ

 本記事はgit pushしたときに403エラーが出たときの対処法についてまとめた記事です。(とはいえ先人の書いた記事を貼っただけですが)
 私と同じような理由で困っている方にこの記事が届いたら幸いです。

【読書記録】なっとく!ディープラーニング_第6章

目次

はじめに

 現在ニューラルネットワークは多くの分野で使われています。私の場合、セキュリティ上の課題を解決する手段としてニューラルネットワークを用いています。
 このニューラルネットワークですが、モデルの表現性を高めるために層を重ねることが必要不可欠となっています。層を重ねたニューラルネットワークは、推定対象のパラメータが多く、前回記事で用いた方法でパラメータを推定することができません。
 以上のような背景のもとで生まれた技術が誤差逆伝播法です。誤差逆伝播法は合成関数の微分の公式を用いることで、全ての層のパラメータの推定を可能にします。
 本記事では、3層構造のニューラルネットワークを題材に、誤差逆伝播法がどのような仕組みになっているのか、数式とJuliaのコードを示すことで説明しようと思います。
 なお、本記事はなっとく!ディープラーニングの第6章に沿って書いております。問題設定等をより詳しく知りたい方は本書をご覧ください。

勾配降下法のおさらい

 勾配降下法の基本式は、


\omega _ {(n+1)} = \omega _ {(n)} - \eta \dfrac{\partial L}{\partial \omega}(\omega _ {(n)} )

です。ただし、\omega _ {(n+1)}は更新後のパラメータ、\omega _ {(n)}は更新前のパラメータ、\etaは学習率、Lは損失関数です。 \dfrac{\partial L}{\partial \omega}(\omega _ {(n)} )によって更新の方向が、 \etaによって更新の大きさが決まります。なお、損失関数は二乗誤差とします。

複数層のニューラルネットワーク

 図1のような3層構造のニューラルネットワークを考えます。

図1:3層構造のニューラルネットワーク

このとき、入力層のベクトルを横ベクトル \boldsymbol{x} = (x_1, x_2, x_3)とします。また、入力層から中間層の変換を


\boldsymbol{u} = (u_1, u_2, u_3, u_4) = \boldsymbol{x} W_{01}

とします。\boldsymbol{x}1\times3のベクトル、W_{01}3\times 4の行列です。
 次に、\boldsymbol{u}の各成分を活性化関数Reluに入力し、


\boldsymbol{z} = ({\rm Relu}(u_1), {\rm Relu}(u_2), {\rm Relu}(u_3), {\rm Relu}(u_4))

と変換します。ただし、


{\rm Relu}(x) = \left\{
\begin{array}{l}
x &(x>0) \\
0 & (x \leq 0)
\end{array}
\right.

とします。
 最後に、中間層から出力層への変換を


\hat{y} = \boldsymbol{z} W_{12}

とします。\hat{y}スカラーW_{12}4 \times 1の行列です。

誤差逆伝播

 ここでは、勾配降下法を使いW _ {01}を推定する方法を紹介します。W_{12}を推定する方法については、過去の記事 aisinkakura-datascientist.hatenablog.com で紹介しているので、興味があればご覧ください。

一つの成分に対する更新式

 「勾配降下法のおさらい」に書いた通り、パラメータを推定するためには損失関数をパラメータで微分した式が必要となります。今回はわかりやすいように、


W_{01} = \left(\begin{array}{cccc}
w_{11} & w_{12} & w_{13} & w_{14} \\
w_{21} & w_{22} & w_{23} & w_{24} \\
w_{31} & w_{32} & w_{33} & w_{34} 
\end{array}\right)

とし、代表として w _ {23}を推定するための更新式を導こうと思います。
 更新式のポイントは、\dfrac{\partial L}{\partial w _ {23}}を計算することです。この式は、合成関数の微分の公式を使うことで次の様に分解できます。


\dfrac{\partial L}{\partial w_{23}} = \dfrac{\partial u_3}{\partial w_{23}} \dfrac{\partial z_3}{\partial u_{3}} \dfrac{\partial \hat{y}}{\partial z_{3}}\dfrac{\partial L}{\partial \hat{y}}

 分解した式を一つずつ計算していきます。まず、 \dfrac{\partial u _ 3}{\partial w _ {23}}を計算します。\boldsymbol{u} = \boldsymbol{x} W_{01}より、


u_3 = w_{13}x_1+w_{23}x_2+w_{33}x_3

となることから、


\dfrac{\partial u _ 3}{\partial w _ {23}} = x_2

となります。次に\dfrac{\partial z _ 3}{\partial u _ {3}}について、 z_3 = {\rm Relu}(u_3)より、


\dfrac{\partial z_3}{\partial u_3} = \left\{
\begin{array}{l}
1 &(u_3>0) \\
0 & (u_3 \leq 0)
\end{array}
\right.

となります。なお、この右辺の式を今後は{\rm ReluDeriv}(\cdot)と呼びます。
 さらに、\dfrac{\partial \hat{y}}{\partial z _ 3}を計算します。


W_{12} = \left(\begin{array}{cccc}
w_1 & w_2 & w_3 & w_4
\end{array}\right)

とすると、\hat{y} = \boldsymbol{z} W _ {12}より、


\hat{y} = z_1 w_1 + z_2 w_2 + z_3 w_3 + z_4 w_4

となります。したがって、


\dfrac{\partial \hat{y}}{\partial z _ 3} = w_3

となります。
 最後に、\dfrac{\partial L}{\partial \hat{y}}を計算します。 L = (\hat{y}-y) ^ 2なので、


\dfrac{\partial L}{\partial \hat{y}} = 2(\hat{y}-y)

となります。
 以上をまとめると、


\dfrac{\partial L}{\partial w_{23}} \propto x_2 {\rm ReluDeriv}(u_3)w_3(\hat{y}-y)

となります。なお、\dfrac{\partial L}{\partial \hat{y}}の係数の2は学習率に吸収すれば良いです。そのため、係数の2は消して等号=を比例記号\proptoに置き換えています。
 上記を踏まえ、一般の w _ {ij}によるL微分を計算すると下記のようになります。


\dfrac{\partial L}{\partial w_{ij}} \propto x_i {\rm ReluDeriv}(u_j)w_j (\hat{y}-y)

全ての成分に対する更新式

 前節で


\dfrac{\partial L}{\partial w_{ij}} \propto x_i {\rm ReluDeriv}(u_j)w_j (\hat{y}-y)

となると書きました。これを基に \dfrac{\partial L}{\partial W _ {01}}を計算すると、下記のようになります。


\begin{eqnarray}
\dfrac{\partial L}{\partial W _ {01}} &\propto& (\hat{y}-y) \left(\begin{array}{cccc}
x_1 {\rm RD}(u_1)w_1 & x_1 {\rm RD}(u_2)w_2 & x_1 {\rm RD}(u_3)w_3 & x_1 {\rm RD}(u_4)w_4 \\
x_2 {\rm RD}(u_1)w_1 & x_2 {\rm RD}(u_2)w_2 & x_2 {\rm RD}(u_3)w_3 & x_2 {\rm RD}(u_4)w_4 \\
x_3 {\rm RD}(u_1)w_1 & x_3 {\rm RD}(u_2)w_2 & x_3 {\rm RD}(u_3)w_3 & x_3 {\rm RD}(u_4)w_4 \\
\end{array}\right) \\
&=& (\hat{y}-y)\boldsymbol{x}^\top \left\{ W_{12}^\top \times ({\rm RD(u_1), \rm RD(u_2), \rm RD(u_3), \rm RD(u_4)})\right\}
\end{eqnarray}

 なお、RDとはReluDerivのこと、行列間の\timesは各成分の積を表します。

コードに落とし込む

 以上のことをJuliaで書いたコードが下記です。W_0_1_delta \dfrac{\partial L}{\partial W _ {01}}です。

using LinearAlgebra, Statistics, Random
"""
データ
"""
# 特徴量
streetlights = [
    1 0 1
    0 1 1
    0 0 1
    1 1 1
]

# 目的変数
walk_vs_stop = [
    1
    1
    0
    0
]

"""
パラメータ
"""
# 学習率
α = 0.2

# 入力層のサイズ
input_size = size(streetlights[1, :])[1]

# 隠れ層のサイズ
hidden_size = 4

# 出力層のサイズ
output_size = 1

# ランダムに初期化された3つの層を結合するパラメータの初期値
#W_0_1 = 2*rand(input_size, hidden_size).-1
#W_1_2 = 2*rand(hidden_size, output_size).-1
Random.seed!(1)
W_0_1 = 2*rand(input_size, hidden_size).-1
W_1_2 = 2*rand(hidden_size).-1

"""
関数
"""
relu(x) = (x>0)*x

relu2deriv(output) = output>0


"""
誤差逆伝播法
"""
# MSEを保存するためのリストを作成
mse_list = []

for iteration=1:60
    for index=1:size(walk_vs_stop)[1]
        # 順伝播
        layer_0 = streetlights[index, :]'
        layer_1_1 = layer_0*W_0_1 # 中間層の活性化関数に入れる前
        layer_1_2 = relu.(layer_1_1) # 中間層の活性化関数に入れた後
        layer_2 = layer_1_2*W_1_2
        
        

        # 更新式の差分
        ## layer_2のパラメータの更新式の差分
        ### layer_2ではなく、layer_2[1]としているのは、layer2が(1, 1)の行列になっているから
        layer_2_delta = layer_2[1]-walk_vs_stop[index]
        W_1_2_delta = α*layer_2_delta*layer_1_2'
        ## layer_1のパラメータの更新式の差分
        W_0_1_delta = α*layer_2_delta*layer_0'*(W_1_2'.*relu2deriv.(layer_1_1))
        

        # 更新
        W_1_2 = W_1_2-W_1_2_delta
        W_0_1 = W_0_1-W_0_1_delta
    end
    
    # MSE(Mean Square Error)の計算
    ## 全てのデータに対して順伝播を行う
    Layer_1_1 = streetlights*W_0_1 # 中間層の活性化関数に入れる前
    Layer_1_2 = relu.(Layer_1_1) # 中間層の活性化関数に入れた後
    pred_list = Layer_1_2*W_1_2
    

    mse = mean((pred_list-walk_vs_stop).^2)
    push!(mse_list, mse)
    println("Error:", mse)
    println("pred_list:", pred_list)
    
end

 図2は学習が進むにつれ平均二乗誤差(Mean Squared Error:MSE)がどのように減少するのかを示した図です。学習が進むにつれ、MSEが減少していることがわかります。このように、誤差逆伝播法によって正しい予測ができるニューラルネットワークを構築できることがわかります。

図2:イテレーションごとのMSEの変化

 なお、図2を描画するのに用いたコードは下記の通りです。

import Pkg
Pkg.add("PyPlot")
using PyPlot

# 折れ線グラフを描画
plot(1:size(mse_list)[1], mse_list)
xlabel("iteration")
ylabel("MSE")

まとめ

 本記事では、3層構造のニューラルネットワークを題材にして誤差逆伝播法について説明しました。また、Juliaを用いて誤差逆伝播法を実装し、ニューラルネットワークに含まれるパラメータを推定しました。
 本記事が誤差逆伝播法の理解促進につながれば幸いです。