本文主要介绍了利用MATLAB2019b实现LVQ二分类和多分类的方法,主要的代码来源是 mathworks网站的支持板块,具体网址会在下面贴出。通过注释和相关介绍,保证文章仅有入门级的理解难度。
学习向量量化(Learning Vector Quantization,LVQ)神经网络是一种用于训练竞争层的有监督学习(supervisedlearning)方法的输入前向神经网络,其算法是从Kohonen竞争算法演化而来的。LVQ神经网络在模式识别和优化领域有着广泛的应用。
LVQ神经网络由3层神经元组成,即输入层、竞争层和线性输出层,如下图所示。输入层与竞争层之间采用全连接的方式,竞争层与线性输出层之间采用部分连接的方式。竞争层神经元个数总是大于线性输出层神经元个数, 每个竞争层神经元只与一个线性输出层神经元相连接且连接权值恒为1。但是,每个线性输出层神经元可以与多个竞争层神经元相连接。竞争层神经元与线性输出层神经元的值只能是1或0。当某个输入模式被送至网络时,与输入模式距离最近的竞争层神经元被激活,神经元的状态为“1”,而其他竞争层神经元的状态均为“0”。因此,与被激活神经元相连接的线性输出层神经元状态也为“1”,而其他线性输出层神经元的状态均为“0”。
上图就是 LVQ 网络的模式聚类功能 ,依据这种功能可以对输入模式(即输入的数据)进行分类识别,具体的解释请参考《MATLAB神经网络43个案例分析》26章的内容[1]。(找不到资源的同学可以私聊我)
竞争层神经网络可以自动学习对输入向量模式的分类,但是竞争层进行的分类只取决于输入向量之间的距离,当两个输入向量非常接近时,竞争层就可能将它们归为一类。在竞争层的设计中没有这样的机制,即严格地判断任意的两个输入向量是属于同一类还是属于不同类。而对于LVQ网络,用户可以指定目标分类结果,网络可以通过监督学习完成对输入向量模式的准确分类。
与其他模式识别和映射方式相比,LVQ神经网络的优点在于网络结构简单,只通过内部单元的相互作用就可以完成十分复杂的分类处理,也很容易将设计域中的各种繁杂分散的设计条件收敛到结论上来。而且它不需要对输入向量进行归一化、正交化处理,只需要直接计算输入向量与竞争层之间的距离,从而实现模式识别,因此简单易行。
二分类的实现是多数人工神经网络的基本功能,也是分类问题中最常见和简单的一种问题(废话)。这里的二分类直接参考 MATLAB官网的example,可以通过以下命令在MATLAB中直接调用。
openExample('nnet/demolvq1')
具体的代码如下,其中画的图不是很好看,等我有空改下。
clc
clear
% 训练数据
x = [-3 -2 -2 0 0 0 0 +2 +2 +3;
0 +1 -1 +2 +1 -1 -2 +1 -1 0]; % x为10个2元素样本输入向量
c = [1 1 1 2 2 2 2 1 1 1]; % c为这些向量所属的类
t = ind2vec(c); % 这些类需要通过ind2vec转换向量,用于网络训练
% 下面绘制了这些数据点。红色 = 第1类,青色 = 第2类
colormap(hsv);
plotvec(x,c)
title('Input Vectors');
xlabel('x(1)');
ylabel('x(2)');
% 构建网络
net = lvqnet(4,0.1); % lvqnet创建了一个具有四个隐含神经元的 LVQ 层,学习率为 0.1
net = configure(net,x,t); % 针对输入x和目标t配置网络(配置通常不是必要步骤,因为train会自动完成配置。)
% 按如下方式绘制竞争神经元权重向量
hold on
w1 = net.IW{1};
plot(w1(1,1),w1(1,2),'ow')
title('Input/Weight Vectors');
xlabel('x(1), w(1)');
ylabel('x(2), w(2)');
% 训练网络
net.trainParam.epochs=150; % 设置训练轮次为150
net=train(net,x,t); % 网络训练
% 训练完成后,重新绘制输入向量“+”和竞争神经元的权重向量“o”,红色 = 第 1 类,青色 = 第 2 类
cla;
plotvec(x,c);
hold on;
plotvec(net.IW{1}',vec2ind(net.LW{2}),'o');
% 现在使用训练过的LVQ网络作为分类器,其中每个神经元都对应于一个不同的类别。。红色 = 第 1 类,青色 = 第 2 类。
x1 = [0.2; 1]; % 输入待预测向量 [0.2; 1]
y1 = vec2ind(net(x1)) % 得到预测结果,net的结果是向量,需要转换为索引
一旦涉及到多分类问题,许多模型就会遇到一定程度的困难,比如称霸一时的SVM在多分类方面就不能一展雄风。根据我的简单查询,LVQ的应用本身就不广泛(与BP和SVM相比),其在多分类方面的应用就更少了。
在 MATLAB官网关于lvqnet函数的介绍中,对鸢尾花数据集进行了三分类的操作,十分的简单易懂。可以说是“傻瓜攻略”完美典范。
具体代码如下
clear
clc
[x,t] = iris_dataset; % 导入鸢尾花数据集,x是4*150的数据,t是3类标签,格式为[0 0 1]这种向量
net = lvqnet(10,0.1,'learnlv1'); % 网络的相关设置,网络隐含层设置为10,学习率是0.1,学习函数是 'learnlv1'或 'learnlv2'
net.trainParam.epochs = 50; % 训练轮次为50
net = train(net,x,t); % 进行网络的训练
view(net) % 网络结构可视化
y = net(x); % 将x输入训练后的网络,得到预测结果
perf = perform(net,y,t) % 计算网络的表现(计算原理未知)
y1 = vec2ind(y); % 将输出的向量转换为类别
t1 = vec2ind(t); % 将原标签转换为索类别
acc = sum(y1==t1)/numel(t1) % 计算网络的识别准确度(预测与真实标签的相同比例)
不过我们在对自己的数据进行分类时,不能和上面一样只是一行代码导入就完事了。通常需要将数据集划分为训练集和测试集,训练后用测试集验证网络的性能。
具体的数据分割应根据数据的格式和特点,确保随机打乱不会出错,训练集和测试集的比例合适(一般为3:1)。作为一个完美主义浅层患者,这里没有进一步简化代码修改的难度。比如将训练集和测试集的比例设置为一个变量,用于矩阵的划分。perform函数的计算应比较简单,但是还没弄清楚。 perform函数介绍
clear
clc
%% 导入鸢尾花数据并划分
[x,t] = iris_dataset; % 导入数据集,提取出数据和标签
data = [x;t]; % 将对应的x和t组合成一个矩阵,用于随机化
rowrank = randperm(size(data,2)); % 随机打乱的数字,从1~行数打乱
data = data(:,rowrank); % 按照rowrank打乱矩阵的行数
train_x = data(1:4,1:120); % 训练集输入
train_t = data(5:7,1:120); % 训练集标签
test_x = data(1:4,121:150); % 测试集输入
test_t = data(5:7,121:150); % 测试集标签
%% 设置网络结构
net = lvqnet(10,0.1,'learnlv1'); % 网络的相关设置,网络隐含层设置为10,学习率是0.1,学习函数是 'learnlv1'或 'learnlv2'
net.trainParam.epochs = 50; % 训练轮次为50
net = train(net,train_x,train_t); % 进行网络的训练,输入训练集数据
view(net) % 网络结构可视化
%% 得到训练集的预测结果
train_y = net(train_x); % 将x输入训练后的网络,得到预测结果
perf1 = perform(net,train_y,train_t) % 计算网络的表现(计算原理未知)
y1 = vec2ind(train_y); % 将输出的向量转换为类别
t1 = vec2ind(train_t); % 将原标签转换为索类别
acc1 = sum(y1==t1)/numel(t1) % 计算网络的识别准确度
%% 得到测试集的预测结果
test_y = net(test_x); % 将x输入训练后的网络,得到预测结果
perf2 = perform(net,test_y,test_t) % 计算网络的表现(计算原理未知)
y2 = vec2ind(test_y); % 将输出的向量转换为类别
t2 = vec2ind(test_t); % 将原标签转换为索类别
acc2 = sum(y2==t2)/numel(t2) % 计算网络的识别准确度
免责声明:本文系网络转载或改编,未找到原创作者,版权归原作者所有。如涉及版权,请联系删