深度學習-Pytorch框架學習之模型定義與簡單操作

前言

這一篇文章主要簡單的瞭解下在Pytorch框架下,卷積神經網絡的一些設置和應用,如有遺漏或錯誤,歡迎指出,不甚感激,互相學習!


深度學習-Pytorch框架學習之模型定義與簡單操作

簡單的兩層卷積網絡

<code> 

class

ConvNet(nn.Module): def __init__(

self

, num_classes=

10

):

super

(ConvNet,

self

).__init__() # 這個

super

我一直沒能理解

self

.layer1 = nn.Sequential( nn.Conv2d(

1

,

16

, kernel_size=

5

, stride=

1

, padding=

2

), nn.BatchNorm2d(

16

), nn.ReLU(), nn.MaxPool2d(kernel_size=

2

, stride=

2

))

self

.layer2 = nn.Sequential( nn.Conv2d(

16

,

32

, kernel_size=

5

, stride=

1

, padding=

2

), nn.BatchNorm2d(

32

), nn.ReLU(), nn.MaxPool2d(kernel_size=

2

, stride=

2

))

self

.fc = nn.Linear(

7

*

7

*

32

, num_classes) def forward(

self

, x):

out

=

self

.layer1(x)

out

=

self

.layer2(

out

)

out

=

out

.reshape(

out

.size(

0

),

-1

)

out

=

self

.fc(

out

)

return

out

model = ConvNet(num_classes).to(device)/<code>

關於卷積運算和對應的可視化,有很多網站做的都很好,可以便於理解和學習卷積操作,有想要分享的可以私信我,交換學習資源,共同進步。


深度學習-Pytorch框架學習之模型定義與簡單操作

多卡同步 BN(Batch normalization)

當使用 torch.nn.DataParallel 將代碼運行在多張 GPU 卡上時,PyTorch 的 BN 層默認操作是各卡上數據獨立地計算均值和標準差,同步 BN 使用所有卡上的數據一起計算 BN 層的均值和標準差,緩解了當批量大小(batch size)比較小時對均值和標準差估計不準的情況,是在目標檢測等任務中一個有效的提升性能的技巧。

<code>sync_bn = torch.nn.SyncBatchNorm(num_features, eps=

1e-05

, momentum=

0.1

, affine=

True

, track_running_stats=

True

)/<code>

但是網絡中可能不止一個BN層,一個一個的修改太繁瑣了。還好,pytorch框架考慮到了這個問題,可以通過下面的代碼,將已有網絡的所有BN層改為同步BN層。

<code>

def

convertBNtoSyncBN

(

module

, process_group=None)

: '''Recursively replace all BN layers to SyncBN layer. Args:

module

[torch.nn.Module]. Network '''

if

isinstance

(

module

, torch.nn.modules.batchnorm._BatchNorm)

: sync_bn

= torch.nn.SyncBatchNorm(

module

.num_features,

module

.eps,

module

.momentum,

module

.affine,

module

.track_running_stats, process_group) sync_bn.running_mean =

module

.running_mean sync_bn.running_var =

module

.running_var

if

module

.affine: sync_bn.weight =

module

.weight.clone().detach() sync_bn.bias =

module

.bias.clone().detach()

return

sync_bn

else

:

for

name, child_module in

module

.named_children(): setattr(

module

, name) = convert_syncbn_model(child_module, process_group=process_group))

return

module

/<code>

雙線性匯合(bilinear pooling)

<code>X = torch.reshape(N, D, H * W)                         
X = torch.bmm(X, torch.transpose(X, 1, 2)) / (H * W)   
assert X.size() == (N, D, D)
X = torch.reshape(X, (N, D * D))
X = torch.sign(X) * torch.sqrt(torch.abs(X) + 1e-5)    
X = torch.nn.functional.normalize(X)                  /<code>

計算模型整體參數量

<code>

num_parameters

= sum(torch.numel(parameter) for parameter in model.parameters())/<code>

查看網絡中的參數

如何查看神經網絡的參數也很重要,在Pytorch中可以通過model.state_dict()函數或者model.named_parameters()函數查看現在的全部可訓練參數(包括通過繼承得到的父類中的參數)。

<code>params = 

list

(model.named_parameters()) (name, param) = params[

28

]

print

(name)

print

(param.grad)

print

(

'-------------------------------------------------'

) (name2, param2) = params[

29

]

print

(name2)

print

(param2.grad)

print

(

'----------------------------------------------------'

) (name1, param1) = params[

30

]

print

(name1)

print

(param1.grad)/<code>

模型權重初始化

注意 model.modules() 和 model.children() 的區別:

model.modules() 會迭代地遍歷模型的所有子層,而 model.children() 只會遍歷模型下的一層。

<code># Common practise 

for

initialization.

for

layer

in

model.modules():

if

isinstance(layer, torch.nn.Conv2d): torch.nn.

init

.kaiming_normal_(layer.weight, mode=

'fan_out'

, nonlinearity=

'relu'

)

if

layer.bias

is

not None: torch.nn.

init

.constant_(layer.bias,

val

=

0.0

) elif isinstance(layer, torch.nn.BatchNorm2d): torch.nn.

init

.constant_(layer.weight,

val

=

1.0

) torch.nn.

init

.constant_(layer.bias,

val

=

0.0

) elif isinstance(layer, torch.nn.Linear): torch.nn.

init

.xavier_normal_(layer.weight)

if

layer.bias

is

not None: torch.nn.

init

.constant_(layer.bias,

val

=

0.0

) # Initialization with given tensor. layer.weight = torch.nn.Parameter(tensor)/<code>

如何提取模型中的某一層

modules()會返回模型中所有模塊的迭代器,它能夠訪問到最內層,比如self.layer1.conv1這個模塊,還有一個與它們相對應的是name_children()屬性以及named_modules(),這兩個不僅會返回模塊的迭代器,還會返回網絡層的名字。

<code> 

new_model

=

nn.Sequential(*list(model.children())[:2]

for

layer in model.named_modules():

if

isinstance(layer[1],nn.Conv2d):

conv_model.add_module(layer[0],layer[1])

/<code>

部分層使用預訓練模型

<code>model.load_state_dict(torch.load(

'model.pth'

),

strict

=

False

)/<code>

將在 GPU 保存的模型加載到 CPU

有些時候,訓練神經網絡時沒有GPU,但是有的人並沒有GPU訓練網絡,而Github上下載的模型大多數都是GPU訓練的,因此將GPU 保存的模型加載到 CPU也很重要。

<code>

model

.load_state_dict

(torch.load(

'model.pth'

, map_location=

'cpu'

))/<code>

導入另一個模型的相同部分到新的模型

模型導入參數時,如果兩個模型結構不一致,則直接導入參數會報錯。用下面方法可以把另一個模型的相同的部分導入到新的模型中。

<code> 
 
model_new_dict = model_new.state_dict()
model_common_dict = {k:v for k, v in model_saved.items() if k in model_new_dict.keys()}
model_new_dict.update(model_common_dict)
model_new.load_state_dict(model_new_dict)/<code>


未完待續...


分享到:


相關文章: