使用 SKLearn 的 Django 项目中的 Heroku 内存配额大大超出
Heroku Memory quota vastly exceeded in Django Project using SKLearn
我已经在 Heroku 上部署了一个 Django 应用程序,目的是让受信任的已知内部用户上传 CSV 文件,单击 "Run",在幕后,Django 应用程序:
- 加载保存的 sklearn 管道
.pkl
模型(假设大小为 120 MB)
- 使用Pandas
读取用户的 CSV 数据
- 使用 CSV 数据作为输入对模型调用
predict
- 使用 Django 存储将文件输出到 S3
这适用于小型 CSV 文件,但如果用户上传大型 CSV 文件,则会导致 Memory quota vastly exceeded
...并且较大的 CSV 文件会增加内存消耗是有道理的。
我不确定在哪里调整。 我想知道是否有人在部署 sklearn 模型时遇到过类似的情况,他们是如何 "solved" 的?
我的想法是:
- 识别内存泄漏?甚至不知道从哪里开始。 Django
DEBUG
设置为 False
。
- 更改我的 celery 任务以改为分块处理输入的文件?
- 用 joblib 以某种方式制作一个较小的 SKLearn 管道文件(我已经使用 compress=1)?
- 增加 Heroku 测功机?工人?
我的 django models.py 看起来像这样:
from django.db import models
from django.urls import reverse
class MLModel(models.Model):
name = models.CharField(max_length=80)
file = models.FileField(upload_to="models/")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Upload(models.Model):
name = models.CharField(max_length=100)
mlmodel = models.ForeignKey(MLModel, on_delete=models.CASCADE)
file = models.FileField(upload_to='data/')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('edit', kwargs={'pk': self.pk})
我的 celery 任务是这样的:
@shared_task
def piparoo(id):
instance = Upload.objects.get(id=id)
model = joblib.load(instance.mlmodel.file.storage.open(instance.mlmodel.file.name))
data = pd.read_csv(instance.file)
data['Predicted'] = model.predict(data)
buffer = StringIO()
data.to_csv(buffer, index=False)
content = buffer.getvalue().encode('utf-8')
default_storage.save('output/results_{}.csv'.format(id), ContentFile(content))
Heroku 日志:
2018-04-12T06:12:53.592922+00:00 app[worker.1]: [2018-04-12 06:12:53,592: INFO/MainProcess] Received task: predictions.tasks.piparoo[f1ca09e1-6bba-4115-8989-04bb32d4f08e]
2018-04-12T06:12:53.737378+00:00 heroku[router]: at=info method=GET path="/predict/" host=tdmpredict.herokuapp.com request_id=ffad9785-5cb6-4e3c-a87c-94cbca47d109 fwd="24.16.35.31" dyno=web.1 connect=0
ms service=33ms status=200 bytes=6347 protocol=https
2018-04-12T06:13:08.054486+00:00 heroku[worker.1]: Error R14 (Memory quota exceeded)
2018-04-12T06:13:08.054399+00:00 heroku[worker.1]: Process running mem=572M(111.9%)
2018-04-12T06:13:28.026973+00:00 heroku[worker.1]: Error R15 (Memory quota vastly exceeded)
2018-04-12T06:13:28.026765+00:00 heroku[worker.1]: Process running mem=1075M(210.1%)
2018-04-12T06:13:28.026973+00:00 heroku[worker.1]: Stopping process with SIGKILL
2018-04-12T06:13:28.187650+00:00 heroku[worker.1]: Process exited with status 137
2018-04-12T06:13:28.306221+00:00 heroku[worker.1]: State changed from up to crashed
解决了我的问题的解决方案(以常识方式)。
不是一次将用户的 CSV 文件读入内存,而是使用 Pandas chunksize
参数分块处理它,然后在最后将数据帧列表连接成一个。我还删除了模型 (120 MB) 以尝试为将来的进程释放内存。
我的 celery 任务现在看起来像这样:
@shared_task
def piparoo(id):
instance = Upload.objects.get(id=id)
model = joblib.load(instance.mlmodel.file.storage.open(instance.mlmodel.file.name))
final = []
for chunk in pd.read_csv(instance.file, chunksize=5000):
chunk['Predicted'] = model.predict(chunk)
final.append(chunk)
del model
final = pd.concat(final)
buffer = StringIO()
final.to_csv(buffer, index=False)
content = buffer.getvalue().encode('utf-8')
default_storage.save('output/results_{}.csv'.format(id), ContentFile(content))
我已经在 Heroku 上部署了一个 Django 应用程序,目的是让受信任的已知内部用户上传 CSV 文件,单击 "Run",在幕后,Django 应用程序:
- 加载保存的 sklearn 管道
.pkl
模型(假设大小为 120 MB) - 使用Pandas 读取用户的 CSV 数据
- 使用 CSV 数据作为输入对模型调用
predict
- 使用 Django 存储将文件输出到 S3
这适用于小型 CSV 文件,但如果用户上传大型 CSV 文件,则会导致 Memory quota vastly exceeded
...并且较大的 CSV 文件会增加内存消耗是有道理的。
我不确定在哪里调整。 我想知道是否有人在部署 sklearn 模型时遇到过类似的情况,他们是如何 "solved" 的?
我的想法是:
- 识别内存泄漏?甚至不知道从哪里开始。 Django
DEBUG
设置为False
。 - 更改我的 celery 任务以改为分块处理输入的文件?
- 用 joblib 以某种方式制作一个较小的 SKLearn 管道文件(我已经使用 compress=1)?
- 增加 Heroku 测功机?工人?
我的 django models.py 看起来像这样:
from django.db import models
from django.urls import reverse
class MLModel(models.Model):
name = models.CharField(max_length=80)
file = models.FileField(upload_to="models/")
created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
class Upload(models.Model):
name = models.CharField(max_length=100)
mlmodel = models.ForeignKey(MLModel, on_delete=models.CASCADE)
file = models.FileField(upload_to='data/')
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('edit', kwargs={'pk': self.pk})
我的 celery 任务是这样的:
@shared_task
def piparoo(id):
instance = Upload.objects.get(id=id)
model = joblib.load(instance.mlmodel.file.storage.open(instance.mlmodel.file.name))
data = pd.read_csv(instance.file)
data['Predicted'] = model.predict(data)
buffer = StringIO()
data.to_csv(buffer, index=False)
content = buffer.getvalue().encode('utf-8')
default_storage.save('output/results_{}.csv'.format(id), ContentFile(content))
Heroku 日志:
2018-04-12T06:12:53.592922+00:00 app[worker.1]: [2018-04-12 06:12:53,592: INFO/MainProcess] Received task: predictions.tasks.piparoo[f1ca09e1-6bba-4115-8989-04bb32d4f08e]
2018-04-12T06:12:53.737378+00:00 heroku[router]: at=info method=GET path="/predict/" host=tdmpredict.herokuapp.com request_id=ffad9785-5cb6-4e3c-a87c-94cbca47d109 fwd="24.16.35.31" dyno=web.1 connect=0
ms service=33ms status=200 bytes=6347 protocol=https
2018-04-12T06:13:08.054486+00:00 heroku[worker.1]: Error R14 (Memory quota exceeded)
2018-04-12T06:13:08.054399+00:00 heroku[worker.1]: Process running mem=572M(111.9%)
2018-04-12T06:13:28.026973+00:00 heroku[worker.1]: Error R15 (Memory quota vastly exceeded)
2018-04-12T06:13:28.026765+00:00 heroku[worker.1]: Process running mem=1075M(210.1%)
2018-04-12T06:13:28.026973+00:00 heroku[worker.1]: Stopping process with SIGKILL
2018-04-12T06:13:28.187650+00:00 heroku[worker.1]: Process exited with status 137
2018-04-12T06:13:28.306221+00:00 heroku[worker.1]: State changed from up to crashed
解决了我的问题的解决方案(以常识方式)。
不是一次将用户的 CSV 文件读入内存,而是使用 Pandas chunksize
参数分块处理它,然后在最后将数据帧列表连接成一个。我还删除了模型 (120 MB) 以尝试为将来的进程释放内存。
我的 celery 任务现在看起来像这样:
@shared_task
def piparoo(id):
instance = Upload.objects.get(id=id)
model = joblib.load(instance.mlmodel.file.storage.open(instance.mlmodel.file.name))
final = []
for chunk in pd.read_csv(instance.file, chunksize=5000):
chunk['Predicted'] = model.predict(chunk)
final.append(chunk)
del model
final = pd.concat(final)
buffer = StringIO()
final.to_csv(buffer, index=False)
content = buffer.getvalue().encode('utf-8')
default_storage.save('output/results_{}.csv'.format(id), ContentFile(content))