反向传播推导+numpy实现

news2025/5/19 16:34:40

很久没有看深度学习了,忘了好多东西。本来想着推导一下,后来发现自己不会了。
再看看以前写的代码,又避开了最终的东西,于是决定重新推导一下。

数据的说明

首先,我们要做一个回归的任务,我们使用numpy随机的生成一些数据
在这里插入图片描述
生成的代码如下,可以看到这一个二次函数,但是我们加入了一些随机的噪声使其更像真实的数据。

import numpy as np
import matplotlib.pyplot as plt
np.random.seed(333)
data = np.random.random(size=(1, 30)) * 5 # 随机生成30个点
data = np.sort(data, axis=1)
y = (data ** 2).T + np.random.randn(30, 1) * 2 # 加入随机噪声
plt.scatter(data, y.T)
plt.show()

然后我们对数据进行升维,使得我们的网络能够捕捉到更多的特征。

np.random.seed(333)
data = np.random.random(size=(1, 30)) * 5
data = np.sort(data, axis=1)
y = (data ** 2).T + np.random.randn(30, 1) * 2
t_data = np.vstack([ # 升维度
    data,
    data ** 2
])

所以我们现在每个数据有两个特征,一个是原本的x,一个是 x 2 x^2 x2。我们的数据集的形状是 2 × 30 2×30 2×30其中30是样本数,2是特征数。每一列是一个样本。

前向传播

我们首先来设定一下各个参数,如下写的参数都是其形状。

w ( 1 ) = ( 100 , 4 ) , b ( 1 ) = ( 100 , 1 ) w^{(1)}=(100, 4), b^{(1)}=(100, 1) w(1)=(100,4),b(1)=(100,1)
w ( 2 ) = ( 400 , 100 ) , b ( 2 ) = ( 400 , 1 ) w^{(2)}=(400, 100), b^{(2)}=(400, 1) w(2)=(400,100),b(2)=(400,1)
w ( 3 ) = ( 1 , 400 ) , b ( 3 ) = ( 1 , 1 ) w^{(3)}=(1, 400), b^{(3)}=(1, 1) w(3)=(1,400),b(3)=(1,1)
请添加图片描述
如上图所示,不算输入层,这是一个三层的网络,每一层左侧的连线就是权重参数和偏置参数

前向传播计算过程(这里我们只算单个样本的):

  1. z ( 1 ) = b ( 1 ) + w ( 1 ) x z^{(1)}=b^{(1)}+w^{(1)}x z(1)=b(1)+w(1)x
  2. a ( 1 ) = s i g m o i d ( z ( 1 ) ) a^{(1)}=sigmoid(z^{(1)}) a(1)=sigmoid(z(1))
  3. z ( 2 ) = b ( 2 ) + w ( 2 ) a ( 1 ) z^{(2)}=b^{(2)}+w^{(2)}a^{(1)} z(2)=b(2)+w(2)a(1)
  4. a ( 2 ) = s i g m o i d ( z ( 2 ) ) a^{(2)}=sigmoid(z^{(2)}) a(2)=sigmoid(z(2))
  5. z ( 3 ) = b ( 3 ) + w ( 3 ) a ( 2 ) z^{(3)}=b^{(3)}+w^{(3)}a^{(2)} z(3)=b(3)+w(3)a(2)
  6. L = ( z ( 3 ) − y ) 2 L = (z^{(3)} - y)^2 L=(z(3)y)2
    由于这里我们只算单个样本的误差,所以我们最后的损失函数计算不需要除以n

反向传播

delta的计算

首先,我们需要引入一个中间变量,叫做 δ j ( l ) \delta^{(l)}_j δj(l),其定义为 δ j ( l ) = ∂ L ∂ z j ( l ) \delta^{(l)}_j=\frac{\partial L}{\partial z^{(l)}_j} δj(l)=zj(l)L这是一个关键的中间变量。

  1. 第三层的 δ \delta δ计算

    由于这一层只有一个z,所以我们可以直接得出 δ j ( 3 ) = ∂ L ∂ z j ( 3 ) = 2 ( z j ( 3 ) − y ) \delta ^{(3)}_j = \frac{\partial L}{\partial z^{(3)}_j}=2(z^{(3)}_j - y) δj(3)=zj(3)L=2(zj(3)y)

  2. 第二层的 δ \delta δ计算

    我们希望递归的去计算 δ \delta δ所以,我们必须要用 δ ( 3 ) \delta^{(3)} δ(3)的计算信息来推出 δ ( 2 ) \delta^{(2)} δ(2)的,也就是我们要化成如下这种形式:
    δ j ( 2 ) = ∂ L ∂ z j ( 2 ) = ∂ L ∂ z ( 3 ) ∂ z ( 3 ) ∂ z j ( 2 ) \delta ^{(2)}_j = \frac{\partial L}{\partial z^{(2)}_j}=\frac{\partial L}{\partial z^{(3)}}\frac{\partial z^{(3)}}{\partial z^{(2)}_j} δj(2)=zj(2)L=z(3)Lzj(2)z(3)
    注意,这个式子并不是一个精确地式子,但是可以看出,通过这种链式法则的拆解,我们得到的第一项中含有 δ ( 3 ) \delta^{(3)} δ(3)
    对于 z i ( 2 ) z^{(2)}_i zi(2)它的产生,都需要经过 z j ( 3 ) z^{(3)}_j zj(3)的计算,所以根据链式求导法则我们有
    δ j ( 2 ) = ∂ L ∂ z j ( 2 ) = ∑ k = 1 1 ∂ L ∂ z k ( 3 ) ∂ z k ( 3 ) ∂ z j ( 2 ) \delta ^{(2)}_j = \frac{\partial L}{\partial z^{(2)}_j}=\sum\limits_{k=1}^1\frac{\partial L}{\partial z^{(3)}_k}\frac{\partial z^{(3)}_k}{\partial z^{(2)}_j} δj(2)=zj(2)L=k=11zk(3)Lzj(2)zk(3).
    形象的来说,就是我们利用链式求导法则计算时,我们把 ∂ L ∂ z j ( 2 ) \frac{\partial L}{\partial z^{(2)}_j} zj(2)L拆成 ∂ L ∂ z ( 3 ) ∂ z ( 3 ) ∂ z j ( 2 ) \frac{\partial L}{\partial z^{(3)}}\frac{\partial z^{(3)}}{\partial z^{(2)}_j} z(3)Lzj(2)z(3)时中间有若干个中间变量 z k ( 3 ) z^{(3)}_k zk(3), 所以我们对于每一个中间变量都需要求出它的分量。
    接下来我们求解 ∂ z k ( 3 ) ∂ z j ( 2 ) \frac{\partial z^{(3)}_k}{\partial z^{(2)}_j} zj(2)zk(3),我们写出 z ( 3 ) z^{(3)} z(3)的表达式:
    z k ( 3 ) = ∑ i w k , i ( 3 ) σ ( z i ( 2 ) ) + b k ( 3 ) z^{(3)}_k=\sum\limits_i w^{(3)}_{k,i}\sigma(z^{(2)}_i) + b^{(3)}_k zk(3)=iwk,i(3)σ(zi(2))+bk(3)
    于是我们得到 ∂ z k ( 3 ) ∂ z j ( 2 ) = w k , j σ ′ ( z j ( 2 ) ) \frac{\partial z^{(3)}_k}{\partial z^{(2)}_j}=w_{k,j}\sigma'(z_j^{(2)}) zj(2)zk(3)=wk,jσ(zj(2)), 于是我们得到最终的计算式
    δ j ( 2 ) = ∂ L ∂ z j ( 2 ) = ∑ k = 1 1 δ k ( 3 ) w k , j ( 3 ) σ ′ ( z j ( 2 ) ) \delta ^{(2)}_j = \frac{\partial L}{\partial z^{(2)}_j}=\sum\limits_{k=1}^1\delta^{(3)}_kw^{(3)}_{k,j}\sigma'(z_j^{(2)}) δj(2)=zj(2)L=k=11δk(3)wk,j(3)σ(zj(2)).
    于是我们得到 δ ( 2 ) = ( w ( 3 ) ) T δ ( 3 ) ⨂ σ ′ ( z ( 2 ) ) \delta^{(2)}=(w^{(3)})^T\delta^{(3)}\bigotimes \sigma'(z^{(2)}) δ(2)=(w(3))Tδ(3)σ(z(2))

  3. 第一层的计算

    同样的思路,我们的计算方式和第二层一模一样
    δ j ( 1 ) = ∂ L ∂ z j ( 1 ) = ∑ k = 1 400 δ k ( 2 ) w k , j ( 2 ) σ ′ ( z j ( 1 ) ) \delta ^{(1)}_j = \frac{\partial L}{\partial z^{(1)}_j}=\sum\limits_{k=1}^{400}\delta^{(2)}_kw^{(2)}_{k,j}\sigma'(z_j^{(1)}) δj(1)=zj(1)L=k=1400δk(2)wk,j(2)σ(zj(1)).
    我们写成向量形式
    [ δ 1 ( 1 ) δ 2 ( 1 ) . . . δ 100 ( 1 ) ] = [ δ 1 ( 2 ) w 1 , 1 ( 2 ) + δ 2 ( 2 ) w 2 , 1 ( 2 ) + . . . + δ 400 ( 2 ) w 400 , 1 ( 2 ) δ 1 ( 2 ) w 1 , 2 ( 2 ) + δ 2 ( 2 ) w 2 , 2 ( 2 ) + . . . + δ 400 ( 2 ) w 400 , 2 ( 2 ) . . . δ 1 ( 2 ) w 1 , 100 ( 2 ) + δ 2 ( 2 ) w 2 , 100 ( 2 ) + . . . + δ 400 ( 2 ) w 400 , 100 ( 2 ) ] ⨂ [ σ ′ ( z 1 ( 1 ) ) σ ′ ( z 2 ( 1 ) ) . . . σ ′ ( z 100 ( 1 ) ) ] \begin{bmatrix} \delta^{(1)}_1 \\ \delta^{(1)}_2 \\ ...\\ \delta^{(1)}_{100} \end{bmatrix} = \begin{bmatrix} \delta^{(2)}_1w^{(2)}_{1,1}+\delta^{(2)}_2w^{(2)}_{2,1}+...+\delta^{(2)}_{400}w^{(2)}_{400,1}\\ \delta^{(2)}_1w^{(2)}_{1,2}+\delta^{(2)}_2w^{(2)}_{2,2}+...+\delta^{(2)}_{400}w^{(2)}_{400,2}\\ ...\\ \delta^{(2)}_1w^{(2)}_{1,100}+\delta^{(2)}_2w^{(2)}_{2,100}+...+\delta^{(2)}_{400}w^{(2)}_{400,100} \end{bmatrix} \bigotimes \begin{bmatrix} \sigma'(z^{(1)}_1)\\ \sigma'(z^{(1)}_2)\\ ...\\ \sigma'(z^{(1)}_{100}) \end{bmatrix} δ1(1)δ2(1)...δ100(1) = δ1(2)w1,1(2)+δ2(2)w2,1(2)+...+δ400(2)w400,1(2)δ1(2)w1,2(2)+δ2(2)w2,2(2)+...+δ400(2)w400,2(2)...δ1(2)w1,100(2)+δ2(2)w2,100(2)+...+δ400(2)w400,100(2) σ(z1(1))σ(z2(1))...σ(z100(1))
    可以得到 δ ( 1 ) = ( w ( 2 ) ) T δ ( 2 ) ⨂ σ ′ ( z ( 1 ) ) \delta^{(1)}=(w^{(2)})^T\delta^{(2)}\bigotimes \sigma'(z^{(1)}) δ(1)=(w(2))Tδ(2)σ(z(1))

b和w的偏导计算

w w w b b b的梯度计算

有了 δ \delta δ之后,想要计算这两个,可以说是很简单了。
由于 ∂ L ∂ b i = δ i ∂ z i ∂ b i \frac{\partial L}{\partial b_i}=\delta_i \frac{\partial z_i}{\partial b_i} biL=δibizi根据z和b的关系,所以 ∂ z i ∂ b i = 1 \frac{\partial z_i}{\partial b_i}=1 bizi=1最终我们得到了梯度
∂ L ∂ b i = δ i \frac{\partial L}{\partial b_i}=\delta_i biL=δi
接下来我们计算 w w w
∂ L ∂ w i , j = δ i ∂ z i ∂ w i , j = δ i a j \frac{\partial L}{\partial w_{i,j}}=\delta_i \frac{\partial z_i}{\partial w_{i,j}}=\delta_i a_j wi,jL=δiwi,jzi=δiaj然后我们改写成矩阵形式
∂ L ∂ w ( l ) = δ ( l ) ( a ( l − 1 ) ) T \frac{\partial L}{\partial w^{(l)}}=\delta^{(l)}(a^{(l-1)})^T w(l)L=δ(l)(a(l1))T
总结一下
∂ L ∂ b ( l ) = δ ( l ) ∂ L ∂ w ( l ) = δ ( l ) ( a ( l − 1 ) ) T \frac{\partial L}{\partial b^{(l)}}=\delta^{(l)}\\\frac{\partial L}{\partial w^{(l)}}=\delta^{(l)}(a^{(l-1)})^T b(l)L=δ(l)w(l)L=δ(l)(a(l1))T

代码实现

class FFCN:
    
    def __init__(self) -> None:
        self.w1 = np.random.randn(100, 2)
        self.b1 = np.random.randn(100).reshape(-1, 1)
        self.w2 = np.random.randn(400, 100)
        self.b2 = np.random.randn(400).reshape(-1, 1)
        self.w3 = np.random.randn(1, 400)
        self.b3 = np.random.randn(1).reshape(-1, 1)

    def forward(self, x: np.ndarray):
        """
        x: (4, 1)
        """
        self.z1 = self.w1.dot(x) + self.b1
        self.a1 = self.__sigmoid(self.z1)

        self.z2 = self.w2.dot(self.a1) + self.b2
        self.a2 = self.__sigmoid(self.z2)

        self.z3 = self.w3.dot(self.a2) + self.b3
        return self.z3
    
    def predict(self, x: np.ndarray): # 用于预测多组的结果
        return np.array([self.forward(x[:, i].reshape(-1, 1))[0][0] for i in range(x.shape[1])])
    
    def backpp(self, data: np.ndarray, target: np.ndarray, lr:float=0.002, iter:int=200):
    """
    lr: 学习率
    iter: 迭代次数
    """
        for _ in range(iter):
            loss = 0
            for i in range(data.shape[1]):
                x = data[:, i].reshape(-1, 1)
                y = target[i]
                loss += (self.forward(x) - y) ** 2

                self.delta3 = 2 * (self.z3 - y)
                self.delta2 = self.w3.T.dot(self.delta3) * self.__dsigmoid(self.z2)
                self.delta1 = self.w2.T.dot(self.delta2) * self.__dsigmoid(self.z1)

                self.dw1 = self.delta1.dot(x.reshape(1,-1))
                self.dw2 = self.delta2.dot(self.a1.T)
                self.dw3 = self.delta3.dot(self.a2.T)
                self.__step(lr)
            print("loss of", _, ":", loss[0][0])
            loss = 0

    def __sigmoid(self, x):# 激活函数
        return 1 / (1 + np.exp(-x))
    
    def __dsigmoid(self, x):
        return np.exp(x) / ((1 + np.exp(x)) ** 2)

    def __step(self, lr: float): # 更新参数权重
        self.w1 -= self.dw1 * lr
        self.w2 -= self.dw2 * lr
        self.w3 -= self.dw3 * lr
        self.b1 -= self.delta1 * lr
        self.b2 -= self.delta2 * lr
        self.b3 -= self.delta3 * lr

效果:
在这里插入图片描述
完整代码:

import numpy as np
import matplotlib.pyplot as plt

"""
造一个三层的神经网络

"""

class FFCN:
    
    def __init__(self) -> None:
        self.w1 = np.random.randn(100, 2)
        self.b1 = np.random.randn(100).reshape(-1, 1)
        self.w2 = np.random.randn(400, 100)
        self.b2 = np.random.randn(400).reshape(-1, 1)
        self.w3 = np.random.randn(1, 400)
        self.b3 = np.random.randn(1).reshape(-1, 1)

    def forward(self, x: np.ndarray):
        """
        x: (4, 1)
        """
        self.z1 = self.w1.dot(x) + self.b1
        self.a1 = self.__sigmoid(self.z1)

        self.z2 = self.w2.dot(self.a1) + self.b2
        self.a2 = self.__sigmoid(self.z2)

        self.z3 = self.w3.dot(self.a2) + self.b3
        return self.z3
    
    def predict(self, x: np.ndarray):
        return np.array([self.forward(x[:, i].reshape(-1, 1))[0][0] for i in range(x.shape[1])])
    
    def backpp(self, data: np.ndarray, target: np.ndarray, lr:float=0.002, iter:int=200):
        for _ in range(iter):
            loss = 0
            for i in range(data.shape[1]):
                x = data[:, i].reshape(-1, 1)
                y = target[i]
                loss += (self.forward(x) - y) ** 2

                self.delat3 = 2 * (self.z3 - y)
                self.delat2 = self.w3.T.dot(self.delat3) * self.__dsigmoid(self.z2)
                self.delta1 = self.w2.T.dot(self.delat2) * self.__dsigmoid(self.z1)

                self.dw1 = self.delta1.dot(x.reshape(1,-1))
                self.dw2 = self.delat2.dot(self.a1.T)
                self.dw3 = self.delat3.dot(self.a2.T)
                self.__step(lr)
            print(_, ":", loss[0][0])
            loss = 0

    def __sigmoid(self, x):
        return 1 / (1 + np.exp(-x))
    
    def __dsigmoid(self, x):
        return np.exp(x) / ((1 + np.exp(x)) ** 2)

    def __step(self, lr: float):
        self.w1 -= self.dw1 * lr
        self.w2 -= self.dw2 * lr
        self.w3 -= self.dw3 * lr
        self.b1 -= self.delta1 * lr
        self.b2 -= self.delat2 * lr
        self.b3 -= self.delat3 * lr

model = FFCN()

np.random.seed(111)
data = np.random.random(size=(1, 30)) * 5
data = np.sort(data, axis=1)
y = (data ** 2).T + np.random.randn(30, 1) * 2
t_data = np.vstack([
    data,
    data ** 2
])
model.backpp(t_data, y)
plt.scatter(data, y.T)
plt.plot(data.squeeze(0), model.predict(t_data), color='r')
plt.show()

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.Java循环控制语句

Java循环控制语句 循环是Java中应用最为广泛的一个知识点,所以也是很需要掌握的。所谓循环,即通过判断条件,重复执行一段代码,根据条件的变化,来确定代码是否执行,执行次数。 一、循环结构 1、while循环…

Java IO常用操作详解(代码示例)

概览 Java I/O操作指的是数据的输入/输出操作。 Java的I/O操作类在java.io包中,主要分以下几种: 基于字节操作的I/O接口: InputStream和OutputStream基于字符操作的I/O接口: Writer和Reader基于磁盘操作的I/O接口: …

5个令人惊艳的AI项目,开源了。。

大家好,我是 Jack。 今天清明,小伙伴们都去哪里玩了? 上个月我已经出去浪过了,清明就老实在家歇着了。 翻看了一些最近热点的开源项目,发现还是 AIGC 的天下。 今天,我将继续着重挑选几个近期的优质开源…

2023第十四届蓝桥杯C++B组菜鸡的落幕

时隔几天,终于还是忍不住来复盘一下蓝桥杯了,还记得去年参加做下填空,再做对个把编程,后面不会的大题打打表混混分,最后就能混个省奖, 这回估计凉透了,填空没对似乎,编程也没对几个,…

Kettle8.2.0连接Hive3.1.2(踩坑,亲测有效)

这是目前遇到的最简单但最头疼的安装,因为是在公司之前用过的服务器上进行安装测试,加上又使用比较新的版本,结果踩了不少坑。Kettle连接Hive这个坑,从2023年4月11日下午开始,一致到2023年4月12日中午才弄好&#xff0…

uni-app常用配置

保存自动格式化 工具》设置》编辑器设置》保存时自动格式化 JS语法检查 安装eslint-js插件eslint-js - DCloud 插件市场 用于校验js和html中的js代码https://ext.dcloud.net.cn/plugin?id2037工具》设置》插件配置》eslint-js 启用实时校检 Vue语法检查 安装eslint-vue插…

【星界探索——通信卫星】铱星:从“星光坠落”到“涅槃重生”,万字长文分析铱星卫星系统市场

【星界探索——通信卫星】铱星:从“星光坠落”到“涅槃重生”一、铱星简介二、铱星系统设计思路2.1 工作原理2.2 铱星布局三、铱星优势四、发展历程五、第一代铱星公司的破产原因分析5.1 终端和资费价格高昂,市场用户群体小5.2 财务危机5.3 市场分析不足…

一文吃透低代码平台源代码交付的重要性(避坑指南)

一、前言 作为这两年IT界的风口,低代码在众人眼里已经不是什么陌生的概念。 对标于传统的纯代码开发,低代码是一种快速开发软件(应用程序)的方法,平台通过对大量功能与场景做提前封装,使得用户可以在可视…

MySQL开发05-MySQL开发规范

文章目录1、命名规范2、表设计规范3、索引规范4、SQL语句规范5、SQL脚本规范6、数据架构规范7、配置文件建议8、其他规范9、总结1、命名规范 命名应有意义,包括库名、表名、用户名等,以使用方便记忆、描述性强的可读性名称为第一准则,尽量避…

Docker网络案例

bridge 是什么 Docker 服务默认会创建一个 docker0 网桥(其上有一个 docker0 内部接口),该桥接网络的名称为docker0,它在内核层连通了其他的物理或虚拟网卡,这就将所有容器和本地主机都放到同一个物理网络。Docker 默认指定了 docker0 接口 的 IP 地址和子网掩码,让主机…

C#基础复习

语句 目录 语句 switch: 跳转语句 标签语句 标签: 标签语句的作用域 goto语句 using 语句 资源的包装使用 using 语句示例: 多个资源和嵌套 语句是描述某个类型或让程序执行某个动作的源代码指令 块在语法上算作一个单条嵌入语句。任何语…

【cmake学习】搭建一个简单的cmake工程(初级版)

目录 1、工程框架介绍 2、编写CMakeLists.txt (1) 限制cmake最低版本、工程命名 (2) 引入头文件目录 (3) 引入库目录(可选) (4) 引入源文件 (5) 生成可执行文件 / 生成动静态库 (6) 链接库文件(可选) 3、完整CMakeLists…

uefi 内存管理

PEI 阶段 PEI 阶段最为重要的结构是HOB, 初始化内存服务前,PEI 申请的内存其实是插入到FV 文件 也就是FLASH 里面去运行。 在此状态下,FLASH 可读不可写,所以是不能使用全局变量的。如果有需要模块间共享信息,需要申请HOB. HO…

gtkmm给组件添加css

设置方式 使用CSS分为两步,1:为组件设这css名称,2:加载样式表。 样式表我们写在文件中就行(似乎也可以从字符串加载,不过不推荐)。 1. 设置css名称 使用gtk的接口:gtk_widget_class_set_css_name()。 这…

rk3568点亮E-ink

rk3568 Android11/12 适配 E-ink “EINK”是英语ElectronicInk的缩写。翻译成中文为“电子墨水”。电子墨水由数百万个微胶囊(Microcapsules)所构成,微胶囊的大小约等同于人类头发的直径。每个微胶囊里含有电泳粒子──带负电荷的白色以及带正电荷的黑色粒子&#…

Ubuntu 交叉编译Windows 版本的ffmpeg最佳实践

之前介绍在Windows上采用msys2+minGW或者cygwin在Windows编译方法。很多读者觉得在Windows搭建一个类Linux比较麻烦或者说方法不够通用,本文就介绍在流行的Linux发行版Ubuntu上编译window版本的ffmpeg。即介绍一种通用办法来编译Windows版本ffmpeg,该方法可以推广到android,…

算法 贪心4 || 860.柠檬水找零 406.根据身高重建队列 452. 用最少数量的箭引爆气球

860.柠檬水找零 很简单的一题&#xff0c;完全是常识题 class Solution { public:bool lemonadeChange(vector<int>& bills) {unordered_map<int,int> map;for(int i 0; i < bills.size(); i){map[bills[i]];if(bills[i] ! 5){if(map[5] 0) return fals…

【Linux】程序中获取和设置cpu和mem相关信息

这里是目录一、CPU和MEM信息1.1、CPU信息1.1.1、CPU核心数1.1.2、CPU频率读取和调整1.1.3、CPU温度1.2、MEM信息二、C程序读取CPU和MEM信息三、测试写在前面&#xff1a; 记录一下日常&#xff0c;之前有做过相关工作&#xff0c;但是没有记录下来&#xff0c;因此写一写文章。…

使用hbuilder连接夜神模拟器调试app

1. Hbuilder设置 这里端口号随便用一个没有被占用的&#xff1b; 路径夜神模拟器的安装路径下的nox_adb.exe的路径。 2. 夜神模拟器设置 设置如下&#xff1a; 工具&#xff0c;设置&#xff0c;关于平板电脑&#xff08;这里应该没有开发者模式选项&#xff0c;这是我配好之…

【LeetCode】剑指 Offer 53. 在排序数组中查找数字 p263 -- Java Version

1. 题目介绍&#xff08;53. 在排序数组中查找数字&#xff09; 面试题53&#xff1a;在排序数组中查找数字 一共分为三小题&#xff1a; 题目一&#xff1a;数字在排序数组中出现的次数题目二&#xff1a;0 ~ n-1 中缺失的数字题目三&#xff1a;数组中数值和下标相等的元素 2…