機械学習において、トレーニングおよび検証メトリック グラフから何がわかるでしょうか?

機械学習において、トレーニングおよび検証メトリック グラフから何がわかるでしょうか?

この記事では、トレーニングと検証の考えられる状況をまとめ、これらのチャートがどのような情報を提供できるかを紹介します。

簡単なコードから始めましょう。次のコードは、トレーニング プロセスの基本的なフレームワークを設定します。

 sklearn.model_selection から train_test_split をインポートします
sklearn.datasets から make_classification をインポートします
輸入トーチ
torch.utils.data から Dataset、DataLoader をインポートします
torch.optim を torch_optim としてインポートします。
torch.nnをnnとしてインポートする
torch.nn.function を F としてインポートします。
numpyをnpとしてインポートする
matplotlib.pyplot を pltclass MyCustomDataset(Dataset) としてインポートします。
def __init__(self, X, Y, スケール=False):
自己.X = torch.from_numpy(X.astype(np.float32))
自己.y = torch.from_numpy(Y.astype(np.int64))

__len__(自分)を定義します:
len(self.y) を返す

__getitem__(self, idx)を定義します。
self.X[idx]、self.y[idx]を返します。def get_optimizer(model、lr=0.001、wd=0.0):
パラメータ = フィルター(lambda p: p.requires_grad, model.parameters())
optim = torch_optim.Adam(パラメータ、lr=lr、weight_decay=wd)
optimdef train_model(model, optim, train_dl, loss_func) を返します:
# モデルがトレーニングモードになっていることを確認する
モデル.train()
合計 = 0
合計損失 = 0
train_dlのx、yについて:
バッチ = y.shape[0]
# このバッチ分のデータに対してモデルをトレーニングする
ロジット = モデル(x)
# 損失関数を実行します。これはトレーニングループを呼び出すときに決定します。
損失 = loss_func(logits, y)
# 次の3行はPyTorchのバックプロパゲーションの優れた機能をすべて実行します
最適化ゼロ勾配()
損失.後方()
最適化ステップ()
# このエポックのサンプルの総数を継続的にチェックする
合計 += バッチ
# そして損失の合計を記録しておく
sum_loss += バッチ*(loss.item())
sum_loss/totalを返す
def train_loop(モデル、train_dl、valid_dl、エポック、loss_func、lr=0.1、wd=0):
optim = get_optimizer(モデル、lr=lr、wd=wd)
トレーニング損失リスト = []
val_loss_list = []
acc_list = []
i が範囲(エポック)内である場合:
損失 = train_model(モデル、最適化、train_dl、損失関数)
# このエポックをトレーニングした後、進捗状況のリストを保持します
# 各時代の損失
train_loss_list.append(損失)
val、acc = val_loss(モデル、valid_dl、loss_func)
# 検証損失と精度についても同様
val_loss_list.append(val)
acc_list.append(acc)
print("トレーニング損失: %.5f 有効な損失: %.5f 精度: %.5f" % (loss, val, acc))

train_loss_list、val_loss_list、acc_list を返す
val_loss(モデル、valid_dl、loss_func):
# モデルをトレーニングモードではなく評価モードにする
モデル評価()
合計 = 0
合計損失 = 0
正解 = 0
バッチカウント = 0
valid_dl の x、y について:
バッチカウント += 1
現在のバッチサイズ = y.shape[0]
ロジット = モデル(x)
損失 = loss_func(logits, y)
合計損失 += 現在のバッチサイズ*(損失.item())
合計 += 現在のバッチサイズ
# 上記のコードはすべて本質的には同じであり、
# トレーニングなのでコメントを見てください
# 返された予測のうちどれが最も大きな声で聞こえるか調べる
# すべて、そしてそれが私たちの予測です
preds = logits.sigmoid().argmax(1)
# 私たちの予測が正しいかどうか見てみましょう
正解 += (予測値 == y).float().mean().item()
sum_loss/total、correct/batch_count を返す
def view_results(train_loss_list、val_loss_list、acc_list):
plt.rcParams["figure.figsize"] = (15, 5)
plt.figure()
エポック = np.arange(0, len(train_loss_list)) plt.subplot(1, 2, 1)
plt.plot(エポック-0.5、train_loss_list)
plt.plot(エポック、val_loss_list)
plt.title('モデル損失')
plt.ylabel('損失')
plt.xlabel('エポック')
plt.legend(['train', 'val', 'acc'], loc = '左上')

plt.サブプロット(1, 2, 2)
plt.plot(acc_list)
plt.title('精度')
plt.ylabel('精度')
plt.xlabel('エポック')
plt.legend(['train', 'val', 'acc'], loc = '左上')
plt.show()

def get_data_train_and_show(モデル、batch_size=128、n_samples=10000、n_classes=2、n_features=30、val_size=0.2、epochs=20、lr=0.1、wd=0、break_it=False):
# 関連するすべてのデータが揃っていると仮定して、架空のデータセットを作成します。
# EDA / 機能エンジニアリングが完了し、これが私たちの
# 結果データ
X、y = make_classification(n_samples=n_samples、n_classes=n_classes、n_features=n_features、n_informative=n_features、n_redundant=0、random_state=1972)

if break_it: # 具体的にデータを壊す
X = np.random.rand(n_samples,n_features)
X_train、X_val、y_train、y_val = train_test_split(X、y、test_size=val_size、random_state=1972) train_ds = MyCustomDataset(X_train、y_train)
valid_ds = MyCustomDataset(X_val, y_val)
train_dl = DataLoader(train_ds、batch_size=batch_size、shuffle=True)
valid_dl = DataLoader(valid_ds、batch_size=batch_size、shuffle=True) train_loss_list、val_loss_list、acc_list = train_loop(model、train_dl、valid_dl、epochs=epochs、loss_func=F.cross_entropy、lr=lr、wd=wd)
結果を表示(train_loss_list、val_loss_list、acc_list)

上記のコードは非常にシンプルです。データの取得、トレーニング、検証という基本的なプロセスです。それでは本題に入りましょう。

シナリオ 1 - モデルは学習しているように見えるが、検証や精度のパフォーマンスが低い

ハイパーパラメータに関係なく、モデルのトレーニング損失はゆっくりと減少しますが、値損失は減少せず、精度は何かを学習していることを示しません。

たとえば、この場合、バイナリ分類の精度は約 50% になります。

クラス Scenario_1_Model_1(nn.Module):
def __init__(self, in_features=30, out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, out_features)
def forward(self, x):
x = 自己.lin1(x)
xを返す
get_data_train_and_show(シナリオ1モデル1()、lr=0.001、break_it=True)

データには「学習」を可能にするのに十分な情報がありません。トレーニング データには、モデルが「学習」するのに十分な情報が含まれていない可能性があります。

この場合(コード内のトレーニング データはランダムです)、実質的なことは何も学習できないことを意味します。

データには、そこから学習するのに十分な情報が含まれている必要があります。 EDA と機能エンジニアリングが鍵です! モデルは、存在しないものを作り出すのではなく、学習可能なものを学習します。

シナリオ2 - トレーニング、検証、精度曲線はすべて非常に不安定です

たとえば、次のコード: lr=0.1, bs=128

クラス Scenario_2_Model_1(nn.Module):
def __init__(self、in_features=30、out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, out_features)
def forward(self, x):
x = 自己.lin1(x)
xを返す
get_data_train_and_show(シナリオ2モデル1()、lr=0.1)

「学習率が高すぎる」または「バッチ サイズが小さすぎる」学習率を 0.1 から 0.001 に下げてみてください。これにより、「跳ね返る」ことはなく、スムーズに減少します。

 get_data_train_and_show(シナリオ1モデル1()、lr=0.001)

学習率を下げるだけでなく、バ​​ッチ サイズを増やすと、よりスムーズになります。

 get_data_train_and_show(シナリオ1_モデル1()、lr=0.001、バッチサイズ=256)

シナリオ3 - トレーニング損失はゼロに近く、精度は良好だが、検証は低下していないが、増加している

クラス Scenario_3_Model_1(nn.Module):
def __init__(self、in_features=30、out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, 50)
自己.lin2 = nn.Linear(50, 150)
自己.lin3 = nn.Linear(150, 50)
self.lin4 = nn.Linear(50, out_features)
def forward(self, x):
x = F.relu(self.lin1(x))
x = F.relu(self.lin2(x))
x = F.relu(self.lin3(x))
x = 自己.lin4(x)
xを返す
get_data_train_and_show(シナリオ3_モデル1()、lr=0.001)

これは明らかに過剰適合です。トレーニング損失は低く、精度は高いですが、検証損失とトレーニング損失はどんどん大きくなっており、これは典型的な過剰適合の指標です。

基本的に、モデルの学習があまりにもうまくいっています。 トレーニング データを非常によく記憶しているため、新しいデータに一般化することもできません。

最初に試せるのは、モデルの複雑さを軽減することです。

クラス Scenario_3_Model_2(nn.Module):
def __init__(self, in_features=30, out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, 50)
self.lin2 = nn.Linear(50, out_features)
def forward(self, x):
x = F.relu(self.lin1(x))
x = 自己.lin2(x)
xを返す
get_data_train_and_show(シナリオ3_モデル2()、lr=0.001)

これにより、モデルはより良くなりますが、L2 重み減衰正規化を導入して、さらにモデルを良くすることもできます (より浅いモデルの場合)。

 get_data_train_and_show(シナリオ3_モデル2()、lr=0.001、wd=0.02)

モデルの深さとサイズを維持したい場合は、ドロップアウト (より深いモデルに適しています) の使用を試すことができます。

クラス Scenario_3_Model_3(nn.Module):
def __init__(self, in_features=30, out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, 50)
自己.lin2 = nn.Linear(50, 150)
自己.lin3 = nn.Linear(150, 50)
self.lin4 = nn.Linear(50, out_features)
自己.ドロップ = nn.ドロップアウト(0.4)
def forward(self, x):
x = F.relu(self.lin1(x))
x = 自己ドロップ(x)
x = F.relu(self.lin2(x))
x = 自己ドロップ(x)
x = F.relu(self.lin3(x))
x = 自己ドロップ(x)
x = 自己.lin4(x)
xを返す
get_data_train_and_show(シナリオ3_モデル3()、lr=0.001)

シナリオ4 - トレーニングと検証はうまくいったが、精度は向上しなかった

lr = 0.001、bs = 128(デフォルト、分類カテゴリ = 5

クラス Scenario_4_Model_1(nn.Module):
def __init__(self, in_features=30, out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, 2)
self.lin2 = nn.Linear(2, out_features)
def forward(self, x):
x = F.relu(self.lin1(x))
x = 自己.lin2(x)
xを返す
get_data_train_and_show(シナリオ4モデル1(出力機能=5)、lr=0.001、n_classes=5)

学習能力が不十分です: モデル内のレイヤーの 1 つに、モデルの可能な出力のクラス数よりも少ないパラメータがあります。 この場合、出力クラスは 5 つありますが、中央のパラメーターは 2 つだけです。

これは、モデルを埋めるために情報をより小さなレイヤーに通す必要があるため情報が失われ、レイヤーのパラメータが再び拡大されるとこの情報を回復することが困難になることを意味します。

したがって、記録層のパラメータはモデルの出力サイズよりも小さくなってはなりません。

クラス Scenario_4_Model_2(nn.Module):
def __init__(self、in_features=30、out_features=2):
スーパー().__init__()
self.lin1 = nn.Linear(in_features, 50)
self.lin2 = nn.Linear(50, out_features)
def forward(self, x):
x = F.relu(self.lin1(x))
x = 自己.lin2(x)
xを返す
get_data_train_and_show(シナリオ4モデル2(出力機能=5)、lr=0.001、n_classes=5)

要約する

上記は、トレーニングおよび検証中の曲線の一般的な例です。同じ状況に遭遇したときに、すぐに見つけて改善できることを願っています。


<<:  欧州のAI法案がまもなく導入され、世界の技術規制に影響を及ぼす可能性がある

>>:  AIは脳スキャンだけであなたの政治的思想を予測できる

ブログ    
ブログ    
ブログ    
ブログ    

推薦する

...

GPT の成熟への道に関する公式メモ | OpenAI Developer Day

OpenAI は ChatGPT 製品の作成の詳細を明らかにしました。そして、この共有の波は、次の...

チューリング賞受賞者:人工知能を実装したものは、もはや人工知能とは呼ばれない

1956年、マッカーシーはダートマス大学で開催された会議で初めて「人工知能」の概念を提唱した。後に、...

50億のブルーオーシャンが呼び寄せる、電力検査ロボットが最前線に

[[398288]]近年、気温が高くなり、多くの地域で扇風機やエアコンが使用されるようになり、それに...

顔認識はどのようにして国民の個人情報を侵害するのでしょうか?犯罪者がアリペイを騙し取るために3D顔モデルを作成

[[360029]]記者 | 趙孟近年、顔認識技術の普及に伴い、国民の個人情報のセキュリティに関する...

...

ディープラーニングによる物体検出モデルの包括的なレビュー: 高速 R-CNN、R-FCN、SSD

[[204169]] Faster R-CNN、R-FCN、SSD は、最も人気があり、広く使用さ...

国産初のオープンソースMoE大型モデルが登場!パフォーマンスはLlama 2-7Bに匹敵し、計算量は60%削減されます。

オープンソースのMoEモデルがついに国内初のプレイヤーを迎えます!そのパフォーマンスは高密度の Ll...

...

...

階段を登るための最小コストを使用するデータ構造とアルゴリズム

[[443068]]最小限のコストで階段を登るLeetCode の問題へのリンク: https://...

在庫: 2020 年の最もクールな AI チップ スタートアップ 10 社

AIチップをめぐる争いはインテルやエヌビディアなどの半導体大手の間で激化しているが、多くの中小企業も...

IDC: 高速サーバー市場は2023年上半期に31億ドルに達し、GPUサーバーが依然として主流となる

10月9日、IDCコンサルティングの公式WeChatアカウントによると、IDCは本日「中国半期加速コ...

...

...