机器学习-TensorFlow建模过程 Linear Regression线性拟合应用

TensorFlow是我们机器学习领域很是经常使用的一个组件,它在数据处理,模型创建,模型验证等等关于机器学习方面的领域都有很好的表现,前面的一节我已经简单介绍了一下TensorFlow里面基础的数据结构即:Tensor和Dataset; 这里我们开始介绍TensorFlow的建模过程以及验证模型的一些简单方法。其实不管是sklearn仍是TensorFlow,他们的模型创建过程都是类似的,都是经历columns类型声明,模型定义,数据训练,validation等等几个步骤。前面的几节内容我已经简单的介绍了如何用sklearn创建tree_based模型,这里我主要是想演示TensorFlow的应用,因此我就用linear regressor来当作例子来演示TensorFlow是如何从数据加载一直到数据验证的阶段。至于线性拟合的实现的具体细节,我在下一节的内容会从数学的角度具体解释的。本节内容所使用的数据都是来自于网络中,你们能够忽略具体的数据的意思,主要的了解TensorFlow的应用过程,没必要过于纠结于模型的细节部分,模型的细节我会在随后的章节解释。好了,那么我们如今开始吧python

第一步:数据准备api

顾名思义,就是我们准备数据的过程,这里包括有missing value handling, categorical data encoding,data split, data permutation等等内容,这一步我们要将我们未来模型训练所用到的数据都能准备好。这个准备过程无非也就是上面的这些步骤,我们能够看下面的代码演示网络

cali_housing_dataset_original = pd.read_csv("https://download.mlcc.google.com/mledu-datasets/california_housing_train.csv")
cali_housing_dataset_original["median_house_value"] /= 1000.0
#create a random generator
generator = np.random.Generator(np.random.PCG64())
#permutate the data frame
cali_housing_dataset_permutation = cali_housing_dataset_original.reindex(
        generator.permutation(cali_housing_dataset_original.index)
        )
cali_housing_dataset_permutation.describe()

#select the features that we will use in the model trainning process
my_feature = cali_housing_dataset_permutation[["total_rooms"]]
#select the targets of the dataset
targets = cali_housing_dataset_permutation[["median_house_value"]]

这里我就不演示那些feature engineering的过程,那些内容太多,你们能够看我以前的博客,这里主要是想向你们演示一下permutation的过程。由于最新的numpy对于randomize的过程已经有更新了,再也不使用的那些老的API了,numpy中最新的randomize的过程是经过建立2个generator来实现随机过程和随机数的生成了,这两个generator一个个是bit generator, 就如我们上面代码中的PCG64(), 它能产生一个随机的bit stream, 根据numpy的官方文档,虽然有不少种bit generator,可是PCG64是最稳定的一种;另一个就是Generator, 它是经过np.random.Generator()函数来实例化一个对象的,它能将bit generator产生的bit stream转化成数字。这里的数据我们就选择一个最最简单的linear regression的方式,那就是只选择一个feature,那就是total_rooms; 我们的target是median_house_value。数据结构

第二步:定义feature 类型 和 optimizerapp

 既然我们的数据都准备好了,那么以后那么得定义一下我们数据的类型(每个column的类型都得定义),未来在我们定义模型的时候我们也得将columns的信息传递给我们的模型对象;以及用什么optimizer未来来训练我们的模型,这个optimizer未来也得传递给我们的模型对象。 具体optimizer是什么我下面会慢慢讲的。为了方便演示,仍是先上代码给你们看dom

#indicates what is the data type of the feature to tensorflow
feature_columns = [tf.feature_column.numeric_column("total_rooms")]
#using stochastic gradient descent as the optimizer for our model #to ensure the magtitute of gradient do not become too large, we apply clipping_norm to our optimizer my_optimizer = tf.optimizers.SGD(learning_rate = 0.0000001, clipnorm=5.0)

从上面的代码能够看出,第一句是声明我们feature_columns里面只有一个numeric_column,记住每个column都有一个feature_column对象,这里由于我们只选取了一个feature是total_rooms,因此我们这里就一个tf.feature_column对象。这里的第二行代码是我们的重点,也是之后优化模型中常常要调整的部分,这里我们能够看出,这里的optimizer是一个SGD, SGD是stochastic gradient descent的缩写,就是每一次计算我们的gradient descent的时候,我们只选取一组数据进行计算,若是每一次计算gradient descent的时候我们都用整个数据进行计算,那么我们的计算机是负担不起的,消耗的存储空间和计算能力都太大了,由于在实际中我们的数据集的数量常常都是以万为单位的。具体计算gradient descent的过程我会在下一节中讲述模型训练过程当中演示的。我们能够看出来,SGD中还有两个参数,分别是learning_rate和clipnorm, 我们知道,当咱们在训练咱们的模型的时候,咱们须要逐步的训练不少次,知道我们的gradient descent趋于0是才中止,我们的每一步的大小都要合理,若是learning_rate过小,我们训练的步数就会太多,影响我们的效率;若是learning_rate太大,则可能致使我们训练模型的过程不能converge,就是永远找不到那个最小值,从而致使训练的模型失败;为了防止我们我们的gradient太大,咱们这里不仅仅用learning_rate来限制,我们还加了一个clipnorm来限制我们的gradient magtitute大小,防止我们fail to converge, 这至关于一个双重保险。机器学习

第三步:定义一个模型model函数

将上面的参数都定义完成后,我们就得定义一下我们的模型啦,TensorFlow提供了大量的模型可供使用,几乎全部主流的机器学习的模型和深度学习相关的模型,TensorFlow几乎实现全覆盖了,具体我们能够去他的官网查询, 他的官网地址是:https://www.tensorflow.org/api_docs/python/tf  ,记住在TensorFlow中,他的模型都在tf.estimator这个模块中。由于这里是我们讲述用TensorFlow开发机器学习应用的入门,我们就选一个最简单的模型linear regressor模型来演示学习

linear_regressor = tf.estimator.LinearRegressor(
        feature_columns = feature_columns,
        optimizer = my_optimizer
        )

这里我们能够看出是如何初始化一个LinearRegressor对象的,一样的,我们能够看出来它初始化的时候也是须要传递feature_columns和optimizer这2个参数的,而这两个参数正是我们第二步中所初始化的,能够说是环环相扣啊,哈哈,也能够看出我们前面定义初始化的一个对象都是没有多余的,都是要用到的。这两个参数分别告诉了我们的模型我们数据columns的类型以及用什么optimizer来训练这2个信息。优化

第四步:数据源input_fn

既然我们的原始数据准备好了,模型也都定义好了,若是须要训练我们的模型,我们还差什么呢?对了就是将我们的原始数据(这里的例子是dataframe)转化成TensorFlow中的dataset,并将转化后的data传递给我们的模型,让我们以前定义的模型用这些数据去训练。这里应该也是我们用TensorFlow来建模的一个核心部分了,我们先看代码演示,而后我会逐个详细解释的

def my_input(features, targets, batch_size=500, shuffle=True, num_epochs=None):
    
    """
    epochs: while trainning, in the case of steps is larger than the length of dataset, we set the epochs to None, which means repeat forever. However,
    in trainning process, we have the steps to control the total number of iterations.  While in the case of making predictions of a given dataset, we must
    set epochs to 1 and shuffle to False. Because we only want the input function return the dataset once, otherwise the function will keep returnning the 
    results forvere once and once again.
    
    shuffle: in the trainning process, in order to balance the dataset, we set it to True. However while in prediction process, we have to set it to False, which
    could help us to evaluate the outputs. For example, if the outputs are shuffled, we have no way to compare the outputs to our original lables.
    
    """
    
    #convert panda dataframe to a dict of Numpy array
    features = {key:tf.multiply(np.array(value),1) for key,value in dict(features).items()}
    #construct a dataset
    ds = tf.data.Dataset.from_tensor_slices((features,targets))
    ds = ds.batch(batch_size).repeat(num_epochs)
    
    if shuffle:
        ds = ds.shuffle(buffer_size = 10000)    
    return ds

这里有几个核心的参数我须要解释一下,首先features和target两个参数很明显就是我们第一步中获取的数据,分别是用来训练这个模型的特征变量和label;重点这里解释一下batch_size, shuffle 和 num_epochs这三个参数,这三个参数在我们TensorFlow的整个学习过程当中都得用到,绝对的重点,不容怀疑。首先我们来看batch_size, 由于SGD每一次都只会选用一条数据来计算我们的gradient(训练模型),而我们的数据具备很强的随机性,那么就会致使我们的模型最后极可能不可用,可是若是我们每个step都选用整个dataset来训练模型,又会致使我们的训练过程很是漫长,那么聪明的人类就天然而然的想到了我们能够每一次选用必定数量的数据来训练模型,通常的数据量我们大体的范围都是在10-10000之间,这种方式就成为mini-batch SGD, 在这里我们就是采用了这种方式,我们每一次选用500条数据来训练我们的模型,这是经过设置batch_size的值来实现的。对于shuffle这个参数呢,也是为了打乱我们的数据来进行训练,最终的目的也是为了能帮助我们训练出更加精确的模型,防止我们的数据分布不合理致使模型有误差,它里面的buffer_size的意思是先从ds中选中buffer_size个数据(这些数据暂时仍是有序的,顺序和ds中同样),而后iterate的时候呢,就从这个buffer中随机的选择数据(这个选择数据的过程就是无序的选择了,实现了随机的目的)。最后还有这个repeat(num_epochs)的函数,首先repeat函数在training的过程当中必定须要的,由于当我们设置steps步数参数的时候,若是steps的总数要多余整个dataset的数据量的时候,那么这时候我们必定得重复利用我们的dataset来达到训练的目的,不然我们的数据源的数据量不够了,会出错的,这就是为何须要repeat的缘由,至于num_epochs是来控制重复的次数的,通常在training阶段我们将它设置成None, 意思就是无限循环,知道training中的steps所有走完位置,若是在predict阶段,我们通常就设置成1,由于我们验证阶段不须要重复的,一样的在predict的时候,数据源函数中的shuffle也要设置成False的,不然predict的结果都是乱序的,没法跟原来的数据进行对比了。前面几个参数在我们模型训练过程当中能够说是最重要的参数了,这里说的也比较多,因此一点得用心搞明白。

第五步:训练模型 training

既然上面我们把模型的参数都设置好了,数据源也定义好了,那么接下来我们的任务就是训练我们定义的模型了,这个过程在代码中是很简单的,但它内部作的工做是不少的,它须要计算在每一个维度(feature)上的gradient descent,知道它趋于0为止,它的计算细节我会在接下来的一个章节中展现出来,我们先看代码

linear_regressor.train(
        input_fn = lambda:my_input(my_feature, targets),
        steps = 1000
        )

是否是很简单,我们只须要将数据源函数做为参数传递给他,而且设置一个steps就能够了。这里input_fn我就不解释了,简单说一下steps,steps指的是我们训练的步数,我们每计算一次gradient descent,就算一步,这里指我们最多计算1000次,即便1000的时候gradient descent不等于0咱也中止咱的训练过程,而后我们能够从新设置optimizer中的learning_rate来从新训练。

第六步:predict和evaluate

通过前面五步后,我们已经训练出来了一个模型,那么接下来我们须要用这个模型来预测一下数据,而且看看它的效果,去evaluate一下这个模型。正常的状况下我们会将数据split成training data 和 validation data,这里我为了方便,咱就直接用training data来演示如何predict还有如何evaluate我们的模型。简单的代码以下

#create a input function for prediction
prediction_input_fn = lambda:my_input(my_feature,targets,shuffle=False,num_epochs=1)
#prediction
predictions = linear_regressor.predict(input_fn = prediction_input_fn)
predictions = np.array([item["predictions"][0] for item in predictions])

#errors MSE
mean_squared_error(targets,predictions)

在我们作prediction的时候,我们也是须要数据源input_fn的,在prediction的时候,shuffle=False, num_epochs=1; 而后调用这个模型linear_regressor的predict方法,将数据源函数传递给他, 它返回的结果是一个list,这个list里面的element是一个dictionary,这个dictionary的key值“predictions”, value也是一个一个list,而且只有一个元素element,此element就是我们要的结果。最后我们要evaluate这个模型预测的结果,我们有不少种方式能够验证,这里只展现了一个最简单的方式,就是计算我们的target和prediction的方差,其实有不少不少种方式,在后面的章节我会慢慢介绍。

第七步:data visualization

好了,最后我们来看一下根据我们的学习的模型,我们想看看它的具体的拟合的效果,这里就须要用一点以前我们学习的数据可视化的内容了,这里比较简单,我们经过模型学习到的参数,画一条拟合线,而后在将数据画到画布上,坐标分别是"total_rooms"和"house_median_price",而后经过scatter plot展现出来。代码以下

sample = cali_housing_dataset_permutation.sample(n=300)
x_0 = sample["total_rooms"].min()
x_1 = sample["total_rooms"].max()
linear_regressor.get_variable_names()#retrieve the name of the variable
weights = linear_regressor.get_variable_value("linear/linear_model/total_rooms/weights")[0]#returns the value of variable given by name
bias = linear_regressor.get_variable_value("linear/linear_model/bias_weights")#retruns the value of bias
y_0 = weights*x_0+bias
y_1 = weights*x_1+bias
plt.plot([x_0,x_1],[y_0,y_1])#plot our regression line
plt.ylabel("median_house_value")#label the y Axes
plt.xlabel("total_rooms")#label the x Axes
plt.scatter(sample["total_rooms"],sample["median_house_value"])#plot a scatter plot from the sample
plt.show()

结果以下

 

 能够看得出来,拟合的还不错。嘿嘿,关于模型训练过程的可视化,后面还有不少种,之后我慢慢说,例如:x坐标是steps, y坐标是loss, 也是很是常见的一种方式。

总结

今天完整的展现了用TensorFlow建立模型的整个过程,一直从data preparation到最后的evaluation,能够说贯穿了TensorFlow开发机器学习应用的整个过程。今天先用一个最简单的线性拟合例子展现这个过程,后面我还会展现更多的更加复杂的模型,例如:Logistic Regression, DNN, LSTM,等等等等。可是万变不离其宗,他们的基础步骤都是上面的七个步骤。最后 ,祝武汉加油!!!!!!!!

相关文章
相关标签/搜索