paddlenlp:社交网络中多模态虚假媒体内容核查(代码篇)

news2024/10/1 21:45:05

初赛之baseline解读篇

  • 一、模型框架图
    • 1、框架解读
    • 2、评价指标解读
  • 二、代码功能
    • 1、数据集加载
    • 2、模型定义
    • 3、模型训练
    • 4、模型预测
  • 三、写在最后

一、模型框架图

1、框架解读

第一列是输入,一部分是文本(需核查文本、文本证据材料),一部分是图片(需核查图像、图像证据材料)。

第二列是pre-trained模型,用于特征提取。文本部分采用Ernie-m模型提取特征,图像部分采用Resnet模型提取特征。

第三列是多头自注意力机制,可得到相关的文本证据特征相关的图像证据特征

最后,使用全连接层将标题特征图像特征相关的文本证据特征相关的图像证据特征四块特征拼接,输入到分类器得到最终预测结果
在这里插入图片描述

2、评价指标解读

采用在三个不同类别上的macro F1的高低进行评分,兼顾了准确率与召回率,是谣言检测领域主流的自动评价指标。

Macro-F1在sklearn里的计算方法就是计算每个类的F1-score的算数平均值,符合赛题定义。

本赛题共有三类,包含文娱、经济、健康。先分别计算每个类别的F1,再求平均值。

F1的计算,首先要了解混淆矩阵:
在这里插入图片描述
TPi 是指第 i 类的 True Positive   正类判定为正类;
FPi 是指第 i 类的 False Positive  负类判定为正类;
FNi 是指第 i 类的 FalseNegative  正类判定为负类;
TNi 是指第 i 类的 True Negative  负类判定为负类。

对第1类 :TP1=a;FP1=d+g;FN1=b+c;TN1=e+f+h+i;
对第2类 :TP2=e;FP2=b+h;FN2=d+f; TN2=a+c+g+i;
对第3类 :TP3=i; FP3=c+f; FN3=g+h;TN3=a+b+d+e;

在这里插入图片描述
最后计算公式如下:
m a c r o − F 1 = ( F 1 − s c o r e 1 + F 1 − s c o r e 2 + F 1 − s c o r e 3 ) / 3 macro-F1= (F1−score_1+F1−score_2+ F1−score_3)/3 macroF1=F1score1+F1score2+F1score3)/3
拿文娱举例,召回率:预测正确文娱的数占真实文娱数的比值​;准确率:预测正确文娱的数占预测为文娱数的比值

二、代码功能

1、数据集加载

#### load Datasets ####
train_dataset = NewsContextDatasetEmbs(data_items_train, 'queries_dataset_merge','train')
val_dataset = NewsContextDatasetEmbs(data_items_val,'queries_dataset_merge','val')
test_dataset = NewsContextDatasetEmbs(data_items_test,'queries_dataset_merge','test')

训练集、测试集、验证集都是通过NewsContextDatasetEmbs这个类函数来创建的。

传入的三个参数分别为 json文件数据指定数据集的根目录指定数据集类别

1)NewsContextDatasetEmbs

class NewsContextDatasetEmbs(Dataset):
    def __init__(self, context_data_items_dict, queries_root_dir, split):
        self.context_data_items_dict = context_data_items_dict
        self.queries_root_dir = queries_root_dir
        self.idx_to_keys = list(context_data_items_dict.keys())
        # 使用Imagenet的均值和标准差归一化
        # 将图像大小调整为(256×256)
        # 将其转换为(224×224)
        # 将其转换为张量 - 图像中的所有元素值都将被缩放,以便在[0,1]之间而不是原来的[0,255]范围内
        # 将其正则化,使用Imagenet数据
        # 均值 = [0.485,0.456,0.406],标准差 = [0.229,0.224,0.225]
        self.transform = T.Compose([
            T.Resize(256),
            T.CenterCrop(224),
            T.ToTensor(),
            T.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),  
        ])
        self.split = split

    # 计算字典的长度
    def __len__(self):
        return len(self.context_data_items_dict)

    #通过pil读取img图像,深度学习模型一般只支持三通道,(其他通道可能是透明度)
    def load_img_pil(self, image_path):
        # imghdr用于探测图片的格式,实际就是图片格式遍历匹配
        if imghdr.what(image_path) == 'gif':
            try:
                with open(image_path, 'rb') as f:
                    img = Image.open(f)
                    return img.convert('RGB')
            except:
                return None
        with open(image_path, 'rb') as f:
            img = Image.open(f)
            return img.convert('RGB')

   #加载图片直接返回图片的tensor
    def load_imgs_direct_search(self, item_folder_path, direct_dict):
        list_imgs_tensors = []
        count = 0
        keys_to_check = ['images_with_captions', 'images_with_no_captions', 'images_with_caption_matched_tags']
        for key1 in keys_to_check:
            if key1 in direct_dict.keys():
                for page in direct_dict[key1]:
                    image_path = os.path.join(item_folder_path, page['image_path'].split('/')[-1])
                    try:
                        pil_img = self.load_img_pil(image_path)   #调用load_img_pil函数读入只含三通道的图片
                    except Exception as e:
                        print(e)
                        print(image_path)
                    if pil_img == None: continue
                    transform_img = self.transform(pil_img)   # 将读入的图片处理成统一大小
                    count = count + 1
                    list_imgs_tensors.append(transform_img)
        stacked_tensors = paddle.stack(list_imgs_tensors, axis=0)
        return stacked_tensors

    #加载inverse_search文件夹下的说明文字,返回说明文字,通过图匹配到的文字
    def load_captions(self, inv_dict):
        captions = ['']

        #不同的方式处理方式不一样
        pages_with_captions_keys = ['all_fully_matched_captions', 'all_partially_matched_captions']
        for key1 in pages_with_captions_keys:
            if key1 in inv_dict.keys():
                for page in inv_dict[key1]:
                    #有title的dict
                    if 'title' in page.keys():
                        item = page['title']
                        item = process_string(item)
                        captions.append(item)
                    #有caption的dict
                    if 'caption' in page.keys():
                        sub_captions_list = []
                        unfiltered_captions = []
                        for key2 in page['caption']:
                            sub_caption = page['caption'][key2]
                            sub_caption_filter = process_string(sub_caption)      
                            # 将文字中的单引号、字体加粗的网页标签过滤掉,为啥需要替换,会有信息损失吗
                            # 是否可以替换更多,或者有其他方式解决
                            if sub_caption in unfiltered_captions: continue  # 如果已经加过的caption数据就不再加了
                            sub_captions_list.append(sub_caption_filter)
                            unfiltered_captions.append(sub_caption)
                        captions = captions + sub_captions_list
        #不同的方式处理不一样
        pages_with_title_only_keys = ['partially_matched_no_text', 'fully_matched_no_text']
        for key1 in pages_with_title_only_keys:
            if key1 in inv_dict.keys():
                for page in inv_dict[key1]:
                    if 'title' in page.keys():
                        title = process_string(page['title'])
                        captions.append(title)
        return captions

    # 加载img_html_news文件夹下的说明文字,返回说明文字,通过文字匹配到的图
    def load_captions_weibo(self, direct_dict):
        captions = ['']
        keys = ['images_with_captions', 'images_with_no_captions', 'images_with_caption_matched_tags']
        for key1 in keys:
            if key1 in direct_dict.keys():
                for page in direct_dict[key1]:
                    if 'page_title' in page.keys():
                        item = page['page_title']
                        item = process_string(item)
                        captions.append(item)
                    if 'caption' in page.keys():
                        sub_captions_list = []
                        unfiltered_captions = []
                        for key2 in page['caption']:
                            sub_caption = page['caption'][key2]
                            sub_caption_filter = process_string(sub_caption)
                            if sub_caption in unfiltered_captions: continue
                            sub_captions_list.append(sub_caption_filter)
                            unfiltered_captions.append(sub_caption)
                        captions = captions + sub_captions_list
                        # print(captions)
        return captions

    # 加载 dataset_items_train.json ,img文件夹的图片,返回 transform的图片img, 和文字caption
    def load_queries(self, key):
        caption = self.context_data_items_dict[key]['caption']
        image_path = os.path.join(self.queries_root_dir, self.context_data_items_dict[key]['image_path'])
        pil_img = self.load_img_pil(image_path)
        transform_img = self.transform(pil_img)
        return transform_img, caption

    def __getitem__(self, idx):
        key = self.idx_to_keys[idx]   #对应id的key值查询
        item = self.context_data_items_dict.get(str(key))
        # 如果为test没有label属性,所以train和val一起处理,else为test处理部分
        if self.split == 'train' or self.split == 'val':
            label = paddle.to_tensor(int(item['label']))
            direct_path_item = os.path.join(self.queries_root_dir, item['direct_path'])
            inverse_path_item = os.path.join(self.queries_root_dir, item['inv_path'])
            inv_ann_dict = json.load(open(os.path.join(inverse_path_item, 'inverse_annotation.json'),'r',encoding='UTF8'))
            direct_dict = json.load(open(os.path.join(direct_path_item, 'direct_annotation.json'),'r',encoding='UTF8'))
            captions = self.load_captions(inv_ann_dict)
            captions += self.load_captions_weibo(direct_dict)
            imgs = self.load_imgs_direct_search(direct_path_item, direct_dict)
            qImg, qCap = self.load_queries(key)
            sample = {'label': label, 'caption': captions, 'imgs': imgs, 'qImg': qImg, 'qCap': qCap}
        else:
            direct_path_item = os.path.join(self.queries_root_dir, item['direct_path'])
            inverse_path_item = os.path.join(self.queries_root_dir, item['inv_path'])
            inv_ann_dict = json.load(open(os.path.join(inverse_path_item, 'inverse_annotation.json'),'r',encoding='UTF8'))
            direct_dict = json.load(open(os.path.join(direct_path_item, 'direct_annotation.json'),'r',encoding='UTF8'))
            captions = self.load_captions(inv_ann_dict)
            captions += self.load_captions_weibo(direct_dict)
            imgs = self.load_imgs_direct_search(direct_path_item, direct_dict)
            qImg, qCap = self.load_queries(key)
            sample = {'caption': captions, 'imgs': imgs, 'qImg': qImg, 'qCap': qCap}
        return sample, len(captions), imgs.shape[0]    
        # 返回样本(包含核查文本、核查图片、query图片、query文本),样本个数,图片个数

2)Dataloader
将dataset数据集传入DataLoader,实现批量读取数据。
dataset:传入的数据集
batch_size:每个batch有多少个样本
shuffle:在每个epoch开始的时候,对数据进行重新排序
collate_fn:指定如何将sample list组成一个mini-batch数据。传给它参数需要是一个callable对象,需要实现对组建的batch的处理逻辑,并返回每个batch的数据。在这里传入的是collate_context_bert_traincollate_context_bert_test函数。
return_list:数据是否以list形式返回

# load DataLoader
from paddle.io import DataLoader
train_dataloader = DataLoader(train_dataset, batch_size=4, shuffle=True, collate_fn = collate_context_bert_train, return_list=True)
val_dataloader = DataLoader(val_dataset, batch_size=4, shuffle=False, collate_fn = collate_context_bert_train,  return_list=True)
test_dataloader = DataLoader(test_dataset, batch_size=2, shuffle=False, collate_fn = collate_context_bert_test, return_list=True)

这里的mini-batch函数有两个,实现代码如下:

#文本行图像长度不一,需要自定义整理,进行格式大小统一,将数据整理成batch
def collate_context_bert_train(batch):
    #print(batch)
    samples = [item[0] for item in batch]
    max_captions_len = max([item[1] for item in batch])
    max_images_len = max([item[2] for item in batch])
    qCap_batch = []
    qImg_batch = []
    img_batch = []
    cap_batch = []
    labels = []
    for j in range(0,len(samples)):
        sample = samples[j]
        labels.append(sample['label'])
        captions = sample['caption']
        cap_len = len(captions)
        for i in range(0,max_captions_len-cap_len):
            captions.append("")
        if len(sample['imgs'].shape) > 2:
            padding_size = (max_images_len-sample['imgs'].shape[0], sample['imgs'].shape[1], sample['imgs'].shape[2], sample['imgs'].shape[3])
        else:
            padding_size = (max_images_len-sample['imgs'].shape[0],sample['imgs'].shape[1])
        padded_mem_img = paddle.concat((sample['imgs'], paddle.zeros(padding_size)),axis=0)
        img_batch.append(padded_mem_img)#pad证据图片
        cap_batch.append(captions)
        qImg_batch.append(sample['qImg'])#[3, 224, 224]
        qCap_batch.append(sample['qCap'])
    img_batch = paddle.stack(img_batch, axis=0)
    qImg_batch = paddle.stack(qImg_batch, axis=0)
    labels = paddle.stack(labels, axis=0)
    return labels, cap_batch, img_batch, qCap_batch, qImg_batch

def collate_context_bert_test(batch):
    samples = [item[0] for item in batch]
    max_captions_len = max([item[1] for item in batch])
    max_images_len = max([item[2] for item in batch])
    qCap_batch = []
    qImg_batch = []
    img_batch = []
    cap_batch = []
    for j in range(0,len(samples)):
        sample = samples[j]
        captions = sample['caption']
        cap_len = len(captions)
        for i in range(0,max_captions_len-cap_len):
            captions.append("")
        if len(sample['imgs'].shape) > 2:
            padding_size = (max_images_len-sample['imgs'].shape[0],sample['imgs'].shape[1],sample['imgs'].shape[2],sample['imgs'].shape[3])
        else:
            padding_size = (max_images_len-sample['imgs'].shape[0],sample['imgs'].shape[1])
        padded_mem_img = paddle.concat((sample['imgs'], paddle.zeros(padding_size)),axis=0)
        img_batch.append(padded_mem_img)
        cap_batch.append(captions)
        qImg_batch.append(sample['qImg'])
        qCap_batch.append(sample['qCap'])
    img_batch = paddle.stack(img_batch, axis=0)
    qImg_batch = paddle.stack(qImg_batch, axis=0)
    return cap_batch, img_batch, qCap_batch, qImg_batch

2、模型定义

主要是Network,其中ErnieMModel由于是预训练的模型,所以不需要写forward。

class EncoderCNN(nn.Layer):
    def __init__(self, resnet_arch = 'resnet101'):
        super(EncoderCNN, self).__init__()
        if resnet_arch == 'resnet101':
            resnet = models.resnet101(pretrained=True)
        modules = list(resnet.children())[:-2]
        self.resnet = nn.Sequential(*modules)
        self.adaptive_pool = nn.AdaptiveAvgPool2D((1, 1))
    def forward(self, images, features='pool'):
        out = self.resnet(images)
        if features == 'pool':
            out = self.adaptive_pool(out)
            out = paddle.reshape(out, (out.shape[0],out.shape[1]))
        return out

class NetWork(nn.Layer):
    def __init__(self, mode):
        super(NetWork, self).__init__()
        self.mode = mode
        self.ernie = ErnieMModel.from_pretrained('ernie-m-base')
        self.tokenizer = ErnieMTokenizer.from_pretrained('ernie-m-base')
        self.resnet = EncoderCNN()
        self.classifier1 = nn.Linear(2*(768+2048),1024)
        self.classifier2 = nn.Linear(1024,3)
        self.attention_text = nn.MultiHeadAttention(768,16)
        self.attention_image = nn.MultiHeadAttention(2048,16)
        if self.mode == 'text':
            self.classifier = nn.Linear(768,3)
        self.resnet.eval()

    def forward(self,qCap,qImg,caps,imgs):
        self.resnet.eval()
        encode_dict_qcap = self.tokenizer(text = qCap ,max_length = 128 ,truncation=True, padding='max_length')
        input_ids_qcap = encode_dict_qcap['input_ids']
        input_ids_qcap = paddle.to_tensor(input_ids_qcap)
        qcap_feature, pooled_output= self.ernie(input_ids_qcap) #(b,length,dim)
        if self.mode == 'text':
            logits = self.classifier(qcap_feature[:,0,:].squeeze(1))
            return logits
        caps_feature = []
        for i,caption in enumerate (caps):
            encode_dict_cap = self.tokenizer(text = caption ,max_length = 128 ,truncation=True, padding='max_length')
            input_ids_caps = encode_dict_cap['input_ids']
            input_ids_caps = paddle.to_tensor(input_ids_caps)
            cap_feature, pooled_output= self.ernie(input_ids_caps) #(b,length,dim)
            caps_feature.append(cap_feature)
        caps_feature = paddle.stack(caps_feature,axis=0) #(b,num,length,dim)
        caps_feature = caps_feature.mean(axis=1)#(b,length,dim)
        caps_feature = self.attention_text(qcap_feature,caps_feature,caps_feature) #(b,length,dim)
        imgs_features = []
        for img in imgs:
            imgs_feature = self.resnet(img) #(length,dim)
            imgs_features.append(imgs_feature)
        imgs_features = paddle.stack(imgs_features,axis=0) #(b,length,dim)
        qImg_features = []
        for qImage in qImg:
            qImg_feature = self.resnet(qImage.unsqueeze(axis=0)) #(1,dim)
            qImg_features.append(qImg_feature)
        qImg_feature = paddle.stack(qImg_features,axis=0) #(b,1,dim)
        imgs_features = self.attention_image(qImg_feature,imgs_features,imgs_features) #(b,1,dim)
        # [1, 128, 768] [1, 128, 768] [1, 1, 2048] [1, 1, 2048] origin
        # print(qcap_feature.shape,caps_feature.shape,qImg_feature.shape,imgs_features.shape)
        # print((qcap_feature[:,0,:].shape,caps_feature[:,0,:].shape,qImg_feature.squeeze(1).shape,imgs_features.squeeze(1).shape))
        # ([1,768], [1 , 768], [1, 2048], [1,  2048])
        feature = paddle.concat(x=[qcap_feature[:,0,:], caps_feature[:,0,:], qImg_feature.squeeze(1), imgs_features.squeeze(1)], axis=-1)
        logits = self.classifier1(feature)
        logits = self.classifier2(logits)
        return logits

model = NetWork("image")

3、模型训练

训练参数设置,包含训练周期,学习率lr,优化器,损失函数,评估指标等

# train_setting
epochs = 2    #迭代周期为2,每个周期都会生成一组模型参数
num_training_steps = len(train_dataloader) * epochs
warmup_steps = int(num_training_steps*0.1)
print(num_training_steps,warmup_steps)      #5592 559
# 定义 learning_rate_scheduler,负责在训练过程中对 lr 进行调度
lr_scheduler = LinearDecayWithWarmup(1e-6, num_training_steps, warmup_steps)
# 训练结束后,存储模型参数
save_dir ="checkpoint/"   #该目录是指在每个周期中最终保存的模型参数
best_dir = "best_model"   #该目录为最好的模型参数,即为最终预测需要的模型参数
# 创建保存的文件夹
os.makedirs(save_dir,exist_ok=True)
os.makedirs(best_dir,exist_ok=True)

decay_params = [
    p.name for n, p in model.named_parameters()
    if not any(nd in n for nd in ["bias", "norm"])
]

# 定义优化器 Optimizer
optimizer = paddle.optimizer.AdamW(
    learning_rate=lr_scheduler,
    parameters=model.parameters(),
    weight_decay=1.2e-4, 
    apply_decay_param_fun=lambda x: x in decay_params)

# 定义损失函数,交叉熵损失
criterion = paddle.nn.loss.CrossEntropyLoss()

# 评估的时候采用准确率指标
metric = paddle.metric.Accuracy()

# 定义线下评估 评价指标为acc,注意线上评估是macro-f1 score
@paddle.no_grad()
def evaluate(model, criterion, metric, data_loader):
    model.eval()
    metric.reset()
    losses = []
    for batch in data_loader:
        labels, cap_batch, img_batch, qCap_batch, qImg_batch = batch
        logits = model(qCap=qCap_batch,qImg=qImg_batch,caps=cap_batch,imgs=img_batch)
        loss = criterion(logits, labels)
        losses.append(loss.numpy())
        correct = metric.compute(logits, labels)
        metric.update(correct)
        accu = metric.accumulate()
    print("eval loss: %.5f, accu: %.5f" % (np.mean(losses), accu))
    model.train()
    metric.reset()
    return np.mean(losses), accu

定义训练,包含五个部分:模型,损失函数,评价指标,训练dataloader,验证dataloader

def do_train(model, criterion, metric, val_dataloader, train_dataloader):
    print("train run start")
    global_step = 0
    tic_train = time.time()
    best_accuracy = 0.0
    for epoch in range(1, epochs + 1):
        for step, batch in enumerate(train_dataloader, start=1):
            labels, cap_batch, img_batch, qCap_batch, qImg_batch = batch
            probs = model(qCap=qCap_batch, qImg=qImg_batch, caps=cap_batch, imgs=img_batch)
            loss = criterion(probs, labels)
            correct = metric.compute(probs, labels)
            metric.update(correct)
            acc = metric.accumulate()

            global_step += 1
            # 每间隔 100 step 输出训练指标
            if global_step % 100 == 0:
                print(
                    "global step %d, epoch: %d, batch: %d, loss: %.5f, accu: %.5f, speed: %.2f step/s"
                    % (global_step, epoch, step, loss, acc,
                       10 / (time.time() - tic_train)))
                tic_train = time.time()
            loss.backward()
            optimizer.step()
            lr_scheduler.step()
            optimizer.clear_grad()

            # 每间隔一个epoch 在验证集进行评估
            if global_step % len(train_dataloader) == 0:
                eval_loss, eval_accu = evaluate(model, criterion, metric, val_dataloader)
                save_param_path = os.path.join(save_dir + str(epoch), 'model_state.pdparams')
                paddle.save(model.state_dict(), save_param_path)
                if (best_accuracy < eval_accu):
                    best_accuracy = eval_accu
                    # 保存模型
                    save_param_path = os.path.join(best_dir, 'model_best.pdparams')
                    paddle.save(model.state_dict(), save_param_path)
                    
do_train(model, criterion, metric, val_dataloader, train_dataloader)

4、模型预测

在预测模型前,需要重启内核,释放了内存(图片数据很吃内存)。

需要重新运行第一块和第二块的代码,再运行以下代码:

params_path = 'best_model/model_best.pdparams'

#加载训练好的模型参数
if params_path and os.path.isfile(params_path):
    # 加载模型参数
    state_dict = paddle.load(params_path)
    model.set_dict(state_dict)
    print("Loaded parameters from %s" % params_path)
 
results = []
# 切换model模型为评估模式,关闭dropout等随机因素
id2name ={ 0:"non-rumor", 1:"rumor",2:"unverified"}
model.eval()
count=0
bar = tqdm(test_dataloader, total=len(test_dataloader))
for batch in bar:
    count+=1
    cap_batch, img_batch, qCap_batch, qImg_batch = batch
    logits = model(qCap=qCap_batch,qImg=qImg_batch,caps=cap_batch,imgs=img_batch)
    # 预测分类
    probs = F.softmax(logits, axis=-1)
    label = paddle.argmax(probs, axis=1).numpy()
    results += label.tolist()

print(results[:5])
print(len(results))
results = [id2name[i] for i in results]

输出结果

#id/label
#字典中的key值即为csv中的列名
id_list=range(len(results))
print(id_list)
frame = pd.DataFrame({'id':id_list,'label':results})
frame.to_csv("result.csv",index=False,sep=',')

# 根据要求打包
!zip test.zip result.csv 

三、写在最后

讲讲最精华的部分,需要从哪些地方入手来提升模型,谈谈我的理解:

1、数据源:数据并不干净,图片数据量很大,是否有操作空间
2、数据特征:抽取的数据特征是否存在信息丢失,或者说能补充更多通过数据探索发现的规律特征
3、模型选择:baseline是一个比较稳的方式,也可以尝试
4、参数调整:这部分尽量放到最后做,好的参数也可能让模型work更好

本次记录主要还是以学习为主,抽了工作之余来进行baseline的翻译和整理。探索了一个带大家最快上手的路径,降低大家的入门难度。

看完觉得有用的话,记得点个赞,不做白嫖党~

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

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

相关文章

ExtJs 7.7.0 下载方法与去除trial水印

背景 最近发现Sencha ExtJs发布了ExtJs7.7.0版本&#xff0c;立刻下载了SDK包&#xff0c;许多朋友不知如何下载&#xff0c;如何去除右上角的trial水印。本文讲下相关下载技巧与方法。 下载SDK 首先需要申请试用&#xff0c;申请地址如下&#xff0c;需要注意可能需要梯子&…

好烦!快让ChatGPT停止道歉!SD创作宣传图的超细教程;教你在PH冷启动薅流量;CSDN举办AI应用创新大赛 | ShowMeAI日报

&#x1f440;日报&周刊合集 | &#x1f3a1;生产力工具与行业应用大全 | &#x1f9e1; 点赞关注评论拜托啦&#xff01; &#x1f916; Stable Diffusion 图生图入门&#xff0c;一份详细的思维导图 &#x1f916; DeeCamp X CSDN 举办AI应用创新大赛&#xff0c;万元奖金…

【C++】继承的基本特性(定义,赋值转换,友元,静态成员,虚拟继承,默认成员函数,作用域)

文章目录 一、继承的定义1.定义格式2.继承基类成员访问方式的变化 二、基类和派生类对象赋值转换三、继承的作用域1. 在继承体系中基类和派生类都有独立的作用域。2.子类和父类中有同名成员3.成员函数的隐藏4.注意在实际中在继承体系里面最好不要定义同名的成员。 四、派生类的…

【C语言学习】整数类型表达数的范围

一、整数类型表达数的范围 1.char类型 char 是1个字节 &#xff0c;即00000000 ~ 11111111&#xff0c;一般情况默认是有符号char(signed char) ,此时char所能表达的数就是 -128 ~ 127&#xff0c;即 -2 ^ n-1 ~ (2 ^ n-1)-1 ,其中n是位数或比特位&#xff08;1字节8位8比特&…

OPENCV C++(四)形态学操作+连通域统计

形态学操作 先得到一个卷积核 Mat kernel getStructuringElement(MORPH_RECT,Size(5,5)); 第一个是形状 第二个是卷积核大小 依次为腐蚀 膨胀 开运算 闭运算 Mat erodemat,dilatemat,openmat,closemat;morphologyEx(result1, erodemat, MORPH_ERODE, kernel);morphologyEx…

万界星空科技/免费开源MES系统/免费仓库管理

仓库管理&#xff08;仓储管理&#xff09;&#xff0c;指对仓库及仓库内部的物资进行收发、结存等有效控制和管理&#xff0c;确保仓储货物的完好无损&#xff0c;保证生产经营活动的正常进行&#xff0c;在此基础上对货物进行分类记录&#xff0c;通过报表分析展示仓库状态、…

道本科技受邀参加建筑产业互联网推动建筑产业现代化体系构建座谈会,以数字化产品为建筑行业注入新动能!

2023年7月底&#xff0c;道本科技作为中国建筑业协会合作伙伴&#xff0c;受邀参加了建筑产业互联网推动建筑产业现代化体系构建座谈会。在这次座谈会上&#xff0c;道本科技旗下产品“合规数”“合同智能审查”和“智合同范本库”被中国建筑&#xff08;中小企业&#xff09;产…

Leaflet.Control.Opacity 控制图层的透明度

最新有一个需求&#xff0c;能动态的控制Leaflet.js 地图图层的透明度&#xff0c;官网文档: https://leafletjs.com/reference.html#gridlayer-setopacity 一直有个setOpacity方法&#xff0c;我以为拿来就能使呢&#xff0c;其实不行。后来找到一个日本人开发的demo: 右侧Co…

部署SpringBoot项目在服务器上,并通过swagger登录

1.项目编译打包 2.上传jar包到服务器并启动 xftp将打包好后的jar包传到虚拟机指定路径 java -jar执行该jar包 3.通过swagger登录 输入后点击下面的执行按钮 会得到一个tocken 4.将tocken放到postman的Headers中 5.修改url 例如我本地测试是http://localhost:8080/接口名&am…

关于Java的未来探讨,看看国外开发者怎么说的

博主在浏览 medium 社区时&#xff0c;发现了一篇点赞量 1.5k 的文章&#xff0c;名称叫《Java is Dead — 5 Misconceptions of developers that still think Java is relevant today!》直译过来就是《Java 已死 — 开发人员对 Java 在现代编程语言中的5个误解》。这篇文章可以…

层叠上下文

一、层叠上下文 在CSS2.1规范中&#xff0c;每个盒模型的位置是三维的&#xff0c;分别是平面画布上的x轴&#xff0c;y轴以及表示层叠的z轴&#xff0c;层叠上下文即元素在某个层级上z轴方向的排列关系。假定用户正面向&#xff08;浏览器&#xff09;视窗或网页&#xff0c;…

合并pdf怎么合并?试试这几种方法

合并pdf怎么合并&#xff1f;合并PDF文件是处理PDF文件时最基本的需求之一。在日常工作和生活中&#xff0c;我们可能需要将多个PDF文件合并成一个文件&#xff0c;以方便管理、浏览和分享。下面就给大家介绍几种PDF合并的方法。 首先&#xff0c;让我们介绍一下【迅捷PDF转换器…

项目中引用svg图标,公共组件SvgIcon使用,注册全局组件,使用自定义插件注册全局组件

在开发项目的时候经常会用到svg矢量图,而且我们使用SVG以后&#xff0c;页面上加载的不再是图片资源, 这对页面性能来说是个很大的提升&#xff0c;而且我们SVG文件比img要小的很多&#xff0c;放在项目中几乎不占用资源。 1、安装依赖插件 pnpm install vite-plugin-svg-ic…

API是什么?

API是什么&#xff1f; API&#xff08;Application Programming Interface,应用程序编程接口&#xff09;是一些预先定义的函数&#xff0c;目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力&#xff0c;而又无需访问源码&#xff0c;或理解内部工作机制…

SAP BAPI BAPI_SALESDOCUMENT_COPY 直接实现VA01复制销售合同创建小搜订单

BAPI :BAPI_SALESDOCUMENT_COPY 输入参数 &#xff1a; 销售合同、订单类型 输出参数&#xff1a;生成的销售订单号 实现的操作:

自动分班软件:一分钟制作分班查询系统,这个工具轻松实现

作为一名老师&#xff0c;在即将到来的新学期&#xff0c;我们需要进行学生的分班工作&#xff0c;而分班查询系统可以帮助我们更加高效地完成这项工作。在这篇文章中&#xff0c;我将向大家介绍如何创建一个分班查询系统。 首先&#xff0c;我们需要确定分班查询系统的需求和…

java八股文补充

1、JAVA BIO、NIO、AIO的区别 BIO &#xff08;Blocking I/O&#xff09;&#xff1a;同步阻塞I/O模式。当有其他线程进行数据读写时阻塞等待。当用户线程发出IO请求之后&#xff0c;内核会去查看数据是否就绪&#xff0c;如果没有就绪就会等待&#xff0c;用户线程就会处于阻…

Linux下多python版本共存

python下载官网 https://www.python.org/downloads/ python支持多版本共存&#xff0c;是大版本共存&#xff0c;小版本不共存。 python3.6 和 3.7 共存python3.6.6和python3.6.8 不共存 1.下载特定版本的python 进入官网后点击Downloads–>All releases点击‘Gzipped s…

在职读研想要成功上岸,社科院杜兰大学金融管理硕士机不可失

近年来&#xff0c;中国考研报名人数节节攀升&#xff0c;2023年考研报名人数达到了474万。在如此庞大的考生群体中&#xff0c;成功被录取的人数却不足两成&#xff0c;这一数字引起了社会各界广泛的热议和关注。招生规模如此浩大&#xff0c;录取率却如此之低。其实考研录取率…

【2023年电赛国一必备】C题报告模板--可直接使用

任务 图1 任务内容 要求 图2 基本要求内容 图3 发挥部分内容 说明 图4 说明内容 评分标准 图5 评分内容 正文 &#xff08;部分&#xff09; 摘要 本实验基于TI公司的TM4C123GH6PM主控&#xff0c;结合OPA2337芯片和其他硬件模块&#xff0c;设计并制作了一种单相逆变器…