主頁 >  其他 > 0802-編程實戰_貓和狗二分類_深度學習專案架構

0802-編程實戰_貓和狗二分類_深度學習專案架構

2021-05-06 21:41:57 其他

0802-編程實戰_貓和狗二分類_深度學習專案架構

目錄
  • 一、比賽介紹
  • 二、資料加載
  • 三、模型定義
  • 四、工具函式
  • 五、組態檔
  • 六、main.py
    • 6.1 命令列工具 fire
    • 6.2 main.py的代碼組織結構
    • 6.3 訓練
      • 6.3.1 torchnet 中的 meter
    • 6.4 驗證
    • 6.5 測驗
    • 6.6 幫助函式
  • 七、使用
  • 八、爭議

pytorch完整教程目錄:https://www.cnblogs.com/nickchen121/p/14662511.html

一、比賽介紹

接下來我們將通過 pytorch 完成 Kaggle 上的經典比賽:Dogs vs. Cats

Dogs vs. Cats 是一個傳統的二分類問題,它的訓練集包含 25000 張圖片,這些圖片都放在同一個檔案夾中,命名格式為 <category>.<num>.jpg,例如 cat.10000.jpgdog.100.jpg,測驗集包含 12500 張圖片,命名為 <num>.jpg,例如 1000.jpg

參賽者需要根據訓練集的圖片訓練模型,并在測驗集上進行預測,輸出它是狗的概率,最后提交的 csv 檔案如下,第一列是圖片的 <num>,第二列是圖片為狗的概率,

id label
10001 0.889
10002 0.01
... ...

二、資料加載

資料的相關處理主要保存在 data/dataset.py 中,

關于資料加載,之前提過,基本原理就是先使用 Dataset 封裝資料集,再使用 Dataloader 實作資料并行加載,

Kaggle 提供的資料包括訓練集和測驗集,但是在我們使用的時候,還需要從訓練集中抽取一部分作為驗證集,

對于上述所說的三個資料集,雖然它們的相應操作不太一樣,但是如果專門寫出三個 Dataset,則會顯得復雜并冗余,因此在這里通過添加一些判斷來區分三者,比如我們希望對訓練集做一些資料增強處理,如隨機裁剪、隨機翻轉、加噪聲等,但是對于驗證集和測驗集則不需要,

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Coding by https://www.cnblogs.com/nickchen121/
# Datatime:2021/5/3 10:15
# Filename:dataset.py
# Toolby: PyCharm

import os
from PIL import Image
from torch.utils import data
import numpy as np
from torchvision import transforms as T


class DogCat(data.Dataset):
    def __init__(self, root, transforms=None, train=True, test=False):
        """
        目標:獲取所有圖片地址,并根據訓練、驗證、測驗劃分資料
        """
        self.test = test  # 獲取測驗集
        imgs = [os.path.join(root, img)
                for img in os.listdir(root)]  # 拼接所有圖片路徑,路徑地址如下所示
        """
        test1: data/test1/8973.jpg
        train: data/train/cat.10004.jpg
        """

        # 區分資料集是否為測驗集,并對資料集的圖片進行排序
        if self.test:
            imgs = sorted(
                imgs,
                key=lambda x: int(x.split('.')[-2].split('/')[-1]))  # 切割出 8973
        else:
            imgs = sorted(imgs,
                          key=lambda x: int(x.split('.')[-2]))  # 切割出 10004

        # 劃分訓練、驗證集,驗證:訓練 = 3:7
        imgs_num = len(imgs)
        if self.test:
            self.imgs = imgs
        elif train:
            self.imgs = imgs[:int(0.7 * imgs_num)]  # 訓練集來自資料集的前 70%
        else:
            self.imgs = imgs[int(0.7 * imgs_num):]

        # 資料轉換操作,測驗驗證和訓練的資料轉換有所區別
        if transforms is None:

            # Normalize給定均值:(R,G,B) 方差:(R,G,B),將會把Tensor正則化
            normalize = T.Normalize(mean=[0.485, 0.456, 0.406],
                                    std=[0.229, 0.224, 0.225])

            # 測驗集和驗證集
            if self.test or not train:
                self.transforms = T.Compose([
                    T.Scale(224),  # 讓圖片統一大小為:224*224
                    T.CenterCrop(224),  # 中心切割
                    T.ToTensor(),
                    normalize
                ])
            # 訓練集
            else:
                self.transforms = T.Compose([
                    T.Scale(256),  # 讓圖片統一大小為:256*256
                    T.RandomSizedCrop(224),  # 隨機切割圖片后,resize成給定的大小 224*224
                    T.RandomHorizontalFlip(),  # 一半的概率翻轉,一半的概率不翻轉
                    T.ToTensor(),
                    normalize
                ])

    def __getitem__(self, index):
        """
        回傳一張圖片的資料
        如果是測驗集,沒有圖片 id,如 8973.jpg 回傳 8973

        test1: data/test1/8973.jpg
        train: data/train/cat.10004.jpg
        """
        img_path = self.imgs[index]
        if self.test:
            label = self.imgs[index].split('.')[-2]  # type:str # 切割出 8973.jpg
            label = int(label.split('/')[-1])  # 切割出 8973

        else:
            label = 1 if 'dog' in img_path.split(
                '/')[-1] else 0  # 切割出 cat.10004.jpg,通過判斷對圖片增加標簽

        data = https://www.cnblogs.com/nickchen121/archive/2021/05/06/Image.open(img_path)
        data = self.transforms(data)  # 對圖片進行處理

        return data, label

    def __len__(self):"""
        回傳資料集中所有圖片的個數
        """
        return len(self.imgs)

# train_dataset = DogCat(opt.train_data_root, train=True)  # opt 是未來會講到的配置物件
# trainloader = DataLoader(train_dataset,
#                          batch_size=opt.batch_size,
#                          shuffle=True,
#                          num_workers=opt.num_workers)
# 
# for ii, (data, label) in enumerate(trainloader):
#     train()

上述代碼中我們需要注意三個點:

  • 把檔案讀取等費時操作放在 __getitem__ 函式中,利用多行程加速
  • 一次性把所有圖片讀進記憶體,不僅費時也會占用較大記憶體,而且不方便進行資料增強操作
  • 訓練集中的 30% 作為驗證集,可以用來檢查模型的訓練效果,避免過擬合

三、模型定義

模型的定義主要保存在 models 目錄下,其中 BasicModule 是對 nn.Module 的簡易封裝,提供快速加載和保存模型的介面,

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Coding by https://www.cnblogs.com/nickchen121/
# Datatime:2021/5/3 10:22
# Filename:BasicModule.py
# Toolby: PyCharm
import time
import torch as t


class BasicModule(t.nn.Module):
    """
    封裝了 nn.Module,主要提供 save 和 load 兩個方法
    """

    def __init__(self):
        super(BasicModule, self).__init__()
        self.model_name = str(type(self))  # 模型的默認名字

    def load(self, path):
        """
        可加載指定路徑的模型
        :param path:
        :return:
        """
        self.load_state_dict(t.load(path))

    def save(self, name=None):
        """
        保存模型,默認使用“模型名字+時間”作為檔案名,
        如 AlexNet_0710_23:57:29.pth
        :param name:
        :return:
        """
        if name is None:
            prefix = 'checkpoints/' + self.model_name + '.'
            name = time.strftime(prefix + '%m%d_%H:%M:%S.pth')
        t.save(self.state_dict(), name)
        return name

在實際使用中,直接呼叫 model.save() 以及 model.load(opt.load_path) 即可,

其他自定義模型一般繼承 BasicModule,然后實作自己的模型,由于實作了 AlexNet 和 ResNet34,在 models/__init__.py 中,可以寫下下述代碼:

from .AlexNet import AlexNet
from .ResNet34 import ResNet34

這樣主函式中就可以寫:

from models import AlexNet
# 或
import models
model = models.AlexNet()
# 或
import models
model = getattr('models', 'AlexNet')()

上述在主函式中的代碼中,其中最后寫法最關鍵,這樣意味著我們可以通過字串直接指定使用的模型,而不需要使用判斷陳述句,同時也不需要在每次新增加模型后都修改代碼,

但是最好的方法,就是在新增模型后需要在 models.__init__.py 中加上 from .new_module import new_module,避免使用第一種方法時報錯,或者避免使用 model = getattr('models', 'AlexNet')() 時找不到該物件,

最后,在模型定義的時候,需要注意以下三點:

  • 盡量使用 nn.Sequenetial
  • 將經常使用的結構封裝為子 module
  • 將重復且有規律性的結構用函式生成

四、工具函式

在專案中,我們可能需要用到一些經常使用的方法,這些方法可以統一放入到 utils 檔案夾中,需要時再匯入,

在這個專案中,主要封裝了可視化工具 visdom 的一些操作,

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Coding by https://www.cnblogs.com/nickchen121/
# Datatime:2021/5/3 10:23
# Filename:visualize.py
# Toolby: PyCharm
import visdom
import time
import numpy as np


class Visualizer(object):
    """
    封裝了 visdom 的基本操作,但仍然可以通過 `self.vis.function`
    或者 `self.function` 呼叫原生的 visdom 介面
    例如:
    self.text('hello visdom')
    self.histogram(t.randn(1000))
    self.line(t.arange(0, 10), t.arange(1, 11))
    """

    def __init__(self, env='default', **kwargs):
        self.vis = visdom.Visdom(env=env, **kwargs)

        # 保存('loss', 23) 即 loss 的第 23 個點
        self.index = {}
        self.log_text = ''

    def reinit(self, env='default', **kwargs):
        """
        修改 visdom 的配置
        :param env:
        :param kwargs:
        :return:
        """
        self.vis = visdom.Visdom(env=env, **kwargs)
        return self

    def plot_many(self, d: dict):
        """
        一次 plot 多個
        :param d: dict(name, value) i.e. ('loss', 0.11)
        :return:
        """
        for k, v in d.items():
            self.plot(k, v)

    def img_many(self, d: dict):
        """
        處理多張圖片
        :param d:
        :return:
        """
        for k, v in d.items():
            self.img(k, v)

    def plot(self, name, y, **kwargs):
        """
        self.plot('loss', 1.00)
        :param name: 
        :param y: 
        :param kwargs: 
        :return: 
        """
        x = self.index.get(name, 0)
        self.vis.line(Y=np.array([y]),
                      X=np.array([x]),
                      win=name,
                      opts=dict(title=name),
                      update=None if x == 0 else 'append',
                      **kwargs)
        self.index[name] = x + 1

    def img(self, name, img_, **kwargs):
        """
        self.img('input_img', t.Tensor(64, 64))
        self.img('input_imgs', t.Tensor(3, 64, 64))
        self.img('input_img', t.Tensor(100, 1, 64, 64))
        self.img('input_imgs', t.Tensor(100, 3, 64, 64), nrows=10)
        :param name:
        :param img_:
        :param kwargs:
        :return:
        """
        self.vis.images(img_.cpu().numpy,
                        win=name,
                        opts=dict(title=name),
                        **kwargs)

    def log(self, info, win='log_text'):
        """
        self.log({'loss':1, 'lr':0.0001}
        :param info:
        :param win:
        :return:
        """
        self.log_text += ('[{time}] {info} <br>'.format(
            time=time.strftime('%m%d_%H%M%S'),
            info=info
        ))
        self.vis.text(self.log_text, win)

    def __getattr__(self, name):
        """
        自定義的 plot,image,log,plot_many 等除外
        self.function 等價于 self.vis.function
        :param name:
        :return:
        """
        return getattr(self.vis, name)

五、組態檔

在模型定義、資料處理和訓練程序中會產生許多變數,這些變數應該提供默認值,并且統一放在組態檔中,如此做的話,在后期除錯、修改代碼的時候會方便很多,在這里,我們把所有課配置項都放在 config.py 中,

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Coding by https://www.cnblogs.com/nickchen121/
# Datatime:2021/5/3 10:20
# Filename:config.py
# Toolby: PyCharm
class DefaultConfig(object):
    env = 'default'
    model = 'AlexNet'  # 使用的模型,名字必須與 models/__init__.py 中的名字一致

    train_data_root = './data/train/'  # 訓練集存放路徑
    test_data_root = './data/test1'  # 測驗集存放路徑
    load_model_path = 'checkpoints/model.pth'  # 加載預訓練模型的路徑,為 None 代表不加載

    batch_size = 128  # batch_size
    use_gpu = False  # use GPU or not
    num_workers = 4  # num of workers for loading data
    print_freq = 20  # print info every N batch

    debug_file = '/tmp/debug'  # if os.path.exists(debug_file): enter ipdb
    result_file = 'result.csv'

    max_epoch = 10
    lr = 0.1  # initial learning rate
    lr_decay = 0.95  # when val_loss increase, lr = lr*lr_decay
    weight_decay = 1e-4  # 損失函式

從上述代碼中可以看出可配置的引數主要包括以下三類:

  • 資料集引數(檔案路徑、batch_size 等)
  • 訓練引數(學習率、訓練 epoch 等)
  • 模型引數

定義好了上述配置引數后,可以在程式中這樣使用配置引數:

import models
from config import DefaultConfig

opt = DefaultConfig()
lr = opt.lr
model = getattr(models, opt.model)
dataset = DogCat(opt.traini_data_error)

上述所說的都是默認引數,在默認配置類中,我們還可以提供一個更新函式,根據字典更新配置引數,

    def parse(self, kwargs: dict):
        """
        根據字典 kwargs 更新 config 引數
        :param kwargs:
        :return:
        """
        # 更新配置引數
        for k, v in kwargs.items():
            if not hasattr(self, k):
                warnings.warn(f"Warning: opt has not attribut {k}")
            setattr(self, k, v)

        # 列印配置資訊
        print('user config: ')
        for k, v in self.__class__.__dict__.items():  # type:str
            if not k.startswith('__'):
                print(k, getattr(self, k))

當然,在實際使用時沒必要每次修改 config.py,只需要通過命令列傳入所需要的引數,覆寫默認配置就行,例如

opt = DefaultConfig()
new_config = {'lr': 0.1, 'use_gpu': False}
opt.parse(new_config)
opt.lr == 0.1

六、main.py

6.1 命令列工具 fire

在講解 main 檔案前,我們先熟悉一個我們可能可以用到的一個命令列工具 fire,可以通過 pip install fire 安裝,下面介紹下 fire 的基礎用法,假設 example.py 檔案代碼如下:

# example.py
import file


def add(x, y):
    return x + y


def mul(**kwargs):
    a = kwargs['a']
    b = kwargs['b']
    return a * b


if __name__ == '__main__':
    fire.Fire()

那我們可以在命令列中通過以下陳述句呼叫 example 檔案中定義的函式:

python example.py add 1 2  # 執行 add(1, 2)
python example.py mul --a=1 --b=2  # 執行 mul(a=1, b=2), kwargs={'a':1, 'b':2}
python example.py add --x=1 --y=2  # 執行 add(x=1, y=2)

從上述代碼可以看出,只要在程式中運行了 fire.Fire(),就可以通過命令列引數 `python file [args,] {--kwargs,},當然,fire 還支持更多的高級功能,具體可以參考官方指南,

6.2 main.py的代碼組織結構

在我們這個專案的 main.py 中主要包括以下四個函式,其中三個需要命令列執行,main.py 的代碼組織結構如下所示:

#!/usr/bin/env python
# -*- coding:utf-8 -*-
# Coding by https://www.cnblogs.com/nickchen121/
# Datatime:2021/5/3 10:20
# Filename:main.py
# Toolby: PyCharm
import os
import csv
import ipdb
import fire
import torch as t
from torchnet import meter
from inspect import getsource
from torch.nn import functional
from torch.autograd import Variable
from torch.utils.data import DataLoader

import models
from config import opt
from data.dataset import DogCat
from utils.visualize import Visualizer


def train(**kwargs):
    """
    訓練
    :param kwargs:
    :return:
    """
    pass


def val(model, dataloader):
    """
    計算模型在驗證集上的準確率等資訊,用來輔助訓練
    :param model:
    :param dataloader:
    :return:
    """
    pass


def test(**kwargs):
    """
    測驗(inference)
    :param kwargs:
    :return:
    """
    pass


def dc_help():
    """
    列印幫助的資訊
    :return:
    """
    print('help')


if __name__ == '__main__':
    fire.Fire()

main.py 搭建好這樣的組織結構后,可以通過 python main.py <function> --args==xx 的方式執行訓練或測驗,

6.3 訓練

訓練的主要步驟如下:

  • 定義網路
  • 定義資料
  • 定義損失函式和優化器
  • 計算重要指標
  • 開始訓練
    • 訓練網路
    • 可視化各種指標
    • 計算在驗證集上的指標

其中訓練函式的代碼如下:

def train(**kwargs):
    """
    訓練
    :param kwargs:
    :return:
    """

    # 根據命令列引數更新配置
    opt.parse(kwargs)
    vis = Visualizer(opt.env)

    # step1:模型
    model = getattr(models, opt.model)()
    if opt.load_model_path:
        model.load(opt.load_model_path)
    if opt.use_gpu: model.cuda()

    # step2:資料
    train_data = https://www.cnblogs.com/nickchen121/archive/2021/05/06/DogCat(opt.train_data_root, train=True)
    val_data = DogCat(opt.train_data_root, train=False)
    train_dataloader = DataLoader(train_data,
                                  opt.batch_size,
                                  shuffle=True,
                                  num_workers=opt.num_workers)
    val_dataloader = DataLoader(val_data,
                                opt.batch_size,
                                shuffle=False,
                                num_workers=opt.num_workers)

    # step3:目標函式和優化器
    criterion = t.nn.CrossEntropyLoss()
    lr = opt.lr
    optimizer = t.optim.Adam(model.parameters(),
                             lr=lr,
                             weight_decay=opt.weight_decay)

    # step4:統計指標:平滑處理之后的損失,還有混淆矩陣
    loss_meter = meter.AverageValueMeter()  # 平均損失
    confusion_matrix = meter.ConfusionMeter(2)  # 混淆矩陣
    previous_loss = 1e100

    # 訓練
    for epoch in range(opt.max_epoch):

        loss_meter.reset()
        confusion_matrix.reset()

        for ii, (data, label) in enumerate(train_dataloader):

            # 訓練模型引數
            inp = Variable(data)
            target = Variable(label)
            if opt.use_gpu:
                inp = inp.cuda()
                target = target.cuda()
            optimizer.zero_grad()
            score = model(inp)
            loss = criterion(score, target)
            loss.backward()
            optimizer.step()

            # 更新統計指標及可視化
            loss_meter.add(loss.data[0])
            confusion_matrix.add(score.data, target.data)

            if ii % opt.print_freq == opt.print_freq - 1:
                vis.plot('loss', loss_meter.value()[0])

                # 如果需要的話,進入 debug 模式
                if os.path.exists(opt.debug_file):
                    ipdb.set_trace()

        model.save()

        # 計算驗證集上的指標及可視化
        val_cm, val_accuracy = val(model, val_dataloader)
        vis.plot('val_accuracy', val_accuracy)
        vis.log('epoch:{epoch},lr:{lr},loss:{loss},train_cm:{train_cm},val_cm{val_cm}'
                .format(epoch=epoch,
                        loss=loss_meter.value()[0],
                        val_cm=str(val_cm.value()),
                        train_cm=str(confusion_matrix.value()),
                        lr=lr))

        # 如果損失不再下降,則降低學習率
        if loss_meter.value()[0] > previous_loss:
            lr = lr * opt.lr_decay
            for param_group in optimizer.param_groups:
                param_group['lr'] = lr

        previous_loss = loss_meter.value()[0]

6.3.1 torchnet 中的 meter

在訓練的代碼中,這里用到了 PyTorchNet 里的一個工具:meter,由于 PyTorchNet 是從 TorchNet 中遷移來的,提供了很多有用的工具,但目前的開發和檔案都不是特別完善,這里不多做贅述,只講上述用到的幾個方法,

mter 提供了一些輕量級工具,可以幫助用戶快速的統計訓練程序中的一些指標,
* AverageValueMeter 能夠計算所有數的平均值和標準差,可以用來統計一個 epoch 中損失的平均值
* confusionmeter 用來統計分類問題中的分類情況,是一個比準確率更詳細的統計指標,給出的是一個混淆矩陣

混淆矩陣舉例:

樣本 判為狗 判為貓
實際是貓 35 15
實際是狗 9 91

注:想詳細了解混淆矩陣的在第七小節

6.4 驗證

驗證相比較訓練來說簡單很多,但是需要注意把模型置于驗證模式(model.eval()),驗證完成后還需要把它設定回訓練模式(model.train()),這兩句代碼會影響 BatchNorm 和 Dropout 等層的運行模式,驗證模型準確率的代碼如下:

def val(model, dataloader):
    """
    計算模型在驗證集上的準確率等資訊,用來輔助訓練
    :param model:
    :param dataloader:
    :return:
    """
    # 把模型設定為驗證模式
    model.eval()

    confusion_matrix = meter.ConfusionMeter(2)
    for ii, data in enumerate(dataloader):
        inp, label = data
        val_inp = Variable(inp, volatile=True)
        val_label = Variable(label.long(), volatile=True)
        if opt.use_gpu:
            val_inp = val_inp.cuda()
            val_label = val_label.cuda()
        score = model(val_inp)
        confusion_matrix.add(score.data.squeeze(), label.long())

    # 把模型恢復為訓練模式
    model.train()

    cm_value = https://www.cnblogs.com/nickchen121/archive/2021/05/06/confusion_matrix.value()
    accuracy = 100. * (cm_value[0][0] + cm_value[1][1]) / (cm_value.sum())

    return confusion_matrix, accuracy

6.5 測驗

測驗的時候,需要計算每個樣本屬于狗的概率,并把結果保存為 csv 檔案,測驗的代碼和驗證比較相似,但需要自己加載模型和資料,

def write_csv(results, file_name):
    with open(file_name, 'w') as f:
        writer = csv.writer(f)
        writer.writerow(['id', 'label'])
        writer.writerows(results)


def test(**kwargs):
    """
    測驗(inference)
    :param kwargs:
    :return:
    """
    opt.parse(kwargs)

    # 模型
    model = getattr(models, opt.model)().eval()
    if opt.load_model_path:
        model.load(opt.load_model_path)
    if opt.use_gpu: model.cuda()

    # 資料
    train_data = https://www.cnblogs.com/nickchen121/archive/2021/05/06/DogCat(opt.test_data_root, test=True)
    test_dataloader = DataLoader(train_data,
                                 batch_sampler=opt.batch_size,
                                 shuffle=False,
                                 num_workers=opt.num_workers)

    results = []
    for ii, (data, path) in enumerate(test_dataloader):
        inp = Variable(data, volatile=True)
        if opt.use_gpu: inp = inp.cuda()
        score = model(inp)

        probability = probability = functional.softmax(score, dim=1)[:, 0].detach().tolist()
        batch_results = [(path_, probability_) for path_, probability_ in zip(path, probability)]
        results += batch_results

    write_csv(results, opt.result_file)
    return results

6.6 幫助函式

為了讓他人方便使用,程式中應該還需要提供一個幫助函式,用于說明函式是如何使用的,

程式的命令列介面有很多引數,如果手動用字串表示不僅復雜,而且后期修改 config 檔案時還需要修改對應的幫助資訊,為此,這里使用 Python 標準庫中的 inspect 方法,可以自動獲取 config 的源代碼,

dg_help 的代碼如下:

def dc_help():
    """
    列印幫助的資訊
    :return:
    """
    print('''
    usage:python{0} <function> [--args=value,]
    <function> := train | test | help
    example:
        python {0} train --env='env0701' --lr=0.01
        python {0} test --dataset='path/to/dataset/root/'
        python {0} help
    avaiable args:
    '''.format(__file__))

    source = (getsource(opt.__class__))  # 獲取配置資訊
    print(source)

七、使用

如 dc_help 函式列印的資訊描述的一樣,可以通過命令列引數指定變數名,下面是三個使用例子,fire 會把包含 “-” 命令列引數自動轉成下劃線 “_”,也會把非數字的數值轉成字串,所以 --train--data-root=data/train--train_data_root = 'data/train' 是等價的,

感興趣的可以把資料集下載下來進行測驗:貓狗分類資料集

由于本章只是講解專案架構,我就不做測驗,但是代碼應該沒什么大問題,修修補補就行了,

想要具體代碼的可以加我微信:chenyoudea,但是沒必要找我要,我也沒有嘗試去跑通這個代碼,并且我也沒有下載資料集,因為這一章沒必要,

# 訓練模型
python main.py train
    --train-data-root=data/train/
    --load-model-path=None
    --lr=0.005
    --batch-size=32
    --model='ResNet34'
    --max-epoch=20
    
python main.py train --train-data-root=data/train/ --load-model-path=None --lr=0.005 --batch-size=32 --model='ResNet34' --max-epoch=20

    
# 測驗模型
python main.py test
    --test-data-root=data/test1
    --load-model-path=None
    --batch-szie=128
    --model='ResNet34'
    --num-workers=12
    
# 列印幫助資訊
python main.py dc_help

八、爭議

這里還是多說一嘴,因為這個風格更多的是書籍作者陳云老師的風格,并不是說以后你寫的代碼都要以這個為標準,這個專案架構更多的是作為一個題意或一種參考,

也就是說,不要把本篇文章的觀點作為一個必須遵守的規范,但是前期的學習可以按照這個架構來,這樣不容易犯錯,但是,對于未來你遇到的很多專案,尤其對于每個公司的專案,專案架構相信都是不一樣的,不唯經驗主義,不唯教條主義,這才是一個碼農想進階的必經之路,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/283119.html

標籤:其他

上一篇:【肌電信號】基于matlab GUI脈搏信號分析(去噪+特征提取)【含Matlab原始碼 862期】

下一篇:Ubuntu20安裝Truffle框架并部署第一個DApp

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 網閘典型架構簡述

    網閘架構一般分為兩種:三主機的三系統架構網閘和雙主機的2+1架構網閘。 三主機架構分別為內端機、外端機和仲裁機。三機無論從軟體和硬體上均各自獨立。首先從硬體上來看,三機都用各自獨立的主板、記憶體及存盤設備。從軟體上來看,三機有各自獨立的作業系統。這樣能達到完全的三機獨立。對于“2+1”系統,“2”分為 ......

    uj5u.com 2020-09-10 02:00:44 more
  • 如何從xshell上傳檔案到centos linux虛擬機里

    如何從xshell上傳檔案到centos linux虛擬機里及:虛擬機CentOs下執行 yum -y install lrzsz命令,出現錯誤:鏡像無法找到軟體包 前言 一、安裝lrzsz步驟 二、上傳檔案 三、遇到的問題及解決方案 總結 前言 提示:其實很簡單,往虛擬機上安裝一個上傳檔案的工具 ......

    uj5u.com 2020-09-10 02:00:47 more
  • 一、SQLMAP入門

    一、SQLMAP入門 1、判斷是否存在注入 sqlmap.py -u 網址/id=1 id=1不可缺少。當注入點后面的引數大于兩個時。需要加雙引號, sqlmap.py -u "網址/id=1&uid=1" 2、判斷文本中的請求是否存在注入 從文本中加載http請求,SQLMAP可以從一個文本檔案中 ......

    uj5u.com 2020-09-10 02:00:50 more
  • Metasploit 簡單使用教程

    metasploit 簡單使用教程 浩先生, 2020-08-28 16:18:25 分類專欄: kail 網路安全 linux 文章標簽: linux資訊安全 編輯 著作權 metasploit 使用教程 前言 一、Metasploit是什么? 二、準備作業 三、具體步驟 前言 Msfconsole ......

    uj5u.com 2020-09-10 02:00:53 more
  • 游戲逆向之驅動層與用戶層通訊

    驅動層代碼: #pragma once #include <ntifs.h> #define add_code CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS) /* 更多游戲逆向視頻www.yxfzedu.com ......

    uj5u.com 2020-09-10 02:00:56 more
  • 北斗電力時鐘(北斗授時服務器)讓網路資料更精準

    北斗電力時鐘(北斗授時服務器)讓網路資料更精準 北斗電力時鐘(北斗授時服務器)讓網路資料更精準 京準電子科技官微——ahjzsz 近幾年,資訊技術的得了快速發展,互聯網在逐漸普及,其在人們生活和生產中都得到了廣泛應用,并且取得了不錯的應用效果。計算機網路資訊在電力系統中的應用,一方面使電力系統的運行 ......

    uj5u.com 2020-09-10 02:01:03 more
  • 【CTF】CTFHub 技能樹 彩蛋 writeup

    ?碎碎念 CTFHub:https://www.ctfhub.com/ 筆者入門CTF時時剛開始刷的是bugku的舊平臺,后來才有了CTFHub。 感覺不論是網頁UI設計,還是題目質量,賽事跟蹤,工具軟體都做得很不錯。 而且因為獨到的金幣制度的確讓人有一種想去刷題賺金幣的感覺。 個人還是非常喜歡這個 ......

    uj5u.com 2020-09-10 02:04:05 more
  • 02windows基礎操作

    我學到了一下幾點 Windows系統目錄結構與滲透的作用 常見Windows的服務詳解 Windows埠詳解 常用的Windows注冊表詳解 hacker DOS命令詳解(net user / type /md /rd/ dir /cd /net use copy、批處理 等) 利用dos命令制作 ......

    uj5u.com 2020-09-10 02:04:18 more
  • 03.Linux基礎操作

    我學到了以下幾點 01Linux系統介紹02系統安裝,密碼啊破解03Linux常用命令04LAMP 01LINUX windows: win03 8 12 16 19 配置不繁瑣 Linux:redhat,centos(紅帽社區版),Ubuntu server,suse unix:金融機構,證券,銀 ......

    uj5u.com 2020-09-10 02:04:30 more
  • 05HTML

    01HTML介紹 02頭部標簽講解03基礎標簽講解04表單標簽講解 HTML前段語言 js1.了解代碼2.根據代碼 懂得挖掘漏洞 (POST注入/XSS漏洞上傳)3.黑帽seo 白帽seo 客戶網站被黑帽植入劫持代碼如何處理4.熟悉html表單 <html><head><title>TDK標題,描述 ......

    uj5u.com 2020-09-10 02:04:36 more
最新发布
  • 2023年最新微信小程式抓包教程

    01 開門見山 隔一個月發一篇文章,不過分。 首先回顧一下《微信系結手機號資料庫被脫庫事件》,我也是第一時間得知了這個訊息,然后跟蹤了整件事情的經過。下面是這起事件的相關截圖以及近日流出的一萬條資料樣本: 個人認為這件事也沒什么,還不如關注一下之前45億快遞資料查詢渠道疑似在近日復活的訊息。 訊息是 ......

    uj5u.com 2023-04-20 08:48:24 more
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:47:46 more
  • vulnhub_Earth

    前言 靶機地址->>>vulnhub_Earth 攻擊機ip:192.168.20.121 靶機ip:192.168.20.122 參考文章 https://www.cnblogs.com/Jing-X/archive/2022/04/03/16097695.html https://www.cnb ......

    uj5u.com 2023-04-20 07:46:20 more
  • 從4k到42k,軟體測驗工程師的漲薪史,給我看哭了

    清明節一過,盲猜大家已經無心上班,在數著日子準備過五一,但一想到銀行卡里的余額……瞬間心情就不美麗了。最近,2023年高校畢業生就業調查顯示,本科畢業月平均起薪為5825元。調查一出,便有很多同學表示自己又被平均了。看著這一資料,不免讓人想到前不久中國青年報的一項調查:近六成大學生認為畢業10年內會 ......

    uj5u.com 2023-04-20 07:44:00 more
  • 最新版本 Stable Diffusion 開源 AI 繪畫工具之中文自動提詞篇

    🎈 標簽生成器 由于輸入正向提示詞 prompt 和反向提示詞 negative prompt 都是使用英文,所以對學習母語的我們非常不友好 使用網址:https://tinygeeker.github.io/p/ai-prompt-generator 這個網址是為了讓大家在使用 AI 繪畫的時候 ......

    uj5u.com 2023-04-20 07:43:36 more
  • 漫談前端自動化測驗演進之路及測驗工具分析

    隨著前端技術的不斷發展和應用程式的日益復雜,前端自動化測驗也在不斷演進。隨著 Web 應用程式變得越來越復雜,自動化測驗的需求也越來越高。如今,自動化測驗已經成為 Web 應用程式開發程序中不可或缺的一部分,它們可以幫助開發人員更快地發現和修復錯誤,提高應用程式的性能和可靠性。 ......

    uj5u.com 2023-04-20 07:43:16 more
  • CANN開發實踐:4個DVPP記憶體問題的典型案例解讀

    摘要:由于DVPP媒體資料處理功能對存放輸入、輸出資料的記憶體有更高的要求(例如,記憶體首地址128位元組對齊),因此需呼叫專用的記憶體申請介面,那么本期就分享幾個關于DVPP記憶體問題的典型案例,并給出原因分析及解決方法。 本文分享自華為云社區《FAQ_DVPP記憶體問題案例》,作者:昇騰CANN。 DVPP ......

    uj5u.com 2023-04-20 07:43:03 more
  • msf學習

    msf學習 以kali自帶的msf為例 一、msf核心模塊與功能 msf模塊都放在/usr/share/metasploit-framework/modules目錄下 1、auxiliary 輔助模塊,輔助滲透(埠掃描、登錄密碼爆破、漏洞驗證等) 2、encoders 編碼器模塊,主要包含各種編碼 ......

    uj5u.com 2023-04-20 07:42:59 more
  • Halcon軟體安裝與界面簡介

    1. 下載Halcon17版本到到本地 2. 雙擊安裝包后 3. 步驟如下 1.2 Halcon軟體安裝 界面分為四大塊 1. Halcon的五個助手 1) 影像采集助手:與相機連接,設定相機引數,采集影像 2) 標定助手:九點標定或是其它的標定,生成標定檔案及內參外參,可以將像素單位轉換為長度單位 ......

    uj5u.com 2023-04-20 07:42:17 more
  • 在MacOS下使用Unity3D開發游戲

    第一次發博客,先發一下我的游戲開發環境吧。 去年2月份買了一臺MacBookPro2021 M1pro(以下簡稱mbp),這一年來一直在用mbp開發游戲。我大致分享一下我的開發工具以及使用體驗。 1、Unity 官網鏈接: https://unity.cn/releases 我一般使用的Apple ......

    uj5u.com 2023-04-20 07:40:19 more