tensorflow学习 -- 使用卷积神经网络进行对fashion-mnist数据集进行分类

# 引入相关的包
import tensorflow as tf
import numpy as np
from tensorflow import keras
# 自定义one_hot编码
def to_onehot(y,num):
    lables = np.zeros([num,len(y)])
    for i in range(len(y)):
        lables[int(y[i]),i] = 1
    return lables.T
# 数据预处理
mnist = keras.datasets.fashion_mnist
(train_images,train_lables),(test_images,test_lables) = mnist.load_data()
# 数据归一化,使得训练更加容易
train_images = train_images / 255.0
test_images = test_images / 255.0
# 标签的one_hot编码
train_lables = to_onehot(train_lables,10)
test_lables = to_onehot(test_lables,10)
# 增加一个维度,因为卷积神经网络中可以处理多个channel,fashion-mnist数据集的channel=1 [batch,28,28,28] -> [batch,28,28,1]
train_images_exp = np.expand_dims(train_images,axis=3)
test_images_exp = np.expand_dims(test_images,axis=3)
input_nodes = 784    # 图片的width*height
output_nodes = 10    # 输出的标签数
image_size = 28     # 图片的宽度(=长度)
channels = 1
labels = 10
conv1_deep = 32    # 第一个卷积层的深度,前一层的输入经过卷积之后会变成[*,*,32]
conv1_size = 5     # 卷积核的大小
conv2_deep = 64
conv2_size = 5
fc_size = 512      # 全连接层的节点数

# 前向传播
def inference(input_tensor,train,regularizer):
    with tf.variable_scope('layer1_conv1',reuse=tf.AUTO_REUSE):
        conv1_weights = tf.get_variable('weight',[conv1_size,conv1_size,channels,conv1_deep],initializer=tf.truncated_normal_initializer(stddev=0.1))
        conv1_bias = 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")   # 问题1 :strides的参数中1,4的参数是定的(在这里为啥是1,有待进一步研究),中间的参数表示向右和向下的滑动距离
        relu1 = tf.nn.relu((tf.nn.bias_add(conv1,conv1_bias)))
        
    with tf.variable_scope('layer2_pool1',reuse=tf.AUTO_REUSE):
        pool1 = tf.nn.max_pool(relu1,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")      #下采样层,问题2:padding = same与上面卷积中的padding具体怎么操作的有待进一步研究一下
                                                                                            #ksize=[1,2,2,1] 表示池化的核是2*2的
    with tf.variable_scope('layer3_conv2',reuse=tf.AUTO_REUSE):
        conv2_weights = tf.get_variable("weights",[conv2_size,conv2_size,conv1_deep,conv2_deep],initializer=tf.truncated_normal_initializer(stddev = 0.1))
        conv2_bias = tf.get_variable("bias",[conv2_deep],initializer=tf.constant_initializer(0.0))
        
        conv2 = tf.nn.conv2d(pool1,conv2_weights,strides=[1,1,1,1],padding="SAME")
        relu2 = tf.nn.relu(tf.nn.bias_add(conv2,conv2_bias))
    
    with tf.variable_scope('layer4_pool2',reuse=tf.AUTO_REUSE):
        pool2 = tf.nn.max_pool(relu2,ksize=[1,2,2,1],strides=[1,2,2,1],padding="SAME")
    pool2_shape = pool2.get_shape().as_list()
    nodes = pool2_shape[1] * pool2_shape[2] * pool2_shape[3]
    # 展开所有的节点 shape[0] 是样本的个数
    reshaped = tf.reshape(pool2,[-1,nodes])   
    with tf.variable_scope('layer5_fc1',reuse=tf.AUTO_REUSE):
        fc1_weights = tf.get_variable("weights",[nodes,fc_size],initializer=tf.truncated_normal_initializer(stddev=0.1))
        # 问题3 :为什么正则化项只加在全连接层
        if regularizer!=None:
            tf.add_to_collection("losses",regularizer(fc1_weights))
        fc1_bias = tf.get_variable("bias",[fc_size],initializer=tf.constant_initializer(0.0))
        fc1 = tf.nn.relu(tf.matmul(reshaped,fc1_weights) + fc1_bias)
        if train:
            fc1 = tf.nn.dropout(fc1,0.2)
           
    with tf.variable_scope('layer6_fc2',reuse=tf.AUTO_REUSE):
        fc2_weights = tf.get_variable("weight",[fc_size,labels],initializer=tf.truncated_normal_initializer(stddev=0.1))
        # 为什么正则化项只加在全连接层
        if regularizer!=None:
            tf.add_to_collection('losses',regularizer(fc2_weights))
        fc2_bias = tf.get_variable("bias",[labels],initializer=tf.constant_initializer(0.0))
        
        logit = tf.matmul(fc1,fc2_weights) + fc2_bias
   # 此时并没有进行softmax操作,因为此时已经可以使用logit来做出预测了,如果是想要概率的话,需要使用softmax来操作
    return logit

epchos = 1000      # 训练的论次数
learning_rate = 0.001
batch_size = 128
model_save_path = "model_conv_1/model.ckpt"

def train_model(data,train=True):
    
    trX,trY,teX,teY = data
    X = tf.placeholder(tf.float32,[None,image_size,image_size,channels],name="x_input")
    Y_ = tf.placeholder(tf.float32,[None,labels],name = 'y_input')
    regularizer = tf.contrib.layers.l2_regularizer(0.0000001)
   
    y_hat = inference(X,train,regularizer)
    # 训练模型
    if train:
        #交叉熵函数,logits 必须为未经过softmax处理的,因为这个函数首先会进行softmax操作,labels 各分量的和必须是1(概率)
        cross_entropy = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(logits=y_hat,labels=Y_))
        loss = cross_entropy + tf.add_n(tf.get_collection("losses"))
        train_step = tf.train.GradientDescentOptimizer(learning_rate=learning_rate).minimize(loss)
        acc = tf.reduce_mean(tf.cast(tf.equal(tf.argmax(Y_,1),tf.argmax(y_hat,1)),tf.float32))
        saver = tf.train.Saver()
        
        with tf.Session() as sess:
            tf.global_variables_initializer().run()
            
            for i in range(epchos):
                total_loss = 0
                for j in range(int(trX.shape[0] / batch_size + 1)):
                    # 这个如何打乱顺序
                    x_batch = trX[j*batch_size:min(trX.shape[0],(j+1)*batch_size),:]
                    y_batch = trY[j*batch_size:min(trY.shape[0],(j+1)*batch_size),:]
                   
                    batch_loss,_=sess.run([cross_entropy,train_step],feed_dict={X:x_batch,Y_:y_batch})
                    total_loss+=batch_loss
                total_loss /= int(trX.shape[0] / batch_size + 1)
                
                
                test_acc = sess.run(acc,feed_dict={X:teX,Y_:teY})
                print("test acc:",test_acc)
                if i % 100 == 0:
                    saver.save(sess,model_save_path)
                    print("保存模型成功!")
train_model((train_images_exp,train_lables,test_images_exp,test_lables))

在实际按照书上编写代码的时候,博主遇到了一下4个问题没有解决,先放在代码下面,进一步研究后,将解答更新一下,欢迎小伙伴们在评论区留下你们的见解:

  1. strides的参数中1,4位置的参数是定的,在这里为啥是1,类似的还有其他参数如池化层的ksize。
  2. padding的“same” 是跟谁same,以及卷积层和池化层的padding具体是怎么操作的。
  3. 为什么正则化项只加在全连接层,其他的参数可以正则化嘛?
  4. 如何打乱每次batch内和batch之间的数据的顺序,来实现随机性?
  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值