人工神经网络 Artificial neural networks(ANN)

一、神经元->感知器->多层感知器

感知器(The Perceptron)

神经元:

神经元是线性阈值单元(LTU)、又叫阈值逻辑单元(TLU)
LTU的工作:
首先每个输入都有一个对应的权重
然后LTU对其加权求和:z = w1 x1 + w2 x2 + ⋯ + wn xn = x⊺ w
再对结果应用一个阶跃函数产生最后的输出:hw(x) = step(z)=step( x⊺ w)

其中阶跃函数step function有:

感知器就是由多个TLU组成的单层结构


有一个额外的偏差特征(x0 = 1),偏差特征通常用偏差神经元来表示,它永远只输出1.

全连接层(dense layer):

一个层的所以单个神经元都与前一层的神经元连接。(上图就是全连接层)
计算完全连接层的输出:
其中:X表示输入特征矩阵(每行表示每个实例、每列表示每个实例对应的特征值)
W是权重矩阵–除了偏差神经元以外的所有神经元权重(每行是输入神经元个数、每列是链接下一层神经元的个数,它们之间的连接权重组成权重矩阵)
b是偏差向量(偏差神经元与人工神经元之间的连接权重)
圈圈加个斜杠(打不出来那个符号)表示的是激活函数:当人工神经元都是TLU时,激活函数就是阶跃函数(上面提及的两种阶跃函数)

感知器学习规划(权重更新)

感知器的学习规则就是权重更新,下一步的连接权重由上一个连接权重更新。
感知器的收敛定理–>训练实例线性可分–>收敛到一个解
SkLearn提供了实现单一LTU网络的Perceptron类。

import numpy as np from sklearn.datasets
import load_iris from sklearn.linear_model
import Perceptron iris = load_iris()
X = iris.data[:, (2, 3)] # petal length, petal width
y = (iris.target == 0).astype(np.int) # Iris setosa?
per_clf = Perceptron()
per_clf.fit(X, y)
y_pred = per_clf.predict([[2, 0.5]])

实际上以上代码等同于使用SkLearn中SGDClassifier类一样

sgd_clf=SGDClassifier(loss="perceptron", learning_rate = "constant",eta0 = 1, penalty = None)

感知器与逻辑分类器相反,感知器不输出某类个概率,它只能根据一个固定的阈值来做预测。

感知器的缺点

它无法处理一些很微小的问题,比如异或分类问题(XOR)
但是,感知器的一些限制可以通过将多个感知器堆叠起来的方式消除,这就是多层感知器

多层感知器(MLP)

一个多层感知器包括输入层(Input layer),一个或多个LTU层组成的隐藏层(Hidden layer),一个LTU层组成的输出层(Output layer)。如果一个ANN有2个以及两个以上的隐藏层。则被称为深度神经网络(DNN)(可见上面的感知器是没有隐藏层的)

反向传播算法(b-p算法)

反向自动微分的梯度下降算法,automatic differentiation(autodiff):
对于每个训练实例,反向传播算法先做一次预测(正向过程),度量误差,然后反向遍历每层来度量每个连接的误差贡献度(反向过程),最好再微调每个连接的权重来降低误差(梯度下降)
为了使反向传播算法正常工作,将多层感知器的人工神经元(TLU)中的阶跃函数改成了逻辑函数。σ(z) = 1 / (1 + exp(–z))
反向传播算法还可以和其他的激活函数一起使用:
tanh(z) = 2σ(2z) – 1
ReLU(z) = max(0, z)

那么为什么需要使用激活函数?
如果没有非线性函数再层间,那么这些层叠就等同于一个单一的层,这样不能解决非常复杂的问题。具有非线性激活函数的足够大的DNN理论上可以近似任何连续函数。

典型回归多层感知器结构

分类多层感知器

1、二分类问题binary classification
比如:邮箱是否为垃圾邮箱是二分类问题,结果只有是(0)与不是(1)。只需要一个输出。
2、多标签二分类问题 multilabel binary classification
比如:邮箱收到的邮件需要预测是否是垃圾邮箱和是否是紧急邮件。需要两个输出。
3、多分类问题multiclass classification
比如:一张图片分类预测属于哪一类(有9类,狗、猫、兔子…),有多少类就多少个输出。

二、实战部分

图片分类实战

导入深度学习需要的库:

import matplotlib as mpl
import matplotlib.pyplot as plt
%matplotlib inline
import numpy as np
import sklearn
import pandas as pd
import os
import sys
import time
import tensorflow as tf
from tensorflow import keras
print(tf.__version__)
for model in mpl, np, pd, sklearn, tf.keras:print(model.__name__,model.__version__)

导入fashion-mnist数据:因为要使用梯度下降来训练网络,所以我们要将训练集归一化为0—1的值(除以255就行)
验证集数据是5000张,训练集55000张,测试集10000张。图片是28*28的

fashion_mnist = keras.datasets.fashion_mnist
(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data()
X_valid, X_train = X_train_full[:5000]/255.0, X_train_full[5000:]/255.0
y_valid, y_train = y_train_full[:5000], y_train_full[5000:]print(X_valid.shape, y_valid.shape)
print(X_train.shape, y_train.shape)
print(X_test.shape, y_test.shape)

输出:
(5000, 28, 28) (5000,)
(55000, 28, 28) (55000,)
(10000, 28, 28) (10000,)

显示一张图片代码

def show_sigle_image(img_arr):plt.imshow(img_arr, cmap = "binary")plt.showshow_sigle_image(X_train[0])


显示一批图片

def show_imgs(n_rows, n_cols, x_data, y_data, class_names):assert len(x_data) == len(y_data)assert n_rows * n_cols < len(x_data)plt.figure(figsize = (n_cols * 1.4, n_rows * 1.6))for row in range(n_rows):for col in range(n_cols):index = n_cols * row + colplt.subplot(n_rows, n_cols, index + 1)plt.imshow(x_data[index], cmap = "binary", interpolation = 'nearest')plt.axis('off')plt.title(class_names[y_data[index]])plt.show()class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat","Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
show_imgs(4, 10, X_train, y_train, class_names)


构建模型。使用顺序API(Sequential API)

model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28]))
model.add(keras.layers.Dense(300, activation="relu"))
model.add(keras.layers.Dense(100, activation="relu"))
model.add(keras.layers.Dense(10, activation="softmax"))#另一种方法。两种都是Sequential API
'''model = keras.models.Sequential([ keras.layers.Flatten(input_shape=[28, 28]), keras.layers.Dense(300, activation="relu"), keras.layers.Dense(100, activation="relu"), keras.layers.Dense(10, activation="softmax")
])
'''

然后可以查看模型结构

model.summary()


其中
784=2828
235500 = 784
300 + 300(输入神经元个数 + 偏差神经元个数)
30100 = 300
100 + 100
1010 = 100*10 +10
其他的辅助操作代码:

可以很容易地获得模型的层列表,按其索引获取一个层,或者按名称获取它

model.layers

out[]:
[<tensorflow.python.keras.layers.core.Flatten at 0x14ae5a99710>,
<tensorflow.python.keras.layers.core.Dense at 0x14ae5a99b70>,
<tensorflow.python.keras.layers.core.Dense at 0x14ae6472ef0>,
<tensorflow.python.keras.layers.core.Dense at 0x14ae6478f60>]

hidden1 = model.layers[1]
hidden1.name

out[]:
‘dense’

model.get_layer('dense') is hidden1

out[]:
True

同时也很容易可以获取权重和偏差

weights, biases = hidden1.get_weights()
print(weights)
print(biases)

可见权重都随机初始化了,而偏差都初始化为0了。
如果你想自定义初始化,可以设置kernel_initializer(权重初始化)、bias_initializer(偏差初始化)

然后编译模型:

model.compile(loss="sparse_categorical_crossentropy", optimizer="sgd", metrics=["accuracy"])

因为这里的标签是数值标签,所以损失函数用sparse_categorical_crossentropy。
如果标签是独热编码,则用categorical_crossentropy 可以转变独热编码:

y_train_onehot = tf.keras.utils.to_categorical( y_train)
y_test_onehot = tf.keras.utils.to_categorical( y_test )

变为独热编码后则如下编译模型,损失函数用categorical_crossentropy。:

model.compile(loss="categorical_crossentropy", optimizer="sgd", metrics=["accuracy"])

如果想改变优化器的学习率,可以:optimizer=keras.optimizers.SGD(lr=???)

model.compile(loss="sparse_categorical_crossentropy", optimizer=keras.optimizers.SGD(lr=0.1),metrics=["accuracy"])

然后训练模型:如果使用的是独热编码。传入的是y_train_onehot和y_test_onehot

history = model.fit(X_train, y_train, epochs=30, validation_data=(X_valid, y_valid))

画学习曲线

def plot_learning_curves(history):pd.DataFrame(history.history).plot(figsize=(8,5))plt.grid(True)plt.gca().set_ylim(0,1) #y轴的值plt.show()plot_learning_curves(history)


最后评估模型得到泛化误差

model.evaluate(X_test, y_test)

最后可以用模型来预测

X_new = X_test[:3]
y_proba = model.predict(X_new)
y_proba.round(2)

out[]:得到属于某一类的估计概率

y_pred = model.predict_classes(X_new)
y_pred

out[]:得到最终属于哪一类

np.array(class_names)[y_pred]

out[]:得到属于哪一类的名称

最后用标签来验证一下

y_new = y_test[:3]
y_new

房价预测回归实战

导入深度学习需要的库如前面所示:
下载数据:

from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScalerhousing = fetch_california_housing()
X_train_full, X_test, y_train_full, y_test = train_test_split( housing.data, housing.target)
X_train, X_valid, y_train, y_valid = train_test_split( X_train_full, y_train_full)

对数据标准归一化

scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)
X_test = scaler.transform(X_test)

一个简单的顺序模型

model = keras.models.Sequential([keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]), keras.layers.Dense(1)
])

然后编译和训练模型即可:

model.compile(loss="mean_squared_error", optimizer="sgd")
history = model.fit(X_train, y_train, epochs=20,validation_data=(X_valid, y_valid))

然后就可以用模型预测啦

X_new = X_test[:3]
y_pred = model.predict(X_new)
y_pred

Sequential API

顺序式API就是上面模型所编译的那样。十分简单。但是对于多输入或多输出的问题,顺序模型不行。

Functional API

对于Wide & Deep神经网络就需要使用函数式API。有两条路经,一条宽路径,一条深路径。

以下函数式API与上面的顺序API效果相同

input_ = keras.layers.Input(shape=X_train.shape[1:])
hidden1 = keras.layers.Dense(30, activation="relu")(input_)
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1)
concat = keras.layers.Concatenate()([input_, hidden2])
output = keras.layers.Dense(1)(concat)
model = keras.Model(inputs=[input_], outputs=[output])
多输入问题。


假设,我们需要将0-4号特征通过宽路径,2-7号特征经过深度路径,有两个子集,创建两个输入。
同样使用加利福尼亚的房价。

input_A = keras.layers.Input(shape=[5], name="wide_input")
input_B = keras.layers.Input(shape=[6], name="deep_input")
hidden1 = keras.layers.Dense(30, activation="relu")(input_B)
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1) #深度路径
concat = keras.layers.concatenate([input_A, hidden2]) #宽路径
output = keras.layers.Dense(1, name="output")(concat)
model = keras.Model(inputs=[input_A, input_B], outputs=[output])

编译模型

model.compile(loss="mse", optimizer=keras.optimizers.SGD(lr=1e-3))

将数据分为两个

X_train_A, X_train_B = X_train[:, :5], X_train[:, 2:]
X_valid_A, X_valid_B = X_valid[:, :5], X_valid[:, 2:]
X_test_A, X_test_B = X_test[:, :5], X_test[:, 2:]
X_new_A, X_new_B = X_test_A[:3], X_test_B[:3]
history = model.fit((X_train_A, X_train_B), y_train, epochs=20, validation_data=((X_valid_A, X_valid_B), y_valid))
mse_test = model.evaluate((X_test_A, X_test_B), y_test)
y_pred = model.predict((X_new_A, X_new_B))
y_pred
多输入输出问题


对于回归问题来说。我们可能需要在网络框架中添加额外的输出,可以从神经网络中获得潜在的有用信息。

input_A = keras.layers.Input(shape=[5], name="wide_input")
input_B = keras.layers.Input(shape=[6], name="deep_input")
hidden1 = keras.layers.Dense(30, activation="relu")(input_B)
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1) #深度路径
concat = keras.layers.concatenate([input_A, hidden2]) #宽路径
output = keras.layers.Dense(1, name="main_output")(concat)
aux_output = keras.layers.Dense(1, name="aux_output")(hidden2)
model = keras.Model(inputs=[input_A, input_B], outputs=[output, aux_output])

在对模型编译的时候,应该添加两个损失函数。不然模型就会简单地计算所有这些损失,并简单地将它们相加,以获得用于培训的最终损失。但是我们更在乎主输出而不是额外输出,所以就要编译时加上权重。

model.compile(loss=["mse", "mse"], loss_weights=[0.9, 0.1], optimizer="sgd")
history = model.fit( [X_train_A, X_train_B], [y_train, y_train], epochs=20, validation_data=([X_valid_A, X_valid_B], [y_valid, y_valid]))

在评估模型时,会返回一个总损失,和个别损失

total_loss, main_loss, aux_loss = model.evaluate( [X_test_A, X_test_B], [y_test, y_test])
y_pred_main, y_pred_aux = model.predict([X_new_A, X_new_B])
y_pred_main, y_pred_aux

Subclassing API

一些模型可能会涉及循环、变换形状、条件分支和其他的动态行为,就要使用子类API来构架模型 以下操作等同于上一个模型的操作

class WideAndDeepModel(keras.Model): def __init__(self, units=30, activation="relu", **kwargs): super().__init__(**kwargs) # handles standard args (e.g., name) self.hidden1 = keras.layers.Dense(units, activation=activation) self.hidden2 = keras.layers.Dense(units, activation=activation) self.main_output = keras.layers.Dense(1) self.aux_output = keras.layers.Dense(1) def call(self, inputs): input_A, input_B = inputs hidden1 = self.hidden1(input_B) hidden2 = self.hidden2(hidden1) concat = keras.layers.concatenate([input_A, hidden2]) main_output = self.main_output(concat) aux_output = self.aux_output(hidden2) return main_output, aux_outputmodel = WideAndDeepModel()

存储和恢复模型:
当使用顺序API和函数API时可以保存模型,而使用子类API时是动态的不能保存模型。
只需要在训练模型后做如下操作即可:自定义明明为xxxxxx.h5

model.save("my_keras_model.h5")

需要重新调用这个模型时,做如下操作:

model = keras.models.load_model("my_keras_model.h5")

三、回调函数Callbacks

Checkpoint

在训练期间定期保存模型检查点,默认情况下在每个epoch结束时
回调函数应用在编译模型后,在调用fit()训练模型中使用。
对于ModelCheckpoint中在训练集中使用验证集时加上save_best_only = True,将存储在验证集中表现最好的模型。

checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.h5", save_best_only=True)
history = model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb]) model = keras.models.load_model("my_keras_model.h5") #回到表现最好的模型

之后向前面实例中操作的一样即可

EarlyStopping

可以将epochs设置得足够大,当验证集不再有进展时,它将中断训练(patience定义的耐心参数),并选择回到最好的模型,而且早期停止法(restore_best_weights=True)在停止训练的时候会调整并保存权重,因此不需要特地保存模型了。

checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.h5", save_best_only=True)
early_stopping_cb = keras.callbacks.EarlyStopping(patience=10, restore_best_weights=True) history = model.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid), callbacks=[checkpoint_cb, early_stopping_cb])

之后向前面实例中操作的一样即可

TensorBoard

根据当前日期和时间生成子目录路径,以便在每次运行时都不同

import os
root_logdir = os.path.join(os.curdir, "my_logs")
def get_run_logdir(): import time run_id = time.strftime("run_%Y_%m_%d-%H_%M_%S") return os.path.join(root_logdir, run_id)
run_logdir = get_run_logdir() # e.g., './my_logs/run_2019_06_07-15_15_22'

然后同上面添加回调函数一样:

tensorboard_cb = keras.callbacks.TensorBoard(run_logdir)
history = model.fit(X_train, y_train, epochs=30, validation_data=(X_valid, y_valid), callbacks=[tensorboard_cb])

之后向前面实例中操作的一样即可
然后再次打开一个Anaconda prompt,在命令行输入

$ tensorboard --logdir=./my_logs --port=6006

然后在浏览器中访问http://localhost:6006.即可。

四、调整神经网络的超参数

使用RandomizedSearchCV
将keras模型转换成Sklearn模型才可以使用网格搜索。

def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]): model = keras.models.Sequential() model.add(keras.layers.InputLayer(input_shape=input_shape))  #输入层for layer in range(n_hidden):  #隐藏层model.add(keras.layers.Dense(n_neurons, activation="relu")) model.add(keras.layers.Dense(1))  #输出层optimizer = keras.optimizers.SGD(lr=learning_rate) model.compile(loss="mse", optimizer=optimizer) return modelkeras_reg = keras.wrappers.scikit_learn.KerasRegressor(build_model)

然后应用网格搜索

from scipy.stats import reciprocal
from sklearn.model_selection import RandomizedSearchCV
param_distribs = { "n_hidden": [0, 1, 2, 3], "n_neurons": np.arange(1, 100), "learning_rate": reciprocal(3e-4, 3e-2), }
rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3)
rnd_search_cv.fit(X_train, y_train, epochs=100, validation_data=(X_valid, y_valid), callbacks=[keras.callbacks.EarlyStopping(patience=10)])

得到做好的参数:

rnd_search_cv.best_params_

得到最好模型对应下的分数:

rnd_search_cv.best_score_

然后得到最好模型

model = rnd_search_cv.best_estimator_.model

接下来就可以用测试集来评估它。

隐藏层个数

对于复杂的问题,可以逐渐增减隐藏层的层次,直到在训练集上产生过度拟合。然后再抑制过拟合。

隐藏层中的神经元个数

一个简单的做法是使用(比实际所需)更多的层次和神经元,然后提前结束训练来避免过度拟合(以及其他正则化技术,特别是dropout)

学习率

找到良好学习率的一种方法是对模型进行几百次迭代训练,从非常低的学习率(例如,10-5)开始,并逐渐将其提高到非常大的值(例如…, 10)

优化器

下一章提及

批量

在训练中,大批量通常会导致训练不稳定,特别是训练的开始。
一种策略是尝试使用大批量,使用学习率热身,如果训练不稳定或最终表现令人失望,那么尝试使用小批量来代替。

激活函数

一般来说,ReLU激活函数将是所有隐藏层的一个很好的默认函数。 对于输出层,它真的取决于您的任务。

迭代次数

在大多数情况下,训练迭代的次数实际上不需要调整;只需要使用早期停止代替即可。

基于tensorflow2.0的深度学习 一相关推荐

  1. 官方推荐!用TensorFlow 2.0做深度学习入门教程

    最近,TensorFlow 2.0版的开发者预览版发布没多久,这不,又有一篇优质教程来了. 最近,前Youtube视频分类的产品经理.Hands-On MachineLearning with Sci ...

  2. 深度学习之基于Tensorflow2.0实现AlexNet网络

    在之前的实验中,一直是自己搭建或者是迁移学习进行物体识别,但是没有对某一个网络进行详细的研究,正好人工智能课需要按组上去展示成果,借此机会实现一下比较经典的网络,为以后的研究学习打下基础.本次基于Te ...

  3. 深度学习之基于Tensorflow2.0实现ResNet50网络

    理论上讲,当网络层数加深时,网络的性能会变强,而实际上,在不断的加深网络层数后,分类性能不会提高,而是会导致网络收敛更缓慢,准确率也随着降低.利用数据增强等方法抑制过拟合后,准确率也不会得到提高,出现 ...

  4. 【Python深度学习】基于Tensorflow2.0构建CNN模型尝试分类音乐类型(二)

    前情提要 基于上文所说 基于Tensorflow2.0构建CNN模型尝试分类音乐类型(一) 我用tf2.0和Python3.7复现了一个基于CNN做音乐分类器.用余弦相似度评估距离的一个音乐推荐模型. ...

  5. 基于NVIDIA GPUs的深度学习训练新优化

    基于NVIDIA GPUs的深度学习训练新优化 New Optimizations To Accelerate Deep Learning Training on NVIDIA GPUs 不同行业采用 ...

  6. 基于三维数据的深度学习综述

    众所周知,计算机视觉的目标是对图像进行理解.我们从图像中获取视觉特征,从视觉特征中对图像.场景等进行认知,最终达到理解.感知.交互.目前,比较主流的计算机视觉基本是基于二维数据进行的,但是回顾计算机视 ...

  7. 基于大数据与深度学习的自然语言对话

    基于大数据与深度学习的自然语言对话 发表于2015-12-04 09:44| 7989次阅读| 来源<程序员>电子刊| 5 条评论| 作者李航.吕正东.尚利峰 大数据深度学习自然语言处理自 ...

  8. 基于TensorFlow Serving的深度学习在线预估

    一.前言 随着深度学习在图像.语言.广告点击率预估等各个领域不断发展,很多团队开始探索深度学习技术在业务层面的实践与应用.而在广告CTR预估方面,新模型也是层出不穷: Wide and Deep[1] ...

  9. 一文入门基于三维数据的深度学习

    本文转载自北京智源人工智能研究院. 这是一篇三维数据深度学习的入门好文,兼顾基础与前沿,值得收藏!为方便大家学习,本文PDF版本和所列出的所有文献提供下载,(2020年7月27日11点后)在我爱计算机 ...

最新文章

  1. 北京理工大学 python专题课程-Python语言程序设计
  2. PHP学习之没有权限修改hosts文件
  3. VTK:几何对象之PolygonIntersection
  4. MySQL主主复制 外键_MySQL 组复制介绍
  5. Vue项目中使用Echarts(一)
  6. python各种库安装
  7. java ppt转图片 内存溢出_Java虚拟机内存及内存溢出异常
  8. [原创]Scala学习:编写Scala脚本
  9. iOS--React Native浏览器插件
  10. 是时候拥有一个你自己的命令行工具了
  11. 使用 Netsh.exe 配置 WinHTTP 的代理设置
  12. easypoi 批量导出_浅谈easypoi快速实现excel批量导入
  13. 洛谷 P1315 观光公交
  14. Linux4.14加密框架中的主要数据结构(5)—— struct crypto_larval(算法幼虫)
  15. Angular动态绑定HTML文本
  16. 600G计算机、编程语言网盘分享链接
  17. 企业业务架构设计方法论及实践(二)
  18. python3 scrapy爬取智联招聘存mongodb
  19. yum安装Nginx教程
  20. 多人 协作 任务 android 软件,MeisterTask(团队协作软件)

热门文章

  1. Windows系统下安装Linux双系统(硬盘安装)
  2. matlab p图,【MATLAB】P图神器,初露锋芒:第一周作业(剧透)
  3. 吉大计算机学院课外八学分,通知|关于吉林大学课外八学分相关规定
  4. 淘宝/天猫获得淘宝app商品详情原数据 API
  5. C++求复数的角度_python实现输入三角形边长自动作图求面积案例
  6. 能远程控制你电脑的苹果充电线正在生产和售卖,走一个?
  7. Jsp+Servlet+Mysql简单的登录
  8. 京东月薪8万快递员:真正牛逼的人,都拥有这个特质
  9. 阿里旺旺自动回复工具开发二
  10. Navicat 被投毒了 | 调查结果来了