|
### TensorFlow 与 Keras 的关系
**TensorFlow** 是一个端到端的开源机器学习平台,性能好,但代码风格偏底层。
**Keras** 是一个用 Python 编写的高级神经网络 API,它以 TensorFlow、CNTK 等框架为后端。
> 为了让开发者更方便的使用 TensorFlow,社区编写了一套更加简单易用的 API,并命名为 **Keras**。
**总结:**
- TensorFlow 是底层计算引擎
- Keras 是封装在 TensorFlow 之上的高层 API
- 通过 Keras 可以用更少的代码完成神经网络搭建
|
|
### TF1 + Keras2 环境搭建(Conda)
推荐使用 Ubuntu,新建一个用户进行安装。通过 Keras 调用 TensorFlow,有 GPU 环境就安装 GPU 版本的 TensorFlow(Keras 本身无 CPU/GPU 之分)。
```bash
# 查看 conda 环境列表
conda env list
# 创建 Python 3.6 虚拟环境
conda create --name py36 python=3.6
conda activate py36
# 安装基础科学计算包
pip install numpy==1.18.1
pip install matplotlib==3.3.4
pip install pandas==1.1.5
pip install scikit-learn==0.24.2
# 安装 TensorFlow 1.15 和 Keras 2.0
conda install tensorflow=1.15.0
pip install Keras==2.0.0
# Windows 环境补充安装
pip install win_unicode_console
# 查看自定义 python 模块路径
python -c "print('\n'.join(__import__('sys').path))"
```
**验证安装:**
```python
import tensorflow as tf
print(tf.test.is_gpu_available())
```
```python
import keras
# 输出: Using TensorFlow backend.
```
**卸载命令:**
```bash
conda uninstall tensorflow=1.15.0
conda uninstall tensorflow-gpu=1.15.0
pip uninstall tensorflow-gpu=1.15.0
```
**常见问题:**
> 警告:`Passing (type, 1) or '1type' as a synonym of type is deprecated`
**解决方法:** 修改 `dtype.py` 对应行的代码,将 `np.dtype([("quint8", np.uint8, 1)])` 修改为 `np.dtype([("quint8", np.uint8, (1,))])`
|
|
### TF2 + Keras2 环境搭建(Conda / Windows)
> Python 3.11 不兼容,推荐使用 **Python 3.10**(截至 2024-06-12)
```bash
# 创建 Python 3.10 环境
conda create -n py310 python=3.10
conda activate py310
# 安装依赖
conda install mingw libpython
conda install theano
# 安装科学计算和依赖包(-U 表示更新安装)
pip install -U numpy==1.22.4
pip install -U pandas==2.1.0
pip install -U protobuf==3.9.2
pip install -U tensorflow-io-gcs-filesystem==0.23.1
pip install -U libclang==13.0.0
# 安装 TensorFlow 2.10 和 Keras 2.10
pip install -U tensorflow==2.10.0
pip install -U keras==2.10.0
# 安装可视化
pip install -U matplotlib==3.8.4
conda deactivate
```
|
|
### 使用 Micromamba 安装 TensorFlow & Keras
[Micromamba](https://mamba.readthedocs.io/en/latest/user_guide/micromamba.html) 是一个轻量级、快速的 conda 包管理器替代品,用 C++ 编写,启动速度快,适合在服务器和 CI 环境中使用。
#### 1. 安装 Micromamba
```bash
# Linux (x86_64)
curl -Ls https://micro.mamba.pm/api/micromamba/linux-64/latest | tar -xvj bin/micromamba
# 或者使用 shell 初始化
"${SHELL}" <(curl -L micro.mamba.pm/install.sh)
```
#### 2. 创建 TF1 环境(Python 3.6)
```bash
micromamba create -n tf1 python=3.6 -c conda-forge
micromamba activate tf1
pip install numpy==1.18.1 matplotlib==3.3.4 pandas==1.1.5 scikit-learn==0.24.2
pip install tensorflow==1.15.0
pip install Keras==2.0.0
```
#### 3. 创建 TF2 环境(Python 3.10)
```bash
micromamba create -n tf2 python=3.10 -c conda-forge
micromamba activate tf2
pip install -U numpy==1.22.4 pandas==2.1.0
pip install -U protobuf==3.9.2 tensorflow-io-gcs-filesystem==0.23.1 libclang==13.0.0
pip install -U tensorflow==2.10.0 keras==2.10.0
pip install -U matplotlib==3.8.4
```
#### 4. 纯 Micromamba 安装 TF2(不使用 pip)
> 直接通过 conda-forge 频道安装 TensorFlow,无需 pip
```bash
# 创建环境并一次性安装所有包
micromamba create -n tf2-mamba python=3.10 -c conda-forge
micromamba activate tf2-mamba
# 通过 micromamba 安装 TensorFlow 及相关包
micromamba install tensorflow=2.10 keras=2.10 -c conda-forge
micromamba install numpy pandas matplotlib scikit-learn -c conda-forge
# 或者创建环境时直接指定所有包
micromamba create -n tf2-all python=3.10 tensorflow=2.10 keras=2.10 numpy pandas matplotlib scikit-learn -c conda-forge
micromamba activate tf2-all
```
**验证安装:**
```python
import tensorflow as tf
print(tf.__version__) # 2.10.0
import keras
print(keras.__version__) # 2.10.0
```
#### 5. GPU 版本安装(Linux + CUDA)
> conda-forge 的 `tensorflow` 包本身已包含 CUDA 支持,无需单独安装 `tensorflow-gpu`。关键是通过 micromamba 管理 CUDA/cuDNN 版本。
**通用安装(TF 2.10 + CUDA 11.2):**
```bash
# 一次性创建 GPU 环境,安装所有包
micromamba create -n tf2-gpu python=3.10 \
tensorflow=2.10 keras=2.10 \
cuda-toolkit=11.2 cudnn=8.1 \
numpy pandas matplotlib scikit-learn \
-c conda-forge -c nvidia
micromamba activate tf2-gpu
```
**针对 RTX 4070 + CUDA 12.7 的安装(TF 2.18 + CUDA 12.5):**
> 显卡:NVIDIA GeForce RTX 4070 Laptop,驱动 566.24,CUDA Version: 12.7
>
> CUDA 12.7 驱动向下兼容,TF 2.18 使用 CUDA 12.5 + cuDNN 9.3 即可正常调用 GPU
- 从 TensorFlow 2.11 开始,GPU 支持不再包含在主包中。
```bash
# 创建匹配 CUDA 12.x 的 TF2 环境
micromamba create -n tf2-gpu-rtx python=3.12 \
tensorflow=2.18 \
cuda-toolkit=12.5 cudnn=9.3 \
numpy pandas matplotlib scikit-learn \
-c conda-forge -c nvidia
# 1. 激活环境
micromamba activate tf2-gpu-rtx
# 2. 卸载 conda 安装的 tensorflow(保留其他包)
micromamba remove tensorflow -y
# 3. 如果之前也混用过 pip 安装,再执行一次确保干净
pip uninstall tensorflow tensorflow-cpu -y
# 4. 安装 pip 的 GPU 版本(会自动带上所需的 CUDA/cuDNN 库)
pip install "tensorflow[and-cuda]==2.18.0"
# 5. 验证
python -c "import tensorflow as tf; print(tf.config.list_physical_devices('GPU'))"
micromamba activate tf2-gpu-rtx
```
**验证 GPU 是否可用:**
```python
import tensorflow as tf
print(tf.__version__) # 2.18.0
print(tf.config.list_physical_devices('GPU')) # 应列出 GPU 设备
# 查看 GPU 详细信息
gpu_devices = tf.config.list_physical_devices('GPU')
if gpu_devices:
for gpu in gpu_devices:
print(f" - {gpu.name}")
```
**注意事项:**
- CUDA Toolkit 和 cuDNN 版本需与 TensorFlow 版本匹配
| TF 版本 | CUDA | cuDNN | Python |
|---------|------|-------|--------|
| 2.10 | 11.2 | 8.1 | 3.7–3.10 |
| 2.15 | 12.2 | 8.9 | 3.9–3.11 |
| 2.16 | 12.3 | 8.9 | 3.9–3.12 |
| 2.18 | 12.5 | 9.3 | 3.9–3.12 |
- NVIDIA 驱动向下兼容:你的 CUDA 12.7 驱动可以运行 CUDA 12.5 的 TF
- Linux 环境推荐使用,Windows 下 GPU 支持建议使用 WSL2 或 pip 安装
#### 6. 常用 Micromamba 命令
```bash
# 查看环境列表
micromamba env list
# 删除环境
micromamba env remove -n tf1
# 导出环境
micromamba env export -n tf2 > tf2_env.yml
# 从文件创建环境
micromamba create -n tf2 -f tf2_env.yml
```
```
xt@qisan:~$ nvidia-smi
Sat Jun 6 15:21:24 2026
+-----------------------------------------------------------------------------------------+
| NVIDIA-SMI 565.57.01 Driver Version: 566.24 CUDA Version: 12.7 |
|-----------------------------------------+------------------------+----------------------+
| GPU Name Persistence-M | Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap | Memory-Usage | GPU-Util Compute M. |
| | | MIG M. |
|=========================================+========================+======================|
| 0 NVIDIA GeForce RTX 4070 ... On | 00000000:01:00.0 On | N/A |
| N/A 53C P8 4W / 70W | 538MiB / 8188MiB | 12% Default |
| | | N/A |
+-----------------------------------------+------------------------+----------------------+
+-----------------------------------------------------------------------------------------+
| Processes: |
| GPU GI CI PID Type Process name GPU Memory |
| ID ID Usage |
|=========================================================================================|
| No running processes found |
+-----------------------------------------------------------------------------------------+
```
|
|
### TF2 环境 pip list 参考列表
> 以下为 `py310` 环境安装后的完整包列表,供对比参考
| 包名 | 版本 |
|------|------|
| keras | 2.10.0 |
| Keras-Preprocessing | 1.1.2 |
| tensorflow | 2.10.0 |
| tensorflow-estimator | 2.10.0 |
| tensorflow-io-gcs-filesystem | 0.23.1 |
| tensorboard | 2.10.0 |
| numpy | 1.22.4 |
| pandas | 2.1.0 |
| matplotlib | 3.8.4 |
| scipy | 1.7.3 |
| protobuf | 3.9.2 |
| libclang | 13.0.0 |
| h5py | 3.11.0 |
| scikit-learn | — |
| pillow | 10.3.0 |
| Theano | 1.0.5 |
| pygpu | 0.7.6 |
| jupyterlab | 4.2.2 |
| notebook | 7.2.1 |
|
|
### API 定义
```python
tf.keras.layers.Conv2D(
filters,
kernel_size,
strides=(1, 1),
padding='valid',
data_format=None,
dilation_rate=(1, 1),
groups=1,
activation=None,
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='zeros',
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs,
)
```
|
|
### 参数说明
- filters
- int
- 输出空间的维度(即卷积核数量)。决定了输出特征图的通道数
- kernel_size
- int/tuple
- 卷积核的宽度和高度。可以是单个整数(正方形核)或两个整数的元组
- strides
- int/tuple
- 卷积的步长。默认为 `(1, 1)`,表示在宽度和高度方向上的步长
- padding
- str
- 填充模式:`'valid'` 表示不填充(输出尺寸缩小),`'same'` 表示填充使输出尺寸与输入相同(当 strides=1 时)
- data_format
- str
- 输入数据的格式:`'channels_last'`(默认,`(batch, height, width, channels)`)或 `'channels_first'`(`(batch, channels, height, width)`)
- dilation_rate
- int/tuple
- 膨胀卷积的膨胀率。用于扩大卷积核的感受野
- groups
- int
- 分组卷积的组数。默认为 1(普通卷积)
- activation
- str/callable
- 激活函数。如 `'relu'`、`'sigmoid'`、`'tanh'` 或 `None`(线性)
- use_bias
- bool
- 是否使用偏置项
- kernel_initializer
- str/callable
- 卷积核权重矩阵的初始化器
- bias_initializer
- str/callable
- 偏置向量的初始化器
- kernel_regularizer
- str/callable
- 卷积核权重的正则化函数
- bias_regularizer
- str/callable
- 偏置的正则化函数
- activity_regularizer
- str/callable
- 输出的正则化函数
- kernel_constraint
- str/callable
- 卷积核权重的约束函数
- bias_constraint
- str/callable
- 偏置的约束函数
|
|
### 使用示例
```python
import tensorflow as tf
import numpy as np
# 创建随机输入数据:batch_size=2, height=28, width=28, channels=3
x = np.random.randn(2, 28, 28, 3).astype(np.float32)
print(f"输入 shape: {x.shape}")
# 输出 shape: (2, 28, 28, 3)
# 创建 Conv2D 层
conv_layer = tf.keras.layers.Conv2D(
filters=32, # 输出 32 个特征图
kernel_size=(3, 3), # 3x3 卷积核
strides=(1, 1), # 步长为 1
padding='same', # 保持尺寸
activation='relu' # ReLU 激活
)
# 应用卷积
output = conv_layer(x)
print(f"输出 shape: {output.shape}")
# 输出 shape: (2, 28, 28, 32)
# batch_size 不变,height/width 因 padding='same' 保持不变,channels 变为 filters=32
# 查看卷积核权重 shape
print(f"卷积核权重 shape: {conv_layer.kernel.shape}")
# 卷积核权重 shape: (3, 3, 3, 32)
# (kernel_height, kernel_width, input_channels, output_filters)
```
**不同 padding 和 strides 的影响:**
```python
# padding='valid' 时的输出尺寸计算
conv_valid = tf.keras.layers.Conv2D(filters=16, kernel_size=3, strides=2, padding='valid')
out_valid = conv_valid(x)
print(f"padding='valid' 输出 shape: {out_valid.shape}")
# 输出 shape: (2, 13, 13, 16)
# 计算公式:output = (input - kernel_size + 2*padding) / strides + 1
# height = (28 - 3 + 0) / 2 + 1 = 13
# padding='same' 时的输出尺寸
conv_same = tf.keras.layers.Conv2D(filters=16, kernel_size=3, strides=2, padding='same')
out_same = conv_same(x)
print(f"padding='same' 输出 shape: {out_same.shape}")
# 输出 shape: (2, 14, 14, 16)
# 当 padding='same' 时,输出尺寸为 ceil(input_size / strides)
```
|
|
### API 定义
```python
tf.keras.layers.MaxPool2D(
pool_size=(2, 2),
strides=None,
padding='valid',
data_format=None,
name=None,
**kwargs
)
```
|
|
### 参数说明
- pool_size
- int/tuple
- 池化窗口的大小。默认为 `(2, 2)`,表示在 2x2 窗口内取最大值
- strides
- int/tuple/None
- 池化的步长。默认为 `pool_size`,表示不重叠池化
- padding
- str
- 填充模式:`'valid'`(默认)或 `'same'`
- data_format
- str
- 输入数据的格式:`'channels_last'`(默认)或 `'channels_first'`
- name
- str
- 层的名称
|
|
### 使用示例
```python
import tensorflow as tf
import numpy as np
# 创建输入数据:batch_size=1, height=8, width=8, channels=1
x = np.arange(64).reshape(1, 8, 8, 1).astype(np.float32)
print(f"输入 shape: {x.shape}")
print(f"输入数据:\n{x[0, :, :, 0]}")
# 输出 shape: (1, 8, 8, 1)
# 创建 MaxPool2D 层
maxpool_layer = tf.keras.layers.MaxPool2D(
pool_size=(2, 2), # 2x2 池化窗口
strides=None, # 默认为 pool_size
padding='valid' # 不填充
)
# 应用池化
output = maxpool_layer(x)
print(f"\n输出 shape: {output.shape}")
# 输出 shape: (1, 4, 4, 1)
# 尺寸计算:output = input / pool_size = 8 / 2 = 4
print(f"输出数据:\n{output[0, :, :, 0]}")
```
**不同池化参数的效果:**
```python
# 使用 strides=1 的池化(滑动窗口)
maxpool_stride1 = tf.keras.layers.MaxPool2D(pool_size=2, strides=1, padding='same')
out_stride1 = maxpool_stride1(x)
print(f"strides=1 输出 shape: {out_stride1.shape}")
# 输出 shape: (1, 8, 8, 1)
# strides=1 时输出尺寸保持不变(padding='same')
# 使用更大的池化窗口
maxpool_4x4 = tf.keras.layers.MaxPool2D(pool_size=4, strides=4, padding='valid')
out_4x4 = maxpool_4x4(x)
print(f"pool_size=4 输出 shape: {out_4x4.shape}")
# 输出 shape: (1, 2, 2, 1)
# 尺寸计算:8 / 4 = 2
```
|
|
### API 定义
```python
tf.keras.layers.Flatten(
data_format=None,
**kwargs
)
```
|
|
### 参数说明
- data_format
- str
- 输入数据的格式:`'channels_last'`(默认)或 `'channels_first'`
**功能说明:**
Flatten 层将多维输入(除了 batch 维度)展平为一维向量。通常用于从卷积层过渡到全连接层。
|
|
### 使用示例
```python
import tensorflow as tf
import numpy as np
# 创建输入数据:batch_size=2, height=4, width=4, channels=3
x = np.random.randn(2, 4, 4, 3).astype(np.float32)
print(f"输入 shape: {x.shape}")
# 输出 shape: (2, 4, 4, 3)
# 创建 Flatten 层
flatten_layer = tf.keras.layers.Flatten()
# 应用展平
output = flatten_layer(x)
print(f"输出 shape: {output.shape}")
# 输出 shape: (2, 48)
# batch_size 保持不变,其余维度相乘:4 * 4 * 3 = 48
# 验证展平后的元素数量
print(f"展平前元素总数: {x.shape[1] * x.shape[2] * x.shape[3]}")
# 展平前元素总数: 48
# 典型使用场景:Conv -> Pool -> Flatten -> Dense
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3), activation='relu'),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Flatten(), # 将 (batch, 7, 7, 64) 展平为 (batch, 3136)
tf.keras.layers.Dense(64, activation='relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
# 查看各层输出形状
for layer in model.layers:
print(f"{layer.__class__.__name__}: 输入 shape -> 输出 shape")
```
|
|
### API 定义
```python
tf.keras.layers.Dense(
units,
activation=None,
use_bias=True,
kernel_initializer='glorot_uniform',
bias_initializer='zeros',
kernel_regularizer=None,
bias_regularizer=None,
activity_regularizer=None,
kernel_constraint=None,
bias_constraint=None,
**kwargs
)
```
|
|
### 参数说明
- units
- int
- 输出空间的维度(即神经元数量)
- activation
- str/callable
- 激活函数。如 `'relu'`、`'sigmoid'`、`'softmax'` 或 `None`(线性)
- use_bias
- bool
- 是否使用偏置项
- kernel_initializer
- str/callable
- 权重矩阵的初始化器
- bias_initializer
- str/callable
- 偏置向量的初始化器
- kernel_regularizer
- str/callable
- 权重的正则化函数
- bias_regularizer
- str/callable
- 偏置的正则化函数
- activity_regularizer
- str/callable
- 输出的正则化函数
- kernel_constraint
- str/callable
- 权重的约束函数
- bias_constraint
- str/callable
- 偏置的约束函数
**功能说明:**
Dense 层实现全连接操作:`output = activation(dot(input, kernel) + bias)`
|
|
### 使用示例
```python
import tensorflow as tf
import numpy as np
# 创建输入数据:batch_size=3, features=5
x = np.random.randn(3, 5).astype(np.float32)
print(f"输入 shape: {x.shape}")
# 输出 shape: (3, 5)
# 创建 Dense 层
dense_layer = tf.keras.layers.Dense(
units=10, # 输出 10 个神经元
activation='relu', # ReLU 激活
use_bias=True # 使用偏置
)
# 应用全连接
output = dense_layer(x)
print(f"输出 shape: {output.shape}")
# 输出 shape: (3, 10)
# batch_size 保持不变,features 变为 units=10
# 查看权重和偏置的 shape
print(f"权重 matrix shape: {dense_layer.kernel.shape}")
# 权重 matrix shape: (5, 10)
# (input_features, output_units)
print(f"偏置 vector shape: {dense_layer.bias.shape}")
# 偏置 vector shape: (10,)
```
**常见激活函数:**
```python
# ReLU 激活(最常用)
dense_relu = tf.keras.layers.Dense(64, activation='relu')
# Sigmoid 激活(用于二分类输出)
dense_sigmoid = tf.keras.layers.Dense(1, activation='sigmoid')
# Softmax 激活(用于多分类输出)
dense_softmax = tf.keras.layers.Dense(10, activation='softmax')
# Tanh 激活
dense_tanh = tf.keras.layers.Dense(32, activation='tanh')
# 线性(无激活)
dense_linear = tf.keras.layers.Dense(16, activation=None)
```
|
|
### API 定义
```python
tf.keras.layers.Dropout(
rate,
noise_shape=None,
seed=None,
**kwargs
)
```
|
|
### 参数说明
- rate
- float
- 丢弃比例。取值范围 [0, 1),表示每个元素被丢弃的概率。如 `rate=0.5` 表示丢弃 50% 的神经元
- noise_shape
- tuple
- 用于确定二值 dropout mask 的形状
- seed
- int
- 随机种子
**功能说明:**
Dropout 是一种正则化技术,在训练过程中随机将部分神经元的输出设为 0,防止模型过拟合。
|
|
### 使用示例
```python
import tensorflow as tf
import numpy as np
# 创建输入数据
x = np.random.randn(2, 10).astype(np.float32)
print(f"输入 shape: {x.shape}")
# 输出 shape: (2, 10)
# 创建 Dropout 层
dropout_layer = tf.keras.layers.Dropout(
rate=0.5 # 丢弃 50% 的神经元
)
# 训练模式下应用 Dropout
tf.keras.backend.set_learning_phase(1) # 训练模式
output_train = dropout_layer(x, training=True)
print(f"训练模式输出 shape: {output_train.shape}")
# 输出 shape: (2, 10)
# 约 50% 的元素被置为 0
# 推理模式下不应用 Dropout
output_inference = dropout_layer(x, training=False)
print(f"推理模式输出 shape: {output_inference.shape}")
# 输出 shape: (2, 10)
# 输出保持不变(除了缩放)
```
**典型使用场景:**
```python
# 典型的网络结构:Conv -> Pool -> Dropout -> Dense
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Dropout(0.25), # 在卷积层后使用较小的 dropout
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128, activation='relu'),
tf.keras.layers.Dropout(0.5), # 在全连接层后使用较大的 dropout
tf.keras.layers.Dense(10, activation='softmax')
])
```
|
|
### API 定义
```python
tf.keras.layers.BatchNormalization(
axis=-1,
momentum=0.99,
epsilon=0.001,
center=True,
scale=True,
beta_initializer='zeros',
gamma_initializer='ones',
moving_mean_initializer='zeros',
moving_variance_initializer='ones',
beta_regularizer=None,
gamma_regularizer=None,
beta_constraint=None,
gamma_constraint=None,
synchronized=False,
**kwargs
)
```
|
|
### 参数说明
- axis
- int
- 需要归一化的轴。默认为 -1(通道维度)
- momentum
- float
- 移动平均的动量
- epsilon
- float
- 防止除零的小常数
- center
- bool
- 是否在输出中加上 beta 偏移
- scale
- bool
- 是否乘以 gamma 缩放
- beta_initializer
- str/callable
- beta 参数的初始化器
- gamma_initializer
- str/callable
- gamma 参数的初始化器
**功能说明:**
批归一化通过对每个 batch 的数据进行标准化(减均值、除方差),加速训练并提高模型稳定性。
|
|
### 使用示例
```python
import tensorflow as tf
import numpy as np
# 创建输入数据:batch_size=4, height=4, width=4, channels=3
x = np.random.randn(4, 4, 4, 3).astype(np.float32)
print(f"输入 shape: {x.shape}")
# 输出 shape: (4, 4, 4, 3)
# 创建 BatchNormalization 层
bn_layer = tf.keras.layers.BatchNormalization()
# 应用批归一化
output = bn_layer(x, training=True)
print(f"输出 shape: {output.shape}")
# 输出 shape: (4, 4, 4, 3)
# shape 保持不变,但数据被归一化
```
**典型使用场景:**
```python
# 在 Conv 层后使用 BatchNormalization
model = tf.keras.Sequential([
tf.keras.layers.Conv2D(32, (3, 3), input_shape=(28, 28, 1)),
tf.keras.layers.BatchNormalization(), # 在激活前使用 BN
tf.keras.layers.Activation('relu'),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Conv2D(64, (3, 3)),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.MaxPooling2D((2, 2)),
tf.keras.layers.Flatten(),
tf.keras.layers.Dense(128),
tf.keras.layers.BatchNormalization(),
tf.keras.layers.Activation('relu'),
tf.keras.layers.Dense(10, activation='softmax')
])
```
|
|
### 网络结构
下面构建一个用于 MNIST 手写数字识别的简单 CNN 网络,整合以上介绍的所有组件:
```
输入层: (28, 28, 1)
↓
Conv2D(32, 3×3, relu)
↓ shape: (28, 28, 32)
MaxPool2D(2×2)
↓ shape: (14, 14, 32)
Conv2D(64, 3×3, relu)
↓ shape: (14, 14, 64)
MaxPool2D(2×2)
↓ shape: (7, 7, 64)
Flatten
↓ shape: (3136,)
Dense(128, relu)
↓ shape: (128,)
Dropout(0.5)
↓
Dense(10, softmax)
↓ shape: (10,)
```
|
|
### 完整代码
```python
import tensorflow as tf
from tensorflow.keras import layers, models
# 1. 加载数据集
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
# 2. 数据预处理
x_train = x_train.reshape(-1, 28, 28, 1).astype('float32') / 255.0
x_test = x_test.reshape(-1, 28, 28, 1).astype('float32') / 255.0
print(f"训练集 shape: {x_train.shape}") # (60000, 28, 28, 1)
print(f"测试集 shape: {x_test.shape}") # (10000, 28, 28, 1)
# 3. 构建 CNN 模型
model = models.Sequential([
# 第一卷积块
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
layers.MaxPooling2D((2, 2)),
# 第二卷积块
layers.Conv2D(64, (3, 3), activation='relu'),
layers.MaxPooling2D((2, 2)),
# 展平并连接全连接层
layers.Flatten(),
layers.Dense(128, activation='relu'),
layers.Dropout(0.5),
# 输出层
layers.Dense(10, activation='softmax')
])
# 4. 查看模型结构
model.summary()
```
**模型输出示例:**
```
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
conv2d (Conv2D) (None, 28, 28, 32) 320
max_pooling2d (MaxPooling2D) (None, 14, 14, 32) 0
conv2d_1 (Conv2D) (None, 14, 14, 64) 18496
max_pooling2d_1 (MaxPooling2 (None, 7, 7, 64) 0
flatten (Flatten) (None, 3136) 0
dense (Dense) (None, 128) 401536
dropout (Dropout) (None, 128) 0
dense_1 (Dense) (None, 10) 1290
=================================================================
Total params: 421,642
Trainable params: 421,642
Non-trainable params: 0
```
|
|
### 训练与评估
```python
# 5. 编译模型
model.compile(
optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy']
)
# 6. 训练模型
history = model.fit(
x_train, y_train,
epochs=5,
batch_size=64,
validation_split=0.2,
verbose=1
)
# 7. 评估模型
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=0)
print(f'\n测试集准确率: {test_acc:.4f}')
# 8. 进行预测
predictions = model.predict(x_test[:5])
predicted_classes = tf.argmax(predictions, axis=1)
print(f"前5个样本的预测结果: {predicted_classes.numpy()}")
print(f"前5个样本的真实标签: {y_test[:5]}")
# 9. 绘制训练曲线(可选)
import matplotlib.pyplot as plt
plt.figure(figsize=(12, 4))
# 损失曲线
plt.subplot(1, 2, 1)
plt.plot(history.history['loss'], label='Train Loss')
plt.plot(history.history['val_loss'], label='Val Loss')
plt.title('Training and Validation Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
# 准确率曲线
plt.subplot(1, 2, 2)
plt.plot(history.history['accuracy'], label='Train Accuracy')
plt.plot(history.history['val_accuracy'], label='Val Accuracy')
plt.title('Training and Validation Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
```
**预期输出:**
```
Epoch 1/5
750/750 [==============================] - 10s 13ms/step - loss: 0.1864 - accuracy: 0.9436 - val_loss: 0.0645 - val_accuracy: 0.9811
...
Epoch 5/5
750/750 [==============================] - 9s 12ms/step - loss: 0.0386 - accuracy: 0.9879 - val_loss: 0.0367 - val_accuracy: 0.9903
测试集准确率: 0.9915
前5个样本的预测结果: [7 2 1 0 4]
前5个样本的真实标签: [7 2 1 0 4]
```
|