《蜥蜴书》_讲义及源码解读_10

从生物神经元到人工神经元

生物神经元

在这里插入图片描述

Cell body 细胞体Nucleus 核axon 轴突axon hillock 轴突丘
dendrite 树突telodendria 终树突synaptic terminals 突触终端Neurons 神经元

生物神经元:这是动物大脑中一种不太常见的细胞,包括:细胞体Cell body (含有细胞核Nucleus和大部分细胞组织),许多貌似树枝的树突dendrite,和一条非常长的轴突axon。轴突的长度可能是细胞体的几倍,也可能是一万倍。在轴突的末梢,轴突分叉成为终树突telodendria,终树突的末梢是突触,突触连接着其它神经元的树突或细胞体。

生物神经元会产生被称为“动作电位”(或称为信号)的短促电脉冲,信号沿轴突传递,使突触释放出被称为神经递质的化学信号。当神经元在几毫秒内接收了足够量的神经递质,这个神经元也会发送电脉冲(事实上,要取决于神经递质,一些神经递质会禁止发送电脉冲)。

生物神经网络(BNN)如今仍是活跃的研究领域,人们通过绘制出了部分大脑的结构,发现神经元分布在连续的皮层上,尤其是在大脑皮质上(大脑外层)

神经元的逻辑计算

McCullochPitts 提出了一个非常简单的生物神经元模型,它后来演化成了人工神经元:一个或多个二元(开或关)输入,一个二元输出。当达到一定的输入量时,神经元就会产生输出。

如下图,假设有两个活跃的输入时,神经元就被激活:
在这里插入图片描述

感知机

感知器是最简单的人工神经网络结构之一,由Frank Rosenblatt发明于 1957 年。它基于一种稍微不同的人工神经元(如下图 ),阈值逻辑单元(TLU),或称为线性阈值单元(LTU):输入和输出是数字(而不是二元开/关值),并且每个输入都连接一个权重。TLU 计算其输入的加权和 ( z = X T W z=X^T W z=XTW),然后将阶跃函数应用于该和,并输出结果: h W ( X ) = s t e p ( X T W ) h_W(X)=step(X^TW) hW(X)=step(XTW)

在这里插入图片描述

感知机最常用的阶跃函数是单位阶跃函数(Heaviside step function)。也使用符号函数 sgn
在这里插入图片描述

单一TLU可用于简单的线性二元分类。它计算输入的线性组合,如果结果超过阈值,它输出正类或者输出负类(就像逻辑回归分类或线性SVM分类)。

一个具有两个输入神经元、一个偏置神经元和三个输出神经元的感知机架构:
在这里插入图片描述

当一层的神经元连接着前一层的每个神经元时,该层被称为全连接层,或紧密层(dense)

此外,通常再添加一个偏置特征( X 0 = 1 X_0=1 X0=1):这种偏置特性通常用一种称为偏置神经元的特殊类型的神经元来表示,它总是输出 1

感知机的训练:
w i , j n e x t s t e p = w i , j + η ( y j − y ^ j ) x i w i , j : 第 i 个 输 入 神 经 元 和 第 j 个 输 出 神 经 元 之 间 的 连 接 权 重 x i : 是 当 前 训 练 实 例 的 第 i 个 输 入 w_{i,j}^{next step}=w_{i,j}+\eta(y_j-\hat y_j)x_i \\ w_{i,j} : 第i个输入神经元和第j个输出神经元 之间的连接权重\\ x_i : 是当前训练实例的第i个输入\\ wi,jnextstep=wi,j+η(yjy^j)xiwi,j:ijxi:i
Scikit-Learn提供了一个 Perceptron 类(感知器),它实现了一个 单 TLU 网络。它可以实现大部分功能

感知器学习算法和随机梯度下降很像。事实上,sklearnPerceptron类相当于使用具有以下超参数的SGDClassifier:loss="perceptron",learning_rate="constant",eta0=1(学习率),penalty=None(无正则化)。
与逻辑回归分类器相反,感知机不输出类概率,而是基于硬阈值进行预测。这是逻辑回归优于感知机的一点。

感知机的一些局限性可以通过堆叠多个感知机消除。由此产生的人工神经网络被称为多层感知机(MLP

多层感知机(MLP)与反向传播

MLP由一个输入层、一个或多个称为隐藏层TLU 组成,一个 TLU层称为输出层。靠近输入层的层,通常被称为浅层,靠近输出层的层通常被称为上层。除了输出层,每一层都有一个偏置神经元,并且全连接到上一层。
在这里插入图片描述

注意:信号是从输入到输出单向流动的,因此这种架构被称为前馈神经网络(FNN

多年来,研究人员努力寻找一种训练 MLP 的方法,但没有成功。但在 1986,David Rumelhart、Geoffrey Hinton、Ronald Williams发表了一篇突破性的论文,提出了至今仍在使用的反向传播训练算法

BP ( 反向传播) 做详细分解:

  • 每次处理一个微批次(假如每个批次包含 32 个实例),用训练集多次训练 BP,大家多称之为一个周期、纪元或轮次(epoch);
  • 每个微批次先进入输入层,输入层再将其发到第一个隐藏层。计算得到该层所有神经元的(微批次的每个实例的)输出。输出接着传到下一层,直到得到输出层的输出。这个过程就是前向传播:就像做预测一样,只是保存了每个中间结果,中间结果要用于反向传播;
  • 然后计算输出误差(使用损失函数比较目标值和实际输出值,然后返回误差);
  • 接着,计算每个输出连接对误差的贡献量。这是通过链式法则(就是对多个变量做微分的方法)实现的;
  • 然后还是使用链式法则,计算最后一个隐藏层的每个连接对误差的贡献,这个过程不断向后传播,直到到达输入层。
  • 最后,BP 算法做一次梯度下降步骤,用刚刚计算的误差梯度调整所有连接权重。
  • 注意:epoch的理解:每次训练都先是要设置周期 epoch 数,每个 epoch 其实做的就是三件事:向前传一次、向后传一次、然后调整参数。接着再进行下一次 epoch。
  • 注意:随机初始化隐藏层的连接权重是很重要的。

为了使 BP 算法正常工作。用其他的激活函数代替阶跃函数(平坦,不可导,链式失效)。

同时,不同层之间如果还都是线性的,再深的网络等效于单层的网络,解决不了复杂问题。足够深并且有非线性激活函数的深度神经网络DNN,在理论上可以近似于任意连续函数。

常用的激活函数有:

  • s i g m o i d 函 数 : σ ( z ) = 1 1 + e x p ( − z ) sigmoid函数:\sigma(z)=\frac{1}{1+exp(-z)} sigmoidσ(z)=1+exp(z)1
  • 双 曲 正 切 函 数 : t a n h ( z ) = 2 σ ( 2 z ) − 1 双曲正切函数:tanh(z)=2 \sigma(2z)-1 tanh(z)=2σ(2z)1
  • R e L U 函 数 : R e L U ( z ) = m a x ( 0 , z ) ReLU函数: ReLU(z)=max(0,z) ReLUReLU(z)=max(0,z)
回归MLP

MLP可以用于回归任务。如果想要预测一个单值(如房价预测),就只需要一个输出神经元,它的输出值就是预测值。

对于多变量回归(即一次预测多个值),则每一维度都要有一个神经元。如要定位一张图片的中心,就要预测 2D坐标,因此需要两个输出神经元。要给对象加个边框,还需要两个值:对象的宽度和高度

通常,当用 MLP 做回归时,输出神经元不需要任何激活函数

训练中的损失函数一般是均方误差,但如果训练集有许多异常值,则可以使用平均绝对误差。另外,也可以使用 Huber 损失函数,它是前两者的组合。

分类 MLP

MLP也可用于分类,对于二元分类问题,只需要一个使用 Logistic 激活的输出神经元:输出是一个 0 和 1 之间的值,作为正类的估计概率。

MLP 也可以处理多标签二元分类

如果每个实例只能属于一个类,但可能是三个或多个类中的一个(如对于数字图片的分类),则每一类都要有一个输出神经元,整个输出层要使用 softmax激活函数。softmax函数可以保证,每个估计概率位于 0 和 1 之间,并且各个值相加等于 1。这被称为多类分类。

在这里插入图片描述

Keras 实现 MLP (TensorFlow 后端)

在这里插入图片描述

使用 Sequential API 创建图片分类器

示例代码:

import tensorflow as tf
from tensorflow import keras
## 1.导入数据集,观察分析数据
fashion_mnist = keras.datasets.fashion_mnist
(X_train_full, y_train_full), (X_test, y_test) = fashion_mnist.load_data() 
#拿数据集
X_train_full.shape  #(60000, 28, 28)
X_test.shape #(10000, 28, 28)

X_valid, X_train = X_train_full[:5000] / 255., X_train_full[5000:] / 255.
y_valid, y_train = y_train_full[:5000], y_train_full[5000:]
X_test = X_test / 255.

#拆分验证集,前5000;拆分 训练集 ,后55000,并归一化数据
import collections
collections.Counter(y_train_full) #图片分成10个类别,索引号是: 0-9

class_names = ["T-shirt/top", "Trouser", "Pullover", "Dress", "Coat",
               "Sandal", "Shirt", "Sneaker", "Bag", "Ankle boot"]
#每个类别的名称

plt.imshow(X_train[0], cmap="binary")
plt.axis('off')
plt.show()

y_train[0]  #  4
class_names[y_train[0]]  #Coat


##2 。创建模型
model = keras.models.Sequential([
    keras.layers.Flatten(input_shape=[28, 28]),  #输入层 28*28=784个输入
    keras.layers.Dense(300, activation="relu"),  #隐藏层1,300个神经元全连接,relu激活函数
    keras.layers.Dense(100, activation="relu"),  #隐藏层2,100个神经元全连接,relu激活函数
    keras.layers.Dense(10, activation="softmax") #输出层,10个神经元(按10个类别),softmax激活函数(分类间互斥)
])

model.summary()  
# 查看模型摘要,依层次,每层784*300+300个权重和偏置参数;30100个参数,1010个参数。

hidden1 = model.layers[1]
weights, biases = hidden1.get_weights()  #拿到第1层的权重和偏置  ,权重随机,偏置默认0?

##3.编译模型
model.compile(loss="sparse_categorical_crossentropy",  #损失函数,稀疏分类交叉熵。此例标签是数字而非one-hot.
              optimizer="sgd",  #随机梯度下降
              metrics=["accuracy"])  #精准度评估

##4. 训练模型
history = model.fit(X_train, y_train, epochs=30,   #30个周期
                    validation_data=(X_valid, y_valid))


##5. 评估模型
model.evaluate(X_test, y_test)
# 313/313 [==============================] - 1s 2ms/step - loss: 0.3339 - accuracy: 0.8838

##6.分片出新数据,验证效果
X_new = X_test[:3]
y_proba = model.predict(X_new)
y_proba.round(2)
#array([[0.  , 0.  , 0.  , 0.  , 0.  , 0.01, 0.  , 0.03, 0.  , 0.96],
#       [0.  , 0.  , 0.99, 0.  , 0.01, 0.  , 0.  , 0.  , 0.  , 0.  ],
#       [0.  , 1.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  , 0.  ]],


#y_pred = model.predict_classes(X_new) # deprecated  已启用
y_pred = np.argmax(model.predict(X_new), axis=-1) 
y_pred
#array([9, 2, 1]) ,如上,用分类概率最大的,9 ,2, 1

plt.figure(figsize=(7.2, 2.4))
for index, image in enumerate(X_new):
    plt.subplot(1, 3, index + 1)
    plt.imshow(image, cmap="binary", interpolation="nearest")
    plt.axis('off')
    plt.title(class_names[y_test[index]], fontsize=12)
plt.subplots_adjust(wspace=0.2, hspace=0.5)

plt.show()

在这里插入图片描述

使用 Functional API 搭建复杂模型

在这里插入图片描述

示例代码:

#  导入数据集
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

housing = fetch_california_housing()
# 切片
X_train_full, X_test, y_train_full, y_test = train_test_split(housing.data, housing.target, random_state=42)
X_train, X_valid, y_train, y_valid = train_test_split(X_train_full, y_train_full, random_state=42)

scaler = StandardScaler() # 标准化
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)
X_test = scaler.transform(X_test)

#function api  -1
input_ = keras.layers.Input(shape=X_train.shape[1:]) 
# 输入层 ,8列数据,8个输入
hidden1 = keras.layers.Dense(30, activation="relu")(input_) 
# 30个神经元,对应下一层 30*(8+1)个参数
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1) 
# 30个神经元,对应下一层30*31个参数
concat = keras.layers.concatenate([input_, hidden2])  
# 做合并层  30+8个输入
output = keras.layers.Dense(1)(concat) 
# 合并层连接输出层,对应输出层,有:38+1个参数
model = keras.models.Model(inputs=[input_], outputs=[output]) 
# 建立模型

model.summary()
# 查看

#function api  -2
input_A = keras.layers.Input(shape=[5], name="wide_input") # 特征0-4
input_B = keras.layers.Input(shape=[6], name="deep_input") # 特征2-7
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.models.Model(inputs=[input_A, input_B], outputs=[output]) #创建模型,注意:是两个输入


#编译、训练、评估预测1
model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=1e-3)) #mse
history = model.fit(X_train, y_train, epochs=20,
                    validation_data=(X_valid, y_valid))
mse_test = model.evaluate(X_test, y_test)
y_pred = model.predict(X_new)


#编译、训练、评估预测2
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))

在这里插入图片描述

如图,接上例,还可以处理多个输出,示例代码:

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.models.Model(inputs=[input_A, input_B],
                           outputs=[output, aux_output])

model.compile(loss=["mse", "mse"], loss_weights=[0.9, 0.1], optimizer=keras.optimizers.SGD(lr=1e-3)) #损失函数和权重是两套


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])


保存和恢复模型
model = keras.models.Sequential([
    keras.layers.Dense(30, activation="relu", input_shape=[8]),
    keras.layers.Dense(30, activation="relu"),
    keras.layers.Dense(1)
])    


model.compile(loss="mse", optimizer=keras.optimizers.SGD(lr=1e-3))
history = model.fit(X_train, y_train, epochs=10, validation_data=(X_valid, y_valid))
mse_test = model.evaluate(X_test, y_test)

model.save("my_keras_model.h5")



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


model.predict(X_new)

model.save_weights("my_keras_weights.ckpt")

model.load_weights("my_keras_weights.ckpt")
使用调回

fit()方法接受参数callbacks,可以让用户指明一个 Keras列表,让 Keras 在训练开始和结束、每个周期开始和结束、甚至是每个批次的前后调用。例如,ModelCheckpoint可以在每个时间间隔保存检查点,默认是每个周期结束之后:

如果训练时使用了验证集,可以在创建检查点时设定save_best_only=True,只有当模型在验证集上取得最优值时才保存模型。这么做可以不必担心训练时间过长和训练集过拟合:只需加载训练好的模型,就能保证是在验证集上表现最好的模型。

使用 TensorBoard 进行可视化

You can then open your web browser to localhost:6006 and use TensorBoard.

归结演绎推理是一种基于逻辑推理的方法,通过对已知事实和规则进行推理,得出结论。Python可以通过实现归结演绎推理来进行逻辑推理。 以下是一个简单的归结演绎推理的Python实现: 1. 定义规则和事实 ``` # 规则 rules = [ ('penguin', 'bird'), # 企鹅是鸟类 ('bird', 'animal'), # 鸟类是动物 ('lizard', 'animal'), # 蜥蜴是动物 ('bird', 'fly') # 鸟类可以飞 ] # 事实 facts = [ 'tweety is a penguin', # 特维是一只企鹅 'penguin is black and white' # 企鹅是黑白相间的 ] ``` 2. 定义归结演绎推理函数 ``` def resolve(a, b): """ 归结规则 """ for fact_a in a: for fact_b in b: if fact_a == ('not', fact_b) or fact_b == ('not', fact_a): # a和b中有相反的事实,无法归结 continue if fact_a == fact_b: # a和b中有相同的事实,无需归结 continue for i in range(len(fact_a)): if fact_a[i] != fact_b[i]: # 找到不同的部分,进行归结 new_fact = fact_a[:i] + fact_a[i+1:] + fact_b[:i] + fact_b[i+1:] if new_fact not in a and new_fact not in b: # 新的事实不在a和b中,加入a a.append(new_fact) return True return False def resolution(rules, facts): """ 归结演绎推理 """ while True: pairs = [(rules[i], rules[j]) for i in range(len(rules)) for j in range(i+1, len(rules))] new_rules = [] for pair in pairs: a, b = pair new_fact = resolve(a, b) if new_fact: # 归结出新的规则,加入新规则列表 new_rules.append(new_fact) if new_rules: # 有新规则,加入规则列表 rules += new_rules continue for fact in facts: if ('not', fact) in rules: # 有矛盾的事实,返回False return False # 执行完毕,返回True return True ``` 3. 测试归结演绎推理函数 ``` if resolution(rules, facts): print('Tweety can fly') else: print('Tweety cannot fly') ``` 输出结果为:`Tweety can fly`,即特维可以飞。因为根据规则,企鹅是鸟类,鸟类可以飞,所以特维可以飞。 这是一个简单的归结演绎推理的Python实现,可以根据实际需要进行扩展和优化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值