Tensorflow模型加载后预测结果不随输入图像变化问题求助
TensorFlow图像分类器预测概率不随输入图像变化的问题
我是TensorFlow的新手,最近在搭建一个基于Fashion MNIST的图像分类器,但遇到了一个非常棘手的问题——不管我更换哪张输入图像,通过sess.run()得到的预测概率都完全没有变化。
我已经完成了模型的搭建和训练流程,以下是加载预训练模型并执行预测的核心代码:
def predict(): train = data.train tf.reset_default_graph() with tf.Session() as sess: new_saver = tf.train.import_meta_graph('~/trained-model.ckpt.meta') new_saver.restore(sess, '~/trained-model.ckpt') print(tf.get_default_graph().get_name_scope()) # 注释:这里应该包含最后一层的softmax输出 y_pred = tf.get_default_graph().get_tensor_by_name('y_pred:0') X = tf.get_default_graph().get_tensor_by_name('X:0') final = imageprepare('tshirts.png') final = np.asarray(final) final = np.reshape(final,[784,1]) output_label = sess.run(y_pred, feed_dict={X: final}) print(output_label)
我尝试替换不同的输入图像(比如换成裤子、鞋子类别的图片),但output_label的结果始终保持一致,完全没有变化。
完整实现代码
import tensorflow as tf import numpy as np from tensorflow.examples.tutorials.mnist import input_data from PIL import Image, ImageFilter data = input_data.read_data_sets('data/fashion', source_url='http://fashion-mnist.s3-website.eu-central-1.amazonaws.com/') # 训练参数 learning_rate = 0.001 num_steps = 500 batch_size = 128 display_step = 10 # 网络参数 num_input = 784 # Fashion MNIST输入维度(28*28像素) num_classes = 10 # 分类类别数(0-9对应不同服饰) dropout = 0.75 # Dropout保留概率 # TF图输入 X = tf.placeholder(tf.float32, [None, num_input], name='X') Y = tf.placeholder(tf.float32, [None, num_classes], name='Y') keep_prob = tf.placeholder(tf.float32, name='keep_prob') # Dropout参数 # 卷积层封装 def conv2d(x, W, b, strides=1): x = tf.nn.conv2d(x, W, strides=[1, strides, strides, 1], padding='SAME') x = tf.nn.bias_add(x, b) return tf.nn.relu(x) # 池化层封装 def maxpool2d(x, k=2): return tf.nn.max_pool(x, ksize=[1, k, k, 1], strides=[1, k, k, 1], padding='SAME') # 构建卷积神经网络 def conv_net(x, weights, biases, dropout): # 将输入reshape为4D张量:[批量大小, 高度, 宽度, 通道数] x = tf.reshape(x, shape=[-1, 28, 28, 1]) # 第一层卷积+池化 conv1 = conv2d(x, weights['wc1'], biases['bc1']) conv1 = maxpool2d(conv1, k=2) # 第二层卷积+池化 conv2 = conv2d(conv1, weights['wc2'], biases['bc2']) conv2 = maxpool2d(conv2, k=2) # 全连接层 fc1 = tf.reshape(conv2, [-1, weights['wd1'].get_shape().as_list()[0]]) fc1 = tf.add(tf.matmul(fc1, weights['wd1']), biases['bd1']) fc1 = tf.nn.relu(fc1) # 应用Dropout fc1 = tf.nn.dropout(fc1, dropout) # 输出层 out = tf.add(tf.matmul(fc1, weights['out']), biases['out']) return out # 定义网络权重和偏置 weights = { 'wc1': tf.Variable(tf.random_normal([5, 5, 1, 32])), 'wc2': tf.Variable(tf.random_normal([5, 5, 32, 64])), 'wd1': tf.Variable(tf.random_normal([7*7*64, 1024])), 'out': tf.Variable(tf.random_normal([1024, num_classes])) } biases = { 'bc1': tf.Variable(tf.random_normal([32])), 'bc2': tf.Variable(tf.random_normal([64])), 'bd1': tf.Variable(tf.random_normal([1024])), 'out': tf.Variable(tf.random_normal([10])) } # 构建模型 logits = conv_net(X, weights, biases, keep_prob) prediction = tf.nn.softmax(logits, name='y_pred') # 定义损失函数和优化器 loss_op = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits(logits=logits, labels=Y)) optimizer = tf.train.AdamOptimizer(learning_rate=learning_rate) train_op = optimizer.minimize(loss_op) # 模型评估 correct_pred = tf.equal(tf.argmax(prediction, 1), tf.argmax(Y, 1)) accuracy = tf.reduce_mean(tf.cast(correct_pred, tf.float32)) # 初始化变量 init = tf.global_variables_initializer() # 开始训练 with tf.Session() as sess: sess.run(init) for step in range(1, num_steps+1): batch_x, batch_y = data.train.next_batch(batch_size) sess.run(train_op, feed_dict={X: batch_x, Y: batch_y, keep_prob: dropout}) if step % display_step == 0 or step == 1: loss, acc = sess.run([loss_op, accuracy], feed_dict={X: batch_x, Y: batch_y, keep_prob: 1.0}) print(f"Step {step}, Minibatch Loss= {loss:.4f}, Training Accuracy= {acc:.3f}") print("Optimization Finished!") # 测试集评估 print("Testing Accuracy:", sess.run(accuracy, feed_dict={X: data.test.images[:256], Y: data.test.labels[:256], keep_prob: 1.0})) # 保存模型 saver = tf.train.Saver() saver.save(sess, '~/trained-model.ckpt') # 图像预处理函数 def imageprepare(argv): im = Image.open(argv).convert('L') width = float(im.size[0]) height = float(im.size[1]) newImage = Image.new('L', (28, 28), (255)) # 创建28x28的白色画布 if width > height: nheight = int(round((20.0/width*height),0)) if nheight == 0: nheight = 1 img = im.resize((20,nheight), Image.ANTIALIAS).filter(ImageFilter.SHARPEN) wtop = int(round(((28 - nheight)/2),0)) newImage.paste(img, (4, wtop)) else: nwidth = int(round((20.0/height*width),0)) if nwidth == 0: nwidth = 1 img = im.resize((nwidth,20), Image.ANTIALIAS).filter(ImageFilter.SHARPEN) wleft = int(round(((28 - nwidth)/2),0)) newImage.paste(img, (wleft, 4)) tv = list(newImage.getdata()) # 归一化像素值到0-1区间 tva = [ (255-x)*1.0/255.0 for x in tv] return tva # 预测函数 def predict(): train = data.train tf.reset_default_graph() with tf.Session() as sess: new_saver = tf.train.import_meta_graph('~/trained-model.ckpt.meta') new_saver.restore(sess, '~/trained-model.ckpt') print(tf.get_default_graph().get_name_scope()) y_pred = tf.get_default_graph().get_tensor_by_name('y_pred:0') X = tf.get_default_graph().get_tensor_by_name('X:0') final = imageprepare('tshirts.png') final = np.asarray(final) final = np.reshape(final,[784,1]) output_label = sess.run(y_pred, feed_dict={X: final}) print(output_label)
我自己排查了一些点:
- 图像预处理函数
imageprepare输出的是长度为784的列表,转换成数组后我reshape成了(784,1),但模型输入X的定义是[None, 784],会不会是输入维度不匹配的问题? - 加载模型的时候,有没有遗漏恢复某些必要的张量或者参数?
实在找不到问题所在,恳请各位帮忙分析一下,谢谢!
内容的提问来源于stack exchange,提问作者RACHIT JAIN
相关产品推荐
相关产品推荐

