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
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
#1.1 np构成(4,16,16,3)nhwc 的矩阵.(0-1)随机,模拟4张16*16的图片。
inputs = np.random.randn(4,16,16,3)#创建4*16*16*3的随机张量
#2.1 连续两次:(用3*3的卷积核输出64个特征图,用relu做激活)
#第一次
conv1 = tf.layers.conv2d(inputs, 64, (3, 3),padding = "same")#卷积操作
relu_output1 = tf.nn.relu(conv1)#relu激活
#第二次
conv2 = tf.layers.conv2d(relu_output1, 64, (3, 3),padding = "same")#卷积操作
relu_output2 = tf.nn.relu(conv2)#relu激活
#3.1 用maxpool池化,3*3 s=2
pool_output1 = tf.nn.max_pool2d(relu_output2, (3, 3), 2, padding = "SAME")#参数依次是输入,窗口大小,步长
#4.1 连续两次:(用3*3的卷积核输出128个特征图,用relu做激活)
#第一次
conv3 = tf.layers.conv2d(pool_output1, 128, (3, 3),padding = "same")#卷积操作
relu_output3 = tf.nn.relu(conv3)#relu激活
#第二次
conv4 = tf.layers.conv2d(relu_output3, 128, (3, 3),padding = "same")#卷积操作
relu_output4 = tf.nn.relu(conv4)#relu激活
#5.1 用maxpool池化, 3*3 s=2
pool_output2 = tf.nn.max_pool(relu_output4, (3, 3), 2, padding = "SAME")
#6.1 拉伸后做一次全连接,输出1024个神经元,用relu激活
flatten = tf.layers.flatten(pool_output2)#输出矩阵拉伸运算
dense1 = tf.layers.dense(flatten, 1024)#设置神经元个数为1024
relu_output5 = tf.nn.relu(dense1)#relu激活
#6.2 再做一次全连接,输出1个神经元,用sigmoid激活
dense2 = tf.layers.dense(relu_output5, 1)#设置神经元个数为1
sigmoid_output = tf.nn.sigmoid(dense2)#sigmoid激活
#在1的基础上,创建一个(4,1)的向量,作为y,并实现以下损失函数,求平均输出一个标量(数字)。
y = np.random.randn(4, 1)#创建(4,1)向量y
#定义损失函数并求均值,返回结果为标量
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)
#6.3 session.run, 并打印3.1, 5.1, 6.2的结果
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),其计算结果如下: