非计算机科班,有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)的线性分类算法
感知机可实现与门(x变量都为1y为1)、与非门(x变量都为0y为1)、或门(x变量有一个为1y就输出1)等简单逻辑电路,以及多层感知机实现的异或门
第三章 神经网络
prompt1:我想知道第三章,作者是怎么讲解的,是如何从上一章节的感知机过渡到神经网络的(通过这个提示词,再加上快速翻看,大概了解神经网络是个啥了)
1、先复习感知机,搭建过渡基础
作者先回顾感知机的核心机制:接收多输入信号,通过权重(控制输入重要性)和偏置(调整激活难度)计算加权和,再经阶跃函数判断是否输出 1(激活),数学表达式为:y={01(b+∑i=1nwixi≤0)(b+∑i=1nwixi>0)同时明确感知机的核心价值 —— 能实现与门、与非门、或门等简单逻辑电路,但关键局限是仅能处理线性可分问题,无法实现异或门(需非线性分割),而多层感知机虽能解决异或门,但权重仍需人工设定,这为神经网络的引入埋下伏笔。
2、指出感知机的核心痛点,引出神经网络的改进方向
作者强调感知机的两大核心问题:
- 激活函数为阶跃函数,输出非 0 即 1,信号传递是 “跳跃式” 的,无法传递连续变化的信息,不利于后续学习;
- 权重和偏置需人工调整,面对复杂任务(如图像识别)时完全不现实。因此,神经网络的核心改进目标是:保留 “加权和 + 激活判断” 的基本结构,通过优化激活函数、实现参数自动学习,突破感知机的局限。
3、神经网络的核心改进:替换激活函数,奠定学习基础
作者提出神经网络与感知机的核心差异 ——激活函数的替换:
- 用平滑连续的 sigmoid 函数(输出 0~1 的连续值)替代阶跃函数,解决信号传递的 “跳跃性” 问题,使神经元输出能反映输入的细微变化,为后续通过梯度下降学习参数提供可能;
- 后续补充 ReLU 函数(输入 > 0 时输出自身,否则输出 0),进一步优化计算效率和梯度消失问题。同时,作者将感知机的 “加权和 + 激活” 流程拆解为两步,明确神经网络的信号传递逻辑:a=b+∑i=1nwixi(计算加权和)y=h(a)(h 为激活函数,如 sigmoid/ReLU)
4、扩展网络结构,实现从 “单层” 到 “多层” 的升级
作者将感知机的单层结构扩展为 “输入层→隐藏层→输出层” 的多层结构:
- 输入层接收原始数据(如图像像素),隐藏层负责提取特征(无需人工干预),输出层输出结果(如分类概率);
- 通过多维数组运算(矩阵乘法)实现层间信号的高效传递,例如输入与权重的矩阵乘积可一次性完成多个神经元的加权和计算,为复杂网络的实现提供工程基础。
通过提示词,再加上AI总结的脑图,可以初步了解神经网络,再让AI提三个问题(八股,让AI当面试官提问并给出答案)
题目 1:什么是激活函数?它在神经网络中起到什么作用?
回答
激活函数是神经网络中神经元的核心组件,本质是对神经元的加权输入信号进行非线性转换的函数,输出结果将传递给下一层神经元或作为最终输出。
核心作用有两个:
- 引入非线性特性:没有激活函数时,多层神经网络会退化为单层线性模型,无法拟合复杂数据(比如异或问题),激活函数通过非线性转换,让网络能学习复杂的映射关系;
- 控制信号传递:筛选有用信号,抑制无用信号,决定神经元是否 “激活”,比如输入信号较小时输出接近 0(不激活),输入信号足够大时输出向 1 靠近(激活)。
题目 2:神经网络的输出层激活函数如何选择?为什么?
回答
输出层激活函数需根据任务类型匹配,核心原则是贴合任务目标和输出需求:
- 二分类任务:用 Sigmoid 函数,输出值在 0~1 之间,可直接表示 “是 / 否” 的概率,比如判断图像是否为猫;
- 多分类任务:用 Softmax 函数,能将输出转换为各类别概率,且所有类别概率和为 1,方便直接判断最优类别,比如手写数字识别(0~9 分类);
- 回归任务:用恒等函数(直接输出原始值),因为回归需预测连续数值(如房价、温度),无需概率化处理。
题目 3:什么是批处理(Batch Processing)?神经网络中使用批处理有什么优势?
回答
批处理是每次训练时,从训练数据中抽取多个样本组成 “批次”,一次性输入网络计算梯度和更新参数,而非逐一样本处理。
核心优势:
- 提升计算效率:NumPy 等数值计算库对批量数据的矩阵运算优化更好,批量处理比逐样本处理速度更快,尤其适合大规模数据;
- 稳定训练过程:单个样本的梯度存在随机性,批量数据的平均梯度更接近整体数据的真实梯度,能减少训练波动,让参数更新更平稳,避免模型震荡。
书里解释了softmax,让AI总结一下:
再用3层神经网络了解运作过程和代码
具体角标大概看一下,书中温馨提示
最后代码是这个,能看明白且着急的话就别敲了
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总结知识点,大概知道每个函数是用来干什么的就行,混个眼熟。
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总结一下大概内容
网上下载的程序没有太多注释,喂给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总结了一下,看起来小白阶段暂时用不上,留个印象吧