深度学习基础


文章目录

  • 深度学习基础
  • 1、加载IMDB数据集
  • 2、准备数据
  • 3、构建网络
  • 3.1、定义模型
  • 3.2编译模型
  • 3.3配置优化器
  • 3.4使用定义的损失和指标
  • 4验证
  • 4.1 预留验证集
  • 4.2 训练模型
  • 4.3绘制训练损失和验证损失
  • 4.4绘制训练精度和验证精度
  • 4.5重新训练一个模型



之前学习了一些深度学习的概念,以及神经网络的一些数学基础,在此以电影评论分类的二分类问题进一步学习深度学习的内容。

1、加载IMDB数据集

#1、加载IMDB数据集
from keras.datasets import imdb #IMDB数据(互联网电影数据库)集是已经经过预处理被转换为整数序列的数据集,整数代表字典中的某个单词
(train_data, train_labels),(test_data, test_labels)=imdb.load_data(num_words=1000)#num_words=10000保留数据中最常出现的前1000个单词
train_data[0]#输出训练集单词索引,单词索引不会超过1000
#列表索引为0-25000,每个列表整数的个数是随机的
train_labels[0]#输出训练集标签
#列表索引为0-25000,train_labels和test_labels的取值为0(负面negative)和1(positive)

标签输出结果:

1
max ([max(sequence) for sequence in train_data])#输出最大索引
999
word_index = imdb.get_word_index()#将单词索引解码为英文单词
reverse_word_index = dict([(value,key) for (key,value) in word_index.items()])#键值颠倒将整数索引映射为单词
decoded_reviw = ' '.join([reverse_word_index.get(i - 3, '?') for i in train_data[0]])#将评论解码,索引减去3是因为0,1,2,3是起始序列为padding填充,他们为‘unknown’未知词保留的索引

2、准备数据

通常要对原始数据大量的预处理以便将其转化为张量再输入到神经网络中。

单词序列可以编码成二进制向量也可以编码成其他。

# 2、准备数据
import numpy as np
def vectorize_sequences(sequences,dimension=1000):#将随机长度整数序列编码为指定尺寸的二进制矩阵,指定的值的大小要大于等于序列输出最大索引,小于数组可调用的计算内存
    results = np.zeros((len(sequences), dimension)).astype('float32')#此处若不指定astype会默认为'float64',因此需要将其指定为惯用'float32'
    for i,  sequence in enumerate(sequences):#枚举序列循环
        results[i,sequence]=1.#指定索引赋值为1
    return results
x_train = vectorize_sequences(train_data)#将训练数据向量化
x_test = vectorize_sequences(test_data)#将测试数据向量化

在准备数据过程中,例如回归问题,将取值范围差异较大的数据输入到神经网络中是不合理的,需要对数据进行标准化,即对输入的每个特征减去均值除以标准差(归一化数据均值为0,标准差为1)。
mean=train_data.mean(axis=0)
train_data -=mean
std = train_data.std(axis=0)
train_data /=std

x_train#显示转化为array形式的 样本
array([[0., 1., 1., ..., 0., 0., 0.],
       [0., 1., 1., ..., 0., 0., 0.],
       [0., 1., 1., ..., 0., 0., 0.],
       ...,
       [0., 1., 1., ..., 0., 0., 0.],
       [0., 1., 1., ..., 0., 0., 0.],
       [0., 1., 1., ..., 0., 0., 0.]], dtype=float32)
#将标签向量化
y_train = np.asarray(train_labels).astype('float32')#此处标签本来就为0和1,故只需用numpy操作将其转化为数组即可
y_test = np.asarray(test_labels).astype('float32')

标签向量化的方法有两种 ,将标签列表转化为 整数张量,或者使用one-hot(分类编码categorical encoding)。
from keras.utils.np_utils import to_categorical
one_hot_test_labels = to_categorical(test_labels)

y_train#输出向量化的y_train
array([1., 0., 0., ..., 0., 1., 0.], dtype=float32)

3、构建网络

3.1、定义模型

二分类问题网络的最后一层应该只有一个单元,并且采用’sigmoid’激活,网络输出应该为0~1范围内的标量,表示概率。前两个层隐层单元可以选更多或者更少。

# 3、构建网络
# 3.1、定义模型
from keras import models
from keras import layers
model = models.Sequential()#模块连续,使模块层间输出输入的张量自适应(因为需要将同一个模型多次实例化)
model.add(layers.Dense(16,activation = 'relu',input_shape=(1000,)))#向模型中添加逐元激活密集层,输出维度为32,采用'relu'非线性激活,输入为1000维(1000行任意列)
model.add(layers.Dense(16,activation = 'relu'))#采用了models.Sequential(),故没有指定输入维度,自适应为32维
model.add(layers.Dense(1,activation = 'sigmoid'))#此层为最后一层采用'sigmoid'激活,仅仅包含一个隐藏单元,后续使用的损失函数最好是二元交叉熵(binary_crossentropy)

三个层的输出维度16,16,1也叫层隐藏单元个数只能相等或者递减,如果中间层较小会造成信息瓶颈(大部分非全部的数据被压缩在这个较小的层,最后网络验证精度也恶化)。
输入数据维2维张量通常用密集层Dense,3维张量用循环层LSTM,4维张量用二维卷积层Conv2D。
在最后一层的激活上多分类问题采用softmax激活,区别于二分零问题的1个隐藏单元,隐藏单元数为分类数,最后输出不同输出类别的概率分布,回归问题不采用非线性激活使网络学会预测任意范围内的值。


神经网络的层结构:

dense只包含两个线性运算,张量点积和加法:

神经网络回归怎么看函数 神经网络 回归问题_深度学习
多个线性层堆叠实现的仍然是线性运算,不会扩展假设空间,故通常通过添加非线性或激活函数来丰富层的假设空间来充分彰显层的优势。

W(权重矩阵)和b都是张量,为dense的中心kernel和偏移bias属性。随机初始化时权重矩阵取较小的随机值,这个起点权重没有任何意义,在训练过程中W受训练反馈调节。

inpute = sigmoid(a1)#激活函数取sigmoid函数,a1为要训练的数据
output = np.dot(inpute,W)+b#同a1可得第二层计算

拓展神经网络中的激活函数:

阶跃函数:

import numpy as np
import matplotlib.pylab as plt
def step_func1(x):
	return np.array(x>0,dtype=np.int)#将布尔型转换为int型,大于零对应true转换为1,小于零false转换为0
x = np.arange(−10.0,10.0,0.1)#在−10到10的范围内以1为单位生成numpy数组
y = step_func1(x)#y值取调用函数得到的值
plt.plot(x,y)#画布横纵轴分别为xy
plt.ylim(−0.01,1.01)#画布中y轴范围指定为从−0.01到1.01
plt.show()

神经网络回归怎么看函数 神经网络 回归问题_深度学习_02

sigmoid函数是平滑的连续的,感知机使用的阶跃函数是神经元之间流动的是0或1的二元信号,而神经网络中流动的是连续的实数值信号:
神经网络回归怎么看函数 神经网络 回归问题_python_03

import numpy as np
import matplotlib.pylab as plt
#参数x取值为numpy数组时也能够正常计算
def sigmoid(x):
	return 1/(1+np.exp(−x))
x = np.arange(−10,10,0.1)#x轴范围
y = sigmoid(x)
plt.plot(x,y)
plt.ylim(−0.1,1.1)#y轴范围
plt.show()

神经网络回归怎么看函数 神经网络 回归问题_数据_04

relu函数:

relu 函数主要表示当输入x 大于0 时输出x,输入x 小于0 时输出0

import numpy as np
import matplotlib.pylab as plt
#relu函数
def relu(x):
    return np.maximum(0,x)#输入大于0输出该值,输入小于0输出0(使用numpy中的maximum函数,该函数可以从输入的数值中选择大的值输出)
x = np.arange(-10,10,1)#x范围和缩进
y = relu(x)
plt.plot(x,y)
plt.ylim(-2,10.1)#y范围
plt.show()

神经网络回归怎么看函数 神经网络 回归问题_数据_05

3.2编译模型

# 3.2编译模型

model.compile(optimizer='rmsprop',#选择优化器
              loss='binary_crossentropy',#选择损失函数二元交叉熵
              metrics=['accuracy'])#选择度量

编译模型,将Keras内置的优化器,损失函数和度量指标作为字符串输入,解决实际问题时常常将将这些参数以自定义函数传入。

3.3配置优化器

# 3.3配置优化器
from keras import optimizers
model.compile(optimizer=optimizers.RMSprop(lr=0.001),#向optimizer参数传入优化器类实例来实现优化
              loss='binary_crossentropy',
              metrics=['accuracy'])

3.4使用定义的损失和指标

# 3.4使用定义的损失和指标
from keras import losses
from keras import metrics
model.compile(optimizer=optimizers.RMSprop(lr=0.001),
              loss=losses.binary_crossentropy,#向loss参数传入函数对象二元交叉熵来实现损失
              metrics=[metrics.binary_accuracy])#向metrics参数传入函数对象二元精确度来实现度量

在多分类问题中损失函数一般选择分类交叉熵categorical_crossentropy,来衡量网络输出的概率分布和标签的真实概率分布之间的距离,通过将这两个分布距离最小化使输出结果尽可能接近真实值。

在回归 问题中,损失函数选择均方误差mse来最小化预测值与目标值之差的平方

4验证

4.1 预留验证集

# 4验证
#4.1 预留验证集
x_val = x_train[:1000]# 预留验证数据
partial_x_train = x_train[1000:]# 预留训练数据
y_val = y_train[:1000]# 预留验证标签
partial_y_train = y_train[1000:]#预留训练标签
#将原始数据留出1000个作为验证集来监控新数据上的精度

4.2 训练模型

# 4.2 训练模型
history = model.fit(partial_x_train,#训练数据
                    partial_y_train,#训练标签
                    epochs=20,#模型训练20个伦次
                    batch_size=512,#512个样本组成小批量
                    validation_data=(x_val, y_val))#将验证数据与标签传入参数validation_data
#fit返回了一个history对象,它包含一个成员history.history,这个成员是一个字典包含4个监控指标,训练损失、验证损失,训练精度、'loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'

训练结果:

Epoch 1/20
47/47 [==============================] - 1s 15ms/step - loss: 0.6133 - binary_accuracy: 0.6610 - val_loss: 0.4261 - val_binary_accuracy: 0.8220
Epoch 2/20
47/47 [==============================] - 0s 4ms/step - loss: 0.3944 - binary_accuracy: 0.8370 - val_loss: 0.3476 - val_binary_accuracy: 0.8560
Epoch 3/20
47/47 [==============================] - 0s 4ms/step - loss: 0.3367 - binary_accuracy: 0.8615 - val_loss: 0.3356 - val_binary_accuracy: 0.8590
Epoch 4/20
47/47 [==============================] - 0s 4ms/step - loss: 0.3227 - binary_accuracy: 0.8666 - val_loss: 0.3217 - val_binary_accuracy: 0.8620
Epoch 5/20
47/47 [==============================] - 0s 4ms/step - loss: 0.3057 - binary_accuracy: 0.8756 - val_loss: 0.3161 - val_binary_accuracy: 0.8630
Epoch 6/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2974 - binary_accuracy: 0.8790 - val_loss: 0.3156 - val_binary_accuracy: 0.8610
Epoch 7/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2998 - binary_accuracy: 0.8757 - val_loss: 0.3146 - val_binary_accuracy: 0.8650
Epoch 8/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2923 - binary_accuracy: 0.8794 - val_loss: 0.3309 - val_binary_accuracy: 0.8480
Epoch 9/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2876 - binary_accuracy: 0.8815 - val_loss: 0.3145 - val_binary_accuracy: 0.8610
Epoch 10/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2806 - binary_accuracy: 0.8832 - val_loss: 0.3131 - val_binary_accuracy: 0.8600
Epoch 11/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2756 - binary_accuracy: 0.8879 - val_loss: 0.3116 - val_binary_accuracy: 0.8590
Epoch 12/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2752 - binary_accuracy: 0.8880 - val_loss: 0.3311 - val_binary_accuracy: 0.8500
Epoch 13/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2697 - binary_accuracy: 0.8914 - val_loss: 0.3194 - val_binary_accuracy: 0.8620
Epoch 14/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2672 - binary_accuracy: 0.8906 - val_loss: 0.3114 - val_binary_accuracy: 0.8630
Epoch 15/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2583 - binary_accuracy: 0.8949 - val_loss: 0.3127 - val_binary_accuracy: 0.8630
Epoch 16/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2434 - binary_accuracy: 0.9015 - val_loss: 0.3159 - val_binary_accuracy: 0.8610
Epoch 17/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2462 - binary_accuracy: 0.9020 - val_loss: 0.3195 - val_binary_accuracy: 0.8600
Epoch 18/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2332 - binary_accuracy: 0.9066 - val_loss: 0.3165 - val_binary_accuracy: 0.8590
Epoch 19/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2257 - binary_accuracy: 0.9097 - val_loss: 0.3216 - val_binary_accuracy: 0.8600
Epoch 20/20
47/47 [==============================] - 0s 4ms/step - loss: 0.2289 - binary_accuracy: 0.9075 - val_loss: 0.3286 - val_binary_accuracy: 0.8550

下面 输出一下这些指标:

history_dict = history.history
history_dict.keys()#history对象,它包含一个成员history.history,这个成员是一个字典包含4个监控指标

结果如下:

dict_keys(['loss', 'binary_accuracy', 'val_loss', 'val_binary_accuracy'])

4.3绘制训练损失和验证损失

# 4.3绘制训练损失和验证损失
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')#bo蓝色圆点
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()

神经网络回归怎么看函数 神经网络 回归问题_数据_06

由图,训练损失随轮次的进行而减小,体现了梯度下降的预期结果,验证损失出现波动的情况,几乎在第7轮达到最佳,模型在训练数据上的表现越来越好(损失一直减小),而在新的验证数据上表现变差(损失转折增大),说明模型在第七轮前是较好的模型。

4.4绘制训练精度和验证精度

# 4.4绘制训练精度和验证精度
plt.clf()   # 清空图像
acc = history_dict['binary_accuracy']
val_acc = history_dict['val_binary_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()

神经网络回归怎么看函数 神经网络 回归问题_神经网络回归怎么看函数_07

由图,训练精度随轮次的进行而增大,验证损失出现波动的情况,几乎在第7轮达到最佳,并且发现由于对训练数据过度优化,在第四轮时学到的表示仅针对训练数据,模型在训练数据表现越来越好,但是逐渐脱离验证数据表现,出现过拟合,模型无法泛化到新的数据中。拟合过程和泛化是此消彼长的,在实际中需要根据实际问题来折中二者。

4.5重新训练一个模型

#4.5重新训练一个模型
model = models.Sequential()
model.add(layers.Dense(16, activation='relu', input_shape=(1000,)))
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)#伦次变为4次
results = model.evaluate(x_test, y_test)
results

为了防止过拟合我们可以在第4轮之后停止训练

Epoch 1/4
49/49 [==============================] - 1s 3ms/step - loss: 0.6231 - accuracy: 0.6756
Epoch 2/4
49/49 [==============================] - 0s 3ms/step - loss: 0.3992 - accuracy: 0.8436
Epoch 3/4
49/49 [==============================] - 0s 3ms/step - loss: 0.3369 - accuracy: 0.8653
Epoch 4/4
49/49 [==============================] - 0s 4ms/step - loss: 0.3209 - accuracy: 0.8696
782/782 [==============================] - 1s 816us/step - loss: 0.3372 - accuracy: 0.8580
[0.3372243046760559, 0.8580399751663208]

参考:《python 深度学习》