【ML】管理和跟踪机器学习实验
??????🔎大家好,我是Sonhhxg_柒,希望你看完之后,能對你有所幫助,不足請指正!共同學習交流🔎
📝個人主頁-Sonhhxg_柒的博客_CSDN博客?📃
🎁歡迎各位→點贊👍 + 收藏?? + 留言📝?
📣系列專欄 - 機器學習【ML】?自然語言處理【NLP】? 深度學習【DL】
?
?🖍foreword
?說明?本人講解主要包括Python、機器學習(ML)、深度學習(DL)、自然語言處理(NLP)等內容。
如果你對這個系列感興趣的話,可以關注訂閱喲👋
介紹
到目前為止,我們一直在訓練和評估我們不同的基線,但還沒有真正跟蹤這些實驗。我們將解決這個問題,但定義一個適當的實驗跟蹤過程,我們將用于所有未來的實驗(包括超參數優化)。實驗跟蹤是管理所有不同實驗及其組件(例如參數、指標、模型和其他工件)的過程,它使我們能夠:
- 組織特定實驗的所有必要組件。重要的是把所有東西都放在一個地方并且知道它在哪里,這樣你以后可以使用它們。
- 使用保存的實驗(輕松)重現過去的結果。
- 記錄跨時間、數據、想法、團隊等的迭代改進。
工具
實驗跟蹤有很多選項,但我們將使用MLFlow(100% 免費和開源),因為它具有我們需要的所有功能(以及不斷增長的集成支持)。我們可以在我們自己的服務器和數據庫上運行 MLFlow,因此沒有存儲成本/限制,使其成為最受歡迎的選項之一,并被 Microsoft、Facebook、Databricks 和其他公司使用。您還可以設置自己的跟蹤服務器,以在多個團隊成員之間同步運行同一任務。
還有一些流行的選項,例如Comet ML(由 Google AI、HuggingFace 等使用)、Neptune(由 Roche、NewYorker 等使用)、Weights and?Biases (由 Open AI、Toyota Research 等使用) .?這些是提供儀表板、無縫集成、超參數搜索、報告甚至調試等功能的出色工具!
許多平臺正在利用它們作為實驗數據源的地位來提供擴展到 ML 開發管道的其他部分的功能,例如版本控制、調試、監控等。
應用
我們將從初始化實驗所需的所有參數開始。
pip install mlflow==1.23.1 -q from argparse import Namespace import mlflow from pathlib import Path輸入參數args包含所有需要的參數,很高興將它們全部組織在一個變量下,這樣我們就可以輕松地記錄它并為不同的實驗調整它(我們會在進行超參數優化時看到這一點)。
# Specify arguments args = Namespace(lower=True,stem=False,analyzer="char",ngram_max_range=7,alpha=1e-4,learning_rate=1e-1,power_t=0.1,num_epochs=100 )接下來,我們將設置我們的模型注冊表,其中將存儲所有實驗及其各自的運行。我們還將使用特定的運行 ID 從此注冊表中加載經過訓練的模型。
# Set tracking URI MODEL_REGISTRY = Path("experiments") Path(MODEL_REGISTRY).mkdir(exist_ok=True) # create experiments dir mlflow.set_tracking_uri("file://" + str(MODEL_REGISTRY.absolute()))?tip:
在 Windows 上,我們設置跟蹤 URI 的最后一行應該有三個正斜杠:
mlflow.set_tracking_uri("file:///" + str(MODEL_REGISTRY.absolute())) ls experiments labeled_projects.csv sample_data訓練
為了簡單起見,我們將所有用于訓練的組件封裝到一個函數中,該函數返回我們希望能夠從實驗中跟蹤的所有工件。
現在忽略trial參數(默認為None),因為它將在超參數優化課程中用于修剪沒有希望的試驗。
def train(args, df, trial=None):"""Train model on data."""# Setupset_seeds()df = pd.read_csv("labeled_projects.csv")df = df.sample(frac=1).reset_index(drop=True)df = preprocess(df, lower=True, stem=False, min_freq=min_freq)label_encoder = LabelEncoder().fit(df.tag)X_train, X_val, X_test, y_train, y_val, y_test = \get_data_splits(X=df.text.to_numpy(), y=label_encoder.encode(df.tag))# Tf-idfvectorizer = TfidfVectorizer(analyzer=args.analyzer, ngram_range=(2,args.ngram_max_range)) # char n-gramsX_train = vectorizer.fit_transform(X_train)X_val = vectorizer.transform(X_val)X_test = vectorizer.transform(X_test)# Oversampleoversample = RandomOverSampler(sampling_strategy="all")X_over, y_over = oversample.fit_resample(X_train, y_train)# Modelmodel = SGDClassifier(loss="log", penalty="l2", alpha=args.alpha, max_iter=1,learning_rate="constant", eta0=args.learning_rate, power_t=args.power_t,warm_start=True)# Trainingfor epoch in range(args.num_epochs):model.fit(X_over, y_over)train_loss = log_loss(y_train, model.predict_proba(X_train))val_loss = log_loss(y_val, model.predict_proba(X_val))if not epoch%10:print(f"Epoch: {epoch:02d} | "f"train_loss: {train_loss:.5f}, "f"val_loss: {val_loss:.5f}")# Logif not trial:mlflow.log_metrics({"train_loss": train_loss, "val_loss": val_loss}, step=epoch)# Pruning (for optimization in next section)if trial:trial.report(val_loss, epoch)if trial.should_prune():raise optuna.TrialPruned()# Thresholdy_pred = model.predict(X_val)y_prob = model.predict_proba(X_val)args.threshold = np.quantile([y_prob[i][j] for i, j in enumerate(y_pred)], q=0.25) # Q1# Evaluationother_index = label_encoder.class_to_index["other"]y_prob = model.predict_proba(X_test)y_pred = custom_predict(y_prob=y_prob, threshold=args.threshold, index=other_index)metrics = precision_recall_fscore_support(y_test, y_pred, average="weighted")performance = {"precision": metrics[0], "recall": metrics[1], "f1": metrics[2]}print (json.dumps(performance, indent=2))return {"args": args,"label_encoder": label_encoder,"vectorizer": vectorizer,"model": model,"performance": performance}追蹤
使用 MLFlow,我們需要首先初始化一個實驗,然后您可以在該實驗下運行。
import joblib import tempfile # Set experiment mlflow.set_experiment(experiment_name="baselines") INFO: 'baselines' does not exist. Creating a new experiment def save_dict(d, filepath):"""Save dict to a json file."""with open(filepath, "w") as fp:json.dump(d, indent=2, sort_keys=False, fp=fp) # Tracking with mlflow.start_run(run_name="sgd"):# Train & evaluateartifacts = train(args=args, df=df)# Log key metricsmlflow.log_metrics({"precision": artifacts["performance"]["precision"]})mlflow.log_metrics({"recall": artifacts["performance"]["recall"]})mlflow.log_metrics({"f1": artifacts["performance"]["f1"]})# Log artifactswith tempfile.TemporaryDirectory() as dp:artifacts["label_encoder"].save(Path(dp, "label_encoder.json"))joblib.dump(artifacts["vectorizer"], Path(dp, "vectorizer.pkl"))joblib.dump(artifacts["model"], Path(dp, "model.pkl"))save_dict(artifacts["performance"], Path(dp, "performance.json"))mlflow.log_artifacts(dp)# Log parametersmlflow.log_params(vars(artifacts["args"])) Epoch: 00 | train_loss: 1.16930, val_loss: 1.21451 Epoch: 10 | train_loss: 0.46116, val_loss: 0.65903 Epoch: 20 | train_loss: 0.31565, val_loss: 0.56018 Epoch: 30 | train_loss: 0.25207, val_loss: 0.51967 Epoch: 40 | train_loss: 0.21740, val_loss: 0.49822 Epoch: 50 | train_loss: 0.19615, val_loss: 0.48529 Epoch: 60 | train_loss: 0.18249, val_loss: 0.47708 Epoch: 70 | train_loss: 0.17330, val_loss: 0.47158 Epoch: 80 | train_loss: 0.16671, val_loss: 0.46765 Epoch: 90 | train_loss: 0.16197, val_loss: 0.46488 {"precision": 0.8929962902778195,"recall": 0.8333333333333334,"f1": 0.8485049088497365 }查看
讓我們看看我們從實驗中跟蹤到了什么。MLFlow 為我們提供了一個儀表板來查看和探索我們在 localhost 端口上的實驗。如果您在本地計算機上運行它,您可以簡單地運行 MLFlow 服務器:
mlflow server -h 0.0.0.0 -p 8000 --backend-store-uri $PWD/experiments/并打開http://localhost:8000/以查看儀表板。但是,如果您使用的是 Google colab,我們將使用 localtunnel在此筆記本和公共 URL 之間創建連接。
如果沒有安裝 localtunnel,你可能需要先!npm install -g localtunnel在一個單元中運行。
# Run MLFlow server and localtunnel get_ipython().system_raw("mlflow server -h 0.0.0.0 -p 8000 --backend-store-uri $PWD/experiments/ &") !npx localtunnel --port 8000MLFlow 創建一個包含所有實驗及其各自運行的主儀表板。我們可以通過單擊列標題對運行進行排序。
?我們可以單擊主儀表板上的任何實驗以進一步探索它(單擊每次運行的時間戳鏈接)。然后單擊左側的指標以在圖中查看它們:
Loading
我們需要能夠加載我們保存的實驗工件以進行推理、再訓練等。
def load_dict(filepath):"""Load a dict from a json file."""with open(filepath, "r") as fp:d = json.load(fp)return d # Load all runs from experiment experiment_id = mlflow.get_experiment_by_name("baselines").experiment_id all_runs = mlflow.search_runs(experiment_ids=experiment_id, order_by=["metrics.val_loss ASC"]) print (all_runs) run_id ... tags.mlflow.runName 0 3e5327289e9c499cabfda4fe8b09c037 ... sgd[1 rows x 22 columns] # Best run best_run_id = all_runs.iloc[0].run_id best_run = mlflow.get_run(run_id=best_run_id) client = mlflow.tracking.MlflowClient() with tempfile.TemporaryDirectory() as dp:client.download_artifacts(run_id=best_run_id, path="", dst_path=dp)vectorizer = joblib.load(Path(dp, "vectorizer.pkl"))label_encoder = LabelEncoder.load(fp=Path(dp, "label_encoder.json"))model = joblib.load(Path(dp, "model.pkl"))performance = load_dict(filepath=Path(dp, "performance.json")) print (json.dumps(performance, indent=2)) {"precision": 0.8929962902778195,"recall": 0.8333333333333334,"f1": 0.8485049088497365 } # Inference text = "Transfer learning with transformers for text classification." predict_tag(texts=[text]) ['natural-language-processing']tip:?
我們還可以通過使用它的運行 ID 直接從模型注冊表加載特定運行的模型工件,而無需將它們保存到臨時目錄。
artifact_uri = mlflow.get_run(run_id=run_id).info.artifact_uri.split("file://")[-1] params = Namespace(**utils.load_dict(filepath=Path(artifact_uri, "args.json"))) label_encoder = data.MultiLabelLabelEncoder.load(fp=Path(artifact_uri, "label_encoder.json")) tokenizer = data.Tokenizer.load(fp=Path(artifact_uri, "tokenizer.json")) model_state = torch.load(Path(artifact_uri, "model.pt"), map_location=device) performance = utils.load_dict(filepath=Path(artifact_uri, "performance.json"))總結
以上是生活随笔為你收集整理的【ML】管理和跟踪机器学习实验的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Flask】官方教程(Tutorial
- 下一篇: 海外社交媒体推广之Linkedln账号如