深度学习大模型训练--分布式 deepspeed PipeLine Parallelism 源码解析

2023-11-20

basic concept

  • 2 台机器(num_node=2),每个机器有 8 个 GPU(8 rank in each node) ,则有 2*8=16 个节点,可以开 16 个 进程(ranks_num=16)
  • DDP 的最佳实践,每一个进程一张卡
  • 以上述 DDP 的最佳实践为例,解释下述名词
    • world-size = 16
    • group default=1
    • rank = 0~15
    • local rank : node1-0~7 ; node2-0~7
    • nnodes : 有多少台机器
    • node-rank : 当前是哪一台机器
    • nproc_per_node:每台机器有多少进程

PipeDream abstract

Gpipe流水线其存在两个问题:硬件利用率低,内存占用大.worker 之间只能同时处理一个 minibatch,系统中只有一个minibatch是活动的,这极大限制了硬件利用率。假如一个batch被分为 n 个micro-batch,则需要缓存 n 份activation。

1F1B 策略可以解决缓存 activation 的份数问题,使得 activation 的缓存数量只跟 stage 数相关,从而进一步节省显存,可以训练更大的模型。

1F1B
  • 由于前向计算的 activation 需要等到对应的后向计算完成后才能释放(无论有没有使用 Checkpointing 技术),因此在流水并行下,如果想尽可能节省缓存 activation 的份数,就要尽量缩短每份 activation 保存的时间,也就是让每份 activation 都尽可能早的释放,所以要让每个 micro-batch 的数据尽可能早的完成后向计算,因此需要把后向计算的优先级提高,让 micro-batch 标号小的后向比 micro-batch 标号大的前向先做。因此,如果我们让最后一个 stage 在做完一次 micro-batch 的前向后,立马就做本 micro-batch 的后向,那么我们就能让其他的 stage 尽可能早的开始后向计算,这就是 1F1B 策略。

  • 1F1B(one-forward-one-backward)的调度模式会在每台worker机器上 交替进行小批次数据的前向后向计算,同时确保这些小批量在"后向传播"时可以路由到"前向传播"的相同worker

4 steps

  • profile 通过小批量数据的profile推理出DNN训练时间。
  • compute partition 依据profile结果确定所有层的运行时间,然后进行优化,优化器返回一个带注释的运算符图,每个模型层映射到一个阶段ID。
  • convert model 对运算符图执行BFS遍历,为每个阶段生成一个单独的torch.nn.Module代码。PipeDream对每个阶段中的运算符进行排序,以确保它们保持与原始PyTorch模型图的输入输出依赖关系的一致性。
  • runtime schedule PipeDream 运行时根据其1F1B-RR调度策略将每个阶段(包括复制阶段的副本)分配给单个工作进程。

本文以 alexnet 为例子,分析这四个步骤在 deepspeed 源码中的实现,其中实现方式与 pipeDream 有些许不同

  • profile 使用 最简单 parameter method,跟据每一层的参数大小推理出训练时间
    结果示例:
[23296, 0, 0, 307392, 0, 0, 663936, 0, 884992, 0, 590080, 0, 0, 0, 0, 0, 37752832, 0, 0, 16781312, 0, 40970]
  • compute partition 依据profile结果确定所有层的运行时间,然后返回一个 parts 数组,保存模型层的分区结果.此时每张卡(即每个 stage 将会保存对应 global 模型分区后的结果映射)
    结果示例:
self.parts= [0,19,22]

self._local_start = 0
self._local_stop = 19

self._local_start = 19
self._local_stop = 22
  • convert model 每张卡根据分区后的结果,为每个阶段生成一个单独的torch.nn.Module代码
  • runtime PipeDream 运行时根据其1F1B-RR调度策略将每个阶段(包括复制阶段的副本)分配给单个工作进程
    在这里插入图片描述

Code comprehension in deepspeed

preparation

code

  1. config 基础配置
    为了简化理解,配置为简单的 pp=2 dp=1 mp=0
    上述配置可以在 DeepSpeedExamples/pipeline_parallelism/ds_config.json 进行配置,其中 micro batch num=train_batch_size/train_micro_batch_size_per_gpu=2.
# DeepSpeedExamples/pipeline_parallelism/ds_config.json
 {
  "train_batch_size" : 256,
  "train_micro_batch_size_per_gpu" : 128,
    ...
    ...
 }

启动 deepspeed 时配置超参数 -p 设置流水并行数,如果 micro batch num == pp num ,则此时是最佳实践配置

# DeepSpeedExamples/pipeline_parallelism/run.sh
deepspeed train.py --deepspeed_config=ds_config.json -p 2 --steps=1

快速运行一个分布式流水并行度=2的 alexnet 网络, 如果设置可用 cuda 数量为 2,此时数据并行度将为 0,因为仅有的两个 rank 将会被用来进行流水并行
Quick Start:

export CUDA_VISIBLE_DEVICES=0,1
sh run.sh
  1. DeepSpeedExamples/pipeline_parallelism/train.py

pp=2,因此,RANK 0 and RANK 1 的进程将会被同时启动,也就是说下面的 main 函数将会分别被 RANK 0 & RANK 1 调用。通过 os 函数 os.getenv('RANK') 可以查看当前函数调用所在的卡

if __name__ == '__main__':
    # __main__ function will be recall 4 times cause open four threads
    args = get_args()
    deepspeed.init_distributed(dist_backend=args.backend)
    args.local_rank = int(os.environ['LOCAL_RANK'])
    torch.cuda.set_device(args.local_rank)

    if args.pipeline_parallel_size == 0:
        train_base(args)
    else:
        train_pipe(args)

1.1. deepspeed.init_distributed(dist_backend=args.backend)
主要是为了初始化通信方法,通信方法可以参考 https://zhuanlan.zhihu.com/p/465967735,https://zhuanlan.zhihu.com/p/79030485
Create a torch backend object, initialize torch distributed, and assign to cdb

# miniconda3/lib/python3.9/site-packages/deepspeed/comm/comm.py
# Main DeepSpeed Comms. public API.
def init_distributed(dist_backend="nccl",
                     auto_mpi_discovery=True,
                     distributed_port=TORCH_DISTRIBUTED_DEFAULT_PORT,
                     verbose=True,
                     timeout=default_pg_timeout,
                     init_method=None,
                     dist_init_required=None,
                     config=None):

1.2 train_pipe(args)

def train_pipe(args, part='parameters'):
    ...
    ...
    net = AlexNet(num_classes=10)
    net = PipelineModule(layers=join_layers(net),
                         loss_fn=torch.nn.CrossEntropyLoss(),
                         num_stages=args.pipeline_parallel_size,
                         partition_method=part,
                         activation_checkpoint_interval=0)

    trainset = cifar_trainset(args.local_rank)

    engine, _, _, _ = deepspeed.initialize(
        args=args,
        model=net,
        model_parameters=[p for p in net.parameters() if p.requires_grad],
        training_data=trainset)

    for step in range(args.steps):
        loss = engine.train_batch()

1.2.0 layers=join_layers(net)

将 视觉上的直观 layers 保存为 feature, avgpool,classifier 为顺序的数组传入 pipeModule 中

def join_layers(vision_model):
    layers = [
        *vision_model.features,
        vision_model.avgpool,
        lambda x: torch.flatten(x, 1),
        *vision_model.classifier,
    ]
    return layers

layers:

[Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2)), ReLU(inplace=True), MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False), Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2)), ReLU(inplace=True), MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False), Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)), ReLU(inplace=True), Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)), ReLU(inplace=True), Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)), ReLU(inplace=True), MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False), AdaptiveAvgPool2d(output_size=(6, 6)), <function join_layers.<locals>.<lambda> at 0x7fc8a6193550>, Dropout(p=0.5, inplace=False), Linear(in_features=9216, out_features=4096, bias=True), ReLU(inplace=True), Dropout(p=0.5, inplace=False), Linear(in_features=4096, out_features=4096, bias=True), ReLU(inplace=True), Linear(in_features=4096, out_features=10, bias=True)]
convert model

1.2.1 PipelineModule(layers=join_layers(net),…)

  • Setup world info
  • Initialize partition information

Setup world info:

# 
# dist.new_group() 将 RANK 实例放入一个组中
self.world_group = dist.new_group(ranks=range(dist.get_world_size()))
self.global_rank = dist.get_rank(group=self.world_group)
self.world_size = dist.get_world_size(group=self.world_group)
self.local_rank = int(os.environ.get("LOCAL_RANK", None))
world_group=<torch._C._distributed_c10d.ProcessGroupNCCL object at 0x7fc8a61af7f0> global_rank =1 world_size=2 local_rank=1
world_group=<torch._C._distributed_c10d.ProcessGroupNCCL object at 0x7f0e9c8af970> global_rank =0 world_size=2 local_rank=0

Initialize partition information

        # 
        self._layer_specs = list(layers)
        self._num_layers = len(self._layer_specs)
        self._local_start = 0
        self._local_stop = None
        self._partition_layers(method=partition_method)
profile

使用简单的 parameter method 通过迭代计算,使用 _count_layer_params() 方法计算出模型每一层的参数量
1.2.1.1 _partition_layers()

        elif method == 'parameters':
            param_counts = self._count_layer_params()
            para_len=len(param_counts)
            ...


# profile count para

    def _count_layer_params(self):
        """Count the trainable parameters in individual layers.

        This routine will only build one layer at a time.

        Returns:
            A list of the number of parameters in each layer.
        """
        param_counts = [0] * len(self._layer_specs)
        for idx, layer in enumerate(self._layer_specs):
            if isinstance(layer, LayerSpec):
                l = layer.build()
                params = filter(lambda p: p.requires_grad, l.parameters())
                param_counts[idx] = sum(p.numel() for p in params)
            elif isinstance(layer, nn.Module):
                params = filter(lambda p: p.requires_grad, layer.parameters())
                param_counts[idx] = sum(p.numel() for p in params)
        return param_counts

得到一个映射每层参数量的数组:

[23296, 0, 0, 307392, 0, 0, 663936, 0, 884992, 0, 590080, 0, 0, 0, 0, 0, 37752832, 0, 0, 16781312, 0, 40970]
compute partition

跟据每一层的参数量,使用 partition_balanced() 方法进行简单的 stage 划分,平衡每张卡的计算量:

            ...
            self.parts = ds_utils.partition_balanced(weights=param_counts,
                                                     num_parts=num_stages)

# compute partition miniconda3/lib/python3.9/site-packages/deepspeed/runtime/utils.py
            def partition_balanced(weights, num_parts, eps=1e-3):
                num_items = len(weights)
                # First check for the trivial edge case
                if num_items <= num_parts:
                    return partition_uniform(num_items, num_parts)

                weights_ = prefix_sum_inc(weights)

                # Find the smallest bottleneck (weight of heaviest partition)
                bottleneck = _rb_partition_balanced(weights_, num_parts, eps=eps)

                # Now compute that partitioning
                parts, success = _lprobe(weights_, num_parts, bottleneck)

                print(f':::::::::::::::;part::::::::::::::{parts}::::::::::sucess:::::::{success}')
                assert success

                return parts

得到一个 global 的数组 保存分层的 index,例如下面的数组表示,stage 0 将运行 层0~层19,stage 1 将运行 层19~层22

self.parts= [0,19,22]

_set_bounds() 方法通过传入 rank 的 id(即 stage id)可以使得每张卡存储不同的私有的变量,以实现分区

            ...
            self._set_bounds(start=self.parts[stage_id], stop=self.parts[stage_id + 1])

            # def _set_bounds
                def _set_bounds(self, start=None, stop=None):
                """Manually define the range of layers that will be built on this process.

                These boundaries are treated as list slices and so start is inclusive and stop is
                exclusive. The default of None for both results in all layers being built
                locally.
                """

                self._local_start = start
                self._local_stop = stop
                print(f'::::::::::::_local_start:;:::{self._local_start}')
                print(f':::::::::::_local_stop:::::::{self._local_stop}')

            ...
            self.forward_funcs = []
            self.fwd_map = {}
            self.tied_modules = nn.ModuleDict()
            self.tied_weight_attrs = {}
            self._build()
self._local_start = 0
self._local_stop = 19

self._local_start = 19
self._local_stop = 22

::RANk0:::::::::::forward_funcs:::::[Conv2d(3, 64, kernel_size=(11, 11), stride=(4, 4), padding=(2, 2)), ReLU(inplace=True), MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False), Conv2d(64, 192, kernel_size=(5, 5), stride=(1, 1), padding=(2, 2)), ReLU(inplace=True), MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False), Conv2d(192, 384, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)), ReLU(inplace=True), Conv2d(384, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)), ReLU(inplace=True), Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1)), ReLU(inplace=True), MaxPool2d(kernel_size=3, stride=2, padding=0, dilation=1, ceil_mode=False), AdaptiveAvgPool2d(output_size=(6, 6)), <function join_layers.<locals>.<lambda> at 0x7f6308dde550>, Dropout(p=0.5, inplace=False), Linear(in_features=9216, out_features=4096, bias=True), ReLU(inplace=True), Dropout(p=0.5, inplace=False)]::::::::;fwd_map:::::{'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9, '10': 10, '11': 11, '12': 12, '13': 13, '15': 15, '16': 16, '17': 17, '18': 18}:::::::tied_modules:::::ModuleDict():::::::

::RANk1:::::::::::forward_funcs:::::[Linear(in_features=4096, out_features=4096, bias=True), ReLU(inplace=True), Linear(in_features=4096, out_features=10, bias=True)]::::::::;fwd_map:::::{'19': 0, '20': 1, '21': 2}:::::::tied_modules:::::ModuleDict():::::::

如何做到分区?
我们知道程序一开始便开启了两个 RANK 进程,即每个 RANK 都会运行 global 的代码.当每个 RANK 运行到 set_bound 函数时,传入的参数 stage_id 是通过 get_coord(global_rank) 得到的,即不同的 RANK 执行到这一步时,会得到不同的 stage_id 此时,不同 RANK 上保存的 self._local_start 将会不同.

再使用 _build 函数,根据每个 RANK 所保存的不同 self._local_start & stop map 一下所对应的 module forward 函数名字 得到 RANK 私有的 self.forward_funcs & self.fwd_map,之后便可以使用 self.module() 内存有不同的 module 数据,此时每张卡内已经存有不同的 model 结构了.之后初始化 engine 时,传入的便已经是分区好的model.

1.2.2 trainset = cifar_trainset(args.local_rank)

    ...
    dist.barrier()
    if local_rank != 0:
        dist.barrier()
    trainset = torchvision.datasets.CIFAR10(root=dl_path,
                                            train=True,
                                            download=True,
                                            transform=transform)
    if local_rank == 0:
        dist.barrier()
    return trainset

dist.barrier()
pytorch在分布式训练过程中,对于数据的读取是采用主进程预读取并缓存,然后其它进程从缓存中读取,不同进程之间的数据同步具体通过torch.distributed.barrier()实现。

在上面的代码示例中,如果执行 cifar_trainset() 函数的进程不是主进程,即rank不等于0,会执行相应的 torch.distributed.barrier(),设置一个阻塞栅栏,让此进程处于等待状态,等待所有进程到达栅栏处(包括主进程数据处理完毕);如果执行create_dataloader()函数的进程是主进程,其会直接去读取数据并处理,然后其处理结束之后会接着遇到torch.distributed.barrier(),此时,所有进程都到达了当前的栅栏处,这样所有进程就达到了同步,并同时得到释放。

1.2.3 deepspeed.initialize(…)

        engine = PipelineEngine(...)

1.2.4 loss = engine.train_batch()

    def train_batch(self, data_iter=None):
        self.module.train() #????????????????????
                self.timers('train_batch').start()
        sched = schedule.TrainSchedule(micro_batches=self.micro_batches,
                                       stages=self.num_stages,
                                       stage_id=self.stage_id)

        self._exec_schedule(sched)
        self.agg_train_loss = self._aggregate_total_loss()

runtime

1.2.4.1 schedule.TrainSchedule(micro_batches=self.micro_batches…)
runtime schedule 将会自动调用 steps 函数

    1. 首先根据传入的 micro batch size 和 batch size 得到 num micro batch,既可以得到每个 stage 有多少个 micro batch
    1. 根据计算的 num micro batch 和 1F1B 策略得到一个 stage 的步数,在此例子中,每个stage 的步数为 6.
    1. 为每个 stage 的步,标一个 index,为 micro batch id,并为这些 id 计算出 cmds。cmds 是计算出的每一步需要做的函数。例如 stage 0 的 step 0 ,需要 load data 和 进行第一步 forward。
    1. 接下来每个 stage 将跟据生成的 cmds,在各自的 rank 里串行的执行每一步。然后每个 stage 有事并行执行的。前面的计算就是为了不同 stage 之间可以同步进行,例如 stage 0 的 step 1 send activation 后,stage 1 step 2 需要执行玩 step 0 的 load 和 forward,并几乎没有延时地执行 receive activation。这样的话,就可以有效率的run 整个网络。
# miniconda3/lib/python3.9/site-packages/deepspeed/runtime/pipe/schedule.py
class TrainSchedule(PipeSchedule):
    def steps(self):
        ..
        ..

    yield cmds

cmds result:

[RecvActivation(buffer_id=0), LoadMicroBatch(buffer_id=0), ForwardPass(buffer_id=0)]

图示:
在这里插入图片描述

其中该图展现了运行时的物理结构,分为两个 stage 进行流水并行,每个 stage 有 6 步,stage 内串行执行,stage 间并行执行。

  • 0 表示在一个 batch 内的 第一个 micro batch 的数据,他将在 rank 0 上通过使用 load 函数被加载,然后跟据生成的 nn.Module 模块执行 层0-19 的 Module 的 forward 函数,forward 结束后的 activation 将会由 step 1 发送给 stage 1 的 step 1.在 stage 1 的 0,也将使用 load 加载数据,然后接收 stage1 发送的前 19 层的 activation,在这个基础上用同样的数据完成模型 层19-22 的 forward 计算。
  • 根据 1f1b 策略,一个batch 的数据前向结束后,应该立即进行 backward,此时 stage 1 的 step 2 将对 层19-22 的参数进行反向传播,反向传播后产生的 gradient 参数将有 stage 1 的 step 3 发送给 stage 0 的 step 3. stage 0 的 step 3 接收到层 19-22 的 grad 后便可以进行 层0-19 的 反向传播,同时它还需要做 第二个 micro batch 前向 activation 的 发送操作。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

深度学习大模型训练--分布式 deepspeed PipeLine Parallelism 源码解析 的相关文章

  • 如何检查 PyTorch 是否正在使用 GPU?

    如何检查 PyTorch 是否正在使用 GPU 这nvidia smi命令可以检测 GPU 活动 但我想直接从 Python 脚本内部检查它 这些功能应该有助于 gt gt gt import torch gt gt gt torch cu
  • PoseWarping:如何矢量化此 for 循环(z 缓冲区)

    我正在尝试使用地面真实深度图 姿势信息和相机矩阵将帧从视图 1 扭曲到视图 2 我已经能够删除大部分 for 循环并将其矢量化 除了一个 for 循环 扭曲时 由于遮挡 视图 1 中的多个像素可能会映射到视图 2 中的单个位置 在这种情况下
  • Cuda和pytorch内存使用情况

    我在用Cuda and Pytorch 1 4 0 当我尝试增加batch size 我遇到以下错误 CUDA out of memory Tried to allocate 20 00 MiB GPU 0 4 00 GiB total c
  • 如何使用 torch.stack?

    我该如何使用torch stack将两个张量与形状堆叠a shape 2 3 4 and b shape 2 3 没有就地操作 堆叠需要相同数量的维度 一种方法是松开并堆叠 例如 a size 2 3 4 b size 2 3 b torc
  • RuntimeError:维度指定为 0 但张量没有维度

    我试图使用 MNIST 数据集实现简单的 NN 但我不断收到此错误 将 matplotlib pyplot 导入为 plt import torch from torchvision import models from torchvisi
  • 预训练 Transformer 模型的配置更改

    我正在尝试为重整变压器实现一个分类头 分类头工作正常 但是当我尝试更改配置参数之一 config axis pos shape 即模型的序列长度参数时 它会抛出错误 Reformer embeddings position embeddin
  • 为什么测试时一定要用DataParallel?

    在GPU上训练 num gpus设置为1 device ids list range num gpus model NestedUNet opt num channel 2 to device model nn DataParallel m
  • pytorch grad 在 .backward() 之后为 None

    我刚刚安装火炬 1 0 0 on Python 3 7 2 macOS 并尝试tutorial https pytorch org tutorials beginner blitz autograd tutorial html sphx g
  • 为什么我在这里遇到被零除的错误?

    所以我正在关注这个文档中的教程 https pytorch org tutorials beginner data loading tutorial html在自定义数据集上 我使用的是 MNIST 数据集 而不是教程中的奇特数据集 这是D
  • 在pytorch张量中过滤数据

    我有一个张量X like 0 1 0 5 1 0 0 1 2 0 我想实现一个名为的函数filter positive 它可以将正数据过滤成新的张量并返回原始张量的索引 例如 new tensor index filter positive
  • 一次热编码期间出现 RunTimeError

    我有一个数据集 其中类值以 1 步从 2 到 2 i e 2 1 0 1 2 其中 9 标识未标记的数据 使用一种热编码 self one hot encode labels 我收到以下错误 RuntimeError index 1 is
  • 下载变压器模型以供离线使用

    我有一个训练有素的 Transformer NER 模型 我想在未连接到互联网的机器上使用它 加载此类模型时 当前会将缓存文件下载到 cache 文件夹 要离线加载并运行模型 需要将 cache 文件夹中的文件复制到离线机器上 然而 这些文
  • pytorch 中的 autograd 可以处理同一模块中层的重复使用吗?

    我有一层layer in an nn Module并在一次中使用两次或多次forward步 这个的输出layer稍后输入到相同的layer pytorch可以吗autograd正确计算该层权重的梯度 def forward x x self
  • 如何计算 CNN 第一个线性层的维度

    目前 我正在使用 CNN 其中附加了一个完全连接的层 并且我正在使用尺寸为 32x32 的 3 通道图像 我想知道是否有一个一致的公式可以用来计算第一个线性层的输入尺寸和最后一个卷积 最大池层的输入 我希望能够计算第一个线性层的尺寸 仅给出
  • 如何使用pytorch构建多任务DNN,例如超过100个任务?

    下面是使用 pytorch 为两个回归任务构建 DNN 的示例代码 这forward函数返回两个输出 x1 x2 用于大量回归 分类任务的网络怎么样 例如 100 或 1000 个输出 对所有输出 例如 x1 x2 x100 进行硬编码绝对
  • pytorch 的 IDE 自动完成

    我正在使用 Visual Studio 代码 最近尝试了风筝 这两者似乎都没有 pytorch 的自动完成功能 这些工具可以吗 如果没有 有人可以推荐一个可以的编辑器吗 谢谢你 使用Pycharmhttps www jetbrains co
  • Pytorch“展开”等价于 Tensorflow [重复]

    这个问题在这里已经有答案了 假设我有大小为 50 50 的灰度图像 在本例中批量大小为 2 并且我使用 Pytorch Unfold 函数 如下所示 import numpy as np from torch import nn from
  • 在 Pytorch 中估计高斯模型的混合

    我实际上想估计一个以高斯混合作为基本分布的归一化流 所以我有点被火炬困住了 但是 您可以通过估计 torch 中高斯模型的混合来在代码中重现我的错误 我的代码如下 import numpy as np import matplotlib p
  • 保存具有自定义前向功能的 Bert 模型并将其置于 Huggingface 上

    我创建了自己的 BertClassifier 模型 从预训练开始 然后添加由不同层组成的我自己的分类头 微调后 我想使用 model save pretrained 保存模型 但是当我打印它并从预训练上传时 我看不到我的分类器头 代码如下
  • Fine-Tuning DistilBertForSequenceClassification:不是学习,为什么loss没有变化?权重没有更新?

    我对 PyTorch 和 Huggingface transformers 比较陌生 并对此尝试了 DistillBertForSequenceClassificationKaggle 数据集 https www kaggle com c

随机推荐

  • three.js开发全景视频播放器的现实方法

    业余弄弄three js 想用three js实现播放全景视频 研究了一段 搜索很多资料 感觉这一遍很棒 搜藏分享下 原理 将video标签拉伸显示在three js场景的一个球模型上 用相机在中间播放渲染 基础 基于three js官方案
  • IntelliJ IDEA 学习笔记 - 几个窗口布局设置技巧

    原文 https blog csdn net cgl125167016 article details 79000774 utm source copy IntelliJ IDEA 简体中文专题教程 编辑区分屏 IntelliJ IDEA
  • 下载Eclipse IDE

    提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档 文章目录 一 下载eclipse 二 安装语言包 一 下载eclipse Eclipse是一个开放源代码的 基于Java的可扩展开发平台 官方网站是https www ecl
  • 为 SQL Server 站点数据库服务器配置 SPN

    如何为 SQL Server 站点数据库服务器配置 SPN 主题上次更新时间 2008 年 1 月 使用 SQL Server 计算机的本地系统帐户运行 SQL Server 服务不是 SQL Server 最佳方案 为了最安全地运行 SQ
  • day 2

    定义一个学生的结构体 包含学生的姓名年龄 成绩 性别 学生的成绩姓名定义为私有权限 定义一个学生类型的结构体变量 设置共有函数用于给学生的成绩和名字进行赋值 include
  • 半导体成新资本洼地,国产化浪潮势不可挡

    配图来自Canva 近日 中芯国际成功登陆科创板 按照中芯国际发行价27 46元 股 发行16 86亿股计算 本次的募资金额是462 87亿元 比此前招股书规划的200亿元高出一倍多 在超额配售选择权行使后 发行总股数扩大至19 38亿股
  • Linux查看与挂载新磁盘

    问题 把CentOS都换成了Ubuntu Server 16 04 LTS 用df h查看磁盘占用情况 确发现之前插入的一块大容量磁盘 dev sdb1消失了 是磁盘坏了 还是没被系统识别 解决 1 用命令fdisk l查看新磁盘是否被系统
  • QSharedMemory在linux下异常崩溃导致的bug

    感谢这位博主 https blog csdn net xinluo7 article details 118226389 在Windows系统下 当程序出现崩溃 虽然没有主动调用QSharedMemory attach 但是系统会自动回收Q
  • Java+MyEclipse+Tomcat (三)配置MySQL及查询数据显示在JSP网页中

    前面两篇文章讲述了如何配置MyEclipse和Tomcat开发JSP网站 如何配置Servlet简单实现表单提交 这篇文章主要讲述配置MySQL实现数据库连接MyEclipse 最后将查询表中的数据显示在JSP网页中 文章主要以图片描述为主
  • Java 多线程编程(入门)

    目录 一 简单介绍 Thread类 1 Thread类中一些常用的方法 2 编写一个简单多线程程序 入门 二 Java中创建多线程的方法 重点面试题 1 继承 Thread 类 2 实现 Runnable 接口 重写 run 3 使用匿名内
  • 00.mipi协议

    mipi差分信号原理 理解mipi协议 MIPI DSI LP mode命令及格式详解 MIPI信号的分析 结合示波器实际测试波形 MIPI 移动行业处理器接口 是Mobile Industry Processor Interface的缩写
  • onlyoffice报 error self signed certificate导致download failed错误处理

    安装nextcloud onlyoffice 打开onlyoffice报错 进入容器看out log报错信息 root nextcloud docker ps a Emulate Docker CLI using podman Create
  • HTTP请求详解

    HTTP概念 HTTP全称是HyperText Transfer Protocal 即超文本传输协议 是应用层协议 当你上网浏览网页的时候 浏览器和web服务器之间就会通过HTTP在Internet上进行数据的发送和接收 HTTP是一个基于
  • PHP 两个二维数组求不同

    public function arrcha arr1 0 id gt 1 name gt name arr1 1 id gt 2 name gt name2 arr1 2 id gt 3 name gt name3 arr1 3 id g
  • JNI入门基础

    环境安装 想要使用jni进行ndk开发 我们首先要安装下面这些工具 否则直接从入门到放弃 下载ndk支持 在Android studio中下载上图中框选的两个工具 版本号自己任意选一个 下载完成之后 Android Studio就拥有了进行
  • 类模板函数特化(专用化)specialization of …… after instantiation

    http stackoverflow com questions 7774188 explicit specialization after instantiation http blog csdn net xcysuccess3 arti
  • [ASP.NET MVC 小牛之路]05 - 使用 Ninject

    在 ASP NET MVC 小牛之路 系列上一篇文章 依赖注入 DI 和Ninject 的末尾提到了在ASP NET MVC中使用Ninject要做的两件事情 续这篇文章之后 本文将用一个实际的示例来演示Ninject在ASP NET MV
  • Spring Boot框架

    目录 一 Spring Boot 1 Spring Boot优点 2 创建Spring Boot 3 Spring Boot配置文件 1 配置文件的作用 2 properties文件格式 3 yml文件的格式 4 properties vs
  • 程序员升职记 全关卡攻略&通俗思路 Human Resource Machine

    程序员升职记 全过关方法 通俗思路 博主本着能过就过的思想 写出的解答必然不是最优解 但是可以给大家提供一点思路来参考 其中17和22的解答整理自网络 特别是17的解答 要比博主的原解答巧妙不少 1 收发室 模拟程序输入输出 HUMAN R
  • 深度学习大模型训练--分布式 deepspeed PipeLine Parallelism 源码解析

    deepspeed PipeLine Parallelism 源码解析 basic concept PipeDream abstract 1F1B 4 steps Code comprehension in deepspeed prepar