1 深度学习及Tensorflow框架简介

  为什么要有框架,深度学习框架目的是让更多的人使用同一个规范来实现一些深度学习的方法,这样便于其他人阅读和学习。

  深度学习框架目前有很多,我们要清楚,框架是让我们快速实现问题的,所以不要觉得这个框架直接用API很简单就觉得比较low。

  目前比较有名气的使以下深度框架:
(1)Caffe2:早期出的一个框架,比较底层,难使用
(3)Paddlepaddle:百度出的:很好用,但是没有占领市场
(4)mxnet:也是中国人出的,很好用,但是也是没有占领市场。
(5)pytorch:学术界主流的框架
(6)Tensorflow:工业街主流的框架
(7)keras:keras现在已经和Tensorflow合并,使用的时候相当于封装了Tensorflow更高级的API,使用起来非常简单。

  深度学习的每一个应用的使用,其实很简单,简单来说,都是要经历三个过程,第一个是定义网络,第二个是定义损失函数,最后优化网络。

  本文章主要使用的是Tensorflow来对各种算法进行实现,因为学习了它的相关API之后,对于其他的框架比如pytorch都可以非常轻松快速的上手,区别不是很大。

  Tensorflow时Google大脑小组开发的,采用数据流图,支持多中平台-GPU、CPU、移动设备;有以下特性:
(1)高度的灵活性
(2)自动求微分(基本每个深度框架必须解决的问题,会方便解决很多问题)
(3)真正的可移植性
(4)多语言支持
(5)产品和科研结合
(6)性能最优化

  Tensorflow的版本发展
(1)2015.11 Tensorflow宣布开源
(2)2015.12 支持GPU,支持python3.3
(3)2016.4 支持分布式的Tensorflow
(4)2016.11 支持Windows
(5)2017.2 性能改进,API稳定性
(6)2017.4 Keras集成
(7)2017.8 更高级的API发行,预估器,支持TPU
(8)2017.11 Eager execution模式,Tensorflow Lite
(9)2018.3 推出TF Hub,Tensorflow.js,Tensorflow Extended
(10)2018.5 Cloud TPU模块与管道
(11)2018.6 新的分步式策略API发行,概率编程工具
(12)2018.8 Cloud Big Table集成
(13)2018.10 可重用性的API改进
(14)2019.3 Tensorflow2.0 Alpha
(15)2019.10 Tensorflow2.0正式版本
(16)2020.1 发布Tensorflow2.1 不在区分GPU和CPU版本,会自动查看

  Tensorflow1.0架构,主要由Keras,Estimator,Datasets,layers,Distribution engine构成如下:

  Tensorflow1.0主要是提成了训练速度,而且可以在移动设备上运行,另外,还引入了更高级别的API,如tf.laryerstf.metricstf.lossestf.keras。最后还有Tensorflow的调试器,支持dorcker镜像,引入了tensorflow serving服务。

  Tensorflow2 架构,主要由两层,第一层是训练层,另一个是部署层。如下图

  Tensorflow2 架构的特性
(1)使用tf.data加载数据
(2)使用tf.keras构建模型,也可以使用premade estimator来验证模型,使用tensorflow hub进行迁移学习
(3)使用eager mode进行运行和调试
(4)使用分发策略来进行分布式训练
(5)导出到SaveModel
(6)使用Tensorflow Server、TensorFlow Lite、TensorFlow.js部署模型
(7)强大的跨平台能力,Tensorflow2服务直接通过HTTP/REST或者GRPC/协议缓冲区实现,TensorFlow Lite可以直接部署在Android、IOS和嵌入式系统上,TensorFlow.js在javascript中部署模型
(8)Tf.keras功能API和子类API,允许创建负责的拓扑结构
(9)自定义训练逻辑,使用tf.GradientTape和tf.custom_gradient进行更细粒度的控制
(10)底层API可以与高层结合使用,完全的可定制
(11)高级扩展:Ragged Tensors、Tensor2Tensor

  下面本文用一个简单的应用来讲以下如何使用Tensorflow框架,

2 tf.keras核心概念

2.1 tf.keras简介

  Keras 是一个高级的 (high-level) 深度学习框架,作者是 Francois Chollet。Keras 可以以两种方法运行:
(1)以 TensorFlow, CNTK, 或者 Theano 作为后端 (backend) 运行
(2)在 TensorFlow 里面直接运行,使用语句 tf.keras,本文使用这个

2.2 tf.完整流程

  很多学习过Scikit-learn的框架,而Keras的完整流程和它也差不多,大致流程如图所示(左图为Scikit-learn流程,右图为Keras流程):

代码实例:

# 导入包
# 导入基础包
import matplotlib as mpl
import matplotlib.pyplot as plt
import pandas as pd
import numpy as np
# 导入tf
import tensorflow as tf
print(tf.__version__)
print(tf.keras.__version__)fashion_minist = tf.keras.datasets.fashion_mnist
(x_train_all,y_train_all),(x_test,y_test) = fashion_minist.load_data()print(x_train_all[0]) # 第一条数据,有很多个特征,每一个特征由一个一维向量表示
x_train_all = x_train_all / 255.0 # 由于数据分散,所以要进行归一化,让每个特征的各个向量都差异不要太大
x_test = x_test / 255.0
print(x_train_all[0])#将训练集合划分为数据集和校验集
x_train , x_valid = x_train_all[5000:],x_train_all[:5000]
y_train , y_valid = y_train_all[5000:],y_train_all[:5000]print(x_train.shape, y_train.shape)
print(x_valid.shape, y_valid.shape)
print(x_test.shape, y_test.shape)# 展示一张图片
def show_image(img_arr):plt.imshow(img_arr, cmap='binary')plt.show()
show_image(x_train[0])
print(y_train[0])
show_image(x_valid[0])
print(y_valid[0])
show_image(x_test[0])
print(y_test[0])# 构建模型
model = tf.keras.models.Sequential() # 相当于一个容器
model.add(tf.keras.layers.Flatten(input_shape=[28,28]))
model.add(tf.keras.layers.Dense(300,activation=tf.keras.activations.relu))
model.add(tf.keras.layers.Dense(100,activation=tf.keras.activations.relu))
model.add(tf.keras.layers.Dense(10,activation=tf.keras.activations.softmax))# 模型编译
model.compile(loss = tf.keras.losses.sparse_categorical_crossentropy,optimizer=tf.keras.optimizers.SGD(lr=0.001),metrics=['accuracy']
)history = model.fit(x_train, y_train, epochs = 5, validation_data=(x_valid, y_valid))print(type(history))
print(type(history.history))
print(history.history)def plot_learing_show(history):pd.DataFrame(history.history).plot(figsize=(8, 5))plt.grid(True)plt.gca().set_ylim(0,1)plt.show()plot_learing_show(history)
test_history = model.evaluate(x_test,y_test)
print(test_history)
print(y_test[9])
test_class_list = model.predict_classes(x_test)
print(test_class_list[9])
show_image(x_test[9])

2.3 神经网络中的数据格式(重要)

  我们一定要非常清楚我们输入到模型的数据是什么样子的,并不是说直接就把比如视频或者文本文件直接输入到模型中,而是要转化为模型所能处理的样式才可以。

  现实生活中一般会遇到的类型有:
(1)结构性的数据:(数据表,如班级名单,股票预测等)
(2)非结构性的数据:(序列(文本),图片,视频)

  神经网络中可以使用的数据
(1)数据表-2D数据 形状=(样本数,特征数)。一般称为2D张量,其实就是举证,一般可以用csv或者excel来存储。

(2)序列类-3D数据 形状=(样本数,步长(每段文字的长度),特征数(每个字的特征数)),一般称为3D张量,通常用来表示文本。(假设,收集一百万条新闻,那么整个数据集的形状为(10000,280,128))

(3)图像类-4D数据 形状=(样本数,宽,高,通道数)。一般称为4D张量,通常用来表示图像。

(4)视频类-5D数据 形状=(样本数,帧数,宽,高,通道数)。一般称为5D张量,通常用来表示视频。

2.4 tf.keras中的神经网络

  现实中的神经由很多的神经元组成,这些神经元有两种状态,一个是激发状态,一个则是
抑制状态。人工神经网络主要由大量的神经元以及它们之间的有向链接构成。

  神经网络主要考虑三方面的事情,一个是神经元的激活规则(使用激活函数):主要是指神经元输入到输出之间的映射关系,一般称为非线性函数。另一个是网络的拓扑结构,就是指整个神经元是如何链接的。第三个是学习算法,就是通过训练数据来学习神经网络的参数,让每个神经元到哪种程度才会触发做一个调整。

  深度学习的网络结构有三种类型,前馈网络,记忆网络和图网络,但是大多数网络都是复合型的结构,包含了多种网络。

  在tf.keras中神经网络通常由以下四个方面组成:
(1)层(layers)和 模型(models)
(2)输入(input)和输出(output)
(3)损失函数(loss)
(4)优化器(optimizer)

  通常神经网络里面的基本数据类型是,而 tf.keraslayers 是层的集合;不同数据格式或不同数据处理类型需要用到不同的层,比如:
(1)形状为 (样本数,特征数) 的 2D 数据,通常用全连接层,对应 tf.keras 里面的 Dense层;
(2)形状为 (样本数,步长,特征数) 的 3D 序列数据,通常用循环层,对应tf.keras 里面的 RNN, GRULSTM
(3)形状为 (样本数,宽,高,通道数) 的 4D 图像数据,通常用二维卷积层,对应tf.keras 里面的 Conv2D

  对于Dense层,经常会做Flatten;

  损失函数:对于分类、回归、序列预测等常见问题,你可以遵循一些简单的指导原则来选择正确的损失函数。
(1)对于二分类问题,用二元交叉熵(binary crossentropy)损失函数
(2)对于多分类问题,用分类交叉熵(categorical crossentropy)损失函数
(3)对于回归问题,用均方误差(mean-squared error)损失函数
(4)对于序列学习问题,用联结主义时序分类(CTC,connectionist temporal classification)损失函数
(5)有时在面对真正全新的问题时,你还需要自主的设计损失函数。

  而优化器常用在tf.keras中有:
(1)Adagrad
(2)Adadelta
(3)RMSprop
(4)Adam
(5)AdaMax
(6)Nadam
(7)AMSGrad

2.5 tf.keras中模型的三种构建方式

  三种模型的构建方式分别称为序列式构建,函数式构建和子类化构建

  序列式构建如下图所示:

# 序列式构建第一种方式(如果模型中有分支就不好处理了)
model = keras.models.Sequential() #相当于一个容器
model.add(keras.layers.Flatten(input_shape=[28,28])) #拉直
model.add(keras.layers.Dense(256, activation='relu'))
model.add(keras.layers.Dense(100, activation='relu'))
model.add(keras.layers.Dense(10, activation='softmax'))
# 序列式构建第二种方式
model2 = keras.models.Sequential([keras.layers.Flatten(input_shape=[28,28]),keras.layers.Dense(256, activation=keras.activations.relu),keras.layers.Dense(100, activation=keras.activations.relu),keras.layers.Dense(10, activation=keras.activations.softmax)]
)

  函数式构建如下图所示:

# 函数式构建 记住一句话:把层当做函数来使用
input = Input(shape=[28,28]) #输入
x = Flatten()(input) #把Flatten()当成函数f, 简化一下呢 x = f(input)
x = Dense(256, activation='relu')(x) #把Dense(256, activation='relu') 当成函数g 简化一下呢 x = g(x)
x = Dense(100, activation='relu')(x) #把Dense(100, activation='relu') 当成函数p 简化一下呢 p = p(x)
output = Dense(10, activation='softmax')(x) #把Dense(10, activation='softmax') 当成函数h 简化一下呢 h = h(x)model3 = keras.Model(inputs = [input], outputs = [output]) #最后用keras.Model将input和output建立关系

  序列式函数式都是声明式编程(declarative programming),它描述目标的性质,让计算机明白目标,而非流程。具体来说,它们都是声明哪些层应该按什么顺序来添加,层与层以什么样的方式连接,所有声明完成之后再给模型喂数据开始训练,这种方法有好有坏:
(1)好处:模型很容易保存、复制和分享,模型结构也容易展示和分析,因此调试起来比较容易;
(2)坏处:是个静态模型,很多情况模型有循环(loops)和条件分支(conditional branching),这时我们更需要命令式编程(imperative programming)了。

  子类化构建:(首先引入必要的包,然后构建一个类集成Model,然后重写__init__()方法和call()方法即可)

class MnistModel(keras.Model):def __init__(self, **kwargs): # 类似序列式定义各个层次super().__init__(**kwargs)self.hidden_layer1 = Dense(units=256, activation='relu')self.hidden_layer2 = Dense(units=100, activation='relu')self.output_layer = Dense(units=10, activation='softmax')def call(self, input):  # 类似函数式,将每次之间的关系进行关联x = Flatten()(input)hidden_layer1 = self.hidden_layer1(x)hidden_layer2 = self.hidden_layer2(hidden_layer1)output = self.output_layer(hidden_layer2)return outputmodel4 = MnistModel()
model4.build(input_shape=(None, 784))

  构造函数负责创建不同的层,在本例中创建了一个隐藏层 self.hidden 和一个输出层self.main_output
  call() 函数负责各种计算,注意到该函数有个参数是 input

3 实战1

3.1 电影评论情感分类

  下面引入一个电影评论情感分类的一个应用来进一步掌握整个深度学习的过程。

  整个流程如下:(大部分应用都是这个步骤)
(1)导入数据
(2)数据预处理
(3)构建模型定义损失函数和优化器
(4)模型训练
(5)评估

代码实例:

# 导包
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import os# 导入tf
import tensorflow as tf
from tensorflow import keras
print(tf.__version__)
print(keras.__version__)# 加载数据集
# num_words:只取10000个词作为词表
imdb = keras.datasets.imdb
(train_x_all, train_y_all),(test_x, test_y)=imdb.load_data(num_words=10000)# 查看数据样本数量
print("Train entries: {}, labels: {}".format(len(train_x_all), len(train_y_all)))
print("Train entries: {}, labels: {}".format(len(test_x), len(test_y)))print(train_x_all[0])   # 查看第一个样本数据的内容print(len(train_x_all[0]))  # 查看第一个和第二个训练样本的长度,不一致
print(len(train_x_all[1]))# 构建字典  两个方法,一个是id映射到字,一个是字映射到id
word_index = imdb.get_word_index()word2id = { k:(v+3) for k, v in word_index.items()}
word2id['<PAD>'] = 0
word2id['START'] = 1
word2id['<UNK>'] = 2
word2id['UNUSED'] = 3id2word = {v:k for k, v in word2id.items()}def get_words(sent_ids):return ' '.join([id2word.get(i, '?') for i in sent_ids])sent = get_words(train_x_all[0])
print(sent)# 句子末尾进行填充
train_x_all = keras.preprocessing.sequence.pad_sequences(train_x_all,value=word2id['<PAD>'],padding='post', #pre表示在句子前面填充, post表示在句子末尾填充maxlen=256
)test_x = keras.preprocessing.sequence.pad_sequences(test_x,value=word2id['<PAD>'],padding='post',maxlen=256
)
print(train_x_all[0])
print(len(train_x_all[0]))
print(len(train_x_all[1]))#模型编写
vocab_size = 10000
model = keras.Sequential()
model.add(keras.layers.Embedding(vocab_size, 16))
model.add(keras.layers.GlobalAveragePooling1D())
model.add(keras.layers.Dense(16, activation='relu'))
model.add(keras.layers.Dense(1, activation='sigmoid'))model.summary()model.compile(optimizer='adam', loss=keras.losses.binary_crossentropy, metrics=['accuracy'])train_x, valid_x = train_x_all[10000:], train_x_all[:10000]
train_y, valid_y = train_y_all[10000:], train_y_all[:10000]# callbacks Tensorboard, earlystoping, ModelCheckpoint
# 创建一个文件夹,用于放置日志文件
logdir = os.path.join("callbacks")
if not os.path.exists(logdir):os.mkdir(logdir)
output_model_file = os.path.join(logdir, "imdb_model.h5")# 当训练模型到什么程度的时候,就停止执行 也可以直接不用,然后直接训练
callbacks = [# 保存的路径(使用TensorBoard就可以用命令,tensorboard --logdir callbacks 来分析结果)keras.callbacks.TensorBoard(logdir),# 保存最好的模型keras.callbacks.ModelCheckpoint(filepath=output_model_file, save_best_only=True),# 当精度连续5次都在1乘以10的-1次方之后停止训练keras.callbacks.EarlyStopping(patience=5, min_delta=1e-3)
]history = model.fit(train_x, train_y,epochs=40,batch_size=512,validation_data=(valid_x, valid_y),callbacks = callbacks,verbose=1   # 设置为1就会打印日志到控制台,0就不打印)def plot_learing_show(history):pd.DataFrame(history.history).plot(figsize=(8,5))plt.grid(True)plt.gca().set_ylim(0,1)plt.show()plot_learing_show(history)result = model.evaluate(test_x, test_y)
print(result)test_classes_list = model.predict_classes(test_x)
print(test_classes_list[1][0])
print(test_y[1])

3.2 earlystoping的使用

  在模型训练过程中,可能会出现过拟合的情况,所以可以使用earlystoping函数来让模型提前结束训练。具体使用方法如下:简单总结如下
(1)定义一个callbacks列表,加载存在的模型,加载EarlyStopping。
(2)在模型训练的使用,把参数callbacks加上上面的列表即可。
(3)如果想用tensorboard打开一个图形化界面来分析训练过程,那么还可以在callbacks外面加入一个TensorBorard。

# callbacks Tensorboard, earlystoping, ModelCheckpoint
# 创建一个文件夹,用于放置日志文件
logdir = os.path.join("callbacks")
if not os.path.exists(logdir):os.mkdir(logdir)
output_model_file = os.path.join(logdir, "imdb_model.h5")# 当训练模型到什么程度的时候,就停止执行 也可以直接不用,然后直接训练
callbacks = [# 保存的路径(使用TensorBoard就可以用命令,tensorboard --logdir callbacks 来分析结果)keras.callbacks.TensorBoard(logdir),# 保存最好的模型keras.callbacks.ModelCheckpoint(filepath=output_model_file, save_best_only=True),# 当精度连续5次都在1乘以10的-1次方之后停止训练keras.callbacks.EarlyStopping(patience=5, min_delta=1e-3)
]history = model.fit(train_x, train_y,epochs=40,batch_size=512,validation_data=(valid_x, valid_y),callbacks = callbacks,verbose=1   # 设置为1就会打印日志到控制台,0就不打印)

4 实战2

4.1 回归问题预测汽车燃油效率

  回归问题在实际中很常见,如预测房屋价格、⽓温、销售额等连续值的问题。与回归问题不同,分类问题中模型的最终输出是⼀个离散值。我们所说的图像分类、垃圾邮件识别、疾病检测等输出为离散值的问题都属于分类问题的范畴。

  预测汽车燃油效率:使用经典的 Auto MPG 数据集,构建了一个用来预测70年代末到80年代初汽车燃油效率的模型。为了做到这一点,本文将为该模型提供许多那个时期的汽车描述。这个描述包含:气缸数,排量,马力以及重量

  MPG数据集:该数据集取自卡内基梅隆大学维护的StatLib库。该数据集用于1983年美国统计协会博览会。数据涉及以每加仑英里为单位的城市循环燃料消耗,将根据3个多值离散值和5个连续属性进行预测。

代码实例:

# 导包
import matplotlib as mpl
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import osimport pathlib
import seaborn as sns# 导入tf
import tensorflow as tf
from tensorflow import kerasprint(tf.__version__)
print(keras.__version__)# 加载数据集
dataset_path = keras.utils.get_file('auto-mpg.data',"http://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")
print(dataset_path)# 使用pandas导入数据集
column_names = ['MPG', 'Cylinders', 'Displacement', 'Horsepower', 'Weight', 'Acceleration', 'Model Year', 'Origin']raw_dataset = pd.read_csv(dataset_path, names=column_names, na_values='?', comment='\t',sep=' ', skipinitialspace=True)dataset = raw_dataset.copy()
print(dataset.tail())# 数据清洗
print(dataset.isna().sum())
dataset = dataset.dropna()
print(dataset.isna().sum())# 将origin转换成one-hot编码
origin = dataset.pop('Origin')
dataset['USA'] = (origin == 1) * 1.0
dataset['Europe'] = (origin == 2) * 1.0
dataset['Japan'] = (origin == 3) * 1.0
print(dataset.tail())# 拆分数据集 拆分成训练集和测试集
train_dataset = dataset.sample(frac=0.8, random_state=0)
test_dataset = dataset.drop(train_dataset.index)# 总体数据统计
train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()
print(train_stats)# 从标签中分类特征
train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')print(train_labels[0])# 数据规范化
def norm(x):return (x - train_stats['mean']) / train_stats['std']norm_train_data = norm(train_dataset)
norm_test_data = norm(test_dataset)# 构建模型
def build_model():model = keras.Sequential([keras.layers.Dense(512, activation='relu', input_shape=[len(train_dataset.keys())]),keras.layers.Dense(256, activation='relu'),keras.layers.Dense(128, activation='relu'),keras.layers.Dense(64, activation='relu'),keras.layers.Dense(1)])optimizer = keras.optimizers.RMSprop(0.001)model.compile(loss='mse', optimizer=optimizer, metrics=['mae', 'mse'])return model# 构建防止过拟合的模型,加入正则项L1和L2
def build_model2():model = keras.Sequential([keras.layers.Dense(512, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001),input_shape=[len(train_dataset.keys())]),keras.layers.Dense(256, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001)),keras.layers.Dense(128, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001)),keras.layers.Dense(64, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001)),keras.layers.Dense(1)])optimizer = keras.optimizers.RMSprop(0.001)model.compile(loss='mse', optimizer=optimizer, metrics=['mae', 'mse'])return model# 构建防止过拟合的模型,加入正则项L1
def build_model3():model = keras.Sequential([keras.layers.Dense(512, activation='relu', kernel_regularizer=keras.regularizers.l1(0.001),input_shape=[len(train_dataset.keys())]),keras.layers.Dense(256, activation='relu', kernel_regularizer=keras.regularizers.l1(0.001)),keras.layers.Dense(128, activation='relu', kernel_regularizer=keras.regularizers.l1(0.001)),keras.layers.Dense(64, activation='relu', kernel_regularizer=keras.regularizers.l1(0.001)),keras.layers.Dense(1)])optimizer = keras.optimizers.RMSprop(0.001)model.compile(loss='mse', optimizer=optimizer, metrics=['mae', 'mse'])return model# 构建防止过拟合的模型,加入正则项L2
def build_model4():model = keras.Sequential([keras.layers.Dense(512, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001),input_shape=[len(train_dataset.keys())]),keras.layers.Dense(256, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001)),keras.layers.Dense(128, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001)),keras.layers.Dense(64, activation='relu', kernel_regularizer=keras.regularizers.l2(0.001)),keras.layers.Dense(1)])optimizer = keras.optimizers.RMSprop(0.001)model.compile(loss='mse', optimizer=optimizer, metrics=['mae', 'mse'])return model# 构建模型 使用dropout来防止过拟合
def build_model5():model = keras.Sequential([keras.layers.Dense(512, activation='relu', input_shape=[len(train_dataset.keys())]),keras.layers.Dropout(0.5),keras.layers.Dense(256, activation='relu'),keras.layers.Dropout(0.5),keras.layers.Dense(128, activation='relu'),keras.layers.Dropout(0.5),keras.layers.Dense(64, activation='relu'),keras.layers.Dropout(0.5),keras.layers.Dense(1)])optimizer = keras.optimizers.RMSprop(0.001)model.compile(loss='mse', optimizer=optimizer, metrics=['mae', 'mse'])return model# 构建模型  使用正则化L1和L2以及dropout来预测
def build_model6():model = keras.Sequential([keras.layers.Dense(512, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001),input_shape=[len(train_dataset.keys())]),keras.layers.Dropout(0.5),keras.layers.Dense(256, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001)),keras.layers.Dropout(0.5),keras.layers.Dense(128, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001)),keras.layers.Dropout(0.5),keras.layers.Dense(64, activation='relu', kernel_regularizer=keras.regularizers.l1_l2(0.001)),keras.layers.Dropout(0.5),keras.layers.Dense(1)])optimizer = keras.optimizers.RMSprop(0.001)model.compile(loss='mse', optimizer=optimizer, metrics=['mae', 'mse'])return modelmodel = bulid_model()
model.summary()early_stop = keras.callbacks.EarlyStopping(monitor='val_loss', patience=200)
# 模型训练
history = model.fit(norm_train_data, train_labels, epochs=1000, validation_split=0.2, verbose=0, callback=[early_stop]
)def plot_history(history):hist = pd.DataFrame(history.history)hist['epoch'] = history.epochplt.figure()plt.xlabel('Epoch')plt.ylabel('Mean Abs ERROR [PMG]')plt.plot(hist['epoch'], hist['mae'], label='Train Error')plt.plot(hist['epoch'], hist['val_mae'], label='Val Error')plt.ylim([0, 5])plt.legend()plt.figure()plt.xlabel('Epoch')plt.ylabel('Mean Squaree ERROR [PMG]')plt.plot(hist['epoch'], hist['mse'], label='Train Error')plt.plot(hist['epoch'], hist['val_mse'], label='Val Error')plt.ylim([0, 20])plt.legend()plt.show()plot_history(history)# 看下测试集合的效果
loss, mae, mse = model.evaluate(norm_test_data, test_labels, verbose=2)
print(loss)
print(mae)
print(mse)# 做预测
test_preditions = model.predict(norm_test_data)
test_preditions = test_preditions.flatten()
plt.scatter(test_labels, test_preditions)
plt.xlabel('True Values [MPG]')
plt.ylabel('Predictios [MPG]')
plt.axis('equal')
plt.axis('square')
plt.xlim([0, plt.xlim()[1]])
plt.ylim([0, plt.ylim()[1]])
_ = plt.plot([-100, 100], [-100, 100])# 看一下误差分布
error = test_preditions - test_labels
plt.hist(error, bins=25)
plt.xlabel("Prediction Error [MPG]")
_ = plt.ylabel('Count')

4.2 回归问题的评价指标

  也就是我们说的用于回归问题的损失函数使用什么的问题。一般我们常用的三个函数是:均方误差MSE,军方根误差RMSE,和平均相对误差MAE
(1)均方误差:MSE(Mean Squared Error)
     M S E = 1 m ∑ i = 1 m ( y i − y ^ i ) 2 MSE = \frac{1}{m}\sum\limits_{i=1}^m(y_i-\hat{y}_i)^2 MSE=m1i=1m(yiy^i)2
(2)均方根误差:RMSE(Root Mean Squard Error)
     M S E = 1 m ∑ i = 1 m ( y i − y ^ i ) 2 MSE =\sqrt{ \frac{1}{m}\sum\limits_{i=1}^m(y_i-\hat{y}_i)^2} MSE=m1i=1m(yiy^i)2


(3)平均绝对误差:MAE(Mean Absolute Error)
     M S E = 1 m ∑ i = 1 m ∣ y i − y ^ i ∣ MSE = \frac{1}{m}\sum\limits_{i=1}^m|y_i-\hat{y}_i| MSE=m1i=1myiy^i

4.2 过拟合和欠拟合

  过拟合是指模型在训练集上表现很好,但是在训练集外的数据集上表现一般。产生原因如下:
(1)训练数据过少或存在噪音,无法对整个数据的分布进行估计
(2)特征维度过多,求解模型中没有那么多的特征值得重用
(3)在对模型进行过度训练(overtraining)时,常常会导致过拟合

  常见的防止过拟合的方法有:
(1)数据清洗
(2)增加数据集
(3)early stopping
(4)数据集扩增(Data augmentation)
(5)正则化(Regularization)
(6)Dropout(神经网络)

  欠拟合指的是模型没有很好地捕捉到数据特征,导致拟合的函数在训练集上表现效果差,
预测的准确率低。产生原因如下:
(1)模型复杂度过低
(2)特征量过少

  常见的防止欠拟合的方法有:
(1)添加其他特征项(e.g.,“组合”、“泛化”、“相关性”),模型出现欠拟合的时候是因为特征项不够导致的,可以添加其他特征项来很好地解决。
(2)添加多项式特征,例如将线性模型通过添加二次项或者三次项使模型泛化能力更强
(3)减少正则化参数,正则化的目的是用来防止过拟合的,当模型出现了欠拟合,则需要减少正则化参数。

4.2.1 正则化

  所谓的使用正则化来防止过拟合,就是在原来 Loss Function 的基础上,加了一些正则化项,或者叫做模型复杂度惩罚项

4.2.1.1 L1正则化

  在原始的损失函数后面加上一个L1正则化项,即全部权重 w 的绝对值的和,再乘以λ/n。

  则损失函数变为:

  •      C = C 0 + λ n ∑ i ∣ w i ∣ C=C_0+\frac{\lambda}{n}\sum\limits_i|w_i| C=C0+nλiwi

  则对应的导数为:

  •      ∂ C ∂ w = ∂ C 0 ∂ w + λ n s g n ( w ) \frac{\partial{C}}{\partial{w}} = \frac{\partial{C_0}}{\partial{w}}+\frac{\lambda}{n}sgn(w) wC=wC0+nλsgn(w)

  其中 sgn(w)只是简单地取 w 各个元素地正负号。

  •      s g n ( w ) = { 1 , w > 0 0 , w = 0 − 1 , w < 0 sgn(w)=\begin{cases}1,\quad w\gt0 \\ 0,\quad w=0\\ -1,\quad w\lt0 \end{cases} sgn(w)=1,w>00,w=01,w<0

  梯度下降时权重 w更新变为:

  •      w − − > w ′ = w − η λ n s g n ( w ) − η ∂ C 0 ∂ w w --> w' = w-\frac{\eta{\lambda}}{n}sgn(w)-\eta\frac{\partial{C_0}}{\partial{w}} w>w=wnηλsgn(w)ηwC0

  (1)当w=0时,|w|是不可导的。所以我们仅仅能依照原始的未经正则化的方法去更新。
  (2)当w>0时,sgn(w)>0,则梯度下降时更新后的w变小。
  (3)当w<0时,sgn(w)>0,则梯度下降时更新后的w变大。换句话说,L1正则化使得权重w往0靠,使网络中的权重尽可能为0,也就相当于减小了网络复杂度,防止过拟合

  这也就是L1正则化会产生更稀疏(sparse)的解的原因。此处稀疏性指的是最优值中的一些参数为0,L1正则化的稀疏性质已经被广泛地应用于特征选择机制,从可用的特征子集中选择出有意义的特征。

4.2.1.2 L2正则化

  L2正则化通常被称为权重衰减(weight decay),就是在原始的损失函数后面再加上一个L2正则化项,即全部权重w的平方和,再乘以λ/2n。

  则损失函数变为:

  •      C = C 0 + λ 2 n ∑ i w i 2 C=C_0+\frac{\lambda}{2n}\sum\limits_iw_i^2 C=C0+2nλiwi2

  对应的梯度为:

  •      ∂ C ∂ w = ∂ C 0 ∂ w + λ n w \frac{\partial{C}}{\partial{w}} = \frac{\partial{C_0}}{\partial{w}}+\frac{\lambda}{n}w wC=wC0+nλw

  •      ∂ C ∂ b = ∂ C 0 ∂ b \frac{\partial{C}}{\partial{b}} = \frac{\partial{C_0}}{\partial{b}} bC=bC0

  能够发现L2正则化项对偏置 b 的更新没有影响,可是对于权重w的更新有影响:

  •      w − − > w ′ = w − η ∂ C 0 ∂ w − η λ n w = ( 1 − η λ n ) w − η ∂ C 0 ∂ w w --> w' = w-\eta\frac{\partial{C0}}{\partial{w}}-\frac{\eta\lambda}{n}w=(1-\frac{\eta\lambda}{n})w-\eta\frac{\partial{C_0}}{\partial{w}} w>w=wηwC0nηλw=(1nηλ)wηwC0

  能够发现L2正则化项对偏置 b 的更新没有影响,可是对于权重w的更新有影响,这里的 η 、 n 、 λ \eta、n、\lambda ηnλ都是大于0的,所以 1 − f r a c η λ n 1-frac{\eta\lambda}{n} 1fracηλn小于1。因此在梯度下降过程中,权重w将逐渐减小,趋向于0但不等于0.这也就是权重衰减(weight decay)的由来。

  为什么L2正则化可以使得权重参数w变小的效果,为什么能防止过拟合呢?因为更小的权重参数w以为着模型的复杂度更低,对训练数据的拟合刚刚好,不会过分拟合训练数据,从而提高模型的泛化能力。

4.2.2 Dropout

  正则是通过在代价函数后面加上正则项来防止模型过拟合的。而在神经网络中,有一种方法是通过修改神经网络本身结构来实现的,其名为Dropout。该方法是在对网络进行训练时用一种技巧(trick),对于如下所示的三层人工神经网络:

  对于上图所示的网络,在训练开始时,随机得删除一些(可以设定为一半,也可以为1/3,1/4等)隐藏层神经元,即认为这些神经元不存在,同时保持输入层与输出层神经元的个数不变,这样便得到如下的神经网络:

  然后按照BP学习算法对神经网络中的参数进行学习更新(虚线连接的单元不更新,因为认为这些神经元被临时删除了)。这样一次迭代更新便完成了。下一次迭代中,同样随机删除一些神经元,与上次不一样,做随机选择。这样一直进行下去,直至训练结束。Dropout方法是通过修改神经网络中隐藏层的神经元个数来防止神经网络的过拟合。

自然语言处理(1)深度学习基础及其通用模板相关推荐

  1. Python深度学习(一)深度学习基础

    翻译自Deep Learning With Python(2018) 第一章 深度学习基础:https://www.jianshu.com/p/6c08f4ceab4c 第二章 深度学习的数学构建模块 ...

  2. 深度学习第一讲之深度学习基础

    技术交流qq群: 659201069 深度学习第一讲之深度学习基础 转载请注明出处! 本篇博文从what.why.when.who.where.how五个方面来分析深度学习,接下来讲如何入门,我门将通 ...

  3. 自然语言处理与深度学习: 集智俱乐部活动笔记

    自然语言处理与深度学习: 集智俱乐部活动笔记 04 Jul 2016 目录 简介 自然语言处理的基本任务 对语言进行建模的若干方法 语言模型简介 N-gram 语言模型 基于神经网络的语言模型 语言的 ...

  4. 深度学习基础之卷积神经网络

    摘要 受Hubel和Wiesel对猫视觉皮层电生理研究启发,有人提出卷积神经网络(CNN),Yann Lecun 最早将CNN用于手写数字识别并一直保持了其在该问题的霸主地位.近年来卷积神经网络在多个 ...

  5. 深度学习基础篇(一)

    深度学习基础篇(一) Part I 深度学习基础 本书1-4章将带你了解一些基本概念:什么是深度学习,它可以用来做什么以及它如何工作.此外,熟悉使用深度学习解决数据问题的典型工作流程.如果还没怎么了解 ...

  6. 资源 | Intel发布AI免费系列课程3部曲:机器学习基础、深度学习基础以及TensorFlow基础

    翻译 | AI科技大本营(公众号ID:rgznai100) 校对 | 成龙 编辑 | 明明 Intel于近期发布了三门AI系列的免费课程,分别是关于机器学习基础.深度学习基础.TensorFlow基础 ...

  7. 深度学习基础(基本概念、优化算法、初始化、正则化等)

    2020-04-25 16:29:09 引言 深度学习目前已成为发展最快.最令人兴奋的机器学习领域之一,许多卓有建树的论文已经发表,而且已有很多高质量的开源深度学习框架可供使用.然而,论文通常非常简明 ...

  8. 【完结】有三AI阿里云的深度学习基础课程暂时完结,欢迎扩散学习

    2021年3月份有三AI与阿里天池联合推出了深度学习系列课程, 课程内容包括人工智能与深度学习发展背景,深度学习典型应用,卷积神经网络,循环神经网络,生成对抗网络,深度学习开源框架等内容,目前已经基本 ...

  9. 人工智能 - paddlepaddle飞桨 - 深度学习基础教程 - 个性化推荐

    人工智能 - paddlepaddle飞桨 - 深度学习基础教程 - 个性化推荐 本教程源代码目录在book/recommender_system,初次使用请您参考Book文档使用说明. 说明: 硬件 ...

最新文章

  1. linux定时任务Crond基础概念原理介绍01
  2. 【干货书】数据科学家统计学基础:R和Python实战
  3. 字节跳动---万万没想到之抓捕孔连顺
  4. 2021技术领域趋势报告:Rust继续增长、低代码是重要趋势
  5. Java for LeetCode 042 Trapping Rain Water
  6. Java sdk及tomcat安装设置
  7. 大疆地理围栏系统预防无人机闯入机场
  8. 科技也能这么酷:无人驾驶轮椅要来啦
  9. 测试工程师,必须掌握的shell变量知识
  10. yum源分类:Linux
  11. 新能源专属车险可在线投保 80%车主基准保费下降
  12. excel函数交叉定位查找内容+根据内容查找行列号(反向查找)
  13. 2021亚洲最佳职场中国大陆区企业公布:工业富联、特斯拉等上榜;黑人牙膏将更名为好来 | 美通社头条...
  14. 关于M0内核MCU的Bootloader编写
  15. 现在移动端还用rem吗?nonono
  16. python中abs和fabs的区别_Python - abs vs fabs
  17. 教育类型网站用户体验分析——以UMU学习平台、学生安全教育平台、师路南通为例...
  18. 索尼美能达50微-版本区别及实拍测评(sony/minolta)50 f2.8 macro
  19. 从网络安装debian到使用中遇到的问题
  20. 中e管家投资理财做好这六件事

热门文章

  1. matlab trapz求二重积分,matlab求积分(超详细,含int integral integral2/3 quad trapz
  2. jstree禁用父节点点击_Jstree选中父节点时禁用子节点也被选中
  3. 数据结构自动组卷系统设计文档
  4. java设置浏览器缓存_JAVA WEB过滤器设置浏览器缓存
  5. 计算机辅助设计教学视频,计算机辅助设计(二维平面)
  6. 你不可不知的《哈利波特》秘密
  7. FSCapture 取色工具(绿色版 )
  8. Windows 中,显示 USB图标但是点击无效的解决办法
  9. java将数字格式化为万或者千亿或者 以亿为单位
  10. OpenMMLab-AI实战营第二期——2-1.人体关键点检测与MMPose