前两者需要广泛的数学和科学知识, 而API和UI开发则以算法思维和设计灵活的架构为中心. 它们非常不同,所以决定你接下来想学哪一种可能很有挑战性. 本文的目的是演示如何在创建图像处理应用程序时使用这四种方法.
我们要构建的应用程序是一个简单的数字识别器. You draw, 的 machine p红色的icts 的 digit. 简单是必不可少的,因为它让我们看到大局,而不是专注于细节.
我们的应用程序的核心部分是算法猜测抽到的数字. 机器学习将成为实现良好猜测质量的工具. 这种基本的人工智能允许系统在给定的数据量下自动学习. 从广义上讲, 机器学习是一个在数据中找到一个巧合或一组巧合的过程,并依靠它们来猜测结果.
在开始编写代码之前,我们需要为我们的机器选择一个合适的“老师”. 通常,数据科学专业人员在选择最佳模型之前会尝试不同的模型. 我们将跳过非常先进的模型,需要大量的技能和继续与 k-nearest 邻居 algorithm .
它是一种算法,它获得一些数据样本,并将它们排列在一个平面上,按照给定的一组特征排序. 为了更好地理解它,让我们看看下面的图片:
< / div >
的类型 绿点 , we should check 的 types of k 最近邻 k 是参数集吗?. Considering 的 image above, if k is equal to 1, 2, 3, or 4, 的 guess will be a 黑色的三角形 as most of 的 绿色 dot’s closest k 邻居 are black triangles. 如果我们增加 k 到5,那么大多数物体是蓝色方块,因此猜测将是a 蓝色的正方形 .
创建我们的机器学习模型需要一些依赖关系:
sklearn.邻居.KNeighborsClassifier 是我们将要使用的分类器吗.
sklearn.模型_selection.train_test_split 这个函数会帮助我们把数据分成训练数据和用来检查模型正确性的数据吗.
sklearn.模型_selection.cross_val_分数 函数是否为模型的正确性获得标记. 的 higher 的 value, 的 better 的 correctness.
sklearn.指标.classification_回购rt 函数是显示模型猜测的统计报告吗.
sklearn.数据集 是用来获取训练数据的包(数字图像).
numpy 是一个在科学领域广泛使用的包,因为它提供了一种高效和舒适的方式来操作Python中的多维数据结构.
matplotlib.pyplot is 的 package used to visualize data.
让我们从安装和导入它们开始:
pip install sklearn numpy matplotlib scipy
从sklearn.数据集导入load_数字
从sklearn.邻居 import KNeighborsClassifier
从sklearn.导入train_test_split, cross_val_分数
导入numpy为np
进口matplotlib.Pyplot为PLT
现在,我们需要加载 MNIST数据库 . MNIST是机器学习领域成千上万新手使用的手写图像的经典数据集:
Digits = load_数字()
Once 的 data is fetched 和 ready, 我们可以进入下一步,将数据分成两部分: 培训 和 测试 .
我们将使用75%的数据来训练我们的模型来猜测数字,我们将使用其余的数据来测试模型的正确性:
(X_train, X_test, y_train, y_test) =
数字.数据,数字.目标,test_size = 0.25日,r和om_state = 42
)
数据现在已经整理好了,我们可以使用它了. We’ll try to find 的 best parameter k 对于我们的模型,所以猜测会更精确. 我们不能保留 k 在这个阶段,价值离开了我们的头脑,因为我们必须用不同的模型来评估 k 值.
让我们看看为什么必须考虑一个范围 k 值以及这如何提高我们模型的准确性:
Ks = np.(2) 10)不等
分数= []
对于k中的k:
模型 = KNeighborsClassifier(n_邻居=k)
得分= cross_val_分数(模型, X_train, y_train, cv=5)
分数.意思是()
分数.追加(得分.意思是())
plt.情节(分数,ks)
plt.包含(精度)
plt.ylabel(“k”)
plt.显示()
执行此代码将向您展示下面的图,该图描述了算法的精度与不同 k 值.
< / div >
如你所见,a k 3的值确保我们的模型和数据集的最佳精度.
使用Flask构建API
应用程序核心是一种从图像中预测数字的算法,现在已经准备好了. 接下来,我们需要用API层修饰算法,使其可用. 让我们用流行的 Flask web框架 to do this cleanly 和 concisely.
我们将从在虚拟环境中安装Flask和与图像处理相关的依赖开始:
pip install Flask Pillow scikit-image
安装完成后,我们开始创建应用程序的入口点文件:
触摸应用程序.py
的 content of 的 file will look like this:
进口操作系统
从烧瓶导入烧瓶
from views import P红色的ictDigitView, IndexView
应用程序 = Flask(__name__)
应用程序.add_url_rule (
/ api /预测,
view_func = P红色的ictDigitView.as_view(“p红色的ict_digit”),
方法=(“文章”)
)
应用程序.add_url_rule (
'/',
view_func = IndexView.as_view(“指数”),
方法=(“得到”)
)
如果__name__ == 'main':
端口= int(os.环境.(“端口”,5000))
应用程序.(主机运行= ' 0.0.0.0,端口=端口)
You will get an error saying that P红色的ictDigitView
和 IndexView
没有定义. 下一步是创建一个文件来初始化这些视图:
从flask中导入render_template、request、Response
从瓶.views import MethodView, View
从瓶.views import视图
from 回购 import Classifier回购
from services import P红色的ictDigit服务
from settings import CLASSIFIER_STORAGE
类IndexView(观点):
def dispatch_request(自我):
return render_template('index.html”)
class P红色的ictDigitView(MethodView):
def post(自我):
回购 = Classifier回购(CLASSIFIER_STORAGE)
service = P红色的ictDigit服务(回购)
Image_data_uri =请求.json('图像')
预测=服务.处理(image_data_uri)
return Response(str(p红色的iction).编码(),状态= 200)
我们将再次遇到关于未解析导入的错误. 的 的观点 软件包依赖于三个我们还没有的文件:
We’ll implement 的m one by one.
设置 模块是否具有配置和常量变量. 它将为我们存储序列化分类器的路径. 这引出了一个合乎逻辑的问题: 为什么 do I need to save 的 classifier?
因为这是一种提高应用性能的简单方法. 而不是每次收到请求时都训练分类器, we’ll store 的 classifier’s prepa红色的 version, enabling it to work out of 的 box:
进口操作系统
BASE_DIR = os.getcwd ()
CLASSIFIER_STORAGE = os.路径.join(BASE_DIR, 'storage/classifier.txt”)
设置机制——获取分类器——将在我们列表中的下一个包中初始化, 的 回购 . 它是一个类,有两个方法来检索和更新使用Python内置的训练分类器 泡菜
模块:
进口泡菜
类Classifier回购:
Def __init__(自我, storage):
自我.存储器
def(自我):
打开(自我.存储,'wb')作为输出:
试一试:
Classifier_str = out.read ()
如果classifier_str != '':
返回泡菜.负载(classifier_str)
其他:
回来没有
除了例外:
回来没有
def update(自我, classifier):
打开(自我.存储,'wb'),如:
泡菜.in_转储(标识符)
We are close to finalizing our API. 现在它只缺少 服务 模块. 它的目的是什么?
Get 的 trained classifier from storage
将从UI传递的图像转换为分类器可以理解的格式
通过分类器对格式化后的图像进行预测
返回预测
让我们编写这个算法:
从sklearn.数据集导入load_数字
from classifier import ClassifierFactory
from image_processing import process_image
类P红色的ictDigit服务:
Def __init__(自我, 回购):
自我.回购=回购
def h和le(自我, image_data_uri):
分类器=自我.回购.get ()
如果classifier为None:
Digits = load_数字()
classifier = ClassifierFactory.create_with_fit (
数字.数据,
数字.目标
)
自我.回购.更新(标识符)
x = process_image(image_data_uri)
如果x为None:
返回0
预测=分类器.预测(x) [0]
回归预测
这里你可以看到 P红色的ictDigit服务
有两个依赖项: ClassifierFactory
和 process_image
.
我们将首先创建一个类来创建和训练我们的模型:
从sklearn.模型_selection import train_test_split
从sklearn.邻居 import KNeighborsClassifier
类ClassifierFactory:
@staticmethod
def create_with_fit (数据、目标):
模型 = KNeighborsClassifier(n_邻居=3)
模型.fit(数据、目标)
回归模型
API已经准备好进行操作了. Now we can proceed to 的 图像处理 step.
图像处理
图像处理是对图像进行某些操作以增强图像或从中提取有用信息的一种方法. 在我们的例子中, 我们需要将用户绘制的图像平滑地转换为机器学习模型格式.
< / div >
Let’s import some helpers to achieve that goal:
导入numpy为np
从skimage导入曝光
进口base64
from PIL import Image, ImageOps, ImageChops
从io导入BytesIO
我们可以将这种转变分为六个不同的部分:
1. Replace a transparent background with a color
< / div >
def replace_transparent_background(image):
Image_arr = np.数组(图片)
如果len (image_arr.形状)== 2:
返回图像
Alpha1 = 0
r2, g2, b2, alpha2 = 255, 255, 255, 255
红色的, 绿色, 蓝色的, Alpha = image_arr [:], :, 0], image_arr [:, :, 1], image_arr [:, :, 2], image_arr [:, :, 3]
掩码= (alpha == alpha1)
image_arr [:, :, :4][mask] = [r2, g2, b2, alpha2]
返回图像.fromarray (image_arr)
2. 修剪开放的边界
< / div >
def trim_borders(图片):
bg =图像.新(图片.模式,形象.大小,图像.获取像素((0,0)))
diff = ImageChops.差异(形象,bg)
diff = ImageChops.加上(diff, diff, 2.0, -100)
Bbox = diff.getbbox ()
如果bbox:
返回图像.作物(bbox)
返回图像
3. 添加相等大小的边框
< / div >
def pad_image(图片):
返回ImageOps.exp和(image, border=30, fill='#fff')
4. Convert 的 image to grayscale mode
def to_grayscale(图片):
返回图像.转换(“L”)
5. 反色
< / div >
def invert_colors(图片):
返回ImageOps.转化(图片)
6. Resize 的 image to 8x8 format
< / div >
def resize_image(图片):
返回图像.调整((8,8),图像.线性)
现在可以测试应用程序了. 运行应用程序并输入下面的命令以发送请求 这个库存图像 到API:
< / div >
出口FLASK_APP =应用
瓶运行
curl "http://localhost:5000/api/p红色的ict" -X "POST" -H "Content-Type: 应用程序lication/json" -d "{\"image\": \"data:image/png,美元(curl http://media.istockphoto.com/vectors/number-eight-8-h和-drawn-with-dry-brush-vector-id484207302?k=6&m=484207302&s=170667a&w=0&h=s3YANDyuLS8u2so-uJbMA2uW6fYyyRkabc1a6OTq7iI=" | base64 " \"}" -i
You should see 的 following output:
HTTP / 1.1100继续
HTTP / 1.0 200 OK
Content-Type: text/html; charset=utf-8
内容长度:1
服务器:Werkzeug / 0.14.1 Python / 3.6.3
Date: Tue, 27 Mar 2018 07:02:08 GMT
8
样本图像描绘了数字8,我们的应用程序正确地识别了它.
Creating a Drawing Pane Via 反应
为了快速引导前端应用程序,我们将使用 CRA样板 :
create-react-应用程序前端
cd前端
在设置工作场所之后,我们还需要一个依赖项来绘制数字. 的 react-sketch package matches our needs perfectly:
NPM I反应-草图
的 应用程序lication has only one component. We can divide this component into two parts: 逻辑和视图 .
视图部分负责表示绘图窗格, 提交 和 重置 按钮. 当交互时,我们也应该表示预测或错误. 从逻辑上看,它有以下职责: 提交的图片 和 清除草图 .
每当用户点击 提交 ,该组件将从草图组件中提取图像,并调用API模块 makeP红色的iction
函数. 如果对后端的请求成功,我们将设置预测状态变量. O的rwise, we’ll update 的 error state.
当用户点击时 重置 ,草图就会清晰:
import 反应, { useRef, useState } from "react";
import { makeP红色的iction } from "./ api”;
const App = () => {
const sketchRef = useRef(null);
const [error, setError] = useState();
const [p红色的iction, setP红色的iction] = useState();
const h和le提交 = () => {
const image = sketchRef .草图.当前的.toDataURL ();
setP红色的iction(定义);
setError(定义);
makeP红色的iction(图片).然后(setP红色的iction).抓住(setError);
};
const h和leClear = (e) => sketchRef.当前的.明确的();
返回null
}
逻辑是充分的. Now we can add 的 visual interface to it:
import 反应, { useRef, useState } from "react";
从“react-sketch”中导入{SketchField, 工具};
import { makeP红色的iction } from "./ api”;
从“./标识.svg”;
进口”./应用程序.css”;
const pixels = (count) => `${count}px`;
const percents = (count) => `${count}%`;
const MAIN_CONTAINER_WIDTH_PX = 200;
const MAIN_CONTAINER_HEIGHT = 100;
const MAIN_CONTAINER_STYLE = {
width: pixels(MAIN_CONTAINER_WIDTH_PX),
height: percents(MAIN_CONTAINER_HEIGHT),
边距:"0 auto",
};
const SKETCH_CONTAINER_STYLE = {
边框:"1px纯黑色",
width: pixels(MAIN_CONTAINER_WIDTH_PX - 2),
height: pixels(MAIN_CONTAINER_WIDTH_PX - 2),
写成backgroundColor:“白”,
};
const App = () => {
const sketchRef = useRef(null);
const [error, setError] = useState();
const [p红色的iction, setP红色的iction] = useState();
const h和le提交 = () => {
const image = sketchRef .草图.当前的.toDataURL ();
setP红色的iction(定义);
setError(定义);
makeP红色的iction(图片).然后(setP红色的iction).抓住(setError);
};
const h和leClear = (e) => sketchRef.当前的.明确的();
回报(
Draw a digit
{预测 &&
P红色的icted value is: {预测} }
Clear
Guess 的 number
{错误 &&
Something went wrong
}
);
};
导出默认App;
组件准备好了,通过执行并转到来测试它 localhost: 3000
后:
NPM运行启动
的 demo 应用程序lication is available 在这里 . You can also browse 的 source code on GitHub .
结束
这个分类器的质量并不完美,我并不假装它是完美的. 我们用于训练的数据和来自UI的数据之间的差异是巨大的. 尽管如此,我们在不到30分钟的时间内从零开始创建了一个可工作的应用程序.
< / div >
在这个过程中,我们在四个方面磨练了自己的技能:
对于能够识别手写数字的软件来说,并不缺乏潜在的用例, 从教育和行政软件到邮政和金融服务.
因此, 我希望这篇文章能够激励您提高机器学习能力, 图像处理, 和 front-end 和 back-end development, 并使用这些技能来设计出色而有用的应用程序.
如果你想拓宽你在机器学习和图像处理方面的知识, 你可能想看看我们的 Adversarial 机器学习 Tutorial .
< / div >< / div >< / div >
Fur的r Reading on 的 Toptal 博客: < / div >
了解基本知识 What is MNIST in machine learning? MNIST是计算机视觉领域最流行的入门级数据集之一. 它包含成千上万的手写数字图像.
< / div >< / div >
What is 培训 in machine learning? 机器学习 模型s learn from data. 为了使模型足够智能,我们需要提供具有预期结果的数据. 模型将使用这些数据来检测数据参数与期望结果之间的关系.
< / div >< / div >
What is 图像处理 in machine learning? 图像处理是对图像进行某些操作以获得增强图像或提取有用信息的一种方法.
< / div >< / div >< / div >< / div >
标签 < / div >< / div >< / div >< / div >
Consult 的 author or an expert on this topic.< / div >
预约电话 < / div >< / div >