(1) 回帰(関係フィッティング)
コードを開始するには、まず Net クラスを定義し、クラスが torch.nn.Moudle から継承されるようにします。__init__とforward をclass に含めると、これら 2 つの関数がほとんどのトーチに組み込まれます。次のコードは、最も単純なニューラル ネットワークを構築するものです。
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim = 1)
y = x.pow(2) + 0.2*torch.rand(x.size())
x, y = Variable(x), Variable(y) #数据的准备
class Net(torch.nn.Module):
def __init__(self, n_features, n_hidden, n_output): #特征,隐藏层,输出层
super(Net, self).__init__() #这一步都得这么写
self.hidden = torch.nn.Linear(n_features, n_hidden)
#命名为hidden,这就是一层神经网络(隐藏层)
self.predict = torch.nn.Linear(n_hidden, n_output)
#预测层,n_hidden是隐藏层的神经元
def forward(self, x): #这一部分才是在搭建神经网络,x是输入信息(data等)
x = F.relu(self.hidden(x)) #x经过hidden处理后,再用激活函数激活信息
x = self.predict(x) #这里的x来自上一行,经predict后直接输出
return x
net = Net(1, 10, 1) #调用,1个特征点,10个隐藏层,1个输出层
print(net)
ここまででニューラルネットワークが構築されました。以下はニューラル ネットワーク (オプティマイザー) を最適化します。
optimizer = torch.optim.SGD(net.parameters(), lr=0.5) #lr是学习速率,通常都小于1
loss_func = torch.nn.MSELoss() #计算误差的方法loss,MSE方法足以用来处理回归问题
# ----------------- 开始训练 ----------------- #
for i in range(100):
prediction = net(x) #看每一步的prediction
loss = loss_func(prediction, y) #y是真实值,前者是预测值
optimizer.zero_grad() #这一步是将梯度降为0,防止先前的梯度造成影响
loss.backward() #进行loss值的反向传播
optimizer.step() #用optimizer以学习效率0.5来优化梯度
上記のコードには視覚化部分は含まれていません。視覚化については別の記事で説明します。上記の 2 つのコードを結合すると、完全なモデル トレーニング フレームワークになります。
さらに、「PyTorch Deep Learning Practice」の完全な コレクションには別のコード スキームがあり、原理は同じです。
import numpy as np
import matplotlib.pyplot as plt
x_data = [1.0, 25.0, 36.0]
y_data = [3.1, 58.0, 73.0]
def forward(x):
return x * w
def loss(x, y):
y_pred = forward(x)
return (y_pred - y) * (y_pred - y)
w_list = []
mse_list = []
for w in np.arange(0.0, 4.1, 0.1):
print('w=', w)
l_sum = 0
for x_val, y_val in zip(x_data, y_data):
y_pred_val = forward(x_val)
loss_val = loss(x_val, y_val)
l_sum += loss_val
print('\t', x_val, y_pred_val, loss_val)
print('MSE=', l_sum / 3)
w_list.append(w)
mse_list.append(l_sum / 3)
plt.plot(w_list, mse_list)
plt.show()
グラフを描いた結果は以下のようになります。
(2) 勾配降下法の再検討
一般に、図 2 のようなより完全な曲線に遭遇することはほとんどありません。多くの場合、次元と重みは複数あり、例えば重みが 2 つある場合、線形探索法は使用できず、面倒になります。分割征服と呼ばれる方法があります。たとえば、2 つの重み w1w2 があるとします。検索するときは、まず比較的疎な検索を実行し、w1 と w2 でそれぞれ 4 つを見つけ、合計 16 つを見つけます。これら 16 個のポイントの中で、探している値が最も小さく、最も小さい点が探しているおおよその範囲になります。緑色の枠内で4×4の範囲探索を行うため、数周すると探索範囲が大幅に狭まります。
しかし、この方法は適切ではありません。初期点が固定されている場合、大域最小点を見逃して局所最小点を見つける可能性があるからです。したがって、このセクションで説明するアルゴリズムである勾配降下法につながります。勾配降下法は導出です。具体的には、重み値 から損失関数を導出します。負の符号を取る理由は、傾きの逆方向に沿って降下するためです。したがって、勾配降下法の完全な公式は次のようになります。ここで、ω は重み、コストは損失関数、α は学習率であり、通常、小さな範囲で減少できるように比較的小さい値です。
同様に、勾配降下法アルゴリズムにも欠陥があります。まず、勾配降下は極小値と鞍点に陥りやすく、極小値を突破することは難しくありませんが、鞍点を突破するのはより困難です。繰り返します。
x_data = [1.0, 2.0, 3.0]
y_data = [2.0, 4.0, 6.0]
w = 1.0
def forward(x):
return x * w
def cost(xs, ys):
cost = 0
for x, y in zip(xs, ys):
y_pred = forward(x)
cost += (y_pred - y) ** 2
return cost / len(xs)
def gradient(xs, ys):
grad = 0
for x, y in zip(xs, ys):
grad += 2 * x * (x * w - y)
return grad / len(xs)
print('Predict(beforetraining)', 4, forward(4))
for epoch in range(100):
cost_val = cost(x_data, y_data)
grad_val = gradient(x_data, y_data)
w -= 0.01 * grad_val
print('Epoch:', epoch, 'w={:.2f}'.format(w), 'loss =', cost_val)
print('Predict(after training)', 4, forward(4))
このコードでは、(1) よりも解釈しやすい勾配降下法アルゴリズムが使用されています。実際のトレーニング プロセスでは、損失曲線は非常に粗く、多くの不具合が発生する可能性があります。滑らかな曲線を得るために、指数平均法を使用します。
深層学習の応用では、勾配降下法はあまり使用されません。確率的勾配降下法がよく使用されますが、確率的勾配降下法を選択する理由は鞍点問題を解決するためです。データセットにランダム ノイズを追加します。たとえ鞍点に落ちたとしても、ランダム ノイズにより勾配が減少し続けるため、鞍点問題を解決できます。