训练模型(TF)
#1.导入库
常见库如下:
| 导入方式 | 库 | 主要作用 |
|---|---|---|
import tensorflow as tf |
TensorFlow | 模型训练、推理、TFLite转换 |
import numpy as np |
NumPy | 数据处理、数组运算 |
import matplotlib.pyplot as plt |
Matplotlib | 数据可视化、绘图 |
from tensorflow.keras import layers |
Layers | 创建神经网络层 |
from tensorflow.keras import models |
Models | 创建模型结构 |
from tensorflow.keras import losses |
Losses | 损失函数 |
from tensorflow.keras import optimizers |
Optimizers | 优化器 |
from tensorflow.keras.callbacks import ... |
Callbacks | 训练控制 |
import math |
Math | 数学运算 |
📌其实大多数项目:这4个就够了
import tensorflow as tf #神经网络训练
import numpy as np #数据处理
import matplotlib.pyplot as plt #画图
from tensorflow.keras import layers #搭网络层
📌 完整训练流程对应关系
导入库
↓
生成/读取数据 ← numpy
↓
画数据图 ← matplotlib
↓
切分训练集 ← numpy
↓
创建模型 ← tensorflow / layers
↓
compile编译 ← tensorflow
↓
fit训练 ← tensorflow
↓
画loss曲线 ← matplotlib
↓
转换TFLite ← tensorflow
#2.数据集准备
本质:不同任务,不同题目+答案,分成大小不同的3份
| 任务类型 | 输入(X) | 标签(y) |
|---|---|---|
| 回归 | 数值/时间序列 | 连续数值 |
| 分类 | 数值/图像/音频/文本 | 类别编号 |
| 生成 | 文本/图像 | 下一词/像素 |
| 检测 | 图像/时序 | 位置+类别 |
案例一:现有数据集
#1.现有数据集(加载MNIST数据集)
(x_train,y_train),(x_test,y_test)=tf.keras.datasets.mnist.load_data()#加载MNIST数据集
案例二:制作数据集
# 生成一些随机样本
np.random.seed(1234) #随机种子,不改变形状
x_values=np.random.uniform(low=0,high=(2*math.pi),size=nsamples) #(nsamples,)
# 使用这些值创建一个带噪声的正弦波
y_values=np.sin(x_values)+(0.1*np.random.randn(x_values.shape[0])) #(nsamples,)
# 将数据集拆分为训练集、验证集和测试集
val_split=int(val_ratio*nsamples) #计算验证集分割点
test_split=int(val_split+(test_ratio*nsamples)) #计算测试集分割点
x_val,x_test,x_train=np.split(x_values,[val_split,test_split]) #(nsamples,)->(验证集,测试集,训练集)
y_val,y_test,y_train=np.split(y_values,[val_split,test_split]) #(nsamples,)->(验证集,测试集,训练集)
#3数据预处理
本质:把数据转换成该种神经网络要求的形式(不同网络吃的数据形式不同)
项目一:识别手写数字(CNN网络)
#预处理函数(对每一条数据做统一处理)
def preprocess(image,label):
image=tf.cast(image,tf.float32)/255.0 #(28,28)->(28,28)
image=tf.expand_dims(image,axis=-1) #(28,28)->(28,28,1)
return image,label #image:(28,28,1)
#训练数据管道
train_dataset=(tf.data.Dataset.from_tensor_slices((x_train,y_train))
#(60000,28,28)->(28,28)
.map(preprocess,num_parallel_calls=tf.data.AUTOTUNE) #(28,28)->(28,28,1)
.shuffle(1000) #形状不变,顺序打乱
.batch(32) #(28,28,1)->(32,28,28,1)
.prefetch(tf.data.AUTOTUNE)) #形状不变
#测试数据管道
test_dataset=tf.data.Dataset.from_tensor_slices((x_test,y_test)) #(10000,28,28)->(28,28)
.map(preprocess) #(28,28)->(28,28,1)
.batch(32) #(28,28,1)->(32,28,28,1)
项目二:识别手写数字(Dense网络)
# 加载内置MNIST数据集
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
# x_train:(60000,28,28) y_train:(60000,) / x_test:(10000,28,28) y_test:(10000,)
# 将像素值缩放到0-1范围
x_train = x_train.astype("float32") / 255 # (60000,28,28)->(60000,28,28)
x_test = x_test.astype("float32") / 255 # (10000,28,28)->(10000,28,28)
# 将图像展平为784维向量
x_train = x_train.reshape(-1, 784) # (60000,28,28)->(60000,784),-1表示自动计算这一维
x_test = x_test.reshape(-1, 784) # (10000,28,28)->(10000,784)
# 标签转为one-hot编码
y_train = keras.utils.to_categorical(y_train, 10) # (60000,)->(60000,10)
y_test = keras.utils.to_categorical(y_test, 10) # (10000,)->(10000,10)
#3.搭建模型
本质:不同网络是为了处理不同类型的数据
| 常见网络 | 输入数据要求 | 用途 |
|---|---|---|
| MLP(全连接神经网络) | 一维特征向量,例如 (784,)、(10,)。通常需要将数据展平。例:MNIST图片 (28,28) → (784,) |
数字识别、传感器数据分类、简单分类任务 |
| CNN(卷积神经网络) | 保留空间结构的多维数据,例如 (28,28,1)、(96,96,3)。例:摄像头图片 (96,96,3) |
图像分类、图像识别、视觉任务 |
| LSTM(长短期记忆网络) | 时序数据,格式通常为 (时间步, 特征数)。例:100个采样点的加速度数据 (100,3) |
语音识别、时间序列预测、传感器时序分析 |
| AutoEncoder(自编码器) | 输入和输出数据格式相同,可以是向量、图像或时序数据。例:振动信号 (128,) → 重构 (128,) |
异常检测、数据压缩、特征提取 |
| Transformer(轻量Transformer) | 序列数据,需要按时间顺序排列。例:语音特征 (50,13)(50帧MFCC,每帧13个特征) |
语音处理、时序分析、轻量级自然语言处理 |
例一:MLP(全连接神经网络)
#搭建模型
model = keras.Sequential([
layers.Dense(512, activation='relu', input_shape=(784,)),
layers.Dropout(0.2),
layers.Dense(256, activation='relu'),
layers.Dense(10, activation='softmax')
])
例二:CNN(卷积神经网络)
model = models.Sequential([
layers.Conv2D(32, (3, 3), activation='relu', input_shape=(28, 28, 1)),
# 卷积层:提取局部特征(32个卷积核)
layers.MaxPooling2D((2, 2)), # 最大池化:下采样,降低特征图尺寸
layers.Conv2D(64, (3, 3), activation='relu'), # 第二层卷积:提取更高层特征
layers.MaxPooling2D((2, 2)), # 再次池化,继续降维
layers.Flatten(), # 展平:把2D特征图变成1D向量
layers.Dense(128, activation='relu'), # 全连接层:进行特征组合与学习
layers.Dropout(0.5), # Dropout:随机失活一部分神经元,防止过拟合
layers.Dense(10, activation='softmax')
# 输出层:10分类(数字0-9),softmax输出概率
])
常见网络层
1.Dense(全连接层)
|
参数 |
作用 |
常见值 |
|---|---|---|
|
units |
神经元数量 |
32、64、128、256 |
|
activation |
激活函数 |
|
|
use_bias |
是否使用偏置 |
|
2.Conv2D(卷积层)
|
参数 |
作用 |
常见值 |
|---|---|---|
|
filters |
卷积核数量 |
8、16、32、64 |
|
kernel_size |
卷积核大小 |
(3,3)、(5,5) |
|
strides |
步长 |
(1,1)、(2,2) |
|
padding |
填充方式 |
|
|
activation |
激活函数 |
|
3.MaxPooling2D(最大池化层)
|
参数 |
作用 |
常见值 |
|---|---|---|
|
pool_size |
池化窗口大小 |
(2,2) |
|
strides |
步长 |
2 |
|
padding |
填充方式 |
|
4.Flatten(展平层)
|
参数 |
作用 |
常见值 |
|---|---|---|
|
无 |
多维数据转一维 |
- |
5.Dropout(随机失活层)
|
参数 |
作用 |
常见值 |
|---|---|---|
| rate | 丢弃比例 | 0.2、0.3、0.5 |
#4.编译模型
📌 model.compile( )最常见写法
model.compile( #告诉TensorFlow:
optimizer='adam', # 1.怎么学习
loss='sparse_categorical_crossentropy', # 2.怎么判断错误
metrics=['accuracy'] # 3.训练时显示什么
)
|
参数 |
作用 |
|---|---|
|
optimizer |
优化器(根据 loss 来修改模型参数) |
|
loss |
损失函数(衡量模型“错了多少”) |
|
metrics |
训练过程中的“成绩显示器” |
📌 1. optimizer(优化器)
optimizer='adam' #根据损失,调整神经网络的权重
|
优化器 |
什么时候用 |
|---|---|
|
|
大部分任务直接用,通用性最强 |
|
|
时间序列、RNN、小数据训练时常见 |
|
|
想手动精细控制训练过程时用,研究和经典模型常见 |
📌 2. loss(损失函数)
loss='mae' #衡量模型“错了多少”
|
loss |
什么时候用 |
|---|---|
|
|
预测连续数值时用,例如温度、房价、sin曲线 |
|
|
也是预测连续数值时用,常用于回归任务 |
|
|
多分类任务,标签是数字时用,例如MNIST的0~9 |
|
|
双分类任务,例如“猫/狗”、“有病/没病” |
📌 3. metrics(指标)
metrics=['accuracy'] #训练时显示什么结果
|
metrics |
什么时候用 |
|---|---|
|
|
分类任务时用,查看预测正确率 |
|
|
回归任务时用,查看预测值平均误差大小 |
#5.训练模型
history = model.fit(
train_dataset, # 训练数据集
epochs=10, # 最多训练 10 轮
validation_data=test_dataset, # 用测试集评估验证效果
callbacks=[
tf.keras.callbacks.EarlyStopping(
patience=3, # 验证集性能连续 3 轮无提升则停止训练
restore_best_weights=True # 停止时自动恢复最佳权重
),
tf.keras.callbacks.ModelCheckpoint(
'best_model.h5', # 模型保存路径
save_best_only=True # 只保存验证集表现最好的那一轮
)
]
)
📌batch_size
假设:
训练集一共有1000张图片
batch_size=100
第1批:学习1~100
第2批:学习101~200
...
第10批:学习901~1000
这10批学完,才算1个epoch
📌callbacks
|
Callback |
作用 |
|---|---|
|
|
效果不再提升时提前停止训练 |
|
|
自动保存训练效果最好的模型 |
|
|
效果变差时自动降低学习率 |
|
|
可视化查看训练过程 |
#6.显示训练记录
本质:绘制Epoch-Accuracy 和 Epoch-Loss两个图,不同任务类型关注点不同
显示的整体流程:
plt.plot(epochs,val_loss,'b',label='验证损失') #画验证损失曲线
plt.title('训练损失和验证损失') #设置标题
plt.legend() #显示图例
plt.show() #显示图像
项目一:分类任务(更关注Accuracy)
# 5. 评估模型
test_loss, test_acc = model.evaluate(test_dataset) # 在测试集上计算损失和准确率
print(f'测试集准确率: {test_acc:.4f}') # 打印准确率,保留4位小数
# 6. 可视化训练过程
plt.plot(history.history['accuracy'], label='Training Accuracy') # 训练集准确率曲线
plt.plot(history.history['val_accuracy'], label='Validation Accuracy') # 验证集准确率曲线
plt.xlabel('Epoch') # x 轴:训练轮次
plt.ylabel('Accuracy') # y 轴:准确率
plt.legend() # 显示图例
plt.show() # 渲染并展示图表
项目二:sin回归任务(更关注Loss)
# 绘制训练过程中的损失曲线
loss = history.history['loss'] # 每轮训练集损失值
val_loss = history.history['val_loss'] # 每轮验证集损失值
epochs = range(1, len(loss) + 1) # 生成轮次序号 [1, 2, ..., n]
plt.plot(epochs, loss, 'bo', label='Training loss') # 训练损失,蓝色圆点
plt.plot(epochs, val_loss, 'b', label='Validation loss') # 验证损失,蓝色实线
plt.title('Training and validation loss') # 图表标题
plt.legend() # 显示图例
plt.show() # 渲染并展示图表
📌plt.plot()
| 参数 | 说明 | 常用值示例 |
|---|---|---|
x |
x 轴数据 | [1,2,3]、range(10) |
y |
y 轴数据 | [0.8, 0.85, 0.9] |
color |
线条颜色 | 'red'、'b'、'#ff0000' |
linewidth |
线条宽度 | 1、2、2.5 |
linestyle |
线型 | '-' 实线、'--' 虚线、':' 点线 |
marker |
标记形状 | 'o' 圆、's' 方、'^' 三角 |
label |
图例名称 | 'Training Accuracy' |
alpha |
透明度 | 0.3、0.5、1.0 |
#7.模型转为tflite格式
本质:Keras 模型 (float32) → 量化压缩 → TFLite 模型 (int8)
# 1. 创建转换器
converter = lite.TFLiteConverter.from_keras_model(model)
# 2. 定义校准数据集(取 100 条训练数据,用于统计每层数值范围)
def representative_dataset():
for i in range(100):
yield [x_train[i:i+1]]
# 3. 开启完全 INT8 量化
converter.optimizations = [lite.Optimize.DEFAULT]
converter.representative_dataset = representative_dataset # 指定校准数据
converter.target_spec.supported_ops = [lite.OpsSet.TFLITE_BUILTINS_INT8]
# 强制所有算子使用 int8
converter.inference_input_type = tf.int8 # 输入改为 int8
converter.inference_output_type = tf.int8 # 输出改为 int8
# 4. 执行转换
tflite_model = converter.convert()
# 5. 保存为 .tflite 文件
open(tflite_model_name + '.tflite', 'wb').write(tflite_model)
converter.optimizations可选项
| 选项 | 说明 |
|---|---|
OPTIMIZE_FOR_SIZE |
将模型权重从 float32 压缩为 int8,体积缩小约 75% |
OPTIMIZE_FOR_LATENCY |
对运算做优化,减少推理时的计算量 |
DEFAULT |
同时对权重和运算做优化,体积和速度都有提升 |
实际上 TensorFlow 后续版本中这三个选项效果已基本相同,官方推荐统一使用 DEFAUL
#8.模型转为C数组
# 函数:将十六进制值转换为 C 编程所需的数组
def hex_to_c_array ( hex_data, var_name ):
c_str = ''
# 创建头部守卫
c_str += '#ifndef ' + var_name.upper() + '_H\n'
c_str += '#define ' + var_name.upper() + '_H\n\n'
# 在文件顶部添加数组长度
c_str += '\nunsigned int ' + var_name + '_len = ' + str(len(hex_data)) + ';\n'
# 声明 C 变量
c_str += 'unsigned char ' + var_name + '[] = {'
hex_array = []
for i, val in enumerate ( hex_data ) :
#从十六进制构造字符串
hex_str = format(val, '#04x' )
# 添加格式,使每行长度不超过 80 个字符
if (i + 1 ) < len(hex_data):
hex_str += ','
if (i + 1 ) % 12 == 0 :
hex_str += '\n'
hex_array.append(hex_str)
# 添加右大括号
c_str += '\n' + format( ' ' .join (hex_array)) + '\n};\n\n'
# 关闭头部 guard
c_str += '#endif //' + var_name.upper() + '_H'
return c_str
#使用 open (c_model_name + '.h' , 'w' ) as file将 TFLite 模型写入 C 源文件(或头文件):
with open(c_model_name + ".h", "w") as file:
file.write(
hex_to_c_array(
tflite_model,
c_model_name
)
)
本质上就是:将二进制文件逐字节转成十六进制写进 C 头文件
.tflite 二进制文件 → unsigned char model[] = {0x1c, 0x00, ...}
只要满足以下两点,任何模型都适用:
| 条件 | 说明 |
|---|---|
已转换为 .tflite 格式 |
这段代码的输入是 tflite_model 二进制数据 |
| 已完成 int8 量化 | 保证 MCU 能正常推理 |
模型是 CNN、RNN 还是全连接网络,对这段代码来说没有任何影响。
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐

所有评论(0)