ハンズオン ディープ ラーニング Web サイト:ハンズオン ディープ ラーニング
注: この部分では、基本的な知識を簡単に紹介し、完全なコードの実装を添付します. 詳細については、上記の URL を参照してください.
簡単な説明
必要な準備
- 数学の偏導関数
- 線形代数
線形モデル
回帰は、1 つ以上の独立変数と従属変数の間の関係をモデル化できるメソッドのクラスです。自然科学や社会科学では、入力と出力の関係を表すために回帰がよく使用されます。
線形回帰は、いくつかの単純な仮定に基づいています。まず、独立変数 x と従属変数 y の間の関係は線形であると仮定されます。ここで、通常、観測値の一部のノイズを含めることができます。次に、ノイズが正規分布に従うなど、ノイズは比較的正常であると仮定します。
データセットが与えられた場合、線形回帰の目標は、モデルの重み w とバイアス b を見つけることです。式は次のとおりです。
重みをベクトルに入れると、次のようになります。
損失関数
二乗誤差を使用します。
ここで、y は実数データです。
上記の式を拡張すると、次のようになります。
最終的な目標は、すべてのトレーニング サンプルの総損失を最小限に抑えることができる一連のパラメーター (w、b) を見つけることです。つまり、
最適化
トレーニング プロセスでは、w と b を継続的に最適化して、最終的な損失を最小限に抑える必要があります。これには、一般的に使用される勾配降下法である最適化手法が必要です。
線形回帰の場合、パラメーター更新の形式は次のとおりです。
パラメーターを毎回更新する前に、データセット全体をトラバースする必要があるためです。したがって、**私たちは通常、更新を計算する必要があるたびに、サンプルの小さなバッチをランダムにサンプリングします.このバリアントは、ミニバッチ確率的勾配降下法と呼ばれます. **上の図に示すように、B は選択された小さなバッチ サンプルの数であり、n は学習率です。
上記の式を展開すると、次のようになります。
コード
線形回帰をゼロから実装する
1. データセットを生成する
1000 サンプルのデータセットを生成します。各サンプルには、標準正規分布からサンプリングされた 2 つの特徴が含まれています。
import torch
import random
from d2l import torch as d2l
# 生成数据集
def generate_data(w,b,num_examples):
# 生成正太分布的数据
X = torch.normal(0,1,(num_examples,len(w)))
# 进行矩阵乘法
y = torch.matmul(X,w) + b
y += torch.normal(0,0.01,y.shape)
return X,y.reshape((-1,1))
# 真实的w
true_w = torch.tensor([2,-3.4])
# 真实的b
true_b = 4.2
# features shape: N * len(W)
# lables shape: N
features,labels = generate_data(true_w,true_b,1000)
print('features:',features[0],'\nlabel:',labels[0])
# 展示生成的数据
d2l.set_figsize()
d2l.plt.scatter(features[:,1].detach().numpy(),labels.detach().numpy(),1)
2. データ読み込み操作
バッチ サイズ、特徴行列、およびラベル ベクトルを入力として受け取り、サイズが batch_size のミニバッチを生成する data_iter 関数を定義します。
# 小批量读取数据集
def data_iter(batch_size,features,lables):
# 获取第一维的大小
num_examples = len(features)
indices = list(range(num_examples))
# 打乱顺序
random.shuffle(indices)
for i in range(0,num_examples,batch_size):
batch_indices = torch.tensor(indices[i:min(i+batch_size,num_examples)])
yield features[batch_indices],labels[batch_indices]
# 调用该函数
# 小批量大小为10
batch_size = 10
for X,y in data_iter(batch_size,features,batch_size):
print(X,'\n',y)
break
3. モデルの関連部分を定義する
(1) 初期化パラメータ
平均 0、標準偏差 0.01 の正規分布から乱数を抽出して重みを初期化し、バイアスを 0 に初期化します。
(2) モデルの定義
wx+b 形式を使用します。
(3) 損失関数
二乗損失関数を使用する
(4) 最適化方法
各ステップでは、データセットからランダムに抽出されたミニバッチが使用され、パラメータに従って損失の勾配が計算されます。次に、損失を減らす方向にパラメータを更新します。各ステップ更新のサイズは、学習率 lr によって決まります。計算する損失はサンプルのバッチの合計であるため、ステップ サイズがバッチ サイズの選択に依存しないように、ステップ サイズをバッチサイズ (batch_size) で正規化します。
# 初始化模型参数
def init_params():
# w服从均值为0,方差为0.01的正太分布,大小为(2,1)
w = torch.normal(0,0.01,(2,1),requires_grad = True)
b = torch.zeros(1,requires_grad = True)
return w,b
# 定义模型
def linear_reg(X,w,b):
# wx + b
return torch.matmul(X,w) + b
# 定义损失函数
def squared_loss(y_pred,y):
return (y_pred - y.reshape(y_pred.shape)) ** 2 / 2
# 定义优化算法
def sgd(params,lr,batch_size):
# 使梯度计算disable
with torch.no_grad():
for param in params:
param -= lr * param.grad / batch_size
# 手动将梯度设置成 0 ,在下一次计算梯度的时候就不会和上一次相关了
param.grad.zero_()
4. トレーニング モデル
次のループを実行します。
- 初期化パラメータ
- 完了するまで、次の演習を繰り返します
- 勾配を計算する (l.sum().backward())
- パラメーターの更新 (sgd)
# 训练
# 学习率
lr = 0.02
# 迭代次数
num_epoches = 3
net = linear_reg
loss = squared_loss
w,b = init_params()
for epoch in range(num_epoches):
for X,y in data_iter(batch_size,features,labels):
l = loss(net(X,w,b),y)
# 后向传播计算梯度
l.sum().backward()
sgd([w,b],lr,batch_size)
with torch.no_grad():
train_l = loss(net(features,w,b),labels)
print(f'epoch {
epoch + 1},loss {
float(train_l.mean())}')
print(f'w的估计误差: {
true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {
true_b - b}')
線形回帰のフレームワーク実装
# 简洁实现
import numpy as np
import torch
from torch.utils import data
from d2l import torch as d2l
from torch import nn
true_w = torch.tensor([2,-3.4])
true_b = 4.2
# 生成数据集
features,labels = d2l.synthetic_data(true_w,true_b,1000)
def load_dataset(data_arrs,batch_size,is_train = True):
dataset = data.TensorDataset(*data_arrs)
return data.DataLoader(dataset,batch_size,shuffle=is_train)
batch_size = 10
data_iter = load_dataset((features,labels),batch_size)
# iter构造迭代器
next(iter(data_iter))
# 定义模型
net = nn.Sequential(nn.Linear(2,1))
# 初始化参数,注意上面使用的是nn.Sequential,创造的是一个序列,所以net[0]表示我们的网络
net[0].weight.data.normal_(0,0.01)
net[0].bias.data.fill_(0)
# 损失函数
loss = nn.MSELoss()
# 优化算法
trainer = torch.optim.SGD(net.parameters(),lr = 0.03)
# 训练
num_epoches = 3
for epoch in range(num_epoches):
for X,y in data_iter:
l = loss(net(X),y)
# 将梯度重置为0
trainer.zero_grad()
# 计算梯度
l.backward()
# 更新所有的参数
trainer.step()
l = loss(net(features),labels)
print(f'epch {
epoch + 1} loss {
l:f}')
w = net[0].weight.data
b = net[0].bias.data
print(f'w的估计误差: {
true_w - w.reshape(true_w.shape)}')
print(f'b的估计误差: {
true_b - b}')