IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 人工智能 -> PyTorch:其他网络,调试PyTorch模型,部署PyTorch -> 正文阅读

[人工智能]PyTorch:其他网络,调试PyTorch模型,部署PyTorch

1,其他网络

1.1,循环神经网络

假设存在两个句子:

  • The cat sat on the mat,(小猫坐在垫子上)
  • She got up and impatiently climbed on the chair,meowing for food. (它站起来,急不可耐地爬上椅子,冲着食物喵喵叫)

假设这两个句子先后输入一个CNN,并且问 “where is the cat?”(小猫在哪里?),就会有一个问题,因为网络没有记忆的概念。处理时域数据时这一点极其重要(例如,文本、语音、视频和时序数据)。循环神经网络(RNN)可以解决这个问题,它通过隐藏状态(hidden state)为神经网络提供记忆。

RNN可以简单想象成混合了一个for循环的神经网络:

在时间步t增加输入,然后得到一个隐藏(hidden)输出状态h(t),这个状态还要在下一个时间步再输入到RNN。

这里有一组全连接层(有共享的参数)、一系列输入,以及输出。向网络提供输入书,然后预测序列的下一项作为输出。在这个展开的视图中可以看到,可以认为RNN是一个全连接层流水线,后续输入提供给序列中的下一层(层之间会插入通常的非线性激活函数,如ReLU)。有了完整的预测序列,必须将误差通过RNN反向传播(BPTT)。在整个序列上计算误差,如上图所示,为每个时间步计算梯度,并组合这些梯度来更新网络的共享参数。可以把它想象为在各个网络上完成反向传播,再把所有梯度累加起来。

1.2,长短期记忆网络

在实际上,不论是以前还是现在,RNN都存在梯度消失的问题,或者可能更糟糕,会有梯度爆炸的情况,即误差趋向于无穷大。这两种情况都不好,所以尽管人们认为很多问题对RNN是适用的,但实际上RNN并不能用来解决这些问题。而LSTM网络的出现,才解决了这些问题。

在一个标准RNN中,我们会永远记住所有一切。不过,我们的大脑并不是这样做的,LSTM的遗忘门允许我们模拟这种想法,即随着在输入链中不断深入,这个链开始的部分会变得不那么重要。LSTM的遗忘程度要在训练中学习,所以如果网络强调非常健忘,遗忘门参数就要保证这一点。

单元最后会成为网络层的“记忆”;输入、输出和遗忘门会确定数据如何流过一层。数据可以简单地直接通过,它可以“写入”单元,而且这个数据可以(或者不可以)流到下一层,由输出门修改。各个部分的这种组合足以解决梯度消失的问题,而且还有一个好处是可以做图灵完备,所以理论上讲,可以利用这样一个网络完成能够在计算机上完成的任何计算。

1.3,门控循环单元

GRU的要点是将遗忘门与输出门合并。这意味着,它的参数比LSTM少,所以往往训练更快,而且在运行时使用的资源更少。由于这些原因,另外因为它们基本上可以直接替代LSTM,所以变得相当流行。不过,严格地讲,由于合并了遗忘门和输出门,GRU不如LSTM能力强,所以一般建议GRU和LSTM都可以进行尝试,看看哪一个表现更好。或许承认LSTM训练时可能慢一些,不过最后会得到更好的结果。

1.4,双向长期记忆网络

LSTM的另一个常见的变形是双向或简写为biLSTM。目前为止我们已经看到,传统LSTM(和一般的RNN)会在训练和做决策时查看过去。遗憾的是,有时你还需要查看将来。在翻译或手写识别之类的应用中尤其如此,这些应用中,当前状态之后的情况对于确定输出可能与前一个状态同样重要。

biLSTM用最简单的方式解决这个问题,它实际上是两个堆叠LSTM,一个LSTM中输入向前传递,另一个LSTM中输入向后传递。

使用PyTorch可以很容易地创建biLSTM,只需要在创建一个LSTM()单元时传入参数bidirectional=True。

2,TensorBoard

2.1,安装TensorBoard

TensorBoard是一个Web应用,设计用来对神经网络的不同方面进行可视化。利用TensorBoard可以很容易地实时查看统计信息,如准确度、损失激活值,实际上可以查看你希望通过网络发送的任何信息。尽管它本身是用TensorFolow编写的,但有一个跨系统而且相当简单的API,在PyTorch中使用与在TensorFlow中使用并没有太大差别。

安装:

#要求PyTorch版本在v1.14以上
pip install tensorboard
conda install tensorboard

启动:

tensorboard --logdir=runs
=========================================================================
TensorBoard 1.14.0 at http://DESKTOP-3T77H9A:6006/ (Press CTRL+C to quit)

根据提示进入网站,可以看到如下欢迎界面:

2.2,向TensorBoard发送数据

PyTorch中使用TensorBoard的模块在torch.utils.tensorboard中:

from torch.utils.tensorboard import SummaryWriter
writer = SummaryWriter()
writer.add_scalar('example',3)

使用SummaryWriter类与TensorBoard交互,这里使用标准位置./runs记录输出,另外使用add_scalar并提供一个标记来发送一个标量。

在PyCharm中打开TensorBoard:

加一层循环:

from torch.utils.tensorboard import SummaryWriter
import random

value = 10
writer = SummaryWriter()
writer.add_scalar('test_loop', 0)
for i in range(1, 10000):
    value += random.random() - 0.5
    writer.add_scalar('test_loop', value, i)

2.3,PyTorch钩子

PyTorch提供了钩子(hook),这是在向前向后传播时看,可以附加到一个张量或模块的函数。PyTorch在传播中遇到一个带钩子的模块时,它会调用所注册的钩子。计算一个张量的梯度时,就会调用这个张量上注册的钩子。

钩子提供了很多可能很强大的方式来管理模块和张量,因为如果需要,可以完全替换进入钩子的(前一层)输出。可以改变梯度、屏蔽激活、替换模块中的所有偏置等。不过这里只是使用钩子在数据流过时得到网络的有关信息。

import torch.utils.data
import torchvision

def print_hook(module,input,output):
    print(input[0].shape)
net = torchvision.models.resnet18()
x = torch.rand(1,3,224,224)
hook_ref = net.fc.register_forward_hook(print_hook)
net(x)
hook_ref.remove()
net(x)
=================================
torch.Size([1, 512])

程序结果打印出一些文本,显示模型全连接层的输入形状。注意,第二次向模型传入张量,不会看到print语句。向一个模块或张量增加一个钩子时,PyTorch会返回这个钩子的一个引用。总是应当保存这个引用,然后工作完成时调用remove()。如果没有保存这个引用,它就会在内存中“游荡”,而占用宝贵的内存。反向钩子的做法类似,只不过要调用register_backward_hook()。

2.4,均值和标准差

建立一个函数,将一个输出层的均值和标准差发送给TensorBoard:

def send_stats(i, module, input, output):
    writer.add_scalar(f"layer {i}-mean", output.data.mean())
    writer.add_scalar(f"layer {i}-stddev", output.data.std())

不能用这个函数本身建立一个前向钩子,不过通过使用Python函数partial(),可以创建一系列前向钩子,将它们附加到指定i值(partial()的第二个参数)的一个层,从而确保把正确的值传送到TensorBoard中正确的图中:

for i, m in enumerate(model.children()):
    m.register_forward_hook(partial(send_stats, i))

注意,这里使用了model.children(),这样只会附加到模型的各个顶层模块,所以如果有一个nn.Sequential()层(基于ResNet的模型都有这样一个层),钩子只会附加到这个模块,而不会附加到nn.Sequential列表中的各个模块。

如果使用通常的训练函数训练这个模型,应该会看到激活值开始流入TensorBoard。必须切换为WALL,因此不再用钩子将训练的步信息发送回TensorBoard(只有在调用PyTorch钩子时才会得到模块信息)。

2.5,获取模型详细信息

理想情况下神经网络中的层应该均值为0,并且标准差为1,从而保证计算不会变成无穷大或者0。如果不是这样,可能这个网络训练有问题。

import torch
import torch.nn as nn
import torch.utils.data
import torchvision
from functools import partial
from torch import optim
from torch.utils.tensorboard import SummaryWriter
from torchvision import datasets, transforms

# Writer will output to ./runs/ directory by default

writer = SummaryWriter()

transform = transforms.Compose(
    [transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,))]
)
trainset = datasets.MNIST("mnist_train", train=True, download=True, transform=transform)
train_data_loader = torch.utils.data.DataLoader(trainset, batch_size=64, shuffle=True)
model = torchvision.models.resnet50(False)

model.conv1 = torch.nn.Conv2d(1, 64, kernel_size=7, stride=2, padding=3, bias=False)
images, labels = next(iter(train_data_loader))

grid = torchvision.utils.make_grid(images)
writer.add_image("images", grid, 0)
writer.add_graph(model, images)


def send_stats(i, module, input, output):
    writer.add_scalar(f"layer {i}-mean", output.data.mean())
    writer.add_scalar(f"layer {i}-stddev", output.data.std())


for i, m in enumerate(model.children()):
    m.register_forward_hook(partial(send_stats, i))

# Now train the model and watch output in Tensorboard

optimizer = optim.Adam(model.parameters(), lr=2e-2)
criterion = nn.CrossEntropyLoss()


def train(model, optimizer, loss_fn, train_loader, val_loader, epochs=20, device="cuda:0"):
    model.to(device)
    for epoch in range(epochs):
        print(f"epoch {epoch + 1}")
        model.train()
        for batch in train_loader:
            optimizer.zero_grad()
            ww, target = batch
            ww = ww.to(device)
            target = target.to(device)
            output = model(ww)
            loss = loss_fn(output, target)
            loss.backward()
            optimizer.step()

        model.eval()
        num_correct = 0
        num_examples = 0
        for batch in val_loader:
            ww, target = batch
            ww = ww.to(device)
            target = target.to(device)
            output = model(ww)
            correct = torch.eq(torch.max(output, dim=1)[1], target).view(-1)
            num_correct += torch.sum(correct).item()
            num_examples += correct.shape[0]
        print("Epoch {}, accuracy = {:.2f}".format(epoch + 1, num_correct / num_examples))


train(model, optimizer, criterion, train_data_loader, train_data_loader, epochs=5)

3,部署PyTorch

3.1,搭建Flask服务

建立模型只是构建深度学习应用的一部分,毕竟一个模型有那么惊人的准确度(或其他优点),但是如果它从不做任何预测,又有什么价值。因为我们希望有一种简单的方法打包我们的模型,使它们能响应请求(可以通过Web或者其他途径),而且可以通过最少的努力使模型在生产环境中运行。

Python允许我们使用Flask框架(Flask是用Python创建Web服务的一个流行框架)快速地部署和运行一个Web服务,接受一个请求(包含一个图像URL),并返回一个JSON响应,指示预测结果。

conda install -c anaconda flask
pip install flask

创建一个名为catfish的新目录,把你的模型定义作为model.py复制到这个目录中:

import torch.nn as nn 
from torchvision import models

CatfishClasses = ["cat","fish"]

CatfishModel = models.resnet50()
CatfishModel.fc = nn.Sequential(nn.Linear(CatfishModel.fc.in_features,500),
                  nn.ReLU(),
                  nn.Dropout(), nn.Linear(500,2))
import os
import requests
import torch
from flask import Flask, jsonify, request
from io import BytesIO
from PIL import Image
from torchvision import transforms
from catfish_model import CatfishModel, CatfishClasses

def load_model():
    m = CatfishModel
    m.eval()
    return m
model = load_model()
img_transforms = transforms.Compose([
    transforms.Resize((224, 224)),
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.485, 0.456, 0.406],
                         std=[0.229, 0.224, 0.225])
])
app = Flask(__name__)

@app.route("/")
def status():
    return jsonify({"status": "ok"})

@app.route("/predict", methods=['GET', 'POST'])
def predict():
    if request.method == 'POST':
        img_url = request.form.image_url
    else:
        img_url = request.args.get('image_url', '')

    response = requests.get(img_url)
    img = Image.open(BytesIO(response.content))
    img_tensor = img_transforms(img).unsqueeze(0)
    prediction = model(img_tensor)
    predicted_class = CatfishClasses[torch.argmax(prediction)]
    return jsonify({"image": img_url, "prediction": predicted_class})
if __name__ == '__main__':
    app.run(host="127.0.0.1",port="8080")

Flask的魅力在于@app.route()注解。这些注解允许我们关联平常的Python函数,用户达到某个特定端点时就会运行这些函数。在我们的predict()方法中,从GET或POST HTTP请求取出img_url参数,打开这个URL(作为一个PIL图像),把它推入一个简单的torchvision转换流水线,调整它的大小并把图像转换为一个张量。

这样我们会得到一个形状为[3, 224, 224]的张量,不过由于这个模型的工作方式,需要把它转换为批量大小为1的一个批次,也就是[1, 3, 224, 224]。所以再使用unsqueeze()扩展这个张量,在现在维度前面插入一个新的空轴(维度)。然后像往常一样把它传入模型,从而得到我们的预测张量。与前面的做法一样,我们使用torch.argmax()找到最大值的张量元素,并用这个元素作为索引来访问CatfishClasses数组。最后返回一个JSON响应,其中包括类别名和做预测的图像URL。

如果现在尝试这个服务,可能发现它的分类性能有些失望。因为这个模型没有经过任何训练,下面将填充load_model()来加载神经网络参数。

3.2,设置模型参数

通过之前的了解,知道了训练之后保存模型的两种方法,可以用torch.save()将整个模型写至磁盘,或者使用state_dict()保存模型的所有权重和偏执(但不包括结构)。对于这个基于生产环境的服务,需要加载一个已训练的模型,应该选择state_dict方法。

尽管保存整个模型是一个很有吸引力的选择,但是你会对模型结构的任何改变非常敏感,甚至训练环境目录结构的改变也会产生很大的影响。在其他地方运行的不同服务中加载这个模型时很可能会出现问题。如果迁移到一个稍有不同的布局(结构),肯定不希望一切从头开始。

另外,如果是用state_dicts()保存模型,加载保存的模型时,最好不要硬编码指定模块的文件名,这样就能将模型更新与服务解耦合。这意味着我们可以用一个新模型重启服务,或者也可以很容易地还原到之前的一个模型。

def load_model():
    m = CatfishModel
    location = "./a.pt"
    m.load_state_dict(torch.load(location))
    m.eval()
    return m
torch.save(net.state_dict(), './data/' + 'model.pt')
  人工智能 最新文章
2022吴恩达机器学习课程——第二课(神经网
第十五章 规则学习
FixMatch: Simplifying Semi-Supervised Le
数据挖掘Java——Kmeans算法的实现
大脑皮层的分割方法
【翻译】GPT-3是如何工作的
论文笔记:TEACHTEXT: CrossModal Generaliz
python从零学(六)
详解Python 3.x 导入(import)
【答读者问27】backtrader不支持最新版本的
上一篇文章      下一篇文章      查看所有文章
加:2022-03-08 22:28:33  更:2022-03-08 22:30:32 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/26 16:28:23-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码