1# Copyright 2018 The TensorFlow Authors. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# http://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14# ============================================================================== 15"""Tests specific to Feature Columns integration.""" 16 17from __future__ import absolute_import 18from __future__ import division 19from __future__ import print_function 20 21import numpy as np 22 23from tensorflow.python import keras 24from tensorflow.python.data.ops import dataset_ops 25from tensorflow.python.feature_column import feature_column_lib as fc 26from tensorflow.python.keras import keras_parameterized 27from tensorflow.python.keras import metrics as metrics_module 28from tensorflow.python.keras import testing_utils 29from tensorflow.python.platform import test 30 31 32class TestDNNModel(keras.models.Model): 33 34 def __init__(self, feature_columns, units, name=None, **kwargs): 35 super(TestDNNModel, self).__init__(name=name, **kwargs) 36 self._input_layer = fc.DenseFeatures(feature_columns, name='input_layer') 37 self._dense_layer = keras.layers.Dense(units, name='dense_layer') 38 39 def call(self, features): 40 net = self._input_layer(features) 41 net = self._dense_layer(net) 42 return net 43 44 45class FeatureColumnsIntegrationTest(keras_parameterized.TestCase): 46 """Most Sequential model API tests are covered in `training_test.py`. 47 48 """ 49 50 @keras_parameterized.run_all_keras_modes 51 def test_sequential_model(self): 52 columns = [fc.numeric_column('a')] 53 model = keras.models.Sequential([ 54 fc.DenseFeatures(columns), 55 keras.layers.Dense(64, activation='relu'), 56 keras.layers.Dense(20, activation='softmax') 57 ]) 58 model.compile( 59 optimizer='rmsprop', 60 loss='categorical_crossentropy', 61 metrics=['accuracy'], 62 run_eagerly=testing_utils.should_run_eagerly()) 63 64 x = {'a': np.random.random((10, 1))} 65 y = np.random.randint(20, size=(10, 1)) 66 y = keras.utils.to_categorical(y, num_classes=20) 67 model.fit(x, y, epochs=1, batch_size=5) 68 model.fit(x, y, epochs=1, batch_size=5) 69 model.evaluate(x, y, batch_size=5) 70 model.predict(x, batch_size=5) 71 72 @keras_parameterized.run_all_keras_modes 73 def test_sequential_model_with_ds_input(self): 74 columns = [fc.numeric_column('a')] 75 model = keras.models.Sequential([ 76 fc.DenseFeatures(columns), 77 keras.layers.Dense(64, activation='relu'), 78 keras.layers.Dense(20, activation='softmax') 79 ]) 80 model.compile( 81 optimizer='rmsprop', 82 loss='categorical_crossentropy', 83 metrics=['accuracy'], 84 run_eagerly=testing_utils.should_run_eagerly()) 85 86 y = np.random.randint(20, size=(100, 1)) 87 y = keras.utils.to_categorical(y, num_classes=20) 88 x = {'a': np.random.random((100, 1))} 89 ds1 = dataset_ops.Dataset.from_tensor_slices(x) 90 ds2 = dataset_ops.Dataset.from_tensor_slices(y) 91 ds = dataset_ops.Dataset.zip((ds1, ds2)).batch(5) 92 model.fit(ds, steps_per_epoch=1) 93 model.fit(ds, steps_per_epoch=1) 94 model.evaluate(ds, steps=1) 95 model.predict(ds, steps=1) 96 97 @keras_parameterized.run_all_keras_modes 98 def test_subclassed_model_with_feature_columns(self): 99 col_a = fc.numeric_column('a') 100 col_b = fc.numeric_column('b') 101 102 dnn_model = TestDNNModel([col_a, col_b], 20) 103 104 dnn_model.compile( 105 optimizer='rmsprop', 106 loss='categorical_crossentropy', 107 metrics=['accuracy'], 108 run_eagerly=testing_utils.should_run_eagerly()) 109 110 x = {'a': np.random.random((10, 1)), 'b': np.random.random((10, 1))} 111 y = np.random.randint(20, size=(10, 1)) 112 y = keras.utils.to_categorical(y, num_classes=20) 113 dnn_model.fit(x=x, y=y, epochs=1, batch_size=5) 114 dnn_model.fit(x=x, y=y, epochs=1, batch_size=5) 115 dnn_model.evaluate(x=x, y=y, batch_size=5) 116 dnn_model.predict(x=x, batch_size=5) 117 118 @keras_parameterized.run_all_keras_modes 119 def test_subclassed_model_with_feature_columns_with_ds_input(self): 120 col_a = fc.numeric_column('a') 121 col_b = fc.numeric_column('b') 122 123 dnn_model = TestDNNModel([col_a, col_b], 20) 124 125 dnn_model.compile( 126 optimizer='rmsprop', 127 loss='categorical_crossentropy', 128 metrics=['accuracy'], 129 run_eagerly=testing_utils.should_run_eagerly()) 130 131 y = np.random.randint(20, size=(100, 1)) 132 y = keras.utils.to_categorical(y, num_classes=20) 133 x = {'a': np.random.random((100, 1)), 'b': np.random.random((100, 1))} 134 ds1 = dataset_ops.Dataset.from_tensor_slices(x) 135 ds2 = dataset_ops.Dataset.from_tensor_slices(y) 136 ds = dataset_ops.Dataset.zip((ds1, ds2)).batch(5) 137 dnn_model.fit(ds, steps_per_epoch=1) 138 dnn_model.fit(ds, steps_per_epoch=1) 139 dnn_model.evaluate(ds, steps=1) 140 dnn_model.predict(ds, steps=1) 141 142 # TODO(kaftan) seems to throw an error when enabled. 143 @keras_parameterized.run_all_keras_modes 144 def DISABLED_test_function_model_feature_layer_input(self): 145 col_a = fc.numeric_column('a') 146 col_b = fc.numeric_column('b') 147 148 feature_layer = fc.DenseFeatures([col_a, col_b], name='fc') 149 dense = keras.layers.Dense(4) 150 151 # This seems problematic.... We probably need something for DenseFeatures 152 # the way Input is for InputLayer. 153 output = dense(feature_layer) 154 155 model = keras.models.Model([feature_layer], [output]) 156 157 optimizer = 'rmsprop' 158 loss = 'mse' 159 loss_weights = [1., 0.5] 160 model.compile( 161 optimizer, 162 loss, 163 metrics=[metrics_module.CategoricalAccuracy(), 'mae'], 164 loss_weights=loss_weights) 165 166 data = ({'a': np.arange(10), 'b': np.arange(10)}, np.arange(10, 20)) 167 print(model.fit(*data, epochs=1)) 168 169 # TODO(kaftan) seems to throw an error when enabled. 170 @keras_parameterized.run_all_keras_modes 171 def DISABLED_test_function_model_multiple_feature_layer_inputs(self): 172 col_a = fc.numeric_column('a') 173 col_b = fc.numeric_column('b') 174 col_c = fc.numeric_column('c') 175 176 fc1 = fc.DenseFeatures([col_a, col_b], name='fc1') 177 fc2 = fc.DenseFeatures([col_b, col_c], name='fc2') 178 dense = keras.layers.Dense(4) 179 180 # This seems problematic.... We probably need something for DenseFeatures 181 # the way Input is for InputLayer. 182 output = dense(fc1) + dense(fc2) 183 184 model = keras.models.Model([fc1, fc2], [output]) 185 186 optimizer = 'rmsprop' 187 loss = 'mse' 188 loss_weights = [1., 0.5] 189 model.compile( 190 optimizer, 191 loss, 192 metrics=[metrics_module.CategoricalAccuracy(), 'mae'], 193 loss_weights=loss_weights) 194 195 data_list = ([{ 196 'a': np.arange(10), 197 'b': np.arange(10) 198 }, { 199 'b': np.arange(10), 200 'c': np.arange(10) 201 }], np.arange(10, 100)) 202 print(model.fit(*data_list, epochs=1)) 203 204 data_bloated_list = ([{ 205 'a': np.arange(10), 206 'b': np.arange(10), 207 'c': np.arange(10) 208 }, { 209 'a': np.arange(10), 210 'b': np.arange(10), 211 'c': np.arange(10) 212 }], np.arange(10, 100)) 213 print(model.fit(*data_bloated_list, epochs=1)) 214 215 data_dict = ({ 216 'fc1': { 217 'a': np.arange(10), 218 'b': np.arange(10) 219 }, 220 'fc2': { 221 'b': np.arange(10), 222 'c': np.arange(10) 223 } 224 }, np.arange(10, 100)) 225 print(model.fit(*data_dict, epochs=1)) 226 227 data_bloated_dict = ({ 228 'fc1': { 229 'a': np.arange(10), 230 'b': np.arange(10), 231 'c': np.arange(10) 232 }, 233 'fc2': { 234 'a': np.arange(10), 235 'b': np.arange(10), 236 'c': np.arange(10) 237 } 238 }, np.arange(10, 100)) 239 print(model.fit(*data_bloated_dict, epochs=1)) 240 241 242if __name__ == '__main__': 243 test.main() 244