classify_fruit_deep_learning.hdev 逐段分析

展示如何训练一个水果分类器。

初始化

dev_update_off ()
dev_close_window ()
WindowWidth := 800
WindowHeight := 600
dev_open_window_fit_size (0, 0, WindowWidth, WindowHeight, -1, -1, WindowHandle)
set_display_font (WindowHandle, 16, 'mono', 'true', 'false')

设置随机种子

set_system ('seed_rand', 42)

展示介绍文字“dev_disp_introduction_text”。(仅作可视化展示作用)

dev_disp_introduction_text ()
***  这是个封装函数,鼠标右击算子点击“显示函数”查看函数具体内容

stop ()
dev_close_window ()
dev_resize_window_fit_size (0, 0, WindowWidth, WindowHeight, -1, -1)
dev_clear_window ()

introduction_text

网络及训练数据设置

read_dl_classifier ('pretrained_dl_classifier_compact.hdl', DLClassifierHandle)
***  “pretrained_dl_classifier_compact.hdl” 是halcon自带的一个分类网络,另外还有“pretrained_dl_classifier_enhanced.hdl”和“pretrained_dl_classifier_resnet50.hdl”,参数量依次增大,自行根据实际情况选择。

RawDataFolder := 'food/' + ['apple_braeburn','apple_golden_delicious','apple_topaz','peach','pear']
***  训练图像路径,不同类别的图片在不同文件夹内;输出是

read_dl_classifier_data_set (RawDataFolder, 'last_folder', RawImageFiles, Labels, LabelIndices, Classes)
***  这是个封装函数,鼠标右击算子点击“显示函数”查看函数具体内容
***  读取训练图像数据并进行分类,输出是后面几个:RawImageFiles, Labels, LabelIndices, Classes;
***  RawImageFiles:图片的详细路径:比如'C:/Users/Public/Documents/MVTec/HALCON-18.11-Steady/examples/images/food/apple_braeburn/apple_braeburn_001.png'
***  Labels:RawImageFiles对应的标签
***  LabelIndices:标签的序号
***  Classes:类别的名称

PreprocessedFolder := 'fruit_preprocessed'
***  图像预处理后,得到的图像的保存路径
OverwritePreprocessingFolder := false
***  一个判断标志(当存在PreprocessedFolder ,是否需要再次进行图像预处理操作,可结合后面代码理解)
RemovePreprocessingAfterExample := true
***  一个判断标志(程序最末尾有一个判断,是否删除PreprocessedFolder 路径)

Classes

图像预处理

file_exists (PreprocessedFolder, FileExists)
***  PreprocessedFolder 是否存在,FileExists:0或1;
if (not FileExists or OverwritePreprocessingFolder)
***  条件满足则进行图像预处理
    if (FileExists)
        remove_dir_recursively (PreprocessedFolder)
    endif 
    make_dir (PreprocessedFolder)
    for I := 0 to |Classes| - 1 by 1
        make_dir (PreprocessedFolder + '/' + Classes[I])
    endfor
***  OverwritePreprocessingFolder满足情况下的保险措施

    parse_filename (RawImageFiles, BaseNames, Extensions, Directories)
    ***  这是个封装函数,鼠标右击算子点击“显示函数”查看函数具体内容
***  得到三个输出:BaseNames, Extensions, Directories;
BaseNames:图片名称(无路径)如,'apple_braeburn_001'
Extensions:扩展名,如,'png'
Directories:图片路径,如,'C:/Users/Public/Documents/MVTec/HALCON-18.11-Steady/examples/images/food/apple_braeburn/'

    ObjectFilesOut := PreprocessedFolder + '/' + Labels + '/' + BaseNames + '.hobj'
***  预处理结果为'.hobj'文件,此处为 为输出的数据设置名称(并无具体内容)

    check_output_file_names_for_duplicates (RawImageFiles, ObjectFilesOut)
 ***  检查 '.hobj' 文件名与图片名是否一一对应。

    for I := 0 to |RawImageFiles| - 1 by 1
        read_image (Image, RawImageFiles[I])
        
        preprocess_dl_fruit_example (Image, ImagePreprocessed, DLClassifierHandle)
 ***  这是图像预处理操作,根据任务不同这个是需要修改的!!!比如这个:
 ***   zoom_image_size (Image, Image, DlImageWidth, DlImageHeight, 'constant')
 ***  convert_image_type (Image, Image, 'real')
 ***  RescaleRange:=(DlRangeMax - DlRangeMin)/255.0
 ***  scale_image (Image, Image, RescaleRange, DlRangeMin)
 ***  count_obj (Image, Number)
 ***  for Index := 1 to Number by 1
 ***    select_obj (Image, ObjectSelected, Index)
 ***   count_channels (ObjectSelected, Channel)
 ***    if (Channel != DlNumChannels)
 ***       compose3(ObjectSelected, ObjectSelected, ObjectSelected, ThreeChannelImage)
 ***      replace_obj (Image, ThreeChannelImage, Image, 1)
 ***     endif                        
 ***  原文链接:https://blog.csdn.net/weixin_44490080/article/details/104283455

        write_object (ImagePreprocessed, ObjectFilesOut[I])        
 ***  图像预处理结果存入ObjectFilesOut
        dev_disp_preprocessing_progress (I, RawImageFiles, PreprocessedFolder, WindowHandle)
 ***  展示作用,这是个封装函数,鼠标右击算子点击“显示函数”查看函数具体内容
    endfor
    dev_clear_window ()
    dev_disp_text ('Preprocessing done.', 'window', 'top', 'left', 'black', [], [])
endif

数据集拆分

read_dl_classifier_data_set (PreprocessedFolder, 'last_folder', ImageFiles, Labels, LabelsIndices, Classes)
 ***  读取数据集图片,得到每个图片的完整路径存入“ImageFiles”,以及图片对应类别的索引“LabelsIndices”

TrainingPercent := 70
ValidationPercent := 15
 ***  拆分比例,拆成了训练,验证和测试三个子数据集(按split_dl_classifier_data_set 的算法应该是7成训练,1.5成验证,剩余测试)

split_dl_classifier_data_set (ImageFiles, Labels, TrainingPercent, ValidationPercent, TrainingImages, TrainingLabels, ValidationImages, ValidationLabels, TestImages, TestLabels)
***  拆分,得到训练集、验证集和测试集

ImageFiles

分类模型设置

set_dl_classifier_param (DLClassifierHandle, 'classes', Classes)
***  设置模型超参数,DLClassifierHandle是模型超参数的句柄,将DLClassifierHandle里的 'classes'设置为Classes

BatchSize := 64
set_dl_classifier_param (DLClassifierHandle, 'batch_size', BatchSize)
***  'batch_size'设置为64

try
    set_dl_classifier_param (DLClassifierHandle, 'runtime_init', 'immediately')
catch (Exception)
    dev_disp_error_text (Exception)
    if (RemovePreprocessingAfterExample and Exception[0] != 4104)
        remove_dir_recursively (PreprocessedFolder)
        dev_disp_text ('Preprocessed data in folder "' + PreprocessedFolder + '" have been deleted.', 'window', 'bottom', 'left', 'black', [], [])
    endif
    stop ()
endtry
***  尝试初始化运行时环境

InitialLearningRate := 0.001
set_dl_classifier_param (DLClassifierHandle, 'learning_rate', InitialLearningRate)
***   'learning_rate'设置为0.001

LearningRateStepEveryNthEpoch := 30
LearningRateStepRatio := 0.1
NumEpochs := 100
***   赋值;(根据train_fruit_classifier 算法,即每30个epoch更新学习率,当前学习率*0.1为新学习率,总共训练100个eopch)

dev_clear_window ()
dev_disp_text ('Training has started...', 'window', 'top', 'left', 'black', [], [])
***   展示作用

PlotEveryNthEpoch := 4
FileName := 'classifier_fruit.hdl'
***   赋值;(根据train_fruit_classifier 算法,应该是4个epoch更新一下绘图,输出的权重文件为'classifier_fruit.hdl')

train_fruit_classifier (DLClassifierHandle, FileName, NumEpochs, TrainingImages, TrainingLabels, ValidationImages, ValidationLabels, LearningRateStepEveryNthEpoch, LearningRateStepRatio, PlotEveryNthEpoch, WindowHandle)
***   开始训练,输出FileName。

dev_disp_text ('Press Run (F5) to continue', 'window', 'bottom', 'right', 'black', [], [])
stop ()
***   展示功能

DLClassifierHandle

验证

read_dl_classifier (FileName, DLClassifierHandle)

get_predicted_classes (ValidationImages, DLClassifierHandle, PredictedClassesValidation)
gen_confusion_matri![请添加图片描述](https://img-blog.csdnimg.cn/direct/836a6a14f6a84b98bdb376ecbd0fe988.png)
x (ValidationLabels, PredictedClassesValidation, [], [], WindowHandle, ConfusionMatrix)
***   计算混淆矩阵;参考:https://blog.csdn.net/seagal890/article/details/105059498
dev_disp_text ('Validation data', 'window', 'top', 'left', 'gray', 'box', 'false')
dev_disp_text ('Press Run (F5) to continue', 'window', 'bottom', 'right', 'black', [], [])
stop ()
dev_clear_window ()

请添加图片描述

推理

read_dl_classifier (FileName, DLClassifierHandle)
***   读权重

set_dl_classifier_param (DLClassifierHandle, 'batch_size', 1)
***   设置推理超参数,句柄为DLClassifierHandle,将'batch_size'设置为1

try
    set_dl_classifier_param (DLClassifierHandle, 'runtime', 'cpu')
    Runtime := 'cpu'
catch (Exception)
    * Keep the 'gpu' runtime if switching to 'cpu' failed.
    Runtime := 'gpu'
endtry
***   设置cpu推理

set_dl_classifier_param (DLClassifierHandle, 'runtime_init', 'immediately')
***   初始化环境

dev_resize_window_fit_size (0, 0, WindowWidth, WindowHeight, -1, -1)
dev_disp_inference_text (Runtime)
stop ()
***   展示作用

for Index := 0 to 20 by 1  ***  推理20张图
    ImageFile := RawImageFiles[floor(rand(1) * |RawImageFiles|)]
    ***   随机读图
    read_image (Image, ImageFile)
    dev_resize_window_fit_image (Image, 0, 0, -1, -1)
    preprocess_dl_fruit_example (Image, ImagePreprocessed, DLClassifierHandle)
    ***   推理图像预处理,同前
    apply_dl_classifier (ImagePreprocessed, DLClassifierHandle, DLClassifierResultHandle)
    ***   推理
    get_dl_classifier_result (DLClassifierResultHandle, 'all', 'predicted_classes', PredictedClass)
    ***   抽出推理结果'predicted_classes'设置入PredictedClass
    *
    dev_display (Image)
    Text := 'Predicted class: ' + PredictedClass
    dev_disp_text (Text, 'window', 'top', 'left', 'white', 'box', 'false')
    dev_disp_text ('Press Run (F5) to continue', 'window', 'bottom', 'right', 'black', [], [])
    stop ()
    ***   展示功能
endfor
stop ()

请添加图片描述

收尾

if (RemovePreprocessingAfterExample)
    remove_dir_recursively (PreprocessedFolder)
    dev_disp_text ('End of program.\nPreprocessed data have been deleted.', 'window', 'bottom', 'right', 'black', [], [])
else
    dev_disp_text ('      End of program      ', 'window', 'bottom', 'right', 'black', [], [])
endif
    ***   如果前面把RemovePreprocessingAfterExample设置为true,就删除PreprocessedFolder
Logo

助力广东及东莞地区开发者,代码托管、在线学习与竞赛、技术交流与分享、资源共享、职业发展,成为松山湖开发者首选的工作与学习平台

更多推荐