如何在 Tensorflow Estimator 的输入中提供更多模型参数?

How to feed further model parameters along the inputs to Tensorflow Estimator?

短版: 我有一个带有层的自定义模型,该层可以通过值 sigma.

进行参数化

我正在将此模型与 Tensorflow Estimator 一起使用:

    classifier = tf.estimator.Estimator(model_fn=model_fun)

例如训练声明如下:

    # Train the model
    train_input_fn=tf.estimator.inputs.numpy_input_fn(x={"x": train_data}, 
    batch_size=batch_size, num_epochs=nEpochs, shuffle=True)
    classifier.train(input_fn=train_input_fn,max_steps=nSteps)

在此设置中,如何将 sigma 传递给我的自定义 Estimator,以便可以使用不同的值对其进行训练/评估?


更长的版本:

我正在研究这个 DNN 自动编码器,为此我有一个层,通过考虑来自已知标准偏差 sigma 分布的 random_normal() 值来添加高斯噪声。

这是一个通信系统模型,使用 model.predict() 函数检索输出 logits(来自最后一层),我的指标即误码率由自定义函数计算在张量流 1.5 中,Python 3.5,Windows 10。

问题如下:

  1. 我想为sigma=sigma1训练系统,并检索输出logits。(这部分没问题,我能够得到想要的输出。)

  2. 我还想预测 sigma=sigma2、sigma=sigma3、sigma=sigma4 等的输出,使用定义的相同 Estimator(在同一程序中)。

我的 DNN 看起来像这样并在模型函数中定义:

  1. 输入层 - 此处提供一个热编码值。

  2. 密集+ReLU

  3. 密集+线性

  4. 归一化层

  5. Addition of Noise:这里我在上一层的输出上加了一个tf.random_normal(stddev=sigma)。在这里,我希望能帮助您理解如何为每个 运行(train/test) 使用不同的西格玛。我想你可以说 sigma 应该是一个参数,每个测试可以有不同的值 运行.

     gnoise=tf.random_normal(mean=0,stddev=sigma) 
     Then the layer's output=norm(which is the prev layer's output)+gnoise
    
  6. 密集+RELU

  7. Softmax-输出为 Logits

我将估算器定义为:

    classifier = tf.estimator.Estimator(model_fn=model_fun)

并且训练声明如下:

    # Train the model
    train_input_fn=tf.estimator.inputs.numpy_input_fn(x={"x": train_data}, 
    batch_size=batch_size, num_epochs=nEpochs, shuffle=True)
    classifier.train(input_fn=train_input_fn,max_steps=nSteps)

预测函数的声明和调用如下:

    pred_input_fn=tf.estimator.inputs.numpy_input_fn(x={"x": test_data}, 
    batch_size=batch_size, num_epochs=nEpochs, shuffle=False)
    pred_results = classifier.predict(input_fn=pred_input_fn)

你应该让你的 sigma 成为你层的参数,然后在运行时通过你的 features 将它的值提供给你的模型(使用列键区分 xsigma ).

没有你的高斯层代码很难准确回复,但假设你的模型是这样定义的:

import tensorflow as tf

def gaussian_noise_layer(x):
    # Currently, your sigma is probably fixed somewhere here, e.g.
    sigma = 1

    dist = tf.distributions.Normal(loc=0., scale=sigma)

    # Build Gaussian kernel from dist:
    # gaussian_kernel = ...

    return tf.nn.depthwise_conv2d(x, gaussian_kernel, [1, 1, 1, 1], padding='SAME')

def model_fun(features, labels, mode, params):

    # Get input x from features:
    x = tf.feature_column.input_layer(features, params.feature_column)

    # ... building your model here, adding at some point the gaussian layer, e.g.
    # ... net = f(x)
    net = gaussian_noise_layer(net)
    # ... predictions = f'(net)
    # ...

    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions=predictions,
        loss=loss,
        train_op=train_op,
        eval_metric_ops=eval_metric_ops
    )

with tf.Session() as sess:
    # ...

    # Specifying your params and inputs:
    params = tf.contrib.training.HParams(
        # ... other hyperparameters,
        # Define feature column for input x of shape "shape_x" (e.g. (64, 64, 3)):
        feature_column=tf.feature_column.numeric_column(key="x", shape=shape_x)
    )

    classifier = tf.estimator.Estimator(model_fn=model_fun, params=params)

    # For training:
    train_input_fn = tf.estimator.inputs.numpy_input_fn(x={"x": train_data},
                                                        batch_size=batch_size, num_epochs=nEpochs, shuffle=True)
    classifier.train(input_fn=train_input_fn, max_steps=nSteps)

...那么您需要像这样编辑它:

import tensorflow as tf

def gaussian_noise_layer(x, sigma):

    # sigma is now a parameter
    dist = tf.distributions.Normal(loc=0., scale=sigma)

    # Build Gaussian kernel from dist:
    # gaussian_kernel = ...

    return tf.nn.depthwise_conv2d(x, gaussian_kernel, [1, 1, 1, 1], padding='SAME')

def model_fun(features, labels, mode, params):

    # Get input x from features:
    x = tf.feature_column.input_layer(features, params.input_feature_column)
    # Get sigma from features:
    sigma = tf.feature_column.input_layer(features, params.sigma_feature_column)

    # ... building your model here, adding at some point the gaussian layer, e.g.
    # ... net = f(x)
    net = gaussian_noise_layer(net, sigma)
    # ... predictions = f'(net)
    # ...

    return tf.estimator.EstimatorSpec(
        mode=mode,
        predictions=predictions,
        loss=loss,
        train_op=train_op,
        eval_metric_ops=eval_metric_ops
    )

with tf.Session() as sess:
    # ...

    # We now specify which columns contain the actual inputs (x), and which columns contain other parameters (sigma):
    params = tf.contrib.training.HParams(
        # ... other hyperparameters,
        # Define feature column for input x of shape "shape_x" (e.g. (64, 64, 3)):
        input_feature_column=tf.feature_column.numeric_column(key="x", shape=shape_x),
        # Define feature column for input sigma of shape () i.e. scalar (default shape):
        sigma_feature_column=tf.feature_column.numeric_column(key="sigma")
    )

    classifier = tf.estimator.Estimator(model_fn=model_fun, params=params)

    # Train:
    num_train_elements = train_data.shape[0]
    sigma = [1] * num_train_elements  # or e.g. sigma = [1, 1, 2, 1, 3, ...]
    # We can now feed sigma along x:
    train_input_fn = tf.estimator.inputs.numpy_input_fn(
         x={"x": train_data, "sigma": numpy.array(sigma)},
         batch_size=batch_size, num_epochs=nEpochs, shuffle=True)

    classifier.train(input_fn=train_input_fn, max_steps=nSteps)

    # ...

    # Predict:
    sigma = [2] * num_train_elements  # or e.g. sigma = [1, 1, 2, 1, 3, ...]
    pred_input_fn=tf.estimator.inputs.numpy_input_fn(
         x={"x": train_data, "sigma": numpy.array(sigma)},
         batch_size=batch_size, num_epochs=nEpochs, shuffle=True)
    pred_results = classifier.predict(input_fn=pred_input_fn)