4、TensorFlow入门与模型构建:安装TensorFlow 2.x,用Keras Sequential API搭建一个简单的全连接网络

好,咱们进入正题。

上一章我们把环境搭好了,现在该动手写代码了。说实话,很多初学者一上来就想着搞复杂的CNN、RNN,结果连个全连接网络都写不利索。我个人习惯是,先跑通一个最简单的模型,再慢慢往上加东西。你想想看,地基都没打牢,盖什么高楼?

4.1 安装TensorFlow 2.x

安装这事,说简单也简单,说坑也多。我建议直接用pip安装,干净利落。

# 创建一个干净的虚拟环境(如果你还没做)
conda create -n tf2_env python=3.8
conda activate tf2_env

# 安装TensorFlow 2.x
pip install tensorflow==2.10.0

# 验证安装
python -c "import tensorflow as tf; print(tf.__version__)"

嗯,这里要注意。如果你用的是Apple Silicon芯片的Mac,建议装tensorflow-macos版本。我在项目里踩过这个坑,直接装普通版,跑起来慢得让人抓狂。

⚠️ 避坑指南: 我曾经在Windows上装TensorFlow 2.0,结果死活装不上。后来发现是Python版本太高了。记住,TensorFlow 2.x 对Python 3.8-3.10支持最好,别用3.11以上版本。

4.2 认识Keras Sequential API

Keras的Sequential API,说白了就是「搭积木」。你一层一层往上堆,模型就出来了。为什么我喜欢用这个?因为直观。你想想看,全连接网络不就是输入层、隐藏层、输出层串在一起吗?Sequential正好对应这个思路。

它的核心用法就三步:

  1. 创建模型对象model = tf.keras.Sequential()
  2. 往里面加层model.add(...)
  3. 编译模型model.compile(...)

就这么简单。我在项目中做过一个手势识别的小demo,就是用Sequential搭的,前后不到20行代码。

4.3 搭建一个全连接网络

好,咱们动手写一个。这个网络用来做手写数字识别(MNIST数据集),虽然老掉牙了,但作为入门例子再合适不过。

import tensorflow as tf
from tensorflow.keras import layers, models

# 1. 创建Sequential模型
model = models.Sequential()

# 2. 添加层
# 输入层:把28x28的图片展平成一维向量
model.add(layers.Flatten(input_shape=(28, 28)))

# 隐藏层1:128个神经元,激活函数用ReLU
model.add(layers.Dense(128, activation='relu'))

# 隐藏层2:64个神经元
model.add(layers.Dense(64, activation='relu'))

# 输出层:10个神经元(对应0-9十个数字),用softmax输出概率
model.add(layers.Dense(10, activation='softmax'))

# 3. 编译模型
model.compile(optimizer='adam',
              loss='sparse_categorical_crossentropy',
              metrics=['accuracy'])

# 4. 查看模型结构
model.summary()

💡 关键点解释:

  • Flatten:把二维图像拉成一维。28x28=784个像素点,变成784个输入特征。
  • Dense:全连接层。每个神经元和上一层的所有神经元都连接。
  • activation='relu':ReLU激活函数,说白了就是「负数变0,正数不变」。它能有效解决梯度消失问题。
  • softmax:把输出变成概率,所有输出加起来等于1。

4.4 模型参数的计算

你可能会问:这个模型到底有多少参数?咱们算一下。

输入维度 输出维度 参数数量
Flatten (28, 28) 784 0
Dense_1 784 128 784×128 + 128 = 100,480
Dense_2 128 64 128×64 + 64 = 8,256
Dense_3 64 10 64×10 + 10 = 650
总计 109,386

你看,一个简单的网络就有10万多个参数。这就是深度学习的「暴力美学」——用大量参数去拟合数据。不过,参数多不代表模型好。我在项目里见过有人堆了上千万参数,结果过拟合得一塌糊涂。

4.5 训练与评估

模型搭好了,得让它学东西。咱们用MNIST数据集来训练。

# 加载MNIST数据集
mnist = tf.keras.datasets.mnist
(x_train, y_train), (x_test, y_test) = mnist.load_data()

# 数据归一化:把像素值从0-255缩放到0-1之间
x_train, x_test = x_train / 255.0, x_test / 255.0

# 训练模型
history = model.fit(x_train, y_train, 
                    epochs=10, 
                    batch_size=32,
                    validation_split=0.2)

# 评估模型
test_loss, test_acc = model.evaluate(x_test, y_test, verbose=2)
print(f'\n测试集准确率: {test_acc:.4f}')

🔧 实用技巧:

  • epochs:训练轮数。我一般先设10轮看看效果,不够再加。
  • batch_size:每次喂多少数据。32是个常用值,显存不够就改小点。
  • validation_split:从训练集里切20%做验证。这样能实时看模型有没有过拟合。

跑完10轮,准确率大概在97%左右。嗯,对于这么简单的网络,这个结果已经不错了。你想想看,一个只有10万参数的小网络,就能识别手写数字,是不是挺神奇的?

4.6 保存与加载模型

训练完了,模型得保存下来。不然每次用都要重新训练,那多麻烦。

# 保存整个模型(包括结构和权重)
model.save('mnist_model.h5')

# 加载模型
loaded_model = tf.keras.models.load_model('mnist_model.h5')

# 用加载的模型做预测
predictions = loaded_model.predict(x_test[:5])

这里有个坑,我提醒一下。保存模型时,如果你用了自定义层或者自定义损失函数,加载的时候要指定custom_objects参数。不然会报错。我曾经因为这个折腾了一下午。

4.7 小结与思考

这一章咱们干了三件事:装环境、搭网络、跑训练。看起来简单,但这是所有深度学习的基础。你想想看,后面要学的CNN、RNN,本质上都是在Sequential的基础上加一些特殊层。

最后留个思考题:如果我把隐藏层的神经元数量改成256和128,参数数量会变成多少?训练时间会变长多少?准确率能提升吗?

下一章,咱们会深入聊聊数据预处理。别小看这一步,我在项目里见过太多人模型写得很漂亮,结果数据没处理好,训练出来的模型根本不能用。嗯,到时候咱们细说。