pytorch深入了解

前言

  经过这几天的零碎学习,我真是觉得神经网络的搭建真的太复杂了,复杂到什么程度呢?就是一个概念不懂,找到解释后,发现解释里又包含着好几个你根本不知道的概念,不过还好我做了一些学习准备,也不算是完全没有头绪。但是目前暴露的缺陷有:

  • python高级语法知识的欠缺
  • pytorch搭建神经网络的细节问题不懂
  • 对于神经网络的每一个相关细节概念的理解和了解不足

  那么针对这些,我认为可以在学习一些实例、教程时碎片化的学习来完善自己的知识框架,所以有了以下的“深入了解”学习阶段

学习阶段————深入了解

思考:

  • 神经网络的框架如何根据自己的要求、向适合解决问题的网络结构改进?
  • 学习如何使用GPU来训练模型?
  • jupyter notebook 中如何正常运行pytorch网络?

二、结合实例理解,弥补缺失的框架体系知识

1. 读取文件必要的DatasetDataLoader

  •   获取数据一直应该都是神经网络的一个要点。有些时候可以通过某些官方渠道的统一数据集来进行训练。但对于实际的项目,往往无法这样做,那么对于这一次我的大作业也就是获取图像信息来说,每一张图像的数据不一样,尺寸也都不一样,如何把这些杂乱的数据统一的放入神经网络中学习呢?在这里DatasetDataLoader就起到了必要的作用
  • DatasetDataLoader分别对应数据的读取和操作,他们是官网提供给我们处理数据的一个范例。

Dataset

  • Dataset位于torch.utils.data.Dataset中,往往我们需要创建自己的获取数据集的Mydataset类,他必须继承官方的Dataset类,并且必须要实现其两个成员函数:__len__()__getitem__()
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
import torch
import cv2
from torch.utils.data import Dataset

class datasets(Dataset):
def __init__(self,data,transform = None,test = False):
imgs = []
labels = []
self.test = test
self.len = len(data)
self.data = data
self.transform = transform
for i in self.data:
imgs.append(i[0])
self.imgs = imgs
labels.append(int(i[1]) ) #pytorch中交叉熵需要从0开始
self.labels = labels
def __getitem__(self,index):
if self.test:
filename = self.imgs[index]
filename = filename
img_path = self.imgs[index]
img = cv2.imread(img_path)
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = cv2.resize(img, (config.img_width, config.img_height))
img = transforms.ToTensor()(img)
return img,filename
else:
img_path = self.imgs[index]
label = self.labels[index]
#label = int(label)
img = cv2.imread(img_path)
img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)
img = cv2.resize(img,(config.img_width,config.img_height))
# img = transforms.ToTensor()(img)

if self.transform is not None:
img = Image.fromarray(img)
img = self.transform(img)

else:
img = transforms.ToTensor()(img)
return img,label

def __len__(self):
return len(self.data)#self.len
  • 在这个实例中,在初始化时需要的参数是,需要训练或者测试的数据,transform操作(这个具体在后面说明),至于后面的test参数也和transform有关
  • 重点看类里内置的方法

    • __getitem__(self,index):该方法支持从 0 到len(self)的索引
        在我们自己的Dataset中必须需要一个这个方法获取数据集中的每一组数据。比如在此例中,由于在建立dataset实例时出入的data数据是所有的.jpg文件,那么当我们需要获取图片进行训练或测试时,需要利用opencv的方法读取图片数据、将图片转换成RGB格式,把每个图片的尺寸统一为设定的模板尺寸,最后将图片信息数据转换为tensor张量形式

    • __len__(self)
        这个方法比较简单,用起来也很方便。目的就是,返回数据集的长度。但这个方法必须有。

  • 现存问题:在初始化时,类里面的一些赋值操作,是否存在必要性。当然,数据必须保存在数据集中,所以一个循环读取全部数据内容的操作应该要有。所以我猜测是自己如果需要用到就加,如果不会用到就不需要写在初始化方法中。

DataLoader

  • torch.utils.data已经提供的类:Dataset,但是通过这种方式只能一个个的数据的把数据全部读出来,定义了数据读取的方式,不能实现批量的把数据读取出来,为此pytorch有提供了一个方法:DataLoader()
      简单点说,就是通过DataLoaderDataset中的数据集以每次Batch_size个大小的组,读取出来,以供训练
  • Dataloader本质是一个可迭代对象,使用iter()访问,不能使用next()访问,由于它本身就是一个可迭代对象,可以使用for inputs, labels in dataloaders进行可迭代对象的访问
  • 我们一般不需要再自己去实现DataLoader的方法了,只需要在构造函数中指定相应的参数即可,比如常见的batch_sizeshuffle等等参数。所以使用DataLoader十分简洁方便。
1
2
3
4
5
6
7
8
9
10
 #自己定义的函数:获取数据并将数据分为训练集和测试集两类
test_list , train_list = get_files(config.data_folder,config.ratio)

#训练集 需要数据增强 transform 使用之前定义好的
input_traindata = datasets(train_list,transform = transform)
train_loader = DataLoader(input_traindata,batch_size = config.batch_size,shuffle = True,collate_fn = collate_fn ,pin_memory = False,num_workers = 4)

#测试集 不要数据增强 transform = None
input_testdata = datasets(test_list,transform = None)
test_loader = DataLoader(input_testdata,batch_size = config.batch_size,shuffle = False,collate_fn = collate_fn,num_workers = 4)
  • 上述例子可以看到,根据自己定义的dataset创建了训练和测试两个实例,训练需要数据增强而测试不需要,所以两个实例除数据不同,tranform也不同
  • DataLoader的参数
    • X_dataset:数据集的实例
    • batch_size:训练的提取数据的单位内所含个数
    • shuffle :布尔值True或者是False ,表示每一个epoch之后是否对样本进行随机打乱,默认是False
    • collate_fn:这个是一个问题,因为通常由自己确定。是一个自己对于数据选取的方法,但是我不知道他有什么意义,或者优势
    • pin_memory:如果设置为True,那么data loader将会在返回它们之前,将tensors拷贝到CUDA中的固定内存(CUDA pinned memory)中
    • num_workers:这个参数决定了有几个进程来处理data loading。0意味着所有的数据都会被load进主进程。(默认为0)

1.2 典型的批训练

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
import torch
import torch.utils.data as Data

torch.manual_seed(1) # reproducible

BATCH_SIZE = 5

x = torch.linspace(1, 10, 10) # this is x data (torch tensor)
y = torch.linspace(10, 1, 10) # this is y data (torch tensor)

torch_dataset = Data.TensorDataset(x, y)
loader = Data.DataLoader(
dataset=torch_dataset, # torch TensorDataset format
batch_size=BATCH_SIZE, # mini batch size
shuffle=True, # random shuffle for training
num_workers=2, # subprocesses for loading data
)

def show_batch():
for epoch in range(3): # train entire dataset 3 times
for step, (batch_x, batch_y) in enumerate(loader): # for each training step
# train your data...

print('Epoch: ', epoch, '| Step: ', step, '| batch x: ',
batch_x.numpy(), '| batch y: ', batch_y.numpy())

if __name__ == '__main__':
show_batch()
  • 不难发现,其实批训练的实现就是对DatasetDataLoader的使用,这里很简单,只是看一个思路。
  • 那么其实每一次训练的时候,对于loader实例的索引,他将带出一组Batch_size个数的数据,但是你的神经网络的输入层的结构不会因为batch_size的变化受到影响
  • 批训练中batch_size对CNN结果的影响,点击这里了解

1.3 collate_fn如何在加载数据时起作用?

  • DataLoader能够为我们自动生成一个多线程的迭代器,只要传入几个参数进行就可以了,但是你真的懂得它是如何工作的么?

问题就在这个collate_fn

  • collate_fn默认是等于default_collate
1
2
3
4
5
6
7
def __next__(self):    #这是DataLoader的关于迭代的方法的源码
if self.num_workers == 0: # same-process loading
indices = next(self.sample_iter) # may raise StopIteration
batch = self.collate_fn([self.dataset[i] for i in indices]) # 在这里调用了collate_fn函数,传递的参数是一个列表
if self.pin_memory:
batch = pin_memory_batch(batch)
return batch
  • 那么其实collate_fn这个函数的输入就是一个list,list的长度是一个batch size,list中的每个元素都是__getitem__得到的结果,想要知道详解点击这里,那么batch中的每一个元素其实就是Dataset__getitem__方法得到的比如(图片信息img、标签label)
  • 那么如果理解了以上的意思,再看collate_fn就能较快地上手了

  • 那什么时候该使用DataLoader的collate_fn这个参数?
      当定义DataSet类中的__getitem__函数的时候,由于每次返回的是一组类似于(x,y)的样本,但是如果在返回的每一组样本x,y中出现什么错误,或者是还需要进一步对x,y进行一些处理的时候,我们就需要再定义一个collate_fn函数来实现这些功能。当然我也可以自己在实现__getitem__的时候就实现这些后处理也是可以的。

  • collate_fn,中单词collate的含义是:核对,校勘,对照,整理。顾名思义,这就是一个对每一组样本数据进行一遍“核对和重新整理”,现在可能更好理解一些


2.1 torchvision是什么?

  • torchvision是PyTorch中专门用来处理图像的库,PyTorch官网的安装教程,也会让你安装上这个包。
  • 这个包中有四个大类
    • torchvision.datasets
    • torchvision.models
    • torchvision.transforms
    • torchvision.utils

torchvision.datasets

  • torchvision.datasets 是用来进行数据加载的,PyTorch团队在这个包中帮我们提前处理好了很多很多图片数据集。

    • MNISTCOCO
    • Captions
    • Detection
    • LSUN
    • ImageFolder
    • Imagenet-12
    • CIFAR
    • STL10
    • SVHN
    • PhotoTour
  • 我们可以直接使用,示例如下:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import torchvision

    trainset = torchvison.datasets.MNIST(
    root = './data', #表示MNIST数据的加载的相对目录
    train = True, #表示是否加载数据库的训练集,false的时候加载测试集
    download = True#表示是否自动下载MNIST数据集
    transform = None #表示是否需要对数据进行预处理,None为不进行预处理
    )
    # 上面代码完成了MNIST数据 训练集的加载环节
    train_loader2 = Dateloader(
    dataset = trainset,
    batch_size = 32,
    shuffle = True
    )
    print("训练集总长度为:",len(trainset))
    print("每个mini-batch的size为32,一共有:",len(train_loader2),"个")

torchvision.models

  • torchvision.models中为我们提供了已经训练好的模型,让我们可以加载之后,直接使用

  • torchvision.models模块的子模块中包含以下模型结构。

    • AlexNet
    • VGG
    • ResNet
    • SqueezeNet
    • DenseNet
  • 我们可以直接使用如下代码来快速创建一个权重随机初始化的模型

    1
    2
    3
    4
    5
    6
    import torchvision.models as models

    resnet18 = models.resnet18()
    alexnet = models.alexnet()
    squeezenet = models.squeezenet1_0()
    densenet = models.densenet_161()
  • 也可以通过使用pretrained=True来加载一个别人预训练好的模型

    1
    2
    3
    4
    import torchvision.models as models

    resnet18 = models.resnet18(pretrained=True)
    alexnet = models.alexnet(pretrained=True)

torchvision.transforms

  • transforms提供了一般的图像转换操作类,这就是我在一开始Dataset中提到了transform,还记得么?哈哈,可以翻一翻上面的例程中在创建Mydataset类的getitem方法中是如何使用transforms的

  • 其实我猜测例程中,作者想在获取每一个图像信息时,除了进行opencv的操作外,训练时还要对图像数据信息做更多处理,而测试时当然就不需要这种处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 我们这里还是对MNIST进行处理,初始的MNIST是 28 * 28,我们把它处理成 96 * 96 的torch.Tensor的格式
from torchvision import transforms as transforms
import torchvision
from torch.utils.data import DataLoader

# 图像预处理步骤
transform = transforms.Compose([
transforms.Resize(96), # 缩放到 96 * 96 大小
transforms.ToTensor(),
transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)) # 归一化
])

DOWNLOAD = True
BATCH_SIZE = 32

train_dataset = torchvision.datasets.MNIST(root='./data/', train=True, transform=transform, download=DOWNLOAD)
train_loader = DataLoader(dataset=train_dataset,
batch_size=BATCH_SIZE,
shuffle=True)

print(len(train_dataset))
print(len(train_loader))
  • 例程中是将从torchvision.datasets中获取的图像数据做transform,这样更简单,那如何在自己定义的Dataset类中加入Transform呢?
    • 第一步:定义自己的DataSet,并重写__getitem__,在里面实现关键的transform操作
    • 第二步:将多个数据增强方式组合起来合成一个transforms,通过Compose类来实现,注意这个类的返回值哦!
    • 第三步:构造DataSet的对象,将组合起来的transform传递进去,这样就会对每一个batch_size的图像都进行相关的数据增强操作了
  • 细节问题在于,我没太搞懂这种的数据类型的转换,一会是图片类型,一会是numpy矩阵类型,最后又要转换成tensor张量类型,这个要之后细究

3.1 什么是Resnet

👴也不知道,👴正在学

pytorch使用说明

torch.normal(means, std, out=None)

  • 返回满足正态分布的张量
  • meansstd分别给出均值和标准差

torch.rand(*sizes, out=None) → Tensor

  • 均匀分布:返回一个张量,包含了从区间[0, 1)的均匀分布中抽取的一组随机数。张量的形状由参数sizes定义

torch.randn(*sizes, out=None) → Tensor

  • 标准正态分布:返回一个张量,包含了从标准正态分布(均值为0,方差为1,即高斯白噪声)中抽取的一组随机数。张量的形状由参数sizes定义

torch.squeeze(a,N)

  • 对数据的维度进行压缩,去掉指定个维数为1的维度,注意:如果不加第二个参数’N’,就是去掉所有维数为1的维度
  • 另一种形式,a.squeeze(N) 也是去掉a中指定的维数为一的维度,去掉的维度数为N

torch.unsqueeze()

  • 对数据维度进行扩充。给指定位置加上维数为1的维度,同样有另外一种形式a.squeeze(N)
  • 注意!当对神经网络的输入层的特征数据提前处理时,可能需要使用该函数,因为输入数据必须是一个至少二维的张量

可以关注一下python自带的numpy数字计算库和torch的数据处理,其实相似度很高


torch.cat((A,B),0)

  • 将两个张量(tensor)拼接在一起,第一个参数是两个张量组成的元组,第二个参数是行拼接(1)或者列拼接(0)
  • 实例

np.hstack((A,B,C..)) & np.vstack((A,B,C..))

  • 将参数元组的元素数组按水平/垂直方向进行叠加,可以和上面的torch.cat比较一下

torch.stack([tensor1, tensor2, tensor3…], dim=0)

  • 将几个矩阵按照dim指定维度堆叠在一起
  • 实例

np.random.shuffle(x)

  • 现场修改序列,改变自身内容。(类似洗牌,打乱顺序)
  • 对多维数组进行打乱排列时,默认是对第一个维度也就是列维度进行随机打乱

np.transpose(x)

  • 常用于二维数组的转置

torch.div(input, value, out=None)

  • 将input逐元素除以标量值value,并返回结果到输出张量out。

plt.scatter(x,y,c='r',s=20,marker=".",lw=2)

  • matplotlib库中画散点图的函数,注意c这个参数的特别用法
  • 详解

Ielts小班课学习-4

雅思口语词汇

单词 释义 单词 释义
burmese 缅甸人 burma 缅甸
portuguese 葡萄牙人 portugal 葡萄牙
iraqi 伊拉克人 kuwaiti 科威特人
cab 出租车 distractor 干扰项
northern 注意拼写 southern 注意拼写
hostel 小旅馆 prompts 提示
introverted 内向的 arduous 非常困难的

part two


describe change
口语表达积累
I’d like to talk about ….  开头
to be honest, this question really got me at the beginning (because ….)
to tell the truth ,a (little) bit
the idea come to my mind
why not …. which ….
specialised for people who …
you know/see
so in this case/in that way , ..
be able to  直接替换can,不要用can了
it would be a relief for people
have cool feet when  害怕

雅思小作文

  • 在小作文地比较中,表示倍数可以使用timesfold(like eightfold),表示百分比有percentageproportion,表示“占比”的动词有account formake uprepresent

  • 那么占比的三种表达方式,不要细究句意与难度,记住形式

1
2
3
1. the percent of excellent evaluation climb to 28%
2. The excellent part accounts for 28 percent of the questionnaire
3. 28% customer service evaluation is excellent
单词 释义 单词 释义
subsequently 随后(放句首) once-in-a-lifetime 一生一次的
Conversely 相反地

雅思阅读

雅思阅读十种题型

作业

整理生词、错题
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×