第十四周学习周报

news2024/9/29 23:50:13

目录

    • 摘要
    • Abstract
    • 1. LSTM的代码实现
    • 2. 序列到序列模型
    • 3. 梯度与方向导数
    • 总结

摘要

在上周的学习基础之上,本周学习的内容有LSTM的代码实现,通过对代码的学习进一步加深了对LSTM的理解。为了切入到transformer的学习,本文通过对一些应用例子的分析,阐述了什么是序列到序列(Seq2Seq)模型。序列到序列模型用于将一个序列(如文本,时间序列数据)转换为另一个序列。这种模型广泛应用于自然语言处理领域,特别是在机器翻译、文本摘要、对话系统和语音识别等任务中。序列到序列模型通常由Encoder和Decoder两部分组成。除此本周还回顾了梯度与方向导数的相关问题与数学推导。

Abstract

On the basis of last week’s learning,this week’s learning content includes the code implementation of LSTM, which further deepens the understanding of LSTM through the study of the code. In order to delve into the learning of transformers, this article explains what sequence to sequence (Seq2Seq) model is through the analysis of some application examples.The sequence to sequence model is used to transform a sequence (such as text, time series data) into another sequence. This model is widely used in the field of natural language processing, especially in tasks such as machine translation, text summarization, dialogue systems, and speech recognition. The sequence to sequence model usually consists of two parts: Encoder and Decoder. In addition, this week we also reviewed the related issues and mathematical derivations of gradients and directional derivatives.

1. LSTM的代码实现

在上周对LSTM的学习基础之上,本周通过对LSTM代码的学习进一步加深对LSTM的理解
(1)激活函数的实现
在LSTM中用到的激活函数为sigmoid()和tanh(),代码实现过程如下;

class SigmoidActivator(object):
    def forward(self, weighted_input):
        return 1.0 / (1.0 + np.exp(-weighted_input))

    def backward(self, output):
        return output * (1 - output)


class TanhActivator(object):
    def forward(self, weighted_input):
        return 2.0 / (1.0 + np.exp(-2 * weighted_input)) - 1.0

    def backward(self, output):
        return 1 - output * output

(2)LSTM的初始化
在构造函数的初始化中,只初始化了与forward计算相关的变量,与backward相关的变量没有初始化。这是因为构造LSTM对象的时候,我们还不知道它未来是用于训练(既有forward又有backward)还是推理(只有forward)。代码实现过程如下:

class LstmLayer(object):
    def __init__(self, input_width, state_width,
                 learning_rate):
        self.input_width = input_width
        self.state_width = state_width
        self.learning_rate = learning_rate
        # 门的激活函数
        self.gate_activator = SigmoidActivator()
        # 输出的激活函数
        self.output_activator = TanhActivator()
        # 当前时刻初始化为t0
        self.times = 0
        # 各个时刻的单元状态向量c
        self.c_list = self.init_state_vec()
        # 各个时刻的输出向量h
        self.h_list = self.init_state_vec()
        # 各个时刻的遗忘门f
        self.f_list = self.init_state_vec()
        # 各个时刻的输入门i
        self.i_list = self.init_state_vec()
        # 各个时刻的输出门o
        self.o_list = self.init_state_vec()
        # 各个时刻的即时状态c~
        self.ct_list = self.init_state_vec()
        # 遗忘门权重矩阵Wfh, Wfx, 偏置项bf
        self.Wfh, self.Wfx, self.bf = (
            self.init_weight_mat())
        # 输入门权重矩阵Wfh, Wfx, 偏置项bf
        self.Wih, self.Wix, self.bi = (
            self.init_weight_mat())
        # 输出门权重矩阵Wfh, Wfx, 偏置项bf
        self.Woh, self.Wox, self.bo = (
            self.init_weight_mat())
        # 单元状态权重矩阵Wfh, Wfx, 偏置项bf
        self.Wch, self.Wcx, self.bc = (
            self.init_weight_mat())

    def init_state_vec(self):
        '''
        初始化保存状态的向量
        '''
        state_vec_list = []
        state_vec_list.append(np.zeros(
            (self.state_width, 1)))
        return state_vec_list

    def init_weight_mat(self):
        '''
        初始化权重矩阵
        '''
        Wh = np.random.uniform(-1e-4, 1e-4,
                               (self.state_width, self.state_width))
        Wx = np.random.uniform(-1e-4, 1e-4,
                               (self.state_width, self.input_width))
        b = np.zeros((self.state_width, 1))
        return Wh, Wx, b

(3)LSTM的前向传播
代码实现如下:

    def forward(self, x):
        '''
        根据式1-式6进行前向计算
        '''
        self.times += 1
        # 遗忘门
        fg = self.calc_gate(x, self.Wfx, self.Wfh,
                            self.bf, self.gate_activator)
        self.f_list.append(fg)
        # 输入门
        ig = self.calc_gate(x, self.Wix, self.Wih,
                            self.bi, self.gate_activator)
        self.i_list.append(ig)
        # 输出门
        og = self.calc_gate(x, self.Wox, self.Woh,
                            self.bo, self.gate_activator)
        self.o_list.append(og)
        # 即时状态
        ct = self.calc_gate(x, self.Wcx, self.Wch,
                            self.bc, self.output_activator)
        self.ct_list.append(ct)
        # 单元状态
        c = fg * self.c_list[self.times - 1] + ig * ct
        self.c_list.append(c)
        # 输出
        h = og * self.output_activator.forward(c)
        self.h_list.append(h)

    def calc_gate(self, x, Wx, Wh, b, activator):
        '''
        计算门
        '''
        h = self.h_list[self.times - 1]  # 上次的LSTM输出
        net = np.dot(Wh, h) + np.dot(Wx, x) + b
        gate = activator.forward(net)
        return gate

从上面的代码我们可以看到,门的计算都是相同的算法,而门和的计算仅仅是激活函数不同。使用calc_gate方法减少了很多重复代码。
(4)LSTM的反向传播
与反向传播相关的内部状态变量是在调用backward方法之后才初始化的。这种延迟初始化的一个好处是,如果LSTM只是用来推理,那么就不需要初始化这些变量,节省了很多内存。

    def backward(self, x, delta_h, activator):
        '''
        实现LSTM训练算法
        '''
        self.calc_delta(delta_h, activator)
        self.calc_gradient(x)

算法主要由两部分组成,一部分使计算误差项,另一部分是梯度的计算。
计算误差项的对应代码如下:

    def calc_delta(self, delta_h, activator):
        # 初始化各个时刻的误差项
        self.delta_h_list = self.init_delta()  # 输出误差项
        self.delta_o_list = self.init_delta()  # 输出门误差项
        self.delta_i_list = self.init_delta()  # 输入门误差项
        self.delta_f_list = self.init_delta()  # 遗忘门误差项
        self.delta_ct_list = self.init_delta()  # 即时输出误差项

        # 保存从上一层传递下来的当前时刻的误差项
        self.delta_h_list[-1] = delta_h

        # 迭代计算每个时刻的误差项
        for k in range(self.times, 0, -1):
            self.calc_delta_k(k)

    def init_delta(self):
        '''
        初始化误差项
        '''
        delta_list = []
        for i in range(self.times + 1):
            delta_list.append(np.zeros(
                (self.state_width, 1)))
        return delta_list

    def calc_delta_k(self, k):
        '''
        根据k时刻的delta_h,计算k时刻的delta_f、
        delta_i、delta_o、delta_ct,以及k-1时刻的delta_h
        '''
        # 获得k时刻前向计算的值
        ig = self.i_list[k]
        og = self.o_list[k]
        fg = self.f_list[k]
        ct = self.ct_list[k]
        c = self.c_list[k]
        c_prev = self.c_list[k - 1]
        tanh_c = self.output_activator.forward(c)
        delta_k = self.delta_h_list[k]

        # 根据式9计算delta_o
        delta_o = (delta_k * tanh_c *
                   self.gate_activator.backward(og))
        delta_f = (delta_k * og *
                   (1 - tanh_c * tanh_c) * c_prev *
                   self.gate_activator.backward(fg))
        delta_i = (delta_k * og *
                   (1 - tanh_c * tanh_c) * ct *
                   self.gate_activator.backward(ig))
        delta_ct = (delta_k * og *
                    (1 - tanh_c * tanh_c) * ig *
                    self.output_activator.backward(ct))
        delta_h_prev = (
                np.dot(delta_o.transpose(), self.Woh) +
                np.dot(delta_i.transpose(), self.Wih) +
                np.dot(delta_f.transpose(), self.Wfh) +
                np.dot(delta_ct.transpose(), self.Wch)
        ).transpose()

        # 保存全部delta值
        self.delta_h_list[k - 1] = delta_h_prev
        self.delta_f_list[k] = delta_f
        self.delta_i_list[k] = delta_i
        self.delta_o_list[k] = delta_o
        self.delta_ct_list[k] = delta_ct

计算梯度的代码如下:

    def calc_gradient(self, x):
        # 初始化遗忘门权重梯度矩阵和偏置项
        self.Wfh_grad, self.Wfx_grad, self.bf_grad = (
            self.init_weight_gradient_mat())
        # 初始化输入门权重梯度矩阵和偏置项
        self.Wih_grad, self.Wix_grad, self.bi_grad = (
            self.init_weight_gradient_mat())
        # 初始化输出门权重梯度矩阵和偏置项
        self.Woh_grad, self.Wox_grad, self.bo_grad = (
            self.init_weight_gradient_mat())
        # 初始化单元状态权重梯度矩阵和偏置项
        self.Wch_grad, self.Wcx_grad, self.bc_grad = (
            self.init_weight_gradient_mat())

        # 计算对上一次输出h的权重梯度
        for t in range(self.times, 0, -1):
            # 计算各个时刻的梯度
            (Wfh_grad, bf_grad,
             Wih_grad, bi_grad,
             Woh_grad, bo_grad,
             Wch_grad, bc_grad) = (
                self.calc_gradient_t(t))
            # 实际梯度是各时刻梯度之和
            self.Wfh_grad += Wfh_grad
            self.bf_grad += bf_grad
            self.Wih_grad += Wih_grad
            self.bi_grad += bi_grad
            self.Woh_grad += Woh_grad
            self.bo_grad += bo_grad
            self.Wch_grad += Wch_grad
            self.bc_grad += bc_grad

        # 计算对本次输入x的权重梯度
        xt = x.transpose()
        self.Wfx_grad = np.dot(self.delta_f_list[-1], xt)
        self.Wix_grad = np.dot(self.delta_i_list[-1], xt)
        self.Wox_grad = np.dot(self.delta_o_list[-1], xt)
        self.Wcx_grad = np.dot(self.delta_ct_list[-1], xt)

    def init_weight_gradient_mat(self):
        '''
        初始化权重矩阵
        '''
        Wh_grad = np.zeros((self.state_width,
                            self.state_width))
        Wx_grad = np.zeros((self.state_width,
                            self.input_width))
        b_grad = np.zeros((self.state_width, 1))
        return Wh_grad, Wx_grad, b_grad

    def calc_gradient_t(self, t):
        '''
        计算每个时刻t权重的梯度
        '''
        h_prev = self.h_list[t - 1].transpose()
        Wfh_grad = np.dot(self.delta_f_list[t], h_prev)
        bf_grad = self.delta_f_list[t]
        Wih_grad = np.dot(self.delta_i_list[t], h_prev)
        bi_grad = self.delta_f_list[t]
        Woh_grad = np.dot(self.delta_o_list[t], h_prev)
        bo_grad = self.delta_f_list[t]
        Wch_grad = np.dot(self.delta_ct_list[t], h_prev)
        bc_grad = self.delta_ct_list[t]
        return Wfh_grad, bf_grad, Wih_grad, bi_grad, \
               Woh_grad, bo_grad, Wch_grad, bc_grad

(5)梯度下降算法的实现
在LSTM中我们使用梯度下降来更新权重,梯度下降的代码如下:

    def update(self):
        '''
        按照梯度下降,更新权重
        '''
        self.Wfh -= self.learning_rate * self.Whf_grad
        self.Wfx -= self.learning_rate * self.Whx_grad
        self.bf -= self.learning_rate * self.bf_grad
        self.Wih -= self.learning_rate * self.Whi_grad
        self.Wix -= self.learning_rate * self.Whi_grad
        self.bi -= self.learning_rate * self.bi_grad
        self.Woh -= self.learning_rate * self.Wof_grad
        self.Wox -= self.learning_rate * self.Wox_grad
        self.bo -= self.learning_rate * self.bo_grad
        self.Wch -= self.learning_rate * self.Wcf_grad
        self.Wcx -= self.learning_rate * self.Wcx_grad
        self.bc -= self.learning_rate * self.bc_grad

(6)梯度检查的实现
为了支持梯度检查,我们首先需要支持重置内部状态,实现的代码如下:

    def reset_state(self):
        # 当前时刻初始化为t0
        self.times = 0
        # 各个时刻的单元状态向量c
        self.c_list = self.init_state_vec()
        # 各个时刻的输出向量h
        self.h_list = self.init_state_vec()
        # 各个时刻的遗忘门f
        self.f_list = self.init_state_vec()
        # 各个时刻的输入门i
        self.i_list = self.init_state_vec()
        # 各个时刻的输出门o
        self.o_list = self.init_state_vec()
        # 各个时刻的即时状态c~
        self.ct_list = self.init_state_vec()

最后,实现梯度检查的代码如下:

def data_set():
    x = [np.array([[1], [2], [3]]),
         np.array([[2], [3], [4]])]
    d = np.array([[1], [2]])
    return x, d


def gradient_check():
    '''
    梯度检查
    '''
    # 设计一个误差函数,取所有节点输出项之和
    error_function = lambda o: o.sum()

    lstm = LstmLayer(3, 2, 1e-3)

    # 计算forward值
    x, d = data_set()
    lstm.forward(x[0])
    lstm.forward(x[1])

    # 求取sensitivity map
    sensitivity_array = np.ones(lstm.h_list[-1].shape,
                                dtype=np.float64)
    # 计算梯度
    lstm.backward(x[1], sensitivity_array, IdentityActivator())

    # 检查梯度
    epsilon = 10e-4
    for i in range(lstm.Wfh.shape[0]):
        for j in range(lstm.Wfh.shape[1]):
            lstm.Wfh[i, j] += epsilon
            lstm.reset_state()
            lstm.forward(x[0])
            lstm.forward(x[1])
            err1 = error_function(lstm.h_list[-1])
            lstm.Wfh[i, j] -= 2 * epsilon
            lstm.reset_state()
            lstm.forward(x[0])
            lstm.forward(x[1])
            err2 = error_function(lstm.h_list[-1])
            expect_grad = (err1 - err2) / (2 * epsilon)
            lstm.Wfh[i, j] += epsilon
            print
            'weights(%d,%d): expected - actural %.4e - %.4e' % (
                i, j, expect_grad, lstm.Wfh_grad[i, j])
    return lstm

在这里只对Wf进行了检查,运行结果如下所示:
在这里插入图片描述

2. 序列到序列模型

Transformer 是一个基于自注意力的序列到序列模型,与基于循环神经网络的序列到序列模型不同,其可以能够并行计算。
序列到序列模型输入和输出都是一个序列,输入与输出序列长度之间的关系有两种情况。
(1)输入跟输出的长度一样;
(2)机器决定输出的长度。
序列到序列模型有广泛的应用,通过以下的应用举例可以更好地了解序列到序列模型。

语音识别、机器翻译与语音翻译

语音识别:输入是声音信号,输出是语音识别的结果,即输入的这段声音信号所对应的文字。
机器翻译:机器输入一个语言的句子,输出另外一个语言的句子。输入句子的长度是N,输出句子的长度是 N′。
语音翻译:我们对机器说一句话,比如“machine learning”,机器直接把听到的英语的声音信号翻译成中文。
在这里插入图片描述
其中存在语音翻译的原因是,世界上有很多种语言可能根本没有文字,因此也就没有可以让机器先进行语音识别然后再进行机器翻译的训练资料。
以闽南语为例,,闽南语的文字不是很普及,一般人不一定能看懂。因此我们想做语音的翻译,对机器讲一句闽南语,它直接输出的是同样意思的白话文的句子,这样一般人就可以看懂。我们可以训练一个神经网络使输入的闽南语输出为可以听懂的白话。在这里插入图片描述
我们可以用视频网站上的带有中文字幕的乡土剧作为资料进行训练,在训练过程中可以忽略多噪声、音乐,乡土剧的字幕不一定跟声音能对应起来等因素的影响。

Text-To-Speech
输入文字、输出声音信号就是语音合成(Text-To-Speech)。
在这里插入图片描述
现在还没有真的做端到端的模型,以闽南语的语音合成为例,其使用的模型还是分成两阶,首先模型会先把白话文的文字转成闽南语的拼音,再把闽南语的拼音转成声音信号。从闽南语的拼音转成声音信号这一段是通过序列到序列模型 echotron 实现的。
聊天机器人
聊天机器人就是我们对它说一句话,它要给出一个回应。因为聊天机器人的输入输出都是文字,文字是一个向量序列,所以可用序列到序列的模型来做一个聊天机器人。我们可以收集大量的人为对话信息作为机器的训练资料。

问答任务
序列到序列模型在自然语言处理的领域的应用很广泛,而很多自然语言处理的任务都可以想成是问答(Question Answering,QA)的任务,例如:翻译、自动做摘要信息、情感分析等。所谓的问答就是给机器读一段文字,问机器一个问题,希望它可以给出一个正确的答案。
在这里插入图片描述

虽然各种自然语言处理的问题都能用序列到序列模型来解,但是对多数自然语言处理的任务或对多数的语音相关的任务而言,往往为这些任务定制化模型会得到更好的结果。针对各种不同的任务定制的模型往往比只用序列到序列模型的模型更好。
syntactic parsing
syntactic parsing给机器一段文字,机器要产生一个句法的分析树,即句法树。通过句法树告诉我们 deep 加 learning 合起来是一个名词短语,very 加 powerful 合起来是一个形容词短语,形容词短语加 is 以后会变成一个动词短语,动词短语加名词短语合起来是一个句子。
在这里插入图片描述
在句法分析的任务中,输入是一段文字,输出是一个树状的结构,而一个树状的结构可以看成一个序列,该序列代表了这个树的结构。

3. 梯度与方向导数

由于对梯度相关问题印象模糊,本次学习回顾了以下梯度与方向导数的概念以及相关推导。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结

在本周,通过对LSTM代码实现的学习,进一步加深了对LSTM的理解。通过对梯度与方向导数相关概念的复习明白了梯度下降算法的原理。在下周我将进入transformer的相关学习。

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

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

相关文章

JUC高并发编程4:集合的线程安全

1 内容概要 2 ArrayList集合线程不安全 2.1 ArrayList集合操作Demo 代码演示 /*** list集合线程不安全*/ public class ThreadDemo4 {public static void main(String[] args) {// 创建ArrayList集合List<String> list new ArrayList<>();for (int i 0; i <…

铺铜修改后自动重铺

很多初学者对于敷铜操作感到比较麻烦&#xff1a;为什么每次打过孔&#xff0c;修改走线后都需要手动右击-重新修改敷铜。如何提升layout的效率&#xff1f; 版本&#xff1a;Altium Designer 21.9.2 首先&#xff0c;点击面板右边的小齿轮&#xff0c;进入设置 接下来&#…

9.29学习

1.线上问题rebalance 因集群架构变动导致的消费组内重平衡&#xff0c;如果kafka集内节点较多&#xff0c;比如数百个&#xff0c;那重平衡可能会耗时导致数分钟到数小时&#xff0c;此时kafka基本处于不可用状态&#xff0c;对kafka的TPS影响极大 产生的原因 ①组成员数量发…

【C++并发入门】摄像头帧率计算和多线程相机读取(上):并发基础概念和代码实现

前言 高帧率摄像头往往应用在很多opencv项目中&#xff0c;今天就来通过简单计算摄像头帧率&#xff0c;抛出一个单线程读取摄像头会遇到的问题&#xff0c;同时提出一种解决方案&#xff0c;使用多线程对摄像头进行读取。同时本文介绍了线程入门的基础知识&#xff0c;讲解了…

2-107 基于matlab的hsv空间双边滤波去雾图像增强算法

基于matlab的hsv空间双边滤波去雾图像增强算法&#xff0c;原始图像经过光照增强后&#xff0c;将RGB转成hsv&#xff0c;进行图像增强处理&#xff0c;使图像更加清晰。程序已调通&#xff0c;可直接运行。 下载源程序请点链接&#xff1a; 2-107 基于matlab的hsv空间双边滤…

“找不到emp.dll,无法继续执行代码”需要怎么解决呢?分享6个解决方法

在日常使用电脑玩游戏的过程中&#xff0c;我们可能会遇到一些错误提示&#xff0c;其中最常见的就是“emp.dll丢失”。那么&#xff0c;emp.dll到底是什么&#xff1f;它为什么会丢失&#xff1f;丢失后会对我们的电脑产生什么影响&#xff1f;本文将为您详细解析emp.dll的概念…

超详细的华为ICT大赛报名流程

1、访问华为人才在线官网&#xff0c;点击右上角“登录/注册“&#xff0c;登录华为账号。 报名链接&#xff1a; https://e.huawei.com/cn/talent/cert/#/careerCert?navTypeauthNavKey ▲如已有华为Uniportal账号&#xff0c;完成实名认证后方可报名大赛。 ▲如没有华为…

【有啥问啥】具身智能(Embodied AI):人工智能的新前沿

具身智能&#xff08;Embodied AI&#xff09;&#xff1a;人工智能的新前沿 引言 在人工智能&#xff08;AI&#xff09;的进程中&#xff0c;具身智能&#xff08;Embodied AI&#xff09;正逐渐成为研究与应用的焦点。具身智能不仅关注于机器的计算能力&#xff0c;更强调…

需求5:增加一个按钮

在之前的几个需求中&#xff0c;我们逐步从修改字段到新增字段&#xff0c;按部就班地完成了相关工作。通过最近的文章&#xff0c;不难看出我目前正在处理前端的“未完成”和“已完成”按钮。借此机会&#xff0c;我决定趁热打铁&#xff0c;重新梳理一下之前关于按钮实现的需…

4、MapReduce编程实践

目录 1、创建文件2、启动HDFS3、启动eclipse 创建项目并导入jar包file->new->java project导入jar包finish 4、编写Java应用程序5、编译打包应用程序&#xff08;1&#xff09;查看直接运行结果&#xff08;2&#xff09;打包程序&#xff08;3&#xff09;查看 JAR 包是…

软硬协同方案破解IT瓶颈,龙蜥衍生版KOS助力内蒙古大学成功迁移10+业务软件 | 龙蜥案例

2024 云栖大会上&#xff0c;龙蜥社区发布了《龙蜥操作系统生态用户实践精选 V2》&#xff0c;为面临 CentOS 迁移的广大用户提供成熟实践样板。截至目前&#xff0c;阿里云、浪潮信息、中兴通讯 | 新支点、移动、联通、龙芯、统信软件等超 12 家厂商基于龙蜥操作系统发布商业衍…

【在Linux世界中追寻伟大的One Piece】命名管道

目录 1 -> 命名管道 1.1 -> 创建一个命名管道 1.2 -> 匿名管道与命名管道的区别 1.3 -> 命名管道的打开规则 1.4 -> 例子 1 -> 命名管道 管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信。如果我们想在不相关的进程之间交换数据&…

串行化执行、并行化执行

文章目录 1、串行化执行2、并行化测试&#xff08;多线程环境&#xff09;3、任务的执行是异步的&#xff0c;但主程序的继续执行是同步的 可以将多个任务编排为并行和串行化执行。 也可以处理编排的多个任务的异常&#xff0c;也可以返回兜底数据。 1、串行化执行 顺序执行、…

C++类和对象(下) 初始化列表 、static成员、友元、内部类等等

1.再探构造函数 之前使用构造函数时都是在函数体内初始化成员变量&#xff0c;还有一种构造函数的用法&#xff0c;叫做初始化列表&#xff1b;那么怎么使用呢&#xff1f; 使用方法用冒号开始(" : ")要写多个就用逗号(" , ")隔开数据成队列每个成员变量后…

DC00023基于jsp+MySQL新生报到管理系统

1、项目功能演示 DC00023基于jsp新生报到管理系统java webMySQL新生管理系统 2、项目功能描述 基于jspMySQL新生报到管理系统项目分为学生、辅导员、财务处和系统管理员四个角色。 2.1 学生功能 1、系统登录 2、校园新闻、报到流程、学校简介、在线留言、校园风光、入校须知…

解决Qt每次修改代码后首次运行崩溃,后几次不崩溃问题

在使用unique_ptr声明成员变量后&#xff0c;我习惯性地在初始化构造列表中进行如下构造&#xff1a; 注意看&#xff0c;我将m_menuBtnGroup的父类指定为ui->center_menu_widget&#xff0c;这便是导致崩溃的根本原因&#xff0c;解决办法便是先用this初始化&#xff0c;后…

pdf页面尺寸裁减

1、编辑pdf 2、点击裁减页面&#xff0c;并在空白区域双击裁减 3、输入裁减数据&#xff1a;

calibre-web浏览器标题icon修改

calibre-web浏览器标题icon修改 Windows安装calibre-web&#xff0c;Python-CSDN博客文章浏览阅读537次&#xff0c;点赞10次&#xff0c;收藏11次。pip install calibreweb报错&#xff1a;error: Microsoft Visual C 14.0 or greater is required. Get it with "Microso…

Springboot中基于注解实现公共字段自动填充

1.使用场景 当我们有大量的表需要管理公共字段&#xff0c;并且希望提高开发效率和确保数据一致性时&#xff0c;使用这种自动填充方式是很有必要的。它可以达到一下作用 统一管理数据库表中的公共字段&#xff1a;如创建时间、修改时间、创建人ID、修改人ID等&#xff0c;这些…

视频剪辑软件哪个好?剪辑更高效用这些

众所周知&#xff0c;视频已经成为我们记录生活、表达自我的重要方式。 无论是制作旅行Vlog&#xff0c;还是剪辑短片分享故事&#xff0c;优秀的视频剪辑软件是让创意变为现实的利器。 那么&#xff0c;如何在众多免费软件中做出明智选择&#xff0c;成为剪辑高手呢&#xf…