In [1]:
from __future__ import division, print_function
from tensorflow.contrib.learn.python.learn.estimators import model_fn as model_fn_lib
import matplotlib.pyplot as plt
import numpy as np
import os
import shutil
import tensorflow as tf
In [2]:
DATA_DIR = "../../data"
TRAIN_FILE = os.path.join(DATA_DIR, "mnist_train.csv")
TEST_FILE = os.path.join(DATA_DIR, "mnist_test.csv")
MODEL_DIR = os.path.join(DATA_DIR, "expt-learn-model")
NUM_FEATURES = 784
NUM_CLASSES = 10
NUM_STEPS = 100
LEARNING_RATE = 1e-3
BATCH_SIZE = 128
tf.logging.set_verbosity(tf.logging.INFO)
In [3]:
def parse_file(filename):
xdata, ydata = [], []
fin = open(filename, "rb")
i = 0
for line in fin:
if i % 10000 == 0:
print("{:s}: {:d} lines read".format(
os.path.basename(filename), i))
cols = line.strip().split(",")
ydata.append(int(cols[0]))
xdata.append([float(x) / 255. for x in cols[1:]])
i += 1
fin.close()
print("{:s}: {:d} lines read".format(os.path.basename(filename), i))
y = np.array(ydata, dtype=np.float32)
X = np.array(xdata, dtype=np.float32)
return X, y
Xtrain, ytrain = parse_file(TRAIN_FILE)
Xtest, ytest = parse_file(TEST_FILE)
print(Xtrain.shape, ytrain.shape, Xtest.shape, ytest.shape)
The train_input_fn and test_input_fn below are equivalent to using the full batches. There is some information on building batch oriented input functions, but I was unable to make it work. Commented out block is adapted from a Keras data generator, but that does not work either.
In [4]:
def train_input_fn():
return tf.constant(Xtrain), tf.constant(ytrain)
def test_input_fn():
return tf.constant(Xtest), tf.constant(ytest)
# def batch_input_fn(X, y, batch_size=BATCH_SIZE,
# num_epochs=NUM_STEPS):
# for e in range(num_epochs):
# num_recs = X.shape[0]
# sids = np.random.permutation(np.arange(num_recs))
# num_batches = num_recs // batch_size
# for bid in range(num_batches):
# sids_b = sids[bid * batch_size : (bid + 1) * batch_size]
# X_b = np.zeros((batch_size, NUM_FEATURES))
# y_b = np.zeros((batch_size,))
# for i in range(batch_size):
# X_b[i] = X[sids_b[i]]
# y_b[i] = y[sids_b[i]]
# yield tf.constant(X_b, dtype=tf.float32), \
# tf.constant(y_b, dtype=tf.float32)
# def train_input_fn():
# return batch_input_fn(Xtrain, ytrain, BATCH_SIZE).next()
# def test_input_fn():
# return batch_input_fn(Xtest, ytest, BATCH_SIZE).next()
In [5]:
def model_fn(features, labels, mode):
# define model
in_training = (mode == tf.contrib.learn.ModeKeys.TRAIN)
fc1 = tf.layers.dense(inputs=features, units=512,
activation=tf.nn.relu, name="fc1")
fc1_dropout = tf.layers.dropout(inputs=fc1, rate=0.2,
training=in_training,
name="fc1_dropout")
fc2 = tf.layers.dense(inputs=fc1_dropout, units=256,
activation=tf.nn.relu, name="fc2")
fc2_dropout = tf.layers.dropout(inputs=fc2, rate=0.2,
training=in_training,
name="fc2_dropout")
logits = tf.layers.dense(inputs=fc2_dropout, units=NUM_CLASSES,
name="logits")
# loss (for TRAIN and EVAL)
loss = None
if mode != tf.contrib.learn.ModeKeys.INFER:
onehot_labels = tf.one_hot(indices=tf.cast(labels, tf.int32),
depth=NUM_CLASSES)
loss = tf.losses.softmax_cross_entropy(
onehot_labels=onehot_labels, logits=logits)
# optimizer (TRAIN only)
train_op = None
if mode == tf.contrib.learn.ModeKeys.TRAIN:
train_op = tf.contrib.layers.optimize_loss(
loss=loss,
global_step=tf.contrib.framework.get_global_step(),
learning_rate=LEARNING_RATE,
optimizer="Adam")
# predictions
predictions = {
"classes" : tf.argmax(input=logits, axis=1),
"probabilities": tf.nn.softmax(logits, name="softmax_tensor")}
# additional metrics
accuracy = tf.metrics.accuracy(labels, predictions["classes"])
eval_metric_ops = { "accuracy": accuracy }
# logging variables to tensorboard
tf.summary.scalar("loss", loss)
tf.summary.scalar("accuracy", accuracy[0] / accuracy[1])
summary_op = tf.summary.merge_all()
tb_logger = tf.contrib.learn.monitors.SummarySaver(summary_op,
save_steps=10)
return model_fn_lib.ModelFnOps(mode=mode,
predictions=predictions,
loss=loss,
train_op=train_op,
eval_metric_ops=eval_metric_ops)
In [6]:
shutil.rmtree(MODEL_DIR, ignore_errors=True)
estimator = tf.contrib.learn.Estimator(model_fn=model_fn,
model_dir=MODEL_DIR,
config=tf.contrib.learn.RunConfig(save_checkpoints_secs=30000))
Using the parameters x, y and batch are deprecated and the warnings say to use the input_fn instead. However, using that results in very slow fit and evaluate. The solution is to use batch oriented input_fns. The commented portions will be opened up once I figure out how to make the batch oriented input_fns work.
In [7]:
estimator.fit(x=Xtrain, y=ytrain,
batch_size=BATCH_SIZE,
steps=NUM_STEPS)
# estimator.fit(input_fn=train_input_fn, steps=NUM_STEPS)
Out[7]:
In [8]:
results = estimator.evaluate(x=Xtest, y=ytest)
# results = estimator.evaluate(input_fn=test_input_fn)
print(results)
In [9]:
NUM_STEPS = 20
def experiment_fn(run_config, params):
feature_cols = [tf.contrib.layers.real_valued_column("",
dimension=NUM_FEATURES)]
estimator = tf.contrib.learn.Estimator(model_fn=model_fn,
model_dir=MODEL_DIR)
return tf.contrib.learn.Experiment(
estimator=estimator,
train_input_fn=train_input_fn,
train_steps=NUM_STEPS,
eval_input_fn=test_input_fn)
In [10]:
shutil.rmtree(MODEL_DIR, ignore_errors=True)
tf.contrib.learn.learn_runner.run(experiment_fn,
run_config=tf.contrib.learn.RunConfig(
model_dir=MODEL_DIR))
Out[10]:
In [ ]: