上一节楼主介绍了BP神经网络的基础,列出了一大堆公式,初学者肯定觉得很疑惑,这些公式有什么用处,一个BP神经网络又能用来干什么呢?本章是个简单的用BP神经网络实现分类的例子,楼主让人工智能Kimi写了一个BP神经网络的matlab的代码,实现了任意输入一个坐标(x,y),输出其坐标象限的功能。
一、任务说明
对于一个直角坐标系,其输入为(x,y),用BP神经网络指出当前坐标所在的象限,用一个向量来表示象限,其图示如下:

这个任务很简单,根据输入(x,y)的符号判断一下就行,如果写代码,用if.....else....就可以快速实现,似乎用不着神经网络这么高大上的东西?其实不是的,举这个例子是为了理解BP神经网络的学习过程,先从一个简单直观的例子切入,掌握之后再逐渐解决更复杂更高级的问题,这是一个循序渐进的过程。
把分类问题抽象出来之后,很多人还是下不了手,似乎理论到实践还有一条鸿沟,毕竟coding是个拦路虎,但是现在不一样了,我们有了人工智能这个工具,接下来,让Kimi帮我们开个头。
二、Kimi首秀
打开Kimi,直接输入自己的需求,Kimi确实给出了一段代码,它选择的是最简单的二分类问题,写的还算有模有样,也谦虚的表明“这只是一个基础的示例,实际应用中可能需要根据问题进行调整”。

可能有人会疑惑,楼主干嘛不让它直接写个坐标四分类的代码呢?楼主其实试过,和Kimi纠缠了半天,各种启发引导,它写的还不如一开始的二分类,楼主没耐心了,对于一个程序员来说,改一个代码比写一个代码更让人抓狂,二分类就二分类吧,改成四分类是分分钟的事情,楼主就用Kimi写的二分类改一个四分类出来,Kimi写的二分类是这样的:
% 随机生成一些数据用于训练和测试(假设为二分类问题)
data = rand(100, 2); % 100个样本,每个样本2个特征
labels = randi([0, 1], 100, 1); % 100个标签,0或1
% 定义网络参数
inputSize = 2; % 输入层神经元数量
hiddenSize = 5; % 隐藏层神经元数量
outputSize = 1; % 输出层神经元数量(二分类问题)
% 初始化权重和偏置
inputToHiddenWeights = rand(inputSize, hiddenSize) - 0.5;
inputToHiddenBias = zeros(1, hiddenSize);
hiddenToOutputWeights = rand(hiddenSize, outputSize) - 0.5;
hiddenToOutputBias = 0;
% 学习率
learningRate = 0.01;
% 前向传播和损失函数
for epoch = 1:1000
for i = 1:size(data, 1)
% 输入层到隐藏层
input = data(i, :);
hiddenInput = input * inputToHiddenWeights' + inputToHiddenBias;
hiddenOutput = sigmoid(hiddenInput);
% 隐藏层到输出层
outputInput = hiddenOutput * hiddenToOutputWeights + hiddenToOutputBias;
output = sigmoid(outputInput);
% 计算损失
loss = -labels(i) * log(output + 1e-8) - (1 - labels(i)) * log(1 - output + 1e-8);
% 反向传播
outputError = -(labels(i) - output) / (output * (1 - output));
hiddenError = outputError * hiddenToOutputWeights' * (hiddenOutput * (1 - hiddenOutput));
% 更新权重和偏置
hiddenToOutputWeights = hiddenToOutputWeights + hiddenOutput' * outputError * learningRate;
hiddenToOutputBias = hiddenToOutputBias + outputError * learningRate;
inputToHiddenWeights = inputToHiddenWeights + input' * hiddenError * learningRate;
inputToHiddenBias = inputToHiddenBias + hiddenError * learningRate;
end
% 每100个epoch打印一次损失
if mod(epoch, 100) == 0
disp(['Epoch ', num2str(epoch), ': loss = ', num2str(loss)]);
end
end
% 测试网络
testData = rand(10, 2); % 随机生成10个测试样本
for i = 1:size(testData, 1)
hiddenInput = testData(i, :) * inputToHiddenWeights' + inputToHiddenBias;
hiddenOutput = sigmoid(hiddenInput);
output = sigmoid(hiddenToOutputWeights * hiddenOutput + hiddenToOutputBias);
% 打印预测结果
fprintf('Output: %f, Class: %d\n', output, round(output));
end
% 辅助函数:Sigmoid激活函数
function g = sigmoid(z)
g = 1 ./ (1 + exp(-z));
end
三、BP实现四分类
首先肯定Kimi的工作,它清楚的写出了“训练”和“测试”这两个步骤,训练时的两个for循环逻辑正确,隐藏层和输出层的计算公式也是对的,sigmoid及其求导也没问题,但是这个代码,它跑不起来。
楼主仔细看了一下,Kimi没有正确区分matlab中的“.*”和“*”,造成维度对应不上,楼主改了一遍,它跑起来了,Kimi还是值得表扬的。现在可以完成坐标四分类的任务了,楼主做了以下三个的修改:
- 重新定义了data,把它指定成[-1,1]内的随机数。
- 重新定义了labels,做了if.....else.....判断,获得图5所示的标准输出。
- outputSize改成4,输出格式改的更符合楼主的需求。
改好的代码如下:
close all;
clear all;
clc;
% 定义网络参数
inputSize = 2; % 输入层神经元数量
hiddenSize = 5; % 隐藏层神经元数量
outputSize = 4; % 输出层神经元数量(四分类问题)
% 随机生成一些数据用于训练和测试(假设为四分类问题)
inputNum = 100;
% data = rand(inputNum, inputSize); % 100个样本,每个样本2个特征
data = rand(inputNum, inputSize)*2-1;
labels = zeros(inputNum,outputSize);
for i = 1 : inputNum
if ((data(i,1)>0) && (data(i,2)>0))
labels(i,:) = [1,0,0,0];
elseif ((data(i,1)<0) && (data(i,2)>0))
labels(i,:) = [0,1,0,0];
elseif ((data(i,1)<0) && (data(i,2)<0))
labels(i,:) = [0,0,1,0];
else
labels(i,:) = [0,0,0,1];
end
end
% labels = randi([0, 1], inputNum, outputSize); % 100个标签,0或1
% 初始化权重和偏置
inputToHiddenWeights = rand(inputSize, hiddenSize) - 0.5;
inputToHiddenBias = zeros(1, hiddenSize);
hiddenToOutputWeights = rand(hiddenSize, outputSize) - 0.5;
hiddenToOutputBias = 0;
% 学习率
learningRate = 0.01;
% 前向传播和损失函数
for epoch = 1:1000
for i = 1:size(data, 1)
% 输入层到隐藏层
input = data(i,:);
hiddenInput = input * inputToHiddenWeights + inputToHiddenBias;
hiddenOutput = sigmoid(hiddenInput);
% 隐藏层到输出层
outputInput = hiddenOutput * hiddenToOutputWeights + hiddenToOutputBias;
output = sigmoid(outputInput);
% 计算损失
loss = -labels(i) * log(output + 1e-8) - (1 - labels(i)) * log(1 - output + 1e-8);
% 反向传播
outputError = (labels(i,:) - output) .* (output .* (1 - output));
hiddenError = (hiddenOutput .* (1 - hiddenOutput)) .* (hiddenToOutputWeights * outputError')';
% 更新权重和偏置
hiddenToOutputWeights = hiddenToOutputWeights + hiddenOutput' * outputError * learningRate;
hiddenToOutputBias = hiddenToOutputBias + outputError * learningRate;
inputToHiddenWeights = inputToHiddenWeights + input' * hiddenError * learningRate;
inputToHiddenBias = inputToHiddenBias + hiddenError * learningRate;
end
% 每100个epoch打印一次损失
if mod(epoch, 100) == 0
disp(['Epoch ', num2str(epoch), ': loss = ', num2str(loss)]);
end
end
% 测试网络
testData = rand(10, inputSize)*2-1; % 随机生成10个测试样本
testOut = zeros(inputSize,outputSize);
for i = 1:size(testData, 1)
hiddenInput = testData(i,:) * inputToHiddenWeights + inputToHiddenBias;
hiddenOutput = sigmoid(hiddenInput);
output = sigmoid(hiddenOutput * hiddenToOutputWeights + hiddenToOutputBias);
testOut(i,:) = round(output);
% 打印预测结果
fprintf('index=%d, Input: [%f,%f], Class: [%d,%d,%d,%d]\n', i, testData(i,:), round(output));
end
楼主跑出的结果如下:

四、总结
以这个代码作为基础版本,可以增加层数、增加节点数或者更换激活函数等,如果想要python的代码,也可以让Kimi写,可以说有了人工智能,基本上实现了代码自由。接下来楼主要慢慢尝试其他更复杂一些的神经网络,并逐渐与ISP的处理结合起来。