import tensorflow as tf from sklearn import datasets from matplotlib import pyplot as plt import numpy as np # 导入数据,分别为输入特征和标签 x_data = datasets.load_iris().data y_data = datasets.load_iris().target # 随机打乱数据(因为原始数据是顺序的,顺序不打乱会影响准确率) # seed: 随机数种子,是一个整数,当设置之后,每次生成的随机数都一样(为方便教学,以保每位同学结果一致) np.random.seed(116) # 使用相同的seed,保证输入特征和标签一一对应 np.random.shuffle(x_data) np.random.seed(116) np.random.shuffle(y_data) tf.random.set_seed(116) # 将打乱后的数据集分割为训练集和测试集,训练集为前120行,测试集为后30行 x_train = x_data[:-30] y_train = y_data[:-30] x_test = x_data[-30:] y_test = y_data[-30:] # 转换x的数据类型,否则后面矩阵相乘时会因数据类型不一致报错 x_train = tf.cast(x_train, tf.float32) x_test = tf.cast(x_test, tf.float32) # from_tensor_slices函数使输入特征和标签值一一对应。(把数据集分批次,每个批次batch组数据) train_db = tf.data.Dataset.from_tensor_slices((x_train, y_train)).batch(32) test_db = tf.data.Dataset.from_tensor_slices((x_test, y_test)).batch(32) # 生成神经网络的参数,4个输入特征故,输入层为4个输入节点;因为3分类,故输出层为3个神经元 # 用tf.Variable()标记参数可训练 # 使用seed使每次生成的随机数相同(方便教学,使大家结果都一致,在现实使用时不写seed) w1 = tf.Variable(tf.random.truncated_normal([4, 3], stddev=0.1, seed=1)) b1 = tf.Variable(tf.random.truncated_normal([3], stddev=0.1, seed=1)) lr = 0.1 # 学习率为0.1 train_loss_results = [] # 将每轮的loss记录在此列表中,为后续画loss曲线提供数据 test_acc = [] # 将每轮的acc记录在此列表中,为后续画acc曲线提供数据 epoch = 500 # 循环500轮 loss_all = 0 # 每轮分4个step,loss_all记录四个step生成的4个loss的和 # 训练部分 for epoch in range(epoch): #数据集级别的循环,每个epoch循环一次数据集 for step, (x_train, y_train) in enumerate(train_db): #batch级别的循环 ,每个step循环一个batch with tf.GradientTape() as tape: # with结构记录梯度信息 y = tf.matmul(x_train, w1) + b1 # 神经网络乘加运算 y = tf.nn.softmax(y) # 使输出y符合概率分布(此操作后与独热码同量级,可相减求loss) y_ = tf.one_hot(y_train, depth=3) # 将标签值转换为独热码格式,方便计算loss和accuracy loss = tf.reduce_mean(tf.square(y_ - y)) # 采用均方误差损失函数mse = mean(sum(y-out)^2) loss_all += loss.numpy() # 将每个step计算出的loss累加,为后续求loss平均值提供数据,这样计算的loss更准确 # 计算loss对各个参数的梯度 grads = tape.gradient(loss, [w1, b1]) # 实现梯度更新 w1 = w1 - lr * w1_grad b = b - lr * b_grad w1.assign_sub(lr * grads[0]) # 参数w1自更新 b1.assign_sub(lr * grads[1]) # 参数b自更新 # 每个epoch,打印loss信息 print("Epoch {}, loss: {}".format(epoch, loss_all/4)) train_loss_results.append(loss_all / 4) # 将4个step的loss求平均记录在此变量中 loss_all = 0 # loss_all归零,为记录下一个epoch的loss做准备 # 测试部分 # total_correct为预测对的样本个数, total_number为测试的总样本数,将这两个变量都初始化为0 total_correct, total_number = 0, 0 for x_test, y_test in test_db: # 使用更新后的参数进行预测 y = tf.matmul(x_test, w1) + b1 y = tf.nn.softmax(y) pred = tf.argmax(y, axis=1) # 返回y中最大值的索引,即预测的分类 # 将pred转换为y_test的数据类型 pred = tf.cast(pred, dtype=y_test.dtype) # 若分类正确,则correct=1,否则为0,将bool型的结果转换为int型 correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32) # 将每个batch的correct数加起来 correct = tf.reduce_sum(correct) # 将所有batch中的correct数加起来 total_correct += int(correct) # total_number为测试的总样本数,也就是x_test的行数,shape[0]返回变量的行数 total_number += x_test.shape[0] # 总的准确率等于total_correct/total_number acc = total_correct / total_number test_acc.append(acc) print("Test_acc:", acc) print("--------------------------") 帮我看看这段代码,我主要是想知道“correct = tf.cast(tf.equal(pred, y_test), dtype=tf.int32) correct = tf.reduce_sum(correct)”这段的correct是怎么做到累积的,不是每次循环都变成0或1了吗
时间: 2025-06-10 16:08:32 浏览: 18
<think>嗯,用户的问题是关于TensorFlow代码中的correct累积部分。他们不理解为什么correct在每次循环中不会被重置为0或1,而是能够正确累加。我需要仔细看看这段代码的逻辑。
首先,用户提供的代码中,测试部分有一个循环遍历test_db数据集。每次循环处理一个batch的数据。在循环内部,计算了预测值pred,然后将其与实际标签y_test比较。这里用到了tf.equal(pred, y_test),得到一个布尔类型的张量,表示每个样本是否预测正确。接着用tf.cast将布尔值转换为int32(0或1),再通过tf.reduce_sum(correct)对这个batch中的正确样本数求和,得到correct的值。这一步的结果是当前batch中正确预测的数量。
用户的问题是,为什么correct不会被每次循环覆盖,而是能够累积起来。看起来用户可能混淆了变量名的作用域。在每次循环迭代中,correct变量是当前batch的正确数,然后通过total_correct += int(correct)将其累加到total_correct变量中。因此,每个batch的正确数被加到总和中,而total_correct是在循环之前初始化为0的,所以每次测试阶段的循环都会正确累加。
可能用户没有注意到total_correct的存在,或者误以为correct变量自身在循环中被累加。但实际上,correct只是当前batch的正确数量,而total_correct才是累积所有batch正确数的变量。
另外,需要确认用户是否理解TensorFlow的数据集迭代方式。test_db是一个batch的数据集,每个batch有多个样本。对于每个batch,计算该batch中的正确数,然后将这些正确数加起来,最后除以总样本数得到准确率。整个过程是正确的,因为每个batch处理完后,correct是该batch的正确数,随后被累加到total_correct,而total_correct在循环外初始化,不会在每次循环中被重置。
可能还需要解释一下变量作用域的问题,即每个循环内的correct是局部变量,不会影响到之前的total_correct。用户可能认为correct本身在累加,但实际上是total_correct在累加各个batch的correct值。
总结来说,正确的累积是通过total_correct变量实现的,而不是correct本身。每次循环处理一个batch,计算该batch的正确数,然后将其加到total_correct中,这样最终得到总的正确样本数。</think>让我们通过分步解析来理解`correct`的累积过程:
**代码段分析:**
```python
total_correct = 0 # 初始化总正确数为0
for x_test, y_test in test_db: # 遍历测试集的所有batch
...
correct = tf.reduce_sum(...) # 计算当前batch的正确数
total_correct += int(correct) # 累加到总正确数
```
**执行流程示意图:**
```
测试阶段开始
│
├─ total_correct = 0 ← 初始化总正确数
│
├─ 第一个batch:
│ ├─ 预测得到pred
│ ├─ 比较pred和y_test → 生成布尔矩阵 [True, False, True...]
│ ├─ 转换为int32 → [1, 0, 1...]
│ ├─ 求和得到correct = 25(假设这个batch有30个样本,正确25个)
│ └─ total_correct = 0 + 25 = 25
│
├─ 第二个batch:
│ ├─ 同样操作得到correct = 28
│ └─ total_correct = 25 + 28 = 53
│
└─ 最后一个batch:
├─ 同样操作得到correct = 27
└─ total_correct = 53 + 27 = 80 → 最终总正确数
```
**关键点解释:**
1. **作用域隔离**:`correct`变量是每个batch内部的局部变量,每次循环都会重新创建
2. **累积载体**:`total_correct`作为外部变量,在循环开始前被初始化为0,承担累积职责
3. **类型转换**:`int(correct)`将TensorFlow张量转换为Python整数进行累加
**错误理解示例:**
如果误以为`correct`自身在累积,代码应该长这样(实际不是):
```python
correct = 0 # 错误写法(实际代码没有这样写)
for ...:
correct += current_batch_correct # 错误理解
```
**Tensor操作验证:**
假设一个batch数据为:
```python
y_test = [0, 1, 2] # 真实标签
pred = [0, 1, 1] # 预测结果
```
则:
1. `tf.equal(pred, y_test)` → [True, True, False]
2. `tf.cast(..., tf.int32)` → [1, 1, 0]
3. `tf.reduce_sum()` → 2(这个batch的正确数)
4. 这个2会被加到`total_correct`
**最终准确率计算:**
假设测试集共有150个样本,分5个batch(每个batch30个):
```
batch1正确数:27 → total_correct=27
batch2正确数:29 → total_correct=56
batch3正确数:28 → total_correct=84
batch4正确数:30 → total_correct=114
batch5正确数:28 → total_correct=142
准确率 = 142/150 ≈ 94.67%
```
**设计模式总结:**
这种`外部累加器+局部临时变量`的模式是处理批量数据统计的典型方法,在以下场景常见:
1. 分布式计算中的结果汇总
2. 流式数据处理
3. 内存受限时的大数据集处理
通过这种设计,既可以处理超出内存容量的大型数据集,又能保证计算结果的准确性。
阅读全文
相关推荐

















