大模型技术实践(四)|参数高效微调技术解析及AdaLoRA的应用

news2024/11/19 14:27:52

在上一期的大模型技术实践中,我们为大家介绍了基于“LangChain+LLM”框架快速搭建知识增强后的问答机器人,并探讨了提升模型内容理解和执行能力的潜在优化方向。


本期内容UCloud将为您介绍参数高效微调技术(PEFT),即对已预训练好的模型,固定住其大部分参数,而仅调整其中小部分或额外增加的参数,以达到与全部参数微调相近的效果。



参数高效微调方法,可大致分为三个类别:增加式方法、选择式方法和重新参数化式方法[1]


01

增加式方法(Additive methods)


增加式方法通过增加额外的参数或层来扩展现有的预训练模型,且仅训练新增加的参数。目前,这是PEFT方法中被应用最广泛的类别。



在增加式方法中,大致分为Adapter类方法和软提示(Soft Prompts)。2019年1月至2022年3月期间,Adapter类的方法Adapter Tuning,软提示类的方法Prefix Tuning、P-Tuning、Prompt Tuning和P-Tuning v2相继出现。



1.1 Adapter Tuning



Adapter的架构如下[2]:
fd9e55ff22261eb02f50a4081b19db0f.jpeg左图是一个Transformer层,右图是一个Adapter层。在每一个Transformer层中的每个子层之后插入两个串行的Adapter。在Adapter微调期间,绿色层是根据下游数据进行训练的,而预训练模型的原参数保持不变。


Adapter的特点:

Adapter 模块主要由两个前馈(Feed-forward)子层组成。



1. 第一个前馈子层将原始特征的维度d投影到一个更小的维度m,应用非线性函数,再投影回维度d的特征(作为Adapter模块的输出)。

2. 总参数量为2md + d + m。通过设置m < d,我们限制了每个任务添加的参数数量。

3. 当投影层的参数初始化接近零时,根据一个skip-connection(跳跃连接),将该模块就初始化为近似恒等函数,以确保微调的有效性。



Adapter的实验结果:

使用公开的预训练BERT作为基础模型,Adapter微调具有高参数效率,可以生成性能强劲的紧凑模型,与完全微调相比表现相当。Adapter通过使用原始模型0.5-5%大小的参数量来微调,性能与BERT-LARGE上具有竞争力的结果相差不到1%。



1.2 Soft Prompts

早期的提示微调通过修改输入文本来控制语言模型的行为,称为硬提示(Hard Prompts)微调。这些方法很难优化,且受到最大模型输入长度的限制。下图为离散的人工设计的Prompt示例:

86743d6b5afe4444eb605db0d0f99a84.jpeg
比如改变输入形式去询问模型:


9b98bdfea7c46d06d7a285e49ce31a7a.jpeg软提示(Soft Prompts)将离散的“提示”问题转为连续的“提示”问题,通过反向传播和梯度下降更新参数来学习Prompts,而不是人工设计Prompts。有仅对输入层进行训练,也有对所有层进行训练的类型。



下面将介绍几种热门的Soft Prompts微调方法。

Prefix Tuning

其结构如下[3]:
45e1a271d496897abdda60b6c088884e.jpeg

只优化前缀(红色前缀块),该前缀添加到每一个Transformer Block中。


Prefix Tuning的特点:

1. 冻结预训练语言模型的参数,为每个任务存储特定的连续可微的前缀,节省空间。

2. 训练间增加MLP层以达到稳定。

3. 对于不同模型构造不同的Prefix。



Prefix Tuning的实验结果:

对于表格到文本任务,使用GPT-2-Medium和GPT-2-Large模型。在表格到文本任务上,Prefix Tuning优于Fine-Tuning(全量微调)和Adapter-Tuning。对于摘要任务,使用BART-LARGE模型。在摘要任务上,Prefix Tuning比全量微调弱。




P-Tuning

其结构如下[4]:
221bd245e1f2660ed9acd2dc011181a6.jpeg在(a)中,提示生成器只接收离散的奖励;在(b)中,伪提示和提示编码器可以以可微分的方式进行优化。


优化h(i)时,为避免陷入局部最优和增强Prompt嵌入关联性,语言模型的真实输入嵌入为:
b12b37a522a2ea2181c6ac0a67cb32b1.jpeg

P-Tuning的特点:

1. P-Tuning只在输入层加入可微的Virtual Token,其会自动插入到文本提示的离散Token嵌入中。

2. Virtual Token不一定作为前缀,其插入位置是可选的。


P-Tuning的实验结果:

使用的是GPT系列和BERT系列的模型。P-Tuning与全参数效果相当,且在一些任务上优于全参数微调,可以显著提高GPT模型在自然语言理解方面的性能,并且BERT风格的模型也可以获得较小的增益。


Prompt Tuning

其结构如下[5]:
227bb5586c23c20a4236f42173d27486.jpeg
上图中,仅Virtual Token部分会由梯度下降法去更新参数。



Prompt Tuning的特点:


1. 只在输入层加入prompt,并且不需要加入MLP进行调整来解决难训练的问题。

2. 提出了Prompt Ensembling,即通过在同一任务上训练N个提示,也就是在同一个批次中,对同一个问题添加不同的Prompt,相当于为任务创建了N个独立的“模型”,同时仍然共享核心语言建模参数。



Prompt Tuning的实验结果:

使用的是预训练的各种T5模型。在流行的SuperGLUE基准测试中,Prompt Tuning的任务性能与传统的模型调优相当,且随着模型规模的增加,差距逐渐减小。在零样本领域迁移中,Prompt Tuning可以改善泛化性能。



P-Tuning v2

其结构如下[6]:
da22d1653f7c0b90395067b01de8064a.jpeg
上图表示了P-Tuning到P-Tuning v2的转变。橙色块指的是可训练的提示嵌入,蓝色块是由冻结的预训练语言模型存储或计算得出的嵌入。



P-Tuning v2的特点:

P-Tuning v2每一层的输入都加入了Tokens,允许更高的任务容量同时保持参数效率;且添加到更深层的提示对模型的预测有更直接的影响。



P-Tuning v2的实验结果:

使用的是BERT系列和GLM系列模型。P-Tuning v2是一种在不同规模和任务中都可与微调相媲美的提示方法。在NLU任务中,整体上P-Tuning v2与全量微调的性能相差很小。


02

选择式方法


选择性方法对模型的现有参数进行微调,可以根据层的深度、层类型或者甚至是个别参数进行选择。



2.1 BitFit

这是一种稀疏微调方法,仅修改模型的Bias(偏置项)或其中的子集[7]。


BitFit的特点:

1. 冻结大部分Transformer编码器的参数,只训练偏置项和任务特定的分类层。

2. 优化的偏置项参数包括:①Attention模块中计算Query、Key、Value,②计算MLP层,③计算Layer Normalization层时遇到的偏置项参数。

3. 每个新任务只需要存储偏置项参数向量(占总参数数量的不到0.1%)和任务特定的最终线性分类器层。


BitFit的实验结果:

使用公开可用的预训练BERT-BASE、BERT-LARGE和RoBERTa-BASE模型。BitFit微调结果不及全量参数微调,但在极少数参数可更新的情况下,远超Frozen(冻结模型参数)方式。



03

重新参数化方法


基于重新参数化的高效微调方法利用低秩表示来最小化可训练参数的数量,其中包括2021年10月到2023年3月间出现的LoRA和AdaLoRA方法。



3.1 LoRA

该方法认为模型权重矩阵在特定微调后具有较低的本征秩,故基于秩分解的概念,将预训练模型的现有权重矩阵分成两个较小的矩阵[8]。

4bd626b809051ab46d4368730f75ddc1.jpeg
LoRA的特点:

1. 将矩阵乘积BA加到原模型参数矩阵W上可以避免推理延迟。

2. 可插拔的低秩分解矩阵模块,方便切换到不同的任务。


LoRA的实验结果:

使用的模型是RoBERTa、DeBERTa、GPT-2和GPT-3-175B。在多个数据集上,LoRA在性能上能和全量微调相近,且在某些任务上优于全量微调。


3.2 AdaLoRA


AdaLoRA的特点:

该方法基于权重矩阵的重要性而自适应调整不同模块的秩[9],节省计算量,可理解为LoRA的升级版。
1608fab3cdbb7d7c505ef4e9f51b841f.jpegAdaLoRA的做法是让模型学习SVD分解的近似。在损失函数中增加了惩罚项,防止矩阵P和Q偏离正交性太远,以实现稳定训练。



AdaLoRA的实验结果:

使用的模型是DeBERTaV3-BASE 和BART-LARGE模型。AdaLoRA的性能通常高于参数量更高的方法。其中,AdaLoRA在0.32M微调参数时,在CoLA数据集上达到了70.04的Mcc分数。



04

参数高效微调方法小结




以上几类参数高效微调方法,各有千秋。Adapter方法在预训练模型的层中插入可训练模块的形式简单,但增加推理延时。Soft Prompts方法避免了人工“硬提示”的局限性,却可能难收敛。



Soft Prompts方法中,Prefix Tuning率先提出可用梯度下降法优化的的Tokens,而P-Tuning、Prompt Tuning和P-Tuning v2相继作出不同的改变,比如:

1. 加入的Tokens:P-Tuning仅限于输入层,而Prefix-Tuning在每一层都加。

2. P-Tuning和Prompt Tuning仅将连续提示插入到输入嵌入序列中,而Prefix Tuning的“软提示”添加在每一个Transformer Block中。

3. Prompt Tuning不需要额外的MLP来解决难训练的问题,P-Tuning v2移除了重参数化的编码器。



BitFit方法只更新模型内部偏置项参数所以训练参数量很微小,但整体效果比LoRA、Adapter等方法弱。LoRA方法不存在推理延时,但无法动态更新增量矩阵的秩,不过改进版AdaLoRA解决了这个问题。



05

AdaLoRA方法的实验




实验模型为ChatGLM2-6B

模型下载参见

(https://github.com/THUDM/ChatGLM2-6B)

可去Hugging Face下载其模型文件。应用AdaLoRA之后的模型训练参数仅占总参数的0.0468%。

trainable params: 2,924,880 ||

all params: 6,246,508,908 ||

trainable%: 0.04682423483386154



实验数据为中文医疗问答数据

下载链接为(https://github.com/Toyhom/Chinese-medical-dialogue-data)

包括儿科、外科等问答数据,数据中会有建议去医院看病之类的文字。此处选取儿科和外科的数据分别10000条数据作为训练数据集,将文件保存为json格式。



构造数据集

文件为dataset.py。

向上滑动查看

from torch.utils.data import Dataset
import torch
import json
import numpy as np
from torch.nn.utils.rnn import pad_sequence
from transformers import AutoTokenizer
from torch.utils.data import DataLoader
from tqdm import tqdm
import sys

class my_dataset(Dataset):
def __init__(self, data_path, tokenizer, max_source_length, max_target_length, is_train = True):
super().__init__()
self.tokenizer = tokenizer
self.max_source_length = max_source_length
self.max_target_length = max_target_length
self.max_seq_length = self.max_source_length + self.max_target_length

self.data_path = data_path
self.data = self._load_data()
self.is_train = is_train

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

def __getitem__(self, index):
item_data = self.data[index]
if self.is_train:
model_inputs = self._preprocess(**item_data)
return model_inputs

def _load_data(self):
data = []
with open(self.data_path, "r", encoding='utf-8') as f:
for line in f:
if not line or line == "":
continue
json_line = json.loads(line)
ask = json_line.get("ask")
answer = json_line.get("answer")
if ask and answer:
data.append({"question": ask, "answer": answer})
return data

def _preprocess(self, question, answer):
model_inputs = {
"input_ids": None,
"labels": None,
}
Prompt = self.tokenizer.build_Prompt(question, None)
a_ids = self.tokenizer.encode(text=Prompt, add_special_tokens=True, truncation=True,
max_length = self.max_source_length)
b_ids = self.tokenizer.encode(text=answer, add_special_tokens=False, truncation=True,
max_length = self.max_target_length)

context_length = len(a_ids)
input_ids = a_ids + b_ids + [self.tokenizer.eos_token_id]
labels = [self.tokenizer.pad_token_id] * context_length + b_ids + [self.tokenizer.eos_token_id]

pad_len = self.max_seq_length - len(input_ids)
input_ids = input_ids + [self.tokenizer.pad_token_id] * pad_len
labels = labels + [self.tokenizer.pad_token_id] * pad_len
labels = [(l if l != self.tokenizer.pad_token_id else -100) for l in labels]

model_inputs["input_ids"] = torch.tensor(input_ids, dtype=torch.long)
model_inputs["labels"] = torch.tensor(labels, dtype=torch.long)

return model_inputs




训练代码

1. 文件为FT.py。

向上滑动查看

from transformers import AutoTokenizer, AutoModel
from peft import AdaLoraConfig, get_peft_model, TaskType
from dataset import my_dataset
from tqdm import tqdm
import torch
from torch.utils.data import DataLoader
import pandas as pd
import os, sys
import argparse
import shutil
from accelerate import Accelerator, DeepSpeedPlugin

parser = argparse.ArgumentParser()
parser.add_argument("--model_name", type=str, default="/data/chatglm2-6b")
parser.add_argument("--r", type=int, default = 8)
parser.add_argument("--lora_alpha", type=int, default = 32)
parser.add_argument("--lora_dropout", type=float, default = 0.01)
parser.add_argument("--epochs", type=int, default = 5)
parser.add_argument("--batch_size", type=int, default = 1)
parser.add_argument("--max_source_length", type=int, default = 128)
parser.add_argument("--max_target_length", type=int, default = 256)
parser.add_argument("--train_json_path", type=str, default = "./test_data/train.json")
parser.add_argument("--lr", type=float, default=1e-4)
parser.add_argument("--model_output_dir", type=str, default="output")
args = parser.parse_args()

accelerator = Accelerator()
device = accelerator.device
accelerator.print(f'device {str(accelerator.device)} is used!')

def main():
adaLoRA_config = AdaLoraConfig(
peft_type = "ADALORA", task_type = "CAUSAL_LM",
r = args.r, lora_alpha = args.lora_alpha,
target_modules = ["query_key_value"],
lora_dropout = args.lora_dropout,
)

tokenizer = AutoTokenizer.from_pretrained(args.model_name, trust_remote_code=True)
model = AutoModel.from_pretrained(args.model_name, trust_remote_code=True)

model = get_peft_model(model, adaLoRA_config)
print(model)
model.print_trainable_parameters()
model = model.half()

train_set = my_dataset(args.train_json_path, tokenizer, args.max_source_length, args.max_target_length)
train_loader = DataLoader(train_set, batch_size = args.batch_size, shuffle = True)

optimizer = torch.optim.AdamW(params = model.parameters(), lr = args.lr)

if os.path.exists(args.model_output_dir):
shutil.rmtree(args.model_output_dir)
os.makedirs(args.model_output_dir)

model, optimizer, data_loader = accelerator.prepare(model, optimizer, train_loader)
for epoch in range(args.epochs):
total_loss = 0
for step, batch in enumerate(t:=tqdm(data_loader)):
with accelerator.accumulate(model):
outputs = model(**batch)
loss_detach = outputs.loss.detach().cpu().float()
t.set_description(f"loss: {loss_detach}")
total_loss += loss_detach

loss = outputs.loss
accelerator.backward(loss)

optimizer.step()
optimizer.zero_grad()
unwrapped_model = accelerator.unwrap_model(model)
unwrapped_model.save_pretrained(os.path.join(args.model_output_dir, f'{epoch}_epoch'),
save_function=accelerator.save,
state_dict=accelerator.get_state_dict(model))

if __name__ == '__main__':
main()




2. 配置文件config_accelerate.yml

deepspeed_config:
gradient_clipping: 1.0
gradient_accumulation_steps: 16
distributed_type: DEEPSPEED



3. 执行文件run.sh

CONFIG_FILE='config_accelerate.yml'
accelerate launch --config_file $CONFIG_FILE FT.py



测试代码

import torch
from transformers import AutoTokenizer, AutoModel
from peft import PeftConfig, PeftModel
import os
import shutil

device = torch.device("cuda:0")

model_name = "/data/chatglm2-6b"
adalora_path = "output_20000_all5/y_epoch"

def ans():
tokenizer = AutoTokenizer.from_pretrained(model_name, trust_remote_code=True)
model = AutoModel.from_pretrained(model_name, trust_remote_code=True)
model = PeftModel.from_pretrained(model, adalora_path)

model = model.half()
model = model.to(device)
model.eval()

ask = input("请输入问题:")
response, history = model.chat(tokenizer, ask, history = [])
print("回答:", response)

if __name__ == "__main__":
ans()



结果为:

2fc476e93d98e12abcc90d2d407ea656.jpeg
06

结语



PEFT技术除了以上三种主流分类之外,还包括了对上述PEFT方法进行综合改进的“混合参数高效微调方法”:MAM Adapter和UniPELT。其中,MAM Adapter引入了Adapter和Prompt-Tuning的思想,而UniPELT综合了LoRA、Prefix Tuning和Adapter的思想。混合参数高效微调方法效果优于单个高效微调方法的概率较大,但同时也存在训练参数和推理延时增加的局限,感兴趣的读者可以阅读原论文了解技术细节。


下一期将会对大模型的加速并行框架进行探讨,欢迎大家持续关注!


【参考文献】

[1] 《Scaling Down to Scale Up: A Guide to Parameter-Efficient Fine-Tuning》

[2] 《Parameter-Efficient Transfer Learning for NLP》

[3] 《Prefix-Tuning: Optimizing Continuous Prompts for Generation》

[4] 《GPT Understands, Too》

[5] 《The Power of Scale for Parameter-Efficient Prompt Tuning》

[6] 《P-Tuning v2: Prompt Tuning Can Be Comparable to Fine-tuning Universally Across Scales and Tasks》

[7] 《BitFit: Simple Parameter-efficient Fine-tuning for Transformer-based Masked Language-models》

[8] 《LoRA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS》

[9] 《ADAPTIVE BUDGET ALLOCATION FOR PARAMETEREFFICIENT FINE-TUNING》

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

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

相关文章

软件研发团队建设---利用“鲇鱼效应”推进研发团队人文环境的建设手记(2)

软件研发团队建设—利用“鲇鱼效应”推进研发团队人文环境的建设手记&#xff08;2&#xff09; 背景 软件研发团队建设—如何协助业主建设软件研发团队并提高其力量的手记&#xff08;1&#xff09; 与业主某研发人员的沟通 &#xff08;长图&#xff0c;耐心点&#xff0…

CDS(一)

Core Data Services 核心数据服务 DDL 定义Query Language 查询DCL 控制&#xff08;权限相关&#xff09;model&#xff0c;从语义层获取数据open SQL 访问CDS viewCDS权限定义,集成旧的权限概念扩展native SQL扩展SQL建模和声明 ABAP ViewCDS View支持所有数据库是是支持查询…

全网最细,Jenkins配合GitLab分支自动合并/自动创建(超细整理)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 GitFlow工作流简介…

python(自4) xpath下载 lxml安装 lxml语法 使用方式

&#xff08;一&#xff09;安装 搜索xpath 讲解 XPath 教程 (w3school.com.cn) 一&#xff0c;下载地址 &#xff1a; https://chrome.zzzmh.cn/info/hgimnogjllphhhkhlmebbmlgjoejdpjl 二 &#xff0c;拖拽 &#xff08;二&#xff09;lxml安装 cmd 打开终端 cd pythond…

数据库及分类详细介绍

目录 一、数据库详细介绍1、什么是数据库2、数据库的种类3、常见的数据库4、关系型数据库4.1、关系型数据库介绍4.2、关系型数据库的优缺点4.3、关系型数据库小结 5、非关系型数据库5.1、非关系数据库诞生的背景5.2、非关系型数据库的介绍5.3、非关系型数据库的优缺点5.4、非关…

LInux本地连接超时ip未显示

关闭防护墙 systemctl stop firewalld 查看防火墙状态 systemctl status firewalld 开启80端口 /sbin/iptables -I INPUT -p tcp --dport 8080 -j ACCEPT 查看Ip ifconfig

清能股份2MW热电联供系统成功下线

2023年9月26日&#xff0c;由清能股份旗下豫氢动力承接的2MW燃料电池热电联供项目已正式下线&#xff0c;发往焦作煤业&#xff08;集团&#xff09;开元化工有限责任公司&#xff08;简称“开元化工”&#xff09;安装运营。 开元化工是河南知名氯碱国企&#xff0c;该项目是国…

左对齐和右对齐

%d默认为左对齐&#xff0c;%5d为右对齐&#xff08;以空格补齐&#xff09;&#xff0c;%05d为右对齐&#xff08;以0补齐&#xff09;&#xff0c;%-5d左补齐&#xff08;以空格补齐&#xff09;&#xff0c;整数和小数同理。%.xf,x为小数点后保留的位数。 #include<stdi…

WebGL实现透明物体(α混合)

目录 α混合 如何实现α混合 1. 开启混合功能&#xff1a; 2. 指定混合函数 混合函数 gl.blendFunc&#xff08;&#xff09;函数规范 可以指定给src_factor和dst_factor的常量 混合后颜色的计算公式 加法混合 半透明的三角形&#xff08;LookAtBlendedTriangl…

使用Python和Pandas处理网页表格数据

在我们的日常工作和生活中&#xff0c;经常会遇到需要处理大量数据的情况&#xff0c;而网页表格数据则是其中常见的一种形式。如果我们能够灵活地使用Python和Pandas这两个强大的工具&#xff0c;就能够快速、高效地对这些数据进行处理和分析。 首先&#xff0c;我们需要了解…

游戏服务商Latis Global参展2023 ChinaJoy B2B

第20届ChinaJoy于2023年7月在上海举行了为期四天的博览会,参展观众达到了33.8万人次。ChinaJoy是全球最具知名度与影响力的年度盛会之一,涵盖了包括游戏、动漫、互联网影视、电子竞技、潮流玩具、智能娱乐在内的多个数字娱乐领域。ChinaJoy不仅仅代表了数字娱乐领域的最新风向,…

搞定零售出海的底层挑战,泡泡玛特的经验是什么?

出品 | CSDN 云计算 从 2010 年成立&#xff0c;2016 年发布 Molly IP 的盲盒产品到现在&#xff0c;泡泡玛特已经成为在全球拥有员工 4000 多人的知名潮流玩具品牌。就像在中国市场被喜爱的迪士尼、日漫等多个 IP 一样&#xff0c;泡泡玛特从 2022 年开始也带着众多 IP 走出中…

如何正确监测蓄电池健康?狠狠学到!

蓄电池在现代生活和工业中发挥着关键作用&#xff0c;它们为无数设备和系统提供了必要的电力支持。然而&#xff0c;蓄电池的性能和可靠性对许多应用至关重要。监控蓄电池状态和性能变得越来越重要&#xff0c;以确保它们在需要时始终可用。 为此&#xff0c;蓄电池监控系统应运…

从零开始之了解电机及其控制(8)clarke和park变换

为了最大化无刷电机产生的扭矩&#xff0c;我们希望感应磁场与转子磁场正交并引导转子磁场&#xff0c;无刷电机定子产生的磁场矢量将与电流矢量逆时针旋转 90 度 但现在我们要稍微改变这个y电路的外观&#xff0c;我们不是将相位表示为电阻器&#xff0c;它会产生垂直于电流方…

家电行业 EDI:Miele EDI 需求分析

Miele是一家创立于1899年的德国公司&#xff0c;以其卓越的工程技术和不懈的创新精神而闻名于世。作为全球领先的家电制造商&#xff0c;Miele的经营范围覆盖了厨房、洗衣和清洁领域&#xff0c;致力于提供高品质、可持续和智能化的家电产品。公司的使命是为全球消费者创造更美…

TSM动作识别模型【详解】

文章目录 本文使用的是somethingv2数据集&#xff0c;解压后是如下形式&#xff1b; 由于该压缩数据进行了分卷操作&#xff0c;需要合并后才能进行解压。首先我们将下面4个json文件剪贴到其他文件夹&#xff0c;只保留00-19的文件&#xff0c;然后在该文件夹下打开cmd&#xf…

Unity vscode 官方debug

把这个先unlock 再升级到最新的 然后重新生成 project files 打开 launch.json {"version": "0.2.0","configurations": [{"name": "Attach to Unity","type": "vstuc","request": "a…

创造您梦寐以求的家居设计——Live Home 3D Pro for Mac

您是否曾经想象过在舒适的家中展现自己独特的风格&#xff1f;现在&#xff0c;您可以通过Live Home 3D Pro for Mac来实现您的家居设计梦想&#xff01;这款强大的3D家居设计软件将带给您无限的创作可能性。 Live Home 3D Pro for Mac是一款专业级的家居设计软件&#xff0c;…

Java初始化大量数据到Neo4j中(二)

接Java初始化大量数据到Neo4j中(一)继续探索&#xff0c;之前用create命令导入大量数据发现太过耗时&#xff0c;查阅资料说大量数据初始化到Neo4j需要使用neo4j-admin import 业务数据说明可以参加Java初始化大量数据到Neo4j中(一)&#xff0c;这里主要是将处理好的节点数据和…

opencv英文识别tesseract-orc安装

文章目录 一、安装并保存所在路径二、配置环境变量1、打开高级设置2、配置环境变量三、修改tesseract.py文件中的路径,否则运行报错1、进入python所在的文件夹,找到Lib,site-packages2、搜索pytesseract3、打开py文件修改路径一、安装并保存所在路径 特别注意路径名中不能有…