论文 辅助笔记:t2vec train.py

news2024/10/6 14:26:22

1 train

1.1 加载training和validation数据

def train(args):
    logging.basicConfig(filename=os.path.join(args.data, "training.log"), level=logging.INFO)
    '''
    设置了日志的基本配置。
    将日志信息保存到名为 "training.log" 的文件中
    日志的级别被设置为 INFO,这意味着所有级别为 INFO 及以上的日志消息都会被记录。
    '''

    trainsrc = os.path.join(args.data, "train.src")
    traintrg = os.path.join(args.data, "train.trg")
    trainmta = os.path.join(args.data, "train.mta")
    trainData = DataLoader(trainsrc, traintrg, trainmta, args.batch, args.bucketsize)
    #使用自定义的Dataloader 加载训练数据

    print("Reading training data...")

    trainData.load(args.max_num_line)
    #从指定的源文件、目标文件和元数据文件中加载数据,并按照桶大小进行组织
    print("Allocation: {}".format(trainData.allocation))
    print("Percent: {}".format(trainData.p))

    valsrc = os.path.join(args.data, "val.src")
    valtrg = os.path.join(args.data, "val.trg")
    valmta = os.path.join(args.data, "val.mta")
    #使用自定义的Dataloader 加载测试数据


    if os.path.isfile(valsrc) and os.path.isfile(valtrg):
        valData = DataLoader(valsrc, valtrg, valmta, args.batch, args.bucketsize, True)
        print("Reading validation data...")
        valData.load()
        assert valData.size > 0, "Validation data size must be greater than 0"
        print("Loaded validation data size {}".format(valData.size))
    else:
        print("No validation data found, training without validating...")
    '''
    首先检查验证数据的文件是否存在。
    如果存在,则加载验证数据;
    否则,输出一个消息表示没有找到验证数据,并且将在没有验证的情况下进行训练
    '''

1.2 创建优化器、loss function等

## create criterion, model, optimizer
    if args.criterion_name == "NLL":
        #检查args.criterion_name是否为"NLL"

        criterion = NLLcriterion(args.vocab_size)
        lossF = lambda o, t: criterion(o, t)
        如果是,使用NLLcriterion创建一个损失函数。
    else:
        assert os.path.isfile(args.knearestvocabs),\
            "{} does not exist".format(args.knearestvocabs)
        '''
        首先,确保args.knearestvocabs指向一个存在的文件。
        如果不是,则触发断言错误。
        '''
        print("Loading vocab distance file {}...".format(args.knearestvocabs))

        with h5py.File(args.knearestvocabs, "r") as f:
            V, D = f["V"][...], f["D"][...]
            V, D = torch.LongTensor(V), torch.FloatTensor(D)
        '''
        加载args.knearestvocabs指向的文件内容
        
        V矩阵存储每个词汇的k个最近词汇的索引,而D矩阵存储与这些词汇的相应距离
        '''

        D = dist2weight(D, args.dist_decay_speed)
        #将距离矩阵逐行softmax

        if args.cuda and torch.cuda.is_available():
            V, D = V.cuda(), D.cuda()

        criterion = KLDIVcriterion(args.vocab_size)
        lossF = lambda o, t: KLDIVloss(o, t, criterion, V, D)
        '''
        使用KLDIVcriterion创建一个损失函数,并定义另一个损失函数lossF
        '''

    triplet_loss = nn.TripletMarginLoss(margin=1.0, p=2)
    '''
    定义一个Triplet loss
    测量一个锚点与一个正面样本之间的距离相对于一个负面样本的距离
    '''

1.3 创建模型

    m0 = EncoderDecoder(args.vocab_size,
                        args.embedding_size,
                        args.hidden_size,
                        args.num_layers,
                        args.dropout,
                        args.bidirectional)
    #创建EncoderDecoder

    m1 = nn.Sequential(nn.Linear(args.hidden_size, args.vocab_size),
                       nn.LogSoftmax(dim=1))
    #线性层,输入维度是args.hidden_size,输出维度是args.vocab_size
    #接着,这个线性层的输出被送入一个LogSoftmax层,用于归一化输出并取对数

    if args.cuda and torch.cuda.is_available():
        print("=> training with GPU")
        m0.cuda()
        m1.cuda()
        criterion.cuda()
        #m0 = nn.DataParallel(m0, dim=1)
    else:
        print("=> training with CPU")
    #是否放在GPU上训练

 1.4 定义优化过程

    m0_optimizer = torch.optim.Adam(m0.parameters(), lr=args.learning_rate)
    m1_optimizer = torch.optim.Adam(m1.parameters(), lr=args.learning_rate)
    #为前面定义的两个模块m0和m1各自创建了一个优化器

    ## load model state and optmizer state
    if os.path.isfile(args.checkpoint):
        print("=> loading checkpoint '{}'".format(args.checkpoint))
        logging.info("Restore training @ {}".format(time.ctime()))
        checkpoint = torch.load(args.checkpoint)
        args.start_iteration = checkpoint["iteration"]
        best_prec_loss = checkpoint["best_prec_loss"]
        m0.load_state_dict(checkpoint["m0"])
        m1.load_state_dict(checkpoint["m1"])
        m0_optimizer.load_state_dict(checkpoint["m0_optimizer"])
        m1_optimizer.load_state_dict(checkpoint["m1_optimizer"])
    else:
        print("=> no checkpoint found at '{}'".format(args.checkpoint))
        logging.info("Start training @ {}".format(time.ctime()))
        best_prec_loss = float('inf')

    '''
    首先检查args.checkpoint指定的路径是否存在检查点文件:

        如果存在,它会加载检查点,然后从中恢复模型m0、m1以及它们的优化器的状态。这对于中断后继续训练非常有用。
        
        如果不存在检查点,代码将记录开始训练的时间,并设置best_prec_loss为无穷大,表示还没有最好的损失值。
        
    '''

1.5 训练过程

    num_iteration = 67000*128 // args.batch
    print("Iteration starts at {} "
          "and will end at {}".format(args.start_iteration, num_iteration-1))
    #设定总迭代次数

    ## training
    for iteration in range(args.start_iteration, num_iteration):
        try:
            m0_optimizer.zero_grad()
            m1_optimizer.zero_grad()
            #在每次迭代开始时,都会清零之前计算的梯度。(pytorch训练三部曲1)

            ## generative loss
            gendata = trainData.getbatch_generative()
            #获取一个桶中一个batch的train、target数据
            #分别将train和val数据pad成相同的长度

            genloss = genLoss(gendata, m0, m1, lossF, args)
            '''
            对于选择的这一个batch的src、target数据
            计算经过encoder-decoder之后的输出,和ground-truth单元格 最近的 k个单元格的加权距离和
            '''

            ## discriminative loss
            disloss_cross, disloss_inner = 0, 0
            if args.use_discriminative and iteration % 10 == 0:
                a, p, n = trainData.getbatch_discriminative_cross()
                '''
                获取三个batch的数据,a、p和n[锚点(anchor)、正例(positive)和负例(negative)]
                '''
                disloss_cross = disLoss(a, p, n, m0, triplet_loss, args)
                #锚点(anchor)、正例(positive)和负例(negative)经过encoder之后的hidden state的三元组距离

                a, p, n = trainData.getbatch_discriminative_inner()
                '''
                从同一个初始数据的不同部分产生a(锚点)、p(正例)、和n(负例)
                '''
                disloss_inner = disLoss(a, p, n, m0, triplet_loss, args)
                #锚点(anchor)、正例(positive)和负例(negative)经过encoder之后的hidden state的三元组距离

            loss = genloss + args.discriminative_w * (disloss_cross + disloss_inner)
            #总的loss

            ## compute the gradients
            loss.backward()
            #梯度反向传播

            ## clip the gradients
            clip_grad_norm_(m0.parameters(), args.max_grad_norm)
            clip_grad_norm_(m1.parameters(), args.max_grad_norm)
            #并对模型的梯度进行裁剪,以防止梯度爆炸

            ## one step optimization
            m0_optimizer.step()
            m1_optimizer.step()
            #使用前面计算的梯度更新模型的参数


            ## average loss for one word
            avg_genloss = genloss.item() / gendata.trg.size(0)
            if iteration % args.print_freq == 0:
                print("Iteration: {0:}\tGenerative Loss: {1:.3f}\t"\
                      "Discriminative Cross Loss: {2:.3f}\tDiscriminative Inner Loss: {3:.3f}"\
                      .format(iteration, avg_genloss, disloss_cross, disloss_inner))
            #打印信息

            if iteration % args.save_freq == 0 and iteration > 0:
                prec_loss = validate(valData, (m0, m1), lossF, args)
                if prec_loss < best_prec_loss:
                    best_prec_loss = prec_loss
                    logging.info("Best model with loss {} at iteration {} @ {}"\
                                 .format(best_prec_loss, iteration, time.ctime()))
                    is_best = True
                else:
                    is_best = False
                print("Saving the model at iteration {} validation loss {}"\
                      .format(iteration, prec_loss))
                savecheckpoint({
                    "iteration": iteration,
                    "best_prec_loss": best_prec_loss,
                    "m0": m0.state_dict(),
                    "m1": m1.state_dict(),
                    "m0_optimizer": m0_optimizer.state_dict(),
                    "m1_optimizer": m1_optimizer.state_dict()
                }, is_best, args)    
            #保存最好的model
        except KeyboardInterrupt:
            break

 t2vec 辅助笔记:data_utils-CSDN博客

2  NLLcriterion

'''
构造负对数似然损失函数(Negative Log Likelihood, y NLL)
'''
def NLLcriterion(vocab_size):

    weight = torch.ones(vocab_size)
    #建一个大小为vocab_size的全1张量,用于为每个词汇项赋权重。

    weight[constants.PAD] = 0
    '''
    constants.PAD是指示填充(Padding)标记的索引,这行代码将其权重设置为0
    这意味着在计算损失时会忽略填充标记。
    '''

    
    criterion = nn.NLLLoss(weight, reduction='sum')
    '''
     创建NLL损失函数。
    其中reduction='sum'表示损失是所有元素的总和
    '''
    return criterion

注:确保传入NLL损失的输入已经经过了log_softmax,因为NLLLoss期望的输入是对数概率。

2.1 举例

假设词汇表由以下词汇组成

词汇表: ["<PAD>", "你好", "再见", "是", "吗"]

其中,"<PAD>"是用于填充序列的特殊标记。

因此,vocab_size是5,constants.PAD的索引是0。

现在,假设有以下批量预测输出(batch=2),每一行表示这个样本的预测结果(经过了log和softmax之后)

log_probs = [[-0.2, -1.5, -2.3, -3.1, -1.8],
             [-0.5, -1.2, -0.9, -2.5, -3.0],
            ]

同时目标标签是[1, 2](表示第一个示例的标签是“你好”,第二个是“再见”)

所以

# 创建损失函数
criterion = NLLcriterion(5)

# 示例数据
log_probs = torch.tensor([
    [-0.2, -1.5, -2.3, -3.1, -1.8],
    [-0.5, -1.2, -0.9, -2.5, -3.0],
])
targets = torch.tensor([1, 2])

# 计算损失
loss = criterion(log_probs, targets)
print(loss)
#2.4
#损失 = -(-1.5) - (-0.9) = 1.5 + 0.9 = 2.4

3 dist2weight

'''
将给定的距离矩阵转换为一个权重矩阵
'''
def dist2weight(D, dist_decay_speed=0.8):
    D = D.div(100)
    D = torch.exp(-D * dist_decay_speed)
    '''
    使用指数衰减————让距离较小的元素(距离更近的)获得更大的权重,并且让距离较大的元素获得更小的权重
    '''
    s = D.sum(dim=1, keepdim=True)
    D = D / s
    '''
    逐行手动softmax
    '''

    ## The PAD should not contribute to the decoding loss
    D[constants.PAD, :] = 0.0
    return D

4 KLDIVcriterion

'''
创建KLloss
'''
def KLDIVcriterion(vocab_size):

    criterion = nn.KLDivLoss(reduction='sum')
    
    return criterion

 5 KLDIVloss

'''
计算 KL 散度损失,但它与通常的直接比较输出和目标之间的损失有所不同。

它基于目标索引的 k-最近邻来计算损失
'''
def KLDIVloss(output, target, criterion, V, D):
    """
    output (batch, vocab_size)
    target (batch,)
    criterion (nn.KLDIVLoss)
    V (vocab_size, k) 最近的K个词汇的ID
    D (vocab_size, k) 最近的K个词汇的距离
    """

    ## (batch, k) index in vocab_size dimension
    ## k-nearest neighbors for target
    indices = torch.index_select(V, 0, target)
    '''
    target的维度也即(seq_len*generator_batch)
    也就是generator_batch个sequence 每个元素的ground-truth 单元格
    index_select就把这些单元格作为索引id给提取了出来,得到了一个 (batch, k)

    generator_batch个sequence 每个元素的最近k个邻居单元格
    '''


    ## (batch, k) gather along vocab_size dimension
    outputk = torch.gather(output, 1, indices)
    '''
    output的维度是 (batch, vocab_size)也即(seq_len*generator_batch, vocab_size)
    
    generator_batch个sequence 每个元素在vocab_size个单元格的概率

    这里只考虑最近的k个邻居单元格的概率,所以使用index_select

    得到的(seq_len*generator_batch, k)

    generator_batch个sequence 每个元素的最近k个邻居单元格的概率
    '''

    ## (batch, k) index in vocab_size dimension
    targetk = torch.index_select(D, 0, target)
    '''
    generator_batch个sequence 每个元素的最近k个邻居单元格的距离
    '''
    return criterion(outputk, targetk)

 pytorch 笔记:KLDivLoss-CSDN博客

6 genLoss

def genLoss(gendata, m0, m1, lossF, args):
    """
    One batch loss

    Input:
    gendata: a named tuple contains
        gendata.src (seq_len1, batch): input tensor
        gendata.lengths (1, batch): lengths of source sequences
        gendata.trg (seq_len2, batch): target tensor.
    m0: map input to output.
    m1: map the output of EncoderDecoder into the vocabulary space and do
        log transform.
    lossF: loss function.
    ---
    Output:
    loss
    """
    input, lengths, target = gendata.src, gendata.lengths, gendata.trg
    if args.cuda and torch.cuda.is_available():
        input, lengths, target = input.cuda(), lengths.cuda(), target.cuda()
    #从gendata中提取数据,并根据是否使用GPU进行调整
    
    ## (seq_len2, batch, hidden_size)
    output = m0(input, lengths, target)
    '''
    m0是一个encoder-decoder
    encoder输入input
    
    decoder将encoder的hidden state和target 作为输入,得到和target通常的一个输出
    '''

    batch = output.size(1)
    loss = 0

    ## we want to decode target in range [BOS+1:EOS]
    target = target[1:]

    for o, t in zip(output.split(args.generator_batch),
                    target.split(args.generator_batch)):
        '''
        !!!这里我存疑,output的维度是 (seq_len2, batch, hidden_size),target的维度是(seq_len2, batch)
        那么进行split的时候,是否需要设置dim=1?
        '''
        
        ## (seq_len2, generator_batch, hidden_size) =>
        ## (seq_len2*generator_batch, hidden_size)
        o = o.view(-1, o.size(2))
        #根据论文作者给的注释,如果第二个维度是generator_batch,那上面的split就应该有dim=1

        o = m1(o)
        # (seq_len2*generator_batch, vocab_size)

        ## (seq_len*generator_batch,)
        t = t.view(-1)

        loss += lossF(o, t)

    return loss.div(batch)
    '''
    seq_len2* generator_batch 每个元素到他最近的k个单元格的距离*在这个单元格的概率  ,这个概率距离的和
    '''

genData的格式如下 

 7 disLoss

'''
计算三元组损失
'''
def disLoss(a, p, n, m0, triplet_loss, args):
    """
    a (named tuple): anchor data
    p (named tuple): positive data
    n (named tuple): negative data
    """
    a_src, a_lengths, a_invp = a.src, a.lengths, a.invp
    p_src, p_lengths, p_invp = p.src, p.lengths, p.invp
    n_src, n_lengths, n_invp = n.src, n.lengths, n.invp
    #从命名元组中解包数据

    if args.cuda and torch.cuda.is_available():
        a_src, a_lengths, a_invp = a_src.cuda(), a_lengths.cuda(), a_invp.cuda()
        p_src, p_lengths, p_invp = p_src.cuda(), p_lengths.cuda(), p_invp.cuda()
        n_src, n_lengths, n_invp = n_src.cuda(), n_lengths.cuda(), n_invp.cuda()


    ## (num_layers * num_directions, batch, hidden_size)
    a_h, _ = m0.encoder(a_src, a_lengths)
    p_h, _ = m0.encoder(p_src, p_lengths)
    n_h, _ = m0.encoder(n_src, n_lengths)
    #从命名元组中解包数据

    ## (num_layers, batch, hidden_size * num_directions)
    a_h = m0.encoder_hn2decoder_h0(a_h)
    p_h = m0.encoder_hn2decoder_h0(p_h)
    n_h = m0.encoder_hn2decoder_h0(n_h)
    #使用函数 encoder_hn2decoder_h0 来调整每个隐藏状态的形状

    ## take the last layer as representations (batch, hidden_size * num_directions)
    a_h, p_h, n_h = a_h[-1], p_h[-1], n_h[-1]
    #使用编码器的最后一个层的输出作为数据的表示

    return triplet_loss(a_h[a_invp], p_h[p_invp], n_h[n_invp])
    #使用 triplet_loss 函数计算锚点、正样本和负样本之间的三元组损失

8 validate

def validate(valData, model, lossF, args):
    """
    valData (DataLoader)
    """
    m0, m1 = model
    ## switch to evaluation mode
    m0.eval()
    m1.eval()    
    #在评估之前将模型设置为评估模式,这样可以关闭dropout

    num_iteration = valData.size // args.batch
    if valData.size % args.batch > 0: num_iteration += 1
    #根据验证数据集的大小和批量大小计算需要的迭代次数。

    total_genloss = 0
    for iteration in range(num_iteration):
        gendata = valData.getbatch_generative()
        #获取一个batch的train、target数据
        #分别将train和val数据pad成相同的长度
        
        with torch.no_grad():
            genloss = genLoss(gendata, m0, m1, lossF, args)
            '''
            对于选择的这一个batch的src、target数据
            计算经过encoder-decoder之后的输出,和ground-truth单元格 最近的 k个单元格的加权距离和
            '''
            total_genloss += genloss.item() * gendata.trg.size(1)
    ## switch back to training mode
    m0.train()
    m1.train()
    return total_genloss / valData.size

9 保存模型

def savecheckpoint(state, is_best, args):
    torch.save(state, args.checkpoint)
    if is_best:
        shutil.copyfile(args.checkpoint, os.path.join(args.data, 'best_model.pt'))
    '''
    如果is_best为True,意味着当前的模型是最好的模型,那么它会使用shutil.copyfile函数把args.checkpoint文件复制到一个新的路径
    这个路径由args.data文件夹和文件名'best_model.pt'组成。
    这样做的目的是为了保留一个单独的最好模型的副本
    '''

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

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

相关文章

Vue动态树、配置请求路径、表格数据显示、实现分页、创建书本管理组件、点击菜单实现路由跳转以及系统首页配置。

目录 1. 准备工作 2. 动态树 2.1 在配置请求路径 2.2 使用动态数据构建导航菜单 2.2.1 通过接口获取数据 2.2.3 通过后台获取的数据构建菜单导航 2.2.3.1 先构建一级导航菜单 2.3 点击菜单实现路由跳转 2.3.1 创建书本管理组件 3. 系统首页配置 4. 表格数据显示 4.…

探密工业互联网网络体系:构建端到端的稳定传输

什么是工业互联网网络&#xff1f; 工业互联网网络是一种将工业设备、传感器和计算机系统连接到一起&#xff0c;以便它们可以共同工作、共享数据和实现更高效的生产和控制。这个网络体系的目标是提高工业过程的效率、可靠性和安全性。 在数字时代的今天&#xff0c;工业互联网…

无广告弹出的便签工具选择哪一款?

广告弹窗&#xff0c;是许多人在日常办公中比较反感的问题&#xff0c;打开一个软件正准备使用时&#xff0c;突然冒出一个广告弹窗&#xff0c;这会给人一种特别反感的情绪&#xff0c;尤其是在专注记录工作任务备忘的时候&#xff0c;意外冒出的广告窗口可真让人心烦。那么&a…

Apple 苹果发布 M3、M3 Pro 和 M3 Max 芯片

本心、输入输出、结果 文章目录 Apple 苹果发布 M3、M3 Pro 和 M3 Max 芯片前言M3、M3 Pro 和 M3 Max 芯片的性能相关资料图M3 Pro规格M3 Max规格弘扬爱国精神 Apple 苹果发布 M3、M3 Pro 和 M3 Max 芯片 编辑&#xff1a;简简单单 Online zuozuo 地址&#xff1a;https://blog…

若依框架中SpringSecurity的实现流程

文章目录 Spring Security概述核心原理 若依Sprint Security分析配置类分析流程分析图过滤器分析 若依登录/退出流程流程图登录退出 写在开头: 本篇博客与核桃共同完成 Spring Security 概述 Spring Security 是一个功能强大且高度可定制的身份验证和访问控制框架&#xff0c…

go微信开发sdk-简单使用_已设置图床

go微信开发sdk-简单使用 GitHub - silenceper/wechat: WeChat SDK for Go &#xff08;微信SDK&#xff1a;简单、易用&#xff09; 使用的sdk为上述的&#xff0c;这边给出快速的项目实例 git clone https://github.com/gowechat/example.git简单的项目结构 这边简单用dock…

多线程锁的升级原理是什么

在 Java 中&#xff0c;锁共有 4 种状态&#xff0c;级别从低到高依次为&#xff1a;无状态锁&#xff0c;偏向锁&#xff0c;轻量级锁和重量级锁状态&#xff0c;这几个状态会随着竞争情况逐渐升级。锁可以升级但不能降级。 多线程锁锁升级过程 如下图所示 多线程锁的升级过程…

数字孪生技术:城市交通的智能引领

城市交通问题一直是我们日常生活中的头等大事。交通拥堵、公共交通不便、环境污染等问题常常困扰着城市居民。然而&#xff0c;数字孪生技术正以令人兴奋的方式改变着城市交通的面貌&#xff0c;为城市交通带来了新的变化。 实时交通监测&#xff1a;数字孪生技术通过网络连接的…

动态规划:“以宇换宙”的优雅工艺

Those who do not remember the past are condemned to repeat it. 那些不能铭记历史的人注定要重蹈覆辙。 在动态规划——经典案例分析中我们提到了斐波那契数列的求解思路。知道动态规划的主要优点是能够在解决问题时避免重复计算&#xff0c;通过利用已经计算过的结果来加速…

Java实现Web的ashx对接ORM

之前的介绍已经实现了ORM的主体和Web的调用结构主题&#xff0c;那么这次把Web和LIS.Core的容器和ORM做对接&#xff0c;通过ashx实现的业务类测试调用ORM查询数据。 首先改造容器让传入根地址 package LIS.Core.Context;import org.w3c.dom.Document; import org.w3c.dom.El…

单例模式-懒汉式双重锁机制

正是因为担心并发问题&#xff0c;才在双重检查锁模式中的synchronized内部进行了再次判断 tnull。 在第一次判断 tnull 之后&#xff0c;当多个线程同时通过这个检查&#xff0c;其中一个线程会获得锁并创建实例。然而&#xff0c;其他线程在此期间可能会继续等待锁释放&…

ViT Vision Transformer超详细解析,网络构建,可视化,数据预处理,全流程实例教程

关于ViT的分析和教程&#xff0c;网上又虚又空的东西比较多&#xff0c;本文通过一个实例&#xff0c;将ViT全解析。 包括三部分内容&#xff0c;网络构建&#xff1b;orchview.draw_graph 将网络每一层的结构与输入输出可视化&#xff1b;数据预处理。附完整代码 网络构建 …

【Code Reading】Transformer in vision and video

文章目录 1. vit2. Swin-t3. vit_3D4. TimeSformer First&#x1f680;&#x1f680;5. vivit 1. vit 详细解释 在论文的Table1中有给出三个模型&#xff08;Base/ Large/ Huge&#xff09;的参数&#xff0c;在源码中除了有Patch Size为16x16的外还有32x32的。其中的Layers就…

基于MIMO通信系统的球形译码算法matlab性能仿真,对比PSK检测,SDR检测

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 2.算法运行软件版本 MATLAB2022A 3.部分核心程序 ................................................................ for i1:length(SNR) Bit…

SpringCloud(六) Nacos配置管理

Nacos除了可以做注册中心,同样可以做配置管理来使用; Nacos做注册中心的使用和注意事项详看:SpringCloud(四) Nacos注册中心-CSDN博客 目录 一, 统一配置管理 1. 在Nacos中添加配置文件 2. 从微服务拉取配置 (1) 引入nacos-config依赖 (2) 添加bootstrap.yaml (3) 读取n…

相机存储卡被格式化了怎么恢复?数据恢复办法分享!

随着时代的发展&#xff0c;相机被越来越多的用户所使用&#xff0c;这也意味着更多的用户面临着相机数据丢失的问题&#xff0c;很多用户在使用相机的过程中&#xff0c;都出现过不小心格式化相机存储卡的情况&#xff0c;里面的数据也将一并消失&#xff0c;相机存储卡被格式…

Android13充电动画实现

充电动画 以MTK平台为例&#xff0c;实现充电动画 效果图 修改文件清单 system/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/systemui/charging/BubbleBean.javasystem/vendor/mediatek/proprietary/packages/apps/SystemUI/src/com/android/system…

2023年【道路运输企业安全生产管理人员】考试资料及道路运输企业安全生产管理人员考试技巧

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 道路运输企业安全生产管理人员考试资料根据新道路运输企业安全生产管理人员考试大纲要求&#xff0c;安全生产模拟考试一点通将道路运输企业安全生产管理人员模拟考试试题进行汇编&#xff0c;组成一套道路运输企业安…

浅谈新能源汽车充电桩的选型与安装

叶根胜 安科瑞电气股份有限公司 上海嘉定201801 摘要&#xff1a;电动汽车的大力发展和推广是国家为应对日益突出的燃油供需矛盾和环境污染&#xff0c;加强生态环境保护和治理而开发新能源和清洁能源的措施之一&#xff0c;加快了电动汽车的发展。如今&#xff0c;电动汽车已…

Pure-Pursuit 跟踪双移线 Gazebo 仿真

Pure-Pursuit 跟踪双移线 Gazebo 仿真 主要参考学习下面的博客和开源项目 自动驾驶规划控制&#xff08;&#xff21;*、pure pursuit、LQR算法&#xff0c;使用c在ubuntu和ros环境下实现&#xff09; https://github.com/NeXTzhao/planning Pure-Pursuit 的理论基础见今年六月…