第2课:TensorFlow|Python深度学习必备基础【语法进阶、数值计算、数据处理、面向对象核心】

文章目录
1. 课前导读
1.1 本节课学习目标
- 熟练掌握Python在深度学习中的进阶语法,包括列表推导式、迭代器与生成器、装饰器、上下文管理器。
- 理解NumPy库的核心数据结构
ndarray,掌握数组创建、索引切片、向量化运算、广播机制。 - 学会使用Matplotlib进行基本的数据可视化,为模型训练过程监控打下基础。
- 掌握面向对象编程(OOP)在深度学习中的应用:类的定义与继承、
@property、静态方法与类方法。 - 能够使用Pandas进行简单的数据加载与预处理(CSV、缺失值处理)。
- 综合运用Python、NumPy、OOP思想搭建一个可扩展的数据处理器框架。
1.2 知识重难点
| 类别 | 内容 |
|---|---|
| 重点 | NumPy向量化运算与广播机制;面向对象中的类继承与多态;生成器在大规模数据加载中的优势 |
| 难点 | 装饰器的底层原理(闭包);NumPy广播规则的完全理解;__slots__与内存优化 |
| 易混淆点 | deepcopy与view的区别;Python普通循环与向量化运算的性能差异;实例方法/类方法/静态方法的适用场景 |
1.3 学习前置条件
- 已安装Python 3.9及以上版本(第1课已完成TensorFlow安装,Python环境已就绪)。
- 了解Python基础语法(变量、数据类型、条件判断、循环、函数定义)。
- 完成第1课的张量基本操作,对本专栏风格已有认知。
1.4 学完可掌握能力
- 能够编写高效的数据预处理流水线,避免低效Python循环。
- 使用NumPy完成矩阵运算、统计汇总、形状变换,为TensorFlow张量操作奠定基础。
- 设计具有复用性的深度学习组件(自定义层、数据加载器)——基于面向对象。
- 独立读取CSV/Excel格式的数据集并进行清洗、归一化等预处理。
- 使用Matplotlib绘制损失曲线、特征分布图等常见训练图表。
1.5 行业应用场景
- 数据预处理:原始日志数据清洗、特征提取、归一化(如用户行为特征工程)。
- 自定义模型组件:在TensorFlow中通过继承
tf.keras.layers.Layer实现非标准算子。 - 数据增强:图像数据增强(旋转、翻转)的底层实现(配合NumPy)。
- 训练监控工具:利用装饰器自动记录每个epoch的训练时间或损失值。
- 配置管理:使用类封装模型超参数,支持序列化与反序列化。
2. 核心理论精讲
2.1 Python进阶语法在深度学习中的价值
深度学习的代码核心是高效的数据处理 + 灵活的模型构建。Python虽然执行速度较慢,但通过向量化(底层C实现)和合理使用高级语法,可以兼顾开发效率和运行性能。
列表推导式:替代map/filter + lambda,更可读。
# 传统循环
squares = []
for i in range(10):
squares.append(i**2)
# 列表推导式
squares = [i**2 for i in range(10)]
生成器:处理大规模数据集时,避免一次性加载全部数据到内存。深度学习中的数据流水线(如tf.data.Dataset)底层也使用了类似惰性求值的概念。
装饰器:在TensorFlow中随处可见,例如@tf.function将Python函数转为计算图;自定义装饰器可用于日志记录、计时、梯度监控。
上下文管理器:资源自动管理,典型应用是with tf.GradientTape()自动管理梯度计算资源的创建与释放。
2.2 NumPy:深度学习的数据基石
NumPy提供了一个高性能的多维数组对象ndarray,以及丰富的数学函数库。TensorFlow的张量在设计上极大借鉴了NumPy,二者可以无缝转换(tf.convert_to_tensor / .numpy())。
核心概念:向量化。对数组的操作会自动应用到每个元素上,避免Python层级的显式循环,利用BLAS等底层库实现并行加速。
广播机制:当两个数组形状不同时,NumPy会尝试扩展其中一个数组的维度,使其形状兼容后再进行逐元素运算。规则如下:
- 从尾部维度开始比对。
- 维度相等或其中一个为1,则兼容;否则抛出错误。
- 缺失的维度假定为1。
示例:形状(3,4)的数组与形状(4,)的数组相加,后者会广播为(3,4)。这极大简化了特征归一化(减去均值、除以标准差)的代码。
2.3 面向对象核心:设计可复用的深度学习组件
TensorFlow的Keras API是典型的面向对象设计:Layer、Model、Optimizer等基类,用户通过继承来扩展。理解OOP思想,才能编写自定义层、自定义损失函数、回调函数等。
类继承与多态:
- 基类定义接口(如
call方法),子类实现具体逻辑。 - 在TensorFlow中,
tf.keras.Model要求子类实现call()方法。
属性装饰器@property:将方法当作属性调用,用于对属性进行只读访问或延迟计算。例如将学习率设置为属性,并在设置时自动更新优化器内部状态。
类方法与静态方法:
@classmethod:操作类变量,可用于工厂模式(如从配置字典创建模型)。@staticmethod:工具函数,不依赖实例或类状态。
__slots__:限制实例属性,减少内存占用。在需要创建大量小对象(如批量数据样本)时非常有用。
2.4 数据预处理流程理论
深度学习的数据预处理通常包括:
- 加载:从文件(CSV、JSON、图像)读取原始数据。
- 清洗:处理缺失值(删除、均值/中位数填充)、异常值剔除。
- 编码:类别特征进行One-Hot或Label Encoding;文本特征转为词向量索引。
- 缩放:数值特征归一化(Min-Max)或标准化(Z-Score),使不同特征处于同一量级,加速梯度下降收敛。
- 划分:训练集、验证集、测试集(通常6:2:2或8:1:1)。
- 批量化:将数据切分为小批量,便于随机梯度下降。
其中,NumPy和Pandas承担了大部分工作。Pandas提供的DataFrame结构非常适合表格数据的操作。
3. 环境搭建与工具配置
本课所需库:numpy, matplotlib, pandas。若已安装TensorFlow,则NumPy通常已被依赖安装,但建议单独确认版本。
3.1 安装必要库
# 激活你的Python环境(假设使用第1课的虚拟环境)
# Windows
tf_env\Scripts\activate
# macOS/Linux
source tf_env/bin/activate
# 安装或升级库
pip install --upgrade numpy pandas matplotlib
# 验证安装
python -c "import numpy; print(numpy.__version__)" # 应输出 1.24+
python -c "import pandas; print(pandas.__version__)" # 应输出 2.0+
python -c "import matplotlib; print(matplotlib.__version__)"
3.2 配置Jupyter Notebook(可选但推荐)
Jupyter Notebook方便分步执行代码和可视化。
pip install jupyter
jupyter notebook
在浏览器中新建一个Notebook,即可逐段运行本课的代码示例。
3.3 IDE设置建议
- PyCharm:将项目解释器设置为虚拟环境,并启用Scientific Mode,内置变量查看器。
- VS Code:安装Python和Jupyter扩展,选择相同解释器。
3.4 常见环境问题
| 问题 | 原因 | 解决 |
|---|---|---|
numpy 导入失败提示 DLL load failed |
Python版本不兼容(如3.11+)或缺少VC++运行库 | 降级到Python 3.9,或安装 numpy‑1.23.5 |
matplotlib 绘图无法显示中文 |
默认字体不支持中文 | 运行以下代码设置中文字体(以黑体为例):plt.rcParams['font.sans-serif'] = ['SimHei']plt.rcParams['axes.unicode_minus'] = False |
| Pandas读取大文件内存耗尽 | 数据集过大 | 使用 chunksize 参数分块读取,或转换为NumPy数组后再处理 |
4. 代码实战教学
本节将分模块编写代码,逐行讲解。建议读者在IDE或Jupyter中边写边运行。
4.1 Python进阶语法实战
4.1.1 列表推导式与生成器表达式
# 1. 列表推导式:生成0-9的平方
squares = [x**2 for x in range(10)]
print("平方列表:", squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
# 带条件的列表推导式:提取偶数平方
even_squares = [x**2 for x in range(10) if x % 2 == 0]
print("偶数平方:", even_squares) # [0, 4, 16, 36, 64]
# 2. 生成器表达式:圆括号代替方括号,惰性求值
gen = (x**2 for x in range(10))
print("生成器类型:", type(gen)) # <class 'generator'>
print("逐个取值:", next(gen), next(gen), next(gen)) # 0 1 4
# 应用场景:大数据集求和(避免创建完整列表)
large_sum = sum(x**2 for x in range(10000000)) # 几乎不占用额外内存
print("和大数:", large_sum)
4.1.2 装饰器:训练计时器
import time
# 定义一个计时装饰器
def timer(func):
def wrapper(*args, **kwargs):
start = time.perf_counter()
result = func(*args, **kwargs)
end = time.perf_counter()
print(f"{func.__name__} 执行耗时: {end - start:.6f} 秒")
return result
return wrapper
@timer
def slow_square(n):
total = 0
for i in range(n):
total += i ** 2
return total
result = slow_square(1000000)
print(f"结果: {result}")
# 在深度学习中,可以用装饰器自动记录每个epoch的时间
4.1.3 上下文管理器:自动文件关闭
# 常规方式:手动关闭
f = open('test.txt', 'w')
f.write('Hello TensorFlow')
f.close()
# 上下文管理器方式:自动关闭
with open('test.txt', 'w') as f:
f.write('Hello TensorFlow')
# 退出with块时,文件自动关闭
# 自定义上下文管理器(用于资源管理)
class ManagedTimer:
def __enter__(self):
self.start = time.perf_counter()
return self
def __exit__(self, exc_type, exc_val, exc_tb):
self.end = time.perf_counter()
print(f"代码块耗时: {self.end - self.start:.6f} 秒")
with ManagedTimer() as timer:
sum(x**2 for x in range(1000000))
# 自动打印耗时
4.2 NumPy核心操作实战
4.2.1 创建数组与基本属性
import numpy as np
# 从列表创建
arr1 = np.array([1, 2, 3, 4])
print(arr1, arr1.shape, arr1.dtype) # [1 2 3 4] (4,) int64
# 特殊数组
zeros = np.zeros((3, 4)) # 3x4全0
ones = np.ones((2, 3)) # 2x3全1
eye = np.eye(5) # 5x5单位矩阵
random_arr = np.random.rand(2, 3) # 均匀分布[0,1)
# 等差数列
lin = np.linspace(0, 10, 5) # [ 0. 2.5 5. 7.5 10. ]
print(lin)
# 查看属性
print("维度数:", arr1.ndim) # 1
print("元素总数:", arr1.size) # 4
print("每个元素字节:", arr1.itemsize) # 8 (int64)
4.2.2 索引与切片(重要)
arr = np.arange(12).reshape(3, 4) # 3行4列
print("原始数组:\n", arr)
# [[ 0 1 2 3]
# [ 4 5 6 7]
# [ 8 9 10 11]]
# 基本切片: [start:stop:step, start:stop:step]
print("第1行:", arr[0, :]) # [0 1 2 3]
print("第2列:", arr[:, 1]) # [1 5 9]
print("子矩阵(前2行, 1~3列):\n", arr[:2, 1:4])
# [[1 2 3]
# [5 6 7]]
# 整数数组索引(花式索引)
rows = np.array([0, 2])
cols = np.array([1, 3])
print("取(0,1)和(2,3)元素:", arr[rows, cols]) # [1, 11]
# 布尔索引(筛选大于5的元素)
mask = arr > 5
print("布尔掩码:\n", mask)
print("大于5的元素:", arr[mask]) # [ 6 7 8 9 10 11]
# 注意:花式索引返回的是副本,不是视图;基本切片返回视图(共享内存)
sub_view = arr[0:2, 0:2]
sub_view[0,0] = 100
print("修改视图后原数组受影响:\n", arr[0,0]) # 100
4.2.3 向量化运算与广播
# 逐元素运算
a = np.array([[1,2],[3,4]])
b = np.array([[5,6],[7,8]])
print("加法:\n", a + b)
print("乘法:\n", a * b) # 不是矩阵乘法,是Hadamard积
print("矩阵乘法:\n", a @ b) # 等价于 np.dot(a,b)
# 通用函数(ufunc)
print("开平方:\n", np.sqrt(a))
print("指数:\n", np.exp(a))
# 广播示例
c = np.array([10, 20]) # shape (2,)
print("广播加法(3x2 + 2):\n", a + c)
# a形状(2,2)与(2,)相加,(2,)扩展为(2,2) -> [[1+10,2+20],[3+10,4+20]] = [[11,22],[13,24]]
d = np.array([[10], [20]]) # shape (2,1)
print("广播加法(2x2 + 2x1):\n", a + d)
# (2,2)与(2,1)广播,列维度扩展 -> [[1+10,2+10],[3+20,4+20]] = [[11,12],[23,24]]
# 减均值除以标准差(标准化)的一行代码
data = np.random.rand(100, 10)
normalized = (data - data.mean(axis=0)) / data.std(axis=0)
print("标准化后均值接近0:", normalized.mean(axis=0).round(6))
4.2.4 形状变换与聚合
arr = np.arange(24)
print("原始形状:", arr.shape) # (24,)
# reshape
arr_3d = arr.reshape(2, 3, 4)
print("3D形状:", arr_3d.shape) # (2,3,4)
# 展平(flatten vs ravel)
flat = arr_3d.flatten() # 返回副本
ravel = arr_3d.ravel() # 返回视图(尽可能)
print("展平后长度:", flat.size)
# 聚合函数
print("总和:", arr.sum())
print("行方向均值:", arr_3d.mean(axis=1)) # 对中间维度求平均,输出(2,4)
print("最大值的索引:", arr.argmax())
4.3 Pandas数据加载与预处理
import pandas as pd
# 创建一个模拟数据集
data = {
'feature1': [1.2, 2.3, 3.1, np.nan, 5.0],
'feature2': [10, 20, 30, 40, 50],
'label': [0, 1, 0, 1, 1]
}
df = pd.DataFrame(data)
print("原始DataFrame:\n", df)
# 1. 处理缺失值
print("缺失值统计:\n", df.isnull().sum())
df['feature1'].fillna(df['feature1'].mean(), inplace=True) # 均值填充
print("填充后:\n", df)
# 2. 特征缩放(Min-Max归一化)
from sklearn.preprocessing import MinMaxScaler # 也可手写
scaler = MinMaxScaler()
df[['feature1', 'feature2']] = scaler.fit_transform(df[['feature1', 'feature2']])
print("归一化后:\n", df)
# 3. 划分特征与标签
X = df[['feature1', 'feature2']].values # 转为numpy数组
y = df['label'].values
print("X形状:", X.shape, " y:", y)
4.4 面向对象实战:自定义数据集类
import numpy as np
class SimpleDataset:
"""自定义数据集类,模拟TensorFlow的Dataset接口"""
def __init__(self, X, y, batch_size=32, shuffle=True):
self.X = np.asarray(X)
self.y = np.asarray(y)
self.batch_size = batch_size
self.shuffle = shuffle
self.num_samples = len(self.X)
self.indices = np.arange(self.num_samples)
if self.shuffle:
np.random.shuffle(self.indices)
self.current_idx = 0
def __iter__(self):
"""使类实例可迭代,用于for循环"""
self.current_idx = 0
if self.shuffle:
np.random.shuffle(self.indices)
return self
def __next__(self):
"""每次迭代返回一个batch"""
if self.current_idx >= self.num_samples:
raise StopIteration
start = self.current_idx
end = min(self.current_idx + self.batch_size, self.num_samples)
batch_indices = self.indices[start:end]
X_batch = self.X[batch_indices]
y_batch = self.y[batch_indices]
self.current_idx = end
return X_batch, y_batch
def __len__(self):
"""返回batch数量"""
return (self.num_samples + self.batch_size - 1) // self.batch_size
# 测试数据集
X_demo = np.random.rand(100, 5)
y_demo = np.random.randint(0, 2, size=100)
dataset = SimpleDataset(X_demo, y_demo, batch_size=16, shuffle=True)
for epoch in range(2):
print(f"Epoch {epoch+1}")
for batch_x, batch_y in dataset:
print(f"batch shape: {batch_x.shape}, labels: {batch_y.shape}")
# 每个epoch结束会自动重新shuffle(因为__iter__中重排)
4.5 Matplotlib可视化基础
import matplotlib.pyplot as plt
# 创建模拟损失曲线
epochs = np.arange(1, 101)
loss = 1.0 / (epochs + 10) + np.random.normal(0, 0.01, size=100)
plt.figure(figsize=(10, 5))
plt.subplot(1, 2, 1)
plt.plot(epochs, loss, 'b-', label='Training Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.title('Loss Curve')
plt.legend()
plt.grid(True)
# 散点图:特征与标签的关系
x_data = np.random.randn(200)
y_data = 2 * x_data + 1 + np.random.randn(200) * 0.3
plt.subplot(1, 2, 2)
plt.scatter(x_data, y_data, alpha=0.5, c='red', edgecolors='k')
plt.xlabel('Feature X')
plt.ylabel('Target Y')
plt.title('Scatter with Noise')
plt.tight_layout()
plt.show()
5. 案例实操演练
案例:从CSV文件中加载房价数据,完成预处理并构建简单的线性回归模型(使用NumPy手动实现梯度下降)
本案例整合Pandas数据加载、NumPy向量化运算、自定义训练循环,不使用TensorFlow高层API,加深对底层原理的理解。
5.1 生成模拟房价数据集
import numpy as np
import pandas as pd
# 生成1000条数据,特征:面积(平米)、卧室数量、房龄(年)
np.random.seed(42)
n_samples = 1000
area = np.random.normal(100, 30, n_samples) # 面积 100±30
bedrooms = np.random.randint(1, 5, n_samples) # 卧室 1~4
age = np.random.uniform(0, 50, n_samples) # 房龄 0~50
# 真实权重: price = 5000*area + 20000*bedrooms - 1000*age + 50000 + noise
true_weights = np.array([5000, 20000, -1000])
bias = 50000
noise = np.random.normal(0, 20000, n_samples)
price = (area * true_weights[0] + bedrooms * true_weights[1] + age * true_weights[2] + bias + noise).astype(np.float32)
# 构建DataFrame并保存为CSV
df = pd.DataFrame({'area': area, 'bedrooms': bedrooms, 'age': age, 'price': price})
df.to_csv('house_prices.csv', index=False)
print("数据样例:\n", df.head())
5.2 使用Pandas加载与预处理
# 加载数据
df = pd.read_csv('house_prices.csv')
print("数据形状:", df.shape)
print("缺失值:\n", df.isnull().sum())
# 提取特征和标签
X_raw = df[['area', 'bedrooms', 'age']].values.astype(np.float32)
y_raw = df['price'].values.astype(np.float32).reshape(-1, 1)
# 标准化特征 (Z-score)
mean = X_raw.mean(axis=0)
std = X_raw.std(axis=0)
X = (X_raw - mean) / std
# 添加一列1作为偏置的系数(将偏置纳入权重矩阵)
X_with_bias = np.c_[X, np.ones((n_samples, 1))] # shape (1000, 4)
# 分割训练集和测试集 (80% train, 20% test)
split = int(0.8 * n_samples)
X_train, X_test = X_with_bias[:split], X_with_bias[split:]
y_train, y_test = y_raw[:split], y_raw[split:]
print("训练集形状:", X_train.shape, y_train.shape)
5.3 NumPy实现批量梯度下降
# 初始化参数 w (4个权重,最后一个对应偏置)
w = np.random.randn(4, 1).astype(np.float32) * 0.01
learning_rate = 0.01
epochs = 500
batch_size = 64
loss_history = []
# 训练
for epoch in range(epochs):
# 随机打乱数据(简单起见,按顺序分批)
indices = np.random.permutation(len(X_train))
X_shuffled = X_train[indices]
y_shuffled = y_train[indices]
epoch_loss = 0.0
for i in range(0, len(X_train), batch_size):
X_batch = X_shuffled[i:i+batch_size]
y_batch = y_shuffled[i:i+batch_size]
# 前向传播
y_pred = X_batch @ w
loss = np.mean((y_pred - y_batch) ** 2) / 2 # MSE/2
# 反向传播:梯度 dW = X_batch.T @ (y_pred - y_batch) / batch_size
grad = (X_batch.T @ (y_pred - y_batch)) / len(X_batch)
# 更新参数
w -= learning_rate * grad
epoch_loss += loss * len(X_batch)
epoch_loss /= len(X_train)
loss_history.append(epoch_loss)
if (epoch+1) % 100 == 0:
print(f"Epoch {epoch+1}, Loss: {epoch_loss:.2f}")
# 测试集评估
y_pred_test = X_test @ w
test_loss = np.mean((y_pred_test - y_test) ** 2) / 2
print(f"测试集MSE/2: {test_loss:.2f}")
print(f"学习到的权重: {w.flatten()}") # 接近 [5000, 20000, -1000, 50000] 但经过标准化,需要还原
5.4 结果可视化
import matplotlib.pyplot as plt
# 绘制损失下降曲线
plt.plot(loss_history)
plt.xlabel('Epoch')
plt.ylabel('Loss (MSE/2)')
plt.title('Training Loss')
plt.yscale('log')
plt.grid(True)
plt.show()
# 绘制预测值与真实值的散点图
plt.scatter(y_test, y_pred_test, alpha=0.5)
plt.plot([y_test.min(), y_test.max()], [y_test.min(), y_test.max()], 'r--', lw=2)
plt.xlabel('True Price')
plt.ylabel('Predicted Price')
plt.title('Prediction vs True')
plt.grid(True)
plt.show()
6. 常见坑点与排错总结
6.1 NumPy坑点
-
坑1:
np.array不指定dtype时,整数列表默认为int64,可能导致后续浮点运算结果截断。
解决:创建时加上dtype=np.float32或使用astype转换。 -
坑2:花式索引与切片混淆,误以为花式索引返回视图,修改后影响原数组。
解决:花式索引始终返回副本,如需视图,使用np.take并设置out参数较为复杂;设计时避免对该结果进行写操作。 -
坑3:广播维度不匹配的错误信息不易理解。
解决:检查两个数组的shape,手动模拟广播:从尾部对齐,缺失维度补1,任一轴长度不等于1且不相等则报错。
6.2 Pandas坑点
-
坑4:
pd.read_csv读取大文件时内存不足。
解决:使用chunksize参数分块读取,例如for chunk in pd.read_csv('large.csv', chunksize=10000): process(chunk)。 -
坑5:
df.apply使用自定义Python函数导致极慢。
解决:优先使用向量化操作(df['col'] * 2);若必须逐行,考虑swifter库或转换为NumPy数组。
6.3 面向对象坑点
-
坑6:在
__init__中定义可变默认参数(如def __init__(self, data=[]))导致实例间共享。
解决:使用None作为默认值,内部再创建新列表。 -
坑7:子类重写
__init__时忘记调用super().__init__(),导致父类属性未初始化。
解决:显式调用super().__init__(*args, **kwargs)。
6.4 性能误区
-
误区1:在循环内重复调用
np.append或np.concatenate导致大量内存拷贝。
正确做法:先预分配列表收集结果,最后一次性转换为数组。 -
误区2:对所有数据都使用
pandas而非numpy,导致不必要的开销。
正确做法:表格型数据且需复杂索引时用Pandas;纯数值矩阵运算用NumPy。
7. 知识点总结 + 课后作业
7.1 核心知识点梳理
- Python进阶:列表推导式(简洁高效)、生成器(惰性求值节省内存)、装饰器(横切关注点)、上下文管理器(资源自动管理)。
- NumPy:
ndarray多维数组、向量化运算比Python循环快1~2个数量级、广播规则、索引切片(基本切片是视图,花式索引是副本)、通用函数(ufunc)。 - Pandas:
DataFrame表结构、缺失值处理、特征缩放、与NumPy无缝转换。 - 面向对象:类继承与多态、
@property、类方法/静态方法、__iter__与__next__实现可迭代数据集类。 - 可视化:Matplotlib 折线图、散点图的基本绘制。
7.2 基础作业
- 使用列表推导式生成一个包含1~100中所有能被3或5整除的数的列表。
- 创建一个5x5的随机整数矩阵(范围0~100),输出其最大值、最小值及所有元素的和。
- 编写一个装饰器
@repeat(n),使得被装饰函数自动调用n次,并返回结果列表。
7.3 进阶实操作业
任务:自定义标准化类
实现一个StandardScaler类,包含以下方法:
fit(X):计算X的均值和方法(要求X为NumPy二维数组)。transform(X):根据fit计算的参数标准化X。fit_transform(X):同时拟合和变换。- 支持
inverse_transform将标准化后的数据还原。
要求:
- 使用面向对象,避免冗余代码。
- 添加属性
mean_和std_,如果是fit后调用则存在,否则抛出NotFittedError。 - 对测试集使用训练集的均值和标准差进行标准化(模拟真实场景)。
- 对比手动实现与
sklearn.preprocessing.StandardScaler结果是否一致。
7.4 思考拓展题
- 生成器相比列表,在训练深度学习模型时具体有哪些优势?请结合
tf.data.Dataset.from_generator说明。 - NumPy的广播机制如果使用不当,可能会意外创建巨大的中间数组(如形状(10000,10000)),导致内存爆炸。如何通过
np.einsum或显式循环避免? - 在自定义数据集类中,如果希望支持
shuffle=True且每个epoch的shuffle不同,但又要保证多次迭代时数据可复现(通过设置随机种子),应该如何设计__iter__方法?
下一课预告:Anaconda开发环境搭建——我们将学习如何使用Conda管理多个Python环境、配置国内镜像源加速下载、统一管理项目依赖,为后续复杂项目的环境隔离打下坚实基础。同时,也会讲解如何在不同的环境中安装TensorFlow GPU版本,避免依赖冲突。
🔗《TensorFlow2.x: 深度学习入门到高阶实战教程》系列课程导航
第一部分:基础入门(1-10 课)
第二部分:神经网络核心(11-25 课)
第三部分:进阶网络与框架高阶(26-40 课)
第四部分:企业实战与项目落地(41-50 课)
🌟 感谢您耐心阅读到这里!
💡 如果本文对您有所启发欢迎:
👍 点赞📌 收藏 📤 分享给更多需要的伙伴。
🗣️ 期待在评论区看到您的想法, 共同进步。
🔔 关注我,持续获取更多干货内容~
🤗 我们下篇文章见~
更多推荐



所有评论(0)