机器学习从入门到精通 - 神经网络入门:从感知机到反向传播数学揭秘


开场白:点燃你的好奇心

各位,有没有觉得那些能识图、懂人话、下棋碾压人类的AI特别酷?它们的"大脑"核心,很多时候就是神经网络!别被"神经网络"这词吓住——它真没想象中那么玄乎。今天这篇长文,我就带你从最最基础的"积木块"感知机开始,一步步搭出真正的神经网络,再亲手撕开那个传说中"劝退无数人"的反向传播黑盒子,看看里面的数学齿轮是怎么咬合转动的。相信我,搞懂这些,你才算真正摸到了深度学习的大门。准备好纸笔(或者你喜欢的IDE),咱们开干!


一、 从零开始:感知机 - 神经网络的"原子"

为什么要搞懂感知机? 很简单,它是神经网络最基础的决策单元,就像乐高积木里最小的那块砖。所有复杂的网络,都是由无数个这样的小玩意儿堆叠、连接而成的。不理解它,后面都是空中楼阁。

感知机模型:模拟生物神经元的"粗糙"尝试

想象一个生物神经元:多个输入信号(树突),一个输出信号(轴突)。如果输入的信号总和足够强,神经元就被"激活"(点火),输出信号。感知机就是这个过程的极度简化版数学模型:

  • x_i (输入信号):比如图片的像素值、文本的词频、传感器读数。
  • w_i (权重):代表对应输入信号的重要程度。关键点来了: 机器学习的核心任务就是学习到一组好的 w_ib,让感知机能做出正确的判断!这是它区别于普通公式的核心。
  • b (偏置项):可以理解为激活的难易程度阈值。b 大,需要更强的输入总和才能激活。
  • f (激活函数):在原始感知机里,通常是一个阶跃函数 (Step Function),也就是"够阈值就输出1,不够就输出0"。
# Python实现一个最简单的感知机 (仅用于二分类)
class Perceptron:def __init__(self, input_size, learning_rate=0.01):# 初始化权重 (接近0的小随机数) 和偏置self.weights = np.random.randn(input_size) * 0.01self.bias = 0.0self.lr = learning_rate  # 学习率,控制每次调整权重的步长def step_function(self, z):"""阶跃激活函数"""return 1 if z >= 0 else 0def predict(self, inputs):"""计算加权和 + 偏置,应用激活函数得到输出"""summation = np.dot(inputs, self.weights) + self.biasreturn self.step_function(summation)def train(self, training_inputs, labels, epochs=100):"""训练过程:核心!通过调整权重和偏置来拟合数据"""for epoch in range(epochs):for inputs, label in zip(training_inputs, labels):# 1. 前向传播:得到当前预测值prediction = self.predict(inputs)# 2. 计算误差:期望值(label)和预测值之差。# **为什么是减法?** 这是梯度下降思想的基础:误差告诉我们需要调整的方向。error = label - prediction# 3. 更新权重和偏置:核心规则!# **为什么这样更新?** 目的是让预测值向真实标签靠近。# 如果 error=1 (预测0,应为1),需要增加加权和(使z变大)# -> 增加权重 w_i (如果对应的 x_i>0) / 减小权重 w_i (如果 x_i<0) / 增加偏置# 如果 error=-1 (预测1,应为0),需要减小加权和(使z变小)# -> 减小权重 w_i (如果对应的 x_i>0) / 增加权重 w_i (如果 x_i<0) / 减小偏置# **学习率 lr 的作用:** 控制每次调整的幅度,防止震荡或收敛过慢。self.weights += self.lr * error * inputsself.bias += self.lr * error

踩坑记录1:线性可分的紧箍咒

这里有个巨坑!经典感知机(用阶跃函数做激活函数)只能解决线性可分问题。啥意思?想象你在纸上画一堆点(两类),如果能用一条直线完美地把两类点分开,那这个问题就是线性可分的(比如AND、OR逻辑门)。但如果是XOR(异或)问题——两类点像螺旋线一样交错或者被一条曲线分割——感知机就抓瞎了!它画不出那条"完美的直线"。这就是神经网络早期陷入低谷(第一次AI寒冬)的重要原因之一。破局的关键?多层感知机 (MLP) 和非线性激活函数

graph LRA[输入 x1] -->|权重 w1| C(求和节点 ∑)B[输入 x2] -->|权重 w2| CC --> D[+ 偏置 b]D --> E[激活函数 f]E --> F[输出 (0 or 1)]

二、 破局者:多层感知机 (MLP) 与激活函数

为啥单层不够? 上面踩坑点说了,单层感知机搞不定非线性问题(如XOR)。解决方案:堆叠! 把多个感知机(现在称为神经元单元)连接起来,形成输入层 -> 隐藏层 -> 输出层的结构。这就是多层感知机 (Multilayer Perceptron, MLP),是最基础的前馈神经网络。

为什么需要隐藏层? 隐藏层中的神经元可以学习输入数据更抽象、更复杂的组合特征。每一层都可以看作是在对输入数据进行一次变换和特征提取。

激活函数的革命:从阶跃到Sigmoid/ReLU

感知机最大的局限在哪? 就在那个硬邦邦的阶跃函数!它有两个致命缺点:

  1. 导数几乎处处为零(除0点外):这使得基于梯度的优化算法(如反向传播)无法工作(梯度消失)。
  2. 输出非0即1:无法表达"部分激活"或连续值预测(如房价预测)。

解决方案:引入非线性、连续、可导的激活函数! 让神经元的输出不再是二元的,而是连续的、有梯度的。常用选择:

  1. Sigmoid (Logistic函数):

    • 优点: 输出在(0,1)区间,像概率;函数光滑可导。
    • 缺点: 饱和区梯度消失严重! 当 |z| 很大时,导数 趋近0。这在深层网络是灾难。另外计算涉及指数,稍慢。
    • 符号含义: z 是加权和(z = w·x + b)
  2. tanh (双曲正切):

    • 优点: 输出在(-1,1)区间,以0为中心,有时收敛比Sigmoid快;同样光滑可导。
    • 缺点: 同样存在饱和区梯度消失问题。
  3. ReLU (Rectified Linear Unit): 强烈推荐首选!
    )

    • 优点:
      • 计算极其简单快速(比较和取大)。
      • 在正区间 (z>0) 导数为常数1极大缓解梯度消失问题! 这是深层网络成功的关键之一。
      • 具有生物学上的稀疏激活性(只有部分神经元被激活)。
    • 缺点: 死亡ReLU问题 (Dying ReLU):如果某个神经元的加权和 z 在训练过程中总是小于0(比如初始化不好或学习率过大),那么它的梯度永远为0,权重永远不会再更新,这个神经元就"死"了。解决方案:使用 Leaky ReLU (α是一个很小的正数如0.01) 或 Parametric ReLU (PReLU) (α可学习)。
import numpy as npclass MLP:def __init__(self, input_size, hidden_size, output_size):# 初始化权重和偏置 (使用更合理的初始化,如Xavier/Glorot)# 输入层 -> 隐藏层self.W1 = np.random.randn(input_size, hidden_size) * np.sqrt(2. / input_size)  # He初始化,适合ReLUself.b1 = np.zeros(hidden_size)# 隐藏层 -> 输出层self.W2 = np.random.randn(hidden_size, output_size) * np.sqrt(2. / hidden_size)self.b2 = np.zeros(output_size)# **强烈推荐 ReLU!** 它在实践中效果通常最好且训练快。Sigmoid/tanh主要用在输出层做概率映射。self.activation = self.reludef relu(self, z):"""ReLU 激活函数。简单、高效、梯度好!"""return np.maximum(0, z)def relu_derivative(self, z):"""ReLU 的导数:小于0时为0,大于0时为1"""return (z > 0).astype(float)def softmax(self, z):"""输出层常用Softmax激活函数,将输出转为概率分布(多分类)"""exp_z = np.exp(z - np.max(z, axis=-1, keepdims=True))  # 防溢出return exp_z / np.sum(exp_z, axis=-1, keepdims=True)def forward(self, X):"""前向传播:计算网络输出"""# 隐藏层输入self.z1 = np.dot(X, self.W1) + self.b1# 隐藏层输出 (应用激活函数)self.a1 = self.activation(self.z1)# 输出层输入self.z2 = np.dot(self.a1, self.W2) + self.b2# 输出层输出 (这里假设是多分类用Softmax)self.a2 = self.softmax(self.z2)return self.a2  # 预测概率分布# **踩坑记录2:初始化很重要!**
# 上面用了 `He初始化` (`* np.sqrt(2./fan_in)`)。为什么不用全0初始化?
# -> 全0初始化会导致同一层所有神经元的梯度更新完全相同,失去多样性(对称性破坏问题)。
# 小随机数初始化(如randn * 0.01)有时在网络深时会导致梯度消失或爆炸。
# He/Xavier初始化根据输入/输出维度缩放权重,有助于保持信号在正向传播和梯度在反向传播时的尺度稳定。
Output Layer
Hidden Layer
Input Layer
ReLU
ReLU
ReLU
Softmax
Softmax
y1
Neuron
y2
Neuron
a1
Neuron
a2
Neuron
a3
Neuron
x1
x2
x3

三、 神经网络的心脏:反向传播算法(Backpropagation)数学大揭秘

为什么需要反向传播? 前向传播计算出了网络的输出(预测值)。但网络一开始的参数(W, b)是随机的,预测肯定不准。我们要根据预测结果和真实标签之间的误差 (Loss),来调整网络参数,让下一次预测更准。反向传播就是用来高效计算误差相对于网络中每一个参数(每一层的 W 和 b)的梯度 (Gradient) 的算法。有了梯度,我们就可以用梯度下降 (Gradient Descent) 及其变体来更新参数,逐步最小化误差。

核心思想:链式法则 (Chain Rule)

反向传播的精髓就是微积分中的链式法则。误差 L 是网络输出 y_pred 的函数,y_pred 是上一层激活 a 的函数,a 是上一层输入 z 的函数,z 是权重 W 和偏置 b 的函数… 环环相扣。要求 L 对 W (或 b) 的导数,就需要一层层从后往前,把导数像链条一样传递回来。

符号约定
  • L:损失函数值 (Loss)。常用:均方误差(MSE)用于回归,交叉熵(Cross-Entropy)用于分类。强烈推荐分类用交叉熵! 它对错误预测的惩罚更陡峭,学习效率常比MSE高。
  • y:真实的标签值 (Ground Truth)。
  • ŷ / a^(L):网络最后一层的输出(预测值)。
  • z^(l): 第 l 层的加权输入 (z = W·a^(l-1) + b)。
  • a^(l): 第 l 层的激活输出 (a = f(z^(l)))。
  • W^(l), b^(l):第 l 层到第 l+1 层的权重矩阵和偏置向量。
  • δ^(l):第 l 层的误差项 (Error Term)。定义为 。这是反向传播的核心变量!
反向传播四步曲(以两层MLP为例,输出层用Softmax + 交叉熵)

Step 1: 计算输出层误差项 δ^(L)
假设输出层是第 L 层。损失函数使用交叉熵 (Cross-Entropy)

其中 k 遍历所有输出类别。ŷ_k 是 Softmax 的输出(预测概率):

  • 推导过程: 这是一个经典的推导。考虑对输出层第 k 个神经元的输入 z_k^(L) 的偏导:

    现在关键求 。Softmax 的求导需要分情况:

    • j = k

      其中 δ_jk 是 Kronecker delta (当 j=k 时为1,否则为0)。
    • j ≠ k

    将上面两个结果代回 δ_k^(L) 的求和式中,经过一番化简(这里涉及到将求和拆开、合并同类项),会得到一个极其优美的结果:

    写成向量形式就是:

    划重点: 输出层的误差项,就是预测概率向量与真实标签向量之差!这个简洁的形式是选择Softmax激活与交叉熵损失这对"黄金搭档"的主要原因之一。它直观地告诉我们,预测概率高出真实标签多少,梯度就有多大,参数就应该向哪个方向调整。

Step 2: 反向传播误差项到隐藏层 δ^(l)
现在我们有了输出层的误差 δ^(L),如何计算前一层(比如隐藏层 l)的误差 δ^(l) 呢?再次请出链式法则:

我们来逐项分解这个链条:

  1. 就是我们刚求出的后一层误差
  2. ,所以 。注意这里的转置!
  3. , 所以 , 也就是 l 层激活函数的导数。

把它们乘起来,就得到了误差从 l+1 层传播到 l 层的核心公式:

  • 符号代表哈达玛积 (Hadamard Product),也就是逐元素相乘
  • 公式解读:l 层的误差,等于后一层 l+1 的误差 δ^(l+1) 通过权重 W^(l+1) 反向传播回来,再乘以 l 层激活函数的局部梯度 f'(z^(l))。这完美体现了误差逐层回传的思想。

Step 3: 计算权重和偏置的梯度
有了每一层的误差项 δ,计算该层参数的梯度就易如反掌了。

  • 权重梯度:

    公式解读: l 层的权重梯度,等于该层的误差项 δ^(l) 与其输入 a^(l-1) 的外积。

  • 偏置梯度:

    公式解读: l 层的偏置梯度,就等于该层的误差项 δ^(l)

Step 4: 梯度下降更新参数
计算出所有参数的梯度后,就可以用梯度下降法来更新权重和偏置了:


  • η学习率 (Learning Rate),控制每次更新的步长。
Python代码实现反向传播

现在,我们为之前的 MLP 类补全 backwardtrain 方法。

# ... 在 MLP class 中补充 ...def backward(self, X, y_true, learning_rate=0.01):"""反向传播:计算梯度并更新权重"""num_samples = X.shape[0]# Step 1: 计算输出层误差项 δ^(L) (L=2)# a2 是 self.forward(X) 的结果, 即 ŷdelta2 = self.a2 - y_true# Step 3 (for W2, b2): 计算输出层权重和偏置的梯度dW2 = np.dot(self.a1.T, delta2) / num_samplesdb2 = np.sum(delta2, axis=0) / num_samples# Step 2: 反向传播误差项到隐藏层 δ^(l) (l=1)# ((W^(l+1))^T δ^(l+1))delta1 = np.dot(delta2, self.W2.T) * self.relu_derivative(self.z1)# Step 3 (for W1, b1): 计算隐藏层权重和偏置的梯度dW1 = np.dot(X.T, delta1) / num_samplesdb1 = np.sum(delta1, axis=0) / num_samples# Step 4: 梯度下降更新参数self.W1 -= learning_rate * dW1self.b1 -= learning_rate * db1self.W2 -= learning_rate * dW2self.b2 -= learning_rate * db2def train(self, X, y, epochs, learning_rate):"""完整的训练循环"""for epoch in range(epochs):# 1. 前向传播predictions = self.forward(X)# 2. 计算损失 (例如交叉熵)loss = -np.sum(y * np.log(predictions + 1e-9)) / X.shape[0] # +1e-9防止log(0)# 3. 反向传播与参数更新self.backward(X, y, learning_rate)if (epoch % 100) == 0:print(f"Epoch {epoch}, Loss: {loss:.4f}")

踩坑记录3:梯度消失与梯度爆炸

反向传播的核心是梯度的连乘。如果每层的梯度(主要是激活函数的导数)都小于1(比如Sigmoid函数在饱和区的导数接近0),那么经过多层传播后,梯度会指数级衰减,变得极其微小,导致靠近输入层的权重几乎不更新。这就是梯度消失 (Vanishing Gradients)。反之,如果梯度都大于1,就会指数级增长,导致更新步子太大,模型无法收敛,这就是梯度爆炸 (Exploding Gradients)
如何缓解?

  1. 明智地选择激活函数:ReLU及其变体是首选,它们在正区间的导数为1,极大缓解了梯度消失。
  2. 合理的权重初始化:He/Xavier初始化确保了前向传播和反向传播时信号的方差大致稳定。
  3. 批归一化 (Batch Normalization):强制将每层神经元的输入调整为均值为0、方差为1的标准正态分布,能有效防止梯度消失/爆炸,并加速收敛。
  4. 梯度裁剪 (Gradient Clipping):当梯度的范数超过某个阈值时,直接缩放它,是解决梯度爆炸的简单粗暴有效方法。
  5. 使用残差连接 (Residual Connections):像ResNet那样,创建"快捷通道",让梯度可以直接流过某些层,是训练极深网络的关键。

四、 总结与展望

好啦,深呼吸!我们今天从最简单的神经元模型感知机出发,理解了它的局限性(线性可分)。然后,通过堆叠神经元和引入非线性激活函数 (ReLU大法好!) 构建了多层感知机 (MLP),解锁了拟合复杂非线性函数的能力。最硬核的是,我们一步步推导了神经网络的训练核心——反向传播算法,看清了链式法则如何将输出层的误差逐层传回,并计算出每个参数的梯度,再通过梯度下降来优化模型。

搞懂了这些,你就掌握了绝大多数神经网络的底层工作原理。虽然现代深度学习框架(TensorFlow, PyTorch)已经帮我们自动完成了求导和反向传播,但理解其数学本质,能让你在模型不工作时,知道从哪里去排查问题(是激活函数选错了?初始化有问题?还是梯度爆炸了?),也能让你在设计新网络结构时更有底气。

这只是个开始!在接下来的文章中,我们将基于今天的基础,去探索那些在特定领域大放异彩的"特种兵"网络,比如专门处理图像的卷积神经网络 (CNN),以及擅长序列数据的循环神经网络 (RNN)。敬请期待!


最后的思考题

  1. 如果一个二分类问题,输出层只用一个神经元,并使用Sigmoid激活函数和二元交叉熵损失,那么它的反向传播输出层误差项 δ^(L) 是什么?(提示:结果同样会非常简洁)
  2. 你能否尝试用我们今天写的 MLP 代码来解决经典的XOR问题?需要如何设置输入 X 和标签 y

希望这篇硬核长文对你有帮助!别忘了动手敲代码实践一下,数学推导和代码实现相结合,效果翻倍!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95273.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95273.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/95273.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

神经网络模型介绍

如果你用过人脸识别解锁手机、刷到过精准推送的短视频&#xff0c;或是体验过 AI 聊天机器人&#xff0c;那么你已经在和神经网络打交道了。作为深度学习的核心技术&#xff0c;神经网络模仿人脑的信息处理方式&#xff0c;让机器拥有了 “学习” 的能力。一、什么是神经网络&a…

苹果开发中什么是Storyboard?object-c 和swiftui 以及Storyboard到底有什么关系以及逻辑?优雅草卓伊凡

苹果开发中什么是Storyboard&#xff1f;object-c 和swiftui 以及Storyboard到底有什么关系以及逻辑&#xff1f;优雅草卓伊凡引言由于最近有个客户咨询关于 苹果内购 in-purchase 的问题做了付费咨询处理&#xff0c;得到问题&#xff1a;“昨天试着把您的那几部分code 组装成…

孩子玩手机都近视了,怎样限制小孩的手机使用时长?

最近两周&#xff0c;我给孩子检查作业时发现娃总是把眼睛眯成一条缝&#xff0c;而且每隔几分钟就会用手背揉眼睛&#xff0c;有时候揉得眼圈都红了。有一次默写单词&#xff0c;他把 “太阳” 写成了 “大阳”&#xff0c;我给他指出来&#xff0c;他却盯着本子说 “没有错”…

医疗AI时代的生物医学Go编程:高性能计算与精准医疗的案例分析(六)

第五章 案例三:GoEHRStream - 实时电子病历数据流处理系统 5.1 案例背景与需求分析 5.1.1 电子病历数据流处理概述 电子健康记录(Electronic Health Record, EHR)系统是现代医疗信息化的核心,存储了患者从出生到死亡的完整健康信息,包括 demographics、诊断、用药、手术、…

GEM5学习(2):运行x86Demo示例

创建脚本 配置脚本内容参考官网的说明gem5: Creating a simple configuration script 首先根据官方说明创建脚本文件 mkdir configs/tutorial/part1/ touch configs/tutorial/part1/simple.py simple.py 中的内容如下&#xff1a; from gem5.prebuilt.demo.x86_demo_board…

通过 FinalShell 访问服务器并运行 GUI 程序,提示 “Cannot connect to X server“ 的解决方法

FinalShell 是一个 SSH 客户端&#xff0c;默认情况下 不支持 X11 图形转发&#xff08;不像 ssh -X 或 ssh -Y&#xff09;&#xff0c;所以直接运行 GUI 程序&#xff08;如 Qt、GNOME、Matplotlib 等&#xff09;会报错&#xff1a; Error: Cant open display: Failed to c…

1.人工智能——概述

应用领域 替代低端劳动&#xff0c;解决危险、高体力精力损耗领域 什么是智能制造&#xff1f;数字孪生&#xff1f;边缘计算&#xff1f; 边缘计算 是 数字孪生 的 “感官和神经末梢”&#xff0c;负责采集本地实时数据和即时反应。琐碎数据不上传总服务器&#xff0c;实时进行…

传统园区能源转型破局之道:智慧能源管理系统驱动的“源-网-荷-储”协同赋能

传统园区能源结构转型 政策要求&#xff1a;福建提出2025年可再生能源渗透率≥25%&#xff0c;山东强调“源网荷储一体化”&#xff0c;安徽要求清洁能源就地消纳。系统解决方案&#xff1a;多能协同调控&#xff1a;集成光伏、储能、充电桩数据&#xff0c;通过AI算法动态优化…

[光学原理与应用-353]:ZEMAX - 设置 - 可视化工具:2D视图、3D视图、实体模型三者的区别,以及如何设置光线的数量

在光学设计软件ZEMAX中&#xff0c;2D视图、3D视图和实体模型是三种不同的可视化工具&#xff0c;分别用于从不同维度展示光学系统的结构、布局和物理特性。它们的核心区别体现在维度、功能、应用场景及信息呈现方式上&#xff0c;以下是详细对比&#xff1a;一、维度与信息呈现…

《sklearn机器学习》——交叉验证迭代器

sklearn 交叉验证迭代器 在 scikit-learn (sklearn) 中&#xff0c;交叉验证迭代器&#xff08;Cross-Validation Iterators&#xff09;是一组用于生成训练集和验证集索引的工具。它们是 model_selection 模块的核心组件&#xff0c;决定了数据如何被分割&#xff0c;从而支持…

Trae+Chrome MCP Server 让AI接管你的浏览器

一、核心优势1、无缝集成现有浏览器环境直接复用用户已打开的 Chrome 浏览器&#xff0c;保留所有登录状态、书签、扩展及历史记录&#xff0c;无需重新登录或配置环境。对比传统工具&#xff08;如 Playwright&#xff09;需独立启动浏览器进程且无法保留用户环境&#xff0c;…

Shell 编程 —— 正则表达式与文本处理器

目录 一. 正则表达式 1.1 定义 1.2 用途 1.3 Linux 正则表达式分类 1.4 正则表达式组成 &#xff08;1&#xff09;普通字符 &#xff08;2&#xff09;元字符&#xff1a;规则的核心载体 &#xff08;3&#xff09; 重复次数 &#xff08;4&#xff09;两类正则的核心…

Springboot 监控篇

在 Spring Boot 中实现 JVM 在线监控&#xff08;包括线程曲线、内存使用、GC 情况等&#xff09;&#xff0c;最常用的方案是结合 Spring Boot Actuator Micrometer 监控可视化工具&#xff08;如 Grafana、Prometheus&#xff09;。以下是完整实现方案&#xff1a; 一、核…

Java 大视界 --Java 大数据在智能教育学习资源整合与知识图谱构建中的深度应用(406)

Java 大视界 --Java 大数据在智能教育学习资源整合与知识图谱构建中的深度应用&#xff08;406&#xff09;引言&#xff1a;正文&#xff1a;一、智能教育的两大核心痛点与 Java 大数据的适配性1.1 资源整合&#xff1a;42% 重复率背后的 “三大堵点”1.2 知识图谱&#xff1a…

2025年新版C语言 模电数电及51单片机Proteus嵌入式开发入门实战系统学习,一整套全齐了再也不用东拼西凑

最近有同学说想系统学习嵌入式&#xff0c;问我有没有系统学习的路线推荐。刚入门的同学可能不知道如何下手&#xff0c;这里一站式安排上。先说下学习的顺序&#xff0c;先学习C语言&#xff0c;接着学习模电数电&#xff08;即模拟电路和数字电路&#xff09;最后学习51单片机…

Android的USB通信 (AOA Android开放配件协议)

USB 主机和配件概览Android 通过 USB 配件和 USB 主机两种模式支持各种 USB 外围设备和 Android USB 配件&#xff08;实现 Android 配件协议的硬件&#xff09;。在 USB 配件模式下&#xff0c;外部 USB 硬件充当 USB 主机。配件示例可能包括机器人控制器、扩展坞、诊断和音乐…

人工智能视频画质增强和修复软件Topaz Video AI v7.1.1最新汉化,自带星光模型

软件介绍 这是一款专业的视频修复工具-topaz video ai&#xff0c;该版本是解压即可使用&#xff0c;自带汉化&#xff0c;免登陆无输出水印。 软件特点 不登录不注册解压即可使用无水印输出视频画质提升 软件使用 选择我们需要提升画质的视频即可 软件下载 夸克 其他网盘…

LeetCode 777.在LR字符串中交换相邻字符

在一个由 ‘L’ , ‘R’ 和 ‘X’ 三个字符组成的字符串&#xff08;例如"RXXLRXRXL"&#xff09;中进行移动操作。一次移动操作指用一个 “LX” 替换一个 “XL”&#xff0c;或者用一个 “XR” 替换一个 “RX”。现给定起始字符串 start 和结束字符串 result&#x…

RK-Android15-WIFI白名单功能实现

实现WIFI白名单功能 。 三个模式: 1、默认模式:允许搜索所有的WIFI显示、搜索出来 ; 2、禁用模式:允许所有WIFI显示,能够搜索出来 ;3、白名单模式:允许指定WIFI名单显示,被搜索出来 文章目录 前言-需求 一、参考资料 二、核心修改文件和实现方式 1、修改文件 疑问思考 …

Maven + JUnit:Java单元测试的坚实组合

Maven JUnit&#xff1a;Java单元测试的坚实组合Maven JUnit&#xff1a;Java单元测试的坚实组合一、什么是软件测试&#xff1f;二、测试的维度&#xff1a;阶段与方法&#xff08;一&#xff09;测试的四大阶段&#xff08;二&#xff09;测试的三大方法三、main方法测试与…