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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import torch
import math
import numpy as np
from visdom import Visdom
import time

env = Visdom()
assert env.check_connection() #测试一下链接,链接错误的话会报错

Y = np.linspace(0, 2 * math.pi, 70)
X = np.column_stack((np.sin(Y), np.cos(Y)))

env.stem(
X=X,
Y=Y,
opts=dict(legend=['Sine', 'Cosine'])
)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 更新损失函数
import time
x,y=0,0
env2 = Visdom()
pane1= env2.line(
X=np.array([x]),
Y=np.array([y]),
opts=dict(title='dynamic data'))
for i in range(10):
time.sleep(1) #每隔一秒钟打印一次数据
x+=i
y=(y+i)*1.5
print(x,y)
env2.line(
X=np.array([x]),
Y=np.array([y]),
win=pane1,#win参数确认使用哪一个pane
update='append') #我们做的动作是追加,除了追加意外还有其他方式,这里我们不做介绍了

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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
import torch
import numpy as np
import torch.nn as nn
import torch.nn.functional as F
from PIL import Image
from torchvision import transforms
from torchvision import models,datasets

# 这里的引用也要修改成torch的引用
#from tensorboardX import SummaryWriter
from torch.utils.tensorboard import SummaryWriter

cat_img = Image.open('./data/cat.jpg')
print(cat_img.size)

# 1280x853的图,我们先把她变成224x224的图片,因为后面要使用的是vgg16
transform_224 = transforms.Compose([
transforms.Resize(224), # 这里要说明下 Scale 已经过期了,使用Resize
transforms.CenterCrop(224),
transforms.ToTensor(),
])
cat_img_224=transform_224(cat_img)

# 展示图片
writer = SummaryWriter(log_dir='./logs', comment='cat image') # 这里的logs要与--logdir的参数一样
writer.add_image("cat",cat_img_224)
writer.close()# 执行close立即刷新,否则将每120秒自动刷新

# 更新损失函数,scalar页面
x = torch.FloatTensor([100])
y = torch.FloatTensor([500])

for epoch in range(30):
x = x * 1.2
y = y / 1.1
loss = np.random.random()
with SummaryWriter(log_dir='./logs', comment='train') as writer: #可以直接使用python的with语法,自动调用close方法
writer.add_histogram('his/x', x, epoch)
writer.add_histogram('his/y', y, epoch)
writer.add_scalar('data/x', x, epoch)
writer.add_scalar('data/y', y, epoch)
writer.add_scalar('data/loss', loss, epoch)
writer.add_scalars('data/data_group', {'x': x,
'y': y}, epoch)

使用PROJECTOR对高维向量可视化
PROJECTOR的的原理是通过PCA,T-SNE等方法将高维向量投影到三维坐标系(降维度)。Embedding Projector从模型运行过程中保存的checkpoint文件中读取数据,默认使用主成分分析法(PCA)将高维数据投影到3D空间中,也可以通过设置设置选择T-SNE投影方法,这里做一个简单的展示。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
BATCH_SIZE=512 
EPOCHS=20
train_loader = torch.utils.data.DataLoader(
datasets.MNIST('data', train=True, download=True,
transform=transforms.Compose([
transforms.ToTensor(),
transforms.Normalize((0.1307,), (0.3081,))
])),
batch_size=BATCH_SIZE, shuffle=True)

class ConvNet(nn.Module):
def __init__(self):
super().__init__()
# 1,28x28
self.conv1=nn.Conv2d(1,10,5) # 10, 24x24
self.conv2=nn.Conv2d(10,20,3) # 128, 10x10
self.fc1 = nn.Linear(20*10*10,500)
self.fc2 = nn.Linear(500,10)
def forward(self,x):
in_size = x.size(0)
out = self.conv1(x) #24
out = F.relu(out)
out = F.max_pool2d(out, 2, 2) #12
out = self.conv2(out) #10
out = F.relu(out)
out = out.view(in_size,-1)
out = self.fc1(out)
out = F.relu(out)
out = self.fc2(out)
out = F.log_softmax(out,dim=1)
return out
model = ConvNet()
optimizer = torch.optim.Adam(model.parameters())
def train(model, train_loader, optimizer, epoch):
n_iter=0
model.train()
for batch_idx, (data, target) in enumerate(train_loader):
optimizer.zero_grad()
output = model(data)
loss = F.nll_loss(output, target)
loss.backward()
optimizer.step()
if(batch_idx+1)%30 == 0:
n_iter=n_iter+1
print('Train Epoch: {} [{}/{} ({:.0f}%)]\tLoss: {:.6f}'.format(
epoch, batch_idx * len(data), len(train_loader.dataset),
100. * batch_idx / len(train_loader), loss.item()))
#相对于以前的训练方法 主要增加了以下内容
out = torch.cat((output.data, torch.ones(len(output), 1)), 1) # 因为是投影到3D的空间,所以我们只需要3个维度
with SummaryWriter(log_dir='./logs', comment='mnist') as writer:
#使用add_embedding方法进行可视化展示
writer.add_embedding(
out,
metadata=target.data,
label_img=data.data,
global_step=n_iter)
1
2
3
# train(model, train_loader, optimizer, 0)
# 打开 http://localhost:6006/#projector 即可看到效果。
# 目前测试投影这部分也是有问题的,根据官网文档的代码进行测试,也显示不出来,正在找原因

绘制网络结构
使用tensorboard的GRAPHS来实现网络结构的可视化。 由于pytorch使用的是动态图计算,所以我们这里要手动进行一次前向的传播.

1
2
vgg16 = models.vgg16(pretrained=True) # 这里下载预训练好的模型
print(vgg16) # 打印一下这个模型
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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
# 前向传播前,先要把图片做一些调整
transform_2 = transforms.Compose([
transforms.Resize(224),
transforms.CenterCrop((224,224)),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225])
])

vgg16_input=transform_2(cat_img)[np.newaxis]# 因为pytorch的是分批次进行的,所以我们这里建立一个批次为1的数据集
vgg16_input.shape

out = vgg16(vgg16_input)
_, preds = torch.max(out.data, 1)
label=preds.numpy()[0]
print(label)
# 含义是预训练模型中,根据这张图估计的类别。https://gist.githubusercontent.com/yrevar/942d3a0ac09ec9e5eb3a/raw/c2c91c8e767d04621020c30ed31192724b863041/imagenet1000_clsid_to_human.txt

with SummaryWriter(log_dir='./logs', comment='vgg161') as writer:
writer.add_graph(vgg16, vgg16_input)

可视化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的实现,有兴趣的可以看看

基于Backpropagation的方法

fastai

fastai库是基于他的创始人Jeremy Howard 等人开发的 Deep Learning 课程深度学习的研究,为计算机视觉、文本、表格数据、时间序列、协同过滤等常见深度学习应用提供单一、一致界面的深度学习库,可以做到开箱即用。这意味着,如果你已经学会用fastai创建实用的计算机视觉(CV)模型,那你就可以用同样的方法创建自然语言处理(NLP)模型,或是其他模型。

https://github.com/fastai

fastai实践

多GPU训练

三个方式

  1. 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
2
3
4
5
6
7
8
9
10
#使用内置的一个模型,我们这里以resnet50为例
model = torchvision.models.resnet50()

#模型使用多GPU
mdp = torch.nn.DataParallel(model)
mdp

#获取到原始的model
m=mdp.module
m
  1. torch.distributed

    构建更为同步的分布式运算。使用torch.distributed不仅可以支持单机还可以支持多个主机,多个GPU进行计算。
    torch.distributed相对于torch.nn.DataParalle 是一个底层的API,所以我们要修改我们的代码,使其能够独立的在机器(节点)中运行。我们想要完全实现分布式,并且在每个结点的每个GPU上独立运行进程,这一共需要N个进程。N是我们的GPU总数,这里我们以4来计算。
    首先 初始化分布式后端,封装模型以及准备数据,这些数据用于在独立的数据子集中训练进程。
    代码

  2. torch.utils.checkpoint
    在我们训练时,可能会遇到(目前我还没遇到)训练集的单个样本比内存还要大根本载入不了,那如何来训练呢?

    pytorch为我们提供了梯度检查点(gradient-checkpointing)节省计算资源,梯度检查点会将我们连续计算的元正向和元反向传播切分成片段。但由于需要增加额外的计算以减少内存需求,该方法效率会有一些下降,但是它在某些示例中有较为明显的优势,比如在长序列上训练RNN模型,这个由于复现难度较大 就不介绍了,官方文档在这里 遇到这种情况的朋友可以查看下官方的解决方案。

在PyTorch中使用DistributedDataParallel进行多GPU分布式模型训练
https://handbook.pytorch.wiki/chapter4/distributeddataparallel/readme.html

数据竞赛平台

kaggle

DrivenData

CrowdANALYTIX

InnoCentive

TundIT

Codalab

Analytics Vidhya

CrowdAI

Numerai

Data Science Challenge

KDD Cup

天池

腾讯广告算法大赛