Tensorflow练习

模型保存

Keras接口的模型保存

model.save("xxx.h5")  # 保存模型结构和权重
model.to_json()  # 保存模型结构

# 加载
model.load_model('xxx.h5')
models.model_from_json()  # json
model.load_weights()  # json

tensorflow接口的模型保存

model.save('tf_model_savedmodel', save_format="tf")  # 保存模型和结构
model.save_weights('./data/tf_model_weights.ckpt',save_format = "tf")  # 仅保存权重

# 加载
tf.keras.models.load_model('tf_model_savedmodel')  # 

数据加载

数据加载是将其他类型的数据转换为tf.data.Dataset类型。

最简单的数据加载在方式是从list中加载,tf.data.Dataset.list_files()可以从一系列满足正则条件的文件中(如图片)加载数据。

Dataset支持的操作

  • Transformations. Dataset.mapDataset.apply
  • Batch. Dataset.batch
  • Cache. 当迭代完成后,会缓存在内存或者文件中,后续的迭代会使用缓存的数据
  • Concatenate. 将两个Dataset类型concatenate,两者必须有相同的数据类型,返回新对象。
  • Filter
  • From_generator
  • Reduce
  • Shuffle
  • Zip
  • unbatch
  • take

图片数据加载

可以使用tf.data.Dataset.list_files()读取一系列照片路径,再配合tf.image类进行读取预处理。

文本数据加载

使用tf.data.TextLineDataset()对一系列文件路径进行每行文本读取,使用map等函数进行处理。

数据处理

特征列

特征列可以将类别特征转换为one-hot编码特征,将连续特征构建分桶特征,以及对多个特征生成交叉特征。

  • numeric_column
  • bucketized_column
  • categorical_column_with_identity
  • categorical_column_with_vocabulary_list
  • categorical_column_with_vocabulary_file
  • categorical_column_with_hash_bucket
  • indicator_column
  • embedding_column
  • crossed_column

定义完特征列后通过tf.keras.layers.DenseFeatures将数据进行特征处理。

图片数据处理

可以使用tf.data.Dataset.list_files()读取一系列照片路径,然后使用map函数对其进行处理,如tf.io.read_filetf.image.decode_jpeg(img)tf.image.resize.

tf.image支持的操作

  • crop
  • crop_and_resize
  • crop_to_bounding_box
  • resize

也可以使用tf.keras.preprocessing.image中的ImageDataGenerator方法从文件中读取一些列照片。

文本数据处理

Tensorflow中文本的处理需要使用到tf.keras.preprocessing中的Tokenizen词典和tf.keras.utils.Sequence构建文本数据生成管道,并结合tf.keras.layers.experimental.preprocessing.TextVectorization进行处理。

tf.strings中的处理操作

  • lower
  • regex_replace

tf.keras.layers.experimental.preprocess.TextVectorization进行处理,arg

  • max_token
  • standardize
  • split
  • ngrams
  • output_mode
  • pad_to_max_token

使用方法

  • adapt,拟合数据
  • get_vocabulary(),得到词典

张量

张量数据结构

张量可以分为常量和变量两类。常量值不可以改变,变量的值可一改变,可以使用assignassign_addassign_sub方法。

结构操作

  • 创建

    rangelinspacezerosoneszeros_likefilluniformnormaltruncated_normal

  • 切片

    gathergather_ndtf.wherescatter_nd

  • 维度变化

    tf.reshapetf.squeezetf.expand_dimstf.transposetf.reshape

  • 合并和分割

    tf.splittf.stacktf.concat

数学运算

  • 标量运算

    tf.clip_by_valuetf.clip_by_norm

  • 向量运算

    reduce_meanreduce_sumreduce_maxreduce_prodtf.math.cumsumtf.math.cumprod

    tf.argmaxtf.math.top_k

  • 矩阵运算

    tf.matmultf.transposetf.linalg.invtf.linalg.tracetf.linalg.norm

求导

张量的求导需要增加tape.watch()

optimizers.minimize() == loss.gradient, optimizers.apply_gradient

AutoGraph使用规范

AutoGraph是将eager转换为静态图,在函数前加入@t f.function修饰

  • 被@tf.function修饰的函数应尽可能使用TensorFlow中的函数而不是Python中的其他函数
  • 避免在@tf.function修饰的函数内部定义tf.Variable
  • 被@tf.function修饰的函数不可修改该函数外部的Python列表或字典等数据结构变量

AutoGraph的机制原理

执行步骤

  • 创建计算图
  • 执行计算图

当计算图已经创建时,不会在执行非计算图中的部分。如果调用被@tf.function装饰的函数时输入的参数不是Tensor类型,则每次都会重新创建计算图。

tf.Module

因为tf.function修饰的函数中不宜包含新建的变量,但是修改提前定义的变量显得封装不完美,解决方案是利用tf.Module封装。

class DemoModule(tf.Module):
    def __init__(self,init_value = tf.constant(0.0),name=None):
        super(DemoModule, self).__init__(name=name)
        with self.name_scope:  #相当于with tf.name_scope("demo_module")
            self.x = tf.Variable(init_value,dtype = tf.float32,trainable=True)

     
    @tf.function(input_signature=[tf.TensorSpec(shape = [], dtype = tf.float32)])  
    def addprint(self,a):
        with self.name_scope:
            self.x.assign_add(a)
            tf.print(self.x)
            return(self.x)

网络构建

定义模型层

继承tf.keras.layers.Layer类,需要实现初始化,buildcall方法。

build定义Layer需要被训练的参数。

def build(self, input_shape): 
    self.w = self.add_weight("w",shape=(input_shape[-1], self.units), initializer='random_normal',trainable=True) #注意必须要有参数名称"w",否则会报错
    self.b = self.add_weight("b",shape=(self.units,), initializer='random_normal', trainable=True)
    super(Linear,self).build(input_shape) # 相当于设置self.built = True
def get_config(self):  
    config = super(Linear, self).get_config()
    config.update({'units': self.units})
    return config

定义模型

继承tf.keras.models.Model类,实现初始化,buildcall方法,build中设置需要学习的参数(网络层)

class ImdbModel(models.Model):
    def __init__(self):
        super(ImdbModel, self).__init__()
        
    def build(self,input_shape):
        self.embedding = layers.Embedding(MAX_WORDS,7)
        self.block1 = ResBlock(7)
        self.block2 = ResBlock(5)
        self.dense = layers.Dense(1,activation = "sigmoid")
        super(ImdbModel,self).build(input_shape)
    
    def call(self, x):
        x = self.embedding(x)
        x = self.block1(x)
        x = self.block2(x)
        x = layers.Flatten()(x)
        x = self.dense(x)
        return(x)

定义损失函数

损失函数接收两个张量y_turey_pred并输出一个标量作为损失函数值。可以继承与tf.keras.losses.Loss类,要实现初始化和call方法。

# wrap up
def focal_loss(alpha, gamma):
    def focal_loss_fixed(y_true,· y_pred):
        pt_1 = tf.where(tf.euqal(y_true, 1), y_pred, tf.ones_like(y_pred))
        pt_0 = tf.where(tf.euqal(y_true, 0), y_pred, tf.zeros_like(y_pred))
        loss = -tf.reduce_sum(alpha * tf.power(1. - pt_1, gamma) * tf.log(1e-07+pt_1)) - tf.reduce_sum((1-alpha) * tf.pow( pt_0, gamma) * tf.log(1. - pt_0 + 1e-07))
       	return loss
    return focal_loss_fixed

# Class
class FocalLoss(losses.Loss):
    
    def __init__(self,gamma=2.0,alpha=0.25):
        self.gamma = gamma
        self.alpha = alpha

    def call(self,y_true,y_pred):
        
        pt_1 = tf.where(tf.equal(y_true, 1), y_pred, tf.ones_like(y_pred))
        pt_0 = tf.where(tf.equal(y_true, 0), y_pred, tf.zeros_like(y_pred))
        loss = -tf.reduce_sum(self.alpha * tf.pow(1. - pt_1, self.gamma) * tf.log(1e-07+pt_1)) \
           -tf.reduce_sum((1-self.alpha) * tf.pow( pt_0, self.gamma) * tf.log(1. - pt_0 + 1e-07))
        return loss

评估指标

与损失函数相同,评估指标需要接收两个张量y_true,y_pred作为输入参数,并输出一个标量作为评估值。用自定义类的方式实现需要继承tf.keras.metrics.Metric

class KS(metrics.Metric):
    
    def __init__(self, name = "ks", **kwargs):
        super(KS,self).__init__(name=name,**kwargs)
        self.true_positives = self.add_weight(
            name = "tp",shape = (101,), initializer = "zeros")
        self.false_positives = self.add_weight(
            name = "fp",shape = (101,), initializer = "zeros")
   
    @tf.function
    def update_state(self,y_true,y_pred):
        y_true = tf.cast(tf.reshape(y_true,(-1,)),tf.bool)
        y_pred = tf.cast(100*tf.reshape(y_pred,(-1,)),tf.int32)
        
        for i in tf.range(0,tf.shape(y_true)[0]):
            if y_true[i]:
                self.true_positives[y_pred[i]].assign(
                    self.true_positives[y_pred[i]]+1.0)
            else:
                self.false_positives[y_pred[i]].assign(
                    self.false_positives[y_pred[i]]+1.0)
        return (self.true_positives,self.false_positives)
    
    @tf.function
    def result(self):
        cum_positive_ratio = tf.truediv(
            tf.cumsum(self.true_positives),tf.reduce_sum(self.true_positives))
        cum_negative_ratio = tf.truediv(
            tf.cumsum(self.false_positives),tf.reduce_sum(self.false_positives))
        ks_value = tf.reduce_max(tf.abs(cum_positive_ratio - cum_negative_ratio)) 
        return ks_value

回调函数

tf.keras的回调函数实际上是一个类,一般是在model.fit时作为参数指定,用于控制在训练过程开始或者在训练过程结束,在每个epoch训练开始或者训练结束,在每个batch训练开始或者训练结束时执行一些操作,例如收集一些日志信息,改变学习率等超参数,提前终止训练过程等等。

所有回调函数都继承至keras.callbacks.Callbacks基类,拥有paramsmodel这两个属性。其中params 是一个dict,记录了训练相关参数 (例如 verbosity, batch size, number of epochs 等等)。model即当前关联的模型的引用。

  • BaseLogger。 收集每个epoch上metrics在各个batch上的平均值
  • History。将BaseLogger计算的各个epoch的metrics结果记录到history这个dict变量中,并作为model.fit的返回值。该回调函数被所有模型默认添加,在BaseLogger之后被添加。
  • EarlyStopping。 当被监控指标在设定的若干个epoch后没有提升,则提前终止训练。
  • ModelCheckpoint。在每个epoch后保存模型。
  • ReduceLROnPlateau。如果监控指标在设定的若干个epoch后没有提升,则以一定的因子减少学习率。
  • TerminateOnNaN。如果遇到loss为NaN,提前终止训练。
  • LearningRateScheduler。学习率控制器。给定学习率lr和epoch的函数关系,根据该函数关系在每个epoch前调整学习率。

GPU设置

gpus = tf.config.experimental.list_physical_devices('GPU') 

if gpus:
    gpu0 = gpus[0] #如果有多个GPU,仅使用第0个GPU
    tf.config.experimental.set_memory_growth(gpu0, True) 	#设置GPU显存用量按需使用
    # 或者也可以设置GPU显存为固定使用量(例如:4G)
   #tf.config.experimental.set_virtual_device_configuration(gpu0,
    #    [tf.config.experimental.VirtualDeviceConfiguration(memory_limit=4096)]) 
    tf.config.set_visible_devices([gpu0],"GPU")

参考资料

  1. lyhue1991, eat_tensorflow2_in_30_days
  2. TF API查询
posted @ 2020-05-27 10:53  Neo_DH  阅读(277)  评论(0编辑  收藏  举报