【NLP笔记】预训练+微调范式之OpenAI Transformer、ELMo、ULM-FiT、Bert..

文章目录

  • OpenAI Transformer
  • ELMo
  • ULM-FiT
  • Bert
    • 基础结构
    • Embedding
    • 预训练&微调

【原文链接】: BERT: Pre-training of Deep Bidirectional Transformers for
Language Understanding

【本文参考链接】

  • The Illustrated BERT, ELMo, and co. (How NLP Cracked Transfer Learning)
  • 【NLP从入门到大模型】5.图解Bert

【其他值得关注的预训练+微调范式模型】

  • 【深度学习】GPT-1
  • GPT系列:GPT-2详解
  • RoBERTa 详解(Bert改进模型)
  • XLNet模型(Bert改进模型)
  • ALBert 详解(Bert改进模型)

2018年前后有很多著名的NLP相关的论文产出,形成了一种预训练语义表征模型+下游任务微调的范式,其中长期内影响力较大的之一Bert。

OpenAI Transformer

OpenAI Transformer(OpenAI的Transformer模型)是在2017年底提出的。它是由OpenAI团队提出的一种基于Transformer架构的语言模型,用于处理自然语言处理任务。OpenAI Transformer是一个堆叠的12层Decoder结构(Decoder-Only),在解码器的注意力模块中,由于没有Encoder,所以就不是Cross-Attention,改为self-attention+mask的方式。
在这里插入图片描述
整个训练过程是无监督的,使用大量的未标记数据集训练,将预测下一个词汇作为模型的预测目标。然后预训练好的Transformer结构(Decoder-Only)后面再加上简单的网络结构进行参数调整,并设定目标场景的预测结果,就实现了通过微调去适应下游任务。
在这里插入图片描述

ELMo

ELMo(Embedding for Language Model)是由斯坦福大学的研究团队在2018年提出的,是一种基于双向 LSTM(长短期记忆)模型的语言表示方法,通过在大规模语料库上训练的双向 LSTM 模型来生成深度上下文相关的词向量。
在这里插入图片描述

大语言模型通过海量数据训练出来的Tokenizer可直接用于文本向量化,开源的大模型Tokenizer使得大家能通过下载已经开源的词嵌入模型来完成NLP的任务。Word2vec是将单词固定为指定长度的向量,和以往的经典词嵌入模型不同的是,ELMo则是在为每个单词分配词向量之前先查看整个句子,然后使用bi-LSTM结合上下文语境来训练它对应的词向量。
在这里插入图片描述

ELMo会训练一个模型,这个模型接受一个句子或者单词的输入,输出最有可能出现在后面的一个单词,采用海量语料进行无监督训练。ELMo通过下图的方式将hidden states的状态组合起来提炼出具有语境意义的词嵌入方式(全连接后加权求和)。
在这里插入图片描述

ULM-FiT

ULM-FiT(Universal Language Model Fine-tuning)是一种用于迁移学习的技术,由 Jeremy Howard 和 Sebastian Ruder 在2018年提出。它基于递归神经网络(RNN)构建的语言模型,并使用了一系列创新的技术来提高迁移学习的效果。

ULM-FiT 的核心思想是首先在大规模的通用语料库上训练一个通用的语言模型,然后通过微调(Fine-tuning)的方式,将这个通用模型应用于特定的任务。具体来说,ULM-FiT 包含以下几个关键步骤:

预训练通用语言模型:首先,在大规模的通用语料库上训练一个通用的语言模型,比如基于AWD-LSTM(ASGD Weight-Dropped LSTM)的语言模型。这个通用模型可以捕捉语言的一般规律和语义信息。

微调:接下来,将预训练的通用模型在特定任务的数据集上进行微调,以适应特定任务的语言模式和特征。微调的过程包括在任务数据上进行进一步的训练,并对模型进行调整以提高任务性能。

多阶段微调策略:ULM-FiT 提出了一种多阶段微调的策略,其中包括逐层解冻和差异学习率调整等技术,以提高微调的效果。这种策略可以使模型逐步适应新任务的特征,从而更好地利用预训练的知识。

ULM-FiT 已经在许多自然语言处理任务中取得了显著的成功,包括文本分类、命名实体识别、情感分析等。它的主要优势在于通过预训练通用模型和微调的方式,能够在少量标注数据的情况下快速有效地解决特定任务。

Bert

BERT 是由Google在2018年10月发布的。它是一种基于Transformer模型的语言表示方法,通过在大规模文本数据上进行预训练来学习文本的语义表示。BERT 通过Masked Language Modeling(MLM)和Next Sentence Prediction(NSP)等任务来训练模型,可以捕捉文本序列中的双向语境信息,取得了在多项自然语言处理任务上的领先性能。Bert的训练模式是半监督预训练(Pre-train)+有监督的微调(fine-tuning),预训练出一个强大的文本表征模型,然后根据具体任务进行微调,实现在特定任务上的应用。Goole开源这个模型,并提供预训练好的模型,这使得所有人都可以通过它来构建一个涉及NLP的算法模型,节约了大量训练语言模型所需的时间、精力、知识和资源。

在这里插入图片描述

基础结构

Bert的基础架构是一个堆叠多层的Encoder架构,参数量更大的Bert就是对应的层数更多(如:Bert-base有12层Encoder,Bert-Large共24层Encoder),Bert就是一种Encoder-Only的架构。
在这里插入图片描述
BERT与Transformer 的编码方式一样。将固定长度的字符串作为输入,数据由下而上传递计算,每一层都用到了self attention,并通过前馈神经网络传递其结果,将其交给下一个编码器。
在这里插入图片描述
每个位置返回的输出都是一个隐藏层大小的向量(Base版本BERT为768),该输出向量可以作为下游微调任务的输入向量,在论文中指出使用单层神经网络作为分类器就可以取得很好的效果。
在这里插入图片描述

Embedding

BERT 模型中的词向量(Word Embedding)、位置编码(Positional Encoding)、以及段落编码(Segment Embedding)是通过一系列的处理步骤得到的:

  1. 词向量(Word Embedding)
    BERT 使用了 WordPiece 或 Byte-Pair Encoding(BPE)等分词算法将输入文本序列分割成词语或子词(subwords)。然后,每个词语或子词都被映射为一个固定长度的向量,这个过程就是词向量。BERT 模型使用了多层的词向量表示,其中包括 WordPiece Embeddings 和 Token Type Embeddings。WordPiece Embeddings 将每个词语或子词映射为一个固定长度的向量,而 Token Type Embeddings 用于区分不同句子之间的关系(同Transformer)。
  2. 位置编码(Positional Encoding)
    在 BERT 模型中,位置编码用于向词向量中添加关于词语或子词在序列中位置的信息。BERT 使用了一种特殊的位置编码方法,通常是通过加法或者叠加来将位置编码添加到词向量中。这种位置编码能够为模型提供关于词语在序列中相对位置的信息,从而帮助模型理解文本的顺序关系(同Transformer)。
  3. 段落编码(Segment Embedding)
    在一些需要处理多个句子的任务中,BERT 还会添加段落编码以区分不同句子之间的关系。段落编码通常是一个固定长度的向量,用于区分不同句子所属的段落或者句子之间的关系。在输入序列中,通过在句子的开头添加特殊的标记(比如 [CLS] 标记)来表示句子的开始,然后添加段落编码来区分不同句子之间的关系(如:第一个句子编码段落token全为0,第二个全为1)。

在这里插入图片描述

预训练&微调

前面有说过Bert的模式也是预训练+下游任务微调,如下图所示:
在这里插入图片描述

  1. 预训练
  • Masked Language Modeling(MLM):通过随机掩盖序列中的一些token,让模型去预测被掩盖的token是什么。如在训练过程中随机mask 15%的token,其中80%的序列我们用[MASK]去取代要掩码的token,10%的序列我们将待掩码token随机替换为其他token,10%的序列保持不变,最终的损失函数只计算被mask掉的那个token。
  • Next Sentence Prediction(NSP):让模型理解两个句子之间的联系。训练的输入是句子A和B,B有一半的几率是A的下一句,输入这两个句子,模型预测B是不是A的下一句。预训练的时候可以达到97-98%的准确度。

模型地址:https://huggingface.co/google-bert/bert-base-chinese

# 安装新版本(>=4.0)的transformer,内置bert
from transformers import AutoTokenizer, AutoModelForMaskedLM
# 加载Tokenizer
tokenizer = AutoTokenizer.from_pretrained("bert-base-chinese")
# 加载模型
model = AutoModelForMaskedLM.from_pretrained("bert-base-chinese")

# MLM任务测试
# BERT 在预训练中引入了 [CLS] 和 [SEP] 标记句子的开头和结尾,准备输入模型的语句
text = '中国的首都是哪里? 北京是 [MASK] 国的首都。'  
inputs = tokenizer(text, return_tensors='pt')
# 获取MASK的位置
mask_position = inputs["input_ids"].tolist()[0].index(tokenizer.mask_token_id)
print("tokenized txt: {}".format(inputs))
# 使用模型进行预测
with torch.no_grad():
    outputs = bert_model(**inputs).logits

# 获取MASK位置的预测分数,并找到预测得分最高的token
predicted_token_idx = outputs[0, mask_position].argmax().item()
predicted_token = tokenizer.convert_ids_to_tokens([predicted_token_idx])[0]

print(f"The masked token in '{text}' is predicted as '{predicted_token}'")

# NSP任务测试
model_path = 'bert-base-chinese'
tokenizer = BertTokenizer.from_pretrained(model_path)
model = BertForNextSentencePrediction.from_pretrained(model_path)

sen_code1 = tokenizer.encode_plus('今天天气怎么样', '今天天气很好')
sen_code2 = tokenizer.encode_plus('小明今年几岁了', '今天天空很蓝')
tokens_tensor = torch.tensor([sen_code1['input_ids'], sen_code2['input_ids']])

model.eval()

outputs = model(tokens_tensor)
seq_relationship_scores = outputs[0]  # seq_relationship_scores.shape= torch.Size([2, 2])
sample = seq_relationship_scores.detach().numpy()  # sample.shape = (2, 2)

pred = np.argmax(sample, axis=1)
print(pred)
# [0 1] 0表示是上下句,1表示不是上下句
  1. 微调
    在这里插入图片描述
    Bert可以实现的几种微调任务:短文本相似 、文本分类、QA机器人、语义标注等微调任务,下面以一个任务为例:
# 下载文本分类数据集
wget http://github.com/skdjfla/toutiao-text-classfication-dataset/raw/master/toutiao_cat_data.txt.zip
import codecs
import json

import torch
from sklearn.model_selection import train_test_split
from torch.utils.data import Dataset, DataLoader
import numpy as np
from transformers import BertTokenizer
from transformers import BertForSequenceClassification, get_linear_schedule_with_warmup


class NewsDataset(Dataset):
    """
    新闻分类数据集
    """

    def __init__(self, encodings, labels):
        self.encodings = encodings
        self.labels = labels

    # 读取单个样本
    def __getitem__(self, idx):
        item = {key: torch.tensor(val[idx]) for key, val in self.encodings.items()}
        item['labels'] = torch.tensor(int(self.labels[idx]))
        return item

    def __len__(self):
        return len(self.labels)


class NewsClassifier(object):
    """
    新闻分类器
    """

    @classmethod
    def finetuning(cls):
        """
        微调新闻分类器
        """
        model_path = 'bert-base-chinese'
        # 加载预训练的向量化模型
        tokenizer = BertTokenizer.from_pretrained(model_path)
        # 加载预训练的分类模型
        model = BertForSequenceClassification.from_pretrained(model_path, num_labels=17)
        device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
        model.to(device)
        # 加载数据集
        train_dataset, test_dataset = cls.load_dataset(tokenizer)
        # 单个读取到批量读取
        train_loader = DataLoader(train_dataset, batch_size=16, shuffle=True)
        test_dataloader = DataLoader(test_dataset, batch_size=16, shuffle=True)
        # 优化方法
        optim = torch.optim.AdamW(model.parameters(), lr=2e-5)
        total_steps = len(train_loader) * 1
        scheduler = get_linear_schedule_with_warmup(optim,
                                                    num_warmup_steps=0,  # Default value in run_glue.py
                                                    num_training_steps=total_steps)
        for epoch in range(1):
            print("------------Epoch: %d ----------------" % epoch)
            cls.train(model, train_loader, optim, device, scheduler, epoch)
            cls.validation(model, test_dataloader, device)

        model.save_pretrained("output/bert-news-clf")
        tokenizer.save_vocabulary("output/bert-news-clf")

    @classmethod
    def train(cls, model, train_loader, optim, device, scheduler, epoch):
        """
        训练函数
        """
        model.train()
        total_train_loss = 0
        iter_num = 0
        total_iter = len(train_loader)
        for batch in train_loader:
            # 正向传播
            optim.zero_grad()
            input_ids = batch['input_ids'].to(device)
            attention_mask = batch['attention_mask'].to(device)
            labels = batch['labels'].to(device)
            outputs = model(input_ids, attention_mask=attention_mask, labels=labels)
            loss = outputs[0]
            total_train_loss += loss.item()

            # 反向梯度信息
            loss.backward()
            torch.nn.utils.clip_grad_norm_(model.parameters(), 1.0)

            # 参数更新
            optim.step()
            scheduler.step()

            iter_num += 1
            if iter_num % 100 == 0:
                print("epoth: %d, iter_num: %d, loss: %.4f, %.2f%%" % (
                    epoch, iter_num, loss.item(), iter_num / total_iter * 100))

        print("Epoch: %d, Average training loss: %.4f" % (epoch, total_train_loss / len(train_loader)))

    @classmethod
    def flat_accuracy(cls, preds, labels):
        """
        计算准确率
        """
        pred_flat = np.argmax(preds, axis=-1).flatten()
        labels_flat = labels.flatten()
        return np.sum(pred_flat == labels_flat) / len(labels_flat)

    @classmethod
    def validation(cls, model, test_dataloader, device):
        """
        验证函数
        """
        model.eval()
        total_eval_accuracy = 0
        total_eval_loss = 0
        for batch in test_dataloader:
            with torch.no_grad():
                # 正常传播
                input_ids = batch['input_ids'].to(device)
                attention_mask = batch['attention_mask'].to(device)
                labels = batch['labels'].to(device)
                outputs = model(input_ids, attention_mask=attention_mask, labels=labels)

            loss = outputs[0]
            logits = outputs[1]

            total_eval_loss += loss.item()
            logits = logits.detach().cpu().numpy()
            label_ids = labels.to('cpu').numpy()
            total_eval_accuracy += cls.flat_accuracy(logits, label_ids)

        avg_val_accuracy = total_eval_accuracy / len(test_dataloader)
        print("Accuracy: %.4f" % avg_val_accuracy)
        print("Average testing loss: %.4f" % (total_eval_loss / len(test_dataloader)))
        print("-------------------------------")

    @classmethod
    def load_dataset(cls, tokenizer):
        """
        加载新闻分类数据集
        """
        data_path = 'dataset/toutiao_cat_data.txt'
        # 标签
        news_label = [int(x.split('_!_')[1]) - 100 for x in codecs.open(data_path)]
        # 存储标签
        label_text_json = {}
        for x in codecs.open(data_path):
            groups = x.split('_!_')
            label_text_json[int(x.split('_!_')[1]) - 100] = groups[2]
        with open('output/news_label.json', 'w') as file_obj:
            json.dump(label_text_json, file_obj, indent=4)

        # 文本
        news_text = [x.strip().split('_!_')[-1] if x.strip()[-3:] != '_!_' else x.strip().split('_!_')[-2]
                     for x in codecs.open(data_path)]

        # 划分为训练集和验证集
        # stratify 按照标签进行采样,训练集和验证部分同分布
        x_train, x_test, train_label, test_label = train_test_split(news_text[:50000],
                                                                    news_label[:50000],
                                                                    test_size=0.2,
                                                                    stratify=news_label[:50000])

        train_encoding = tokenizer(x_train, truncation=True, padding=True, max_length=64)
        test_encoding = tokenizer(x_test, truncation=True, padding=True, max_length=64)

        train_dataset = NewsDataset(train_encoding, train_label)
        test_dataset = NewsDataset(test_encoding, test_label)
        return train_dataset, test_dataset

    @classmethod
    def predict(cls):
        """
        微调后的模型预测函数
        """
        s = '金价下跌预示着什么?'

        model_path = 'output/bert-news-clf'
        tokenizer = BertTokenizer.from_pretrained(model_path)
        model = BertForSequenceClassification.from_pretrained(model_path, num_labels=17)

        sen_code = tokenizer.encode_plus(s)
        tokens_tensor = torch.tensor([sen_code['input_ids']])
        attention_mask = torch.tensor([sen_code['attention_mask']])

        model.eval()

        outputs = model(tokens_tensor, attention_mask)
        outputs = outputs[0].detach().numpy()
        print(outputs)
        outputs = outputs[0].argmax(0)
        print(outputs)
        # 4

        with open('output/news_label.json') as file_obj:
            news_label_json = json.load(file_obj)
            print(news_label_json[str(outputs)])
            # news_finance


if __name__ == '__main__':
    # 微调
    NewsClassifier.finetuning()
    # 调用微调的模型进行预测
    NewsClassifier.predict()

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

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

相关文章

单片机LED灯闪烁

延时函数计算&#xff08;相关代码生成&#xff09;&#xff1a; #include "reg52.h" #include <INTRINS.H> void Delay500ms() //11.0592MHz {unsigned char i, j, k;_nop_();_nop_();i 22;j 3;k 227;do{do{while (--k);} while (--j);} while (--i); }vo…

以太网协议(数据链路层)

一些基础知识: 平时使用的网线,也叫做"以太网线".平时使用的交换机,也叫做"以太网交换机".以太网这个协议,既涉及到数据链路层的内容,也涉及到物理层的内容. 1. 以太网帧的格式 ①目的地址,源地址: 此处的地址,叫做mac地址(物理地址).作用也是区分不同…

水果软件FL Studio 21 for mac 21.2.3.3586破解版的最新版本2024介绍安装

音乐是人类最美好的语言&#xff0c;它能够跨越国界、文化和语言&#xff0c;将人们紧密地联系在一起。在当今数字化时代&#xff0c;音乐创作已经不再是专业人士的专利&#xff0c;越来越多的音乐爱好者开始尝试自己动手制作音乐。而FL Studio21中文版编曲软件正是这样一个为你…

Linux:点命令source

相关阅读 Linuxhttps://blog.csdn.net/weixin_45791458/category_12234591.html?spm1001.2014.3001.5482 source命令用于读取一个文件的内容并在当前Shell环境&#xff08;包括交互式Shell或是非交互式Shell&#xff09;执行里面的命令。它被称为点命令是因为命令名source也可…

【Web应用技术基础】HTML(4)——表单类的标签

目录 题目1&#xff1a;文本框 题目2&#xff1a;密码框 题目3&#xff1a;单选框 题目4&#xff1a;多选框 题目5&#xff1a;单选框选中 题目6&#xff1a;禁用disabled 题目7&#xff1a;lable标签 题目8&#xff1a;下拉框 题目9&#xff1a;textarea 题目10&…

【STM32】读写BKP备份寄存器RTC实时时钟

目录 BKP BKP简介 BKP基本结构 BKP测试代码 RTC RTC简介 RTC框图 RTC基本结构 硬件电路 RTC操作注意事项 接线图 初始化 使用BKP解决只初始化一次时间 初始化参考代码 RTC设置时间 RTC读取时间 完整代码 MyRTC.c MyRTC.h main.c BKP BKP简介 BKP&#xff0…

05.自定义指令,插槽和路由配置

一、学习目标 1.自定义指令 基本语法&#xff08;全局、局部注册&#xff09;指令的值v-loading的指令封装 2.插槽 默认插槽具名插槽作用域插槽 3.综合案例&#xff1a;商品列表 MyTag组件封装MyTable组件封装 4.路由入门 单页应用程序路由VueRouter的基本使用 一、自…

基于 HBase Phoenix 构建实时数仓(5)—— 用 Kafka Connect 做实时数据同步

目录 一、总体架构 二、安装配置 MySQL 1. 创建 mysql 用户 2. 建立 MySQL 使用的目录 3. 解压安装包 4. 配置环境变量 5. 创建 MySQL 配置文件 6. MySQL 系统初始化 7. 启动 mysql 服务器 8. 创建 dba 用户 三、配置 MySQL 主从复制 四、安装部署 Kafka Connector…

【机器学习】k近邻(k-nearest neighbor )算法

文章目录 0. 前言1. 算法原理1.1 距离度量1.2 参数k的选择 2. 优缺点及适用场景3. 改进和扩展4. 案例5. 总结 0. 前言 k近邻&#xff08;k-nearest neighbors&#xff0c;KNN&#xff09;算法是一种基本的监督学习算法&#xff0c;用于分类和回归问题。k值的选择、距离度量及分…

(2024,YOSO,自协同学习,扩散 GAN,单步生成)您只需采样一次:通过自协同扩散 GAN 驯服一步文本到图像合成

You Only Sample Once: Taming One-Step Text-To-Image Synthesis by Self-Cooperative Diffusion GANs 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 相关工作 3. 背景…

Vue3 中应该使用 Ref 还是 Reactive?

一、引言 在Vue 3中&#xff0c;构建响应式数据结构是构建用户界面和交互体验的核心部分。而在创建这些响应式数据时&#xff0c;我们有两个主要工具&#xff1a;reactive和ref。选择使用哪一个&#xff0c;实际上取决于你的数据结构和访问需求。 reactive主要用于处理复杂的数…

麒麟 V10 一键安装 Oracle 19C 19.22 单机版

Oracle 一键安装脚本&#xff0c;演示 麒麟 V10 一键安装 Oracle 19C 19.22 单机版过程&#xff08;全程无需人工干预&#xff09;&#xff1a;&#xff08;脚本包括 ORALCE PSU/OJVM 等补丁自动安装&#xff09; ⭐️ 脚本下载地址&#xff1a;Shell脚本安装Oracle数据库 脚…

使用paho.mqtt.client实现MQTT Client连接EMQX Broker

目录 概述 1 认识paho.mqtt.client 2 实现MQTT Client 2.1 功能介绍 2.2 paho.mqtt.client库函数介绍 2.3 MQTT Client实现 2.3.1 创建项目 2.3.2 编写MQTT Client代码 2.3.3 Log工具源码 2.4 功能测试代码实现 2.4.1 功能介绍 2.4.2 代码实现 3 测试 3.1 EMQX上创…

学点儿Java_Day6_面向对象:类、封装、构造方法

1 类 1.1 定义 类&#xff1a;对现实世界中事物的抽象。Student 对象&#xff1a;现实世界中具体的个体。张三、李四 这些具体的学生 面向对象的特征&#xff1a;抽象、封装、继承、多态 OOP: Object Oriented Programming 类和对象的总结&#xff1a; 1、现实世界都是由很多…

语音识别教程:Whisper

语音识别教程&#xff1a;Whisper 一、前言 最近看国外教学视频的需求&#xff0c;有些不是很适应&#xff0c;找了找AI字幕效果也不是很好&#xff0c;遂打算基于Whisper和GPT做一个AI字幕给自己。 二、具体步骤 1、安装FFmpeg Windows: 进入 https://github.com/BtbN/FF…

python爬虫学习第二天----类型转换

&#x1f388;&#x1f388;作者主页&#xff1a; 喔的嘛呀&#x1f388;&#x1f388; &#x1f388;&#x1f388;所属专栏&#xff1a;python爬虫学习&#x1f388;&#x1f388; ✨✨谢谢大家捧场&#xff0c;祝屏幕前的小伙伴们每天都有好运相伴左右&#xff0c;一定要天天…

C语言 指针练习

一、 a、b是两个浮点型变量&#xff0c;给a、b赋值&#xff0c;建立两个指针分别指向a的地址和b的地址&#xff0c;输出两个指针的值。 #include<stdio.h> int main() {float a,b,*p1,*p2;a10.2;b2.3;p1&a;p2&b;printf("a%f,b%f\n",a,b);printf("…

墨菲安全在软件供应链安全领域阶段性总结及思考

向外看&#xff1a;墨菲安全在软件供应链安全领域的一些洞察、思考、行动 洞察 现状&挑战&#xff1a; 过去开发安全体系是无法解决软件供应链安全问题的&#xff1b;一些过去专注开发安全领域的厂商正在错误的引导行业用开发安全思维解决软件供应链安全问题&#xff0c;治…

ResNet目标检测算法实现交通灯分类

红绿灯识别方案&#xff1a;https://zhuanlan.zhihu.com/p/674791906 目录 一、制作数据集二、ResNet算法三、pytorch转onnx文件四、onnx推理测试五、onnx转mnn 一、制作数据集 1、数据集划分 将红绿灯数据集大文件夹中不同类别的小文件夹中的图片按照9&#xff1a;1进行划分…

【Flutter】文件选择器(file_picker)的用法

Flutter 没有提供内置的文件选择器&#xff0c;但社区内有人贡献了一个比较完整的解决方案——file_picker。 file_picker 的 API 简洁易用&#xff0c;支持全平台&#xff08;Android / iOS / Mac / Linux / Windows&#xff09;&#xff0c;是我开发桌面应用时的首选。 这边…