小白学Pytorch使用(6):Pytorch模型部署——Flask预测

任务背景

使用Flask微框架部署花数据集分类模型
项目数据+代码

Flask简介

Flask 是一个轻量级的 Web 应用框架,用 Python 编写。它基于 Werkzeug WSGI 工具箱和 Jinja2 模板引擎。Flask 也被称为“微框架”,因为它旨在保持核心简单且易于扩展,开发者可以按需添加功能。
以下是 Flask 的一些主要特点:

  1. 轻量级和简单:Flask 保持核心简单,使得开发者能够轻松理解其核心组件,并快速构建 Web 应用。
  2. 可扩展性:虽然 Flask 本身很简单,但开发者可以轻松地扩展其功能,通过添加插件和扩展。
  3. WSGI 兼容:Flask 基于 Werkzeug,这是一个强大的 WSGI 工具库,为 Flask 提供了底层的路由、请求和响应处理功能。
  4. Jinja2 模板引擎:Flask 默认使用 Jinja2 作为模板引擎,它提供了强大的模板功能,包括自动转义、变量过滤和宏等。
  5. 强大的 URL 路由:Flask 的路由系统简单且强大,允许开发者定义复杂的 URL 规则和反向 URL 生成。
  6. 内置的开发服务器:Flask 提供了一个简单的开发服务器,使得开发者能够轻松地启动和测试应用。
  7. 单元测试和集成测试:Flask 易于进行单元测试和集成测试,这有助于确保代码的质量和稳定性。
  8. RESTful API 开发:Flask 也非常适合用于构建 RESTful API。

任务步骤

在 Flask 中进行预测通常涉及以下步骤:

  1. 训练模型:首先,你需要有一个已经训练好的机器学习模型。这个模型可能是在另一个脚本或环境中训练好的,并保存了其权重和架构。
  2. 加载模型:在 Flask 应用中,你需要加载这个已经训练好的模型。这通常是通过使用模型对应的库(如 TensorFlow、PyTorch、scikit-learn 等)的加载功能来实现的。
  3. 定义预测路由:在 Flask 应用中,你需要定义一个或多个路由来处理预测请求。这些路由将接收客户端发送的数据,使用加载的模型进行预测,并返回预测结果。
  4. 处理请求数据:在路由函数中,你需要从客户端请求中提取数据,并可能需要进行一些预处理,以便模型能够接受这些数据作为输入。
  5. 进行预测:使用加载的模型对预处理后的数据进行预测。
  6. 返回预测结果:将预测结果以适当的格式(如 JSON)返回给客户端。

一、flask_predict.py——客户端

# 客户端

import requests
import argparse

# url和端口携程自己的
flask_url = 'http://127.0.0.1:5012/predict'


def predict_result(image_path):
    #啥方法都行,opencv、PIL
    image = open(image_path, 'rb').read()
    payload = {'image': image}
    #request发给server.
    r = requests.post(flask_url, files=payload).json()

    # 成功的话在返回.
    if r['success']:
        # 输出结果.
        for (i, result) in enumerate(r['predictions']):
            print('{}. {}: {:.4f}'.format(i + 1, result['label'],
                                          result['probability']))
    # 失败了就打印.
    else:
        print('Request failed')


if __name__ == '__main__':
    parser = argparse.ArgumentParser(description='Classification demo')
    parser.add_argument('--file', default='./flower_data/val_filelist/image_03173.jpg', type=str, help='test image file')

    args = parser.parse_args()
    predict_result(args.file)

二、flask_server.py——服务端

# 服务端: 加载模型,加载数据,数据预处理,模型预测,预测结果返还

import io
import json
import flask
import torch
import torch
import torch.nn.functional as F
from PIL import Image
from torch import nn
#from torchvision import transforms as T
from torchvision import transforms, models, datasets
from torch.autograd import Variable

# 初始化Flask app——————固定写法
app = flask.Flask(__name__)
model = None
use_gpu = False

# 加载模型进来
def load_model():
    """Load the pre-trained model, you can use your model just as easily.
    """
    # 定义全局变量
    global model
    #这里我们直接加载官方工具包里提供的训练好的模型(代码会自动下载)括号内参数为是否下载模型对应的配置信息
    # 加载模型跟训练时的模型需要一致,resnet18
    model = models.resnet18()
    # resnet18是1000分类的网络,修改为102分类的,跟训练时的网络结构相同
    num_ftrs = model.fc.in_features
    # model.fc = nn.Sequential(nn.Linear(num_ftrs, 102))  # 类别数自己根据自己任务来        .pth文件
    # print(model)
    # ResNet(
    #   (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
    #   (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #   (relu): ReLU(inplace=True)
    #   (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    #   (layer1): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (layer2): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (downsample): Sequential(
    #         (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
    #         (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       )
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (layer3): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (downsample): Sequential(
    #         (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
    #         (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       )
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (layer4): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (downsample): Sequential(
    #         (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
    #         (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       )
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
    #   (fc): Sequential(
    #     (0): Linear(in_features=512, out_features=102, bias=True)
    #   )
    # )

    # 加载模型当前参数

    model.fc = nn.Linear(num_ftrs, 102)     # .pt文件
    # print(model)
    # ResNet(
    #   (conv1): Conv2d(3, 64, kernel_size=(7, 7), stride=(2, 2), padding=(3, 3), bias=False)
    #   (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #   (relu): ReLU(inplace=True)
    #   (maxpool): MaxPool2d(kernel_size=3, stride=2, padding=1, dilation=1, ceil_mode=False)
    #   (layer1): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (layer2): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (downsample): Sequential(
    #         (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)
    #         (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       )
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (layer3): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (downsample): Sequential(
    #         (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)
    #         (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       )
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (layer4): Sequential(
    #     (0): BasicBlock(
    #       (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (downsample): Sequential(
    #         (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)
    #         (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       )
    #     )
    #     (1): BasicBlock(
    #       (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #       (relu): ReLU(inplace=True)
    #       (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)
    #       (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
    #     )
    #   )
    #   (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))
    #   (fc): Linear(in_features=512, out_features=102, bias=True)
    # )

    checkpoint = torch.load('best_my_true.pt')
    # 导入最佳模型的权重参数
    model.load_state_dict(checkpoint['state_dict'])
    #将模型指定为测试格式
    model.eval()
    #是否使用gpu
    if use_gpu:
        model.cuda()

# 数据预处理
def prepare_image(image, target_size):
    """Do image preprocessing before prediction on any data.

    :param image:       original image
    :param target_size: target image size
    :return:
                        preprocessed image
    """
    #针对不同模型,image的格式不同,但需要统一至RGB格式
    # print(image.mode)
    # RGB
    if image.mode != 'RGB':
        image = image.convert("RGB")

    # Resize the input image and preprocess it.(按照所使用的模型将输入图片的尺寸修改,并转为tensor)
    # print(image)
    # <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=750x500 at 0x12643C39310>
    image = transforms.Resize(target_size)(image)
    # print(image)
    # <PIL.Image.Image image mode=RGB size=64x64 at 0x1D2F0129A60>
    image = transforms.ToTensor()(image)
    # print(image)
    # tensor([[[0.2353, 0.2039, 0.2824,  ..., 0.2196, 0.2863, 0.3647],
    #          [0.2549, 0.2235, 0.2431,  ..., 0.1647, 0.2275, 0.3333],
    #          [0.2471, 0.1882, 0.1294,  ..., 0.1608, 0.2431, 0.3412],
    #          ...,
    #          [0.6863, 0.6235, 0.3569,  ..., 0.3608, 0.2314, 0.2902],
    #          [0.6235, 0.5490, 0.3451,  ..., 0.5608, 0.4431, 0.2588],
    #          [0.5647, 0.3882, 0.2784,  ..., 0.6039, 0.4980, 0.2314]],
    #
    #         [[0.1765, 0.1451, 0.2235,  ..., 0.2039, 0.3294, 0.4706],
    #          [0.1569, 0.1333, 0.1843,  ..., 0.1647, 0.3137, 0.4706],
    #          [0.1412, 0.0980, 0.0824,  ..., 0.1725, 0.3412, 0.4824],
    #          ...,
    #          [0.6471, 0.5843, 0.2902,  ..., 0.3412, 0.1961, 0.2275],
    #          [0.5882, 0.5020, 0.2784,  ..., 0.5647, 0.4275, 0.2314],
    #          [0.5294, 0.3333, 0.2118,  ..., 0.6196, 0.4941, 0.2118]],
    #
    #         [[0.0314, 0.0353, 0.0863,  ..., 0.1294, 0.1647, 0.2157],
    #          [0.0314, 0.0392, 0.0627,  ..., 0.0745, 0.0863, 0.1765],
    #          [0.0314, 0.0314, 0.0235,  ..., 0.0667, 0.0863, 0.1569],
    #          ...,
    #          [0.5804, 0.5216, 0.2471,  ..., 0.3216, 0.1686, 0.1765],
    #          [0.5216, 0.4510, 0.2392,  ..., 0.5412, 0.4000, 0.2000],
    #          [0.4627, 0.2902, 0.1804,  ..., 0.5882, 0.4784, 0.2078]]])

    # Convert to Torch.Tensor and normalize. mean与std   (RGB三通道)这里的参数和数据集中是对应的,训练过程中一致
    image = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])(image)
    # print(image)
    # tensor([[[-1.0904, -1.2274, -0.8849,  ..., -1.1589, -0.8678, -0.5253],
    #          [-1.0048, -1.1418, -1.0562,  ..., -1.3987, -1.1247, -0.6623],
    #          [-1.0390, -1.2959, -1.5528,  ..., -1.4158, -1.0562, -0.6281],
    #          ...,
    #          [ 0.8789,  0.6049, -0.5596,  ..., -0.5424, -1.1075, -0.8507],
    #          [ 0.6049,  0.2796, -0.6109,  ...,  0.3309, -0.1828, -0.9877],
    #          [ 0.3481, -0.4226, -0.9020,  ...,  0.5193,  0.0569, -1.1075]],
    #
    #         [[-1.2479, -1.3880, -1.0378,  ..., -1.1253, -0.5651,  0.0651],
    #          [-1.3354, -1.4405, -1.2129,  ..., -1.3004, -0.6352,  0.0651],
    #          [-1.4055, -1.5980, -1.6681,  ..., -1.2654, -0.5126,  0.1176],
    #          ...,
    #          [ 0.8529,  0.5728, -0.7402,  ..., -0.5126, -1.1604, -1.0203],
    #          [ 0.5903,  0.2052, -0.7927,  ...,  0.4853, -0.1275, -1.0028],
    #          [ 0.3277, -0.5476, -1.0903,  ...,  0.7304,  0.1702, -1.0903]],
    #
    #         [[-1.6650, -1.6476, -1.4210,  ..., -1.2293, -1.0724, -0.8458],
    #          [-1.6650, -1.6302, -1.5256,  ..., -1.4733, -1.4210, -1.0201],
    #          [-1.6650, -1.6650, -1.6999,  ..., -1.5081, -1.4210, -1.1073],
    #          ...,
    #          [ 0.7751,  0.5136, -0.7064,  ..., -0.3753, -1.0550, -1.0201],
    #          [ 0.5136,  0.1999, -0.7413,  ...,  0.6008, -0.0267, -0.9156],
    #          [ 0.2522, -0.5147, -1.0027,  ...,  0.8099,  0.3219, -0.8807]]])

    # 正常训练图像格式为(batch, c, h, w),这里输入图像为(c, h, w)缺少batch维度
    # Add batch_size axis.增加一个维度,用于按batch测试   本次这里一次测试一张
    # print(image.shape)
    # torch.Size([3, 64, 64])
    image = image[None]
    # print(image.shape)
    # torch.Size([1, 3, 64, 64])

    if use_gpu:
        image = image.cuda()

    # Variable()创建一个变量(Variable)对象,这个对象会包装一个张量(Tensor)并添加一些额外的功能
    # volatile=True 不计算反向传播梯度
    return Variable(image, volatile=True) #不需要求导

# 开启服务   这里的predict只是一个名字,可自定义
@app.route("/predict", methods=["POST"])
def predict():
    # Initialize the data dictionary that will be returned from the view.
    #做一个标志,刚开始无图像传入时为false,传入图像时为true
    data = {"success": False}

    # 如果收到请求
    if flask.request.method == 'POST':
        #判断是否为图像
        if flask.request.files.get("image"):
            # Read the image in PIL format
            # 将收到的图像进行读取
            image = flask.request.files["image"].read()

            # 根据传进来的格式做对应格式的转换:opencv、PIL
            image = Image.open(io.BytesIO(image)) #二进制数据
            # print(image)
            # <PIL.JpegImagePlugin.JpegImageFile image mode=RGB size=750x500 at 0x168731BB340>
            # 利用上面的预处理函数将读入的图像进行预处理
            image = prepare_image(image, target_size=(64, 64))

            # print(model(image))
            # tensor([[ -9.5559,  -8.1000,  -2.6516,  -5.2182,  -8.3926,  -2.1914,  -6.0543,
            #           -2.5473,  -0.8185,   3.7398,  -1.7632,  -4.7178,  -1.0276,   1.3324,
            #           -5.9588,  -3.5195,  -2.0410,  -4.4536,  -1.2245,  -6.2287,  -6.5768,
            #            2.1391,   1.9552,  -5.2685,  -0.2492,  -5.1897,  -3.9089,   2.8292,
            #            3.5677,  -3.9431,  -5.4511,  -1.5507,   2.6308,  -5.8747,   9.6252,
            #           -7.8688,  -2.3988,   2.9660,  -3.4955,  -4.4205,  -5.4727, -10.1396,
            #           -5.9788,  -8.7872,  -4.5330,  -3.5834, -10.5849,  -5.5623,  -4.1344,
            #           -2.9875,  -4.3243,  -8.0216,  -6.9015,  -1.8619,   1.9538,  -8.7561,
            #            0.8259,  -8.6491, -12.3239,  -5.4678,   0.0699,  -6.8360,  -5.7916,
            #          -13.5242,  -7.3065,  -5.3132,   1.5096,  -2.5056,  -9.2860,  -6.7030,
            #           -1.0362,  -4.7022,  -7.8719,  -5.0323,  -6.3051,  -5.7584,   4.9914,
            #           -8.7419,  -0.3761,  -5.5667,  -4.4460,  -6.2864,  -8.4817,  -0.4995,
            #           -7.8316, -10.3253,  -5.4185,  -5.9210,  -8.2310,  -9.2931, -10.4689,
            #            3.6223,  -3.8204,   1.4811,  -3.8428, -10.9786,  -8.9536,  -3.2359,
            #           -4.5767,  -5.7379, -10.0122,  -3.2436]], grad_fn=<AddmmBackward0>)

            # softmax()函数: 将原始的输出值转换为概率分布,使得所有输出值的和等于1,并且每个输出值都在0和1之间。这通常用于多分类问题的输出层,其中每个输出值代表输入样本属于某个类别的概率。
            # dim=1: 这个参数指定了softmax函数应该在哪一维上进行操作。如果dim=1,那么softmax会在每个样本的输出向量上独立进行。
            preds = F.softmax(model(image), dim=1)
            # print(preds)
            # tensor([[4.5676e-09, 1.9586e-08, 4.5517e-06, 3.4957e-07, 1.4618e-08, 7.2114e-06,
            #          1.5150e-07, 5.0523e-06, 2.8462e-05, 2.7160e-03, 1.1066e-05, 5.7654e-07,
            #          2.3093e-05, 2.4458e-04, 1.6667e-07, 1.9110e-06, 8.3819e-06, 7.5091e-07,
            #          1.8965e-05, 1.2725e-07, 8.9841e-08, 5.4793e-04, 4.5592e-04, 3.3241e-07,
            #          5.0294e-05, 3.5965e-07, 1.2946e-06, 1.0926e-03, 2.2866e-03, 1.2511e-06,
            #          2.7692e-07, 1.3686e-05, 8.9595e-04, 1.8130e-07, 9.7702e-01, 2.4683e-08,
            #          5.8611e-06, 1.2528e-03, 1.9573e-06, 7.7617e-07, 2.7102e-07, 2.5479e-09,
            #          1.6337e-07, 9.8515e-09, 6.9359e-07, 1.7927e-06, 1.6322e-09, 2.4779e-07,
            #          1.0332e-06, 3.2532e-06, 8.5457e-07, 2.1184e-08, 6.4931e-08, 1.0026e-05,
            #          4.5530e-04, 1.0163e-08, 1.4738e-04, 1.1310e-08, 2.8679e-10, 2.7235e-07,
            #          6.9199e-05, 6.9329e-08, 1.9701e-07, 8.6348e-11, 4.3308e-08, 3.1786e-07,
            #          2.9198e-04, 5.2674e-06, 5.9823e-09, 7.9192e-08, 2.2895e-05, 5.8559e-07,
            #          2.4604e-08, 4.2099e-07, 1.1789e-07, 2.0366e-07, 9.4944e-03, 1.0308e-08,
            #          4.4301e-05, 2.4670e-07, 7.5665e-07, 1.2012e-07, 1.3372e-08, 3.9158e-05,
            #          2.5616e-08, 2.1161e-09, 2.8611e-07, 1.7309e-07, 1.7182e-08, 5.9405e-09,
            #          1.8331e-09, 2.4148e-03, 1.4144e-06, 2.8378e-04, 1.3831e-06, 1.1011e-09,
            #          8.3414e-09, 2.5375e-06, 6.6394e-07, 2.0787e-07, 2.8941e-09, 2.5182e-06]],
            #        grad_fn=<SoftmaxBackward0>)

            # torch.topk(): 返回张量中沿指定维度dim的前k个最大元素。
            # k=3,找到概率最大的三个
            results = torch.topk(preds.cpu().data, k=3, dim=1)
            # print(results)
            # torch.return_types.topk(
            # values=tensor([[0.9770, 0.0095, 0.0027]]),
            # indices=tensor([[34, 76,  9]]))
            results = (results[0].cpu().numpy(), results[1].cpu().numpy())
            # print(results)
            # (array([[0.9770208 , 0.0094944 , 0.00271605]], dtype=float32), array([[34, 76,  9]], dtype=int64))

            #将data字典增加一个key,value,其中value为list格式
            data['predictions'] = list()

            # Loop over the results and add them to the list of returned predictions
            for prob, label in zip(results[0][0], results[1][0]):
                # print(prob, label)
                # 0.9770208 34
                # 0.009494401 76
                # 0.0027160475 9

                #label_name = idx2label[str(label)]
                r = {"label": str(label), "probability": float(prob)}
                #将预测结果添加至data字典
                data['predictions'].append(r)

            # Indicate that the request was a success.
            data["success"] = True
    # 将最终结果以json格式文件传出
    return flask.jsonify(data)

"""
test_json = {
                "status_code": 200,
                "success": {
                            "message": "image uploaded",
                            "code": 200
                        },
                "video":{
                    "video_name":opt['source'].split('/')[-1],
                    "video_path":opt['source'],
                    "description":"1",
                    "length": str(hour)+','+str(minute)+','+str(round(second,4)),
                    "model_object_completed":model_flag
                    }
                    "status_txt": "OK"
                    }
                    response = requests.post(
                        'http://xxx.xxx.xxx.xxx:8090/api/ObjectToKafka/',,
                        data={'json': str(test_json)})
"""

if __name__ == '__main__':
    print("Loading PyTorch model and Flask starting server ...")
    print("Please wait until server has fully started")
    #先加载模型
    load_model()
    #再开启服务
    app.run(port='5012')

三、运行结果

1、在终端运行flask_server.py使模型处于加载状态

Terminal运行flask_server.py

2、运行flask_predict.py导入数据,得到模型检测输出

客户端展示结果

3、查看终端连接结果

200代表连接成功
连接成功
500代表连接失败
连接失败

  • 30
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将FlaskPyTorch目标检测模型部署为Web服务,可以按照以下步骤进行操作: 1. 准备环境:确保已安装FlaskPyTorch和其他必要的依赖库。 2. 构建Web应用:创建Python脚本或包含Flask应用的目录结构。在Flask应用中,定义一个路由(route)用于接收图像文件或URL,并将其传递给目标检测模型。 3. 加载模型和预处理:使用PyTorch加载预训练的目标检测模型,并进行必要的预处理操作,例如图像缩放和归一化。 4. 目标检测推理:将输入图像传递给目标检测模型进行推理。根据模型输出的结果,提取目标框的位置、类别和置信度等信息。 5. 可视化结果:根据推理结果,在原始图像上绘制检测到的目标框和类别,并将结果返回给用户。 6. 部署与测试:在本地环境中运行Flask应用,并通过浏览器或其他HTTP工具发送图像或URL请求进行测试。可以使用前端技术(如HTML、CSS和JavaScript)美化界面和实现用户交互。 7. 部署到服务器:将Flask应用部署到云服务器或虚拟机中,确保服务器具有足够的计算资源和网络带宽来支持多个并发请求。 8. 性能优化:根据实际需求,可以优化目标检测模型的推理速度,例如使用FP16精度、模型剪枝或量化等技术。 9. 安全性考虑:在处理用户上传的图像或URL时,确保实施适当的安全性措施,例如输入验证和图像过滤,以防止恶意程序或内容的传输。 通过以上步骤,就可以成功将PyTorch目标检测模型部署为一个可访问的Web服务。用户可以使用该服务上传图像或提供URL,查看模型对该图像中目标的检测结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值