全部產品
Search
文件中心

Platform For AI:Responsible AI-錯誤分析

更新時間:Jul 13, 2024

Responsible AI對人工智慧模型(AI模型)開發人員和企業管理者十分重要,Responsible AI貫穿在AI模型的開發、訓練、微調、評估、部署等環節,是保障AI模型安全、穩定、公平、符合社會道德的重要方法。PAI已支援使用者在DSW中整合Responsible AI的相關工具對產出的AI模型進行公平性分析、錯誤分析及可解釋性分析。

原理介紹

錯誤分析作為Responsible AI實踐的一部分,是理解和改進模型效能的關鍵步驟。其核心原理圍繞著系統地識別、分析和解決AI模型預測中的錯誤,以提升模型的準確性和公平性。下面是錯誤分析的幾個核心原理:

  • 識別錯誤:識別出模型的預測錯誤。這通常通過比較模型的預測結果與真實值來實現,從而找出不一致的案例。錯誤可以分為不同的類型,如假陽性、假陰性等。

  • 分類錯誤:將這些錯誤按照其性質進行分類。錯誤的分類有助於我們深入理解錯誤背後的原因,比如是否因為資料不平衡、特徵不足、模型偏見或其他因素。這個過程可能需要領域知識和人的判斷。

  • 分析錯誤原因:分析每一類錯誤背後的原因。這一步非常關鍵,因為它直接關係到如何採取措施去最佳化模型。這可能涉及到資料品質的分析、模型設計的問題、特徵工程或資料表示的問題等。

  • 採取改進措施:根據錯誤分析的結果,Team Dev可以採取特定的措施來解決模型中的問題。這些措施可能包括資料清洗、重新平衡資料集、修改模型架構、引入新的特徵或使用不同的演算法等。

  • 迭代和評估:錯誤分析不是一次性的過程,而是一個持續迭代的過程。每次對模型進行修改後,都需要重新進行錯誤分析,以評估修改是否有效,模型效能是否有所提高,以及是否有新的問題出現。

  • 文檔和報告:為確保透明度和可解釋性,重要的是要詳盡記錄錯誤分析的過程、發現的問題以及採取的解決措施。這也有助於團隊成員理解模型的限制,同時為專案的其他階段提供寶貴的反饋。

本文以“預測人口普查資料集中不同類型人群年度營收是否大於50K”為例,介紹了如何在阿里雲PAI的DSW產品中使用responsible-ai-toolbox對模型進行錯誤分析。

準備環境和資源

  • DSW執行個體:如果您還沒有DSW執行個體,請參見建立DSW執行個體。推薦配置如下:

    • 推薦執行個體規格:ecs.gn6v-c8g1.2xlarge

    • 鏡像選擇:建議使用Python3.9及以上版本。本文選擇的官方鏡像為:tensorflow-pytorch-develop:2.14-pytorch2.1-gpu-py311-cu118-ubuntu22.04

    • 模型選擇:responsible-ai-toolbox支援Sklearn架構的迴歸和二分類模型。

  • 訓練資料集:推薦您使用自己的資料集;如果您需要使用樣本資料集,請按步驟三:準備資料集操作。

  • 演算法模型:推薦您使用自己的演算法模型;如果您需要使用樣本演算法模型,請按步驟五:模型訓練操作。

步驟一:進入DSW Gallery

  1. 登入PAI控制台

  2. 在頂部左上方根據實際情況選擇地區。

  3. 在左側導覽列選擇巨量資料與AI體驗 > DSW Gallery,搜尋“Responsible AI-錯誤分析”並單擊對應卡片上的在阿里雲DSW開啟

  4. 選擇AI工作空間DSW執行個體,單擊確定,系統會開啟“Responsible AI-錯誤分析”Notebook案例。

步驟二:匯入依賴包

安裝responsible-ai-toolbox的依賴包(raiwidgets),用於後續的評估。

!pip install raiwidgets==0.34.1

匯入Responsible AI和Sklearn依賴包,用於後續的訓練。

# 匯入Response AI相關依賴包

import zipfile
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer

import pandas as pd
from lightgbm import LGBMClassifier
from raiutils.dataset import fetch_dataset
import sklearn
from packaging import version
from sklearn.pipeline import Pipeline
from sklearn.impute import SimpleImputer
from sklearn.preprocessing import StandardScaler, OneHotEncoder
from sklearn.compose import ColumnTransformer

步驟三:準備資料集

下載並解壓人口普查資料集,解壓後包含訓練資料adult-train.csv和測試資料adult-test.csv。

# 資料集檔案名稱
outdirname = 'responsibleai.12.28.21'
zipfilename = outdirname + '.zip'

# 下載資料集,並進行解壓
fetch_dataset('https://publictestdatasets.blob.core.windows.net/data/' + zipfilename, zipfilename)
with zipfile.ZipFile(zipfilename, 'r') as unzip:
    unzip.extractall('.')

步驟四:資料預先處理

  1. 載入訓練資料adult-train.csv和測試資料adult-test.csv。

  2. 把訓練資料和測試資料分別拆分為特徵變數和目標變數。目標變數是指模型預測的真實結果,特徵變數是指每條執行個體資料中目標變數以外的變數。在本文樣本中,目標變數是income,特徵變數是workclasseducationmarital-status等。

  3. 將訓練資料轉換為NumPy資料格式,用於訓練。

# 載入訓練資料和測試資料
train_data = pd.read_csv('adult-train.csv', skipinitialspace=True)
test_data = pd.read_csv('adult-test.csv', skipinitialspace=True)


# 定義特徵變數和目標變數所在的列
target_feature = 'income'
categorical_features = ['workclass', 'education', 'marital-status',
                        'occupation', 'relationship', 'race', 'gender', 'native-country']

# 定義函數:用於拆分特徵變數和目標變數
def split_label(dataset, target_feature):
    X = dataset.drop([target_feature], axis=1)
    y = dataset[[target_feature]]
    return X, y


# 拆分特徵變數和目標變數
X_train_original, y_train = split_label(train_data, target_feature)
X_test_original, y_test = split_label(test_data, target_feature)


# 轉換為numpy格式
y_train = y_train[target_feature].to_numpy()
y_test = y_test[target_feature].to_numpy()

# 定義測試樣本
test_data_sample = test_data.sample(n=500, random_state=5)

您也可以載入自己的資料集,CSV格式的資料集對應的指令如下:

import pandas as pd

# 載入自己的資料集,csv 格式資料集
# 使用pandas讀取CSV檔案
try:
    data = pd.read_csv(filename)
except:
    pass

步驟五:模型訓練

本文樣本中,基於Sklearn定義一個資料訓練流水線並訓練一個二分類模型。

# 根據scikit-learn的不同版本定義ohe_params參數
if version.parse(sklearn.__version__) < version.parse('1.2'):
    ohe_params = {"sparse": False}
else:
    ohe_params = {"sparse_output": False}

# 定義分類流水線,進行特徵轉換,輸入參數X表示訓練集的資料    
def create_classification_pipeline(X):
    pipe_cfg = {
        'num_cols': X.dtypes[X.dtypes == 'int64'].index.values.tolist(),
        'cat_cols': X.dtypes[X.dtypes == 'object'].index.values.tolist(),
    }
    num_pipe = Pipeline([
        ('num_imputer', SimpleImputer(strategy='median')),
        ('num_scaler', StandardScaler())
    ])
    cat_pipe = Pipeline([
        ('cat_imputer', SimpleImputer(strategy='constant', fill_value='?')),
        ('cat_encoder', OneHotEncoder(handle_unknown='ignore', **ohe_params))
    ])
    feat_pipe = ColumnTransformer([
        ('num_pipe', num_pipe, pipe_cfg['num_cols']),
        ('cat_pipe', cat_pipe, pipe_cfg['cat_cols'])
    ])

    pipeline = Pipeline(steps=[('preprocessor', feat_pipe),
                               ('model', LGBMClassifier(random_state=0))])

    return pipeline
    
# 建立分類模型訓練流水線
pipeline = create_classification_pipeline(X_train_original)

# 模型訓練
model = pipeline.fit(X_train_original, y_train)

步驟六:添加Responsible AI組件

執行以下指令碼,為Responsible AI添加了錯誤分析組件,並通過rai_insights進行計算。

# 匯入RAI儀錶盤組件
from raiwidgets import ResponsibleAIDashboard
from responsibleai import RAIInsights

# 定義RAIInsights對象
from responsibleai.feature_metadata import FeatureMetadata
feature_metadata = FeatureMetadata(categorical_features=categorical_features, dropped_features=[])
rai_insights = RAIInsights(model, train_data, test_data_sample, target_feature, 'classification',
                           feature_metadata=feature_metadata)

# 添加錯誤分析組件
rai_insights.error_analysis.add()

# RAI計算
rai_insights.compute()

步驟七:建立Responsible AI儀錶盤

  1. 通過不同的過濾條件,建立不同的資料分組,可以對過濾出的不同的資料分組進行錯誤分析,例如:

  • 年紀 (age) 小於65歲且每周工作時間 (hours-per-week) 大於40小時。

  • 婚姻狀態 (marital-status) 為"Never-married" 或者 "Divorced"。

  • 資料分組索引 (Index) 小於20。

  • 預測值(Predicted Y)大於50K。

  • 實際值 (True Y) 大於50K。

  1. 引入ResponsibleAIDashboard儀錶盤,使用responsible-ai-toolbox對模型進行分析。

from raiutils.cohort import Cohort, CohortFilter, CohortFilterMethods
import os
from urllib.parse import urlparse

# 年紀 (age) 小於65歲且每周工作時間 (hours-per-week) 大於40小時
cohort_filter_age = CohortFilter(
    method=CohortFilterMethods.METHOD_LESS,
    arg=[65],
    column='age')
cohort_filter_hours_per_week = CohortFilter(
    method=CohortFilterMethods.METHOD_GREATER,
    arg=[40],
    column='hours-per-week')

user_cohort_age_and_hours_per_week = Cohort(name='Cohort Age and Hours-Per-Week')
user_cohort_age_and_hours_per_week.add_cohort_filter(cohort_filter_age)
user_cohort_age_and_hours_per_week.add_cohort_filter(cohort_filter_hours_per_week)

# 婚姻狀態 (marital-status) 為"Never-married" 或者 "Divorced"
cohort_filter_marital_status = CohortFilter(
    method=CohortFilterMethods.METHOD_INCLUDES,
    arg=["Never-married", "Divorced"],
    column='marital-status')

user_cohort_marital_status = Cohort(name='Cohort Marital-Status')
user_cohort_marital_status.add_cohort_filter(cohort_filter_marital_status)

# 資料分組索引 (Index) 小於20
cohort_filter_index = CohortFilter(
    method=CohortFilterMethods.METHOD_LESS,
    arg=[20],
    column='Index')

user_cohort_index = Cohort(name='Cohort Index')
user_cohort_index.add_cohort_filter(cohort_filter_index)

# 預測值(Predicted Y)大於50K
cohort_filter_predicted_y = CohortFilter(
    method=CohortFilterMethods.METHOD_INCLUDES,
    arg=['>50K'],
    column='Predicted Y')

user_cohort_predicted_y = Cohort(name='Cohort Predicted Y')
user_cohort_predicted_y.add_cohort_filter(cohort_filter_predicted_y)

# 實際值 (True Y) 大於50K
cohort_filter_true_y = CohortFilter(
    method=CohortFilterMethods.METHOD_INCLUDES,
    arg=['>50K'],
    column='True Y')

user_cohort_true_y = Cohort(name='Cohort True Y')
user_cohort_true_y.add_cohort_filter(cohort_filter_true_y)

cohort_list = [user_cohort_age_and_hours_per_week,
               user_cohort_marital_status,
               user_cohort_index,
               user_cohort_predicted_y,
               user_cohort_true_y]

# 建立Responsible AI儀錶盤
metric_frame_tf = ResponsibleAIDashboard(rai_insights, cohort_list=cohort_list, feature_flights="dataBalanceExperience")

# 設定URL跳轉連結
metric_frame_tf.config['baseUrl'] =  'https://{}-proxy-{}.dsw-gateway-{}.data.aliyun.com'.format(
    os.environ.get('JUPYTER_NAME').replace("dsw-",""),
    urlparse(metric_frame_tf.config['baseUrl']).port,
    os.environ.get('dsw_region') )

步驟八:訪問Responsible AI儀錶盤,查看錯誤分析

單擊URL,訪問Responsible AI儀錶盤。

image

查看錯誤分析:

樹形圖(Tree Map)

image

  1. 單擊Tree map,在Select metric中選擇Error rate,進行錯誤性分析。錯誤分析樹形視圖根據模型的所有特徵,以二叉樹方式按照特徵的不同數值進行拆分。例如,該樹形根節點下的二叉樹兩個分支分別表示:

    • marital-status == Married-civ-spouse(54/224)

    • marital-status != Married-civ-spouse(18/276)

  2. 本次樣本包含500個樣本,有72個預測錯誤,則錯誤率為72/500 = 14.4%。每個二叉樹的節點展示了滿足該分支條件的資料總量以及預測錯誤的數量和錯誤比例。

  3. 您需要重點關注紅色的節點,紅色越深,表明錯誤率(error rate)越高。

  4. 在本樣本中,單擊紅色最深的葉子節點,可以看出同時滿足以下條件的資料,模型預測錯誤比例高達43.40%。條件如下:

    • marital-status == Married-civ-spouse

    • fnlwgt <= 207583

    • hours-per-week > 40.5

熱度圖(Heat Map)

image

  1. 單擊Heat map,切換到熱度圖分析視圖,在Select metric中選擇Error rate,進行錯誤性分析。

  2. (可選)配置參數:

    • Quantile binning:是一種將連續變數分成若干個具有相同資料點的區間的方法。

      • 設定為OFF,表示關閉。採用預設均勻分段策略,每個區間的長度保持相同。

      • 設定為ON,表示開啟。每個區間包含相同數量的資料點,使得資料在每個區間中均勻分布。

    • Binning threshold:表示將資料分割的區間個數,調整threshold可調整分割的區間數量(在本樣本中預設為8,表示將age和hours-per-week平均分割為8個區間)。

  3. 在熱度圖中,您可以選定2個輸入特徵進行資料交叉分析。本樣本中選定age、hours-per-week 進行熱度圖分析。

  4. 您需要重點關注紅色的節點,紅色越深,表明錯誤率(error rate)越高。

  5. 從分析結果看,兩個特徵在以下分布區間的錯誤率最高,高達 100%:

    • age[71.8,80.9]、hours-per-week[39.0,51.0]

    • age[44.4,53.5]、hours-per-week[75.0,87.0]

    • age[16.9,26.1]、hours-per-week[63.0,75.0]

    • ...