本文将拆解常见的TensorFlow神经网络层,从开发者的角度来看,这些神经网络层都是一个一个的函数,完成对数据的处理。
一个常见的CNN网络模型包含卷积层,ReLU,MaxPooling, Flatten和Fully-Connected几种常见操作,已经成了一个常见的讨论,如下图所示:卷积神经网络的常见操作
使用TensorFlow.Keras创建神经网络模型,可以使用三种方式:
- Keras顺序化模型,Sequential API ,使用起来最简单
- Keras函数式模型,Functional API ,支持Python控制流,使用起来最灵活
- Keras子类化模型,Subclassing API ,面向对象,封装性好!
第一:tf.keras.layers.Conv2D
需要注意的是:The Conv2D op currently only supports the NHWC tensor format on the CPU TensorFlow.Keras支持的数据格式跟PyTorch的不一样。PyTorch中的数据默认格式是:NCHW;TensorFlow中的数据默认格式是:NHWC。
参看《图像数据通道格式:NCHW和NHWC的区别》
tf.keras中的Conv2D自带激活函数,而PyTorch中没有,这点也要注意,平时开发程序的时候,API手册要放在旁边随时查阅
范例程序:
import tensorflow as tf
from tensorflow.keras import layers
input = tf.random.normal([64,28,28,3]) #The Conv2D op currently only supports the NHWC tensor format on the CPU
cnn1 = layers.Conv2D(filters=5, kernel_size=3, input_shape=[28,28,3], activation='relu') # 28->26
maxpooling = layers.MaxPool2D(pool_size=(2,2)) # 26->13
cnn2 = layers.Conv2D(filters=10, kernel_size=3) # 13->11
print(f"input'shape:{input.shape}")
output_cnn1_relu = cnn1(input)
print(f"output_cnn1_relu'shape:{output_cnn1_relu.shape}")
output_maxpooling1 = maxpooling(output_cnn1_relu)
print(f"output_maxpooling1'shape:{output_maxpooling1.shape}")
output_cnn2 = cnn2(output_maxpooling1)
print(f"output_cnn2'shape:{output_cnn2.shape}")
input'shape:(64, 28, 28, 3)
output_cnn1_relu'shape:(64, 26, 26, 5)
output_maxpooling1'shape:(64, 13, 13, 5)
output_cnn2'shape:(64, 11, 11, 10)
第二,全连接层,tf.keras.layers.Dense(),主要用于分类,类似PyTorch中的Linear()
输入输出形状第三,展平层tf.keras.layers.Flatten(),将多维的输入一维化,常用在从卷积层到全连接层的过渡。Flatten()不会影响Batch Size这个维度。
tf.keras.layers中的类继承于tf.Module,所以要获得参数或者可训练参数,使用属性:
- trainable_variables,返回本模块以及子模块的可训练参数
- variables,返回本模块以及子模块的所有参数
- non_trainable_variables,返回返回本模块以及子模块的不可训练参数
范例代码:
import tensorflow as tf
from tensorflow.keras import layers
input = tf.random.normal([64,28,28,3]) #The Conv2D op currently only supports the NHWC tensor format on the CPU
cnn1 = layers.Conv2D(filters=5, kernel_size=3, input_shape=[28,28,3], activation='relu') # 28->26
maxpooling = layers.MaxPool2D(pool_size=(2,2)) # 26->13
cnn2 = layers.Conv2D(filters=10, kernel_size=3) # 13->11
print(f"input'shape:{input.shape}")
output_cnn1_relu = cnn1(input)
print(f"output_cnn1_relu'shape:{output_cnn1_relu.shape}")
output_maxpooling1 = maxpooling(output_cnn1_relu)
print(f"output_maxpooling1'shape:{output_maxpooling1.shape}")
output_cnn2 = cnn2(output_maxpooling1)
print(f"output_cnn2'shape:{output_cnn2.shape}")
flatten = layers.Flatten()
flatten_output = flatten(output_cnn2)
print(f"flatten_output's shape:{flatten_output.shape}")
fc = layers.Dense(10)
fc_output = fc(flatten_output)
print(f"fc_output's shape:{fc_output.shape}")
print(f"fc.trainable_variables:{fc.trainable_variables}")
input'shape:(64, 28, 28, 3)
output_cnn1_relu'shape:(64, 26, 26, 5)
output_maxpooling1'shape:(64, 13, 13, 5)
output_cnn2'shape:(64, 11, 11, 10)
flatten_output's shape:(64, 1210)
fc_output's shape:(64, 10)
fc.trainable_variables:[<tf.Variable 'dense/kernel:0' shape=(1210, 10) dtype=float32, numpy=
array([[ 0.05487769, 0.02527855, -0.04165767, ..., 0.00269682,
0.02042296, 0.04551943],
[ 0.00149468, -0.01011398, -0.05749704, ..., -0.03202325,
-0.04738416, -0.05263525],
[ 0.05657671, 0.05550244, -0.01307932, ..., 0.00162582,
0.03672835, 0.05790787],
...,
[-0.00091738, -0.06285797, -0.01832154, ..., -0.00189883,
-0.04094192, -0.0634547 ],
[ 0.0671357 , 0.02940496, -0.05299052, ..., 0.02853093,
0.01459268, 0.06423645],
[ 0.01751739, -0.01606247, 0.00306457, ..., -0.05763508,
0.06858329, 0.04299241]], dtype=float32)>, <tf.Variable 'dense/bias:0' shape=(10,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>]
总结:
- TensorFlow.Keras的每个神经网络计算层都是tf.keras.layers.Layer的子类,都具有call()方法实现前向计算。要非常注意,PyTorch用的是forward()。
- 认真阅读API手册可以更加深入的理解tf.Keras的神经网络层的实现
tf.Keras子类化模型实现范例代码:
class Linear(keras.layers.Layer):
def __init__(self, units=32, input_dim=32):
super(Linear, self).__init__()
w_init = tf.random_normal_initializer()
self.w = tf.Variable(
initial_value=w_init(shape=(input_dim, units), dtype="float32"),
trainable=True,
)
b_init = tf.zeros_initializer()
self.b = tf.Variable(
initial_value=b_init(shape=(units,), dtype="float32"), trainable=True
)
def call(self, inputs):
return tf.matmul(inputs, self.w) + self.b
网友评论