Pytorch 英語公式ドキュメント学習メモ (3、Torch.nn および torch.optim)

1. nn.Moduleの使用

PyTorch のすべてのモジュールは nn.Module をサブクラス化し、
それ自体で定義されたすべてのモジュールは nn.Module のサブクラスである必要があります。

Pytorch は nn.Module に __call__ メソッドを実装し、 __call__ メソッドで forward 関数を呼び出します。
主にパラメータとメソッドが付属しています:
model.state_dict() メソッドと model.parameters() メソッドの
重みパラメータとバイアス パラメータ

class Ethan(nn.Module):
    def __init__(self):
        super().__init__()

    def forward(self, input):
        out_put = input + 1
        return out_put

if __name__ == '__main__':
    ethan=Ethan()
    x=torch.tensor(1.0)
    output=ethan(x)
    #此步代码调用的是pytorch内置的__call__()函数,然后这个__call__函数会做很多事情,其中包括调用forward函数
    print(output)


torch.nn.Module に付属する eval 関数と train 関数

torch.nn.Module.eval
モジュールを評価モードに設定します
これは特定のモジュールにのみ影響します。Dropout、BatchNorm など、影響を受ける場合、トレーニング/評価モードでの動作の詳細については、特定のモジュールのドキュメントを参照してください。
これは self.train(False) と同等です。

torch.nn.Module.train
モジュールをトレーニング モードに設定します。
これは特定のモジュールにのみ影響します。Dropout、BatchNorm などの特定のモジュールが影響を受ける場合、トレーニング/評価モードでの動作の詳細については、そのモジュールのドキュメントを参照してください。


二、nn.function.conv2d() → テンソル

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups=1) 
→ Tensor

パラメータ
input – 形状の入力テンソル ( minibatch \text minibatchミニバッチ_チャネル\ text in \ _channels _in _チャンネル, iH \ textiH _ _ _ _ _HW へ \text to WW

重み – 形状のフィルター ( out _channels \text out\_channelso u t _チャンネルin_channelsグループ \frac{\text{ in \ _channels } }{ \ text { groups } }グループチャンネル内k H \text kHk Hk W \テキスト kWkW ) _

bias – 形状のオプションのバイアス テンソル ( out_channels \text{out\_channels}out_channels )。デフォルト: なし

stride – 畳み込みカーネルのストライド。単一の数値またはタプルを指定できます ( s H \text sHs Hs W \text sws W ).デフォルト: 1
ストライドはカーネルが 1 ステップ移動する距離を表します

パディング – input の両側の暗黙的なパディング。文字列 {'valid', 'same'}、単一の数値、またはタプルを指定できます ( pad H \text PadHパッドH パッド W \text PadWパッドW ) _ デフォルト: 0。padding ='valid' はパディングなしと同じです。padding='same' は、出力が入力と同じ形状になるように入力をパディングします。ただし、このモードは 1 以外のストライド値をサポートしません

警告:padding='same' の場合、重みが偶数長で、どの次元でも拡張が奇数の場合、内部で完全な Pad() 操作が必要になる可能性があります。パフォーマンスの低下。

dilation – カーネル要素間の間隔。単一の数値またはタプル ( d H \text dHd Hd W \text dWdW )デフォルト: 1

グループ – 入力をグループに分割します ( in_channels \text{in\_channels})in_channels はグループの数で割り切れる必要があります。デフォルト: 1

	input=torch.tensor([[1,2,0,3,1],
                        [0,1,2,3,1],
                        [1,2,1,0,0],
                        [5,2,3,1,1],
                        [2,1,0,1,1]])
    kernel=torch.tensor([[1,2,1],
                         [0,1,0],
                         [2,1,0]])

    input=torch.reshape(input,(1,1,5,5))
    kernel=torch.reshape(kernel,(1,1,3,3))

    output1=nn.functional.conv2d(input,kernel,stride=1)
    print(output1)

    output2=nn.functional.conv2d(input,kernel,stride=2)
    print(output2)

    output3 = nn.functional.conv2d(input, kernel, stride=1,padding=1)
    print(output3)
	# tensor([[[[10, 12, 12],
    #           [18, 16, 16],
    #           [13, 9, 3]]]])
    # tensor([[[[10, 12],
    #           [13, 3]]]])
    # tensor([[[[1, 3, 4, 10, 8],
    #           [5, 10, 12, 12, 6],
    #           [7, 18, 16, 16, 8],
    #           [11, 13, 9, 3, 4],
    #           [14, 13, 9, 7, 4]]]])



三、torch.nn.Conv2d()、torch.nn.ConvTranspose2d()

1、torch.nn.Conv2d()

torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, 
				dilation=1, groups=1, bias=True, padding_mode='zeros', 
				device=None, dtype=None)

パラメータ:
in_channels (int) – 入力画像のチャンネル数

out_channels (int) – 畳み込みによって生成されるチャネルの数
out_channel>1 の場合、毎回トレーニング用に異なるコンボリューション カーネルがランダムに生成されます。

kernel_size (int または tuple) – 畳み込みカーネルのサイズ

stride (int または tuple、オプション) – 畳み込みのストライド。デフォルト: 1

パディング (int、タプル、または str、オプション) – 入力の 4 つの側面すべてに追加されるパディング。デフォルト: 0

padding_mode (文字列、オプション) – 'zeros'、'reflect'、'replicate'、または 'circular'。デフォルト: 'ゼロ'

dilation (int または tuple、オプション) – カーネル要素間の間隔。デフォルト: 1
膨張のデフォルトは 1 \color{red}膨張のデフォルトは 1拡張デフォルト1 _ _ _ _ _ _ _

拡張デモのレンダリングは以下の通りで、拡張が 1 のときの kernel_size 3 のコンボリューション カーネルの形状は 5×5 なので、拡張の値が H out と W out に影響ます
ここに画像の説明を挿入します

groups (int、オプション) – 入力チャンネルから出力チャンネルへのブロックされた接続の数。デフォルト: 1

bias (bool、オプション) – True の場合、出力に学習可能なバイアスを追加します。デフォルト: True

H outと W outの計算式は以下のとおりです。
パラメータpadding、dilation、kernel_sizeがintの場合、padding[0]=padding[1]、dilation[0]=dilation[1]、kernel_size[0]=kernel_size[1]はパラメータ内の全てint値となります。

HoutとWoutの計算式


このリンクは、ストライド、パディング、拡張の 3 つのパラメーターの役割を非常に直観的に示しています。
ここに画像の説明を挿入します


dataset=datasets.CIFAR10("./数据集",train=False,download=True,
						transform=transforms.ToTensor())
dataLoader=DataLoader(dataset,batch_size=64,drop_last=True)
class Ethan(nn.Module):
    def __init__(self):
        super(Ethan,self).__init__()
        self.conv=nn.Conv2d(in_channels=3,out_channels=6,kernel_size=3,
        					stride=1,padding=0)

    def forward(self,input):
        output=self.conv(input)
        return output

ethan=Ethan()
step=0
writer=SummaryWriter("./log1")
for data in dataLoader:
    imgs,targets=data
    output=ethan(imgs)
    print(imgs.shape)#torch.Size([64, 3, 32, 32])
    print(output.shape)#torch.Size([64, 6, 30, 30])
    #由Conv2d的形参stride=1等可以推断出为何是[64, 6, 30, 30]
    writer.add_images("input",imgs,step)
    output=torch.reshape(output,(-1,3,30,30))#add_image要求channel为3
    print(output.shape)#torch.Size([128, 3, 30, 30])
    writer.add_images("output",output,step)
    step+=1

ここに画像の説明を挿入します

ここに画像の説明を挿入します
nn.Conv2d() は毎回新しいコンボリューション カーネルをランダムに生成するため、実行ごとの効果は異なり、結果も異なります。
この単純なモデルでは、ランダムに生成されたコンボリューション カーネルのパラメーターをトレーニングしませんでした。


2、torch.nn.ConvTranspose2d()

torch.nn.ConvTranspose2d(in_channels, out_channels, kernel_size, 
	stride=1, padding=0, output_padding=0, groups=1, bias=True, 
	dilation=1, padding_mode='zeros', device=None, dtype=None)

パラメーター:
in_channels (int) – 入力画像のチャンネル数

out_channels (int) – 畳み込みによって生成されるチャネルの数

kernel_size (int または tuple) – 畳み込みカーネルのサイズ

stride (int または tuple、オプション) – 畳み込みのストライド。デフォルト: 1

パディング (int またはタプル、オプション)– dilation * (kernel_size - 1) -パディング 入力の各次元の両側にゼロパディングが追加されます。デフォルト: 0

Output_padding (int または tuple、オプション)出力形状の各寸法の片側に追加のサイズが追加されます。デフォルト: 0

groups (int、オプション) – 入力チャンネルから出力チャンネルへのブロックされた接続の数。デフォルト: 1

bias (bool、オプション) – True の場合、出力に学習可能なバイアスを追加します。デフォルト: True

dilation (int または tuple、オプション) – カーネル要素間の間隔。デフォルト: 1


H outと W outの計算式は次のとおりです:
H out = ( H in − 1 ) × stride [ 0 ] − 2 × padding [ 0 ] + dilation [ 0 ] × ( kernel _ size [ 0 ] − 1 ) + Output _パディング [ 0 ] + 1 H_{out}=(H_{in}-1)×stride[0]-2×padding[0]+dilation[0]×(kernel\_size[0]-1)+output\ _パディング[0]+1Hあなた_=( H1 )×歩幅[ 0 ] _ _ _ _ _2×パディング[ 0 ] _ _ _ _ _ _+拡張[ 0 ] _ _ _ _ _ _ _×(カーネル_サイズ[ 0 ] _ _ _ _ _ _ _ _1 )+出力_パディング[ 0 ] _ _ _ _ _ _ _ _ _ _ _+1
W
out = ( W in − 1 ) × ストライド [ 1 ] − 2 × パディング [ 1 ] + 拡張 [ 1 ] × ( カーネル _ サイズ [ 1 ] − 1 ) + 出力_パディング [ 1 ] + 1 W_{ out}=(W_{in}-1)×stride[1]-2×padding[1]+dilation[1]×(kernel\_size[1]-1)+output\_padding[1]+1Wあなた_=( W1 )×ストライド[ 1 ] _ _ _ _ _2×パディング[ 1 ] _ _ _ _ _ _+拡張[ 1 ] _ _ _ _ _ _ _×(カーネル_サイズ[ 1 ] _ _ _ _ _ _ _ _1 )+出力_パディング[ 1 ] _ _ _ _ _ _ _ _ _ _ _+1


デバイス コンボリューションで実行される操作:
① 入力特徴マップに対して補間演算を実行して新しい特徴マップを取得します、
② 特定のサイズのコンボリューション カーネルをランダムに初期化します、最後に、ランダムに初期化された特定のサイズのコンボリューション カーネルを新しい Convolution で使用します。操作は特徴マップ上で実行されます。
重要なのは、新しい特徴マップを取得する方法であり、stride=1 と stride>1 に分割されます。stride>1 の場合、元の特徴マップの各隣接行に (stride-1) 行が挿入され、(stride) -) 隣接する列に挿入されます。 1) 列; stride=1 の場合、周囲の 2 つのレイヤーで塗りつぶされます。デフォルトは 0 (に基づく) です。次に、パディング値に従って周囲が埋められ、最終的に新しい特徴マップが取得されます。

no_padding_no_strides_transused
パディングストライド_トランスポーズド

input = torch.rand(1,2,3,4)
model1=nn.ConvTranspose2d(in_channels=2,out_channels=4,kernel_size=4,stride=1,padding=0)
model2 = nn.ConvTranspose2d(in_channels=2, out_channels=4, kernel_size=4, stride=1, padding=1)
output1 = model1(input)
output2 = model2(input)
print (output1.shape)#torch.Size([1, 4, 6, 7])
print (output2.shape)#torch.Size([1, 4, 4, 5])


アップサンプリング方法もあります:
1.
CLASS torch.nn.Upsample(size=None,scale_factor=None,mode='nearest',align_corners=None,recompute_scale_factor=None)

パラメータ:
align_corners (ブール値、オプション) – True の場合、入力テンソルと出力テンソルのコーナー ピクセルが位置合わせされ、したがってそれらのピクセルの値が維持されます。これは、モードが「linear」、「bilinear」、「bicubic」、または「trilinear」の場合にのみ効果があります。デフォルト: 偽
ここに画像の説明を挿入します


mode='nearest' と mode='bilinear' の違いは、以下の例を見ると簡単に理解できます。

>>> input = torch.arange(1, 5, dtype=torch.float32).view(1, 1, 2, 2)
>>> input
tensor([[[[1., 2.],
          [3., 4.]]]])

>>> m = nn.Upsample(scale_factor=2, mode='nearest')
>>> m(input)
tensor([[[[1., 1., 2., 2.],
          [1., 1., 2., 2.],
          [3., 3., 4., 4.],
          [3., 3., 4., 4.]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear')  # align_corners=False
>>> m(input)
tensor([[[[1.0000, 1.2500, 1.7500, 2.0000],
          [1.5000, 1.7500, 2.2500, 2.5000],
          [2.5000, 2.7500, 3.2500, 3.5000],
          [3.0000, 3.2500, 3.7500, 4.0000]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
>>> m(input)
tensor([[[[1.0000, 1.3333, 1.6667, 2.0000],
          [1.6667, 2.0000, 2.3333, 2.6667],
          [2.3333, 2.6667, 3.0000, 3.3333],
          [3.0000, 3.3333, 3.6667, 4.0000]]]])

>>> # Try scaling the same data in a larger tensor
>>> input_3x3 = torch.zeros(3, 3).view(1, 1, 3, 3)
>>> input_3x3[:, :, :2, :2].copy_(input)
tensor([[[[1., 2.],
          [3., 4.]]]])
>>> input_3x3
tensor([[[[1., 2., 0.],
          [3., 4., 0.],
          [0., 0., 0.]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear')  # align_corners=False
>>> # Notice that values in top left corner are the same with the small input (except at boundary)
>>> m(input_3x3)
tensor([[[[1.0000, 1.2500, 1.7500, 1.5000, 0.5000, 0.0000],
          [1.5000, 1.7500, 2.2500, 1.8750, 0.6250, 0.0000],
          [2.5000, 2.7500, 3.2500, 2.6250, 0.8750, 0.0000],
          [2.2500, 2.4375, 2.8125, 2.2500, 0.7500, 0.0000],
          [0.7500, 0.8125, 0.9375, 0.7500, 0.2500, 0.0000],
          [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]]])

>>> m = nn.Upsample(scale_factor=2, mode='bilinear', align_corners=True)
>>> # Notice that values in top left corner are now changed
>>> m(input_3x3)
tensor([[[[1.0000, 1.4000, 1.8000, 1.6000, 0.8000, 0.0000],
          [1.8000, 2.2000, 2.6000, 2.2400, 1.1200, 0.0000],
          [2.6000, 3.0000, 3.4000, 2.8800, 1.4400, 0.0000],
          [2.4000, 2.7200, 3.0400, 2.5600, 1.2800, 0.0000],
          [1.2000, 1.3600, 1.5200, 1.2800, 0.6400, 0.0000],
          [0.0000, 0.0000, 0.0000, 0.0000, 0.0000, 0.0000]]]])


2、
torch.nn.function.interpolate(input, size=None,scale_factor=None,mode='nearest', align_corners=None, recompute_scale_factor=None, antialias=False)


3. torch.nn.MaxPool2d()

torch.nn.MaxPool2d(kernel_size, stride=None, padding=0, dilation=1, 
					return_indices=False, ceil_mode=False)

kernel_size – 最大ストライドを超えるウィンドウのサイズ
設定されていない場合、デフォルト値は kernelsize \color{red}stride に等しくなります 設定されていない場合、デフォルト値は kernel_size に等しくなりますs t r i d e が設定されていない場合デフォルトker n e lと等しくなりますs_

ceil_mode – True の場合、floor の代わりに ceil を使用して出力形状を計算します。
true の場合の ceil_mode の役割を次の図で説明します カーネルが入力イメージを部分的に超えた場合に、出力を考慮するかどうかが ceil_mode の役割です。


H outと W outの計算式は以下のとおりです。
ここに画像の説明を挿入します

class Ethan(nn.Module):
    def __init__(self):
        super(Ethan,self).__init__()
        self.maxpool=nn.MaxPool2d(kernel_size=3,ceil_mode=False)
    def forward(self,input):
        output=self.maxpool(input)
        return output
input = torch.tensor([[1, 2, 0, 3, 1],
                      [0, 1, 2, 3, 1],
                      [1, 2, 1, 0, 0],
                      [5, 2, 3, 1, 1],
                      [2, 1, 0, 1, 1]], dtype=torch.float32)  # 池化核不能处理Long型变量

if torch.cuda.is_available():
	input = input.to("cuda")
input = torch.reshape(input, (-1, 1, 5, 5))
ethan = Ethan()
output = ethan(input)
print(output)
#tensor([[[[2.]]]], device='cuda:0')
#ceil_mode=True时的输出
#tensor([[[[2., 3.],
#          [5., 1.]]]], device='cuda:0')

マックスプーリングの機能:画像の特徴を抽出し、ニューラルネットワークの学習負荷を大幅に軽減します!


4. BatchNorm2d() および LN、IN、GN。形が変わらない

BatchNorm2d は、畳み込みニューラル ネットワークの畳み込み層の後に常に追加されてデータを正規化し、Relu が実行される前に過剰なデータによってネットワークのパフォーマンスが不安定にならないようにします。

torch.nn.BatchNorm2d(num_features, eps=1e-05, momentum=0.1, affine=True,
					 track_running_stats=True, device=None, dtype=None)

パラメータ:
num_features– C、サイズ:math:Cの予期される入力から、つまり入力のチャネル値に設定されます。
(N, C, H, W)

eps– 数値安定性のために分母に追加される値。デフォルト: 1e-5

momentum– running_mean および running_var の計算に使用される値。累積移動平均 (つまり、単純な平均) の場合は、[なし] に設定できます。デフォルト: 0.1

affine– True に設定すると、このモジュールには学習可能なアフィン パラメータがあるブール値 デフォルト: True
#nn.Module モデルに付属する重みパラメータとバイアス パラメータが使用されることを示すために、アフィン パラメータは True に設定されます

track_running_stats– ブール値。True に設定すると、このモジュールは移動平均と分散を追跡し、False に設定すると、このモジュールはそのような統計を追跡せず、統計バッファ running_mean および running_var を None として初期化します。これらのバッファーが None の場合、このモジュールは常にバッチ統計を使用します。トレーニング モードと評価モードの両方で。デフォルト: True

BatchNorm2d() 関数の数学的原理は次のとおりです。
ここに画像の説明を挿入します
各チャネルには、対応する重み (上図の γ) およびバイアス (上図の β) パラメーター、E[x]、Var[x] があります。

BatchNorm2d() インスタンスの操作プロセスについては、このブログを参照してください。

    def _block(self, in_channels, out_channels, kernel_size, stride, padding):
        return nn.Sequential(
            nn.Conv2d(
                in_channels,
                out_channels,
                kernel_size,
                stride,
                padding,
                bias=False,
            ),
            #nn.BatchNorm2d(out_channels),
            nn.LeakyReLU(0.2),
        )


BN、LN、IN、GNの比較ブログ


官方LayerNorm文档
CLASS torch.nn.LayerNorm(normalized_shape, eps=1e-05, elementwise_affine=True, device=None, dtype=None)


公式 GroupNorm ドキュメント
CLASS torch.nn.GroupNorm(num_groups, num_channels, eps=1e-05, affine=True, device=None, dtype=None)


官方InstanceNorm2d文档
CLASS torch.nn.InstanceNorm2d(num_features、eps=1e-05、momentum=0.1、affine=False、track_running_stats=False、device=None、dtype=None)


ここに画像の説明を挿入します


5. 非線形活性化関数

nn.ReLU(inplace=False)
inplace – オプションでその場で操作を実行できます デフォルト: False は、元の変数を直接置き換えるかどうかを決定します。
Sigmoid、Tanh、LeakyReLU などの非線形活性化関数もあります。それらの機能は、ネットワークにさらに非線形特性を持たせることです。

torch.nn.LeakyReLU(negative_slope=0.01, inplace=False)

ここに画像の説明を挿入します

class Ethan(nn.Module):
    def __init__(self):
        super(Ethan,self).__init__()
        self.sigmoid=Sigmoid()
    def forward(self,input):
        output=self.sigmoid(input)
        return output
dataset=datasets.CIFAR10("./数据集",train=False,download=True,transform=transforms.ToTensor())
dataLoader=DataLoader(dataset,batch_size=64)
ethan = Ethan()

writer=SummaryWriter("./log2")
step=0
for data in dataLoader:
    imgs,target=data
    writer.add_images("input",imgs,step)
    output = ethan(imgs)
    writer.add_images("output",output,step)
    step+=1
writer.close()


6.nn.Linear()

nn.Linear(in_features, out_features, bias=True, 
		  device=None, dtype=None)
bias指的就是下图中b参数是否有

受信データに線形変換を適用します: y = x AT + by = xA^T + by=× AT+bここに画像の説明を挿入します
上図の赤線の説明リニアは最後の次元のみを変更します

ここに画像の説明を挿入します

m = nn.Linear(2, 3)
input = torch.tensor([[-0.6547, -1.5076],[-1.9709, -2.0016]])
output = m(input)
print(output.size())
print(output)

上記のコードを複数回実行すると、print(出力)の結果が異なります モデルがトレーニングされると、Linear 線形層のパラメーターもトレーニングされます。


'''
介绍flatten函数
torch.flatten(input, start_dim=0, end_dim=- 1)
Parameters:
	input (Tensor) – the input tensor.
	start_dim (int) – the first dim to flatten
	end_dim (int) – the last dim to flatten
'''
t = torch.tensor([[[1, 2],
                   [3, 4]],
                  [[5, 6],
                   [7, 8]]])
torch.flatten(t)
#tensor([1, 2, 3, 4, 5, 6, 7, 8])
torch.flatten(t, start_dim=1)
#tensor([[1, 2, 3, 4],
#        [5, 6, 7, 8]])


7. nn.Sequential (具体的な例については 9 を参照)

torch.nn.Sequential(*args)
Sequential を構築する次の 2 つの方法は同じ効果がありますが、OrderedDict は内部の各操作にエイリアスを与えることしかできません。

model = nn.Sequential(
          nn.Conv2d(1,20,5),
          nn.ReLU(),
          nn.Conv2d(20,64,5),
          nn.ReLU()
        )

# Using Sequential with OrderedDict. This is functionally the
# same as the above code
model = nn.Sequential(OrderedDict([
          ('conv1', nn.Conv2d(1,20,5)),
          ('relu1', nn.ReLU()),
          ('conv2', nn.Conv2d(20,64,5)),
          ('relu2', nn.ReLU())
        ]))


8.nn.ドロップアウト

torch.nn.Dropout(p=0.5, inplace=False)
パラメータ
p – 要素がゼロになる確率。デフォルト: 0.5
inplace – True に設定すると、この操作がインプレースで実行されます。デフォルト: 偽

形状
: ( )(*) を入力します。入力は任意の形状にすることができます。
出力: (
)(*)。出力は入力と同じ形状です

さらに、出力は1 1 − p \frac{1}{1-p}の係数でスケーリングされます。1 p1これは、評価中にモジュールが単純に恒等関数を計算することを意味します (0 ではない他の要素が1 1 − p \frac{1}{1-p}で乗算されることを意味します)1 p1)

	m = nn.Dropout(p=0.5)
    input = torch.randn(3, 4)
    print(input)
    output = m(input)
    print(output)
'''
tensor([[-0.6425, -0.2633, -0.6924, -1.8469],
        [ 1.0353, -1.3861,  1.1678,  1.1759],
        [ 0.9972, -0.5695, -0.1986,  0.2483]])
tensor([[-1.2851, -0.0000, -0.0000, -0.0000],
        [ 2.0705, -2.7722,  2.3356,  0.0000],
        [ 1.9943, -1.1390, -0.0000,  0.0000]])
没有变成0的元素都乘了1/(1-0.5)=2倍
'''


9. オプティマイザー torch.optim と backward()

各オプティマイザーには基本的に params と (lr) 学習率の 2 つのパラメーターがあります。
例として cifar10 データ モデルを取り上げます。
ここに画像の説明を挿入します

device = "cuda" if torch.cuda.is_available() else "cpu"
dataset=datasets.CIFAR10("./数据集",train=False,download=True,transform=transforms.ToTensor())
dataLoader=DataLoader(dataset,batch_size=1,drop_last=True)
class Ethan(nn.Module):
    def __init__(self):
        super(Ethan,self).__init__()
        self.model=nn.Sequential(
            nn.Conv2d(3,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,32,5,padding=2),
            nn.MaxPool2d(2),
            nn.Conv2d(32,64,5,padding=2),
            nn.MaxPool2d(2),
            nn.Flatten(),
            nn.Linear(1024,64),
            nn.Linear(64,10)
        )

    def forward(self,input):
        output=self.model(input)
        return output
loss=nn.CrossEntropyLoss()
if torch.cuda.is_available():
	loss = loss.to("cuda")
ethan=Ethan().to(device)
optim=torch.optim.SGD(ethan.parameters(),lr=0.01)
for epoch in range(20):
    running_loss=0.0
    for data in dataLoader:
        img,target=data
        img=img.to(device)
        '''
        一定要有这步处理,否则会报如下错
        Input type (torch.FloatTensor) and weight type (torch.cuda.FloatTensor) should be the same
        '''
        output=ethan(img)
        if torch.cuda.is_available():
            output = output.to("cuda")
        if torch.cuda.is_available():
            target = target.to("cuda")
        result_loss=loss(output,target)
        
        optim.zero_grad()#有些调用的是model.zero_grad()
        result_loss.backward()#损失函数调用backward()把ethan模型的梯度grad参数计算出来
        optim.step()#优化器模型调用step(),对权重或特征的值进行更新
	#以随机梯度下降SGD为例:学习率lr(learning rate)来控制步幅,即:x=x-lr *x.grad
        running_loss+=result_loss
    print(running_loss)


reverse(retain_graph) 分析:
backward() が使用されるたびに、デフォルトで計算グラフ全体が解放されます。一般に、反復ごとに必要なのは、forward() と Backward() の 1 つだけです。順方向演算の forward() と逆方向伝播の Backward() はペアで存在します。一般に、Backward() は 1 つで十分です。

ただし、カスタム損失などの複雑さにより、パラメータを更新するために同じネットワークの勾配を蓄積するために、異なる損失を持つ 1 つの forward() と複数の backward() が必要になる可能性も排除されません。したがって、現在のbackward()の後にforward()を実行せずに別のbackward()を実行する場合は、現在のbackward()中に保持計算グラフbackward(retain_graph)を指定する必要があります。


model.zero_grad() と optimizer.zero_grad() の違い:
model.zero_grad() の機能は、すべてのモデル パラメーターの勾配を 0 に設定することです。そのソースコードは次のとおりです。

for p in self.parameters():
    if p.grad is not None:
        p.grad.detach_()
        p.grad.zero_()

optimizer.zero_grad() の機能は、トレーニング可能なすべての torch.Tensor の勾配をクリアすることです。そのソースコードは次のとおりです。

for group in self.param_groups:
    for p in group['params']:
        if p.grad is not None:
            p.grad.detach_()
            p.grad.zero_()


10. GPUの使用

GPU を使用してコードを実行するには、ネットワーク モデル、データ、損失関数に対する .to (「cuda」) 操作が必要です。

#方式1
device = "cuda" if torch.cuda.is_available() else "cpu"
	xx=xx.to(device)
#方式2
if torch.cuda.is_available():
	xx=xx.to("cuda")

おすすめ

転載: blog.csdn.net/m0_50364811/article/details/126665237