深度学习—BP算法梯度下降及优化方法Day37

梯度下降

1.公式

w i j n e w = w i j o l d − α ∂ E ∂ w i j w_{ij}^{new}= w_{ij}^{old} - \alpha \frac{\partial E}{\partial w_{ij}} wijnew=wijoldαwijE
α为学习率
在这里插入图片描述
当α过小时,训练时间过久增加算力成本,α过大则容易造成越过最优解导致震荡。

2.梯度下降过程

1.初始化参数:权重:W,偏置:b
2.求梯度:利用损失函数求出权重W的导数。
3.参数更新:按照梯度下降公式求出新的W。
4.循环迭代:按照设定的条件或次数循环更新W。

3.常见梯度下降方法

3.1批量梯度下降

Batch Gradient Descent BGD

  • 特点

    • 每次更新参数时,使用整个训练集来计算梯度。
  • 优点

    • 收敛稳定,能准确地沿着损失函数的真实梯度方向下降。
    • 适用于小型数据集。
  • 缺点

    • 对于大型数据集,计算量巨大,更新速度慢。
    • 需要大量内存来存储整个数据集。
  • 公式
    θ : = θ − α 1 m ∑ i = 1 m ∇ θ L ( θ ; x ( i ) , y ( i ) ) \theta := \theta - \alpha \frac{1}{m} \sum_{i=1}^{m} \nabla_\theta L(\theta; x^{(i)}, y^{(i)}) θ:=θαm1i=1mθL(θ;x(i),y(i))
    其中, m m m 是训练集样本总数,$x^{(i)}, y^{(i)} $是第 i i i 个样本及其标签。

3.2随机梯度下降

Stochastic Gradient Descent, SGD

  • 特点

    • 每次更新参数时,仅使用一个样本来计算梯度。
  • 优点

    • 更新频率高,计算快,适合大规模数据集。
    • 能够跳出局部最小值,有助于找到全局最优解。
  • 缺点

    • 收敛不稳定,容易震荡,因为每个样本的梯度可能都不完全代表整体方向。
    • 需要较小的学习率来缓解震荡。
  • 公式
    θ : = θ − α ∇ θ L ( θ ; x ( i ) , y ( i ) ) \theta := \theta - \alpha \nabla_\theta L(\theta; x^{(i)}, y^{(i)}) θ:=θαθL(θ;x(i),y(i))

3.3小批量梯度下降

Mini-batch Gradient Descent MGBD

  • 特点

    • 每次更新参数时,使用一小部分训练集(小批量)来计算梯度。
  • 优点

    • 在计算效率和收敛稳定性之间取得平衡。
    • 能够利用向量化加速计算,适合现代硬件(如GPU)。
  • 缺点

    • 选择适当的批量大小比较困难;批量太小则接近SGD,批量太大则接近批量梯度下降。
    • 通常会根据硬件算力设置为32\64\128\256等2的次方。
  • 公式
    θ : = θ − α 1 b ∑ i = 1 b ∇ θ L ( θ ; x ( i ) , y ( i ) ) \theta := \theta - \alpha \frac{1}{b} \sum_{i=1}^{b} \nabla_\theta L(\theta; x^{(i)}, y^{(i)}) θ:=θαb1i=1bθL(θ;x(i),y(i))
    其中, b b b 是小批量的样本数量,也就是 b a t c h _ s i z e batch\_size batch_size
    其中, x ( i ) , y ( i ) x^{(i)}, y^{(i)} x(i),y(i) 是当前随机抽取的样本及其标签。

4.存在问题

在这里插入图片描述

  • 收敛速度慢:BGD和MBGD使用固定学习率,太大会导致震荡,太小又收敛缓慢。

  • 局部最小值和鞍点问题:SGD在遇到局部最小值或鞍点时容易停滞,导致模型难以达到全局最优。

  • 训练不稳定:SGD中的噪声容易导致训练过程中不稳定,使得训练陷入震荡或不收敛。

5.优化方法

5.1指数加权平均数

在这里插入图片描述
其中:

  • St 表示指数加权平均值(EMA);
  • Yt 表示 t 时刻的值;
  • β \beta β 是平滑系数,取值范围为 0 ≤ β < 1 0\leq \beta < 1 0β<1 β \beta β 越接近 1 1 1,表示对历史数据依赖性越高;越接近 0 0 0 则越依赖当前数据。该值越大平均数越平缓
import numpy as np
import matplotlib.pyplot as plt



def test01():
    np.random.seed(666)
    y = np.random.randint(5,40,30)
    print(y)
    x = np.arange(30)
    plt.plot(x,y,color='b')
    plt.scatter(x,y,color='r')
    plt.show()

def test02(beta = 0.9):
    np.random.seed(666)
    y = np.random.randint(5,40,30)
    print(y)
    x = np.arange(30)
    y_e = []
    for i in range(30):
        if i == 0:
            y_e.append(y[0])
        else:
            st = beta*y_e[-1]+(1-beta)*y[i]
            y_e.append(st)
    plt.plot(x,np.array(y_e),color='b')
    plt.scatter(x,y,color='r')
    plt.show()


if __name__ == '__main__':
    test01()
    test02()


在这里插入图片描述
在这里插入图片描述

5.2Momentum

Momentum 的基本思想
在传统的梯度下降法中,参数的更新仅依赖于当前的梯度方向。Momentum 方法通过引入一个累积的动量来加速参数的更新。具体来说,Momentum 方法在参数更新时不仅考虑当前的梯度方向,还考虑了过去梯度的方向。

  • 惯性效应: 该方法加入前面梯度的累积,这种惯性使得算法沿着当前的方向继续更新。如遇到鞍点,也不会因梯度逼近零而停滞。
  • 减少震荡: 该方法平滑了梯度更新,减少在鞍点附近的震荡,帮助优化过程稳定向前推进。
  • 加速收敛: 该方法在优化过程中持续沿着某个方向前进,能够更快地穿越鞍点区域,避免在鞍点附近长时间停留。

梯度计算公式:
D t = β ∗ S t − 1 + ( 1 − β ) ∗ D t Dt = β * S_{t-1} + (1- β) * Dt Dt=βSt1+(1β)Dt

  1. S t − 1 S_{t-1} St1 表示历史梯度移动加权平均值
  2. Dt 表示当前时刻的梯度值
  3. β 为权重系数

Momentum 算法是对梯度值的平滑调整,但是并没有对梯度下降中的学习率进行优化。

import torch


# 1.创建一个神经网络:继承官方的nn.Module
class mynet(torch.nn.Module):
    # 2.定义网络结构
    def __init__(self, input_size, output_size):
        # 3.初始化父类:python语法要求调用super方法生成父类的功能让子类对象去继承
        super(mynet, self).__init__()
        # 4.定义网络结构
        self.hide1 = torch.nn.Sequential(torch.nn.Linear(input_size, 3), torch.nn.Sigmoid())
        self.hide2 = torch.nn.Sequential(torch.nn.Linear(3, 2), torch.nn.Sigmoid())
        self.hide3 = torch.nn.Sequential(torch.nn.Linear(2, 12), torch.nn.Sigmoid())
        self.out = torch.nn.Sequential(torch.nn.Linear(12, output_size), torch.nn.Sigmoid())

    def forward(self, input):
        # input.shape[1]
        x = self.hide1(input)
        x = self.hide2(x)
        x = self.hide3(x)
        pred = self.out(x)
        return pred


def train():
    # 数据集
    input = torch.tensor([[0.5, 0.1],
                          [0.05, 0.180],
                          [0.05, 0.310]])
    target = torch.tensor([[1, 2],
                           [0, 3],
                           [1, 123]], dtype=torch.float32)

    # 5.创建网络
    net = mynet(2, 2)
    # 6.定义损失函数
    loss_func = torch.nn.MSELoss()
    # 7.定义优化器
    optimizer = torch.optim.SGD(net.parameters(), lr=0.1,momentum=0.6)
    # 8.训练
    for epoch in range(100):
        # 9.前向传播
        y_pred = net(input)
        # 10.计算损失
        loss = loss_func(y_pred, target)
        # 11.梯度清零
        optimizer.zero_grad()
        # 12.反向传播(计算每一层的w的梯度值)
        loss.backward()
        # print(net.hide1[0].weight.data)
        # 13.梯度更新
        optimizer.step()  # w = w -lr*当前的移动指数加权平均(s = momentum*s + (1-momentum)*w.grad
        print(loss)

if __name__ == '__main__':
    train()

5.3AdaGrad

AdaGrad(Adaptive Gradient Algorithm)为每个参数引入独立的学习率,它根据历史梯度的平方和来调整这些学习率,这样就使得参数具有较大的历史梯度的学习率减小,而参数具有较小的历史梯度的学习率保持较大,从而实现更有效的学习。AdaGrad避免了统一学习率的不足,更多用于处理稀疏数据和梯度变化较大的问题。

AdaGrad流程:

  1. 初始化学习率 α、初始化参数 θ、小常数 σ = 1e-6

  2. 初始化梯度累积变量 s = 0

  3. 从训练集中采样 m 个样本的小批量,计算梯度 g

  4. 累积平方梯度 s = s + g ⊙ g,⊙ 表示各个分量相乘

  5. 学习率 α 的计算公式如下:在这里插入图片描述

  6. 参数更新公式如下:在这里插入图片描述

其中:

  • α \alpha α 是全局的初始学习率。

  • $ \sigma$ 是一个非常小的常数,用于避免除零操作(通常取$ 10^{-8}$)。

  • $ \frac{\alpha}{\sqrt{s }+\sigma} $ 是自适应调整后的学习率。

import torch


# 1.创建一个神经网络:继承官方的nn.Module
class mynet(torch.nn.Module):
    # 2.定义网络结构
    def __init__(self, input_size, output_size):
        # 3.初始化父类:python语法要求调用super方法生成父类的功能让子类对象去继承
        super(mynet, self).__init__()
        # 4.定义网络结构
        self.hide1 = torch.nn.Sequential(torch.nn.Linear(input_size, 3), torch.nn.Sigmoid())
        self.hide2 = torch.nn.Sequential(torch.nn.Linear(3, 2), torch.nn.Sigmoid())
        self.hide3 = torch.nn.Sequential(torch.nn.Linear(2, 12), torch.nn.Sigmoid())
        self.out = torch.nn.Sequential(torch.nn.Linear(12, output_size), torch.nn.Sigmoid())

    def forward(self, input):
        # input.shape[1]
        x = self.hide1(input)
        x = self.hide2(x)
        x = self.hide3(x)
        pred = self.out(x)
        return pred


def train():
    # 数据集
    input = torch.tensor([[0.5, 0.1],
                          [0.05, 0.180],
                          [0.05, 0.310]])
    target = torch.tensor([[1, 2],
                           [0, 3],
                           [1, 123]], dtype=torch.float32)

    # 5.创建网络
    net = mynet(2, 2)
    # 6.定义损失函数
    loss_func = torch.nn.MSELoss()
    # 7.定义优化器
    optimizer = torch.optim.Adagrad(net.parameters(), lr=0.1)
    # 8.训练
    for epoch in range(100):
        # 9.前向传播
        y_pred = net(input)
        # 10.计算损失
        loss = loss_func(y_pred, target)
        # 11.梯度清零
        optimizer.zero_grad()
        # 12.反向传播(计算每一层的w的梯度值)
        loss.backward()
        # print(net.hide1[0].weight.data)
        # 13.梯度更新
        optimizer.step()  # w = w -lr*当前的移动指数加权平均(s = momentum*s + (1-momentum)*w.grad
        print(loss)

if __name__ == '__main__':
    train()

5.4RMSProp

RMSProp(Root Mean Square Propagation)在时间步中,不是简单地累积所有梯度平方和,而是使用指数加权平均来逐步衰减过时的梯度信息。这种方法专门用于解决AdaGrad在训练过程中学习率过度衰减的问题。

RMSProp过程

  1. 初始化学习率 α、初始化参数 θ、小常数 σ = 1e-8( 用于防止除零操作(通常取 1 0 − 8 10^{-8} 108))。

  2. 初始化参数 θ

  3. 初始化梯度累计变量 s=0

  4. 从训练集中采样 m 个样本的小批量,计算梯度 g

  5. 使用指数移动平均累积历史梯度,公式如下:在这里插入图片描述

  6. 学习率 α 的计算公式如下:在这里插入图片描述

  7. 参数更新公式如下:在这里插入图片描述

优点

  • 适应性强:RMSProp自适应调整每个参数的学习率,对于梯度变化较大的情况非常有效,使得优化过程更加平稳。

  • 适合非稀疏数据:相比于AdaGrad,RMSProp更加适合处理非稀疏数据,因为它不会让学习率减小到几乎为零。

  • 解决过度衰减问题:通过引入指数加权平均,RMSProp避免了AdaGrad中学习率过快衰减的问题,保持了学习率的稳定性

缺点

依赖于超参数的选择:RMSProp的效果对衰减率 $ \beta$ 和学习率 $ \alpha$ 的选择比较敏感,需要一些调参工作。

需要注意的是:AdaGrad 和 RMSProp 都是对于不同的参数分量使用不同的学习率,如果某个参数分量的梯度值较大,则对应的学习率就会较小,如果某个参数分量的梯度较小,则对应的学习率就会较大一些。

import torch


# 1.创建一个神经网络:继承官方的nn.Module
class mynet(torch.nn.Module):
    # 2.定义网络结构
    def __init__(self, input_size, output_size):
        # 3.初始化父类:python语法要求调用super方法生成父类的功能让子类对象去继承
        super(mynet, self).__init__()
        # 4.定义网络结构
        self.hide1 = torch.nn.Sequential(torch.nn.Linear(input_size, 3), torch.nn.Sigmoid())
        self.hide2 = torch.nn.Sequential(torch.nn.Linear(3, 2), torch.nn.Sigmoid())
        self.hide3 = torch.nn.Sequential(torch.nn.Linear(2, 12), torch.nn.Sigmoid())
        self.out = torch.nn.Sequential(torch.nn.Linear(12, output_size), torch.nn.Sigmoid())

    def forward(self, input):
        # input.shape[1]
        x = self.hide1(input)
        x = self.hide2(x)
        x = self.hide3(x)
        pred = self.out(x)
        return pred


def train():
    # 数据集
    input = torch.tensor([[0.5, 0.1],
                          [0.05, 0.180],
                          [0.05, 0.310]])
    target = torch.tensor([[1, 2],
                           [0, 3],
                           [1, 123]], dtype=torch.float32)

    # 5.创建网络
    net = mynet(2, 2)
    # 6.定义损失函数
    loss_func = torch.nn.MSELoss()
    # 7.定义优化器
    optimizer = torch.optim.RMSprop(net.parameters(), lr=0.01,momentum=0.8)
    # 8.训练
    for epoch in range(100):
        # 9.前向传播
        y_pred = net(input)
        # 10.计算损失
        loss = loss_func(y_pred, target)
        # 11.梯度清零
        optimizer.zero_grad()
        # 12.反向传播(计算每一层的w的梯度值)
        loss.backward()
        # print(net.hide1[0].weight.data)
        # 13.梯度更新
        optimizer.step()  # w = w -lr*当前的移动指数加权平均(s = momentum*s + (1-momentum)*w.grad
        print(loss)

if __name__ == '__main__':
    train()

5.5Adam

Adam(Adaptive Moment Estimation)算法将动量法和RMSProp的优点结合在一起:

  • 动量法:通过一阶动量(即梯度的指数加权平均)来加速收敛,尤其是在有噪声或梯度稀疏的情况下。
  • RMSProp:通过二阶动量(即梯度平方的指数加权平均)来调整学习率,使得每个参数的学习率适应其梯度的变化。
  • Momentum 使用指数加权平均计算当前的梯度值、AdaGrad、RMSProp 使用自适应的学习率,Adam 结合了 Momentum、RMSProp 的优点,使用:移动加权平均的梯度和移动加权平均的学习率。使得能够自适应学习率的同时,也能够使用 Momentum 的优点。

优点

  1. 高效稳健:Adam结合了动量法和RMSProp的优势,在处理非静态、稀疏梯度和噪声数据时表现出色,能够快速稳定地收敛。

  2. 自适应学习率:Adam通过一阶和二阶动量的估计,自适应调整每个参数的学习率,避免了全局学习率设定不合适的问题。

  3. 适用大多数问题:Adam几乎可以在不调整超参数的情况下应用于各种深度学习模型,表现良好。

缺点

  1. 超参数敏感:尽管Adam通常能很好地工作,但它对初始超参数(如 $ \beta_1 、 、 \beta_2$ 和 η \eta η)仍然较为敏感,有时需要仔细调参。
  2. 过拟合风险:由于Adam会在初始阶段快速收敛,可能导致模型陷入局部最优甚至过拟合。因此,有时会结合其他优化算法(如SGD)使用。
import torch


# 1.创建一个神经网络:继承官方的nn.Module
class mynet(torch.nn.Module):
    # 2.定义网络结构
    def __init__(self, input_size, output_size):
        # 3.初始化父类:python语法要求调用super方法生成父类的功能让子类对象去继承
        super(mynet, self).__init__()
        # 4.定义网络结构
        self.hide1 = torch.nn.Sequential(torch.nn.Linear(input_size, 3), torch.nn.Sigmoid())
        self.hide2 = torch.nn.Sequential(torch.nn.Linear(3, 2), torch.nn.Sigmoid())
        self.hide3 = torch.nn.Sequential(torch.nn.Linear(2, 12), torch.nn.Sigmoid())
        self.out = torch.nn.Sequential(torch.nn.Linear(12, output_size), torch.nn.Sigmoid())

    def forward(self, input):
        # input.shape[1]
        x = self.hide1(input)
        x = self.hide2(x)
        x = self.hide3(x)
        pred = self.out(x)
        return pred


def train():
    # 数据集
    input = torch.tensor([[0.5, 0.1],
                          [0.05, 0.180],
                          [0.05, 0.310]])
    target = torch.tensor([[1, 2],
                           [0, 3],
                           [1, 123]], dtype=torch.float32)

    # 5.创建网络
    net = mynet(2, 2)
    # 6.定义损失函数
    loss_func = torch.nn.MSELoss()
    # 7.定义优化器
    optimizer = torch.optim.Adam(net.parameters(), lr=0.1)
    # 8.训练
    for epoch in range(100):
        # 9.前向传播
        y_pred = net(input)
        # 10.计算损失
        loss = loss_func(y_pred, target)
        # 11.梯度清零
        optimizer.zero_grad()
        # 12.反向传播(计算每一层的w的梯度值)
        loss.backward()
        # print(net.hide1[0].weight.data)
        # 13.梯度更新
        optimizer.step()  # w = w -lr*当前的移动指数加权平均(s = momentum*s + (1-momentum)*w.grad
        print(loss)

if __name__ == '__main__':
    train()

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

wp the_posts_pagination 与分类页面搭配使用

<ul> <?php while( have_posts() ) : the_post(); <li > <a href"<?php the_permalink(); ?>"> <?php xizhitbu_get_thumbnail(thumb-pro); ?> </a> <p > <a href&q…

深度学习-49-AI应用实战之基于HyperLPR的车牌识别

文章目录 1 车牌识别系统1.1 识别原理1.1.1 车牌定位1.1.2 字符识别2 实例应用2.1 安装hyperlpr32.2 识别结果2.3 可视化显示2.4 结合streamlit3 附录3.1 PIL.Image转换成OpenCV格式3.2 OpenCV转换成PIL.Image格式3.3 st.image嵌入图像内容3.4 参考附录1 车牌识别系统 车牌识别…

ShuffleNet V2:高效卷积神经网络架构设计的实用指南

摘要 https://arxiv.org/pdf/1807.11164 当前&#xff0c;神经网络架构设计大多以计算复杂度的间接指标&#xff0c;即浮点运算数&#xff08;FLOPs&#xff09;为指导。然而&#xff0c;直接指标&#xff08;例如速度&#xff09;还取决于其他因素&#xff0c;如内存访问成本…

在C#中使用OpenCV的.net包装器EmguCV

Emgu.CV OpenCvSharp 两个库都是OpenCV的C#封装。这里不讨论优劣&#xff0c;两个都有相应的用途。 下载安装4.6.0.5131&#xff0c;执行文件exe https://sourceforge.net/projects/emgucv/files/emgucv/4.6.0/ 安装到一个目录下&#xff0c;这里安装到H:\Emgu\ 目录下。…

HarmonyOS:@Provide装饰器和@Consume装饰器:与后代组件双向同步

一、前言 Provide和Consume&#xff0c;应用于与后代组件的双向数据同步&#xff0c;应用于状态数据在多个层级之间传递的场景。不同于上文提到的父子组件之间通过命名参数机制传递&#xff0c;Provide和Consume摆脱参数传递机制的束缚&#xff0c;实现跨层级传递。 其中Provi…

webrtc 3A移植以及实时处理

文章目录 前言一、交叉编译1.Pulse Audio webrtc-audio-processing2.交叉编译 二、基于alsa进行实时3A处理1.demo源码2.注意项3.效果展示 总结 前言 由于工作需要&#xff0c;硬件3A中的AEC效果实在太差&#xff0c;后面使用SpeexDSP的软3A&#xff0c;效果依旧不是很好&#…

Java 反射(Reflection)

Java 反射&#xff08;Reflection&#xff09; Java 反射&#xff08;Reflection&#xff09;是一个强大的特性&#xff0c;它允许程序在运行时查询、访问和修改类、接口、字段和方法的信息。反射提供了一种动态地操作类的能力&#xff0c;这在很多框架和库中被广泛使用&#…

深入浅出剖析典型文生图产品Midjourney

2022年7月,一个小团队推出了公测的 Midjourney,打破了 AIGC 领域的大厂垄断。作为一个精调生成模型,以聊天机器人方式部署在 Discord,它创作的《太空歌剧院》作品,甚至获得了美国「数字艺术/数码摄影」竞赛单元一等奖。 这一事件展示了 AI 在绘画领域惊人的创造力,让人们…

【Linux】磁盘 | 文件系统 | inode

&#x1fa90;&#x1fa90;&#x1fa90;欢迎来到程序员餐厅&#x1f4ab;&#x1f4ab;&#x1f4ab; 主厨&#xff1a;邪王真眼 主厨的主页&#xff1a;Chef‘s blog 所属专栏&#xff1a;青果大战linux 总有光环在陨落&#xff0c;总有新星在闪烁 模电好难啊&#xff…

PHP 去掉特殊不可见字符 “\u200e“

描述 最近在排查网站业务时&#xff0c;发现有数据匹配失败的情况 肉眼上完全看不出问题所在 当把字符串 【M24308/23-14F‎】复制出来发现 末尾有个不可见的字符 使用删除键或左右移动时才会发现 最后测试通过 var_dump 打印 发现这个"空字符"占了三个长度 &#xf…

【C#设计模式(15)——命令模式(Command Pattern)】

前言 命令模式的关键通过将请求封装成一个对象&#xff0c;使命令的发送者和接收者解耦。这种方式能更方便地添加新的命令&#xff0c;如执行命令的排队、延迟、撤销和重做等操作。 代码 #region 基础的命令模式 //命令&#xff08;抽象类&#xff09; public abstract class …

使用zabbix监控k8s

一、 参考文献 小阿轩yx-案例&#xff1a;Zabbix监控kubernetes云原生环境 手把手教你实现zabbix对Kubernetes的监控 二、部署经验 关于zabbix监控k8s&#xff0c;总体来说是分为两块内容&#xff0c;一是在k8s集群部署zabbix-agent和zabbix- proxy。二是在zabbix进行配置。…

ThingsBoard规则链节点:GCP Pub/Sub 节点详解

目录 引言 1. GCP Pub/Sub 节点简介 2. 节点配置 2.1 基本配置示例 3. 使用场景 3.1 数据传输 3.2 数据分析 3.3 事件通知 3.4 任务调度 4. 实际项目中的应用 4.1 项目背景 4.2 项目需求 4.3 实现步骤 5. 总结 引言 ThingsBoard 是一个开源的物联网平台&#xff0…

10.机器学习--集成学习

机器学习领域有一个强大的思路&#xff1a;集成学习&#xff0c;该方法在诸多机器学习竞赛中往往能够获得最优的结果。集成学习的基本思想实际上非常简单&#xff1a;三个臭皮匠顶一个诸葛亮&#xff0c;即将多个模型组合在一起获得的效果往往要强于单一模型。 目录 集成学习…

结构体详解+代码展示

系列文章目录 &#x1f388; &#x1f388; 我的CSDN主页:OTWOL的主页&#xff0c;欢迎&#xff01;&#xff01;&#xff01;&#x1f44b;&#x1f3fc;&#x1f44b;&#x1f3fc; &#x1f389;&#x1f389;我的C语言初阶合集&#xff1a;C语言初阶合集&#xff0c;希望能…

深度解析猎板 PCB树脂塞孔工艺

PCB 的树脂塞孔工艺是一种在印制电路板制造过程中广泛应用的重要技术&#xff0c;以下是猎板PCB批量工厂对PCB树脂塞孔该工艺的详细介绍&#xff1a; 猎板 PCB树脂塞孔工艺目的 防止短路&#xff1a;在 PCB 制造中&#xff0c;若过孔未被有效封堵&#xff0c;锡膏可能会从孔内…

扫雷-完整源码(C语言实现)

云边有个稻草人-CSDN博客 在学完C语言函数之后&#xff0c;我们就有能力去实现简易版扫雷游戏了&#xff08;成就感满满&#xff09;&#xff0c;下面是扫雷游戏的源码&#xff0c;快试一试效果如何吧&#xff01; 在test.c里面进行扫雷游戏的测试&#xff0c;game.h和game.c…

当前就业形势下C++方向后端开发学习指南

文章目录 1. C后端开发的职业方向1.1 C的应用领域1.2 后端开发的职业选择 2. 当前就业形势分析2.1 C开发者的市场需求2.2 C开发者的薪资水平 3. 学习路线3.1 入门阶段&#xff1a;掌握基础知识3.2 进阶阶段&#xff1a;掌握后端开发的核心技术3.2.1 数据库与C3.2.2 网络编程 3.…

FFmpeg 简介与编译

1. ffmpeg 简介&#xff1a; FFmpeg是一套可以用来记录、转换数字音频、视频&#xff0c;并能将其转化为流的开源计算机程序。采用LGPL或GPL许可证。它提供了录制、转换以及流化音视频的完整解决方案。它包含了非常先进的音频/视频编解码库libavcodec&#xff0c;为了保证高可移…

【论文复现】BERT论文解读及情感分类实战

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ BERT论文解读及情感分类实战 简介BERT文章主要贡献BERT模型架构技术细节任务1 Masked LM&#xff08;MLM&#xff09;任务2 Next Sentence P…