2.CIFAR-10与ImageNet图像识别
·
2.1.CIFAR-10数据集
epoch:
是什么:
- 1 个 epoch = 把整个训练集完整遍历、计算一遍;
为什么:
- 学完全部避免只学了局部;
- 方便观察训练进度;
- 防止:不足时欠拟合(类似于学习次数太少没学透知识);过多时过拟合(学习过多,全部死记硬背下来,在训练集中好,但测试里差)
- 学习率衰减(前期:大学习率 → 快速下降,快速缩小损失范围;后期:逐步降低学习率 → 微调权重,平稳收敛到最优谷底,提升最终精度)
- 进行模型保持,方便后续评估
怎么用:
- 「总样本数 /batch_size」算每 epoch 步数,设定总步数对应 epoch 数,在循环中监控进度。
TensorFlow中的数据读取:
原始输入层-数据集初始化-Epoch循环-数据预处理映射层-迭代-二进制写入本地
import tensorflow as tf
import os
#创文件
if not os.path.exists('read_tf2'):
os.makedirs('read_tf2')
file_list = ["A.jpg", "B.jpg", "C.jpg"]
# 1. 构建数据集,repeat(5) 等价 num_epochs=5
ds = tf.data.Dataset.from_tensor_slices(file_list).repeat(5)
# 读取整文件二进制
def load_img(path):
return tf.io.read_file(path)
ds = ds.map(load_img)
# 迭代读取保存
for idx, img_bin in enumerate(ds):
with open(f"read_tf2/test_{idx+1}.jpg", "wb") as f:
f.write(img_bin.numpy())
print("5轮遍历完成,自动结束,无异常抛出")

2.1.4实验:将CIFAR-10数据集保存为图片形式
import tensorflow as tf
import os
import numpy as np
from PIL import Image
from cifar10_input import load_bin_file # 导入修复后的函数
if __name__ == "__main__":
data_dir = "cifar10_data/cifar-10-batches-bin"
save_dir = "cifar10_data/raw"
if not os.path.exists(save_dir):#解析后存放处
os.makedirs(save_dir)
# 加载第一个训练bin文件
first_bin = os.path.join(data_dir, "data_batch_1.bin")
ds = load_bin_file(first_bin)
# 只取前30张图片
ds = ds.take(30)
save_idx = 0#从0开始命名
for img_tensor, label_tensor in ds:#图片,标签
# 浮点转uint8图像
img_arr = np.clip(img_tensor.numpy(), 0, 255).astype(np.uint8)
#转为numpy数组,才能被PIL识别
#裁剪像素,防止花屏全黑图
#强制转型为8位
img = Image.fromarray(img_arr)#像素数组转为图像
img.save(os.path.join(save_dir, f"{save_idx}.jpg"))#写入磁盘
save_idx += 1#文件名+1
print(f"✅ 成功保存30张CIFAR10图片至 {save_dir}")
"""
TF2 原生tf.data重构CIFAR10二进制读取,替代TF1 string_input_producer、FixedLengthRecordReader队列
完全兼容原接口调用逻辑,无废弃API、无线程手动管理、无Session依赖
"""
import tensorflow as tf
import os
# 基础超参
IMAGE_SIZE = 24
NUM_CLASSES = 10
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 50000
NUM_EXAMPLES_PER_EPOCH_FOR_EVAL = 10000
RECORD_BYTES = 1 + 3 * 32 * 32 # 1字节标签 + 3通道32*32图像
def parse_single_cifar_record(raw_record):
"""解析单条CIFAR10二进制样本,等价原read_cifar10读取逻辑"""
# 拆分标签与图像
label = tf.cast(tf.slice(raw_record, [0], [1]), tf.int32)
image_raw = tf.slice(raw_record, [1], [3 * 32 * 32])
# 通道优先转通道最后 [C,H,W] -> [H,W,C]
image = tf.reshape(image_raw, [3, 32, 32])
image = tf.transpose(image, [1, 2, 0])
image = tf.cast(image, tf.float32)
return image, label
def load_bin_file(file_path):
"""读取单个bin文件,解码全部样本(兼容旧版TF2,无decode_fixed_length_records依赖)"""
# 读取整个bin文件为字节串
file_content = tf.io.read_file(file_path)
# 解码为uint8字节张量
bytes_tensor = tf.io.decode_raw(file_content, tf.uint8)
# 计算总样本数 = 总字节数 ÷ 单条样本字节数
total_records = tf.shape(bytes_tensor)[0] // RECORD_BYTES
# 截断到完整样本长度,避免余数
bytes_tensor = bytes_tensor[:total_records * RECORD_BYTES]
# 重塑为 [样本数, 单条样本字节数]
records = tf.reshape(bytes_tensor, [total_records, RECORD_BYTES])
# 构建数据集并逐条解析
ds = tf.data.Dataset.from_tensor_slices(records)
ds = ds.map(parse_single_cifar_record, num_parallel_calls=tf.data.AUTOTUNE)
return ds
def distorted_inputs(data_dir, batch_size):
"""
训练集:带数据增强,等价原版distorted_inputs
return: image_batch (B,24,24,3), label_batch (B,)
"""
# 拼接5个训练bin文件
file_paths = [os.path.join(data_dir, f"data_batch_{i}.bin") for i in range(1, 6)]
ds = tf.data.Dataset.from_tensor_slices(file_paths)
# 逐个加载bin文件并合并数据集
ds = ds.flat_map(load_bin_file)
# 数据增强
def augment(image, label):
# 随机裁剪 32->24
image = tf.image.random_crop(image, [IMAGE_SIZE, IMAGE_SIZE, 3])
# 随机水平翻转
image = tf.image.random_flip_left_right(image)
# 亮度、对比度
image = tf.image.random_brightness(image, max_delta=63)
image = tf.image.random_contrast(image, lower=0.2, upper=1.8)
# 标准化
image = tf.image.per_image_standardization(image)
return image, tf.reshape(label, [])
ds = ds.map(augment, num_parallel_calls=tf.data.AUTOTUNE)
# 打乱、批次、预取加速
min_queue_examples = int(NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN * 0.4)
ds = ds.shuffle(buffer_size=min_queue_examples)
ds = ds.batch(batch_size, drop_remainder=False)
ds = ds.prefetch(tf.data.AUTOTUNE)
return ds
def inputs(eval_data, data_dir, batch_size):
"""
测试/验证集:无随机增强,中心裁剪,等价原版inputs
"""
if not eval_data:
file_paths = [os.path.join(data_dir, f"data_batch_{i}.bin") for i in range(1, 6)]
else:
file_paths = [os.path.join(data_dir, "test_batch.bin")]
ds = tf.data.Dataset.from_tensor_slices(file_paths)
ds = ds.flat_map(load_bin_file)
# 测试预处理:中心裁剪+标准化
def preprocess_eval(image, label):
image = tf.image.resize_with_crop_or_pad(image, IMAGE_SIZE, IMAGE_SIZE)
image = tf.image.per_image_standardization(image)
return image, tf.reshape(label, [])
ds = ds.map(preprocess_eval, num_parallel_calls=tf.data.AUTOTUNE)
ds = ds.batch(batch_size)
ds = ds.prefetch(tf.data.AUTOTUNE)
return ds

2.2利用TensorFlow训练CIFAR-10识别模型
数据增强(distorted_inputs()):在训练阶段对原图做随机几何、像素变换,用有限 5 万张训练图生成大量 “新样本”,扩充数据分布,降低过拟合、提升泛化能力,让模型在测试集陌生图片上表现更好。
建立模型识别图像: cifar10_inference_tf2()
输入归一化后的 24×24 彩色图片 → 双层卷积提取视觉特征 → 池化降维 + 归一化增强特征 → 特征扁平化 → 两层全连接提炼高层语义 → 输出 10 分类原始得分
import tensorflow as tf
# 全局常量和原代码保持一致
NUM_CLASSES = 10
def lrn_alternative(x):
return tf.keras.layers.BatchNormalization()(x)
def cifar10_inference_tf2(images, batch_size):
#TF2 等价原TF1 inference推理函数
# 第一层卷积conv1:提取底层基础视觉特征:边缘、线条、色块、纹理,是图像最基础像素级特征
# 权重初始化 stddev=5e-2,L2权重衰减wd=0.0
conv1 = tf.keras.layers.Conv2D(
filters=64,kernel_size=(5, 5),activation="relu",
strides=(1, 1),
padding="SAME",
kernel_initializer=tf.keras.initializers.RandomNormal(stddev=5e-2),
bias_initializer=tf.keras.initializers.Zeros(),
kernel_regularizer=tf.keras.regularizers.L2(0.0),
name="conv1"
)(images)
# 第一层最大池化 pool1
pool1 = tf.keras.layers.MaxPool2D(
pool_size=(3, 3),
strides=(2, 2),
padding="SAME",
name="pool1"
)(conv1)
# 归一化:norm1 LRN
norm1 = lrn_alternative(pool1)
# 第二层卷积 conv2
conv2 = tf.keras.layers.Conv2D(
filters=64,
kernel_size=(5, 5),
strides=(1, 1),
padding="SAME",
kernel_initializer=tf.keras.initializers.RandomNormal(stddev=5e-2),
bias_initializer=tf.keras.initializers.Constant(0.1),
kernel_regularizer=tf.keras.regularizers.L2(0.0),
activation="relu",
name="conv2"
)(norm1)
#原norm2 LRN
norm2 = lrn_alternative(conv2)
#第二层最大池化 pool2
pool2 = tf.keras.layers.MaxPool2D(
pool_size=(3, 3),
strides=(2, 2),
padding="SAME",
name="pool2"
)(norm2)
# 展平,适配全连接
flatten = tf.keras.layers.Flatten()(pool2)
# 固定batch维度,和原代码reshape([batch_size, -1])行为一致
flatten = tf.reshape(flatten, [batch_size, -1])
# 全连接 local3 2304 -> 384
local3 = tf.keras.layers.Dense(
units=384,
kernel_initializer=tf.keras.initializers.RandomNormal(stddev=0.04),
bias_initializer=tf.keras.initializers.Constant(0.1),
kernel_regularizer=tf.keras.regularizers.L2(0.004), # 原wd=0.004
activation="relu",
name="local3"
)(flatten)
#全连接 local4 384 -> 192
local4 = tf.keras.layers.Dense(
units=192,
kernel_initializer=tf.keras.initializers.RandomNormal(stddev=0.04),
bias_initializer=tf.keras.initializers.Constant(0.1),
kernel_regularizer=tf.keras.regularizers.L2(0.004),
activation="relu",
name="local4"
)(local3)
#输出分类层 softmax_linear 192->10
logits = tf.keras.layers.Dense(
units=NUM_CLASSES,
kernel_initializer=tf.keras.initializers.RandomNormal(stddev=1.0 / 192.0),
bias_initializer=tf.keras.initializers.Zeros(),
kernel_regularizer=tf.keras.regularizers.L2(0.0), # 输出层无权重衰减
activation=None, # 关键:和原版一致,不提前softmax
name="softmax_linear"
)(local4)
return logits
# 封装为完整Sequential模型
def create_cifar10_sequential_model(batch_size):
input_tensor = tf.keras.Input(shape=(24, 24, 3), batch_size=batch_size)
out = cifar10_inference_tf2(input_tensor, batch_size)
model = tf.keras.Model(inputs=input_tensor, outputs=out, name="CIFAR10_Official_TF2")
return model
训练模型:
(没弄清楚代码,累了。)
# Copyright 2015 The TensorFlow Authors. All Rights Reserved.
# ==============================================================================
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import tensorflow.compat.v1 as tf
tf.disable_v2_behavior()
from datetime import datetime
import time
import sys
import os
import cifar10
import cifar10_input
from absl import flags
FLAGS = flags.FLAGS
flags.DEFINE_string('train_dir', 'cifar10_train/', "")
flags.DEFINE_string('data_dir', 'cifar10_data/cifar-10-batches-bin/', "")
flags.DEFINE_integer('batch_size', 128, "")
flags.DEFINE_integer('max_steps', 100000, "")
flags.DEFINE_boolean('log_device_placement', False, "")
flags.DEFINE_integer('log_frequency', 10, "")
flags.DEFINE_float('learning_rate', 0.1, "")
NUM_EXAMPLES_PER_EPOCH_FOR_TRAIN = 50000
def train():
with tf.Graph().as_default():
global_step = tf.train.get_or_create_global_step()
# 数据加载
train_dataset = cifar10_input.distorted_inputs(
data_dir=FLAGS.data_dir,
batch_size=FLAGS.batch_size
)
data_iterator = tf.compat.v1.data.make_one_shot_iterator(train_dataset)
images, labels = data_iterator.get_next()
# 网络与损失
logits = cifar10.inference(images)
loss = cifar10.loss(logits, labels)
train_op = cifar10.train(loss, global_step)
# TensorBoard 日志
tf.summary.scalar('train_loss', loss)
merged_summary = tf.summary.merge_all()
# 手动模型保存器
saver = tf.train.Saver(max_to_keep=5)
class _LoggerHook(tf.train.SessionRunHook):
def begin(self):
self._step = -1
self._start_time = time.time()
self.summary_writer = tf.summary.FileWriter(FLAGS.train_dir, tf.get_default_graph())
def before_run(self, run_context):
self._step += 1
return tf.train.SessionRunArgs([loss, global_step, merged_summary])
def after_run(self, run_context, run_values):
loss_val, step, summary = run_values.results
# 写入 TensorBoard
if self._step % FLAGS.log_frequency == 0:
self.summary_writer.add_summary(summary, step)
cost_time = time.time() - self._start_time
self._start_time = time.time()
samples_per_sec = FLAGS.log_frequency * FLAGS.batch_size / cost_time
sec_per_batch = cost_time / FLAGS.log_frequency
print(f"{datetime.now()}: step {step}, loss={loss_val:.2f}, {samples_per_sec:.1f} samples/sec")
# 每 500 步手动保存模型
if step % 500 == 0 and step > 0:
saver.save(
run_context.session,
os.path.join(FLAGS.train_dir, "model.ckpt"),
global_step=step
)
# 关键:彻底关闭自动保存,避免参数冲突
with tf.train.MonitoredTrainingSession(
checkpoint_dir=FLAGS.train_dir,
save_checkpoint_secs=None, # 关闭按时间保存
save_checkpoint_steps=None, # 关闭按步数保存
hooks=[
tf.train.StopAtStepHook(last_step=FLAGS.max_steps),
tf.train.NanTensorHook(loss),
_LoggerHook()
],
config=tf.ConfigProto(log_device_placement=FLAGS.log_device_placement)
) as mon_sess:
while not mon_sess.should_stop():
mon_sess.run(train_op)
def main(argv=None):
train_path = FLAGS.train_dir
if tf.io.gfile.exists(train_path):
tf.io.gfile.rmtree(train_path)
tf.io.gfile.makedirs(train_path)
time.sleep(0.3)
train()
if __name__ == '__main__':
FLAGS(sys.argv)
main()
启动Anaconda Navigator命令窗口
- conda activate dl_21project
- D:
- cd Deep-Learning-21-Examples\chapter_2
- python cifar10_train.py --train_dir cifar10_train/ --data_dir cifar10_data/cifar-10-batches-bin/

这里使用的是cpu训练,输入修改def train()后可以查看:
def train():
# ========== 新增:设备检测,启动就打印CPU/GPU状态 ==========
physical_devices = tf.config.list_physical_devices()
print("===== 训练硬件设备检测结果 =====")
for dev in physical_devices:
print(f"检测到设备: {dev}")
gpu_devices = tf.config.list_physical_devices('GPU')
if len(gpu_devices) > 0:
print("✅ 识别到GPU,将使用GPU加速训练")
else:
print("❌ 无可用GPU,将使用CPU训练")
print("==================================\n")
with tf.Graph().as_default():
global_step = tf.train.get_or_create_global_step()
# 下方原有代码完全不变
train_dataset = cifar10_input.distorted_inputs(
data_dir=FLAGS.data_dir,
batch_size=FLAGS.batch_size
)
data_iterator = tf.compat.v1.data.make_one_shot_iterator(train_dataset)
images, labels = data_iterator.get_next()
logits = cifar10.inference(images)
loss = cifar10.loss(logits, labels)
train_op = cifar10.train(loss, global_step)
tf.summary.scalar('train_loss', loss)
merged_summary = tf.summary.merge_all()
saver = tf.train.Saver(max_to_keep=5)
class _LoggerHook(tf.train.SessionRunHook):
def begin(self):
self._step = -1
self._start_time = time.time()
self.summary_writer = tf.summary.FileWriter(FLAGS.train_dir, tf.get_default_graph())
def before_run(self, run_context):
self._step += 1
return tf.train.SessionRunArgs([loss, global_step, merged_summary])
def after_run(self, run_context, run_values):
loss_val, step, summary = run_values.results
if self._step % FLAGS.log_frequency == 0:
self.summary_writer.add_summary(summary, step)
cost_time = time.time() - self._start_time
self._start_time = time.time()
samples_per_sec = FLAGS.log_frequency * FLAGS.batch_size / cost_time
sec_per_batch = cost_time / FLAGS.log_frequency
print(f"{datetime.now()}: step {step}, loss={loss_val:.2f}, {samples_per_sec:.1f} samples/sec")
if step % 500 == 0 and step > 0:
saver.save(run_context.session, os.path.join(FLAGS.train_dir, "model.ckpt"), global_step=step)
with tf.train.MonitoredTrainingSession(
checkpoint_dir=FLAGS.train_dir,
save_checkpoint_secs=None,
save_checkpoint_steps=None,
hooks=[
tf.train.StopAtStepHook(last_step=FLAGS.max_steps),
tf.train.NanTensorHook(loss),
_LoggerHook()
],
config=tf.ConfigProto(log_device_placement=FLAGS.log_device_placement)
) as mon_sess:
while not mon_sess.should_stop():
mon_sess.run(train_op)

在TensorFlow中查看训练进度
在Anaconda Navigator命令窗口执行:
执行训练模型后不关闭,新开窗口:
- D:
- cd Deep-Learning-21-Examples\chapter_2
- conda activate dl_21project
- tensorboard --logdir cifar10_train/ --port 6006
浏览器输入网址: http://localhost:6006/
summary_writer.add_summary() 没有被正确执行,loss 数据没写入日志文件:

改后依旧有问题......
每秒训练步数的情况:

代码train有问题,只能看到global_step.......,没看到total -loss -1和learning -rate
测试模型效果:
cifar10_eval.py没运行出来.....
更多推荐




所有评论(0)