Pyinstaller打包部署在Win2008上的Bug排查之路

1.前言

python项目的部署工作基本是属于算法的最后阶段,同样也是最容易出现问题的阶段,毕竟IDE中的运行甚至debug都是可以直接给出问题,再加上开发机器的版本较新,也很少会出现各种各样的dll系统问题。win和linux部署相比,linux由于其系统相对较为简单,部署问题较少,但windows的部署所面临的bug则千奇百怪,尤其是较为老的服务器版本。

本次问题主要是算法库版本与windows服务器不兼容导致的,开发机使用了windows11,并且算法库均为最新版本;测试人员不够专业,没有使用与生产环境相同的测试环境;直到上线前期,不兼容问题出现,搜集了各类资料,最终定位解决。

2.系统环境信息

硬件环境
  • 处理器 12th Gen Intel® Core™ i5-12500H 3.10 GHz
  • 机带 RAM 32.0 GB (31.7 GB 可用)
  • 设备 ID B3E450C9-FC4F-4934-9ADC-C643A1484672
  • 产品 ID 00342-30616-35677-AAOEM
  • 系统类型 64 位操作系统, 基于 x64 的处理器
系统信息
  • 版本 Windows 11 家庭中文版
  • 版本号 24H2
  • 安装日期 ‎2024/‎12/‎27
  • 操作系统版本 26100.2605
  • 体验 Windows 功能体验包 1000.26100.36.0
生产服务器系统
  • 版本win2008 R2
开发阶段算法库版本
算法库 版本
pandas 2.2.0
numpy 1.26.4
lightgbm 4.4.0
pyinstaller 6.9.0
torch 2.3.0

4.Bug排查过程

1.问题发生--dll丢失

打包程序部署后,在win2008服务器上,系统报错丢失api-ms-win-core-path-l1-1-0.dll, 这Microsoft Windows 操作系统中的一个动态链接库(DLL)文件,主要与文件路径操作和路径管理相关。它是 Windows API(应用程序编程接口)的一部分,提供了一些核心功能,帮助 Windows 应用程序在操作系统中进行路径相关的操作。

2.dll丢失问题解决

DLL下载网站上下载这个库,分别放入C:\Windows\System32和C:\Windows\SysWOW64目录下,问题解决。此时运行框能够正常显示出来,表明dll确实问题已经解决,问题到这,都算是很简单的事件。

3.模型调用报错

紧接着,需要进行接口测试,传参后,程序报错,内容大致如下:

复制代码
0SError:[winError193]x1 不是有效的 Win32 应用程序。
Failed to load \lightghm\win\lib.Lightgbm.dll'. Most likely this dynlib/dll was not found when the applicat ion wfrozen

4.Pyinstaller降版本

最显眼的winError193故障报错,第一时间对此进行了排查(被这个故障报错干扰了判断),很多内容答案显示可能在 64 位 Windows 系统上尝试运行一个 32 位应用程序,或者反过来。比如,尝试用 32 位的应用程序加载 64 位的动态链接库(DLL),或者使用 64 位的程序加载 32 位的 DLL,会出现这个错误。

针对这个问题,重新下载了dll文件,并且使用了dll depends工具进行了相应排查,并没有发现任何问题。怀疑是Pyinstaller问题,将其降级到3.0+版本,并且重新进行了多次打包,问题没有解决。

5.lightgbm问题排查

由于winError193故障并没有找到有效的解决方案,开始怀疑是lightgbm的版本问题导致,并对此进行了相应的搜索,发现存在此类相关可能,经搜索,lightgbm可能不完全支持 Windows 2008 及其早期版本,这将会导致兼容性问题。

6.lightgbm降版本

经过搜集,针对windows2008的支持情况,选择了2.2.3版本的lightgbm,为了快速验证,构建了一个小项目进行打包测试,使用了lightgbm和torch,代码如下:

python 复制代码
import numpy as np
import lightgbm as lgb
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.metrics import accuracy_score

# 1. 使用 LightGBM 进行分类任务
# 创建一个简单的二分类数据集
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)

# 划分训练集和测试集
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# 将数据转换为 LightGBM Dataset 格式
train_data = lgb.Dataset(X_train, label=y_train)
test_data = lgb.Dataset(X_test, label=y_test, reference=train_data)

# 设置 LightGBM 超参数
params = {
    'objective': 'binary',
    'metric': 'binary_error',
    'boosting_type': 'gbdt',
    'num_leaves': 31,
    'learning_rate': 0.05,
    'feature_fraction': 0.9,
}

# 训练 LightGBM 模型
lgb_model = lgb.train(params, train_data, valid_sets=[test_data], num_boost_round=100)

# 使用 LightGBM 模型进行预测
y_pred_lgb = lgb_model.predict(X_test)
y_pred_lgb = (y_pred_lgb > 0.5).astype(int)

# 评估 LightGBM 模型的准确度
accuracy_lgb = accuracy_score(y_test, y_pred_lgb)
print(f"LightGBM 分类模型准确率: {accuracy_lgb:.4f}")

# 2. 使用 PyTorch 构建神经网络进行回归任务
# 创建一个简单的回归数据集
X_reg, y_reg = make_classification(n_samples=1000, n_features=20, n_informative=5, n_classes=2, random_state=42)

# 划分训练集和测试集
X_train_reg, X_test_reg, y_train_reg, y_test_reg = train_test_split(X_reg, y_reg, test_size=0.2, random_state=42)

# 将数据转换为 PyTorch Tensor
X_train_tensor = torch.tensor(X_train_reg, dtype=torch.float32)
y_train_tensor = torch.tensor(y_train_reg, dtype=torch.float32).view(-1, 1)
X_test_tensor = torch.tensor(X_test_reg, dtype=torch.float32)
y_test_tensor = torch.tensor(y_test_reg, dtype=torch.float32).view(-1, 1)

# 定义一个简单的神经网络
class SimpleNN(nn.Module):
    def __init__(self):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(20, 64)
        self.fc2 = nn.Linear(64, 32)
        self.fc3 = nn.Linear(32, 1)

    def forward(self, x):
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

# 初始化模型,定义损失函数和优化器
model = SimpleNN()
criterion = nn.MSELoss()  # 由于是回归任务,使用均方误差损失
optimizer = optim.Adam(model.parameters(), lr=0.001)

# 训练神经网络模型
epochs = 100
for epoch in range(epochs):
    model.train()
    optimizer.zero_grad()
    outputs = model(X_train_tensor)
    loss = criterion(outputs, y_train_tensor)
    loss.backward()
    optimizer.step()
    
    if (epoch + 1) % 10 == 0:
        print(f"Epoch [{epoch+1}/{epochs}], Loss: {loss.item():.4f}")

# 使用神经网络模型进行预测
model.eval()
with torch.no_grad():
    y_pred_nn = model(X_test_tensor)

# 计算模型的均方误差
mse = criterion(y_pred_nn, y_test_tensor)
print(f"神经网络回归模型均方误差: {mse.item():.4f}")

打包测试后发现,2.2.3版本的lightgbm能够正常运行在win2008上,说明lightgbm降版本可以解决当前的系统报错问题。

7.问题解决

lightgbm进行降版本,使用2.2.3版本,重新打包后,发到win2008的测试环境中测试,正常运行,正常建模,问题得到解决。

5.总结

1算法库版本与系统兼容性问题

  1. 在项目的部署过程中,算法库版本与生产环境的系统兼容性问题是常见的挑战。特别是在Windows 2008 R2服务器上部署现代算法库时,由于操作系统较旧且不再接收微软的更新,很多新的库和API可能无法正常工作。
  2. 例如,在此次部署中,开发环境中使用了较新的算法库版本(如lightgbm 4.4.0),而在Windows 2008服务器上,这些库可能存在兼容性问题,导致程序运行时出现报错(如dll丢失)。在这种情况下,选择适配服务器环境的较旧版本的算法库(如lightgbm 2.2.3)往往能够解决问题。
  3. 在进行生产环境部署时,确保开发环境与生产环境的一致性,包括操作系统和算法库版本的兼容性,对于顺利部署和避免不必要的技术障碍至关重要。

2.PyInstaller与系统环境的配合

  1. PyInstaller作为一个将Python程序打包为可执行文件的工具,尽管在现代开发环境中表现良好,但在老旧的操作系统上可能会遇到意外的兼容性问题。
  2. 在此次案例中,虽然PyInstaller被用于打包Python程序,但由于系统环境较为陈旧,导致报错(如winError193),这通常是因为32位与64位架构的不兼容所引起的。降级PyInstaller版本(如3.0+版本)并重新打包,未能直接解决问题。通过进一步排查发现,问题的根源在于使用的lightgbm版本与Windows 2008的兼容性。
  3. 在使用PyInstaller打包程序时,除了关注打包本身的设置外,还需要特别考虑目标服务器的操作系统版本及其支持的Python库版本,以确保打包后的程序能够在目标环境中正常运行。
相关推荐
越学不动啦6 小时前
四、Bug篇+用例篇
软件测试·测试用例·bug·软件工程·测试基础
有时间要学习6 小时前
Test——BUG篇
bug·测试
猫猫头有亿点炸2 天前
电脑连不上手机热点会出现的小bug
bug
不想加班的码小牛3 天前
第4期:重构软件测试体系——生成式AI如何让BUG无所遁形
人工智能·重构·bug·集成测试
limanjihe3 天前
PrimeTime生成.lib竟暗藏PG添加Bug
bug
Java手札5 天前
【bug】Cannot connect to already running IDE instance.SocketTimeoutException
ide·bug
妄想出头的工业炼药师5 天前
pcl 1.14.1 vs2022 Eigen::internal::aligned_free bug
bug
小海海不怕困难5 天前
xxljob阻塞处理策略设置为单机串行导致的bug
bug
Littlehero_1215 天前
关于bug总结记录
bug
深度Linux6 天前
告别代码Bug,GDB调试工具详解
linux内核·bug·内核调试