基于 Keras 的图像分类器

引言

深度学习是使用人工神经网络进行机器学习的一个子集,目前已经被证明在图像分类方面非常强大。尽管这些算法的内部工作在数学上是严格的,但 Python 库(比如 keras)使这些问题对我们所有人都可以接近。在本文中,我将介绍一个简单的图像分类器的设计,它使用人工神经网络将食物图像分为两类:披萨或意大利面。

 

下载图片

为了训练我们的模型,我们将需要下载大量比萨饼和意大利面的图像,这是一个可能非常繁琐的任务,通过 bing-image-downloader Python 库可以非常容易地完成。

# Install Bing image downloader

pip install bing-image-downloader

现在,我们已经安装了 bing-image-downloader,我们可以很容易地抓取500张比萨饼和意大利面的照片用于训练和测试我们的模型!

# Import bing-image-downloader
from bing_image_downloader import downloader
# Download images
downloader.download("pizza", limit=500, output_dir="photos")
downloader.download("pasta", limit=500, output_dir="photos")

这应该需要几分钟,之后你将有两个子目录下的照片称为比萨饼和面食,每个包含500张照片。这很简单!

 

数据整理

为了将我们的数据转换成对我们的模型有利的格式,我们需要使用 glob、 pandas、 numpy 和 PIL 库。

# Import packages
import glob
import numpy as np
import pandas as pd
from PIL import Image

我们将使用 glob 来收集我们下载的所有图像的文件路径。为此,我们使用 * 通配符分配变量,以对应目录中的所有文件。

# Filepaths for the pizza and pasta images
filepath_pizza = "./photos/pizza/*"
filepath_pasta = "./photos/pasta/*"

现在,我们可以使用 glob 创建列表,其中每个元素都包含文件夹中单个图像的文件路径:

# Collect all the image filepaths into lists
pizza_files = [file for file in glob.iglob(filepath_pizza)]
pasta_files = [file for file in glob.iglob(filepath_pasta)]

使用所有的文件路径,我们现在可以构建一个 pandas 数据框架,我们可以在其中跟踪文件路径及其相关标签(比萨或意大利面)。在这种情况下,我们将给披萨图像一个0的标签,给意大利面图像一个1的标签。为了方便地为这些标签创建数组,我们可以使用 np.zeros()和 np.ones():

# Construct pandas dataframe with all the image filenames and labels
df_photos = (pd.DataFrame({"filepath": pizza_files, "label": np.zeros(len(pizza_files))}).append(pd.DataFrame({"filepath": pasta_files, "label": np.ones(len(pasta_files))}))
)

 

c911f676466c0375df48a9609f97b167.png

现在,我们希望将数据集拆分为训练数据和测试数据。幸运的是,scikit-learn 有一个非常简单的功能,可以直接在我们的 pandas 数据库上为我们实现这个功能。我们需要设置 test_size ,它是我们用于测试集数据的一个百分比,并且,通过指定 random_state,我们可以使拆分的结果可重复进行以进行后续测试。最后,我们将重新设置并删除新数据流的索引,因为 train_test_split  会自动为我们分配数据,所以旧的索引值现在没有意义了。

# Import train_test_split
from sklearn.model_selection import train_test_split
# Split our dataset
df_train, df_test = train_test_split(df_photos, test_size=0.2, random_state=1)
df_train.reset_index(drop=True, inplace=True)
df_test.reset_index(drop=True, inplace=True)

 

601b608e3ddcb696135c816b6df6e7c5.png

我们的训练数据集已经将数据与其相关的标签混合在一起

 

我们有我们的图像和标签到一个可接受的形式,现在我们必须从文件路径加载我们的图像。我们将 PIL.Image 封装到一个函数中,该函数将加载图像,将其调整为128 x 128像素,将其转换为灰度图像,并将亮度正常化为0到1之间的值。

# Wrapper function to load and process images
def process_image(filepath):return np.asarray(Image.open(filepath).resize((128, 128)).convert("L")) / 255.0

让我们来测试一下我们的封装函数,我们可以从 pizza_files 文件中加载第一张图片,然后绘制出来看:

# Load image
img = process_images(pizza_files[0])
# Plot image
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111)
ax.imshow(img, cmap="gray")
ax.set_xticks([])
ax.set_yticks([])
plt.show()

 

d74d4ff5bb7f0b074e1114b37cf4d5b4.png

酷!现在让我们继续从我们的训练集中绘制16张图片,连同它们的相关标签,来了解我们的数据是什么样的:

# Plot 16 images from our training set with labels
fig = plt.figure(figsize=(10, 10))
for i in range(16):plt.subplot(4, 4, i+1)img = process_image(df_train["filepath"].iloc[i])plt.imshow(img, cmap="gray")plt.grid(False)plt.xticks([])plt.yticks([])if df_train["label"].iloc[i] == 0:plt.title("Pizza", size=16)else:plt.title("Pasta", size=16)
plt.show()

 

df7858d93373c65ab49fc0d392ac98ec.png

在构建分类器之前,我们需要做的最后一件事是将所有的图像和标签加载到数组中,以便加载到模型中。对于我们的图像,我们首先创建一个空的 numpy 数组,其长度等于训练集中图像的数量。这个数组的每个元素都是一个128 x 128的矩阵,代表一幅图像。我们也可以对我们的测试集图像做同样的事情。

# Create array of training images
train_images = np.empty([df_train.shape[0], 128, 128])
for index, row in df_train.iterrows():img = process_image(row.filepath)train_images[index] = img
# Create array of test images
test_images = np.empty([df_test.shape[0], 128, 128])
for index, row in df_test.iterrows():img = process_image(row.filepath)test_images[index] = img

我们可以看到一个示例图像看起来像一个 numpy 数组:

>>> train_images[0]
array([[0.12941176, 0.12156863, 0.12941176, ..., 0.10588235, 0.10588235,0.09803922],[0.1254902 , 0.1254902 , 0.1254902 , ..., 0.10588235, 0.10196078,0.09803922],[0.13333333, 0.13333333, 0.1254902 , ..., 0.11372549, 0.10588235,0.09803922],...,[0.09019608, 0.09411765, 0.09803922, ..., 0.0745098 , 0.07058824,0.0745098 ],[0.09019608, 0.09411765, 0.09411765, ..., 0.0745098 , 0.0745098 ,0.0745098 ],[0.09019608, 0.09411765, 0.09411765, ..., 0.0745098 , 0.07058824,0.0745098 ]])

制作训练标签和测试标签的数组更加简单 —— 我们已经在数据框的一列中有了值,所以我们只需将这列转换为 numpy 数组:

# Create array of training labels
train_labels = df_train["label"].to_numpy()
# Create array of test labels
test_labels = df_test["label"].to_numpy()

我们现在准备构建和训练我们的模型!

 

模型构建与训练

我们将使用 keras 创建我们的模型,keras 是一个用于创建人工神经网络的高级 API。我们首先导入所需的软件包:

# Import keras
import tensorflow.keras as keras

我们的模型将由一系列层组成,我们将它们封装在 keras.Sequential() 中。神经网络通常包括:

  • 一个输入层ーー将数据输入其中

  • 一个或多个隐藏层ーー数据流经这些层,这些层具有激活函数,以确定节点的输入如何影响输出

  • 输出层ーー读取最终的输出神经元以确定分类

 

在我们的示例中,我们将有一个输入层、一个隐藏层和一个输出层。我们的模型将构建如下:

  1. 输入层将图像压平为一维(128 x 128 = 16384个输入节点)

  2. 隐藏层有256个节点——我们将使用的激活函数是一个rectified linear unit,但你可以使用其他方法,例如sigmoid function

  3. 输出层有2个节点(分别对应于比萨和意大利面)ー我们将添加一个softmax function 。因此,每个节点上的值代表了我们的分类器认为图像是披萨或意大利面的概率​​​​​​​

# Create our model
model = keras.Sequential([keras.layers.Flatten(input_shape=(128, 128)),keras.layers.Dense(256, activation="relu"),keras.layers.Dense(2, activation="softmax")
])

我们可以查看我们的模型:

model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
flatten (Flatten)            (None, 16384)             0         
_________________________________________________________________
dense (Dense)                (None, 256)               4194560   
_________________________________________________________________
dense_1 (Dense)              (None, 2)                 514       
=================================================================
Total params: 4,195,074
Trainable params: 4,195,074
Non-trainable params: 0

现在我们已经有了网络层,为了构建我们的模型,我们还需要3样东西:1)优化函数,2)损失函数,3)性能指标。

对于优化函数,我们将使用自适应矩估计(ADAM) ,它在较大数据集上往往比梯度下降法更好。我们还将设置我们的优化器的学习速率,以便在更新权重时不会出现大的跳跃。

对于我们的损失函数,我们将使用稀疏绝对交叉熵。

我们的性能指标是准确性,即正确分类照片的比例。

# Set the learning rate
opt = keras.optimizers.Adam(learning_rate=0.000005)
# Compile our model
model.compile(optimizer=opt,           loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True), metrics=['accuracy'])

现在我们可以训练我们的模型了!我们需要决定我们的数据集中有多少比例将用于未来的交叉验证,以及有多少 epoch 将用于我们的训练。在这种情况下,我将使用20% 的验证和运行我们的50个 epoch 的训练。

# Train our model
history = model.fit(train_images, train_labels, epochs=50, validation_split=0.2)

在我们的训练结束时,我们应该看到这样的东西:

Epoch 48/50
20/20 [==============================] - 0s 10ms/step - loss: 0.4522 - accuracy: 0.9453 - val_loss: 0.4958 - val_accuracy: 0.8875
Epoch 49/50
20/20 [==============================] - 0s 9ms/step - loss: 0.4505 - accuracy: 0.9500 - val_loss: 0.4943 - val_accuracy: 0.8750
Epoch 50/50
20/20 [==============================] - 0s 9ms/step - loss: 0.4493 - accuracy: 0.9438 - val_loss: 0.4981 - val_accuracy: 0.8625

酷!我们训练的神经网络在我们的训练数据上达到了94% 的准确率,在交叉验证上达到了86% 。通过将我们的适应输出设置为一个名为 history 的变量,我们可以将性能作为训练 epoch 的函数来绘制:

# Plot accuracy
fig = plt.figure(figsize=(15,5))
ax1 = fig.add_subplot(121)
ax2 = fig.add_subplot(122)
ax1.plot(history.history['accuracy'])
ax1.plot(history.history['val_accuracy'])
ax1.set_title('Model Accuracy')
ax1.set_ylabel('Accuracy')
ax1.set_xlabel('Epoch')
ax1.legend(['train', 'val'], loc='upper left')
ax2.plot(history.history['loss'])
ax2.plot(history.history['val_loss'])
ax2.set_title('Model Loss')
ax2.set_ylabel('Loss')
ax2.set_xlabel('Epoch')
ax2.legend(['train', 'val'], loc='upper left')
plt.show()

 

723e75e26073c01db0c9fa7e29cd8fad.png

这样的图可以用来检验我们是否过度拟合(即训练和交叉验证准确性和损失之间的巨大差异,在这里训练集是合适的)。

 

让我们看看我们的模型在我们之前分割出的测试数据上的准确性:

# Evaluate training accuracy
model.evaluate(test_images, test_labels, verbose=2)
7/7 - 0s - loss: 0.5233 - accuracy: 0.8250

我们的分类器在训练数据上有82.5% 的准确率ー现在让我们在一些新的照片上尝试我们的训练模型。

 

模型预测

现在让我们用一些新的看不见的数据来测试我们的模型。首先,我们可以编写一个封装函数,它接受模型和图像作为 numpy 数组,并返回一个字符串,其中包含预测的类和根据模型该类的概率。

# Function to return prediction and probability
def model_prediction(model, img):predictions = model.predict(np.array([img]))if predictions[0][0] > predictions[0][1]:return f"Pizza: {round(100*predictions[0][0], 2)}%"else:return f"Pasta: {round(100*predictions[0][1], 2)}%"

现在,我们可以用我自己做饭的两张图片来测试这一点:一碗意大利面和一个比萨饼。

 

意大利面

# Load image of cacio e pepe
cacio_e_pepe = process_image("./cacioepepe.jpg")
# Plot image along with prediction
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111)
ax.imshow(cacio_e_pepe, cmap="gray")
ax.set_xticks([])
ax.set_yticks([])
ax.set_title(model_prediction(model, cacio_e_pepe))
plt.show()

 

28f548cfb3cdc0b1d4718aecdc8d1e79.png

披萨

# Load image of pizza
home_pizza = process_image("./pizza.jpg")
# Plot image along with prediction
fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111)
ax.imshow(home_pizza, cmap="gray")
ax.set_xticks([])
ax.set_yticks([])
ax.set_title(model_prediction(model, home_pizza))
plt.show()

 

3989bd584a435e278c99ddaaba7469ad.png

可以正确的分类!我们现在有一个图像分类器比可以区分比萨饼和面食。从这里,我们可以调整神经网络的一些层,优化器,损失函数,甚至考虑使用卷积,以提高我们模型的准确性。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/192530.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Sentinel 流控规则

Sentinel 是面向分布式、多语言异构化服务架构的流量治理组件,主要以流量为切入点,从流量路由、流量控制、流量整形、熔断降级、系统自适应过载保护、热点流量防护等多个维度来帮助开发者保障微服务的稳定性。 SpringbootDubboNacos 集成 Sentinel&…

ACM练习——第三天

今天继续练习C和ACM模式 在写题之前先了解一些新的知识 1.#include <algorithm> #include <algorithm> 是 C 标准库中的头文件之一&#xff0c;其中包含了一系列用于处理各种容器&#xff08;如数组、向量、列表等&#xff09;和其他数据结构的算法。这个头文件提供…

Windows下安装Anaconda5.3.1+Python3.8+TensorFlow2.13.0-CPU版本总结

Python3.8安装可以参考博文https://janus.blog.csdn.net/article/details/55274849 进行安装即可。 【1】Anaconda 清华的开源软件镜像站&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/anaconda/archive/下载&#xff0c;这里选择的是5.3.1版本。 然后正常安装就可以&am…

构建Docker基础镜像(ubuntu20.04+python3.9.10+pytorch-gpu-cuda11.8)

文章目录 一、前置条件1.创建 ubuntu 镜像源文件【sources.list】2.下载 python 安装包【Python-3.9.10.tgz】 二、构建方法1.构建目录2.创建DockerFile3.打包镜像 一、前置条件 配置一下 ubuntu 的镜像源下载 python 安装包 1.创建 ubuntu 镜像源文件【sources.list】 内容…

3ds Max渲染用专业显卡还是游戏显卡?

使用3dsmax建模时&#xff0c;会面临诸多选择&#xff0c;除了用vr还是cr的决策&#xff0c;硬件选择上也存在着疑问&#xff0c;比如用专业显卡还是消费级游戏显卡&#xff1f;一般来说&#xff0c;除非是特别专业的大型项目和软件&#xff0c;且预算在5位数以上&#xff0c;常…

保姆级使用vuedraggable三方组件

第一步 引入vuedraggable npm i vuedraggable -S 第二步 直接使用&#xff0c;源码如下 <template><draggableclass"list-group"tag"ul"v-model"list"v-bind"{animation: 1000,group: description,disabled: false,ghostClass:…

mq具体使用方式

代码方式 第一步方式导入依赖的方式 <dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!--AMQP依赖&#xff0c;包含RabbitMQ--><…

php+vue3实现点选验证码

buildadmin 中的点选验证码实现 验证码类 <?phpnamespace ba;use Throwable; use think\facade\Db; use think\facade\Lang; use think\facade\Config;/*** 点选文字验证码类*/ class ClickCaptcha {/*** 验证码过期时间(s)* var int*/private int $expire 600;/*** 可以…

理工ubuntu20.04电脑配置记录

8188gu无线网卡配置 首先下载github上的文件&#xff0c;进入文件夹 安装make命令 1. 查看usb无线网卡 sudo lsusb|grep 8188 2. 环境准备 sudo apt-get install git make build-essential git dkms linux-headers-$(uname -r) 3. 编译安装 git clone https://github.com…

Linux_磁盘管理_df命令

1、df命令是用来干什么的 df的全称是disk free&#xff0c;意为“磁盘空间”。 使用df命令可以查看系统中磁盘的占用情况&#xff0c;有哪些文件系统&#xff0c;在什么位置&#xff08;挂载点&#xff09;&#xff0c;总空间&#xff0c;已使用空间&#xff0c;剩余空间等。…

SpringBoot写接口小记 以及 几个层的功能总结(自用 勿喷)

目录 Entity层&#xff1a;实体层 数据库在项目中的类 Mapper层&#xff1a; 持久层 主要与数据库进行交互 Service层&#xff1a;业务层 控制业务 Controller层&#xff1a;控制层 控制业务逻辑 Entity层&#xff1a;实体层 数据库在项目中的类 Entity层是实体层&#xff…

医院手术麻醉信息系统(麻醉知情同意书)源码

手术室麻醉信息管理系统是定位于手术室和麻醉科的科室级临床信息管理系统&#xff0c;主要用于与手术麻醉相关的各项数据的记录、管理和应用&#xff0c;实现医疗信息的共享及再利用&#xff0c;提高科室的整体信息化水平。 该系统将手术室内的各种设备&#xff08;如呼吸机、麻…

#[量化投资-学习笔记018]Python+TDengine从零开始搭建量化分析平台-正态分布与收益率

正态分布(Normal Distribution)又叫高斯分布、常态分布。通常用来描述随机变量的概率分布。 自然界的数据分布通常是符合正态分布规律的&#xff0c;比如说人的身高、体重。但是非自然界数据就不一定了。尤其是经过人为加工过的数据。 金融领域大量使用正态分布来计算收益率和…

如何进行iOS技术博客的备案?

如何进行iOS技术博客的备案&#xff1f; 标题&#xff1a;iOS技术博客备案流程及要求解析 摘要&#xff1a; 在本篇问答中&#xff0c;我们将为iOS技术博主介绍如何进行备案。如果你的iOS应用只包含简单的页面&#xff0c;并通过蓝牙进行数据采集和传输&#xff0c;那么你可能…

Android实验:Activity界面基础

目录 前言实验目的实验内容实验要求代码实现mainActivityResultActivityactivity_mainactivity_result 结果展示 前言 我们都知道&#xff0c;activity是Android中最重要的组件之一&#xff0c;关于activity的具体内容在这里就不多赘述&#xff0c;主打的就是一个主次分明&…

源码级JVS低代码功能新增:动态配置、逻辑多级循环嵌套等等

低代码更新功能 新增: 1.下拉组件选项新增动态配置&#xff1b; 选项的内容可以根据特定的条件或数据源进行动态变化的功能&#xff0c;通过动态配置&#xff0c;用户可以灵活地设置下拉组件的选项内容&#xff0c;例如从数据库或其他数据源中获取选项数据&#xff0c;或者根…

3.3 Linux 文件管理

1、查看系统信息 tty 命令 描述&#xff1a;查看当前系统在哪个终端语法&#xff1a;tty Linux默认情况下提供6个虚拟终端来让用户登录&#xff0c;系统将F1~F6定义为tty1~tty6。 ctrlalt(F1~F6) &#xff1a;从图形界面切换到命令行界面的第 n 个虚拟终端&#xff08;F1 是…

DAY53 1143.最长公共子序列 + 1035.不相交的线 + 53. 最大子序和

1143.最长公共子序列 题目要求&#xff1a;给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长公共子序列的长度。 一个字符串的 子序列 是指这样一个新的字符串&#xff1a;它是由原字符串在不改变字符的相对顺序的情况下删除某些字符&#xff08;也可以不删…

MHA的那些事儿

什么是MHA&#xff1f; masterhight availability&#xff1a;基于主库的高可用环境下&#xff0c;主从复制和故障切换 主从的架构 MHA至少要一主两从 出现的目的&#xff1a;解决MySQL的单点故障问题。一旦主库崩溃&#xff0c;MHA可以在0-30s内自动完成故障切换 MHA使用的…

redis-5.0.8主从集群搭建、不重启修改配置文件

一、环境准备 192.168.5.100 redis-01 192.168.5.101 redis-02 192.168.5.102 redis-03 关闭防火墙、能够通网 二、安装redis [rootlocalhost ~]# wget http://download.redis.io/releases/redis-5.0.8.tar.gz [rootlocalhost ~]# tar xf redis-5.0.8.tar.gz -C /usr/loca…