我有一个使用 Apache 运行网站的 Django 应用程序,在后端,我需要运行一个机器学习模型。
我已经使用 pickle 训练并保存了模型,并将其存储在主目录之外的“ml_models”目录中。
在我的目录中,我有 urls.py 指向我调用以运行模型的函数:
path('classify', views.classify),
在 views.py 中,我有函数:
def classify(request):
if request.method == "GET":
str_data = request.GET.get("data")
dataSplit = str_data.split(",")
sendData = dataSplit[4] + "," + dataSplit[5] + "," + dataSplit[6]
data = [[float(x) for x in sendData.split(",")]]
model_path = settings.ML_ROOT + '/my_model.sav'
with open(model_path, 'rb') as f:
model = pickle.load(f)
prediction = float(model.predict(data))
f.close()
r = {"response": str(int(prediction))}
return JsonResponse(r)`
我发送的数据是这样的:
<mysite>/api/classify?data=1,1.2,42.2,12.3,57.84,0.2,29.67,0.95,3
data[0] = device ID, int
data[1] = sensor measurement, float
data[2] = sensor measurement, float
data[3] = sensor measurement, float
data[4] = sensor measurement, float
data[5] = sensor measurement, float
data[6] = sensor measurement, float
data[7] = calculated value, float
data[8] = Project ID, int
数据来自通过蓝牙连接到传感器套件的移动应用程序(Android 和 iPhone)。这些值是来自我用来记录不断变化的传感器测量值并从某些值中获得预测的硬件的数字数据。
发生的事情是: 当我第一次打开网站时,它会正常加载。 如果我调用预测,它将工作一次。 任何后续调用,服务器就像它被冻结一样,我最终得到一个“网关超时”。
理想情况下,我想每秒做一次预测。 我试过将它放慢到每 60 秒执行一次并得到相同的结果。
我已经使用 POST 和 GET 请求对其进行了测试,并且每个请求的行为都相同。
我发现如果我在进行预测调用之前访问网站上的任何页面,它永远不会冻结,也就是说,如果我打开网站,进行预测,然后刷新我所在的页面或者只是转到另一个页面页面,然后再做一个预测,很好。 只要我在每次预测调用之前在网站上做一些事情,它就会起作用。 如果我在没有访问网站上任何页面的情况下启动网络服务器并尝试从应用程序或 Postman 进行预测,它将冻结。为了做出成功的预测,我必须在网站上做一些事情,任何事情,我访问哪个页面似乎并不重要。
我使用 Postman 通过发送数据和读取响应来测试它,这是一回事,如果我在每次预测之间在网站上做一些事情,那很好,如果我尝试在不先与网站交互的情况下运行预测,它会冻结.
我输入了一些语句来写入服务器上的静态文件,发现它在尝试加载模型时失败了:
model = pickle.load(f)
我尝试将 pickle.load 函数移动到 apps.py,但所做的一切都是由于相同的 pickle.load 函数导致网站无法加载。
我尝试将 pickle.load 放入 try/except 中,但仍然得到相同的结果。
网络服务器显示 httpd 是好的:
systemctl status httpd
● httpd.service - The Apache HTTP Server
Loaded: loaded (/usr/lib/systemd/system/httpd.service; enabled; vendor preset: disabled)
Active: active (running) since Thu 2023-05-11 08:36:26 PDT; 4min 57s ago
Docs: man:httpd.service(8)
Process: 11960 ExecReload=/usr/sbin/httpd $OPTIONS -k graceful (code=exited, status=0/SUCCESS)
Main PID: 117820 (httpd)
Status: "Total requests: 5; Idle/Busy workers 99/1;Requests/sec: 0.0173; Bytes served/sec: 74 B/sec"
Tasks: 297 (limit: 23656)
Memory: 90.4M
CGroup: /system.slice/httpd.service
├─117820 /usr/sbin/httpd -DFOREGROUND
├─117822 /usr/sbin/httpd -DFOREGROUND
├─117823 /usr/sbin/httpd -DFOREGROUND
├─117826 /usr/sbin/httpd -DFOREGROUND
├─117827 /usr/sbin/httpd -DFOREGROUND
├─117828 /usr/sbin/httpd -DFOREGROUND
└─118100 /usr/sbin/httpd -DFOREGROUND
May 11 08:36:25 <mysite> systemd[1]: httpd.service: Succeeded.
May 11 08:36:25 <mysite> systemd[1]: Stopped The Apache HTTP Server.
May 11 08:36:25 <mysite> systemd[1]: Starting The Apache HTTP Server...
May 11 08:36:26 <mysite> httpd[117820]: [Thu May 11 08:36:26.041188 2023] [so:warn] [pid 117820:tid 140091425315136] AH01574: module w>
May 11 08:36:26 <mysite> systemd[1]: Started The Apache HTTP Server.
May 11 08:36:26 <mysite> httpd[117820]: Server configured, listening on: port <port>, port <port>
另一个有趣的细节是,有时,由于不明原因,它会自发地工作。 两天前,在我尝试修改发送给函数的数据后,(我将值 [1]、[2]、[3]、[7] 替换为 0 而不是实际测量值,因为它们不需要这个预测),它完美地工作了一个多小时。第二天,当我尝试运行它时,没有更改代码、没有更改服务器、没有更改应用程序,它又回到了冻结状态。在它刚刚开始工作时,我所做的唯一更改是对 views.py 中的分类函数。在它开始工作后,我对应用程序进行了一些更改,它继续没有问题地工作,直到我停下来。
我尝试省略所有未专门用于预测的数据并得到相同的结果。问题似乎特别在于加载模型。
还有,网站卡顿后,如果我等~5分钟,就解冻了,也就是可以访问网站了。如果我尝试在不在网站上做任何事情的情况下做出另一个预测,它仍然会冻结。无论我尝试什么,只有先在网站上做一些事情,我才能获得成功的预测。