You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
ML-For-Beginners/translations/zh/3-Web-App/1-Web-App/README.md

359 lines
15 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

<!--
CO_OP_TRANSLATOR_METADATA:
{
"original_hash": "e0b75f73e4a90d45181dc5581fe2ef5c",
"translation_date": "2025-09-05T09:06:07+00:00",
"source_file": "3-Web-App/1-Web-App/README.md",
"language_code": "zh"
}
-->
# 构建一个使用机器学习模型的网页应用
在本课中你将使用一个非常特别的数据集来训练一个机器学习模型_过去一个世纪的UFO目击事件_数据来源于NUFORC的数据库。
你将学习:
- 如何对训练好的模型进行“pickle”处理
- 如何在Flask应用中使用该模型
我们将继续使用notebook来清理数据并训练模型但你可以更进一步尝试在“真实世界”中使用模型也就是在一个网页应用中。
为此你需要使用Flask构建一个网页应用。
## [课前小测验](https://ff-quizzes.netlify.app/en/ml/)
## 构建一个应用
有多种方法可以构建网页应用来使用机器学习模型。你的网页架构可能会影响模型的训练方式。想象一下,你正在一个企业中工作,数据科学团队已经训练了一个模型,他们希望你在应用中使用它。
### 需要考虑的问题
你需要问自己许多问题:
- **这是一个网页应用还是一个移动应用?** 如果你正在构建一个移动应用,或者需要在物联网环境中使用模型,你可以使用 [TensorFlow Lite](https://www.tensorflow.org/lite/) 并在Android或iOS应用中使用该模型。
- **模型将存储在哪里?** 是在云端还是本地?
- **是否需要离线支持?** 应用是否需要在离线状态下运行?
- **训练模型使用了什么技术?** 所选技术可能会影响你需要使用的工具。
- **使用TensorFlow。** 如果你使用TensorFlow训练模型该生态系统提供了将TensorFlow模型转换为网页应用中使用的能力例如通过 [TensorFlow.js](https://www.tensorflow.org/js/)。
- **使用PyTorch。** 如果你使用 [PyTorch](https://pytorch.org/) 等库构建模型,你可以选择将其导出为 [ONNX](https://onnx.ai/)开放神经网络交换格式用于支持JavaScript网页应用的 [Onnx Runtime](https://www.onnxruntime.ai/)。在未来的课程中我们将探索如何将Scikit-learn训练的模型导出为ONNX格式。
- **使用Lobe.ai或Azure Custom Vision。** 如果你使用 [Lobe.ai](https://lobe.ai/) 或 [Azure Custom Vision](https://azure.microsoft.com/services/cognitive-services/custom-vision-service/?WT.mc_id=academic-77952-leestott) 等机器学习SaaS软件即服务系统来训练模型这类软件提供了多平台导出模型的方法包括构建一个定制的API通过云端供在线应用查询。
你还可以选择构建一个完整的Flask网页应用该应用能够在网页浏览器中自行训练模型。这也可以通过JavaScript环境中的TensorFlow.js实现。
对于我们的目的由于我们一直在使用基于Python的notebook让我们来探索将训练好的模型从notebook导出为Python构建的网页应用可读取的格式所需的步骤。
## 工具
完成此任务你需要两个工具Flask和Pickle它们都运行在Python上。
✅ 什么是 [Flask](https://palletsprojects.com/p/flask/)Flask被其创建者定义为一个“微框架”它使用Python和模板引擎来构建网页提供了网页框架的基本功能。可以参考 [这个学习模块](https://docs.microsoft.com/learn/modules/python-flask-build-ai-web-app?WT.mc_id=academic-77952-leestott) 来练习使用Flask构建应用。
✅ 什么是 [Pickle](https://docs.python.org/3/library/pickle.html)Pickle 🥒 是一个Python模块用于序列化和反序列化Python对象结构。当你对模型进行“pickle”处理时你会将其结构序列化或扁平化以便在网页上使用。需要注意的是Pickle本身并不安全因此在被提示“un-pickle”文件时要小心。Pickle文件的后缀为`.pkl`。
## 练习 - 清理数据
在本课中,你将使用来自 [NUFORC](https://nuforc.org)国家UFO报告中心的80,000条UFO目击数据。这些数据中包含一些有趣的UFO目击描述例如
- **长描述示例。** “一个人从夜晚草地上的一道光束中出现,跑向德州仪器的停车场。”
- **短描述示例。** “灯光追逐我们。”
[ufos.csv](../../../../3-Web-App/1-Web-App/data/ufos.csv) 表格包含关于目击发生的 `city`(城市)、`state`(州)和 `country`(国家),物体的 `shape`(形状),以及其 `latitude`(纬度)和 `longitude`(经度)的列。
在本课提供的空白 [notebook](../../../../3-Web-App/1-Web-App/notebook.ipynb) 中:
1. 像之前的课程一样,导入 `pandas`、`matplotlib` 和 `numpy`并导入ufos表格。你可以查看数据集的样本
```python
import pandas as pd
import numpy as np
ufos = pd.read_csv('./data/ufos.csv')
ufos.head()
```
1. 将ufos数据转换为一个小型数据框并重新命名列标题。检查 `Country` 字段中的唯一值。
```python
ufos = pd.DataFrame({'Seconds': ufos['duration (seconds)'], 'Country': ufos['country'],'Latitude': ufos['latitude'],'Longitude': ufos['longitude']})
ufos.Country.unique()
```
1. 现在你可以通过删除任何空值并仅导入1-60秒之间的目击事件来减少需要处理的数据量
```python
ufos.dropna(inplace=True)
ufos = ufos[(ufos['Seconds'] >= 1) & (ufos['Seconds'] <= 60)]
ufos.info()
```
1. 导入Scikit-learn的 `LabelEncoder` 库,将国家的文本值转换为数字:
✅ LabelEncoder 按字母顺序对数据进行编码
```python
from sklearn.preprocessing import LabelEncoder
ufos['Country'] = LabelEncoder().fit_transform(ufos['Country'])
ufos.head()
```
你的数据应如下所示:
```output
Seconds Country Latitude Longitude
2 20.0 3 53.200000 -2.916667
3 20.0 4 28.978333 -96.645833
14 30.0 4 35.823889 -80.253611
23 60.0 4 45.582778 -122.352222
24 3.0 3 51.783333 -0.783333
```
## 练习 - 构建模型
现在你可以准备通过将数据分为训练组和测试组来训练模型。
1. 选择三个特征作为你的X向量y向量将是 `Country`。你希望能够输入 `Seconds`、`Latitude` 和 `Longitude`并返回一个国家ID。
```python
from sklearn.model_selection import train_test_split
Selected_features = ['Seconds','Latitude','Longitude']
X = ufos[Selected_features]
y = ufos['Country']
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=0)
```
1. 使用逻辑回归训练模型:
```python
from sklearn.metrics import accuracy_score, classification_report
from sklearn.linear_model import LogisticRegression
model = LogisticRegression()
model.fit(X_train, y_train)
predictions = model.predict(X_test)
print(classification_report(y_test, predictions))
print('Predicted labels: ', predictions)
print('Accuracy: ', accuracy_score(y_test, predictions))
```
模型的准确率还不错 **大约95%**,这并不奇怪,因为 `Country``Latitude/Longitude` 是相关的。
你创建的模型并不是非常具有革命性,因为你应该能够从 `Latitude``Longitude` 推断出 `Country`,但这是一个很好的练习,可以尝试从清理过的原始数据中训练模型,导出模型,然后在网页应用中使用它。
## 练习 - 对模型进行“pickle”处理
现在是时候对你的模型进行“pickle”处理了你可以用几行代码完成这一步。一旦完成“pickle”处理加载你的Pickle模型并用一个包含秒数、纬度和经度值的样本数据数组进行测试
```python
import pickle
model_filename = 'ufo-model.pkl'
pickle.dump(model, open(model_filename,'wb'))
model = pickle.load(open('ufo-model.pkl','rb'))
print(model.predict([[50,44,-12]]))
```
模型返回了 **'3'**,这是英国的国家代码。太神奇了!👽
## 练习 - 构建一个Flask应用
现在你可以构建一个Flask应用来调用你的模型并以更直观的方式返回类似的结果。
1. 首先,在 _notebook.ipynb_ 文件旁边创建一个名为 **web-app** 的文件夹,其中存放你的 _ufo-model.pkl_ 文件。
1. 在该文件夹中再创建三个文件夹:**static**(其中包含一个名为 **css** 的文件夹)和 **templates**。你现在应该有以下文件和目录:
```output
web-app/
static/
css/
templates/
notebook.ipynb
ufo-model.pkl
```
✅ 参考解决方案文件夹以查看完成的应用
1._web-app_ 文件夹中创建第一个文件 **requirements.txt**。像JavaScript应用中的 _package.json_ 一样,此文件列出了应用所需的依赖项。在 **requirements.txt** 中添加以下内容:
```text
scikit-learn
pandas
numpy
flask
```
1. 现在,通过导航到 _web-app_ 运行此文件:
```bash
cd web-app
```
1. 在终端中输入 `pip install`,以安装 _requirements.txt_ 中列出的库:
```bash
pip install -r requirements.txt
```
1. 现在,你可以创建另外三个文件来完成应用:
1. 在根目录创建 **app.py**
2._templates_ 目录中创建 **index.html**
3._static/css_ 目录中创建 **styles.css**
1._styles.css_ 文件中添加一些样式:
```css
body {
width: 100%;
height: 100%;
font-family: 'Helvetica';
background: black;
color: #fff;
text-align: center;
letter-spacing: 1.4px;
font-size: 30px;
}
input {
min-width: 150px;
}
.grid {
width: 300px;
border: 1px solid #2d2d2d;
display: grid;
justify-content: center;
margin: 20px auto;
}
.box {
color: #fff;
background: #2d2d2d;
padding: 12px;
display: inline-block;
}
```
1. 接下来,构建 _index.html_ 文件:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>🛸 UFO Appearance Prediction! 👽</title>
<link rel="stylesheet" href="{{ url_for('static', filename='css/styles.css') }}">
</head>
<body>
<div class="grid">
<div class="box">
<p>According to the number of seconds, latitude and longitude, which country is likely to have reported seeing a UFO?</p>
<form action="{{ url_for('predict')}}" method="post">
<input type="number" name="seconds" placeholder="Seconds" required="required" min="0" max="60" />
<input type="text" name="latitude" placeholder="Latitude" required="required" />
<input type="text" name="longitude" placeholder="Longitude" required="required" />
<button type="submit" class="btn">Predict country where the UFO is seen</button>
</form>
<p>{{ prediction_text }}</p>
</div>
</div>
</body>
</html>
```
查看此文件中的模板语法。注意变量周围的“大括号”语法,例如预测文本:`{{}}`。还有一个表单会将预测结果发布到 `/predict` 路由。
最后你已经准备好构建驱动模型使用和预测显示的Python文件
1.`app.py` 中添加:
```python
import numpy as np
from flask import Flask, request, render_template
import pickle
app = Flask(__name__)
model = pickle.load(open("./ufo-model.pkl", "rb"))
@app.route("/")
def home():
return render_template("index.html")
@app.route("/predict", methods=["POST"])
def predict():
int_features = [int(x) for x in request.form.values()]
final_features = [np.array(int_features)]
prediction = model.predict(final_features)
output = prediction[0]
countries = ["Australia", "Canada", "Germany", "UK", "US"]
return render_template(
"index.html", prediction_text="Likely country: {}".format(countries[output])
)
if __name__ == "__main__":
app.run(debug=True)
```
> 💡 提示当你在使用Flask运行网页应用时添加 [`debug=True`](https://www.askpython.com/python-modules/flask/flask-debug-mode),任何对应用的更改都会立即反映出来,而无需重启服务器。但要小心!不要在生产应用中启用此模式。
如果你运行 `python app.py``python3 app.py`你的网页服务器会在本地启动你可以填写一个简短的表单获取关于UFO目击地点的答案
在此之前,先看看 `app.py` 的各个部分:
1. 首先,加载依赖项并启动应用。
1. 然后,导入模型。
1. 接着,在主页路由上渲染 index.html。
`/predict` 路由上,当表单被提交时,会发生以下几件事:
1. 表单变量被收集并转换为一个numpy数组。然后将其发送到模型并返回一个预测结果。
2. 我们希望显示的国家代码被重新渲染为可读的文本值,并将该值发送回 index.html在模板中渲染。
通过Flask和Pickle模型以这种方式使用模型是相对简单的。最难的部分是理解必须发送到模型的数据形状以获得预测结果。这完全取决于模型的训练方式。这个模型需要输入三个数据点才能获得预测。
在专业环境中,你可以看到训练模型的团队和在网页或移动应用中使用模型的团队之间良好沟通的重要性。在我们的案例中,只有一个人,那就是你!
---
## 🚀 挑战
与其在notebook中工作并将模型导入Flask应用你可以直接在Flask应用中训练模型尝试将notebook中的Python代码转换为在应用中的 `train` 路由上训练模型。尝试这种方法的优缺点是什么?
## [课后小测验](https://ff-quizzes.netlify.app/en/ml/)
## 复习与自学
构建一个使用机器学习模型的网页应用有很多方法。列出你可以使用JavaScript或Python构建网页应用以利用机器学习的方法。考虑架构模型应该保留在应用中还是存储在云端如果是后者你将如何访问它绘制一个应用机器学习网页解决方案的架构模型。
## 作业
[尝试一个不同的模型](assignment.md)
---
**免责声明**
本文档使用AI翻译服务[Co-op Translator](https://github.com/Azure/co-op-translator)进行翻译。尽管我们努力确保准确性,但请注意,自动翻译可能包含错误或不准确之处。应以原始语言的文档作为权威来源。对于关键信息,建议使用专业人工翻译。对于因使用本翻译而引起的任何误解或误读,我们概不负责。