bert中文文本摘要代码(3)

news2025/2/28 23:54:01

bert中文文本摘要代码

  • 写在最前面
  • 关于BERT
    • 使用transformers库进行微调
  • train.py
    • 自定义参数
    • 迭代训练
    • 验证评估
    • 更新损失
    • 绘图
    • 主函数
  • test.py
    • top_k或top_p采样
    • sample_generate函数
    • generate_file函数
    • 主函数

写在最前面

熟悉bert+文本摘要的下游任务微调的代码,方便后续增加组件实现idea

代码来自:
https://github.com/jasoncao11/nlp-notebook/tree/master

已跑通,略有修改

关于BERT

BERT模型参数的数量取决于具体实现,在Google发布的BERT模型中,大概有1.1亿个模型参数。

通常情况下,BERT的参数是在训练期间自动优化调整的,因此在使用预训练模型时不需要手动调节模型参数。
如果想微调BERT模型以适应特定任务,可以通过改变学习率、正则化参数和其他超参数来调整模型参数。在这种情况下,需要进行一些实验以找到最佳的参数配置。

论文地址:https://arxiv.org/pdf/1810.04805.pdf

使用transformers库进行微调

主要包括:

  • Tokenizer:使用提供好的Tokenizer对原始文本处理,得到Token序列;
  • 构建模型:在提供好的模型结构上,增加下游任务所需预测接口,构建所需模型;
  • 微调:将Token序列送入构建的模型,进行训练。

第一part:【bert中文文本摘要代码(1)】https://blog.csdn.net/wtyuong/article/details/130972775
第二part:【bert中文文本摘要代码(2)】https://blog.csdn.net/wtyuong/article/details/130981010

本文主要为第三part

train.py

自定义参数

# -*- coding: utf-8 -*-
import torch
import matplotlib.pyplot as plt
import numpy as np
from tqdm import tqdm
from transformers import AdamW, get_linear_schedule_with_warmup
from load_data import traindataloader, valdataloader
from model import BertForSeq2Seq

N_EPOCHS = 5
LR = 5e-4
WARMUP_PROPORTION = 0.001
MAX_GRAD_NORM = 1.0
MODEL_PATH = './bert-base-chinese'
SAVE_PATH = './saved_models/pytorch_model.bin'
# device = "cuda" if torch.cuda.is_available() else 'cpu'
device = torch.device('cuda:5')

使用不同的权重衰减值设置了带有分组参数的优化器。

no_decay列表包含了在优化过程中不应进行权重衰减的参数的名称。optimizer_grouped_parameters变量定义了两个参数组:一个带有权重衰减,一个没有权重衰减。

  • 对于不在no_decay列表中的参数,weight_decay值设置为0.01;
  • 对于在no_decay列表中的参数,weight_decay值设置为0.0。
def run():
    best_valid_loss = float('inf')
    model = BertForSeq2Seq.from_pretrained(MODEL_PATH)
    model.to(device)

    no_decay = ['bias', 'LayerNorm.bias', 'LayerNorm.weight']
    optimizer_grouped_parameters = [
        {'params': [p for n, p in model.named_parameters() if not any(nd in n for nd in no_decay)],
        'weight_decay': 0.01},
        {'params': [p for n, p in model.named_parameters() if any(nd in n for nd in no_decay)], 'weight_decay': 0.0}
    ]

设置优化器和学习率调度器的部分。

total_steps表示总的训练步数,计算方法是训练数据集的批次数*训练轮数(N_EPOCHS)。

optimizer使用AdamW优化器,接受两个参数:optimizer_grouped_parameters是之前定义的参数组,lr是学习率,这里设置为LR

scheduler是学习率调度器,使用get_linear_schedule_with_warmup函数进行设置。学习率在预热阶段逐渐增加,然后保持稳定进行训练。接受三个参数:

  • optimizer是之前定义的优化器
  • num_warmup_steps表示预热步数,这里设置为总步数的一部分(WARMUP_PROPORTION
  • num_training_steps表示总的训练步数。

迭代训练

    total_steps = len(traindataloader) * N_EPOCHS
    optimizer = AdamW(optimizer_grouped_parameters, lr=LR, eps=1e-8)
    scheduler = get_linear_schedule_with_warmup(optimizer, num_warmup_steps=int(WARMUP_PROPORTION * total_steps), num_training_steps=total_steps)

迭代训练数据集中的批次,并在每个批次上执行训练步骤。

在每个训练轮次(epoch)开始时,将模型设置为训练模式(model.train()),并初始化一个空列表epoch_loss用于存储每个批次的损失值。

然后,通过使用tqdm库创建一个进度条显示训练进度,使得训练过程更加可视化。在每个批次上,从traindataloader中获取批次数据,并将数据移动到指定的device上。

接下来的代码执行以下操作:

  • 将模型梯度置零(model.zero_grad())。
  • 将输入数据传递给模型,并获取预测结果和损失值。
  • 对损失值进行反向传播(loss.backward())。
  • 使用torch.nn.utils.clip_grad_norm_函数对梯度进行裁剪,以防止梯度爆炸问题。
  • 将批次损失值添加到epoch_loss列表中。
  • 更新优化器的参数(optimizer.step())。
  • 更新进度条的显示,包括当前批次的损失值(pbar.set_postfix(loss=loss.item()))。
  • 调用学习率调度器的step()方法,更新学习率。

在每个轮次结束后,计算当前轮次的平均损失值,并将其添加到loss_vals列表中,用于后续的可视化或记录。

    loss_vals = []
    loss_vals_eval = []
    for epoch in range(N_EPOCHS):
        model.train()
        epoch_loss = []
        pbar = tqdm(traindataloader)
        pbar.set_description("[Train Epoch {}]".format(epoch)) 
    
        for batch_idx, batch_data in enumerate(pbar):
            
            input_ids = batch_data["input_ids"].to(device)
            token_type_ids = batch_data["token_type_ids"].to(device)
            token_type_ids_for_mask = batch_data["token_type_ids_for_mask"].to(device)
            labels = batch_data["labels"].to(device)
                       
            model.zero_grad()
            predictions, loss = model(input_ids, token_type_ids, token_type_ids_for_mask, labels)           
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), MAX_GRAD_NORM)
            epoch_loss.append(loss.item())
            optimizer.step()
            pbar.set_postfix(loss=loss.item())
            scheduler.step()
        loss_vals.append(np.mean(epoch_loss))

验证评估

模型在验证集上进行评估的部分。它与训练循环类似,但模型处于评估模式(model.eval())。

在每个验证轮次(epoch)开始时,将模型设置为评估模式,并初始化一个空列表epoch_loss_eval用于存储每个批次的验证损失值。

然后,通过使用tqdm库创建一个进度条显示评估进度,使得评估过程更加可视化。在每个批次上,你从valdataloader中获取批次数据,并将数据移动到指定的device上。

接下来的代码执行以下操作:

  • 使用torch.no_grad()上下文管理器,以确保在评估模式下,梯度不会被计算和更新。
  • 将输入数据传递给模型,并获取预测结果和损失值。
  • 将批次损失值添加到epoch_loss_eval列表中。
  • 更新进度条的显示,包括当前批次的损失值(pbar.set_postfix(loss=loss.item()))。

在每个验证轮次结束后,计算当前轮次的平均验证损失值,并将其添加到epoch_loss_eval列表中。

获得模型在验证集上的损失值,以评估模型的性能。

        model.eval()
        epoch_loss_eval= []
        pbar = tqdm(valdataloader)
        pbar.set_description("[Eval Epoch {}]".format(epoch))
        
        with torch.no_grad():
            for batch_idx, batch_data in enumerate(pbar):
                input_ids = batch_data["input_ids"].to(device)
                token_type_ids = batch_data["token_type_ids"].to(device)
                token_type_ids_for_mask = batch_data["token_type_ids_for_mask"].to(device)
                labels = batch_data["labels"].to(device)
                predictions, loss = model.forward(input_ids, token_type_ids, token_type_ids_for_mask, labels)                    
                epoch_loss_eval.append(loss.item())
                pbar.set_postfix(loss=loss.item())

更新损失

这部分代码用于更新验证损失值,并在验证损失达到新的最低值时保存模型。

  1. 计算当前验证轮次的平均验证损失值,并将其添加到loss_vals_eval列表中。
  2. 通过比较当前验证损失值与之前的最佳验证损失值(best_valid_loss),确定是否需要更新最佳验证损失值和保存模型。
  3. 如果当前验证损失值小于最佳验证损失值,则将最佳验证损失值更新为当前值,并使用torch.save()函数保存模型的状态字典到指定的路径(SAVE_PATH)。这样可以保留当前具有最低验证损失的模型。
  4. 在打印出"best - epoch: %d"消息后,使用torch.cuda.empty_cache()函数清空GPU缓存,以释放不再使用的显存。

跟踪最佳验证损失值,并保存在每个验证轮次中具有最佳性能的模型。

        valid_loss = np.mean(epoch_loss_eval)
        loss_vals_eval.append(valid_loss)    
    
        if valid_loss < best_valid_loss:
            best_valid_loss = valid_loss
            torch.save(model.state_dict(), SAVE_PATH)
            print("best - epoch: %d"%(epoch))
        torch.cuda.empty_cache()

绘图

绘制训练损失和验证损失随着训练轮次的变化图表,并保存图表为文件。

  1. 使用plt.plot()函数分别绘制训练损失和验证损失随着训练轮次的变化。np.linspace(1, N_EPOCHS, N_EPOCHS).astype(int)生成了从1到N_EPOCHS的整数数组,用作x轴的取值范围。loss_vals是训练损失的列表,loss_vals_eval是验证损失的列表。l1l2是对应的绘图线条对象。
  2. 使用plt.legend()函数创建图例,并指定图例的句柄(handles)和标签(labels)。这里使用l1l2作为句柄,并指定标签为"Train loss"和"Eval loss"。loc='best'将图例放置在最佳位置。
  3. 使用plt.savefig()函数保存图表为文件,文件名为’bert-seq2seq 3.png’。
  4. 使用plt.show()函数显示图表。

可视化训练损失和验证损失随着训练轮次的变化,以便进行性能分析和比较。

    l1, = plt.plot(np.linspace(1, N_EPOCHS, N_EPOCHS).astype(int), loss_vals)
    l2, = plt.plot(np.linspace(1, N_EPOCHS, N_EPOCHS).astype(int), loss_vals_eval)
    plt.legend(handles=[l1,l2],labels=['Train loss','Eval loss'],loc='best')
    plt.savefig('bert-seq2seq 3.png')
    plt.show()

在这里插入图片描述

主函数

if __name__ == '__main__':
    run()

test.py

saved_models文件夹包含两个文件:
(1)在原有bert-base-chinese基础上fine-tune的pytorch_model.bin
(2)配置文件config.json,和原有bert-base-chinese的配置文件一样

# -*- coding: utf-8 -*-
import torch 
import torch.nn.functional as F
import numpy as np
from model import BertForSeq2Seq
from tokenizer import Tokenizer
import pandas as pd

top_k或top_p采样

函数top_k_top_p_filtering()用于对logits进行top-k和top-p采样。

函数接受以下参数:

  • logits:logits分布,形状为(vocabulary size)的张量。
  • top_k:保留概率最高的top_k个标记(token)。
  • top_p:保留累积概率大于等于top_p的标记(token)。
  • filter_value:过滤掉的标记(token)所对应的值。

函数的实现逻辑如下:

  • 首先,进行维度检查,确保logits是一个一维张量。
  • 如果top_k大于0,则将概率小于top_k中最低概率的标记设为filter_value
  • 如果top_p大于0.0,则对logits进行排序,并计算累积概率。然后,将累积概率超过top_p的标记设为filter_value
  • 最后,返回经过过滤后的logits。

用于对生成的概率分布进行过滤,保留top_k个概率最高的标记,或者保留累积概率大于等于top_p的标记。这样可以控制生成结果的多样性和可靠性。

def top_k_top_p_filtering(logits, top_k=0, top_p=0.0, filter_value=-float('Inf')):
    """ Filter a distribution of logits using top-k and/or nucleus (top-p) filtering
        Args:
            logits: logits distribution shape (vocabulary size)
            top_k > 0: keep only top k tokens with highest probability (top-k filtering).
            top_p > 0.0: keep the top tokens with cumulative probability >= top_p (nucleus filtering).
                Nucleus filtering is described in Holtzman et al. (http://arxiv.org/abs/1904.09751)
        From: https://gist.github.com/thomwolf/1a5a29f6962089e871b94cbd09daf317
    """
    assert logits.dim() == 1  # batch size 1 for now - could be updated for more but the code would be less clear
    top_k = min(top_k, logits.size(-1))  # Safety check
    if top_k > 0:
        # Remove all tokens with a probability less than the last token of the top-k
        indices_to_remove = logits < torch.topk(logits, top_k)[0][..., -1, None]
        logits[indices_to_remove] = filter_value

    if top_p > 0.0:
        sorted_logits, sorted_indices = torch.sort(logits, descending=True)
        cumulative_probs = torch.cumsum(F.softmax(sorted_logits, dim=-1), dim=-1)

        # Remove tokens with cumulative probability above the threshold
        sorted_indices_to_remove = cumulative_probs > top_p
        # Shift the indices to the right to keep also the first token above the threshold
        sorted_indices_to_remove[..., 1:] = sorted_indices_to_remove[..., :-1].clone()
        sorted_indices_to_remove[..., 0] = 0

        indices_to_remove = sorted_indices[sorted_indices_to_remove]
        logits[indices_to_remove] = filter_value
    return logits

sample_generate函数

这段代码定义了一个函数sample_generate(),用于生成文本。

函数接受以下参数:

  • text:输入的文本。
  • out_max_length:生成文本的最大长度。
  • top_k:top-k过滤的k值。
  • top_p:top-p过滤的概率阈值。
  • max_length:输入文本的最大长度。
  1. 将模型设置为评估模式(model.eval())。
  2. 根据max_lengthout_max_length计算输入文本的最大长度input_max_length,然后使用Tokenizer.encode()函数对输入文本进行编码,生成input_idstoken_type_idstoken_type_ids_for_masklabels
  3. 将编码后的张量转换为torch.tensor,并将其移动到指定的设备上。
  4. 初始化一个空列表output_ids,用于存储生成的文本。
  5. with torch.no_grad()的上下文中,进行文本生成的循环。在每个步骤中,通过模型预测下一个标记的概率分布。然后使用top_k_top_p_filtering()函数对概率分布进行过滤,得到过滤后的logits。接着使用torch.multinomial()函数从过滤后的分布中采样出下一个标记。
  6. 如果采样到的标记是结束标记(Tokenizer.sep_id),则停止生成过程。否则,将采样到的标记添加到output_ids中,并更新输入的input_idstoken_type_idstoken_type_ids_for_mask,以便下一步的生成。
  7. 最后,使用Tokenizer.decode()函数将生成的标记序列解码为文本,并返回生成的文本。

这个函数实现了使用预训练模型生成文本的功能,可以根据指定的输入文本生成相应的输出文本。
通过调整out_max_lengthtop_ktop_p等参数,可以控制生成文本的长度和多样性。

def sample_generate(text, out_max_length=256, top_k=30, top_p=0.0, max_length=512):
    # device = "cuda" if torch.cuda.is_available() else 'cpu'
    model.eval()

    input_max_length = max_length - out_max_length
    input_ids, token_type_ids, token_type_ids_for_mask, labels = Tokenizer.encode(text, max_length=input_max_length)

    input_ids = torch.tensor(input_ids, device=device, dtype=torch.long).view(1, -1)
    token_type_ids = torch.tensor(token_type_ids, device=device, dtype=torch.long).view(1, -1)
    token_type_ids_for_mask = torch.tensor(token_type_ids_for_mask, device=device, dtype=torch.long).view(1, -1)
    #print(input_ids, token_type_ids, token_type_ids_for_mask)
    output_ids = []

    with torch.no_grad(): 
        for step in range(out_max_length):
            scores = model(input_ids, token_type_ids, token_type_ids_for_mask)
            logit_score = torch.log_softmax(scores[:, -1], dim=-1).squeeze(0)
            logit_score[Tokenizer.unk_id] = -float('Inf')
            
            # 对于已生成的结果generated中的每个token添加一个重复惩罚项,降低其生成概率
            for id_ in set(output_ids):
                logit_score[id_] /= 1.5                
            
            filtered_logits = top_k_top_p_filtering(logit_score, top_k=top_k, top_p=top_p)
            next_token = torch.multinomial(F.softmax(filtered_logits, dim=-1), num_samples=1)
            if Tokenizer.sep_id == next_token.item():
                break
            output_ids.append(next_token.item())
            input_ids = torch.cat((input_ids, next_token.long().unsqueeze(0)), dim=1)
            token_type_ids = torch.cat([token_type_ids, torch.ones((1, 1), device=device, dtype=torch.long)], dim=1)
            token_type_ids_for_mask = torch.cat([token_type_ids_for_mask, torch.zeros((1, 1), device=device, dtype=torch.long)], dim=1)
            #print(input_ids, token_type_ids, token_type_ids_for_mask)

    return Tokenizer.decode(np.array(output_ids))

generate_file函数

这段代码定义了一个函数generate_file(df),用于生成文本文件。

函数接受DataFrame对象df作为输入参数。

在函数内部

  1. 首先创建一个副本df.copy(),然后初始化一个空列表generate_diagnosis用于存储生成的诊断摘要。
  2. 接下来,使用循环遍历df的每一行,获取描述文本(假设在第二列),并调用sample_generate()函数生成对应的诊断摘要。
  3. 将生成的诊断摘要添加到generate_diagnosis列表中,并打印输出摘要信息。
  4. 循环结束后,将generate_diagnosis列表作为新列添加到副本DataFrame df 中,并将结果保存到Excel文件中。
  5. 最后将生成的DataFrame保存为名为"bert-seq2seq生成4.xlsx"的Excel文件,保存在"Sheet1"工作表中,不包含行索引。

这个函数可以根据给定的描述文本生成相应的诊断摘要,并将结果保存为Excel文件。

def generate_file(df):
    df = df.copy()
    generate_diagnosis = []
    i = 1
    for description in df.iloc[:,1]:
        summary = sample_generate(description, top_k=5, top_p=0.95)
        generate_diagnosis.append(summary)
        print(i,"摘要:",summary)
        i = i + 1
    df.loc[:, "generate_diagnosis"] = generate_diagnosis
    df.to_excel("bert-seq2seq生成4.xlsx", sheet_name='Sheet1', index=False)

主函数

  1. 指定了模型路径model_path为"./bert-base-chinese"。
  2. 通过torch.cuda.is_available()判断是否有可用的CUDA设备,并将设备指定为"cuda:5"。
  3. 使用BertForSeq2Seq.from_pretrained(model_path)加载预训练模型,并将其移动到指定的设备上。
  4. 指定了要处理的文件路径filepath为"./data/test.tsv",并使用pd.read_csv()函数读取该文件内容,以DataFrame的形式存储在变量file中。
  5. 调用generate_file()函数,将读取的文件数据作为参数传递给该函数,用于生成诊断摘要,并将结果保存为Excel文件。

运行脚本时,加载模型并处理指定的文件,生成诊断摘要并保存结果。

if __name__ == '__main__':
    model_path = './bert-base-chinese'

    print(torch.cuda.is_available())
    device = torch.device('cuda:5')
    model = BertForSeq2Seq.from_pretrained(model_path).to(device)

    filepath = './data/test.tsv'
    file = pd.read_csv(filepath, sep='\t')
    generate_file(file)

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

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

相关文章

网络安全合规-数据出境安全评估

&#xff08;一&#xff09;数据出境安全评估的适用范围为&#xff1a; 数据处理者向境外提供重要数据&#xff1b; 关键信息基础设施运营者和处理100万人以上个人信息的数据处理者向境外提供个人信息&#xff1b;自上年1月1日起累计向境外提供10万人个人信息或者1万人敏感个…

浮点数在内存中的存储

&#x1f493;博主CSDN主页:杭电码农-NEO&#x1f493;   ⏩专栏分类:C语言学习分享⏪   &#x1f69a;代码仓库:NEO的学习日记&#x1f69a;   &#x1f339;关注我&#x1faf5;带你学习更多C语言知识   &#x1f51d;&#x1f51d; 浮点数在内存的存储 1. 前言&#…

vue3+WebRTC拉流(正确姿势)

vue3WebRTC拉流&#xff08;正确姿势&#xff09; 文章目录 vue3WebRTC拉流&#xff08;正确姿势&#xff09;缘由一、webRtc拉流是什么&#xff1f;1.实时通信&#xff1a;2.网络穿越&#xff1a;3.媒体处理&#xff1a;4.数据通道&#xff1a;5.使用场景: 二、使用webRtc引用…

《priority_queue的模拟实现》

本文主要介绍 文章目录 一、仿函数1.1 仿函数的定义1.2 普通仿函数1.3 需要自己实现仿函数 二、priority_queue的模拟实现 一、仿函数 1.1 仿函数的定义 所谓的仿函数(functor)&#xff0c;是通过重载()运算符模拟函数形为的类。 因此&#xff0c;这里需要明确两点&#xff1…

纯干货:数据库连接耗时慢原因排查

背景 最近公司的社区相关的服务需要优化&#xff0c;由于对业务不熟悉&#xff0c;只能借助监控从一些慢接口开始尝试探索慢的原因。由于社区相关的功能务是公司小程序流量入口&#xff0c;所以相应的服务访问量还是比较高的。针对这类高访问的项目&#xff0c;任何不留神的地…

中睿天下参编的《中国网信产业桔皮书-数据安全》正式发布

5月28日&#xff0c;2023中关村论坛中关村国际技术交易大会第七届中国网信产业前锋汇成功举办&#xff0c;本次会议以“全球数字经济发展与数据安全关键技术”为主题&#xff0c;会议由中国&#xff08;中关村&#xff09;网络安全与信息化产业联盟主办&#xff08;以下简称联盟…

芯片的XIP与BootRom启动方式

XIP&#xff1a;execute in place&#xff0c;就地执行&#xff0c;即芯片内执行&#xff0c;指应用程序可以直接在flash闪存中取指然后译码、执行&#xff0c;不必再把代码读到系统RAM中&#xff0c;flash内执行时指Nor flash不需要初始化&#xff0c;可以直接在flash内执行代…

Elsevier期刊中,撰写Author Statement

Author Statement或Authorship Contribution通常指作者声明&#xff0c;用于声明当前学术论文中每位作者的贡献。 大部分期刊都要求作者在首次投稿的时候就添加这部分内容&#xff0c;也有一些仅要求在发表之前提交。作者声明指导与模板有些学术期刊会专门提供具体的作者声明模…

Vue3 mixin 自定义指令 teleport

文章目录 Vue3 mixin & 自定义指令 & teleportmixin 混入简单使用 自定义指令简单使用全局注册参数 teleport 传送门简单使用 Vue3 mixin & 自定义指令 & teleport mixin 混入 mixins 选项接受一个 mixin 对象数组。这些 mixin 对象可以像普通的实例对象一样…

【企业化架构部署】Apache网页优化

文章目录 一、Apache网页优化概述1.优化内容2.网页压缩2.1gzip概述2.2作用2.3Apache的压缩模块概述mod_gzip模块与mod_deflate模块 3.配置网页压缩功能3.1启用网页压缩功能步骤3.2具体操作步骤 4.配置网页缓存功能4.1启用网页压缩功能步骤4.2具体操作步骤 二、Apache安全优化1.…

【JVM】.class类文件是如何被加载的?

一、类加载过程 .class文件最终加载到JVM并使用整体步骤及图示如下&#xff1a; 每个步骤所做的事情如下&#xff1a; 1、加载 &#xff08;1&#xff09;通过一个类的全限定名来获取该类文件的二进制字节流&#xff1b;&#xff08;读取class文件到内存中&#xff09; &am…

点击这里!解锁海量数据在openGauss Developer Day 2023的高光时刻

5月26日&#xff0c;openGauss Developer Day 2023在此起彼伏的掌声中圆满落幕。最前沿的核心产品、最深度的专业解读、最全面的落地案例......海量数据在此次盛会上时时高光&#xff0c;事事精彩&#xff0c;尤其是在专场分论坛上&#xff0c;数据库领域各路精英济济一堂&…

linuxOPS基础_linux文件检索及筛选

find命令 查找文件 主要功能&#xff1a;当我们查找一个文件时&#xff0c;必须使用的一个命令。 find 搜索路径 [选项]选项选项说明-name指定要搜索文件的名称&#xff0c;支持*星号通配符&#xff08;Shift 8&#xff09;-type代表搜索的文件类型&#xff0c;f代表普通文件…

使用开源代码和开源软件如何选择开源许可证

常用的开源许可证 世界上的开源许可证大约有近百种&#xff0c;如何使用开源代码和开源软件并正确理解、遵守这些开源许可证赋予的权利和义务是个比较繁琐的问题&#xff0c;我们对其中主要的六种许可证GPL、BSD、MIT、Mozilla、Apache和LGPL做个简单的梳理&#xff0c;对比一下…

什么是企业移动化管理 (EMM)

什么是EMM或企业移动化管理 企业移动化管理 &#xff08;EMM&#xff09; 是组织用来保护公司拥有和员工拥有的移动设备上的敏感公司数据的一组策略和做法。Mobile Device Manager Plus 是一个全面的 EMM 解决方案&#xff0c;允许 IT 团队和管理员跨多个平台管理设备&#xf…

推进产业发展健全服务体系,中国信通院数字员工评测工作正式启动

数字技术与应用正在快速重塑全新的经济发展格局&#xff0c;创新应用人工智能、大数据、云计算等新兴技术是企业实施数字化转型的重要策略之一。 “数字员工”是数字生产力与创造力体系的核心要素&#xff0c;自动化、智能化的执行模式将成为企业业务运营的新常态。随着数字员…

外包实在是太坑了,划水三年,感觉人都废了

先说一下自己的情况&#xff0c;专科生&#xff0c;19年通过校招进入杭州某个外包软件公司&#xff0c;干了接近3年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了3年的功…

革命性3D打印数据处理软件 CHITUBOX Pro 1.3.0 Crack

CHITUBOX PRO登场 革命性的3D打印数据处理软件&#xff0c;让你发挥3D打印的无限潜力 支持多种主流CAD文件格式 除了传统的stl和obj文件&#xff0c;CHITUBOX Pro还支持导入各种主流的CAD文件格式&#xff0c;包括3ds、3mf、3dm、stp、step、wrl、x3d、sat、sab、dae、dxf、fb…

5.2.5 IP数据报(三)IP数据报的分片与重组

5.2.5 IP数据报&#xff08;三&#xff09;IP数据报的分片与重组 前面我们在学习IP数据报的格式中&#xff0c;提及了数据报的分片&#xff0c;这里我们要弄明白几个问题 为什么要分片&#xff1f; 前面我们已经解释过&#xff0c;如图 因为在数据报传送的过程中如果总长度超出…

Sui教育资助计划:共同构建Web3教育的未来

Sui教育资助计划旨在通过与社区成员一起构建公开的教育资料&#xff0c;加速推广Web3&#xff0c;并支持Sui生态系统的发展。 内容类别 包括教程、指南、视频以及文本等形式的教育材料包括学习奖励和其他体验式的教育产品&#xff0c;将学习游戏化可帮助开发人员加快构建速度…