深度学习作业 - 作业十一 - LSTM

问题一

推导LSTM网络中参数的梯度,并的分析其避免梯度消失的效果

LSTM网络是为了解简单RNN中存在的长程依赖问题而提出的一种新型网络结构,其主要思想是通过引入门控机制来控制数据的流通,门控机制包括输入门、遗忘门与输出门,同时在LSTM结构中,还存在一个内部记忆单元来存储每一个时间步的内部记忆,用于相关运算,具体的LSTM介绍与引入部分我们已经在上次作业中进行了相关叙述:

深度学习作业 - 作业十 - BPTT-CSDN博客

那么本次作业我们就不进行进一步的详细赘述了,直接进行推导。

首先,一个完整的LSTM网络如上图所示,各种状态与门值的计算已经写在图片里面了,我们要想推到反向传播参数,得先知道前向传播的计算过程,下面我们来总结一下这个过程。

前向传播

前向传播过程在每个时间步t上的发生顺序为

(1)更新遗忘门输出

f^{\left( t \right)}=\sigma \left( W_fh^{\left( t-1 \right)}+U_fx^{\left( t \right)}+b_f \right)

(2)更新输入门和其控制对象

i^{\left( t \right)}=\sigma \left( W_ih^{\left( t-1 \right)}+U_ix^{\left( t \right)}+b_i \right)

a^{\left( t \right)}=\sigma \left( W_ah^{\left( t-1 \right)}+U_ax^{\left( t \right)}+b_a \right) 

(3)更新细胞状态,从C^{\left( t-1 \right)}C^{\left( t \right)}

C^{\left( t \right)}=C^{\left( t-1 \right)}\odot f^{\left( t \right)}+a^{\left( t \right)}\odot i^{\left( t \right)} 

(4)更新输出门和其控制对象,从h^{\left( t-1 \right)}h^{\left( t \right)}

 o^{\left( t \right)}=\sigma \left( W_oh^{\left( t-1 \right)}+U_ox^{\left( t-1 \right)}+b_o \right)

h^{\left( t \right)}=o^{\left( t \right)}\odot \tan\text{h}\left( C^{\left( t \right)} \right)

 (5)得到当前时间步t的预测输出

\hat{y}^{\left( t \right)}=\sigma \left( Vh^{\left( t \right)}+c \right)

反向传播

之前的反向传播中,我们都是仅仅定义了一个隐藏状态误差项\delta,这是由于之前的网络结构只有一个隐藏状态,在LSTM中,隐层不止有h_t还有一个C_t,因此这里我们定义两个\delta,即

\delta _{h}^{\left( t \right)}=\frac{\partial L}{\partial h^{\left( t \right)}}

\delta _{C}^{\left( t \right)}=\frac{\partial L}{\partial C^{\left( t \right)}}

为了方便找到梯度的递推模式,下面是根据前向传播公式给出数据在LSTM中数据的前向流动示意图

我们首先看最后一个时间步t=T

我们可以发现,在t=T时,误差只有L^{\left( T \right)}\rightarrow h^{\left( T \right)}这一条路径,因此\delta ^{\left( T \right)}可以很轻易的求出来,这里先假设损失函数是SSE,方便求解梯度(实际过程中这个损失函数可以改变,改变的话再对应求就可以了)

\delta ^{\left( T \right)}=\frac{\partial L}{\partial h^{\left( T \right)}}=\frac{\partial L}{\partial \hat{y}^{\left( T \right)}}\cdot \frac{\partial \hat{y}^{\left( T \right)}}{\partial h^{\left( T \right)}}=V^T\left( \hat{y}^{\left( T \right)}-y^{\left( T \right)} \right)

下面求\delta _{C}^{\left( t \right)},由于链式法则可以得到

\delta _{C}^{\left( T \right)}=\left( \frac{\partial h^{\left( T \right)}}{\partial C^{\left( T \right)}} \right) ^T\frac{\partial L}{\partial h^{\left( T \right)}}

又有

 h^{\left( t \right)}=o^{\left( t \right)}\odot \tan\text{h}\left( C^{\left( t \right)} \right)

最终可求得

\delta _{C}^{\left( T \right)}=\delta _{h}^{\left( T \right)}\odot o^{\left( T \right)}\odot \tan\text{h'}\left( C^{\left( T \right)} \right) 

知道了最后一个时间步T的梯度值,下一步就是求得每一步的梯度反向传播递推公式,即可由此推得前面每一个时刻t的梯度公式。

下面求t<T时的梯度

根据LSTM中数据的前向流动示意图可以得到,\delta _{h}^{\left( t \right)}的误差来源如下:

(1)l_{(t)}\rightarrow h^{(t)}(注意这里的l代表单元损失,而L是整体损失,是单元损失的累加)。

(2)h^{t+1}\rightarrow o^{(t+1)}\rightarrow h^{(t)}(来自输出门)

(3)C^{t+1}\rightarrow i^{(t+1)}\rightarrow h^{(t)}(来自输入门)

(4)C^{t+1}\rightarrow a^{(t+1)}\rightarrow h^{(t)}a代表输入门激活前的状态)

(5)C^{t+1}\rightarrow f^{(t+1)}\rightarrow h^{(t)}(来自遗忘门)

由此,我们知道,误差主要来自于l_{(t)}h^{t+1}C^{t+1},下面是推导过程

由此我们求得了\delta _{h}^{\left( t \right)}\delta _{C}^{\left( t+1 \right)}\delta _{h}^{\left( t+1 \right)}之间的递推关系。

下面继续求\delta _{C}^{\left( t \right)}

根据LSTM中数据的前向流动示意图可以得到,\delta _{C}^{\left( t \right)}的误差来源如下:

(1)h^t\rightarrow C^t(来自隐层状态)

(2)C^{t+1}\rightarrow C^{t}(来自隐层状态记忆单元)

由此,我们知道,误差主要来自于h^{t}C^{t+1},下面是推导过程

由此我们求得了\delta _{C}^{\left( t \right)}\delta _{C}^{\left( t+1 \right)}\delta _{h}^{\left( t \right)}之间的递推关系。 

有了递推公式,现在计算梯度就比较容易了。

梯度计算

总结一下,对于所有门参数(遗忘门、输入门、候选状态、输出门)W_g,其统一的梯度表达为:

\frac{\partial L}{\partial W_g}=\sum_{t=1}^T{\left[ \delta _{g}^{\left( t \right)} \right] \left( h^{\left( t-1 \right)} \right) ^T}

其中:

\delta _{g}^{\left( t \right)}是各门的误差信号,具体为:

遗忘门:\delta _{f}^{\left( t \right)}=\delta _{C}^{\left( t \right)}\odot C^{\left( t-1 \right)}\odot f^{\left( t \right)}\odot \left( 1-f^{\left( t \right)} \right)

输入门:\delta _{i}^{\left( t \right)}=\delta _{C}^{\left( t \right)}\odot a^t\odot i^{\left( t \right)}\odot \left( 1-i^{\left( t \right)} \right)

候选状态:\delta _{a}^{\left( t \right)}=\delta _{C}^{\left( t \right)}\odot i^{\left( t \right)}\odot \left( 1-a^{\left( t \right)}\odot a^{\left( t \right)} \right)

输出门:\delta _{o}^{\left( t \right)}=\delta _{h}^{\left( t \right)}\odot \tanh\left( C^{\left( t \right)} \right) \odot o^{\left( t \right)}\odot \left( 1-o^{\left( t \right)} \right)

其他参数的计算

其他参数的计算均与W的计算类似。

对于输入权重矩阵U,对应的梯度计算类似于W,只需要将h^{(t-1)}替换为x^{(t)}

而偏置项的梯度是激活前状态的偏导的累加,即\sum_{t=1}^T{\left[ \delta _{g}^{\left( t \right)} \right]}

为什么LSTM能够避免梯度消失

这里要明确的一点是,RNN的梯度消失/爆炸并不是我们所说的传统意义上的梯度消失/爆炸。比如CNN中,各个层有各个层的不同参数,梯度各自不同,而RNN中权重在各个时间步是共享的,最终梯度是所有时间步的梯度之和

因此,RNN 中总的梯度是不会消失的。即便梯度越传越弱,那也只是远距离的梯度消失,由于近距离的梯度不会消失,所有梯度之和便不会消失。RNN 所谓梯度消失的真正含义是,梯度被近距离梯度主导,导致模型难以学到远距离的依赖关系。

回到问题中,LSTM中有很多条传播的路径,但是有一条路径C^{\left( t \right)}=C^{\left( t-1 \right)}\odot f^{\left( t \right)}+a^{\left( t \right)}\odot i^{\left( t \right)}能够永远为梯度总和贡献远距离的梯度,因为这条路径上只涉及到了逐元素相乘与相加两个操作(之前SRN梯度消失就是因为涉及到了矩阵连乘,会导致梯度越乘越偏),梯度流是非常稳定的。同时对于LSTM中其他路径来说,由于梯度的计算还是矩阵连乘,照样会发生一些梯度消失或爆炸现象。

不过由于总的远距离梯度 = 各条路径的远距离梯度之和,即便其他远距离路径梯度消失了,只要保证有一条远距离路径(就是上面说的那条高速公路)梯度不消失,总的远距离梯度就不会消失(正常梯度 + 消失梯度 = 正常梯度)。因此 LSTM 通过改善一条路径上的梯度问题拯救了总体的远距离梯度

问题二

编程实现LSTM的运行过程

这张图是老师用于让我们清楚看到LSTM内部运作的图,定义了每个序列由三个变量x_1x_2x_3组成,网络内部存在一个记忆单元Memory。

x_2取1时,将x_1输入进记忆单元Memory中,模拟了输入门的效果。

x_2取-1时,将记忆单元Memory清空为0,模拟了遗忘门的效果。

x_3取1时,将记忆单元Memory中的数据输出为y

按照如下图设置权重,来模拟这一过程,相应的在程序中也定义相同的权重,再编写一个算子即可。

实际上的LSTM网络结构比这个复杂,并且每个门控结构并不是全开或者全关,是以一定权重开启一部分的,这个例子还是比较形象的,下面分别使用Numpy与Pytorch实现。

1. 使用Numpy实现LSTM算子

代码

import numpy as np# 激活函数
def sigmoid(x):return 1 / (1 + np.exp(-x))# 权重参数
W_i = np.array([1, 0, 0, 0])
W_IGate = np.array([0, 100, 0, -10])
W_fGate = np.array([0, 100, 0, 10])
W_OGate = np.array([0, 0, 100, -10])# 输入数据
input = np.array([[1, 0, 0, 1], [3, 1, 0, 1], [2, 0, 0, 1], [4, 1, 0, 1], [2, 0, 0, 1], [1, 0, 1, 1], [3, -1, 0, 1], [6, 1, 0, 1],[1, 0, 1, 1]])y = []  # 输出
c_t = 0  # 内部状态for x in input:g_t = np.matmul(W_i, x)  # 计算候选状态IGate = np.round(sigmoid(np.matmul(W_IGate, x)))  # 计算输入门after_IGate = g_t * IGate  # 候选状态经过输入门FGate = np.round(sigmoid(np.matmul(W_fGate, x)))  # 计算遗忘门after_fGate = FGate * c_t  # 内部状态经过遗忘门c_t = np.add(after_IGate, after_fGate)  # 新的内部状态OGate = np.round(sigmoid(np.matmul(W_OGate, x)))  # 计算输出门after_OGate = OGate * c_t  # 新的内部状态经过输出门y.append(after_OGate)  # 输出
print(f"输出:{y}")

运行结果 

可见,输出结果与我们预期的相同,其实就是简单在循环里模拟了一下LSTM的计算过程,按照PPT上的权重与计算过程实现即可。 

2. 使用nn.LSTMCell实现

代码

import numpy as np
import torch.nn# 设置参数
input_size = 4
hidden_size = 1
# 模型实例化
Cell = torch.nn.LSTMCell(input_size=input_size, hidden_size=hidden_size)
# 权重
Cell.weight_ih.data = torch.tensor([[0, 100, 0, -10], [0, 100, 0, 10], [1, 0, 0, 0], [0, 0, 100, -10]],dtype=torch.float32)
Cell.weight_hh.data = torch.zeros(4, 1)
# 初始化内部状态
h_t = torch.zeros(1, 1)
c_t = torch.zeros(1, 1)
# 输入的数据[batch_size,seq_len,input_size]
input_0 = torch.tensor([[[1, 0, 0, 1], [3, 1, 0, 1], [2, 0, 0, 1], [4, 1, 0, 1], [2, 0, 0, 1], [1, 0, 1, 1], [3, -1, 0, 1], [6, 1, 0, 1],[1, 0, 1, 1]]], dtype=torch.float32)
# 交换前两维顺序,方便遍历
input = torch.transpose(input_0, 1, 0)
y = []
# 计算
for x in input:h_t, c_t = Cell(x, (h_t, c_t))  # 传入序列输入与各个状态y.append(np.round(h_t.item(), decimals=3))
print(f"输出:{y}")

输出结果 

使用实例化的LSTMCell,每次循环分别传入输入,上一时间步的隐层状态与内部记忆单元值,即可自动计算,需要注意的是,由于LSTMCell内部有激活函数tanh,并且每一步计算都是数值计算,无法取整等,故输出不是严格的与示例相同,但是大小关系与0-1关系都是存在的。

3. 使用nn.LSTM实现

代码

import numpy as np
import torch.nn# 设置参数
input_size = 4
hidden_size = 1
# 模型实例化
Lstm = torch.nn.LSTM(input_size=input_size, hidden_size=hidden_size, batch_first=True)
# 权重
Lstm.weight_ih_l0.data = torch.tensor([[0, 100, 0, -10], [0, 100, 0, 10], [1, 0, 0, 0], [0, 0, 100, -10]],dtype=torch.float32)
Lstm.weight_hh_l0.data = torch.zeros(4, 1)
# 初始化内部状态
h_t = torch.zeros(1, 1, 1)
c_t = torch.zeros(1, 1, 1)
# 输入的数据[batch_size,seq_len,input_size]
input = torch.tensor([[[1, 0, 0, 1], [3, 1, 0, 1], [2, 0, 0, 1], [4, 1, 0, 1], [2, 0, 0, 1], [1, 0, 1, 1],[3, -1, 0, 1], [6, 1, 0, 1], [1, 0, 1, 1]]], dtype=torch.float32)
y, (h_t, c_t) = Lstm(input, (h_t, c_t))
y = torch.round(y * 1000) / 1000
print(f"输出:{y}")

运行结果 

输出与使用LSTMCell相同,这里Numpy版本的程序与这两个API实现差在了tanh激活函数与内部取整操作。 

LSTM就无需我们自己进行循环计算每一步骤的数据了,初始化数据后直接计算,输出结果即可。

总结

1.LSTM的推导主要是参照SumWaiLiu的博客园自己梳理复现了一遍,这里强烈推荐这个博客,写得又清楚又好,推导的过程再一次加深了对反向传播算法的认识,其实本质就是找到梯度的反向递归式,通过对求导链式法则的推导,一步一步由后面的损失函数计算前面的损失函数。得到递推公式后,想要计算任何一个参数的梯度直接使用已经计算好的损失函数代入求导式子即可,这也是本学期最后一次推导反向传播的作业了(大概),从开始到现在,接触并学会了推导式子,而不是像之前一样只会拿到一个特例来算了,这是一个很大的进步。

2.在大佬的博客园认识到,其实对于RNN来说,梯度消失不是对于整体来说的,而是对于时间间隔较长的两个时间步之前,反向传播计算梯度时,涉及到矩阵连乘,故会丢失这一部分的梯度信息,也就降低了学习这一部分数据的能力,而对于间隔较短的时间步来说,发生梯度消失或梯度爆炸的情况比较少,还是能够学得相邻时间步的信息的。也就是说对于RNN梯度消失与爆炸是说丢失了较远时间步的信息,以较近时间步的信息为主导。在LSTM中,引入了内部记忆状态这一概念,为梯度的计算提供了一条“高速公路”,其计算方式保证了不会发生矩阵连乘,也就不容易发生梯度消失或爆炸,所以在每一次求梯度都有这条路径作为保证,从而改善了梯度消失。

3. 在编程实现PPT上的例子时,从应用的角度再次认识了LSTMCell与LSTM,对于这两个函数,只需要实例化时传入参数,并且在调用之前做好初始化工作,即可成功运行。实际上由于这两个API内部存在tanh激活函数与精确的数值计算,无法与课上的模拟例子绝对相同,但是这就是我们正常应用的状态,故也不需要特别进行调整。

参考 

【1】LSTM参数梯度推导与实现:对抗梯度消失,

【2】《神经网络的梯度推导与代码验证》之LSTM的前向传播和反向梯度推导 - SumwaiLiu - 博客园

【3】NNDL 作业十一 LSTM-CSDN博客

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

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

相关文章

医院与医疗设备供应商网络安全事故综述

医院与医疗设备供应商网络安全事故综述 在医疗行业中&#xff0c;医院和医疗设备供应商的网络安全问题同样不容忽视。以下是一些近年来发生的重大网络安全事故的总结&#xff1a; 1. 德国杜塞尔多夫大学医院勒索软件攻击&#xff08;2020年&#xff09; 事件描述&#xff1a…

修改vscode中emmet中jsx和tsx语法中className的扩展符号从单引号到双引号 - HTML代码补全 - 单引号双引号

效果图 实现步骤 文件 > 首选项 > 设置搜索“”在settings.json中修改&#xff0c;增加 "emmet.syntaxProfiles": {"html": {"attr_quotes": "single"},"jsx": {"attr_quotes": "double","…

从0到1实现vue3+vite++elementuiPlus+ts的后台管理系统(一)

前言&#xff1a;从这篇文章开始实现vue3vite的后台管理系统&#xff0c;记录下自己搭建后台系统图的过程。 这篇文章完成项目的初始化和基本配置&#xff0c;这一步可以直接跟着vue3官网进行。整个系列只有前端部分&#xff0c;不涉及后端。 vue3官网&#xff1a;https://cn.…

JavaEE初阶——多线程(线程安全-锁)

复习上节内容&#xff08;部分-掌握程度不够的&#xff09; 加锁&#xff0c;解决线程安全问题。 synchronized关键字&#xff0c;对锁对象进行加锁。 锁对象&#xff0c;可以是随便一个Object对象&#xff08;或者其子类的对象&#xff09;&#xff0c;需要关注的是&#xff…

如何在NGINX中实现基于IP的访问控制(IP黑白名单)?

大家好&#xff0c;我是锋哥。今天分享关于【如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f;】面试题。希望对大家有帮助&#xff1b; 如何在NGINX中实现基于IP的访问控制&#xff08;IP黑白名单&#xff09;&#xff1f; 1000道 互联网大…

Docker--Docker Registry(镜像仓库)

什么是Docker Registry&#xff1f; 镜像仓库&#xff08;Docker Registry&#xff09;是Docker生态系统中用于存储、管理和分发Docker镜像的关键组件。 镜像仓库主要负责存储Docker镜像&#xff0c;这些镜像包含了应用程序及其相关的依赖项和配置&#xff0c;是构建和运行Doc…

微信小程序:实现节点进度条的效果;正在完成的节点有动态循环效果;横向,纵向排列

参考说明 微信小程序实现流程进度功能 - 知乎 上面的为一个节点进度条的例子&#xff0c;但并不完整&#xff0c;根据上述代码&#xff0c;进行修改完善&#xff0c;实现其效果 横向效果 代码 wxml <view classorder_process><view classprocess_wrap wx:for&quo…

window下的qt5.14.2配置vs2022

这里做一个笔记&#xff0c;已知qt5.14.2和vs2022不兼容&#xff0c;无法自动扫描到vs的编译器。但由于团队协作原因&#xff0c;必须使用qt5.14.2&#xff0c;并且第三方库又依赖vs2022。其实qt5.15.2是支持vs2022的&#xff0c;如果能够用qt5.15.2&#xff0c;还是建议使用qt…

Java-27 深入浅出 Spring - 实现简易Ioc-03 在上节的业务下手动实现IoC

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; 大数据篇正在更新&#xff01;https://blog.csdn.net/w776341482/category_12713819.html 目前已经更新到了&#xff1a; MyBatis&#xff…

梳理你的思路(从OOP到架构设计)_UML应用:业务内涵的分析抽象表达01

目录 1、 系统分析(System Analysis) 系統分析的涵意 业务(领域)知识 业务内涵 业务(领域)概念 2、举例(一) &#xff1a;东方传说 UML与建模工具 1、 系统分析(System Analysis) 系統分析的涵意 许多人在学习系统分析(System Analysis)时&#xff0c;常迷失于其字面上…

Web 安全 跨站 跨域 XSS CSRF

跨站 跨站即 cross-site&#xff0c;它和同站&#xff08;same-site&#xff09;相对&#xff0c;对协议和端口号无要求&#xff0c;只要两个 URL 的 eTLD 1 一致&#xff0c;就能称为同站。那么什么是 eTLD 呢&#xff1f; eTLD 即 effective top level domain&#xff0c;…

k8s服务搭建与实战案例

Kubernetes&#xff08;K8s&#xff09;作为一个开源的容器编排平台&#xff0c;广泛应用于现代的云原生应用架构中。以下是一些常见的 **Kubernetes 实战案例**&#xff0c;包括从基础部署到高级应用场景的使用。通过这些案例&#xff0c;可以更好地理解 K8s 的运作原理和最佳…

PYQT5程序框架

pyqt5程序框架_哔哩哔哩_bilibili 1.UI代码 Qhkuja.py # -*- coding: utf-8 -*-# Form implementation generated from reading ui file Qhkuja.ui # # Created by: PyQt5 UI code generator 5.15.7 # # WARNING: Any manual changes made to this file will be lost when py…

基于MobileNet v2模型的口罩实时检测系统实现

基于kaggle数据集训练的模型其实现结果如下&#xff1a; 代码结构如下&#xff1a; 实时口罩检测器&#xff1a; 从导航栏中的链接“实时的口罩检测器”功能&#xff0c;该系统包含一个实时检测用户是否佩戴口罩的功能。基于图片的口罩检测器&#xff1a; 从另一个导航链接“基…

高效项目托管指南:从本地到 GitHub 的完整流程

在现代软件开发中&#xff0c;将项目托管在 GitHub 上是一个常见且高效的方式。GitHub 不仅可以用作版本控制工具&#xff0c;还能帮助你与团队协作或展示自己的项目。本文将带你一步步完成项目的打包和上传。 高效项目托管指南&#xff1a;从本地到 GitHub 的完整流程 1. 准备…

用TPS54531绘制BUCK电路板

首先&#xff0c;这TPS54531 是一款非同步降压转换器芯片&#xff08;异步&#xff09;。 这是BUCK的基本原理图&#xff0c;它是异步的。 我们用这款芯片来控制MOS管的高频开关&#xff0c;以此实现降压。 这里使用的应该是CCM模式。 这里&#xff1a; Vi为24V&#xff0c;…

【新人系列】Python 入门(十六):正则表达式

✍ 个人博客&#xff1a;https://blog.csdn.net/Newin2020?typeblog &#x1f4dd; 专栏地址&#xff1a;https://blog.csdn.net/newin2020/category_12801353.html &#x1f4e3; 专栏定位&#xff1a;为 0 基础刚入门 Python 的小伙伴提供详细的讲解&#xff0c;也欢迎大佬们…

人工智能增强的音频和聊天协作服务

论文标题&#xff1a;AI-enabled Audio and Chat Collaboration Services 中文标题&#xff1a;人工智能增强的音频和聊天协作服务 作者信息&#xff1a; Emil P. Andersen, Norwegian Defence Research Establishment (FFI), Kjeller, NorwayJesper R. Goksr, Sindre E. Ha…

【原创】- 澳门预约医疗系统 - 一个基于Vue3编写的程序

在空余时间写了一个前端预约医疗系统&#xff0c;用Vue3写的一套前端模块&#xff0c;里面数据都是本地模拟&#xff0c;一个练手的简单项目。 此项目主要功能有&#xff1a; 1.预约挂号、挂号记录 2.疫苗接种 3.就医记录 4.科室导航 5.AI问诊 6.个人病例 7.支付可配置化 8.健康…

Cadence学习笔记 3 MCU主控原理图绘制

基于Cadence 17.4&#xff0c;四层板4路HDMI电路 更多Cadence学习笔记&#xff1a;Cadence学习笔记 1 原理图库绘制Cadence学习笔记 2 PCB封装绘制 目录 3、MCU主控原理图绘制 快捷键总结&#xff1a; 3、MCU主控原理图绘制 新建原理图Design&#xff0c;选择好SCH文件夹&…