anaconda创建虚拟环境

在Anaconda中conda可以理解为一个工具,也是一个可执行命令,其核心功能是包管理与环境管理。所以对虚拟环境进行创建、删除等操作需要使用conda命令。

创建虚拟环境

conda create -n hanjunan python=3.6

我这里创建的虚拟环境名字叫做hanjunan,Python的版本是3.6

激活虚拟环境

2.1 pytorch官方demo(Lenet)_卷积网络

删除虚拟环境

使用命令conda remove -n your_env_name(虚拟环境名称) --all, 即可删除。

conda常用命令

  1. conda list:查看安装了哪些包。
  2. conda install package_name(包名):安装包
  3. conda env list 或 conda info -e:查看当前存在哪些虚拟环境
  4. conda update conda:检查更新当前conda


使用命令conda list

2.1 pytorch官方demo(Lenet)_卷积网络_02

使用命令conda env list

2.1 pytorch官方demo(Lenet)_Lenet_03

pytorch安装

网址:​​https://pytorch.org/get-started/locally/​

安装命令:

conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch

2.1 pytorch官方demo(Lenet)_Lenet_04


安装过程,cmd查看激活hanjunan虚拟环境,输入命令:

conda install pytorch torchvision torchaudio cudatoolkit=10.2 -c pytorch

2.1 pytorch官方demo(Lenet)_卷积网络_05


再安装一些必要的packages

pip install numpy 

pip install matplotlib

pip install pandas

pip install tensorboard



​Python官网

​https://pytorch.org/​

pytorch官方demo(Lenet)

2.1 pytorch官方demo(Lenet)_卷积网络_06


一定要注意的是:Pytorch Tensor的通道排列顺序为:[batch,channel,height,width]即BCHW格式。


搭建网络结构model.py文件

2.1 pytorch官方demo(Lenet)_Lenet_07

在pytorch框架中搭建网络,必须主要上面三点:

  1. 首先定义一个类,继承nn.Module类
  2. 重写__init__方法,定义搭建网络过程中需要使用的网络结构,且第一句是super()方法,固定写法
  3. 重写forward方法,定义前向传播过程


补全上面的网络结构,使用的是cifar10数据集,彩色图像32*32大小:

import torch
import torch.nn as nn
import torch.nn.functional as F

class LeNet(nn.Module):
def __init__(self):
super(LeNet, self).__init__()
self.conv1 = nn.Conv2d(in_channels=3,out_channels=16,kernel_size=5)
self.pool1 = nn.MaxPool2d(kernel_size=(2,2))
self.conv2 = nn.Conv2d(in_channels=16,out_channels=32,kernel_size=5)
self.pool2 = nn.MaxPool2d(kernel_size=(2,2))
self.fc1 = nn.Linear(in_features=32*5*5,out_features=120)
self.fc2 = nn.Linear(in_features=120,out_features=84)
self.fc3 = nn.Linear(in_features=84,out_features=10)

def forward(self,x):
x = F.relu(self.conv1(x)) # input(3,32,32) output(16,28,28)
x = self.pool1(x) # output(16,14,14)
x = F.relu(self.conv2(x)) # output(32,10,10)
x = self.pool2(x) # output(32,5,5)
x = x.view(-1,32*5*5)
x = F.relu(self.fc1(x)) # output(120)
x = F.relu(self.fc2(x)) # output(84)
x = self.fc3(x)
# 注意这里最后没有使用softmax激活
return x

if __name__ == '__main__':
input1 = torch.rand([32,3,32,32])
model = LeNet()
output1 = model(input1)
print("output1.shape = ",output1.shape)


    1. 注意,这里最后一层没有使用Softmax,一般来说我们对于多分类问题,都在最后一层加上Softmax,将预测输出转为概率分布,但是在实际中,计算交叉熵的过程中,已经实现了更加高效的Softmax。
    2. 注意,每个卷积操作之后,会接F.relu()激活,相当于做一次非线性变换,增强模型的拟合能力,一定记得卷积nn.Conv2d之后,要加上F.relu()。
    3. 注意,在使用全连接之前,必须将数据进行展平操作,即使用x.view()函数。



    训练脚本train.py文件

    import torch
    import torch.nn as nn
    import torchvision
    import torchvision.transforms as transforms
    from model import Lenet
    from torch.utils.data import DataLoader
    import matplotlib.pyplot as plt
    import numpy as np


    def imshow(img):
    img = img / 2 + 0.5 # unnormalize
    npimg = img.numpy()
    plt.imshow(np.transpose(npimg, (1, 2, 0)))
    plt.show()

    def main():

    # 对图像做变换
    transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=(0.5,0.5,0.5),std=(0.5,0.5,0.5))
    ])
    # 50000张训练图片
    # 第一次使用时要将download设置为True才会自动去下载数据集
    train_set = torchvision.datasets.CIFAR10(root="./data",train=True,transform=transform,download=True)
    # 定义训练集的dataloader
    train_loader = DataLoader(dataset=train_set,batch_size=36,shuffle=True,num_workers=0)

    # 10000张验证图片
    # 第一次使用时要将download设置为True才会自动去下载数据集
    val_set = torchvision.datasets.CIFAR10(root="./data",train=False,transform=transform,download=True)
    val_loader = DataLoader(dataset=val_set,batch_size=5000,shuffle=True,num_workers=0)

    # 查看验证集张啥样子
    val_data_iter = iter(val_loader)
    val_image,val_label = val_data_iter.next()

    img0,lb0 = val_image[0],val_label[0]
    print("img0.shape = ",img0.shape)
    print("lb0 = ",lb0)

    # classes = ('plane', 'car', 'bird', 'cat',
    # 'deer', 'dog', 'frog', 'horse', 'ship', 'truck')
    # # show images
    # imshow(torchvision.utils.make_grid(val_image))
    # # print labels
    # print(' '.join('%5s' % classes[val_label[j]] for j in range(4)))

    # 定义网络
    net = Lenet()

    # 定义多分类的交叉熵损失函数
    # Note that this case is equivalent to the combination of:
    # class: `~torch.nn.LogSoftmax` and: class: `~torch.nn.NLLLoss`.
    # 意思是交叉熵损失函数包括了LogSoftmax,所以不需要在网络最后一层再Softmax了
    loss_function = nn.CrossEntropyLoss()

    # 定义优化器
    optimizer = torch.optim.Adam(params=net.parameters(),lr=0.001)

    # 循环训练5轮
    for epoch in range(5):
    # 一个批次的损失
    running_loss = 0.0
    for step,data in enumerate(train_loader,start=0):
    inputs,labels = data

    # 梯度清零
    optimizer.zero_grad()
    # 前向传播,得到预测结果
    outputs = net(inputs)
    # 使用交叉熵函数计算损失,该损失为一个batch的损失
    loss = loss_function(outputs,labels)
    # 误差反向传播
    loss.backward()
    # 优化器更新参数
    optimizer.step()

    # 打印信息
    running_loss += loss.item()
    # 每500个batch打印一次
    if step % 500 == 499:
    # 测试时不计算梯度,减少资源消耗
    with torch.no_grad():
    outputs = net(val_image) # [batch, 10]
    predict_y = torch.max(outputs,dim=1)[1]
    accuracy = torch.eq(predict_y,val_label).sum().item() / val_label.size(0)

    print("[%d,%5d] train_loss:%.3f test_accuracy:%.3f" %
    (epoch+1,step+1,running_loss/500,accuracy))


    print("Finished Training")

    # 保存模型
    save_path = "./Lenet.pth"
    # obj:要保存的对象,f:要保存的路径
    torch.save(obj=net.state_dict(),f=save_path)

    if __name__ == '__main__':
    main()


    训练结果:

    2.1 pytorch官方demo(Lenet)_Lenet_08


    注意事项:

    ToTensor函数的作用:

    Converts a PIL Image or numpy.ndarray (H x W x C) in the range
    [0, 255] to a torch.FloatTensor of shape (C x H x W)
    in the range [0.0, 1.0]

    将PIL或者ndarray类型转为Tensor类型,并且取值从[0,255]转为[0,1]


    DataLoader函数中的参数num_workers在window下必须设置为0,不然一般会出现以下错误:

    2.1 pytorch官方demo(Lenet)_Lenet_09



    交叉熵损失nn.CrossEntropyLoss():label可以是one-hot编码,也可以不是。

    并且

    # Note that this case is equivalent to the combination of:
    # class: `~torch.nn.LogSoftmax` and: class: `~torch.nn.NLLLoss`.
    # 意思是交叉熵损失函数包括了LogSoftmax,所以不需要在网络最后一层再Softmax了

    如果使用交叉熵做损失函数,网络最后一层不需要用softmax输出,因为最终网络输出的outputs结果,在使用CrossEntropyLoss()和labels计算损失时,会先进行softmax的。