预热TensorFlow2.0(2)——房价预估实战

这篇文章承接上一篇预热TensoFlow2.0——IRIS数据集实战,主是想更加详细介绍一下如何使用tensorflow2.0中使用Keras高级API快速构建模型。Keras是一个底层为tensoflow或者theano的高度封装的深度学习库。TensorFlow2.0官方推荐使用Keras进行深度神经网络构建,说明Keras在网络构建方面确实有着其独到的优势。很多人不满意Keras的灵活性,称其无法根据自己的需求构建网络结构。我这里小小的反驳一下:

  • 其实Keras可以可以很方便的让用户的自定义神经网络层,
  • Keras也可以让用户很方便的定义损失函数,
  • Keras本身就是基于tensorflow封装的,能非常好的和tensorflow兼容。

接下来笔者就通过一个房价预估实战,为大家介绍一下这个即将成为TensoFlow2.0版模型构建新宠儿的Keras。这里笔者只使用了tensorflow去构建损失函数,大多数API依然是pure Keras,不过整个流程参考的是TensorFlow2.0 preview版本的教程

import tensorflow as tf
import keras
from keras.optimizers import Adam
import keras.backend as K

载入数据

from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
housing = fetch_california_housing()

房价预测任务就是给模型输入房屋信息数据,模型能够准确的预测出房价的值。数据格式如下图所示一个data是一个维度为8维的数组,是一些房屋的年岁,卧室面积大小之类的信息,需要预测的target是房价的值。

data

数据预处理

将数据分为训练集和测试剂,然后对数据做一些简单的预处理工作——标准化:即将数据转换为均值为0,方差为1的正态分布。

X_train_full, X_test, y_train_full, y_test = train_test_split(
    housing.data, housing.target.reshape(-1, 1), random_state=42)
X_train, X_valid, y_train, y_valid = train_test_split(
    X_train_full, y_train_full, random_state=42)

scaler = StandardScaler()
X_train_scaled = scaler.fit_transform(X_train)
X_valid_scaled = scaler.transform(X_valid)
X_test_scaled = scaler.transform(X_test)

用户自定义层

这里就开始使用keras自定义层了,需要注意keras自定义层的格式:

  • 一定要继承keras.layers.Layer这个类
  • __ init __ 定义网络层的一些基本属性,神经元个数,激活函数之类。这里激活函数继承了keras自带的Activation,
  • build方法用于定义需要优化的参数,
  • call方法很重要,这里你需要定义网络层需要做的操作,笔者定义的就是一个简单的Dense层的操作F(wx+b),
  • compute_output_shape是用来控制输出的维度,如果这个网络层的输入和输出形状一致,那么此方法可以省略。

笔者这里为了演示,把keras.layers.Dense重新实现了一遍而已。大家可以通过这样的格式定义各种其他功能的网络层。

class MyDense(keras.layers.Layer):
    def __init__(self,units, activation=None, **kwargs):
        self.units = units
        self.output_dim = units
        self.activation = keras.layers.Activation(activation)
        super(MyDense, self).__init__(**kwargs)

    def build(self, input_shape):
        self.kernel = self.add_weight(name='kernel', 
                                      shape=(input_shape[1], self.units),
                                      initializer='uniform',
                                      trainable=True)
        self.biases = self.add_weight(name='bias', 
                                      shape=(self.units,),
                                      initializer='zeros',
                                      trainable=True)
        super(MyDense, self).build(input_shape)

    def call(self, X):
        return self.activation(K.dot(X,self.kernel) + self.biases)
    def compute_output_shape(self, input_shape):
        # 计算输出形状,如果输入和输出形状一致,那么可以省略,否则最好加上
        return (input_shape[0], self.output_dim)

用户自定义模型(Wide and Deep)

接下来就是用户自定义模型,这里依然有个keras官方建议的标准格式:

  • 首先必须继承keras.models.Model这个类,
  • __ init __ 定义模型需要的网络层,如果把搭网络架构比作堆积木的话,这里就是从袋子里把积木块拿出来。
  • call 就是将这层就是用已有的积木块组合搭建网络结构啦

这里笔者搭建了一个Wide and Deep的网络架构,笔者之前的文章对这个模型进行了详细的介绍,不明白的可以点这个链接去了解下。从call方法的代码中可以看出其具体的操作是——将原输入经过两层神经网络后的输出原输入拼接之后再喂给一层感知器

class MyModel(keras.models.Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.hidden1 = MyDense(30, activation="relu")
        self.hidden2 = MyDense(30, activation="relu")
        self.output_ = MyDense(1)

    def call(self, input):
        hidden1 = self.hidden1(input)
        hidden2 = self.hidden2(hidden1)
        concat = keras.layers.concatenate([input, hidden2])
        output = self.output_(concat)
        return output

用户自定以损失函数

自定义损失函数,用tensoflow的api,就可以定义你自己想要的损失函数。由于是做一个回归问题,笔者这里定义了一个mean square error的损失函数。

def my_mse(y_true, y_pred):
    return tf.reduce_mean(tf.square(y_pred - y_true))

实例化模型

解下来要做的就是实例化和编译模型,代码也很简单。使用keras自带的compile方法,传入之前定义好的损失函数和优化器即可。

model = MyModel()
model.compile(loss=my_mse, optimizer=Adam(lr=1e-4))

定以callbacks

callbacks在笔者看来是keras里面的一个神奇的特性,你可以通过callbacks定义模型一些在训练过程中的适当时机可被调用函数。keras里面已经帮你封装了一些特别有用的callbacks函数,这里介绍三个常用的方法:

  • keras.callbacks.TensorBoard 可以通过tensorboard 可视化训练过程,需要传一个可视化文件保存的路径给这个函数,
  • keras.callbacks.EarlyStopping能够有效的防止模型过拟合,其机制就是如果模型的val_loss不降反增,此方法能够提前终止模型训练。笔者这里设置的是连续5个epoch模型的val_loss都是增加的话,模型就停止训练。
  • keras.callbacks.ModelCheckpoint 保存模型的checkpoint,同时你可以自己定义checkpoint的命名和保存频率,这里笔者选择5个epoch,保存一下checkpoint。
    大家也可以自己定义一下其他的callback函数,比如计算acc和recall之类的。
logdir = "./log"
filepath="./checkpoint/model_{epoch:02d}-{val_loss:.2f}.hdf5"
checkpoint = keras.callbacks.ModelCheckpoint(filepath,
    monitor='val_loss', save_weights_only=True,verbose=1,save_best_only=True, period=5)
callbacks = [
    keras.callbacks.TensorBoard(logdir),
    keras.callbacks.EarlyStopping(patience=5),
    checkpoint,
]

模型训练

接下来模执行下面代码模型就跑起来了,记得把之前定义的callbacks函数的list传给fit方法。

model.fit(X_train_scaled, y_train,batch_size=32, epochs=20,
             validation_data=(X_valid_scaled, y_valid),
              callbacks=callbacks)

从模型训练输出,我们可以看到,模型每5个epoch帮我保存了一个checkpoint。不知道你们发现没有,原本笔者定义跑20个epoch,但是最终只跑着13个epoch模型就终止了训练。仔细观察的话,9-13epoch的过程中val_loss一直在增加,说明模型开始过拟合了,callbacks定义的keras.callbacks.EarlyStopping起了作用,在模型过拟合时提前终止了模型的训练。


train

使用tensorboard --logdir log 之后我们通过浏览器访问localhost:6006 我们就可以看到模型训练过程中的loss曲线了。

tensorboard

结语

整个过程代码量极少,而且模型的构建(复杂的模型也可以很方便的构建),模型的训练模型的保存loss的可视化相比于tensorflow之前的操作容易了许多。是时候学习一波tensorflow2.0官方推荐的模型构建API——Keras了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,921评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,635评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,393评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,836评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,833评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,685评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,043评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,694评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 42,671评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,670评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,779评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,424评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,027评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,984评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,214评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,108评论 2 351
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,517评论 2 343

推荐阅读更多精彩内容