BP神经网络Matlab实现(工具箱实现、自主编程实现)

2023-11-03



BP神经网络是最常见、也是最基础的一种神经网络。网上教程颇多,但是对初学者可能会不太友好。本文打算由浅入深,先使用神经网络工具箱快速实现,然后再自己编写代码加深理解。本文使用 MATLAB 2018B。


一、快速实现


1.1 背景介绍

我们将拟合一个非线性的函数,为简单起见而不失一般性,这个函数有两个自变量,函数为:

那么,现在神经网络的结构如下:

输入为 x1, x2,输出为 z,中间层数量待定,现需要训练网络,使得各个箭头获得合适的权值,以拟合我们的目标式子。


1.2 神经网络工具箱实现

%% ann_toobox.m
%% 1、模拟产生数据
x1 = -10: 0.2: 10;              					% 自变量1(行向量)
x2 = -10: 0.2: 10;             				 		% 自变量2(行向量)
z  = cos(x1) + sqrt(abs(x2))-2;  					% 真实函数关系

inputs = [x1; x2];									% 输入矩阵(变量数 x 样本数)
targets = z;										% 目标矩阵(目标数 x 样本数)

%% 2、训练网络

net = newff(inputs,targets, 50);  					% 定义网络结构,一个隐含层,含50个神经元
net = train(net,inputs,targets);  					% 训练网络
outputs = net(inputs);            					% 训练结果
 
%% 3、可视化  
plot(x1, targets,'--','LineWidth', 2); hold on   	% 绘制真实目标曲线
plot(x1, outputs, 'LineWidth', 1);               	% 绘制拟合结果
legend('目标值', '拟合值'); hold off              	% 加图标

结果如下:

可见,整体上已经拟合得很不错了,但是在 0 附近还是有一定偏差。我们可以调节调节网络参数,使得拟合更加准确。


二、更进一步


2.1 归一化

基于以上例子,我们可以做进一步思考和完善。首先是需要归一化,好处有:

  • 如果输入值很大,而初始化的权值不变,容易导致非线性变换前的数值太大,梯度消失,不利于训练;
  • 输入数据可能量纲不一样,取值范围可能在不同数量级,不利于权值初始化;

一种归一化的方式为

实现了从 x —>y 的映射。这也即 MATLAB 里面的mapminmax()函数,默认归一化到 [-1, 1] 区间。


2.2 非线性函数

常用的非线性函数及其图像如下:

遗憾的是,MATLAB似乎只提供前三个,而没有ReLU 函数。在实际工程中,最常用的方式是最后一层使用 tansig,而前面所有层使用ReLU。实际上,ReLU具有

  • 单侧抑制
  • 相对宽阔的兴奋边界
  • 稀疏激活性质(小于零则为零,而不像其他的稍微有点激活)

这些特点其实与生物的神经元有相似之处,自2001年来 ReLU函数成为了后起之秀。


三、自己实现(2020.5.5补充)

3.1 写在前面

其实,关于BP神经网络实现,网上有不少教程,但大多数直接调用工具箱。讲解BP神经网络原理的文章也可以说汗牛充栋。但是,从原理到实例到编程的文章,少之又少。

其实,个人觉得神经网络之所以复杂,其中一个原因就是向量化带来的矩阵运算。如果输入层,隐含层和输出层都只含有一个节点,那么会容易实现很多,包括前向后反向传播,想要自己实现的同行可以先尝试次方案,由浅入深。

为了说明向量化过程,此处以输入层 2 个节点,隐含层 3 个节点,输出层 1 个节点,每次同时输入100个数据训练为例。

为了弄懂原理,务必自己手动计算下面三张图片的过程。没有谁是大神,一眼就能看出里面的矩阵,反正我不能。

如果图片不够清晰,可以在百度网盘链接(链接:https://pan.baidu.com/s/1zo4gm_71OsYxS8G8rgN0kA 提取码:fsyf)下载原图(据说CSDN下载要积分,一个好好的功能就这么废了大半)。


3.2 向量化过程

第一张图片,只考虑一个样本输入,而不是100个样本一起输入的情况。图中包括整个网络结构图,正向传播、部分反向传播。第一层指的是隐含层,第二层值的是输出层。输入层一般不算。注意,图中有的符号,比如 w11 同时是两层的参数,但是注意一下是容易辨识的。为了简洁,牺牲一点精确性是值得的。这里采用经典的 sigma 函数作为激活函数。

BP1
第二张图接着实现剩下的 dW1, db1,并且进行更新。可以看出,最关键的就是求导的链式法则,算好每一个导数,最终的导数自然也有了。注意,这里用星号(*)表示对应元素相乘,用点(·)表示矩阵乘法。

BP2
最后更新是为什么是减法而不是加法呢?还是简单看下原理:

d W 2 = z 2 − t dW_{2} = z_{2} - t dW2=z2t
特殊点,例如当 z 2 < t z_{2}<t z2<t 的每一项时, d W 2 dW_{2} dW2 为负,还没达到输出目标。而归一化后的 x 2 x_{2} x2 总是正数,为了增大输出,当然必须增大 W 2 W2 W2
W 2 = W 2 − α d W 2 W_{2} = W_{2} - \alpha dW_{2} W2=W2αdW2
减去一个负数才能增大 W 2 W_{2} W2,因此是减法而不是加。

第三张图片是考虑100个样本同时输入时的情况,图中所有求和都是这100个样本的数据对应求和。这里多引入一个符号(圆圈内加点)表示这一步即含有矩阵的乘法又含有对应元素相乘的方法。随时标注矩阵大小更容易明白整个过程。
BP3


3.3 编程实现

弄懂上面三张图片,才有可能自己编写出程序,当然,只想要程序的话,直接看下面程序即可。还是拟合下面的函数,在 [-10, 10] 之间取100个点拟合。

先看效果,看起来不够完美,但是莫方,后面会有改进。
拟合效果
程序如下,里面最难的就是dW2, db2, dW1, db1 的计算,矩阵顺序为什么这样,为什么要转置,这些原因都在上面的图片里。

此外,我觉得使用模块化的思想很重要,这是学习吴恩达《神经网络与深度学习》课程时深刻感受到的。这里也把很多小模块封装成函数,一个个调用,思路更清晰,也方便debug。

rng(0)                                  % 设定随机数种子,保证可重复性
m = 2;                                  % 输入层数量
n1 = 5;                                 % 隐含层数量
n2 = 1;                                 % 输出层数量
N = 100;                                % 并行输入样本数

x = [linspace(-10, 10, N);              % 目标函数的 x1
     linspace(-10, 10, N)];             % 目标函数的 x2
t = cos(x(1,:))+ sqrt(abs(x(2,:)))-2;   % 目标值

x1 = mapminmax(x);                      % 归一化

W1 = randn(n1, m);                      % 随机初始化参数 W1
b1 = randn(n1, 1);                      % 随机初始化参数 b1
W2 = randn(n2, n1);                     % 随机初始化参数 W2
b2 = randn(n2, 1);                      % 随机初始化参数 b2

alpha = 0.001;                          % 学习率,可调节查看效果

for k = 1:50000                         % 训练50000次
    z1 = forward_linear(x1, W1, b1);    % 前向线性变换
    x2 = forward_nonlinear(z1);         % 非线性变换
    z2 = forward_linear(x2, W2, b2);    % 前向线性变换
    E = sum_err_squ(z2, t);             % 计算误差
    if E < 0.01
        break;                          % 误差小于给定值,退出
    end
    [dW2, db2] = backward_w2b2(z2, t, x2);          % 计算参数增量
    [dW1, db1] = backward_w1b1(z2, t, W2, x2, x1);  % 计算参数增量
    W2 = W2 - alpha * dW2;              % 更新参数
    b2 = b2 - alpha * db2;              % 更新参数
    W1 = W1 - alpha * dW1;              % 更新参数
    b1 = b1 - alpha * db1;              % 更新参数
end

plot(x(1,:), t, '--',x(1,:), z2);       % 绘图
legend('目标值', '拟合值');

function z = forward_linear(x, W, b)    % 前向线性变换
    z = W * x + b;
end

function x = forward_nonlinear(z)       % 前向非线性变换
    x = 1 ./ (1 + exp(-z));
end

function E = sum_err_squ(z2, t)        % 误差平方和
    E = 1/2 * sum((z2 - t).^2);
end

function [dW2, db2] = backward_w2b2(z2, t, x2)          % 参数增量 dW2, db2
    dW2 = (z2 - t) * x2';
    db2 = sum(z2 - t);
end

function [dW1, db1] = backward_w1b1(z2, t, W2, x2, x1)  % 参数增量 dW1, db1
    dW1 = (z2 - t) .* (W2' .* x2 .* (1-x2)) * x1';
    db1 = (W2' .* x2 .* (1-x2)) * (z2 - t)';
end

运行结果已经在上面了。可是尝试改变隐含层神经元数量,学习因子 alpha 来看看不同的效果。


3.4 改进

曲线总是拟合得不够好,其实一个原因是学习率是固定的,这又个缺点,学习率太小训练缓慢,学习率太大精度有限。因此,我们希望刚开始学习率大些,后期学习率小些,一种方法是给定学习率函数,但是比较复杂。动量因子法是经过历史考验传承下来的方法,因此采用。

依旧是简单看下原理:

之前的更新公式: W 2 = W 2 − α ∗ d W 2 W_{2} = W_{2} - \alpha*dW_{2} W2=W2αdW2
使用动量法的更新公式: d W 2 = m ⋅ d W 2 ^ + α ⋅ d W 2 dW_{2} = m\cdot \hat{dW_{2}} + \alpha \cdot dW_{2} dW2=mdW2^+αdW2
W 2 = W 2 − d W 2 W_{2} = W_{2} - dW_{2} W2=W2dW2
其中 m m m 是动量因子, d W 2 ^ \hat{dW_{2}} dW2^ 是上一次的误差量,也即梯度。

简单说, W 2 W_{2} W2 的最终增量从 α ∗ d W 2 \alpha*dW_{2} αdW2 变为 m ⋅ d W 2 ^ + α ⋅ d W 2 m\cdot \hat{dW_{2}} +\alpha \cdot dW_{2} mdW2^+αdW2
这样的好处是什么呢?能够延续上一次的梯度。上一次梯度和这一次梯度都为正,这一次也将会有很大正的梯度,而且越加越快,加快刚开始时的网络收敛速度。后期某一次上次梯度为正,这次为负,那么一次又一次地负梯度打击下,梯度绝对值将逐渐减小,最后到 0 附近,可能收敛了,也可能继续往负方向越来越快地增大。但最终,网络收敛时,梯度接近0。

说了那么多,先看效果(其他条件不变),使用动量(动量因子0.9)后好一些:
动量前后程序如下:

rng(0)                                  % 设定随机数种子
m = 2;                                  % 输入层数量
n1 = 5;                                 % 隐含层数量
n2 = 1;                                 % 输出层数量
N = 100;                                % 并行输入样本数

x = [linspace(-10, 10, N);              % 目标函数的 x1
     linspace(-10, 10, N)];             % 目标函数的 x2
t = cos(x(1,:))+ sqrt(abs(x(2,:)))-2;   % 目标值

x1 = mapminmax(x);                      % 归一化

W1 = randn(n1, m);                      % 随机初始化参数 W1
b1 = randn(n1, 1);                      % 随机初始化参数 b1
W2 = randn(n2, n1);                     % 随机初始化参数 W2
b2 = randn(n2, 1);                      % 随机初始化参数 b2

alpha = 0.001;                          % 学习率,可调节查看效果
m = 0.9;

dW2 = zeros(size(W2));
db2 = zeros(size(b2));
dW1 = zeros(size(W1));
db1 = zeros(size(b1));

for k = 1:50000                         % 训练50000次
    z1 = forward_linear(x1, W1, b1);    % 前向线性变换
    x2 = forward_nonlinear(z1);         % 非线性变换
    z2 = forward_linear(x2, W2, b2);    % 前向线性变换
    E = sum_err_squ(z2, t);             % 计算误差
    if E < 0.01
        break;                          % 误差小于给定值,退出
    end
    
    dW2_last = dW2;                     % 记录上次 dW2
    db2_last = db2;
    dW1_last = dW1;
    db1_last = db1;
    
    [dW2, db2] = backward_w2b2(z2, t, x2);          % 计算参数增量
    [dW1, db1] = backward_w1b1(z2, t, W2, x2, x1);  % 计算参数增量

    dW2 = m * dW2_last + alpha * dW2;   % 动量法更新 dW2
    db2 = m * db2_last + alpha * db2;
    dW1 = m * dW1_last + alpha * dW1;
    db1 = m * db1_last + alpha * db1;
    
    W2 = W2 - dW2;              % 更新参数
    b2 = b2 - db2;              % 更新参数
    W1 = W1 - dW1;              % 更新参数
    b1 = b1 - db1;              % 更新参数
end

plot(x(1,:), t, '--',x(1,:), z2); hold on      % 绘图
legend('目标值', '拟合值');

function z = forward_linear(x, W, b)    % 前向线性变换
    z = W * x + b;
end

function x = forward_nonlinear(z)       % 前向非线性变换
    x = 1 ./ (1 + exp(-z));
end

function E = sum_err_squ(z2, t)        % 误差平方和
    E = 1/2 * sum((z2 - t).^2);
end

function [dW2, db2] = backward_w2b2(z2, t, x2)          % 参数增量 dW2, db2
    dW2 = (z2 - t) * x2';
    db2 = sum(z2 - t);
end

function [dW1, db1] = backward_w1b1(z2, t, W2, x2, x1)  % 参数增量 dW1, db1
    dW1 = (z2 - t) .* (W2' .* x2 .* (1-x2)) * x1';
    db1 = (W2' .* x2 .* (1-x2)) * (z2 - t)';
end

3.5 炼丹师的工作

慢慢调节隐含层数目、动量因子、学习率、初始化参数这些,如果有能力,连激活函数改了(记得反向传播公式也要修改)或许能够找到一组好的参数。深度学习工程师(炼丹师)就是做这个的。调了一组,效果如下:
调参后
比其刚开始的使用工具箱的那张,效果差些,但是勉强可以接受了。代码附上:

rng(0)                                  % 设定随机数种子
m = 2;                                  % 输入层数量
n1 = 8;                                 % 隐含层数量
n2 = 1;                                 % 输出层数量
N = 100;                                % 并行输入样本数

x = [linspace(-10, 10, N);              % 目标函数的 x1
     linspace(-10, 10, N)];             % 目标函数的 x2
t = cos(x(1,:))+ sqrt(abs(x(2,:)))-2;   % 目标值

x1 = mapminmax(x);                      % 归一化

W1 = randn(n1, m) / 10;                      % 随机初始化参数 W1
b1 = randn(n1, 1) / 10;                      % 随机初始化参数 b1
W2 = randn(n2, n1) / 10;                     % 随机初始化参数 W2
b2 = randn(n2, 1) / 10;                      % 随机初始化参数 b2

alpha = 0.008;                          % 学习率,可调节查看效果
m = 0.90;

dW2 = zeros(size(W2));
db2 = zeros(size(b2));
dW1 = zeros(size(W1));
db1 = zeros(size(b1));

for k = 1:50000                         % 训练50000次
    z1 = forward_linear(x1, W1, b1);    % 前向线性变换
    x2 = forward_nonlinear(z1);         % 非线性变换
    z2 = forward_linear(x2, W2, b2);    % 前向线性变换
    E = sum_err_squ(z2, t);             % 计算误差
    if E < 0.01
        break;                          % 误差小于给定值,退出
    end
    
    dW2_last = dW2;                     % 记录上次 dW2
    db2_last = db2;
    dW1_last = dW1;
    db1_last = db1;
    
    [dW2, db2] = backward_w2b2(z2, t, x2);          % 计算参数增量
    [dW1, db1] = backward_w1b1(z2, t, W2, x2, x1);  % 计算参数增量

    dW2 = m * dW2_last + alpha * dW2;   % 动量法更新 dW2
    db2 = m * db2_last + alpha * db2;
    dW1 = m * dW1_last + alpha * dW1;
    db1 = m * db1_last + alpha * db1;
    
    W2 = W2 - dW2;              % 更新参数
    b2 = b2 - db2;              % 更新参数
    W1 = W1 - dW1;              % 更新参数
    b1 = b1 - db1;              % 更新参数
end

plot(x(1,:), t, '--',x(1,:), z2);       % 绘图
legend('目标值', '拟合值');

function z = forward_linear(x, W, b)    % 前向线性变换
    z = W * x + b;
end

function x = forward_nonlinear(z)       % 前向非线性变换
    x = 1 ./ (1 + exp(-z));
end

function E = sum_err_squ(z2, t)        % 误差平方和
    E = 1/2 * sum((z2 - t).^2);
end

function [dW2, db2] = backward_w2b2(z2, t, x2)          % 参数增量 dW2, db2
    dW2 = (z2 - t) * x2';
    db2 = sum(z2 - t);
end

function [dW1, db1] = backward_w1b1(z2, t, W2, x2, x1)  % 参数增量 dW1, db1
    dW1 = (z2 - t) .* (W2' .* x2 .* (1-x2)) * x1';
    db1 = (W2' .* x2 .* (1-x2)) * (z2 - t)';
end

完!

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

BP神经网络Matlab实现(工具箱实现、自主编程实现) 的相关文章

  • 在 MATLAB 中模拟 C++ 模板

    我试图找出创建 C 模板或 Java 通用对象的替代方案的最佳方法 出于多种不同的原因 我过去曾多次想这样做 但现在我想做的是为几个相关的类创建 saveobj 和 loadobj 函数 我的想法是 我想要一组通用的例程来创建默认结构 然后
  • MATLAB 编译器与 MATLAB 编码器

    两者有什么区别 据我了解 MATLAB Compiler将MATLAB代码包装成 exe文件 这样就可以在不安装MATLAB的情况下使用它 并且只需要MCR 除此之外 MATLAB Builder NE 还可以用于生成与 Net 框架一起使
  • 以 2 为底的矩阵对数

    Logm 取矩阵对数 并且log2 取矩阵每个元素以 2 为底的对数 我正在尝试计算冯 诺依曼熵 它涉及以 2 为底的矩阵对数 我该怎么做呢 如果将 以 2 为底 的矩阵指数定义为B expm log 2 A 或者如果您类似地通过特征分解直
  • 在matlab中,如何读取python pickle文件?

    在 python 中 我生成了一个 p 数据文件 pickle dump allData open myallData p wb 现在我想在Matlab中读取myallData p 我的Matlab安装在Windows 8下 其中没有Pyt
  • 获取向量幂的有效方法

    我编写了一个代码 在数值上使用勒让德多项式直至某个高 n 阶 例如 case 8 p 6435 x 8 12012 x 6 6930 x 4 1260 x 2 35 128 return case 9 如果向量x太长这会变得很慢 我发现说之
  • Ilnumerics Ilpanel 在 winform 中编译成 dll 并加载到 matlab 时不激活

    我想将 Visual studio 2012 中用 C 编写的 winform 编译为 dll 然后将其加载到 matlab 2013a 中 然后 我想使用 matlab net 接口与 winform 进行交互 侦听其事件并通过一组预定义
  • FMINCON 的替代方案

    除了 fmincon 之外还有其他更快 更高效的求解器吗 我正在使用 fmincon 来解决特定问题 但对于中等大小的向量变量来说 我的内存不足 我也没有任何超级计算机或云计算选项可供使用 我知道任何替代解决方案仍然会耗尽内存 但我只是想看
  • 如何选择面积最大的对象?

    我用过bwconvhull检测图像的某个部分 正如您在图像中看到的那样 有许多具有特定质心的对象 我想做的是检测面积最大的物体 左起第一个大物体 并忽略其他物体 我应该遵循哪种方法 我将非常感谢您的帮助 以下是代码 由于我仍在努力 所以写得
  • 通过颜色渐变修补圆

    我正在尝试绘制一个颜色渐变 我希望它沿轴均匀 在下图由角度定义的情况下 pi 7 当我使用patch命令 绘图与所需的梯度方向匹配 但沿其方向并不均匀 沿圆的点之间形成各种三角形 这是代码 N 120 theta linspace pi p
  • 优先连接,Matlab 中的复杂网络

    大家好 我现在正在 MATLAB 中研究优先附件模型 在理解以下内容时遇到一些困难 假设我一开始有 4 个节点 连接如下 time 0 1 lt gt 2 3 lt gt 4 在下一个时间步骤中 我添加一个节点和 4 个连接 然后添加另一个
  • 氡变换线检测

    我正在尝试检测灰度图像中的线条 为此 我在 MATLAB 中使用 Radon 变换 我的 m 文件的示例如下所示 我可以使用此代码检测多行 我还使用线条的移位和旋转属性来绘制线条 但是 我不明白在获取rho和theta值后如何获取检测线的起
  • 图像处理方面的空间和时间表征有什么区别?

    我是学习图像处理的初学者 我对空间和时间表征的概念有点困惑 那么 对于空间表征来说 是不是像一张二维地图 包含了一些关于地图的统计信息呢 就时间特征而言 值是相对于时间的吗 这意味着什么以及我们为何关心 谢谢 当您在不同时间拍摄一系列图像时
  • matlab中优先级队列的实现方法

    matlab中有没有提供minpriorityqueue功能的库 import java util PriorityQueue import java util public class MyQueue Comparator
  • 计算给出数组中最小标准差的子集

    让我们有一个大小的向量N 例如 x rand N 1 我想计算长度子集的最小标准差K在向量中 When N and K很小 很容易找到最好的子集 因为我可以使用nchoosek N K 枚举所有可能的子集 但是当值N and K比我们说的要
  • 如何从 Matlab 运行 R 脚本 [重复]

    这个问题在这里已经有答案了 我有 m 文件 我想用它来运行 R 脚本 我怎样才能做到这一点 Matlab文件 caller m some matlab code need to call a R script some matlab cod
  • Matlab 中的 3D 堆叠条形图

    我想在一个图中绘制多个堆叠条形图 detached 条形图 例如 准确地想象一下bar http mathworks com help matlab ref bar3 detached png绘图 但堆叠在一起 而不是单一颜色 Set up
  • 将值从 C++ MEX 文件返回到 MATLAB

    我正在编写一个从 C 代码中检索数据的 MATLAB 程序 为此 我在 MATLAB 中创建了一个 MEX 文件和一个网关 mexFunction 虽然可以在 MATLAB 中读取读取值 但我无法检索它来使用它 如果不清楚 我有与这里完全相
  • 计算向量的导数

    我有以下函数 维维亚尼曲线 Phi t cos t 2 cos t sin t sin t 只需检查它是否有效 s linspace 0 T 1000 plot3 cos s 2 cos s sin s sin s 如何推导函数Phi 可能
  • MATLAB 符号替换

    我知道在 MATLAB 中如果声明了 syms x y f x 2 y 2 grad gradient f 然后grad会存储值 2 x 2 y 如果我想评估梯度 2 2 I use subs f x y 2 2 这返回 4 4 我正在编写
  • 在matlab中融合2个以上的图像

    在 MATLAB 中 如何融合两个以上的图像 例如 我想要做什么imfuse但对于超过 2 个图像 使用两张图像 这是我的代码 A imread file1 jpg B imread file2 jpg C imfuse A B blend

随机推荐

  • Linux命令入门教程(五):系统管理篇

    Linux系统管理 包括权限管理 网络配置 软件安装 各类参数设置 开关机 系统运行状态等 5 1 权限管理 在linux系统中 用户类别有超级用户和普通用户 只有一个超级用户root 普通用户可以有多个 最根本的区别就是权限不同 在lin
  • iOS17可以更新了!网友实测炫酷值拉满,但续航嘛…

    丰色 发自 凹非寺量子位 公众号 QbitAI iOS 17终于来了 今天凌晨正式推送 有数码博主评价 实用性不高 但酷炫值拉满 旺柴 可以说是一句话概括了 不过有测评发现 更新后续航掉依然的厉害 特别是iPhone XR 可得谨慎了 还登
  • 关于代理抓包,ssl pinning解决方案

    详情见我的博客小生博客 抓包 代理抓包 Fiddler charles能抓http https websocket属于应用层 优点 配置简单 抓取解析ssl方便 缺点 app对代理抓包的检测越发厉害 https http是明文传播 易被修改
  • 轻松搭建基于 SpringBoot + Vue 的 Web 商城应用

    首先介绍下在本文出现的几个比较重要的概念 函数计算 Function Compute 函数计算是一个事件驱动的服务 通过函数计算 用户无需管理服务器等运行情况 只需编写代码并上传 函数计算准备计算资源 并以弹性伸缩的方式运行用户代码 而用户
  • ajax.request,ajaxrequest.js ajaxrequest 0.7最新版 使用AJAXRequest进行AJAX应用程序开发入门小技巧...

    使用AJAXRequest进行AJAX应用程序开发 1 初识AJAXRequest 前言 在发布了AJAXRequest类的几个版本之后 渐渐地有许多朋友用上了它 也有许多朋友问我有没有更详细的说明和示例 不过因为时间的问题以及我能想到的示
  • ClamAV 详解

    1 ClamAV介绍Clam AntiVirus是一个类UNIX系统上使用的反病毒软件包 主要应用于邮件服务器 采用多线程后台操作 可以自动升级病毒库 ClamAV是一个在命令行下查毒软件 因为它不将杀毒作为主要功能 默认只能查出您计算机内
  • 微信小程序canvas生成图片并保存

    需求 做一个类似下图的功能 图片内容是动态的 用canvas画出来 生成临时图片 再保存 实现
  • Python中的isinstance()函数

    1 描述 Python中的 isinstance 函数 是Python中的一个内置函数 用来判断一个函数是否是一个已知的类型 类似 type 2 语法 isinstance object classinfo 参数 object 实例对象 c
  • Servlet工作原理

    文章目录 一 Servlet是什么 二 相关接口 三 Servlet的工作流程 四 Servlet的生命周期 总结 一 Servlet是什么 Servlet 类是 JavaWeb 的三大组件之一 它属于动态资源 是一组 Tomcat 提供给
  • Thread的API介绍

    join 等待当前线程执行完成之后 再执行接下来的语句 如下面的例子所示 在t1线程启动完之后 调用t1 join 的方法 那么会在这里阻塞住 直到t1线程执行完之后 才会继续执行下面的语句 public class RunnableJob
  • 什么是MTTF、MTBF、MTRF?

    1 MTTF 全称是Mean Time ToFailure 即平均失效时间 系统平均能够正常运行多长时间 才发生一次故障 系统的可靠性越高 平均无故障时间越长 2 MTBF 全称是Mean Time BetweenFailure 即平均无故
  • lisp编译器_200行代码实现超轻量级编译器

    前言 本篇内容主要由 https github com jamiebuilds the super tiny compiler 中的注释翻译而来 该项目实现了一款包含编译器核心组成的极简的编译器 希望能够给想要初步了解编译过程的同学提供到一
  • 2021-02-06

    DVWA SQL Injection Blind SQL Injection SQL Injection 即SQL注入 是指攻击者通过注入恶意的SQL命令 破坏SQL查询语句的结构 从而达到执行恶意SQL语句的目的 SQL注入漏洞的危害是巨
  • Qt项目中出现的问题小结

    Qt项目中出现的问题小结 写在前面 总结这个星期自学Qt踩过的一些坑 并不包含所有问题 仅仅是基于自己所做的小界面而言 文章目录 Qt项目中出现的问题小结 1 Qt中文乱码 2 关于Qt调用vs编译的dll控件 3 关于动态链接库导出类与函
  • xss靶场挑战之旅总结

    第一关 没有做任何的过滤 我们试下 第二关 我们用 gt 有转义 参考HTML的转义 输入的 gt lt 被做了转义处理 变成了 gt lt 我们用javascript里边的oninput事件试试 我们用12 ninput alert 12
  • 利用 Redis 构建全文索引组件

    文章目录 前言 一 反向索引 二 实现代码 前言 数据库文章全文搜索中我们很少使用 like 查询 因为假设使用包含查询 我们需要对每个检索词每一篇文章的每个单词进行遍历 检索的时间复杂度则会达到 o n三次方 通常 我们会直接使用 ela
  • 线性插值方法介绍及图像缩放

    1 线性插值 设函数 y f x y f x y f x 在两点
  • NewStarCTF week5 web wp

    Give me your photo PLZ 进去后看内容 看这个文字意思应该是考的二次渲染 贴个利用代码 制作二次渲染后不会被修改的图片马 其实还可以自己比对哪块地方被修改了 然后插到没被修改的里面就行
  • git am详解

    git am详解 在使用git am前 首先要使用git am abort 用来放弃以前的am信息 否则可能会遇到这样的错误 git rebase apply still exists but mbox given 打patch git a
  • BP神经网络Matlab实现(工具箱实现、自主编程实现)

    序 BP神经网络是最常见 也是最基础的一种神经网络 网上教程颇多 但是对初学者可能会不太友好 本文打算由浅入深 先使用神经网络工具箱快速实现 然后再自己编写代码加深理解 本文使用 MATLAB 2018B 一 快速实现 1 1 背景介绍 我