自己的理解和总结:
对H随机赋值然后求来达到最小化代价函数的目的,加快了运算速度。
一、数学原理
对于一个单隐层神经网络,结构如下图:
假设有m个输入节点,M个隐藏神经元,N个输出节点。
- 前向传播的详细矩阵推导
第i个神经元的输入为:(m项输入乘以对应权重矩阵)
即
极限学习机的网络训练模型可用数学表达式表示如下:(N个输出节点的值)
-
基于代价函数最小,优化神经网络参数
和
极限学习机的优化过程就是寻求最优解使得损失函数最小的过程。
令:
则:
最优的情况为:
即:
其中表示表示网络的输入权值和隐藏层节点阈值,H表示网络关于样本的隐藏层输出矩阵,
表示输出权值矩阵,
表示样本集的目标值矩阵。
-
训练过程
这里分析了为什么极限学习速度快。
在传统的单层神经网络中,input weight不可以随机产生,必须在求解过程中和output weight一起进行update,这一过程必须运用iteration的方式进行,运算时间较长。ELM证明了input weight随机产生并且在之后的计算中固定也可以达到同样的目的,所以在求解过程中只需要求output weight。 这样就可以运用简单的矩阵运算一步求出标准解而大大提高运算效率。
极限学习机算法的训练过程可归结为一个非线性优化问题。
当隐藏层节点的激活函数可微时,网络的输入权值和隐藏层节点阈值可以随机赋值,此时矩阵H是一个常数矩阵,极限学习机的学习过程可等价位求取线性系统最小范数的最小二乘解
,其计算公式为:
,
是矩阵H的广义逆,可以通过奇异值分解求得。
通过这种方式就可以计算出学习网络的输出权值。
同迭代算法相比,极限学习机及大地提高了网络的泛化能力和学习速度。
为什么”当隐藏层节点的激活函数可微时,网络的输入权值和隐藏层节点阈值可以随机赋值“?
我自己的理解是,激活函数都得可微,这样才能进行反向传播吧。(虽然这里没有涉及反向传播)
下面我们从具体的高维数据来分析:
# 计算h
x.shape
(3647, 5)
b.shape
(3647, 90)
w.shape
(5, 90)
h = sigmoid(np.dot(x, w) + b)
(3647, 90)
# h为隐神经元的输出
H_.shape
(90, 3647)
T.shape
(3647, 1)
beta.shape
(90, 1)
体会如下:
- w和x的点乘把维度项给抵消掉了:不同的输出x与同一个神经元连接的权重w是相同的
- beta并不是单纯地相乘,也是相乘之后再相加,起到了点乘的效果
二、评价/与Deep learning的区别:
- ELM最初只是一种特殊单隐层神经网络,有解析解,因此简单、快速;而深度学习需要参数更新,样本需求大、速度慢;
线性和非线性的区别
DL具有明确的‘学习’意味或者说是非线性特征抽取的能力,因为它可以根据数据和任务调整参数,使得DL在诸多场景下都适用;尽管ELM也是学习模型,但它本质上是线性的(至少答主是这么理解),看它的优化函数,本质上就是岭回归,是线性的。
优化函数- 性能上,不可否认ELM在低维度简单的小数据集上效果是要略优于DL的,但在复杂数据上,如语音、图像上,DL依旧是独领风骚。另外,ELM不能或者很难作生成模型。
三、项目实现
ELM实现思路:
下面用MNIST dataset来训练网络实现手写数字的分类。
数据准备
- 导入必要库
import numpy as np
import pandas as pd
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import OneHotEncoder
from sklearn.preprocessing import MinMaxScaler
- 读入dataset
train = pd.read_csv('mnist_train.csv')
test = pd.read_csv('mnist_test.csv')
- 用sckikit-learn包中的
MinMaxScaler
归一化数据到(0,1)之间,然后用OneHotEncoder
把tagets转化成one-hot encoding format. -
MinMaxScaler
:数据(x)按照最小值中心化后,再按极差(最大值 - 最小值)缩放,数据移动了最小值个单位,并且会被收敛到[0,1]之间。 -
StandardScaler()
(更常用):数据(x)按均值(μ)中心化后,再按标准差(σ)缩放,数据就会服从为均值为0,方差为1的正态分布(即标准正态分布) -
scaler.fit_transform
这个函数计算数据的均值和方差,并基于此进行数据转化 -
onehotencoder
:对target/label进行onehot编码。
对类别变量进行“二进制化”操作,然后将其作为模型训练的特征。
关于one hot编码的讲解
onehotencoder = OneHotEncoder(categories='auto')
scaler = MinMaxScaler()
X_train = scaler.fit_transform(train.values[:,1:])
y_train = onehotencoder.fit_transform(train.values[:,:1]).toarray()
X_test = scaler.fit_transform(test.values[:,1:])
y_test = onehotencoder.fit_transform(test.values[:,:1]).toarray()
初始化网络
需要确定如下参数:
- The size of the input layer, which is the number of input features
- Number of hidden neurons
- Input to hidden weights
- Hidden layer activation function
输入层的尺寸取决于the number of input features of the dataset
input_size = X_train.shape[1]
隐藏神经元数目初始化为1000
hidden_size = 1000
输入权重和偏差biases的基于高斯分布的初始化
input_weights = np.random.normal(size=[input_size,hidden_size])
biases = np.random.normal(size=[hidden_size])
激活函数设置为Relu函数
def relu(x):
return np.maximum(x, 0, x)
进一步的计算
计算输出权重:
公式中, H (dagger) is the Moore–Penrose generalized inverse of matrix H, and T is our target.
先计算H:
def hidden_nodes(X):
G = np.dot(X, input_weights)
G = G + biases
H = relu(G)
return H
再计算。
output_weights = np.dot(pinv2(hidden_nodes(X_train)), y_train)
用pinv
这个函数就可以计算H的逆,进而计算H的逆和T的点乘。
模型测试
def predict(X):
out = hidden_nodes(X)
out = np.dot(out, output_weights)
return out
prediction = predict(X_test)
correct = 0
total = X_test.shape[0]
for i in range(total):
predicted = np.argmax(prediction[i])
actual = np.argmax(y_test[i])
correct += 1 if predicted == actual else 0
accuracy = correct/total
print('Accuracy for ', hidden_size, ' hidden nodes: ', accuracy)