前言
本文是接着上一文多層感知機所寫的。上一文說的瞭如何初始化一個MLP。本文簡單介紹一下前向傳播的概念以及代碼實現。
上文:http://blog.csdn.net/skullfang/article/details/78609851
回顧
還是從一個簡單的多層感知器入手,這個感知器只有兩層(輸入層不算)。輸入層——隱藏層——輸出層
模型:
其中w是 權重。b 是偏置。(注意隱藏層和輸出層中w和b各不相同)
前向傳播
每個神經元有兩部分組成一部分是根據權重w和偏置b計算出值z。通過激勵函數sigmoid刺激之後產生一個輸出y。而這個y就是下一層的輸入,然後下一層又產生一個輸出作爲下下一層的輸入,一直到最後一層。
由模型可以看出隱藏層的輸出yh就是輸出層的輸入。
每一層的輸出 作爲 下一層的輸入。從而一層一層的傳播下去就叫做前向傳播。
同樣有個概念叫反向傳播(更新)。就是我們輸出層產生輸出之後yo要與y的真實值進行比較學習之後。反向一層一層的更新w和b。詳細的緊接着一篇博文會說到。
回到前向傳播
概念很簡單
直接就看代碼部分了。
# -*- coding: utf-8 -*-
# @Time : 2017/11/23 上午10:21
# @Author : SkullFang
# @Email : [email protected]
# @File : TwoDemo.py
# @Software: PyCharm
import numpy as np
class Network(object):
def __init__(self,sizes):
"""
sizes表示 網絡的結構
:param sizes:
"""
#網絡層數
self.num_layers=len(sizes) #層數
#神經元的個數
self.sizes=sizes
#初始化每一層的偏置 z=wx+b 就是b的值
self.baises=[np.random.randn(y,1) for y in sizes[1:]]
#等同與
"""
baises=[]
#意思就是生成一個符合正態分佈的 y*1的數組
for y in sizes[1:]:
biases.append(np.random.randn(y, 1))
結果
[array([[ 1.05154644],
[-0.02986238]]), array([[-0.88098138]])]
"""
#初始化權重W
self.weights=[np.random.randn(y,x) for x,y in zip(sizes[:-1],sizes[1:])]
"""
產生一個y*x 符合正態的
weights=[]
for x,y in zip(sizes[:-1],sizes[1:]):
weights.appenf(np.random.randn(y,x))
pass
>>> weights
[array([[-0.22826557, -0.54427902, 0.19502928],
[ 0.21433594, 0.72849057, 0.12851307]]), array([[ 0.27181857, -0.55032853]])]
"""
#梯度下降
def GD(self,training_data,epochs):
"""
這個是梯度下降
:param training_data: 訓練數據
:param epochs: 訓練次數
:return:
"""
for j in xrange(epochs):
#洗牌 就是打亂訓練數據
random.shuffle(training_data)
#訓練每一個數據
for x,y in training_data:
self.update(x,y)
print "Epoch {0} complete".format(j)
#前向傳播
def update(self,x,y):
"""
:param x:
:param y:
:return:
"""
# 保存每一層的偏導
nabla_b = [np.zeros(b.shape) for b in self.baises]
nabla_w = [np.zeros(b.shape) for b in self.weights]
#保存輸入數據
#第一層的activation
activation=x
#保存每一層的激勵值a=sigmoid(z)
activations=[x]
#zs保存每一層的z=wx+b
zs=[]
#要做前向傳播
for b,w in zip(self.baises,self.weights):
#計算每一層的z,
# 這裏的activation就是上一層的輸出。
# 從而達到傳播的效果
z=np.dot(w,activation)+b
#保存每一層的z
zs.append(z)
#計算每一層的a(其實就是y)
activation=sigmoid(z)
#保存每一層的a
#做個記錄反向傳播有用
activations.append(activation)
#sigmoid
def sigmoid(z):
"""
激活函數
:param z:
:return:
sigmoid(z)=1/(1+e^-z)
"""
return 1.0/(1.0+np.exp(-z))