携手创作,一起生长!这是我参加「日新计划 8 月更文应战」的第5天,点击检查活动详情

导语

前面的两篇博客幻方萤火AI算力渠道运用笔记(1):MacOS下的客户端安装与办理渠道概览和幻方萤火AI算力渠道运用笔记(2):Hfai本地指令行东西运用,咱们介绍了如何装备MacOS端的网络vpn和本地hfai指令行东西,在完结以上基础装备后,本篇博客将测验运用算力渠道运转一个小的example作为示例,以清晰开发流程,本文将以幻方官方文档提供的Resnet-50代码作为示例。

hfai workspace简介

幻方的萤火超算是一个长途的服务集群。对于研究者来说,他们需求将本地的数据、代码传到这个长途集群中,才能够练习其模型。hfai workspace便是用来连通本地工程目录和长途萤火集群的东西。

经过该东西,用户能够在自己环境,如个人电脑、个人集群等,编写代码,调试模型,然后经过一行指令直接将调试好的代码上传长途萤火集群,利用超算算力来练习模型。

一个简单的示例:Resnet-50网络练习

为了愈加直观的理解hfai workspace的功用,这儿介绍一个快速上手的案例进行运转。

Resnet-50简介

Resnet是是经典的残差网络(Residual Network)的缩写,该系列网络广泛用于方针分类等范畴以及作为计算机视觉使命骨干经典神经网络的一部分,其中一些典型的网络有Resnet-50, Resnet-101等。Resnet网络在计算机视觉范畴应用广泛,是一个非常经典的模型。

Resnet-50练习代码

本篇博客中运用的练习文件train.py代码来自幻方萤火渠道文档快速开端中引荐的模型库中的模型,详细如下:

import hf_env
hf_env.set_env('202111')
import os
from pathlib import Path
import torch
from torch import nn
from torch.nn.parallel import DistributedDataParallel
from torch.utils.data.distributed import DistributedSampler
from torch.optim import SGD
from torch.optim.lr_scheduler import StepLR
from torchvision import transforms, models
import hfai
import hfai.distributed as dist
def train(dataloader, model, criterion, optimizer, epoch, local_rank, start_step, best_acc):
    model.train()
    for step, batch in enumerate(dataloader):
        step += start_step
        samples, labels = [x.cuda(non_blocking=True) for x in batch]
        outputs = model(samples)
        optimizer.zero_grad()
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        if local_rank == 0 and step % 20 == 0:
            print(f'Epoch: {epoch}, Step: {step}, Loss: {loss.item()}', flush=True)
        # 保存
        model.try_save(epoch, step + 1, others=best_acc)
def validate(dataloader, model, criterion, epoch, local_rank):
    loss, correct1, correct5, total = torch.zeros(4).cuda()
    model.eval()
    with torch.no_grad():
        for step, batch in enumerate(dataloader):
            samples, labels = [x.cuda(non_blocking=True) for x in batch]
            outputs = model(samples)
            loss += criterion(outputs, labels)
            _, preds = outputs.topk(5, -1, True, True)
            correct1 += torch.eq(preds[:, :1], labels.unsqueeze(1)).sum()
            correct5 += torch.eq(preds, labels.unsqueeze(1)).sum()
            total += samples.size(0)
    for x in [loss, correct1, correct5, total]:
        dist.reduce(x, 0)
    if local_rank == 0:
        loss_val = loss.item() / dist.get_world_size() / len(dataloader)
        acc1 = 100 * correct1.item() / total.item()
        acc5 = 100 * correct5.item() / total.item()
        print(f'Epoch: {epoch}, Loss: {loss_val}, Acc1: {acc1:.2f}%, Acc5: {acc5:.2f}%', flush=True)
    return correct1.item() / total.item()
def main(local_rank):
    # 超参数设置
    epochs = 2
    batch_size = 50
    lr = 0.1
    save_path = 'output/resnet'
    Path(save_path).mkdir(exist_ok=True, parents=True)
    # 多机通信
    ip = os.environ['MASTER_ADDR']
    port = os.environ['MASTER_PORT']
    hosts = int(os.environ['WORLD_SIZE'])  # 机器个数
    rank = int(os.environ['RANK'])  # 当时机器编号
    gpus = torch.cuda.device_count()  # 每台机器的GPU个数
    # world_size是大局GPU个数,rank是当时GPU大局编号
    dist.init_process_group(backend='nccl',
                            init_method=f'tcp://{ip}:{port}',
                            world_size=hosts * gpus,
                            rank=rank * gpus + local_rank)
    torch.cuda.set_device(local_rank)
    # 模型、数据、优化器
    model = models.resnet50()
    model = DistributedDataParallel(model.cuda(), device_ids=[local_rank])
    train_transform = transforms.Compose([
        transforms.RandomResizedCrop(224),
        transforms.RandomHorizontalFlip(),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ])  # 界说练习集改换
    train_dataset = hfai.datasets.ImageNet('train', transform=train_transform)
    train_datasampler = DistributedSampler(train_dataset)
    train_dataloader = train_dataset.loader(batch_size, sampler=train_datasampler, num_workers=4, pin_memory=True)
    val_transform = transforms.Compose([
        transforms.Resize(256),
        transforms.CenterCrop(224),
        transforms.ToTensor(),
        transforms.Normalize(mean=[0.485, 0.456, 0.406],
                             std=[0.229, 0.224, 0.225])
    ])  # 界说测验集改换
    val_dataset = hfai.datasets.ImageNet('val', transform=val_transform)
    val_datasampler = DistributedSampler(val_dataset)
    val_dataloader = val_dataset.loader(batch_size, sampler=val_datasampler, num_workers=4, pin_memory=True)
    criterion = nn.CrossEntropyLoss()
    optimizer = SGD(model.parameters(), lr=lr, momentum=0.9, weight_decay=1e-4)
    scheduler = StepLR(optimizer, step_size=30, gamma=0.1)
    ckpt_path = os.path.join(save_path, 'latest.pt')
    start_epoch, start_step, best_acc = hfai.checkpoint.init(model, optimizer, scheduler=scheduler, ckpt_path=ckpt_path)
    best_acc = best_acc or 0
    # 练习、验证
    for epoch in range(start_epoch, epochs):
        # resume from epoch and step
        train_datasampler.set_epoch(epoch)
        train_dataloader.set_step(start_step)
        train(train_dataloader, model, criterion, optimizer, epoch, local_rank, start_step, best_acc)
        start_step = 0  # reset
        scheduler.step()
        acc = validate(val_dataloader, model, criterion, epoch, local_rank)
        # 保存
        if rank == 0 and local_rank == 0:
            if acc > best_acc:
                best_acc = acc
                print(f'New Best Acc: {100*acc:.2f}%!')
                torch.save(model.module.state_dict(),
                           os.path.join(save_path, 'best.pt'))
if __name__ == '__main__':
    ngpus = torch.cuda.device_count()
    torch.multiprocessing.spawn(main, args=(), nprocs=ngpus)

该练习代码会在ImageNet数据集上对Resnet-50进行epochs = 2的练习(这儿是为了快速演示,所以设置了一个较小的epochs)。

该练习代码运用分布式数据并行(DistributedDataParallel,即DDP)练习,并在每个epoch练习完结后进行一次验证,计算Top-1和Top-5的分类准确率。最终,会将最好的模型checkpoint进行存储,保存为best.pt

最终,需求留意的是咱们在文件开头加入了

import hf_env
hf_env.set_env('202111')

设置该练习文件的运转环境,这儿直接运用了幻方官方的2021年11月的运转环境。

hfai workspace初始化

假定咱们在本地现已调试开发好了一个在ImageNet上进行练习的Resnet-50模型的练习代码,接下来,咱们需求将代码上传到算力渠道进行练习。

首要,咱们需求初始化该项意图workspace,即该模型对应的项目文件夹。首要,咱们需求手动创建一个本地的文件夹,这儿我取名为workspace_example_for_resnet

(hfai) jiexing@jiexingdeMacBook-Pro hfai % mkdir workspace_example_for_resnet
(hfai) jiexing@jiexingdeMacBook-Pro hfai % cd workspace_example_for_resnet 

接着,咱们将练习的文件加入到改文件夹中,练习文件命名为train.py,并添加了一个Readme文件。

(hfai) jiexing@jiexingdeMacBook-Pro workspace_example_for_resnet % ls
README.md       train.py

之后,咱们进行初始化操作,指令为hfai workspace init [workspace_name],输出如下:

(hfai) jiexing@jiexingdeMacBook-Pro workspace_example_for_resnet % hfai workspace init workspace_example_for_resnet
查询用户 group 信息...
初始化 workspace [/Users/jiexing/Nextcloud/project/hfai/workspace_example_for_resnet]->[oss://group_linzhh/linzhh/workspaces/workspace_example_for_resnet] 成功

hfai workspace推送与履行

初始化完结后,咱们将这两个文件推送到长途渠道端,运用指令hfai workspace push

(hfai) jiexing@jiexingdeMacBook-Pro workspace_example_for_resnet % hfai workspace push
开端遍历本地作业区目录...
开端遍历集群作业区目录...
开端打包本地作业区目录...
(1/2) 开端同步本地目录 /Users/jiexing/Nextcloud/project/hfai/workspace_example_for_resnet 到远端,共3.05KB...
pushing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
(2/2) 上传成功,开端同步到集群,请等待...
syncing ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 100% 0:00:00
推送成功

hfai东西会主动将作业目录进行打包和上传,推送至幻方萤火渠道。而对于履行,hfai提供了多重形式的履行方法,详细能够运用hfai python -h查询。

整体来说,hfai提供三种形式的履行方法:

  1. 本地履行。这种方法和普通的python脚本在本地环境中履行没有区别,运用的指令为hfai python <experiment.py> [<experiment_params>...]
  2. 长途履行。这种方法即提交使命到萤火二号运转,运用的指令为hfai python <experiment.py> [<experiment_params>...] -- [CLUSTER_OPTIONS],比较于1,这儿运用--指令添加后续长途参数;
  3. 模仿履行。这种方法在本地模仿运转,会提供萤火二号共同的环境变量和体现,主要测验本地编写的代码脚本能否收到幻方办理渠道的使命打断信号等,运用的指令为hfai python <experiment.py> [<experiment_params>...] ++ [CLUSTER_OPTIONS],比较于1,这儿运用++指令添加模仿参数。

这儿,咱们运用官方库房引荐的运转指令

hfai python train.py -- -n 1

该指令表示咱们要运用长途算力渠道运转train.py,运用的服务器节点数为1(一台机器8张卡)。

运转进程如下:

(hfai) jiexing@jiexingdeMacBook-Pro workspace_example_for_resnet % hfai python train.py -- -n 1
检测到是 [/Users/jiexing/Nextcloud/project/hfai/workspace_example_for_resnet] -> [group_linzhh/linzhh/workspaces/workspace_example_for_resnet] 中的代码,先推送到远端...
开端遍历本地作业区目录...
开端遍历集群作业区目录...
数据已同步,忽略本次操作
……
====================  fetching  log on rank 0... ====================
[2022-08-01 09:17:40.756442] [start training train.py on jd-h0605-dl for linzhh]
[2022-08-01 09:17:40.855583] [练习前检查] 检查[jd-h0605-dl] cpu memory 44.0 < 150G and total gpu memory 0 < 100M 经过
[2022-08-01 09:18:10.096679] Epoch: 0, Step: 0, Loss: 7.289088249206543
[2022-08-01 09:18:13.314214] Epoch: 0, Step: 20, Loss: 7.264989852905273
[2022-08-01 09:18:15.124726] Epoch: 0, Step: 40, Loss: 7.147526264190674
……
[2022-08-01 09:28:06.848568] Epoch: 1, Step: 3200, Loss: 3.582792282104492
[2022-08-01 09:28:15.918022] Epoch: 1, Loss: 3.25835107421875, Acc1: 30.57%, Acc5: 56.37%
[2022-08-01 09:28:17.562394] New Best Acc: 30.57%!
[2022-08-01 09:28:21.328877] [finish training train.py on jd-h0605-dl for linzhh]

输出检查与下载

咱们能够登录网页端的办理渠道(studio.yinghuo.high-flyer.cn/ ),在作业区栏目中找到咱们这次运转运用的作业区目录,即可检查这次的输出

幻方萤火AI算力平台使用笔记(3):Workspace功能浅试——Resnet-50训练示例

咱们能够经过workspace的同步指令,将这些内容下载到本地,这些内容将在后边的博客中记载。

总结

本篇博客为咱们介绍了幻方萤火AI算力渠道上一个最简单的demo示例程序的运转,咱们经过在本地编写Resnet-50模型的代码,将其推送到长途后在Imagenet数据集上进行练习,得到了预期的输出成果。下篇博客将记载workspace相关指令的学习笔记,敬请期待。