『跟着雨哥学AI』系列之七:趣味案例——动手制作专属证件照
點擊左上方藍字關注我們
課程簡介:
“跟著雨哥學AI”是百度飛槳開源框架近期針對高層API推出的系列課。本課程由多位資深飛槳工程師精心打造,不僅提供了從數據處理、到模型組網、模型訓練、模型評估和推理部署全流程講解;還提供了豐富的趣味案例,旨在幫助開發者更全面清晰地掌握百度飛槳框架的用法,并能夠舉一反三、靈活使用飛槳框架進行深度學習實踐。
前言:?嗨,同學們好,我是雨哥,又是一年畢業季啦,很多同學今年三月或者六月份就陸陸續續從學校畢業啦,那么不管是繼續深造還是著手找工作都需要我們自己提前制備一份充實的簡歷。制備簡歷那就自然少不了一張好看的證件照了,然而每個單位對證件照的要求各不相同,有的需要白底,有的需要紅底,除此之外攝影師的水平也隨心所欲,還不如我們手機前置攝像頭的自拍。既然如此,那么今天我們就結合我們之前學過的理論知識,制作一個專屬證件照吧。
證件照的制作原理?
開始之前同學們會有幾個疑問,什么是證件照的制作呢?我們該如何去制作證件照呢?
本次的證件照制作是基于我們手機中普通的正面自拍照片,簡單來說,我們需要制作一個生成證件照的系統,輸入一張生活正面自拍照,就會輸出一個白底或者藍底的證件照。大家是不是已經明白了?簡而言之我們的制作的核心工藝在于摳圖,通過一張生活自拍照,我們使用深度學習模型去掉我們生活照雜亂的背景,扣出我們的正面自拍,搭配純色背景,就可以快速制作一款令我們滿意的證件照。
By the way,畢竟攝影師是我們自己,拍的丑了也不能打自己~
在計算機視覺領域,摳圖可以通過圖像分割技術來實現,而圖像分割技術指的是將數字圖像細分為多個圖像子區域的過程。其實,圖像分割的目的是簡化或改變圖像的表示形式,使得圖像更容易理解和分析。圖像分割通常用于定位圖像中的物體和邊界(線,曲線等)。更精確的說,圖像分割是對圖像中的每個像素加標簽的一個過程,這一過程使得具有相同標簽的像素具有某種共同視覺特性。
圖像分割的應用領域非常多,無人車、地塊檢測、表計識別等等。
證件照的制作流程?
萬變不離其宗,我們需要遵循如下圖所示的框架。從左到右,數據集的準備、數據的預處理及加載、模型組建、模型訓練、模型測試以及模型預測等。本教程將簡要介紹如何通過飛槳開源框架的高層API實現圖像分割技術,實現證件照的制作。?
Note:有同學問(其實沒同學問),為什么這個圖要畫成U型啊,很奇怪唉?咳咳,只是單純的為了和下文呼應一下,下面介紹我們的嘉賓。
本教程中我們采用了一個在圖像分割領域比較熟知的U-Net網絡結構,是一個基于FCN做改進后的一個深度學習網絡,包含下采樣(編碼器,特征提取)和上采樣(解碼器,分辨率還原)兩個階段,因模型結構比較像U型而命名為U-Net。模型結構如下圖所示。
Ronneberger O , Fischer P , Brox T . U-Net: Convolutional Networks for Biomedical Image Segmentation[C]// International Conference on Medical Image Computing and Computer-Assisted Intervention. Springer, Cham, 2015.
數據集的準備
我們采用的是AI Studio數據集中自帶人像語義分割數據集,如圖所示,為人體正面照片。我們首先需要在建立項目的時候添加該數據集,然后解壓該數據集。
解壓數據集之后,我們可以看到如下的目錄結構:
imgs和annos目錄分別對應原圖和標簽數據,train_list.txt和valid_list.txt分別為訓練集和驗證集。
數據加載
得到數據集以后,我們需要進行數據的加載工作。飛槳(PaddlePaddle)數據集加載方案是統一使用Dataset(數據集定義) + DataLoader(多進程數據集加載)。
首先我們先進行數據集的定義,數據集定義主要是實現一個新的Dataset類,繼承父類paddle.io.Dataset,并實現父類中以下兩個抽象方法,__getitem__和__len__:
import?paddle paddle.__version__'2.0.0-rc1'需要注意的是,這個數據集中的標簽數據為黑白單通道的圖像,每個像素點的值為0-255,根據任務需要,我們將其轉換為0、1標簽,0表示背景,1表示人像。由于數據中部分人像為黑色,部分為白色,所以根據第一個像素點的值決定其背景的顏色,分類討論。
import?io import?numpy?as?np import?matplotlib.pyplot?as?plt from?PIL?import?Image?as?PilImageimport?paddle from?paddle.io?import?Dataset from?paddle.vision.transforms?import?transforms?as?T from?paddle.nn?import?functional?as?FIMAGE_SIZE?=?(384,?384) class?PetDataset(Dataset):"""數據集定義"""def?__init__(self,?mode='train'):"""構造函數"""self.image_size?=?IMAGE_SIZEself.mode?=?mode.lower()assert?self.mode?in?['train',?'valid',?'predict'],?\"mode?should?be?'train'?or?'valid'?or?'predict',?but?got?{}".format(self.mode)self.train_images?=?[]self.label_images?=?[]with?open('koto/{}_list.txt'.format(self.mode),?'r')?as?f:for?line?in?f.readlines():image,?label?=?line.strip().split('?')image?=?image.replace('/mnt/d/data/',?'')label?=?label.replace('/mnt/d/data/',?'')self.train_images.append(image)self.label_images.append(label)def?_load_img(self,?path,?color_mode='rgb',?transforms=[]):"""統一的圖像處理接口封裝,用于規整圖像大小和通道"""with?open(path,?'rb')?as?f:img?=?PilImage.open(io.BytesIO(f.read()))if?color_mode?==?'grayscale':#?if?image?is?not?already?an?8-bit,?16-bit?or?32-bit?grayscale?image#?convert?it?to?an?8-bit?grayscale?image.if?img.mode?not?in?('L',?'I;16',?'I'):img?=?img.convert('L')elif?color_mode?==?'rgba':if?img.mode?!=?'RGBA':img?=?img.convert('RGBA')elif?color_mode?==?'rgb':if?img.mode?!=?'RGB':img?=?img.convert('RGB')else:raise?ValueError('color_mode?must?be?"grayscale",?"rgb",?or?"rgba"')return?T.Compose([T.Resize(self.image_size)]?+?transforms)(img)def?__getitem__(self,?idx):"""返回?image,?label"""train_image?=?self._load_img(self.train_images[idx],transforms=[T.Transpose(),T.Normalize(mean=127.5,?std=127.5)])?#?加載原始圖像label_image?=?self._load_img(self.label_images[idx],color_mode='grayscale',transforms=[T.Grayscale()])?#?加載Label圖像#?返回image,?labeltrain_image?=?np.array(train_image,?dtype='float32')label_image?=?np.array(label_image,?dtype='int64')#?將Label圖像轉換為標簽,0:背景,1:人像if?label_image[0][0]?==?0:??#?背景黑色,人像白色for?i?in?range(len(label_image)):for?j?in?range(len(label_image[i])):if?label_image[i][j]?>?128:label_image[i][j]?=?1else:label_image[i][j]?=?0else:#?背景白色,人像黑色for?i?in?range(len(label_image)):for?j?in?range(len(label_image[i])):if?label_image[i][j]?<?128:label_image[i][j]?=?1else:label_image[i][j]?=?0return?train_image,?label_imagedef?__len__(self):"""返回數據集總數"""return?len(self.train_images)模型組建
網絡結構這里我們用了上節課講到的U-Net網絡,本節課就不做過多的贅述了,如果大家想具體了解也可以回顧上節課的內容,『跟著雨哥學AI』系列06:趣味案例——基于U-Net的寵物圖像分割
定義網絡結構組建當中用到的一些基礎模塊
定義模型所需要用到的深度可分離卷積、編碼器和解碼器。
from?paddle.nn?import?functional?as?F import?numpy?as?np#?深度可分離卷積定義,目標減少參數個數,減少計算量 class?SeparableConv2D(paddle.nn.Layer):def?__init__(self,in_channels,out_channels,kernel_size,stride=1,padding=0,dilation=1,groups=None,weight_attr=None,bias_attr=None,data_format="NCHW"):super(SeparableConv2D,?self).__init__()self._padding?=?paddingself._stride?=?strideself._dilation?=?dilationself._in_channels?=?in_channelsself._data_format?=?data_format#?第一次卷積參數,沒有偏置參數filter_shape?=?[in_channels,?1]?+?self.convert_to_list(kernel_size,?2,?'kernel_size')self.weight_conv?=?self.create_parameter(shape=filter_shape,?attr=weight_attr)#?第二次卷積參數filter_shape?=?[out_channels,?in_channels]?+?self.convert_to_list(1,?2,?'kernel_size')self.weight_pointwise?=?self.create_parameter(shape=filter_shape,?attr=weight_attr)self.bias_pointwise?=?self.create_parameter(shape=[out_channels],attr=bias_attr,is_bias=True)def?convert_to_list(self,?value,?n,?name,?dtype=np.int):if?isinstance(value,?dtype):return?[value,?]?*?nelse:try:value_list?=?list(value)except?TypeError:raise?ValueError("The?"?+?name?+"'s?type?must?be?list?or?tuple.?Received:?"?+?str(value))if?len(value_list)?!=?n:raise?ValueError("The?"?+?name?+?"'s?length?must?be?"?+?str(n)?+".?Received:?"?+?str(value))for?single_value?in?value_list:try:dtype(single_value)except?(ValueError,?TypeError):raise?ValueError("The?"?+?name?+?"'s?type?must?be?a?list?or?tuple?of?"?+?str(n)?+?"?"?+?str(dtype)?+?"?.?Received:?"?+?str(value)?+?"?""including?element?"?+?str(single_value)?+?"?of?type"?+?"?"+?str(type(single_value)))return?value_listdef?forward(self,?inputs):conv_out?=?F.conv2d(inputs,self.weight_conv,padding=self._padding,stride=self._stride,dilation=self._dilation,groups=self._in_channels,data_format=self._data_format)out?=?F.conv2d(conv_out,self.weight_pointwise,bias=self.bias_pointwise,padding=0,stride=1,dilation=1,groups=1,data_format=self._data_format)return?out#?定義下采樣編碼器 class?Encoder(paddle.nn.Layer):def?__init__(self,?in_channels,?out_channels):super(Encoder,?self).__init__()self.relus?=?paddle.nn.LayerList([paddle.nn.ReLU()?for?i?in?range(2)])self.separable_conv_01?=?SeparableConv2D(in_channels,out_channels,kernel_size=3,padding='same')self.bns?=?paddle.nn.LayerList([paddle.nn.BatchNorm2D(out_channels)?for?i?in?range(2)])self.separable_conv_02?=?SeparableConv2D(out_channels,out_channels,kernel_size=3,padding='same')self.pool?=?paddle.nn.MaxPool2D(kernel_size=3,?stride=2,?padding=1)self.residual_conv?=?paddle.nn.Conv2D(in_channels,out_channels,kernel_size=1,stride=2,padding='same')def?forward(self,?inputs):previous_block_activation?=?inputsy?=?self.relus[0](inputs)y?=?self.separable_conv_01(y)y?=?self.bns[0](y)y?=?self.relus[1](y)y?=?self.separable_conv_02(y)y?=?self.bns[1](y)y?=?self.pool(y)residual?=?self.residual_conv(previous_block_activation)y?=?paddle.add(y,?residual)return?y#?定義上采樣解碼器 class?Decoder(paddle.nn.Layer):def?__init__(self,?in_channels,?out_channels):super(Decoder,?self).__init__()self.relus?=?paddle.nn.LayerList([paddle.nn.ReLU()?for?i?in?range(2)])self.conv_transpose_01?=?paddle.nn.Conv2DTranspose(in_channels,out_channels,kernel_size=3,padding=1)self.conv_transpose_02?=?paddle.nn.Conv2DTranspose(out_channels,out_channels,kernel_size=3,padding=1)self.bns?=?paddle.nn.LayerList([paddle.nn.BatchNorm2D(out_channels)?for?i?in?range(2)])self.upsamples?=?paddle.nn.LayerList([paddle.nn.Upsample(scale_factor=2.0)?for?i?in?range(2)])self.residual_conv?=?paddle.nn.Conv2D(in_channels,out_channels,kernel_size=1,padding='same')def?forward(self,?inputs):previous_block_activation?=?inputsy?=?self.relus[0](inputs)y?=?self.conv_transpose_01(y)y?=?self.bns[0](y)y?=?self.relus[1](y)y?=?self.conv_transpose_02(y)y?=?self.bns[1](y)y?=?self.upsamples[0](y)residual?=?self.upsamples[1](previous_block_activation)residual?=?self.residual_conv(residual)y?=?paddle.add(y,?residual)return?y模型組網
按照U型網絡結構格式進行整體的網絡結構搭建,三次下采樣,四次上采樣。
class?PetNet(paddle.nn.Layer):def?__init__(self,?num_classes):super(PetNet,?self).__init__()self.conv_1?=?paddle.nn.Conv2D(3,?32,kernel_size=3,stride=2,padding='same')self.bn?=?paddle.nn.BatchNorm2D(32)self.relu?=?paddle.nn.ReLU()in_channels?=?32self.encoders?=?[]self.encoder_list?=?[64,?128,?256]self.decoder_list?=?[256,?128,?64,?32]#?根據下采樣個數和配置循環定義子Layer,避免重復寫一樣的程序for?out_channels?in?self.encoder_list:block?=?self.add_sublayer('encoder_{}'.format(out_channels),Encoder(in_channels,?out_channels))self.encoders.append(block)in_channels?=?out_channelsself.decoders?=?[]#?根據上采樣個數和配置循環定義子Layer,避免重復寫一樣的程序for?out_channels?in?self.decoder_list:block?=?self.add_sublayer('decoder_{}'.format(out_channels),Decoder(in_channels,?out_channels))self.decoders.append(block)in_channels?=?out_channelsself.output_conv?=?paddle.nn.Conv2D(in_channels,num_classes,kernel_size=3,padding='same')def?forward(self,?inputs):y?=?self.conv_1(inputs)y?=?self.bn(y)y?=?self.relu(y)for?encoder?in?self.encoders:y?=?encoder(y)for?decoder?in?self.decoders:y?=?decoder(y)y?=?self.output_conv(y)return?y模型可視化
模型組建完成后,我們可以調用飛槳提供的summary接口對組建好的模型進行可視化,方便進行模型結構和參數信息的查看和確認。
num_classes?=?2 model?=?paddle.Model(PetNet(num_classes)) model.summary((-1,?3,?384,384)) -----------------------------------------------------------------------------Layer?(type)????????Input?Shape??????????Output?Shape?????????Param?#???? =============================================================================Conv2D-1???????[[1,?3,?384,?384]]???[1,?32,?192,?192]?????????896??????BatchNorm2D-1???[[1,?32,?192,?192]]???[1,?32,?192,?192]?????????128??????ReLU-1???????[[1,?32,?192,?192]]???[1,?32,?192,?192]??????????0???????ReLU-2???????[[1,?32,?192,?192]]???[1,?32,?192,?192]??????????0??????? SeparableConv2D-1?[[1,?32,?192,?192]]???[1,?64,?192,?192]????????2,400?????BatchNorm2D-2???[[1,?64,?192,?192]]???[1,?64,?192,?192]?????????256??????ReLU-3???????[[1,?64,?192,?192]]???[1,?64,?192,?192]??????????0??????? SeparableConv2D-2?[[1,?64,?192,?192]]???[1,?64,?192,?192]????????4,736?????BatchNorm2D-3???[[1,?64,?192,?192]]???[1,?64,?192,?192]?????????256??????MaxPool2D-1????[[1,?64,?192,?192]]????[1,?64,?96,?96]???????????0???????Conv2D-2??????[[1,?32,?192,?192]]????[1,?64,?96,?96]?????????2,112?????Encoder-1?????[[1,?32,?192,?192]]????[1,?64,?96,?96]???????????0???????ReLU-4????????[[1,?64,?96,?96]]?????[1,?64,?96,?96]???????????0??????? SeparableConv2D-3??[[1,?64,?96,?96]]?????[1,?128,?96,?96]????????8,896?????BatchNorm2D-4????[[1,?128,?96,?96]]????[1,?128,?96,?96]?????????512??????ReLU-5????????[[1,?128,?96,?96]]????[1,?128,?96,?96]??????????0??????? SeparableConv2D-4??[[1,?128,?96,?96]]????[1,?128,?96,?96]???????17,664?????BatchNorm2D-5????[[1,?128,?96,?96]]????[1,?128,?96,?96]?????????512??????MaxPool2D-2?????[[1,?128,?96,?96]]????[1,?128,?48,?48]??????????0???????Conv2D-3???????[[1,?64,?96,?96]]?????[1,?128,?48,?48]????????8,320?????Encoder-2??????[[1,?64,?96,?96]]?????[1,?128,?48,?48]??????????0???????ReLU-6????????[[1,?128,?48,?48]]????[1,?128,?48,?48]??????????0??????? SeparableConv2D-5??[[1,?128,?48,?48]]????[1,?256,?48,?48]???????34,176?????BatchNorm2D-6????[[1,?256,?48,?48]]????[1,?256,?48,?48]????????1,024?????ReLU-7????????[[1,?256,?48,?48]]????[1,?256,?48,?48]??????????0??????? SeparableConv2D-6??[[1,?256,?48,?48]]????[1,?256,?48,?48]???????68,096?????BatchNorm2D-7????[[1,?256,?48,?48]]????[1,?256,?48,?48]????????1,024?????MaxPool2D-3?????[[1,?256,?48,?48]]????[1,?256,?24,?24]??????????0???????Conv2D-4???????[[1,?128,?48,?48]]????[1,?256,?24,?24]???????33,024?????Encoder-3??????[[1,?128,?48,?48]]????[1,?256,?24,?24]??????????0???????ReLU-8????????[[1,?256,?24,?24]]????[1,?256,?24,?24]??????????0??????? Conv2DTranspose-1??[[1,?256,?24,?24]]????[1,?256,?24,?24]???????590,080????BatchNorm2D-8????[[1,?256,?24,?24]]????[1,?256,?24,?24]????????1,024?????ReLU-9????????[[1,?256,?24,?24]]????[1,?256,?24,?24]??????????0??????? Conv2DTranspose-2??[[1,?256,?24,?24]]????[1,?256,?24,?24]???????590,080????BatchNorm2D-9????[[1,?256,?24,?24]]????[1,?256,?24,?24]????????1,024?????Upsample-1??????[[1,?256,?24,?24]]????[1,?256,?48,?48]??????????0???????Upsample-2??????[[1,?256,?24,?24]]????[1,?256,?48,?48]??????????0???????Conv2D-5???????[[1,?256,?48,?48]]????[1,?256,?48,?48]???????65,792?????Decoder-1??????[[1,?256,?24,?24]]????[1,?256,?48,?48]??????????0???????ReLU-10???????[[1,?256,?48,?48]]????[1,?256,?48,?48]??????????0??????? Conv2DTranspose-3??[[1,?256,?48,?48]]????[1,?128,?48,?48]???????295,040????BatchNorm2D-10????[[1,?128,?48,?48]]????[1,?128,?48,?48]?????????512??????ReLU-11???????[[1,?128,?48,?48]]????[1,?128,?48,?48]??????????0??????? Conv2DTranspose-4??[[1,?128,?48,?48]]????[1,?128,?48,?48]???????147,584????BatchNorm2D-11????[[1,?128,?48,?48]]????[1,?128,?48,?48]?????????512??????Upsample-3??????[[1,?128,?48,?48]]????[1,?128,?96,?96]??????????0???????Upsample-4??????[[1,?256,?48,?48]]????[1,?256,?96,?96]??????????0???????Conv2D-6???????[[1,?256,?96,?96]]????[1,?128,?96,?96]???????32,896?????Decoder-2??????[[1,?256,?48,?48]]????[1,?128,?96,?96]??????????0???????ReLU-12???????[[1,?128,?96,?96]]????[1,?128,?96,?96]??????????0??????? Conv2DTranspose-5??[[1,?128,?96,?96]]????[1,?64,?96,?96]????????73,792?????BatchNorm2D-12????[[1,?64,?96,?96]]?????[1,?64,?96,?96]??????????256??????ReLU-13???????[[1,?64,?96,?96]]?????[1,?64,?96,?96]???????????0??????? Conv2DTranspose-6??[[1,?64,?96,?96]]?????[1,?64,?96,?96]????????36,928?????BatchNorm2D-13????[[1,?64,?96,?96]]?????[1,?64,?96,?96]??????????256??????Upsample-5??????[[1,?64,?96,?96]]????[1,?64,?192,?192]??????????0???????Upsample-6??????[[1,?128,?96,?96]]???[1,?128,?192,?192]?????????0???????Conv2D-7??????[[1,?128,?192,?192]]??[1,?64,?192,?192]????????8,256?????Decoder-3??????[[1,?128,?96,?96]]???[1,?64,?192,?192]??????????0???????ReLU-14??????[[1,?64,?192,?192]]???[1,?64,?192,?192]??????????0??????? Conv2DTranspose-7?[[1,?64,?192,?192]]???[1,?32,?192,?192]???????18,464?????BatchNorm2D-14???[[1,?32,?192,?192]]???[1,?32,?192,?192]?????????128??????ReLU-15??????[[1,?32,?192,?192]]???[1,?32,?192,?192]??????????0??????? Conv2DTranspose-8?[[1,?32,?192,?192]]???[1,?32,?192,?192]????????9,248?????BatchNorm2D-15???[[1,?32,?192,?192]]???[1,?32,?192,?192]?????????128??????Upsample-7?????[[1,?32,?192,?192]]???[1,?32,?384,?384]??????????0???????Upsample-8?????[[1,?64,?192,?192]]???[1,?64,?384,?384]??????????0???????Conv2D-8??????[[1,?64,?384,?384]]???[1,?32,?384,?384]????????2,080?????Decoder-4?????[[1,?64,?192,?192]]???[1,?32,?384,?384]??????????0???????Conv2D-9??????[[1,?32,?384,?384]]????[1,?2,?384,?384]?????????578?????? ============================================================================= Total?params:?2,058,690 Trainable?params:?2,051,138 Non-trainable?params:?7,552 ----------------------------------------------------------------------------- Input?size?(MB):?1.69 Forward/backward?pass?size?(MB):?676.12 Params?size?(MB):?7.85 Estimated?Total?Size?(MB):?685.67 -----------------------------------------------------------------------------{'total_params':?2058690,?'trainable_params':?2051138}定義評估指標
由于框架中沒有提供相應的評估指標,所以我們使用前面章節中講解過的自定義評估指標方法,『跟著雨哥學AI』系列04:詳解飛槳框架高階用法。
IoU(interp over union)指標就是大家常說的交并比,通常作為語義分割任務的標準度量,在做此任務時我們自定義該指標用來衡量模型的預測效果。?
from?paddle.metric?import?Metric import?numpy?as?npclass?IOU(Metric):def?__init__(self,?name='iou',?*args,?**kwargs):super(IOU,?self).__init__(*args,?**kwargs)self._name?=?nameself.interp?=?0??#?交集self.union?=?0?????????#?并集def?name(self):return?self._namedef?update(self,?preds,?labels):#?在preds第二維上取預測概率最大的標簽序號preds?=?np.argmax(preds,?axis=1)self.interp?=?np.logical_and(labels,?preds)?self.union?=?np.logical_or(labels,?preds)def?accumulate(self):return?np.sum(self.interp)?/?np.sum(self.union)def?reset(self):self.interp?=?0self.union?=?0模型訓練
使用模型代碼進行Model實例生成,使用model.prepare接口定義優化器、損失函數和評價指標等信息,用于后續訓練使用。在所有初步配置完成后,調用model.fit接口開啟訓練執行過程,調用fit時只需要將前面定義好的訓練數據集、測試數據集、訓練輪次(Epoch)和批次大小(batch_size)配置好即可。
在本案例中加入了save_dir和save_freq參數,分別指定模型的存儲路徑和保存的頻率,方便訓練過程中斷后可以接著之前的繼續訓練。
另外我們使用了飛槳提供的EarlyStopping接口,當驗證集上iou指標5輪沒有更高的值時,我們將提前結束訓練過程,并保存最好的模型,存儲名為best_model。
train_dataset?=?PetDataset(mode='train')?#?訓練數據集 val_dataset?=?PetDataset(mode='valid')?#?驗證數據集print('訓練集大小:{},?驗證集大小:{}'.format(len(train_dataset),?len(val_dataset))) 訓練集大小:5666,?驗證集大小:1416 num_classes?=?2 model?=?paddle.Model(PetNet(num_classes))optim?=?paddle.optimizer.RMSProp(learning_rate=0.001,rho=0.9,momentum=0.0,epsilon=1e-07,centered=False,parameters=model.parameters())model.prepare(optim,?paddle.nn.CrossEntropyLoss(axis=1),?metrics=IOU())callbacks?=?paddle.callbacks.EarlyStopping('iou',mode='max',patience=5,verbose=1,min_delta=0,baseline=None,save_best_model=True)model.fit(train_dataset,val_dataset,epochs=100,batch_size=64,drop_last=True,verbose=1,save_dir='./ckpt/',save_freq=5,log_freq=1,callbacks=[callbacks]) The?loss?value?printed?in?the?log?is?the?current?step,?and?the?metric?is?the?average?value?of?previous?step. Epoch?1/100 step?88/88?[==============================]?-?loss:?1.4115?-?iou:?0.0982?-?8s/step????????? save?checkpoint?at?/home/aistudio/ckpt/0 Eval?begin... The?loss?value?printed?in?the?log?is?the?current?batch,?and?the?metric?is?the?average?value?of?previous?step. step?23/23?[==============================]?-?loss:?0.5246?-?iou:?0.4950?-?7s/step????????? Eval?samples:?1416 Epoch?2/100 step?88/88?[==============================]?-?loss:?0.5149?-?iou:?0.4484?-?8s/step???????? Eval?begin... The?loss?value?printed?in?the?log?is?the?current?batch,?and?the?metric?is?the?average?value?of?previous?step. step?23/23?[==============================]?-?loss:?0.3571?-?iou:?0.4504?-?7s/step????????? Eval?samples:?1416……Epoch?25/100 step?88/88?[==============================]?-?loss:?0.1769?-?iou:?0.8273?-?8s/step???????? Eval?begin... The?loss?value?printed?in?the?log?is?the?current?batch,?and?the?metric?is?the?average?value?of?previous?step. step?23/23?[==============================]?-?loss:?0.0705?-?iou:?0.9176?-?7s/step????????? Eval?samples:?1416 Epoch?26/100 step?88/88?[==============================]?-?loss:?0.1179?-?iou:?0.8665?-?8s/step????????? save?checkpoint?at?/home/aistudio/ckpt/25 Eval?begin... The?loss?value?printed?in?the?log?is?the?current?batch,?and?the?metric?is?the?average?value?of?previous?step. step?23/23?[==============================]?-?loss:?0.0618?-?iou:?0.9094?-?7s/step????????? Eval?samples:?1416 Epoch?26:?Early?stopping. Best?checkpoint?has?been?saved?at?/home/aistudio/ckpt/best_model save?checkpoint?at?/home/aistudio/ckpt/final模型預測
模型訓練好之后,我們調用model.load接口下載訓練效果最好的模型,然后直接使用model.predict接口來對數據集進行預測操作,只需要將預測數據集傳遞到接口內即可。
在本例中我們選取valid_list.txt中的任意一條數據另外創建了predict_list.txt用于測試。
predict_dataset?=?PetDataset(mode='predict')num_classes?=?2 model?=?paddle.Model(PetNet(num_classes)) #?模型加載 model.load('ckpt/best_model') model.prepare() predict_results?=?model.predict(predict_dataset)Predict?begin... step?1/1?[==============================]?-?283ms/step Predict?samples:?1預測結果可視化
得到預測結果之后,我們借助工具將原圖、標簽圖和預測結果可視化。
制作證件照
我們在得到預測結果之后,就可以動手進行證件照的制作啦。此處是選用了白色背景,大家可以根據自己的需要來自定義背景顏色。
總結
本節課和大家一起完成了制作自己的專屬證件照案例,下節課同學們想實現什么趣味案例呢?歡迎大家在評論區告訴我,我們將會在后續的課程中給大家安排上哈,今天的課程到這里就結束了,我是雨哥,下節課再見啦~
歡迎關注飛槳框架高層API官方賬號:飛槳PaddleHapi
有任何問題可以在本項目中評論或到飛槳Github倉庫提交Issue。
歡迎掃碼加入飛槳框架高層API技術交流群
回顧往期:
第一篇:『跟著雨哥學AI』系列:詳解飛槳框架數據管道
第二篇:『跟著雨哥學AI』系列之二:詳解飛槳框架模型組網
第三篇:『跟著雨哥學AI』系列之三:詳解飛槳框架模型訓練
第四篇:『跟著雨哥學AI』系列之四:詳解飛槳框架高階用法
第五篇:『跟著雨哥學AI』系列之五:快速上手趣味案例FashionMNIST
第六篇:『跟著雨哥學AI』系列之六:趣味案例——基于U-Net的寵物圖像分割
如果您想詳細了解更多飛槳的相關內容,請參閱以下文檔。
·飛槳官網地址·
https://www.paddlepaddle.org.cn/
·飛槳開源框架項目地址·
GitHub: https://github.com/PaddlePaddle/Paddle?
Gitee: https://gitee.com/paddlepaddle/Paddle
????長按上方二維碼立即star!????
飛槳(PaddlePaddle)以百度多年的深度學習技術研究和業務應用為基礎,是中國首個開源開放、技術領先、功能完備的產業級深度學習平臺,包括飛槳開源平臺和飛槳企業版。飛槳開源平臺包含核心框架、基礎模型庫、端到端開發套件與工具組件,持續開源核心能力,為產業、學術、科研創新提供基礎底座。飛槳企業版基于飛槳開源平臺,針對企業級需求增強了相應特性,包含零門檻AI開發平臺EasyDL和全功能AI開發平臺BML。EasyDL主要面向中小企業,提供零門檻、預置豐富網絡和模型、便捷高效的開發平臺;BML是為大型企業提供的功能全面、可靈活定制和被深度集成的開發平臺。
END
總結
以上是生活随笔為你收集整理的『跟着雨哥学AI』系列之七:趣味案例——动手制作专属证件照的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 正则表达式攻略
- 下一篇: 题解 [CF1682D] Circula