小白速通《深度学习入门:基于python的理论和实现》(1-3)

32 阅读13分钟

非计算机科班,有python基础知识,上学期上过机器学习课,吴恩达的机器学习看一半累了没看下去,但是进度不能拖了,打算速通这本书。时刻提醒我自己,不要完美学习,上来就一页一页的读,每一段代码不懂就详细做笔记,太累了,对类ADHD人群也不友好,本来定力就不够高,一旦新鲜劲过了就开始拖延了。 所以这本书的学习思路是,喂给AI,然后让AI做笔记。不懂的地方让AI总结,最大化减少能量的溢出,把主要精力放在框架的理解,项目的实现。这本书学完之后,做到手搓复现小项目的代码,然后对书中介绍的神经网络、反向传播等有一个大概思路(可以让AI出八股,用简答题的方式进行学习),形成MVP,就去做下一步——学pytorch了,要是觉得哪里有不明白的还可以到时候再回来看。 第一步:喂AI总结框架

第一章 python基础知识

第一章简单介绍python知识点,主要是对类的理解。定义类,装入参数,定义动作,最后就是创造实例。其中容易混乱的地方是:

def __init__(self, username): # 参数名改成username 
self.name = username # 右边跟着改成username,逻辑完全一样
m = Man("David")

self.name = username等号右边是 __init__(self, username) 里的参数名,作用是接收你创建实例时传入的字符串(David);

左边的 self.name

  • self 代表当前实例(也就是m),self.name 是给这个实例绑定一个属性,属性名叫name
  • 左边属性另外的用处是在类里面定义其他动作是可以用上比如:
 def hello(self): 
        print(f"Hello {self.name}!")
  • self.属性 = 参数:相当于传入的参数绑定到实例属性身上,方便之后其他动作调用这个属性

第二章 感知机

用提问的方式来学习基本知识

请简述感知机的定义、核心构成及工作原理,并用数学公式表示其输出逻辑。

  • 最简单的人工神经网络模型
  • 输入信号加权求和后,加上偏置,若结果超过阈值则输出 1,否则输出 0
  • 本质是接收多个输入信号、输出单个二进制信号(0/1)的线性分类算法 image.png 感知机可实现与门(x变量都为1y为1)、与非门(x变量都为0y为1)、或门(x变量有一个为1y就输出1)等简单逻辑电路,以及多层感知机实现的异或门

第三章 神经网络

prompt1:我想知道第三章,作者是怎么讲解的,是如何从上一章节的感知机过渡到神经网络的(通过这个提示词,再加上快速翻看,大概了解神经网络是个啥了)

1、先复习感知机,搭建过渡基础

作者先回顾感知机的核心机制:接收多输入信号,通过权重(控制输入重要性)和偏置(调整激活难度)计算加权和,再经阶跃函数判断是否输出 1(激活),数学表达式为:y={01​(b+∑i=1n​wi​xi​≤0)(b+∑i=1n​wi​xi​>0)​同时明确感知机的核心价值 —— 能实现与门、与非门、或门等简单逻辑电路,但关键局限是仅能处理线性可分问题,无法实现异或门(需非线性分割),而多层感知机虽能解决异或门,但权重仍需人工设定,这为神经网络的引入埋下伏笔。

2、指出感知机的核心痛点,引出神经网络的改进方向

作者强调感知机的两大核心问题:

  1. 激活函数为阶跃函数,输出非 0 即 1,信号传递是 “跳跃式” 的,无法传递连续变化的信息,不利于后续学习;
  2. 权重和偏置需人工调整,面对复杂任务(如图像识别)时完全不现实。因此,神经网络的核心改进目标是:保留 “加权和 + 激活判断” 的基本结构,通过优化激活函数、实现参数自动学习,突破感知机的局限。

3、神经网络的核心改进:替换激活函数,奠定学习基础

作者提出神经网络与感知机的核心差异 ——激活函数的替换

  1. 用平滑连续的 sigmoid 函数(输出 0~1 的连续值)替代阶跃函数,解决信号传递的 “跳跃性” 问题,使神经元输出能反映输入的细微变化,为后续通过梯度下降学习参数提供可能;
  2. 后续补充 ReLU 函数(输入 > 0 时输出自身,否则输出 0),进一步优化计算效率和梯度消失问题。同时,作者将感知机的 “加权和 + 激活” 流程拆解为两步,明确神经网络的信号传递逻辑:a=b+∑i=1n​wi​xi​(计算加权和)y=h(a)(h 为激活函数,如 sigmoid/ReLU)

4、扩展网络结构,实现从 “单层” 到 “多层” 的升级

作者将感知机的单层结构扩展为 “输入层→隐藏层→输出层” 的多层结构:

  1. 输入层接收原始数据(如图像像素),隐藏层负责提取特征(无需人工干预),输出层输出结果(如分类概率);
  2. 通过多维数组运算(矩阵乘法)实现层间信号的高效传递,例如输入与权重的矩阵乘积可一次性完成多个神经元的加权和计算,为复杂网络的实现提供工程基础。

image.png 通过提示词,再加上AI总结的脑图,可以初步了解神经网络,再让AI提三个问题(八股,让AI当面试官提问并给出答案)

题目 1:什么是激活函数?它在神经网络中起到什么作用?

回答

激活函数是神经网络中神经元的核心组件,本质是对神经元的加权输入信号进行非线性转换的函数,输出结果将传递给下一层神经元或作为最终输出。

核心作用有两个:

  1. 引入非线性特性:没有激活函数时,多层神经网络会退化为单层线性模型,无法拟合复杂数据(比如异或问题),激活函数通过非线性转换,让网络能学习复杂的映射关系;
  2. 控制信号传递:筛选有用信号,抑制无用信号,决定神经元是否 “激活”,比如输入信号较小时输出接近 0(不激活),输入信号足够大时输出向 1 靠近(激活)。

题目 2:神经网络的输出层激活函数如何选择?为什么?

回答

输出层激活函数需根据任务类型匹配,核心原则是贴合任务目标和输出需求:

  1. 二分类任务:用 Sigmoid 函数,输出值在 0~1 之间,可直接表示 “是 / 否” 的概率,比如判断图像是否为猫;
  2. 多分类任务:用 Softmax 函数,能将输出转换为各类别概率,且所有类别概率和为 1,方便直接判断最优类别,比如手写数字识别(0~9 分类);
  3. 回归任务:用恒等函数(直接输出原始值),因为回归需预测连续数值(如房价、温度),无需概率化处理。

题目 3:什么是批处理(Batch Processing)?神经网络中使用批处理有什么优势?

回答

批处理是每次训练时,从训练数据中抽取多个样本组成 “批次”,一次性输入网络计算梯度和更新参数,而非逐一样本处理。

核心优势:

  1. 提升计算效率:NumPy 等数值计算库对批量数据的矩阵运算优化更好,批量处理比逐样本处理速度更快,尤其适合大规模数据;
  2. 稳定训练过程:单个样本的梯度存在随机性,批量数据的平均梯度更接近整体数据的真实梯度,能减少训练波动,让参数更新更平稳,避免模型震荡。

书里解释了softmax,让AI总结一下: image.png 再用3层神经网络了解运作过程和代码

image.png image.png image.png 具体角标大概看一下,书中温馨提示 image.png 最后代码是这个,能看明白且着急的话就别敲了 image.png

MNIST手写识别

我是先把程序运行一遍,然后读代码的

1、运行程序

数据网址如下:deep-learning/deeplearning-from-scratch at master · ghxjk/deep-learning 把ch3整个文件夹下载后在vscode中打开,里面有自动下载数据集的脚本mnist.py,运行程序,生成mnist.pkl,然后运行mnist_show.py,监测数据是否下载完好。

主程序是neuralnet_mnist 运行输出精确度Accuracy:0.9352

2、读代码

mnist下载脚本的程序我没读,现成的代码就读了mnist_show和主程序,读代码的过程简单粗暴,扔给AI解读,顺便让AI总结知识点,大概知道每个函数是用来干什么的就行,混个眼熟。

image.png from PIL import Image:导入 Python Imaging Library(PIL)的 Image 模块,用于图像的转换和显示。

定义img_show函数,用于将 NumPy 数组格式的图像转换为 PIL 图像并显示:

  • np.uint8(img):将图像数组的数值类型转换为uint8(8 位无符号整数,范围 0-255,符合图像像素的标准格式)。
  • Image.fromarray():将 NumPy 数组转换为 PIL 的 Image 对象。
  • pil_img.show():调用系统默认图片查看器显示图像

调用load_mnist加载 MNIST 数据集:(load_mnist函数是下载数据集脚本中函数,脚本下载的数据存储为pkl格式- pkl 文件存储的内容:是一个字典,键为 train_img/train_label/test_img/test_label,值为对应的 NumPy 数组;load_mnist 函数的返回值:是一个嵌套元组,结构为 ((train_img, train_label), (test_img, test_label))

  • flatten=True:将二维的图像(28×28)展平为一维数组(784 个元素)。
  • normalize=False:不将像素值归一化(像素值保持 0-255,若为 True 则缩放到 0-1)。
  • 返回值:x_train(训练集图像数据)、t_train(训练集标签)、x_test(测试集图像数据)、t_test(测试集标签)。

对了python运行有顺序(由上到下),但是def函数只是定义函数,又没调用,所以这个顺序无所谓 主程序读代码,书上也有讲,一起参考。 主程序同理,因为主程序书上也有代码,就让AI总结一下大概内容

image.png

image.png

网上下载的程序没有太多注释,喂给AI,添加一些注释更加直观

# coding: utf-8  # 指定代码文件的编码格式为utf-8,避免中文等字符编码错误
import sys, os  # 导入sys(系统路径操作)和os(文件/目录路径处理)模块
current_dir = os.path.dirname(os.path.abspath(__file__))  # 获取当前代码文件的绝对路径,解决跨环境路径问题
sys.path.append(os.path.join(current_dir, ".."))  # 将当前目录的上级目录加入系统路径,让Python能找到自定义模块
import numpy as np  # 导入numpy库并简写为np,用于数值计算和数组操作(深度学习核心库)
import pickle  # 导入pickle模块,用于序列化/反序列化Python对象,此处用于加载预训练权重
from dataset.mnist import load_mnist  # 从自定义模块导入加载MNIST数据集的函数
from common.functions import sigmoid, softmax  # 从自定义模块导入神经网络常用的激活函数


def get_data():
    # 加载MNIST数据集:normalize=True(像素值归一化到0-1)、flatten=True(28×28图像展平为784维数组)、one_hot_label=False(标签为普通数字而非独热编码)
    (x_train, t_train), (x_test, t_test) = load_mnist(normalize=True, flatten=True, one_hot_label=False)
    return x_test, t_test  # 仅返回测试集的图像数据和标签数据,用于模型预测评估

def init_network():
    # 获取当前代码文件所在目录的绝对路径
    current_dir = os.path.dirname(os.path.abspath(__file__))
    # 拼接出sample_weight.pkl的绝对路径,避免硬编码路径导致文件找不到
    file_path = os.path.join(current_dir, "sample_weight.pkl")
    
    with open(file_path, 'rb') as f:  # 使用二进制读模式打开预训练权重文件(pickle加载二进制文件需指定rb)
        network = pickle.load(f)  # 加载预训练的网络参数(字典形式,包含各层权重W和偏置b)
    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 = np.dot(x, W1) + b1  # 计算第一层线性输出:输入x与第一层权重W1点积 + 第一层偏置b1
    z1 = sigmoid(a1)  # 对第一层线性输出应用sigmoid激活函数,引入非线性
    a2 = np.dot(z1, W2) + b2  # 计算第二层线性输出:第一层输出z1与第二层权重W2点积 + 第二层偏置b2
    z2 = sigmoid(a2)  # 对第二层线性输出应用sigmoid激活函数,引入非线性
    a3 = np.dot(z2, W3) + b3  # 计算输出层线性输出:第二层输出z2与第三层权重W3点积 + 第三层偏置b3
    y = softmax(a3)  # 对输出层线性输出应用softmax,转换为0-1的概率值(所有类别概率和为1)

    return y  # 返回预测概率数组,每个元素对应0-9某个数字的预测概率


x, t = get_data()  # 调用函数获取测试集的图像数据(x)和真实标签(t)
network = init_network()  # 调用函数加载预训练的网络参数
batch_size = 100  # 设置批次大小为100,批量处理提升计算效率
accuracy_cnt = 0  # 初始化准确率计数变量,统计预测正确的样本数量
for i in range(0,len(x),batch_size):  # 按批次遍历测试集:起始0、终止测试集长度、步长batch_size
    x_batch = x[i:i+batch_size]  # 截取当前批次的图像数据
    y_batch = predict(network, x_batch)  # 对当前批次数据进行预测,得到各样本的类别概率
    p= np.argmax(y_batch,axis=1) # 获取概率最高的元素的索引(即预测的数字,如索引3对应数字3)
    accuracy_cnt += np.sum(p == t[i:i+batch_size])  # 变量 += 数值 等价于 变量 = 变量 + 数值,p 是当前批次的预测结果
#t[i:i+batch_size] 是当前批次的真实标签,== 会逐元素对比,返回一个布尔数组
#所以这个是accuracy_cnt初始值为0,加上当前批次中预测正确的样本数量
print("Accuracy:" + str(float(accuracy_cnt) / len(x)))  # 计算并打印总准确率:正确数/测试集总数

看到最后总结部分发现漏了一个RELU,让AI总结了一下,看起来小白阶段暂时用不上,留个印象吧

image.png