【機械学習】ステップ関数とシグモイド関数の使い道の違い、パーセプトロンとニューラルネットワーク

申し訳ないですが、ガンガン他の方の記事を貼らせて頂きます
poppingcarp.com

この記事ではステップ関数とシグモイド関数、それぞれの役割が書かれています。

この記事の重要な部分だけを抜粋すると・・・

ステップ関数は

閾値0を境に1(次のニューロンに伝送する)か0(次のニューロンに伝送しない)がはっきり決まる。

つまり閾値よりも出力の値が大きければ1、小さければ0と白黒ハッキリさせるということですね。


そしてシグモイド関数

ステップ関数が0か1しか返せないのに対して、シグモイド関数の方が滑らかな曲線で、0.23や0.78などの実数が返却できる。
ステップ関数と共通しているのは、xが小さくなると返却ちが0に近づき、xが大きくなると1に近づくという点です。

これで大体ステップ関数とシグモイド関数の違いが分かったと思います。


次は、これらの関数の使い道と紹介します。

rightcode.co.jp

ステップ関数は、この記事にも紹介してあるようにパーセプトロン学習にて利用されると見れます。


そしてシグモイド関数ニューラルネットワークにて利用されるケースが多いです。(恐らくシグモイド関数を使わず、ステップ関数単体だけでのニューラルネットワークの学習は上手くいかないと思いますが、もし間違ってたら意見ください。)

終わリンゴ

【AI】重み・しきい値の学習時の式の考察、その式になる理由

しきい値や、重みを学習する際に・・・

#oは出力層の出力
o * (1 - o)

#hi[i]は、中間層の出力
hi[i] * (1 - hi[i])

ってな感じの式が含まれているが、この式はどういう意味なんだろう。

この式にはシグモイド関数が深く関わっている。

シグモイド関数伝達関数といって、0~1の間の値を返す関数であり、シグモイド関数f(α)のαの値によって返ってくる値が変動する

    """出力層の重み学習"""
def olearn(wo,hi,e,o):
    #誤差の計算
    d = (e[INPUTNO] - o) * o * (1 - o)
    #重みの学習
    for i in range(HIDDENNO):
        wo[i] += ALPHA * hi[i] * d
    #しきい値の学習
    wo[HIDDENNO] += ALPHA * (-1.0) * d
    return 

    """中間層の重み学習"""
def hlearn(wh,wo,hi,e,o):
    #中間層の各セルjを対象
    for j in range(HIDDENNO):
        dj = hi[j] * (1 - hi[j]) * wo[j] * (e[INPUTNO] - o) * o * (1 - o)
        #i番目の重みを処理
        for i in range(INPUTNO):
            wh[j][i] += ALPHA * e[i] * dj
        #しきい値の学習
        wh[j][INPUTNO] += ALPHA * (-1.0) * dj
    return 
    """伝達関数"""
def f(u):
    #シグモイド関数の計算
    return 1.0/(1.0 + math.exp(-u))
    """順方向の計算"""
def forward(wh,wo,hi,e):
    #hiの計算
    for i in range(HIDDENNO):
        u = 0.0
        for j in range(INPUTNO):
            u += e[j] * wh[i][j]
        u -= wh[i][INPUTNO] #しきい値の処理
        hi[i] = f(u)
    #出力oの計算
    o=0.0
    for i in range(HIDDENNO):
        o += hi[i] * wo[i]
    o -= wo[HIDDENNO] #しきい値の処理
    return f(o)

実行される関数の順番は
forward関数→olearn関数→hlearn関数なので・・・

forward関数が先に呼ばれており、o、hi[i]達はすでにシグモイド関数f()を通っている。(すでに微係数が掛けられている)

o * (1 - o)やhi[i] * (1 - hi[i])は重みやしきい値を学習させるために使われる。


ここから追記:
olearn関数の

d = (e[INPUTNO] - o) * o * (1 - o)------①

wo[i] += ALPHA * hi[i] * d------②

①は誤差×伝達関数(o * (1- o))で構成される式です。
o * (1- o)のoはシグモイド関数で値が0~1になるように調整されています。
そのため伝達関数(o * (1 - o))<= 1になり、それを誤差に掛けることによって誤差dを微調整することが出来ます。

②は出力層の重みを更新します。
APLHAは学習係数(今回は10)なので取りあえず無視します。
hi[i]は中間層の出力・・・・割愛

hlearn関数にて

dj = hi[j] * (1 - hi[j]) * wo[j] * (e[INPUTNO] - o) * o * (1 - o)

これは中間層の重みや閾値を更新するための誤差の計算なんですけど・・・何故こうなるのか。

出力層の出力が教師データ(答え)から外れているのは出力層の重みと閾値の責任でもあるんですが、中間層の重みや閾値の責任も僅かながら関わっているんです。

というわけで中間層の重み、閾値を学習させるのですが、この式はどういう意味なんだろうか。

まず、hi[j] * (1 - hi[j])とo * (1 - o)ですが、これは中間層の重みが急激に更新されることを防ぐための式です。この二つの式は、シグモイド関数を通った値(hi[i],o)を使用しているので、最終的に誤差に掛ける値は0.001とか0.02とかのめちゃくちゃ小さな値になる場合が多いです。

後もう一つの利点は、0.001みたいな超絶小さい値でもシグモイド関数を通った値(hi[i],o)を使っているので、微量ですが重みを調整してくれます。

【AI】ngpool[i * 2],ngpool[i * 2 + 1]にする理由

機械学習と深層学習の本の95ページ目からのコードを解析する

N = 30 #染色体の個数

mama = selectp(roulette,totalfitness)#親選択ルーレット、mamaには良い傾向にある染色体が入っている
papa = selectp(roulette,totalfitness)#親選択ルーレット、papaには良い傾向にある染色体が入っている

crossing(mama,papa,ngpool[i * 2],ngpool[i * 2 + 1])

#交叉の実践部分
def crossing(m,p,c1,c2):
    cp = rndn(N)

    for j in range(cp):
        c1[j] = m[j]
        c2[j] = p[j]

    for j in range(cp, N):
        c2[j] = m[j]
        c1[j] = p[j]

    return

ngpool[i * 2],ngpool[i * 2 + 1]になる理由は・・・

引数のm(mama)、p(papa)の二つの優秀な染色体を"同時に"一つのリスト(ngpool)に入れようとするから。

一つの染色体の要素の選ばれた優秀なデータを交叉して新たな染色体を生み出すよりも、

二つの染色体(優秀なmama、優秀なpapa)を交叉して新たな染色体を生み出す方がより効率的だから。

よって、二つの染色体を交叉して一つの次世代染色体(ngpool)に保存させるには、

ngpool[i * 2],ngpool[i * 2 + 1]と、仮引数にとって同時に操作するしかないのである。


そして、遺伝的アルゴリズムの次世代を選ぶ所までを、おまけ程度に続きを載せておくと・・・

    """次世代の選択"""
def selectng(ngpool,pool):
    totalfitness = 0                            #適応度の合計値
    roulette = [0 for i in range(POOLSIZE * 2)] #ルーレット
    acc = 0                                     #適応度の積算値

    #選択を繰り返す
    for i in range(POOLSIZE):----------------5
        #ルーレットの作成
        totalfitness=0
        for c in range(POOLSIZE * 2): -------1
            roulette[c] = evalfit(ngpool[c])----2
            #適応度の合計値を計算
            totalfitness += roulette[c]
        #染色体を一つ選ぶ
        ball = rndn(totalfitness)
        acc = 0
        for c in range(POOLSIZE*2):---------3
            acc += roulette[c]  #適応度を積算
            if acc > ball:
                break           #対応する遺伝子
        # 染色体のコピー
        pool[i] = copy.deepcopy(ngpool[c])----4
    return 

①:for文を、ngpoolの持っている染色体分(60個分)回す。

②:ngpool[c](ngpoolのc個めの染色体)の評価値を、c個めのrouletteリストに格納する。

③:ここのfor文で、それぞれ評価値の高い染色体が選ばれるように設定されているルーレットを60回(ngpoolの持っている染色体分)まわしており、ループの途中でaccの値がランダムに決められたルーレットの範囲内(ball)に突入したらループを終了する。

④:そして終了した直後のcの値が、ルーレットで決まったngpoolの中の超優秀な染色体です。
その超優秀な染色体を優秀な次次世代のpoolリストに格納している。

⑤:ngpoolの超優秀な染色体を次々世代のpoolリストが満タン(30個分全て埋まる)になるまでループする

終わり。

要素に何も入っていない二次元リストの作り方

# リスト内包表記で作る方法
data1 = [[] for i in range(10)]
print("data1 =",data1)

# 素直にfor文で作る方法
data2 = []
for i in range(10):
    data2 += [[]]
print("data2 =",data2)
data1 = [[], [], [], [], [], [], [], [], [], []]
data2 = [[], [], [], [], [], [], [], [], [], []]

二次元リストを作る際に参考にさせて頂いたサイト👇

delta114514.hatenablog.jp

Python勉強:1日目

1日目ですね~

編集とか全く凝ってないですが、ご了承ください(-_-;)

あと悪魔で自分向けの成長日記みたいな感じなんで、コードとかは参考にしないほうが良いと思います

Pythonの勉強が一通り終わったらAIに挑戦するつもりです。

今日徹夜で頭がぼーっとしててですね、何もできなかったのでテキトーに書いたクソコードでも貼っときます

汚いコードで申し訳ないです、初心者なので許してくださいm(__)m

from random import randint

fruits = ["apple","banana","lemon","grapes"]

num = randint(0,2)

fruits.pop()

fruits.pop(num)

print(fruits)

str = "banana"

if "banana" not in fruits :
    fruits.insert(1,"super banana")

    print(fruits)
 
    if "lemon" in fruits :
        fruits.remove("lemon")
        fruits.append("ultra lemons!!")
        print(fruits)
        fruits.pop()
        fruits.pop(0)
        print(fruits)

実行例:

['apple', 'lemon']
['apple', 'super banana', 'lemon']
['apple', 'super banana', 'ultra lemons!!']
['super banana']
続行するには何かキーを押してください . . .

※randint関数を使用してますので毎回実行結果は変わります


こんなうんこみたいな記事ですが何かモチベにでも繋がれば幸いです

そんじゃさよなら