pytorch深度学习的大致框架

本人是人工智能的一枚大一学生,最近感慨自己专业就业的形势严峻,遂开始学习pytorch

今天是学习深度学习的第n天

这是一些个人理解,请各位大佬们指点

pytorch深度学习步骤:

1.导入各种包

import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms

这是其中的一些包,仅作为一个举例

2.准备数据集

从网上下载数据集,并分成训练集和测试集

train_dataset = datasets.FashionMNIST(
    root='../datasets', train=True, transform=transforms.ToTensor(), download=True)

test_dataset = datasets.FashionMNIST(
    root='../datasets', train=False, transform=transforms.ToTensor())
# 将数据处理成 DataLoader
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 选择打乱数据
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 选择不打乱数据

def __getitem__(self,index):
    img_path,label=self.data[index].img_path,self.data[index].label
    img=Image.open(img_path)
    return img,label

3.设计模型

设计模型又分为

定义模型

class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        self.conv1 = Conv2d(in_channels=1, out_channels=10, kernel_size=5, stride=1, padding=0)#卷积层
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(in_channels=10, out_channels=20, kernel_size=5, stride=1, padding=0)#卷积层
        self.maxpool2 = MaxPool2d(2)
        self.linear1 = Linear(320, 128)#全连接层
        self.linear2 = Linear(128, 64)
        self.linear3 = Linear(64, 10)
        self.relu = ReLU()#激活函数

    def forward(self, x):
        x = self.relu(self.maxpool1(self.conv1(x)))
        x = self.relu(self.maxpool2(self.conv2(x)))
        x = x.view(x.size(0), -1)
        x = self.linear1(x)
        x = self.linear2(x)
        x = self.linear3(x)

        return x

损失函数

# 损失函数CrossentropyLoss
model = MnistModel()#实例化
criterion = nn.CrossEntropyLoss()   # 交叉熵损失,相当于Softmax+Log+NllLoss
# 线性多分类模型Softmax,给出最终预测值对于10个类别出现的概率,Log:将乘法转换为加法,减少计算量,保证函数的单调性
# NLLLoss:计算损失,此过程不需要手动one-hot编码,NLLLoss会自动完成

优化器

# SGD,优化器,梯度下降算法e
optimizer = torch.optim.SGD(model.parameters(), lr=0.14)#lr:学习率

下面是简单模型的模板(有需要可以照着模仿一下)

#八股文式的深度学习训练流程
model = Model()  # 初始化模型
creterion = nn.CrossEntropyLoss()  # 选用交叉熵损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 选用Adam优化器,传入模型参数,设置学习率
for epoch in range(50):  # 50个epoch
    for data, label in dataloader:  # DataLoader是一个可迭代对象
        optimizer.zero_grad()  # 待优化参数梯度清空
        prob = model(data)  # 执行一次前向传播,计算预测结果
        loss = creterion(prob, label)  # 评估模型损失
        loss.backward()  # 损失反向传播,完成对待优化参数的梯度求解
        optimizer.step()  # 参数更新
    if (epoch + 1) % 5 == 0:  # 每隔5个epoch打印当前模型训练效果
        with torch.no_grad():
            train_prob = model(X_train_tensor)
            train_pred = train_prob.argmax(dim=1)
            acc_train = (train_pred==y_train_tensor).float().mean()
            test_prob = model(X_test_tensor)
            test_pred = test_prob.argmax(dim=1)
            acc_test = (test_pred==y_test_tensor).float().mean()
            print(f"epoch: {epoch}, train_accuracy: {acc_train}, test_accuracy: {acc_test} !")

或者

# 基本的网络构建类模板
class net_name(nn.Module):
    def __init__(self):
        super(net_name, self).__init__()
        # 可以添加各种网络层
        self.conv1 = nn.Conv2d(3, 10, 3)
        # 具体每种层的参数可以去查看文档
        
    def forward(self, x):
        # 定义向前传播
        out = self.conv1(x)
        return out

4.训练模型

# 模型训练
def train():
    # index = 0
    for index, data in enumerate(train_loader):#获取训练数据以及对应标签
        # for data in train_loader:
       input, target = data   # input为输入数据,target为标签
       y_predict = model(input) #模型预测
       loss = criterion(y_predict, target)
       optimizer.zero_grad() #梯度清零
       loss.backward()#loss值反向传播
       optimizer.step()#更新参数
       # index += 1
       if index % 100 == 0: # 每一百次保存一次模型,打印损失
           torch.save(model.state_dict(), "./model/model.pkl")   # 保存模型
           torch.save(optimizer.state_dict(), "./model/optimizer.pkl")
           print("训练次数为:{},损失值为:{}".format(index, loss.item() ))

# 加载模型
if os.path.exists('./model/model.pkl'):
   model.load_state_dict(torch.load("./model/model.pkl"))#加载保存模型的参数


# 模型测试
def test():
    correct = 0     # 正确预测的个数
    total = 0   # 总数
    with torch.no_grad():   # 测试不用计算梯度
        for data in test_loader:
            input, target = data
            output = model(input)   # output输出10个预测取值,概率最大的为预测数
            probability, predict = torch.max(input=output.data, dim=1)    # 返回一个元祖,第一个为最大概率值,第二个为最大概率值的下标
            # loss = criterion(output, target)
            total += target.size(0)  # target是形状为(batch_size,1)的矩阵,使用size(0)取出该批的大小
            correct += (predict == target).sum().item()  # predict 和target均为(batch_size,1)的矩阵,sum求出相等的个数
        print("测试准确率为:%.6f" %(correct / total))


#测试识别函数
if __name__ == '__main__':
    #训练与测试
    for i in range(100):#训练和测试进行5轮
        print({"————————第{}轮测试开始——————".format (i + 1)})
        train()
        test()


def test_mydata():
    image = Image.open('./test/test_two.png')   #读取自定义手写图片
    image = image.resize((28, 28))   # 裁剪尺寸为28*28
    image = image.convert('L')  # 转换为灰度图像
    transform = transforms.ToTensor()
    image = transform(image)
    image = image.resize(1, 1, 28, 28)
    output = model(image)
    probability, predict = torch.max(output.data, dim=1)
    print("此手写图片值为:%d,其最大概率为:%.2f " % (predict[0], probability))
    plt.title("此手写图片值为:{}".format((int(predict))), fontname='SimHei')
    plt.imshow(image.squeeze())
    plt.show()

# 测试主函数
# if __name__ == '__main__':
#     test_mydata()

完整模型案例

上面的是我零零散散从几个完整的模型代码中截取的案例

以下是完整的几个模型代码(都是关于手写数据集方面的

from pathlib import Path
import requests
import pickle
import gzip
import torch
from torch import nn
import torch.nn.functional as F
from torch import optim
import numpy as np
from torch.utils.data import TensorDataset
from torch.utils.data import DataLoader
#  下载文件,放到data目录下
DATA_PATH = Path("data")
PATH = DATA_PATH / "mnist"
PATH.mkdir(parents=True, exist_ok=True)
URL = "http://deeplearning.net/data/mnist/"
FILENAME = "mnist.pkl.gz"
if not (PATH / FILENAME).exists():
    content = requests.get(URL + FILENAME).content
    (PATH / FILENAME).open("wb").write(content)
# 读取文件
with gzip.open((PATH / FILENAME).as_posix(), "rb") as f:
    ((x_train, y_train), (x_valid, y_valid), _) = pickle.load(f, encoding="latin-1")
# 将所有使用的数据格式转化为tensor的格式
# tensor:张量,通俗理解就是矩阵
 # torch可以处理的数据就是tensor,需要进行一下数据转换
x_train, y_train, x_valid, y_valid = map(torch.tensor, (x_train, y_train, x_valid, y_valid))

bs = 64
# batchsize是64,在数据集中每次读取64张图片
# 使用定义好的交叉熵损失作为损失函数
loss_func = F.cross_entropy
class Mnist_NN(nn.Module):
    def __init__(self):
        super().__init__()
# #  nn.Linear就相当于xw+b,(784,128):输入784像素点,输出128个特征
# # 第一个全连接层  1*(784)×w1(784*128)->1*128
        self.hidden1 = nn.Linear(784, 128)
# # 第二个全连接层:hidden2的输入是hidden1的输出  (1*128)×w2(128*256)->1*256
        self.hidden2 = nn.Linear(128, 256)
# # 输出层,获得十个特征(1*256)×w2(256*10)->1*10
        self.out  = nn.Linear(256, 10)
# # dropout:避免过拟合,随机杀死一些神经元
# # 按照百分之0.5的概率杀死一些神经元
        self.dropout=nn.Dropout(0.5)
# # 前向传播,输入——得到结果,
# # 前向传播需要自己定义,反向传播是自动进行的
# # 定义前向传播
# # x:就是一个batch,在这里是64*784
# # 设计一个前向传播
    def forward(self, x):
        x = F.relu(self.hidden1(x))  # 64*128
#         每一个全连接层都加dropout,卷积层不加
        x = self.dropout(x)
        x = F.relu(self.hidden2(x))  # 64*256
        x = self.dropout(x)
#         输出层
        x = self.out(x) # 64*10
        return x

#获取数据函数
def get_data(train_ds, valid_ds, bs):
    return (
#         shuffle=True:训练集数据打乱数据
#         测试集不用打乱顺序
        DataLoader(train_ds, batch_size=bs, shuffle=True),
        DataLoader(valid_ds, batch_size=bs * 2),
    )
#定义损失
def loss_batch(model, loss_func, xb, yb, opt=None):
    loss = loss_func(model(xb), yb)
# 计算损失   model(xb):预测  yb:真实值
# 优化器
    if opt is not None:
#         反向传播,计算梯度
        loss.backward()
#     更新w和b
        opt.step()
#     每一次的迭代更新之间没关系,要及时归0
        opt.zero_grad()

    return loss.item(), len(xb)

#模型实例化
def get_model():
#     模型实例化
    model = Mnist_NN()
#     optim.SGD(model.parameters(), lr=0.001)
# SGD梯度下降,model.parameters():w和b全部更新
# lr=0.001 学习率
    return model, optim.SGD(model.parameters(), lr=0.001)

#模型训练与测试
def fit(steps, model, loss_func, opt, train_dl, valid_dl):
#     steps=epoch:整个数据集,
# batch:
    for step in range(steps):
#         模型训练:更新w和b
# xb, yb:数据包和标签
        model.train()
        for xb, yb in train_dl:
            loss_batch(model, loss_func, xb, yb, opt)
# 模型验证:不更新参数,直接验证
        model.eval()
        with torch.no_grad():
            losses, nums = zip(
                *[loss_batch(model, loss_func, xb, yb) for xb, yb in valid_dl]
            )
#             计算验证集的loss,、得出的是平均损失
        val_loss = np.sum(np.multiply(losses, nums)) / np.sum(nums)
        print('当前step:'+str(step), '验证集损失:'+str(val_loss))

#加载数据
# 该方法不常用,了解即可
train_ds = TensorDataset(x_train, y_train)
# DataLoader相当于打包员,打包成一个个batchsize的数据
train_dl = DataLoader(train_ds, batch_size=bs, shuffle=True)

valid_ds = TensorDataset(x_valid, y_valid)
valid_dl = DataLoader(valid_ds, batch_size=bs * 2)

#程序运行
train_dl, valid_dl = get_data(train_ds, valid_ds, bs)
model, opt = get_model()
fit(10, model, loss_func, opt, train_dl, valid_dl)

#计算准确率
#  计算准确率
correct=0
total=0
# 看验证集的正确率
for xb,yb in valid_dl:
    outputs=model(xb)
    _,predicted=torch.max(outputs.data,1)# 最大值和索引
    total+=yb.size(0)# 验证的验证集数量,
#     (predicted==yb).sum计算预测对的结果
# item的作用就是将数据结构由tensor换成数字
    correct+=(predicted==yb).sum().item()
print("网络的准确率:%d %%"%(100*correct/total))

import os
import matplotlib.pyplot as plt
import torch
from PIL import Image
from torch import nn
from torch.nn import Conv2d, Linear, ReLU
from torch.nn import MaxPool2d
from torchvision import transforms
from torchvision.datasets import MNIST
from torch.utils.data import DataLoader


# Dataset:创建数据集的函数;__init__:初始化数据内容和标签
# __geyitem:获取数据内容和标签
# __len__:获取数据集大小
# daataloader:数据加载类,接受来自dataset已经加载好的数据集
# torchbision:图形库,包含预训练模型,加载数据的函数、图片变换,裁剪、旋转等
# torchtext:处理文本的工具包,将不同类型的额文件转换为datasets

# 预处理:将两个步骤整合在一起
transform = transforms.Compose({
    transforms.ToTensor(),  # 将灰度图片像素值(0~255)转为Tensor(0~1),方便后续处理
    # transforms.Normalize((0.1307,),(0.3081)),    # 归一化,均值0,方差1;mean:各通道的均值std:各通道的标准差inplace:是否原地操作
})

# normalize执行以下操作:image=(image-mean)/std?????
# input[channel] = (input[channel] - mean[channel]) / std[channel]

# 加载数据集
# 训练数据集
train_data = MNIST(root='./data', train=True, transform=transform, download=True)
train_loader = DataLoader(dataset=train_data, batch_size=64, shuffle=True)
# transform:指示加载的数据集应用的数据预处理的规则,shuffle:洗牌,是否打乱输入数据顺序
# 测试数据集
test_data = MNIST(root="./data", train=False, transform=transform, download=True)
test_loader = DataLoader(dataset=test_data, batch_size=64, shuffle=True)

train_data_size = len(train_data)
test_data_size = len(test_data)
print("训练数据集的长度:{}".format(train_data_size))
print("测试数据集的长度:{}".format(test_data_size))
# print(test_data)
# print(train_data)

#设计模型
class MnistModel(nn.Module):
    def __init__(self):
        super(MnistModel, self).__init__()
        self.conv1 = Conv2d(in_channels=1, out_channels=10, kernel_size=5, stride=1, padding=0)#卷积层
        self.maxpool1 = MaxPool2d(2)
        self.conv2 = Conv2d(in_channels=10, out_channels=20, kernel_size=5, stride=1, padding=0)#卷积层
        self.maxpool2 = MaxPool2d(2)
        self.linear1 = Linear(320, 128)#全连接层
        self.linear2 = Linear(128, 64)
        self.linear3 = Linear(64, 10)
        self.relu = ReLU()#激活函数

    def forward(self, x):
        x = self.relu(self.maxpool1(self.conv1(x)))
        x = self.relu(self.maxpool2(self.conv2(x)))
        x = x.view(x.size(0), -1)
        x = self.linear1(x)
        x = self.linear2(x)
        x = self.linear3(x)

        return x


# 损失函数CrossentropyLoss
model = MnistModel()#实例化
criterion = nn.CrossEntropyLoss()   # 交叉熵损失,相当于Softmax+Log+NllLoss
# 线性多分类模型Softmax,给出最终预测值对于10个类别出现的概率,Log:将乘法转换为加法,减少计算量,保证函数的单调性
# NLLLoss:计算损失,此过程不需要手动one-hot编码,NLLLoss会自动完成

# SGD,优化器,梯度下降算法e
optimizer = torch.optim.SGD(model.parameters(), lr=0.14)#lr:学习率


# 模型训练
def train():
    # index = 0
    for index, data in enumerate(train_loader):#获取训练数据以及对应标签
        # for data in train_loader:
       input, target = data   # input为输入数据,target为标签
       y_predict = model(input) #模型预测
       loss = criterion(y_predict, target)
       optimizer.zero_grad() #梯度清零
       loss.backward()#loss值反向传播
       optimizer.step()#更新参数
       # index += 1
       if index % 100 == 0: # 每一百次保存一次模型,打印损失
           torch.save(model.state_dict(), "./model/model.pkl")   # 保存模型
           torch.save(optimizer.state_dict(), "./model/optimizer.pkl")
           print("训练次数为:{},损失值为:{}".format(index, loss.item() ))

# 加载模型
if os.path.exists('./model/model.pkl'):
   model.load_state_dict(torch.load("./model/model.pkl"))#加载保存模型的参数


# 模型测试
def test():
    correct = 0     # 正确预测的个数
    total = 0   # 总数
    with torch.no_grad():   # 测试不用计算梯度
        for data in test_loader:
            input, target = data
            output = model(input)   # output输出10个预测取值,概率最大的为预测数
            probability, predict = torch.max(input=output.data, dim=1)    # 返回一个元祖,第一个为最大概率值,第二个为最大概率值的下标
            # loss = criterion(output, target)
            total += target.size(0)  # target是形状为(batch_size,1)的矩阵,使用size(0)取出该批的大小
            correct += (predict == target).sum().item()  # predict 和target均为(batch_size,1)的矩阵,sum求出相等的个数
        print("测试准确率为:%.6f" %(correct / total))


#测试识别函数
if __name__ == '__main__':
    #训练与测试
    for i in range(100):#训练和测试进行5轮
        print({"————————第{}轮测试开始——————".format (i + 1)})
        train()
        test()


def test_mydata():
    image = Image.open('./test/test_two.png')   #读取自定义手写图片
    image = image.resize((28, 28))   # 裁剪尺寸为28*28
    image = image.convert('L')  # 转换为灰度图像
    transform = transforms.ToTensor()
    image = transform(image)
    image = image.resize(1, 1, 28, 28)
    output = model(image)
    probability, predict = torch.max(output.data, dim=1)
    print("此手写图片值为:%d,其最大概率为:%.2f " % (predict[0], probability))
    plt.title("此手写图片值为:{}".format((int(predict))), fontname='SimHei')
    plt.imshow(image.squeeze())
    plt.show()

# 测试主函数
# if __name__ == '__main__':
#     test_mydata()
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
# 定义超参数
batch_size = 64
learning_rate = 1e-2
num_epochs = 5 # 训练次数
# 判断GPU是否可用
use_gpu = torch.cuda.is_available()

# 下载训练集 MNIST 手写数字训练集
# 数据是datasets类型的
train_dataset = datasets.FashionMNIST(
    root='../datasets', train=True, transform=transforms.ToTensor(), download=True)

test_dataset = datasets.FashionMNIST(
    root='../datasets', train=False, transform=transforms.ToTensor())
# 将数据处理成 DataLoader
train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True) # 选择打乱数据
test_loader = DataLoader(test_dataset, batch_size=batch_size, shuffle=False) # 选择不打乱数据

def __getitem__(self,index):
    img_path,label=self.data[index].img_path,self.data[index].label
    img=Image.open(img_path)
    return img,label

# 定义简单的前馈神经网络
class neuralNetwork(nn.Module):
    def __init__(self, in_dim, n_hidden_1, n_hidden_2, out_dim):
        super(neuralNetwork, self).__init__() # super() 函数是用于调用父类(超类)的一个方法
# Sequential()表示将一个有序的模块写在一起,也就相当于将神经网络的层按顺序放在一起,这样可以方便结构显示
        self.layer1 = nn.Sequential(
            nn.Linear(in_dim, n_hidden_1),
            nn.ReLU(True)) # 表示使用ReLU激活函数
        self.layer2 = nn.Sequential(
            nn.Linear(n_hidden_1, n_hidden_2),
            nn.ReLU(True))
        self.layer3 = nn.Sequential(
            nn.Linear(n_hidden_2, out_dim),
            nn.ReLU(True))

# 定义向前传播
    def forward(self, x):
        x = self.layer1(x)
        x = self.layer2(x)
        x = self.layer3(x)
        return x
# 图片大小是28*28,中间定义了两个隐藏层大小分别为300和100,最后输出层为10,10分类问题
model = neuralNetwork(28 * 28, 300, 100, 10)
if use_gpu:
    model = model.cuda() # 现在可以在GPU上跑代码了

criterion = nn.CrossEntropyLoss() # 定义损失函数类型,使用交叉熵
optimizer = torch.optim.SGD(model.parameters(), lr=learning_rate) # 定义优化器,使用随机梯度下降

# 开始模型训练
for epoch in range(num_epochs):
    print('*' * 10)
    print(f'epoch {epoch+1}')
    running_loss = 0.0 # 初始值
    running_acc = 0.0
    for i, data in enumerate(train_loader, 1): # 枚举函数enumerate返回下标和值
        img, label = data
        img = img.view(img.size(0), -1) # 将图片展开为28*28
        # 使用GPU?
        if use_gpu:
            img = img.cuda()
            label = label.cuda()
        # 向前传播
        out = model(img) # 前向传播
        loss = criterion(out, label) # 计算loss
        running_loss += loss.item() # loss求和
        _, pred = torch.max(out, 1)
        running_acc += (pred == label).float().mean()
        # 向后传播
        optimizer.zero_grad() # 梯度归零
        loss.backward() # 后向传播
        optimizer.step() # 更新参数

        if i % 300 == 0:
            print(f'[{epoch+1}/{num_epochs}] Loss: {running_loss/i:.6f}, Acc: {running_acc/i:.6f}')
    print(f'Finish {epoch+1} epoch, Loss: {running_loss/i:.6f}, Acc: {running_acc/i:.6f}')
    
## 模型测试
model.eval() # 让模型变成测试模式
eval_loss = 0.
eval_acc = 0.
for data in test_loader:
    img, label = data
    img = img.view(img.size(0), -1)
    if use_gpu:
        img = img.cuda()
        label = label.cuda()
    with torch.no_grad():
        out = model(img)
        loss = criterion(out, label)
    eval_loss += loss.item()
    _, pred = torch.max(out, 1)
    eval_acc += (pred == label).float().mean()
print(f'Test Loss: {eval_loss/len(test_loader):.6f}, Acc: {eval_acc/len(test_loader):.6f}\n')

# 保存模型
torch.save(model.state_dict(), './neural_network.pth')

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值