日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Dropout技术之随机神经元与随机深度

發布時間:2024/3/12 编程问答 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Dropout技术之随机神经元与随机深度 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

1. 寫在前面

在學習復現EfficientNet網絡的時候,里面有一個MBConv模塊長下面這個樣子:


當然,這個結構本身并不是很新奇,從resNet開始,幾乎后面很多網絡,比如DenseNet, MobileNet系列,ShuffleNet系列以及EfficientNet系列都會發現這樣的殘差結構。 但這次探索里面發現了Dropout這個點, 之前在實現殘差結構的時候, 如果碰到Dropout, 我一直以為是之前學習到的隨機失活神經元的Dropout,但直到在這里看到源碼才發現,不是我想象的那么簡單!

這種殘差結構里面使用的Dropout,是一種叫做隨機深度的Dropout技術。這個是2016年ECCV上發表的一篇paper,論文叫做《Deep Network with Stochastic depth》, 說的是訓練過程中,不是隨機失活每一層的神經元了,而是隨機去掉很多層,這樣能減少冗余,還能加速訓練。

出于好奇,我讀了下這篇paper, 又學習到了一種訓練帶有殘差網絡的騷操作,所以,這篇文章想統一把這兩種Dropout放一塊整理下。

2. Dropout之隨機神經元

這個技術就是普通的Dropout技術了,Dropout隨機失活神經元,就是我們給出一個概率,讓神經網絡層的某個神經元權重為0(失活)

就是每一層,讓某些神經元不起作用,這樣就就相當于把網絡進行簡化了(左邊和右邊可以對比),我們有時候之所以會出現過擬合現象,就是因為我們的網絡太復雜了,參數太多了,并且我們后面層的網絡也可能太過于依賴前層的某個神經元

加入Dropout之后, 首先網絡會變得簡單,減少一些參數,并且由于不知道淺層的哪些神經元會失活,導致后面的網絡不敢放太多的權重在前層的某個神經元,這樣就減輕了一個過渡依賴的現象, 對特征少了依賴, 從而有利于緩解過擬合

這個類似于我們期末考試的時候有沒有,老師總是會給我們畫出一個重點,但是由于我們不知道這些重點哪些會真的出現在試卷上,所以就得把精力分的均勻一些,都得看看, 這樣保險一些,也能泛化一點,至少只要是這些類型的題都會做。 而如果我們不把精力分的均勻一些,只關注某種題型, 那么準糊一波

所以這種Dropout技術可以幫助網絡緩解過擬合。不太難理解, 但使用的時候有幾個注意問題:

  • 數據尺度變化
    我們用Dropout的時候是這樣用的: 只在訓練的時候開啟Dropout,而測試的時候是不用Dropout的,也就是說模型訓練的時候會隨機失活一部分神經元, 而測試的時候我們用所有的神經元,那么這時候就會出現這個數據尺度的問題, 所以測試的時候,所有權重都乘以1-drop_prob, 以保證訓練和測試時尺度變化一致。 怎么理解? 依然拿上面的圖來說:

    假設我們的輸入是100個特征, 那么第一層的第一個神經元的表達式應該是這樣, 這里先假設不失活:
    Z11=∑i=1100wixiZ_{1}^{1}=\sum_{i=1}^{100} w_{i} x_{i} Z11?=i=1100?wi?xi?
    假設我們這里的wixi=1w_ix_i=1wi?xi?=1, 那么第一層第1個神經元Z11=100Z_1^1=100Z11?=100, 注意這是不失活的情況,那么如果失活呢? 假設失活率drop_prob=0.3, 也就是我們的輸入大約有30%是不起作用的,也就是會有30個不起作用, 當然這里是大約哈,因為失活率%30指的是每個神經元的失活率。換在整體上差不多可以理解成30個不起作用,那么我們的Z11Z_1^1Z11?相當于
    Z11train=∑i=170wixi=70{Z_1^1}_{train} = \sum_{i=1}^{70} w_ix_i = 70Z11?train?=i=170?wi?xi?=70
    我們發現,如果使用Dropout之后,我們的Z11Z_1^1Z11?成了70, 比起不失活來少了30, 這就是一個尺度的變化, 所以我們就發現如果訓練的時候用Dropout, 我們每個神經元取值的一個尺度是會縮小的,比如這里的70, 而測試的時候我們用的是全部的神經元,尺度會變成100,這就導致了模型在數值上有了一個差異。因此,我們在測試的時候,需要所有的權重乘以1-drop_prob這一項, 這時候我們在測試的時候就相當于:
    Z11test=∑i=1100(0.7×wi)xi=0.7×100=70{Z_1^1}_{test} = \sum_{i=1}^{100}(0.7\times w_i)x_i = 0.7 \times100 = 70Z11?test?=i=1100?(0.7×wi?)xi?=0.7×100=70

    這樣采用Dropout的訓練集和不采用Dropout的測試集的尺度就變成一致了。 Pytorch在實現Dropout的時候, 是權重乘以11?p\frac{1}{1-p}1?p1?的,也就是除以1-p, 這樣就不用再測試的時候權重乘以1-p了, 也沒有改變原來數據的尺度。 也就是上面公式中的
    Z11train=∑i=170(700.7wi)xi=100Z11test=∑i=1100wixi=100{Z_1^1}_{train} = \sum_{i=1}^{70} (\frac{70}{0.7}w_i)x_i = 100 \\ {Z_1^1}_{test} = \sum_{i=1}^{100} w_ix_i = 100Z11?train?=i=170?(0.770?wi?)xi?=100Z11?test?=i=1100?wi?xi?=100
    這個細節要注意下。

  • Dropout層放置的位置
    比如,我們寫下面這段代碼

    class MLP(nn.Module):def __init__(self, neural_num, d_prob=0.5):super(MLP, self).__init__()self.linears = nn.Sequential(nn.Linear(1, neural_num),nn.ReLU(inplace=True),nn.Dropout(d_prob), # 注意這里用上了Dropout, 我們看到這個Dropout是接在第二個Linear之前,Dropout通常放在需要Dropout網絡的前一層nn.Linear(neural_num, neural_num),nn.ReLU(inplace=True),nn.Dropout(d_prob),nn.Linear(neural_num, neural_num),nn.ReLU(inplace=True),nn.Dropout(d_prob), # 通常輸出層的Dropout是不加的,這里由于數據太簡單了才加上nn.Linear(neural_num, 1),)def forward(self, x):return self.linears(x)net_prob_05 = MLP(neural_num=n_hidden, d_prob=0.5)# ============================ step 3/5 優化器 ============================ optim_reglar = torch.optim.SGD(net_prob_05.parameters(), lr=lr_init, momentum=0.9)# ============================ step 4/5 損失函數 ============================ loss_func = torch.nn.MSELoss()# ============================ step 5/5 迭代訓練 ============================for epoch in range(max_iter):pred_wdecay = net_prob_05(train_x)loss_wdecay = loss_func(pred_wdecay, train_y)optim_reglar.zero_grad()loss_wdecay.backward()optim_reglar.step()if (epoch+1) % disp_interval == 0:# 這里要注意一下,Dropout在訓練和測試階段不一樣,這時候需要對網絡設置一個狀態net_prob_05.eval() # 這個.eval()函數表示我們的網絡即將使用測試狀態, 設置了這個測試狀態之后,才能用測試數據去測試網絡, 否則網絡怎么知道啥時候測試啥時候訓練?test_pred_prob_05 = net_prob_05(test_x)

    這里注意看MLP網絡里面Dropout層的位置,一般是放在需要Dropout的層的前面。輸入層不需要dropout,最后一個輸出層一般也不需要。就是由于Dropout操作,模型訓練和測試是不一樣的,上面我們說了,訓練的時候采用Dropout而測試的時候不用Dropout, 那么我們在迭代的時候,就得告訴網絡目前是什么狀態,如果要測試,就得先用.eval()函數告訴網絡一下子,訓練的時候就用.train()函數告訴網絡一下子。

  • 這就是我們之前熟知的Dropout隨機神經元技術了, 之前我的學習認知也停留在這里為止,直到又見識到了隨機深度技術, 所以下面重點整理下這個是怎么玩的。

    3. Dropout之隨機深度

    隨機深度是黃高博士在2016年提出來的一種針對網絡高效訓練的技術, 談到黃高博士,可能大家更熟悉他提出的DenseNet網絡, 這個網絡要比隨機深度晚一些,但也受到隨機深度的一些啟發。

    3.1 背景

    深的網絡在現在表現出了十分強大的能力,但是也存在許多問題。即使在現代計算機上,梯度會消散、前向傳播中信息的不斷衰減、訓練時間也會非常緩慢等問題。

    ResNet的強大性能在很多應用中已經得到了證實,盡管如此,ResNet還是有一個不可忽視的缺陷——更深層的網絡通常需要進行數周的訓練——因此,把它應用在實際場景下的成本非常高。為了解決這個問題,作者們引入了一個“反直覺”的方法,即在我們可以在訓練過程中任意地丟棄一些層,并在測試過程中使用完整的網絡。

    在EfficientNet中也逐漸發現了這個現象, 之前的一些研究, 主要是關注網絡的準確率和參數數量,比如設計更加復雜的網絡結構,更深,更寬,分辨率更大等,去提高網絡的準確率,但后來逐漸發現,這些網絡在實際場景中可能不太好落地。 所以后續的一些研究,又開始關注與網絡的訓練速度,推理速度等,所以一些輕量級的網絡慢慢誕生。 比如MobileNet系列,ShuffleNet系列以及EfficientNet系列。 當然也有可能是精度慢慢的到了瓶頸了。

    這篇paper也是想提高網絡的訓練速度或者效率,所以思路就是提出隨機深度,在訓練時使用較淺的深度(隨機在resnet的基礎上pass掉一些層),在測試時使用較深的深度,較少訓練時間,提高訓練性能,最終在四個數據集上都超過了resnet原有的性能(cifar-10, cifar-100, SVHN, imageNet)。其訓練過程中采用隨機dropout一些中間層的方法改進ResNet,發現可以顯著提高ResNet的泛化能力。

    那么怎么做到呢?

    3.2 網絡基本思想

    作者用了殘差塊作為他們網絡的構件,因此,在訓練中,如果一個特定的殘差塊被啟用了,那么它的輸入就會同時流經恒等表換shortcut(identity shortcut)和權重層;否則輸入就只會流經恒等變換shortcut。

    在訓練的過程中,每一個層都有一個“生存概率”,并且都會被任意丟棄。在測試過程中,所有的block都將保持被激活狀態,而且block都將根據其在訓練中的生存概率進行調整。


    假設HlH_lHl?是第lll個殘差塊的輸出結果, flf_lfl?是由第lll個殘差塊的主分支輸出。blb_lbl?是一個隨機變量(只有1或者0,反映一個block是否是被激活的,或者是否啟用當前主分支)。那么加了隨機深度的Dropout之后的殘差塊輸出公式計算如下:
    H?=ReLU?(b?f?(H??1)+id?(H??1))H_{\ell}=\operatorname{ReLU}\left(b_{\ell} f_{\ell}\left(H_{\ell-1}\right)+\operatorname{id}\left(H_{\ell-1}\right)\right) H??=ReLU(b??f??(H??1?)+id(H??1?))
    這個其實也非常好理解, 原先的殘差結構,就是跳遠連接+主分支然后非線性激活,只不過這里多了一個blb_lbl?來控制主分支是否有效。 如果bl=0b_l=0bl?=0, 那么
    Hl=ReLU?(id(Hl?1))H_{l}=\operatorname{ReLU}\left(i d\left(H_{l-1}\right)\right) Hl?=ReLU(id(Hl?1?))
    直走跳遠連接,而這個是恒等映射,相當于當前的殘差塊不起作用,否則當前的殘差塊就被啟用。

    那么這個blb_lbl?是怎么得到的呢? 這個和普通Dropout差不多,我們對于每個殘差塊,都指定一個是主分支激活的概率ppp,即每個殘差塊都有1?p1-p1?p可能性被dropout掉,即bl=0b_l=0bl?=0

    當然,在實際操作的時候,作者是將“線性衰減規律”應用到了每一層的生存概率,因為他們覺得較早的層會提取低級特征,而這些基礎特征對后面的層很重要,所以這些層不應該頻繁的丟棄主分支。 而隨著后面層提取的特征越來越抽象,冗余度可能更高,所以越到后面,這個丟棄主分支的概率就增加,具體計算公式如下:
    p?=1??L(1?pL)p_{\ell}=1-\frac{\ell}{L}\left(1-p_{L}\right) p??=1?L??(1?pL?)
    這里的plp_lpl?表示lll層訓練中主分支的保留概率,LLL是block塊的總數量, pLp_LpL?是我們給出的dropout_rate。lll是表示lll層的殘差塊。

    實驗表明,同樣是訓練一個110層的ResNet,以任意深度進行訓練的性能,比以固定深度進行訓練的性能要好。這就意味著ResNet中的一些層(路徑)可能是冗余的。

    所以這種訓練方式的優點:

  • 成果解決深度網絡訓練時間難題
  • 大大減少訓練時間,并顯著改善網絡的精度
  • 可以使得網絡更深
  • 當然,這里的原理不是很難, 下面主要是從代碼層面看看具體是怎么實現的。

    這里拿EfficientNet網絡里面的代碼進行說明,其他的也都類似:

    # kernel_size, in_channel, out_channel, exp_ratio, strides, use_SE, drop_connect_rate, repeats default_cnf = [[3, 32, 16, 1, 1, True, drop_connect_rate, 1],[3, 16, 24, 6, 2, True, drop_connect_rate, 2],[5, 24, 40, 6, 2, True, drop_connect_rate, 2],[3, 40, 80, 6, 2, True, drop_connect_rate, 3],[5, 80, 112, 6, 1, True, drop_connect_rate, 3],[5, 112, 192, 6, 2, True, drop_connect_rate, 4],[3, 192, 320, 6, 1, True, drop_connect_rate, 1]]

    這里給出每個stage的配置, 這個具體不用管,這個看EfficientNet的網絡結構就知道。

    這里是修改配置的代碼,也就是會遍歷上面的每個stage,然后根據重復次數建立殘差塊,這里的殘差塊是倒殘差模塊,開頭的那個圖里面的結構。 主要是框出來的這句話,就是“線性衰減規律”的那個公式, 這里的cnf[-1]表示的當前殘差塊的dropout_rate, 而args[-2]是我們指定的dropout_rate, bbb表示當前lll層, num_blocks就是總的blocks數, 和上面公式一一對應。

    這里就會發現,搭建網絡的時候,每個殘差塊都會指定一個dropout_rate, 那么在每個殘差塊里面,我們搭建的dropout層如下, 這里直接拿EfficientNetV1來看,重點關注self.dropout即可,上面的那些是主分支上的擴張卷積,dw卷積以及降維卷積,不是這篇文章的重點:

    class InvertedResidualEfficientNetV1(nn.Module):def __init__(self,cnf: InvertedResidualConfigEfficientNet,norm_layer: Callable[..., nn.Module]):super(InvertedResidualEfficientNetV1, self).__init__()self.use_res_connect = (cnf.stride == 1 and cnf.input_c == cnf.out_c)layers = OrderedDict()activation_layer = nn.SiLU # alias Swish# expandif cnf.expanded_c != cnf.input_c:layers.update({"expand_conv": ConvBNActivation(cnf.input_c,cnf.expanded_c,kernel_size=1,norm_layer=norm_layer,activation_layer=activation_layer)})# depthwiselayers.update({"dwconv": ConvBNActivation(cnf.expanded_c,cnf.expanded_c,kernel_size=cnf.kernel,stride=cnf.stride,groups=cnf.expanded_c,norm_layer=norm_layer,activation_layer=activation_layer)})if cnf.use_se:layers.update({"se": SqueezeExcitationV2(cnf.input_c,cnf.expanded_c)})# projectlayers.update({"project_conv": ConvBNActivation(cnf.expanded_c,cnf.out_c,kernel_size=1,norm_layer=norm_layer,activation_layer=nn.Identity)})self.block = nn.Sequential(layers)self.out_channels = cnf.out_cself.is_strided = cnf.stride > 1# 只有在使用shortcut連接時才使用dropout層if self.use_res_connect and cnf.drop_rate > 0:self.dropout = DropPath(cnf.drop_rate)else:self.dropout = nn.Identity()def forward(self, x: Tensor) -> Tensor:result = self.block(x)result = self.dropout(result)if self.use_res_connect:result += x

    這里的代碼細節不用多說, 其實就是開頭的那個殘差網絡結構, 我們主要看看啥時候使用Dropout, 只有使用跳遠連接,以及當前的dropout_rate大于0的時候, 我們的Dropout層會走一個DropPath, 否則不是殘差結構,或者沒有dropout_rate, 那么我們就恒等過去,所以DropoutPath只用于殘差結構。

    那么DropPath是怎么實現呢?

    class DropPath(nn.Module):def __init__(self, drop_prob=None):super(DropPath, self).__init__()self.drop_prob = drop_probdef forward(self, x):return drop_path(x, self.drop_prob, self.training)

    這里是建了一個DropPath層, 這里的核心實現是drop_path函數,在這里面,實現的就是根據給定的dropout_rate概率隨機失活主分支。所以重點看看這個的實現邏輯:

    def drop_path(x, drop_prob: float = 0, training: bool = False):if drop_prob == 0. or not training:return xkeep_prob = 1 - drop_prob# ndim是維度個數 x.shape[0] 是樣本個數, shape: (x.shape[0], 1, 1, 1) 維度可以用+拼接shape = (x.shape[0], ) + (1, ) * (x.ndim - 1)# 為每個樣本生成一個隨機數 torch.rand[0, 1), keep_prob (0, 1], 兩者之和是[0, 2) 形狀是(x.shape[0], 1, 1, 1)random_tensor = keep_prob + torch.rand(shape, dtype=x.dtype, device=x.device) # torch.rand 均勻分布抽取的隨機數([0,1))# 下取整,即random_tensor非0即1 形狀(x.shape[0], 1, 1, 1)random_tensor.floor_() # 下取整# 這里隨機失活主分支, 除以keep_prob是為了保持訓練和測試的尺度一致,普通dropout思路output = x.div(keep_prob) * random_tensorreturn output

    這里為了弄明白,我每一行代碼就加了注釋。 其實邏輯很簡單, 對于我們一個batch里面的樣本,比如nnn個, 那么輸入x的形狀就是(n,channelsize,h,w)(n, channel_{size}, h, w)(n,channelsize?,h,w), 我們首先會每個樣本,都會生成一個[0,2)之間的隨機數, 然后下取整,就得到了非0即1的random_tensor, 這個其實就是我們的blb_lbl?, 每個樣本對應一個,所以每個樣本訓練的時候,都會看看是否激活主分支。 然后具體是否激活,就是最后一行代碼做的事情, 這里除以keep_prob是為了保證訓練集和測試集的尺度范圍一致,和普通的dropout一樣。

    這樣,就實現了dropout技術隨機丟棄某些殘差層。

    之所以整理, 我覺得這個技術在網絡的訓練中還是非常實用的,并且是一種通用技術,可以用到帶有殘差網絡的很多模型,比如resnet, densenet, efficientnet等等,既能加快訓練速度,也能增加網絡精度,非常powerful的東西。

    參考:

    • 深度學習模型之——Stochastic depth(隨機深度)

    總結

    以上是生活随笔為你收集整理的Dropout技术之随机神经元与随机深度的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

    主站蜘蛛池模板: 精品一区二区不卡 | 天天色综合1 | 久久久欧美精品 | 九九视频免费看 | jizz18欧美18| 亚色在线视频 | 神马午夜国产 | 国产片淫乱18一级毛片动态图 | 中文字幕色图 | 精品午夜久久 | 亚洲激情在线观看 | 一级免费视频 | 日韩欧美在线免费 | 午夜影视体验区 | 国产一区二区精彩视频 | 午夜精品久久久久久久99热黄桃 | 韩国精品视频在线观看 | 久久久久久中文字幕 | 三级黄色短视频 | aⅴ在线免费观看 | 1024金沙人妻一区二区三区 | 亚洲成av人在线观看 | 日本少妇中文字幕 | 欧美性猛交xxxx偷拍洗澡 | 久久婷婷综合色丁香五月 | 丰满白嫩尤物一区二区 | 国产xxx69麻豆国语对白 | 2025国产精品| 传媒一区二区 | 成年人在线免费观看网站 | 九一在线观看免费高清视频 | 高潮喷水一区二区三区 | 嫩草av久久伊人妇女超级a | av片在线免费观看 | 日韩在线一区二区三区四区 | 国产精品野外户外 | 台湾少妇xxxx做受 | 国产精品11| 在线观看国产一级片 | 噼里啪啦动漫 | 欧美极品一区二区 | 午夜天堂网 | 波多野结衣欧美 | 国产精品午夜无码专区 | 欧美性插视频 | 在线免费观看视频你懂的 | 娇妻玩4p被三个男人伺候电影 | 超碰人人人 | 久久精品视频免费观看 | 国产中文字幕二区 | 国产视频99 | 三级av在线免费观看 | 中文字幕有码无码人妻av蜜桃 | 亚洲欧美日本一区 | 手机在线免费观看av | 国产高清在线免费 | 欧美xxx在线观看 | 麻豆乱码国产一区二区三区 | 久久精品99国产 | 黑丝一区 | 久久伊人中文字幕 | 亚洲精品第一页 | 欧美国产日韩视频 | 中文字幕狠狠 | 中文字幕日本一区二区 | 中文在线字幕免 | 91在线无精精品入口 | 成人激情在线观看 | 巨大胸大乳奶电影 | 免费看片亚洲 | 国产精品欧美久久久久天天影视 | 九九色视频 | 日韩毛片在线看 | 69热在线观看| 亚洲精品1234| 91精品国产高清一区二区三区蜜臀 | 天天做天天操 | 国产欧美一区二区三区在线看蜜臂 | 老师上课夹震蛋高潮了 | 男女av免费 | 久久av影视 | 一区二区国产在线 | 精品少妇人妻av一区二区 | 青青成人在线 | 日本一区视频在线观看 | 91精产品一区观看 | 欧美一级做a爰片久久高潮 久热国产精品视频 | 国产精品久久国产愉拍 | 亚洲国产影院 | 爱操av | av体验区 | 91在线无精精品一区二区 | 亚洲色图视频在线 | 亚洲精品国产一区二 | 麻豆视频网 | 91精品国产闺蜜国产在线闺蜜 | 韩日免费视频 | 日产精品久久久久 | 美女扒逼 |