
单层感知机可以表示的数据是能够被一个超平面线性可分的单层感知机本质上就是一个“带可调阈值的二值分类器”其输入到输出的关系就是阶跃函数。阶跃函数、sigmoid函数、ReLU函数都是非线性函数多层神经网络的激活函数输出层除外一定是非线性的否则没和单层神经网络是一样就没意义了添加了权重为b的输入信号1。这个感知机将x1、x2、1三个信号作为神经元的输入将其和各自的权重相乘后传送至下一个神经元。输入信号的总和会被函数h(x)转换转换后的值就是输出y。刚才登场的hx函数会将输入信号的总和转换为输出信号这种函数 一般称为激活函数activation function。如“激活”一词所示激活函数的 作用在于决定如何来激活输入信号的总和。以阈值为界的激活函数一旦输入超过阈值就切换输出。这样的函数称为“阶跃函数”。如果感知机使用其他函数作为激活函数的话会怎么样呢实际上如果将激活函数从阶跃函数换成其他函数就可以进入神经网络的世界了。阶跃函数实现import numpy as np import matplotlib.pyplot as plt # def step_function(x): # 无法处理np数组 # if x 0: # return 1 # else: # return 0 def step_function(x): # 二者兼容处理 返回值是整型元素 print(x.dtype) y x 0 # 布尔类型 # return y.astype(np.int) return y * 1 # 布尔类型会自动变成整形 # a step_function(np.array([-1, 0, 3])) # print(a) # print(type(a)) x np.arange(-5, 5 0.01, 0.01) y step_function(x) plt.plot(x, y) plt.ylim(-0.1,1.1) plt.show()sigmoid函数实现import numpy as np import matplotlib.pyplot as plt def sigmoid_function(x): # 由于广播的特性所以也能兼容np数组 return 1/(1np.exp(-x)) x np.arange(-5, 5 0.01, 0.01) y sigmoid_function(x) plt.plot(x, y) plt.ylim(-0.1,1.1) plt.show()“平滑性”的不同。sigmoid函数是一条平滑的曲线输出随着输入发生连续性的变化。而阶跃函数以0为界输出发生急剧性的变化。sigmoid函数的平滑性对神经网络的学习具有重要意义。感知机中神经元之间流动的是0或1的二元信号而神经网络中流动的是连续 的实数值信号。阶跃函数和sigmoid函数虽然在平滑性上有差异但是如果从宏观视角看可以发现它们具有相似的形状。实际上两者的结构均是“输入小时输出接近0为0随着输入增大输出向1靠近变成1”。也就是说当输入信号为重要信息时阶跃函数和sigmoid函数都会输出较大的值当输入信号为不重要的信息时两者都输出较小的值。还有一个共同点是不管输入信号有多小或者有多大输出信号的值都在0到1之间。阶跃函数和sigmoid函数还有其他共同点就是两者均为非线性函数。sigmoid函数是一条曲线阶跃函数是一条像阶梯一样的折线两者都属于非线性的函数。ReLU函数实现import numpy as np import matplotlib.pyplot as plt def relu_function(x): # return np.maximum(0,x) # 只能处理np数组 y x 0 return x * y x np.arange(-5, 5 0.01, 0.01) y relu_function(x) plt.plot(x, y) plt.show()多维数组的维度和形状 import numpy as np Anp.array([1,2,3]) np.ndim(A) 1 Bnp.array([[1,2,3],[4,5,6]]) np.ndim(B) 2 Cnp.array([[[1]]]) np.ndim(C) 3 A.shape (3,) B.shape (2, 3) C.shape (1, 1, 1)ndim维度数量就是shape元组的元素个数2×3的数组B。2×3的数组表示第一个维度有2个元素 第二个维度有3个元素。另外第一个维度对应第0维第二个维度对应第 1维Python的索引从0开始二维数组也称为矩阵matrix。 数组的横向排列称为行row纵向排列称为列column。矩阵的乘积是通过左边矩阵的行横向和右边矩阵的列纵向以对应元素的方式相乘后再求和而得到的。并且运算的结果保存为新的多维数组的元素。矩阵乘法 Anp.array([[1,2],[3,4]]) Bnp.array([[5,6],[7,8]]) A*B array([[ 5, 12], [21, 32]]) B*A array([[ 5, 12], [21, 32]]) np.dot(A,B) array([[19, 22], [43, 50]]) np.dot(B,A) array([[23, 34], [31, 46]])A和B都是2×2的矩阵它们的乘积可以通过NumPy的np.dot()函数计算乘积也称为点积。np.dot()接收两个NumPy数组作为参数并返回数组的乘积。这里要注意的是np.dot(A, B)和np.dot(B, A)的值可能不一样。和一般的运算或*等不同矩阵的乘积运算中操作数A、B的顺序不同结果也会不同。shape:(3x2)x(2x3)(3x3)首尾相连内标消去前行后列坐等结果。AXB计算时A的第一维和B的第0维的元素个数必须相等才能计算神经网络的内积内积的物理意义它衡量了一个向量在另一个向量方向上的投影长度与另一个向量长度的乘积。a · b x₁·x₂ y₁·y₂ |a| × |b| × cosθ输入层有2个神经元输出层有3个神经元 Xnp.array([[1,2]]) # 1、2分别是输入的x1、x2的值 Wnp.array([[3,4,5],[6,7,8]]) # 3、6分别是对应的权重w1、w2 np.dot(X,W) array([15, 18, 21]) # 15就是计算得出的y1 Xnp.array([[1,2],[10,20]]) # 多组输入 np.dot(X,W) array([[ 15, 18, 21], [150, 180, 210]]) # 多组输出使用np.dot多维数组的点积面对多个神经元输入层和多个神经元的输出层的多组输入也可以一次性计算出Y多组输出的结果。如果不使用np.dot就必须多次单独计算Y的每一个元素或者说必须使用for语句非常麻烦。因此通过矩阵的乘积一次性完成计算的技巧在实现的层面上可以说是非常重要的。3层神经网络从输入到输出的前向处理的实现3层神经网络输入层第0层有 2个神经元第1个隐藏层第1层有 3个神经元第2个隐藏层第2层有 2个神经元输出层第3层有 2个神经元import numpy as np def sigmoid_function(x): # 由于广播的特性所以也能兼容np数组 return 1 / (1 np.exp(-x)) def identity_function(x): return x def init_network(): network {} # W的行数等于该层输入神经元的数量列数等于该层输出神经元的数量 network[W1] np.array([[0.1, 0.3, 0.5], [0.2, 0.4, 0.6]]) network[W2] np.array([[0.1, 0.4], [0.2, 0.5], [0.3, 0.6]]) network[W3] np.array([[0.1, 0.3], [0.2, 0.4]]) network[B1] np.array([0.1, 0.2, 0.3]) network[B2] np.array([0.1, 0.2]) network[B3] np.array([0.1, 0.2]) # B的元素数量等于该层输出神经元的数量 return network def forward(network, X): W1, W2, W3 network[W1], network[W2], network[W3] B1, B2, B3 network[B1], network[B2], network[B3] A1 sigmoid_function(np.dot(X, W1) B1) print(A1) A2 sigmoid_function(np.dot(A1, W2) B2) print(A2) Y A3 identity_function(np.dot(A2, W3) B3) print(A3) # A的每一行表示该层一组数据输出所以列数等于该层输出神经元的数量行数等于输入层输入了多少组数据 # 输出层的激活函数可能和隐藏层的不一样 return Y X np.array([[1.0, 0.5], [3.0, 4.0], [5.0, 6.0]]) # X的列数等于输入层的神经元的个数行数数表示输入了多少组数据 network init_network() Y forward(network, X) print(Y)init_network()函数会进行权重和偏置的初始化并将它们保存在字典变量network中。这个字典变量network中保存了每一层所需的参数权重和偏置。forward()函数中则封装了将输入信号转换为输出信号的处理过程。了forward前向一词它表示的是从输入到输出方向的传递处理。后面在进行神经网络的训练时我们将介绍后向backward从输出到输入方向的处理。机器学习的问题大致可以分为分类问题和回归问题。分类问题是数据属于哪一个类别的问题。比如区分图像中的人是男性还是女性的问题就是分类问题。而回归问题是根据某个输入预测一个连续的数值的问题。比如根据一个人的图像预测这个人的体重的问题就是回归问题类似“57.4kg”这样的预测神经网络可以用在分类问题和回归问题上不过需要根据情况改变输出层的激活函数。一般而言回归问题用恒等函数分类问题用softmax函数。softmax函数def softmax(X): Cnp.max(X,axis-1,keepdimsFalse) # axis表示沿着哪个维度对其他维度进行操作这里-1表示沿着倒数第一个维度列对其他维度行的数据进行操作取最大值导致其他维度最终缩减 # keepdims表示被操作的维度是否被删除这里选择保留被操作维度的空壳确保后续广播运算 print(C) exp_xnp.exp(X-C) # 防止溢出 sum_expnp.sum(exp_x,axis-1,keepdimsTrue) return exp_x/sum_expsoftmax函数的输出是0.0到1.0之间的实数。并且softmax函数的输出值的总和是1。输出总和为1是softmax函数的一个重要性质。正因为有了这个性质我们才可以把softmax函数的输出解释为“概率”即便使用了softmax函数各个元素之间的大小关系也不会改变。这是因为指数函数yexp(x)是单调递增函数。一般而言神经网络只把输出值最大的神经元所对应的类别作为识别结果。并且即便使用softmax函数输出值最大的神经元的位置也不会变。因此神经网络在进行分类时输出层的softmax函数可以省略。求解机器学习问题的步骤可以分为“学习”和“推理”两个阶段。首先在学习阶段进行模型的学习然后在推理阶段用学到的模型对未知的数据进行推理分类。如前所述推理阶段一般会省略输出层的softmax函数。在输出层使用softmax函数是因为它和神经网络的学习有关系。输出层的神经元数量需要根据待解决的问题来决定。对于分类问题输出层的神经元数量一般设定为类别的数量。Python有pickle这个便利的功能。这个功能可以将程序运行中的对象保存为文件。如果加载保存过的pickle文件可以立刻复原之前程序运行中的对象。用于读入MNIST数据集的load_mnist()函数内部也使用了pickle功能在第2次及以后读入时。利用pickle功能可以高效地完成MNIST数据的准备工作。MNIST数据集import sys,os import numpy as np from mnist import load_mnist from PIL import Image def img_show(img): pil_imgImage.fromarray(np.uint8(img)) pil_img.show() # 通过py数组展示图像 (train_img, train_label), (test_img, test_label) load_mnist(False,True,False) print(train_img.shape) print(train_label.shape) print(test_img.shape) print(test_label.shape) imgtrain_img[0] labeltrain_label[0] print(img.shape) print(label) imgimg.reshape(28,28) print(img.shape) img_show(img)神经网络的推理处理import pickle import numpy as np from mnist import load_mnist def sigmoid_function(x): # 由于广播的特性所以也能兼容np数组 return 1 / (1 np.exp(-x)) def softmax(X): C np.max(X, axis-1, keepdimsFalse) # axis表示沿着哪个维度对其他维度进行操作这里-1表示沿着倒数第一个维度列对其他维度行的数据进行操作取最大值导致其他维度最终缩减 # keepdims表示被操作的维度是否被删除这里选择保留被操作维度的空壳确保后续广播运算 exp_x np.exp(X - C) # 防止溢出 sum_exp np.sum(exp_x, axis-1, keepdimsTrue) return exp_x / sum_exp def get_test_data(): (train_img, train_label), (test_img, test_label) load_mnist(True, True, False) return test_img, test_label def init_network(): with open(../DeepLearningFromScratch-master/DeepLearningFromScratch-master/ch03/sample_weight.pkl, rb) as f: network pickle.load(f) return network def predict(network, x): W1, W2, W3 network[W1], network[W2], network[W3] b1, b2, b3 network[b1], network[b2], network[b3] a1 sigmoid_function(np.dot(x, W1) b1) a2 sigmoid_function(np.dot(a1, W2) b2) a3 sigmoid_function(np.dot(a2, W3) b3) y softmax(a3) return y test_img, test_label get_test_data() network init_network() accuracy 0 for i in range(len(test_img)): # len返回的是元素个数对应np数组来说就是第0维度的元素个数 y predict(network, test_img[i]) p np.argmax(y) if p test_label[i]: accuracy 1 print(accuracy) print(len(test_img)) print(accuracy / len(test_img))在这个例子中我们把load_mnist函数的参数normalize设置成了True。将normalize设置成True后函数内部会进行转换将图像的各个像素值除以255使得数据的值在0.01.0的范围内。像这样把数据限定到某个范围内的处理称为正规化normalization。此外对神经网络的输入数据进行某种既定的转换称为预处理pre-processing。这里作为对输入图像的一种预处理我们进行了正规化。很多预处理都会考虑到数据的整体分布。比如利用数据整体的均值或标准差移动数据使数据整体以0为中心分布或者进行正规化把数据的延展控制在一定范围内。除此之外还有将数据整体的分布形状均匀化的方法即数据白化whitening等。看下单个输入时神经网络各层权重的shapedef predict(network, x): W1, W2, W3 network[W1], network[W2], network[W3] b1, b2, b3 network[b1], network[b2], network[b3] a1 sigmoid_function(np.dot(x, W1) b1) a2 sigmoid_function(np.dot(a1, W2) b2) a3 sigmoid_function(np.dot(a2, W3) b3) y softmax(a3) print(x.shape) print(W1.shape) print(W2.shape) print(W3.shape) return y test_img, test_label get_test_data() network init_network() y predict(network, test_img[0])D:\Python\python.exe C:\Users\w30070889\Desktop\python学习\demo\test.py (784,) (784, 50) (50, 100) (100, 10) 进程已结束退出代码为 0点积(1,784)(784,50)(50,100)(100,10)得到最终的结果是(1,10)批处理就是一次性输入一批数据多组数据一次性得到一批结果(n,784)(784,50)(50,100)(100,10)得到最终的结果是(n,10)输入层数据组数等于输出的数据组数输出层的神经元数量等于需要分类的类别批处理import pickle import numpy as np from mnist import load_mnist def sigmoid_function(x): # 由于广播的特性所以也能兼容np数组 return 1 / (1 np.exp(-x)) def softmax(X): C np.max(X, axis-1, keepdimsFalse) # axis表示沿着哪个维度对其他维度进行操作这里-1表示沿着倒数第一个维度列对其他维度行的数据进行操作取最大值导致其他维度最终缩减 # keepdims表示被操作的维度是否被删除这里选择保留被操作维度的空壳确保后续广播运算 # exp_x np.exp(X - C) # 防止溢出 exp_x np.exp(X / 255) # 防止溢出两个都是正规化不影响最后的推理精度 sum_exp np.sum(exp_x, axis-1, keepdimsTrue) return exp_x / sum_exp def get_test_data(): (train_img, train_label), (test_img, test_label) load_mnist(True, True, False) return test_img, test_label def init_network(): with open(../DeepLearningFromScratch-master/DeepLearningFromScratch-master/ch03/sample_weight.pkl, rb) as f: network pickle.load(f) return network def predict(network, x): W1, W2, W3 network[W1], network[W2], network[W3] b1, b2, b3 network[b1], network[b2], network[b3] a1 sigmoid_function(np.dot(x, W1) b1) a2 sigmoid_function(np.dot(a1, W2) b2) a3 sigmoid_function(np.dot(a2, W3) b3) y softmax(a3) print(x.shape) print(W1.shape) print(W2.shape) print(W3.shape) return y test_img, test_label get_test_data() network init_network() # accuracy 0 # for i in range(len(test_img)): # len返回的是元素个数对应np数组来说就是第0维度的元素个数 # y predict(network, test_img[i]) # p np.argmax(y) # if p test_label[i]: # accuracy 1 # print(accuracy) # print(len(test_img)) # print(accuracy / len(test_img)) X test_img # shape已经被处理好程二维的了 Y predict(network, X) P np.argmax(Y, axis-1, keepdimsFalse) # 取Y中沿着-1就是最后一维就是第一维就是列方向计算其他维按行计算就是每次固定axis指定的维度去计算其他维度表示的元素 print(P) accuracy P test_label print(accuracy) correct_count np.sum(accuracy) # True 被视为 1False 被视为 0 print(correct_count) print(correct_count / len(test_label)) # 准确率 # for i in range(0, len(x), batch_size): # x_batch x[i:i batch_size] # y_batch predict(network, x_batch) # 这样可以控制每批处理的数据组数• 神经网络中的激活函数使用平滑变化的sigmoid函数或ReLU函数。• 通过巧妙地使用NumPy多维数组可以高效地实现神经网络。• 机器学习的问题大体上可以分为回归问题和分类问题。• 关于输出层的激活函数回归问题中一般用恒等函数分类问题中一般用softmax函数。• 分类问题中输出层的神经元的数量设置为要分类的类别数。• 输入数据的集合称为批。通过以批为单位进行推理处理能够实现高速的运算。