Fork me on GitHub

TensorFlow Estimator实战

TensorFlow Estimator

1.泰坦尼克号示例:

  • 导包

    import matplotlib as mpl
    import matplotlib.pyplot as plt
    %matplotlib inline
    import numpy as np
    import sklearn
    import pandas as pd
    import os
    import sys
    import time
    import tensorflow as tf
    from tensorflow import keras
    # 打印版本
    print(tf.__version__)
    print(sys.version_info)
    for module in mpl,np,pd,sklearn,tf,keras:
        print(module.__name__, module.__version__)
    
  • 准备训练集和验证集数据

    train_file = "./data/train.csv"
    eval_file = "./data/eval.csv"
    # pandas读取csv数据
    train_df = pd.read_csv(train_file)
    eval_df = pd.read_csv(eval_file)
    print(train_df.head())
    print(eval_df.head())
    
  • 取出训练集,验证集特征值,survived为获救数

    # 取出训练集特征值:
    y_train = train_df.pop("survived")
    # 取出验证集特征值
    y_eval = eval_df.pop("survived")
    # 取出前5条数据看看
    print(train_df.head())
    print(eval_df.head())
    
  • 训练集统计

    # 训练结果统计量:数据量,均值 方差,最小值,最大值,25%,50%,75%,100%中位数
    train_df.describe()
    
  • 行数,列数打印

    # 行数,列数
    print(train_df.shape, eval_df.shape)
    # (627, 9) (264, 9)
    
  • 取出年龄,查看年龄分布 bins直方图分布份数

    # 取出年龄,查看年龄分布  bins直方图分布份数
    train_df.age.hist(bins=30)
    

  • 查看男性女性人数

    # 查看男性女性人数
    train_df.sex.value_counts().plot(kind="barh")
    

  • 查看仓位等级

    # 查看class等级
    train_df["class"].value_counts().plot(kind="barh")
    

  • 查看男,女有多少获救了

    # 查看男,女有多少获救了
    pd.concat([train_df, y_train],axis=1).groupby("sex").survived.mean().plot(kind="barh")
    

  • 离散型特征

    # 1.离散型特征: 特点有固定值
    # sex   性别
    # n_siblings_spouses  亲戚个数
    # parch  父母孩子是否在船上
    # class 仓位
    # embark_town 出发港口
    # deck  卧仓
    # alone 是否独自一人
    cate_gorical_columns = ["sex", "n_siblings_spouses","parch","class","deck", "embark_town", "alone"]
    
  • 连续特征

    # 2.连续特征
    # age 年龄
    # fare 票价
    numeric_columns = ["age", "fare"]
    
  • 离散特征处理

    # 离散特征处理
    feature_columns = []
    for categorical_column in cate_gorical_columns:
        # 获取所有离散特征值数据
        vocab = train_df[categorical_column].unique()
        print(categorical_column,vocab)
        # tf.feature_column.actegorical_column_with_vocabulary_list 将其定义成为feature_column
        # tf.feature_column.indicator_column 进行one-hot编码
        item = tf.feature_column.indicator_column(
            tf.feature_column.categorical_column_with_vocabulary_list(
        categorical_column, vocab))
        # 加入列表
        feature_columns.append(item)
        
    
  • 连续特征处理

    # 连续特征处理
    for categorical_column in numeric_columns:
        feature_columns.append(
            tf.feature_column.numeric_column(categorical_column, dtype=tf.float32)
        )
    
  • 构建dataset

    # 构建dataset 
    def make_dataset(data_df, label_df, epochs=10,shuffle=True,batch_size=32):
        """
        data_df  x
        label_df   y
        epochs  数据集遍历次数
        shuffle 是否需要混排
        batch_size
        """
        # Dataset 可以接收字典类型数据
        dataset = tf.data.Dataset.from_tensor_slices(
        (dict(data_df), label_df))
        # 打乱顺讯
        if shuffle:
            dataset = dataset.shuffle(10000)
        # repeat + batch
        dataset = dataset.repeat(epochs).batch(batch_size)
        return dataset
    train_dataset = make_dataset(train_df, y_train, batch_size=5)
    
  • 演示:使用keras.layers.DenseFeature 将 feature_columns应用在dadaset上

    # 演示:使用keras.layers.DenseFeature 将 feature_columns应用在dadaset上
    for x,y in train_dataset.take(1):
        # 
        age_column = feature_columns[7]
        gender_column = feature_columns[0]
        # age没有发生变化 因为是数值,保留原有密集特征
        print(keras.layers.DenseFeatures(age_column)(x).numpy())
        #  因性别是分为['male' 'female'], 不是数值, 它会进行one-hot编码变换
        print(keras.layers.DenseFeatures(gender_column)(x).numpy())
    
  • 模型构建

    # keras模型构建
    model = keras.models.Sequential([
        keras.layers.DenseFeatures(feature_columns),# 使用keras.layers.DenseFeature 将 feature_columns应用在dadaset上
        keras.layers.Dense(100, activation="relu"),#全连接层
        keras.layers.Dense(100, activation="relu"),#全连接层
        keras.layers.Dense(2, activation="softmax"),# 输出层
    ])
    
    model.compile(
        loss="sparse_categorical_crossentropy",
        optimizer = keras.optimizers.SGD(lr=0.01),
        metrics=["accuracy"],
    )
    
    
  • 训练模型:

    • 方式1
    # 1.训练模型
    # 方式1:
    train_dataset = make_dataset(train_df, y_train,epochs=100)
    eval_dataset = make_dataset(eval_df, y_eval, epochs=1, shuffle=False)
    # steps_per_epoch=627//32 627为训练集样本数, 32为batch_size 设置偏大会导致训练到后面数据不充足,训练失败
    # validation_steps=264//32 264为验证集样本数, 32为batch_size
    history = model.fit(
        train_dataset, 
        validation_data = eval_dataset, 
        steps_per_epoch=627//32, 
        validation_steps=264//32,
        epochs = 100
    )
    
    
    • 方式2:estimator
    # estimator 方式进行训练
    estimator = keras.estimator.model_to_estimator(model)
    # input_fn是一个函数或lambda匿名函数,返回值必须是:(features, labels)的元组 或 dataset->(feature,label)
    estimator.train(input_fn= lambda : make_dataset(train_df, y_train, epochs=100))
    
    
  • tf.estimator.BaselineClassifier

    # estimator进行训练
    output_dir = "baseline_model"
    if not os.path.exists(output_dir):
        os.mkdir(output_dir)
    #  tf.estimator.BaselineClassifier 2.0之后报错
    baseline_estimator = tf.compat.v1.estimator.BaselineClassifier(
        model_dir = output_dir,n_classes = 2)
    baseline_estimator.train(input_fn = lambda: make_dataset(
        train_df, y_train,epochs=100))
    # 验证
    baseline_estimator.evaluate(input_fn=lambda: make_dataset(
        eval_df,y_eval, epochs=1, shuffle=False, batch_size=20))
    """
    {'accuracy': 0.625,
     'accuracy_baseline': 0.625,
     'auc': 0.5,
     'auc_precision_recall': 0.6875,
     'average_loss': 0.66191846,
     'label/mean': 0.375,
     'loss': 12.481891,
     'precision': 0.0,
     'prediction/mean': 0.38796115,
     'recall': 0.0,
     'global_step': 3920}
    """
    
  • tf.LinearClassifier

    linear_output_dir = "linear_model"
    if not os.path.exists(linear_output_dir):
        os.mkdir(linear_output_dir)
    linear_estimator = tf.compat.v1.estimator.LinearClassifier(
        model_dir=linear_output_dir, n_classes=2, feature_columns=feature_columns)
    linear_estimator.train(input_fn = lambda:make_dataset(
        train_df, y_train, epochs=100))
    # 它不会像tf.keras打印输出训练情况,而是生成tensorborad 文件,里面记载训练情况
    
    # 验证
    linear_estimator.evaluate(input_fn=lambda: make_dataset(
        eval_df,y_eval, epochs=1, shuffle=False))
    """
    {'accuracy': 0.780303,
     'accuracy_baseline': 0.625,
     'auc': 0.83673096,
     'auc_precision_recall': 0.7801561,
     'average_loss': 0.4695529,
     'label/mean': 0.375,
     'loss': 13.773552,
     'precision': 0.69902915,
     'prediction/mean': 0.40130255,
     'recall': 0.72727275,
     'global_step': 3920}
    """
    
  • tf.DNNClassifier

    dnn_output_dir = "./dnn_model"
    if not os.path.exists(dnn_output_dir):
        os.mkdir(dnn_output_dir)
    # hidden_units需要定义每一层和每一层单元数  这里定义2层
    # activation_fn 激活函数
    # optimizer 优化器
    dnn_estimator = tf.compat.v1.estimator.DNNClassifier(
        model_dir=dnn_output_dir, 
        n_classes=2, 
        feature_columns=feature_columns,
        hidden_units=[128,128],
        activation_fn=tf.nn.relu,
        optimizer = "Adam"
    )
    # 训练
    dnn_estimator.train(input_fn = lambda:make_dataset(
        train_df, y_train, epochs=100))
    # 验证
    dnn_estimator.evaluate(input_fn=lambda: make_dataset(
        eval_df,y_eval, epochs=1, shuffle=False))
    """
    {'accuracy': 0.79545456,
     'accuracy_baseline': 0.625,
     'auc': 0.8303337,
     'auc_precision_recall': 0.81163746,
     'average_loss': 0.47359046,
     'label/mean': 0.375,
     'loss': 13.891987,
     'precision': 0.8,
     'prediction/mean': 0.33048365,
     'recall': 0.6060606,
     'global_step': 3920}
    """
    
  • 可以看到DNNClassifier比LinearClassifier 后期loss值要小,训练效果要好

2.交叉特征(cross feature)使用

  • 对两个离散特征做笛卡尔积,比如上述age 有5个值, gender有2个值,进行笛卡尔积后会生成10个特征。

    # hash_bucket_size 当数据量特别大比如有10万个数据,全都加载模型数据量特别大,而 hash_bucket_size=100
    # 我们把 10万个值与100 进行hash,会分配到100个桶里,这样把10万个值分到100个桶中
    # 减少模型的size,因为这10万个值是稀疏的矩阵,一些位置值可以进行重用。
    
    # 转换 indicator_column 才能在 DNNClassifier比LinearClassifier 中使用
    
    feature_columns.append(
        tf.feature_column.indicator_column(
        tf.feature_column.crossed_column(["age","sex"], hash_bucket_size=100)
        )
    )
    
  • 再进行BaselineClassifier,DNNClassifier,LinearClassifier进行训练查看...

posted @   是阿凯啊  阅读(383)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
点击右上角即可分享
微信分享提示