动态图片素材网站wordpress搭建企业网站思路
动态图片素材网站,wordpress搭建企业网站思路,扬州中兴建设有限公司网站,跨境网络营销是什么1. 感知机#xff1a;从“人工神经元”到你的第一个分类器
大家好#xff0c;我是老张#xff0c;在AI和智能硬件这块儿摸爬滚打了十几年。今天我们不聊那些高大上的深度学习模型#xff0c;咱们返璞归真#xff0c;从最基础、最经典的感知机开始。如果你对神经网络充满好…1. 感知机从“人工神经元”到你的第一个分类器大家好我是老张在AI和智能硬件这块儿摸爬滚打了十几年。今天我们不聊那些高大上的深度学习模型咱们返璞归真从最基础、最经典的感知机开始。如果你对神经网络充满好奇但又觉得它像一团迷雾不知从何下手那么恭喜你你来对地方了。感知机就是打开神经网络世界大门的第一把钥匙它结构简单思想却非常深刻理解了它后续学习支持向量机、多层神经网络都会轻松很多。简单来说感知机就是一个最简单的“人工神经元”。你可以把它想象成一个非常尽职的“门卫”。这个门卫的工作很简单他面前有一条看不见的线我们称之为决策边界每个来访者数据点都带着两个特征值比如身高和体重来报到。门卫会根据一套内部规则权重和阈值计算一下然后决定把这个来访者归到线的左边比如标记为-1代表“拒绝入内”还是右边标记为1代表“允许进入”。感知机的整个“学习”过程就是这位门卫在不断调整他心中那条“线”的位置直到能最准确地区分两类来访者为止。为什么我强烈推荐用MATLAB来实现它呢原因有三。第一MATLAB的矩阵运算和可视化能力太强了写感知机的核心代码可能就几行非常直观。第二我们可以实时地、动态地看到那条“决策边界”是如何在一次次错误中“扭动”身体最终找到正确位置的这个过程就像看一场慢放的魔术对理解算法本质有奇效。第三对于初学者尤其是学生和工程师MATLAB的环境友好调试方便能让你把精力完全集中在算法逻辑本身而不是纠结于复杂的语法和环境配置。所以这篇文章就是一份“手把手”的实战指南。我会带你从生成第一份模拟数据开始一步步写出感知机的核心训练代码并且我们会用丰富的图形把数据分布、决策边界动态变化、损失函数曲线都画出来让你亲眼见证这个简单模型是如何“学会”分类的。相信我跟着走完这一趟你收获的不仅仅是一段能运行的代码更是一种对机器学习最朴素思想的理解。2. 环境准备与数据生成打造你的第一个“数据集”工欲善其事必先利其器。在开始写算法之前我们得先把“战场”布置好。这里没有复杂的环境依赖只要你安装了MATLAB建议2016a及以上版本就可以直接开始了。2.1 创建项目与规划文件我习惯为一个完整的实验单独建一个文件夹这样代码和数据都在一起管理起来清晰。你可以在你的工作目录下新建一个文件夹比如就叫Perceptron_Demo。在这个文件夹里我们计划创建三个文件generate_data.m: 用于生成我们需要的模拟数据。perceptron_train.m: 感知机训练的核心函数。main.m: 主脚本用来调用上面的函数组织整个流程并绘制各种可视化图表。为什么要分开写这是一种良好的编程习惯。生成数据、模型训练、主流程控制各司其职代码结构清晰后期修改和调试也方便。比如你想换一种数据分布只需要改generate_data.m其他部分完全不用动。2.2 生成模拟的二分类数据感知机是线性二分类器这意味着我们的数据最好能被一条直线大致分开。我们手动生成这样的数据可以完全掌控数据的“脾气”。打开generate_data.m我们来写一个数据生成函数。思路是生成两组服从不同均值的高斯分布正态分布的点一组作为正类1一组作为负类-1。为了让数据有轻微的重叠这样训练过程才更有看头太容易分开就没意思了我们让两个分布的均值不要离得太远。function [data, label] generate_data(num_samples) % 生成用于感知机训练的二维二分类数据 % 输入num_samples - 总样本数正负类各一半 % 输出data - 2 x num_samples 的矩阵每列是一个样本的特征[x1; x2] % label - 1 x num_samples 的向量对应每个样本的标签1或-1 % 确保样本数是偶数方便平分 if mod(num_samples, 2) ~ 0 num_samples num_samples 1; end half num_samples / 2; % 设置两类数据的均值和协方差矩阵 % 正类数据围绕点 (6, 6) 分布 mu_pos [6; 6]; % 负类数据围绕点 (4, 4) 分布 mu_neg [4; 4]; % 使用相同的协方差矩阵保证数据形状大致相同 sigma [1.5, 0.3; 0.3, 1.5]; % 有一定相关性更接近真实数据 % 使用mvnrnd生成多维正态分布随机数 data_pos mvnrnd(mu_pos, sigma, half); % 转置为2行 half列 data_neg mvnrnd(mu_neg, sigma, half); % 合并数据 data [data_pos, data_neg]; % 生成标签正类为1负类为-1 label_pos ones(1, half); label_neg -ones(1, half); label [label_pos, label_neg]; % 非常重要的一步打乱数据顺序 % 防止训练时连续输入同一类数据影响学习效果 rand_index randperm(num_samples); data data(:, rand_index); label label(:, rand_index); end这段代码中mvnrnd函数是核心它生成了我们指定均值和协方差的二维高斯数据点。协方差矩阵非对角线上的值0.3引入了特征间的相关性让数据点呈椭圆形分布而不是标准的圆形这更贴近现实。最后一步打乱数据顺序是机器学习数据预处理中的常规操作能避免一些潜在的问题。2.3 数据可视化先看看我们的“对手”数据生成好了我们先别急着喂给模型。一个好的习惯是先把数据画出来看看做到心中有数。我们在main.m里先调用生成函数并绘图。% main.m 初始部分 clear; clc; close all; % 生成500个样本点 num_samples 500; [all_data, all_label] generate_data(num_samples); % 划分训练集和测试集这里按8:2划分 split_ratio 0.8; train_num floor(num_samples * split_ratio); train_data all_data(:, 1:train_num); train_label all_label(1:train_num); test_data all_data(:, train_num1:end); test_label all_label(train_num1:end); % 绘制数据分布图 figure(Name, 数据分布, Position, [100, 100, 800, 400]); subplot(1,2,1); % 绘制训练集 idx_train_pos (train_label 1); idx_train_neg (train_label -1); scatter(train_data(1, idx_train_pos), train_data(2, idx_train_pos), b, o, filled, DisplayName, 训练集 (1)); hold on; scatter(train_data(1, idx_train_neg), train_data(2, idx_train_neg), r, ^, filled, DisplayName, 训练集 (-1)); xlabel(特征 x1); ylabel(特征 x2); title(训练集数据分布); legend(Location, best); grid on; axis equal; subplot(1,2,2); % 绘制测试集 idx_test_pos (test_label 1); idx_test_neg (test_label -1); scatter(test_data(1, idx_test_pos), test_data(2, idx_test_pos), c, o, DisplayName, 测试集 (1)); hold on; scatter(test_data(1, idx_test_neg), test_data(2, idx_test_neg), m, ^, DisplayName, 测试集 (-1)); xlabel(特征 x1); ylabel(特征 x2); title(测试集数据分布); legend(Location, best); grid on; axis equal;运行这部分代码你会看到两幅并排的散点图。蓝色圆圈和红色三角形分别代表训练集中的正负类青色圆圈和品红色三角形代表测试集。可以清晰地看到数据大致分为左上和右下两个簇但在中间区域有部分重叠。我们的感知机就要学习如何画一条直线尽可能好地分开这两个颜色的点。这个直观的印象对我们后续理解模型的决策边界至关重要。3. 感知机核心原理错误驱动学习的智慧现在数据已经准备就绪是时候请出我们今天的主角——感知机模型了。别看它结构简单但其背后的学习思想非常经典可以说是“错误驱动学习”的鼻祖。我们来彻底拆解一下它的工作原理。3.1 模型结构一个公式的智慧感知机的模型结构用一个公式就能说清楚。对于一个输入样本x [x1; x2]注意我们这里用列向量表示感知机首先计算一个加权和再加上一个偏置项也叫阈值z w1 * x1 w2 * x2 b这里w1和w2就是权重你可以理解为模型对两个特征的“重视程度”。b是偏置它决定了决策边界离原点的偏移。这个z值是一个实数。接下来感知机通过一个激活函数对这个实数z进行处理输出最终的分类预测y_pred。对于标准的二分类感知机这个激活函数就是sign函数符号函数y_pred sign(z) 1, 如果 z 0; 否则为 -1。看模型就是这么简单输入两个数经过一个线性计算和一个“非正即负”的判断输出分类结果。它的全部知识就储存在w1,w2和b这三个参数里。学习的过程就是找到一组最优的w1,w2,b使得对于大部分样本模型的预测y_pred都和真实标签y_true一致。3.2 学习规则从错误中成长感知机是怎么学习的呢它的规则朴素而有效只从错分的样本中学习。初始化时我们随机给w1,w2,b赋一些小值比如在0附近。然后我们遍历训练集中的每一个样本。对于每个样本(x, y_true)用当前的参数计算预测值y_pred。比较y_pred和y_true。如果预测正确(y_pred y_true)皆大欢喜参数纹丝不动。如果预测错误(y_pred ! y_true)参数就需要按照以下规则更新w w η * y_true * xb b η * y_true这里的η是一个非常重要的超参数叫做学习率。它控制着每次参数更新的“步长”。你可以把它想象成学走路时的步伐大小步子太小η太小走到目标要花很久步子太大η太大可能会在目标附近来回蹦跶甚至越走越远。通常我们会把它设为一个0到1之间的小数比如0.1或0.01。这个更新规则怎么理解呢我们以权重更新w w η * y_true * x为例。假设一个正类样本y_true 1被错误地分成了负类y_pred -1。这意味着当前的z w*x b是负数。为了让这个样本下次能被正确分类我们需要增大z。根据公式增大w或b都能增大z。更新规则中y_true * x对于这个正样本就是1 * x所以w会加上一个η * x的正数从而被增大。同理如果负样本被错分成正类y_true * x是负数w会被减小。这个规则的本质就是让决策边界朝着误分类样本的方向“挪动”一点以减少对这个样本的误判。3.3 损失函数目标与动力虽然感知机的原始算法没有显式地定义一个损失函数然后求梯度但我们可以从另一个角度来理解它。感知机追求的是最小化误分类样本到决策边界的距离之和。对于线性可分的数据集即存在一条直线能完美分开两类感知机保证能在有限步内找到一个解即所有样本都被正确分类。对于线性不可分的数据就像我们生成的有重叠的数据感知机会在某个解附近震荡无法完全收敛。这种“错误驱动”的方式可以看作是在优化一个叫做“0-1损失”的函数但这个函数不是连续可导的所以感知机采用了这种更直接的参数更新方式。理解这一点能帮你更好地衔接后续的机器学习模型比如逻辑回归使用连续的交叉熵损失和支持向量机使用合页损失。4. MATLAB实战手把手编码实现理论说得再多不如动手写一行代码。现在我们就将上一节的理论转化为实实在在的MATLAB程序。我会把关键步骤拆解开来并配上详细的注释。4.1 编写训练函数感知机的“大脑”我们创建一个独立的函数文件perceptron_train.m。这个函数接收训练数据、标签和学习参数输出训练好的模型参数以及训练过程中的历史记录方便我们后续可视化分析。function [w, b, train_loss_history, decision_boundary_history] perceptron_train(train_data, train_label, learning_rate, max_epochs) % 感知机训练函数 % 输入 % train_data - 2 x N 矩阵训练样本特征 % train_label - 1 x N 向量训练样本标签 (1/-1) % learning_rate - 学习率 % max_epochs - 最大训练轮数 % 输出 % w - 训练得到的权重向量 (2 x 1) % b - 训练得到的偏置标量 % train_loss_history - 每一轮训练后的误分类数历史记录 % decision_boundary_history - 每一轮训练后的决策边界参数历史记录 [dim, num_samples] size(train_data); % 1. 参数初始化随机初始化权重和偏置 w randn(dim, 1) * 0.01; % 用小随机数初始化这是一个常用技巧 b randn() * 0.01; % 预分配历史记录数组提高效率 train_loss_history zeros(1, max_epochs); decision_boundary_history zeros(max_epochs, 3); % 存储 [w1, w2, b] fprintf(开始训练感知机...\n); fprintf(初始参数: w [%.4f, %.4f]^T, b %.4f\n, w(1), w(2), b); % 2. 多轮迭代训练 for epoch 1:max_epochs misclassified_count 0; % 记录本轮误分类数 % 遍历本轮所有训练样本 for i 1:num_samples x_i train_data(:, i); y_true_i train_label(i); % 前向传播计算预测值 z w * x_i b; y_pred_i sign(z); % 判断是否误分类 if y_pred_i ~ y_true_i misclassified_count misclassified_count 1; % 参数更新核心学习规则 w w learning_rate * y_true_i * x_i; b b learning_rate * y_true_i; end end % 记录本轮结果 train_loss_history(epoch) misclassified_count; decision_boundary_history(epoch, :) [w(1), w(2), b]; % 每10轮打印一次进度 if mod(epoch, 10) 0 || epoch 1 fprintf( 第 %3d 轮 | 误分类数: %d\n, epoch, misclassified_count); end % 提前终止条件如果本轮没有误分类点说明已完全分开可以提前结束 if misclassified_count 0 fprintf( 第 %d 轮后已无误分类点训练提前终止\n, epoch); train_loss_history train_loss_history(1:epoch); decision_boundary_history decision_boundary_history(1:epoch, :); break; end end fprintf(训练结束。最终参数: w [%.4f, %.4f]^T, b %.4f\n, w(1), w(2), b); end这段代码有几个值得注意的细节第一参数初始化使用了randn() * 0.01即从标准正态分布采样并缩小100倍。这是一种常见的初始化小技巧避免初始值过大。第二我们记录了每一轮训练后的误分类数以及决策边界的参数这些数据是后续可视化的黄金材料。第三我们设置了一个简单的提前终止条件如果某一轮遍历完所有样本都没有发现错误说明模型已经找到了一个完美解对于线性可分数据就可以停止训练节省计算资源。4.2 在主流程中调用与测试回到main.m脚本我们在数据可视化之后加入训练和测试的代码。% ...接前面的数据生成和可视化代码 % 感知机训练 learning_rate 0.1; % 学习率可以尝试调整如0.01, 0.5 max_epochs 100; % 最大训练轮数 [w, b, loss_history, param_history] perceptron_train(train_data, train_label, learning_rate, max_epochs); % 在训练集上绘制最终的决策边界 figure(Name, 训练结果); scatter(train_data(1, idx_train_pos), train_data(2, idx_train_pos), b, o, filled, DisplayName, 1); hold on; scatter(train_data(1, idx_train_neg), train_data(2, idx_train_neg), r, ^, filled, DisplayName, -1); % 根据最终参数 w 和 b 绘制决策边界直线 % 决策边界直线方程 w1*x1 w2*x2 b 0 x1_range [min(train_data(1,:)), max(train_data(1,:))]; x2_boundary (-w(1)/w(2)) * x1_range - (b / w(2)); plot(x1_range, x2_boundary, k-, LineWidth, 2, DisplayName, 决策边界); xlabel(特征 x1); ylabel(特征 x2); title(感知机在训练集上的分类结果); legend(Location, best); grid on; axis equal; % 在测试集上进行评估 fprintf(\n 在测试集上评估模型 \n); test_predictions sign(w * test_data b); accuracy sum(test_predictions test_label) / length(test_label) * 100; fprintf(测试集分类准确率: %.2f%%\n, accuracy); % 绘制测试集结果 figure(Name, 测试集验证); scatter(test_data(1, idx_test_pos), test_data(2, idx_test_pos), c, o, DisplayName, 测试 1); hold on; scatter(test_data(1, idx_test_neg), test_data(2, idx_test_neg), m, ^, DisplayName, 测试 -1); plot(x1_range, x2_boundary, k-, LineWidth, 2, DisplayName, 决策边界); xlabel(特征 x1); ylabel(特征 x2); title(sprintf(测试集分类结果 (准确率: %.1f%%), accuracy)); legend(Location, best); grid on; axis equal;运行整个main.m脚本你会在命令窗口看到训练过程的输出并弹出三张图数据分布、训练集分类结果、测试集分类结果。黑色的决策边界直线应该能够大致将两类点分开。测试集准确率通常很高可能超过95%但由于数据随机生成且存在重叠每次运行结果会有细微差异。这正体现了机器学习的一个特点结果具有随机性我们关注的是其统计上的性能。5. 可视化分析眼见为实的理解代码跑通了结果也出来了但我们的探索不能止步于此。感知机学习过程中那些动态的变化才是理解其精髓的关键。下面我们利用训练时记录的历史数据制作几个直观的图表。5.1 损失曲线观察学习的“收敛”损失曲线是监控模型训练的“仪表盘”。对于感知机我们记录的“损失”就是每轮的误分类数。% 绘制训练损失误分类数曲线 figure(Name, 训练过程分析); subplot(2,2,1); plot(1:length(loss_history), loss_history, b-o, LineWidth, 1.5, MarkerSize, 4); xlabel(训练轮数 (Epoch)); ylabel(误分类样本数); title(训练损失曲线 (误分类数)); grid on; % 添加一条y0的参考线表示完美分类 yline(0, r--, LineWidth, 1); legend(误分类数, 零错误线, Location, best);这张图会告诉你模型学习得是否顺利。一个理想的曲线是误分类数随着训练轮数快速下降最终在0附近波动或达到0。如果曲线一直居高不下可能意味着学习率设置不当或者数据本身线性不可分程度很高。5.2 决策边界动态图看直线如何“跳舞”这是最有趣的部分我们把每一轮或每隔几轮训练后得到的决策边界都画出来做成一个动画或者序列图就能清晰地看到这条直线是如何被误分类点“拉扯”着移动到最终位置的。% 绘制决策边界动态变化序列图每隔5轮画一条 subplot(2,2,2); scatter(train_data(1, idx_train_pos), train_data(2, idx_train_pos), b, o); hold on; scatter(train_data(1, idx_train_neg), train_data(2, idx_train_neg), r, ^); xlabel(特征 x1); ylabel(特征 x2); title(决策边界演化过程); grid on; axis equal; plot_interval 5; % 每隔5轮画一条线 epochs_to_plot 1:plot_interval:size(param_history, 1); colors jet(length(epochs_to_plot)); % 使用彩虹色系区分不同轮次 for idx 1:length(epochs_to_plot) epoch epochs_to_plot(idx); w_hist param_history(epoch, 1:2); b_hist param_history(epoch, 3); x2_hist (-w_hist(1)/w_hist(2)) * x1_range - (b_hist / w_hist(2)); plot(x1_range, x2_hist, -, Color, colors(idx, :), LineWidth, 1, ... DisplayName, sprintf(Epoch %d, epoch)); end % 突出显示最终的决策边界 plot(x1_range, x2_boundary, k-, LineWidth, 3, DisplayName, 最终边界); legend(Location, best, NumColumns, 2);在这张图上你会看到从初始的随机直线开始多条彩色线条最终收敛到那条粗黑的最终边界附近。线条颜色的变化如从蓝到红代表了训练轮次的推进。仔细观察线条移动的方向你会发现它总是在试图“纠正”位于错误一侧的点。5.3 参数空间轨迹理解优化的路径我们还可以从参数的角度来看学习过程。将权重w1,w2和偏置b的变化画出来。% 绘制参数变化轨迹 subplot(2,2,3); plot3(param_history(:,1), param_history(:,2), param_history(:,3), g-, LineWidth, 1.5); hold on; scatter3(param_history(1,1), param_history(1,2), param_history(1,3), 100, ro, filled, DisplayName, 起点); scatter3(w(1), w(2), b, 100, ks, filled, DisplayName, 终点); xlabel(权重 w1); ylabel(权重 w2); zlabel(偏置 b); title(参数 (w1, w2, b) 优化轨迹); grid on; legend; view(45, 20); % 调整三维视角 % 绘制参数分量随时间的变化 subplot(2,2,4); epochs 1:size(param_history, 1); plot(epochs, param_history(:,1), r-, LineWidth, 1.5, DisplayName, w1); hold on; plot(epochs, param_history(:,2), g-, LineWidth, 1.5, DisplayName, w2); plot(epochs, param_history(:,3), b-, LineWidth, 1.5, DisplayName, b); xlabel(训练轮数 (Epoch)); ylabel(参数值); title(参数分量变化曲线); grid on; legend(Location, best);三维轨迹图展示了参数在空间中的搜索路径而分量变化曲线则展示了每个参数随时间变化的细节。你可以看到在训练初期参数变化往往比较剧烈随着错误减少变化也逐渐平缓。这些可视化让你对“优化”这个过程有了更几何化的认识。6. 深入探索与避坑指南基本的感知机跑起来了也看到了可视化效果。但要想真正掌握它我们还得再深入一步玩玩“调参”并理解它的局限性。这是我多年实践中总结的一些经验和需要注意的“坑”。6.1 学习率的影响步伐大小的艺术学习率η是感知机最重要的超参数。我们来做个对比实验。在main.m里我们可以用循环尝试不同的学习率。% 探索不同学习率的影响 learning_rates [0.01, 0.1, 0.5, 1.0]; max_epochs 50; figure(Name, 不同学习率对比); for lr_idx 1:length(learning_rates) lr learning_rates(lr_idx); [~, ~, loss_hist, ~] perceptron_train(train_data, train_label, lr, max_epochs); subplot(2,2,lr_idx); plot(1:length(loss_hist), loss_hist, b-o, LineWidth, 1, MarkerSize, 3); xlabel(训练轮数); ylabel(误分类数); title(sprintf(学习率 η %.2f, lr)); grid on; ylim([0, max(loss_hist)*1.1]); end运行这段代码你会得到四张损失曲线图。通常你会发现η 0.01曲线下降非常缓慢可能需要很多轮才能收敛。η 0.1曲线下降平稳是比较常用的值。η 0.5曲线下降很快但可能在最低点附近有轻微震荡。η 1.0曲线剧烈震荡误分类数可能降不下去甚至上升模型无法稳定学习。经验之谈学习率通常从0.1或0.01开始尝试。如果损失曲线震荡就调小如果下降太慢就适当调大。没有一个绝对最优值需要根据具体数据和任务进行微调。6.2 感知机的局限性线性可分的“执念”感知机有一个著名的缺陷它只能解决线性可分问题。什么是线性可分就是存在一条直线在高维是超平面能完美分开两类数据。我们生成的数据基本是线性可分的所以感知机效果不错。但现实中很多问题不是这样。我们可以构造一个经典的“异或”XOR问题来看看。异或问题的数据分布是(0,0)和(1,1)属于一类比如-1(0,1)和(1,0)属于另一类比如1。你在纸上画一下这四个点就会发现没有任何一条直线能把它们完美分开。% 演示感知机对线性不可分问题如XOR的失败 xor_data [0, 0, 1, 1; 0, 1, 0, 1]; xor_label [-1, 1, 1, -1]; % XOR 标签 % 尝试训练感知机 [w_xor, b_xor, loss_xor, ~] perceptron_train(xor_data, xor_label, 0.1, 100); % 绘制结果 figure(Name, 感知机无法解决XOR问题); gscatter(xor_data(1,:), xor_data(2,:), xor_label, rb, ox); hold on; % 尝试画出决策边界可能是一条无意义的线 x1_xor [-0.5, 1.5]; if abs(w_xor(2)) 1e-10 % 避免除零 x2_xor_boundary (-w_xor(1)/w_xor(2)) * x1_xor - (b_xor / w_xor(2)); plot(x1_xor, x2_xor_boundary, k--, LineWidth, 1.5); end title(感知机无法处理线性不可分问题 (如XOR)); xlabel(x1); ylabel(x2); legend(-1, 1, 决策边界); grid on; axis([-0.5 1.5 -0.5 1.5]);你会发现无论训练多少轮误分类数都不会降到0决策边界也无法正确分类所有点。这个局限性是感知机被诟病的主要原因也直接推动了多层感知机即神经网络的发展。多层感知机通过引入隐藏层和非线性激活函数具备了解决非线性问题的能力。6.3 实战建议与调试技巧最后分享几个在实现和使用感知机时的实用建议数据标准化如果特征x1和x2的量纲差异巨大比如一个在0-1一个在1000-10000最好先进行标准化处理如Z-score标准化。这能使梯度下降更平稳收敛更快。MATLAB里可以用zscore函数轻松实现。随机种子为了结果可复现可以在代码开头使用rng(42)42是常用种子固定随机数生成器。这样每次运行数据生成和参数初始化的结果都是一样的。观察收敛如果训练轮数max_epochs设得很大但损失曲线早早就平了误分类数不再变化可以在训练函数里加入提前终止的逻辑就像我们代码里做的那样节省时间。理解输出感知机输出的是1或-1。如果你需要概率形式的输出比如样本属于正类的可能性那么感知机不适合你你应该考虑逻辑回归。从感知机出发彻底弄懂这个简单的模型后你可以尝试去实现它的“升级版”——对偶感知机它通过样本间的内积来计算为理解支持向量机的核方法打下基础。你也可以尝试增加层数实现一个多层感知机并引入sigmoid、ReLU等非线性激活函数亲手搭建一个最简单的神经网络。感知机就像机器学习领域的“Hello World”。它简单但绝不肤浅。通过这次从零开始的MATLAB实战我希望你不仅获得了一段可运行的代码更重要的是建立了对机器学习模型如何从数据中学习、如何通过优化参数做出决策的直观感受。这种感受在你未来面对更复杂的模型时会是一笔宝贵的财富。