大模型的云端部署:flask部署模型简单案例

模型部署有多种方式:

我们之前完成了本地部署的两种方法:包括ollama的本地部署和transforms库调用下载到本地的模型文件进行对话甚至调参数等。

今天我们通过flask库进行简单的模型云端部署。

一、必备计算机网络基础

Flask服务端与客户端的通信依赖很多计算机网络的知识如:IP、端口等基础网络组件,理清这些概念,能快速解决服务端和客户端交互很有帮助。

1. 局域网、路由器与WiFi的核心区别

  • 路由器:局域网的核心管理者,相当于"小区物业",负责分配内网IP、转发设备间流量、对接公网,是设备互通的核心。

  • 局域网:由路由器管理的私有网络,相当于"整个小区",同一局域网内的设备可直接通信,无需经过公网。

  • WiFi:仅为"无线接入局域网"的技术,相当于"小区无线门禁",替代网线实现设备无线联网,本身不是网络。

关键结论:同一WiFi下的设备属于同一局域网,本质是"同一路由器管理";哪怕电脑插网线、手机连WiFi,只要连同一个路由器,即可实现内网通信。

2. 内网IP与端口:服务访问的"精准门牌号"

局域网内设备通信,需通过「内网IP+端口」定位服务,两者缺一不可:

  • 内网IP:由路由器DHCP功能分配,同一局域网内唯一,常见段为192.168.x.x/10.x.x.x,仅路由器可识别。核心区别:127.0.0.1(回环地址,仅本机可访问);0.0.0.0(监听所有网络接口,允许局域网设备访问)。

  • 端口:区分电脑上不同服务的"窗口号"(0-65535),如Flask服务用5012端口,避免与微信、浏览器等服务冲突,客户端需与服务端端口完全一致。

  • 内网IP用来定位到内网的设备如手机,端口定位到手机中具体的服务如微信。

3. HTTP协议:客户端与服务端的"沟通规则"

Flask通信基于HTTP协议,核心规则适配模型部署场景:

  • 请求方法:POST适合传输图片等二进制大文件(模型部署首选),GET仅适合少量文本参数。

  • 数据格式:客户端传图片用multipart/form-data格式,服务端返回结果用JSON格式(跨语言易解析)。

二、Flask框架核心认知

Flask是轻量级Python Web框架,核心优势是简洁、可扩展,无需复杂配置即可快速搭建Web服务,是模型部署的首选框架,核心逻辑适配模型预测场景。

python流行的web框架对比:

Django是比较专业的框架,有专门的前端岗位,Pyramid基本没人用了,我们ai应用开发岗位使用flask框架是最多的,flask对我们的岗位来说足够了。

1. 核心定位与优势

  • 轻量级:核心代码少,无强制依赖,新手可快速上手,按需扩展功能。

  • 路由驱动:核心机制是「URL路径与处理函数映射」,客户端访问指定URL,Flask自动调用对应函数处理请求。

  • WSGI兼容:可监听指定IP和端口,支持局域网/公网HTTP请求,适配模型部署的服务需求。

2. 本案例核心逻辑

服务端:启动服务(绑定IP+端口)→ 监听HTTP请求 → 解析图片参数 → 调用模型预测 → 构造JSON响应 → 返回结果。

客户端:读取图片(二进制)→ 构造POST请求 → 发送到服务端地址 → 解析JSON响应 → 处理预测结果。

三、案例:flask部署模型实现内网设备访问服务

基于ResNet18模型,实现"客户端上传图片→服务端预测→返回结果"的完整流程,代码可直接复用,重点标注关键细节和避坑点。

1. 服务端代码全解析

服务端负责加载模型、监听请求、处理图片、返回结果,完整代码如下,关键细节标注注释:

python 复制代码
import io
import flask
import torch
import torch.nn.functional as F
from PIL import Image
from torch import nn
from torchvision import transforms, models

# 初始化Flask应用,__name__用于定位静态/模板文件
app = flask.Flask(__name__)

# 全局变量:模型实例+GPU开关(新手先关闭,用CPU运行)
model = None
use_gpu = False

def load_model():
    """加载预训练模型,可替换为自己的模型"""
    global model
    # 加载ResNet18骨干网络,修改全连接层适配102类任务(按需调整)
    model = models.resnet18()
    num_ftrs = model.fc.in_features
    model.fc = nn.Sequential(nn.Linear(num_ftrs, 102))
    
    # 加载训练好的权重文件(确保best.pth与代码同目录)
    checkpoint = torch.load('best.pth', map_location='cpu')  # 强制CPU加载,避免GPU兼容问题
    model.load_state_dict(checkpoint['state_dict'])
    model.eval()  # 设为评估模式,禁止Dropout/BatchNorm训练行为
    
    # 可选:GPU加速(需配置CUDA)
    if use_gpu:
        model.cuda()

def prepare_image(image, target_size):
    """图片预处理,适配ResNet18输入格式(224x224、RGB、标准化)"""
    if image.mode != 'RGB':
        image = image.convert('RGB')  # 统一图片格式
    # 缩放→转Tensor→标准化→增加Batch维度
    image = transforms.Resize(target_size)(image)
    image = transforms.ToTensor()(image)
    image = transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])(image)
    image = image[None]  # 补Batch维度(模型要求输入[batch, channel, h, w])
    if use_gpu:
        image = image.cuda()
    return image

# 预测接口,仅允许POST请求(适合传图片)
@app.route("/predict", methods=["POST"])
def predict():
    data = {"success": False}  # 初始化响应状态
    try:
        if flask.request.method == 'POST' and flask.request.files.get("image"):
            # 读取客户端上传的图片二进制数据,内存中解析(无需保存本地)
            image_bytes = flask.request.files["image"].read()
            image = Image.open(io.BytesIO(image_bytes))
            
            # 图片预处理+模型预测(关闭梯度计算,提升速度)
            image = prepare_image(image, target_size=(224, 224))
            with torch.no_grad():
                preds = F.softmax(model(image), dim=1)  # 计算类别概率
                results = torch.topk(preds.cpu().data, k=3, dim=1)  # 取Top3结果
            
            # 转换结果格式,构造JSON响应
            results = (results[0].cpu().numpy(), results[1].cpu().numpy())
            data['predictions'] = []
            for prob, label in zip(results[0][0], results[1][0]):
                data['predictions'].append({"label": str(label), "probability": float(prob)})
            data["success"] = True  # 标记请求成功
    except Exception as e:
        data["error"] = str(e)  # 捕获异常,避免服务崩溃
    return flask.jsonify(data)  # 返回JSON格式结果

if __name__ == '__main__':
    print("Loading PyTorch model and Flask starting server ...")
    load_model()  # 启动前先加载模型(耗时操作)
    # 启动Flask服务
    app.run(host='0.0.0.0', port=5012, debug=False, threaded=True)
    

3. 客户端代码全解析

客户端负责上传图片、接收结果,无需复杂逻辑,完整代码如下:

python 复制代码
import requests

# 服务端地址(核心:替换为服务端实际内网IP+端口,与服务端一致)
flask_url = 'http://192.168.31.168:5012/predict'

def predict_result(image_path):
    # 二进制读取图片(rb模式,保留图片完整信息,不可用r模式)
    image = open(image_path, 'rb').read()
    # 构造请求数据(key='image'需与服务端request.files.get("image")一致)
    payload = {'image': image}
    
    # 发送POST请求,解析JSON响应
    r = requests.post(flask_url, files=payload).json()
    
    # 处理返回结果
    if r['success']:
        for (i, result) in enumerate(r['predictions']):
            print('{}.预测类别为{}:的概率: {}'.format(i + 1, result['label'], result['probability']))
    else:
        print('Request failed: {}'.format(r.get('error', '未知错误')))

if __name__ == '__main__':
    # 传入测试图片路径(确保图片与客户端代码同目录)
    predict_result('1ac045e892813b1c03457caca572862f.jpg')
    

4. 完整运行步骤

  1. 准备文件:服务端代码(server.py)、模型权重(best.pth)、客户端代码(client.py)、测试图片,确保服务端目录包含server.py和best.pth。

  2. 启动服务端:运行server.py,正常日志会显示"Running on http://127.0.0.1:5012"和"http://192.168.x.x:5012"(内网IP)。

  3. 配置客户端:修改client.py中的flask_url,替换为服务端日志显示的内网IP+端口。

  4. 运行客户端:运行client.py,正常输出Top3预测类别及概率,即部署成功。

运行结果:

注释:app.run中host的设置:

127.0.0.1(回环地址,仅本机可访问);0.0.0.0(监听所有网络接口,允许局域网设备访问)

我们这里设置为第二种,因此内网设备都可以访问。

总结

本文从网络原理出发,结合ResNet18模型实战,完整讲解了Flask模型部署的核心逻辑:网络基础是部署的前提,Flask框架是服务搭建的核心,服务端与客户端的配合是实现功能的关键。掌握本文内容,可轻松实现任意PyTorch模型的Flask部署,避开常见连接、预测问题。

怎么进行公网访问服务端呢?

番外篇:跨局域网访问本地Flask模型(公网访问)

一、核心原理补充

本地电脑的192.168.x.x属于「内网私有IP」,仅在路由器管理的局域网内有效,外网设备无法直接识别。要实现跨网访问,核心是"将本地服务暴露到公网",本质是通过中间介质(内网穿透工具、路由器、云服务器),将外网请求转发到本地Flask服务。

二、3种方案

方案1:内网穿透

无需公网IP、无需修改路由器设置、无需购买服务器,通过免费内网穿透工具,即可快速将本地服务暴露到公网,适合测试、临时分享。

核心原理

内网穿透工具自带公网服务器,相当于"中介":外网设备发送请求到工具的公网地址,工具再将请求转发到本地Flask服务,全程无需手动配置复杂规则。

推荐工具与操作步骤(以cpolar为例,中文友好、Windows适配)
  1. 下载安装:访问cpolar官网,下载Windows版,一路下一步完成安装(无需复杂配置)。

  2. 启动本地Flask服务:确保服务正常运行,配置不变(host='0.0.0.0',port=5012)。

  3. 启动穿透:打开cpolar命令行,输入命令 cpolar http 5012,回车后会自动生成公网地址(如:https://xxxx.cpolar.io)。

  4. 外网访问:将客户端代码中的flask_url替换为cpolar生成的公网地址,例如:flask_url = 'https://xxxx.cpolar.io/predict',无论对方在哪、用什么网络,均可正常访问。

补充:免费版cpolar公网地址会每24小时更换,若需固定地址,可升级基础版;除cpolar外,ngrok(国际通用)、花生壳(国产老牌)也可实现相同功能,操作逻辑一致。

方案2:路由器端口映射/公网映射(有公网IP可用)

若家庭/公司宽带拥有公网IP(可拨打运营商客服查询,如电信、联通部分宽带可申请),可通过路由器端口映射,将本地服务直接暴露到公网,无需依赖第三方工具。

操作步骤
  1. 查询公网IP:百度搜索"我的公网IP",记录查询到的IP(如:123.xxx.xxx.xxx)。

  2. 登录路由器后台:在浏览器输入路由器管理地址(通常为192.168.1.1或192.168.0.1,路由器背面可查),输入账号密码登录。

  3. 配置端口映射:找到「转发规则」→「虚拟服务器」,添加映射规则:外部端口设为5012,内部IP设为本地电脑的内网IP(如192.168.31.168),内部端口设为5012,保存配置。

  4. 外网访问:客户端代码中flask_url改为 http://公网IP:5012/predict,即可实现跨网访问。

缺点:家庭宽带公网IP多为"动态IP",重启光猫后会变化;部分运营商会屏蔽80、443等常用端口,需更换端口(如5012、8080)。

方案3:云服务器部署(正式使用首选)

若需长期稳定提供服务(如分享给多人使用、用于小型项目),最推荐将模型部署到云服务器,这也是工业界常用的正式部署方案。

核心步骤
  1. 购买云服务器:选择阿里云、腾讯云等平台的轻量应用服务器(新手推荐,几十元/月),操作系统选择CentOS或Ubuntu。

  2. 配置服务器:登录服务器,安装Python环境及核心依赖(与本地环境一致),开放5012端口(在服务器安全组中添加规则)。

  3. 部署服务:将本地服务端代码(server.py)、模型权重(best.pth)上传到服务器,启动Flask服务(配置host='0.0.0.0',port=5012)。

  4. 公网访问:客户端代码中flask_url改为 http://服务器公网IP:5012/predict,即可稳定访问,无需担心IP变化。

相关推荐
橘子133 小时前
NAT,代理服务,内网穿透
网络·智能路由器
眼镜哥(with glasses)15 小时前
网络技术三级考试综合题笔记整理(第二题、第三题)
网络·笔记·智能路由器
Du_chong_huan18 小时前
3.4 路由器的附加功能
网络·计算机网络·智能路由器
tang7778919 小时前
哪些行业用动态代理ip?哪些行业用静态代理IP?怎样区分动态ip和静态ip?(互联网人必码·实用长文)
大数据·网络·爬虫·python·网络协议·tcp/ip·智能路由器
线束线缆组件品替网19 小时前
Adam Tech NPC-6-003-BU-BB网线组件详解
网络·数码相机·智能手机·智能路由器·电脑·电视盒子·智能电视
Du_chong_huan1 天前
3.3 路由器的包转发操作
网络·智能路由器
BugShare2 天前
怎么一步步实现小米智能家居之玄关篇
网络·智能路由器·智能家居
深念Y3 天前
腾达路由器无线中继模式:WISP与Client+AP什么意思
网络·wifi·智能路由器·路由器·ssid·腾达·无线中继
袁小皮皮不皮3 天前
【HCIA】第一章网络基础
运维·服务器·网络·网络协议·智能路由器