Pytorch笔记

Pytorch采用动态计算图引擎,区别于Tensorflow不采用eager模式的静态计算图,无需等到计算图的所有节点(所有操作)构建完成才能进行实际操作。

Pytorch API List

Package Description
torch The top-level PyTorch package and tensor library.
torch.nn A subpackage that contains modules and extensible classes for building neural networks.
torch.autograd A subpackage that supports all the differentiable Tensor operations in PyTorch.
torch.nn.functional A functional interface that contains typical operations used for building neural networks like loss functions, activation functions, and convolution operations.
torch.optim A subpackage that contains standard optimization operations like SGD and Adam.
torch.utils A subpackage that contains utility classes like data sets and data loaders that make data preprocessing easier.
torchvision A package that provides access to popular datasets, model architectures, and image transformations for computer vision.

Tensor, DataSet & DataLoader

Tensor类似于numpy,网络训练时使用的tensor shape通常为[Batch, Channels, Height, Width]。Tensor的常见变换以及数据预处理的ETL(Extract, Transform, Load)三步见下面的代码示例:

import numpy as np
import matplotlib.pyplot as plt
import torchvision
import torchvision.transforms as transforms

class Getdata(Dateset):
    def __init__(self, csv_file):
        self.data = pd.read_csv(csv_file)

    def __getitem__(self, index):
        r = self.data.iloc[index]
        label = torch.tensor(r.is_up_day, dtype=torch.long)
        sample = self.normalize(torch.tensor(r.open, r.high, r.low, r.close))
        return sample, label

    def __len__(self):
        return len(self.data)

train_set = torchvision.datasets.FashionMNIST(
    root='./data/FashionMNIST',
    train=True,
    download=True,
    transforms=transforms.Compose([
        transforms.ToTensor()
        ])
    )

# 数据探索
len(train_set)
train_set.train_labels
train_set.train_labels.bincount() #样本均衡性,如果不均衡best method for oversampling is copy

# 访问数据集中单个元素
sample = next(iter(train_set))
len(sample)
# len: 2
type(sample)
# type: tuple
# sample为sequence类型, 获取元组中每个元素 sequence unpacking
image, label = sample
# 维度挤压 例如灰度图,去掉维度为1的维
image.squeeze()

t1 = torch.tensor([
    [1,1,1,1],
    [1,1,1,1],
    [1,1,1,1],
    [1,1,1,1]
])

t2 = torch.tensor([
    [2,2,2,2],
    [2,2,2,2],
    [2,2,2,2],
    [2,2,2,2]
])

t3 = torch.tensor([
    [3,3,3,3],
    [3,3,3,3],
    [3,3,3,3],
    [3,3,3,3]
])
t = torch.stack((t1, t2, t2)) #squeeze的反向操作
t = t.reshape([3,1,4,4]) #构造适合网络训练的数据
t.flatten(start_dim=1).shape
#tensor.Size([3,16])
t.cuda()
# .cuda函数将Tensor转移到GPU
plt.imshow(image.squeeze(), cmap='gray') # color map

# 数据加载
train_loader = torch.utils.data.DataLoader(train_set,
    batch_size=1000,
    shuffle=True
    )
# 获取单个batch的数据
batch = next(iter(train_loader))
len(batch)
# 2
type(batch)
# list
images, labels = batch
image.shape
# torch.Size([10,1,28,28]) 对应(Batch Size, Channels, Height, Width)

# 输出结果
grid = torchvision.utils.make_grid(images, nrow=10)
plt.figure(figsize=(15,15))
plt.imshow(np.transpose(grid, (1,2,0)))
# 按行排列输出十张灰度图
print('labels:', labels)
# labels: tensor([9, 0, 0, 3, 0, 2, 7, 2, 5, 5])

Model/Network

torch.nn.Module是pytorch中所有包含layer的network module的基类,继承torch.nn.Module可以实现自定义的网络模型。在构造函数中可以使用torch.nn预定义的layer组合网络模型的各层,在基类forward方法的实现中,可以使用layer的属性或nn.functional API提供的操作定义各层的forward pass,forward接收一个tensor返回一个tensor从而实现data transformation。

forward函数需要自定义,而backward函数是autograd自动定义的。autograd.Variable 包装一个Tensor并且记录应用在其上的历史运算操作,即每一个变量都有一个.creator属性,它引用一个常见Variable的Function。在Variable上调用backward()可以自动地计算全部的梯度。通过.data属性来访问最原始的tensor,而梯度则相应地被累计到了.grad中。


import torch
from torch.autograd import Variable
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim

class Network(nn.Module):
    def __init__(self):
        super(Network, self).__init__()
        self.conv1 = nn.Conv2d(in_channels=1, out_channels=6, kernel_size=5)
        # the first in_channels and the last out_features are data depend parameters
        # the out_channels are filter amount
        self.conv2 = nn.Conv2d(in_channels=6, out_channels=12, kernel_size=5)
        
        self.fc1 = nn.Linear(in_features=12*4*4, out_features=120)
        # outputSizeOfConv = [(inputSize + 2*pad - filterSize)/stride] + 1
        # The output of conv1 should be ((28-5) + 1) / 2 = 12x12 image
        # The output of conv2 should be ((12-5) + 1) / 2 = 4x4 image
        self.fc2 = nn.Linear(in_features=120, out_features=60)
        self.out = nn.Linear(in_features=60, out_features=10)
        #Linear = Dense

    def forward(self, t):
        #pooling operation
        t = F.max_pool2d(F.relu(self.conv1(t)), (2,2))
        t = F.max_pool2d(F.relu(self.conv2(t)), (2,2))
        t = t.view(-1, t.flatten(start_dim=1))
        t = F.relu(self.fc1(t))
        t = F.relu(self.fc2(t))
        t = self.out(t)
        return t

net = Network()
net.cuda()

# nn.Parameter也是一种Variable,当给Module赋值时自动注册的一个参数
params = list(net.parameters())
params[0].shape
# torch.Size([6,1,5,5]) conv1's weight

input =  Variable(torch.randn(1, 1, 28, 28))
output = net(input)
# 计算损失
target = Variable(torch.arange(1,11)) # a dummy target
criterion = nn.CrossEntropyLoss()
loss = criterion(output, target)

# 反向传播 更新网络权重
# 梯度缓冲区设为0,否则梯度将累积到现有梯度
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)
optimizer.zero_grad()
loss.backward()
optimizer.step()

训练网络

综合上述内容,我们对网络进行多次迭代训练

# 修改上述代码将根据网络输出计算损失,反向传播更新梯度的代码放到训练网络的循环中

#首先定义好损失函数和梯度下降优化方法
criterion = nn.CrossEntropyLoss()
optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)

for epoch in range(10): # loop over the dataset multiple times
    running_loss = 0.0
    for i, data in enumerate(trainloader, 0):
        # get the input
        inputs, labels = data

        # wrap in Variable
        inputs, labels = Variable(inputs.cuda()), Variable(labels.cuda())

        # zero the parameter gradients
        optimizer.zero_grad()

        # forward + backward + optimize
        outputs = net(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()

        # print statistics
        running_loss += loss.data[0]
        if i % 2000 == 1999:   # print every 2000 mini-batches
            print('[%d, %5d] loss: %.3f' %
                  (epoch + 1, i + 1, running_loss / 2000))
            running_loss = 0.0

分析训练结果

correct = 0
total = 0
for data in testloader:
    images, labels = data
    outputs = net(Variable(images))
    _, predicted = torch.max(outputs.data, 1)
    # torch.max(..., 1) 返回每行的最大值
    # torch.max(..., 0) 返回每列的最大值
    # _为返回的最大值的值,predicted为最大值对应的索引即预测的label
    total += labels.size(0)
    correct += (predicted == labels).sum()

print('Accuracy of the network on the 10000 test images: %d %%' % (100 * correct / total))

常见问题记录:

  • load 和 load_state_dict 区别
    load加载torch.save(model, PATH)保存的整个模型,而load_state_dict加载保存的参数
torch.save(model.state_dict(), PATH)
model = TheModelClass(*args, **kwargs)
model.load_state_dict(torch.load(PATH))
model.eval()
  • model.eval() 设置dropout and batch normalization layers为evaluation mode

  • view和unsqueeze的区别
    view按参数更改数据维度
    unsqueeze returns a new tensor with a dimension of size one inserted at the specified position.

>>> x = torch.tensor([1, 2, 3, 4])
>>> torch.unsqueeze(x, 0)
tensor([[ 1,  2,  3,  4]])
>>> torch.unsqueeze(x, 1)
tensor([[ 1],
        [ 2],
        [ 3],
        [ 4]])

参考资料:
Pytorch官方文档
Deeplizard Python教程

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容