这次的看点是怎么在TensorFlow里实现正则化、dropout和学习率递减的技巧;顺便演示了下自动调参。

任务 3: 正则化
使用正则化去优化深度学习模型
题目1
给上次练习实现的逻辑斯谛回归和神经网络加上L2正则,检查性能提升。
逻辑斯谛回归
对于beta这个超参数的取值,用一段自动调参的脚本在一个区间内遍历搜索:
beta_val = np.logspace(-4, -2, 20)
accuracy_val = []
# logistic model
batch_size = 128
graph = tf.Graph()
with graph.as_default():
# Input data. For the training data, we use a placeholder that will be fed
# at run time with a training minibatch.
tf_train_dataset = tf.placeholder(tf.float32,
shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
beta_regul = tf.placeholder(tf.float32)
# Variables.
weights = tf.Variable(tf.truncated_normal([image_size * image_size, num_labels]))
biases = tf.Variable(tf.zeros([num_labels]))
# Training computation.
logits = tf.matmul(tf_train_dataset, weights) + biases
loss = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels)) + beta_regul * tf.nn.l2_loss(weights)
# Optimizer.
optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
# Predictions for the training, validation, and test data.
train_prediction = tf.nn.softmax(logits)
valid_prediction = tf.nn.softmax(tf.matmul(tf_valid_dataset, weights) + biases)
test_prediction = tf.nn.softmax(tf.matmul(tf_test_dataset, weights) + biases)
num_steps = 3001
for beta in beta_val:
with tf.Session(graph=graph) as session:
tf.initialize_all_variables().run()
for step in range(num_steps):
# Pick an offset within the training data, which has been randomized.
# Note: we could use better randomization across epochs.
offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
# Generate a minibatch.
batch_data = train_dataset[offset:(offset + batch_size), :]
batch_labels = train_labels[offset:(offset + batch_size), :]
# Prepare a dictionary telling the session where to feed the minibatch.
# The key of the dictionary is the placeholder node of the graph to be fed,
# and the value is the numpy array to feed to it.
feed_dict = {tf_train_dataset: batch_data, tf_train_labels: batch_labels, beta_regul: beta}
_, l, predictions = session.run([optimizer, loss, train_prediction], feed_dict=feed_dict)
# if (step % 500 == 0):
# print("Minibatch loss at step %d: %f" % (step, l))
# print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
# print("Validation accuracy: %.1f%%" % accuracy(valid_prediction.eval(), valid_labels))
print("L2 regularization(beta=%.5f) Test accuracy: %.1f%%" % (
beta, accuracy(test_prediction.eval(), test_labels)))
accuracy_val.append(accuracy(test_prediction.eval(), test_labels))
print('Best beta=%f, accuracy=%.1f%%' % (beta_val[np.argmax(accuracy_val)], max(accuracy_val)))
plt.semilogx(beta_val, accuracy_val)
plt.grid(True)
plt.title('Test accuracy by regularization (logistic)')
plt.show()
输出
L2 regularization(beta=0.00010) Test accuracy: 86.8% L2 regularization(beta=0.00013) Test accuracy: 87.0% L2 regularization(beta=0.00016) Test accuracy: 87.2% L2 regularization(beta=0.00021) Test accuracy: 87.2% L2 regularization(beta=0.00026) Test accuracy: 87.7% L2 regularization(beta=0.00034) Test accuracy: 87.7% L2 regularization(beta=0.00043) Test accuracy: 87.9% L2 regularization(beta=0.00055) Test accuracy: 88.2% L2 regularization(beta=0.00070) Test accuracy: 88.7% L2 regularization(beta=0.00089) Test accuracy: 88.7% L2 regularization(beta=0.00113) Test accuracy: 89.1% L2 regularization(beta=0.00144) Test accuracy: 89.1% L2 regularization(beta=0.00183) Test accuracy: 89.0% L2 regularization(beta=0.00234) Test accuracy: 89.1% L2 regularization(beta=0.00298) Test accuracy: 89.1% L2 regularization(beta=0.00379) Test accuracy: 89.0% L2 regularization(beta=0.00483) Test accuracy: 89.0% L2 regularization(beta=0.00616) Test accuracy: 88.9% L2 regularization(beta=0.00785) Test accuracy: 88.7% L2 regularization(beta=0.01000) Test accuracy: 88.6% Best beta=0.001129, accuracy=89.1%
可视化

神经网络模型
用类似的手法
# NN model
batch_size = 128
hidden_size = 1024
graph = tf.Graph()
with graph.as_default():
# Input data. For the training data, we use a placeholder that will be fed
# at run time with a training minibatch.
tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
tf_beta = tf.placeholder(tf.float32)
# Variables.
W1 = tf.Variable(tf.truncated_normal([image_size * image_size, hidden_size]))
b1 = tf.Variable(tf.zeros([hidden_size]))
W2 = tf.Variable(tf.truncated_normal([hidden_size, num_labels]))
b2 = tf.Variable(tf.zeros([num_labels]))
# Training computation.
y1 = tf.nn.relu(tf.matmul(tf_train_dataset, W1) + b1)
logits = tf.matmul(y1, W2) + b2
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels))
loss = loss + tf_beta * (tf.nn.l2_loss(W1) + tf.nn.l2_loss(b1) + tf.nn.l2_loss(W2) + tf.nn.l2_loss(b2))
# Optimizer.
optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
# Predictions for the training, validation, and test data.
train_prediction = tf.nn.softmax(logits)
y1_valid = tf.nn.relu(tf.matmul(tf_valid_dataset, W1) + b1)
valid_logits = tf.matmul(y1_valid, W2) + b2
valid_prediction = tf.nn.softmax(valid_logits)
y1_test = tf.nn.relu(tf.matmul(tf_test_dataset, W1) + b1)
test_logits = tf.matmul(y1_test, W2) + b2
test_prediction = tf.nn.softmax(test_logits)
# Let's run it:
num_steps = 3001
accuracy_val.clear()
for beta in np.logspace(-4, -2, 20):
with tf.Session(graph=graph) as session:
tf.initialize_all_variables().run()
# print("Initialized")
for step in range(num_steps):
# Pick an offset within the training data, which has been randomized.
# Note: we could use better randomization across epochs.
offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
# Generate a minibatch.
batch_data = train_dataset[offset:(offset + batch_size), :]
batch_labels = train_labels[offset:(offset + batch_size), :]
# Prepare a dictionary telling the session where to feed the minibatch.
# The key of the dictionary is the placeholder node of the graph to be fed,
# and the value is the numpy array to feed to it.
feed_dict = {tf_train_dataset: batch_data, tf_train_labels: batch_labels, tf_beta: beta}
_, l, predictions = session.run([optimizer, loss, train_prediction], feed_dict=feed_dict)
# if (step % 500 == 0):
# print("Minibatch loss at step %d: %f" % (step, l))
# print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
# print("Validation accuracy: %.1f%%" % accuracy(valid_prediction.eval(), valid_labels))
print("L2 regularization(beta=%.5f) Test accuracy: %.1f%%" % (
beta, accuracy(test_prediction.eval(), test_labels)))
accuracy_val.append(accuracy(test_prediction.eval(), test_labels))
print('Best beta=%f, accuracy=%.1f%%' % (beta_val[np.argmax(accuracy_val)], max(accuracy_val)))
plt.semilogx(beta_val, accuracy_val)
plt.grid(True)
plt.title('Test accuracy by regularization (1-layer net)')
plt.show()
输出
L2 regularization(beta=0.00010) Test accuracy: 89.7% L2 regularization(beta=0.00013) Test accuracy: 89.8% L2 regularization(beta=0.00016) Test accuracy: 90.5% L2 regularization(beta=0.00021) Test accuracy: 90.2% L2 regularization(beta=0.00026) Test accuracy: 90.5% L2 regularization(beta=0.00034) Test accuracy: 90.2% L2 regularization(beta=0.00043) Test accuracy: 91.1% L2 regularization(beta=0.00055) Test accuracy: 91.4% L2 regularization(beta=0.00070) Test accuracy: 92.1% L2 regularization(beta=0.00089) Test accuracy: 92.8% L2 regularization(beta=0.00113) Test accuracy: 93.4% L2 regularization(beta=0.00144) Test accuracy: 93.7% L2 regularization(beta=0.00183) Test accuracy: 93.0% L2 regularization(beta=0.00234) Test accuracy: 92.9% L2 regularization(beta=0.00298) Test accuracy: 92.4% L2 regularization(beta=0.00379) Test accuracy: 91.9% L2 regularization(beta=0.00483) Test accuracy: 91.4% L2 regularization(beta=0.00616) Test accuracy: 91.0% L2 regularization(beta=0.00785) Test accuracy: 90.8% L2 regularization(beta=0.01000) Test accuracy: 90.3% Best beta=0.001438, accuracy=93.7%
最佳beta是0.001438,我们可以将这个值用于接下来的试验。
可视化

事实上,上面只是追求test分数好看而已,应该在开发集上选择参数。《CS229编程5:正则化线性回归与偏差方差权衡》才是正确做法。
题目2:过拟合
将训练集减小到batch数目的几倍,看看会发生什么。
few_batch_size = batch_size * 5
small_train_dataset = train_dataset[:few_batch_size, :]
small_train_labels = train_labels[:few_batch_size, :]
print('Training set', small_train_dataset.shape, small_train_labels.shape)
num_steps = 3001
with tf.Session(graph=graph) as session:
tf.initialize_all_variables().run()
print("Initialized")
for step in range(num_steps):
# Pick an offset within the training data, which has been randomized.
# Note: we could use better randomization across epochs.
offset = (step * batch_size) % (small_train_labels.shape[0] - batch_size)
# Generate a minibatch.
batch_data = small_train_dataset[offset:(offset + batch_size), :]
batch_labels = small_train_labels[offset:(offset + batch_size), :]
# Prepare a dictionary telling the session where to feed the minibatch.
# The key of the dictionary is the placeholder node of the graph to be fed,
# and the value is the numpy array to feed to it.
feed_dict = {tf_train_dataset: batch_data, tf_train_labels: batch_labels, tf_beta: 0.001438}
_, l, predictions = session.run(
[optimizer, loss, train_prediction], feed_dict=feed_dict)
if (step % 500 == 0):
print("Minibatch loss at step %d: %f" % (step, l))
print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
print("Validation accuracy: %.1f%%" % accuracy(
valid_prediction.eval(), valid_labels))
print("Overfitting with small dataset Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))
输出
Training set (640, 784) (640, 10) Overfitting with small dataset Test accuracy: 84.5%
跌了很多,当然的。
题目3:Dropout
引入Dropout技巧,看看性能提升,以及能否改善上面的过拟合。
改善性能
batch_size = 128
hidden_size = 1024
graph = tf.Graph()
with graph.as_default():
# Input data. For the training data, we use a placeholder that will be fed
# at run time with a training minibatch.
tf_train_dataset = tf.placeholder(tf.float32, shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
tf_beta = tf.placeholder(tf.float32)
# Variables.
W1 = tf.Variable(tf.truncated_normal([image_size * image_size, hidden_size]))
b1 = tf.Variable(tf.zeros([hidden_size]))
W2 = tf.Variable(tf.truncated_normal([hidden_size, num_labels]))
b2 = tf.Variable(tf.zeros([num_labels]))
# Training computation.
y1 = tf.nn.relu(tf.matmul(tf_train_dataset, W1) + b1)
y1 = tf.nn.dropout(y1, 0.5) # Dropout
logits = tf.matmul(y1, W2) + b2
loss = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels))
loss = loss + tf_beta * (tf.nn.l2_loss(W1) + tf.nn.l2_loss(b1) + tf.nn.l2_loss(W2) + tf.nn.l2_loss(b2))
# Optimizer.
optimizer = tf.train.GradientDescentOptimizer(0.5).minimize(loss)
# Predictions for the training, validation, and test data.
train_prediction = tf.nn.softmax(logits)
y1_valid = tf.nn.relu(tf.matmul(tf_valid_dataset, W1) + b1)
valid_logits = tf.matmul(y1_valid, W2) + b2
valid_prediction = tf.nn.softmax(valid_logits)
y1_test = tf.nn.relu(tf.matmul(tf_test_dataset, W1) + b1)
test_logits = tf.matmul(y1_test, W2) + b2
test_prediction = tf.nn.softmax(test_logits)
# Let's run it:
num_steps = 3001
with tf.Session(graph=graph) as session:
tf.initialize_all_variables().run()
print("Initialized")
for step in range(num_steps):
# Pick an offset within the training data, which has been randomized.
# Note: we could use better randomization across epochs.
offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
# Generate a minibatch.
batch_data = train_dataset[offset:(offset + batch_size), :]
batch_labels = train_labels[offset:(offset + batch_size), :]
# Prepare a dictionary telling the session where to feed the minibatch.
# The key of the dictionary is the placeholder node of the graph to be fed,
# and the value is the numpy array to feed to it.
feed_dict = {tf_train_dataset: batch_data, tf_train_labels: batch_labels, tf_beta: 0.001438}
_, l, predictions = session.run([optimizer, loss, train_prediction], feed_dict=feed_dict)
if (step % 500 == 0):
print("Minibatch loss at step %d: %f" % (step, l))
print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
print("Validation accuracy: %.1f%%" % accuracy(
valid_prediction.eval(), valid_labels))
print("Dropout Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))
唯一的改动是调用了一次dropout:
y1 = tf.nn.dropout(y1, 0.5) # Dropout

该方法会自动缩放倍数,所以不用操心:
With probability keep_prob, outputs the input element scaled up by 1 / keep_prob, otherwise outputs 0. The scaling is so that the expected sum is unchanged.
输出
Dropout Test accuracy: 92.3%
改善过拟合
Dropout with small dataset Test accuracy: 86.1%
的确有所回升。
题目4:深度神经网络
上面1-layer(指的是隐藏层)神经网络并不稀奇,Python版的matlab版的Java版的满大街都是,并不能发挥TF的全力,试试multi-layer如何?还可以尝试学习率递减的策略。
那就不客气了,来个3-layer,迭代数目也4倍:
batch_size = 128
fc1_size = 4096
fc2_size = 2048
fc3_size = 128
graph = tf.Graph()
with graph.as_default():
# Input data. For the training data, we use a placeholder that will be fed
# at run time with a training minibatch.
tf_train_dataset = tf.placeholder(tf.float32,
shape=(batch_size, image_size * image_size))
tf_train_labels = tf.placeholder(tf.float32, shape=(batch_size, num_labels))
tf_valid_dataset = tf.constant(valid_dataset)
tf_test_dataset = tf.constant(test_dataset)
tf_beta = tf.placeholder(tf.float32)
global_step = tf.Variable(0) # count the number of steps taken.
# Variables.
# stddev is very important!!!
W1 = tf.Variable(
tf.truncated_normal([image_size * image_size, fc1_size], stddev=np.sqrt(2.0 / (image_size * image_size))))
b1 = tf.Variable(tf.zeros([fc1_size]))
W2 = tf.Variable(tf.truncated_normal([fc1_size, fc2_size], stddev=np.sqrt(2.0 / fc1_size)))
b2 = tf.Variable(tf.zeros([fc2_size]))
W3 = tf.Variable(tf.truncated_normal([fc2_size, fc3_size], stddev=np.sqrt(2.0 / fc2_size)))
b3 = tf.Variable(tf.zeros([fc3_size]))
W4 = tf.Variable(tf.truncated_normal([fc3_size, num_labels], stddev=np.sqrt(2.0 / fc3_size)))
b4 = tf.Variable(tf.zeros([num_labels]))
# Training computation.
y1 = tf.nn.relu(tf.matmul(tf_train_dataset, W1) + b1)
# y1 = tf.nn.dropout(y1, 0.5)
y2 = tf.nn.relu(tf.matmul(y1, W2) + b2)
# y2 = tf.nn.dropout(y2, 0.5)
y3 = tf.nn.relu(tf.matmul(y2, W3) + b3)
# y3 = tf.nn.dropout(y3, 0.5)
logits = tf.matmul(y3, W4) + b4
loss = tf.reduce_mean(
tf.nn.softmax_cross_entropy_with_logits(logits, tf_train_labels))
loss = loss + tf_beta * (tf.nn.l2_loss(W1) + tf.nn.l2_loss(b1) + tf.nn.l2_loss(W2) + tf.nn.l2_loss(b2) +
tf.nn.l2_loss(W3) + tf.nn.l2_loss(b3) + tf.nn.l2_loss(W4) + tf.nn.l2_loss(b4))
# Optimizer
learning_rate = tf.train.exponential_decay(0.5, global_step, 1000, 0.7, staircase=True)
optimizer = tf.train.GradientDescentOptimizer(learning_rate).minimize(loss, global_step=global_step)
# Predictions for the training, validation, and test data.
train_prediction = tf.nn.softmax(logits)
y1_valid = tf.nn.relu(tf.matmul(tf_valid_dataset, W1) + b1)
y2_valid = tf.nn.relu(tf.matmul(y1_valid, W2) + b2)
y3_valid = tf.nn.relu(tf.matmul(y2_valid, W3) + b3)
valid_logits = tf.matmul(y3_valid, W4) + b4
valid_prediction = tf.nn.softmax(valid_logits)
y1_test = tf.nn.relu(tf.matmul(tf_test_dataset, W1) + b1)
y2_test = tf.nn.relu(tf.matmul(y1_test, W2) + b2)
y3_test = tf.nn.relu(tf.matmul(y2_test, W3) + b3)
test_logits = tf.matmul(y3_test, W4) + b4
test_prediction = tf.nn.softmax(test_logits)
# Let's run it:
num_steps = 12001
with tf.Session(graph=graph) as session:
tf.initialize_all_variables().run()
print("Initialized")
for step in range(num_steps):
# Pick an offset within the training data, which has been randomized.
# Note: we could use better randomization across epochs.
offset = (step * batch_size) % (train_labels.shape[0] - batch_size)
# Generate a minibatch.
batch_data = train_dataset[offset:(offset + batch_size), :]
batch_labels = train_labels[offset:(offset + batch_size), :]
# Prepare a dictionary telling the session where to feed the minibatch.
# The key of the dictionary is the placeholder node of the graph to be fed,
# and the value is the numpy array to feed to it.
feed_dict = {tf_train_dataset: batch_data, tf_train_labels: batch_labels, tf_beta: 0.001438}
_, l, predictions = session.run([optimizer, loss, train_prediction], feed_dict=feed_dict)
if (step % 500 == 0):
print("Minibatch loss at step %d: %f" % (step, l))
print("Minibatch accuracy: %.1f%%" % accuracy(predictions, batch_labels))
print("Validation accuracy: %.1f%%" % accuracy(
valid_prediction.eval(), valid_labels))
print("Final Test accuracy: %.1f%%" % accuracy(test_prediction.eval(), test_labels))
这里是学习率指数递减decay_rate ^ (global_step / decay_steps):
learning_rate = tf.train.exponential_decay(0.5, global_step, 1000, 0.7, staircase=True)
MBP烧开两壶水之后输出:
Final Test accuracy: 96.0%
听说最高有97的,那一定是N卡土豪玩家。
Reference
https://github.com/Arn-O/udacity-deep-learning
https://github.com/runhani/udacity-deep-learning
码农场