颠覆语言认知的革命!神经概率语言模型如何突破人类思维边界?

news2025/3/11 6:31:52

颠覆语言认知的革命!神经概率语言模型如何突破人类思维边界?

一、传统模型的世纪困境:当n-gram遇上"月光族难题"

令人震惊的案例:2012年Google语音识别系统将

用户说:“我要还信用卡”
系统识别:“我要环信用开”

三大困境解析

  1. 维度灾难:当n=3时,词表大小10万 → 需要存储10^15个组合
  2. 数据稀疏:"量子计算融资"在10亿语料库中出现0次
  3. 长程依赖:无法捕捉"虽然…但是…"的超距离关联

二、神经概率语言模型:NPLM

NPLM的结构包括3个主要部分:输⼊层、隐藏层和输出层。

输⼊层将词汇映射到连续的词向量空间,隐藏层通过⾮线性激活函数学习词与词之间的复杂关系,输出层通过softmax函数产⽣下⼀个单词的概率分布。

image-20250309184522370

数学之美
P ( w t ∣ w t − 1 , . . . , w t − n + 1 ) = s o f t m a x ( C ⋅ t a n h ⁡ ( W x + b ) ) P ( w t ∣ w t − 1 , . . . , w t − n + 1 ) = softmax ( C ⋅ tanh ⁡ ( W x + b ) ) P(wt∣wt−1,...,wt−n+1)=softmax(C⋅tanh⁡(Wx+b))P(w_t|w_{t-1},...,w_{t-n+1}) = \text{softmax}(C \cdot \tanh(Wx + b)) P(wtwt1,...,wtn+1)=softmax(Ctanh(Wx+b))P(wtwt1,...,wtn+1)=softmax(Ctanh(Wx+b))
其中:

  • C C C:词向量到输出的连接矩阵
  • W W W:上下文词向量组合矩阵
  • x x x:上下文词向量拼接

2.1 NPLM的实现

image-20250309184711801

2.1.1 建立语料库
# 构建一个非常简单的数据集
sentences = ["我 喜欢 玩具", "我 爱 爸爸", "我 讨厌 挨打"] 
# 将所有句子连接在一起,用空格分隔成多个词,再将重复的词去除,构建词汇表
word_list = list(set(" ".join(sentences).split())) 
# 创建一个字典,将每个词映射到一个唯一的索引
word_to_idx = {word: idx for idx, word in enumerate(word_list)} 
# 创建一个字典,将每个索引映射到对应的词
idx_to_word = {idx: word for idx, word in enumerate(word_list)} 
voc_size = len(word_list) # 计算词汇表的大小
print(' 词汇表:', word_to_idx) # 打印词汇到索引的映射字典
print(' 词汇表大小:', voc_size) # 打印词汇表大小
 词汇表: {'爸爸': 0, '讨厌': 1, '我': 2, '玩具': 3, '爱': 4, '喜欢': 5, '挨打': 6}
 词汇表大小: 7
2.1.2 生成NPLM训练数据
# 构建批处理数据
import torch # 导入 PyTorch 库
import random # 导入 random 库
batch_size = 2 # 每批数据的大小
def make_batch():
    input_batch = []  # 定义输入批处理列表
    target_batch = []  # 定义目标批处理列表
    selected_sentences = random.sample(sentences, batch_size) # 随机选择句子
    for sen in selected_sentences:  # 遍历每个句子
        word = sen.split()  # 用空格将句子分隔成多个词
        # 将除最后一个词以外的所有词的索引作为输入
        input = [word_to_idx[n] for n in word[:-1]]  # 创建输入数据
        # 将最后一个词的索引作为目标
        target = word_to_idx[word[-1]]  # 创建目标数据
        input_batch.append(input)  # 将输入添加到输入批处理列表
        target_batch.append(target)  # 将目标添加到目标批处理列表
    input_batch = torch.LongTensor(input_batch) # 将输入数据转换为张量
    target_batch = torch.LongTensor(target_batch) # 将目标数据转换为张量
    return input_batch, target_batch  # 返回输入批处理和目标批处理数据
input_batch, target_batch = make_batch() # 生成批处理数据
print(" 输入批处理数据:",input_batch)  # 打印输入批处理数据
# 将输入批处理数据中的每个索引值转换为对应的原始词
input_words = []
for input_idx in input_batch:
    input_words.append([idx_to_word[idx.item()] for idx in input_idx])
print(" 输入批处理数据对应的原始词:",input_words)
print(" 目标批处理数据:",target_batch) # 打印目标批处理数据
# 将目标批处理数据中的每个索引值转换为对应的原始词
target_words = [idx_to_word[idx.item()] for idx in target_batch]
print(" 目标批处理数据对应的原始词:",target_words)
 输入批处理数据: tensor([[2, 1], [2, 4]])
 输入批处理数据对应的原始词: [['我', '讨厌'], ['我', '爱']]
 目标批处理数据: tensor([6, 0])
 目标批处理数据对应的原始词: ['挨打', '爸爸']

batch_size = 2 # 每批数据的大小

image-20250310194259986

即为整理好数据集,及其对应的结果,接下来只等构建网络和训练

2.1.3 定义NPLM
import torch.nn as nn # 导入神经网络模块
# 定义神经概率语言模型(NPLM)
class NPLM(nn.Module):
    def __init__(self):
        super(NPLM, self).__init__() 
        self.C = nn.Embedding(voc_size, embedding_size) # 定义一个词嵌入层
        # 第一个线性层,其输入大小为 n_step * embedding_size,输出大小为 n_hidden
        self.linear1 = nn.Linear(n_step * embedding_size, n_hidden) 
        # 第二个线性层,其输入大小为 n_hidden,输出大小为 voc_size,即词汇表大小
        self.linear2 = nn.Linear(n_hidden, voc_size) 
    def forward(self, X):  # 定义前向传播过程
        # 输入数据 X 张量的形状为 [batch_size, n_step]
        X = self.C(X)  # 将 X 通过词嵌入层,形状变为 [batch_size, n_step, embedding_size]        
        X = X.view(-1, n_step * embedding_size) # 形状变为 [batch_size, n_step * embedding_size]
        # 通过第一个线性层并应用 ReLU 激活函数
        hidden = torch.tanh(self.linear1(X)) # hidden 张量形状为 [batch_size, n_hidden]
        # 通过第二个线性层得到输出 
        output = self.linear2(hidden) # output 形状为 [batch_size, voc_size]
        return output # 返回输出结果

image-20250310194659088

进一部的说明我们结合以下代码

2.1.4 实例化NPLM
n_step = 2 # 时间步数,表示每个输入序列的长度,也就是上下文长度 
n_hidden = 2 # 隐藏层大小
embedding_size = 2 # 词嵌入大小
model = NPLM() # 创建神经概率语言模型实例
print(' NPLM 模型结构:', model) # 打印模型的结构

输入数据[[1,3], [1,6]](对应句子片段[“我 爱”, “我 讨厌”])

处理流程

  1. 嵌入层转为形状 [2,2,2] 的张量
  2. 展平为 [2,4]
  3. 第一线性层压缩到 [2,2]
  4. 第二线性层扩展到 [2,7](每个样本对应7个词的概率)

image-20250310195024069

2.1.5 训练NPLM
import torch.optim as optim # 导入优化器模块
criterion = nn.CrossEntropyLoss() # 定义损失函数为交叉熵损失
optimizer = optim.Adam(model.parameters(), lr=0.1) # 定义优化器为 Adam,学习率为 0.1
# 训练模型
for epoch in range(5000): # 设置训练迭代次数
   optimizer.zero_grad() # 清除优化器的梯度
   input_batch, target_batch = make_batch() # 创建输入和目标批处理数据
   output = model(input_batch) # 将输入数据传入模型,得到输出结果
   loss = criterion(output, target_batch) # 计算损失值
   if (epoch + 1) % 1000 == 0: # 每 1000 次迭代,打印损失值
     print('Epoch:', '%04d' % (epoch + 1), 'cost =', '{:.6f}'.format(loss))
   loss.backward() # 反向传播计算梯度
   optimizer.step() # 更新模型参数

是不是中一段训练的设定看着挺抽象,接下来举一个简单的栗子:

for epoch in range(5000):
    optimizer.zero_grad()          # 清空炒锅残留(重置梯度)
    input_batch, target = make_batch()  # 随机选菜谱(数据采样)
    output = model(input_batch)    # 学生试做菜品(前向传播)
    loss = criterion(output, target) # 老师试吃评分(计算损失)
    loss.backward()                # 分析哪里做错了(反向传播)
    optimizer.step()               # 根据建议改进(参数更新)

image-20250310195240344
2.1.6 用NPLM预测新词
# 进行预测
input_strs = [['我', '讨厌'], ['我', '喜欢']]  # 需要预测的输入序列
# 将输入序列转换为对应的索引
input_indices = [[word_to_idx[word] for word in seq] for seq in input_strs]
# 将输入序列的索引转换为张量
input_batch = torch.LongTensor(input_indices) 
# 对输入序列进行预测,取输出中概率最大的类别
predict = model(input_batch).data.max(1)[1]  
# 将预测结果的索引转换为对应的词
predict_strs = [idx_to_word[n.item()] for n in predict.squeeze()]  
for input_seq, pred in zip(input_strs, predict_strs):
   print(input_seq, '->', pred)  # 打印输入序列和预测结果
['我', '讨厌'] -> 挨打

['我', '喜欢'] -> 玩具

image-20250310195543613

2.2 完整手撕

最开始的学习中容易对NPLM建立中纬度的变化中产生疑惑,接下来进行具体得分析。

image-20250310195740161

其结构可以拆分为一个三明治结构

输入词索引 → 嵌入层 → 全连接层1+激活 → 全连接层2 → 词汇概率分布

让我们用具体数值示例(假设参数如下)逐步解析:

voc_size = 7        # 词汇表大小(示例数据实际值)
n_step = 2          # 用前2个词预测第3个词
embedding_size = 2  # 词向量维度(示例设定)
n_hidden = 2        # 隐藏层维度(示例设定)

2.2.1 输入数据示例

假设输入批处理数据为:

input_batch = [[1,3], [1,6]]  # 对应句子片段:"我 爱"、"我 讨厌"
# 转换为张量后形状:[batch_size=2, n_step=2]

2.2.2 前向传播逐层分解

1. 嵌入层(Embedding Layer)
self.C = nn.Embedding(7, 2)  # 参数:7词→2维向量
X = self.C(input_batch)      # 输入:[2,2] → 输出:[2,2,2]

相当于把索引中的七个词转化为二维的向量,转化过程如下

计算过程

  • 每个词索引查表获取对应向量
# 假设嵌入矩阵(随机初始化示例):
[
 [0.1, 0.2],  # 索引0:'挨打'
 [0.3, 0.4],  # 索引1:'我'
 [0.5, 0.6],  # 索引2:'爸爸' 
 [0.7, 0.8],  # 索引3:'爱'
 [0.9, 1.0],  # 索引4:'喜欢'
 [1.1, 1.2],  # 索引5:'玩具'
 [1.3, 1.4]   # 索引6:'讨厌'
]

# 输入[[1,3], [1,6]]的嵌入结果:
[
 [[0.3,0.4], [0.7,0.8]],  # "我 爱"
 [[0.3,0.4], [1.3,1.4]]   # "我 讨厌"
]

数学本质
将离散的词索引映射为连续可训练的向量空间中的点,公式:
E = EmbeddingLookup ( X ) \mathbf{E} = \text{EmbeddingLookup}(\mathbf{X}) E=EmbeddingLookup(X)
其中 X ∈ Z b a t c h × n _ s t e p \mathbf{X} \in \mathbb{Z}^{batch×n\_step} XZbatch×n_step, E ∈ R b a t c h × n _ s t e p × e m b e d d i n g _ s i z e \mathbf{E} \in \mathbb{R}^{batch×n\_step×embedding\_size} ERbatch×n_step×embedding_size


2. 特征拼接(Flatten)
X = X.view(-1, n_step*embedding_size)  # [2,2,2] → [2,4]

具体变换

# 第一个样本:"我 爱"  
原始嵌入 → [0.3,0.4], [0.7,0.8]  
拼接后 → [0.3, 0.4, 0.7, 0.8]

# 第二个样本:"我 讨厌"  
原始嵌入 → [0.3,0.4], [1.3,1.4]  
拼接后 → [0.3, 0.4, 1.3, 1.4]

技术意义
将序列的时序信息转换为空间特征,为全连接层提供固定长度的输入。


3. 第一全连接层(Feature Projection)
self.linear1 = nn.Linear(4, 2)  # 输入4维 → 输出2维
hidden = torch.tanh(self.linear1(X))  # [2,4] → [2,2]

参数示例
假设权重和偏置为(点乘):
W 1 = [ 0.1 − 0.2 0.3 0.4 − 0.5 0.6 0.7 − 0.8 ] , b 1 = [ 0.1 − 0.2 ] W_1 = \begin{bmatrix} 0.1 & -0.2 & 0.3 & 0.4 \\ -0.5 & 0.6 & 0.7 & -0.8 \end{bmatrix}, \quad b_1 = \begin{bmatrix} 0.1 \\ -0.2 \end{bmatrix} W1=[0.10.50.20.60.30.70.40.8],b1=[0.10.2]

计算演示

# 第一个样本计算:
[0.3, 0.4, 0.7, 0.8] × W1 + b1
= (0.3*0.1 + 0.4*(-0.2) + 0.7*0.3 + 0.8*0.4) + 0.1 = 0.54 → tanh(0.54)0.49  
= (0.3*(-0.5) + 0.4*0.6 + 0.7*0.7 + 0.8*(-0.8)) + (-0.2) = -0.56 → tanh(-0.56)-0.51
输出 → [0.49, -0.51]

数学表达式
h = tanh ⁡ ( X f l a t W 1 ⊤ + b 1 ) \mathbf{h} = \tanh(\mathbf{X}_{flat}W_1^\top + \mathbf{b}_1) h=tanh(XflatW1+b1)
其中 W 1 ∈ R n _ h i d d e n × ( n _ s t e p × e m b e d d i n g _ s i z e ) W_1 \in \mathbb{R}^{n\_hidden×(n\_step×embedding\_size)} W1Rn_hidden×(n_step×embedding_size)


4. 第二全连接层(Output Projection)
self.linear2 = nn.Linear(2,7)  # 2维→7分类
output = self.linear2(hidden)  # [2,2] → [2,7]

相当于将第一层的输入进行线性变换后(上下文特征的抽象提取),通过激活函数得出的结果分别再与第二层的参数进行线性变换(语义到词汇的概率映射),通过结果可以判断出哪一个词语为预测词的概率更大。

参数示例
假设:
W 2 = [ 0.2 − 0.3 0.4 0.1 − 0.5 0.6 0.7 − 0.8 − 0.9 0.2 1.0 0.3 0.1 − 0.4 ] , b 2 = [ 0.1 , 0.2 , − 0.3 , 0.4 , − 0.5 , 0.6 , − 0.7 ] W_2 = \begin{bmatrix} 0.2 & -0.3 \\ 0.4 & 0.1 \\ -0.5 & 0.6 \\ 0.7 & -0.8 \\ -0.9 & 0.2 \\ 1.0 & 0.3 \\ 0.1 & -0.4 \end{bmatrix}, \quad b_2 = [0.1, 0.2, -0.3, 0.4, -0.5, 0.6, -0.7] W2= 0.20.40.50.70.91.00.10.30.10.60.80.20.30.4 ,b2=[0.1,0.2,0.3,0.4,0.5,0.6,0.7]

计算演示

# 第一个样本隐藏值 [0.49, -0.51]
计算每个输出单元:
0.49*0.2 + (-0.51)*(-0.3) + 0.10.098 + 0.153 + 0.1 = 0.351 → 输出单元0  
0.49*0.4 + (-0.51)*0.1 + 0.20.196 - 0.051 + 0.2 = 0.345 → 输出单元1  
...以此类推所有7个单元

数学表达式
o = h W 2 ⊤ + b 2 \mathbf{o} = \mathbf{h}W_2^\top + \mathbf{b}_2 o=hW2+b2
其中 W 2 ∈ R v o c _ s i z e × n _ h i d d e n W_2 \in \mathbb{R}^{voc\_size×n\_hidden} W2Rvoc_size×n_hidden


2.2.3 输出结果解读

最终得到形状为 [batch_size, voc_size]未归一化概率(logits),例如:

output = [
    [0.35, 0.34, -1.2, 0.8, 2.1, -0.3, 0.5],  # 样本1:预测"喜欢"(索引4)概率最高
    [1.2, -0.5, 0.7, 0.3, -0.8, 0.9, 2.3]     # 样本2:预测"讨厌"(索引6)概率最高
]

要得到概率分布,需应用Softmax:

probs = torch.softmax(output, dim=1)
# probs ≈ [
#   [0.05, 0.05, 0.01, 0.10, 0.60, 0.09, 0.10], 
#   [0.15, 0.03, 0.08, 0.07, 0.02, 0.10, 0.55]
# ]

2.2.4 参数计算详解

1. 嵌入层参数

参数数 = v o c _ s i z e × e m b e d d i n g _ s i z e = 7 × 2 = 14 \text{参数数} = voc\_size × embedding\_size = 7×2 = 14 参数数=voc_size×embedding_size=7×2=14

2. 第一全连接层

参数数 = ( n _ s t e p × e m b e d d i n g _ s i z e ) × n _ h i d d e n + n _ h i d d e n = 4 × 2 + 2 = 10 \text{参数数} = (n\_step×embedding\_size) × n\_hidden + n\_hidden = 4×2 + 2 = 10 参数数=(n_step×embedding_size)×n_hidden+n_hidden=4×2+2=10

3. 第二全连接层

参数数 = n _ h i d d e n × v o c _ s i z e + v o c _ s i z e = 2 × 7 + 7 = 21 \text{参数数} = n\_hidden × voc\_size + voc\_size = 2×7 + 7 = 21 参数数=n_hidden×voc_size+voc_size=2×7+7=21

总参数:14 + 10 + 21 = 45个可训练参数

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

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

相关文章

练习:关于静态路由,手工汇总,路由黑洞,缺省路由相关

这是题目,我已经画分好了网段,题目要求是这样的: 划分网段 我为什么一个网段划了6个可用IP(一个网段8个地址)呢,因为我刚开始吧环回接口理解成一个主机了,导致我认为两个环回主机在一个网段,其实每个网段只需要2个地址就可以完成这个练习,我懒得划了,就按第一张图的网段来吧…

J6打卡——pytorch实现ResNeXt-50实现猴痘检测

🍨 本文为🔗365天深度学习训练营中的学习记录博客 🍖 原作者:K同学啊 1.检查GPU import torch import torch.nn as nn import torchvision.transforms as transforms import torchvision from torchvision import transforms, d…

vue+dhtmlx-gantt 实现甘特图-快速入门【甘特图】

文章目录 一、前言二、使用说明2.1 引入依赖2.2 引入组件2.3 引入dhtmlx-gantt2.4 甘特图数据配置2.5 初始化配置 三、代码示例3.1 Vue2完整示例3.2 Vue3 完整示例 四、效果图 一、前言 dhtmlxGantt 是一款功能强大的甘特图组件,支持 Vue 3 集成。它提供了丰富的功…

音视频入门基础:RTP专题(16)——RTP封装音频时,音频的有效载荷结构

一、引言 《RFC 3640》和《RFC 6416》分别定义了两种对MPEG-4流的RTP封包方式,这两个文档都可以从RFC官网下载: RFC Editor 本文主要对《RFC 3640》中的音频打包方式进行简介。《RFC 3640》总共有43页,本文下面所说的“页数”是指在pdf阅读…

超分之DeSRA

Desra: detect and delete the artifacts of gan-based real-world super-resolution models.DeSRA:检测并消除基于GAN的真实世界超分辨率模型中的伪影Xie L, Wang X, Chen X, et al.arXiv preprint arXiv:2307.02457, 2023. 摘要 背景: GAN-SR模型虽然…

Ubuntu用户安装cpolar内网穿透

前言 Cpolar作为一款体积小巧却功能强大的内网穿透软件,不仅能够在多种环境和应用场景中发挥巨大作用,还能适应多种操作系统,应用最为广泛的Windows、Mac OS系统自不必多说,稍显小众的Linux、树莓派、群辉等也在起支持之列&#…

小程序事件系统 —— 33 事件传参 - data-*自定义数据

事件传参:在触发事件时,将一些数据作为参数传递给事件处理函数的过程,就是事件传参; 在微信小程序中,我们经常会在组件上添加一些自定义数据,然后在事件处理函数中获取这些自定义数据,从而完成…

【Java学习】包装类

面向对象系列九 包装类变量 一、装箱 1.实例化包装对象 2.静态缓存池 3.写法 二、拆箱 包装类变量 每个基本数据类型都有对应的基本类型的包装类变量,将基本数据类型通过对应的包装类对象载入着进入到类与对象面向对象体系 一、装箱 Integer.valueOf(int) —…

中国自动化领域零部件研究报告

一、引言 1.1 研究背景与目的 随着科技的飞速发展,自动化技术已成为推动各行业转型升级的关键力量。中国自动化领域零部件行业在近年来取得了显著进展,市场规模持续扩大,技术水平不断提升。在政策支持与市场需求的双重驱动下,中…

MySQL数据集成:高效数据同步与监控

MySQL数据集成案例分享:user-钉钉部门树-名称刷新 在企业信息系统中,数据的高效流动和准确同步是确保业务连续性和决策支持的重要环节。本文将聚焦于一个具体的系统对接集成案例——将MySQL中的数据集成到另一个MySQL数据库中,方案名称为“u…

时序数据库TimescaleDB基本操作示例

好的&#xff01;以下是使用 TimescaleDB 的 Java 示例&#xff08;基于 JDBC&#xff0c;因为 TimescaleDB 是 PostgreSQL 的扩展&#xff0c;官方未提供独立的 Java SDK&#xff09;&#xff1a; 1. 添加依赖&#xff08;Maven&#xff09; <dependency><groupId&g…

【VBA】WPS/PPT设置标题字体

通过VBA&#xff0c;配合左上角的快速访问工具栏&#xff0c;实现自动化调整 选中文本框的 字体位置、大小、颜色。 配合quicker更加便捷 Sub DisableAutoWrapAndFormat()Dim shp As Shape 检查是否选中了一个形状&#xff08;文本框&#xff09;If ActiveWindow.Selection.Typ…

Qt:事件

目录 处理事件 鼠标事件 键盘事件 定时器事件 窗口事件 虽然 Qt 是跨平台的 C 开发框架&#xff0c;Qt 的很多能力其实是操作系统提供的 只不过 Qt 封装了系统的 API 事件 前面学习过信号槽&#xff1a; 用户进行的各种操作&#xff0c;就可能会产生出信号&#xff0c;可以…

3个 Vue Scoped 的核心原理

大家好&#xff0c;我是大澈&#xff01;一个喜欢结交朋友、喜欢编程技术和科技前沿的老程序员&#x1f468;&#x1f3fb;‍&#x1f4bb;&#xff0c;关注我&#xff0c;科技未来或许我能帮到你&#xff01; 先用一句话概括 Vue Scoped 的核心原理&#xff1a;Vue 的 scoped…

物联网IoT系列之MQTT协议基础知识

文章目录 物联网IoT系列之MQTT协议基础知识物联网IoT是什么&#xff1f;什么是MQTT&#xff1f;为什么说MQTT是适用于物联网的协议&#xff1f;MQTT工作原理核心组件核心机制 MQTT工作流程1. 建立连接2. 发布和订阅3. 消息确认4. 断开连接 MQTT工作流程图MQTT在物联网中的应用 …

ubuntu 20.04 C++ 源码编译 cuda版本 opencv4.5.0

前提条件是安装好了cuda和cudnn 点击下载&#xff1a; opencv_contrib4.5.0 opencv 4.5.0 解压重命名后 进入opencv目录&#xff0c;创建build目录 “CUDA_ARCH_BIN ?” 这里要根据显卡查询一下,我的cuda是11&#xff0c;显卡1650&#xff0c;所以是7.5 查询方法1&#xff1…

2025-03-07 学习记录--C/C++-PTA 习题8-5 使用函数实现字符串部分复制

合抱之木&#xff0c;生于毫末&#xff1b;九层之台&#xff0c;起于累土&#xff1b;千里之行&#xff0c;始于足下。&#x1f4aa;&#x1f3fb; 一、题目描述 ⭐️ 二、代码&#xff08;C语言&#xff09;⭐️ #include <stdio.h> #define MAXN 20void strmcpy( char…

江科大51单片机笔记【10】蜂鸣器(上)

一、蜂鸣器 1.原理 蜂鸣器是一种将电信号转换为声音信号的器件&#xff0c;常同来产生设备的按键音、报警音等提示信号蜂鸣器按驱动方式可分为有源蜂鸣器和无源蜂鸣器&#xff08;外观基本一样&#xff09;有源蜂鸣器&#xff1a;内部自带振荡源&#xff0c;将正负极接上直流…

最新版本WebContext构造函数-避坑

import org.thymeleaf.context.IWebContext; import org.thymeleaf.context.WebContext; 当你想把页面信息全部获取出来存到redis缓存中使用时&#xff0c;SpringWebContext在Spring5中报错 SpringWebContext ctx new SpringWebContext(request, response,request.getServlet…

忘记dedecms后台超级管理员账号和密码的解决方案

解决方案&#xff1a; 方案一、数据库修改&#xff1a; 1、前提是您能登录到数据库后台&#xff0c;登录MySQL数据库管理工具&#xff08;如phpMyAdmin&#xff09; 2、打开数据库中的 dede_admin 表&#xff0c;找到管理员记录&#xff0c;将 pwd 字段的值改成 f297a57a5a7…