神经网络实现-python

该图为本篇文章中出现的所有符号的参考,来源:周志华《机器学习》

神经网络的原理不再赘述,下面只讲按照公式怎么使用python实现。

首先考虑正向传播,就是算b和y结点的值。

对于权重的命名规则,如v_1h,表示从1指向h结点的线,w同理,注意,这两个权重位于不同层之间,由于使用矩阵乘法进行计算,需要先确定各个层的尺寸

d:输入层的结点数,q:隐藏层的结点数,l:输出层的结点数

对v:如x1->b1:v11,x1->b2:v12,也就是说,其大小为(d,q)

对w:类似上面的道理,大小为(q,l)

确定了各个层的尺寸后开始考虑如何计算:

输入层到隐藏层:

输入层的尺寸为(1,d),那么计算其结点的和则是,(1,d)与(d,q) ->(1,q),即可得到隐藏层的结点值,代码表示则是:

b=np.dot(x,v)

隐藏层到输出层:

类似的,w:(q,l),b:(1,q),因此(1,q)(q,l),则可得到(1,l),代码表示为:

y=np.dot(b,w)

至此,正向传播的计算结束,下面是反向传播,即更新权重。

书上的推导使用链式法则,计算预测的标签与目标标签的差值,将这个差值与各个权重求偏导得到权重更新的公式,这里不做推导,会先把公式列出,然后对公式进行矩阵乘法可能性的探讨。

首先是对于输出层->隐藏层而言的,一个用于计算的中间变量:

g_j = y^{'}_j (1-y^{'}_j)(y_j-y^{'}_j)

y_j表示数据的标签,y'_j表示预测的标签,从最开始的图推测,j的取值应该是[1,l],即对应输出层的各个结点。

此时对于标签y与预测的y'的结果的尺寸均为(1,l),要实现上面的式子暂时没有想到好的做法,因为你如果尝试转置一下的话就会得到(1,1),在摸索了一段时间后发现貌似python中的*法运算可以直接得到结果,因此代码实现为:

g = (self.y * (1 - self.y)) * (y - self.y)

接下来是对隐藏层->输入层而言的,同样是一个中间变量:

e_h = b_h(1-b_h)\sum_{j=1}^{l}w_{hj}g_j

前一部分就如上面的操作一样直接乘就可以了,那么后面的求和,先进行分析,对于w:(q,l),g:(1,l),各位可以在草稿纸上画一下就知道了,是可行的,最后的尺寸则是(1,q),代码表示为:

np.dot(g,w.T)

就是(1,l)(l,q),在草稿纸上试一下就发现就是上面求和式子中的表示,现在就得到了两个均为(1,q)的矩阵,接下来直接使用python的*即可,因此代码表示为:

e = (self.b * (1 - self.b)) * (np.dot(g,self.w.T))

计算完这两个中间变量之后就可以开始更新权重了,具体而言各个公式如下:

\Delta w_{hj}=\eta g_jb_h \\ \Delta \theta_j=-\eta g_j \\ \Delta v_{ih}=\eta e_hx_i\\ \Delta \gamma_h = -\eta e_h

其中\eta表示学习率,可以理解成速度,\gamma全文没出现过,我的猜测是隐藏层的阈值,其余字母的定义与上文提到的定义一致。

按照上面的式子一一讲述:

1.dw:w:(q,l), g:(1,l), b:(1,q) -> b.T dot g ,演算后正确,代码表示为:

dw = self.lr * np.dot(self.b.T,g)

2.dtheta:直接乘,略

3.dv: v:(d,q), e:(1,q), x:(1,d) -> x.T dot e,代码表示为:

dv = self.lr * np.dot(x.T,e)    

4.dgamma:直接乘,略

然后直接修改就可以了,然而在我兴致勃勃的将上面的实现尝试操作时,发现在运行之后的准确率只有3%,比盲猜还要低,我的数据是识别手写的字母,因此是1/26的概率,可以说还是比盲猜要低,具体原因不知道,代码如下所示,希望有大佬可以指点我:

import numpy as np
import random as rd 
import pandas as pd

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

class MP:

    def __init__(self):

        #nodes for each layer
        self.input_size = 100
        self.hide_size = 50
        self.output_size = 26

        #weight,v:in->hid, w:hid->out
        self.v = np.random.randn(self.input_size, self.hide_size)
        self.w = np.random.randn(self.hide_size, self.output_size)

        #bias
        self.theta_v = np.random.randn(1,self.hide_size)
        self.theta_w = np.random.randn(1,self.output_size)

        #learning rate
        self.lr = 0.1

    def predict(self,x):

        self.b = sigmoid(np.dot(x,self.v) - self.theta_v)
        self.y = sigmoid(np.dot(self.b,self.w) - self.theta_w)
  
    def train(self,x,y):

        #get b and y
        self.predict(x)
        y = np.array(y).reshape(1,self.output_size)
        #print the err of the epoch
        print(np.sum(y - self.y))

        #g,e
        g = (self.y * (1 - self.y)) * (y - self.y)
        e = (self.b * (1 - self.b)) * (np.dot(g,self.w.T))

        g = np.array(g).reshape(1,self.output_size)
        self.b = np.array(self.b).reshape(1,self.hide_size)
        e = np.array(e).reshape(1,self.hide_size)
        x = np.array(x).reshape(1,self.input_size)

        #update w and v
        dw = self.lr * np.dot(self.b.T,g)
        theta_w = -self.lr * g
        dv = self.lr * np.dot(x.T,e)     
        theta_v = -self.lr * e

        self.w += dw
        self.theta_w += theta_w
        self.v += dv
        self.theta_v += theta_v   

#读取数据
data = pd.read_csv("all_alphas.csv")
data = data[data.iloc[:, -1].isin(["A", "B", "C", "D", "E", "F", "G", "H", "I", "J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X", "Y", "Z"])]
y = data['label']
#将标签转换为one-hot编码
y = pd.get_dummies(y)
x = data.drop(['label'],axis=1)

model = MP()
for i in range(len(x)):
    model.train(x.iloc[i,:],y.iloc[i,:])

#查看准确率
count = 0
for i in range(len(x)):
    model.predict(x.iloc[i,:])
    if np.argmax(model.y) == np.argmax(y.iloc[i,:]):
        count += 1
print(count/len(x))

  • 20
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值