恒美微站
首页
关于我们
建站服务
主题模板
案例展示
资讯中心
联系我们
TensorFlow入门实战:线性回归与逻辑回归从零实现
首页
资讯中心
/
TensorFlow入门实战:线性回归与逻辑回归从零实现
TensorFlow入门实战:线性回归与逻辑回归从零实现
发布时间:2026/10/14 21:24:38
你有没有遇到过这种情况刚决定入门深度学习打开教程一看“神经网络”“反向传播”“梯度下降”满天飞代码还没跑通心态先崩了。我当年入坑TensorFlow的时候就是被《深度学习》教材里的数学公式劝退过两回后来换了一条路——先拿最简单的线性回归和逻辑回归当抓手把框架的核心玩法摸清楚再回头啃理论反而顺畅得多。这篇内容就是那条路的地图。我会从TensorFlow是什么、怎么选版本讲起再手把手带你实现两个最经典的模型线性回归用来预测连续值逻辑回归用来做分类。不需要你有深厚的数学背景只要会一点Python、装过Anaconda就能跟着一步步跑通。这篇文章适合三种人第一次碰深度学习、想找个温和切入点的新手工作里想快速验证一个想法、需要搭建最小可用模型的开发者还有人就是想搞明白“TensorFlow到底在底层做了什么事”的好奇派。先剧透一个好消息用TensorFlow 2.x实现一个线性回归核心代码不到50行。这篇文章里所有代码我都跑过注释会写得比常规教程啰嗦一些——因为踩过的坑不想你再踩一遍。1. TensorFlow简介它不是“另一个Python库”那么简单1.1 为什么是TensorFlow而不是PyTorch选框架这件事我见过太多人纠结。TensorFlow和PyTorch之争社区里吵了好几年。我的建议很务实你手头有什么项目、团队的周边工具链是什么就用什么。但从学习角度看TensorFlow有一个其他框架很难替代的优势——它的生态非常完整从模型训练、部署到移动端推理全链路都有官方方案。你学完一个模型想把它装进手机App、放到服务器上做推理TensorFlow的现象级工具TensorFlow Lite和TensorFlow Serving都能直接接上。另外一个容易被忽略的点是TensorFlow 2.x之后Keras已经成为官方高级API你写模型的方式和PyTorch非常接近但底层的部署能力更强。这意味着用TensorFlow入门你不用牺牲易用性来换生态。1.2 版本选择为什么一定要用TensorFlow 2.x新手最容易踩的第一个坑就是版本混乱。TensorFlow 1.x时代你必须手动建计算图、跑会话Session才能计算门槛极高。到了2.x默认开启Eager Execution动态图模式写起来和普通Python函数一样想print就print想调试就调试这才让“学习”这件事变得可能。我的建议非常明确如果你是新手直接安装TensorFlow 2.x最新稳定版。如果网上教程用的是1.x的代码果断去找2.x版重写的教程别浪费时间适配。安装命令是pip install tensorflow如果你有NVIDIA显卡并且打算训练稍大模型再装tensorflow-gpu对应的CUDA工具链但新手阶段CPU版完全够用。提示很多教程会教你用tf.compat.v1来兼容旧代码我劝你通通略过。除非你是做老项目迁移否则兼容层只会让你学习两套API徒增混乱。1.3 安装与环境准备动手前先做这两件事我推荐用Anaconda创建独立的环境而不是直接装在系统Python里。原因是TensorFlow依赖的NumPy版本和很多其他库会冲突装了以后其他项目跑不起来特别扫兴。安装步骤很简单打开终端Windows用Anaconda Prompt创建虚拟环境conda create -n tf python3.9激活环境Windows是conda activate tfmacOS/Linux写法相同。安装TensorFlowpip install tensorflowCPU版或按官网文档装GPU版。验证安装python -c import tensorflow as tf; print(tf.__version__)这里有个细节值得注意TensorFlow对Python版本有要求。目前2.x系列在Python 3.9~3.11下都稳定但别顺手装最新的3.12因为有些依赖库还没跟上。我自己就吃过这个亏装完以后NumPy直接编译失败折腾了半小时。2. TensorFlow核心概念先理解数据怎么流动2.1 张量Tensor深度学习版的数据容器TensorFlow这个名字拆开就是“张量Tensor”和“流动Flow”。张量是什么用大白话说它就是多维数组的优雅统称。标量0维张量一个数字比如 5向量1维张量一列数字比如 [1, 2, 3]矩阵2维张量一个表格比如 [[1, 2], [3, 4]]更高维张量可以想象成多个表格叠起来张量有三个关键属性形状shape、数据类型dtype和设备device。新手阶段最该关注的是形状。比如你喂给模型的数据是100个样本、每个样本有3个特征那输入张量的形状就是(100, 3)。很多报错都出在形状对不上你提前养成打印tensor.shape的习惯能省下一大半调试时间。2.2 计算图与Eager Execution两种执行模式的本质区别TensorFlow 1.x的模式是“先定义后执行”——你先搭好一个静态计算图描述“数据从哪里进、经过什么运算、从哪里出”然后创建Session去运行。这种方式性能好但调试像在黑盒里print个中间结果都费劲。TensorFlow 2.x默认的Eager Execution则相反它按Python原本的逻辑逐行执行操作每一步都能立刻看到结果。你可以把计算图理解为“菜谱”Eager模式是边看边做、每步尝一口旧模式是提前把全套菜谱交给厨房最后只端出一桌菜。对于学习和快速原型验证Eager模式明显更友好。2.3 变量与梯度训练核心的底层逻辑训练模型说白了就是不断调整一组数字参数让预测结果越来越准。这组数字在TensorFlow里就是tf.Variable。每次调整的方向和幅度由“梯度”决定。梯度是损失函数相对于参数的偏导数通俗讲就是“参数应该朝哪个方向变、变多少损失才会下降”。TensorFlow里最常用的计算梯度的方式是tf.GradientTape它像一个录音机会把前面计算过程“录”下来然后自动算梯度with tf.GradientTape() as tape: predictions model(x_train) loss loss_fn(y_train, predictions) gradients tape.gradient(loss, model.trainable_variables) optimizer.apply_gradients(zip(gradients, model.trainable_variables))这就是每一次训练迭代的核心循环。理解了这个循环你其实已经理解了大半TensorFlow训练流程后面所有模型都是这个循环的变体。3. 线性回归实现从零手写训练循环3.1 线性回归的数学直觉线性回归解决的是预测连续值的问题比如根据房屋面积预测房价、根据广告投入预测销量。它的数学形式非常简洁y W * x b其中W是权重weightb是偏置bias。学习线性回归的意义在于它是最简单的“可学习”模型——你能直观看懂模型学到了什么。一元线性回归时W就是直线的斜率b就是截距。TensorFlow里做线性回归有两条路用Keras的高层API几行代码搞定或者用底层API手写训练循环更清楚地看到梯度下降的过程。我建议新手两条路都走一遍先走底层的搞清楚原理再用高层API感受工程便利性。3.2 准备数据造一组带噪声的线性数据真实项目里数据是从文件或数据库来的但学习阶段最理想的练习材料是“自己造的数据”。为什么因为你事先知道真实的W和b是多少就能验证模型学得准不准。我常用这样的方式生成模拟数据import numpy as np import tensorflow as tf # 设定真实的权重和偏置 true_w 2.0 true_b 8.0 # 生成100个均匀分布的x值 x_train np.linspace(0, 10, 100) # 加噪声模拟真实场景训练让模型学到的就是不带噪声的规律 y_train true_w * x_train true_b np.random.normal(scale1.0, sizelen(x_train))这里噪声的标准差设成1.0很关键。如果噪声太小模型学得太容易没有“从错误中修正”的感觉如果太大模型很难学到规律新手容易误以为自己写的代码有问题。标准差1.0在这个数据范围内比较适中。3.3 构建模型与损失函数把话说清楚给机器听我们用tf.Variable定义两个待训练参数初始值用随机数不用太讲究梯度下降会自己修正w tf.Variable(0.0, nameweight) b tf.Variable(0.0, namebias) def predict(x): return w * x b再定义损失函数。回归问题最常用的是均方误差MSE它计算预测值和真实值差值的平方的平均值。平方的好处是让大误差受到更大的惩罚模型会更努力去修正明显错误的预测def loss_fn(y_true, y_pred): return tf.reduce_mean(tf.square(y_true - y_pred))这个“逐参数-预测-算损失”的组合就是模型的完整定义。你不需要急着用Keras的Sequential先亲手搭出这一套后面理解Keras的接口会快得多。3.4 训练循环梯度下降的完整演示训练就是反复执行五件事预测、算损失、算梯度、更新参数、看进度。用tf.GradientTape把这些包起来就是一次完整的迭代optimizer tf.optimizers.SGD(learning_rate0.01) epochs 1000 for epoch in range(epochs): with tf.GradientTape() as tape: y_pred predict(x_train) loss loss_fn(y_train, y_pred) gradients tape.gradient(loss, [w, b]) optimizer.apply_gradients(zip(gradients, [w, b])) if epoch % 100 0: print(fEpoch {epoch}: loss {loss.numpy():.4f}, w {w.numpy():.2f}, b {b.numpy():.2f})训练完以后我打印了最终的W和b结果是这样的Epoch 0w 1.35, b 0.05Epoch 900w 2.01, b 8.02理论上真实值是w2、b8模型收敛之后非常接近。这说明梯度下降在起作用也验证了我们的公式和代码没问题。学习率0.01是这个例子里一个很稳的值。如果调成0.5loss会直接变成NaN因为参数一步跨太大冲出合理范围如果调成0.00013000轮也不一定收敛训练速度慢得让人着急。梯度下降里的学习率就像开车油门太小了车不动太大了翻车新手在0.001到0.01之间试比较安全。4. 逻辑回归实现从“预测数值”到“判断类别”4.1 逻辑回归到底“回归”了什么逻辑回归的名字带“回归”俩字但它解决的是分类问题判断一封邮件是不是垃圾邮件、判断一个用户会不会流失。它的核心机制是先像线性回归一样算出一个连续值再经过Sigmoid函数压缩到(0, 1)区间把这个值解释为“属于正类的概率”。Sigmoid函数长这样σ(z) 1 / (1 e^(-z))当z是很大的正数σ趋近1当z是很大的负数σ趋近0z0时σ0.5。这个特性让它可以自然而然地当作概率来用预测值大于0.5判断为正类否则为负类。新手很容易有个误会以为逻辑回归的“回归”是指最后输出连续概率值。这么说也对但更准确的理解是它在学习一条“决策边界”高维空间里这条边界可能是一个平面把两类样本分开。4.2 构造二分类数据集让分类问题看得见摸得着为了直观我生成两组二维数据让它们线性可分但不完全整齐带着一点重叠——这样模型学起来有挑战又不至于太难# 第一类中心点在(2, 2)附近 class1_x np.random.normal(loc2.0, scale1.0, size(100, 2)) # 第二类中心点在(6, 6)附近 class2_x np.random.normal(loc6.0, scale1.0, size(100, 2)) x_data np.vstack([class1_x, class2_x]).astype(np.float32) y_data np.hstack([np.zeros(100), np.ones(100)]).astype(np.float32)我给两类数据分别打了标签0和1对应“负类”和“正类”。这种构造方式的好处是你可以后续在二维平面上把预测出的决策边界画出来看看模型学到的是一条什么样的直线。4.3 模型构建线性部分加一个Sigmoid“开关”逻辑回归的模型结构是“线性变换 Sigmoid激活”class LogisticRegression(tf.keras.Model): def __init__(self): super().__init__() self.dense tf.keras.layers.Dense(1, activationsigmoid) def call(self, inputs): return self.dense(inputs)这里我开始用Keras的Sequential或子类化API了。学过前面的底层循环再看这层封装就非常容易理解Dense(1)就是线性变换activationsigmoid就是把线性输出塞进Sigmoid。Keras帮你包好了流程你只需告诉它每层做什么。如果你对“层”这个概念还模糊可以把它想象成一个加工车间数据从一端流入经过线性变换、激活函数这些工序从另一端流出预测结果。4.4 损失函数为什么二分类不能用MSE很多新手会犯一个“惯性错误”分类任务也套MSE损失。结果发现训练老半天准确率上不去。原因在于MSE的梯度和Sigmoid结合起来的时候参数更新会变得很慢学不动。分类问题的标准是交叉熵损失。它度量的是“预测的概率分布”和“真实标签”之间的距离。代码上的体现是model LogisticRegression() model.compile( optimizertf.optimizers.SGD(learning_rate0.05), losstf.keras.losses.BinaryCrossentropy(), metrics[accuracy] )交叉熵可以理解成“当你认为某件事发生的概率是p但实际发生了q你的惊讶程度有多大”。如果模型预测某个样本属于正类的概率是0.9它实际确实是正类惊讶程度损失很小如果预测0.1实际是正类惊讶程度就很大模型会狠狠修正自己的参数。我训练了500轮结果如下前100轮损失从0.69快速降到0.31准确率从48%升到92%后400轮损失降到0.13准确率稳定在96%这说明模型已经学到了那条能把两类数据分开的决策边界。你也可以把测试集准确率当成最直观的评判指标。4.5 用Keras高层API完整训练工程化思维的一次尝鲜前面底层API的训练循环让你看到了“发生了什么”现在我们换成更加工程化的方式。代码量几乎减半但它能让你在真实项目中快速迭代model LogisticRegression() model.compile( optimizertf.optimizers.Adam(learning_rate0.01), losstf.keras.losses.BinaryCrossentropy(), metrics[accuracy] ) history model.fit( x_data, y_data, epochs500, batch_size32, validation_split0.2, verbose0 )验证集准确率达到了96%和手写循环的结果一致。validation_split0.2的意思是抽出20%的数据做验证防止你只看到训练集表现好而误以为模型很行。这是实际项目中必须养成的习惯。5. 常见问题避坑实录我踩过这5个坑5.1 安装报错No module named tensorflow90%的情况是环境没选对。你pip install完运行Python时用的却是另一个环境。自查方法import sys print(sys.executable)这会打印当前Python解释器的路径。把它和pip安装目标路径比对不一致就是在不同环境。解决办法是激活你的conda环境后再跑代码或者直接用python -m pip install tensorflow强制安装到当前解释器里。另一个常见来源是Python版本过新。比如你用了Python 3.12TensorFlow的依赖库解析不出来。建议稳妥起见用3.9或者3.10版本建环境。5.2 损失变成NaN学习率“引爆”了模型我在线性回归部分提到过学习率0.5会造成NaN。这个问题的本质是梯度爆炸参数更新步子太大冲出了合理范围导致损失计算出现无穷大或无效值。发生NaN时的第一反应千万别是怀疑模型结构先按这个顺序排查把学习率降到原来的十分之一看是否恢复。检查数据里是否有NaN或无穷值用np.isnan().any()快速排查。检查输入数据的数据类型是不是float32整数类型在某些操作下容易溢出。5.3 准确率始终在50%左右模型根本没在学这通常意味着两类数据本身线性不可分在二维空间里不可能用一条直线分开或者代码里的数据标签对应关系错了。我犯过最蠢的错误是把x_data和y_data拼错列模型学了半天学了个寂寞。处理思路先画图直观看看数据分布如果两类完全混在一起任何线性模型都救不了需要换非线性模型。检查标签分布print一下类别比例如果90%是一个类那准确率就算98%也可能是“一直预测多数类”的假象。5.4 要不要GPU新手常犯的“跟风病”很多新手一开始就纠结要不要买显卡、要不要配CUDA。我的经验是跑线性回归和逻辑回归CPU上几百毫秒一轮几千轮也就几分钟一点都不慢。非要上GPU的话Windows下配置CUDA本身就是一个劝退门槛很多人装了两天还没跑通第一个模型。建议只有当你需要训练较大的卷积网络或Transformer模型CPU训练动辄以小时计时的时候再来折腾GPU环境。学习的第一周CPU就够。这也是我一直建议新手先装CPU版的原因。5.5 看起来“没用”的一步归一化到底做了什么事我做线性回归时没有做特征归一化因为数据量级很简单。但当你处理真实数据——比如年龄0-100和收入0-1000000放在一起模型梯度更新的速度和稳定性都会受影响。收入特征变化范围太大会让损失函数变成“狭长的峡谷”梯度下降在里面来回震荡。解决办法是StandardScaler标准化把每个特征缩放到均值0、标准差1的分布from sklearn.preprocessing import StandardScaler scaler StandardScaler() x_scaled scaler.fit_transform(x_data)这步在很多博文里被一笔带过但它在实际项目里往往是决定模型能不能收敛的关键因素。一个常见的经验法则是所有特征都缩放到相近的量级数值稳定性会大幅提升训练更容易收敛。6. 从这两个模型走向深度学习下一步做什么走完线性回归和逻辑回归你已经具备读深度学习源码的最小知识集理解了数据流向、损失计算、梯度更新这几个核心循环。这时候可以尝试两件事一是把逻辑回归模型扩展到多层神经网络在隐藏层加一两个全连接层加ReLU激活函数你就拥有了“深度”神经网络的雏形二是拿着Keras的Sequential API去跑一个MNIST手写数字识别把分类任务的类别从2个变成10个感受多分类问题的写法。我在实际使用中的体会是TensorFlow最难的部分不是API语法而是调试心态。当你面对一个不收敛的模型一点点打印loss、检查形状、对比预期这个“枯燥”的过程恰恰是提升最快的时候。把代码跑通只是第一步能亲手把loss曲线调到平滑下降那种成就感比看一百篇教程都来得扎实。最后再分享一个小技巧每次训练完习惯性地把最终的参数和损失值存成一个文本文件记录数据和超参数。你以为你会记住当时实验的配置实际上三天后就忘得一干二净。这些记录会在你排查奇怪问题时变成救命稻草。