草庐IT

Python TensorFlow深度学习回归代码:DNNRegressor

fkxxgis 2023-03-28 原文

  本文介绍基于Python语言中TensorFlowtf.estimator接口,实现深度学习神经网络回归的具体方法。

1 写在前面

  1. 本文介绍的是基于TensorFlow tf.estimator接口的深度学习网络,而非TensorFlow 2.0中常用的Keras接口;关于Keras接口实现深度学习回归,我们将在下一篇博客中介绍。

  2. 本文代码以DNNRegressor回归为例;而由于基于 tf.estimator接口的深度学习回归分类整体较为类似,因此二者具有触类旁通的效果。

  3. 本文第二部分为代码的分解介绍,第三部分为完整代码。

  4. 相关版本信息:Python版本:3.8.5TensorFlow版本:2.4.1;编译器版本:Spyder 4.1.5

2 代码分解介绍

2.1 准备工作

  首先需要引入相关的库与包。

import os
import openpyxl
import numpy as np
import pandas as pd
import tensorflow as tf
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import train_test_split

  其次,基于TensorFlow的代码往往会输出较多的日志信息,从而使得我们对代码执行情况的了解受到一定影响。代码输出的日志信息有四种,依据严重程度由低到高排序:INFO(通知)<WARNING(警告)<ERROR(错误)<FATAL(致命的);我们可以通过如下代码来对TensorFlow的输出日志信息加以约束。

os.environ['TF_CPP_MIN_LOG_LEVEL']='3'

  其中,3代表只输出FATAL信息。但要注意,这句代码需要放在import tensorflow的前面:

import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
import openpyxl
import numpy as np
import pandas as pd
import tensorflow as tf
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import train_test_split

2.2 参数配置

  深度学习代码一大特点即为具有较多的参数需要我们手动定义。为避免调参时上下翻找,我们可以将主要的参数集中在一起,方便我们后期调整。

  其中,具体参数的含义在本文后续部分详细介绍。

# 将各类变量放在一个位置集中定义,十分有利于机器学习等变量较多的代码
MyModelPath="G:/CropYield/03_DL/02_DNNModle" # 确定每一次训练所得模型保存的位置
MyDataPath="G:/CropYield/03_DL/00_Data/AllDataAll.csv" # 确定输入数据的位置
MyResultSavePath="G:/CropYield/03_DL/03_OtherResult/EvalResult54.xlsx" # 确定模型精度结果(RMSE等)与模型参数保存的位置
TestSize=0.2 # 确定数据中测试集所占比例
RandomSeed=np.random.randint(low=24,high=25) # 确定划分训练集与测试集的随机数种子
OptMethod='Adam' # 确定模型所用的优化方法
LearningRate=0.01 # 确定学习率
DecayStep=200 # 确定学习率下降的步数
DecayRate=0.96 # 确定学习率下降比率
HiddenLayer=[64,128] # 确定隐藏层数量与每一层对应的神经元数量
ActFun='tf.nn.relu' # 确定激活函数
Dropout=0.3 # 确定Dropout的值
LossReduction='tf.compat.v1.ReductionV2.SUM_OVER_BATCH_SIZE' # 指定每个批次训练误差的减小方法
BatchNorm='False' # 确定是否使用Batch Normalizing
TrainBatchSize=110 # 确定训练数据一个Batch的大小
TrainStep=3000 # 确定训练数据的Step数量
EvalBatchSize=1 # 确定验证数据一个Batch的大小
PredictBatchSize=1 # 确定预测数据(即测试集)一个Batch的大小

2.3 原有模型删除

  DNNRegressor每执行一次,便会在指定路径中保存当前运行的模型。为保证下一次模型保存时不受上一次模型运行结果干扰,我们可以将模型文件夹内的全部文件删除。

# DeleteOldModel函数,删除上一次运行所保存的模型
def DeleteOldModel(ModelPath):
    AllFileName=os.listdir(ModelPath) # 获取ModelPath路径下全部文件与文件夹
    for i in AllFileName:
        NewPath=os.path.join(ModelPath,i) # 分别将所获取的文件或文件夹名称与ModelPath路径组合
        if os.path.isdir(NewPath): # 若组合后的新路径是一个文件夹
            DeleteOldModel(NewPath) # 递归调用DeleteOldModel函数
        else:
            os.remove(NewPath) # 若不是一个新的文件夹,而是一个文件,那么就删除

# 调用DeleteOldModel函数,删除上一次运行所保存的模型
DeleteOldModel(MyModelPath)

  需要注意,以上代码仅删除指定路径下的文件,文件夹不删除。大家如果需要将文件夹也同时删除,修改以上代码函数中的后面几句即可。

2.4 数据导入与数据划分

  我的数据已经保存在了.csv文件中,因此可以用pd.read_csv直接读取。

  其中,数据的每一列是一个特征,每一行是全部特征与因变量(就是下面的Yield)组合成的样本。

# LoadData函数,加载全部数据
def LoadData(DataPath):
    MyData=pd.read_csv(DataPath,names=['EVI0610','EVI0626','EVI0712','EVI0728','EVI0813','EVI0829',
                                       'EVI0914','EVI0930','EVI1016','Lrad06','Lrad07','Lrad08',
                                       'Lrad09','Lrad10','Prec06','Prec07','Prec08','Prec09',
                                       'Prec10','Pres06','Pres07','Pres08','Pres09','Pres10',
                                       'SIF161','SIF177','SIF193','SIF209','SIF225','SIF241',
                                       'SIF257','SIF273','SIF289','Shum06','Shum07','Shum08',
                                       'Shum09','Shum10','SoilType','Srad06','Srad07','Srad08',
                                       'Srad09','Srad10','Temp06','Temp07','Temp08','Temp09',
                                       'Temp10','Wind06','Wind07','Wind08','Wind09','Wind10',
                                       'Yield'],header=0) # 加载DataPath路径所指定的数据,names中的内容为各列的名称
    return MyData

# 初始数据处理
AllXY=LoadData(MyDataPath) # 调用LoadData函数,获取数据
Label={"Yield":AllXY.pop("Yield")} # 将因变量从全部数据中提取出
AllX,AllY=AllXY,(pd.DataFrame(Label)) # 将自变量与因变量分离

# 划分数据训练集与测试集
TrainX,TestX,TrainY,TestY=train_test_split(AllX,
                                           AllY,
                                           test_size=TestSize, # 指定数据中测试集所占比例
                                           random_state=RandomSeed # 指定划分训练集与测试集的随机数种子
                                           )

2.5 Feature Columns定义

  Feature Columns就是一个桥梁,联系你的初始数据与模型;其好比一个名单,模型拿着这个名单到你的数据(即本文2.4部分你导入的数据)中按列的名称一一搜索,若初始数据中的某列名称在Feature Columns里,那么模型就会把初始数据中这一列的数据全部拿到自己这里,进行训练。

  因为我们是希望导入数据的全部特征,那么可以直接在全部数据的自变量中循环,将全部特征的名称导入Feature Columns

  在这里需要注意的是,只有连续数值变量才可以用tf.feature_column.numeric_column处理;若是类别变量可以对其加以独热编码等操作。

# estimator接口中的模型需要用“Feature columns”对象作为输入数据,只有这样模型才知道读取哪些数据
FeatureColumn=[] # 定义一个新的“Feature columns”对象
for key in AllX.keys():
    FeatureColumn.append(tf.feature_column.numeric_column(key=key)) # 将全部因变量数据(需要均为连续变量)导入

2.6 模型优化方法构建与模型结构构建

  模型优化方法即模型中的optimizer,其可以在模型结构构建时输入;但有时优化方法较为复杂(例如引入了学习率下降),那么在构建模型时配置优化方法的话就会有些不方便。因此我们首先构建模型优化方法。

# 定义模型优化方法
# Optimizer=OptMethod # 优化方法选用OptMethod所指定的方法
Optimizer=lambda:tf.keras.optimizers.Adam(
    learning_rate=tf.compat.v1.train.exponential_decay(learning_rate=LearningRate, # 初始学习率
                                                       global_step=tf.compat.v1.train.get_global_step(),
                                                       # 全局步数,用以计算已经衰减后的学习率
                                                       # get_global_step()函数自动获取当前的已经执行的步数
                                                       decay_steps=DecayStep, # 学习率下降完成的指定步数
                                                       decay_rate=DecayRate # 衰减率
                                                       ) # 选用基于学习率指数下降的Adam方法,此举有助于降低过拟合风险
                                                         # 这一函数返回每次对应的学习率
    )

  以上代码中有两个Optimizer=,第一个是直接输入优化方法的名称即可,名称包括:'Adagrad', 'Adam', 'Ftrl', 'RMSProp', SGD';默认为Adagrad

  第二个是在选择了优化方法的基础上,配置其他信息。例如第二个,其代表着学习率指数下降的Adam优化方法。其中,tf.compat.v1.train.exponential_decay可视作一个计算每次训练学习率的函数,他返回的是每一次对应的学习率。可能这么说不太好理解,看这个公式:其返回值为learning_rate *decay_rate ^ (global_step / decay_steps),是不是就明白啦。

  我们选择第二个优化方法,因此把第一个注释掉。

  随后,我们定义模型的结构。

# 基于DNNRegressor构建深度学习模型
DNNModel=tf.estimator.DNNRegressor(feature_columns=FeatureColumn, # 指定模型所用的“Feature columns”对象
                                   hidden_units=HiddenLayer, # 指定隐藏层数量与每一层对应的神经元数量
                                   optimizer=Optimizer, # 指定模型所用的优化方法                                  
                                   activation_fn=eval(ActFun), # 指定激活函数
                                   dropout=Dropout, # 指定Dropout的值
                                   label_dimension=1, # 输出数据的维度,即因变量的个数
                                   model_dir=MyModelPath, # 指定每一次训练所得模型保存的位置
                                   # loss_reduction=eval(LossReduction), # 指定每个批次训练误差的减小方法
                                   batch_norm=eval(BatchNorm) # 指定是否使用Batch Normalizing
                                   )

  模型的构建,对照着代码上的注释,就比较好理解了;其中,我把loss_reduction注释掉,是因为可能由于TensorFlow版本的问题,其总是报错,所以就用默认的值就好;而最后一个batch_norm,决定了是否进行Batch NormalizingBatch Normalizing可以保持深度神经网络在每一层保持相同分布,从而加快网络收敛与增强网络稳固性。

  其它参数可以参考官方网站,这里暂时不再赘述。

2.7 模型训练

  训练模型这一部分,我认为反而比模型的构建可能还难理解一些。我们先看代码:

# 基于训练数据训练模型
DNNModel.train(input_fn=lambda:InputFun(TrainX,
                                        TrainY,
                                        True,
                                        TrainBatchSize
                                        ), # 调用InputFun函数;InputFun函数返回“tf.data.Dataset”对象,这个对象才可以被
                                           # train函数识别并带入模型;由于InputFun函数每次返回BatchSize大小的数据个数,
                                           # 因此需要多次执行,前面需要加lambda
               steps=TrainStep # 指定模型训练的步数
               )

  我们可以这么理解:在train函数中,只有一个参数input_fn;而这个参数的输入,又是一个新的函数——这个新的函数就是大名鼎鼎的input function了。

  他长这个样子:

# InputFun函数,训练数据与验证数据所用的Input函数
def InputFun(Features,Labels,Training,BatchSize):
    Datasets=tf.data.Dataset.from_tensor_slices((dict(Features),Labels)) # 对数据加以加载
    if Training:
        Datasets=Datasets.shuffle(1000).repeat() # 对于训练数据,需要打乱(shuffle)、重复(repeat)
    return Datasets.batch(BatchSize) # 将经过上述处理后的数据以每次BatchSize个输出

  那我们首先就看input function——也就是代码中的InputFun函数。其实这个函数的用处很简单,用官网的话说,其就是用来输入模型支持的数据类型的——只有经过input function处理后,数据才可以被DNNRegressor识别。听上去这么厉害,它到底是如何操作的呢?

  很简单,它只需要将初始的数据转换为特定的格式即可,这个格式是一个元组(tuple),这个元组有两个元素:

  一就是features,是一个字典。这个字典的每一个键是每一个特征的名称,就比如用植物特性对花的种类加以区分,那么花的“叶长”“叶片厚度”等等就是一个个特征的名称,也就是这里的一个个“键”;而这个字典的值,就是这个特征对应的全部样本的数值组成的数组。

  二就是label,是全部样本对应的label,也就是因变量。

  不知道大家有没有理解,我们就举一个简单的例子。假如我们用两个地方的温度与降水预测这两个地方的作物产量:其温度分别为10 ℃、20 ℃,降水分别为15 mm,25 mm,作物产量分别为100千克每公顷,150千克每公顷——那么tuple由两个部分组成:

tuple=(features,label)
features={'温度':np.array([10,20]),'降水':np.array([15,25])}
label=np.array([100,150])

  怎么样,是不是明白啦。

  理解了之后,我们继续看InputFun函数。首先,tf.data.Dataset.from_tensor_slices用来将输入的数据加载并转换为Datase的形式;随后,如果是训练状态下,那么数据会进行打乱.shuffle(1000)——相当于对数据加以洗牌,防止初始数据具有一定的趋势。例如如果我们做分类,其中初始数据的前80%都是第一类,后20%都是第二类,那么如果我们不打乱数据,会使得用前80%数据训练出来的结果都是第一类(即模型只认识第一类),在后20%进行测试时,所得结果也全都为第一类;所以要打乱。其中的1000buffer_size参数,这个数据必须要比你的数据样本个数大。至于.shuffle(1000)这个函数的原理我一直没有搞明白,大家感兴趣的话可以加以进一步了解。

  .repeat()则是对数据集加以重复,之所以要重复,是因为我们需要对全部数据训练好几轮(即好几个Epoch),因此要对初始数据加以重复。

  随后,用.batch()函数输出BatchSize个数据,也就是一批数据;其中BatchSize就是每一批数据的个数。

  这个就是InputFun函数。再看train函数函数:大家也看出来了,这个InputFun函数是每次输出一批(BatchSize个)数据;而我们训练的时候,肯定是要一批一批不停输入数据的,因此这就解释了为什么InputFun函数前有一个lambda——因为InputFun函数要把处理后的数据分多次传给train

2.8 模型验证与测试

  理解了以上内容,接下来就好理解多了。我们需要进行验证与测试的操作——其实验证也就是利用了测试集数据,之所以我还进行了测试,是因为希望可以获取测试集预测结果,从而更直观地了解模型精度水平。

# InputFunPredict函数,测试数据所用的Input函数
def InputFunPredict(Features,BatchSize):
    return tf.data.Dataset.from_tensor_slices(dict(Features)).batch(BatchSize) # 对数据加以加载,以每次BatchSize个输出    

# 验证模型并保存验证结果
EvalResult=DNNModel.evaluate(input_fn=lambda:InputFun(TestX,
                                                      TestY,
                                                      False,
                                                      EvalBatchSize
                                                      )
                             )
# 打印验证结果
print('ev:{}'.format(EvalResult))

# 基于测试数据测试模型精度结果
PredictValues=DNNModel.predict(input_fn=lambda:InputFunPredict(TestX,
                                                               PredictBatchSize
                                                               )
                               )

  其中,验证时.evaluate所用的InputFun函数其实和训练集所用的是一样的函数,只不过验证时不需要进行打乱.shuffle(1000)和重复.repeat()操作;而测试时.predictInputFun函数则是新的,其只需要输入自变量、无需输入因变量。

2.9 精度评定、拟合图像绘制与模型参数与精度结果保存

  精度评定与拟合图像就不用过多说啦~最终,我们最好将模型参数与精度衡量指标结果保存在Excel表格中,这样子方便之后的调参过程。这里就不再一一介绍啦,大家对照代码中的注释即可。

# AccuracyVerification函数,进行精度验证指标的计算与绘图
def AccuracyVerification(PredictLabels,TestLabels):
    value=0
    PredictValuesList=[]
    for k in PredictLabels:
        value=k.get('predictions')[0]
        PredictValuesList.append(value)
    TestLabels=TestLabels.values.tolist()
    TestYList=sum(TestLabels,[])
    # 以上为获取测试数据的因变量与模型预测所得的因变量
    Pearsonr=stats.pearsonr(TestYList,PredictValuesList) # 计算皮尔逊相关系数
    R2=metrics.r2_score(TestYList,PredictValuesList) # 计算R方
    RMSE=metrics.mean_squared_error(TestYList,PredictValuesList)**0.5 # 计算RMSE
    plt.cla()
    plt.plot(TestYList,PredictValuesList,'r*')
    plt.xlabel('Actual Values')
    plt.ylabel('Predicted Values')
    # 以上为绘制拟合图像
    print('Pearson correlation coefficient is {0}, and RMSE is {1}.'.format(Pearsonr[0],RMSE))
    return (Pearsonr[0],R2,RMSE,PredictValuesList)

# WriteAccuracy函数,将模型所涉及的参数与最终精度结果保存
def WriteAccuracy(*WriteVar):
    ExcelData=openpyxl.load_workbook(WriteVar[0])
    SheetName=ExcelData.get_sheet_names() # 获取全部Sheet
    WriteSheet=ExcelData.get_sheet_by_name(SheetName[0]) # 获取指定Sheet
    WriteSheet=ExcelData.active # 激活指定Sheet
    MaxRowNum=WriteSheet.max_row # 获取指定Sheet对应第一个空行
    for i in range(len(WriteVar)-1):
        exec("WriteSheet.cell(MaxRowNum+1,i+1).value=WriteVar[i+1]") # 用exec执行语句,写入信息
    ExcelData.save(WriteVar[0]) # 保存文件

# 调用AccuracyVerification函数,进行精度验证指标的计算与绘图
AccuracyResult=AccuracyVerification(PredictValues,TestY)
PearsonR,R2,RMSE,PredictY=AccuracyResult[0],AccuracyResult[1],AccuracyResult[2],AccuracyResult[3]

# 调用WriteAccuracy函数,将模型所涉及的参数与最终精度结果保存
WriteAccuracy(MyResultSavePath,PearsonR,R2,RMSE,TestSize,RandomSeed,OptMethod,LearningRate,DecayStep,
              DecayRate,','.join('%s' %i for i in HiddenLayer),ActFun,Dropout,LossReduction,
              BatchNorm,TrainBatchSize,TrainStep,EvalBatchSize,PredictBatchSize)

  至此,全部的代码分解介绍都结束啦~

3 详细代码

# -*- coding: utf-8 -*-
"""
Created on Tue Feb 23 16:13:21 2021

@author: Chutj
"""

# 加载必要的库、包等
import os
os.environ['TF_CPP_MIN_LOG_LEVEL']='3'
import openpyxl
import numpy as np
import pandas as pd
import tensorflow as tf
import scipy.stats as stats
import matplotlib.pyplot as plt
from sklearn import metrics
from sklearn.model_selection import train_test_split

# ===============*** 函数声明区域 ***===============

# DeleteOldModel函数,删除上一次运行所保存的模型
def DeleteOldModel(ModelPath):
    AllFileName=os.listdir(ModelPath) # 获取ModelPath路径下全部文件与文件夹
    for i in AllFileName:
        NewPath=os.path.join(ModelPath,i) # 分别将所获取的文件或文件夹名称与ModelPath路径组合
        if os.path.isdir(NewPath): # 若组合后的新路径是一个文件夹
            DeleteOldModel(NewPath) # 递归调用DeleteOldModel函数
        else:
            os.remove(NewPath) # 若不是一个新的文件夹,而是一个文件,那么就删除

# LoadData函数,加载全部数据
def LoadData(DataPath):
    MyData=pd.read_csv(DataPath,names=['EVI0610','EVI0626','EVI0712','EVI0728','EVI0813','EVI0829',
                                       'EVI0914','EVI0930','EVI1016','Lrad06','Lrad07','Lrad08',
                                       'Lrad09','Lrad10','Prec06','Prec07','Prec08','Prec09',
                                       'Prec10','Pres06','Pres07','Pres08','Pres09','Pres10',
                                       'SIF161','SIF177','SIF193','SIF209','SIF225','SIF241',
                                       'SIF257','SIF273','SIF289','Shum06','Shum07','Shum08',
                                       'Shum09','Shum10','SoilType','Srad06','Srad07','Srad08',
                                       'Srad09','Srad10','Temp06','Temp07','Temp08','Temp09',
                                       'Temp10','Wind06','Wind07','Wind08','Wind09','Wind10',
                                       'Yield'],header=0) # 加载DataPath路径所指定的数据,names中的内容为各列的名称
    return MyData

# InputFun函数,训练数据与验证数据所用的Input函数
def InputFun(Features,Labels,Training,BatchSize):
    Datasets=tf.data.Dataset.from_tensor_slices((dict(Features),Labels)) # 对数据加以加载
    if Training:
        Datasets=Datasets.shuffle(1000).repeat() # 对于训练数据,需要打乱(shuffle)、重复(repeat)
    return Datasets.batch(BatchSize) # 将经过上述处理后的数据以每次BatchSize个输出

# InputFunPredict函数,测试数据所用的Input函数
def InputFunPredict(Features,BatchSize):
    return tf.data.Dataset.from_tensor_slices(dict(Features)).batch(BatchSize) # 对数据加以加载,以每次BatchSize个输出

# AccuracyVerification函数,进行精度验证指标的计算与绘图
def AccuracyVerification(PredictLabels,TestLabels):
    value=0
    PredictValuesList=[]
    for k in PredictLabels:
        value=k.get('predictions')[0]
        PredictValuesList.append(value)
    TestLabels=TestLabels.values.tolist()
    TestYList=sum(TestLabels,[])
    # 以上为获取测试数据的因变量与模型预测所得的因变量
    Pearsonr=stats.pearsonr(TestYList,PredictValuesList) # 计算皮尔逊相关系数
    R2=metrics.r2_score(TestYList,PredictValuesList) # 计算R方
    RMSE=metrics.mean_squared_error(TestYList,PredictValuesList)**0.5 # 计算RMSE
    plt.cla()
    plt.plot(TestYList,PredictValuesList,'r*')
    plt.xlabel('Actual Values')
    plt.ylabel('Predicted Values')
    # 以上为绘制拟合图像
    print('Pearson correlation coefficient is {0}, and RMSE is {1}.'.format(Pearsonr[0],RMSE))
    return (Pearsonr[0],R2,RMSE,PredictValuesList)

# WriteAccuracy函数,将模型所涉及的参数与最终精度结果保存
def WriteAccuracy(*WriteVar):
    ExcelData=openpyxl.load_workbook(WriteVar[0])
    SheetName=ExcelData.get_sheet_names() # 获取全部Sheet
    WriteSheet=ExcelData.get_sheet_by_name(SheetName[0]) # 获取指定Sheet
    WriteSheet=ExcelData.active # 激活指定Sheet
    MaxRowNum=WriteSheet.max_row # 获取指定Sheet对应第一个空行
    for i in range(len(WriteVar)-1):
        exec("WriteSheet.cell(MaxRowNum+1,i+1).value=WriteVar[i+1]") # 用exec执行语句,写入信息
    ExcelData.save(WriteVar[0]) # 保存文件


# ===============*** 代码由此开始执行 ***===============
#      ++++++++++--- 建议由这里开始看 ---++++++++++

# 将各类变量放在一个位置集中定义,十分有利于机器学习等变量较多的代码
MyModelPath="G:/CropYield/03_DL/02_DNNModle" # 确定每一次训练所得模型保存的位置
MyDataPath="G:/CropYield/03_DL/00_Data/AllDataAll.csv" # 确定输入数据的位置
MyResultSavePath="G:/CropYield/03_DL/03_OtherResult/EvalResult54.xlsx" # 确定模型精度结果(RMSE等)与模型参数保存的位置
TestSize=0.2 # 确定数据中测试集所占比例
RandomSeed=np.random.randint(low=24,high=25) # 确定划分训练集与测试集的随机数种子
OptMethod='Adam' # 确定模型所用的优化方法
LearningRate=0.01 # 确定学习率
DecayStep=200 # 确定学习率下降的步数
DecayRate=0.96 # 确定学习率下降比率
HiddenLayer=[64,128] # 确定隐藏层数量与每一层对应的神经元数量
ActFun='tf.nn.relu' # 确定激活函数
Dropout=0.3 # 确定Dropout的值
LossReduction='tf.compat.v1.ReductionV2.SUM_OVER_BATCH_SIZE' # 指定每个批次训练误差的减小方法
BatchNorm='False' # 确定是否使用Batch Normalizing
TrainBatchSize=110 # 确定训练数据一个Batch的大小
TrainStep=3000 # 确定训练数据的Step数量
EvalBatchSize=1 # 确定验证数据一个Batch的大小
PredictBatchSize=1 # 确定预测数据(即测试集)一个Batch的大小

# 调用DeleteOldModel函数,删除上一次运行所保存的模型
DeleteOldModel(MyModelPath)

# 初始数据处理
AllXY=LoadData(MyDataPath) # 调用LoadData函数,获取数据
Label={"Yield":AllXY.pop("Yield")} # 将因变量从全部数据中提取出
AllX,AllY=AllXY,(pd.DataFrame(Label)) # 将自变量与因变量分离

# 划分数据训练集与测试集
TrainX,TestX,TrainY,TestY=train_test_split(AllX,
                                           AllY,
                                           test_size=TestSize, # 指定数据中测试集所占比例
                                           random_state=RandomSeed # 指定划分训练集与测试集的随机数种子
                                           )

# estimator接口中的模型需要用“Feature columns”对象作为输入数据,只有这样模型才知道读取哪些数据
FeatureColumn=[] # 定义一个新的“Feature columns”对象
for key in AllX.keys():
    FeatureColumn.append(tf.feature_column.numeric_column(key=key)) # 将全部因变量数据(需要均为连续变量)导入

# 定义模型优化方法
# Optimizer=OptMethod # 优化方法选用OptMethod所指定的方法
Optimizer=lambda:tf.keras.optimizers.Adam(
    learning_rate=tf.compat.v1.train.exponential_decay(learning_rate=LearningRate, # 初始学习率
                                                       global_step=tf.compat.v1.train.get_global_step(),
                                                       # 全局步数,用以计算已经衰减后的学习率
                                                       # get_global_step()函数自动获取当前的已经执行的步数
                                                       decay_steps=DecayStep, # 学习率下降完成的指定步数
                                                       decay_rate=DecayRate # 衰减率
                                                       ) # 选用基于学习率指数下降的Adam方法,此举有助于降低过拟合风险
                                                         # 这一函数返回每次对应的学习率
    )


# 基于DNNRegressor构建深度学习模型
DNNModel=tf.estimator.DNNRegressor(feature_columns=FeatureColumn, # 指定模型所用的“Feature columns”对象
                                   hidden_units=HiddenLayer, # 指定隐藏层数量与每一层对应的神经元数量
                                   optimizer=Optimizer, # 指定模型所用的优化方法                                  
                                   activation_fn=eval(ActFun), # 指定激活函数
                                   dropout=Dropout, # 指定Dropout的值
                                   label_dimension=1, # 输出数据的维度,即因变量的个数
                                   model_dir=MyModelPath, # 指定每一次训练所得模型保存的位置
                                   # loss_reduction=eval(LossReduction), # 指定每个批次训练误差的减小方法
                                   batch_norm=eval(BatchNorm) # 指定是否使用Batch Normalizing
                                   )

# tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.INFO) # 将INFO级别的日志信息显示到屏幕

# 基于训练数据训练模型
DNNModel.train(input_fn=lambda:InputFun(TrainX,
                                        TrainY,
                                        True,
                                        TrainBatchSize
                                        ), # 调用InputFun函数;InputFun函数返回“tf.data.Dataset”对象,这个对象才可以被
                                           # train函数识别并带入模型;由于InputFun函数每次返回BatchSize大小的数据个数,
                                           # 因此需要多次执行,前面需要加lambda
               steps=TrainStep # 指定模型训练的步数
               ) 

# 验证模型并保存验证结果
EvalResult=DNNModel.evaluate(input_fn=lambda:InputFun(TestX,
                                                      TestY,
                                                      False,
                                                      EvalBatchSize
                                                      )
                             )
# 打印验证结果
print('ev:{}'.format(EvalResult))

# 基于测试数据测试模型精度结果
PredictValues=DNNModel.predict(input_fn=lambda:InputFunPredict(TestX,
                                                               PredictBatchSize
                                                               )
                               )

# 调用AccuracyVerification函数,进行精度验证指标的计算与绘图
AccuracyResult=AccuracyVerification(PredictValues,TestY)
PearsonR,R2,RMSE,PredictY=AccuracyResult[0],AccuracyResult[1],AccuracyResult[2],AccuracyResult[3]

# 调用WriteAccuracy函数,将模型所涉及的参数与最终精度结果保存
WriteAccuracy(MyResultSavePath,PearsonR,R2,RMSE,TestSize,RandomSeed,OptMethod,LearningRate,DecayStep,
              DecayRate,','.join('%s' %i for i in HiddenLayer),ActFun,Dropout,LossReduction,
              BatchNorm,TrainBatchSize,TrainStep,EvalBatchSize,PredictBatchSize)

  至此,大功告成。

有关Python TensorFlow深度学习回归代码:DNNRegressor的更多相关文章

  1. ruby - 如何在 buildr 项目中使用 Ruby 代码? - 2

    如何在buildr项目中使用Ruby?我在很多不同的项目中使用过Ruby、JRuby、Java和Clojure。我目前正在使用我的标准Ruby开发一个模拟应用程序,我想尝试使用Clojure后端(我确实喜欢功能代码)以及JRubygui和测试套件。我还可以看到在未来的不同项目中使用Scala作为后端。我想我要为我的项目尝试一下buildr(http://buildr.apache.org/),但我注意到buildr似乎没有设置为在项目中使用JRuby代码本身!这看起来有点傻,因为该工具旨在统一通用的JVM语言并且是在ruby中构建的。除了将输出的jar包含在一个独特的、仅限ruby​​

  2. ruby-on-rails - Rails 源代码 : initialize hash in a weird way? - 2

    在rails源中:https://github.com/rails/rails/blob/master/activesupport/lib/active_support/lazy_load_hooks.rb可以看到以下内容@load_hooks=Hash.new{|h,k|h[k]=[]}在IRB中,它只是初始化一个空哈希。和做有什么区别@load_hooks=Hash.new 最佳答案 查看rubydocumentationforHashnew→new_hashclicktotogglesourcenew(obj)→new_has

  3. ruby-on-rails - 浏览 Ruby 源代码 - 2

    我的主要目标是能够完全理解我正在使用的库/gem。我尝试在Github上从头到尾阅读源代码,但这真的很难。我认为更有趣、更温和的踏脚石就是在使用时阅读每个库/gem方法的源代码。例如,我想知道RubyonRails中的redirect_to方法是如何工作的:如何查找redirect_to方法的源代码?我知道在pry中我可以执行类似show-methodmethod的操作,但我如何才能对Rails框架中的方法执行此操作?您对我如何更好地理解Gem及其API有什么建议吗?仅仅阅读源代码似乎真的很难,尤其是对于框架。谢谢! 最佳答案 Ru

  4. ruby - 模块嵌套代码风格偏好 - 2

    我的假设是moduleAmoduleBendend和moduleA::Bend是一样的。我能够从thisblog找到解决方案,thisSOthread和andthisSOthread.为什么以及什么时候应该更喜欢紧凑语法A::B而不是另一个,因为它显然有一个缺点?我有一种直觉,它可能与性能有关,因为在更多命名空间中查找常量需要更多计算。但是我无法通过对普通类进行基准测试来验证这一点。 最佳答案 这两种写作方法经常被混淆。首先要说的是,据我所知,没有可衡量的性能差异。(在下面的书面示例中不断查找)最明显的区别,可能也是最著名的,是你的

  5. ruby - 寻找通过阅读代码确定编程语言的ruby gem? - 2

    几个月前,我读了一篇关于ruby​​gem的博客文章,它可以通过阅读代码本身来确定编程语言。对于我的生活,我不记得博客或gem的名称。谷歌搜索“ruby编程语言猜测”及其变体也无济于事。有人碰巧知道相关gem的名称吗? 最佳答案 是这个吗:http://github.com/chrislo/sourceclassifier/tree/master 关于ruby-寻找通过阅读代码确定编程语言的rubygem?,我们在StackOverflow上找到一个类似的问题:

  6. ruby - Net::HTTP 获取源代码和状态 - 2

    我目前正在使用以下方法获取页面的源代码:Net::HTTP.get(URI.parse(page.url))我还想获取HTTP状态,而无需发出第二个请求。有没有办法用另一种方法做到这一点?我一直在查看文档,但似乎找不到我要找的东西。 最佳答案 在我看来,除非您需要一些真正的低级访问或控制,否则最好使用Ruby的内置Open::URI模块:require'open-uri'io=open('http://www.example.org/')#=>#body=io.read[0,50]#=>"["200","OK"]io.base_ur

  7. 程序员如何提高代码能力? - 2

    前言作为一名程序员,自己的本质工作就是做程序开发,那么程序开发的时候最直接的体现就是代码,检验一个程序员技术水平的一个核心环节就是开发时候的代码能力。众所周知,程序开发的水平提升是一个循序渐进的过程,每一位程序员都是从“菜鸟”变成“大神”的,所以程序员在程序开发过程中的代码能力也是根据平时开发中的业务实践来积累和提升的。提高代码能力核心要素程序员要想提高自身代码能力,尤其是新晋程序员的代码能力有很大的提升空间的时候,需要针对性的去提高自己的代码能力。提高代码能力其实有几个比较关键的点,只要把握住这些方面,就能很好的、快速的提高自己的一部分代码能力。1、多去阅读开源项目,如有机会可以亲自参与开源

  8. 7个大一C语言必学的程序 / C语言经典代码大全 - 2

    嗨~大家好,这里是可莉!今天给大家带来的是7个C语言的经典基础代码~那一起往下看下去把【程序一】打印100到200之间的素数#includeintmain(){ inti; for(i=100;i 【程序二】输出乘法口诀表#includeintmain(){inti;for(i=1;i 【程序三】判断1000年---2000年之间的闰年#includeintmain(){intyear;for(year=1000;year 【程序四】给定两个整形变量的值,将两个值的内容进行交换。这里提供两种方法来进行交换,第一种为创建临时变量来进行交换,第二种是不创建临时变量而直接进行交换。1.创建临时变量来

  9. LC滤波器设计学习笔记(一)滤波电路入门 - 2

    目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称

  10. CAN协议的学习与理解 - 2

    最近在学习CAN,记录一下,也供大家参考交流。推荐几个我觉得很好的CAN学习,本文也是在看了他们的好文之后做的笔记首先是瑞萨的CAN入门,真的通透;秀!靠这篇我竟然2天理解了CAN协议!实战STM32F4CAN!原文链接:https://blog.csdn.net/XiaoXiaoPengBo/article/details/116206252CAN详解(小白教程)原文链接:https://blog.csdn.net/xwwwj/article/details/105372234一篇易懂的CAN通讯协议指南1一篇易懂的CAN通讯协议指南1-知乎(zhihu.com)视频推荐CAN总线个人知识总

随机推荐