用了pre estimators,不够灵活,便翻译边学习。
这篇文档立志于建立一个custom estimator来模仿pre-made estimator DNN。
pre-made estima 是tf.estimator.Estimator基类的子类,而custom是它的实例。
很多时候,你需要更多的控制权在estimator的表现上,这样的话就需要custom了,你可以创建一个cunstom Estimator做任何你想做的事,你想用隐藏层进行一些非常规的链接,用它,你想计算模型中的单一节点,用它,基本上,如果你想用estimator优化你的特定的问题,用它
一个model function表示机器学习算法,premade和custom间的唯一不同就是
pre 有人帮你写过模型了 custom你要自己写
你得model function 能够实现很多算法,定义各种各样的隐藏层和矩阵,像输入函数,所有的mf必须接受一组标准的参数,返回一种标准的值,就像input function 能够影响DAtaset API,mf 也会影响Layer API和Mertics API
看一下我们怎么用custom解决问题,这是我们要模仿的模型结构
写一个input function:(和pre-made)一样
def
train_input_fn
(
features
,
labels
,
batch_size
):
"""An input function for training"""
# Convert the inputs to a Dataset.
dataset = tf . data . Dataset . from_tensor_slices (( dict ( features ), labels )) 切片
# Shuffle, repeat, and batch the examples.
dataset = dataset . shuffle ( 1000 ). repeat (). batch ( batch_size ) 随机,不重复,分成子块
# Return the read end of the pipeline.
return dataset . make_one_shot_iterator (). get_next ()
"""An input function for training"""
# Convert the inputs to a Dataset.
dataset = tf . data . Dataset . from_tensor_slices (( dict ( features ), labels )) 切片
# Shuffle, repeat, and batch the examples.
dataset = dataset . shuffle ( 1000 ). repeat (). batch ( batch_size ) 随机,不重复,分成子块
# Return the read end of the pipeline.
return dataset . make_one_shot_iterator (). get_next ()
这个函数见了一个输入管道,返回(features,lebels)对儿,其中features事字典。
建立feature columns
我们必须定义模型的feature columns来确定我们的模型怎么使用每个特征,pre-made custom在这一点上一致。
下面的代码对每个特征都用numeric-column的方法,表示输入的特征应该直接输入模型:
# Feature columns describe how to use the input.
my_feature_columns = []
for key in train_x.keys():
my_feature_columns.append(tf.feature_column.numeric_column(key=key))
写一个模型函数:
def my_model_fn(
features, # This is batch_features from input_fn
labels, # This is batch_labels from input_fn
mode, # An instance of tf.estimator.ModeKeys
params): # Additional configuration
前两个参数事从输入函数返回的数据块,也就是说features和labels控制着你得模型会用到的数据,mode参数知名这个调用是用来训练,预测还是评价/
这个调用会传递params给estimator's的constructor。任何传递给constructor的params都传递给了model-fn。
classifier
=
tf
.
estimator
.
Estimator
(
model_fn = my_model ,
params ={
'feature_columns' : my_feature_columns ,
# Two hidden layers of 10 nodes each.
'hidden_units' : [ 10 , 10 ],
# The model must choose between 3 classes.
'n_classes' : 3 ,
})
model_fn = my_model ,
params ={
'feature_columns' : my_feature_columns ,
# Two hidden layers of 10 nodes each.
'hidden_units' : [ 10 , 10 ],
# The model must choose between 3 classes.
'n_classes' : 3 ,
})
为了实现一个典型的模型函数,你必须做几件事:
定义model 对于不同的modes来说明确不同的计算。
定义一个模型:基本的DNN必须定义一个输入层 一个或者多个隐藏层,一个输出层
定义input layer
model-fn的第一行调用tf.feature_column.input_layer来把特征字典和feature_columns输入模型:
# Use `input_layer` to apply the feature columns.
net = tf.feature_column.input_layer(features, params['feature_columns'])
feature_columns处理,变换对应的数据:
隐藏层:
如果你创立一个DNN,必须建立隐藏层,Layers API提供了大量的函数创建各种隐层层,通多params中定义的lidden-layers维度。一个dense层,每一个节点都和千一层的每个节点相连,相关代码:
# Build the hidden layers, sized according to the 'hidden_units' param.
for units in params['hidden_units']:
net = tf.layers.dense(net, units=units, activation=tf.nn.relu)
变量net标志着网络的最新一层节点,创建了两层隐藏层后,我们的网络结构如下:
注意,tf.layers.dense提供了很多功能,包括正则化等操作,其余的参数都是默认值
输出层,我们再次调用tf.layers.dense函数,这次没有激活函数:
# Compute logits (1 per class).
logits = tf.layers.dense(net, params['n_classes'], activation=None)
这样我们的结构如下:
我们定义了输出层,units参数知名输出节点的数量,这样的话,我们用n_classes给params,模型给每个输出类别一个值,每个输出向量的element都会包含分值(Logit),稍后,这些值会被tf.nn.softmax函数变为概率
构建 训练 评价 预测:
最后一步是创建model function的评价 预测 训练部分代码。
model function使用train evaluate 或者predict方法都可以唤醒。不同的mode调用不同的方法。
分别说一下:
预测:
当predict 方法被调用的时候,model_fn接受mode = ModeKeys.PREDICT。这种情况下,model function必须返回一个tf.estimator.EstimatorSpec来包含预测。
模型必须经过训练,训练的结果会保存在硬盘上。
# Compute predictions.
predicted_classes = tf.argmax(logits, 1)
if mode == tf.estimator.ModeKeys.PREDICT:
predictions = {
'class_ids': predicted_classes[:, tf.newaxis],
'probabilities': tf.nn.softmax(logits),
'logits': logits,
}
return tf.estimator.EstimatorSpec(mode, predictions=predictions)
predictions包含模型返回的所有信息,包括logit值,概率,类别。
计算loss
对于训练和评价来说,我们需要计算模型的损失,以便于优化。
# Compute loss.
loss = tf.losses.sparse_softmax_cross_entropy(labels=labels, logits=logits)
评价:
当evaluate被调用时,model-fn接收mode = Modekeys.EVAL.这种情况下,model function返回一个tf.estimator.EstimatorSpec包含模型的损失和操作的矩阵
# Compute evaluation metrics.
accuracy = tf . metrics . accuracy ( labels = labels ,
predictions = predicted_classes ,
name = 'acc_op' )
accuracy = tf . metrics . accuracy ( labels = labels ,
predictions = predicted_classes ,
name = 'acc_op' )
metrics = {'accuracy': accuracy}
tf.summary.scalar('accuracy', accuracy[1])
if mode == tf.estimator.ModeKeys.EVAL:
return tf.estimator.EstimatorSpec(
mode, loss=loss, eval_metric_ops=metrics)
训练:
当Estimator's的train方法被调用时,model-fn接手Mode Keys.TRAIN,这种情况下,EstimatorSpec包含损失和training operation。建立训练操作需要油壶,我们又ft.train.Adagrad)ptimizer,因为我们在模仿DNN,所以我们也这么用,tf.train包提供很多其他的优化,很容易去试试。
optimizer = tf.train.AdagradOptimizer(learning_rate=0.1)
接下来,我们建立训练操作,通过用优化器的minimize方法,在我们之前建立的loss基础上。
train_op = optimizer.minimize(loss, global_step=tf.train.get_global_step())
这样estimatorspec返回loss和train-op