zoukankan      html  css  js  c++  java
  • Tensorflow2.0语法

    转自 https://segmentfault.com/a/1190000020447666

    训练集-测试集-验证集切割

    方法1:(借用三方sklearn库)

    因为sklearn的train_test_split只能切2份,所以我们需要切2次:

    from sklearn.model_selection import train_test_split
    
    x_train, x_test, y_train, y_test = train_test_split(
        x, y,                # x,y是原始数据
        test_size=0.2        # test_size默认是0.25
    )  # 返回的是 剩余训练集+测试集
    
    x_train, x_valid, y_train, y_valid = train_test_split(
        x_train, y_train,    # 把上面剩余的 x_train, y_train继续拿来切
        test_size=0.2        # test_size默认是0.25
    )  # 返回的是 二次剩余训练集+验证集

    切分好的数据,一般需要做 batch_size, shuffle等, 可以使用 tf.keras模型的 fit() 一步传递!
    eg:

    model.compile(
        loss=keras.losses.mean_squared_error, 
        optimizer=keras.optimizers.SGD(),
        metrics=['acc']    # 注意这个metrics参数,下面一会就提到
    )
    
    history = model.fit(
        x_train, 
        y_train, 
        validation_data=(x_valid, y_valid),     # 验证集在这里用了!!!
        epochs=100, 
        batch_size = 32      #  batch_size 不传也行,因为默认就是32
        shuffle=True,        #  shuffle    不传也行,因为默认就是True
        # callbacks=callbacks, #
    )
    度量指标 = model.evaluate(x_test, y_test)    # 返回的是指标(可能包括loss,acc)
    # 这里说一下,为什么我说可能包括。
    # 因为这个返回结果取决于 你的  model.compile() 传递的参数
        # 如果你传了  metrics=['acc'], 那么这个度量指标的返回结果就是 (loss, acc)
        # 如果你没传 metrics ,         那么这个度量指标的返回结果就是一个 loss
    
    y_predict = model.predict(x_test)            # 返回的是预测结果
    
    

    方法2:(tf.split)

    自己封装的代码:功能包括: 3切分,乱序数据集,分批操作 一体化!!! (可能有瑕疵)
    已上传至Github : https://github.com/hacker-lin...
    定义部分:

    class HandlerData:
        def __init__(self, x, y):
            """我封装的类,数据通过实例化传进来保存"""
            self.x = x
            self.y = y
    
        def shuffle_and_batch(self, x, y, batch_size=None):
            """默认定死乱序操作,batch_size可选参数, 其实乱序参数也应该设置可选的。懒了"""
            data = tf.data.Dataset.from_tensor_slices((x, y))    # 封装 dataset数据集格式
    
            data_ = data.shuffle(        # 乱序
                buffer_size=x.shape[0],  # 官方文档说明 shuffle的buffer_size 必须大于或等于样本数量
            )
            if batch_size:
                data_ = data_.batch(batch_size)
            return data_
    
        def train_test_valid_split(self, 
            test_size=0.2,                 # 测试集的切割比例
            valid_size=0.2,                # 验证集的切割比例
            batch_size=32,                 # batch_size 默认我设为了32
            is_batch_and_shuffle=True      # 这个是需不需要乱序和分批,默认设为使用乱序和分批
        ):
        
            sample_num = self.x.shape[0]    # 获取样本总个数
            train_sample = int(sample_num * (1 - test_size - valid_size))  # 训练集的份数
            test_sample = int(sample_num * test_size)                      # 测试集测份数
            valid_train = int(sample_num * valid_size)                     # 验证集的份数
            # 这三个为什么我用int包裹起来了,因为我调试过程中发现,有浮点数计算精度缺失现象。
            # 所以必须转整形
            
            # tf.split()  此语法上一篇我讲过,分n份,每份可不同数量
            x_train, x_test, x_valid = tf.split(  
                self.x,
                num_or_size_splits=[train_sample, test_sample, valid_train],
                axis=0
            )
            y_train, y_test, y_valid = tf.split(
                self.y,
                [train_sample, test_sample, valid_train],
                axis=0
            )
            # 因为份数是我切割x,y之前计算出来的公共变量。所以不用担心 x,y不匹配的问题。
                
            if is_batch_and_shuffle:   # 是否使用乱序和分批,默认是使用的,所以走这条
                return (
                    self.shuffle_and_batch(x_train, y_train, batch_size=batch_size),
                    self.shuffle_and_batch(x_test, y_test, batch_size=batch_size),
                    self.shuffle_and_batch(x_valid, y_valid, batch_size=batch_size),
                )
            else:    # 如果你只想要切割后的原生数据,那么你把is_batch_and_shuffle传False就走这条路了
                return (
                    (x_train, y_train),
                    (x_test, y_test),
                    (x_valid, y_valid)
                )

    调用案例:

    x = tf.ones([1000, 5000])
    y = tf.ones([1000, 1])
    
    data_obj = HandlerData(x,y)   # x是原生的样本数据,x是原生的label数据
    
    # 方式1:使用乱序,使用分批,就是一个参数都不用传,全是默认值
    train, test, valid = data_obj.train_test_valid_split(
        # test_size=0.2, 
        # valid_size=0.2, 
        # batch_size=32, 
        # is_batch_and_shuffle=True
    ) # 这些参数你都可以不传,这都是设置的默认值。
    
    print(train)
    print(test)
    print(valid)
    
    # 结果
    >>> <BatchDataset shapes: ((None, 5000), (None, 1)), types: (tf.float32, tf.float32)>
    >>> <BatchDataset shapes: ((None, 5000), (None, 1)), types: (tf.float32, tf.float32)>
    >>> <BatchDataset shapes: ((None, 5000), (None, 1)), types: (tf.float32, tf.float32)>
    
    # 虽然你看见了样本数为None,但是没关系,因为你还没使用,遍历一下就明白了    
    for x_train,y_train in train:
        print(x_train.shape,y_train.shape)
    
    # 结果  600 // 32 == 18 (你可以查一下正好18个)
    # 结果  600 % 32 == 24 (你可以看一下最后一个就是24)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (32, 5000) (32, 1)
    (24, 5000) (24, 1)   # 32个一批,最后一个就是余数 24个了。
    
    
    # 方式2:不使用乱序,使用分批,只要原生数据,
    (x_train, y_train), (x_test, y_test), (x_valid, y_valid) = data_obj.train_test_valid_split(
        # test_size=0.2,
        # valid_size=0.2,
        # batch_size=32,
        is_batch_and_shuffle=False    # 这个改为False即可,其他参数可选
    )
    
    print(x_train.shape, y_train.shape)
    print(x_test.shape, y_test.shape)
    print(x_valid.shape, y_valid.shape)
    
    # 结果
    >>> (600, 5000) (600, 1)
    >>> (200, 5000) (200, 1)
    >>> (200, 5000) (200, 1)

    方式3(训验分割)

    history = model.fit(
        .....
        validation_split=0.2      # 训练集分出0.2给验证集
    )
    

    数据处理 (dataset)

    这个模块的作用就是,将我们的数据,或者 TF张量,封装成数据集。
    这个数据集具有成品API,比如:可以帮助我们,分批,乱序,制作迭代,等一些列操作。

    基本理解

    dataset = tf.data.Dataset.from_tensor_slices(np.arange(16).reshape(4,4))
    按理来说(先不取),数据形状应该是这样的。  (一个大列表里面,有4个小列表)
    [
        [0, 1, 2 ,3 ],
        [4, 5, 6 ,7 ],
        [8, 9, 10,11],
        [12,13,14,15],
    ]
    
    for data in dataset:   # 封装的数据集需要遍历(或者 iter() 改变为迭代器类型),才能返回值
        print(data)        # 每遍历一条就是里面的小列表。 eg:第一条形状: [0, 1, 2 ,3 ]
                           # 但是别忘了。我们这是Tensorflow,因此每层数据集都被封装为Tensor。
                           # 因此,我们每遍历出一条数据,都是一条Tensor
    输出:
    >>    tf.Tensor([0 1 2 3], shape=(4,), dtype=int32)
          tf.Tensor([4 5 6 7], shape=(4,), dtype=int32)
          tf.Tensor([ 8  9 10 11], shape=(4,), dtype=int32)
          tf.Tensor([12 13 14 15], shape=(4,), dtype=int32)
    
    前面说了,这个数据的格式就是(一个大列表里面,有4个小列表)
    对应来看, (一个大Tensor里面, 有4个小Tensor)。 记住这个理念

    数据来源参数类型

    参数传元组:

    question = [[1, 0], [1, 1]]
    answer = ['encode', 'decoder']
    dataset = tf.data.Dataset.from_tensor_slices( (question, answer) ) # 用元组包起来了
    for data in dataset:
        print(data[0],'=>' ,data[1])
    输出:
    >> tf.Tensor([1 0], shape=(2,), dtype=int32) => tf.Tensor(b'encode', shape=(), dtype=string)
       tf.Tensor([1 1], shape=(2,), dtype=int32) => tf.Tensor(b'decoder', shape=(), dtype=string)
       
    你可以看出它自动把我们传递的 question 和 answer 两个大列表。  "相当于做了zip()操作"。
    
    # 我的实验经历:训练 Encoder-Decoder模型的,"问答对数据",做编码后,就可以这样用元组传。

    参数传字典:

    data_dict = {
        'encoder': [1, 0],
        'decoder': [1, 1]
    }
    
    dataset = tf.data.Dataset.from_tensor_slices(data_dict)
    for data in dataset:    # 其实每一个元素就是一个字典
        print(data)
    
    # 其实就是把你的 value部分,转成了Tensor类型。 总体结构没变

    链式调用

    Dataset API 大多数操作几乎都是链式调用(就像python字符串的 replace方法)
    用上面的数据作为案例数据, 介绍几种API:

    batch (分批)

    for data in dataset.batch(2):    # 若设置 drop_remainder=True,则最后余下一批会被丢弃
        print(data) 
    输出: 
    >>    tf.Tensor([[0 1 2 3] [4 5 6 7]], shape=(2, 4), dtype=int32)
          tf.Tensor([[ 8  9 10 11] [12 13 14 15]], shape=(2, 4), dtype=int32)
                         
    上面说过,默认就是 遍历出的每个子项,就是一个Tensor,  如上数据,遍历出 4个Tensor
    而调用 batch(2) 后, 把2个子项分成一批, 然后再包装成为Tensor。
    so, 4/2 = 2批 , 包装成2个Tensor

    repeat(重复使用数据:epoch理念, 重复训练n轮次)

    注意(传的就是总重复数,算自身): 
        1. 如果repeat() 不传参数,那就是无限重复。。。
        2. 如果传参数 = 0,  那么代表不取数据
        3. 如果传参数 = 1,  那么代表一共就一份数据
        4. 如果传参数 = 2,  那么代表一共就2份数据(把自己算上,一共2份,就这么个重复的意思)
        
    for data in dataset.repeat(2).batch(3):   # 重复2次。 3个一组  (这就是链式调用)
        print(data)
    
    结果
    >>  tf.Tensor([[ 0  1  2  3] [ 4  5  6  7] [ 8  9 10 11]], shape=(3, 4), dtype=int32)  
        tf.Tensor([[12 13 14 15] [ 0  1  2  3] [ 4  5  6  7]], shape=(3, 4), dtype=int32)
        tf.Tensor([[ 8  9 10 11] [12 13 14 15]], shape=(2, 4), dtype=int32)  
        
        原数据是4个子项,  重复2次 :  4*2=8 
        然后链式调用分3批: 8/3=2 ..... 2    (整批3个一组, 最后一批余数一组)
        # 还要注意一下, 它们重复是顺序重复拼接。 分批时,可以首尾相连的 
        (eg:就像小时候吃的一连串棒棒糖, 拽不好,会把上一个的糖皮连着拽下来)
  • 相关阅读:
    fedora上部署ASP.NET——(卡带式电脑跑.NET WEB服务器)
    SQL Server 请求失败或服务未及时响应。有关详细信息,请参见事件日志或其它适合的错误日志
    8086CPU的出栈(pop)和入栈(push) 都是以字为单位进行的
    FTP 服务搭建后不能访问问题解决
    指定的 DSN 中,驱动程序和应用程序之间的体系结构不匹配
    Linux 安装MongoDB 并设置防火墙,使用远程客户端访问
    svn Please execute the 'Cleanup' command. 问题解决
    .net 操作MongoDB 基础
    oracle 使用绑定变量极大的提升性能
    尝试加载 Oracle 客户端库时引发 BadImageFormatException。如果在安装 32 位 Oracle 客户端组件的情况下以 64 位模式运行,将出现此问题。
  • 原文地址:https://www.cnblogs.com/whw1314/p/12121900.html
Copyright © 2011-2022 走看看