Python手动搭建神经网络

神经网络

神经网络算法其实大体分为前向传播和反向传播两个部分,前向传播用于计算当前各参数(权重)下的预测值与实际值的误差(损失函数)。反向传播用于计算各参数的下降梯度,同时用这些梯度更新各参数值。这样反反复复训练直到最终损失函数收敛即不再下降。这里使用numpy库来手动搭建简单的单隐藏层神经网络。

参数调试

在这次验证码识别网络中,主要的参数有learning_rate,batch_size,iter_num 。当然对于隐藏层数和隐藏层单元数,这里仅仅是用于做简单识别,并不作很高的要求。就采用了单隐藏层,500单元数(略大于输入单元数486)作为神经网络的主要结构。输出单元为36个,对应26个字母和10个数字。

Learning_rate

learning_rate 控制各参数下降速度。当最终的cost不断上升下降或者上升时,learning_rate 过大,函数不能收敛,需要调小learning_rate。而当cost下降过慢,或者说下降幅度过小时,就需要适当提升learning_rate来提升训练速度(如果主机计算能力足够则可以忽略啦)。

Batch_size

对 batch_size,实际就是每次迭代中输入多少的数据,同样由于计算量原因可以适量减小batch_size。但当它过小,比如为1时,就成了随机梯度下降,有可能只能达到最终收敛点附近却不能达到最好。在这个网络中,我之前选用了1000大小的batch_size,但是最后预测效果不好。于是改为100大小,分批多次训练。不但降低了发生memory error的可能性,同时得到了性能的提升。

Iter_num

Iter_num其实就是某批训练数据的迭代次数,这个大小可以通过观察某批训练集每次迭代后cost下降情况来决定。比如说在第10代左右cost就不再明显下降的话,10可能就是一个可用的迭代数。如果这个值过大的话,当然会造成计算资源和时间的浪费,因为函数收敛后再优化已经没有多大意义了。过小呢则有可能出现尚未收敛,训练集没有充分使用上的情况。在确定上面两个参数后再确定这个参数也许可行。

各模块搭建

Y标签转one-hot码

神经网络的最终学习是要分出36类,而现有的标签值表示的是某类的index,所以需要将Y标签转为one-hot码来进行训练。举例来说,如果我只要分出4类,而某一个样本的真实值是第三类那么y=3。但是y=3需要转成[0,0,1,0]这一个数组来表示,下面是转码函数(输入数值y,返回one-hot数组)。

def tran_y(y):
    y_ohe=np.zeros(36)
    y_ohe[y]=1
    return y_ohe

激活函数sigmoid

神经网络是离不开激活函数的,如果没有了非线性激活函数,那么神经网络只是单一的线性变换,就像W*X+b一样。这里给出的sigmoid只是激活函数中的一种,另外还有tanh,softmax,relu等等。注意激活函数的编写需要满足向量化的要求,也就是说对与输入的数组激活函数同样适用。下面是sigmoid函数。

def sigmoid(x):
    s=1/(1+np.exp(-x))
    return s

初始化参数

这里初始化的参数包括隐藏层的W1,b1和输出层的W2,b2。需要注意的是参数W的维度是本层单元数*前层单元数,参数b是本层单元数*1。为什么是这个尺度可以根据A1=W*A0+b来理解。A0是前一层输入,A1是这一层输出,各个参数维度需要满足矩阵相乘的条件。这里的n_x,n_h,n_y分别代表输入,隐藏层和输出层的单元数大小。W参数使用随机初始化,并用0.01缩小尺度,b参数则可以0-1随意,这里用的是0.01。

def initialize_parameters(n_x,n_h,n_y):
    W1=np.random.randn(n_h,n_x)*0.01
    b1=np.ones(shape=(n_h,1))*0.01
    W2=np.random.randn(n_y,n_h)*0.01
    b2=np.ones(shape=(n_y,1))*0.01
    parameters={"W1":W1,"b1":b1,"W2":W2,"b2":b2}
    return parameters

前向传播

前向传播就是一个将样本通过各层网络,并计算各层输出和最终输出的过程。计算公式总的可以用上述的A1=W*A0+b来表示,不过在计算完每层输出后需要套上激活函数A1=sigmoid(A1)。由于里面的A,Z在后面的反向传播要用,所以同时返回了。

def forward_propagation(x,parameters):
    W1=parameters["W1"]
    b1=parameters["b1"]
    W2=parameters["W2"]
    b2=parameters["b2"]
    
    Z1=np.dot(W1,x)+b1
    A1=np.tanh(Z1)
    Z2=np.dot(W2,A1)+b2
    A2=sigmoid(Z2)
    cache={"Z1":Z1,"A1":A1,"Z2":Z2,"A2":A2}

    return A2,cache

误差计算

说是误差其实就是cost代价,用来表示当前预测值和实际值的偏差程度。具体为什么使用这个代价函数,一时不好讲清,我自己也不是懂。但用最小二乘是不行的好像,会陷入局部极小。

def compute_cost(A2,y,parameters):
    m=y.shape[1]
    W1 = parameters['W1']
    W2 = parameters['W2']
    cost=-1/m*np.sum(np.multiply(y,np.log(A2))+np.multiply((1-y),np.log(1-A2)))
    cost=np.squeeze(cost)
    return cost

反向传播

未完。。。明日更

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值