神经网络---用python实现异或运算详细解释

11 篇文章 5 订阅
10 篇文章 2 订阅

摘要:本文主要介绍神经网络中如何用python实现异或运算,有代码以及对代码相关函数功能的详细解释;以及其过程的详细说明;比较适合刚刚入门的学习者。

1.代码运行效果图

在这里插入图片描述

2.整个程序的完整代码

import numpy as np

def sigmoid(z):#定义sigmoid激活函数
    return 1/(1+np.exp(-z))

def initialize_parameters(n_x,n_h,n_y):#初始化参数(权重和偏置)
    W1=np.random.randn(n_h,n_x)#返回对应维度的数组
    b1=np.zeros((n_h,1))#(2,1)
    #print(b1)
    W2=np.random.randn(n_y,n_h)
    b2=np.zeros((n_y,1))
    #print(b2)
    parameters={"W1":W1,"b1":b1,"W2":W2,"b2":b2}
    return parameters

def forward_prop(X,parameters):#前向传播
    W1=parameters["W1"]
    b1=parameters["b1"]
    W2=parameters["W2"]
    b2=parameters["b2"]
    Z1=np.dot(W1,X)+b1#(2,1)
    #print(Z1)
    A1=np.tanh(Z1)#双曲正切函数(tanh)
    Z2=np.dot(W2,A1)+b2#(1,1)
    #print(Z2)
    A2=sigmoid(Z2)

    cache={"A1":A1,"A2":A2}
    return A2,cache

def calculate_cost(A2,Y):#计算损失函数
    cost=-np.sum(np.multiply(Y,np.log(A2))+np.multiply(1-Y,np.log(1-A2)))/m#实现两矩阵对应元素相乘,所有元素之和
    #print(cost)
    cost=np.squeeze(cost)#从数组的形状中删除单维条目,即把shape中为1的维度去掉
    return cost


def backward_prop(X,Y,cache,parameters):#反向传播(计算梯度)
    A1=cache["A1"]
    A2=cache["A2"]
    W2=parameters["W2"]
    dZ2=A2-Y#sigmoid激活函数的导数格式 A=sigmod(Z2) 具体怎么来的看我CSDN博客 神经网络笔记二的2.2和6.1节
    dW2=np.dot(dZ2,A1.T)/m
    db2=np.sum(dZ2,axis=1,keepdims=True)/m
    dZ1=np.multiply(np.dot(W2.T,dZ2),1-np.power(A1,2))
    dW1=np.dot(dZ1,X.T)/m
    db1=np.sum(dZ1,axis=1,keepdims=True)/m
    grads={"dW1":dW1,"db1":db1,"dW2":dW2,"db2":db2}
    return grads


def updata_parameters(parameters,grads,learning_rate):#使用梯度下降更新参数
    W1=parameters["W1"]
    b1=parameters["b1"]
    W2=parameters["W2"]
    b2=parameters["b2"]
    dW1=grads["dW1"]
    db1=grads["db1"]
    dW2=grads["dW2"]
    db2=grads["db2"]
    W1=W1-learning_rate*dW1
    b1=b1-learning_rate*db1
    W2=W2-learning_rate*dW2
    b2=b2-learning_rate*db2
    new_parameters={"W1":W1,"W2":W2,"b1":b1,"b2":b2}
    return new_parameters

#这个训练模型主要是通过足够的训练次数来更新参数
def model(X,Y,n_x,n_h,n_y,num_of_iters,learning_rate):#将上面的函数整合起来,成为训练函数整体
    parameters=initialize_parameters(n_x,n_h,n_y)
    for i in range(0,num_of_iters+1):
        a2,cache=forward_prop(X,parameters)
        cost=calculate_cost(a2,Y)
        grads=backward_prop(X,Y,cache,parameters)
        parameters=updata_parameters(parameters,grads,learning_rate)#使用梯度下降算法更新参数
        if(i%100==0):
            print('cost after iteration#{:d}:{:f}'.format(i,cost))
    return parameters

def predict(X, parameters):  # 利用训练完的模型进行预测
    a2, cache = forward_prop(X, parameters)
    yhat = a2
    yhat = np.squeeze(yhat)
    #print(a2,yhat)
    if (yhat >= 0.5):
        y_predict = 1
    else:
        y_predict = 0
    return y_predict

#0.011831
if __name__ == '__main__':
    # 主程序
    np.random.seed(2)
    X = np.array([[0, 0, 1, 1], [0, 1, 0, 1]])
    print(X)
    Y = np.array([[0, 1, 1, 0]])
    m = X.shape[1]  #训练样本数,m为矩阵X的列数,m=4
    n_x = 2
    n_h = 2
    n_y = 1
    num_of_iters = 1000
    learning_rate = 5.93
    # 训练模型
    trained_parameters = model(X, Y, n_x, n_h, n_y, num_of_iters, learning_rate)
    print(trained_parameters)
    # 测试数据
    X_test = np.array([[0], [1]])
    y_predict = predict(X_test, trained_parameters)
    print('NN for example({:d},{:d}) is {:d}'.format(X_test[0][0], X_test[1][0], y_predict))


3.理解程序辅助代码

与上述程序相关的python函数知识整理的代码,读懂程序辅助代码

from numpy.random import rand
import numpy as np

import matplotlib.pyplot as plt

"""seed()函数知识点,随机数生成器 原来每次运行代码时设置相同的seed,
则每次生成的随机数也相同,如果不设置seed,则每次生成的随机数都会不一样。"""
def seed_():
    # 第一次不使用seed()
    a = rand(5)
    print("第一次不使用seed():", a)
    print("=======================================================================")
    # 第二次不使用seed()
    a = rand(5)
    print("第二次不使用seed():", a)
    print("=======================================================================")
    # 第一次使用seed()
    np.random.seed(2)
    a = rand(5)
    print("第一次使用seed():", a)
    print("=======================================================================")
    # 第二次使用seed()
    np.random.seed(2)
    a = rand(5)
    print("第二次使用seed():", a)
    print("=======================================================================")

"""NumPy 是一个 Python 的第三方库,代表 “Numeric Python”,主要用于数学/科学计算;
它是一个由多维数组对象和用于处理数组的例程集合组成的库。
    使用 Numpy 我们可以轻松进行如下等计算:
    1.数组的算数和逻辑运算。
    2.傅立叶变换和用于图形操作的例程。
    3.与线性代数有关的操作。 NumPy 拥有线性代数和随机数生成的内置函数。
"""
def numpy_():
    list = [1, 2, 3, 4]
    oneArray = np.array(list)

    print(list)  # [1, 2, 3, 4]  这是python的列表对象
    print(oneArray)  # [1 2 3 4]     这是一个一维数组

    twoArray = np.array([[1, 2], [3, 4], [5, 6]])

    print(twoArray)  # [[1 2] [3 4] [5 6]]  这是一个二维数组
    print(twoArray.ndim)

    X = np.array([[0, 0, 1, 1], [0, 1, 0, 1]])
    print(X)
    m = X.shape[1]
    print(m)

"""
矩阵(ndarray)的shape属性可以获取矩阵的形状(例如二维数组的行列),获取的结果是一个元组
"""
def shap_():
    x = np.array([[1, 2, 5], [2, 3, 5], [3, 4, 5], [2, 3, 6]])
    print(x)
    # 输出数组的行和列数
    print(x.shape)  # 结果: (4, 3)
    # 只输出行数
    print(x.shape[0])  # 结果: 4
    # 只输出列数
    print(x.shape[1])  # 结果: 3

"""np.random.randn()函数:通过本函数可以返回一个或一组服从标准正态分布的随机样本值。
    语法:
    np.random.randn(d0,d1,d2……dn)
    1)当函数括号内没有参数时,则返回一个浮点数; 
    2)当函数括号内有一个参数时,则返回秩为1的数组,不能表示向量和矩阵; 
    3)当函数括号内有两个及以上参数时,则返回对应维度的数组,能表示向量或矩阵; 
    4)np.random.standard_normal()函数与np.random.randn()类似,但是np.random.standard_normal()的输入参数为元组(tuple). 
    5)np.random.randn()的输入通常为整数,但是如果为浮点数,则会自动直接截断转换为整数。
    
    标准正态分布是以0为均数、以1为标准差的正态分布,记为N(0,1)。对应的正态分布曲线如下所示:
    
    在神经网络构建中,权重参数W通常采用该函数进行初始化,当然需要注意的是,
    通常会在生成的矩阵后面乘以小数,比如0.01,目的是为了提高梯度下降算法的收敛速度。 
    W = np.random.randn(2,2)*0.01
"""
def randn_():
    a = np.random.randn(1)
    print(a)

    b = np.random.randn(3,3)
    print(b)

"""返回来一个给定形状和类型的用0填充的数组;
    zeros(shape, dtype=float, order=‘C’)
    shape:形状
    dtype:数据类型,可选参数,默认numpy.float64
    order:可选参数,c代表与c语言类似,行优先;F代表列优先
"""
def zeros_():
    print(np.zeros((2, 5)))
    print(np.zeros((2, 5), dtype=np.int))

"""dot()返回的是两个数组的点积(dot product)
    1.如果处理的是一维数组,则得到的是两数组的內积
    2.如果是二维数组(矩阵)之间的运算,则得到的是矩阵积(mastrix product)
"""
def dot_():
    #处理的是一维数组
    d = np.arange(0, 9)
    print(d)
    e = d[::-1]
    print(e)
    r = np.dot(d,e)
    print(r)
    print("==========================")
    #二维数组(矩阵)之间的运算
    a = np.arange(1, 5).reshape(2, 2)
    print(a)
    b = np.arange(5, 9).reshape(2, 2)
    print(b)
    print("==========================")
    r = np.dot(a, b)
    print(r)

"""
双曲正切函数(tanh) 用python 画一个tanh的图
linspace的第一个参数表示起始点,第二个参数表示终止点,第三个参数表示数列的个数。

双曲正切函数(tanh)与tf.sigmoid非常接近,且与后者具有类似的优缺点。
tf.sigmoid和tf.tanh的主要区别在于后者的值域为[-1.0,1.0]。
"""
def tanh_():
    x = np.linspace(-100, 100, 1000)
    y = np.tanh(x)

    plt.plot(x, y, label="label", color="red", linewidth=2)
    plt.xlabel("abscissa")
    plt.ylabel("ordinate")
    plt.title("tanh Example")
    plt.show()

"""
在Python中,实现对应元素相乘,有2种方式,一个是np.multiply(),
另外一个是*,这种方式要求两个个矩阵的的形状shape相同。见如下Python代码:"""
def multipy_():
    # 2-D array: 2 x 3
    a = np.array([[1, 2, 3], [4, 5, 6]])
    b = np.array([[7, 8, 9], [4, 7, 1]])
    print(a)
    print(b)
    # 对应元素相乘 element-wise product
    c = a * b
    print('element wise product: %s' % (c))

    # 对应元素相乘 element-wise product
    d = np.multiply(a, b)
    print('element wise product: %s' % (d))

"""numpy.squeeze(a,axis = None)
 1)a表示输入的数组;
 2)axis用于指定需要删除的维度,但是指定的维度必须为单维度,否则将会报错;
 3)axis的取值可为None 或 int 或 tuple of ints, 可选。若axis为空,则删除所有单维度的条目;
 4)返回值:数组
 5) 不会修改原数组;
 作用:从数组的形状中删除单维度条目,即把shape中为1的维度去掉
 
 场景:在机器学习和深度学习中,通常算法的结果是可以表示向量的数组(即包含两对或以上的方括号形式[[]]),
 (见后面的示例)。我们可以利用squeeze()函数将表示向量的数组转换为秩为1的数组,
 这样利用matplotlib库函数画图时,就可以正常的显示结果了。
 """
def squeeze_():
    #例一
    a = np.arange(10).reshape(1, 10)
    print(a)
    a = np.arange(10).reshape(1, 10)
    b = np.squeeze(a)
    print(b)
    print("==============================")
    #例二
    c = np.arange(10).reshape(1, 2, 5)
    print(c)
    d = np.squeeze(c)
    print(d)

"""
1.sum不传参的时候,是所有元素的总和。
2.sum()输入参数带有axis时,将按照指定axis进行对应求和
    这个axis的取值就是这个精确定位某个元素需要经过多少数组的长度
    如果一个数组精确到某个元素需要a[n0][n1][n2][...][n],则axis的取值就是n。
"""
def sum_():
    x = np.arange(9).reshape(3,3)
    print(x)
    print(np.sum(x))
    print("==================================")
    print(np.sum(x,axis=1))#在第一个轴展开方向上求和 行
    print(np.sum(x,axis=0)) #在第一个轴展开方向上求和 列
    print("==================================")
    a = np.array([[[1, 2, 3, 2], [1, 2, 3, 1], [2, 3, 4, 1]], [[1, 0, 2, 0], [2, 1, 2, 0], [2, 1, 1, 1]]])
    print(a)
    print("==================================")
    b = a.sum(axis=0)
    print(b)
    print("==================================")
    c = a.sum(axis=1)
    print(c)
    #print(a.sum(axis=(0,1)))
    print("==================================")
    d = a.sum(axis=2)
    print(d)


"""
any()方法是查看两矩阵是否有一个对应元素相等。
事实上,all()操作就是对两个矩阵的比对结果再做一次与运算,而any则是做一次或运算
"""
def sum_any():
    a = np.array([1,2,3])
    b = np.array([1,2,1])
    print(a==b)
    print((a==b).all())
    c = a.copy()
    print((a==c).all())
    print((a==b).any())
    d = np.array([0,0,0])
    print((a==d).any())

if __name__ == '__main__':
    #seed_()
    #numpy_()
    #shap_()
    #randn_()
    #zeros_()
    #dot_()
    #tanh_()
    multipy_()
    #squeeze_()
    #sum_()
    #sum_any()

"""
选择学习率的初始值只是问题的一部分。另一个需要优化的是学习计划(learning schedule):
如何在训练过程中改变学习率。传统的观点是,随着时间推移学习率要越来越低,
而且有许多方法进行设置:例如损失函数停止改善时逐步进行学习率退火、指数学习率衰退、余弦退火等。

只在训练之前选择一次学习率是不够的。训练过程中,最优学习率会随着时间推移而下降。
你可以定期重新运行相同的学习率搜索程序,以便在训练的稍后时间查找学习率。

学习率 learning_rate:表示了每次参数更新的幅度大小。
如果学习率过大,会导致待优化的参数在最小值附近波动,不收敛;
学习率过小,会导致待优化的参数收敛缓慢。
"""

"""
这里包含11个Python神经网络编程的一些函数必备知识;
可以帮助读者很快地看懂Python代码:
至于一些重要原理的话,我会写在其他的文章中;
"""

"""
python国内镜像
https://pypi.python.org/simple 国外
http://pypi.douban.com/simple/ 豆瓣
http://mirrors.aliyun.com/pypi/simple/ 阿里
http://pypi.hustunique.com/simple/ 华中理工大学
http://pypi.sdutlinux.org/simple/ 山东理工大学
http://pypi.mirrors.ustc.edu.cn/simple/ 中国科学技术大学
https://pypi.tuna.tsinghua.edu.cn/simple 清华
"""

4.过程的详细说明,理解原理辅助图片说明(手写)

在这里插入图片描述

5.全文总结

相信看完我前面五个笔记(下面有链接)后,再看这个程序,应该是可以看懂的;这里还有写知识没写上。后期可能补上,本人也是小白一个,如果你是大佬请勿喷。

6.往期文章推荐

神经网络与深度学习笔记(一)适合刚入门的小白
神经网络与深度学习笔记(二)神经网络基础
神经网络与深度学习笔记 (三)python和向量化
神经网络与深度学习笔记 (四)浅层神经网络
神经网络与深度学习笔记 (五)深层神经网络

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

yue200403

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值