用封面预测书的价格【图像回归】

news2025/2/26 5:10:03

今天,我将介绍计算机视觉的深度学习应用,用封面简单地估算一本书的价格。 我没有看到很多关于图像回归的文章,所以我为你们写这篇文章。

距离我上一篇文章已经过去很长时间了,我不得不承认,作为一名数据科学家,我用于副业或写文章的时间更少了(或者,也许这只是我的懒惰)。

如果你对本文旁边的编码感兴趣,请查看此 GitHub。

在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 

1、数据

本文使用的数据可以从此处提供的 Kaggle 数据集下载。 它包含来自 BookDepository 网站的书籍特征数据,但我们将主要使用书籍封面图像来训练深度学习模型。 现在让我们看看图书数据是什么样的。

import pandas as pd 
df= pd.read_csv('main_dataset.csv')
df

数据的形状为  (32581, 11),但在本文中,我们将仅关注“图像”和“价格”字段给出的书籍封面图像数据和价格标签(不是旧价格)。 如果仔细查看加载的数据,我们会发现除了“图像”列中给出的图像 URL 之外,我们没有图像数据。 原因是图像数据是非结构化数据,不能与其他数据采用相同的格式。

抛开这些原因不谈,我如何访问这种格式的图像数据? 我需要创建一个函数来从这些 URL 中获取图像并将它们全部加载到文件夹图像中。

2、加载并查看图片

from matplotlib import pyplot as plt
import numpy as np
import urllib
import cv2
def show_image_from_url(image_url):
"""
  Fetches image online from the image_url and plots it as it is using matplotlib's pyplot's image show
  """
response = urllib.request.urlopen(image_url)
  image = np.asarray(bytearray(response.read()), dtype="uint8")
  image_bgr = cv2.imdecode(image, cv2.IMREAD_COLOR)
  image_rgb = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2RGB)
  plt.imshow(image_rgb), plt.axis('off')

上面的函数将从图像 URL 获取图像,并使用 matplotlib 和 OpenCV 库显示图像。 让我们看看该函数是如何工作的:

plt.figure()
show_image_from_url(df['image'].loc[10])

我们得到了Michael Mosley 撰写的 The Clever Guts Diet 一书的封面。 现在你看到我们可以显示给定 URL 中的图像,是时候获取图像并将其加载到你的计算机以将其放入深度学习中了。

3、图像预处理

下面是一个相当长的函数,因为它不仅加载图像,还进行图像预处理—转换为灰度、裁剪和调整图像大小。 所有这些预处理都是为了让覆盖数据更加一致,适合即将到来的深度学习:

def image_processing(image_url):
"""Converts the URL of any image to an array of size 100x1 
    The array represents an OpenCV grayscale version of the original image
    The image will get cropped along the biggest red contour (4 line polygon) tagged on the original image (if any)
    """
#Download from image url and import it as a numpy array
    response = urllib.request.urlopen(image_url)
    image = np.asarray(bytearray(response.read()), dtype="uint8")
#Read the numpy arrays as color images in OpenCV
    image_bgr = cv2.imdecode(image, cv2.IMREAD_COLOR)
#Convert to HSV for creating a mask
    image_hsv = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2HSV)
#Convert to grayscale that will actually be used for training, instead of color image 
    image_gray = cv2.cvtColor(image_bgr, cv2.COLOR_BGR2GRAY)
#Create a mask that detects the red rectangular tags present in each image
    mask = cv2.inRange(image_hsv, (0,255,255), (0,255,255))
#Get the coordinates of the red rectangle in the image, 
    #But take entire image if mask fails to detect the red rectangle
    if len(np.where(mask != 0)[0]) != 0:
        y1 = min(np.where(mask != 0)[0])
        y2 = max(np.where(mask != 0)[0])
    else:
        y1 = 0                                     
        y2 = len(mask)
if len(np.where(mask != 0)[1]) != 0:
        x1 = min(np.where(mask != 0)[1])
        x2 = max(np.where(mask != 0)[1])
    else:
        x1 = 0
        x2 = len(mask[0])
#Crop the grayscle image along those coordinates
    image_cropped = image_gray[y1:y2, x1:x2]
    if image_cropped.size ==0:
        print(image_url)
        return image_cropped
    else:
    #Resize the image to 100x100 pixels size
        image_100x100 = cv2.resize(image_cropped, (100, 100))
#Save image as in form of array of 10000x1
        image_arr = image_100x100.flatten()
return image_arr

预处理的阶段包括:

  • 灰度化:灰度表示经常用于提取描述符而不是直接对彩色图像进行操作的主要原因是灰度简化了算法并降低了计算要求。 大多数时候,HSV 格式中的颜色并不重要,灰度可以轻松完成相同的工作。
  • 裁剪:图像裁剪是一种常见的照片处理过程,它通过删除不需要的区域来改善整体构图。 显然,图像的角落并不是人类感知图像的焦点,我们只关注中心。 书的封面一角并没有对其书的价格留下任何解释力,而且大部分都是相同的。
  • 调整大小:为了促进小批量学习,我们需要给定批次内的图像具有固定的形状。 这就是为什么需要初始调整大小的原因。 我们首先将所有图像的大小调整为 (300 x 300) 形状,然后学习它们在 (150 x 150) 分辨率下的最佳表示。 调整大小并不能以任何方式帮助我们改进模型,这只是数据通过神经网络的方式,需要相同的结构。

4、加载数据

现在我们将该函数应用于图像 URL 列以获取图像数据。 请注意,这将花费你一两个小时来加载整个数据集。 如果想快速工作,你可以加载至少 2000 个 URL,这将花费大约 20 到 30 分钟。

from tqdm import tqdm
for url in tqdm(df['image'].tolist()[:]): # 3000 urls is enough
    image_list.append(image_processing(url))

请注意,你的图像不再是 PNG 或 JPEG。 现在它是 NumPy 对象中具有灰度的像素向量。 这就是你需要在深度学习模型中传递的内容。

X = np.array(image_list)
np.save('processed_100x100_image.npy',X/255,allow_pickle=True)
book_array = np.load('processed_100x100_image.npy',allow_pickle=True)

现在,加载数据并将其保存在 image_list 中,它只是存储在你的代码中,这是不好的做法,因为每次想要再次获取这些数据时,都必须浪费 30 分钟。 所以这里需要将那些处理后的图像数据保存到本地计算机中。

5、清理不同尺寸的图像和价格标签

要将数据传递到深度学习模型中,所有数据都需要具有相同的维度,即 100x100。 但是,当我查看处理后的图像 NumPy 数组时,我发现存在一些错误,即某些图像与其他图像的尺寸不同,因此我们需要在训练模型之前删除这些图像。

#remove non 10000 dimension out of the numpy array
X =[]
exclude =[]
for i in range(len(book_array)):
    if book_array[i].shape == (10000,):
        X.append(book_array[i])
    else:
        exclude.append(i)
X =np.array(X)
#also remove from the dataframe
df.drop(df.index[exclude],inplace=True)

在这里,我删除了与 100x100 尺寸不同的数据,并从数据框中删除了这些数据,因为我们需要使用价格标签数据,而我们不希望有任何复杂的数据映射或不匹配。

import re
df['price'] = df.price.apply(lambda x :re.sub("[^0-9.]",'',x)).apply(float)

价格标签中会有非数字值,如“$”、“dollars”等,不适用于运行深度模型。 我将使用正则表达式仅保留数字。

6、预处理后的图像示例

执行如下代码随机选择两张预处理后的图片并显示:

np.random.seed(17)
for i in np.random.randint(0, len(book_array), 2):
    plt.figure()
    plt.imshow(book_array[i].reshape(100, 100), cmap='gray'), plt.axis('off')

 

7、卷积神经网络

为了估算这本书的价格,在这项任务中,我将使用卷积神经网络或 CNN,它是针对涉及图像数据作为输入的任何类型的预测问题最有效的深度学习模型之一。

简而言之,CNN 算法会将图像简化为更易于处理的形式,而不会丢失对于获得良好预测至关重要的特征。

from tensorflow.keras.utils import to_categorical
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Conv2D, MaxPool2D, BatchNormalization
from tensorflow.keras.layers import Activation, Dropout, Flatten, Dense
from tensorflow.keras.losses import categorical_crossentropy
from tensorflow.keras.optimizers import Adam
from tensorflow.keras.callbacks import ModelCheckpoint
from tensorflow.keras.models import load_model
#Define a Convolutional Neural Network Model
model = Sequential()
model.add(Conv2D(filters = 16, kernel_size = (3, 3), activation='relu',
                 input_shape = input_shape))
model.add(BatchNormalization())
model.add(Conv2D(filters = 16, kernel_size = (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(strides=(2,2)))
model.add(Dropout(0.25))
model.add(Conv2D(filters = 32, kernel_size = (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(Conv2D(filters = 32, kernel_size = (3, 3), activation='relu'))
model.add(BatchNormalization())
model.add(MaxPool2D(strides=(2,2)))
model.add(Dropout(0.25))
model.add(Flatten())
model.add(Dense(512, activation='relu'))
model.add(Dropout(0.25))
model.add(Dense(1024, activation='relu'))
model.add(Dropout(0.4))
#model.add(Dense(n_classes, activation='softmax'))
model.add(Dense(1, activation='relu'))
learning_rate = 0.001
model.compile(loss = 'mse',
              optimizer = Adam(learning_rate))
model.summary()
Model: "sequential_1"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
conv2d_4 (Conv2D)            (None, 98, 98, 16)        160       
_________________________________________________________________
batch_normalization_4 (Batch (None, 98, 98, 16)        64        
_________________________________________________________________
conv2d_5 (Conv2D)            (None, 96, 96, 16)        2320      
_________________________________________________________________
batch_normalization_5 (Batch (None, 96, 96, 16)        64        
_________________________________________________________________
max_pooling2d_2 (MaxPooling2 (None, 48, 48, 16)        0         
_________________________________________________________________
dropout_4 (Dropout)          (None, 48, 48, 16)        0         
_________________________________________________________________
conv2d_6 (Conv2D)            (None, 46, 46, 32)        4640      
_________________________________________________________________
batch_normalization_6 (Batch (None, 46, 46, 32)        128       
_________________________________________________________________
conv2d_7 (Conv2D)            (None, 44, 44, 32)        9248      
_________________________________________________________________
batch_normalization_7 (Batch (None, 44, 44, 32)        128       
_________________________________________________________________
max_pooling2d_3 (MaxPooling2 (None, 22, 22, 32)        0         
_________________________________________________________________
dropout_5 (Dropout)          (None, 22, 22, 32)        0         
_________________________________________________________________
flatten_1 (Flatten)          (None, 15488)             0         
_________________________________________________________________
dense_3 (Dense)              (None, 512)               7930368   
_________________________________________________________________
dropout_6 (Dropout)          (None, 512)               0         
_________________________________________________________________
dense_4 (Dense)              (None, 1024)              525312    
_________________________________________________________________
dropout_7 (Dropout)          (None, 1024)              0         
_________________________________________________________________
dense_5 (Dense)              (None, 1)                 1025      
=================================================================
Total params: 8,473,457
Trainable params: 8,473,265
Non-trainable params: 192

我们将创建一个具有四个卷积层和过滤器 [16,16,32,32] 的 CNN 模型,然后该架构师将池化特征图转换为单个列,并传递到全连接层。

save_at = "model_regression.hdf5"
save_best2 = ModelCheckpoint (save_at, monitor='val_accuracy', verbose=0, save_best_only=True, save_weights_only=False, mode='max')
#set up the x, y for training 
Y = np.array(df.price.tolist())
X_test = X[30000:,]
Y_test = Y[30000:,]
X_train, X_val, Y_train, Y_val = train_test_split(X[:30000,], Y[:30000,], test_size=0.15, random_state=13)
img_rows, img_cols = 100, 100
input_shape = (img_rows, img_cols, 1)
X_train = X_train.reshape(X_train.shape[0], img_rows, img_cols, 1)
X_test = X_test.reshape(X_test.shape[0], img_rows, img_cols, 1)
X_val = X_val.reshape(X_val.shape[0], img_rows, img_cols, 1)

前三行是设置训练完成后保存模型的参数。 剩下的就是为训练集和测试集设置目标或价格为 y。 现在我们正在使用 15 个 epoch 和 batch_size 为 100 来训练模型。如果你的计算机有足够的资源,请继续输入与 batch_size 一样多的数据,然后运行以下代码:

history = model.fit( X_train, Y_train, 
                    epochs = 15, batch_size = 100, 
                    callbacks=[save_best2], verbose=1, 
                   validation_data = (X_val, Y_price_val))

在这里,你可以看到模型正在过度拟合,绿线或验证损失约为 200,而红线或训练损失则越来越低。 当我将模型设置为保存最低的验证损失时,我们的模型性能将在第七个epoch保存。

plt.figure(figsize=(6, 5))
# training loss
plt.plot(history.history['loss'], color='r')
#validation loss
plt.plot(history.history['val_loss'], color='g')
plt.show()

让我们看看模型结果是什么:

Y_pred = np.round(model.predict(X_test))
np.random.seed(23)
for rand_num in np.random.randint(0, len(Y_test), 10):
    plt.figure()
    plt.imshow(X_test[rand_num].reshape(100, 100),cmap='gray'), plt.axis('off')
    if np.where(Y_pred[rand_num] < 10)[0].sum() == np.where(Y_test[rand_num] <10)[0].sum():
        plt.title(str(Y_pred[rand_num]) +' dollars', color='g')
    else :
        plt.title(str(Y_pred[rand_num]) +' dollars', color='r')

 

8、进一步的工作

我我们构建了一个基于封面的书籍价格预测器,希望你也可以将其应用于其他应用程序。 请注意,该模型仍然需要针对过度拟合进行调整,以使其能够很好地适应现实世界。 你可以采取一下错误来解决 CNN 中的过度拟合问题。

  • 添加更多数据
  • 使用数据增强
  • 使用泛化良好的架构
  • 添加正则化(主要是dropout,L1/L2正则化也是可以的)
  • 降低架构复杂性。

原文链接:用封面预测书价 - BimAnt

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OceanBase杨冰:完全自研,才能逢山开路遇水搭桥

11月16日&#xff0c;在OceanBase2023年度发布会上&#xff0c;OceanBase CEO杨冰介绍&#xff0c;中国数字经济的蓬勃发展催生了对分布式数据库的强大需求&#xff0c;这种需求也牵引了OceanBase坚定投入自主研发&#xff0c;从而推动树立了分布式数据库的四项新标准。 据了解…

Harmony SDK API 版本 与 Harmony OS 版本对照表,及如何查看鸿蒙手机Harmony SDK Api 版本

Harmony SDK API 版本 与 Harmony OS 版本对照表 Harmony OSHarmony SDK APIHarmony 4.09Harmony 3.19Harmony 3.08Harmony 3.0 pre7Harmony 2.2.06Harmony 2.1.05Harmony 2.04 具体到真机上可能会有差异&#xff0c;如我的手机OS版本是2.0&#xff0c;按照上面表应该是4&…

jsp中使用PDF.js实现pdf文件的预览

本文介绍的是在使用jsp作为模板引擎的spring-mvc项目中&#xff0c;如何利用 PDF.js实现pdf文件的预览。 1、下载 PDF.js Getting Started (mozilla.github.io) 下载解压后其中有两个目录&#xff0c;直接将这两个文件夹放到项目的web资源目录中。此时相当于把PDF.js这个项目也…

使用Kohya_ss训练Stable Diffusion Lora

Stable Diffusion模型微调方法 Stable Diffusion主要有 4 种方式&#xff1a;Dreambooth, LoRA, Textual Inversion, Hypernetworks。 Textual Inversion &#xff08;也称为 Embedding&#xff09;&#xff0c;它实际上并没有修改原始的 Diffusion 模型&#xff0c; 而是通过…

Android 14 Beta 1

Android 14的第一个 Beta 版&#xff0c;围绕隐私、安全、性能、开发人员生产力和用户定制等核心主题构建&#xff0c;同时继续改进平板电脑、可折叠设备等大屏幕设备的体验。我们一直在完善 Android 14 的功能和稳定性方面取得稳步进展&#xff0c;现在是时候向开发者和早期采…

软件系统集成指南

软件产品集成是将各种软件组件、模块和代码组装成最终可执行、可应用的软件产品的过程。这个过程涉及到将工作产品转化为产品的组装过程。在软件工程中&#xff0c;产品集成是一个重要的环节&#xff0c;通过持续性集成&#xff0c;将产品集成的过程常态化、自动化。做好产品集…

收集整理微信小程序源码精选8500套(不同行业的源码集合)/带后台+含搭建开发教程

这下面分享的是精心收集整理的微信小程序源码精选8500套&#xff0c;它含有不同行业的源码集合&#xff0c;带后台&#xff0c;而且含搭建开发教程。可以转存起来&#xff0c;需要的时候直接搜索关键词查找就行了&#xff0c;方便得很。 很多伙伴学习小程序不知怎么开始&#…

【Vue-Demo】倒计时3秒后返回首页

首页path:/ 倒计时结束后要清除计时器&#xff0c;防止内存泄漏&#xff1a; if (this.count 0) {clearInterval(this.timer); }<!-- ErrorJump.vue --> <template><h2>Error&#xff1a;找不到页面&#xff01;</h2><h4>{{ count }}S后<R…

01序列 卡特兰数

解法&#xff1a; 将01序列置于坐标轴上&#xff0c;起始点为原点。0表示向右走&#xff0c;1表示向上走。这样就可以将前缀0的个数不少于1的个数就可以转换为路径上的点&#xff0c;横坐标大于纵坐标&#xff0c;也就是求合法路径个数。 注意题目mod的数是质数&#xff0c;所…

【嵌入式项目应用】__单片机STM32有什么好的裸机程序架构思路推荐?

目录 前言 没设计好程序架构&#xff0c;根本做不稳定。 按照我的思维&#xff0c;我会这样去设计程序&#xff1a; 那这样的好处是什么&#xff1f; (*&#xffe3;︶&#xffe3;)创作不易&#xff01;期待你们的 点赞、收藏和评论喔。 前言 在我刚出来的时候&#x…

Android笔记(十三):结合JetPack Compose和CameraX实现视频的录制和存储

在“Android笔记&#xff08;八&#xff09;&#xff1a;基于CameraX库结合Compose和传统视图组件PreviewView实现照相机画面预览和照相功能”&#xff0c;文中介绍了拍照功能的实现&#xff0c;在本文中将介绍结合JetPack Compose和CameraX实现视频的录制。 新建一个项目 在项…

nn.Embedding()的原理

nn.Embedding()的原理&#xff1a; 定义一个Embedding&#xff1a; embeddings nn.Embedding(num_embeddings10, embedding_dim3)vocab_size : 10 输出维度为&#xff1a; 3 假定输入inputs如下&#xff1a; inputs torch.tensor([[1,3,6, 8],[9,1,3,5] ],dtypetorch.lo…

达索系统SOLIDWORKS Electrical机电一体化协同设计

一秒读懂 SOLIDWORKS Electrical 问题点 电气、机械设计各自为政数据传递困难&#xff0c;存在设计错误 CHALLENGE电气设计面临挑战 问题点&#xff1a;电气、机械设计各自为政数据传递困难&#xff0c;存在设计错误 原理图绘制完毕后&#xff0c;再绘制接线图,人工统计BOM&a…

Valgrind——程序分析工具

目录 Valgrind一.摘要二.安装Valgrind三,简单上手和分析程序1(C程序):使用未初始化的内存程序2(C程序):在内存被释放后进行读/写程序3(C程序): 内存泄露程序4(C程序): 不匹配使用malloc free 和 new delete程序5(C程序): 两次释放内存 四.Qt中使用Valgrind五.内存泄露分析 Valg…

Java学习day12:static关键字,字符串声明,字符串常量池

声明&#xff1a;该专栏本人重新过一遍java知识点时候的笔记汇总&#xff0c;主要是每天的知识点题解&#xff0c;算是让自己巩固复习&#xff0c;也希望能给初学的朋友们一点帮助&#xff0c;大佬们不喜勿喷(抱拳了老铁&#xff01;) 往期回顾&#xff1a; Java学习day11&…

HBase中的数据表是如何用CHAT进行分区的?

问CHA&#xff1a;HBase中的数据表是如何进行分区的&#xff1f; CHAT回复&#xff1a; 在HBase中&#xff0c;数据表是水平分区的。每一个分区被称为一个region。当一个region达到给定的大小限制时&#xff0c;它会被分裂成两个新的region。 因此&#xff0c;随着数据量的增…

Unity | 运行时显示调试信息

「公众号&#xff1a;游戏开发手记」 1 简介 在 Unity 编辑器中&#xff0c;我们可以通过点击 Stats 按钮来查看 Statistics 面板&#xff0c;这个面板显示了许多关于游戏渲染的信息&#xff0c;如每帧的渲染时间、Tris 和 Verts 的数量、SetPass Calls 的数量等。但在其他运…

Spring6(五):Resources、i18n、Validation

文章目录 7. 资源操作&#xff1a;Resources7.1 Resource接口7.2 Resource的实现类7.2.1 UrlResource访问网络资源7.2.2 ClassPathResource 访问类路径下资源7.2.3 FileSystemResource 访问文件系统资源7.2.4 其他 7.3 Resource类图7.4 ResourceLoader 接口7.5 ResourceLoaderA…

EV代码签名证书

为了增强软件的安全性和可信度&#xff0c;EV代码签名证书&#xff08;Extended Validation Code Signing Certificate&#xff09;成为了一种具有最高级别保障的关键工具。 EV代码签名证书是一种由受信任的证书颁发机构&#xff08;CA&#xff09;或证书供应商提供的高级别代…

linux之shell

一、是什么 Shell是一个由c语言编写的应用程序&#xff0c;它是用户使用 Linux 的桥梁。Shell 既是一种命令语言&#xff0c;又是一种程序设计语言 它连接了用户和Linux内核&#xff0c;让用户能够更加高效、安全、低成本地使用 Linux 内核 其本身并不是内核的一部分&#x…