赞
踩
MNIST 数据集是手写数字图像集,MNIST 是机器学习领域最有名的数据集之一,
- %sigmoid函数
- function r = sigmoid(x)
- r = 1 ./ (1 + exp(-x));
- end
- function r = softmax(x)
- S = sum(exp(x));
- r = zeros(length(x), 1);
- for i = 1:length(x)
- r(i) = exp(x(i)) / S;
- end
- end
- % 反向传播代码
- function [W1, W2, W3, error, accuracy] = BP(W1, W2, W3, alpha, D, imageData, accuracy)
- %卷积
- img_conv1 = zeros(20, 20, 20);
- for k = 1:20
- img_conv1(:, :, k) = filter2(W1(:, :, k), imageData, 'valid');
- end
- %ReLU激活
- img_act = max(0, img_conv1);
- %池化
- img_pool = (img_act(1:2:end, 1:2:end, :) + img_act(2:2:end, 2:2:end, :) +
- img_act(1:2:end, 2:2:end, :) +img_act(2:2:end, 1:2:end, :)) / 4;
- %将img_pool转换成列向量(2000*1)
- img_input = reshape(img_pool, [], 1);
- %第一个隐层的输出
- v1 = W2 * img_input;
- y1 = max(0, v1);
- %输出层的输出
- v2 = W3 * y1;
- y2 = softmax(v2);
- %观察模型是否训练准确
- [value1, index1] = max(y2);
- [value2, index2] = max(D);
- if index1 == index2
- accuracy = accuracy + 1;
- end
- % 计算交叉熵函数
- error = sum(- D .* log(y2) - (1 - D) .* log(1 - y2)) / 10;
- %误差反向传播过程
- %计算输出层的delta
- e2 = D - y2;
- delta2 = e2;
- %计算第一层隐藏层的delta1
- e1 = W3' * delta2;
- delta1= (y1 > 0) .* e1;
- %计算输入层(reshape层)的e
- e = W2' * delta1;
- %将输入层的误差进行reshape,以便于误差进一步反向传播穿过池化层和卷积层
- E2 = reshape(e, size(img_pool));
- %将池化层的误差传播到卷积层
- E1 = zeros(size(img_act));
- E2_4 = E2 / 4;
- E1(1:2:end, 1:2:end, :) = E2_4;
- E1(1:2:end, 2:2:end, :) = E2_4;
- E1(2:2:end, 1:2:end, :) = E2_4;
- E1(2:2:end, 2:2:end, :) = E2_4;
- delta = (img_act > 0) .* E1;
- dW1 = zeros(9, 9, 20);
- for k = 1:20
- dW1(:, :, k) = alpha * (filter2(delta(:, :, k), imageData, 'valid'));
- end
- %更改权重
- W1 = W1 + dW1;
- W2 = W2 + alpha * delta1 * img_input';
- W3 = W3 + alpha * delta2 * y1';
- end
- %训练并测试
- %第一个卷积层的权重
- W1 = randn(9, 9, 20);
- %学习率
- alpha = 0.001;
- %训练集文件夹路径
- train_path = 'MNIST_train/';
- %第一个隐层的权重
- W2 = (2 * rand(100, 2000) - 1) / 20;
- %输出层的连接权重
- W3 = (2 * rand(10, 100) - 1) / 10;
- %设置迭代次数
- n = 1;
- %初始化样本标签数据(一共有60000张图片,所以需要保存60000个标签数据)
- label = zeros(60000, 1);
-
- %先对每个样本进行标记
- for i = 0:9
- trainfolderpath = strcat(train_path, num2str(i));
- % 获取文件夹中的所有图像文件
- trainimageFiles = dir(fullfile(trainfolderpath, '*.jpg'));
- % 循环读取每个图像
- for j = 1:length(trainimageFiles)
- % 假设imageFiles(j).name包含文件名
- FileName = trainimageFiles(j).name;
- % 利用fileparts获得文件名,方便后续辨识每张图片的标签
- [~, name_number, ~] = fileparts(FileName);
- %通过解析文件名就可以获得图片的序号
- number = str2num(name_number);
- %给图片打上标签
- label(number) = i;
- end
- end
-
- %开始计时
- tic;
-
- %训练网络时用到的文件夹,在该文件夹下将所有类别的图片混合,可以提高训练效果
- Path_mix = 'train_mix/';
- %每张图片的交叉熵
- loss = zeros(60000, 1);
- %平均交叉熵
- loss_ave = zeros(60000, 1);
- %训练集的准确率
- acc_train = zeros(60000, 1);
- accuracy = 0;
- %开始训练,只训练一轮
- for epochs = 1:n
- folderpath = Path_mix;
- %获取文件夹中的所有图像文件
- imageFiles = dir(fullfile(folderpath, '*.jpg')); % 可以更改文件扩展名以匹配你的图像格式
- % 循环读取每个图像
- for j = 1:length(imageFiles)
- % 构建完整的文件路径
- lab = label(j);
- %设置目标输出
- D = zeros(10, 1);
- D(lab+1) = 1;
- %获取要读取的图片的地址
- imagePath = strcat(folderpath, num2str(j));
- imagePath = strcat(imagePath, '.jpg');
- %输出正在处理的图像和训练进度
- fprintf('模型训练的进度:%f%%\n', j/600);
- s = sprintf('正在训练的图片为:%s', imagePath);
- disp(s);
- % 使用 imread 读取图像
- imageData = imread(imagePath);
- %对图像进行归一化操作
- imageData = round(imageData / 255);
- [W1, W2, W3, error, accuracy] = BP(W1, W2, W3, alpha, D, imageData, accuracy);
- acc_train(j) = accuracy / j;
- loss(j) = error;
- loss_ave(j) = sum(loss(1:j)) / j;
- end
- end
- % 停止计时
- elapsedTime = toc;
- % 打印执行时间
- fprintf('训练时长为:%.4f 秒\n', elapsedTime);
- %训练结束的信号
- disp('训练结束,正在进行测试...');
- %测试集地址
- testPath = 'MNIST_test/';
- %记录测试集有多少张图片
- image_numbers_test = 1;
- %测试集上的准确率
- acc = 0;
- for i = 0:9
- %依次遍历MINIST_train(训练集)文件夹下的每一个子文件夹,每一个子文件夹中包含相同的数字
- test_path = strcat(testPath, num2str(i));
- % 获取文件夹中的所有图像文件
- testimageFiles = dir(fullfile(test_path, '*.jpg'));
- % 循环读取每个图像
- for j = 1:length(testimageFiles)
- %测试集中每张图片的路径
- imagePath = fullfile(test_path, testimageFiles(j).name);
- %读取图像
- imageData = imread(imagePath);
- %图片归一化操作
- imageData = round(imageData / 255);
- %卷积
- img_conv1 = zeros(20, 20, 20);
- for k = 1:20
- img_conv1(:, :, k) = filter2(W1(:, :, k), imageData, 'valid');
- end
- %对卷积得到的图片进行ReLU激活
- img_act = max(0, img_conv1);
- %平均池化(2*2)
- img_pool = (img_act(1:2:end, 1:2:end, :) + img_act(2:2:end, 2:2:end, :) + img_act(1:2:end, 2:2:end, :) +img_act(2:2:end, 1:2:end, :)) / 4;
- %将img_pool转换成列向量(2000*1)
- img_input = reshape(img_pool, [], 1);
- %第一个隐层的输出
- v1 = W2 * img_input;
- y1 = max(0, v1);
- %输出层的输出
- v2 = W3 * y1;
- y2 = softmax(v2);
- [~, index] = max(y2);
- %如果分类正确准确率就加1
- acc = acc + ((index-1) == i);
- image_numbers_test = image_numbers_test + 1;
- end
- end
- %画图观察模型训练效果
- subplot(1, 2, 1);
- plot(1:60000, loss_ave);
- xlabel('训练的图片数');
- ylabel('平均损失函数值');
- title('平均交叉熵随训练的图片数量的变化');
- subplot(1, 2, 2);
- plot(1:60000, acc_train);
- xlabel('训练的图片数');
- ylabel('准确率');
- title('准确率随训练的图片数量的变化');
- fprintf('测试集的准确率为%f\n', acc/(image_numbers_test-1));
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。