Tensorflow随手记

2333, 还是一如既往的对什么都有兴趣,趁着这学期不忙,了解一些机器学习知识,跑几个小demo

在机器学习中,我们通常反复的实验,尝试不同的神经网络,修改层级数和神经元数量,已得到更优的模型。

图像是由大量像素点构成,而机器学习的输入只能是向量,所以,一般我没会把图片转换为[nn]的一个一维矩阵,这个过程叫做*扁平化**

在训练模型时,我们通常把数据集划分为不同的子集(训练集/测试集),原因是,当我们通过训练集训练模型后,我们希望通过模型没有见过的数据来看看模型的效果如何

通过测试数据集,我们可以使用网络从未见过的数据测试网络。这样我们便能检测模型的泛化程度,即泛化到训练期间未见过的数据的效果,而不是仅仅记住训练样本。

机器学习模型只有两种,一种是分类模型,一种是回归模型;区别在于我们是想得到一个数字,还是一组概率分布

密集层的概念

这是一种神经网络层级,他是完全连接的层级,所以Keras中称为密集层。这种连接灵活性很好,能够构建更庞大的网络,但是,有时候你可能一开始并不太了解到底应该如何设计网络,所以就设定一切都相互连接,这就是密集层。

当要解决的问题非线性时,我们可以通常在密集层添加一些数学函数,一遍可以达到更好的训练效果。如下面介绍的ReLU

修正线性单元 (ReLU)

ReLU 是修正线性单元的简称,他是一种激活函数,能够使模型解决非线性问题。并且是如下所示的数学函数:

img

如果输入是负数或 0,ReLU 函数的输出将是 0,如果输入是正数,那么输出将等于输入。

卷积神经网络CNN

卷积神经网络。即至少有一个卷积层的网络。典型的 CNN 还包括其他类型的层级,例如池化层和密集层

卷积层的原理是:创建另一个数字网格,叫做核或滤波器,然后利用核扫描图像,卷积层会将核应用到输入图像的各个区域(对于边缘像素,有多种解决方法,常见的一种为零填充)最终得到一个新的卷积图像。

卷积:是指向图像应用滤波器(核)的过程。

池化:通过总结区域减小输入图像大小的过程,新图像的大小取决于网格大小和步长;池化层有多种类型,常见的有平均池化、最大池化等

下采样:缩小图像,他的主要目的有两个:

  1. 使得图像符合显示区域的大小
  2. 生成对应图像的缩略图

CNN处理猫狗图片

两个挑战

  1. 图片的尺寸不是固定的
  2. 图片是彩色的
挑战一:不同的图片尺寸

众所周知,神经网络要求输入尺寸是固定的,图片必须是固定大小的,如果才有之前衣服数据集的方法,将图像扁平化为一维数组,对于不同尺寸的图片,得到的数组大小是不一样的

解决方法是:始终将所有图片调整为相同尺寸(Resizing)

挑战二:如何处理彩色图像

计算机将灰度图像解析为二维数组,这个二维数组包含灰度图像对应的像素值,二维数组的宽高是由图像的尺寸决定的。

同理,计算机会将彩色图像解析为三维数组,三维数组的宽高是由图像的宽高决定的,深度由颜色通道数量决定。大多数彩色图像可以表示成三个颜色通道,分别是红绿蓝,这种图像被称为RGB图像。

在RGB图像中,每个颜色通道都有他自己的二维数组表示,由于有三个颜色通道,所以最终由三个二维数组,所以,对于RGB图像来说,他的深度等于红绿蓝通道对应的三个二维数组的堆叠层数

QQ截图20200328203243.png

在调用函数时,三个参数,(x, y, d),之前模型中,因为是灰度图像,d设为了1

对彩色图像执行卷积运算

可以思考回顾一下灰阶图像的卷积操作

与灰阶图像的卷积操作类似,首先要选择特定尺寸的过滤器(3阶的),而且核的深度要与彩色图像的颜色通道数量一致,之后的卷积运算和灰阶图像一样(零填充,矩阵乘法),计算出每个颜色通道的卷积结果后,我没需要把他们相加起来,而且通过会再多加一个偏差值(通常为1),核对图像每个区域进行扫描后,就得到了卷积图像(二维数组)。

但是,对于彩色图像,通常会采用多个三维过滤器(当然也可以更多),这样就会得到三个卷积结果,我们可以将卷积结果看做三维数组,深度对应于过滤器数量

QQ截图20200328205659.png

在代码中,我们通过设置filters来指定Conv2D层生成多少个输出结果,还可以通过kernel_size来指定三维过滤器的大小

1
tf.keras.layers.Conv2D(filters, kernel_size, ...)

注意,再训练CNN时,我们将更新三维核中的值,从而最小化损失函数

对彩色图像执行最大池化运算

最大池化和灰度图像的处理一样,只是处理后,得到的数据宽高会变小,深度不变

过拟合问题

训练次数过多时,会使网络开始过拟合或记住训练数据。有三种方法可以避免过拟合

  1. 早停法:验证集防止过拟合

    判断过拟合的方法

    查看训练损失和验证损失与周期的函数图,经过几个周期后,验证损失开始上升,而训练损失不断下降,并且再结束训练后,验证损失非常高,而训练损失非常低,这就表明升级网络过拟合训练数据,因为他无法很好的泛化到验证集上

    启发:如果有多个潜在的模型结构可供选择,这种流程将会很有帮助。例如:如果你要决定再网络神经中添加多少个层级,你可以创建具有不同结构的各种模型,然后实验验证集比较他们,验证损失最低的结构将是最佳模型

    疑问:为什么有了测试集,还需要设置验证集?直接使用测试集验证模型不行吗?

    问题是,虽然再训练过程中,不适应验证集调试权重和偏差,但最终调试出的模型会同时再验证集和训练集上表现很好,所以神经网络最终将偏向于验证集,我们需要一个单独的测试集,实际检验模型泛化到从未见过的数据的效果

  2. 通过数据增强和丢弃,来避免过拟合

    在训练CNN识别图像中的特定对象时,我们希望无论这些对象的大小和位置如何,CNN都能检测这些对象。对于各种可能的情况(如狗在左侧,中间,或者只有狗身体的一部分等),如果能有一个足够大的各种情况都有且量大的数据集,那么就可以训练出很好的模型,而且不会产生严重的过拟合。

    但是,大多数时候,训练集并不包含很多不同的样本,在这种情况下,CNN有可能会过拟合,无法很好的泛化到之前没见过的数据上。对于这个问题,我们可以使用图像增强技巧来避免。

    图像增强:是指通过对原始训练集应用各种随即图像转换,创造新的训练图像

    QQ截图20200328220133.png

  3. 丢弃是帮助避免过拟合的另一个技巧

    我们知道,在训练过程中,神经网络通过调整权重和偏差来最小化 损失函数

    QQ截图20200328220746.png

    一种方法是,在不同的训练周期中,指定每个神经元被丢弃的概率,这样就能很好的避免过拟合,还可以使网络变得更有弹性。因为他无法依赖于解决问题能用到的所有神经元,最终,其他神经元将能够起到作用

熟悉代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
%matplotlib inline
import d2lzh as d2l
from mxnet.gluon import data as gdata
import sys
import time

# 我们通过指定train为true来设置数据集是做为训练数据集还是测试集
mnist_train = gdata.vision.FashionMNIST(train=True)
mnist_test = gdata.vision.FashionMNIST(train=False)

# 输出查看两数据集大小
print("train data: {}".format(len(mnist_train)))
print("test data : {}".format(len(mnist_train)))

# 样本:feature + label,即输入数据 和 预测结果
feature, label = mnist_train[0]

# 由于这里使用的是灰度图像,所有只有一个颜色通道. 每个像素是0-255的8位无符号整数
In [5]: feature.shape, feature.dtype
Out[5]: ((28, 28, 1), numpy.uint8)

# 图像的标签使用NumPy的标量表示,他的类型是32位整数(int32)
In [6]: label, type(label), label.dtype
Out[6]: (2, numpy.int32, dtype('int32'))

# 对Fashion-MNIST而言,数据集中一共有10个类别,我们可以封装函数,将上面的label设置标签转为相应的文本标签
def get_fashion_mnist_labels(labels):
text_labels = ['t-shirt', 'trouser', 'pullover', 'dress', 'coat',
'sandal', 'shirt', 'sneaker', 'bag', 'ankle boot']
return [text_labels[int(i)] for i in labels]

# 下面定义一个画图函数,在一行内画出多张图像和对应标签的函数
def show_fashion_mnist(images, labels):
d2l.use_svg_display()
# 这里的_表示我们忽略(不使用)的变量
_, figs = d2l.plt.subplots(1, len(images), figsize=(12, 12))
for f, img, lbl in zip(figs, images, labels):
f.imshow(img.reshape((28, 28)).asnumpy())
f.set_title(lbl)
f.axes.get_xaxis().set_visible(False)
f.axes.get_yaxis().set_visible(False)

# 下面的操作是看一下训练集中前9个样本的图像内容和文本标签
X, y = mnist_train[0:9]
show_fashion_mnist(X, get_fashion_mnist_labels(y))

# 批量处理数据
batch_size = 256
transformer = gdata.vision.transforms.ToTensor()
if sys.platform.startswith('win'): # windows还不支持多线程来加快数据读取
num_workers = 0
else:
num_workers = 4

train_iter = gdata.DataLoader(mnist_train.transform_first(transformer),
batch_size, shuffle=True,
num_workers=num_workers)
test_iter = gdata.DataLoader(mnist_test.transform_first(transformer),
batch_size, shuffle=True,
num_workers=num_workers)