咱们开门见山,实话实说。

聊聊图像识别的小原理,动手实现自己的图像分类

虽然ChatGPT带火了人工智能,但它还没找好挣钱的门路。急得投资人微软充任OpenAI的销售,大夏天的拎着2.5L的矿泉水,背着电脑包,处处下基层去跟人聊职业结合,谈产品落地。

镜头一转,在核算机视觉(Computer Vision, CV)范畴,人工智能反而挣着钱了。咱们用AI生成衣服图片替换模特,也用AI生成游戏怪物替换特效师。甚至在传统的图书出书职业,有些书本的插画,也开始用AI去生成。

因而,我打算聊聊人工智能在视觉方面的原理。然后,顺手从0到1创建一个属于自己的图画分类开放能力。

一、看看作用

为了让咱们直观感受到AI对视觉处理的能力,我先拿一个低成本的图画分类代码演示一下。后边,咱再讲原理并自己建设。

from transformers import AutoImageProcessor, ResNetForImageClassification
import torch
from PIL import Image
# 加载模型权重
processor = AutoImageProcessor.from_pretrained("model")
model = ResNetForImageClassification.from_pretrained("model")
# 挑选一个图片
image = Image.open("pics/dog.jpeg")
inputs = processor(image, return_tensors="pt")
with torch.no_grad():
    logits = model(**inputs).logits
predicted_label = logits.argmax(-1).item()
print(model.config.id2label[predicted_label])

上面利用transformers加载了一个练习好的权重,完成了一个图画分类的功用。这便是悉数的python代码。

我的项目文件结构是这样的:

|---- model # 模型权重 
    |---- cofig.json
    |---- preprocessor_config.json
    |---- pytorch_model.bin 
|---- pics # 测验图片
    |---- dog.jpeg # 随便一张狗的图片
|---- main.py # python代码文件

model文件夹下,是人家练习好的模型,咱们直接拿来用。你能够下载pytorch的权重,也能够挑选TensorFlow的权重。记得对应pip install一下它们。别的别忘了 pip install transformers

下载地址是huggingface.co/microsoft/r… 。这是微软的resnet-50模型,它是从COCO 2017数据集中找了1000类图片进行练习的产品。这些分类对应model/config.json中的id2label。

聊聊图像识别的小原理,动手实现自己的图像分类

我找了一些动物的图片来测验。我原以为它仅能区分出猫、狗、鼠、兔。没想到,它竟然还能进一步辨认详细的种类。

聊聊图像识别的小原理,动手实现自己的图像分类

如上图,它能辨认出是狗,而且是金毛犬。他能辨认出是松鼠,仍是狐狸松鼠。我又拿哈士奇和狼试了试,成果几毫秒就出正确成果了。

挺神奇!怪不得图画范畴能赚钱,这玩意儿的确有用哇。

那么问题来了,它的原理是什么?又是怎样完成的呢?

二、讲讲原理

2.1 图画的构成

你有没有想过这样一个问题:

煤炭是黑的,因它本身便是黑的。馒头是白的,因它本来便是白的。但显示器、电视,为啥一瞬间黑,一瞬间白,有时候还五彩斑斓。颜色和图画究竟是怎样被定义的呢?

想明白这个问题,有助于你了解核算机视觉。

咱们都知道(看完就知道了),红(Red)、绿(Green)、蓝(Blue)是三原色,又称RGB

这三种颜色彼此交融,可调合出人间的五彩斑斓。

聊聊图像识别的小原理,动手实现自己的图像分类

很有意思,颜色学和数学扯上了联系。赤色的RGB(255, 0, 0), 绿色的RGB(0, 255, 0)。赤色混合绿色是黄色,黄色的RGB(255, 255, 0)。如你所料,红绿蓝混在一同,便是(255, 255, 255),它是白色。

根据这个原理,咱们才能够用三组数据表明一个颜色点。同时,咱们又能够用多个颜色点表明一幅图。这一点,咱们经过显示器的屏幕就能看得出来。

聊聊图像识别的小原理,动手实现自己的图像分类

你的电脑、手机的显示器,便是由很多个小像素格子组成的。仅仅它太小太密布,你看不出来。假如,你往屏幕上滴一滴水,就会发现其中的奥妙。

至此,我想表达,咱们能够用数字来描绘任何一幅图。它无非便是横竖(宽高)有多少个点,每个点是什么颜色(RGB的数值)。

聊聊图像识别的小原理,动手实现自己的图像分类

那么对这些个数据,咱们能做什么呢?

2.2 聊透卷积神经网络的原理

说到图画处理,不得不提卷积神经网络(Convolutional Neural Network, CNN)。它构建起一个层级化的模型,可谓是经典中的经典。

CNN三板斧卷积层(Convolutional Layer)、池化层(Pooling Layer)和全衔接层(Fully Connected Layer)。

一般的文章说到卷积层,大多会放出这样的图。

聊聊图像识别的小原理,动手实现自己的图像分类

而且配上文字解说说:小绿方块是个33的卷积核,在淡蓝色55像素的图上以1为步长行进。在不填充的情况下,最大能走3步。所以,终究形成右侧33的成果。这个卷积核,便是一个特征提取器,能过滤它所关注的数据特征。

这……说得没错。但对初学者来说,仍是很笼统:它怎样就学会过滤特征了?它又过滤了什么样的特征?

首要,做卷积运算应该不难了解。下面这幅图,演示了卷积运算。

聊聊图像识别的小原理,动手实现自己的图像分类

这是一个33的卷积核。它每个格子都带参数。从图画上卷过之后,将图上的像素和自己进行运算,终究输出卷积后的数据。上面的卷积成果让概括愈加明显。

卷积层在参加练习时,它的参数是可变的。它会经过学习来改变自己的数值。它先随机猜测一个特征,比方只需中心点的像素,其它全都0变为空白。在验证的过程中,假如猜对了,当然挺好。假如猜不对,那么再进行改变,直到接近正确答案。

一套神经网络,会有好多个卷积层。每个卷积层,又会有好多个卷积核。这样就能够从不同的维度来搜集一张图片的特征。甚至说,还能够前面卷完了后边接着卷。

咱们看下面这张经典的VGG-19的结构图。33 conv,64表明有6433的卷积核在一张图片上提取信息。后边还有128个、256个。

聊聊图像识别的小原理,动手实现自己的图像分类

卷积就像是提取一个学生的成果。前面卷数学核算,中心卷体能目标,后边卷文学涵养。甚至在文学大类中,再提取关于诗人“李白”的专项查核。总归便是要找不同,要靠特征来断定你是不是优秀学生。不得不说卷积的“卷”,翻译得很到位。

经过练习,模型合格,每个卷积核都会得到合适的参数值。这就比方关于评价学生,咱们先猜了一个自认为靠谱的方案。然后经过多轮测验和调整,终究形成了一套量化标准。

那么,卷积层的参数能看吗?都说AI是黑盒,不知道它发生了什么!这句话虽然没错,但在一些简略的场景,还不至于上升到玄学的境地。

模型权重(终究练习出来的那玩意儿)定型后,会体现在模型参数的数值上。整个网络有多少层结构,每层的数值是多少,其实能打印,不过满是向量,你看不出啥道道。但是,假如咱们生成噪点图画,让图画的特征向卷积核的权重挨近,去极大化这个特征,那么或许能够有些收获。

下面,我解剖一个图片分类网络结构的权重。我挑选几个层,然后极大化这些数值,也输出了一些视觉的成果。这个操作稍微有点专业,因而我仅摆出来作用,期望帮助咱们从视觉上去加深了解。请原谅我不去细讲它。

聊聊图像识别的小原理,动手实现自己的图像分类

我并没有拿生物书上的细胞相片来忽悠您,虽然这两者有点像。这的确是将神经网络的权重碎片“反编译”成图片的成果。或许这个成果,让那些持有“生物便是核算机程序”这一观念的人很兴奋。

其实有些图片也并不笼统,或多或少也能推测出一些特征信息。

聊聊图像识别的小原理,动手实现自己的图像分类

看来这个卷积层的含义便是对图画进行特征提取。它经过撒出很多的卷积核,去发掘一张图中存在的独特边缘或是纹理,从而给下流分类任务提供判断根据。

这一层接一层地卷积,是不是太卷了?不累吗?

设计者也考虑到了这个问题,因而引入了池化层(Pooling layer)的概念。

池化层能够在必定程度上解决过“卷”的问题!其手段就类似于灭霸的响指,会让样本中一半的像素消失。看下面这个图。

聊聊图像识别的小原理,动手实现自己的图像分类

上图选用的是最大池化(Max Pooling)。一个22的池化窗口,在图片上行进。它所经过的地方,取一个窗口内最大的数值作为输出。

按照这个装备,它能够将一张8080的样本缩小到4040。而且你看上面的图,即便是缩小后,特征也不变,还能看出本来的概括。假如不嫌麻烦,你再往上翻找到那张VGG-19的结构图。output size开始是224,经过pool,/2之后就变成了112,少了一半。这便是池化起的作用。

在算力不变的情况下,数据量成半砍,那干活肯定快,空出的时间能够去休闲。所以我说它“反卷”。

在练习时,卷积层的卷积核参数会重复调整并纠正。而池化层不必动脑子,没东西参加练习,要么找一个最大值,要么找一个平均值(平均池化, Average Pooling)。安逸得很!

池化层一般搭配着卷积层使用。这似乎是程序员在对外宣扬:人生要间隔着“卷一程”、“躺一程”。

聊聊图像识别的小原理,动手实现自己的图像分类

经过神经网络的层层提取,到后期基本上就浓缩出了很多的样本特征。此刻经过全衔接层(Fully Connected Layer)进行判决。它是组委会的决赛评委。它的作业简略且重要。前面甭管多少层,都是在搜集特征,就像是上报学生的证书、成果、荣誉、行为、美德、习气等数据。到全衔接层这里,会对特征数据进行加权求和并评分,给出终究成果。

好了,卷积神经网络的组成,咱们就讲完了。下面,咱们就自己去攒一个网络去完成图画分类。

三、详细完成

我想练习个辨认气候相片的分类模型。咱们的气候一般分为三类:晴天、多云、有雨。

因而,我找到了一些相关的图片数据,作为数据集。

图片样例如下:

聊聊图像识别的小原理,动手实现自己的图像分类

将图片整理成如下的目录结构:

mian.py 程序文件
[datasets] 数据集文件夹
   |--- [cloudy] 多云
   |--- [rain] 有雨
   |--- [shine] 晴天

所以,咱们要练习的图片是3类:cloudyrainshine。咱们练习完,让模型对一张陌生图片进行分类,也会是其中之一。就算不像,成果也得是:分类 cloudy, 得分 0.01。这便是分类问题。除此之外还有一个回归问题,它能给出无限的成果,比方明天的股市数据。

# 分类称号
names = ['cloudy', 'rain', 'shine'] 

有了图片数据,就有了种子。趁着热乎劲儿,咱们先来建立卷积神经网络。

本次挑选TensorFlow作为AI结构。我的原则是小数据量用TensorFlow,大数据量用Torch

以下代码运行环境:python 3.9, tensorflow 2.6

3.1 神经网络结构

首要导入tensorflow的包。然后构建一个卷积神经网络。

import tensorflow as tf
from tensorflow.keras import layers
from tensorflow.keras.models import Sequential
model = Sequential([
  layers.Rescaling(1./255, input_shape=(200, 200, 3)),
  layers.Conv2D(16, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(32, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Conv2D(64, 3, padding='same', activation='relu'),
  layers.MaxPooling2D(),
  layers.Dropout(0.2),
  layers.Flatten(),
  layers.Dense(128, activation='relu'),
  layers.Dense(3)])

前面咱们现已学过了卷积神经网络的结构。它的入口是图片数据,后边是卷积层和池化层循环替换。随后,接上全衔接层,直达分类的输出。

咱们看上面的代码也是这样。主体是卷积层Conv2D搭配着池化层MaxPooling2D。最上层的input_shape=(200, 200, 3)是图片输入的尺寸,表明200200像素,3代表RGB三通道。到最后Dense(3)输出3个分类。这便是咱们设计的网络。

里边的多少个卷积核,每个是几几,这个咱们自己定,就跟搭积木似的,调这些玩意儿才是终究趣味。

有两点需求说明一下:

  • Dropout(0.2)能够不必。这才是灭霸的响指,它是真的随机断掉20%的参数。目的是防止过拟合。你想啊,剩下的80%都能猜测精确,那么它的通用性肯定差不了。
  • Flatten()也叫“拉平层”。咱们输入的图片以及后边的卷积池化,都是2维的,有宽有高。但终究咱们要输出3分类,这是1维的。因而经过拉平层把2维拉成1维。即:[[1,2],[3,4]]->[1,2,3,4]。便利后边核算。

神经网络的建立就这么简略。请记住咱们现已有了一个model,便是刚才经过Sequential实例化出来的,后边还会用到。

3.2 练习数据

有了神经网络。下面要将数据交给它去练习。经过练习,会把模型里的每个层的模型参数给练出来。所以,它才能完成从量变到质变,拥有智慧,完成自我分类。

# 加载练习数据
train_ds = tf.keras.utils.image_dataset_from_directory(
  "datasets", image_size=(200, 200), batch_size=24)

咱们现已准备好练习的图片文件夹datasets了。现在就加载这些数据。而且把里边的图片都规范成image_size=(200, 200)batch_size=24是把数据以24个化为一组,否则太大吃不下。

假如你履行上面的代码的话,控制台会打印如下内容:

Found 768 files belonging to 3 classes.

它说找到了768个文件,属于3个分类。这正好对应我的datasets文件夹下3个子文件夹和768张图片。

随后,给模型model装备一下,然后启动练习。

model.compile(optimizer='adam',
    loss=tf.keras.losses.SparseCategoricalCrossentropy(from_logits=True), 
    metrics=['accuracy'])
cp_callback = tf.keras.callbacks.ModelCheckpoint(filepath="tf2/checkpoint", save_weights_only=True)
model.fit(train_ds, epochs=10, callbacks=[cp_callback])

model.compile是装备优化器选adam。其余装备丢失函数,衡量目标,这些记住就能够。对初学来说,一般不会变。

ModelCheckpoint指定了权重保存的策略,也便是练习成果保存途径是tf2/checkpoint,只保存权重。

model.fit这一行代码便是说对train_ds数据进行练习,练习10个次序,练习成果回调权重保存策略。

假如履行正常的话,会有如下打印:

Epoch 1/10
32/32 [==========] - loss: 0.8752 - accuracy: 0.6589
Epoch 2/10
32/32 [==========] - loss: 0.4711 - accuracy: 0.8255
Epoch 3/10
32/32 [==========] - loss: 0.3381 - accuracy: 0.8854
Epoch 4/10
……
Epoch 9/10
32/32 [==========] - loss: 0.1136 - accuracy: 0.9583
Epoch 10/10
32/32 [==========] - loss: 0.0623 - accuracy: 0.9831

练习10Epoch。一共768张图,每个batch是24,所以需求768/24=32次才能遍历一次。

accuracy是精确率,随着Epoch增加,精确率现已到了98%以上。

每一个Epoch结束后,你去看tf文件夹下,会生成模型的权重。

mian.py
[datasets]
[tf] 权重文件夹
   |--- checkpoint
   |--- checkpoint.data-00000-of-00001
   |--- checkpoint.index

好吧,这就练习完了!

3.3 猜测数据

我从网上搜到这么一张图片,这是模型从未见过的图片。

聊聊图像识别的小原理,动手实现自己的图像分类

咱们来猜测一下,它会属于哪个分类。

# 加载模型
model.load_weights("tf2/checkpoint")  
# 导入图片
img = tf.keras.utils.load_img("test.png", target_size=(200, 200))
img_array = tf.keras.utils.img_to_array(img)
img_array = tf.expand_dims(img_array, 0)
# 进行猜测
predictions = model.predict(img_array)
score = tf.nn.softmax(predictions[0])
# 输出分类
print( "分类 {}, 得分 {:.2f}".format(names[np.argmax(score)], 100*np.max(score)))

上面代码是利用tensorflow加载图片,并转换为模型需求的格式。调用model.predict能够进行猜测。终究成果是一批独热数据,经过tf.nn.softmax能够读出来。

假如一切正常,控制台会输出:

1/1 [==========] - 0s 171ms/step
分类 cloudy, 得分 78.98

是的,这张图的确是多云。看来,模型仍是挺有作用的。

四、小总结

最后,我给咱们布置个作业。虽然文中讲解的内容现已够用。但我仍是将愈加健壮的代码上传到了Github。地址是github.com/hlwgy/jueji…

里边涉及到了一些细节,比方数据缓存、验证集、练习曲线等。咱们能够检查完好代码,去了解更详尽的知识。

聊聊图像识别的小原理,动手实现自己的图像分类

很棒,我讲完了,您听完了。您现在能够练习自己的数据,去完成自己的业务。不必花钱买API接口,想怎样玩就怎样玩!

关键是,它也不复杂呀!

本文为稀土技能社区首发签约文章,30天内制止转载,30天后未获授权制止转载,侵权必究!