对于常见的神经网络层的实现方式:
个人理解:其实网络层无非就是 线性计算+非线性计算。 张量+函数的实现就是手动写这些计算,用keras里面的类实现的话,更加高层和方便,因为这个类整合了许多步骤,不止可以帮我们 实现前向传播,对于优化参数、优化过程…都
例子:
两种方式使用softmax。
# 1.手动实现softmax计算
x = tf.constant([1, 2, 3], dtype=tf.float32)
print(tf.nn.softmax(x)) # softmax函数输入tensor的dtype只能是float
# 2.将softmax看作一个激活层,先定义层类,调用__call__前向传播
soft_layer = layers.Softmax()
print(soft_layer(x))
tf.Tensor([0.09003057 0.24472848 0.66524094], shape=(3,), dtype=float32)
tf.Tensor([0.09003057 0.24472848 0.66524094], shape=(3,), dtype=float32)
前面说直接调用层类对象的__call__就可以实现前向传播,但是如果层多的话就很麻烦,一层运算要写一行代码。
Sequential 容器可以将很多层封起来,组成一个大的网络类。这样就一行代码就可以实现前向传播。
Sequential 容器还可以动态添加网络层。使用add()方法即可。
创建网络层类对象时,其实并没有马上就创建 内部的权值变量【而且刚创建的时候层对象也不知道输入自变量的维度,也没办法初始化参数】。有两种方法可以让其开始初始化参数:
调用容器的sunmmary()方法可以打印出网络层信息。
当我们通过 Sequential 容量封装多个网络层时,每层的参数列表将会自动并入Sequential 容器的参数列表中,不需要人为合并网络参数列表,这也是 Sequential 容器的便捷之处。
trainable_variables查看优化变量。
★想要快速搭建神经网络,就多使用Sequential容器。
举例:
# 用Sequential创建网络模块
network = Sequential([layers.Dense(12),
layers.ReLU()])
network.add(layers.Dense(6, activation=tf.nn.relu))
network.add(layers.Dense(3))
network.add(layers.Softmax())
# 注意:上面的过程,各层并没有初始化优化参数。所以也不能调用summary
# 先build()初始化参数
network.build(input_shape=(2, 12))
print(network.summary()) # 查看层信息
print(network.trainable_variables) # 查看待优化参数
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (2, 12) 156
_________________________________________________________________
re_lu (ReLU) (2, 12) 0
_________________________________________________________________
dense_1 (Dense) (2, 6) 78
_________________________________________________________________
dense_2 (Dense) (2, 3) 21
_________________________________________________________________
softmax_1 (Softmax) (2, 3) 0
=================================================================
Total params: 255
Trainable params: 255
Non-trainable params: 0
_________________________________________________________________
None
[<tf.Variable 'dense/kernel:0' shape=(12, 12) dtype=float32, numpy=
array([[-0.27115655, 0.47336185, 0.2828573 , -0.278363 , -0.0466733 ,
-0.2525444 , 0.13503373, -0.2440865 , -0.20501089, -0.36603403,
-0.1139586 , 0.24573612],
[-0.11659145, -0.21124482, -0.20497859, 0.3065722 , 0.25811064,
-0.24284196, -0.18037868, 0.27580488, -0.39474 , 0.36589956,
-0.03579831, -0.09541678],
[-0.20566857, -0.43593872, -0.02920258, 0.23201895, 0.38322675,
0.06354761, -0.01775253, 0.01123834, -0.36589122, -0.06792116,
-0.06842864, 0.26064432],
[ 0.08437002, -0.4490955 , 0.20239806, 0.33669388, 0.2143184 ,
0.07211125, -0.03253841, -0.38362134, 0.11893249, -0.14639115,
0.3551526 , 0.20892286],
[-0.29488575, -0.33770454, 0.32004416, 0.05990362, -0.47750747,
0.29144013, 0.13108361, 0.49194396, -0.41245055, 0.4011867 ,
0.37970603, -0.23793125],
[ 0.18782783, 0.3589393 , 0.16789973, -0.18371761, -0.12820065,
-0.3582753 , -0.32084024, -0.15329528, -0.2535621 , -0.49638534,
-0.3608055 , -0.0319742 ],
[-0.40736163, 0.44559813, -0.3252629 , -0.38218868, -0.15831864,
0.01440752, -0.42295408, -0.3983345 , 0.01377714, 0.20315146,
-0.07179451, -0.44959486],
[ 0.2072916 , 0.44173884, 0.2631284 , -0.27917206, 0.02291143,
-0.4345652 , 0.40696323, 0.19208694, 0.20922303, 0.30478394,
-0.4812032 , 0.18127465],
[ 0.24665415, -0.28622878, 0.16420722, -0.24770892, 0.42384446,
-0.48718286, 0.0955956 , 0.4056425 , -0.48339534, -0.28314996,
0.31511712, 0.11212027],
[ 0.3926463 , 0.34880483, 0.10928345, 0.28680348, 0.0005244 ,
0.49009955, 0.21589959, 0.14624858, -0.31632268, -0.17861533,
-0.08858144, 0.24264467],
[ 0.10800171, 0.28843105, -0.43341768, 0.17394817, -0.37016177,
0.30060303, 0.44355917, -0.38225472, -0.24899876, 0.3676721 ,
0.15166163, -0.29331326],
[ 0.13651466, -0.04272437, -0.381634 , -0.23172796, 0.2969885 ,
0.17349887, -0.08437574, 0.08433819, -0.21293032, 0.1835233 ,
-0.46423614, 0.03961575]], dtype=float32)>, <tf.Variable 'dense/bias:0' shape=(12,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0.], dtype=float32)>, <tf.Variable 'dense_1/kernel:0' shape=(12, 6) dtype=float32, numpy=
array([[-0.23331451, 0.30367553, -0.3541571 , 0.43473315, -0.2222336 ,
-0.3421381 ],
[ 0.07925999, 0.57003903, 0.13756335, 0.4526521 , 0.04195219,
0.08552188],
[-0.41391292, 0.24933255, -0.37173706, -0.1225068 , -0.30069083,
0.12283343],
[-0.11492595, -0.47368526, -0.51996505, 0.1703046 , -0.23165497,
-0.0510878 ],
[-0.5368057 , -0.3997321 , -0.48116028, -0.3055492 , 0.1829868 ,
0.2629329 ],
[ 0.4613613 , 0.4893328 , 0.25862056, -0.51134425, 0.38423866,
-0.11083591],
[-0.16761655, 0.03647625, 0.11263502, -0.30546263, -0.5287304 ,
0.51868653],
[-0.3589878 , 0.1787104 , -0.06481296, 0.4160319 , 0.05502391,
0.49774897],
[ 0.4067946 , 0.37878394, 0.01554096, 0.07497674, 0.40437728,
0.5641812 ],
[-0.32358247, -0.3909354 , -0.17894027, 0.42217445, 0.14248645,
-0.17294708],
[ 0.22035849, 0.17013997, -0.0615266 , 0.20346582, -0.34752464,
-0.1323103 ],
[ 0.35789144, 0.33759165, -0.24724436, 0.49597716, 0.2938168 ,
0.37021393]], dtype=float32)>, <tf.Variable 'dense_1/bias:0' shape=(6,) dtype=float32, numpy=array([0., 0., 0., 0., 0., 0.], dtype=float32)>, <tf.Variable 'dense_2/kernel:0' shape=(6, 3) dtype=float32, numpy=
array([[ 0.25808632, 0.02955544, -0.4274161 ],
[-0.06362468, 0.59382105, 0.06266963],
[ 0.59541655, -0.21273041, -0.4085191 ],
[ 0.39662504, 0.58782756, -0.09506768],
[ 0.47423184, -0.7482291 , -0.21534908],
[-0.5175892 , 0.07570094, -0.74620277]], dtype=float32)>, <tf.Variable 'dense_2/bias:0' shape=(3,) dtype=float32, numpy=array([0., 0., 0.], dtype=float32)>]
Process finished with exit code 0
神经网络优化/训练 的 理论流程:
搭建完网络框架以后,进行前向传播计算,其中前向传播的最后一步一般是损失函数的计算。
前向传播的过程中会记录计算图。
使用反向传播BP算法,利用前向传播时创建的计算图,反向路径计算所有待优化参数的梯度。
得到梯度以后,选择优化算法,对参数进行 优化。
【因为优化算法绝大部分是梯度相关的算法,因此BP算法计算梯度非常重要,是深度学习的基石。】
训练的一般流程:
将样本数据分成多个batch进行循环。
每一个batch时,先前向传播计算损失,然后反向传播计算梯度。【损失函数也要自己事先确定好】
得到当前梯度后,进行一步梯度迭代。【具体的梯度迭代形式取决于用什么优化算法】
…
直至达到规定的精度 or 最大迭代次数。
如果手动实现上述流程,代码量不少,也要考虑很多细节。但是,
Keras提供了compile()和fit()高层函数来帮我们实现上述流程,
只需两行代码,轻松搞定。
装配:compile()函数先指定 优化器对象、损失函数类型、评价指标
模型训练:fit()函数将训练集 和 验证集 数据送入。
history = network.fit(train_db, epochs=5, validation_data=val_db, validation_freq=2)
train_db 为 tf.data.Dataset 对象,也可以传入 Numpy Array 类型的数据
epochs 参数指定训练迭代的 Epoch 数量
validation_data 参数指定用于验证(测试)的数据集和验证的频率validation_freq
其中 history.history 为字典对象,包含了训练过程中的 loss、测量指标等记录项,我们可以直接查看这些训练数据
{'accuracy': [0.00011666667, 0.0, 0.0, 0.010666667, 0.02495],
'loss': [2465719710540.5845, # 历史训练误差
78167808898516.03,
404488834518159.6,
1049151145155144.4,
1969370184858451.0],
'val_accuracy': [0.0, 0.0], # 历史验证准确率
# 历史验证误差
'val_loss': [197178788071657.3, 1506234836955706.2]}
【【train_db = tf.data.Dataset.from_tensor_slices((x, y)) # 构建 Dataset 对象】】
数据加载进入内存后,需要转换成 Dataset 对象,才能利用 TensorFlow 提供的各种便捷功能。
train_db = train_db.shuffle(10000) # 随机打散样本,不会打乱样本与标签映射关系
train_db = train_db.batch(128) # 设置批训练,batch size 为 128
y = tf.one_hot(y, depth=10) # one-hot 编码
for step, (x,y) in enumerate(train_db): # 迭代数据集对象,带 step 参数
或
for x,y in train_db: # 迭代数据集对象
for epoch in range(20): # 训练 Epoch 数
for step, (x,y) in enumerate(train_db): # 迭代 Step 数
# training...
注:batch这个属性是嵌入在train_db里的。