Keras for Beginners: Building a Basic Neural Network.
作者:禅与计算机程序设计艺术
1.简介
Keras作为首个开放源代码框架,在深度学习领域具有重要地位。它不仅能够快速实现基于深度学习模型的开发,并借助GPU进行加速计算。这本教程旨在教给您掌握Keras的基本概念,并指导您在PyTorch中搭建基础神经网络。
2.Keras 简介
Keras 被认为是深度学习领域中最具影响力的主要框架之一。
它提供了高度抽象且易于使用的API,
使用户能够构建和训练复杂的神经网络架构,
无需深入处理底层代码细节。
在Keras 中,
层 作为神经网络的基本构建单元,
其作用相当于将输入数据转化为输出数据的过程。
模型 由多个层组成,
通过将各层进行组合连接构建更为复杂的网络架构。
编译器 用于配置并优化训练过程中的各种参数设置,
例如优化器、损失函数等参数。
而回调函数 则是在神经网络训练过程中执行特定功能的任务。
相对于其他框架来说,Keras以其易于上手和高度可定制的特性脱颖而出。通过几行简洁的代码就能搭建一个基础的神经网络架构,并在训练阶段使用fit()方法即可完成模型的优化过程。借助GPU资源可以显著提升Keras的训练速度,并从而使得处理大规模数据集成为一种可行的选择。此外,在机器学习领域中提供了大量经过预先训练优化的标准模型模块供开发者灵活运用。
Keras中的张量计算引擎(TensorFlow、Theano或CNTK)支持多维数据处理,并可在CPU和GPU上高效运行。此外,该系统可迅速执行多种运算过程:矩阵乘法、卷积运算以及归一化操作等基础步骤。此外,它还集成了内置激活函数与池化层结构,并支持填充操作以维持数据完整性。
此外,在Keras中包含了一系列的可视化功能模块, 可以直观显示网络结构和训练指标. 这些功能都支持在Jupyter Notebook中实现. 由此可见, 初学者或资深者只需掌握几个核心概念即可熟练运用Keras进行深度学习.
3.基本概念
下面我们将对Keras中一些重要的概念进行详细介绍:
3.1 层(Layers)
在神经网络中,层被视为最基本的功能模块。每个层都可视为输入数据经过特定变换后生成的输出数据,并赋予其相应的权重参数。Keras支持多种类型的层次组件包括卷积型层次组件Conv2D全连接型层次组件Dense批量归一化型层次组件BatchNormalization丢弃型层次组件Dropout以及最大值池化型层次组件MaxPooling2D等。每个层次组件均可根据需求设置相关参数如卷积核尺寸过滤器数量步长等关键属性以实现特定的功能需求。
3.2 模型(Models)
该模型由多个层构成。通过将各层依次连接即可构建更为复杂的网络架构。Keras提供了三种构建深度学习模型的方法:顺序堆叠、模块化设计以及整合编译器。其中顺序堆叠仅限于构造线性层次结构;而模块化设计则允许我们将整个系统划分为输入端、若干中间处理环节以及输出结果;最后整合编译器这一方案则不仅能够整合各种基础组件,并且支持完整的训练流程。
3.3 编译器(Compilers)
编译器负责设置训练过程的相关参数。这些参数主要包括优化器、损失函数以及指标函数等核心组件。编译器通常会调用 model.compile 方法来完成这一配置工作。此外,在实际应用中还可以通过直接修改模型的 optimizer 属性、 loss 属性或 metrics 属性来完成参数设置。
3.4 回调函数(Callbacks)
在训练过程中负责完成特定任务的是回调函数。Keras 包含 Callbacks 类这一功能模块,在其中定义了一些标准回调机制如 EarlyStopping、ModelCheckpoint 和 ReduceLROnPlateau 等,在训练过程中可以根据模型的关键性能指标(包括准确率、损失值以及F1分数等)来调节训练进程。通过 callbacks 参数传递给 fit() 函数后即可使用这些回调机制。
4.基于Keras的MNIST数字识别例子
为了更好地通过一个基于MNIST手写数字分类任务来感受Keras的强大功能,并在开始之前导入必要的库模块。
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
print("TensorFlow version:",tf.__version__)
print("Keras version:",keras.__version__)
代码解读
TensorFlow version: 2.3.1
Keras version: 2.4.3
代码解读
我们加载mnist数据集,数据已经被划分好了训练集、测试集和验证集。
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape((60000, 28*28))
x_test = x_test.reshape((10000, 28*28))
x_train, x_val = x_train[:50000], x_train[50000:]
y_train, y_val = y_train[:50000], y_train[50000:]
print("Training set:", x_train.shape, y_train.shape)
print("Validation set:", x_val.shape, y_val.shape)
print("Test set:", x_test.shape, y_test.shape)
代码解读
Training set: (60000, 784) (60000,)
Validation set: (10000, 784) (10000,)
Test set: (10000, 784) (10000,)
代码解读
接下来,构建模型,使用Sequential模型。
model = keras.Sequential([
layers.Dense(units=64, activation='relu', input_dim=28 * 28),
layers.Dense(units=10, activation='softmax')
])
model.summary() # 查看模型概要信息
代码解读
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
dense (Dense) (None, 64) 1792
_________________________________________________________________
dense_1 (Dense) (None, 10) 650
=================================================================
Total params: 2,442
Trainable params: 2,442
Non-trainable params: 0
_________________________________________________________________
代码解读
进行模型的构建与训练时,采用SparseCategoricalCrossentropy损失函数,并选用Adam优化器。
model.compile(optimizer='adam',
loss='sparse_categorical_crossentropy',
metrics=['accuracy'])
代码解读
训练模型,这里使用验证集监控模型的训练进度。
history = model.fit(x_train,
y_train,
epochs=10,
validation_data=(x_val, y_val))
代码解读
Epoch 1/10
/usr/local/lib/python3.6/dist-packages/tensorflow/python/ops/math_ops.py:3485: FutureWarning: Using a non-tuple sequence for multidimensional indexing is deprecated; use `arr[tuple(seq)]` instead of `arr[seq]`. In the future this will be interpreted as an array index, `arr[np.array(seq)]`, which will result either in an error or a different result.
return op(self._outputs[0], other)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/framework/indexed_slices.py:365: UserWarning: Converting sparse IndexedSlices to a dense Tensor of unknown shape. This may consume a large amount of memory.
"Converting sparse IndexedSlices to a dense Tensor of unknown shape. "
WARNING:tensorflow:sample_weight modes were coerced from
代码解读
将参数设置为None时,请按照以下步骤进行更新:
- 当输入数据采用批处理模式时,请将样本权重模式指定为'temporal'。
例如,在模型训练时,请参考下述代码片段:
model.fit(batch_size=16, ..., sample_weight_mode='temporal')
当调用fit()函数并提供steps_per_epoch或validation_steps参数时,请注意这可能导致错误。
---------------------------------------------------------------------------
KeyboardInterrupt Traceback (most recent call last)
<ipython-input-13-fdcc3fc71bf6> in <module>()
6 validation_data=(x_val, y_val))
----> 7 history = model.fit(x_train,
8 y_train,
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)
1083 max_queue_size=max_queue_size,
1084 workers=workers,
-> 1085 use_multiprocessing=use_multiprocessing)
1086
1087 @trackable.no_automatic_dependency_tracking
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in _method_wrapper(self, *args, **kwargs)
640 self._self_setattr_tracking = False # pylint: disable=protected-access
641 try:
--> 642 return method(self, *args, **kwargs)
643 finally:
644 self._self_setattr_tracking = previous_value # pylint: disable=protected-access
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in fit(self, x, y, batch_size, epochs, verbose, callbacks, validation_split, validation_data, shuffle, class_weight, sample_weight, initial_epoch, steps_per_epoch, validation_steps, validation_batch_size, validation_freq, max_queue_size, workers, use_multiprocessing)
1033 training_logs = run_compiler(
1034 model,
代码解读
--> 内部函数self._compile_inputs接收四个参数:x、y、sample_weights以及mask。
当validation_data为空时,默认设置val_logs为None;否则,则执行run_compiler操作应用于当前模型。
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/engine/training.py in _run_CompiledNetwork(self, inputs, targets, sample_weights, masks, training)
985 fetches = self.predict_function.call_and_update_losses(
986 ops.convert_to_tensor_or_dataset(inputs),
--> 987 targets, sample_weights, masks)
988
989 if not isinstance(fetches, list):
/usr/local/lib/python3.6/dist-packages/tensorflow/python/keras/distribute/predict_distributed_utils.py in call_and_update_losses(strategy, iterator, distributed_function, args)
94 """Calls and updates losses."""
95
---> 96 losses = strategy.experimental_run_v2(distributed_function, args=args)
97
98 def allreduce():
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/distribute_lib.py in experimental_run_v2(self, fn, args, kwargs)
1210
1211 results = self._grouped_call(
-> 1212 grouped_fn, args=args, kwargs=kwargs)
1213
1214 if not self._require_all_reduced:
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/distribute_lib.py in _grouped_call(self, grouped_fn, args, kwargs)
1297 per_replica_results = []
1298 for group in self._groupings:
-> 1299 sub_results = _local_per_device_graph_run(getattr(group, "_name", "default"), *args, **kwargs)
1300 per_replica_results.append(sub_results)
1301
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/mirrored_run.py in _local_per_device_graph_run(devices, fn, args, kwargs)
621 values, device_map = zip(*captured)
622
--> 623 outputs = ctx.invoke_per_replica(list(zip(values, devices))[::-1], fn, kwargs)
624
625 local_return_values = [_get_single_value_for_scope(i, v, device_map, output)
/usr/local/lib/python3.6/dist-packages/tensorflow/python/distribute/mirrored_run.py in invoke_per_replica(self, arg_tuples, replica_fn, replica_kwargs)
55 per_replica_outs = []
56 for i, arg_tuple in enumerate(arg_tuples):
---> 57 out = replica_fn(**{k: v for k, v in dict(arg_tuple).items()})
58 per_replica_outs.append(out)
59
/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/def_function.py in wrapped_fn(*args, **kwds)
582 )
583 elif self._do_captures:
--> 584 capture_record = self._maybe_capture(args, kwds)
585
586 compiled_fn = self._stateful_fn._get_concrete_function_internal_garbage_collected( # pylint: disable=protected-access
/usr/local/lib/python3.6/dist-packages/tensorflow/python/eager/def_function.py in _maybe_capture(self, args, kwds)
1340 closure = grad_state.tape.gradient_function(
1341 outputs, captured_inputs, tape._watch_targets()) # pylint: disable=protected-access
-> 1342 arg_vals = _concatenate(args, captured_inputs)
1343 arg_vars, captured_mask = _capture_helper(closure, len(arg_vals))
1344 # Use identity_n ops to assign captured variables to appropriate arguments.
ValueError: Cannot concatenate tensors with shapes [(None, 784), (None, 784)], because they are different ranks.
代码解读
这个错误是由于批量大小的问题导致的。
