news 2026/8/29 5:57:24

鱼书学习--神经网络

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
鱼书学习--神经网络

单层感知机可以表示的数据,是能够被一个超平面线性可分的
单层感知机本质上就是一个“带可调阈值的二值分类器”,其输入到输出的关系就是阶跃函数。

阶跃函数、sigmoid函数、ReLU函数都是非线性函数
多层神经网络的激活函数(输出层除外)一定是非线性的,否则没和单层神经网络是一样,就没意义了

添加了权重为b的输入信号1。这个感知机将x1、x2、1三个信号作为神经元的输入,将其和各自的权重相乘后,传送至下一个神经元。输入信号的总和会被函数h(x)转换,转换后的值就是输出y。

刚才登场的h(x)函数会将输入信号的总和转换为输出信号,这种函数 一般称为激活函数(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/(1+np.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 >>> A=np.array([1,2,3]) >>> np.ndim(A) 1 >>> B=np.array([[1,2,3],[4,5,6]]) >>> np.ndim(B) 2 >>> C=np.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)。

矩阵的乘积是通过左边矩阵的行(横向)和右边矩阵的列(纵向)以对应元素的方式相乘后再求和而得到的。并且,运算的结果保存为新的多维数组的元素。

矩阵乘法:

>>> A=np.array([[1,2],[3,4]]) >>> B=np.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个神经元:

>>> X=np.array([[1,2]]) # 1、2分别是输入的x1、x2的值 >>> W=np.array([[3,4,5],[6,7,8]]) # 3、6分别是对应的权重w1、w2 >>> np.dot(X,W) array([15, 18, 21]) # 15就是计算得出的y1 >>> >>> X=np.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): C=np.max(X,axis=-1,keepdims=False) # axis表示沿着哪个维度对其他维度进行操作,这里-1表示沿着倒数第一个维度(列)对其他维度(行)的数据进行操作(取最大值),导致其他维度最终缩减 # keepdims表示被操作的维度是否被删除,这里选择保留被操作维度的空壳,确保后续广播运算 print(C) exp_x=np.exp(X-C) # 防止溢出 sum_exp=np.sum(exp_x,axis=-1,keepdims=True) return exp_x/sum_exp

softmax函数的输出是0.0到1.0之间的实数。并且,softmax函数的输出值的总和是1。输出总和为1是softmax函数的一个重要性质。正因为有了这个性质,我们才可以把softmax函数的输出解释为“概率”

即便使用了softmax函数,各个元素之间的大小关系也不会改变。这是因为指数函数(y=exp(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_img=Image.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) img=train_img[0] label=train_label[0] print(img.shape) print(label) img=img.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, keepdims=False) # axis表示沿着哪个维度对其他维度进行操作,这里-1表示沿着倒数第一个维度(列)对其他维度(行)的数据进行操作(取最大值),导致其他维度最终缩减 # keepdims表示被操作的维度是否被删除,这里选择保留被操作维度的空壳,确保后续广播运算 exp_x = np.exp(X - C) # 防止溢出 sum_exp = np.sum(exp_x, axis=-1, keepdims=True) 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.0~1.0的范围内。像这样把数据限定到某个范围内的处理称为正规化(normalization)。此外,对神经网络的输入数据进行某种既定的转换称为预处理(pre-processing)。这里,作为对输入图像的一种预处理,我们进行了正规化。

很多预处理都会考虑到数据的整体分布。比如,利用数据整体的均值或标准差,移动数据,使数据整体以0为中心分布,或者进行正规化,把数据的延展控制在一定范围内。除此之外,还有将数据整体的分布形状均匀化的方法,即数据白化(whitening)等。

看下单个输入时神经网络各层权重的shape

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() 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, keepdims=False) # axis表示沿着哪个维度对其他维度进行操作,这里-1表示沿着倒数第一个维度(列)对其他维度(行)的数据进行操作(取最大值),导致其他维度最终缩减 # keepdims表示被操作的维度是否被删除,这里选择保留被操作维度的空壳,确保后续广播运算 # exp_x = np.exp(X - C) # 防止溢出 exp_x = np.exp(X / 255) # 防止溢出,两个都是正规化,不影响最后的推理精度 sum_exp = np.sum(exp_x, axis=-1, keepdims=True) 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, keepdims=False) # 取Y中沿着-1(就是最后一维,就是第一维,就是列方向,计算其他维(按行计算,就是每次固定axis指定的维度,去计算其他维度表示的元素)) print(P) accuracy = P == test_label print(accuracy) correct_count = np.sum(accuracy) # True 被视为 1,False 被视为 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函数。
• 分类问题中,输出层的神经元的数量设置为要分类的类别数。
• 输入数据的集合称为批。通过以批为单位进行推理处理,能够实现
高速的运算。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/8/29 5:56:44

LLM智能与单任务成本:从预算失控到成本优化的实践指南

2024年底,我参与过一个给业务部门做 LLM Agent 方案的项目。团队当时定了一条很简单却代价很高的规则:所有任务一律用市面上能力最强的模型来跑。结果功能演示很顺利,一到真实业务量就卡住了——每天几千个任务,按 Token 一算&…

作者头像 李华
网站建设 2026/8/29 5:56:40

nccstf_string

老样子,下载,查壳,64位,IDA打开 f5查看伪代码 伪码分析: 一、整体流程 这个 main 函数只是一层输入输出外壳,本身不包含任何加密校验逻辑。所有核心的 flag 验证算法都封装在 flag() 函数里。 完整执行流程…

作者头像 李华
网站建设 2026/8/29 5:55:50

快手社招技术3面面经:系统设计与故障排查全复盘

上周HR通知我快手社招技术面全部通过时,我其实最想复盘的是第三轮。1面和2面各有侧重,但基本都在预料内——手写算法、基础八股、常规项目介绍。只有3面,整场给我的感觉是完全不同维度的:面试官几乎没有问我任何"标准答案&qu…

作者头像 李华
网站建设 2026/8/29 5:54:14

从零构建电商大数据分析平台:Spark与Flink实战架构与核心模块详解

简介:本资源是一个面向大数据开发工程师与电商数据分析师的Spark大型实战项目,聚焦电商用户行为分析场景,提供从离线画像构建、实时流量监控到推荐算法落地的一站式解决方案。资源共82个文件,含77个Java核心业务代码(覆…

作者头像 李华
网站建设 2026/8/29 5:52:34

携程2019秋招研发岗笔试复盘:题型拆解与踩坑记录

复盘携程2019届秋招研发岗笔试:题型拆解、考点复盘与踩坑记录如果你正在准备OTA行业的研发岗位,或者手里正好有一份携程往年的笔试题,那么这篇内容应该能帮你省下不少走弯路的时间。我当年参加的是携程2019届秋招研发方向的线上笔试&#xff…

作者头像 李华
网站建设 2026/8/29 5:52:26

C++笔试入门必刷题:从语法到实战的核心考点解析

C笔试入门,最怕的不是不会写,而是会写但没拿到分。很多刚入门的同学刷题时经常遇到这种情况:题目一看就懂,代码也能跑通,但一到笔试现场就处处碰壁。这份C入门级笔试题合集(一),就是…

作者头像 李华