next up previous
次へ: 減衰項付のニューロンモデル 上へ: ニューラルネットの基本:実習編 戻る: 自習のための URL

簡単なニューロンのモデル

簡単のため入力、出力とも一個しかない場合を考えます。

図 1: もっとも簡単なニューロンのモデル
\resizebox{50mm}{!}{\includegraphics{fig.eps}}

$\displaystyle u = \sum_{i=1}^nw_ix_i = wx$ (1)

このニューロンへの入力 $ x$$ -10$ から $ 10$ まで変化したときに出力が どのように変化するかを出力する program を書いてみましょう。 C の場合、一つのニューロンを一つの構造体で表現することにすれば、

typedef struct {
    double output;
    double inner_state;
    double thres;
    double inp_wgt;
} neuron;


のように neuron という構造体を定義することになります。 このニューロンの出力が次のような sigmoid 関数に従うとすると

$\displaystyle f(\mu) = \frac{1}{1+e^{-\mu}}$ (2)

以下のような関数を定義することになります。
double sigmoid(double u) {
    return 1.0 / ( 1.0 + exp(- (u)) );
}


入力 $ x$$ -10$ から $ 10$ まで変化させるには for 文でも、 while 文でも until 文でよいです。たとえば次のようになるでしょう。

double FROM = -10.0;
double TO   =  10.0;
double STEP =   0.01;

x = FROM;
while ( x <= TO ) {
    printf("%f\n", /* ここに出力を計算する関数の呼出しが入る */);
    x += STEP;
}


本当はこれだけならば、わざわざ C を使うまでもなく、gnuplotMathematica などを用いる方が簡単です。 Excel でも可能で、洒落たグラフも作ってくれますが、 自分でモデルをいじって感覚を掴むためにはやはり プログラムを書いてみてください。一応正解を挙げておくと、次のようになります。

#include <stdio.h>
#include <math.h>

#define FROM -10.0
#define TO    10.0
#define STEP   0.01

#define sigmoid_slope -1.0

typedef struct {
    double output;
    double thres;
    double inp_wgt;
} neuron;

void initialize_neuron(neuron *x)
{
    x->thres = 0.0;
    x->inp_wgt = 1.0;
    x->output = 0.0;
}

double sigmoid(double value)
{
    return 1.0 / ( 1.0 + exp(sigmoid_slope * value) );
}

void update_neuron(neuron *x, double input)
{
    x->output = sigmoid(x->inp_wgt * input - x->thres);
}

int main(int argc, char **argv)
{
    neuron a;
    double x;

    initialize_neuron(&a);
    x = FROM;
    while ( x <= TO ){
        update_neuron(&a, x);
        printf("%f %f\n", x, a.output);
        x += STEP;
    }
}


プログラムには、4 つの定数(FROM, TO, STEP, sigmoid_slope)、 1 つの構造体(neuron)、 3 つの関数(initialize_neuron(),sigmoid(),main()) が定義されています。

C プログラムの初心者にとって理解しにくい点はおそらく、ニューロンを表す(構造体を 使って定義された)変数 a (main 関数から呼び出された関数 initialize_neuron()update_neuron()では x となっている)の前に付いている

*& の記号の意味
と、これらの変数の後ろに付いている記号
->. との違い
ではないかと思います。 * はポインタ, & はアドレス演算子です。 ポインタの理解は C をマスターする上で非常に大切ですので、不安な人は必ず 参考書をあたってください。ここでは、 C の関数呼び出しには との 2 つがあって、呼び出された側の関数の中で引数に指定された変数値を変 更する場合には call by address すなわち & をつけて関数を呼び出さ ねばならない、ということを確認してください。 呼び出された関数側では変数はポインタ(*)として参照しなければなりません。 また、構造体の内容を参照するには . でよいのですが、 ポインタとして渡された関数の内部では -> で参照しなければならないという ことも忘れてはいけません。

あとは、main() 関数から実行が始まることに注意すればプログラムを読むのは それほど難しいことではないでしょう。

最初なので、コンパイル方法と実行方法を確認しておくと

% gcc -o Neuron Neuron.c -lm    
% ./Neuron
となります。 ただし、Windows 環境では上記の操作を MS-DOS プロンプトを起動して実行する必要があります。

課題 1:
(1) 上記のプログラムの出力を使ってグラフを描きなさい

--ヒント--
プログラムの結果をファイルに出力するには
% ./Neuron > ファイル名
とします。


(2) sigmoid 関数の傾きを変化させるとグラフはどうなるか
(3) 閾値を変化させるとグラフはどうなるか
(4) $ f(\mu) = \displaystyle\frac{1}{1+e^{-\mu}}$$ \mu$ について微分しなさい

--ヒント--
高等学校での微分の公式を思い出して

$\displaystyle \Brc{\frac{f}{g}}'=\frac{f'g-fg'}{g^2}$ (3)

だから

$\displaystyle f(x) = \frac{1}{1+e^{-x}}$ (4)

$ x$ について微分すると
$\displaystyle \frac{df}{dx}$ $\displaystyle =$ $\displaystyle \frac{e^{-x}}{\Brc{1+e^{-x}}^2} = \frac{1+e^{-x}-1}{\Brc{1+e^{
-x}}^2}$ (5)
  $\displaystyle =$ $\displaystyle \frac{1+e^{-x}}{\Brc{1+e^{-x}}^2} - \frac{1}{\Brc{1+e^{-x}}^2}$ (6)
  $\displaystyle =$ $\displaystyle \frac{1}{\Brc{1+e^{-x}}}\Brc{1- \frac{1}{1+e^{-x}}}
= <tex2html_comment_mark>19$ (7)

ついでに、

$\displaystyle f(x) = \tanh{x} = \frac{e^{x}-e^{-x}}{e^{x}+e^{-x}}$

$ x$ について微分すると
$\displaystyle \frac{df}{dx}$ $\displaystyle =$ $\displaystyle \frac{1}{\cosh^2x} = \BRC{\frac{1}{\cosh x}}^2
= \BRC{\frac{2}{e^x+e^{-x}}}^2$ (8)
  $\displaystyle =$ $\displaystyle \frac{\BRC{e^x+e^{-x}}^2-\BRC{e^x-e^{-x}}^2}{\BRC{e^x+e^{-x}}^2}
= 1 - \BRC{\frac{e^x-e^{-x}}{e^x+e^{-x}}}^2$ (9)
  $\displaystyle =$ $\displaystyle 1 - \tanh^2x = 1 - \BRC{f(x)}^2$ (10)

$ tanh$ は双曲線関数です。詳しくは付録参照のこと


next up previous
次へ: 減衰項付のニューロンモデル 上へ: ニューラルネットの基本:実習編 戻る: 自習のための URL
Shinichi ASAKAWA 平成14年4月30日