资讯动态

Python+Keras+TensorFlow神经网络入门:从环境搭建到模型部署全流程

发布时间:2026/10/26 7:58:05 来源:尧图企业网站定制
1. 从零理解神经网络为什么选择 Python Keras TensorFlow 这条技术路线1.1 三条技术路线摆在面前我为什么最终选了 Keras如果你刚开始接触神经网络大概率会在网上搜到三种主流方案纯 Python NumPy 手写、PyTorch、以及 Keras TensorFlow。我当初也在这三条路之间犹豫了很久最后选的是 Keras 搭 TensorFlow 后端。原因不复杂但值得说清楚。纯 NumPy 手写适合理解原理比如反向传播到底怎么算梯度、链式法则怎么一层层传回去。但一旦你要做一个稍微像样的项目比如图像分类或者文本情感分析手写版本很快就会变成一场噩梦——你得自己管理权重初始化、自己写优化器、自己处理 GPU 加速。这些工作对于学习原理有价值但对于交付项目来说时间成本太高。PyTorch 这几年在学术界确实很火动态图机制让调试变得直观。但如果你是一个刚入门的人或者你的团队里有人更习惯 Keras 那种“搭积木”式的写法Keras 的上手速度会快很多。model.add(Dense(64, activationrelu))这种写法几乎不需要额外解释看一眼就知道在干什么。Keras 最大的优势在于它把“定义模型”和“训练模型”这两件事拆得很干净。你不需要在定义网络结构的时候就去想优化器怎么配置、损失函数怎么选这些可以后面再补。这种分离让代码的可读性提升了一个档次尤其适合团队协作——别人接手你的代码时能很快看懂网络长什么样。提示如果你完全没接触过神经网络建议先用 NumPy 手写一个两层的前馈网络跑通 MNIST哪怕只训练一个 epoch。这一步能帮你建立“前向传播算输出、反向传播算梯度、梯度下降更新权重”的直觉。有了这个直觉之后再用 Keras 就会觉得一切都很自然。1.2 TensorFlow 在后端到底做了什么很多人用 Keras 的时候不太关心后端觉得反正 API 都一样。但理解 TensorFlow 在后端做的事情对你排查问题和优化性能很有帮助。Keras 本质上是一个高层 API 规范它需要一个大计算框架来执行实际的张量运算。TensorFlow 就是这个执行引擎。当你调用model.fit()的时候Keras 会把你的网络结构翻译成 TensorFlow 的计算图然后把数据喂进去由 TensorFlow 来调度 CPU 或 GPU 完成矩阵乘法、激活函数、梯度计算这些底层操作。TensorFlow 2.x 之后默认开启了 Eager Execution也就是说你写一行tf.matmul(a, b)它会立刻算出结果而不是像 1.x 那样先建图再执行。这个改变让调试变得容易很多——你可以在任意位置插入print或者断点直接看到张量的值。但 Eager Execution 也有代价就是性能上不如静态图。所以 TensorFlow 提供了tf.function装饰器你可以把一段计算逻辑用tf.function包起来它会自动把这段代码编译成图模式执行兼顾调试便利性和运行效率。Keras 的model.fit()内部其实就用了类似机制。1.3 版本选择为什么我建议从 TensorFlow 2.x 起步网上有很多教程还在用 TensorFlow 1.x 的tf.Session()写法如果你照着那些教程敲代码大概率会报一堆弃用警告。我的建议是直接上 TensorFlow 2.x具体来说 2.5 以上的版本都比较稳定。TensorFlow 2.5.0 是一个比较经典的版本它对 CUDA 和 cuDNN 的兼容性做得不错。如果你有 NVIDIA 显卡想用 GPU 加速需要确认驱动版本和 CUDA 版本的对应关系。比如驱动版本 550.144.03 对应的 CUDA 版本一般在 12.x 左右你需要装对应版本的 CUDA Toolkit 和 cuDNN然后安装tensorflow-gpu或者直接装tensorflow2.x 之后 GPU 支持已经整合到主包了。安装命令很简单pip install tensorflow2.5.0如果你要用 GPU还需要额外确认import tensorflow as tf print(tf.config.list_physical_devices(GPU))如果输出是空列表说明 GPU 没被识别到大概率是 CUDA 或 cuDNN 版本不匹配。这个问题后面在常见问题部分会详细说。2. 前馈神经网络的核心细节从输入到输出的完整链路2.1 一个神经元到底在算什么很多人第一次看到神经网络的结构图会觉得复杂但其实单个神经元做的事情非常简单加权求和然后过一个激活函数。假设一个神经元有三个输入 x1、x2、x3对应的权重是 w1、w2、w3偏置是 b。那么这个神经元的输出就是output activation(w1*x1 w2*x2 w3*x3 b)就这么简单。w1*x1 w2*x2 w3*x3 b是一个线性组合activation是一个非线性函数。如果没有激活函数多层神经网络叠加起来等价于一个单层线性变换那就失去了“深度”的意义。常用的激活函数有几种。ReLURectified Linear Unit是max(0, x)计算简单梯度在正区间恒为 1能有效缓解梯度消失问题。Sigmoid 是1 / (1 exp(-x))输出在 0 到 1 之间适合做二分类的输出层但在隐藏层用多了容易导致梯度消失。Tanh 是(exp(x) - exp(-x)) / (exp(x) exp(-x))输出在 -1 到 1 之间比 Sigmoid 好一些但仍有梯度消失风险。我个人的经验是隐藏层默认用 ReLU输出层根据任务选。二分类用 Sigmoid多分类用 Softmax回归任务直接不加激活函数。2.2 前馈网络的层叠逻辑前馈神经网络Feedforward Neural Network也叫全连接网络它的特点是每一层的每个神经元都和上一层的所有神经元相连。信息从输入层单向流向输出层没有循环或反馈。假设你有一个三层的网络输入层 784 个节点对应 28x28 的灰度图像展平隐藏层 128 个节点输出层 10 个节点对应 0-9 十个数字类别。那么第一层的权重矩阵形状是(784, 128)第二层的权重矩阵形状是(128, 10)。参数量计算很简单784*128 128 128*10 10 100480 128 1280 10 101898个参数。这就是为什么全连接网络在处理大尺寸图像时会参数量爆炸——一张 256x256 的彩色图像展平后是 196608 个输入节点如果隐藏层还是 128 个节点光第一层就有两千五百万个参数。这也是卷积神经网络出现的根本原因。卷积层通过局部连接和权重共享大幅减少了参数量。但前馈网络仍然是理解神经网络的基础而且在小规模结构化数据上表现很好。2.3 损失函数网络怎么知道自己错了损失函数衡量的是网络输出和真实标签之间的差距。训练的目标就是让这个差距越来越小。对于回归问题常用均方误差MSEloss mean((y_pred - y_true)^2)。对于二分类问题常用二元交叉熵Binary Crossentropyloss -mean(y_true * log(y_pred) (1 - y_true) * log(1 - y_pred))。对于多分类问题常用分类交叉熵Categorical Crossentropy。为什么分类问题不用 MSE 而用交叉熵因为交叉熵的梯度性质更好。当预测值偏离真实值很远的时候交叉熵给出的梯度更大网络更新更快而 MSE 在同样情况下梯度会变得很小导致学习缓慢。这个细节在实际调参时很关键——如果你用 MSE 做分类可能会发现 loss 下降得特别慢。在 Keras 里指定损失函数很简单model.compile(optimizeradam, losscategorical_crossentropy, metrics[accuracy])如果是二分类把categorical_crossentropy换成binary_crossentropy。如果是回归换成mse。2.4 反向传播梯度到底怎么传回去反向传播是神经网络训练的核心算法但很多人只是知道这个名字不太清楚具体过程。我用一个简化的例子说明。假设网络只有两层输入 x第一层权重 W1激活函数 f1输出 h第二层权重 W2激活函数 f2输出 y_pred。损失函数 L。前向传播h f1(W1 * x) y_pred f2(W2 * h) loss L(y_pred, y_true)反向传播要计算 loss 对 W1 和 W2 的偏导数。根据链式法则dL/dW2 dL/dy_pred * dy_pred/dW2 dL/dW1 dL/dy_pred * dy_pred/dh * dh/dW1实际计算的时候dL/dy_pred由损失函数求导得到dy_pred/dW2由第二层激活函数和线性变换求导得到然后这些梯度会继续往前传乘以dy_pred/dh和dh/dW1得到第一层的梯度。关键点在于梯度是一层一层往前传的每一层都会用到后面传回来的梯度乘以自己这层的局部梯度。这就是“反向”的含义。在 TensorFlow 里你不需要手动实现这个过程。tf.GradientTape会自动记录前向传播中的运算然后调用tape.gradient()就能得到所有可训练变量的梯度。Keras 的model.fit()内部封装了这一切。但理解反向传播对于排查问题很重要。比如你发现 loss 不下降可能是梯度消失了深层网络用了 Sigmoid也可能是梯度爆炸了学习率太大这些都需要从反向传播的角度去分析。3. 用 Keras 搭建第一个神经网络完整实操流程3.1 环境准备与依赖安装在开始写代码之前先把环境搭好。我推荐用 Anaconda 创建一个独立环境避免和系统 Python 冲突。conda create -n neural_net python3.8 conda activate neural_net pip install tensorflow2.5.0 numpy matplotlibPython 3.8 是我实测下来和 TensorFlow 2.5.0 兼容性最好的版本。如果你用 3.9 或 3.10可能会遇到一些依赖包版本冲突的问题。安装完成后验证一下import tensorflow as tf print(tf.__version__)如果输出2.5.0说明安装成功。如果报错说找不到 CUDA 相关的库但你确实没有 GPU可以忽略TensorFlow 会自动回退到 CPU 模式。注意不要同时安装tensorflow和tensorflow-gpu2.x 之后这两个包已经合并了。同时安装会导致版本冲突。3.2 数据加载与预处理我用 MNIST 手写数字数据集来演示因为它足够小、足够经典而且 Keras 内置了下载接口。import tensorflow as tf from tensorflow.keras import layers, models import numpy as np # 加载数据 (x_train, y_train), (x_test, y_test) tf.keras.datasets.mnist.load_data() # 归一化把像素值从 0-255 缩放到 0-1 x_train x_train.astype(float32) / 255.0 x_test x_test.astype(float32) / 255.0 # 展平28x28 的图像变成 784 维向量 x_train x_train.reshape(-1, 784) x_test x_test.reshape(-1, 784) # 标签转 one-hot 编码 y_train tf.keras.utils.to_categorical(y_train, 10) y_test tf.keras.utils.to_categorical(y_test, 10)归一化这一步很关键。如果不做归一化像素值在 0-255 之间输入到网络后经过加权求和会得到很大的值导致激活函数饱和、梯度消失。缩放到 0-1 之后数值范围合理训练会稳定很多。标签转 one-hot 是因为输出层用的是 Softmax它输出的是每个类别的概率分布需要和 one-hot 标签做交叉熵计算。3.3 定义网络结构用 Keras 的 Sequential API 定义网络model models.Sequential([ layers.Dense(128, activationrelu, input_shape(784,)), layers.Dropout(0.3), layers.Dense(64, activationrelu), layers.Dropout(0.3), layers.Dense(10, activationsoftmax) ])这个网络有三层全连接层。第一层 128 个神经元第二层 64 个输出层 10 个。中间加了 Dropout 层随机丢弃 30% 的神经元防止过拟合。Dropout 的原理是在训练时随机把一部分神经元的输出置零这样网络不能依赖某些特定的神经元必须学习更鲁棒的特征。在推理时 Dropout 不生效所有神经元都参与计算。input_shape(784,)指定了输入维度。第一层的权重矩阵形状会自动推导为(784, 128)。3.4 编译与训练model.compile( optimizeradam, losscategorical_crossentropy, metrics[accuracy] ) history model.fit( x_train, y_train, epochs20, batch_size128, validation_split0.1, verbose1 )optimizeradam是自适应学习率优化器对大多数任务都能给出不错的结果。batch_size128表示每次用 128 个样本计算梯度并更新一次权重。validation_split0.1表示从训练集中划出 10% 作为验证集用来监控过拟合。训练过程中你会看到 loss 和 accuracy 的变化。正常情况下训练集的 loss 持续下降验证集的 loss 先下降后可能回升。如果验证集 loss 开始回升而训练集 loss 还在下降说明过拟合了需要增加 Dropout 比例或者减少网络容量。3.5 模型评估与预测test_loss, test_acc model.evaluate(x_test, y_test) print(fTest accuracy: {test_acc:.4f}) predictions model.predict(x_test[:5]) print(np.argmax(predictions, axis1))model.evaluate()返回测试集上的损失和准确率。model.predict()返回每个样本属于各个类别的概率用argmax取出概率最大的类别作为预测结果。我实测下来这个简单的全连接网络在 MNIST 上能跑到 98% 左右的准确率。如果想更高可以加卷积层但那就是另一个话题了。4. 常见问题与排查技巧实录4.1 Loss 不下降或者变成 NaN这是新手最常遇到的问题。可能的原因有几个学习率太大。Adam 默认学习率是 0.001大多数情况下没问题但如果你的数据没有归一化梯度会很大导致权重更新过猛loss 直接飞掉。解决办法是先检查数据是否归一化然后尝试把学习率调小比如optimizertf.keras.optimizers.Adam(learning_rate0.0001)。损失函数选错了。多分类用了binary_crossentropy或者二分类用了categorical_crossentropy都会导致 loss 计算异常。确认输出层激活函数和损失函数的搭配Sigmoid 配 binary_crossentropySoftmax 配 categorical_crossentropy。标签编码不对。categorical_crossentropy要求标签是 one-hot 格式如果你直接传了整数标签loss 会算错。用to_categorical转换一下。4.2 过拟合训练集准确率很高但测试集很差过拟合的本质是网络记住了训练集的噪声而没有学到泛化特征。解决办法有几种增加 Dropout 比例。我一般从 0.2 开始试如果过拟合严重就加到 0.5。但注意 Dropout 太高会导致欠拟合训练集准确率也上不去。加 L2 正则化。在 Dense 层里加kernel_regularizertf.keras.regularizers.l2(0.001)惩罚大的权重值。减少网络容量。如果网络参数太多减少层数或每层的神经元数量。增加训练数据。如果条件允许做数据增强比如图像旋转、平移、缩放。早停Early Stopping。用tf.keras.callbacks.EarlyStopping监控验证集 loss当它连续几个 epoch 不下降就停止训练。early_stop tf.keras.callbacks.EarlyStopping( monitorval_loss, patience3, restore_best_weightsTrue ) model.fit(x_train, y_train, epochs100, callbacks[early_stop], validation_split0.1)4.3 GPU 不被识别如果你有 NVIDIA 显卡但 TensorFlow 检测不到按以下顺序排查确认显卡驱动版本。nvidia-smi命令能看到驱动版本和 CUDA 版本。TensorFlow 2.5.0 需要 CUDA 11.2 和 cuDNN 8.1。如果驱动太新或太旧都可能不兼容。确认 CUDA Toolkit 和 cuDNN 安装正确。cuDNN 的文件需要手动拷贝到 CUDA 安装目录下这一步容易出错。建议直接看 TensorFlow 官方的版本对应表。确认环境变量。CUDA_HOME和LD_LIBRARY_PATH需要指向正确的 CUDA 安装路径。如果以上都没问题试试重装 TensorFlowpip uninstall tensorflow pip install tensorflow2.5.04.4 常见问题速查表问题现象可能原因排查方法Loss 变成 NaN学习率太大或数据未归一化检查数据范围调小学习率Loss 不下降损失函数与激活函数不匹配确认输出层和 loss 的搭配训练集准确率高但测试集低过拟合加 Dropout、L2 正则、早停GPU 不被识别CUDA/cuDNN 版本不匹配检查驱动版本和 CUDA 版本训练速度极慢没用 GPU 或 batch_size 太小确认 GPU 可用适当增大 batch_size准确率波动大batch_size 太小或学习率太大增大 batch_size调小学习率4.5 几个我踩过的坑第一个坑是数据维度搞错。Keras 的 Dense 层要求输入是二维的(样本数, 特征数)如果你直接把(样本数, 28, 28)的图像喂进去会报错。一定要先 reshape 成(样本数, 784)。第二个坑是验证集和测试集混用。validation_split是从训练集里划出来的测试集是独立的。不要用测试集去调超参数否则测试结果就不客观了。第三个坑是忘了保存模型。训练了半天的模型关掉 notebook 就没了。养成习惯model.save(my_model.h5)下次用的时候model tf.keras.models.load_model(my_model.h5)第四个坑是盲目追求复杂网络。我见过有人用十几层的全连接网络做 MNIST结果还不如三层的效果好。网络深度要匹配任务复杂度简单任务用简单网络过深的网络反而难训练。5. 从全连接网络到更复杂的架构下一步怎么走5.1 卷积神经网络解决图像问题全连接网络处理图像有两个硬伤参数量太大以及丢失了空间信息。一张 28x28 的图像展平后相邻像素的关系就没了。卷积神经网络通过卷积核在图像上滑动保留了空间结构同时通过权重共享大幅减少参数。一个典型的卷积网络结构是卷积层 - 池化层 - 卷积层 - 池化层 - 全连接层。卷积层提取局部特征池化层降低空间维度全连接层做最终分类。在 Keras 里搭建卷积网络model models.Sequential([ layers.Conv2D(32, (3, 3), activationrelu, input_shape(28, 28, 1)), layers.MaxPooling2D((2, 2)), layers.Conv2D(64, (3, 3), activationrelu), layers.MaxPooling2D((2, 2)), layers.Flatten(), layers.Dense(64, activationrelu), layers.Dense(10, activationsoftmax) ])这个网络在 MNIST 上能轻松跑到 99% 以上的准确率。关键是输入形状变成了(28, 28, 1)不需要手动展平。5.2 循环神经网络处理序列数据如果你的数据是序列比如文本、时间序列、音频全连接网络和卷积网络都不太合适。循环神经网络RNN通过维护一个隐藏状态能够捕捉序列中的时间依赖关系。LSTMLong Short-Term Memory是 RNN 的一种改进版本通过门控机制解决了长序列中的梯度消失问题。在 Keras 里用 LSTM 很简单model models.Sequential([ layers.LSTM(64, input_shape(timesteps, features)), layers.Dense(1, activationsigmoid) ])LSTM 的参数量比全连接层大不少训练也更慢但在序列任务上效果显著。5.3 迁移学习站在别人的肩膀上如果你要做一个图像分类任务但训练数据不多从头训练一个卷积网络很容易过拟合。这时候可以用迁移学习拿一个在大规模数据集上预训练好的网络把它的卷积层冻结只训练最后的分类层。base_model tf.keras.applications.MobileNetV2( input_shape(224, 224, 3), include_topFalse, weightsimagenet ) base_model.trainable False model models.Sequential([ base_model, layers.GlobalAveragePooling2D(), layers.Dense(1, activationsigmoid) ])MobileNetV2 在 ImageNet 上预训练过已经学会了提取通用的图像特征。你只需要在它后面加一个分类层用你自己的数据微调一下就能得到不错的效果。这比从头训练节省了大量时间和数据。5.4 模型部署的初步思路训练好的模型最终要能用起来。最简单的部署方式是把模型保存成文件然后在服务端加载对外提供 API。import flask app flask.Flask(__name__) model tf.keras.models.load_model(my_model.h5) app.route(/predict, methods[POST]) def predict(): data flask.request.json[data] prediction model.predict(np.array([data])) return flask.jsonify({prediction: prediction.tolist()})这只是个最简版本实际部署还要考虑并发、批处理、GPU 资源管理等问题。但至少你知道了从训练到上线的完整链路长什么样。5.5 持续学习的建议神经网络这个领域变化很快新的架构、新的优化器、新的训练技巧层出不穷。但基础的东西变化很慢前向传播、反向传播、梯度下降、过拟合与正则化这些核心概念十年没变过。我的建议是把基础打牢然后选一个方向深入。如果你做图像就深入卷积网络和视觉 Transformer如果你做自然语言处理就深入 LSTM、Attention 和 Transformer。不要什么都学一点但什么都不精。另外多动手。看十篇教程不如自己从头搭一个网络跑通。遇到问题先自己排查实在搞不定再搜。排查问题的过程本身就是最好的学习。提示Keras 官方文档和 TensorFlow 官方教程是最好的学习资源比大多数第三方教程准确。遇到 API 用法不确定的时候直接查官方文档。5.6 关于工具链的一些个人体会我试过 PyCharm 和 VS Code 两个 IDE最后长期用 VS Code。原因是轻量、启动快而且 Python 插件和 Jupyter 插件都很好用。PyCharm 功能更全但资源占用也更大看个人习惯。调试神经网络代码的时候我习惯先用小数据集跑通流程确认没有维度错误、没有 NaN、loss 能正常下降然后再换全量数据。这样能快速定位问题不用等半天才发现是数据格式错了。版本管理方面我建议用 conda 管理环境用 pip 安装包。conda 的好处是能管理 Python 版本本身而 pip 在包版本解析上更灵活。两者结合用基本能覆盖大多数场景。最后说一点不要被各种新框架、新工具分散注意力。Keras TensorFlow 这套组合已经足够强大能覆盖从入门到生产的绝大多数需求。把一套工具用熟比每样都浅尝辄止要有效得多。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑