极限学习机(Extreme Learning Machine),是一种训练单隐层前馈神经网络的随机化算法。
它不用BP训练,更像是求解析解。
第一层可以看作Linear层,不过其中的参数 w , b w,b w,b只需要随机初始化,不需要再训练。Linear后跟一个sigmoid。输出一个矩阵H,具体计算为:
其中 n n n为样本数, m m m为神经元个数。
第二层为求解析解,我们定义:
β = ( β 1 T , . . . , β m T ) T \beta = (\beta_1^T,...,\beta_m^T)^T β=(β1T,...,βmT)T
优化问题:
min β ∣ ∣ H β − Y ∣ ∣ \min_\beta||H\beta - Y|| minβ∣∣Hβ−Y∣∣
等价于均方差损失最小,从而求解出:
β ^ = H † Y \hat{\beta} = H^{\dag}Y β^=H†Y
H † H^{\dag} H†是矩阵 H H H的Moore-Penrose广义逆矩阵。
在优化问题中引入正则化项:
min β ∣ ∣ β ∣ ∣ + λ ∣ ∣ H β − Y ∣ ∣ \min_\beta||\beta|| + \lambda||H\beta - Y|| minβ∣∣β∣∣+λ∣∣Hβ−Y∣∣
λ \lambda λ是控制参数,此时解为:
β ^ = ⎱ ( I / λ + H T H ) − 1 H T Y i f n > m ⎰ H T ( I / λ + H H T ) − 1 Y i f n ≤ m \hat{\beta} = ^{\lmoustache H^T(I/\lambda+HH^T)^{-1}Y\quad if \quad n\le m}_{\rmoustache (I/\lambda+H^TH)^{-1}H^TY\quad if\quad n>m} β^=⎱(I/λ+HTH)−1HTYifn>m⎰HT(I/λ+HHT)−1Yifn≤m
用ELM实现分类任务,博主先尝试分类MNIST手写体,效果很不好,在这里使用随机生成的简单数据集进行分类实验。
import numpy as np
class ELM():
# 输入数据集X、标签Y、神经元个数m、控制参数L
def __init__(self, X, Y, m, L):
self.X = X
self.Y = Y
self.m, self.L = m, L
self.TRAIN_beta()
def sigmoid(self, x):
return 1.0/(1+np.exp(-x))
# 训练函数,随机w,b 计算H、beta
def TRAIN_beta(self):
n, d = self.X.shape
self.w = np.random.rand(d, self.m)
self.b = np.random.rand(1, self.m)
H = self.sigmoid(np.dot(self.X, self.w) + self.b)
self.beta = np.dot(np.linalg.inv(np.identity(self.m)/self.L + np.dot(H.T, H)), np.dot(H.T, self.Y)) # 加入正则化且 n >> m
#self.beta = np.dot(np.linalg.pinv(H), self.Y) # 不加入正则化
print('TRAIN FINISH beta_shape ',self.beta.shape)
# 测试函数,计算方法
def TEST(self, x):
H = self.sigmoid(np.dot(x, self.w) + self.b) # 使用测试集计算H,其中w、b是之前随机得到的
result = np.dot(H, self.beta)
return result
# 使用sklearn随机生成数据
# make_classification生成三元分类模型数据
from sklearn.datasets import make_classification
import matplotlib.pyplot as plt
# 关键参数有n_samples(生成样本数), n_features(样本特征数), n_redundant(冗余特征数)和n_classes(输出的类别数)
# X1为样本特征,Y1为样本类别输出, 共400个样本,每个样本2个特征,输出有2个类别,没有冗余特征,每个类别一个簇
X,Y = make_classification(n_samples=10000, n_features=2, n_redundant=0, n_clusters_per_class=1, n_classes=3)
plt.scatter(X[:,0], X[:,1], c=Y, s=3, marker='o')
plt.show()
# 训练时将标签改为OneHot编码效果比较好
Y_onehot = np.eye(3)[Y]
# 用前8000个数据训练,5000个神经元,控制参数取0.1
elm = ELM(X[:8000], Y_onehot[:8000], 5000, 0.1)
# 用后2000个数据进行测试
predict = elm.TEST(X[8000:])
predict = np.argmax(predict, axis = 1) # OneHot编码形式 取每行最大值的索引即类别
acc = np.sum(predict == Y[8000:])/2000
print('acc :', acc)
这里由于数据集较简单,且分布集中,能获得较高的正确率
acc : 0.9525
# 绘制分类彩图
import matplotlib as mpl
x_np = np.asarray(X)
y_np = np.asarray(Y)
N, M = 50, 50 # 横纵各采样多少个值
x1_min, x2_min = x_np.min(axis = 0) # 列最小值
x1_max, x2_max = x_np.max(axis = 0) # 列最大值
t1 = np.linspace(x1_min, x1_max, N) # 在min-max间线性采样
t2 = np.linspace(x2_min, x2_max, M)
x1, x2 = np.meshgrid(t1, t2) # 生成网格采样点
x_show = np.stack((x1.flat, x2.flat), axis = 1) # 测试点
y_predict = np.argmax(elm.TEST(x_show), axis = 1)
# 绘制分类图
cm_light = mpl.colors.ListedColormap(['#A0FFA0', '#FFA0A0', '#A0A0FF'])
cm_dark = mpl.colors.ListedColormap(['g', 'r', 'b'])
plt.pcolormesh(x1, x2, np.array(y_predict).reshape(x1.shape), cmap = cm_light)
plt.scatter(X[:,0], X[:,1], c=Y, s=3, marker='o')
plt.show()
ELM随机取参数,后面采用解析解的形式。感觉上效果不太好,并且不知道为什么在MNIST数据集上不work。
附一张计算图