###### tags: `選修` # 人工智慧導論 + 部份範例來源 - [Python實現人工智慧](https://ctld.video.nccu.edu.tw/km/1172) - [成為 Python 數據分析達人的第一課](https://ctld.video.nccu.edu.tw/km/1399) - [2021 北一女 Python 人工智慧工作坊](https://www.youtube.com/playlist?list=PLpltJwWB6egIKy68TSew5cbKamQdjccEE) - [教育部中小學人工智慧教育教學示範例系列-和AI做朋友,從0開始學AI](https://market.cloud.edu.tw/list/ai.jsp) - [Coursera 吴恩达机器学习 课后作业题](https://blog.csdn.net/m0_37867091/category_9817315.html) + 自學參考網站 - [深度學習 Deep Learning:中文學習資源整理](https://jerrynest.io/deep-learning-resource/) - [LeeMeng - 由淺入深的深度學習資源整理](https://leemeng.tw/deep-learning-resources.html) - [國立聯合大學資訊管理學系 機器學習課程](http://debussy.im.nuu.edu.tw/sjchen/ML_final.html) - [機器學習首部曲](https://www.youtube.com/playlist?list=PLy7MS-q4l3xDYoR8MACYA3YyidUbEiz6j)、[二部曲](https://www.youtube.com/playlist?list=PLy7MS-q4l3xC1UbPAhuIRrStZuKV-xaPR) - [以100張圖理解 Neural Network -- 觀念與實踐](https://ithelp.ithome.com.tw/users/20001976/ironman/1395) - [有趣的機器器學習系列(莫煩Python)](https://mofanpy.com/tutorials/machine-learning/ML-intro/) - [CS583: Deep Learning](https://github.com/wangshusen/DeepLearning) - [深度学习 (DS-GA 1008 · 2020 春季 · 纽约大学数据科学中心)](https://atcold.github.io/pytorch-Deep-Learning/zh/) - 李宏毅教授 ML ([2021](https://speech.ee.ntu.edu.tw/~hylee/ml/2021-spring.php)、[YouTube](https://www.youtube.com/playlist?list=PLJV_el3uVTsMhtt7_Y6sgTHGHp1Vb2P2J))[(2022)](https://speech.ee.ntu.edu.tw/~hylee/ml/2022-spring.php) - [Machine Learning Crash Course  |  Google Developers](https://developers.google.com/machine-learning/crash-course) + 評量方式 - 上課練習 50% - 專案 30%(10%+10%+10%) - 筆試 20% + 修課建議目標 - 低:真實了解人工智慧。 - 中:對申請入學有幫助(修課紀錄、學習歷程自述、面試)。 - 高:能產出課程學習成果。 ::: info 專案一:[Kaggle競賽 - 鐵達尼號生存預測(Titanic - Machine Learning from Disaster)](https://www.kaggle.com/c/titanic) + [Kaggle](https://www.kaggle.com/) + 分數計算:Score*100 + 作業格式 1. 最高分數截圖。 2. 增加處理說明(需列出參考網站、分數截圖和程式碼)(每項加4分,不完整不予計分)。 3. 完整程式碼(從colab裏複製貼上,不要貼截圖)。 + 分數提昇參考:[(1)](http://ielab.ie.nthu.edu.tw/108_IIE_project/2/108IIE_proj2_4_PPT.pdf)、[(2)](https://yulongtsai.medium.com/https-medium-com-yulongtsai-titanic-top3-8e64741cc11f)、[(3)](https://hackmd.io/@f820920/BJH6xeihu)、[(4)](https://hackmd.io/@Go3PyC86QhypSl7kh5nA2Q/Hk4nXFYkK#%E7%89%B9%E5%BE%B5%E5%B7%A5%E7%A8%8B) - 有做特徵工程(Feature Engineering):填補遺漏值、調整數據型態範圍、創造有利分析新特徵...,分數才會更高。 - 如果想要增加的特徵中有遺漏值,如 Age、Fare…,不會寫程式處理,可以直接修改train.csv、test.csv,填入適當的數值。 + 簡略參考架構如下(不做資料前處理,只看 Pclass 和 Sex 兩個特徵)。 ::: ``` javascript= import numpy as np import pandas as pd from sklearn import tree from sklearn.svm import SVC from sklearn.neighbors import KNeighborsClassifier # 讀入檔案 train=pd.read_csv('train.csv') test=pd.read_csv('test.csv') # 將文字轉成數字 train['Sex'],_=pd.factorize(train['Sex']) test['Sex'],_=pd.factorize(test['Sex']) # 只看 Pclass 和 Sex 兩個特徵 x_train=train[['Pclass','Sex']] y_train=train[['Survived']] x_test=test[['Pclass','Sex']] # 以「KNN(0.76)」或「決策樹」或「SVM」或「DNN」預測 ~ ~ ~ # 產生匯出檔案 submission_df=pd.DataFrame({ 'PassengerId':test['PassengerId'], 'Survived':y_test_predict }) submission_df.to_csv('submission.csv', index=False) ``` ::: info 專案二:[Kaggle競賽 - Digit Recognizer](https://www.kaggle.com/c/digit-recognizer) + 分數計算 1. DNN ((Score-0.98)/0.015)*15+80 2. CNN ((Score-0.99)/0.015)*15+80 3. Score 0.95 以下者皆為 50 分 + 作業格式 1. 分數截圖。 2. 增加處理說明(需列出參考網站、分數截圖和程式碼)(每項加4分,不完整不予計分)。 3. 完整程式碼(從colab裏複製貼上,不要貼截圖)。 + 分數提昇參考:[(1)](https://www.kaggle.com/code/cdeotte/25-million-images-0-99757-mnist/notebook)、[(2)](https://www.kaggle.com/code/loveunk/kaggle-digit-recognizer-keras-cnn-100-accuracy/notebook)、[(3)](https://www.kaggle.com/competitions/digit-recognizer/discussion/61480)、[(4)](https://www.kaggle.com/code/jedrzejdudzicz/mnist-dataset-100-accuracy/notebook)、[(5)](https://www.kaggle.com/code/barindersingh/digit-recognizer-with-100-accuracy-with-keras) + 避免 Overfitting - BatchNormalization [(1)](https://medium.com/ching-i/batch-normalization-%E4%BB%8B%E7%B4%B9-135a24928f12)、[(2)](https://www.youtube.com/watch?v=BABPWOkSbLE) ``` python # 需匯入相對的模組 model.add(BatchNormalization()) ``` - Dropout ``` python # 需匯入相對的模組 model.add(Dropout(0.3)) ``` - EarlyStopping [(1)](https://ithelp.ithome.com.tw/m/articles/10361486)、[(2)](https://blog.csdn.net/yangwohenmai1/article/details/123274494) ``` python # 需匯入相對的模組 early = EarlyStopping(monitor="val_accuracy", min_delta=0, patience=20, verbose=1, mode="max") history = model.fit(x_train, y_train, batch_size=100, epochs=300, validation_split=0.2, callbacks=[early]) ``` + 簡略參考架構如下 - DNN 的部分請參考 EX_08_6 的程式碼。 - CNN 的部分請參考 EX_10_2 的程式碼。 + 訓練、測試資料可上傳至 Colab 或 Google 雲端硬碟。 - 上傳至Colab:Colab 左側 -> 檔案 ->上傳至工作階段儲存空間。 - 上傳至雲端硬碟:Colab 左側 -> 檔案 -> 掛接雲端硬碟。(登入Google帳號後,將授權金鑰貼過來) 檔案路徑:'drive/MyDrive/檔案名' ::: ``` javascript= import numpy as np import pandas as pd from tensorflow.keras.utils import to_categorical from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Activation, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D from tensorflow.keras.optimizers import SGD, Adam # 讀入檔案 # 先將檔案上傳至 Colab train=pd.read_csv('train.csv') test=pd.read_csv('test.csv') # 先將檔案上傳至自己的雲端硬碟 # train=pd.read_csv('drive/MyDrive/train.csv') # test=~ # 第1欄(label)為答案 y_train = train['label'] # 删除「label」列 x_train = train.drop(labels=['label'], axis=1) # 輸入格式整理 # 如果用標準神經網路,要 reshape 成 784*1 的矩陣 x_train = x_train.values.reshape(-1, 784, 1) x_test = test.values.reshape(-1, 784, 1) # 如果用CNN,要 reshape 成 28*28*1 的矩陣 # x_train = x_train.values.reshape(-1, 28, 28, 1) # x_test = test.values.reshape(-1, 28, 28, 1) # nomarlization x_train = x_train.astype('float32')/255 x_test = x_test.astype('float32')/255 # 將答案轉換為 One-hot encoding y_train = to_categorical(y_train, num_classes=10) # 打造標準(EX_08_6 程式碼區塊2 5-17行) 或 CNN 神經網路(EX_10_2 程式碼區塊2 7-26行),編譯,訓練 # 如果要用 EX_08_7 神經網路為 Sequential 的參數的寫法,因為輸入不是圖檔,已經是784*1的矩陣,所以不用加 flatten 層,且第一個 Dense 層要有 input_shape=(784,) ~ # 預測結果(EX_08_6 程式碼區塊2 28行) ~ # 產生匯出檔案 submission_df = pd.DataFrame({ 'ImageId': list(range(1,len(y_test_predict)+1)), 'Label': y_test_predict }) submission_df.to_csv('submission.csv', index=False) ``` ::: info 專案三:[Kaggle競賽 - Dogs vs. Cats Redux: Kernels Edition](https://www.kaggle.com/competitions/dogs-vs-cats-redux-kernels-edition/) + 分數計算:100-Score*20 + 作業格式 1. 分數截圖。 2. 增加處理說明(需列出參考網站、分數截圖和程式碼)(每項加4分,不完整不予計分)。 有利用 ImageDataGenerator 進行數據增強 + 20分。 3. 完整程式碼(從 Kaggle 裏複製貼上,不要貼截圖)。 + 簡略參考架構如下:CNN 的部分請參考 EX_10_2 的程式碼。 + 因 Colab RAM(13GB)不足,本專案請在 Kaggle Notebook(30GB,還是吃緊) 或其它資源上實作,或把圖片格式壓小一點。 ::: ``` javascript= # 解壓縮訓練圖檔 !unzip /kaggle/input/dogs-vs-cats-redux-kernels-edition/train.zip -d /kaggle/working/ ``` ``` javascript= # 解壓縮測試圖檔 !unzip /kaggle/input/dogs-vs-cats-redux-kernels-edition/test.zip -d /kaggle/working/ ``` ``` javascript= import numpy as np import matplotlib.pyplot as plt import os from tqdm import tqdm from tensorflow.keras.preprocessing import image from sklearn.model_selection import train_test_split from tensorflow.keras.utils import to_categorical from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Activation, Flatten from tensorflow.keras.layers import Input, Conv2D, MaxPooling2D # 1. 訓練資料的檔名和標籤 train_file_lists = os.listdir('/kaggle/working/train') # 所有訓練集的檔案名稱 test_file_lists = os.listdir('/kaggle/working/test') labels = np.array([1 if 'dog' in file else 0 for file in train_file_lists]) # 2. 讀取圖片並轉換為 numpy array def load_images(dir, file_lists): images = [] for file in tqdm(file_lists): # tqdm 有進度條 img_path = os.path.join(dir, file) img = image.load_img(img_path, target_size=(140,140)) img_array = image.img_to_array(img) / 255.0 # 正規化到 [0,1] images.append(img_array) return np.array(images) # 加載所有訓練及測試圖片 train_images = load_images('/kaggle/working/train',train_file_lists) test_images = load_images('/kaggle/working/test',test_file_lists) # 3. 將訓練資料分為訓練集和驗證集 x_train, x_val, y_train, y_val = train_test_split(train_images, labels, test_size=0.2, random_state=50) ``` ``` javascript= # 4. 打造 CNN 神經網路(EX_10_2 程式碼區塊2 7-26行),編譯,訓練 ~ # 二分類問題,輸出層一個神經元即可,激發函數用 sigmoid model.add(Dense(units=1, activation='sigmoid')) # 二分類問題,損失函數改用 'binary_crossentropy' 是否會比較好?categorical_crossentropy 預期輸出是多分類 one-hot 編碼形式,但在二分類問題中,輸出為一個純量(0 或 1),可能無法正確解釋這樣的輸出,導致損失值計算不合理或不穩定。。 model.compile(optimizer='adam', loss='~', metrics=['accuracy']) # EX_10_2的寫法 history = model.fit(x_train, y_train, batch_size=64, epochs=10, validation_split=0.2) 每次訓練會隨機分配 20% 的資料作為驗證集,不需事先分配驗證集,方便快速檢查模型性能。 history = model.fit(x_train, y_train, batch_size=100, epochs=10, validation_data=(x_val, y_val)) # 驗證集已先分割好,確保每次訓練過程中的驗證集保持不變,較能準確比較模型。 ``` ``` javascript= # 5. 對測試集進行預測,並產生匯出檔案 predictions = model.predict(test_images) predictions = predictions.flatten() # 將預測結果展平為一維數組 submission_df = pd.DataFrame({ 'id': [int(filename.split('.')[0]) for filename in test_file_lists], 'label': predictions }) submission_df.to_csv('submission.csv', index=False) ``` ::: info 專案四:[Kaggle競賽 - Bag of Words Meets Bags of Popcorn](https://www.kaggle.com/competitions/word2vec-nlp-tutorial) + 分數計算:Score*100 + 作業格式 1. 分數截圖。 2. 增加處理說明(需列出參考網站、分數截圖和程式碼)(每項加4分,不完整不予計分)。 3. 完整程式碼(從 Kaggle 裏複製貼上,不要貼截圖)。 + 分數提昇參考:[(1)](https://medium.com/kkproject/%E6%96%87%E5%AD%97%E6%8E%A2%E5%8B%98-%E9%9B%BB%E5%BD%B1%E8%A9%95%E8%AB%96%E6%83%85%E7%B7%92%E5%88%86%E6%9E%90keras%E5%AF%A6%E4%BD%9C-eef01316a76e) + 簡略參考架構如下:RNN 的部分請參考 EX_11_2 # 5. 建立 RNN model,編譯,訓練。 + 本專案請在 Kaggle Notebook 上完成。 ::: ``` javascript= # 解壓縮訓練集 !unzip /kaggle/input/word2vec-nlp-tutorial/labeledTrainData.tsv.zip -d /kaggle/working/ ``` ``` javascript= # 解壓縮測試集 !unzip /kaggle/input/word2vec-nlp-tutorial/testData.tsv.zip -d /kaggle/working/ ``` ``` javascript= import pandas as pd import numpy as np import tensorflow as tf import csv from tensorflow.keras.preprocessing.text import Tokenizer from tensorflow.keras.preprocessing.sequence import pad_sequences from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Embedding, LSTM, Dense, Dropout # 1. 載入資料 train = pd.read_csv('/kaggle/working/labeledTrainData.tsv', delimiter='\t', quoting=3) test = pd.read_csv('/kaggle/working/testData.tsv', delimiter='\t', quoting=3) # 2. 資料預處理 train_texts = train['review'].values train_labels = train['sentiment'].values test_texts = test['review'].values # 3. 文字向量化 max_vocab_size = 20000 # 詞彙表大小 max_sequence_length = 300 # 每個序列的最大長度 tokenizer = Tokenizer(num_words=max_vocab_size) tokenizer.fit_on_texts(train_texts) x_train = tokenizer.texts_to_sequences(train_texts) x_test = tokenizer.texts_to_sequences(test_texts) x_train = pad_sequences(x_train, maxlen=max_sequence_length) x_test = pad_sequences(x_test, maxlen=max_sequence_length) y_train = np.array(train_labels) ``` ``` javascript= # 4. 建立 LSTM 模型(EX_11_2 #5),編譯,訓練 embedding_dim = 128 ~ ``` ``` javascript= # 5. 對測試集進行預測,並產生匯出檔案 predictions = np.argmax(model.predict(x_test), axis=1) # 將概率轉為類別 submission_df = pd.DataFrame({ 'id': test['id'], 'sentiment': predictions }) submission = submission_df.to_csv('submission.csv', index=False, quoting=csv.QUOTE_NONE) ``` ## 零、環境 + [Google Colaboratory](https://colab.research.google.com/) - [GPU 加速](https://www.youtube.com/watch?v=-P28LKWTzrI) * Runtime / Change runtine type / Hardware accelerator / GPU * 執行階段/變更執行階段類型/硬體加速器/GPU - `ctrl + /`:多行註解 - `Tab、Shift+Tab`:增、減縮排 + 相關套件 - [Scikit-learn](https://scikit-learn.org/stable/) * 建立於 NumPy, SciPy 之上的 Python 機器學習套件,內建許多常見的機器學習演算法 。 * [Choosing the right estimator](https://scikit-learn.org/stable/tutorial/machine_learning_map/index.html) - [TensorFlow](https://www.tensorflow.org/) - [Pandas](https://pandas.pydata.org/) - [Matplotlib](https://matplotlib.org/) - [openAI gym](https://gym.openai.com/) + 學習歷程檔案(修課記錄、課程學習成果)(Bonus) - 最後一週上課結束前如果認證完成,學期總成績加分。 - [撰寫「課程學習成果」參考資源](https://hackmd.io/@cube/HkCv90e19)。 <br /> ## 一、人工智慧(Artificial Intelligence,AI) + [人工智慧在臺灣:產業轉型的契機與挑戰|陳昇瑋研究員](https://www.youtube.com/watch?v=OddYM6aq-zM) + 關於AI的種種傳聞 & 機器學習的七個步驟 & 任務分類(PPT) + <font color="red">體驗</font> - [自動駕駛車](https://vimeo.com/192179726) - [超級實用!精選 15 款文本、繪圖、音樂、影音剪輯等領域的 AI 工具,賦予創作者前所未有的便利性 - 映CG 媒體 | InCG Media](https://www.incgmedia.com/spotlight/15-featured-ai-tools-introduction) - [人類還剩幾集可以逃?ChatGPT + Midjourney + Clipchamp AI大軍聯合玩內容創作 (文稿/插圖/配樂/配音/字幕全包) ](https://www.youtube.com/watch?v=9T8Dn2cY_04&t=205s) - [Leonardo.ai](https://leonardo.ai/) - [PaintsChainer 线稿自动上色服务](https://paintschainer.preferred.tech/) - [Vision AI 透過機器學習技術取得圖片的深入分析結果](https://cloud.google.com/vision/)([說明](https://ithelp.ithome.com.tw/articles/10214867)) <br /> ![](https://i.imgur.com/SHtuGvu.png) <br /> ## 二、機器學習(Machine Learning)簡介 + 從訓練資料中擷取出資料的特徵(features),建立判斷基準(模型、函數)對未來做預測。 + [機器學習大補帖](https://ithelp.ithome.com.tw/articles/10265942) ### 1. 任務類型 + 分類(classification)、迴歸(regression)、分群(clustering) - 分類(classification):將未知的新訊息歸納進已知的資訊中。 - 分群(clustering):將特徵相似的資料歸類於同一組,事先並不知道會依那些特徵進行分組。 <a href="https://www.researchgate.net/figure/Examples-of-real-life-problems-in-the-context-of-supervised-and-unsupervised-learning_fig8_319093376"><img src="https://www.researchgate.net/profile/Sinan_Kaplan2/publication/319093376/figure/fig8/AS:526859928834054@1502624603775/Examples-of-real-life-problems-in-the-context-of-supervised-and-unsupervised-learning.png"/></a> <br /> ### 2. 不同的訓練方法 + 監督式學習(Supervised)(分類、迴歸) - 給予「有標籤」的資料,例如給機器各看1000張有標示貓和狗的照片,讓機器學會判斷照片中是貓還是狗。 + 非監督式學習(Unsupervised)(分群) - 給予「無標籤」的資料,讓機器自行找出資料規律。 + 半監督式學習(Semi-supervised) - 少部分資料有標籤,大部分資料沒有標籤,以資料分群來說先以有標籤的資料切出一條分界線,再利用剩下沒標籤資料的整體分布調整分界線。 + 強化學習(Reinforcement)(分類) - 使用未標記的資料,透過獎勵函數,讓機器知離正確答案越來越近還是遠。 <br /> ## 三、機器學習(Machine Learning)演算法 ### 1. [Linear regression(線性迴歸)](https://scikit-learn.org/stable/modules/generated/sklearn.linear_model.LinearRegression.html)(PPT) + <font color=red>迴歸,監督式學習</font> + [線性迴歸(Linear Regression)](https://medium.com/@chih.sheng.huang821/%E7%B7%9A%E6%80%A7%E5%9B%9E%E6%AD%B8-linear-regression-3a271a7453e) - [微積分到底在幹嘛?讓我們從微分開始](https://home.gamer.com.tw/creationDetail.php?sn=4946297) - [微分公式參考](http://www.math.ncu.edu.tw/~yu/ecocal95/boards/lec12_c_95.pdf) - $\displaystyle Loss(\hat\beta_0,\hat\beta_1)=\sum_{i=1}^{n}(y_i-\hat y_i)^2=\sum_{i=1}^{n}(y_i-(\hat\beta_0+\hat\beta_1 x_i))^2$ - 為了推估$\beta_0$,對 $Loss(\hat\beta_0,\hat\beta_1)$ 做 $\beta_0$ 偏微分等於 0 $\begin{align*} & \displaystyle \frac{\partial oss(\hat\beta_0,\hat\beta_1)}{\partial \beta_0}=\frac{\partial \displaystyle \sum_{i=1}^{n}(y_i-\hat\beta_0-\hat\beta_1 x_i)^2} {\partial\beta_0}=0 \\ & \displaystyle \Rightarrow \sum_{i=1}^{n}2(y_i-\hat\beta_0-\hat\beta_1 x_i)(-1)=0 \\ & \displaystyle \Rightarrow -2\sum_{i=1}^{n}(y_i-\hat\beta_0-\hat\beta_1 x_i)=0 \\ & \displaystyle \Rightarrow \sum_{i=1}^{n}(y_i-\hat\beta_0-\hat\beta_1 x_i)=0 \\ & \displaystyle \Rightarrow n\hat\beta_0=\sum_{i=1}^{n}(y_i-\hat\beta_1 x_i) \\ & \displaystyle \Rightarrow \hat\beta_0=\frac{1}{n}\sum_{i=1}^{n}(y_i-\hat\beta_1 x_i) \\ & \Rightarrow \hat\beta_0=\bar y-\hat\beta_1 \bar x \end{align*}$ - 為了推估$\beta_1$,對 $Loss(\hat\beta_0,\hat\beta_1)$ 做 $\beta_1$ 偏微分等於 0 $\begin{align*} & \displaystyle \frac{\partial Loss(\hat\beta_0,\hat\beta_1)}{\partial \beta_1}=\frac{\partial \displaystyle \sum_{i=1}^{n}(y_i-\hat\beta_0-\hat\beta_1 x_i)^2} {\partial\beta_1}=0 \ ,先將上式求得的\hat\beta_0代入 \\ & \displaystyle \Rightarrow \frac{\partial \displaystyle \sum_{i=1}^{n}(y_i-(\bar y-\hat\beta_1 \bar x)-\hat\beta_1 x_i)^2} {\partial\beta_1}=\frac{\partial \displaystyle \sum_{i=1}^{n}((y_i-\bar y)-\hat\beta_1 (x_i-\bar x))^2} {\partial\beta_1}=0 \\ & \displaystyle \Rightarrow \sum_{i=1}^{n}2((y_i-\bar y)-\hat\beta_1(x_i-\bar x))(-1)(xi-\bar x)=0 \\ & \displaystyle \Rightarrow \sum_{i=1}^{n}-2(x_i-\bar x)(y_i-\bar y)+2\hat\beta_1(x_i-\bar x)^2=0 \\ & \displaystyle \Rightarrow \hat\beta_1 \sum_{i=1}^{n}(x_i-\bar x)^2=\sum_{i=1}^{n}(x_i-\bar x)(y_i-\bar y) \\ & \displaystyle \Rightarrow \hat\beta_1 = \frac{ \displaystyle \sum_{i=1}^{n}(y_i-\bar y)(x_i-\bar x)}{ \displaystyle \sum_{i=1}^{n}(x_i-\bar x)^2} \end{align*}$ + [用人话讲明白线性回归 LinearRegression](https://zhuanlan.zhihu.com/p/72513104) + [用人话讲明白梯度下降 Gradient Descent(以求解多元线性回归参数为例)](https://zhuanlan.zhihu.com/p/137713040) + [資料視覺化](https://ithelp.ithome.com.tw/articles/10264416) + 應用:產品需求預測、保險費用預測、犯罪率預測… :::info EX_01_1:完成[線性迴歸學習單(5~7)](https://docs.google.com/spreadsheets/d/1EoCpDRgVxW-aULNg9ya9IaZZJU9M8zsa/edit?usp=sharing&ouid=118043800222804360069&rtpof=true&sd=true),練習以線性代數公式求參數。 ::: :::info EX_01_2:呈上題,練習以程式求參數,看看答案是否看上題相同。 + $y=\beta_0+\beta_1 x,y=6.8762+0.0401x$ ::: + [簡明 Python Numpy 入門教學](https://blog.techbridge.cc/2020/08/24/numpy-zen-intro-tutorial/) + [Routines — NumPy v1.22 Manual](https://numpy.org/doc/stable/reference/routines.html) ``` javascript= x=[1,2,3] y=[4,5,6] print('3*x:', 3*x) print('x+y:', x+y) print('x加總:', sum(x)) ``` ``` javascript= import numpy as np x=np.array([1,2,3]) y=np.array([4,5,6]) print('x+10:', x+10) print('3*x:', 3*x) print('x+y:', x+y) print('x*y:', x*y) print('x加總:', np.sum(x)) print('x平均:', np.average(x)) print('x的長度:', x.size) ``` + [matplotlib.pyplot.scatter](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.scatter.html?highlight=scatter#matplotlib.pyplot.scatter) + [matplotlib.pyplot.plot](https://matplotlib.org/stable/api/_as_gen/matplotlib.pyplot.plot.html?highlight=plot#matplotlib.pyplot.plot) ``` javascript= import numpy as np import matplotlib.pyplot as plt x=np.array([24.3, 19.5, 18.8, 20.1, 22.2, 29.8, 26.3, 28.3, 31.9, 26.9]) # 油價 y=np.array([7.9, 7.7, 7.6, 7.7, 7.7, 8.2, 7.8, 7.9, 8.1, 8.1]) # 民眾搭捷運平均里程 plt.scatter(x, y) # plt.scatter 產生散點圖 X=x-np.average(x) Y=~ b1=np.sum(X*Y)/~ b0=~ print(b0,b1) plt.plot(x, b0+b1*x, 'r') # 以 plt.plot 畫出函數 y=b0+b1*x ``` :::info EX_01_3:呈上題,練習以 [Gradient Descent](https://ithelp.ithome.com.tw/articles/10266246) 求參數,看看答案是否看上題相同。 + 先試試用梯度下降法逼近多項式函數的最小值。 ![](https://i.imgur.com/YhdM5bH.png =200x) + 多元回歸公式 $\hat\beta=(X^TX)^{-1}X^TY$ 維度多時算反矩陣時間複雜度很大,也可能X沒有反矩陣,因此用梯度下降法找答案。 + 以 MSE(均方誤差) 為損失函數 $\begin{align*} \displaystyle L&=\frac{1}{n}\sum_{i=1}^{n}{(y_i-\hat y)^2}\\ \displaystyle &=\frac{1}{n}\sum_{i=1}^{n}(y_i-(\beta_0+\beta_1 x_i))^2\\ \displaystyle &=\frac{1}{n}\sum_{i=1}^{n}(y_i-\beta_0-\beta_1 x_i)^2 \end{align*}$ + $\displaystyle \frac{\partial L}{\partial \beta_0}=-\frac{2}{n}\sum_{i=1}^{n}(y_i-\beta_0-\beta_1 x_i)$ + $\displaystyle \frac{\partial L}{\partial \beta_1}=-\frac{2}{n}\sum_{i=1}^{n}(y_i-\beta_0-\beta_1 x_i)x_i$ + $\displaystyle \beta_0=\beta_0-\eta*\frac{\partial L}{\partial \beta_0}$ + $\displaystyle \beta_1=\beta_1-\eta*\frac{\partial L}{\partial \beta_1}$ + $\eta$ (eta):學習率 ::: ``` javascript= # 先試試用梯度下降法逼近多項式函數的最小值 import numpy as np import matplotlib.pyplot as plt def f(x): # 定義多項式函數 return x**4-70*x**2-80*x+90 def f_prime(x): # 定義多項式函數的導函數 ~ x0,lr=-10,0.0001 # 梯度下降的起點,學習率 nx=[] # 儲存梯度下降每一步的 x 座標 for i in range(100): # 執行梯度下降次數 nx.append(x0) ~ # 梯度下降 NX=np.array(nx) # 將 list 轉成 numpy array # 畫出梯度下降的更新路徑 plt.figure(figsize=(10,5)) x=np.linspace(-10,10,100) # 取 x 坐標軸的數據點 plt.plot(x,f(x),'r') # 多項式函數 plt.plot(x,f_prime(x),'b') # 導函數 ~ # 以scatter畫出梯度下降每一步的座標點 plt.xlabel('x') plt.ylabel('y') ``` ``` javascript= import numpy as np import matplotlib.pyplot as plt from sklearn.linear_model import LinearRegression x=np.array([24.3, 19.5, 18.8, 20.1, 22.2, 29.8, 26.3, 28.3, 31.9, 26.9]) # 油價 y=np.array([7.9, 7.7, 7.6, 7.7, 7.7, 8.2, 7.8, 7.9, 8.1, 8.1]) # 民眾搭捷運平均里程 ~ # 以 plt.scatter 產生散點圖 #1. 以 Gradient Descent 求參數 b0,b1,lr=5.0,5.0,0.001 # 初值隨機選取,試試b0,b1不同初值(例如500,500)是否可得到答案,如果不行,增加次數或調高lr看看? for i in range(100000): # Gradient Descent 次數 b0=b0-lr*-2/x.size*np.sum(y-b0-b1*x) b1=~ print(b0,b1) ~ # 以 plt.plot 畫出函數 y=b0+b1*x ``` ``` javascript= import numpy as np a=np.array([[1,2,3],[4,5,6]]) print('a:\n', a) print('a.shape:', a.shape) x=np.array([1,2,3,4,5,6]) print('x:\n', x) print('x.shape:', x.shape) xx=x.reshape(6,1) # xx=x.reshape(3,2) print('xx:\n', xx) print('xx.shape:', xx.shape) ``` ``` javascript= #2. 用 SKlearn 線性迴歸模組做預測 XX=x.reshape(10,1) # 若 x 為[x1,x2,....,x50](1x50的陣列),但 SKlearn 需要[[x1],[x2],....,[x50]](50x1的陣列) regModel = LinearRegression() # 初始化線性迴歸模組 regModel.fit(XX, y) # 讓線性迴歸模組學習,模組的變數名稱.fit(輸入資料,正確答案) y_predict = regModel.predict(XX) # y_predict為線性迴歸模組預測的結果 plt.plot(x, y_predict, 'b' ,alpha=0.4) ``` :::info (進階) EX_01_4:將上題的程式碼改以向量的方式完成(容易推廣至多元回歸)。 + [參考網站](https://github.com/yaojenkuo/ml-newbies/blob/master/05-regression.ipynb) + 多元迴歸方程的一般形式為$y=\beta_0+\beta_1x_1+\beta_2x_2+...+\beta_dx_d$ 可以簡寫為矩陣形式 $\textbf{Y}=\textbf{X}\mathbf{\beta}$ 其中, $\textbf{Y}= \begin{bmatrix} y_1 \\ y_2 \\ \vdots \\ y_n \\ \end{bmatrix} , \textbf{X}= \begin{bmatrix} 1 & x_{11} & \cdots & x_{1d} \\ 1 & x_{21} & \cdots & x_{2d} \\ \vdots & \vdots & & \vdots \\ 1 & x_{n1} & \cdots & x_{nd} \\ \end{bmatrix} , \mathbf{\beta}= \begin{bmatrix} \beta_0 \\ \beta_1 \\ \vdots \\ \beta_d \\ \end{bmatrix}$ + 將 $L(\beta)$ 對於 $\beta$ 的偏微分式子展開 $\begin{align*} \displaystyle \frac{\partial L}{\partial \beta}&=\frac{1}{n}\frac{\partial}{\partial \beta}(\left\| Y-\hat Y \right\|^2)\\ \displaystyle &=\frac{1}{n}\frac{\partial}{\partial \beta}(\left\| Y-X\beta\right\|^2)\\ \displaystyle &=\frac{1}{n}\frac{\partial}{\partial \beta}(Y-X\beta)^T(Y-X\beta)\\ \displaystyle &= \frac{1}{n}\frac{\partial}{\partial \beta}(Y^TY-Y^TX\beta-\beta^TX^TY+\beta^TX^TX\beta)\\ \displaystyle &= \frac{1}{n}(-(Y^TX)^T-X^TY+(X^TX+(X^TX)^T)\beta)\\ \displaystyle &= \frac{1}{n}(-X^TY-X^TY+2X^TX\beta)\\ \displaystyle &= \frac{1}{n}(2X^TX\beta-2X^TY)\\ \displaystyle &= \frac{2}{n}(X^TX\beta-X^TY)\\ \displaystyle &=\frac{2}{n}X^T(X\beta-Y)\\ \displaystyle &=\frac{2}{n}X^T(\hat{Y}-Y) \end{align*}$ + $\displaystyle \beta_0=\beta_0-\eta*\frac{\partial L}{\partial \beta_0},\beta_1=\beta_1-\eta*\frac{\partial L}{\partial \beta_1}$ 以係數向量的外觀表示$\displaystyle \beta=\beta-\eta*\frac{\partial L}{\partial \beta}=\beta-\eta*\frac{2}{n}X^T(\hat{Y}-Y)$ + 矩陣相關公式 - $(A+B)^T=A^T+B^T$ - $(AB)^T=B^TA^T$ + 矩陣偏微分相關公式[(1)](https://blog.csdn.net/crazy_scott/article/details/80557814)[(2)](https://www.mdnice.com/writing/e8944e0cca324a46b31f19a656c6ae7c) - $\frac{\partial X^T}{\partial X}=I$ - $\frac{\partial X^TA}{\partial X}=A$ - $\frac{\partial AX^T}{\partial X}=A$ - $\frac{\partial AX}{\partial X}=A^T$ - $\frac{\partial XA}{\partial X}=A^T$ - $\frac{\partial X^TAX}{\partial X}=(A+A^T)X$ ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt x=np.array([24.3, 19.5, 18.8, 20.1, 22.2, 29.8, 26.3, 28.3, 31.9, 26.9]) # 油價 y=np.array([7.9, 7.7, 7.6, 7.7, 7.7, 8.2, 7.8, 7.9, 8.1, 8.1]) # 民眾搭捷運平均里程 plt.scatter(x, y) # 以 plt.scatter 產生散點圖 # 將x轉換為向量X,參考網站 [12] ~ # 先產生一個(10x1),全都是1的陣列x0 ~ # 將x reshape為(10x1) 的陣列x1 ~ # 將x0,x1合併成向量X lr=0.001 np.random.seed(50) ~ # 隨機初始化向量b,參考網站 [13] # Gradient Descent for i in range(100000): ~ # 計算y_hat,參考網站 (6)[14] ~ # 計算gradients(梯度),參考網站 (34)[16] ~ # 更新向量b,參考網站 (35)[18] print(b) plt.plot(x, b[0]+b[1]*x, 'r') # 以 plt.plot(紅色線條) 畫出函數 y=b0+b1*x ``` :::info EX_01_5:Scikit-learn(SKlearn) 內建一些真實世界的數據,以線性迴歸預測加州房價。[(特徵說明)](https://inria.github.io/scikit-learn-mooc/python_scripts/datasets_california_housing.html) ::: ``` javascript= import matplotlib.pyplot as plt from sklearn.datasets import fetch_california_housing from sklearn.linear_model import LinearRegression from sklearn.model_selection import train_test_split from sklearn.metrics import mean_squared_error #1. 讀入加州房價資料 housing = fetch_california_housing() # 了解加州房價資料資料庫 # housing.feature_names # 資料庫中所有的欄位名稱(features) # print(housing.DESCR) # 解釋資料庫內容 # housing.data.shape # 幾列、幾欄 # len(housing.data) # 筆數 # housing.data # 內容(8個屬性) # housing.target # 房價 #2. 切分訓練與測試資料(x指資料,y指答案) x_train, x_test, y_train, y_test = train_test_split(housing.data, housing.target, test_size=0.2, random_state=50) # random_state為隨機種子,確保每次切分資料的結果都相同。 # x_train.shape # x_test.shape #3. 用線性迴歸做預測 ~ # 初始化線性迴歸模組 ~ # 讓線性迴歸模組學習,模組的變數名稱.fit(輸入資料,正確答案) ~ # y_test_predict=模組的變數名稱.predict(要預測的資料),y_test_predict為線性迴歸模組預測的結果 # 以評估指標MSE(mean squared error均方誤差),評估模型的誤差。MSE越接近0越好。 score=mean_squared_error(y_test,y_test_predict) print("MSE:",score) # MSE: 0.5124 #4. 畫出真實價格與預測價格 plt.scatter(y_test, y_test_predict, s=0.5) # s->size plt.xlabel('True Price') plt.ylabel('Predicted Price') plt.plot([0,5],[0,5],'r') # 畫(0,0)(5,5)連成的直線。如果預測正確,點會落在對角線上 ``` + [Python enumerate() 函数 | 菜鸟教程](https://www.runoob.com/python/python-func-enumerate.html) + [視覺化資料 - Matplotlib - legend、subplot、GridSpec、annotate](https://ithelp.ithome.com.tw/articles/10201670) + [matplotlib subplot 子圖繪製](https://www.itread01.com/content/1541685249.html) ``` javascript= #5. 畫出個別屬性和房價關係 plt.figure(figsize=(10,5)) # 單位為英吋 for i, feature in enumerate(housing.feature_names): plt.subplot(2, 4, i+1) # 使用子圖,2列,4欄,第幾張圖 plt.scatter(housing.data[:,i], housing.target, s=0.1) # s->size plt.xlabel(feature) plt.ylabel('price') plt.tight_layout() # 自動調整繪圖區的大小及間距,使繪圖區、標題、坐標軸標籤等都可完整顯示(不會重疊) ``` :::info (進階) EX_01_6:特徵關聯分析。 + 嘗試不使用全部的特徵(8個)來訓練模型,觀察 MSE 的變化。考驗你的觀察、預測能力,看能不能使用更少的特徵,讓 MSE 小於0.5124。 ::: ``` javascript= x_train_partial=x_train[:,[0,1,6]] # 使用第0,1,6個特徵 x_test_partial=x_test[:,[0,1,6]] ``` + Hint:以相關係數來看,應該選擇? - 計算相關係數的方法預設為pearson(皮爾森相關係數),為兩個特徵的共變異數與標準差乘積的關係。 - 皮爾森相關係數的值介於 -1 ~ 1,0 表示兩個特徵沒相關,越接近 1 表示正相關越強,越接近 -1 表示負相關越強,所以絕對值越大表示相關性越大。皮爾森相關係數適用於線性分布且常態分布的特徵值。 ``` javascript= import pandas as pd import seaborn as sns dfHousing=pd.DataFrame(housing.data, columns=housing.feature_names) # columns 指定欄標籤名稱 dfHousing['MEDV']=housing.target # dfHousing.head() 印出前5項來看看 corr_matrix=dfHousing.corr().round(2) plt.figure(figsize=(12, 10)) sns.heatmap(corr_matrix, annot=True) # annot 為 True 會將數值寫入每個儲存格裏 ``` <font color="#fff">[0,1,2,3,6,7]->0.5121</font> ### 2. [KNN(K Nearest Neighbor,K 最近鄰居法)](https://scikit-learn.org/stable/modules/generated/sklearn.neighbors.KNeighborsClassifier.html) (PPT) + <font color=red>分類,監督式學習</font> + <font color="red">體驗</font>:[K-Nearest Neighbors Demo](http://vision.stanford.edu/teaching/cs231n-demos/knn/) + [KNN 演算法](https://ithelp.ithome.com.tw/articles/10269826) 1. 決定 K 值。 2. 求每個鄰居跟自己之間的距離。 3. 找出跟自己最近的 K 個鄰居,鄰居多數是哪一類自己就是哪一類。 + [沒有想像中簡單的簡單分類機 KNN](https://www.slideshare.net/ssuserf88631/knn-51511604) + [KD-Tree 演算法筆記](https://blog.yucheng.me/post/kd-tree/) + [機器學習中的幾種距離度量方法比較](https://www.itread01.com/content/1545370955.html) - 標準化歐氏距離 (Standardized Euclidean Distance) * Normalization:經過 Normalization 之後,資料的範圍會介在 0~1 之間,原本的最大值變為 1,最小值變為 0。 $X_{nom} = \frac{X-X_{min}}{X_{max}-X_{min}} \in [0,1]$ * Standardization:經過 Z分數標準化後,資料會符合標準常態分佈(Standard Normal Distribution),轉換後的平均值=0、標準差=1。 $Z=\frac{X-\mu}{\sigma} \sim N(0,1)$ $\mu:平均數,\sigma:標準差\sqrt \frac{\sum(X-\mu)^2}{n}$ * [【資料科學】 - 資料的正規化與標準化](https://aifreeblog.herokuapp.com/posts/54/data_science_203/) * [[資料分析&機器學習] 第2.4講:資料前處理(Missing data, One-hot encoding, Feature Scaling)](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC2-4%E8%AC%9B-%E8%B3%87%E6%96%99%E5%89%8D%E8%99%95%E7%90%86-missing-data-one-hot-encoding-feature-scaling-3b70a7839b4a):One-hot 編碼可消除數值的大小關係。 - (進階) [馬氏距離(Mahalanobis Distance)](http://mccormickml.com/2014/07/22/mahalanobis-distance/) * [標準差、變異數、期望值](https://www.learnmode.net/flip/video/7226) * [相關係數與共變異數(Correlation Coefficient and Covariance)](https://chih-sheng-huang821.medium.com/%E7%9B%B8%E9%97%9C%E4%BF%82%E6%95%B8%E8%88%87%E5%85%B1%E8%AE%8A%E7%95%B0%E6%95%B8-correlation-coefficient-and-covariance-c9324c5cf679) :::info EX_02_1:完成 [KNN學習單](https://drive.google.com/file/d/1PIiHIqWXHskAUh68j8L16021uCS3HOjF/view?usp=sharing),練習 KNN 分類原理。 ::: :::info EX_02_2:使用 Scikit-learn(SKlearn) 實作 KNN ,將[鳶尾花卉 Iris 資料集](https://zh.wikipedia.org/wiki/%E5%AE%89%E5%BE%B7%E6%A3%AE%E9%B8%A2%E5%B0%BE%E8%8A%B1%E5%8D%89%E6%95%B0%E6%8D%AE%E9%9B%86)(欄位說明[(1)](https://blog.yeshuanova.com/2018/10/dataset-iris/)[(2)](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC2-1%E8%AC%9B-%E5%A6%82%E4%BD%95%E7%8D%B2%E5%8F%96%E8%B3%87%E6%96%99-sklearn%E5%85%A7%E5%BB%BA%E8%B3%87%E6%96%99%E9%9B%86-baa8f027ed7b))分類並預測。 ::: + [淺談機器學習的效能衡量指標 (1) -- 準確率(Accuracy)、精確率(Precision)、召回率(Recall)](https://ithelp.ithome.com.tw/articles/10228941) ``` javascript= from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score #1. 讀入鳶尾花資料 iris = load_iris() # 了解鳶尾花資料庫 # iris.feature_names # 資料庫中所有的欄位名稱(features) # print(iris.DESCR) # 解釋資料庫內容 # iris.data.shape # 幾列、幾欄 # len(iris.data) # 筆數 # iris.data # 內容 # iris.target # 內容 #2. 切分訓練與測試資料 ~ # x_train.shape #3. 初始化 knn 分類模組 knnModel = KNeighborsClassifier() # 預設 K 值為5 ~ # 讓KNN模組學習,模組的變數名稱.fit(輸入資料,正確答案) #4. 預測 ~ # y_test_predict=模組的變數名稱.predict(要預測的資料),y_test_predict為KNN模組預測的結果 print(y_test_predict) # 預測的分類 print(y_test) # 標準答案的分類 print(accuracy_score(y_test, y_test_predict)) # 正確率 0.9 ``` :::info EX_02_3:使用 KNN 遇到的最大問題和 K-Means 類似,即如何確定 K 值? 請探討 EX_02_2 使用不同 K 值,對預測正確率的影響。(將 K 最大值調為資料集樣本數) + K 值過小會降低分類的精確度。K 值越大,對於異常值越不敏感,但也會使類別之間的界限變得模糊。 + [Machine Learning-交叉驗證(Cross Validation)-找到KNN中適合的K值-Scikit Learn一步一步實作教學 | by Chwang | Medium](https://chwang12341.medium.com/machine-learning-%E4%BA%A4%E5%8F%89%E9%A9%97%E8%AD%89-cross-validation-%E6%89%BE%E5%88%B0knn%E4%B8%AD%E9%81%A9%E5%90%88%E7%9A%84k%E5%80%BC-scikit-learn%E4%B8%80%E6%AD%A5%E4%B8%80%E6%AD%A5%E5%AF%A6%E4%BD%9C%E6%95%99%E5%AD%B8-4109bf470340) ::: + [numpy.arange](https://numpy.org/doc/stable/reference/generated/numpy.arange.html) ``` javascript= # 預設的 k 值,但以交叉驗証計算準確率 # 以避免上例留出法(holdout cross validation)的缺點: # 如果只做一次劃分,不同的劃分方式,可能會有不同的準確率。 from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import cross_val_score iris = load_iris() x = iris.data y = iris.target knnModel = KNeighborsClassifier() # 預設 K 值為5 # 做交叉驗証計算準確率 accuracy = cross_val_score(knnModel, x, y, cv=10, scoring='accuracy') # cv:將資料分成幾組。 print(accuracy) print(accuracy.mean()) # 從 accuracy 中,可看到不同組的準確度差很大。如果EX_02_2的程式取到第一組的狀況,還會誤以為 K 值選對了。 ``` ``` javascript= # 對每一個 k 做實驗 import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier from sklearn.model_selection import cross_val_score iris = load_iris() x = iris.data y = iris.target k_range = range(1,31) accuracies = [] for ~ # 對每一個 k 做實驗 ~ # 初始化 knn 分類模組,n_neighbors = ?為參數 ~ # 使用交叉驗証計算準確率 ~ # 將每次的準確率平均加入 accuracies 串列 print('K值: ' + str(k) + ' Accuracy: ' + str(accuracy.mean())) print('最佳 K 值: ' , accuracies.index(max(accuracies))+1) plt.plot(k_range, accuracies) plt.xlabel('Value of K for KNN') plt.ylabel('Cross-Validated Accuracy') ``` + [GridSearchCV 函數](https://ithelp.ithome.com.tw/articles/10234203) ``` javascript= # 使用 GridSearchCV 函數自動找出最佳參數組合(GridSearchCV會自動作Cross Validation) from sklearn.model_selection import GridSearchCV from sklearn.datasets import load_iris from sklearn.neighbors import KNeighborsClassifier iris = load_iris() x = iris.data y = iris.target parameter={'n_neighbors':[1,3,5,7,9,11,13,15]} knnModel=KNeighborsClassifier() grid=GridSearchCV(estimator=knnModel,param_grid=parameter,cv=5) # cv 為交叉驗證參數,表示將資料分成 n 段, default 為 3 grid.fit(x,y) print(f'最佳的 K 值參數為:{grid.best_params_} ,準確率為:{grid.best_score_:.3f}') ``` + [numpy axis概念整理筆記](http://changtw-blog.logdown.com/posts/895468-python-numpy-axis-concept-organize-notes) + [關於Python 中 axis](https://itselementary993.wordpress.com/2017/05/26/%E9%97%9C%E6%96%BCpython-%E4%B8%AD-axis/) + ![](https://i.imgur.com/g7P4yqa.png =450x) :::info EX_02_4:將鳶尾花卉 Iris 資料集 sepal length (cm) normalization ,sepal width (cm) standardization。 ::: ``` javascript= import pandas as pd from sklearn.datasets import load_iris iris = load_iris() x = pd.DataFrame(iris['data'], columns=iris['feature_names']) y = pd.DataFrame(iris['target'], columns=['target_names']) data = pd.concat([x,y], axis=1) data.head() # normalization data['sepal length (cm)'] = (data['sepal length (cm)'] - data['sepal length (cm)'].min())/(~ - ~) data.head() # standardization data['sepal width (cm)'] = (data['sepal width (cm)'] - data['sepal width (cm)'].mean())/ ~ # std() 求標準差 data.head() ``` ``` javascript= # 可直接使用 SKlearn 的 MinMaxScaler、StandardScaler 模組 from sklearn.datasets import load_iris iris = load_iris() iris.data from sklearn.preprocessing import MinMaxScaler scaler = MinMaxScaler() iris_scaled = scaler.fit_transform(iris.data) iris_scaled from sklearn.preprocessing import StandardScaler scaler = StandardScaler() iris_scaled = scaler.fit_transform(iris.data) iris_scaled ``` :::info (進階) EX_02_5:Ball Tree 簡介報告。 + k-d tree 可以解決 brute force 效率不佳的問題,假設資料集樣本數為 n,特徵數為 d,當 n>>2^d,k-d tree 搜尋效果會比較好。例如 1000 個樣本且特徵數不超過 10 個(2^10=1024)的資料集。 + 一但特徵過多,k-d tree 的搜尋效率就會大幅下降,最終變得和暴力搜尋差不多。通常 k-d tree 適合不超過 20 維的資料集。 + 一個導致性能下降的最核心因素是因為 k-d tree 中被分割的子空間是一個個的超方體,計算距離使用歐式距離(Euclidean Distance),會形成超球體的判斷空間。超方體與超球體相交的可能性極高。如下圖所示,凡是相交的子空間,都需要進行檢查,大大的降低運行效率。 [![](https://i.imgur.com/Sg3bSGm.png =100x)](https://www.jianshu.com/p/2e6f3ca6e3e7) + ball tree 通過超球體劃分空間,劃分和搜尋超球體相交的機率會大大降低,能解決 k-d tree 高維效率不佳的問題。請搜尋 ball tree 相關文章,完成 ball tree 簡介報告(觀念、建樹演算法、搜尋演算法、為何可以解決 k-d tree的問題…,文後附上參考文獻)。 - [kNN里面的两种优化的数据结构:kd-tree和ball-tree,在算法实现原理上有什么区别?](https://www.zhihu.com/question/30957691) - [KNN的核心算法kd-tree和ball-tree](https://www.jianshu.com/p/2e6f3ca6e3e7) - [KNN算法常见问题总结](https://www.jianshu.com/p/da5e38fee345) - [Ball tree - Wikipedia](https://en.wikipedia.org/wiki/Ball_tree) - [Mohamad Dolatshah, Ali Hadian, Behrouz Minaei-Bidgoli, "Ball*-tree: Efficient spatial indexing for constrained nearest-neighbor search in metric spaces", ArXiv e-prints, Nov 2015.](https://arxiv.org/abs/1511.00628) - 其它(請自行搜尋) ::: ### 3. Decision Trees(決策樹) + <font color=red>分類,監督式學習</font> + <font color="red">體驗</font>:[R2D3 - A Decision Tree](http://www.r2d3.us/%E5%9B%BE%E8%A7%A3%E6%9C%BA%E5%99%A8%E5%AD%A6%E4%B9%A0/) + [決策樹直覺且執行效率好,適用於 classification 及 regression 資料類型的預測。](https://ithelp.ithome.com.tw/articles/10276079) - 吉尼係數表示模型的不純度(亂度)。基尼係數越高越不純,越低越純。 - 假設集合 S 包含 n 個類別,吉尼係數$\displaystyle Gini(S)=1-\sum_{j=1}^{n}p_j^2$。 $p_j$ 為在 S 中的值,屬於類別 j 的機率。 - 若利用屬性 A 分割集合 S 為 S~1~ 與 S~2~,則 $\displaystyle Gini_A(S)=\frac{|S_1|}{S}Gini(S_1)+\frac{|S_2|}{S}Gini(S_2)$ - 挑選吉尼不純度 $Gini_A(S)$ 最小的屬性為分割的屬性。 :::info EX_03_1:完成[Decision_Tree學習單](https://drive.google.com/file/d/19Y6cpKMhNJcH4ncOCbBTa8-wLwJ4CTyq/view?usp=sharing),練習如何挑選每個節點分類的屬性。 ::: :::info EX_03_2:以[EX_03_1學習單的資料](https://drive.google.com/file/d/1K7JBIwb8YsQTCGYe3lEnCqtsnUT2nLVG/view?usp=sharing)實作決策樹,比對計算結果和程式實作是否相同。 (1) 上傳檔案至Colab:Colab 左側 -> 檔案 ->上傳至工作階段儲存空間。 (2) 使用自己的雲端硬碟檔案:Colab 左側 -> 檔案 -> 掛接雲端硬碟。(登入Google帳號後,將授權金鑰貼過來) 檔案路徑:'drive/My Drive/檔案名' ::: + [pandas.factorize](https://pandas.pydata.org/pandas-docs/stable/reference/api/pandas.factorize.html) ``` javascript= import pandas as pd import pydotplus from IPython.display import Image from sklearn import tree #1. 將csv檔讀入pandas的DataFrame df = pd.read_csv('Decision_Tree_data.csv') # 先將檔案上傳至 Colab # df = pd.read_csv('drive/My Drive/Decision_Tree_data.csv') # 先將檔案上傳至自己的雲端硬碟 # print(df) #2. factorize函數將Series中的字串,映射為一組數字;相同的字串映射為相同的數字 df['age'],_ = pd.factorize(df['age']) df['income'],_ = pd.factorize(df['income']) df['student'],_ = pd.factorize(df['student']) df['buy_computer'],uniques = pd.factorize(df['buy_computer']) # uniques->the unique value in an array # print(df) # print(uniques) """ 亦可使用 SKlearn 的 LabelEncoder 模組 from sklearn.preprocessing import LabelEncoder le = LabelEncoder() df['age'] = le.fit_transform(df['age']) le.classes_ # 查詢轉換後數值代表的特徵值 """ #3. 訓練資料及分類答案 x_train=df[['age','income','student']] y_train=df[['buy_computer']] # print(x_train) # print(y_train) #4. 建立決策樹分類模組 dtreeModel = tree.DecisionTreeClassifier() dtreeModel.fit(x_train, y_train) #5. 畫出決策樹 feature_names = x_train.columns dot_data = tree.export_graphviz(dtreeModel, out_file=None, feature_names=feature_names, class_names=uniques, filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data) Image(graph.create_png()) ``` :::info EX_03_3:使用 Scikit-learn(SKlearn) 實作決策樹,將[鳶尾花卉 Iris 資料集](https://zh.wikipedia.org/wiki/%E5%AE%89%E5%BE%B7%E6%A3%AE%E9%B8%A2%E5%B0%BE%E8%8A%B1%E5%8D%89%E6%95%B0%E6%8D%AE%E9%9B%86)(欄位說明[(1)](https://blog.yeshuanova.com/2018/10/dataset-iris/)[(2)](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC2-1%E8%AC%9B-%E5%A6%82%E4%BD%95%E7%8D%B2%E5%8F%96%E8%B3%87%E6%96%99-sklearn%E5%85%A7%E5%BB%BA%E8%B3%87%E6%96%99%E9%9B%86-baa8f027ed7b))分類並預測。 ::: ``` javascript= from sklearn.datasets import load_iris from sklearn import tree from sklearn.model_selection import train_test_split from sklearn.metrics import accuracy_score #1. 讀入鳶尾花資料 ~ # print(iris.data) 150個樣本,每個樣本4個特徵 # print(iris.target) #2. 切分訓練與測試資料 ~ #3. 建立決策樹分類模組 ~ ~ #4. 預測 ~ # 預測 x_test 資料 print(y_test_predict) # 預測的分類 print(y_test) # 標準答案的分類 print(accuracy_score(y_test, y_test_predict)) # 正確率 ``` ``` javascript= import pydotplus from IPython.display import Image #5. 畫出決策樹 dot_data = tree.export_graphviz(dtreeModel, out_file=None, feature_names=iris.feature_names, class_names=iris.target_names, filled=True, rounded=True, special_characters=True) graph = pydotplus.graph_from_dot_data(dot_data) Image(graph.create_png()) # gini屬性用於測量節點的不純度(亂度),如果一個節點包含的都是同一類,此節點gini=0 ``` ### 4. SVM(Support Vector Machine,支持向量機) + <font color=red>分類,監督式學習</font> + <font color="red">體驗</font>:[Dash-Support Vector Machine (SVM) Explorer](https://dash-gallery.plotly.host/dash-svm/) [(參數說明)](https://cloud.tencent.com/developer/article/1065624) + [白話文講解支持向量機(一) 線性SVM](https://notes.andywu.tw/2020/%E7%99%BD%E8%A9%B1%E6%96%87%E8%AC%9B%E8%A7%A3%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%A9%9F%E4%B8%80-%E7%B7%9A%E6%80%A7svm/) - $loss_1(\theta^Tx)=max(0,1-\theta^Tx))$ * 紅色點離決策線越近,損失會越大。 * 例如在 $\theta_0+\theta_1x_1+\theta_2x_2=1$ 以下的點,帶入方程式的值會 <1。值為 0.4(離決策線近) 損失為 0.6(大),值為 0.8(離決策線遠) 損失為 0.2(小)。 - $loss_0(\theta^Tx)=max(0,1+\theta^Tx))$ * 藍色點離決策線越近,損失會越大。 * 例如在 $\theta_0+\theta_1x_1+\theta_2x_2=-1$ 以上的點,帶入方程式的值會 >-1。值為 -0.4(離決策線近) 損失為 0.6(大),值為 -0.8(離決策線遠) 損失為 0.2(小)。 - 結合上兩個式子,損失函數為 $\displaystyle \min_{θ} \sum_{i=1}^{m} [ y^{(i)} * loss_1(θ^Tx^{(i)}) + (1-y^{(i)}) * loss_0(θ^Tx^{(i)}) ]$ * y為練資料的類別 (1或0),如果是類別 1,後面 (1-y) 會讓 $loss_0$ 沒作用,只計算 $loss_1$;反之如果是類別 0,前面 $loss_1$ 沒作用,只計算 $loss_0$。 * 為了處理離群值,加入正規化項,並以超參數 C,控制前半的分類損失和後半正規化項的比例。 + [白話文講解支持向量機(二) 非線性SVM](https://notes.andywu.tw/2020/%E7%99%BD%E8%A9%B1%E6%96%87%E8%AC%9B%E8%A7%A3%E6%94%AF%E6%8C%81%E5%90%91%E9%87%8F%E6%A9%9F%E4%BA%8C-%E9%9D%9E%E7%B7%9A%E6%80%A7svm/) + [(進階)Kernel 函數](https://medium.com/@chih.sheng.huang821/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-kernel-%E5%87%BD%E6%95%B8-47c94095171)的手法為在原始空間不好區分的資料(無法線性區分),可以用一個非線性的映射函數,將這些資料轉換到更高維度的空間,或許比較好區分(可線性區分)。 - [SVM with polynomial kernel visualization](https://www.youtube.com/watch?v=3liCbRZPrZA) :::info EX_04_1:線性SVM的損失函數為 $\displaystyle \min_{θ} C \sum_{i=1}^{m} [ y^{(i)} * loss_1(θ^Tx^{(i)}) + (1-y^{(i)}) * loss_0(θ^Tx^{(i)}) ] + \frac{1}{2} \sum_{j=1}^{n} θ_j^2$ 請下載 [ex4data.mat](https://drive.google.com/file/d/1K9Th2WgzLwYfrb6RCccLloPod6NjlScM/view?usp=sharing) 數據集,觀察誤差項懲罰系數 C 對決策邊界的影嚮(C越大,容錯率越低,越易過擬合)。 ::: - [numpy.ravel()和numpy.flatten()的區別](https://www.itread01.com/content/1541532855.html) ``` javascript= #1. 先畫出原始數據分佈,左上角的那個數據點為異常點。 import numpy as np import scipy.io as sio import matplotlib.pyplot as plt data = sio.loadmat('ex4data.mat') # print(data) X,y = data['X'],data['y'] def plot_data(): plt.scatter(X[:,0],X[:,1], c=y.flatten(), cmap='jet') # X[:,0] 表示所有列的第0欄,即所有點的x座標。 plt.xlabel('x1') plt.ylabel('y1') plot_data() ``` + [numpy.linspace](https://numpy.org/doc/stable/reference/generated/numpy.linspace.html) + [meshgrid(p.98)](https://github.com/yenlung/Python-3-Data-Analysis-Basics/blob/master/%E6%8A%95%E5%BD%B1%E7%89%87/%E6%89%8B%E6%8A%8A%E6%89%8B%E6%89%93%E9%96%8BPython%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90%E5%A4%A7%E9%96%80.pdf) + [Python3 zip() 函数](https://www.runoob.com/python3/python3-func-zip.html) + [numpy中np.c_和np.r_](https://blog.csdn.net/yj1556492839/article/details/79031693) + [資料視覺化之 contour ( matplotlib.pyplot ) 教學與用法](https://tree.rocks/python-matplotlib-plt-contour-or-contourf-tutorial-with-sklearn-e4497f76280) + [Hello Matplotlib!(2)](https://ithelp.ithome.com.tw/articles/10225391) ``` javascript= #2. 使用 Scikit-learn SVM,kernel=‘linear’,C=1 from sklearn.svm import SVC svcModel = SVC(C=1,kernel='linear') # 初始化 SVC 分類器,C 為誤差項懲罰系數,核函数選擇線性核 svcModel.fit(X,y.flatten()) # 導入數據讓分類模組學習 svcModel.score(X,y.flatten()) # 分類器準確率0.9803921568627451 # 繪製決策邊界 def plot_boundary(model): x_min,x_max= -0.5,4.5 y_min,y_max= 1.3,5 xx,yy = np.meshgrid(np.linspace(x_min,x_max,40), np.linspace(y_min,y_max,40)) # 以 meshgrid 產生格點,xx,yy的表示法請參考講義 # plt.scatter(xx.flatten(),yy.flatten()) # 畫出平面上的所有點(先試) z = model.predict(list(zip(xx.flatten(),yy.flatten()))) # 將xx,yy組成點。print(list(zip(xx.flatten(),yy.flatten()))) # 或z = model.predict(np.c_[xx.flatten(),yy.flatten()]) zz = z.reshape(xx.shape) # 將預測結果調整成xx的形狀,為等高線圖每個點的深度 plt.contourf(xx,yy,zz,alpha=0.3) plot_boundary(svcModel) plot_data() ``` ``` javascript= #3. C=25 ~ # 初始化 SVC 分類器,C 為誤差項懲罰系數(C=25),核函数選擇線性核 ~ # 導入數據讓分類模組學習 ~ # 分類器準確率為 1.0 (perfect) # 繪製決策邊界 plot_boundary(svcModel) plot_data() ``` ### 5. [K-Means Clustering(K-平均演算法)](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.KMeans.html)(PPT) + <font color=red>分群,非監督式學習</font> + <font color="red">體驗</font>:[Visualizing K-Means Clustering](https://www.youtube.com/watch?v=nXY6PxAaOk0) + [K-means 演算法](https://ithelp.ithome.com.tw/articles/10266672) 1. 初始化:指定 K 個分群,並隨機挑選 K 個資料點的值當作群組中心點。 2. 分配資料點:每個資料點與距離最近的中心點同群。 3. 計算平均值:重新計算每個分群的中心點。 重複步驟2、3,直到資料點不再變換群組為止。 + [K-means 怎麼選 K ?](https://blog.v123582.tw/2019/01/20/K-means-%E6%80%8E%E9%BA%BC%E9%81%B8-K/) + [Kmeans 分群演算法 與 Silhouette 輪廓分析](https://jimmy-huang.medium.com/kmeans%E5%88%86%E7%BE%A4%E6%BC%94%E7%AE%97%E6%B3%95-%E8%88%87-silhouette-%E8%BC%AA%E5%BB%93%E5%88%86%E6%9E%90-8be17e634589) - Silhouette Coefficient(輪廓係數)表示資料點和所屬群之間的相似度([-1, 1])。Silhouette 值接近1,表示資料點與所屬群之間有密切聯繫;反之則接近-1。 - $\displaystyle S=\frac{b-a}{max(a,b)}$,S 越大越好,代表分得越清楚。 - a 為點和同群之間點的平均距離(越小表示樣本在該群中越集中), b 為點和不同群之間點的平均距離(越大表示資料點越不屬於其它群)。 :::info EX_05_1:完成[K-Means學習單](https://drive.google.com/open?id=1B5ekbseevr4THHw4532EtltskNxTVlMf),練習K-Means分群原理。 ::: :::info EX_05_2:使用 Scikit-learn(SKlearn) 以 K-Means 實作非監督式學習分群,將平面上的數據分群,並探討 K 值該如何選取。 ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt from sklearn.cluster import KMeans from sklearn.datasets import make_blobs # 載入 scikit-learn 套件中的資料集模組,用來產生資料集 #1. 分群資料準備,隨機產生 5 群資料 points, label = make_blobs(n_samples=1500, centers=5, cluster_std=2, random_state=170) # make_blobs()隨機產生一群一群圓形的資料。cluster_std為群中資料點離群中央的距離標準差,值愈大資料愈分散。random_state為隨機種子。 # print(points) # print(label) # plt.scatter(points[:, 0], points[:, 1], c=label) # 先試試看畫出產生的點,依據不同群給予不同顏色 #2. 用 K-Means 做分群 kmeansModel = KMeans(n_clusters=5) # 初始化 KMeans 分群模組,n_clusters為要分成幾群,試其它數字 y_predict = kmeansModel.fit_predict(points) # 用 K-Means 分群 #3. 畫出分群結果(並列顯示) plt.figure(figsize=(10, 5)) plt.subplot(1,2,1) # 1列,2欄,第1個位子 plt.title('Original data') ~ # 以 plt.scatter 畫出原圖 ~ # Kmeans分類的結果畫在右側,# 1列,2欄,第2個位子 ~ # 標題為'KMeans' ~ # 畫出分群結果 c=y_predict # print(kmeansModel.cluster_centers_) # 標示各群的中心點 plt.scatter(kmeansModel.cluster_centers_[:, 0], kmeansModel.cluster_centers_[:, 1], s=200, c="r", marker='*') ``` + [Python 繪製折線圖 Plot Line Charts ](http://homepage.ntu.edu.tw/~weitingc/fortran_lecture/Lecture_P_2_1Dplot.slides.html) ``` javascript= from sklearn.metrics import silhouette_score #4. Silhouette Coefficient silhouette = [] for i in range(2,11): # 試分成2~10群 kmeansModel = KMeans(~指定分幾群).fit(~資料) # n_clusters=? 指定分幾群 silhouette.append(silhouette_score(points, ~分群結果)) # kmeansModel.labels_ 有為分群的結果,不用再設一個變數y_predict plt.plot(range(2,11), silhouette, "b-o") # "b-o" 為 style_code(顏色代碼、線條樣式代碼、符號樣式代碼) plt.xlabel("k") plt.ylabel("Silhouette score") ``` :::info EX_05_3:使用 Scikit-learn(SKlearn) 以 K-Means 實作非監督式學習分群,將[鳶尾花卉 Iris 資料集](https://zh.wikipedia.org/wiki/%E5%AE%89%E5%BE%B7%E6%A3%AE%E9%B8%A2%E5%B0%BE%E8%8A%B1%E5%8D%89%E6%95%B0%E6%8D%AE%E9%9B%86)(欄位說明[(1)](https://blog.yeshuanova.com/2018/10/dataset-iris/)[(2)](https://medium.com/jameslearningnote/%E8%B3%87%E6%96%99%E5%88%86%E6%9E%90-%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E7%AC%AC2-1%E8%AC%9B-%E5%A6%82%E4%BD%95%E7%8D%B2%E5%8F%96%E8%B3%87%E6%96%99-sklearn%E5%85%A7%E5%BB%BA%E8%B3%87%E6%96%99%E9%9B%86-baa8f027ed7b))分群。 ::: ``` javascript= import matplotlib.pyplot as plt from sklearn.datasets import load_iris from sklearn.cluster import KMeans iris = load_iris() x = iris.data[~, ~] # 為畫圖方便,簡化只取花瓣(Petal)的長度、寬度來預測 plt.scatter(x[~], x[~]) # 花瓣的長為 x 軸,寬為 y 軸。plt.scatter(x[~], x[~], c=iris.target) plt.xlabel('petal length') plt.ylabel('petal width') ``` | ![](https://i.imgur.com/GACyPuN.png) | ![](https://i.imgur.com/5QZxJqQ.png) | |--|--| ``` javascript= ~ # 初始化 KMeans 分群模組,n_clusters為要分成幾群,試試看其它數字 ~ # 用 K-Means分群 ~ # 畫出分群結果(plt.scatter) ~ # x軸 label ~ # y軸 label ``` ![](https://hackmd.io/_uploads/BkHtGrLkyx.png =30x) ``` javascript= # 改以『花萼』長、寬分群,且並列顯示兩張圖。 ``` ![](https://hackmd.io/_uploads/B1gEfHL11g.png) ``` javascript= # 使用『花萼+花瓣』分群,且並列顯示兩張圖(以花萼長、寬繪圖)(分群效果更好)。 ``` ![](https://hackmd.io/_uploads/ryKXzBLJ1l.png) ### 6. Density-Based Clustering(密度集群法) + <font color=red>分群,非監督式學習</font> + <font color="red">體驗</font>:[Visualizing DBSCAN Clustering](https://www.naftaliharris.com/blog/visualizing-dbscan-clustering/) + DBSCAN(Density-based spatial clustering of applications with noise) - 以資料的密度來分群,使用者不需要設定群組數。 - 能夠自動處理 noise。 - min_samples:最少樣本數。 - eps($ε$):半徑長度。 - Core Point (核心點):以該點為圓心,$ε$為半徑所圍繞出來的 範圍內有超過 min_samples 個點,則該點為核心點。 - Border Point (Non-Core Point、邊緣點):若該點被其它核心點所包含,但它 為圓心卻沒辦法包含超過 min_samples 個點,則該點即為邊緣點。 - Noise Point (Outlier、雜訊點):不屬於核心點,也不屬於邊界點。 + [DBSCAN 演算法](https://www.youtube.com/watch?v=RDZUdRSDOok) 1. 挑選一個尚未分群的資料點,如果該點是核心點,則給予一個新的群組標籤並進行步驟2,否則標為雜訊點(並重新挑選點)。 2. 拜訪此核心點的所有鄰居點(距離小於$ε$),如果該點尚未分群,則設為同群。 3. 如果鄰居點也是核心點,以該點為圓心重複步驟2,直到沒有其它核心點。 4. 將該群周圍的邊緣點加入該群(不再從邊緣點往外擴充)。 5. 重複步驟1~4,直到所有資料點均處理完畢。 + [不要再用K-means! 超實用分群法DBSCAN詳解. sklearn DBSCAN使用介紹](https://axk51013.medium.com/%E4%B8%8D%E8%A6%81%E5%86%8D%E7%94%A8k-means-%E8%B6%85%E5%AF%A6%E7%94%A8%E5%88%86%E7%BE%A4%E6%B3%95dbscan%E8%A9%B3%E8%A7%A3-a33fa287c0e) + [Data science and machine learning](http://yltang.net/tutorial/dsml/14/) :::info EX_06_1:K-Means 演算法會計算資料點的中心,沒有方向性,因此適合處理凸型群組, 對於分散、歪斜、或凹形群組的效果不佳,例如月形資料,群組中心會在凹形尖端。改用DBSCAN看看結果會如何。 ::: ``` javascript= import matplotlib.pyplot as plt from sklearn.datasets import make_moons # 載入 scikit-learn 套件中的資料集模組,用來產生資料集 from sklearn.cluster import KMeans # 產生半月形資料 x, y = make_moons(n_samples=200, noise=0.05, random_state=0) kmeansModel = KMeans(n_clusters=2) y_predict = kmeansModel.fit_predict(x) plt.scatter(x[:, 0], x[:, 1], c=y_predict) plt.scatter(kmeansModel.cluster_centers_[:, 0], kmeansModel.cluster_centers_[:, 1], s=200, c=['b', 'r'], marker='*',) # 標示各群的中心點 ``` ``` javascript= import matplotlib.pyplot as plt from sklearn.datasets import make_moons # 載入 scikit-learn 套件中的資料集模組,用來產生資料集 from sklearn.cluster import DBSCAN from sklearn.preprocessing import StandardScaler x, y = make_moons(n_samples=200, noise=0.05, random_state=0) # 執行 DBSCAN 演算法的資料需標準化,使用 StandardScaler 物件的 fit_transform()方法轉換,不用自己算 scaler = StandardScaler() X_scaled = scaler.fit_transform(x) dbscanModel = DBSCAN() # DBSCAN 使用預設參數(eps=0.5, min_samples=5)。試試 eps=0.3、eps=0.7 的分群結果。 y_predict = dbscanModel.fit_predict(X_scaled) plt.scatter(X_scaled[:, 0], X_scaled[:, 1], c=y_predict) ``` ### 7. Hierarchical Clustering(階層式分群法) + <font color=red>分群,非監督式學習</font> + [Clustering method 4. Hierarchical Clustering ](https://medium.com/ai-academy-taiwan/clustering-method-4-ed927a5b4377) + 階層式分群法通常分為兩種作法:聚合法 (agglomerative, bottom-up, 小群到大群) 與分裂法 (divisive, top-down, 大群到小群)兩種。 + [linkage: 各群間距離的計算方式(linkage criteria)](http://mirlab.org/jang/books/dcpr/dcHierClustering.asp?title=3-2%20Hierarchical%20Clustering%20(%B6%A5%BCh%A6%A1%A4%C0%B8s%AAk)&language=chinese): - [ward (預設值)](https://scikit-learn.org/stable/modules/generated/sklearn.cluster.AgglomerativeClustering.html): 在將兩群合併後,各點到合併後的群中心的距離平方和為兩群之距離。 - single: 不同群中最接近兩點間的距離為兩群之距離。 - complete: 不同群中最遠兩點間的距離作為兩群之距離。 - average: 不同群中各點與各點間之平均距離作為兩群之距離。 :::info EX_07_1:完成[階層式分群法學習單](https://drive.google.com/open?id=1_2rDD9NYEvA0Hvd0RIkPXR3nKeEgO5T-),練習聚合法(不同群距離計算方式)的分群原理。 ::: :::info EX_07_2:使用 Scikit-learn(SKlearn) 以聚合法 (agglomerative) 實作非監督式學習分群,將平面上的數據分成四群。 ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt from sklearn.datasets import make_blobs # 載入 scikit-learn 套件中的資料集模組,用來產生資料集 from sklearn.cluster import AgglomerativeClustering #1. 分群資料準備,隨機產生4群資料 points, label = make_blobs(n_samples=1500, centers=4, cluster_std=2, random_state=170) # make_blobs()隨機產生一群一群圓形的資料。cluster_std為群中資料點離群中央的距離標準差,值愈大資料愈分散(試試1~10)。random_state為隨機種子。 # plt.scatter(points[:, 0], points[:, 1], c=label) # 先試試看畫出產生的點,依據不同群給予不同顏色 #2. 以 Agglomerative Clustering 分群模組做分群 aggModel = AgglomerativeClustering(n_clusters=4) # 初始化 AgglomerativeClustering 分群模組 y_predict = aggModel.fit_predict(points) # 開始分群 #3. 畫出分群結果 plt.scatter(points[:, 0], points[:, 1], c=y_predict) ``` <br /> ## 四、深度學習(Deep Learning)之神經網路結構 + Teachable Machine 體驗 + <font color="red">體驗</font>:[有學習能力的電腦帶來的美好例駭人影響](https://www.ted.com/talks/jeremy_howard_the_wonderful_and_terrifying_implications_of_computers_that_can_learn/transcript?fb_ref=talk&language=zh-tw) + [【深度學習】如果電腦有神經,可以教它做什麼?](http://research.sinica.edu.tw/deep-learning-2017-ai-month/) + 應用:語音辨識、影像辨識、自然語言處理、天氣預測、醫療影像辨識、金融股市預測、網路異常入侵偵測、自駕車… ### 1. DNN(Deep Neural Network,深度神經網路) (1) 原理(PPT) + 模擬人類大腦神經元的刺激傳導機制,讓機器自己提取特微、試誤。 + 不管多麼複雜的函數,都可以用非線性函數組合出近似函數。[機器學習就是讓機器自動找出函數](https://www.youtube.com/watch?v=yXd2D5J0QDU#t=2m38s)。 + [Why "Deep", not "Fat"?](https://www.youtube.com/watch?v=yXd2D5J0QDU#t=9m18s) + 3Blue1Brown Neural networks:[①神經網路是什麼?](https://www.youtube.com/watch?v=aircAruvnKk) [②神經網路如何學習?梯度下降](https://www.youtube.com/watch?v=IHZwWFHWa-w) [③反向傳播](https://www.youtube.com/watch?v=Ilg3gGewQ5U)[(計算)](https://www.youtube.com/watch?v=tIeHLnjs5U8) (2) <font color="red">體驗&參數</font> + [Teachable Machine](https://teachablemachine.withgoogle.com/) - [Epochs(訓練次數)](https://medium.com/%E4%BA%BA%E5%B7%A5%E6%99%BA%E6%85%A7-%E5%80%92%E5%BA%95%E6%9C%89%E5%A4%9A%E6%99%BA%E6%85%A7/epoch-batch-size-iteration-learning-rate-b62bf6334c49):當一個完整的資料集,在神經網路正向傳播及反向傳播一次,稱為一個 epoch。 * 例如將 epochs 設為 50,則資料集會訓練 50 次。 - Batch Size:一次訓練的樣本數量,每處理完 batch size 的樣本數量後,將重新計算模型的損失值並調整模型的參數(權重和偏差)。 * 例如資料集有 80 個樣本, batch size 如果是 16,則處理完 16 個樣本後會調整模型參數;資料集會分成 80/16=5 批,當 5 批資料餵入模型訓練,即完全一個 epoch。 - [Learning Rate(學習率)](https://kknews.cc/zh-tw/code/936ylkj.html):學習率的大小決定優化演算法的優化步代。 * 若學習率過大,會使每次參數更新的步長過大,可能會躍過最佳值並且離底部愈來愈遠。 * 若學習率過小,優化的效率可能過低,經過長時間訓練仍無法找到最佳值。 * [Google Machine Learning Crash Course 的 Learning Rate 實驗](https://developers.google.com/machine-learning/crash-course/fitter/graph) * [高維的梯度下降無法可視化,以 loss 來判斷 learning rate 是否適當(p.5)](https://speech.ee.ntu.edu.tw/~tlkagk/courses/ML_2016/Lecture/Gradient%20Descent%20(v2).pdf)。 + [A Neural Network Playground](http://playground.tensorflow.org/) - [Tensorflow Playground 筆記](https://ithelp.ithome.com.tw/articles/10218185) - Ratio of training to test data:設定訓練資料與測試資料的比例。 - Regularization(正規化):用來止 [overfitting(過度擬合,訓練資料的loss小,測試資料的loss大)](https://developers.google.com/machine-learning/crash-course/overfitting/overfitting?hl=zh-tw)。 * [防止過度擬合的 8 種簡單技術](https://kknews.cc/zh-tw/code/kk2qno8.html) * L1 Regularization 會讓某些權重變成 0(也會保留大的權重)。 * [L2 Regularization 會讓權重接近 0(不會有太突出的權重)](https://developers.google.com/machine-learning/crash-course/overfitting/regularization?hl=zh-tw)。 * [(進階) Regularization 公式說明](https://www.youtube.com/watch?v=xki61j7z-30#t=57m43s):L1、L2正則化是透過修改損失函數來實現,在損失函數中加上對應的 L1 及 L2 penalty(懲罰項)。 :::info EX_08_1:[Neural Networks: Playground Exercises](http://playground.tensorflow.org/) 練習。 + 『分類問題/Circle』,[「互動式練習」說明](https://developers.google.com/machine-learning/crash-course/neural-networks/interactive-exercises?hl=zh-tw)。 + 完成『分類問題/Spiral』,將畫面截圖上傳。(最多 1000 次 Epoch) - 可嘗試增加其它特徵,增加或刪除隱藏層和神經元、更改學習率、正則化、批量大小…等參數,可以獲得的最佳測試損失是多少?模型輸出表面有多光滑? ::: (3) [Keras 模型、函數及參數使用說明](https://ithelp.ithome.com.tw/articles/10191725) + [Activation Function(激發函數)](https://codingnote.cc/zh-tw/p/176736/) - 提供非線性函數的轉換外(如果沒有激發函數,不管神經網路有多少層,都只能學習到線性方程式),也是一種門檻(Threshold)的過濾,讓神經元的參數能更快的收斂。 - [常用激發函數](https://en.wikipedia.org/wiki/Activation_function) * [ReLU(Rectifie Linear Units)](https://mropengate.blogspot.com/2017/02/deep-learning-role-of-activation.html):定義為 f(x)=max(0,x),將負數變為0會凸顯特徵。(好計算、等同無窮多 sigmoid 疊加,可以處理梯度消失) * Tanh(hyperbolic tangent) * sigmoid:反向傳播時,每經過一個 sigmoid 激發函數,都會衰減至少 0.25 倍([sigmoid微分後的上限為0.25](https://ithelp.ithome.com.tw/m/articles/10237661)),傳遞越多層,衰減越多。由於梯度消失的緣故,不會使用在隱藏層,會用在輸出層(輸出介於 0 到 1 之間)。 * [softmax](https://zhuanlan.zhihu.com/p/25723112):[輸出層激發函數(17:30)](https://www.youtube.com/watch?v=JR8bo75U3fc#t=17m30s) + [Loss Function(損失函數)](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8-%E6%B7%B1%E5%BA%A6%E5%AD%B8%E7%BF%92-%E5%9F%BA%E7%A4%8E%E4%BB%8B%E7%B4%B9-%E6%90%8D%E5%A4%B1%E5%87%BD%E6%95%B8-loss-function-2dcac5ebb6cb) - 用來計算模型預測值與預期輸出之間的差異程度,看離目標差多少。 - 迴歸問題常用 [MSE(Mean Squared Error,均方誤差,將誤差值取平方)或 MAE(Mean Absolute Error,平均絕對誤差,將誤差值取絕對值)](https://medium.com/@CinnamonAITaiwan/cnn%E6%A8%A1%E5%9E%8B-%E6%90%8D%E5%A4%B1%E5%87%BD%E6%95%B8-loss-function-647e13956c50)。 - 二元分類問題常用 [Binary Cross-Entropy](https://ithelp.ithome.com.tw/articles/10218158)。 - 多類別分類問題常用 [Categorical Cross-Entropy](https://blog.csdn.net/xg123321123/article/details/80781611)。 $\displaystyle loss=-\frac{1}{N}\sum_{i=1}^{N} y_{i1}log (\hat y_{i1}) + y_{i2}log (\hat y_{i2}) + \cdots +y_{im}log (\hat y_{im})$ + [Optimizer(優化器)](https://keras.io/zh/optimizers/) - [梯度下降](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E5%9F%BA%E7%A4%8E%E6%95%B8%E5%AD%B8-%E4%BA%8C-%E6%A2%AF%E5%BA%A6%E4%B8%8B%E9%99%8D%E6%B3%95-gradient-descent-406e1fd001f):根據每次輸出結果和實際結果的誤差,重新調整各個神經元的權重、偏差值,使 Loss Function(損失函數)的 Loss(損失值)最小的收斂過程。 - SGD * Batch Gradient Descent(BGD,批量梯度下降)是一次使用全部訓練資料計算損失函數的梯度,並更新一次權重,效率差。 * Stochastic Gradient Descent(SGD,隨機梯度下降法)是一次隨機抽取一個樣本,計算出一次梯度就更新一次。 * Mini-Batch SGD 是跑小批次(mini-batch)樣本後更新一次。 * BGD、SGD、Mini-Batch SGD 比較 * [SGD 缺點](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E5%9F%BA%E7%A4%8E%E6%95%B8%E5%AD%B8-%E4%B8%89-%E6%A2%AF%E5%BA%A6%E6%9C%80%E4%BD%B3%E8%A7%A3%E7%9B%B8%E9%97%9C%E7%AE%97%E6%B3%95-gradient-descent-optimization-algorithms-b61ed1478bd7) * [(進階) 不同 Batch Size 影響比較(p.18~29)](https://speech.ee.ntu.edu.tw/~hylee/ml/ml2021-course-data/small-gradient-v7.pdf) [(youtube解說)](https://www.youtube.com/watch?v=zzbr1h9sF54)。 - [Momentum(22:41)](https://www.youtube.com/watch?v=zzbr1h9sF54#t=22m41s) * 模擬物理動量的概念。參數更新方向前會考慮前一次參數更新的方向,如果當下梯度方向和歷史參數更新的方向一致,則會增強這個方向的梯度;若方向不一致,則梯度會衰退。 $v_{t+1}=\alpha v_t-\eta\frac{\partial L}{\partial W_t}$ $W_{t+1}=W_t+v_{t+1}$ * 可以[抑制震盪](https://iace.fun/2019/11/28/shen-du-xue-xi-zhi-you-hua-suan-fa/)加速收斂,並且有[擺脫局部最佳解](https://chih-sheng-huang821.medium.com/%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92-%E5%9F%BA%E7%A4%8E%E6%95%B8%E5%AD%B8-%E4%B8%89-%E6%A2%AF%E5%BA%A6%E6%9C%80%E4%BD%B3%E8%A7%A3%E7%9B%B8%E9%97%9C%E7%AE%97%E6%B3%95-gradient-descent-optimization-algorithms-b61ed1478bd7)的能力。 * [Interactive Visualization of Optimization Algorithms in Deep Learning](https://emiliendupont.github.io/2018/01/24/optimization-visualization/)(Momentum:藍) - (進階) [AdaGrad(9:22)](https://www.youtube.com/watch?v=HYUXEeh3kwY#t=9m22s) * 解決 SGD 中學習率不能調整的問題,將學習率除以歷史梯度平方和的平方根,使得更新每次參數時的學習率不同。 $\displaystyle w^{t+1}=w^t - \frac{\eta}{\sqrt{\sum_{i=0}^{t}(g^i)^2}}g^t$ * 隨著迭代的次數增加,學習率會逐漸變小,符合直觀上接近最優解時,函數的坡度會越平緩,也必須走的更慢來確保不會穿過最優解。 * 缺點為訓練中後期,分母上梯度平方的累加會越來越大,會導致學習率過早、過量的減少,使得訓練提前結束。 - (進階) [RMSProp(17:18)](https://www.youtube.com/watch?v=HYUXEeh3kwY#t=17m17s) * 和 AdaGrad 的差別為累積歷史梯度的方法不同。RMSProp 不像 AdaGrad 直接累加梯度平方,而是加了一個衰減係數來控制歷史梯度訊息要獲取多少。 * 改進 AdaGrad 學習率下降過快的問題。 * [Interactive Visualization of Optimization Algorithms in Deep Learning](https://emiliendupont.github.io/2018/01/24/optimization-visualization/)(RMSProp:紅) - (進階) Adam * 結合 RMSProp 和 Momentum 的優點,是目前最常使用的優化器。 * [Interactive Visualization of Optimization Algorithms in Deep Learning](https://emiliendupont.github.io/2018/01/24/optimization-visualization/)(Adam:綠) - (進階) [A Visual Explanation of Gradient Descent Methods (Momentum, AdaGrad, RMSProp, Adam)](https://towardsdatascience.com/a-visual-explanation-of-gradient-descent-methods-momentum-adagrad-rmsprop-adam-f898b102325c) + [Backpropagation(反向傳播)](https://speech.ee.ntu.edu.tw/~tlkagk/courses/ML_2017/Lecture/BP.mp4) - 反向傳播(誤差反向傳播),是一種與梯度下降法結合使用的方法。當神經網路的構造很複雜時,計算梯度的過程會有大量的重複計算,反向傳播藉由微積分的鏈鎖率(Chain Rule),從神經網路的末端開始計算誤差與各權重的關係,由後往前更新,藉此減少運算量。說明網站參考 [(1)](https://medium.com/ai-academy-taiwan/back-propagation-3946e8ed8c55)、[(2)](https://medium.com/%E4%BA%BA%E5%B7%A5%E6%99%BA%E6%85%A7-%E5%80%92%E5%BA%95%E6%9C%89%E5%A4%9A%E6%99%BA%E6%85%A7/%E5%8F%8D%E5%90%91%E5%82%B3%E6%92%AD%E7%AE%97%E6%B3%95-backpropagation-algorithm-71a1845100cf)、[(3)](https://www.cnblogs.com/charlotte77/p/5629865.html) - 神經網路圖示 ![](https://i.imgur.com/rcpoAyZ.png) * $w^2_{21}$:上標 2 表示第 2 層的權重。下標 2 表示後一層第 2 個神經元,下標 1 表示前一層第 1 個神經元。 * $z^1_1$:上標 1 表示第 1 層,下標 1 表示此層第 1 個神經元。$z^1_1$ 表示第 1 層 activation function 的輸入 ($z^1_1=x_1w_{11}^1+x_2w_{12}^1$)。 * $a_1^1$:上下標意義與 $z_1^1$ 相同,差別為$a_1^1$ 為 activation function 的輸出 ($a_1^1=\sigma(z_1^1)$)。 * 假設訓練資料只有一筆。 - $\displaystyle \quad \ \hat w_{11}^1=w_{11}^1-\eta \frac{\partial L}{\partial w_{11}^1}$ $\displaystyle \quad \frac{\partial L}{\partial w_{11}^1} =\frac{\partial L}{\partial z_{1}^1} \frac{\partial z_1^1}{\partial w_{11}^1} \ (根據\ Chain\ Rule)$ * 後一項為 Forward pass,對每個參數,計算$\frac{\partial z}{\partial w}$。 例如 $z^1_1=x_1w_{11}^1+x_2w_{12}^1$,$\frac{\partial z_1^1}{\partial w_{11}^1}=x_1$。 所以 Forward pass 會等於此參數的輸入。 * 前一項為 Backward pass,對每個激發函數的輸入z,計算$\frac{\partial L}{\partial z}$。需以 Chain Rule 不斷拆解。 $\begin{align*} \displaystyle \frac{\partial L}{\partial w_{11}^1} &=\underline{\frac{\partial L}{\partial z_{1}^1}} \frac{\partial z_1^1}{\partial w_{11}^1} \\ &=[\frac{\partial L}{\partial a_{1}^1} \frac{\partial a_1^1}{\partial z_{1}^1}] \frac{\partial z_1^1}{\partial w_{11}^1} \quad (\ \because a_1^1=\sigma(z_1^1) \ \therefore \frac{\partial a_1^1}{\partial z_{1}^1} 為 \sigma^\prime(z_{1}^1)\ )\\ &=[\frac{\partial L}{\partial a_{1}^1} \sigma^\prime(z_{1}^1)] \frac{\partial z_1^1}{\partial w_{11}^1} \\ &=[(\underline{\frac{\partial L}{\partial z_{1}^2}} \frac{\partial z_1^2}{\partial a_{1}^1} + \underline{\frac{\partial L}{\partial z_{2}^2}} \frac{\partial z_2^2}{\partial a_{1}^1}) \sigma^\prime(z_{1}^1)] \frac{\partial z_1^1}{\partial w_{11}^1}\\ &=[(\underline{\frac{\partial L}{\partial z_{1}^2}} w_{11}^2 + \underline{\frac{\partial L}{\partial z_{2}^2}} w_{21}^2) \sigma^\prime(z_{1}^1)] \frac{\partial z_1^1}{\partial w_{11}^1}\\ \end{align*}$ * 上式概念圖示 ![](https://i.imgur.com/BKTu2GA.png) * 如果紅色神經元已經是輸出層 ![](https://i.imgur.com/iMyucXA.png =450x) $\displaystyle \frac{\partial L}{\partial z_{1}^2}=\frac{\partial L}{\partial \hat y_1}\ \frac{\partial \hat y_1}{\partial z_{1}^2} = \frac{\partial L}{\partial \hat y_1}\ \sigma^\prime(z_{1}^2) \quad \quad \frac{\partial L}{\partial z_{2}^2}=\frac{\partial L}{\partial \hat y_2}\ \frac{\partial \hat y_2}{\partial z_{2}^2}$ * 如果紅色神經元不是輸出層(不斷往後展開$\frac{\partial L}{\partial z}$,直到遇到輸出層) ![](https://i.imgur.com/8DTvB3k.png) - Backpropagation - Backward Pass * 由輸出層往前,對每個激發函數的輸入z,計算$\frac{\partial L}{\partial z}$,即可節省計算量。 ![](https://i.imgur.com/zeNeGzS.png) - Backpropagation相關公式 * Chain Rule [(教學1)](http://ocw.nctu.edu.tw/course_detail-v.php?bgid=1&gid=1&nid=490&v5=xj8d1cAaJWA)([教學2)](http://aca.cust.edu.tw/online/calculusI/05/05_03_12.html) $① \quad u=g(x) \quad y=f(u)=f(g(x)) \\ \quad \quad \bigtriangleup x \rightarrow \bigtriangleup u \rightarrow \bigtriangleup y \quad \quad \frac{dy}{dx}=\frac{dy}{du}\frac{du}{dx}$ $② \quad x=g(t) \quad y=h(t) \quad z=f(x,y)$ $\quad \quad$![](https://i.imgur.com/XtN70kf.png =160x)$\quad \ \ \frac{dz}{dt}=\frac{\partial z}{\partial x}\frac{dx}{dt}+\frac{\partial z}{\partial y}\frac{dy}{dt}$ * [Sigmoid 函數($\frac{1}{1+e^{-x}}$)微分](https://blog.csdn.net/weixin_44331401/article/details/103081979) $\begin{align*} \sigma^\prime(x) &= \frac{d}{dx}(1+e^{-x})^{-1}\\ &=-(1+e^{-x})^{-2}(-e^{-x})\\ &=\frac{e^{-x}}{(1+e^{-x})^2}\\ &=\frac{1}{1+e^{-x}}\frac{e^{-x}}{1+e^{-x}}\\ &=\sigma(x)(1-\sigma(x))\end{align*}$ * 其它微分公式 [$\displaystyle \frac{d(f(x))^n}{dx}=n(f(x))^{n-1} \times f'(x)$](http://www.math.ncu.edu.tw/~yu/ecocal95/boards/lec12_c_95.pdf) [$\displaystyle \frac{d}{dx}e^{f(x)}=f'(x)e^{f(x)}$](https://socratic.org/questions/derivative-of-e-2x) <br/> :::info EX_08_2:建立神經網路程式。 Param 50240、4160、650為需要利用梯度下降來訓練的權重數量,完成 [DNN 學習單](https://docs.google.com/spreadsheets/d/1Bc3fuejyCHChblISU96On1HiT8U19uVP/edit?usp=sharing&ouid=118043800222804360069&rtpof=true&sd=true),練習參數數量是如何計算出來。 (每層的權重數量=上一層神經元數量×本層神經元數量+本層每個神經元有一個bias) ::: ``` javascript= # 以 Sequential Model API 建立標準神經網路 from tensorflow.keras.models import Sequential # Sequential Model(順序式模型)是一種簡單的模型,是將神經網路層線性堆疊的建模方式。單一輸入、單一輸出,按順序一層(Dense)一層的由上往下執行。 from tensorflow.keras.layers import Dense # Dense為全連階層 model = Sequential() # 建一個空的神經網路(sequential的model) model.add(Dense(units=64, activation='relu', input_shape=(784,))) # 增加第一層隱藏層,64個神經元,Activation Function 用relu,第一層需要定義輸入尺寸(input_shape) model.add(Dense(units=64, activation='relu')) # 第二隱藏層 model.add(Dense(units=10, activation='softmax')) # 輸出層有10個神經元,輸出總和為1,使用 softmax activation function,將結果分類 model.summary() ``` ``` javascript= # 以 Functional Model API(Advanced) 建立標準神經網路。 # 更複雜,但也更靈活,明確將一層的輸出連接到另一層的輸入,每個連接都要被指定。 from tensorflow.keras import Model from tensorflow.keras import layers # define the layers x_in = layers.Input(shape=(784,)) x = layers.Dense(64, activation='relu')(x_in) x = layers.Dense(64, activation='relu')(x) x_out = layers.Dense(10, activation='softmax')(x) # define the model model = Model(inputs=x_in, outputs=x_out) model.summary() ``` :::info EX_08_3:輸出層激發函數練習。 輸出層要使用 softmax 或 sigmoid 激發函數將輸出轉為可能的百分比(總和為1),完成 [softmax & sigmoid 學習單](https://drive.google.com/file/d/1qSgIr_doEkry8yL7-vRKutmQr2x2_Qd7/view?usp=sharing),練習計算過程。 ::: :::info EX_08_4:完成 [Cross Entropy 學習單](https://drive.google.com/file/d/10yI-V85WmXAiRr5RcJrPUX5a9ogbODJ6/view?usp=sharing),練習分類問題損失函數的計算過程。 + 如果輸出層用 softmax 激發函數輸出各分類機率,一般會用 categorical_crossentropy 作為損失函數。 + [tf.keras.losses.BinaryCrossentropy ](https://www.tensorflow.org/api_docs/python/tf/keras/losses/BinaryCrossentropy) + [tf.keras.losses.CategoricalCrossentropy ](https://www.tensorflow.org/api_docs/python/tf/keras/losses/CategoricalCrossentropy) ::: ``` javascript= # 以程式驗證計算是否正確 import tensorflow as tf import numpy as np y_true = np.array([1, 0, 1]) y_pred = np.array([0.7, 0.2, 0.6]) bce = tf.keras.losses.BinaryCrossentropy(from_logits=False) bce(y_true, y_pred).numpy() ``` ``` javascript= import tensorflow as tf import numpy as np y_true = np.array([[1,0,0],[0,1,0],[1,0,0],[0,0,1]]) y_pred = np.array([[0.7,0.1,0.2],[0.1,0.8,0.1],[0.9,0.1,0],[0.4,0.3,0.3]]) cce = tf.keras.losses.CategoricalCrossentropy() cce(y_true, y_pred).numpy() ``` :::info EX_08_5:完成[正向傳播(forward-propagation)和反向傳播(back-propagation)學習單](https://docs.google.com/spreadsheets/d/10su--e3odIWrMou0nFVQD-5N5ens7iBR/edit?usp=sharing&ouid=118043800222804360069&rtpof=true&sd=true),練習神經網路參數訓練過程。 ::: :::info EX_08_6:以標準神經網路做手寫數字辨識。 + [MNIST Demo](https://ufal.mff.cuni.cz/~straka/courses/npfl129/2223/demos/mnist_web.html) ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.datasets import mnist from tensorflow.keras.utils import to_categorical #1. 匯入 MNIST 手寫阿拉伯數字數據庫 (x_train, y_train), (x_test, y_test) = mnist.load_data() # 載入MNIST資料庫的訓練資料,並分為「訓練組」及「測試組」 ''' 看看載入的資料長什麼樣子 len(x_train) # 訓練資料有6萬筆 len(x_test) # 測試資料有1萬筆 x_train.shape # (60000, 28, 28) x_train[9999].shape # 28x28 x_train[9999] # 0白色,255黑色,灰階 plt.imshow(x_train[9999], cmap='Greys') # 顯示出圖檔 y_train[9999] # 正確答案 ''' #2. 輸入、輸出格式整理 x_train = x_train.reshape(60000, 784) # 輸入格式整理,將28*28的矩陣改成784*1的矩陣 x_test = x_test.reshape(10000, 784) y_test_ori=y_test # 保留原始 y_test 後面confusion_matrix 統計時會用到 y_train = to_categorical(y_train,10) # 輸出格式整理,One-hot encoding轉換。例如7->[0,0,0,0,0,0,0,1,0,0],即第7個值為 1 y_test = to_categorical(y_test,10) # y_train[9999] ``` + [tf.keras.Model](https://www.tensorflow.org/versions/r2.1/api_docs/python/tf/keras/Model#fit) + [np.argmax](https://www.cnblogs.com/zhouyang209117/p/6512302.html) ``` javascript= from tensorflow.keras.models import Sequential # Sequential Model(順序式模型)是一種簡單的模型,是將神經網路層線性堆疊的建模方式。單一輸入、單一輸出,按順序一層(Dense)一層的由上往下執行。 from tensorflow.keras.layers import Dense, Activation # Dense為全連階層 from tensorflow.keras.optimizers import SGD # 優化器的方法 #3. 建立神經網路模型(2層hidden layers,每層128個神經元) model = Sequential() # 建一個空的神經網路ze=100, epochs=5) # 一次訓練100筆(100筆調一次 model.add(Dense(units=128, activation='sigmoid', input_shape=(784,))) # 增加第一層隱藏層,128個神經元,,Activation Function 用sigmoid model.add(Dense(units=128, activation='sigmoid')) # 增加第二層隱藏層,Activation Function 用sigmoid model.add(Dense(units=10, activation='softmax')) # 有10個神經元,輸出總和為1,使用 softmax activation function,將結果分類 #4. 編譯:選擇優化器(optimizer),損失函數(loss function),learning rate,效能衡量指標(metrics)的類別 model.compile(optimizer=SGD(learning_rate=0.1), loss='mse', metrics=['accuracy']) # 損失函數mse為最小平方法,metrics=['accuracy']訓練過程可隨時知道正確率 model.summary() #5. 訓練神經網路(以GPU加速->執行階段/變更執行階段類型) model.fit(x_train, y_train, batch_size=100, epochs=5) # 一次訓練100筆(100筆調一次參數),epochs設定訓練5次。 # 每次訓練完會輸出訓練成果數據(loss、accuracy、val_loss、val_accuracy)。 #6. 模型評估,打分數 score = model.evaluate(x_test, y_test) print('測試資料的loss:',score[0]) print('測試資料的正確率:',score[1]) #7. 成果測試,指定一張圖 # model.predict(x_test) # model.predict(x_test)[101] # np.argmax(model.predict(x_test)[101]) y_test_predict = np.argmax(model.predict(x_test), axis=1) num=101 # 試試其它測資8、38、87、187、877、1062、1068 plt.imshow(x_test[num].reshape(28,28), cmap="Greys") print('神經網路判斷為', y_test_predict[num]) #8. 成果測試,改用interact_manual互動輸入 from ipywidgets import interact_manual def judge(測試編號): plt.imshow(x_test[測試編號].reshape(28,28), cmap="Greys") print('神經網路判斷為', y_test_predict[測試編號]) interact_manual(judge, 測試編號=(0,9999)) ``` + [confusion_matrix](https://blog.csdn.net/m0_38061927/article/details/77198990) + [pandas.DataFrame](https://oranwind.org/python-pandas-ji-chu-jiao-xue/) + [numpy.nonzero](https://codertw.com/%E7%A8%8B%E5%BC%8F%E8%AA%9E%E8%A8%80/366994/) ``` javascript= import numpy as np import pandas as pd from sklearn.metrics import confusion_matrix #9. 以confusion_matrix統計整體預測狀況 pd.DataFrame(confusion_matrix(y_test_ori,y_test_predict)) #10. 印出預測錯誤的圖片(前100張) false_index=np.nonzero(y_test_predict != y_test_ori)[0] # 預測錯誤的位置 false_img=x_test[false_index] # 預測錯誤的圖片 orig_label=y_test_ori[false_index] # 預測錯誤的原始y值 pred_label=y_test_predict[false_index] # 預測錯誤的預測值 col = 10 # 一列放10張圖(欄) row = len(false_index)//10 + 1 # 列數用計算的 plt.figure(figsize=(25,500)) # 指定每張圖的寬和高,單位為英吋 for (index,img) in enumerate(false_img): plt.subplot(row,col,index+1) # plt.subplot(總列,總欄,第幾張圖) plt.title("Pred:[" + str(pred_label[index])+ "] , Ans:["+ str(orig_label[index]) + "]" ) plt.axis("off") plt.imshow(img.reshape(28,28), cmap='Greys') if index==100: break ``` ``` javascript= #11. 以 Gradio 來展示 !pip install gradio ``` ``` javascript= import gradio as gr def recognize_digit(img): img = img.reshape(1,784) prediction = model.predict(img).flatten() #[[p1,p2...]]->[p1,p2...] labels = list('0123456789') return {labels[i]: float(prediction[i]) for i in range(10)} #return 字典 gr.Interface(fn=recognize_digit, inputs="sketchpad", outputs="label").launch() ``` ``` javascript= #12. 模型存檔 # 方法一:同時儲存架構與權重 from tensorflow.keras.models import load_model model.save('mymodel.h5') # 同時儲存架構與權重,檔案的類型為HDF5 # 模型載入 del model model.summary() # model 刪除所以未定義 model = load_model('mymodel.h5') model.summary() # 方法二:架構與權重分開存 from tensorflow.keras.models import model_from_json model_jason=model.to_json() # 將神經網路架構轉成json格式 open('mymodel_architecture.json','w').write(model_jason) # 存架構 model.save_weights('mymodel_weights.h5') # 存權重 # 模型載入 del model model.summary() # model 刪除所以未定義 import numpy as np from tensorflow.keras.models import Sequential from tensorflow.keras.models import model_from_json with open("mymodel_architecture.json", "r") as input_file: json_string = input_file.read() model = Sequential() model = model_from_json(json_string) model.load_weights("mymodel_weights.h5", by_name=False) model.summary() ``` :::info EX_08_7:以EX_08_6手寫辨識的程式為範例,改用 [Fashion-MNIST 數據庫](https://github.com/zalandoresearch/fashion-mnist/blob/master/README.zh-CN.md),練習建立模型的另一種語法(將所有的網路層放到一個 list 中,作為 Sequential 的參數),並嘗試調整超參數 (Hyperparamters),讓神經網路準確率提昇(0.89 ⭡)。 + Hyperparameters(超參數):相對於由機器在學習過程中自行調整的parameters(參數),超參數是機器學習中使用者自行調整的參數(例如學習速率、Batch Size、層數、神經元數目…)。 1. 改變神經網路結構 - 改變神經元的數目(128->64、256、512、1024),理論上越多神經元表示迴歸線的特徵數越多,預測應該越準確。 - 將隱藏層增加或減少(2層->3層、1層),理論上越多層表示有越多的迴歸線組合,預測應該越準確。多層訓練的時間會較久。 - 當訓練集loss下降,驗證集loss上升表示過擬合,可[加入 Dropout 層(每次 batch run 隨機丟棄某比例的神經元不予計算),減少過度擬合(1:10:29)](https://www.youtube.com/watch?v=xki61j7z-30#t=1h10m29s)。[<font color="#f77777">Demo</font>](https://colab.research.google.com/drive/1Hn2Q4TxrxNI1BJY4QjatX5MCasNP0TDZ?usp=sharing) ```javascript # 每個隱藏層後都可加入 dropout 層,看看測試資料的準確率是否會上升。 model.add(Dropout(0.3)) # 隨機丟棄 30% 的神經元 ``` 2. 編譯參數調整 - 損失函數由 mse 改為 [categorical_crossentropy](https://blog.csdn.net/dou3516/article/details/103364900)(分類問題常用)。 - 優化方式由 SGD 改為 adam(結合 RMSProp 和 Momentum 的優點)。準確率上升的速度會變快。 3. 更換activation function - activation 用 relu 取代 sigmoid。 - 需把輸入的資料做 normalization(標準化):每張數字圖片是784維,數字介於0~255,把每個數字壓縮到 [0,1] 間,公式為 (x - min) / (max - min),因為顏色範圍為 0~255,所以公式化簡為 x / 255。 ``` javascript x_train = x_train.astype('float32')/255 x_test = x_test.astype('float32')/255 ``` - 輸入做 normalization 也可避免輸入特徵因為不同單位,造成數值大的影響過大。 - 實驗在其它條件不變下,將神經網路加到 10 層,如果激發函數用 sigmoid,準確率會上升或下降?。 PS1. [Deep Learning with TensorFlow 2 and Keras](https://ithelp.ithome.com.tw/articles/10234059) 書中的建議。 PS2. [KerasTuner 超參數優化起手式](https://flag-editors.medium.com/kerastuner-%E8%B6%85%E5%8F%83%E6%95%B8%E5%84%AA%E5%8C%96%E8%B5%B7%E6%89%8B%E5%BC%8F-43c72cb5aa7a) ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.datasets import fashion_mnist from tensorflow.keras.utils import to_categorical from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Activation, Flatten, Dropout from tensorflow.keras.optimizers import SGD, Adam #1. 匯入 Fashion-MNIST 數據庫 (x_train, y_train),(x_test, y_test) = fashion_mnist.load_data() #2. 輸入、輸出格式整理 # 輸入格式整理,將28*28的矩陣改成784*1的矩陣 ~ # 多做normalization(標準化),讓數字壓縮到 [0,1] 間。 ~ # 輸出格式整理,One-hot encoding轉換。 ~ #3. 建立神經網路模型 ~ #4. 編譯:選擇優化器(optimizer)、損失函數(loss)、效能衡量指標(metrics)的類別 model.compile(optimizer='....', loss='....', metrics=['accuracy']) #5. 模型訓練(訓練資料切成兩份,分為訓練集(讀書)和驗證集(20%)(模擬考)) history = model.fit(x_train, y_train, batch_size=100, epochs=5, validation_split=0.2) #6. 模型評估,打分數 ~ # 對訓練過程的準確度繪圖 plt.plot(history.history['accuracy'], 'r') # red plt.plot(history.history['val_accuracy'], 'b') # blue # 對訓練過程的損失函數繪圖 plt.plot(history.history['loss'], 'y') # yellow plt.plot(history.history['val_loss'], 'c') # cyan ``` ``` javascript= #3. 以Sequential函式建立神經網路模型 model = Sequential([ Flatten(input_shape=(28, 28)), # 直接用flatten層,將28*28的矩陣改成784*1的矩陣。所以不需先將28*28的矩陣改成784*1的矩陣 Dense(128, activation='sigmoid'), Dense(259, activation='sigmoid'), Dropout(0.5), # 增加 Dropout 層 Dense(10, activation='softmax') ]) ``` ``` javascript= #7. 成果測試,隨機挑10張圖 y_test_predict = np.argmax(model.predict(x_test), axis=1) pick = np.random.randint(1,9999, 10) # 隨機選10個[1,999)間的數字 category = ["T-shirt/top(T恤)", "Trouser(褲子)", "Pullover(套衫)", "Dress(裙子)", "Coat(外套)", "Sandal(涼鞋)", "Shirt(汗衫)", "Sneaker(運動鞋)", "Bag(包)", "Ankle boot(踝靴)"] plt.figure(figsize=(10,5)) for i in range(10): plt.subplot(2,5,i+1) # 將圖像區域分為2列5欄,目前位置為i+1 plt.title(category[y_test_predict[pick[i]]]) # 印出預測的種類(英文) plt.imshow(x_test[pick[i]].reshape(28,28), cmap='Greys') plt.axis("off") ``` :::success (進階) 在 matplotlib 中顯示中文 1. 使用一個免費中文字型(如[台北黑體](https://sites.google.com/view/jtfoundry/))到 Colab。 ``` javascript # 下載台北黑體字型 !wget -O taipei_sans_tc_beta.ttf https://drive.google.com/uc?id=1eGAsTN1HBpJAkeVM57_C7ccp7hbgSz3_&export=download ``` 2. 把中文字型加入 matplotlib 字型家族。 ``` javascript import matplotlib import matplotlib.pyplot as plt # 新增字體 matplotlib.font_manager.fontManager.addfont('taipei_sans_tc_beta.ttf') # 設定中文字型及負號正確顯示 plt.rcParams['font.sans-serif'] = 'Taipei Sans TC Beta' plt.rcParams["axes.unicode_minus"] = False ``` 3. 查看 matplotlib 字型名稱,確定已安裝好。 ``` javascript [f.name for f in matplotlib.font_manager.fontManager.ttflist] ``` ::: ### 2. CNN(Convolutional Neural Network,卷積神經網路)(PPT) + 可以進行『特徵萃取』,是圖形辨識的天王。 - [用全連接神經網路來做影像處理,會需要太多的參數。CNN可簡化神經網路的架構。(討論1~3)](http://debussy.im.nuu.edu.tw/sjchen/AIIntro/NNDL_CNN.pdf) + <font color="red">體驗</font> - [Google AutoDraw](https://www.autodraw.com/) - [Quick, Draw! 限時塗鴉](https://quickdraw.withgoogle.com/) - [以圖搜尋](https://www.google.com.tw/imghp?hl=zh-TW&tab=ri&authuser=0&ogbl) - [APP - Object Detector and Classifier - TensorFlow](https://play.google.com/store/apps/details?id=hash.tf.objectdetection) - [Yolo:基於深度學習的物件偵測 (含YoloV3) ](https://mropengate.blogspot.com/2018/06/yolo-yolov3.html) - [圖形辨識的運用-機器手臂(18:00)](https://www.youtube.com/watch?v=UwsrzCVZAb8#t=18m00s) - [AI 輔助醫療鑑別診斷(21:41)](https://www.youtube.com/watch?v=t-P6bCXz-c4#t=29m41s) + 卷積層:擷取局部特徵 - 將濾波器(filter)在輸入圖片上滑動並進行矩陣內積,得到的圖片稱之為特徵圖(feature map)。 - [觀察不同濾波器對圖片卷積運算的結果](https://demo.leemeng.tw/)。 - Q1:filter是人決定還是神經網路自己學習? * [![](https://i.imgur.com/ErDoBt8.png =100x)](https://i.imgur.com/ErDoBt8.png) * 卷積層其實只是「不完全連接」的神經網路,神經元的運算方式同DNN。 - Q2:如果有多個卷積層,filter的數量是32→64→128,還是128→64→32、64→64→64會比較好? * [CNN前面幾層負責識別邊緣或線條等簡單的特徵,後面幾層負責識別更加具體的特徵](http://hk.noobyard.com/article/p-afdkrifz-sd.html) + 池化層:降低取樣 - <font color="red">體驗</font>:[2D Visualization of a Convolutional Neural Network](https://adamharley.com/nn_vis/cnn/2d.html) - 一個特徵相對於其它特徵的粗略位置才是重要的。[subsampling the pixels will not change the object (p.27)](https://speech.ee.ntu.edu.tw/~hylee/ml/ml2021-course-data/cnn_v4.pdf) - 池化層會把圖片變小,因此參數的數量和計算量也會下降,降低過擬合問題。 - 如果要偵測的物件很細微,池化層也會讓表現變差。隨著運算能力愈強,近年影像辨識的神經網路架構會不加池化層。 + Q:CNN在影像放大縮小或旋轉時,還能正確辨識嗎? - [CNN is not invariant to scaling and rotation (we need data augmentation) (p.35)](https://speech.ee.ntu.edu.tw/~hylee/ml/ml2021-course-data/cnn_v4.pdf) - [(進階) Spatial Transformer Layer](https://youtu.be/SoCywZ1hZak ) + Q:圖形辨識無敵?如何欺騙神經網路[(1)](https://www.techbang.com/posts/85040-openai-machine-vision-adversarial-typographic-attacka-clip) [(2)](https://finance.ettoday.net/news/1288118)? - [[李宏毅教授演講]今天的人工智慧 其實沒有你想的那麼厲害(5:21)](https://www.youtube.com/watch?v=YjfzJdimPDA#t=5m21s) - [(進階) Explainable AI / Adversarial Attack(李宏毅教授 ML 2021 Spring)](https://speech.ee.ntu.edu.tw/~hylee/ml/2021-spring.html) + (進階)[Residual Network](https://medium.com/%E8%BB%9F%E9%AB%94%E4%B9%8B%E5%BF%83/deep-learning-residual-leaning-%E8%AA%8D%E8%AD%98resnet%E8%88%87%E4%BB%96%E7%9A%84%E5%86%A0%E5%90%8D%E5%BE%8C%E7%B9%BC%E8%80%85resnext-resnest-6bedf9389ce):模型更深時,可以進行更加複雜的特徵模式的提取,理論上會有更好的結果,但是更深的網路有時反而帶來更差的效果。 - [Resnet 原理解說](https://www.youtube.com/watch?v=6Ru8RggInsU#t=1h20m28s) :::info EX_09:[ResNets 模型(2015年冠軍)](https://ithelp.ithome.com.tw/articles/10192162)可辨識 [1000種類別](https://gist.github.com/yrevar/942d3a0ac09ec9e5eb3a),自己找任意一張圖片,看看 CNN 辨識為? PS.[預先訓練好的模型 (Keras Applications)](https://ithelp.ithome.com.tw/m/articles/10236654) ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt from tensorflow.keras.applications import ResNet50 from tensorflow.keras.preprocessing.image import load_img, img_to_array from tensorflow.keras.applications.resnet50 import preprocess_input, decode_predictions model = ResNet50() # model.summary() img = load_img('dog.jpg', target_size=(224, 224)) # 載入影像,dog.jpg改為自己的檔名,大小調為224x224(內定) # img 印出圖片 x = img_to_array(img) # RBG: x.shape = (224, 224, 3) 灰階:(224, 224, 1) # x # x.shape # plt.imshow(x/255) x = x.reshape(1, 224, 224, 3) # keras 預設是處理批次圖片,所以將圖片的維度改為 x.shape = (1, 224, 224, 3) # x.shape x = preprocess_input(x) # 預處理,讓影像辨識度更高(每種模型不同,如明亮度、對比、色調調整…) # x # plt.imshow(x.reshape(224, 224, 3)/255) preds = model.predict(x) # 預測結果,1000維的向量 # preds print('預測結果:', decode_predictions(preds, top=3)[0]) ``` + [Gradio](https://gradio.app/) + [說明文件](https://gradio.app/docs/) ``` javascript= # 以 Gradio 來展示 !pip install gradio ``` ``` javascript= import gradio as gr from urllib.request import urlretrieve # 抓 ImageNet 1000種類別的標籤 urlretrieve("https://raw.githubusercontent.com/yenlung/Deep-Learning-Basics/master/data/imagnet-classes.txt", "imagnet-classes.txt") with open('imagnet-classes.txt') as f: labels = [line.strip() for line in f.readlines()] # strip()移除字串頭尾特定的字元(預設為為空格或換行) # labels def classify_image(img): img = img.reshape((-1, 224, 224, 3)) # -1由程式自己判斷 img = preprocess_input(img) preds = model.predict(img).flatten() return {labels[i]: float(preds[i]) for i in range(1000)} gr.Interface(fn=classify_image, inputs=gr.inputs.Image(shape=(224, 224)), outputs=gr.outputs.Label(num_top_classes=3)).launch() ``` :::info EX_10_1: CNN 結構認識。 (1) 完成 [CNN 學習單](https://drive.google.com/open?id=1wwPYfZg9ieH0P6NCiU_DtKCQD8sEXj7E),練習 CNN 卷積層、池化層的運作。 (2) 以下面程式建立簡易 CNN,練習參數數量是如何計算出來。 ::: ``` javascript= from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Activation, Flatten from tensorflow.keras.layers import Conv2D, MaxPooling2D model = Sequential() model.add(Conv2D(filters=32, kernel_size=(3,3), padding='same', input_shape=(28,28,4), activation='relu')) # 為了構建一個非常深的網路,使用填充可以在正向傳播的過程中讓特徵圖的大小保持不變,只使用池化層來縮小。否則就會使得輸入迅速的變小。 model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu')) # 第二層64個3x3filter。 model.add(MaxPooling2D(pool_size=(2,2))) model.add(Flatten()) # Flatten 層把多維的輸入一維化,常用在從卷積層到全連接層的過渡。 model.add(Dense(units=256, activation='relu')) # 隱藏層256個神經元 model.add(Dense(units=10, activation='softmax')) # 輸出層有10個神經元,輸出總和為1,使用 softmax activation function,將結果分類。 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) model.summary() ``` :::info EX_10_2:以 CNN 做手寫數字辨識。 ::: ``` javascript= import numpy as np import matplotlib.pyplot as plt import tensorflow as tf from tensorflow.keras.datasets import mnist from tensorflow.keras.utils import to_categorical #1. 匯入 MNIST 手寫阿拉伯數字數據庫 (x_train, y_train), (x_test, y_test) = tf.keras.datasets.mnist.load_data() # 載入MNIST資料庫的訓練資料,並分為「訓練組」及「測試組」 #2. 輸入、輸出格式整理 x_train = x_train.reshape(60000, 28, 28, 1) # 輸入格式整理,將28*28的矩陣改成28*28*1的矩陣(灰階只有一個矩陣,正常的圖有RGB三個矩陣) x_test = x_test.reshape(10000, 28, 28, 1) x_train = x_train.astype('float32')/255 # nomarlization x_test = x_test.astype('float32')/255 y_train = to_categorical(y_train,10) # 輸出格式整理,One-hot encoding轉換。例如7->[0,0,0,0,0,0,0,1,0,0],即第7個值為 1 y_test = to_categorical(y_test,10) ``` + [padding='same' (p.216) ](https://drive.google.com/file/d/1W56bpTuiiJlodAFSwjrf5bQJqJ1cPLEQ/view?fbclid=IwAR13z_93x1lmZhIqLzF0lvEqhZZcwoSpje0B39rLYcUQXeiUjKpMT6LRAuQ) ``` javascript= #3. 打造CNN神經網路(做3次convolution(filter大小3x3),每次都接max-pooling(2x2為一小區塊))。完成後會送入一個標準的神經網路(1個隱藏層,256個神經元) from tensorflow.keras.models import Sequential # Sequential Model(順序式模型)是一種簡單的模型,是將神經網路層線性堆疊的建模方式。單一輸入、單一輸出,按順序一層(Dense)一層的由上往下執行。 from tensorflow.keras.layers import Dense, Activation, Flatten # Dense為全連階層,Flatten為CNN完成後的結果為矩陣,要拉成向量再送進一般NN from tensorflow.keras.layers import Conv2D, MaxPooling2D model = Sequential() # 建一個空的神經網路(sequential的model) model.add(Input(shape=(28, 28, 1))) # Keras 不建議將 input_shape 直接傳遞給 Conv2D 或其他層,而應該使用 Input 層來指定輸入形狀。 model.add(Conv2D(filters=32, kernel_size=(3,3), padding='same', activation='relu')) # 第一層32個3x3filter。padding='same'輸出大小維持(藉由邊緣補零強化特徵圖邊緣的影響力), model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(filters=64, kernel_size=(3,3), padding='same', activation='relu')) # 第二層64個3x3filter。 model.add(MaxPooling2D(pool_size=(2,2))) model.add(Conv2D(filters=128, kernel_size=(3,3), padding='same', activation='relu')) # 第三層128個3x3filter。 model.add(MaxPooling2D(pool_size=(2,2))) model.add(Flatten()) # Flatten 層把多維的輸入一維化,常用在從卷積層到全連接層的過渡。 model.add(Dense(units=256, activation='relu')) # 隱藏層256個神經元 model.add(Dense(units=10, activation='softmax')) # 輸出層有10個神經元,輸出總和為1,使用 softmax activation function,將結果分類。 model.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # 優化方式使用 adam 可以更快收斂, 並提高準確率。損失函數分類問題常用 categorical crossentropy。 model.summary() #4. 訓練神經網路(以GPU加速->執行階段/變更執行階段類型) history = model.fit(x_train, y_train, batch_size=64, epochs=10, validation_split=0.2) # 一次訓練64筆(64筆調一次參數),epochs設定訓練10次。 #5. 模型評估,打分數 score = model.evaluate(x_test, y_test) print('測試資料的loss:',score[0]) print('測試資料的正確率:',score[1]) # 對訓練過程的準確度繪圖 plt.plot(history.history['accuracy'], 'r') # red plt.plot(history.history['val_accuracy'], 'b') # blue # 對訓練過程的損失函數繪圖 plt.plot(history.history['loss'], 'y') # yellow plt.plot(history.history['val_loss'], 'c') # cyan ``` ``` javascript= #6.成果測試,隨機挑10張圖 y_test_predict = np.argmax(model.predict(x_test), axis=1) pick = np.random.randint(1,9999, 10) # 隨機選10個[1,999)間的數字 for i in range(10): plt.subplot(2,5,i+1) # 將圖像區域分為2列5欄,目前位置為i+1 plt.title(y_test_predict[pick[i]]) plt.imshow(x_test[pick[i]].reshape(28,28), cmap='Greys') plt.axis("off") ``` :::info EX_10_3:以EX_10_2手寫辨識的程式為範例,改用 Cifar-10 [(1)](https://www.cs.toronto.edu/~kriz/cifar.html) 、[(2)](https://paperswithcode.com/sota/image-classification-on-cifar-10),並調整超參數(Hyperparamters),讓 CNN 準確率提昇(0.75 ⭡)。 + 程式碼先要修改的地方 - from tensorflow.keras.datasets import cifar10 - (x_train, y_train), (x_test, y_test) = tf.keras.datasets.cifar10.load_data() - x_train.shape 為 (50000, 32, 32, 3),即是正確輸入,不需像 MNIST 數據庫要 reshape - CNN 第一層輸入層 shape=(32, 32, 3) - 預測的結果為數字,請改成文字。 category = ["airplane","automobile","bird","cat","deer","dog","frog","horse","ship","truck"] - plt.title(y_test_predict[pick[i]]) 要改成? 因為之前圖沒有reshape,所以如果要看圖不用加reshape,plt.imshow(x_test[pick[i]]) <br /> 調整 CNN 結構(可參考[ CNN 模型設計](https://ithelp.ithome.com.tw/articles/10192028)) [![](https://i.imgur.com/LVgbc2l.png =300x)](https://i.imgur.com/LVgbc2l.png) + 將卷積層、池化層增加或減少(3層->2層、4層)。 + 將 filter(濾波器)增加或減少(32->16、64), + 將 kernel_size 增加或減少(3x3->5x5)。 - 較大的 kernel size 會使解析度降低、參數減少、準確度降低。 + 不一定要每個卷積層後都要加池化層。 + 將 pool_size 增加或減少(2x2->3x3)。 + 將 pooling function 改用平均。 - 一般而言,最大池化層保留更多的紋理資訊,而平均池化層保留更多的背景資訊。 ```javascript from tensorflow.keras.layers import AveragePooling2D model.add(AveragePooling2D(pool_size=(2, 2))) ``` + 調整最後的全聯結層的單元(256->512)。 + 在3層的卷積與池化後,加入 Dropout 層,減少過度擬合。 ```javascript model.add(Dropout(0.25)) ``` PS1. [[Keras] 使用 CNN 建立 Cifar-10 的分類器 (實戰篇)](https://clay-atlas.com/blog/2019/10/03/python-chinese-tutorial-keras-cnn-cifar10/) ::: :::info (進階)EX_10_4:利用 CNN 模型進行 Kaggle 「Dogs vs. Cats」分類 + 學習『[參考程式](https://colab.research.google.com/drive/1frZC2twBMUBlhjO90BbGed7GXAPV5Fyf?usp=sharing)』裏真實世界圖片的訓練過程。 + 學習如何以 Dropout、Data Augmentation、遷移學習解決 overfitting。 + [Batch Normalization](https://www.youtube.com/watch?v=BABPWOkSbLE):可以在較短的時間達到同樣的準確率。 - [Batch Normalization 介紹](https://medium.com/ching-i/batch-normalization-%E4%BB%8B%E7%B4%B9-135a24928f12) - [深度學習中 Batch Normalization](https://iter01.com/556333.html) - [什么是批标准化 (Batch Normalization) | 莫烦Python](https://mofanpy.com/tutorials/machine-learning/torch/intro-batch-normalization/) ::: ### 3. RNN(Recurrent Neural Network,循環神經網路)(PPT) + 有記憶的神經網路,能夠處理序列變化的輸入資料。例如某個單字的意思會因為前文內容的不同而有不同的含義。可應用在對話機器人、翻譯、生成文章、完成半成品圖、video captioning。 + <font color="red">體驗</font>:[少女詩人小冰](https://poem.xiaoice.com/) + [十分鐘了解RNN的基本概念](https://www.youtube.com/watch?v=6AW80qmaAOk) ![](https://i.imgur.com/DzQy6Gj.png =345x) ![](https://i.imgur.com/2pzsvKC.png =330x) + RNN 的問題 - 長序列訓練過程中會有[梯度消失或梯度爆炸](https://www.youtube.com/watch?v=rTqmWlnwz_0#t=13m53s)的問題。 - RNN 會忘掉很早之前看過的訊息。 - RNN 的變形 LSTM (Long Short Term Memory) 與 GRU (Gated Recurrent Units)。 - Bidirectional LSTM:當有一個句子,一般的 LSTM 只會從前面掃過去,但 Bidirectional LSTM 除了從前面掃過去,也會從後面掃過來,類似從後文回推前文。與一般的 LSTM 相比 Bidirectional LSTM 在一些語音辨識、NLP 應用上有更好的效果。 + [LSTM](https://medium.com/@tengyuanchang/%E6%B7%BA%E8%AB%87%E9%81%9E%E6%AD%B8%E7%A5%9E%E7%B6%93%E7%B6%B2%E8%B7%AF-rnn-%E8%88%87%E9%95%B7%E7%9F%AD%E6%9C%9F%E8%A8%98%E6%86%B6%E6%A8%A1%E5%9E%8B-lstm-300cbe5efcc3) - [台大資訊 深度學習之應用 | ADL 4: Gating Mechanism 帶你了解LSTM與GRU的細節](https://www.youtube.com/watch?v=9gW__8-NfU8) - [LSTM和GRU很難?別擔心,這有一份超生動的圖解](https://kknews.cc/code/vegon84.html) - [如何从RNN起步,一步一步通俗理解LSTM ](https://blog.csdn.net/v_JULY_v/article/details/89894058) - 一般 RNN cell 的 hidden state 可視為短期記憶。LSTM 新增的 cell state 可視為長期記憶,並讓其容易一直傳下去(不經過非線性轉換)。 - LSTM 結構, 為什麼可以解決 RNN 的問題? ![](https://i.imgur.com/UX1RoDi.png =330x)  ![](https://i.imgur.com/boRwKNS.png =250x) - 忘記門($f_t$) → 控制上一個步驟的 cell state 要保留多少比例到現在的 cell state。 ![](https://i.imgur.com/JlxLh3g.png) - 輸入門($i_t$) →控制現在新產生的 cell state暫態($\widetilde{C}_t$),有多少比例要被寫入現在的 cell state ($C_t$)。($\widetilde{C}_t$ 即 Vanilla RNN) ![](https://i.imgur.com/BeWI3hs.png) cell state ($C_t$) update:舊資訊 ($f_t$ 決定之前有多少資訊要忘掉) + 新資訊 ($i_t$ 決定有多少新資訊要更新進來) ![](https://i.imgur.com/ela1621.png) - 輸出門($o_t$) → 控制上一步驟的結果 $C_t$,有多少資訊要被當成隱藏層輸出。 ![](https://i.imgur.com/SuFMGNn.png) + [GRU](https://clay-atlas.com/blog/2020/06/02/machine-learning-cn-gru-note/):記憶門、重設門。 :::info EX_11_1:RNN 結構認識。 (1) 完成 [RNN 學習單](https://drive.google.com/file/d/1NlET1hwgwXGtNB3EitLTdKXsBu6ZBjsQ/view?usp=sharing),練習 RNN 的原理。 (2) 以下面程式建立簡易 RNN 和 LSTM,練習參數數量是如何計算出來。 + [每個 LSTM cell 參數數量是 RNN 的 4 倍。(p.27)](https://speech.ee.ntu.edu.tw/~tlkagk/courses/ML_2016/Lecture/RNN%20(v2).pdf) ::: ``` javascript= from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Embedding, SimpleRNN, LSTM model=Sequential() model.add(Embedding(1000, 128)) # 1000 個字,每個字經 One-hot encoding 為 1000 維的向量,轉變成 128 維向量 model.add(SimpleRNN(units=64)) # model.add(LSTM(units=64)) model.add(Dense(units=2,activation='softmax')) model.summary() ``` :::info EX_11_2:利用 RNN 進行語句分類(情感/觀點/評論傾向性分析),判斷用戶的評價為正評或負評。 + 資料集:[中文自然語言處理 Chinese NLP Corpus](https://github.com/InsaneLife/ChineseNLPCorpus) 裏 [waimai_10k 資料集(某外賣平台收集的用戶評價,正向 4000 條,負向約 8000 條)](https://github.com/SophonPlus/ChineseNlpCorpus/blob/master/datasets/waimai_10k/intro.ipynb) + 架構圖(範例來源2:40) - 把字換成向量([Text processing and word embedding](https://github.com/wangshusen/DeepLearning/blob/master/Slides/9_RNN_1.pdf)) - RNN Layer - Classification Layer ![](https://i.imgur.com/eWPLPcZ.jpg =250x) + 範例來源:[(1)](https://www.youtube.com/watch?v=ubDtr6dh0c8)、[(2)](https://www.youtube.com/watch?v=SyYIuVJ9BhQ) ::: ``` javascript= # 1. 載入資料 import pandas as pd df=pd.read_csv('https://raw.githubusercontent.com/SophonPlus/ChineseNlpCorpus/master/datasets/waimai_10k/waimai_10k.csv') # df 印出來看看 # df.head() 列出前5筆,df.tail() 列出後5筆 ``` + [Python正则表达式指南](https://www.cnblogs.com/huxi/archive/2010/07/04/1771073.html) ``` javascript= # 2. 以正則斷字 import re pattern=re.compile('.{1}') # 告訴compile以這個pattern斷字(每一個字) # pattern.findall(df.review[0]) 取review這個欄位,看第一列以pattern斷字的結果 myData=[pattern.findall(s) for s in df.review] # 將df斷字結果存在myData # myData[0:5] 看myData前5句的結果 ``` ``` javascript= # 3. 將每個字賦予一個token(標籤化),並將句子以token表示,調整長度 from tensorflow.keras.preprocessing import sequence from tensorflow.keras.preprocessing.text import Tokenizer # 3_1. 將myData裏每個不重復的字賦予token tokenizer=Tokenizer(filters='') # filters=''表全部都處理(包含標點符號) tokenizer.fit_on_texts(myData) # tokenizer.index_word 每個字都有一個index # len(tokenizer.index_word) 共有2537個字 # 3_2. 將句子變成token的組合(sequence) myTxtTensor=tokenizer.texts_to_sequences(myData) # myTxtTensor[0:5] 看前 5 個sequence # 3_3. 將每個sequence處理到一樣長度 myTxtTensor=sequence.pad_sequences( myTxtTensor, # 要處理的sequence padding='post', # 長度不夠補在後面,補前面?請Google truncating='post', # 長度過長刪後面 maxlen=30 # 可試試其它數字 ) # myTxtTensor[0:5] 看前3個sequence經長度處理後的結果 ``` ``` javascript= # 4. 觀察 Embedding layers 轉換出的向量 from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Embedding, SimpleRNN, LSTM # 參數設定 numWords=len(tokenizer.index_word) # 單字數量,為embedding layer 的輸入維度 embedding_dim=5 # embedding layer 的輸出維度(自訂),練習完改為128(可試試其它數字) embedding_layer=Embedding(numWords+1,embedding_dim) # 輸入的input_dim為有多少字,因為補0,所以總數+1。 # import tensorflow as tf # embedding_layer(tf.constant([13,30,1])) 輸出維度為5的向量 ``` ``` javascript= # 5. 建立 RNN model,編譯,訓練 model = Sequential() model.add(Embedding(numWords+1,embedding_dim)) model.add(SimpleRNN(units=128)) # 最原始RNN,或 model.add(LSTM(units=128)),神經元數量可與embedding_dim不同 model.add(Dense(units=2,activation='softmax')) # model.summary() model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics=['accuracy']) # sparse_categorical_crossentropy 適用於整數編碼形式的標籤,categorical_crossentropy 適用於 one-hot encoded 形式的標籤。 model.fit(myTxtTensor,df.label,epochs=5) ``` ``` javascript= # 6. 輸入自己的評語 newSen=pattern.findall('又油又咸,很难吃') # 評語轉成簡體 # newSen newSen=[newSen] # check myTxtTensor[0:5] 輸入為[[],[]]2維,所以把newSen變成2維 # newSen ~ # 3_2. 將句子變成token的組合(sequence) # newSen ~ # 3_3. 將每個sequence處理到一樣長度 # newSen model.predict(newSen) # 各類的機率[第0類(負向)機率,第1類(正向)機率) ``` ``` javascript= # 7_1. 改用 Bidirectional LSTM from tensorflow.keras.models import Sequential from tensorflow.keras.layers import Dense, Embedding, LSTM, Bidirectional model.add(Bidirectional(LSTM(units=128))) # 7_2. 或接2層以上 model.add(SimpleRNN(units=128, return_sequences=True)) # return_sequences=True 可讓第一層SimpleRNN返回完整的序列,以便作為第二層SimpleRNN的輸入 model.add(SimpleRNN(units=128)) ``` + [RNN任務類型](https://ithelp.ithome.com.tw/articles/10267429) + (進階) [文本生成(Text generation)](https://youtu.be/10cjvcrU_ZU) + [機器翻譯(Machine translation),Sequence-to-Sequence Model(Seq2Seq)](https://youtu.be/gxXJ58LR684) (PPT) - 常見的 sequence-to-sequence (Seq2Seq) model 為 encoder-decoder model,把兩個 RNN 結合在一起。 - 訓練階段模型 ![](https://i.imgur.com/Hs6Rl0w.png) - 預測階段模型 ![](https://i.imgur.com/CklRz0o.png) - Encoder 可將連續的輸入(如文字、聲音訊號…),壓縮成指定長度的向量,這個向量可以想像為整個輸入的抽象表示,包含了原序列的重要訊息。 - Decoder 接受 Encoder 輸出的向量來生成文字,一次輸出一個結果,每次的輸出會影響下一次的輸出。 + [Attention Mechanism (注意力機制)](https://www.youtube.com/watch?v=XhWdv7ghmQQ) (PPT) - Attention 是為了解決訊息過長,訊息遺忘的問題。透過注意力機制,Decoder 在生成新序列的每個元素時都能動態地考慮自己要看哪些 Encoder 的向量。 - 把輸入的每個文字視為 <Key, Value> 所構成,輸出的每個文字視為 Query。透過計算 Query 和每個 Key 的相似性,得到每個 Key 對應 Value 的權重係數 $\alpha$ (代表輸入訊息的重要性),Context vector 為 Value 的加權和 。 * Q:query( 前一個 Decoder 的輸出狀態,要去 match Enocder 狀態) * K:key( 要被 match 的 Encoder 狀態) * V:value( Encoder 狀態要被抽取出來的資訊) + [Self-attention](https://www.youtube.com/watch?v=Vr4UNt7X6Gw) (PPT) :::info (進階)EX_11_3:利用 Seq2Seq 模型進行機器翻譯(英翻中)。 + 學習『[參考程式](https://colab.research.google.com/drive/16F23DXr0xuwjKrLdabjS6xps95qrAP6D?usp=sharing)』,理解Seq2Seq 模型的建模方式。([參考網站](https://blog.csdn.net/PIPIXIU/article/details/81016974)) + 下載訓練資料 [cmn.txt](https://drive.google.com/file/d/16IkKs9FYItP9Umnonk5yrGSUGUmWDerr/view?usp=sharing) 上傳至 Colab。 - 訓練資料由 [Anki](https://www.manythings.org/anki/) 中取前5000筆(全部使用Colab會記憶體不足) ::: ### 4. Transformer(PPT) + Transformer 為基於自注意力機制(self-attention mechanism)的 Sequence-to-sequence(Seq2seq) 模型,解決RNN無法有效平行運算的問題。近年在圖像描述、聊天機器人、語音辨識以及機器翻譯等各大領域大放異彩。 + <font color="red">體驗</font> - [InferKit's text generation](https://app.inferkit.com/demo) - [Hokkien Translation](https://huggingface.co/spaces/facebook/Hokkien_Translation) - [ChatGPT](https://openai.com/blog/chatgpt/) * [原理說明:一路到 ChatGPT: 生成語言 AI 的原理與應用](https://www.youtube.com/watch?v=kexXNAWvugg) * [终于有人把chatGPT说清楚了——全网最深入浅出的chatGPT原理科普,包你看懂 ](https://www.youtube.com/watch?v=DI4J2n1nfPw) + [Transformer(1)](https://www.youtube.com/watch?v=aButdUV0dxI)[ (筆記)](https://andy6804tw.github.io/2021/07/27/attention-without-rnn/)、[(2)](https://www.youtube.com/watch?v=aJRsr39F4dI) + [详解Transformer (Attention Is All You Need)](https://zhuanlan.zhihu.com/p/48508221) + [李宏毅教授【機器學習2021】自注意力機制 (Self-attention) (上)](https://www.youtube.com/watch?v=hYdO9CscNes)、[(下)](https://www.youtube.com/watch?v=gmsMY5kc-zw)、[Transformer (上)](https://www.youtube.com/watch?v=n9TlOhRjYoc)、[(下)](https://www.youtube.com/watch?v=N6aRv06iv2g) + [七天看懂自然語言處理的七年演進](https://tw.coderbridge.com/series/2ec9cf0af3f74ed99371952f4849ae33) + [淺談神經機器翻譯 & 用 Transformer 與 TensorFlow 2 英翻中](https://leemeng.tw/neural-machine-translation-with-transformer-and-tensorflow2.html) + [自然語言處理技術簡介 – 那些常見的 NLP 分析處理技術與範例](https://inbound.technology/%E8%87%AA%E7%84%B6%E8%AA%9E%E8%A8%80%E8%99%95%E7%90%86%E6%8A%80%E8%A1%93%E7%B0%A1%E4%BB%8B-%E9%82%A3%E4%BA%9B%E5%B8%B8%E8%A6%8B%E7%9A%84-nlp-%E5%88%86%E6%9E%90%E8%99%95%E7%90%86%E6%8A%80%E8%A1%93/) + [BERT(預訓練 Transformer 模型)](https://www.youtube.com/watch?v=UlC6AjQWao8) (PPT) + [ELMO, BERT, GPT](https://www.youtube.com/watch?v=UYPa347-DdE) + [3Blue1Brown:But what is a GPT? Visual intro to transformers(Deep Learning Chapter 5)](https://www.youtube.com/watch?v=wjZofJX0v4M&t=705s) + [3Blue1Brown:Attention in transformers, visually explained(Deep Learning Chapter 6)](https://www.youtube.com/watch?v=eMlx5fFNoYc) :::info EX_12_1:[體驗 Transformers](https://zhuanlan.zhihu.com/p/390819358) + [Hugging Face 的 Transformers](https://huggingface.co/transformers) 提供很多套件,pipeline API 將模型的預處理、後處理等步驟包裝起來,指定好任務名稱後,輸出文本,即可直接得到結果。 + 目前支持的 pipeline 如下: - feature-extraction(get the vector representation of a text)(特徵抽取) - fill-mask(填字) - ner(named entity recognition)(命名實體識別) - question-answering(問答) - sentiment-analysis(情意分析) - summarization(摘要) - text-generation(文本生成) - translation(翻譯) - zero-shot-classification(零樣本分類) + 練習『[參考程式](https://colab.research.google.com/drive/18610AJjSVt4VWG198WpqXhsyCRYIJzYJ?usp=sharing)』裏 Transformers 的應用。 ::: :::info EX_12_2:[體驗 BERT](https://axk51013.medium.com/%E5%BF%AB%E9%80%9F%E4%BD%BF%E7%94%A8%E8%B6%85%E5%BC%B7nlp-model-bert-db9c2a331b0f) + [Sentence-Transformers](https://sbert.net/) 將 BERT 常見的操作整理成 Package。 ``` javascript= pip install -U sentence-transformers ``` + [clip-ViT-B-32](https://huggingface.co/sentence-transformers/clip-ViT-B-32) 這個模組可以同時encode圖片跟文字,並計算文字敘述跟圖像內容的相似程度。 ::: <br /> ## [五、強化學習(Reinforcement Learning、RL)](https://hackmd.io/@cube/r1v4t7wvs) ## 六、GAN(Generative Adversarial Network,生成對抗網路)