为何match_filenames_once返回局部变量?TensorFlow队列读图疑问
首先,你的错误根源很明确:tf.train.match_filenames_once会创建局部变量来缓存匹配到的文件名列表,但你只初始化了全局变量,导致局部变量未被初始化,队列里没有可读取的元素,最终抛出OutOfRangeError。
接下来逐个解答你的困惑:
1. 为什么match_filenames_once会返回局部变量?
tf.train.match_filenames_once的设计目标是仅在会话启动时执行一次文件路径匹配,并将结果缓存起来供后续使用——这样可以避免每次读取都重复扫描文件系统,提升效率。而局部变量(local variables)的特性正好契合这个需求:它们的生命周期与当前会话绑定,不需要被保存到检查点(checkpoint),适合存储这种一次性初始化、会话内复用的临时状态。所以这个函数内部会自动创建局部变量来存储匹配到的文件名列表,这是它的核心实现逻辑。
2. 是否始终如此?
是的,在整个TensorFlow 1.x版本(包括你使用的1.3.0)中,tf.train.match_filenames_once的实现都是依赖局部变量的,这是函数的固有设计,不会因为小版本更新而改变。
3. 能否控制这个行为?
你无法直接修改match_filenames_once使用局部变量的行为,但可以通过两种方式绕开这个限制:
方式一:显式初始化局部变量
在会话中同时初始化全局变量和局部变量,替换原来的tf.global_variables_initializer():
# 合并全局和局部变量初始化操作 tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()).run()
修改后的完整代码如下:
import tensorflow as tf filename_queue = tf.train.string_input_producer(tf.train.match_filenames_once('D:/Dataset/*.jpg')) image_reader = tf.WholeFileReader() image_name, image_file = image_reader.read(filename_queue) image = tf.image.decode_jpeg(image_file) with tf.Session() as sess: # 同时初始化全局和局部变量 tf.group(tf.global_variables_initializer(), tf.local_variables_initializer()).run() coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(coord=coord) image_tensor = sess.run([image]) print(image_tensor) # 停止线程并等待回收 coord.request_stop() coord.join(threads)
方式二:绕过match_filenames_once,提前获取文件名
在构建计算图之前,用tf.gfile.Glob直接获取文件名列表,再将其作为张量传入队列。这种方式不需要依赖局部变量,代码更直观:
import tensorflow as tf # 提前扫描文件系统,获取文件名列表 filenames = tf.gfile.Glob('D:/Dataset/*.jpg') filename_queue = tf.train.string_input_producer(filenames) image_reader = tf.WholeFileReader() image_name, image_file = image_reader.read(filename_queue) image = tf.image.decode_jpeg(image_file) with tf.Session() as sess: tf.global_variables_initializer().run() coord = tf.train.Coordinator() threads = tf.train.start_queue_runners(coord=coord) image_tensor = sess.run([image]) print(image_tensor) coord.request_stop() coord.join(threads)
另外补充一点:旧版本的tf.initialize_all_variables()其实会同时初始化全局和局部变量,但在TensorFlow 0.12之后,这个函数被拆分成了tf.global_variables_initializer()和tf.local_variables_initializer(),所以你用1.3.0时只调用全局初始化就会出问题。
内容的提问来源于stack exchange,提问作者Eypros

