第2章 TensorFlow 2快速入门
一、TensorFlow 2环境搭建
1.1 什么是TensorFlow?
TensorFlow是谷歌开发的开源深度学习框架,它可以帮助我们:
- 构建神经网络(就像搭积木一样)
- 训练模型(让计算机学会处理数据)
- 使用模型进行预测
通俗理解:TensorFlow就像一个"人工智能工具箱",里面有很多现成的工具,我们只需要学会如何使用这些工具,就能快速搭建AI应用。
1.2 安装TensorFlow
1.2.1 安装前的准备
需要区分两种版本:
| 版本 | 适用情况 | 特点 |
|---|---|---|
| CPU版本 | 普通笔记本电脑 | 安装简单,适合学习和练习 |
| GPU版本 | 有独立NVIDIA显卡的电脑 | 训练速度快,适合处理大数据 |
查看自己电脑的显卡:
- Windows:右键"此电脑" → “管理” → “设备管理器” → “显示适配器”
- 如果有NVIDIA显卡(如GTX、RTX系列),可以安装GPU版本
- 如果没有独立显卡或者是AMD/Intel显卡,只能安装CPU版本
1.2.2 安装CPU版本(推荐学生使用)
方法一:直接安装(最简单)
打开命令提示符(CMD)或Anaconda Prompt,输入:
|
|
方法二:使用国内镜像源(下载更快)
|
|
为什么使用国内镜像?
- 默认的下载源在国外,下载速度很慢
- 使用清华源、阿里源等国内镜像,速度可以提升10-100倍
1.2.3 验证安装是否成功
打开Python交互式环境(输入python或ipython),然后输入:
|
|
如果没有报错,并能看到版本号(如2.10.0),说明安装成功!
学生可能遇到的错误:
ModuleNotFoundError: No module named 'tensorflow':说明没有安装成功,重新安装- 安装过程中出现红色错误信息:可能是网络问题,尝试使用国内镜像源
二、TensorFlow 2基本数据类型
2.1 什么是张量(Tensor)?
张量是TensorFlow中最基本的数据单位,可以理解为:
- 0阶张量:就是一个数(标量) → 例如:5, 3.14
- 1阶张量:就是一个列表(向量) → 例如:[1, 2, 3]
- 2阶张量:就是一个表格(矩阵) → 例如:[[1,2], [3,4]]
- 3阶张量:就是多个表格叠在一起 → 例如:图片的RGB三个通道
生活中的例子:
| 张量阶数 | 数学名称 | 生活中的例子 |
|---|---|---|
| 0阶 | 标量 | 一个人的年龄、体重 |
| 1阶 | 向量 | 班级所有学生的成绩列表 |
| 2阶 | 矩阵 | Excel表格 |
| 3阶 | 3维张量 | 彩色图片(高度×宽度×RGB通道) |
2.2 创建张量
|
|
2.3 张量的重要属性
每个张量都有三个重要属性:
|
|
2.3.1 形状(shape)
- 用元组表示,每个数字代表该维度的大小
(2, 3)表示2行3列(28, 28)表示28×28的矩阵(如手写数字图片)(100, 28, 28, 3)表示100张28×28的彩色图片(3个颜色通道)
2.3.2 数据类型(dtype)
| 数据类型 | 说明 | 示例 |
|---|---|---|
| int32 | 32位整数 | tf.constant([1,2,3]) |
| float32 | 32位浮点数 | tf.constant([1.0, 2.0]) |
| string | 字符串 | tf.constant(“Hello”) |
| bool | 布尔值 | tf.constant([True, False]) |
2.3.3 维度数(ndim/rank)
- 0维:标量
- 1维:向量
- 2维:矩阵
- 3维及以上:高维张量
2.4 张量的常用操作
|
|
2.5 动手练习
练习1:创建以下张量
- 一个3×3的全1矩阵
- 一个包含数字1-9的3×3矩阵
- 一个形状为(2, 3, 4)的随机张量
练习2:对两个2×2矩阵进行加法和乘法运算
三、用TensorFlow 2训练一个线性模型
3.1 问题描述
我们有一份包含100个样本的数据,每个样本有:
- x:输入数据(特征)
- y:输出数据(目标值)
我们要找到一条直线 y = w*x + b 来拟合这些数据,其中:
- w(权重):直线的斜率
- b(偏置):直线的截距
现实意义:
- 预测房价:x是房子面积,y是房价
- 预测销量:x是广告投入,y是产品销量
- 预测成绩:x是学习时间,y是考试成绩
3.2 完整代码实现
|
|
3.3 逐行详细解释
3.3.1 导入必要的库
|
|
-
TensorFlow是谷歌开发的深度学习库,提供了构建和训练神经网络所需的所有工具
-
pandas用于数据处理和分析,特别是处理表格数据(如CSV文件)
-
NumPy提供了高性能的多维数组对象和数学函数
-
matplotlib是Python最常用的数据可视化库,
plt是pyplot模块的常用别名,用于绘制图表、显示图片、可视化训练过程等
|
|
作用:解决matplotlib绘图时中文显示乱码的问题。
rcParams是matplotlib的运行时配置参数font.sans-serif设置无衬线字体为SimHei(黑体),这样中文就能正常显示axes.unicode_minus设置为False,解决负号显示为方块的问题
3.3.2 加载数据
|
|
作用:打印分隔线,让输出更清晰易读。
"="*50表示将字符串"="重复50次,形成一个分隔线- 这样在控制台输出时,每个步骤都有明显的分隔,便于查看
|
|
作用:使用pandas读取CSV文件。
read_csv()是pandas的函数,用于读取CSV格式的文件'../data/line_fit_data.csv'是文件路径,..表示上级目录- 返回的
data是一个DataFrame对象,类似于Excel表格,有行和列 - CSV文件内容示例:
1 2 3x,y 0.8521031222662713,6.1302578056656785 0.6309219899845755,5.5773049749614385
|
|
作用:显示数据的前5行,快速查看数据格式。
head()是DataFrame的方法,默认显示前5行数据- 可以让我们确认数据是否正确加载,查看列名和数据格式
|
|
作用:显示数据的形状(行数和列数)。
shape是DataFrame的属性,返回一个元组(行数, 列数)- 例如
(100, 2)表示有100行数据,2列(x和y)
3.3.3 数据预处理
|
|
作用:从DataFrame中提取特征x和目标值y。
data['x']选取名为’x’的列,返回一个Series对象.values将Series转换为NumPy数组,便于后续计算x是输入特征,y是要预测的目标值
|
|
作用:将数据集划分为训练集和测试集。
[:-10]是Python的切片语法,表示从开头到倒数第10个元素(不包括最后10个)- 例如:
x[:-10]取x的前90个元素
- 例如:
[-10:]表示取最后10个元素- 训练集:用于训练模型,让模型学习数据规律
- 测试集:用于评估模型性能,测试模型在未见过的数据上的表现
|
|
作用:打印训练集和测试集的大小。
f"..."是f-string格式化字符串,可以在字符串中直接嵌入变量len(x_train)获取训练集样本数量
3.3.4 构建模型
|
|
作用:创建一个Sequential模型实例。
- Sequential:顺序模型,一层接一层堆叠,像搭积木一样
tf.keras.models是TensorFlow中Keras API的模型模块- 此时
model是一个空模型,还没有任何层
|
|
作用:向模型中添加一个全连接层(Dense层)。
参数详解:
- 第一个参数
1:输出维度,即本层神经元的数量- 这里设置为1,因为我们只需要预测一个数值y
input_shape=(1,):输入数据的形状(1,)表示每个样本有1个特征(即x值)- 注意:input_shape只需要在模型的第一层指定,后续层会自动推导
tf.keras.layers.Dense:全连接层,每个神经元与上一层的所有神经元相连
数学原理:
- 这一层实现的运算:
output = activation(w * input + b) - 由于没有指定激活函数(activation),默认使用线性激活函数
- 所以实际上就是:
y = w * x + b,这正是我们需要的线性模型
|
|
作用:打印模型的详细结构信息。
summary()会显示:- 每一层的名称、类型、输出形状
- 每一层的参数数量(需要学习的权重和偏置)
- 模型的总参数数量
- 帮助我们确认模型构建是否正确
3.3.5 编译模型
|
|
作用:配置模型的学习过程。
参数详解:
-
loss='mse':损失函数- MSE:Mean Squared Error(均方误差)
- 公式:
MSE = 1/n * Σ(y_true - y_pred)² - 作用:衡量模型预测值与真实值的差距
- 值越小,表示预测越准确
- 适合回归问题(预测连续值)
-
optimizer=tf.keras.optimizers.SGD(learning_rate=0.5):优化器- SGD:Stochastic Gradient Descent(随机梯度下降)
- 作用:根据损失函数的值,更新模型的权重和偏置
- learning_rate=0.5:学习率
- 控制每次参数更新的步长
- 学习率太大:可能跳过最优解,训练不稳定
- 学习率太小:训练速度慢,可能陷入局部最优
- 0.5是一个相对较大的学习率,适合这个简单问题
|
|
作用:提示模型编译完成。
3.3.6 训练模型
|
|
作用:训练模型。
参数详解:
-
x_train, y_train:训练数据和对应的标签x_train:输入特征(90个x值)y_train:目标值(90个y值)
-
epochs=20:训练轮数- 1个epoch表示使用全部训练数据训练一次
- 这里训练20轮,即整个数据集被用来训练20次
- 每轮结束后,模型参数都会更新
-
validation_split=0.2:验证集比例- 从训练集中分出20%的数据作为验证集
- 验证集不参与训练,只用于评估模型在训练过程中的表现
- 这里90个训练样本中,72个用于训练,18个用于验证
-
verbose=1:日志显示模式- 0:不显示训练进度
- 1:显示进度条
- 2:每个epoch显示一行
返回值:
history:记录训练过程中的损失值和评估指标- 可以通过
history.history查看训练损失和验证损失的变化
3.3.7 模型预测
|
|
作用:使用训练好的模型对测试集进行预测。
predict()方法接收输入数据,返回模型的预测结果x_test是10个测试样本y_pred的形状是(10, 1),每行是一个样本的预测值
|
|
作用:打印真实值和预测值的对比。
range(len(y_test))生成0到9的索引y_test[i]:第i个样本的真实值y_pred[i][0]:第i个样本的预测值(因为预测结果是二维数组,取第一个元素):.2f:格式化输出,保留两位小数\t:制表符,用于对齐输出
3.3.8 模型评估
|
|
作用:计算测试集上的均方误差(MSE)。
逐步解析:
y_test - y_pred.flatten():y_pred.flatten()将预测结果从(10,1)展平为(10,),使形状与y_test一致- 计算真实值与预测值的差(残差)
(...)**2:对每个差值求平方- 消除正负号,放大较大的误差
np.mean(...):计算所有平方差的平均值- 得到最终的均方误差
|
|
作用:打印均方误差,保留4位小数。
3.3.9 可视化结果
|
|
作用:创建新图形,设置图形大小。
figsize=(12,4):图形宽度12英寸,高度4英寸
|
|
作用:创建子图,将图形划分为1行2列,选择第1个子图。
- 参数
(1, 2, 1)表示:1行2列,当前是第1个子图
|
|
作用:绘制损失曲线。
history.history['loss']:训练过程中的训练损失值列表history.history['val_loss']:训练过程中的验证损失值列表label:图例标签marker='o':数据点用圆圈标记marker='s':数据点用方块标记
|
|
作用:设置图表的标签、标题、图例和网格。
xlabel:x轴标签ylabel:y轴标签title:图表标题legend():显示图例grid(True):显示网格线
|
|
作用:绘制散点图,显示数据分布。
scatter():绘制散点图alpha=0.5:设置透明度为0.5(0透明,1不透明)c='red':设置测试数据点的颜色为红色
|
|
作用:绘制拟合的直线。
np.linspace(0, 1, 100):在0到1之间生成100个等间隔的点model.predict(x_line):用模型预测这些点的y值'g-':绿色实线linewidth=2:线宽为2
|
|
作用:设置图表属性并显示。
tight_layout():自动调整子图参数,使布局更紧凑show():显示图形
3.3.10 查看模型参数
|
|
作用:获取模型第一层(也是唯一一层)的权重参数。
model.layers[0]:获取模型的第一层(Dense层)get_weights():返回该层的权重和偏置- 返回值是一个列表:
[weights, biases]
|
|
作用:提取权重和偏置的具体数值。
weights[0]:权重矩阵,形状为(1, 1)weights[0][0][0]:取第一个(也是唯一一个)权重值
weights[1]:偏置向量,形状为(1,)weights[1][0]:取第一个(也是唯一一个)偏置值
|
|
作用:打印拟合得到的直线方程。
w:.4f:权重保留4位小数b:.4f:偏置保留4位小数- 例如输出:
拟合得到的直线方程: y = 5.1234 * x + 4.5678
3.4 关键概念详细解释
3.4.1 模型(Model)
| 概念 | 通俗解释 | 代码对应 |
|---|---|---|
| 模型 | 一个数学公式,描述输入和输出的关系 | Sequential() |
| 参数 | 模型中需要学习的变量(w和b) | get_weights()返回的值 |
| 前向传播 | 输入数据经过模型计算得到输出 | model.predict() |
3.4.2 层(Layer)
| 概念 | 通俗解释 | 代码对应 |
|---|---|---|
| 层 | 模型的基本组成单元 | Dense() |
| Dense层 | 全连接层,每个神经元连接所有输入 | layers.Dense() |
| 神经元 | 层中的基本计算单元 | Dense(1)中的1 |
| 激活函数 | 引入非线性,让模型学习复杂模式 | activation参数 |
3.4.3 训练过程
| 概念 | 通俗解释 | 代码对应 |
|---|---|---|
| 损失函数 | 衡量预测值与真实值的差距 | loss='mse' |
| 优化器 | 决定如何更新参数 | optimizer='sgd' |
| 学习率 | 参数更新的步长 | learning_rate=0.5 |
| Epoch | 使用全部数据训练一次 | epochs=20 |
| Batch | 一次更新使用的样本数 | batch_size(默认32) |
| 训练集 | 用于训练模型的数据 | x_train, y_train |
| 验证集 | 用于调整超参数的数据 | validation_split=0.2 |
| 测试集 | 用于最终评估的数据 | x_test, y_test |
3.4.4 评估指标
| 概念 | 公式 | 含义 | 代码对应 |
|---|---|---|---|
| 均方误差(MSE) | 1/n * Σ(y - ŷ)² |
预测误差的平方的平均值 | loss='mse' |
| 平均绝对误差(MAE) | `1/n * Σ | y - ŷ | ` |
3.5 常见问题及解决方法
Q1: 损失值不下降怎么办?
可能原因:
- 学习率太小或太大
- 网络结构不合适
- 数据未正确归一化
解决方法:
|
|
Q2: 预测结果都是同一个值?
可能原因:
- 模型没有收敛
- 数据有问题
- 网络太简单
解决方法:
- 增加训练轮数
- 检查数据是否有问题
- 尝试增加网络层数
Q3: 训练速度太慢?
可能原因:
- 数据量太大
- 网络太复杂
- 学习率太小
解决方法:
|
|
3.6 动手练习
练习1:调整训练轮数
修改代码,将训练轮数改为50轮,观察损失值的变化。回答以下问题:
- 损失值是否继续下降?
- 50轮后是否出现过拟合?
练习2:调整学习率
尝试不同的学习率(0.1、0.5、1.0),比较训练效果:
- 哪个学习率收敛最快?
- 哪个学习率最终损失最小?
练习3:尝试不同的优化器
将优化器改为Adam,比较SGD和Adam的区别:
|
|
四、深度学习通用流程
4.1 深度学习流程图
|
|
4.1.1 为什么需要这个流程?
就像做饭的步骤:
- 买菜(数据加载)
- 洗菜切菜(数据预处理)
- 准备锅具(构建网络)
- 设置火候(编译网络)
- 炒菜(训练网络)
- 尝味道(性能评估)
- 保存菜谱(模型保存)
4.2 数据加载
TensorFlow提供了多种方式加载不同类型的数据:
4.2.1 加载自带数据集
|
|
4.2.2 加载CSV文件
|
|
4.2.3 加载TFRecord文件
|
|
4.2.4 加载文本文件
|
|
4.2.5 加载图片文件集
|
|
4.3 数据预处理
4.3.1 图片数据预处理
|
|
4.3.2 MNIST数据预处理
|
|
4.3.3 文本数据预处理
|
|
4.4 数据预处理的常用操作
| 操作 | 作用 | 代码示例 |
|---|---|---|
| 归一化 | 将数据缩放到0-1 | image / 255.0 |
| 打乱 | 随机打乱顺序 | .shuffle(buffer_size) |
| 分批 | 将数据分成小批量 | .batch(batch_size) |
| one-hot编码 | 将类别转换为向量 | tf.one_hot(label, depth) |
| 调整大小 | 改变图片尺寸 | tf.image.resize() |
4.5 动手练习
练习1:加载Fashion-MNIST数据集,查看数据形状
练习2:对MNIST数据做归一化和分批处理
练习3:加载自己的图片文件夹,创建Dataset对象
五、项目一:MNIST手写数字识别
5.1 项目概述
5.1.1 项目目标
使用TensorFlow 2构建一个神经网络模型,对MNIST手写数字图片进行分类,识别0-9十个数字。
5.1.2 数据集说明
- 训练集:60,000张28×28的灰度图片
- 测试集:10,000张28×28的灰度图片
- 标签:0-9的数字
- 数据格式:mnist.npz文件(包含x_train, y_train, x_test, y_test)
5.1.3 项目流程
|
|
5.2 完整项目代码
|
|
5.3 代码逐行解释
5.3.1 导入库
|
|
5.3.2 加载数据
|
|
np.load():加载NumPy的.npz格式文件data.files:查看文件中包含的所有数据键名- 从文件中提取训练集和测试集的图片和标签
5.3.3 数据预处理
|
|
- 归一化:将0-255的像素值缩放到0-1,有利于模型训练
- 展平:将28×28的二维图片变成784的一维向量
- one-hot编码:将数字标签转换为向量形式
- 例如:3 → [0,0,0,1,0,0,0,0,0,0]
5.3.4 构建模型
|
|
- Flatten层:将28×28的输入展平为784
- Dense层:全连接层
- 128/64:神经元数量
- activation=‘relu’:ReLU激活函数
- activation=‘softmax’:输出概率分布
5.3.5 编译模型
|
|
- optimizer:优化器,决定如何更新参数
- loss:损失函数,衡量预测值与真实值的差距
- metrics:评估指标,监控模型性能
5.3.6 训练模型
|
|
- epochs:训练轮数
- validation_data:验证数据
- history:记录训练过程中的损失和准确率
5.3.7 预测新样本
|
|
六、项目二:TFRecord数据处理与模型应用
6.1 项目概述
6.1.1 项目目标
学习如何处理TFRecord格式的数据,并应用训练好的模型进行预测。
6.1.2 数据集说明
- fsns.tfrec:TFRecord格式的数据文件
- TFRecord是TensorFlow专用的二进制数据格式
- 包含图片和对应的文本标签
- testimages:30张手写数字测试图片
6.1.3 项目流程
|
|
6.2 完整项目代码
|
|
6.3 代码逐行解释
6.3.1 TFRecord解析
|
|
- FixedLenFeature:定长特征,指定数据类型
- parse_single_example:解析单个TFRecord样本
- decode_jpeg:解码JPEG格式的图片
6.3.2 创建TFRecord
|
|
- TFRecordWriter:创建TFRecord写入器
- Example:TFRecord中的数据单元
- SerializeToString:序列化为二进制字符串
6.3.3 模型预测
|
|
附录:常见问题解答
Q1: 安装TensorFlow时出现错误怎么办?
A: 尝试以下解决方案:
- 使用国内镜像源:
pip install tensorflow -i https://pypi.tuna.tsinghua.edu.cn/simple - 更新pip:
python -m pip install --upgrade pip - 创建虚拟环境安装
Q2: 训练时内存不足怎么办?
A: 减小batch_size,例如从128改为64或32
Q3: 模型准确率不高怎么办?
A: 尝试:
- 增加训练轮数
- 增加网络层数或神经元数量
- 调整学习率
- 检查数据预处理是否正确
Q4: 加载mnist.npz时找不到文件怎么办?
A: 确保文件路径正确,或者使用tf.keras.datasets.mnist.load_data()直接下载
Q5: TFRecord解析出错怎么办?
A: 检查特征描述是否与数据格式匹配,可以使用tf.train.Example.FromString()查看原始数据
教学总结
本章重点
- TensorFlow环境搭建
- 张量的概念和操作
- 线性回归模型
- 深度学习通用流程
- 多种数据格式的加载(CSV、TFRecord、图片)
- 项目一:MNIST手写数字识别
- 项目二:TFRecord数据处理与应用
能力目标
学完本章后,学生应该能够:
- 独立安装TensorFlow
- 理解张量的基本概念
- 使用TensorFlow构建分类模型
- 处理不同格式的数据(CSV、TFRecord、图片)
- 完成完整项目开发
- 保存和加载模型
- 对新样本进行预测
项目练习建议
- 修改MNIST项目的网络结构,观察准确率变化
- 尝试用Fashion-MNIST数据集训练模型
- 自己收集手写数字图片,用训练好的模型测试
- 尝试将其他格式的数据转换为TFRecord