python随缘学习笔记
神经网络的数学基础(略)
初识神经网络
神经网络的数据表示
数据存储在多维Numpy数组中 => 张量(tensor)
当前所有机器学习系统都使用张量作为基本数据结构
张量是一个数据容器
矩阵是二维张量
张量是矩阵向任意维度的推广
张量的维度通常叫做轴(axis)
在Numpy中可以用ndim属性查看张量中轴的个数
标量(0D张量)
大概就是数组中只有一个数字
array([12, 3, 6, 14, 7])
向量(1D张量)
vector
一维数组
array([12, 3, 6, 14, 7])
矩阵(2D张量)
array([
[5, 78, 2, 34, 0],
[6, 79, 3, 35, 1],
[7, 80, 4, 36, 2]
])
3D张量与更高维张量
将多个矩阵组合成一个新的数组,可以得到一个 3D 张量
将多个 3D 张量组合成一个数组,可以创建一个 4D 张量
深度学习处理的一般是 0D 到 4D 的张量,但处理视频数据时可能会遇到 5D 张量。
张量的关键属性
轴的个数(阶)
3D 张量有 3 个轴,矩阵有 2 个轴。这在 Numpy 等 Python 库中也叫张量的 ndim。
形状
一个整数元组,表示张量沿每个轴的维度大小(元素个数)
前面矩阵示例的形状为 (3, 5)
3D 张量示例的形状为 (3, 3, 5)
向量的形状只包含一个元素,比如 (5,)
而标量的形状为空,即 ()
数据类型
张量中所包含数据的类型
在 Python 库中通常叫作 dtype
张量的类型可以是 float32、uint8、float64 等
在极少数情况下,你可能会遇到字符(char)张量
Numpy(以及大多数其他库)中不存在字符串张量
因为张量存储在预先分配的连续内存段中,而字符串的长度是可变的,无法用这种方式存储。
在 Numpy 中操作张量
数据批量的概念
通常来说,深度学习中所有数据张量的第一个轴(0 轴,因为索引从0开始)都是样本轴(samples axis,有时也叫样本维度)
深度学习模型不会同时处理整个数据集,而是将数据拆分成小批量
对于这种批量张量,第一个轴(0 轴)叫作批量轴(batch axis)或批量维度(batch dimension)
现实世界中的数据张量
-
向量数据:2D 张量,形状为 (samples, features)
-
时间序列数据或序列数据:3D 张量,形状为 (samples, timesteps, features)
-
图像:4D 张量,形状为 (samples, height, width, channels) 或 (samples, channels, height, width)
-
视频:5D 张量,形状为 (samples, frames, height, width, channels) 或 (samples, frames, channels, height, width)
张量运算
神经网络入门
神经网络剖析
训练神经网络主要围绕一下四个方面
- 层,多个层组合成网络(模型)
- 输入数据和相应目标
- 损失函数,用于学习的反馈信号
- 优化器,决定学习过程如何进行

多个层链接在一起组成了网络,将输入数据映射为预测值。
损失函数将这些预测值与目标进行比较,得到损失值,用于衡量网络预测值与预期结果的匹配程度。
优化器使用这个损失值来更新网络的权重
层
深度学习的基础组件
神经网络的基本数据结构是层
层是一个数据处理模块,将一个或多个输入张量转换为一个或多个输出张量
层兼容性(layer compatibility):每一层只接受特定形状的输入张量,并返回特定形状的输出张量
不同的张量格式与不同的数据处理类型需要用到不同的层
(samples, features) 2D 张量
密集连接层
[densely connected layer,也叫全连接层(fully connected layer)或密集层(dense layer)对应于 Keras 的 Dense 类]
(samples, timesteps, features) 的 3D 张量
循环层(recurrent layer,比如 Keras 的 LSTM 层)
图像数据 4D 张量
二维卷积层(Keras 的 Conv2D)
模型
层构成的网络
深度学习模型是层构成的有向无环图
损失函数与优化器
一旦确定了网络架构,你还需要选择以下两个参数
损失函数
在训练过程中需要将其最小化
衡量当前任务是否已成功完成
优化器
决定如何基于损失函数对网络进行更新
它执行的是随机梯度下降(SGD)的某个变体
原则
对于二分类问题,你可以使用二元交叉熵(binary crossentropy)损失函数
对于多分类问题,可以用分类交叉熵(categorical crossentropy)损失函数
对于回归问题,可以用均方误差(mean-squared error)损失函数
对于序列学习问题,可以用联结主义时序分类(CTC,connectionist temporal classification)损失函数
Keras
流程
(1) 定义训练数据:输入张量和目标张量。
(2) 定义层组成的网络(或模型),将输入映射到目标。
使用 Sequential 类(仅用于层的线性堆叠,这是目前最常见的网络架构)
另一种是函数式 API(functional API,用于层组成的有向无环图,让你可以构建任意形式的架构)
(3) 配置学习过程:选择损失函数、优化器和需要监控的指标。
单一损失函数的例子,目前最常见的
from keras import optimizers
model.compile(optimizer=optimizers.RMSprop(lr=0.001),loss='mse', metrics=['accuracy'])
(4) 调用模型的 fit 方法在训练数据上进行迭代。
model.fit(input_tensor, target_tensor, batch_size=128, epochs=10)
建立深度学习工作站
推荐
Ubuntu
Jupyter
NVIDIA GPU
电影评论分类:二分类问题
# 加载数据集
from keras.datasets import imdb
# num_words=10000 的意思是仅保留训练数据中前 10 000 个最常出现的单词
(train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000)
out:
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/imdb.npz
17465344/17464789 [==============================] - 3s 0us/step
17473536/17464789 [==============================] - 3s 0us/step
要将列表转换为张量
转换方法有以下两种
填充列表,使其具有相同的长度,再将列表转换成形状为 (samples, word_indices)的整数张量,然后网络第一层使用能处理这种整数张量的层(即 Embedding 层)
对列表进行 one-hot 编码,将其转换为 0 和 1 组成的向量。举个例子,序列 [3, 5] 将会被转换为 10 000 维向量,只有索引为 3 和 5 的元素是 1,其余元素都是 0。然后网络第一层可以用 Dense 层,它能够处理浮点数向量数据。
下面我们采用后一种方法将数据向量化。为了加深理解,你可以手动实现这一方法
import numpy as np
# 创建一个形状为(len(sequences),dimension) 的零矩阵
def vectorize_sequences(sequences, dimension=10000):
results = np.zeros((len(sequences), dimension))
for i, sequence in enumerate(sequences):
# 将 results[i] 的指定索引设为 1
results[i, sequence] = 1.
return results
# 向量化
x_train = vectorize_sequences(train_data)
x_test = vectorize_sequences(test_data)
#将标签向量化
y_train = np.asarray(train_labels).astype('float32')
y_test = np.asarray(test_labels).astype('float32')
x_train[0]
out:
array([0., 1., 1., ..., 0., 0., 0.])
y_train[0]
out:
1.0
构建网络
- 输入数据是向量
- 标签是标量(1 和 0)
最简单的情况
带有 relu 激活的全连接层(Dense)的简单堆叠,在这种问题上表现很好
如Dense(16, activation='relu')
参数(16)是该层隐藏单元的个数
一个隐藏单元(hidden unit)是该层表示空间的一个维度。我们在第 2 章讲过,每个带有 relu 激活的 Dense 层都实现了下列张量运算:
output = relu(dot(W, input) + b)
16 个隐藏单元对应的权重矩阵 W 的形状为 (input_dimension, 16),与 W 做点积相当于将输入数据投影到 16 维表示空间中(然后再加上偏置向量 b 并应用 relu 运算)。你可以将表示空间的维度直观地理解为“网络学习内部表示时所拥有的自由度”。
隐藏单元越多(即更高维的表示空间),网络越能够学到更加复杂的表示
但网络的计算代价也变得更大,而且可能会导致学到不好的模式(这种模式会提高训练数据上的性能,但不会提高测试数据上的性能)
对于这种 Dense 层的堆叠,你需要确定以下两个关键架构:
网络有多少层;
每层有多少个隐藏单元。
第 4 章中的原则将会指导你对上述问题做出选择。现在你只需要相信我选择的下列架构:
两个中间层,每层都有 16 个隐藏单元;
第三层输出一个标量,预测当前评论的情感
中间层使用 relu 作为激活函数,最后一层使用 sigmoid 激活以输出一个 0~1 范围内的概率值(表示样本的目标值等于 1 的可能性,即评论为正面的可能性)
relu(rectified linear unit,整流线性单元)函数将所有负值归零,而 sigmoid 函数则将任意值“压缩”到 [0, 1] 区间内(见图 3-5),其输出值可以看作概率值。
模型定义
from keras import models
from keras import layers
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
什么是激活函数?为什么要使用激活函数?
如果没有 relu 等激活函数(也叫非线性),Dense 层将只包含两个线性运算
点积和加法:output = dot(W, input) + b
这样 Dense 层就只能学习输入数据的线性变换(仿射变换)
该层的假设空间是从输入数据到 16 位空间所有可能的线性变换集合。
这种假设空间非常有限,无法利用多个表示层的优势,因为多个线性层堆叠实现的仍是线性运算,添加层数并不会扩展假设空间。
为了得到更丰富的假设空间,从而充分利用多层表示的优势,你需要添加非线性或激活函数。
relu 是深度学习中最常用的激活函数,但还有许多其他函数可选,它们都有类似的奇怪名称,比如 prelu、elu 等
选择损失函数和优化器
面对的是一个二分类问题
网络输出是一个概率值(网络最后一层使用 sigmoid 激活函数,仅包含一个单元)
最好使用 binary_crossentropy(二元交叉熵)损失
还可以使用 mean_squared_error(均方误差)
但对于输出概率值的模型,交叉熵(crossentropy)往往是最好的选择
交叉熵是来自于信息论领域的概念,用于衡量概率分布之间的距离,在这个例子中就是真实分布与预测值之间的距离。
用 rmsprop 优化器和 binary_crossentropy 损失函数来配置模型
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])
有时你可能希望配置自定义优化器的参数
或者传入自定义的损失函数或指标函数
前者可通过向 optimizer 参数传入一个优化器类实例来实现from keras import optimizers model.compile(optimizer=optimizers.RMSprop(lr=0.001),loss='binary_crossentropy',metrics=['accuracy'])后者可通过向 loss 和 metrics 参数传入函数对象来实现
from keras import losses from keras import metrics model.compile(optimizer=optimizers.RMSprop(lr=0.001),loss=losses.binary_crossentropy,metrics=[metrics.binary_accuracy])
# 留出验证集
x_val = x_train[:10000]
partial_x_train = x_train[10000:]
y_val = y_train[:10000]
partial_y_train = y_train[10000:]
#训练模型
history = model.fit(partial_x_train,
partial_y_train,
# 对 x_train 和 y_train 两个张量中的所有样本进行 20 次迭代
epochs=20,
# 使用 512 个样本组成的小批量
batch_size=512,
validation_data=(x_val, y_val))
out:
Epoch 1/20
30/30 [==============================] - 2s 46ms/step - loss: 0.5285 - accuracy: 0.7911 - val_loss: 0.4037 - val_accuracy: 0.8633
Epoch 2/20
30/30 [==============================] - 0s 14ms/step - loss: 0.3218 - accuracy: 0.9001 - val_loss: 0.3188 - val_accuracy: 0.8807
Epoch 3/20
30/30 [==============================] - 0s 13ms/step - loss: 0.2317 - accuracy: 0.9273 - val_loss: 0.2827 - val_accuracy: 0.8898
Epoch 4/20
30/30 [==============================] - 0s 13ms/step - loss: 0.1814 - accuracy: 0.9419 - val_loss: 0.2740 - val_accuracy: 0.8920
Epoch 5/20
30/30 [==============================] - 0s 13ms/step - loss: 0.1463 - accuracy: 0.9531 - val_loss: 0.2789 - val_accuracy: 0.8883
Epoch 6/20
30/30 [==============================] - 0s 13ms/step - loss: 0.1225 - accuracy: 0.9635 - val_loss: 0.2920 - val_accuracy: 0.8851
Epoch 7/20
30/30 [==============================] - 0s 13ms/step - loss: 0.1019 - accuracy: 0.9686 - val_loss: 0.3358 - val_accuracy: 0.8753
Epoch 8/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0857 - accuracy: 0.9748 - val_loss: 0.3241 - val_accuracy: 0.8823
Epoch 9/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0689 - accuracy: 0.9809 - val_loss: 0.3563 - val_accuracy: 0.8805
Epoch 10/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0565 - accuracy: 0.9863 - val_loss: 0.3883 - val_accuracy: 0.8788
Epoch 11/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0469 - accuracy: 0.9879 - val_loss: 0.4084 - val_accuracy: 0.8778
Epoch 12/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0378 - accuracy: 0.9917 - val_loss: 0.4345 - val_accuracy: 0.8717
Epoch 13/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0312 - accuracy: 0.9939 - val_loss: 0.4619 - val_accuracy: 0.8717
Epoch 14/20
30/30 [==============================] - 0s 14ms/step - loss: 0.0233 - accuracy: 0.9961 - val_loss: 0.4947 - val_accuracy: 0.8708
Epoch 15/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0195 - accuracy: 0.9963 - val_loss: 0.5319 - val_accuracy: 0.8692
Epoch 16/20
30/30 [==============================] - 0s 14ms/step - loss: 0.0147 - accuracy: 0.9980 - val_loss: 0.5663 - val_accuracy: 0.8682
Epoch 17/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0102 - accuracy: 0.9993 - val_loss: 0.6252 - val_accuracy: 0.8682
Epoch 18/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0069 - accuracy: 0.9997 - val_loss: 0.6526 - val_accuracy: 0.8669
Epoch 19/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0076 - accuracy: 0.9988 - val_loss: 0.6850 - val_accuracy: 0.8667
Epoch 20/20
30/30 [==============================] - 0s 13ms/step - loss: 0.0069 - accuracy: 0.9991 - val_loss: 0.7175 - val_accuracy: 0.8661
绘制训练损失和验证损失
import matplotlib.pyplot as plt
history_dict = history.history
loss_values = history_dict['loss']
val_loss_values = history_dict['val_loss']
epochs = range(1, len(loss_values) + 1)
plt.plot(epochs, loss_values, 'bo', label='Training loss')
plt.plot(epochs, val_loss_values, 'b', label='Validation loss')
plt.title('Training and validation loss')
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend()
plt.show()
out:
绘制训练精度和验证精度
#清空图像
plt.clf()
acc = history_dict['accuracy']
val_acc = history_dict['val_accuracy']
plt.plot(epochs, acc, 'bo', label='Training acc')
plt.plot(epochs, val_acc, 'b', label='Validation acc')
plt.title('Training and validation accuracy')
plt.xlabel('Epochs')
plt.ylabel('Accuracy')
plt.legend()
plt.show()
out:
训练损失每轮都在降低
训练精度每轮都在提升
这就是梯度下降优化的预期结果——你想要最小化的量随着每次迭代越来越小。
但验证损失和验证精度它们在第四轮达到最佳值
模型在训练数据上的表现越来越好
过拟合(overfit)
在第二轮之后,对训练数据过度优化,最终学到的表示仅针对于训练数据,无法泛化到训练集之外的数据。
在这种情况下,为了防止过拟合,你可以在 3 轮之后停止训练
从头开始重新训练一个模型
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(10000,)))
model.add(layers.Dense(16, activation='relu'))
model.add(layers.Dense(1, activation='sigmoid'))
model.compile(optimizer='rmsprop',loss='binary_crossentropy',metrics=['accuracy'])
model.fit(x_train, y_train, epochs=4, batch_size=512)
results = model.evaluate(x_test, y_test)
out:
Epoch 1/4
49/49 [==============================] - 1s 9ms/step - loss: 0.4651 - accuracy: 0.8119
Epoch 2/4
49/49 [==============================] - 0s 9ms/step - loss: 0.2654 - accuracy: 0.9088
Epoch 3/4
49/49 [==============================] - 0s 9ms/step - loss: 0.2026 - accuracy: 0.9295
Epoch 4/4
49/49 [==============================] - 0s 8ms/step - loss: 0.1687 - accuracy: 0.9407
782/782 [==============================] - 2s 2ms/step - loss: 0.3145 - accuracy: 0.8772
in:
results
out:
[0.3144741356372833, 0.8772000074386597]

浙公网安备 33010602011771号