Slim简介
TF-Slim 是 TensorFlow 中用来构建、训练、评估复杂模型的轻量级库,tf-slim 能够将你从复杂的原生tensorflow中解放出来。
TensorFlow 安装后 tf-slim会自动安装。
Slim模块的优点
Slim模块可以使模型的构建、训练、评估变得简单:
- 允许用户用紧凑的代码定义模型。这主要由arg_scope、layers和variables来实现。这些工具增加了代码的可读性和可维护性,减少了复制粘贴超参数值出错的可能性,并简化了超参数的调整。
- 通过提供常用的regularizer来简化模型的开发。很多常用的计算机视觉模型(例如VGG、AlexNet)在Slim里面已经有了实现。这些模型开箱可用,并且能够以多种方式进行扩展。
- Slim使得”复杂模型的扩展“ 以及 “从现有的模型ckpt开始训练” 变得容易。
使用Slim来构建模型
可以使用slim、variables、layers和scopes来十分简洁的定义定义模型。
Slim 定义变量(Variables)
在原生的tensorflow中创建Variables需要一个预定义的值或者一个初始化机制(例如,高斯分布随机采样)。更进一步,如果需要在一个指定的设备上创建一个variable,必须进行显式指定。为了减少创建variable需要的代码,slim模块在variable.py内提供了一系列的wrapper函数,从而使得变量的定义更加容易。
例如,要创建一个权重variable,用一个截断的正态分布初始化它,用l2_loss进行正则,并将他放到CPU上。只需要进行如下声明即可:
weight = slim.variable('weights',
shape=[10, 10, 3, 3],
initializer=tf.truncated_normal_initialzer(stddev=0.1),
regularizer=slim.l2_regularizer(0.05),
device='/CPU:0')
Slim定义 网络层(Layers)
slim定义网络层相当的方便,比tensorflow原生操作更加抽象,方便。
用conv层举例说明,通常一个卷积层的创建是由很多低级op组成的,比如:
- 创建权重variable和偏置值baises
- 对权重的输入进行卷积(输入来自前一层)
- 卷积结果加上偏置值
- 使用激活函数激活
原生的TensorFlow定义卷积层:
input = ...
with tf.name_scope('conv1_1') as scope:
kernel = tf.Variable(tf.truncated_normal([3, 3, 64, 128], dtype=tf.float32, stddev=1e-1), name='weights') # 定义卷积核
conv = tf.nn.conv2d(input, kernel, [1, 1, 1, 1], padding='SAME')
biases = tf.Variable(tf.constant(0.0, shape=[128], dtype=tf.float32), trainable=True, anme='biases')
conv1 = tf.nn.relu(bias, name=scope)
如果使用slim来定义就简单很多了,只有一行代码:
input = ...
net = slim.conv2d(input, 128, [3, 3], scope='conv1_1')
经上面比较发现slim构建网络的层相当的简介,这时候可能会有读者会问用slim好像少了一个必要参数。
定义卷积核时 [filter_height, filter_width, in_channels, out_channels] ,分别代表卷积核的高/宽/输入通道数/输出通道数,slim少了一个in_channels(输入通道数)。这个不必担心,in_channels(输入通道数),Slim从input中自动提取了,同样的定义全连接层时也不需要在slim方法中指定上一层的节点数。
input = ...
net = slim.fully_connected(inputs, 32, scope='fc1') # 只需要指定自己的节点数
关于Slim定义层的内容这里就讲这么多,slim关于层的定义和使用还有很多更加灵活的方式,后续会继续补充!接下来进行用slim进行网络训练实战。
使用Slim创建一个神经网络
以一个简单的多层感知机解决回归问题为例。
该模型只有两个隐藏层,模型输出层只有一个节点。
此外,示例还展示了在第一个全连接层FC1后如何添加Dropout层。
在测试阶段,不需要要Dropout节点,而是采用平均激活,因此需要知道该模型是处于training或tesing阶段,因为在两种情况下的计算图是不同的。
先训练并保存模型
import numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slim
import matplotlib.pyplot as plt
# 随机生成1d的回归数据
def produce_batch(batch_size, noise=0.3):
xs = np.random.random(size=[batch_size, 1]) * 10
ys = np.sin(xs) + 5 + np.random.normal(size=[batch_size, 1], scale=noise)
return [xs.astype(np.float32), ys.astype(np.float32)]
# 生成训练和测试数据集
x_train, y_train = produce_batch(200)
x_test, y_test = produce_batch(200)
# plt.scatter(x_test, y_test, c='r')
# plt.show()
# 用slim定义的前向传播
def regression_model(inputs, is_training=True, scope='deep_regression'):
with tf.variable_scope(scope, 'deep_regression', [inputs]):
end_points = {}
with slim.arg_scope([slim.fully_connected], activation_fn = tf.nn.relu, weights_regularizer=slim.l2_regularizer(0.001)):
net = slim.fully_connected(inputs, 32, scope='fc1')
end_points['fc1'] = net
net = slim.dropout(net, 0.8, is_training=is_training)
net = slim.fully_connected(net, 16, scope='fc2')
end_points['fc2'] = net
predictions = slim.fully_connected(net, 1, activation_fn=None, scope='prediction')
end_points['out'] = predictions
return predictions, end_points
# 将数据转化为tensor
def convert_data_to_tensors(x, y):
inputs = tf.constant(x)
inputs.set_shape([None, 1])
outputs = tf.constant(y)
outputs.set_shape([None, 1])
return inputs, outputs
# 训练网络,并将训练模型保存到指定文件夹内
ckpt_dir = '/home/hxy/husin/Test/Slim/'
with tf.Graph().as_default():
tf.logging.set_verbosity(tf.logging.INFO) # 日志信息
inputs, targets = convert_data_to_tensors(x_train, y_train)
predictions, nodes = regression_model(inputs, is_training=True)
loss = tf.losses.mean_squared_error(labels=targets, predictions=predictions)
total_loss = slim.losses.get_total_loss() # 正则化的loss
optimizer = tf.train.AdamOptimizer(learning_rate=0.005)
train_op = slim.learning.create_train_op(total_loss, optimizer)
final_loss = slim.learning.train(train_op,
logdir=ckpt_dir, # 模型保存位置
number_of_steps=5000, # 迭代次数
save_interval_secs=5, # 每5秒保存一次模型
log_every_n_steps=500) # 损失函数和step打印的频率
print final_loss
print ckpt_dir
运行结果:
接下来验证模型:
import numpy as np
import tensorflow as tf
import tensorflow.contrib.slim as slim
import matplotlib.pyplot as plt
# 随机生成1d的回归数据
def produce_batch(batch_size, noise=0.3):
xs = np.random.random(size=[batch_size, 1]) * 10
ys = np.sin(xs) + 5 + np.random.normal(size=[batch_size, 1], scale=noise)
return [xs.astype(np.float32), ys.astype(np.float32)]
# 生成训练和测试数据集
x_train, y_train = produce_batch(200)
x_test, y_test = produce_batch(200)
# plt.scatter(x_test, y_test, c='r')
# plt.show()
# 用slim定义的前向传播
def regression_model(inputs, is_training=True, scope='deep_regression'):
with tf.variable_scope(scope, 'deep_regression', [inputs]):
end_points = {}
with slim.arg_scope([slim.fully_connected], activation_fn = tf.nn.relu, weights_regularizer=slim.l2_regularizer(0.001)):
net = slim.fully_connected(inputs, 32, scope='fc1')
end_points['fc1'] = net
net = slim.dropout(net, 0.8, is_training=is_training)
net = slim.fully_connected(net, 16, scope='fc2')
end_points['fc2'] = net
predictions = slim.fully_connected(net, 1, activation_fn=None, scope='prediction')
end_points['out'] = predictions
return predictions, end_points
# 将数据转化为tensor
def convert_data_to_tensors(x, y):
inputs = tf.constant(x)
inputs.set_shape([None, 1])
outputs = tf.constant(y)
outputs.set_shape([None, 1])
return inputs, outputs
# 进行模型验证
ckpt_dir = '/home/hxy/husin/Test/Slim/'
with tf.Graph().as_default():
inputs, targets = convert_data_to_tensors(x_test, y_test)
predictions, end_point = regression_model(inputs, is_training=False)
# 创建会话,从checkpoint文件恢复参数
sv = tf.train.Supervisor(logdir=ckpt_dir)
with sv.managed_session() as sess:
inputs, predictions, targets = sess.run([inputs, predictions, targets])
plt.scatter(inputs, targets, c='r')
plt.scatter(inputs, predictions, c='b')
plt.title('red=true, blue=predicted')
plt.show()
验证结果: