我目前正在用MNIST数据集训练一个CNN,随着训练的进行,输出概率(softmax)给出的结果是[0.1,0.1,…,0.1]。初始值并非均匀分布,所以我无法确定自己是否犯了什么愚蠢的错误?
我只训练了15个步骤,只是为了观察训练的进展;尽管这个数字很低,但我认为这不应该导致均匀的预测结果吧?
import numpy as npimport tensorflow as tfimport imageiofrom sklearn.datasets import fetch_mldatamnist = fetch_mldata('MNIST original')# Getting datafrom sklearn.model_selection import train_test_splitdef one_hot_encode(data): new_ = [] for i in range(len(data)): _ = np.zeros([10],dtype=np.float32) _[int(data[i])] = 1.0 new_.append(np.asarray(_)) return new_data = np.asarray(mnist["data"],dtype=np.float32)labels = np.asarray(mnist["target"],dtype=np.float32)labels = one_hot_encode(labels)tr_data,test_data,tr_labels,test_labels = train_test_split(data,labels,test_size = 0.1)tr_data = np.asarray(tr_data)tr_data = np.reshape(tr_data,[len(tr_data),28,28,1])test_data = np.asarray(test_data)test_data = np.reshape(test_data,[len(test_data),28,28,1])tr_labels = np.asarray(tr_labels)test_labels = np.asarray(test_labels)def get_conv(x,shape): weights = tf.Variable(tf.random_normal(shape,stddev=0.05)) biases = tf.Variable(tf.random_normal([shape[-1]],stddev=0.05)) conv = tf.nn.conv2d(x,weights,[1,1,1,1],padding="SAME") return tf.nn.relu(tf.nn.bias_add(conv,biases))def get_pool(x,shape): return tf.nn.max_pool(x,ksize=shape,strides=shape,padding="SAME")def get_fc(x,shape): sh = x.get_shape().as_list() dim = 1 for i in sh[1:]: dim *= i x = tf.reshape(x,[-1,dim]) weights = tf.Variable(tf.random_normal(shape,stddev=0.05)) return tf.nn.relu(tf.matmul(x,weights) + tf.Variable(tf.random_normal([shape[1]],stddev=0.05)))#Creating modelx = tf.placeholder(tf.float32,shape=[None,28,28,1])y = tf.placeholder(tf.float32,shape=[None,10])conv1_1 = get_conv(x,[3,3,1,128])conv1_2 = get_conv(conv1_1,[3,3,128,128])pool1 = get_pool(conv1_2,[1,2,2,1])conv2_1 = get_conv(pool1,[3,3,128,512])conv2_2 = get_conv(conv2_1,[3,3,512,512])pool2 = get_pool(conv2_2,[1,2,2,1])conv3_1 = get_conv(pool2,[3,3,512,1024])conv3_2 = get_conv(conv3_1,[3,3,1024,1024])conv3_3 = get_conv(conv3_2,[3,3,1024,1024])conv3_4 = get_conv(conv3_3,[3,3,1024,1024])pool3 = get_pool(conv3_4,[1,3,3,1])fc1 = get_fc(pool3,[9216,1024])fc2 = get_fc(fc1,[1024,10])softmax = tf.nn.softmax(fc2)loss = tf.losses.softmax_cross_entropy(logits=fc2,onehot_labels=y)train_step = tf.train.AdamOptimizer().minimize(loss)sess = tf.Session()sess.run(tf.global_variables_initializer())for i in range(15): print(i) indices = np.random.randint(len(tr_data),size=[200]) batch_data = tr_data[indices] batch_labels = tr_labels[indices] sess.run(train_step,feed_dict={x:batch_data,y:batch_labels})
非常感谢您。
回答:
您的代码中存在几个问题,包括一些基础错误。我强烈建议您先浏览Tensorflow的MNIST逐步教程,适合机器学习初学者的MNIST和专家的深度MNIST。
简而言之,关于您的代码:
首先,您的最后一层fc2
不应该使用ReLU激活函数。
其次,您构建批次的方式,即
indices = np.random.randint(len(tr_data),size=[200])
只是在每次迭代中随机抽取样本,这远非正确的方法…
第三,您输入到网络中的数据没有标准化到[0, 1]的范围内,这是应该做的:
np.max(tr_data[0]) # 获取您的第一个训练样本的最大值# 255.0
第三点最初也让我感到困惑,因为在上述Tensorflow教程中似乎也没有对数据进行标准化。但仔细检查后发现了原因:如果您通过Tensorflow提供的工具函数(而不是像您在这里使用的那样使用scikit-learn函数)导入MNIST数据,它们已经标准化到[0, 1]的范围内了,而这一点在任何地方都没有提示:
from tensorflow.examples.tutorials.mnist import input_dataimport tensorflow as tfimport numpy as npmnist = input_data.read_data_sets("MNIST_data/", one_hot=True)np.max(mnist.train.images[0])# 0.99607849
这确实是一个奇怪的设计决定——据我所知,在所有其他类似的案例/教程中,标准化输入数据是管道的一个明确部分(例如,参见Keras示例),而且有充分的理由(当您以后使用自己的数据时,您肯定会被期望自己完成这一步)。