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

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

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

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

 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は脳スキャンだけであなたの政治的思想を予測できる

ブログ    
ブログ    

推薦する

...

...

Nuscenes 最新 SOTA | DynamicBEV が PETRv2/BEVDepth を上回る!

1. 論文情報2. はじめにこの論文では、自動運転、ロボット工学、監視などのアプリケーションに不可...

JD Search EE リンクの進化

検索システムにはヘッド効果が存在する可能性が高く、高品質のミッドテールおよびロングテール製品が十分な...

...

AIと機械理解の限界を押し広げ、オックスフォード大学の博士論文は3Dオブジェクトの再構築とセグメント化を学ぶ

機械が人間のように 3D の物体や環境を認識できるようにすることは、人工知能の分野における重要なトピ...

ゲームの背後にあるAIストーリー:小規模サンプル学習と転移学習

2019年、人間と機械のゲームバトルにおいて、Open AI Fiveが圧倒的なパフォーマンスでD...

Amap、ADAS警告ナビゲーション機能を発表:視覚AI技術を使用して車両と歩行者の衝突をインテリジェントに警告

11月18日、高徳地図の新バージョンは革新的なADAS警告ナビゲーション機能をリリースしました。視覚...

ChatGPTのメタバージョンが登場: Llama 2がサポートされ、Bing検索に接続され、ザッカーバーグがライブでデモを実施

今朝早く、毎年恒例の Meta Connect カンファレンスで、AI に焦点を当てた一連の発表が行...

...

警告!長距離LiDAR認識

この記事は、Heart of Autonomous Driving の公開アカウントから許可を得て転...

大きな AI 問題の解決: AI 操作のエネルギー消費を削減するにはどうすればよいでしょうか?

現在、AI分野で画期的な進歩を遂げているディープラーニングモデルの規模が大きくなるほど、エネルギー消...

WAVE SUMMITが今年もやって来ました! AI 開発者の饗宴がこの寒い冬を盛り上げます!

WAVE SUMMIT+ ディープラーニング開発者カンファレンス 2023 が 12 月 28 日...

科学者たちは指紋の水分調節メカニズムを研究しており、これはロボットや義肢の開発に役立つだろう。

この記事はAI新メディアQuantum Bit(公開アカウントID:QbitAI)より許可を得て転載...