Tensorflow:介绍常见激活函数和池化,并用Tensorflow搭建前向神经网络
一、常见激活函数和池化
1 激活函数
? 激活函数通常用于卷积层和全连接层的末端,为神经网络提供非线性变化。
? 1.1 sigmoid
? S形曲线,早期用于卷积层,通常用于逻辑回归任务的最后一层输出 ? tensorflow对应api:tf.nn.sigmoid()
?分类中通常和损失函数 一起使用
? 1.2 relu
? 线性整流函数,通常用于卷积层和全连接的前几层
? relu = max(0,x)
? tensorflow对应api:tf.nn.relu()
? 1.3 softmax
? 多分类激活,通常用于多分类任务最后一层输出
?
? 不好画图,但是所有求和=1
? 分类中通常与损失函数-log(f)一起使用
? tensorflow对应的api:tf.nn.softmax()
? 1.4 tanh 图片来源于知乎,侵删
? tensorflow对应的api,tf.nn.tanh()
? 2 池化
? 池化的作用:特征采样,降维度
? maxpool,对应的api为tf.nn.maxpool,通常size为(3,3)或者(5,5),stride为2
二、用Tensorflow搭建前向神经网络
要求如下:
? 1 练习搭建前向神经网络:
? 1.1 np构成(4,16,16,3)的矩阵,(0-1)随机,模拟4张16*16的图片。
? 2.1 连续两次:(用3*3的卷积核输出64个特征图,用relu做激活)
? 3.1 用maxpool池化,3*3,s=2
? 4.1 连续两次:(用3*3的卷积核输出128个特征图,用relu做激活)
? 5.1 用maxpool池化, 3*3,s=2
? 6.1 拉伸后做一次全连接,输出1024个神经元,用relu激活
? 6.2 再做一次全连接,输出1个神经元,用sigmoid激活
? 6.3 session.run, 并打印3.1, 5.1, 6.2的结果
? 2 在1的基础上,创建一个(4,1)的向量,作为y,并实现以下损失函数
求平均输出一个标量(数字)。
代码如下:
import tensorflow as tf
import numpy as np
inputs = np.random.randn(4,16,16,3)
conv1 = tf.layers.conv2d(inputs, 64, (3, 3),padding = "same")
relu_output1 = tf.nn.relu(conv1)
conv2 = tf.layers.conv2d(relu_output1, 64, (3, 3),padding = "same")
relu_output2 = tf.nn.relu(conv2)
pool_output1 = tf.nn.max_pool2d(relu_output2, (3, 3), 2, padding = "SAME")
conv3 = tf.layers.conv2d(pool_output1, 128, (3, 3),padding = "same")
relu_output3 = tf.nn.relu(conv3)
conv4 = tf.layers.conv2d(relu_output3, 128, (3, 3),padding = "same")
relu_output4 = tf.nn.relu(conv4)
pool_output2 = tf.nn.max_pool(relu_output4, (3, 3), 2, padding = "SAME")
flatten = tf.layers.flatten(pool_output2)
dense1 = tf.layers.dense(flatten, 1024)
relu_output5 = tf.nn.relu(dense1)
dense2 = tf.layers.dense(relu_output5, 1)
sigmoid_output = tf.nn.sigmoid(dense2)
y = np.random.randn(4, 1)
def cost(y_pre, y):
return tf.reduce_mean(-y*t.log(y_pre)-(1-y)*tf.log(1-y_pre))
mean = cost(sigmoid_output, y)
with tf.compat.v1.Session() as sess:
sess.run(tf.global_variables_initializer())
[pool_output1, pool_output2, sigmoid_output,mean] = sess.run([pool_output1, pool_output2, sigmoid_output,mean])
print("第一次池化结果形状:", pool_output1.shape)
print("第一次池化结果:\n", pool_output1)
print("第二次池化结果形状:", pool_output2.shape)
print("第二次池化结果:\n", pool_output2)
print("两次全连接后结果形状:", sigmoid_output.shape)
print("两次全连接后结果:\n", sigmoid_output)
print("平均损失值为:",mean)
理解各个步骤中的形状变化:
第一次卷积:由于原输入形状为(4,16,16,3),经过第一次有64个卷积核且padding="same"的卷积操作后,一共会得到64个feature map,且每个feature map的形状不变(上节讲过),故输出形状为(4,16,16,64);再通过relu函数激活后,输出形状仍为(4,16,16,64)。
第二次卷积:同上,输出形状仍为(4,16,16,64)。
第一次池化:在第一次池化操作时,由于窗口大小设置为3*3,且步长为2,所以池化操作后的每个feature map的形状要比输入时的形状缩小一半,故第一次池化结果形状为(4,8,8,64),见下图。
第三次卷积:输入形状为(4,8,8,64),此时经过有128个卷积核且padding="same"的卷积操作后,一共会得到128个feature map,且每个feature map的形状不变,故输出形状为(4,8,8,128);再通过relu函数激活后,输出形状仍为(4,8,8,128)。
第四次卷积:同上,输出形状仍为(4,8,8,128)。
第二次池化:在第二次池化操作时,同第一次池化,由于窗口大小设置为3*3,且步长为2,所以池化操作后的每个feature map的形状要比输入时的形状缩小一半,故第二次池化结果形状为(4,4,4,128),见下图。
第一次全连接:该全连接的输入形状为(4,4,4,128),设置神经元个数为1024,故经过第一次全连接后的形状为(4,1024),再通过relu函数激活后,输出形状仍为(4,1024)。
第二次全连接:该全连接的输入形状为(4,1024),设置神经元个数为1,故故经过第二次全连接后的形状为(4,1),再通过sigmoid函数激活后,输出形状仍为(4,1)。见下图:
自行定义损失函数cost并求均值函数,参数为预测值(神经网络最后输出的sigmoid_output)和真实值(随机向量y),其计算结果如下:
|