他の人からより良く学び、
より良いものになりますように。
—— 「ウェイカ・ジーシャン」
この記事の長さは 1739ワードで、読むのにかかる時間は 5分です。
序文
pyTorch の初心者としては、デモを行って自分で練習する必要があるため、このエントリーは、pyTorch のトレーニングから始まり、モデルの保存、推論に C++ OpenCV DNN を使用する、そして Andorid に移植して手書きを直接実現するまでのシリーズです。数学の識別は、プロセス全体の実際の戦闘の小さなプロジェクトとみなすことができます。今日は最初の記事で、最も単純な完全に接続された Minist データセット pyTorch のトレーニングを作成します。
効果を達成する
コード
マイクロカード志祥
完全接続ネットワークモデル
import torch
import torch.nn.functional as F
##Minist的图像为1X28X28的
class LinearNet(torch.nn.Module):
def __init__(self):
super(LinearNet, self).__init__()
##784是图像为 1X28X28,通道X宽度X高度,然后总的输入就是784
self.l1 = torch.nn.Linear(784, 512)
self.l2 = torch.nn.Linear(512, 256)
self.l3 = torch.nn.Linear(256, 128)
self.l4 = torch.nn.Linear(128, 64)
self.l5 = torch.nn.Linear(64, 10)
##定义损失函数
self.criterion = torch.nn.CrossEntropyLoss()
def forward(self, x):
##将输入的图像矩阵改为N行784列
x = x.view(-1, 784)
x = F.relu(self.l1(x))
x = F.relu(self.l2(x))
x = F.relu(self.l3(x))
x = F.relu(self.l4(x))
##最后一层激活在损失函数中加入了,这里直接输出,不要加上rule了
return self.l5(x)
Init 初期化関数からわかるように、完全接続ネットワーク モデルも非常に単純です。これは 5 層の線形であり、各層の入力値は前の層の出力値です。データセットは 1*28* 28 であるため、最初の層の入力は 1X28X28 = 784 です。ここでは、LinearNet クラスの作成で損失関数が定義されており、外部から直接呼び出すことができます。クラス全体も非常にシンプルです。
トレーニングモデル
この記事では、トレーニング モデルのファイルに焦点を当てます。このファイルは、後で他のネットワーク モデルを使用するときにトレーニングに使用されるためです。セット モデルの名前に従って、さまざまなトレーニング モデルを読み込みます。そこで、書き込むための ministmodel.py ファイルを作成しました。
01
関連ファイルと基本パラメータをインポートします
上の図からわかるように、ここでは上で作成した LinearNet モデルをインポートし、主にこのトレーニングに使用するモデルを設定するためにいくつかのパラメーターを設定しました。これは、毎回トレーニング モデルを変更し、これをトレーニングするためです。コードは再利用できるため、Ctrl + C や Ctrl + V は必要ありません。
02
Minist データセットをロードする
一番上のtransfromの平均値と標準偏差は、オンラインでは事前に計算されているものが多いので、ここに直接入力して、トレーニングセットとテストセットを呼び出し、torchvisionで実現します。現在のディレクトリにある場合は、自動的にダウンロードされます。
03
ロードモデル
現在ロードされているモデルを処理するための switch 関数が追加されています。新しいモデルを追加する場合は、入力に従って新しいモデルを直接返すだけです。私はPython 3.9 バージョンを使用しているため、それを実現するための switch メソッドはありません。 if else は自分で作成し、Python 3.10 以降では match case 構文があります。
青いボックス内のロードされたモデルは、上で定義した train_name に従って対応するモデルを直接選択し、オプティマイザーの設定も上で定義した学習率と運動量によって行われ、トレーニングを開始できます。
04
モデルをトレーニングして保存する
トレーニング機能
テスト機能
テスト関数は、最初に定義した toppredicted 変数に注意する必要があります。当時は、予測率が現在の予測率よりも高ければ、予測率を更新して現在のモデルを保存すると言われていました。宣言するには global を使用しますtoppredicted は、関数内および関数外で宣言されたグローバル変数を変更するために使用されます。それ以外の場合は、エラーが報告されます。
保存されたモデルファイル
トレーニングを開始する
最後にトレーニングを開始します。合計 10 ラウンドのトレーニングが設定されており、トレーニングが完了すると、合計トレーニング時間が出力されます。完全なコードは次のとおりです。
import torch
import time
from torchvision import transforms
from torchvision import datasets
from torch.utils.data import DataLoader
import torch.optim as optim
from NetLinear import LinearNet
batch_size = 64
##设置本次要训练用的模型
train_name = 'LinearNet'
print("train_name:" + train_name)
##设置模型保存名称
savemodel_name = train_name + ".pt"
print("savemodel_name:" + savemodel_name)
##设置初始预测率,用于判断高于当前预测率的保存模型
toppredicted = 0.0
##设置学习率
learnrate = 0.01
##设置动量值,如果上一次的momentnum与本次梯度方向是相同的,梯度下降幅度会拉大,起到加速迭代的作用
momentnum = 0.5
transform = transforms.Compose([
transforms.ToTensor(),
transforms.Normalize(mean=(0.1307,), std=(0.3081,))
]) ##Normalize 里面两个值0.1307是均值mean, 0.3081是标准差std,计算好的直接用了
##训练数据集位置,如果不存在直接下载
train_dataset = datasets.MNIST(
root = '../datasets/mnist',
train = True,
download = True,
transform = transform
)
##读取训练数据集
train_dataloader = DataLoader(
dataset= train_dataset,
shuffle=True,
batch_size=batch_size
)
##测试数据集位置,如果不存在直接下载
test_dataset = datasets.MNIST(
root= '../datasets/mnist',
train= False,
download=True,
transform= transform
)
##读取测试数据集
test_dataloader = DataLoader(
dataset= test_dataset,
shuffle= True,
batch_size=batch_size
)
##设置选择训练模型,因为python用的是3.9,用不了match case语法
def switch(train_name):
if train_name == 'LinearNet':
return LinearNet()
##定义训练模型
class Net(torch.nn.Module):
def __init__(self, train_name):
super(Net, self).__init__()
self.model = switch(train_name= train_name)
self.criterion = self.model.criterion
def forward(self, x):
x = self.model(x)
return x
model = Net(train_name)
##加入判断是CPU训练还是GPU训练
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model.to(device)
##优化器
optimizer = optim.SGD(model.parameters(), lr= learnrate, momentum= momentnum)
##训练函数
def train(epoch):
running_loss = 0.0
for batch_idx, data in enumerate(train_dataloader, 0):
inputs, target = data
##加入CPU和GPU选择
inputs, target = inputs.to(device), target.to(device)
optimizer.zero_grad()
#前馈,反向传播,更新
outputs = model(inputs)
loss = model.criterion(outputs, target)
loss.backward()
optimizer.step()
running_loss += loss.item()
##计算每300次打印一次学习效果
if batch_idx % 300 == 299:
print('[%d, %5d] loss: %.3f' % (epoch + 1, batch_idx + 1, running_loss / 300))
running_loss = 0.0
def test():
correct = 0
total = 0
##with这里标记是不再计算梯度
with torch.no_grad():
for data in test_dataloader:
inputs, labels = data
##加入CPU和GPU选择
inputs, labels = inputs.to(device), labels.to(device)
outputs = model(inputs)
##预测返回的是两列,第一列是下标就是0-9的值,第二列为预测值,下面的dim=1就是找维度1(第二列)最大值输出
_, predicted = torch.max(outputs.data, dim=1)
total += labels.size(0)
correct += (predicted == labels).sum().item()
currentpredicted = (100 * correct / total)
##用global声明toppredicted,用于在函数内部修改在函数外部声明的全局变量,否则报错
global toppredicted
##当预测率大于原来的保存模型
if currentpredicted > toppredicted:
toppredicted = currentpredicted
torch.save(model.state_dict(), savemodel_name)
print(savemodel_name+" saved, currentpredicted:%d %%" % currentpredicted)
print('Accuracy on test set: %d %%' % currentpredicted)
##开始训练
timestart = time.time()
for epoch in range(10):
train(epoch)
test()
timeend = time.time() - timestart
print("use time: {:.0f}m {:.0f}s".format(timeend // 60, timeend % 60))
以上
過去の素晴らしいレビュー
Android Kotlin は署名ホワイトボードを作成し、写真を保存します
超簡単な pyTorch トレーニング -> onnx モデル -> C++ OpenCV DNN 推論 (ソース コード アドレス付き)