Kears高级接口
Kears是对函数的高级封装,但是Kears!= tf.Kears
Metrics(测量表)
Metrics可以记录网络运行过程中的各种指标的记录 如loss,acc等,对比于
自己来记录这些值 使用Metrics更加的方便
1. 创建metrics
acc_meter = keras.metrics.Accuracy()
loss_meter = keras.metrics.Mean()
2. 向metrics传入值
这样 loss_meter会自动的计算 平均loss
loss = tf.reduce_mean(tf.losses.categorical_crossentropy(y_onehot,logits,from_logits=True))
将loss传入后 会自动的计算平均值
loss_meter.update_state(loss)
传入正确的y和预测的结果 会自动的计算准确度
acc_meter.update_state(y,pred)
3. 打印metrics的值
定期的打印平均loss
print(epoch,step,"loss:",loss_meter.result().numpy())
定期的计算准确度 每次传入 都会将 值 当打印的时候 会自动的计算准确度
print(acc_meter:",acc_meter.result().numpy())
4. 重置metrics的值
每n次重置一次 这样记录的就是n次的平均loss
loss_meter.reset_states()
acc_meter.reset_states()
Compile & Fit(快捷训练方法)
Compile可以快速的训练网络 通过传入优化器 训练集 测试集 loss指标 测量
这里需要注意的是 传入的数据集和测试集的格式 必须和网络指定的一样
并且比如标签 也要提前的变为和设置的网络一样的格式
设置优化器
optimizer = tf.optimizers.Adam(lr = 0.01)
传入训练参数 metrics可以指定打印的指标
model.compile(optimizer=optimizer,loss=tf.losses.CategoricalCrossentropy(from_logits=True)
,metrics = ['accuracy'])
传入训练次数 数据集 测试集 测试频率
model.fit(db,epochs=10,validation_data=db_test,validation_freq=2)
进行一次测试
model.evaluate(db_test)
不需要 计算loss 计算梯度 记录梯度 根据梯度迭代 进行测试
自定义网络
创建层 创建的都是默认层 可以自定义层
layer1 = keras.layers.Dense(256,activation=tf.nn.relu)
layer2 = keras.layers.Dense(128,activation=tf.nn.relu)
layer3 = keras.layers.Dense(64,activation=tf.nn.relu)
layer4 = keras.layers.Dense(32,activation=tf.nn.relu)
layer5 = keras.layers.Dense(10)
创建容器 运用Sequential创建的网络 不能进行特殊操作
model = keras.Sequential([layer1,layer2,layer3,layer4,layer5])
设置传入格式
如果不是设置 可以根据model(x)传入的值 自动的获得shape
model.build(input_shape=[None,28*28])
查看网络参数
model.summary()
通过继承类 来定义自己的层和网络
"
import tensorflow as tf
from tensorflow import keras
(x,y),(x_test,y_test) = keras.datasets.mnist.load_data()
x = tf.reshape(x,[-1,28*28])
x_test = tf.reshape(x_test,[-1,28*28])
y = tf.one_hot(y,depth=10)
y_test = tf.one_hot(y_test,depth=10)
def preprocess(x,y):
# 类型转换并且归一化
x = tf.cast(x,dtype=tf.float32) / 255.
y = tf.cast(y,dtype=tf.int32)
return x,y
db = tf.data.Dataset.from_tensor_slices((x,y))
db = db.map(preprocess)
db_test = tf.data.Dataset.from_tensor_slices((x_test,y_test))
db_test = db_test.map(preprocess)
batchs = 64
db = db.shuffle(60000).batch(batchs)
db_test = db_test.shuffle(60000).batch(batchs)
class MyDense(keras.layers.Layer):
def __init__(self,inp_dim,out_dim):
super().__init__()
# 设置 kernel 变量 w,b指定类型 后面跟shape
self.kernel = self.add_weight('w',[inp_dim,out_dim])
self.bias = self.add_weight('b',[out_dim])
# 这里被设置后 才能调用model 的 summary 查看网络信息
self.built = True
# 当训练时 会自动的调用 层对象的call 来运算 传入上层的输出 返还本层输出
# 因为继承自 Layer 所以里面有 激活函数等方法
def call(self,inputs,tarining=None):
out = inputs @ self.kernel + self.bias
return tf.nn.relu(out)
class MyModel(keras.Model):
def __init__(self):
super().__init__()
# 输入是 28*28的一个图片 输出是256维的
# 内部生成了 w和b
self.layer1 = MyDense(28*28,256)
self.layer2 = MyDense(256,128)
self.layer3 = MyDense(128,64)
self.layer4 = MyDense(64,32)
self.layer5 = keras.layers.Dense(10)
def call(self, inputs, training=None, mask=None):
# 在这里 自定义的model 就可以来进行一些特殊操作 比如 +n 等 在seq内无法完成的操作
# seq内是简单的将层进行连接
# 这里其实 会自动的调用layer的call函数
x = self.layer1(inputs)
x = self.layer2.call(x)
x = self.layer3.call(x)
x = self.layer4.call(x)
x = self.layer5(x)
return x
model = MyModel()
model.build(input_shape=[None,28*28])
model.summary()
model.compile(optimizer=keras.optimizers.Adam(lr=0.01),loss=tf.losses.CategoricalCrossentropy(from_logits=True),metrics=['accuracy'])
model.fit(db,epochs=5,validation_data = db_test,validation_freq=2)
model.evaluate(db_test)
"
模型保存和加载
保存为ckpt格式 只能在tensorflow下使用
1. model.save_weights("./checkpoints/my_checkpoint")
生成一个 checkpoint.txt 一个my_checkpoint.data-00000-of-00001 一个my_checkpoint.index
其中txt记录了名字...似乎没什么用 另外两个文件记录了权值
model.save_weights("./checkpoints/my_checkpoint")
# 在加载权之前 必须要构建和原网络相同的结构
model2 = MyModel()
model2.compile(optimizer=keras.optimizers.Adam(lr=0.01),loss=tf.losses.CategoricalCrossentropy(from_logits=True),metrics=['accuracy'])
model2.load_weights('./checkpoints/my_checkpoint')
model2.evaluate(db_test)
保存为模型+值格式
2. model.save('model.h5')
保存的模型的全部状态 包括网络结构 就不用和方法一一样 要先创建网络 才能导入权
而是直接可以网络和权一起导入
对于自定义模型会报错;
NotImplementedError:将模型保存为 HDF5 格式要求模型是功能模型或顺序模型。
它不适用于子类模型,因为此类模型是通过 Python 方法的主体定义的,该方法不能安全地序列化。
考虑保存为 Tensorflow SavedModel 格式(通过设置 save_format="tf")或使用 `save_weights`。
大概的意思就是 HDF5只能保存官方的模型 自定义的不行
对于自定义对象的HDF5对象的保存:
看这里:
https://www.tensorflow.org/tutorials/keras/save_and_load?hl=zh-cn#%E4%BF%9D%E5%AD%98%E8%87%AA%E5%AE%9A%E4%B9%89%E5%AF%B9%E8%B1%A1
但是可以不保存为h5 保存为tf格式
默认就是保存为tf格式
model.save("./myModel")
model2 = tf.keras.models.load_model("./myModel")
model2.evaluate(db_test)
/
model.save("./myModel",save_format='tf')
model2 = tf.keras.models.load_model("./myModel")
model2.evaluate(db_test)
保存格式结构
assets/
assets.extra/
variables/
variables.data-?????-of-?????
variables.index
saved_model.pb
可以通过 save_format来指定保存的类型 也可以直接的使用.xx来指定
save_format: Either `'tf'` or `'h5'`, indicating whether to save the
model to Tensorflow SavedModel or HDF5. Defaults to 'tf' in TF 2.X,
and 'h5' in TF 1.X.
关于tensorflow到底有多少类型(类型不仅仅是一个文件)
1. CheckPoint(*.ckpt) 及保存方法一保存的类型 仅仅有权值 无网络结构
2. GraphDef(*.pb)
这种格式文件包含 protobuf 对象序列化后的数据,包含了计算图,可以从中得到所有运算符(operators)的细节,也包含张量(tensors)和 Variables 定义,但不包含 Variable 的值,因此只能从中恢复计算图,但一些训练的权值仍需要从 checkpoint 中恢复。
TensorFlow 一些例程中用到 *.pb 文件作为预训练模型,这和上面 GraphDef 格式稍有不同,属于冻结(Frozen)后的 GraphDef 文件,简称 FrozenGraphDef 格式。
这种文件格式不包含 Variables 节点。将 GraphDef 中所有 Variable 节点转换为常量(其值从 checkpoint 获取),
就变为 FrozenGraphDef 格式。代码可以参考 tensorflow/python/tools/freeze_graph.py.pb 为二进制文件,实际上 protobuf 也支持文本格式(.pbtxt),但包含权值时文本格式会占用大量磁盘空间,一般不用。
也就是说GraphDef和checkpoint互补,只保存了模型结构没有保存变量值。 --- 原文链接:https://blog.csdn.net/qq_42058018/article/details/108639460
就是.pb文件可以存储权值 但是会很大 所以一般不用
但是如果使用opencv的dnn来读取 .pb 就肯定是需要有权值的才可以
下面这两个是保存的是完整的模型 值+网络
3. SavedModel是tensorflow2的默认格式
在使用 TensorFlow Serving 时,会用到这种格式的模型。
该格式为 GraphDef 和 CheckPoint 的结合体
就是方法二保存的tf类型 一组文件
4. HDF5