【持续更新】 TensorFlow命令笔记
- tf.constant
- tf.Session和tf.global_variables_initializer
- tf.Variable和tf.get_variable
- tf.variable_scope
- tf.flags
- tf.placeholder
- tf.train.GradientDescentOptimizer和tf.train.AdamOptimizer
- tf.nn.softmax_cross_entropy_with_logits
- tf.train.exponential_decay
- tf.contrib.layers.l1_regularizer和tf.contrib.layers.l2_regularizer
- tf.train.ExponentialMovingAverage
- tf.convert_to_tensor
- tf.GPUOptions和tf.ConfigProto
- tf.train.slice_input_producer、tf.train.batch和tf.train.shuffle_batch
- tf.read_file
- tf.image.decode_jpeg和tf.image.decode_png
- tf.image.convert_image_dtype
- tf.image.resize_images
- tf.image.random_flip_up_down和tf.image.flip_up_down
- tf.image.random_flip_left_right和tf.image.filp_left_right
- tf.image.transpose_image
- tf.image.random_brightness和tf.image.adjust_brightness
- tf.image.random_contrast和tf.image.adjust_contrast
- tf.argmax
- tf.trainable_variables
- tf.reduce_mean
- tf.train.Saver
- tf.nn.conv2d
- tf.nn.max_pool和tf.nn.avg_pool
- 卷积神经网络样例
- 关于tensorflow-slim
- tf.concat
- tf.expand_dims
- 结语
tf.constant
创建一个常数张量
tf.constant(value, dtype=None, shape=None, name=None, verity_shape=False)
//value可以是一个数值,也可以是一个列表,即这个常数张量的值
//dtype表示数据类型,一般是tf.float32、tf.float64或tf.int32、tf.int64
//shape表示张量形状
//verity_shape默认是False,如果为True会检查value和shape是否相符,不相符则报错
tf.Session和tf.global_variables_initializer
会话
- 方式一
sess = tf.Session()
sess.run(...)
sess.close()
- 方式二
with tf.Session() as sess:
sess.run(...)
- 关于tf.global_variables_initializer()
sess.run(tf.global_variables_initializer())
//初始化所有变量
仅仅是初始化变量
tf.Variable和tf.get_variable
- tf.Variable
设定一个初始化参数
tf.Variable(initializer, name)
//initializer是初始化参数
//name是这个参数的自定义名称
通过tf.Variable设定的初始化参数,需要在session中sess.run()才能使用
可以通过tf.global_variables_initializer()全部初始化
- tf.get_variable
获取一个已经存在的变量或者创建一个新的变量
tf.get_variable(name, shape, dtype, ininializer, trainable)
//ininializer:如果创建了则用它来初始化变量
//trainable:如果为True,还将变量添加到图形集合GraphKeys.TRAINABLE_VARIABLES
例子 1:
global_step = tf.get_variable("step", [], initializer=tf.constant_initializer(0.0), trainable=False)
例子2:
v = tf.Variable(tf.constant(1.0, shape=[1], name="v"))
v = tf.get_variable("v", shape=[1], initializer=tf.constant_initializer(1.0))
例子2中两个定义是等价的
tf.variable_scope
生成一个上下文管理器
with tf.variable_scope("foo"):
v = tf.get_variable("v", [1], initializer=tf.constant_initializer(1.0))
//在命名空间“foo”中,定义一个名字为“v”的变量
--------------------------------------------------------------------------------------------------------------------
with tf.variable_scope("foo"):
v = tf.get_variable("v", [1])
//因为命名空间中已经有“v”,所以上面命令报错
--------------------------------------------------------------------------------------------------------------------
with tf.variable_scope("foo", resue=True):
v1 = tf.get_variable("v", [1])
print v == v1
//上述命令打印“True”
//当“resue”参数设置为True时,tf.get_variable()不是创建变量,而是获取已有变量
--------------------------------------------------------------------------------------------------------------------
with tf.variable_scope("bar", resue=True):
v1 = tf.get_variable("v", [1])
//上面命令报错,因为在命名空间“bar”中不存在变量“v”
tf.variable_scope函数嵌套使用时,reuse的确定:
新建一个嵌套的上下文管理器但不指定reuse,这是reuse的取值会和外面一层保持一致
tf.flags
用于传递和解析命令行参数,相当于python的argparse
tf.flags.DEFINE_string("str_name", "str", "str_descrip")
//定义一个字符串类型的参数
//括号中第一个参数是定义的这个参数的名称,第二个是默认值,第三个是描述
tf.flags.DEFINE_boolean("bool_name", True or False, "bool_descrip")
//定义一个布尔类型的参数
tf.flags.DEFINE_integer("int_name", num, "int_descrip")
//定义一个整形类型的参数
FLAGS = tf.flags.FlAGS
//使定义的参数生效,并通过FLAGS使用
FLAGS.str_name
//值为"str"
FLAGS.bool_name
//值为True or False
FLAGS.int_name
//值为num
tf.placeholder
在神经网络构建graph时在模型中占位,分配必要的内存
tf.placeholder(dtype, shape, name)
//dtype是数据类型,常用tf.float32或tf.float64等
//shape是数据形状
//name是数据名称
tf.placeholder占位的变量,需要在sess.run()中使用一个名为feed_dict的字典赋初始值,否则会报错
tf.train.GradientDescentOptimizer和tf.train.AdamOptimizer
这是两种常用的优化算法
- tf.train.GradientDescentOptimizer
梯度下降算法
tf.train.GradientDescentOptimizer(learning_rate).minimize(cost_function, global_step=global_step)
//global_step是一个计数器,global_step自动更新为执行该命令的次数
列子:
global_step = tf.get_variable("step", [], initializer=tf.constant_initializer(0.0), trainable=False)
//初始化global_step为0
optimizer = tf.train.GradientDescentOpt.imizer(learning_rate=0.1).minimize(loss, global_step=global_step)
...
_, step = sess.run(optimizer, global_step)
//step是执行次数
该方法学习率恒定
- tf.train.AdamOptimizer
自适应学习率
beta1、beta2和epsilon是学习率变化相关参数,缺省值不一定最优,需要根据具体情况进行调整
tf.train.AdamOptimizer(learning_rate, beta1=0.9, beta2=0.999, epsilon=1e-08, use_locking=False, name='Adam' ).minimize(cost_function, global_step=global_step)
//global_step使用方法和上面相同
tf.nn.softmax_cross_entropy_with_logits
交叉熵损失函数,多接softmax使用
cross_entropy = tf.nn.softmax_cross_entropy_with_logits(y, y_)
//y是网络输出的结果,y_是真实标签
tf.nn.sparse_softmax_cross_entropy_with_logits
//进一步加速计算
交叉熵随时函数多用于分类问题
回归问题多使用均方误差(MSE)
mse = tf.reduce_mean(tf.square(y_ - y))
//MSE
tf.train.exponential_decay
指数衰减法改变学习率
learning_rate = tf.train.exponential_decay(base_learning_rate, global_step, decay_step, decay_rate, staircase = False)
//学习率计算公式:
learning_rate = base_learning_rate * decay_rate ^ (global_step / decay_step)
//staircase为True时,global_step / decay_step会被转化为整数
tf.contrib.layers.l1_regularizer和tf.contrib.layers.l2_regularizer
L1正则会让参数变得更稀疏
L1的公式不可导,L2的公式可导,优化带L1正则化的损失函数要更加复杂
tf.contrib.layers.l1_regularizer(lambda)(weights)
//lambda是正则化权重系数
//weights是参数
tf.contrib.layers.l2_regularizer(lambda)(weights)
当参数很多时,每组参数每组参数的加正则项很不方便,通过下面的代码简化
import tensorflow as tf
def get_weight(shape, lambda):
var = tf.Variable(tf.random_normal(shape), dtype = tf.float32)
tf.add_to_collection(
"losses", tf.contrib.layers.l2_regularizer(lambda)(var))
//参数正则的结果加入集合“losses”
return var
x = tf.placeholder(tf.float32, shape=(None, 2))
//输入特征占位 shape=None x 2
y_ = tf.placeholder(tf.float32, shape=(None, 1))
//label占位 shape=None x 1
batch_size = 8
layer_dimension = [2, 10, 10, 10, 1]
n_layers = len(layer_dimension)
cur_layer = x
in_dimension = layer_dimension[0]
for i in range(1, n_layers):
//从第二层起每一层循环
out_dimension = layer_dimension[i]
weight = get_weight([in_dimension, out_dimension], 0.001)
bias = tf.Variable(tf.constant(0.1, shape=[out_dimension]))
cur_layer = tf.nn.relu(tf.matmul(cur_layer, weight) + bias)
//完成一次正向传播
in_dimension = layer_dimension[i]
mse_loss = tf.reduce_mean(tf.square(y_ - cur_layer))
//损失函数
tf.add_to_collection("losses", mse_loss)
//损失函数加入集合losses“”
loss = tf.add_n(tf.get_collection("losses"))
//损失函数加所有参数的正则结果,得到最终的带正则化的损失函数
tf.train.ExponentialMovingAverage
神经网络在测试时给可训练参数使用滑动平均模型
意在让权重与历史权重有关联,使模型在测试数据上更加robust
训练的权重和测试的权重不相等,测试的权重是训练的权重滑动平均后的结果
import tensorflow as tf
v1 = tf.Variable(0, dtype=tf.float32)
step = tf.Variable(0, trainable=False)
ema = tf.train.ExponentialMovingAverage(0.99, step)
//decay为0.99
maintain_averages_op = ems.apply([v1])
//v1作为初始值
with tf.Session() as sess:
init_op = tf.global_variables_initializer
sess.run(init_op)
//初始化v1和step
print sess.run([v1, ema.average(v1)])
//输出[0.0, 0.0]
//v1初始化为0.0,影子变量初始为0.0
sess.run(tf.assign(v1, 5))
//将v1的值更新为5
sess.run(maintain_averages_op)
//v1初始化
print sess.run([v1, ema.average(v1)])
//输出[5.0, 4.5]
//v1初始化为5.0,影子变量为min{0.99, (1+step)/(10+step)}*0.0 + (1-min{0.99, (1+step)/(10+step)})*5.0 = 4.5
sess.run(tf.assign(step, 10000))
//step更新为10000
sess.run(tf.assign(v1, 10))
//v1更新为10
sess.run(maintain_averages_op)
//v1初始化
print sess.run([v1, ema.average(v1)])
//输出[10.0, 4.555]
sess.run(maintain_averages_op)
print sess.run([v1, ema.average(v1)])
//输出[10.0, 4.60945]
tf.convert_to_tensor
将不同的数据转化成张量
tf.convert_to_tensor(data, dtype)
//将data转化成张量,dtype是data的数据类型
//比如:tf.convert_to_tensor(str, dtype=tf.string) 将字符串类型的数据str转化为张量
tf.GPUOptions和tf.ConfigProto
限制GPU资源的使用
- 方法一
gpu_options=tf.GPUOptions(per_process_gpu_memory_fraction=0.7)
//设置GPU显存使用率为70%
config=tf.ConfigProto(gpu_options=gpu_options)
session = tf.Session(config=config)
- 方法二
config = tf.ConfigProto()
config.gpu_options.per_process_gpu_memory_fraction = 0.7
//设置GPU显存使用率为70%
session = tf.Session(config=config)
申请动态显存
- 方法一
gpu_options=tf.GPUOptions(allow_growth = True)
config=tf.ConfigProto(gpu_options=gpu_options)
session = tf.Session(config=config)
- 方法二
config = tf.ConfigProto()
config.gpu_options.allow_growth = True
session = tf.Session(config=config
tf.train.slice_input_producer、tf.train.batch和tf.train.shuffle_batch
tf.train.slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None)
//tensor_list是一个列表,两个元素,第一个是全部数据,第二个是顺序对应的全部标签,比如:[image, labels]
//num_epochs是训练epoch个数
//shuffle,布尔类型,设置是否随机打乱数据集
//seed,可选的整数,是生成随机数的种子,在第三个参数设置为shuffle=True的情况下才有用
//capacity,第一个参数中tensor列表的容量
//shared_name,如果设置一个‘shared_name’,则在不同的上下文环境(Session)中可以通过这个名字共享生成的tensor
//name,设置操作的名称
上面命令返回的就是这个tensor列表,tensor[0]就是数据,tensor[1]就是labels。[[tensor[0], tensor[1]]就作为下面这个命令的参数:tensors的输入(可以进行处理后在输入)
tf.train.batch(tensors, batch_size, num_threads=1, capacity=32, enqueue_many=False, shapes=None, dynamic_pad=False, allow_smaller_final_batch=False, shared_name=None, name=None)
//tensor,tensor序列或tensor字典,可以是含有单个样本的序列
//batch_size,设置batch size值
//num_threads,执行tensor入队操作的线程数量,可以设置使用多个线程同时并行执行,提高运行效率,但也不是数量越多越好
//capacity,定义生成的tensor序列的最大容量
//enqueue_many,定义第一个传入参数tensors是多个tensor组成的序列,还是单个tensor
//shapes,默认是推测出的传入的tensor的形状
//dynamic_pad,定义是否允许输入的tensors具有不同的形状,设置为True,会把输入的具有不同形状的tensor归一化到相同的形状
//allow_smaller_final_batch,设置为True,表示在tensor队列中剩下的tensor数量不够一个batch_size的情况下,允许最后一个batch的数量少于batch_size, 设置为False,则不管什么情况下,生成的batch都拥有batch_size个样本
tf.train.shuffle_batch和tf.train.batch的区别仅仅是前者会将数据集随机打乱
tf.read_file
读取图片
tf.read_file("路径,可以是tensor类型的列表")
//读取进来的图片需要根据后缀解码
tf.image.decode_jpeg和tf.image.decode_png
解码tf.read_file读取的图片
tf.image.decode_jpeg(image_value, channels)
//第一个参数是tf.read_file读取的图片,第二个参数是图片通道数
tf.image.decode_png(image_value, channels)
tf.image.convert_image_dtype
将image转换为dtype类型
tf.image.convert_image_dtype(image, dtype, saturate=False, name=None)
//image,是经过解码的图片
//dtype常用:tf.float32(0-1之间)
//saturate,默认为false,如果为True则在强制转换前裁剪输入
tf.image.resize_images
缩放图片
tf.image.resize_images(image, size, method, align_corners=False)
//image:0-255的图片或者转化为dtype类型的图片都可以
//size:2个元素(new_height, new_width)的1维int32张量,表示图像的新大小
//method:ResizeMethod,默认为ResizeMethod.BILINEAR(双线性插值)
//ResizeMethod.BILINEAR:双线性插值。也可以用method=0表示
//ResizeMethod.NEAREST_NEIGHBOR:最近的邻居插值。也可以用method=1表示
//ResizeMethod.BICUBIC:双三次插值。也可以用method=2表示
//ResizeMethod.AREA:区域插值。也可以用method=3表示
//align_corners:布尔型,如果为True,则输入和输出张量的4个拐角像素的中心对齐,并且保留角落像素处的值;默认为False
tf.image.random_flip_up_down和tf.image.flip_up_down
图像上下翻转
tf.image.random_flip_up_down(image, seed=None)
//0-255的图片或者转化为dtype类型的图片都可以
tf.image.file_up_down(image),不是随机的,就是单纯的翻转
tf.image.random_flip_left_right和tf.image.filp_left_right
图像左右翻转
tf.image.random_flip_left_right(image, seed=None)
//0-255的图片或者转化为dtype类型的图片都可以
tf.image.file_left_right(image),不是随机的,就是单纯的翻转
tf.image.transpose_image
通过交换高度和宽度维度来转置图像,也就是沿对角线翻转
tf.image.transpose_image(image)
//0-255的图片或者转化为dtype类型的图片都可以
tf.image.random_brightness和tf.image.adjust_brightness
通过随机因子调整图像亮度
tf.image.random_brightness(image, max_delta, seed=None)
//0-255的图片或者转化为dtype类型的图片都可以
//max_delta,这里必须是非负的,在-max_delta到max_delta中随机改变亮度
tf.image.adjust_brightness(image, delta),不是随机的,就是根据delta调整亮度
tf.image.random_contrast和tf.image.adjust_contrast
通过随机因子调整图像对比度
tf.image.random_contrast(image, lower, upper, seed=None)
//0-255的图片或者转化为dtype类型的图片都可以
//lower,浮点型,随机对比因子的下限
//upper,浮点型,随机对比因子的上限
tf.image.adjust_contrast(image, delta),不是随机的,就是根据delta调整对比度
tf.argmax
tf.argmax(x, 1)
//x是一个矩阵,返回一个向量,每个元素是矩阵对应行的最大值的索引值(0起始)
tf.trainable_variables
tf.trainable_variables()
//返回所有待训练的变量列表
tf.reduce_mean
用于计算张量沿指定轴的平均值
tf.reduce_mean(input_tensor, axis=None, keep_dims=False, name=None, reduction_indices=None)
//axis:指定的轴,如果不指定,则计算所有元素的均值
//keep_dims:是否降维度,设置为True,输出的结果保持输入tensor的形状,设置为False,输出结果会降低维度
tf.train.Saver
保存和还原一个神经网络模型
import tensorflow as tf
...
saver = tf.train.Saver()
with tf.Session() as sess:
...
saver.save(sess, "/path/to/model/model.ckpt")
TensorFlow模型将保存到/path/to/model/model.ckpt文件中。
/path/to/model路径下会保存三个文件:
- model.ckpt.meta 这个文件保存了TensorFlow计算图的结构,可以理解为神经网络的网络结构
- model.ckpt 这个文件保存了TensorFlow程序中每一个变量的取值
- checkpoint 这个文件保存了一个目录下所有的模型文件列表
import tensorflow as tf
...
saver = tf.train.Saver()
with tf.Session() as sess:
...
saver.restore(sess, "/path/to/model/model.ckpt")
加载保存后的模型
比如,可能有一个之前训练好的五层神经网络模型,但现在想尝试一个六层的神经网络,那么可以将前面五层神经网络中的参数直接加载到新的模型,而仅仅将最后一层神经网络重新训练
为了保存或者加载部分变量,在声明tf.train.Saver类时可以提供一个列表来指定需要保存或者加载的变量
//比如
saver = tf.train.Saver([v1])
//只有变量v1会被加载尽量
//注意要讲其他变量也初始化,否则将报错初始化错误
tf.nn.conv2d
卷积计算
卷积核虽然是3x3、5x5之类,但是一个卷积核用在一个多channel的张量上时,卷积核对应每个channel的值是不同的。比如一个5x5x5的张量,3x3的卷积核做卷积,卷积核实际维度是3x3x5,卷积核的5个channel的值各不相同。
对卷积的理解
从函数(或者说映射、变换)的角度理解。 卷积过程是在图像每个位置进行线性变换映射成新值的过程,将卷积核看成权重,若拉成向量记为w,图像对应位置的像素拉成向量记为x,则该位置卷积结果为y=w′x+b,即向量内积+偏置,将x变换为y。从这个角度看,多层卷积是在进行逐层映射,整体构成一个复杂函数,训练过程是在学习每个局部映射所需的权重,训练过程可以看成是函数拟合的过程。
从模版匹配的角度理解,认为卷积核定义了某种模式,卷积运算是在计算每个位置与该模式的相似程度,或者说每个位置具有该模式的分量有多少,当前位置与该模式越像,响应越强。
一个卷积核代表一种模式,缺乏泛化能力。通过多层卷积,来将简单模式组合成复杂模式,通过这种灵活的组合来保证具有足够的表达能力和泛化能力。
浅层layer学到的特征为简单的边缘、角点、纹理、几何形状、表面等,到深层layer学到的特征则更为复杂抽象,为狗、人脸、键盘等等。
卷积神经网络每层的卷积核权重是由数据驱动学习得来。
数据驱动卷积神经网络逐层学到由简单到复杂的特征,复杂模式是由简单模式组合而成。
以上参考自卷积神经网络之卷积计算、作用与思想
关于zero-padding
如果使用了zero-padding,输出的尺寸计算方式如下:
out-length = |in-length/stride-length|,即:输出长度等于输入程度除以步长,然后向上取整
如果不使用zero-padding,遵循:不足一次移动了就扔掉的原则
tensorflow相关命令
filter_weight = tf.get_variable("weights", [5, 5, 3, 16], initializer = tf.truncated_normal_initializer(stddev=0.1))
//5x5的卷积核,输入的深度为3,输出深度为16
biases = tf.get_variable("biases", [16], initializer = tf.constant_initializer(0.1))
//偏置
conv = tf.nn.conv2d(input, filter_weight, strides = [1, 1, 1, 1], padding="SAME")
//input是输入卷积核的张量, strides第一个元素和最后一个元素必须是1,分别对应batch维度的步长和输入深度维度的步长
//tensorflow中padding有两种选择,“SAME”是使用zero-padding,“VALID”是不使用zero-padding
bias = tf.nn.bias_add(conv, biases)
//
actived_conv = tf.nn.relu(bias)
//
tf.nn.max_pool和tf.nn.avg_pool
卷积层使用的滤波器是横跨整个深度的,池化层使用的滤波器只影响一个深度上的节点
pool = tf.nn.max_pool(actived_conv, ksize=[1, 3, 3, 1], strides=[1, 2, 2, 1], padding="SAME")
//tf.nn.max_pool是最大池化
//tf.nn.avg_pool是平均池化
卷积神经网络样例
import tensorflow as tf
INPUT_NODE = 784
//28x28的图片
OUTPUT_NODE = 10
//10类
IMAGE_SIZE = 28
//长宽都是28
NUM_CHANNELS = 1
//灰度图
MUM_LABELS = 10
//10类
CONV1_DEEP = 32
CONV1_SIZE = 5
//第一层卷积的输出深度和尺寸
CONV2_DEEP = 64
CONV2_SIZE = 5
//第二层卷积的输出深度和尺寸
FC_SIZE = 512
//全连接层的节点个数
//输入batch_size x 28 x 28 x 1
def inference(input_tensor, train, regularizer):
//参数train用来区分训练过程还是测试过程
with tf.variable_scope("layer1-conv1"):
conv1_weights = tf.get_variable("weight", [CONV1_SIZE, CONV1_SIZE, NUM_CHANNELS, CONV1_DEEP], initializer=tf.truncated_normal_initializer(stddev=0.1))
conv1_biases = tf.get_variable("bias", [CONV1_DEEP], initializer=tf.constant_initializer(0.0))
conv1 = tf.nn.conv2d(input_tensor, conv1_weights, strides=[1, 1, 1, 1], padding="SAME")
relu1 = tf.nn.relu(tf.nn.bias_add(conv1, conv1_biases))
//第一层卷积的输出batch x 28 x 28 x 32
with tf.name_scope("layer2-pool1"):
pool1 = tf.nn.max_pool(relu1, ksize = [1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
//第一层池化的输出batch x 14 x 14 32
with tf.variable_scope("layer3-conv2"):
conv2_weights = tf.get_variable("weight", [CONV2_SIZE, CONV2_SIZE, CONV1_DEEP, CONV2_DEEP], initializer=tf.truncated_normal_initializer(stddev=0.1))
conv2_biases = tf.get_variable("bias", [CONV2_DEEP], initializer=tf.constant_initializer(0.0))
conv2 = tf.nn.conv2d(input_tensor, conv2_weights, strides=[1, 1, 1, 1], padding="SAME")
relu2 = tf.nn.relu(tf.nn.bias_add(conv2, conv2_biases))
//低二层卷积的输出为batch x 14 x 14 x 64
with tf.name.scope("layer4-pool2"):
pool2 = tf.nn.max_pool(relu2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding="SAME")
//第二层池化的输出为batch x 7 x 7 x 64
pool_shape = pool2.get_shape().as_list()
//pool_shape是一个列表
//pool_shape[0]、[1]、[2]、[3]分别对应batch、7、7、64
nodes = pool_shape[1]*pool_shape[2]*pool_shape[3]
//nodes是batch中每一个图片的所有节点数
reshaped = tf.reshape(pool2, [pool_shape[0], nodes])
//把 batch x 7 x 7 x 64 转变为 batch x 3136
//每一行的内容是一个图片的所有节点
with tf.variable_scope("layer5-fc1"):
fc1_weight = tf.get_variable("weight", [nodes, FC_SIZE], initializer=tf.truncated_normal_initializer(stddev=0.1))
//nodes x FC_SIZE (3136 x 512)
//每一列是一个特征
//只有全连接层的权重需要加入正则化
if regularizer != None:
tf.add_to_collection("losses", regularizer(fc1_weights))
fc1_biases = tf.get_variable("bias", [FC_SIZE], initializer=tf.constant_initializer(0.1))
fc1 = tf.nn.relu(tf.matmul(reshaped, fc1_weight) + fc1_biases)
if train:
fc1 = tf.nn.dropout(fc1, 0.5)
//输出batch x 512,每一个行是batch中每个图片提取的512个特征
with tf.variable_scope("layer6-fc2"):
fc2_weight = tf.get_variable("weight", [FC_SIZE, NUM_LABELS], initializer=tf.trunacted_normal_initializer(stddev=0.1))
//FC_SIZE x NUM_LABELS (512 x 10)
//十列是十类,每一列都是对512个特征的不同组合方法
if regularizer != None:
tf.add_to_collection("losses", regularizer(fc2_weights))
fc2_biases = tf.get_variable("bias", [NUM_LABELS], initializer=tf.constant_initializer(0.1))
logit = tf.matmul(fc1, fc2_weights) + fc2_biases
//batch x 10 每一行是每个图片是10类中每一个的依次的置信度
return logit
关于tensorflow-slim
用tensorflow-slim实现inception-v3节选
with slim.arg_scope([slim.conv2d, slim.max_pool2d, slim.avg_pool2], stride=1, padding="SAME"):
//slim.arg_scope函数用于设置默认的参数取值
//如果使用了slim.conv2d,slim.max_pool2,slim.avg_pool2,如果不指定stride或padding,会默认为1或“SAME”;如果指定,则不使用默认值
net = 上一层的输出节点矩阵
with tf.varibale_scope("Mixed_7c"):
with tf.variable_scope("Branch_0"):
branch_0 = slim.conv2d(net, 320, [1, 1], scope="Conv2d_0a_1x1")
with tf.variable_scope("Branch_1"):
branch_1 = slim.conv2d(net, 384, [1, 1], scope="Conv2d_0a_1x1")
branch_1 = tf.concat(3, [slim.conv2d(branch_1, 384, [1, 3], scope="Conv2d_0b_1x3"), slim.conv2d(branch1, 384, [3, 1], scope="Conv2d_0c_3x1")])
//tf.concat第一个参数指定拼接的维度
with tf.variable_scope("Branch_2"):
branch2 = slim.conv2(net, 448, [1, 1], scope="Conv2d_0a_1x1")
branch2 = slim.conv2(branch2, 384, [3, 3], scope="Conv2d_0b_3x3")
branch2 = tf.concat(3, [slim.conv2d(branch2, 384, [1, 3], scope="Conv2d_0c_1x3"), slim.conv2d(branch2, 384, [3, 1], scope="Conv2d_0d_3x1")])
with tf.variable_scope("Branch_3"):
branch3 = slim.avg_pool2d(net, [3, 3], scope="AvgPool_0a_3x3")
branch3 = slim.conv2d(branch3, 192, [1, 1], scope="Conv2d_0b_1x1")
net = tf.concat(3, [branch_0, branch_1, branch_2, branch3])
tf.concat
tensorflow张量拼接
tf.concant([tensor1, tensor2], 指定维度)
//tensor1和tensor2维度需要一致
//指定维度为:0,1,2...
tf.expand_dims
tensorflow张量增加维度
tf.expand_dims(tensor, 指定维度)
//指定维度为0时,在最前面加一个维度
//指定维度为1时,在第一个维度后面加一个维度,以此类推
//指定维度为-1时,在最后加一个维度
结语
如果您有修改意见或问题,欢迎留言或者通过邮箱和我联系。
手打很辛苦,如果我的文章对您有帮助,转载请注明出处。