PyTorch深度学习

Posted 古路

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了PyTorch深度学习相关的知识,希望对你有一定的参考价值。

PyTorch深度学习

0.引言

1.pyhton 开发环境安装

2.创建python虚拟环境以及pip国内源设置

目前 python3.8 是一个兼容性比较好的版本:

conda create -n py38 python=3.8

新建的 conda 环境在电脑中的位置为: /home/q/anaconda3/envs/py38
相关的命令行:

#显示所有的虚拟环境
conda env list 或 conda info --envs

#创建python3.5的xxxx虚拟环境
conda create -n [your_env_name] python=3.5
#复制虚拟环境(必须在base环境下进行以上操作)
conda create -n [new_env_name] --clone [env_name]
#删除虚拟环境(必须在base环境下进行以上操作)
conda remove -n [your_env_name] --all
#重命名虚拟环境
#直接修改环境所在路径的文件夹名即可

#切换虚拟环境
conda activate xxxx
#关闭当前虚拟环境
conda deactivate

全局修改,需要修改配置文件。
Linux/Mac os 环境中,配置文件位置在 ~/.pip/pip.conf(如果不存在创建该目录和文件):

mkdir ~/.pip

打开配置文件 ~/.pip/pip.conf,修改如下:

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = https://pypi.tuna.tsinghua.edu.cn

查看 镜像地址:

$ pip3 config list   
global.index-url='https://pypi.tuna.tsinghua.edu.cn/simple'
install.trusted-host='https://pypi.tuna.tsinghua.edu.cn'

可以看到已经成功修改了镜像。Windows下,你需要在当前对用户目录下(C:\\Users\\xx\\pip,xx 表示当前使用对用户,比如张三)创建一个 pip.ini在pip.ini文件中输入以下内容:

[global]
index-url = https://pypi.tuna.tsinghua.edu.cn/simple
[install]
trusted-host = pypi.tuna.tsinghua.edu.cn

3.PyCharm基本用法及设置解释器

第一次打开的时候需要创建一个工程,工程的名字和位置自己定义,把 Create a main.py 取消勾选。选择解释器的时候可以选择anaconda3的解释器:

在setting->Editor->font 将字体改大一点:18号。

也可以选择我们创建的虚拟环境解释器:

PyCharm右下角可以快速切换解释器:

4.第一个深度学习实例手写字符识别

  • 代码地址:https://github.com/mivlab/AI_course
  • 打开PyCharm新建工程位置为代码根目录
  • 解释器选择虚拟环境解释器
  • 点击从已有源代码进行创建

下一弹窗单击左边三个按钮任意一个都行。

  • 1.安装pytorch: https://pytorch.org/get-started/locally/

安装时一定要在你使用的虚拟环境中进行安装: conda install pytorch torchvision torchaudio cpuonly -c pytorch

在这里插入图片描述

  • 2.继续在虚拟环境中安装 opencv: pip install opencv-python
  • 3.下载数据集:
    1)下载数据集:链接:https://pan.baidu.com/s/18Fz9Cpj0Lf9BC7As8frZrw 提取码:xhgk
    2)训练:train_mnist.py
    需要加一个参数,–datapath=数据集所在的目录。
    train_mnist.py --datapath=/home/q/dataset/mnist
    3)测试:tes_mnist.py 可以识别一张新的图片的类别。

MNIST数据库一共有四个文件:
‒ 1. train-images-idx3-ubyte.gz:训练集图片(9912422字节),55000张训练集,5000张验证集
‒ 2. train-labels-idx1-ubyte.gz:训练集图片对应的标签(28881字节),
‒ 3. t10k-images-idx3-ubyte .gz:测试集图片(1648877字节),10000张图片
‒ 4. t10k-labels-idx1-ubyte.gz:测试集图片对应的标签(4542字节)

将参数填进去:--datapath=/home/q/dataset/mnist/train_images

  • 4.安装torchsummary:pip install torchsummary

  • 5.开始训练:

  • 6.测试: 运行 test_mnist.py 文件

5.第一个深度学习实例–手写字符识别代码解析

Module 代码:

import torch.nn as nn
import torch
#    # 在pytorch中,自己定义的网络必须继承自 nn.Module
class Net(nn.Module):
    def __init__(self, c):
        super(Net, self).__init__()
        self.conv1 = nn.Sequential(
            nn.Conv2d(3, 32, 3, 1, 1),  # 32x28x28
            nn.ReLU(),
            nn.MaxPool2d(2)
        )  # 32x14x14
        self.conv2 = nn.Sequential(
            nn.Conv2d(32, 64, 3, 1, 1),  # 64x14x14
            nn.ReLU(),
            nn.MaxPool2d(2)  # 64x7x7
        )
        self.conv3 = nn.Sequential(
            nn.Conv2d(64, 64, 3, 1, 1),  # 64x7x7
            nn.ReLU(),
            nn.MaxPool2d(2)  # 64x3x3
        )
        self.dense = nn.Sequential(
            nn.Linear(64 * 3 * 3, 128),  # fc4 64*3*3 -> 128
            nn.ReLU(),
            nn.Linear(128, c)  # fc5 128->10
        )
    def forward(self, x):
        conv1_out = self.conv1(x)
        conv2_out = self.conv2(conv1_out)
        conv3_out = self.conv3(conv2_out)  # 64x3x3
        res = conv3_out.view(conv3_out.size(0), -1)  # batch x (64*3*3)
        #res = torch.reshape(conv3_out, (conv3_out.size(0), 64*3*3))
        out = self.dense(res) #dense 表示做全连接
        return out

训练代码:

import torch
import math
import torch.nn as nn
from torch.autograd import Variable
from torchvision import transforms, models
import argparse
import os
from torch.utils.data import DataLoader

from dataloader import mnist_loader as ml
from models.cnn import Net
from toonnx import to_onnx


parser = argparse.ArgumentParser(description='PyTorch MNIST Example')
parser.add_argument('--datapath', required=True, help='data path')
parser.add_argument('--batch_size', type=int, default=256, help='training batch size')
parser.add_argument('--epochs', type=int, default=300, help='number of epochs to train')
parser.add_argument('--use_cuda', default=False, help='using CUDA for training')

args = parser.parse_args()
args.cuda = args.use_cuda and torch.cuda.is_available()
if args.cuda:
    torch.backends.cudnn.benchmark = True


def train():
    os.makedirs('./output', exist_ok=True)
    if True: #not os.path.exists('output/total.txt'):
        ml.image_list(args.datapath, 'output/total.txt')  #将图像列表的文件分成训练集和验证集两部分  输出的文件在output文件夹下面
        ml.shuffle_split('output/total.txt', 'output/train.txt', 'output/val.txt') # 80% 作为训练集  20作为验证集

    train_data = ml.MyDataset(txt='output/train.txt', transform=transforms.ToTensor()) # 像素值0~255归一化到0~1之间
    val_data = ml.MyDataset(txt='output/val.txt', transform=transforms.ToTensor())
    train_loader = DataLoader(dataset=train_data, batch_size=args.batch_size, shuffle=True) #将训练集进行分批次加载训练,一次加载batch_size大小的数据
    val_loader = DataLoader(dataset=val_data, batch_size=args.batch_size)

    model = Net(10)
    #model = models.vgg16(num_classes=10)
    #model = models.resnet18(num_classes=10)  # 调用内置模型
    #model.load_state_dict(torch.load('./output/params_10.pth'))
    from torchsummary import summary
    summary(model, (3, 28, 28))

    if args.cuda:
        print('training with cuda')
        model.cuda()
    optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=1e-3) #优化器采用 Adam,初始学习率为0.01,权重衰减系数为 1*10^-4
    scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, [20, 30], 0.1) #按照阶梯调整学习速率的方式:达到第20个 epoch的时候,学习率*0.1,达到第30个 epoch的时候,学习率再*0.1,
    loss_func = nn.CrossEntropyLoss()#定义损失函数:交叉熵损失函数

    for epoch in range(args.epochs): #开始训练
        # training-----------------------------------
        model.train() #进入训练模式
        train_loss = 0
        train_acc = 0
        for batch, (batch_x, batch_y) in enumerate(train_loader):#第二层循环对每一个批次做训练,使用训练加载器train_loader加载batch
            if args.cuda:
                batch_x, batch_y = Variable(batch_x.cuda()), Variable(batch_y.cuda())
            else:
                batch_x, batch_y = Variable(batch_x), Variable(batch_y)
            # 256x3x28x28  256:一个批次有256张图,3:rgb 3通道,28*28:图像的宽高。
            # out 256x10 ,256:一个批次有256个样本,10:表示每张图要输出10个值,
            # 这10个值就代表了这个样本属于这10个类别的概率值(和为1),注意:要经过softmax才会变成概率值,这一步是在CrossEntropyLoss里面做的。
            out = model(batch_x)
            loss = loss_func(out, batch_y) #计算损失函数
            train_loss += loss.item()
            pred = torch.max(out, 1)[1] #取最大的那一类的标签
            train_correct = (pred == batch_y).sum() #统计正确的个数
            train_acc += train_correct.item()
            print('epoch: %2d/%d batch %3d/%d  Train Loss: %.3f, Acc: %.3f'
                  % (epoch + 1, args.epochs, batch, math.ceil(len(train_data) / args.batch_size),
                     loss.item(), train_correct.item() / len(batch_x)))

            optimizer.zero_grad()
            loss.backward() #误差反向传播?
            optimizer.step()
        scheduler.step()  # 更新learning rate
        print('Train Loss: %.6f, Acc: %.3f' % (train_loss / (math.ceil(len(train_data)/args.batch_size)),
                                               train_acc / (len(train_data))))
        # 在完成一个epoch后对模型进行一次评估
        # evaluation--------------------------------
        model.eval()
        eval_loss = 0
        eval_acc = 0
        for batch_x, batch_y in val_loader:
            if args.cuda:
                batch_x, batch_y = Variable(batch_x.cuda()), Variable(batch_y.cuda())
            else:
                batch_x, batch_y = Variable(batch_x), Variable(batch_y)

            out = model(batch_x)
            loss = loss_func(out, batch_y)
            eval_loss += loss.item()
            pred = torch.max(out, 1)[1]
            num_correct = (pred == batch_y).sum()
            eval_acc += num_correct.item()
        print('Val Loss: %.6f, Acc: %.3f' % (eval_loss / (math.ceil(len(val_data)/args.batch_size)),
                                             eval_acc / (len(val_data))))
        # 保存模型。每隔多少帧存模型,此处可修改------------
        if (epoch + 1) % 1 == 0:
            # torch.save(model, 'output/model_' + str(epoch+1) + '.pth')
            torch.save(model.state_dict(), 'output/params_' + str(epoch + 1) + '.pth')
            #to_onnx(model, 3, 28, 28, 'params.onnx')

if __name__ == '__main__':
    train()

保存模型:

        # 保存模型。每隔多少帧存模型,此处可修改------------
        if (epoch + 1) % 1 == 0:
            # torch.save(model, 'output/model_' + str(epoch+1) + '.pth')
            torch.save(model.state_dict(), 'output/params_' + str(epoch + 1) + '.pth')
            #to_onnx(model, 3, 28, 28, 'params.onnx')

使用模型:

import torch
import cv2
from torch.autograd import Variable
from torchvision import transforms
from models.cnn import Net
from toonnx import to_onnx

use_cuda = False
model = Net(10)
# 注意:此处应把pth文件改为你训练出来的params_x.pth,x为epoch编号,
# 一般来讲,编号越大,且训练集(train)和验证集(val)上准确率差别越小的(避免过拟合),效果越好。
model.load_state_dict(torch.load('output/params_yl.pth'))
# model = torch.load('output/model.pth')
model.eval()
if use_cuda and torch.cuda.is_available():
    model.cuda()

to_onnx(model, 3, 28, 28, 'output/params.onnx')

img = cv2.imread('4_00440.jpg')
img = cv2.resize(img, (28, 28))
img_tensor = transforms.ToTensor()(img)
img_tensor = img_tensor.unsqueeze(0)
if use_cuda and torch.cuda.is_available():
    prediction = model(Variable(img_tensor.cuda()))
else:
    prediction = model(Variable(img_tensor))
pred = torch.max(prediction, 1)[1]
print(prediction)
print(pred)
cv2.imshow("image", img)
cv2.waitKey(0)

6.性别识别-最简单的神经网络-逻辑回归

根据一个人的身高体重,预测其性别:

import torch
import math
import torch.nn as nn
from torch.autograd import Variable
from torchvision import transforms, models
import argparse
import os
from torch.utils.data import DataLoader
from torch.utils.data import Dataset

class SexDataset(Dataset):
    def __init__(self, txt, transform=None, target_transform=None):
        fh = open(txt, 'r')
        data = []
        for line in fh:
            line = line.strip('\\n')
            words = line.split()
            data.append((float(words[0]) / 2.0, float(words[1]) / 80.0, int(words[2])))
        self.data = data

    def __getitem__(self, index):
        return torch.FloatTensor([self.data[index][0], self.data[index][1]]), self.data[index][2]

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

class SexNet(nn.Module):
    def __init__(self):
        super(SexNet, self).__init__()
        self.dense = nn.Sequential(
            nn.Linear(2, 2)
        )

    def forward(self, x):
        out = self.dense(x)
        return out

def train():
    os.makedirs('./output', exist_ok=True)
    train_data = SexDataset(txt='sex_train.txt')
    val_data = SexDataset(txt='sex_val.txt')
    batchsize = 10
    train_loader = DataLoader(dataset=train_data, batch_size=batchsize, shuffle=True)
    val_loader = DataLoader(dataset=val_data, batch_size=batchsize)

    model = SexNet()

    optimizer = torch.optim.Adam(model.parameters(), lr=0.01, weight_decay=1e-3)
    scheduler = torch.optim.lr_scheduler.MultiStepLR(optimizer, [100, 200], 0.1)
    loss_func = nn.CrossEntropyLoss()

    epochs = 100
    for epoch in range(epochs):
        # training-----------------------------------
        model.train()
        train_loss = 0
        train_acc = 0
        for batch, (batch_x, batch_y) in enumerate(train_loader):
            batch_x, batch_y = Variable(batch_x), Variable(batch_y)
     

以上是关于PyTorch深度学习的主要内容,如果未能解决你的问题,请参考以下文章

PyTorch深度学习框架笔记1

对比学习:《深度学习之Pytorch》《PyTorch深度学习实战》+代码

为什么用PyTorch?PyTorch如何支持深度学习?

[十九]深度学习Pytorch-可视化工具TensorBoard

深度学习pytorch训练代码模板(个人习惯)

PyTorch深度学习:60分钟入门(Translation)