pytorch-3-可视化
Visdom可视化
官网https://github.com/facebookresearch/visdom
visdom由于其功能简单,一般会被定义为服务器端的matplot,也就是说我们可以直接使用python的控制台模式进行开发并在服务器上执行,将一些可视化的数据传送到Visdom服务上,通过Visdom服务进行可视化
使用命令python -m visdom.server 在本地启动服务器,启动后会提示It’s Alive! You can navigate to http://localhost:8097 这就说明服务已经可用,我们打开浏览器,输入http://localhost:8097 即可看到页面。
端口8097是默认的端口可以在启动命令后加 -port参数指定端口,常用的参数还有 –hostname,-base_url等
https://blog.csdn.net/qq_36941368/article/details/82288154
新版的不需要了 pip install –upgrade visdom就好
可视化接口
Visdom是由Plotly 提供的可视化支持,所以提供一下可视化的接口: - vis.scatter : 2D 或 3D 散点图 - vis.line : 线图 - vis.stem : 茎叶图 - vis.heatmap : 热力图 - vis.bar : 条形图 - vis.histogram: 直方图 - vis.boxplot : 箱型图 - vis.surf : 表面图 - vis.contour : 轮廓图 - vis.quiver : 绘出二维矢量场 - vis.image : 图片 - vis.text : 文本 - vis.mesh : 网格图 - vis.save : 序列化状态
1 | import torch |
1 | # 更新损失函数 |
Tensorboard可视化
tensorboard –logdir logs 即可启动,默认的端口是 6006,在浏览器中打开 http://localhost:6006/ 即可看到web页面。
(这样启动后 网页正常,但加载了图片不显示。解决方法:在Anaconda Prompt中先进入日志存放的目录,再运行TensorBoard,并将日志的地址指向程序日志输出的地址。命令: tensorboard –logdir=./logs)(因为下面代码写的是log_dir=’./logs’)
IMAGES
可视化当前轮训练使用的训练/测试图片或者 feature maps
GRAPHS
可视化计算图的结构及计算图上的信息,通常用来展示网络的结构
HISTOGRAMS
可视化张量的取值分布,记录变量的直方图(统计张量随着迭代轮数的变化情况)
PROJECTOR
全称Embedding Projector 高维向量进行可视化
1 | import torch |
使用PROJECTOR对高维向量可视化
PROJECTOR的的原理是通过PCA,T-SNE等方法将高维向量投影到三维坐标系(降维度)。Embedding Projector从模型运行过程中保存的checkpoint文件中读取数据,默认使用主成分分析法(PCA)将高维数据投影到3D空间中,也可以通过设置设置选择T-SNE投影方法,这里做一个简单的展示。
1 | BATCH_SIZE=512 |
1 | # train(model, train_loader, optimizer, 0) |
绘制网络结构
使用tensorboard的GRAPHS来实现网络结构的可视化。 由于pytorch使用的是动态图计算,所以我们这里要手动进行一次前向的传播.
1 | vgg16 = models.vgg16(pretrained=True) # 这里下载预训练好的模型 |
VGG(
(features): Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): ReLU(inplace=True)
(2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(3): ReLU(inplace=True)
(4): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(5): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(6): ReLU(inplace=True)
(7): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(8): ReLU(inplace=True)
(9): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(10): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(11): ReLU(inplace=True)
(12): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(13): ReLU(inplace=True)
(14): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(15): ReLU(inplace=True)
(16): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(17): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(18): ReLU(inplace=True)
(19): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(20): ReLU(inplace=True)
(21): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(22): ReLU(inplace=True)
(23): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
(24): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(25): ReLU(inplace=True)
(26): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(27): ReLU(inplace=True)
(28): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(29): ReLU(inplace=True)
(30): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(avgpool): AdaptiveAvgPool2d(output_size=(7, 7))
(classifier): Sequential(
(0): Linear(in_features=25088, out_features=4096, bias=True)
(1): ReLU(inplace=True)
(2): Dropout(p=0.5, inplace=False)
(3): Linear(in_features=4096, out_features=4096, bias=True)
(4): ReLU(inplace=True)
(5): Dropout(p=0.5, inplace=False)
(6): Linear(in_features=4096, out_features=1000, bias=True)
)
)
1 | # 前向传播前,先要把图片做一些调整 |
可视化cnn
两类方法,一种是基于Deconvolution, 另一种则是基于反向传播的方法
基于Deconvolution的方法
Visualizing and Understanding Convolutional Networks(https://arxiv.org/abs/1311.2901 ) 主要是将激活函数的特征映射回像素空间,来揭示什么样的输入模式能够产生特定的输出,因为网络是有层级关系的,所以越靠近输出的层级学到的特征越抽象,与实际任务越相关,这里就不多介绍了,这里(https://github.com/saketd403/Visualizing-and-Understanding-Convolutional-neural-networks )有一个使用 keras的实现,有兴趣的可以看看
fastai
fastai库是基于他的创始人Jeremy Howard 等人开发的 Deep Learning 课程深度学习的研究,为计算机视觉、文本、表格数据、时间序列、协同过滤等常见深度学习应用提供单一、一致界面的深度学习库,可以做到开箱即用。这意味着,如果你已经学会用fastai创建实用的计算机视觉(CV)模型,那你就可以用同样的方法创建自然语言处理(NLP)模型,或是其他模型。
多GPU训练
三个方式
torch.nn.DataParalle
一般情况下我们都会使用一台主机带多个显卡,这样是一个最节省预算的方案,在Pytorch中为我们提供了一个非常简单的方法来支持但主机多GPU,那就torch.nn.DataParalle 我们只要将我们自己的模型作为参数,直接传入即可,剩下的事情Pytorch都为我们做了我们只需要增大我们训练的batch_size(一般计算为N倍,N为显卡数量),其他代码不需要任何改动。 虽然代码不需要做更改,但是batch size太大了训练收敛会很慢,所以还要把学习率调大一点。大学率也会使得模型的训练在早期的阶段变得十分不稳定,所以这里需要一个学习率的热身(warm up) 来稳定梯度的下降,然后在逐步的提高学习率。
这种热身只有在超级大的批次下才需要进行,一般我们这种一机4卡或者说在batch size 小于 5000(个人测试)基本上是不需要的。例如最近富士通使用2048个GPU,74秒训练完成resnet50的实验中使用的batch size 为 81920 arivx这种超大的size才需要。
DataParallel的并行处理机制是,首先将模型加载到主 GPU 上(默认的第一个GPU,GPU0为主GPU),然后再将模型复制到各个指定的从 GPU 中,然后将输入数据按 batch 维度进行划分,具体来说就是每个 GPU 分配到的数据 batch 数量是总输入数据的 batch 除以指定 GPU 个数。每个 GPU 将针对各自的输入数据独立进行 forward 计算,最后将各个 GPU 的 loss 进行求和,再用反向传播更新单个 GPU 上的模型参数,再将更新后的模型参数复制到剩余指定的 GPU 中,这样就完成了一次迭代计算。
DataParallel其实也是一个nn.Model所以我们可以保存权重的方法和一般的nn.Model没有区别,只不过如果你想使用单卡或者cpu作为推理的时候需要从里面读出原始的model
DataParallel会将定义的网络模型参数默认放在GPU 0上,所以dataparallel实质是可以看做把训练参数从GPU拷贝到其他的GPU同时训练,这样会导致内存和GPU使用率出现很严重的负载不均衡现象,即GPU 0的使用内存和使用率会大大超出其他显卡的使用内存,因为在这里GPU0作为master来进行梯度的汇总和模型的更新,再将计算任务下发给其他GPU,所以他的内存和使用率会比其他的高。
1 | #使用内置的一个模型,我们这里以resnet50为例 |
torch.distributed
构建更为同步的分布式运算。使用torch.distributed不仅可以支持单机还可以支持多个主机,多个GPU进行计算。
torch.distributed相对于torch.nn.DataParalle 是一个底层的API,所以我们要修改我们的代码,使其能够独立的在机器(节点)中运行。我们想要完全实现分布式,并且在每个结点的每个GPU上独立运行进程,这一共需要N个进程。N是我们的GPU总数,这里我们以4来计算。
首先 初始化分布式后端,封装模型以及准备数据,这些数据用于在独立的数据子集中训练进程。
代码torch.utils.checkpoint
在我们训练时,可能会遇到(目前我还没遇到)训练集的单个样本比内存还要大根本载入不了,那如何来训练呢?pytorch为我们提供了梯度检查点(gradient-checkpointing)节省计算资源,梯度检查点会将我们连续计算的元正向和元反向传播切分成片段。但由于需要增加额外的计算以减少内存需求,该方法效率会有一些下降,但是它在某些示例中有较为明显的优势,比如在长序列上训练RNN模型,这个由于复现难度较大 就不介绍了,官方文档在这里 遇到这种情况的朋友可以查看下官方的解决方案。
在PyTorch中使用DistributedDataParallel进行多GPU分布式模型训练
https://handbook.pytorch.wiki/chapter4/distributeddataparallel/readme.html
数据竞赛平台
kaggle