PyTorch

官网

参考1:文字版,方便整理(可视化、分布式用到的时候再整理)

参考2:入门视频

参考3:李沐老师的视频(较全面,有具体代码实现,d2l

参考4:李宏毅老师的视频(有14个作业)

kaggle

Google Colab

李宏毅课程

AI资讯、模型、论文等

论文地址(以残差网络为例):https://arxiv.org/abs/1512.03385,15年12月

CV和NLP的顶会整理如下,相关的论文可以定期关注下

  • CV
    • CVPR:International Conference on Computer Vision and Pattern Recognition
    • ICCV:International Conference on Computer Vision
    • ECCV:European Conference on Computer Vision
  • NLP
    • ACL:Annual Meeting of the Association for Computational Linguistics
    • EMNLP:Empirical Methods in Natural Language Processing
    • CoNLL:Conference on Computational Natural Language Learning
    • COLING:International Conference on Computational Linguistics

安装

CPU版本,测试的时候用CPU版本就可以了(mac系统不支持GPU版本)

# Linux
pip install torch==1.9.0+cpu torchvision==0.10.0+cpu torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html

# Mac & Windows
pip install torch torchvision torchaudio

GPU版本,需要安装对应版本的CUDA工具包,查看GPU支持的CUDA官网下载

# Linux & Windows
pip install torch==1.9.0+cu111 torchvision==0.10.0+cu111 torchaudio==0.9.0 -f https://download.pytorch.org/whl/torch_stable.html

检查torch是否支持GPU以及查看torch版本

import torch

print(torch.cuda.is_available())
print(torch.__version__)

在终端中输入"nvidia-smi"命令,会显示出显卡驱动的版本和CUDA的版本

如果显卡驱动的版本过低,与CUDA版本不匹配,那么GPU也不可用,需要根据显卡的型号更新显卡驱动

PyTorch版本同样与CUDA版本有对应关系,我们可以在这个页面查看它们之间的对应关系。如果两者版本不匹配,可以重新安装对应版本的PyTorch,或者升级CUDA工具包

如果使用docker的话,这里有很多的PyTorch的Docker镜像

三步曲

所有深度学习项目都可以简单划分成3步:数据加载、训练与模型评估

训练数据不外乎这三种:图片、文本以及类似二维表那样的结构化数据

我们先以单张图片为例,将图片分别用Pillow与OpenCV读入,然后转换为NumPy的数组

注意:老版本的OpenCV读入后的通道顺序是B、G、R(新版已调整成:R、G、B),以下Pillow中有查看通道颜色值的示例

Pillow

from PIL import Image
import numpy as np
import matplotlib.pyplot as plt

# <PIL.PngImagePlugin.PngImageFile image mode=RGBA size=420x180 at 0x114E47E80>
im = Image.open('./test.png')
# (420, 180)
print(im.size)
# Pillow是以二进制形式读入保存的,numpy可以直接接收
# (180, 420, 4) 180行,每行420个RGBA的像素点
im_pillow = np.array(im)
print(im_pillow.shape)

red_background = np.array(im_pillow)
red_background[:, :, 1] = 0
red_background[:, :, 2] = 0

green_background = np.array(im_pillow)
green_background[:, :, 0] = 0
green_background[:, :, 2] = 0

blue_background = np.array(im_pillow)
blue_background[:, :, 0] = 0
blue_background[:, :, 1] = 0

fig, axes = plt.subplots(2, 2)
axes[0, 0].imshow(im_pillow)
axes[0, 0].set_title("origin pic")
# 不要显示坐标轴
axes[0, 0].axis('off')
axes[0, 1].imshow(red_background)
axes[0, 1].set_title("red pic")
axes[0, 1].axis('off')
axes[1, 0].imshow(green_background)
axes[1, 0].set_title("green pic")
axes[1, 0].axis('off')
axes[1, 1].imshow(blue_background)
axes[1, 1].set_title("blue pic")
axes[1, 1].axis('off')
plt.show()

OpenCV

import cv2

# OpenCV读取后直接是numpy
# (180, 420, 3) 180行,每行420个RGB的像素点(通道的顺序是:B、G、R)
im_cv2 = cv2.imread('./test.png')
print(im_cv2.shape)

模型评估

在模型评估时,我们一般会将模型的输出转换为对应的标签

假设现在我们的问题是将图片分为2个类别,包含logo的图片与不包含logo的图片。模型会输出形状为(2,)的数组

我们把它叫做probs,它存储了两个概率,我们假设索引为0的概率是包含logo图片的概率,另一个是其它图片的概率,它们两个概率的和为1

如果包含logo对应的概率大,则可以推断该图片为包含logo的图片,否则为其他图片

简单的做法就是判断probs[0]是否大于0.5,如果大于0.5,则可以认为图片是我们要寻找的

如果类别很多,假设有1000个类别的ImageNet。如果要找概率最大的那个,可以使用np.argmax(probs)

如果要找概率前N大的,可以使用:argsort,如果是Tensor的话,可以直接使用:topk

import numpy as np

probs = np.array([8, 7, 1, 3, 0, 2, 5, 6, 4])
# 加了负号,是按降序排序
probs_idx_sort = np.argsort(-probs)
# 值前3大的是8,7,6,对应的索引是:[0 1 7]
print(probs_idx_sort[0:3])

对于分类模型的评估来说,有很多评价指标,例如准确率、精确率、召回率、F1-Score等。其中,最直观、最有说服力的就是精确率与召回率,这也是我在项目中观察的主要是指标

混淆矩阵

精确率与召回率就是通过混淆矩阵计算出来的

根据预测结果和真实类别的组合,一共有四种情况:

  1. TP是说真实类别为Logo,模型也预测为Logo;
  2. FP是说真实类别为Others,但模型预测为Logo;
  3. FN是说真实类别为Logo,但模型预测为Others;
  4. TN是说真实类别为Others,模型也预测为Others;

精确率的计算方法为:

precision=TPTP+FP precision = \frac{TP}{TP+FP}

召回率的计算方式为:

recall=TPTP+FN recall = \frac{TP}{TP+FN}

精确率与召回率分别衡量了模型的不同表现,精确率说的是,如果模型认为一张图片是A类,那有多大概率是A类。而召回率衡量的是,在整个验证集中,模型能找到多少A类图片

那问题来了,怎样根据这两个指标来选择模型呢?业务需求不同,我们侧重的指标就不一样

如果老板允许一部分A类图片没有被识别,但是模型必须非常准,模型说一张图片是A类,那图片真实类别就有非常大的概率是A类图片,那应该侧重的就是精确率;

如果老板希望把线上A类尽可能地识别出来,允许一部分图片被误识别,那应该侧重的就是召回率

在实际项目中,我们可以把模型对每张图片的预测结果保存到一个txt中,这样可以比较直观地筛选一些模型的badcase,并且验证集如果非常大,又需要调整的时候,直接更改txt就可以了,不需要再次让模型预测整个验证集

下面是txt文件的一部分,分别记录了A类的概率、others类的概率、真实类别是否为A、真实类别是否为others、预测类别是否为A、预测类别是否为ohters、图片名


0.64460 0.35540 1 0 1 0 ./data/val/class_a/13.jpeg
0.58476 0.41524 1 0 1 0 ./data/val/class_a/14.jpeg
...

原地操作

在PyTorch中,方法名末尾带有下划线(通常是一个或两个)往往表示该方法是原地操作(in-place operation)

原地操作是指该方法会直接修改输入张量(tensor)的内容,而不是返回一个新的张量。这种方式可以节省内存,因为不需要为结果分配额外的存储空间

例如,对于张量x,调用x.zero()会将x的所有元素设置为0,而不会返回一个新的全零张量。同样地,x.add(y)会将y的元素加到x上,并直接修改x的内容

固定随机种子

myseed = 42069
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
np.random.seed(myseed)
torch.manual_seed(myseed)
if torch.cuda.is_available():
    torch.cuda.manual_seed_all(myseed)

results matching ""

    No results matching ""