MindSpore實現圖片分類

      網友投稿 1106 2022-05-30

      MindSpore圖片分類

      實驗介紹

      本實驗主要介紹使用MindSpore在CIFAR-10數據集上訓練ResNet50。本實驗使用MindSpore model_zoo中提供的ResNet50模型定義,以及MindSpore官網教程在云上使用MindSpore里的訓練腳本。

      實驗目的

      了解如何使用MindSpore加載常用的CIFAR-10圖片分類數據集。

      了解MindSpore的model_zoo模塊,以及如何使用model_zoo中的模型。

      了解ResNet50這類大模型的基本結構和編程方法。

      預備知識

      熟練使用Python,了解Shell及Linux操作系統基本知識。

      具備一定的深度學習理論知識,如卷積神經網絡、損失函數、優化器,訓練策略、Checkpoint等。

      了解華為云的基本使用方法,包括OBS(對象存儲)、ModelArts(AI開發平臺)、訓練作業等功能。華為云官網:https://www.huaweicloud.com

      了解并熟悉MindSpore AI計算框架,MindSpore官網:https://www.mindspore.cn/

      實驗環境

      MindSpore 1.2.0;

      華為云ModelArts(控制臺左上角選擇“華北-北京四”):ModelArts是華為云提供的面向開發者的一站式AI開發平臺,集成了昇騰AI處理器資源池,用戶可以在該平臺下體驗MindSpore。

      實驗準備

      數據集準備

      CIFAR-10是一個圖片分類數據集,包含60000張32x32的彩色物體圖片,訓練集50000張,測試集10000張,共10類,每類6000張。

      從CIFAR-10官網下載“CIFAR-10 binary version (suitable for C programs)”到本地并解壓。

      腳本準備

      從MindSpore tutorial倉庫里下載相關腳本。將腳本和數據集組織為如下形式:

      experiment_3 ├── dataset.py ├── resnet.py ├── resnet50_train.py └── cifar10 ├── batches.meta.txt ├── eval │?? └── test_batch.bin └── train ├── data_batch_1.bin ├── data_batch_2.bin ├── data_batch_3.bin ├── data_batch_4.bin └── data_batch_5.bin

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      創建OBS桶

      本實驗需要使用華為云OBS存儲腳本和數據集,可以參考快速通過OBS控制臺上傳下載文件了解使用OBS創建桶、上傳文件、下載文件的使用方法(下文給出了操作步驟)。

      提示: 華為云新用戶使用OBS時通常需要創建和配置“訪問密鑰”,可以在使用OBS時根據提示完成創建和配置。也可以參考獲取訪問密鑰并完成ModelArts全局配置獲取并配置訪問密鑰。

      打開OBS控制臺,點擊右上角的“創建桶”按鈕進入桶配置頁面,創建OBS桶的參考配置如下:

      區域:華北-北京四

      數據冗余存儲策略:單AZ存儲

      桶名稱:如ms-course

      存儲類別:標準存儲

      桶策略:公共讀

      歸檔數據直讀:關閉

      企業項目、標簽等配置:免

      上傳文件

      點擊新建的OBS桶名,再打開“對象”標簽頁,通過“上傳對象”、“新建文件夾”等功能,將腳本和數據集上傳到OBS桶中。上傳文件后,查看頁面底部的“任務管理”狀態欄(正在運行、已完成、失?。_保文件均上傳完成。若失敗請:

      參考上傳對象大小限制/切換上傳方式,

      參考上傳對象失敗常見原因。

      若無法解決請新建工單,產品類為“對象存儲服務”,問題類型為“桶和對象相關”,會有技術人員協助解決。

      實驗步驟

      推薦使用ModelArts訓練作業進行實驗,適合大規模并發使用。若使用ModelArts Notebook,請參考LeNet5及Checkpoint實驗案例,了解Notebook的使用方法和注意事項。

      代碼梳理

      resnet50_train.py:主腳本,包含性能測試PerformanceCallback、動態學習率get_lr、執行函數resnet50_train、主函數;

      dataset.py:數據處理腳本。

      resnet.py: resnet模型定義腳本,包含ResidualBlock模塊類ResidualBlock、ResNet類、ResNet50類、ResNet101類等。

      PerformanceCallback繼承MindSpore Callback類,并統計每個訓練step的時延:

      class PerformanceCallback(Callback): """ Training performance callback. Args: batch_size (int): Batch number for one step. """ def __init__(self, batch_size): super(PerformanceCallback, self).__init__() self.batch_size = batch_size self.last_step = 0 self.epoch_begin_time = 0 def step_begin(self, run_context): self.epoch_begin_time = time.time() def step_end(self, run_context): params = run_context.original_args() cost_time = time.time() - self.epoch_begin_time train_steps = params.cur_step_num -self.last_step print(f'epoch {params.cur_epoch_num} cost time = {cost_time}, train step num: {train_steps}, ' f'one step time: {1000*cost_time/train_steps} ms, ' f'train samples per second of cluster: {device_num*train_steps*self.batch_size/cost_time:.1f}\n') self.last_step = run_context.original_args().cur_step_num

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      get_lr生成學習率數組,其中每個元素對應每個step的學習率,這里學習率下降采用二次曲線的形式:

      def get_lr(global_step, total_epochs, steps_per_epoch, lr_init=0.01, lr_max=0.1, warmup_epochs=5): """ Generate learning rate array. Args: global_step (int): Initial step of training. total_epochs (int): Total epoch of training. steps_per_epoch (float): Steps of one epoch. lr_init (float): Initial learning rate. Default: 0.01. lr_max (float): Maximum learning rate. Default: 0.1. warmup_epochs (int): The number of warming up epochs. Default: 5. Returns: np.array, learning rate array. """ lr_each_step = [] total_steps = steps_per_epoch * total_epochs warmup_steps = steps_per_epoch * warmup_epochs if warmup_steps != 0: inc_each_step = (float(lr_max) - float(lr_init)) / float(warmup_steps) else: inc_each_step = 0 for i in range(int(total_steps)): if i < warmup_steps: lr = float(lr_init) + inc_each_step * float(i) else: base = ( 1.0 - (float(i) - float(warmup_steps)) / (float(total_steps) - float(warmup_steps)) ) lr = float(lr_max) * base * base if lr < 0.0: lr = 0.0 lr_each_step.append(lr) current_step = global_step lr_each_step = np.array(lr_each_step).astype(np.float32) learning_rate = lr_each_step[current_step:] return learning_rate

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      MindSpore支持直接讀取CIFAR-10數據集:

      if device_num == 1 or not do_train: ds = de.Cifar10Dataset(dataset_path, num_parallel_workers=8, shuffle=do_shuffle) else: ds = de.Cifar10Dataset(dataset_path, num_parallel_workers=8, shuffle=do_shuffle,num_shards=device_num, shard_id=device_id)

      1

      2

      3

      4

      使用數據增強,如隨機裁剪、隨機水平反轉:

      # define map operations random_crop_op = C.RandomCrop((32, 32), (4, 4, 4, 4)) random_horizontal_flip_op = C.RandomHorizontalFlip(device_id / (device_id + 1)) resize_op = C.Resize((resize_height, resize_width)) rescale_op = C.Rescale(rescale, shift) normalize_op = C.Normalize([0.4914, 0.4822, 0.4465], [0.2023, 0.1994, 0.2010]) change_swap_op = C.HWC2CHW() trans = [] if do_train: trans += [random_crop_op, random_horizontal_flip_op] trans += [resize_op, rescale_op, normalize_op, change_swap_op] type_cast_op = C2.TypeCast(mstype.int32) ds = ds.map(input_columns="label", num_parallel_workers=8, operations=type_cast_op) ds = ds.map(input_columns="image", num_parallel_workers=8, operations=trans)

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      ResNet的不同版本均由5個階段(stage)組成,其中ResNet50結構為Convx1 -> ResidualBlockx3 -> ResidualBlockx4 -> ResidualBlockx6 -> ResidualBlockx5 -> Pooling+FC。

      [1] 圖片來源于https://arxiv.org/pdf/1512.03385.pdf

      ResidualBlock為殘差模塊,相比傳統卷積多了一個short-cut支路,用于將淺層的信息直接傳遞到深層,使得網絡可以很深,而不會出現訓練時梯度消失/爆炸的問題。ResNet50采用了下圖右側Bottleneck形式的殘差模塊:

      [2] 圖片來源于https://arxiv.org/pdf/1512.03385.pdf

      ResNet的ResidualBlock(殘差模塊)定義如下,是組成ResNet網絡的基礎模塊。

      class ResidualBlock(nn.Cell): """ ResNet V1 residual block definition. Args: in_channel (int): Input channel. out_channel (int): Output channel. stride (int): Stride size for the first convolutional layer. Default: 1. Returns: Tensor, output tensor. Examples: >>> ResidualBlock(3, 256, stride=2) """ expansion = 4 def __init__(self, in_channel, out_channel, stride=1): super(ResidualBlock, self).__init__() channel = out_channel // self.expansion self.conv1 = _conv1x1(in_channel, channel, stride=1) self.bn1 = _bn(channel) self.conv2 = _conv3x3(channel, channel, stride=stride) self.bn2 = _bn(channel) self.conv3 = _conv1x1(channel, out_channel, stride=1) self.bn3 = _bn_last(out_channel) self.relu = nn.ReLU() self.down_sample = False if stride != 1 or in_channel != out_channel: self.down_sample = True self.down_sample_layer = None if self.down_sample: self.down_sample_layer = nn.SequentialCell([_conv1x1(in_channel, out_channel, stride), _bn(out_channel)]) self.add = P.TensorAdd() def construct(self, x): identity = x out = self.conv1(x) out = self.bn1(out) out = self.relu(out) out = self.conv2(out) out = self.bn2(out) out = self.relu(out) out = self.conv3(out) out = self.bn3(out) # ResNet50未使用帶有下采樣的殘差支路 if self.down_sample: identity = self.down_sample_layer(identity) # output為殘差支路,identity為short-cut支路 out = self.add(out, identity) out = self.relu(out) return out

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      ResNet類定義如下,傳入的參數包括:

      layer_nums:每個stage中ResidualBlock重復次數列表(list)

      in_channels:每個stage輸入通道數列表(list)

      out_channels:每個stage輸出通道數列表(list)

      strides:每個stage中卷積算子的stride列表(list)

      num_classes:圖片分類數(int)

      注解:

      這里的stage不是ResNet真實層數,只是將ResNet分成多個stage,每個stage包含多個ResidualBlock。

      layer_nums、in_channels、out_channels、strides列表的長度必須相同。

      傳入的參數不同則網絡結構不同,典型的有ResNet50、ResNet101。其定義可以參考resnet.py文件。學員可以嘗試自定義參數設計一個新的網絡。

      class ResNet(nn.Cell): """ ResNet architecture. Args: block (Cell): Block for network. layer_nums (list): Numbers of block in different layers. in_channels (list): Input channel in each layer. out_channels (list): Output channel in each layer. strides (list): Stride size in each layer. num_classes (int): The number of classes that the training images are belonging to. Returns: Tensor, output tensor. Examples: >>> ResNet(ResidualBlock, >>> [3, 4, 6, 3], >>> [64, 256, 512, 1024], >>> [256, 512, 1024, 2048], >>> [1, 2, 2, 2], >>> 10) """ def __init__(self, block, layer_nums, in_channels, out_channels, strides, num_classes): super(ResNet, self).__init__() if not len(layer_nums) == len(in_channels) == len(out_channels) == 4: raise ValueError("the length of layer_num, in_channels, out_channels list must be 4!") self.conv1 = _conv7x7(3, 64, stride=2) self.bn1 = _bn(64) self.relu = P.ReLU() self.maxpool = nn.MaxPool2d(kernel_size=3, stride=2, pad_mode="same") self.layer1 = self._make_layer(block, layer_nums[0], in_channel=in_channels[0], out_channel=out_channels[0], stride=strides[0]) self.layer2 = self._make_layer(block, layer_nums[1], in_channel=in_channels[1], out_channel=out_channels[1], stride=strides[1]) self.layer3 = self._make_layer(block, layer_nums[2], in_channel=in_channels[2], out_channel=out_channels[2], stride=strides[2]) self.layer4 = self._make_layer(block, layer_nums[3], in_channel=in_channels[3], out_channel=out_channels[3], stride=strides[3]) self.mean = P.ReduceMean(keep_dims=True) self.flatten = nn.Flatten() self.end_point = _fc(out_channels[3], num_classes) def _make_layer(self, block, layer_num, in_channel, out_channel, stride): """ Make stage network of ResNet. Args: block (Cell): Resnet block. layer_num (int): Layer number. in_channel (int): Input channel. out_channel (int): Output channel. stride (int): Stride size for the first convolutional layer. Returns: SequentialCell, the output layer. Examples: >>> _make_layer(ResidualBlock, 3, 128, 256, 2) """ layers = [] resnet_block = block(in_channel, out_channel, stride=stride) layers.append(resnet_block) for _ in range(1, layer_num): resnet_block = block(out_channel, out_channel, stride=1) layers.append(resnet_block) return nn.SequentialCell(layers) def construct(self, x): x = self.conv1(x) x = self.bn1(x) x = self.relu(x) c1 = self.maxpool(x) c2 = self.layer1(c1) c3 = self.layer2(c2) c4 = self.layer3(c3) c5 = self.layer4(c4) out = self.mean(c5, (2, 3)) out = self.flatten(out) out = self.end_point(out) return out

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      20

      21

      22

      23

      24

      25

      26

      27

      28

      29

      30

      31

      32

      33

      34

      35

      36

      37

      38

      39

      40

      41

      42

      43

      44

      45

      46

      47

      48

      49

      50

      51

      52

      53

      54

      55

      56

      57

      58

      59

      60

      61

      62

      63

      64

      65

      66

      67

      68

      69

      70

      71

      72

      73

      74

      75

      76

      77

      78

      79

      80

      81

      82

      83

      84

      85

      86

      87

      88

      89

      90

      91

      92

      93

      94

      95

      96

      97

      98

      99

      100

      101

      102

      103

      104

      105

      106

      107

      108

      109

      ResNet50類定義如下:

      def resnet50(class_num=10): """ Get ResNet50 neural network. Args: class_num (int): Class number. Returns: Cell, cell instance of ResNet50 neural network. Examples: >>> net = resnet50(10) """ return ResNet(ResidualBlock, [3, 4, 6, 3], [64, 256, 512, 1024], [256, 512, 1024, 2048], [1, 2, 2, 2], class_num)

      1

      2

      3

      4

      5

      6

      MindSpore實現圖片分類

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      19

      適配訓練作業(跳過)

      創建訓練作業時,運行參數會通過腳本傳參的方式輸入給腳本代碼,腳本必須解析傳參才能在代碼中使用相應參數。如data_url和train_url,分別對應數據存儲路徑(OBS路徑)和訓練輸出路徑(OBS路徑)。腳本對傳參進行解析后賦值到args變量里,在后續代碼里可以使用。

      import argparse parser = argparse.ArgumentParser() parser.add_argument('--data_url', required=True, default=None, help='Location of data.') parser.add_argument('--train_url', required=True, default=None, help='Location of training outputs.') parser.add_argument('--num_epochs', type=int, default=90, help='Number of training epochs.') args, unknown = parser.parse_known_args()

      1

      2

      3

      4

      5

      6

      MindSpore暫時沒有提供直接訪問OBS數據的接口,需要通過ModelArts自帶的moxing框架與OBS交互。

      訓練開始前,拷貝自己賬戶下或他人共享的OBS桶內的數據集至執行容器。

      import moxing as mox # src_url形如's3://OBS/PATH',為OBS桶中數據集的路徑,dst_url為執行容器中的路徑 mox.file.copy_parallel(src_url=args.data_url, dst_url='cifar10/')

      1

      2

      3

      如需將訓練輸出(如模型Checkpoint)從執行容器拷貝至自己的OBS中,請參考:

      import moxing as mox # dst_url形如's3://OBS/PATH',將ckpt目錄拷貝至OBS后,可在OBS的`args.train_url`目錄下看到ckpt目錄 mox.file.copy_parallel(src_url='ckpt', dst_url=os.path.join(args.train_url, 'ckpt'))

      1

      2

      3

      創建訓練作業

      可以參考使用常用框架訓練模型來創建并啟動訓練作業(下文給出了操作步驟)。

      打開ModelArts控制臺-訓練管理-訓練作業,點擊“創建”按鈕進入訓練作業配置頁面,創建訓練作業的參考配置:

      算法來源:常用框架->Ascend-Powered-Engine->MindSpore

      代碼目錄:選擇上述新建的OBS桶中的experiment_3目錄

      啟動文件:選擇上述新建的OBS桶中的experiment_3目錄下的resnet50_train.py(注意,針對此文件,課程gitee倉庫代碼在167行有錯,多打了一個空格,同時,將120行改為local_data_path = 'cifar10' # your cifar10 path務必修改后重新上傳至obs)

      數據來源:數據存儲位置->選擇上述新建的OBS桶中的experiment_3文件夾下的cifar10目錄

      訓練輸出位置:選擇上述新建的OBS桶中的experiment_3目錄并在其中創建output目錄

      作業日志路徑:同訓練輸出位置

      規格:Ascend:1*Ascend 910

      其他均為默認

      啟動并查看訓練過程:

      點擊提交以開始訓練;

      在訓練作業列表里可以看到剛創建的訓練作業,在訓練作業頁面可以看到版本管理;

      點擊運行中的訓練作業,在展開的窗口中可以查看作業配置信息,以及訓練過程中的日志,日志會不斷刷新,等訓練作業完成后也可以下載日志到本地進行查看;

      在訓練日志中可以看到epoch 90 cost time = 27.328994035720825, train step num: 1562, one step time: 17.496154952446112 ms, train samples per second of cluster: 1829.0等字段,即訓練過程的性能數據;

      在訓練日志中可以看到epoch: 90 step 1562, loss is 0.0002547435578890145等字段,即訓練過程的loss數據;

      在訓練日志里可以看到Evaluation result: {'acc': 0.9467147435897436}.字段,即訓練完成后的驗證精度。

      epoch 1 cost time = 156.34279108047485, train step num: 1562, one step time: 100.09141554447814 ms, train samples per second of cluster: 319.7 epoch: 1 step 1562, loss is 1.5020508766174316 epoch 2 cost time = 27.33933186531067, train step num: 1562, one step time: 17.502773281248828 ms, train samples per second of cluster: 1828.3 epoch: 2 step 1562, loss is 1.612194299697876 epoch 3 cost time = 27.33275270462036, train step num: 1562, one step time: 17.498561270563613 ms, train samples per second of cluster: 1828.7 epoch: 3 step 1562, loss is 1.0880045890808105 ... ... ... epoch 50 cost time = 27.318379402160645, train step num: 1562, one step time: 17.48935941239478 ms, train samples per second of cluster: 1829.7 epoch: 50 step 1562, loss is 0.028316421434283257 epoch 51 cost time = 27.317234992980957, train step num: 1562, one step time: 17.488626756069756 ms, train samples per second of cluster: 1829.8 epoch: 51 step 1562, loss is 0.09725271165370941 ... ... ... Start run evaluation. Evaluation result: {'acc': 0.9467147435897436}.

      1

      2

      3

      4

      5

      6

      7

      8

      9

      10

      11

      12

      13

      14

      15

      16

      17

      18

      折騰了三個版本,筆者可算是訓練成功了。訓練大約需要45min。

      實驗結論

      本實驗主要介紹使用MindSpore在CIFAR-10數據集上訓練ResNet50,了解了以下知識點:

      使用自定義Callback實現性能監測;

      使用動態學習率提升訓練效果;

      加載CIFAR-10數據集、數據增強;

      ResNet50模型的結構及其MindSpore實現。

      MindSpore 機器學習

      版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。

      上一篇:淺談緩存與分布式鎖(分布式緩存的分布式鎖lock是否會造成死鎖)
      下一篇:Excel表格怎么使用照相機功能(excel表格中照相機的使用方法)
      相關文章
      亚洲人成免费网站| 亚洲国产激情一区二区三区| 亚洲精品无码av天堂| 亚洲色偷偷偷综合网| 亚洲成AV人片久久| 久久亚洲私人国产精品| 亚洲AV本道一区二区三区四区| 亚洲精品无码午夜福利中文字幕| 国产乱辈通伦影片在线播放亚洲| 亚洲麻豆精品国偷自产在线91| 国产成人亚洲精品无码AV大片| 国产AV无码专区亚洲AV琪琪| 亚洲AV无码一区二区三区在线观看| 国内成人精品亚洲日本语音| 男人的天堂亚洲一区二区三区 | 亚洲成a人片在线不卡| 亚洲福利在线视频| 亚洲国产综合专区电影在线| 亚洲男人天堂2017| 亚洲黄色网站视频| 亚洲成aⅴ人在线观看| 亚洲丝袜中文字幕| 一本色道久久88亚洲精品综合 | 亚洲国产综合人成综合网站00| 久久亚洲精品成人av无码网站| 久久久久亚洲av无码专区导航| 亚洲视频在线免费看| 亚洲国产午夜电影在线入口| 97久久国产亚洲精品超碰热| 亚洲午夜福利在线视频| 亚洲AV无码XXX麻豆艾秋| 亚洲电影日韩精品| 日韩精品亚洲aⅴ在线影院| 亚洲av综合av一区| 亚洲日韩国产精品无码av| 亚洲国产精品一区二区三区在线观看 | 亚洲AV成人潮喷综合网| 亚洲午夜精品久久久久久浪潮 | 国产亚洲综合色就色| 亚洲一区二区三区高清| 亚洲高清免费在线观看|