4.1 机器学习的四个分支
4.1.1 监督学习
含义:给定一组样本,它可以学会将输入数据映射到已知目标。
常见监督学习有:分类、回归、序列生成、语法树预测、目标检测、图像分割。
4.1.2 无监督学习
含义:是指在没有i目标的情况下寻找输入数据的有趣变换,其目的在于数据可视化、数据压缩、数据去噪或更好地理解数据中的相关性。
常见无监督学习有:降维、聚类。
4.1.3 自监督学习
含义:是没有人工标注的标签的监督学习,可以看作没有人参与的监督学习。
常见自监督学习有:自编码器、时序监督学习。
4.1.4 强化学习
含义:在强化学习中,智能体接收有关其环境的信息,并学会选择使某种奖励最大化的行动。
主要应用于游戏领域。
4.2 评估机器学习模型
4.2.1 训练集、验证集和测试集
(1)简单的留出验证:留出一定比例的数据作为测试集。在剩余的数据上训练模型,然后再测试机上评估模型。
1 from keras import models 2 from keras import layers 3 import numpy as np 4 5 data = list(range(60000)) #模拟全部样本 6 num_validation_samples = 10000 #验证集个数 7 num_test_samples = 10000 #测试集个数 8 np.random.shuffle(data) #随机打乱data 9 10 validation_data = data[:num_validation_samples]#验证集 10000个样本 11 training_data = data[num_validation_samples:-num_test_samples]#训练集 40000个样本 12 test_data = data[num_test_samples:]#测试集 10000个样本 13 14 #这里是示例,可以用keras建立更复杂的网络结构 15 def get_model(): 16 model = models.Sequential() 17 model.add(layers.Dense(1,activation='relu',input_shape=(1,))) 18 model.compile(optimizer='rmsprop',loss='mse',metrics=['mae']) 19 return model 20 21 model = get_model() 22 23 validation_score = model.evaluate(validation_data) 24 25 #调节模型、重新训练、评估等过程之后 26 27 model = get_model() 28 model.fit(np.concatenate([training_data,validation_data])) 29 30 test_score = model.evaluate(test_data)
(2)K折验证:将数据划分为大小相同的K个分区,对于每个分区i,再剩余的K-1个分区上训练模型,然后在分区i上评估模型。
1 from keras import models 2 from keras import layers 3 import numpy as np 4 5 data = list(range(60000)) #模拟全部样本 6 num_test_samples = 10000 #测试集个数 7 data = data[:-num_test_samples] 8 test_data = data[num_test_samples:]#测试集 10000个样本 9 k = 4 10 num_validation_samples = len(data) // k 11 np.random.shuffle(data) 12 13 validation_scores = [] 14 15 #这里是示例,可以用keras建立更复杂的网络结构 16 def get_model(): 17 model = models.Sequential() 18 model.add(layers.Dense(1,activation='relu',input_shape=(1,))) 19 model.compile(optimizer='rmsprop',loss='mse',metrics=['mae']) 20 return model 21 22 for fold in range(k): 23 validation_data = data[num_validation_samples * fold:num_validation_samples * (fold + 1)] 24 training_data = data[:num_validation_samples * fold] + data[num_validation_samples * (fold + 1):] 25 model = get_model() 26 model.fit(training_data) 27 validation_score = model.evaluate(validation_data) 28 validation_scores.append(validation_score) 29 30 validation_score = np.average(validation_scores) 31 32 model = get_model() 33 model.fit(np.concatenate([training_data,validation_data])) 34 test_score = model.evaluate(test_data)
(3)带有打乱数据的重复K折验证:如果可用的数据相对较少,而你又需要尽可能精确地评估模型,那么可以选择带有打乱数据的重复K折验证。
具体做法是多次使用K折验证,在每次将数据划分为K个分区之前都先将数据打乱。最终分数是每次K折验证分数的平均值。
1 from keras import models 2 from keras import layers 3 import numpy as np 4 5 data = list(range(60000)) #模拟全部样本 6 num_test_samples = 10000 #测试集个数 7 data = data[:-num_test_samples] 8 test_data = data[num_test_samples:]#测试集 10000个样本 9 epoch = 3 10 k = 4 11 num_validation_samples = len(data) // k 12 np.random.shuffle(data) 13 14 validation_scores = [] 15 16 #这里是示例,可以用keras建立更复杂的网络结构 17 def get_model(): 18 model = models.Sequential() 19 model.add(layers.Dense(1,activation='relu',input_shape=(1,))) 20 model.compile(optimizer='rmsprop',loss='mse',metrics=['mae']) 21 return model 22 for e in range(epoch): 23 for fold in range(k): 24 np.random.shuffle(data) 25 validation_data = data[num_validation_samples * fold:num_validation_samples * (fold + 1)] 26 training_data = data[:num_validation_samples * fold] + data[num_validation_samples * (fold + 1):] 27 model = get_model() 28 model.fit(training_data) 29 validation_score = model.evaluate(validation_data) 30 validation_scores.append(validation_score) 31 32 validation_score = np.average(validation_scores) 33 34 model = get_model() 35 model.fit(np.concatenate([training_data,validation_data])) 36 test_score = model.evaluate(test_data)
如代码所示:循环变成了两层循环,在24行每次都要随机打乱训练集data中的数据。
4.2.2 评估模型的注意事项
(1)数据代表性:如果数据本身是按类别连续分布的,需要随机打乱数据。
(2)时间箭头:如果要根据过去预测未来,不应该随机打乱数据,要保证测试集中所有数据都i晚于训练集数据。
(3)数据冗余:保证训练集和验证集之间没有交集。
4.3 数据预处理、特征工程和特征学习
4.3.1 神经网络的数据预处理
数据预处理的目的是使原始数据更适于用神经网络处理,包括向量化、标准化、处理缺失值和特征提取。
(1)向量化:神经网络所有输入和目标都必须是浮点数/整数的张量,无论处理什么数据,都必须将其转换为张量。
(2)值标准化:输入数据赢具有以下特征(取值较小,同质性)。
(3)处理缺失值:如果测试数据中有缺失值,而训练数据没有缺失值,需要人为在训练数据制造缺失值。
4.3.2 特征工程
含义:是指将数据输入模型之前,利用自己关于数据和机器学习算法的知识对数据进行硬编码的转换,以改善模型的效果。
本质:用更简单的方式表述问题,从而使问题变得更容易。
现代深度学习,大部分特侦工程都是不需要的,因为神经网络能从原始数据中自动提取有用特征,
但仍然需要特征工程,原因是:
(1)良好的特征仍然可以让你用更少的资源更优雅的解决问题。
(2)良好的特征可以让你用更少的数据解决问题。
4.4 过拟合与欠拟合
机器学习的根本问题是优化和泛化之间的对立。优化是指调节模型以在训练数据上得到最佳的性能,而泛化是指训练好的模型在前所未见的数据上的性能好坏。
解决过拟合的常用方式:
(1)获取更多的训练数据。
(2)正则化
4.4.1 减小网络大小
减小模型的大小(减少模型中可学习参数的个数)
但网络规模太小又会导致欠拟合,因此需要找到网络模型的一个适中的规模。
一般的工作流程是开始时选择相对较少的层和参数,然后逐渐增加层的大小或增加新层,知道这种增加对验证损失的影响变得很小。
4.4.2 添加权重正则化
奥卡姆剃刀原理:如果一件事情有两种解释,那么可能正确的解释就是最简单的哪个,即假设更少的哪个。
权重正则化:强制让模型权重只能取较小的值,从而限制模型的复杂度,使这种权重的分布更加规则。
(1)L1正则化:添加的成本与权重系数的绝对值成正比
(2)L2正则化:添加的成本与权重系数的平方成正比。
1 from keras import regularizers 2 from keras import models 3 from keras import layers 4 import matplotlib.pyplot as plt 5 from keras.datasets import imdb 6 import numpy as np 7 8 (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000) 9 10 def vectorize_sequences(sequences, dimension=10000): 11 # Create an all-zero matrix of shape (len(sequences), dimension) 12 results = np.zeros((len(sequences), dimension)) 13 for i, sequence in enumerate(sequences): 14 results[i, sequence] = 1. # set specific indices of results[i] to 1s 15 return results 16 17 # Our vectorized training data 18 x_train = vectorize_sequences(train_data) 19 # Our vectorized test data 20 x_test = vectorize_sequences(test_data) 21 # Our vectorized labels 22 y_train = np.asarray(train_labels).astype('float32') 23 y_test = np.asarray(test_labels).astype('float32') 24 25 original_model = models.Sequential() 26 original_model.add(layers.Dense(16, activation='relu', input_shape=(10000,))) 27 original_model.add(layers.Dense(16, activation='relu')) 28 original_model.add(layers.Dense(1, activation='sigmoid')) 29 30 original_model.compile(optimizer='rmsprop', 31 loss='binary_crossentropy', 32 metrics=['acc']) 33 34 original_hist = original_model.fit(x_train, y_train, 35 epochs=20, 36 batch_size=512, 37 validation_data=(x_test, y_test)) 38 39 epochs = range(1, 21) 40 original_val_loss = original_hist.history['val_loss'] 41 42 43 l2_model = models.Sequential() 44 l2_model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001), 45 activation='relu', input_shape=(10000,))) 46 l2_model.add(layers.Dense(16, kernel_regularizer=regularizers.l2(0.001), 47 activation='relu')) 48 l2_model.add(layers.Dense(1, activation='sigmoid')) 49 50 l2_model.compile(optimizer='rmsprop', 51 loss='binary_crossentropy', 52 metrics=['acc']) 53 54 l2_model_hist = l2_model.fit(x_train, y_train, 55 epochs=20, 56 batch_size=512, 57 validation_data=(x_test, y_test)) 58 59 60 l2_model_val_loss = l2_model_hist.history['val_loss'] 61 62 plt.plot(epochs, original_val_loss, 'b+', label='Original model') 63 plt.plot(epochs, l2_model_val_loss, 'bo', label='L2-regularized model') 64 plt.xlabel('Epochs') 65 plt.ylabel('Validation loss') 66 plt.legend() 67 68 plt.show() 69 70 71 from keras import regularizers 72 73 # L1 regularization 74 regularizers.l1(0.001) 75 76 # L1 and L2 regularization at the same time 77 regularizers.l1_l2(l1=0.001, l2=0.001)
4.4.3 添加dropout正则化
dropout时神经网络最有效也最常用的正则化方法之一,就是在训练过程中随机将该层的一些输出特征舍弃。
dropout比率是被设为0的特征所占的比例,通常在0.2~0.5范围内。
测试时没有单元被舍弃,而该层的输出值需要按dropout比例缩小。
1 from keras import regularizers 2 from keras import models 3 from keras import layers 4 import matplotlib.pyplot as plt 5 from keras.datasets import imdb 6 import numpy as np 7 8 (train_data, train_labels), (test_data, test_labels) = imdb.load_data(num_words=10000) 9 10 def vectorize_sequences(sequences, dimension=10000): 11 # Create an all-zero matrix of shape (len(sequences), dimension) 12 results = np.zeros((len(sequences), dimension)) 13 for i, sequence in enumerate(sequences): 14 results[i, sequence] = 1. # set specific indices of results[i] to 1s 15 return results 16 17 # Our vectorized training data 18 x_train = vectorize_sequences(train_data) 19 # Our vectorized test data 20 x_test = vectorize_sequences(test_data) 21 # Our vectorized labels 22 y_train = np.asarray(train_labels).astype('float32') 23 y_test = np.asarray(test_labels).astype('float32') 24 25 26 original_model = models.Sequential() 27 original_model.add(layers.Dense(16, activation='relu', input_shape=(10000,))) 28 original_model.add(layers.Dense(16, activation='relu')) 29 original_model.add(layers.Dense(1, activation='sigmoid')) 30 31 original_model.compile(optimizer='rmsprop', 32 loss='binary_crossentropy', 33 metrics=['acc']) 34 35 original_hist = original_model.fit(x_train, y_train, 36 epochs=20, 37 batch_size=512, 38 validation_data=(x_test, y_test)) 39 40 epochs = range(1, 21) 41 original_val_loss = original_hist.history['val_loss'] 42 43 dpt_model = models.Sequential() 44 dpt_model.add(layers.Dense(16, activation='relu', input_shape=(10000,))) 45 dpt_model.add(layers.Dropout(0.5)) 46 dpt_model.add(layers.Dense(16, activation='relu')) 47 dpt_model.add(layers.Dropout(0.5)) 48 dpt_model.add(layers.Dense(1, activation='sigmoid')) 49 50 51 52 dpt_model.compile(optimizer='rmsprop', 53 loss='binary_crossentropy', 54 metrics=['acc']) 55 56 dpt_model_hist = dpt_model.fit(x_train, y_train, 57 epochs=20, 58 batch_size=512, 59 validation_data=(x_test, y_test)) 60 61 62 dpt_model_val_loss = dpt_model_hist.history['val_loss'] 63 64 plt.plot(epochs, original_val_loss, 'b+', label='Original model') 65 plt.plot(epochs, dpt_model_val_loss, 'bo', label='Dropout-regularized model') 66 plt.xlabel('Epochs') 67 plt.ylabel('Validation loss') 68 plt.legend() 69 70 plt.show()
4.5 机器学习的通用工作流程
4.5.1 定义问题,收集数据集
4.5.2 选择衡量成功的指标
4.5.3 确定评估方法
4.5.4 准备数据
4.5.5 开发比基准更好的模型
4.5.6 扩大模型规模:开发过拟合的模型
4.5.7 模型正则化与调节超参数