新手也能懂!手把手教你用 TensorFlow 搭建神经网络(附完整代码
prediction = model.predict(test_image_input.reshape(1, 784)) # 要把输入转成(1,784)(1个样本,784维)。赶紧把代码复制到本地跑一遍,动手实践才是最好的学习方式!print("训练集图片形状:", x_train.shape) # 输出 (60000, 28, 28) → 6万张图,每张28x28像素。print("训练集标
大家好!最近很多朋友问我:“想入门深度学习,可神经网络总觉得抽象,怎么才能亲手搭一个出来?” 其实不用怕 —— 今天就用TensorFlow/Keras(最适合新手的深度学习框架),带大家从 0 到 1 搭建一个能识别手写数字的神经网络,全程附可运行代码,看完跟着敲一遍,你就能入门神经网络搭建!
一、先搞懂:神经网络到底是什么?
简单说,神经网络是模仿人脑神经元结构设计的 “计算模型”,核心是通过 “层” 的堆叠,让计算机从数据中学习规律。比如今天要做的 “手写数字识别”,就是让模型从成千上万张手写数字图片中,学会 “哪些像素组合对应 0,哪些对应 1……”
它的核心组成很简单:
- 输入层:接收原始数据(比如手写数字图片的像素值);
- 隐藏层:对输入数据做 “复杂运算”(比如加权、激活),是模型 “学习” 的核心;
- 输出层:给出最终结果(比如判断图片是 0-9 中哪个数字的概率);
- 激活函数:给模型注入 “非线性能力”(比如 ReLU、Softmax),让模型能学习复杂规律。
二、实战准备:3 分钟搭好环境
今天用TensorFlow 2.x(自带 Keras 高层 API,不用写复杂底层代码),先搞定环境:
- 安装 TensorFlow:打开终端 / 命令提示符,输入以下命令(需要先装 Python 3.8+):
TypeScript取消自动换行复制
- 验证安装:打开 Python 终端,输入import tensorflow as tf,不报错就说明装好了。
三、核心实战:搭建手写数字识别神经网络
我们用经典的MNIST 数据集(包含 6 万张训练用手写数字图、1 万张测试图,每张图是 28x28 像素的黑白图),目标是让模型识别图中的数字(0-9)。
步骤 1:导入需要的库
先把工具包导入,就像做饭前把锅碗瓢盆准备好:
TypeScript取消自动换行复制
import tensorflow as tf
from tensorflow.keras import layers, models # 用来搭神经网络的层和模型
import matplotlib.pyplot as plt # 用来画图
步骤 2:加载并查看数据集
MNIST 数据集是 TensorFlow 自带的,直接调用 API 就能加载,不用自己找数据:
TypeScript取消自动换行复制
# 加载MNIST数据集(第一次运行会自动下载,后续直接用本地文件)
(x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data()
# 查看数据格式:理解数据长什么样
print("训练集图片形状:", x_train.shape) # 输出 (60000, 28, 28) → 6万张图,每张28x28像素
print("训练集标签形状:", y_train.shape) # 输出 (60000,) → 6万张图对应的数字(0-9)
print("测试集图片形状:", x_test.shape) # 输出 (10000, 28, 28) → 1万张测试图
print("测试集标签形状:", y_test.shape) # 输出 (10000,) → 1万张测试图的真实数字
# 画一张训练集的图看看(比如第0张)
plt.imshow(x_train[0], cmap='gray') # 用灰度模式显示图片
plt.title(f"真实数字:{y_train[0]}") # 标题显示真实数字
plt.axis('off') # 隐藏坐标轴
plt.show() # 弹出图片窗口
运行后会看到一张手写 “5” 的图片(因为 x_train [0] 对应的标签 y_train [0] 是 5),这就是我们要让模型识别的数据。
步骤 3:数据预处理(关键!模型训练的 “地基”)
原始数据不能直接喂给模型,需要做 2 件事:
- 展平图片:我们要搭的是 “全连接神经网络”,输入必须是 “一维向量”,而原始图片是 28x28 的二维矩阵,所以要把它展成 784 个元素的一维向量(28*28=784);
- 归一化像素值:原始像素值是 0-255(黑色是 0,白色是 255),数值范围太大容易导致模型训练不稳定,所以归一化到 0-1 之间(除以 255)。
代码实现:
TypeScript取消自动换行复制
# 1. 展平图片:从(样本数, 28, 28) → (样本数, 784)
x_train_flatten = x_train.reshape((60000, 28*28))
x_test_flatten = x_test.reshape((10000, 28*28))
# 2. 归一化:将像素值从0-255转为0-1
x_train_norm = x_train_flatten / 255.0
x_test_norm = x_test_flatten / 255.0
# 3. 处理标签:将标签转为“独热编码”(适合多分类问题)
# 比如标签5 → [0,0,0,0,0,1,0,0,0,0],方便计算损失
y_train_onehot = tf.keras.utils.to_categorical(y_train, 10) # 10表示有10个类别(0-9)
y_test_onehot = tf.keras.utils.to_categorical(y_test, 10)
# 查看预处理后的数据格式
print("预处理后训练集输入形状:", x_train_norm.shape) # 输出 (60000, 784)
print("预处理后训练集标签形状:", y_train_onehot.shape) # 输出 (60000, 10)
步骤 4:搭建神经网络模型
用 Keras 的Sequential(序贯模型)搭建,就像 “搭积木” 一样一层一层堆上去:
TypeScript取消自动换行复制
# 1. 初始化序贯模型
model = models.Sequential()
# 2. 添加输入层+第一个隐藏层(全连接层)
# Dense:全连接层,units=128表示该层有128个神经元
# activation='relu':用ReLU激活函数(解决梯度消失,计算快)
# input_shape=(784,):输入数据的形状(784维向量)
model.add(layers.Dense(units=128, activation='relu', input_shape=(784,)))
# 3. 添加第二个隐藏层(可选,增加模型复杂度)
model.add(layers.Dense(units=64, activation='relu'))
# 4. 添加输出层
# units=10:输出10个值(对应0-9的概率)
# activation='softmax':将输出转为概率分布(所有值总和为1,方便判断类别)
model.add(layers.Dense(units=10, activation='softmax'))
# 查看模型结构
model.summary()
运行后会输出模型结构,类似这样:
TypeScript取消自动换行复制
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 128) 100480
dense_1 (Dense) (None, 64) 8256
dense_2 (Dense) (None, 10) 650
=================================================================
Total params: 109,386
Trainable params: 109,386
Non-trainable params: 0
“Param #” 是该层的参数数量,比如第一个隐藏层有 784*128 + 128 = 100480 个参数(每个输入神经元对应一个权重,加每个神经元的偏置)。
步骤 5:编译模型(告诉模型 “怎么学”)
编译时要指定 3 个关键参数:
- 优化器(optimizer):控制模型如何调整参数来降低误差,选adam(自适应学习率,新手不用手动调参);
- 损失函数(loss):衡量模型预测值和真实值的差距,多分类问题用categorical_crossentropy;
- 评估指标(metrics):训练时看什么指标,选accuracy(准确率,即预测对的样本占比)。
代码:
TypeScript取消自动换行复制
model.compile(
optimizer='adam',
loss='categorical_crossentropy',
metrics=['accuracy']
)
步骤 6:训练模型(让模型 “从数据中学习”)
用训练集数据训练,同时用部分数据验证模型是否过拟合(“过拟合” 就是模型只学懂了训练数据,没学懂通用规律):
TypeScript取消自动换行复制
# 开始训练:fit()方法
history = model.fit(
x=x_train_norm, # 训练集输入
y=y_train_onehot, # 训练集标签
epochs=5, # 训练轮次:整个训练集跑5遍
batch_size=32, # 批次大小:每次用32个样本更新参数
validation_split=0.1 # 用10%的训练数据做验证(看模型在未训练过的数据上的表现)
)
训练过程中会实时输出日志,类似这样:
TypeScript取消自动换行复制
Epoch 1/5
1688/1688 [==============================] - 5s 3ms/step - loss: 0.2574 - accuracy: 0.9251 - val_loss: 0.1147 - val_accuracy: 0.9668
Epoch 2/5
1688/1688 [==============================] - 4s 2ms/step - loss: 0.1047 - accuracy: 0.9687 - val_loss: 0.0893 - val_accuracy: 0.9732
...
- loss/accuracy:训练集上的损失和准确率;
- val_loss/val_accuracy:验证集上的损失和准确率;
- 可以看到:随着训练轮次增加,损失在下降,准确率在上升,说明模型在进步。
步骤 7:评估模型(看模型 “学的怎么样”)
用测试集(模型从没见过的数据)评估泛化能力:
TypeScript取消自动换行复制
# 用测试集评估
test_loss, test_acc = model.evaluate(x_test_norm, y_test_onehot)
print(f"测试集准确率:{test_acc:.4f}") # 输出类似 测试集准确率:0.9750 → 97.5%的测试图能识别对
正常情况下,测试准确率能达到 97% 以上,对于一个简单的全连接网络来说,这个效果已经很好了。
步骤 8:用模型做预测(让模型 “干活”)
选一张测试图,让模型预测它是什么数字:
TypeScript取消自动换行复制
# 1. 选一张测试图(比如第10张)
test_image_index = 10
test_image = x_test[test_image_index] # 原始28x28图片(用于画图)
test_image_input = x_test_norm[test_image_index] # 预处理后的输入(用于预测)
# 2. 模型预测:predict()返回概率分布(10个值,对应0-9的概率)
prediction = model.predict(test_image_input.reshape(1, 784)) # 要把输入转成(1,784)(1个样本,784维)
predicted_label = tf.argmax(prediction, axis=1).numpy()[0] # 取概率最大的索引,就是预测的数字
true_label = y_test[test_image_index] # 真实数字
# 3. 画图+显示结果
plt.imshow(test_image, cmap='gray')
plt.title(f"真实数字:{true_label} | 预测数字:{predicted_label}")
plt.axis('off')
plt.show()
# 打印预测概率分布
print("0-9的预测概率:")
for i in range(10):
print(f"数字{i}的概率:{prediction[0][i]:.4f}")
运行后会看到:比如真实数字是 0,模型预测数字也是 0,且数字 0 的概率接近 1,其他数字的概率接近 0,说明模型预测得很准。
四、进阶方向:让模型更强大
如果想进一步提升准确率,可以尝试这些优化:
- 增加隐藏层或神经元数量:比如把隐藏层改成units=256,或多加一层Dense(32, activation='relu');
- 加入 dropout 防止过拟合:在隐藏层后加model.add(layers.Dropout(0.2))(随机让 20% 的神经元不工作,避免模型 “死记硬背”);
- 用卷积神经网络(CNN):MNIST 是图像数据,CNN 比全连接网络更擅长处理图像,准确率能轻松达到 99% 以上(后续可以专门写一篇 CNN 的教程);
- 调整超参数:比如epochs=10(多训练几轮)、batch_size=64(调整批次大小)。
五、总结
今天我们用不到 50 行核心代码,完成了神经网络的全流程:
- 数据加载→预处理(展平 + 归一化);
- 模型搭建(Sequential+Dense 层);
- 模型编译(optimizer+loss+metrics);
- 训练→评估→预测。
其实神经网络没那么抽象,新手从简单的全连接网络入手,熟悉流程后再学复杂模型(CNN、RNN)会更轻松。赶紧把代码复制到本地跑一遍,动手实践才是最好的学习方式!
更多推荐
所有评论(0)