黃昕暐

@meebox

編輯/工程師雙面人

Joined on Oct 30, 2016

  • 使用 Embedding 最重要的事情就是計算兩個向量之間的相似度, 不同的工具預設的計算方式不同, 甚至名稱一樣的計算工具計算方式也不見得一樣。如果沒有搞清楚, 就會被弄得一頭霧水, 同樣的兩個向量為什麼算出來的相似度差那麼多! Chroma 預設是計算幾何距離的平方 計算向量相似度最精確的作法是計算向量之間的幾何距離, 不過這牽涉求平方根運算, 所以在 Chroma 資料庫中, 預設使用的是底層 hsnwlib 的 'l2', 計算向量之間幾何距離的平方。由於我們實際需要比較的是單一向量與多個向量之間的相似度, 距離平方只會加大尺度, 但不會變更相似度順序, 計算時還可以省去求平方根的運算, 可以說是效率不錯的作法。 以下以 LangChain 為例, 先匯入相關類別: >>> from langchain.vectorstores import Chroma >>> from langchain.embeddings.openai import OpenAIEmbeddings >>> embeddings = OpenAIEmbeddings()
     Like  Bookmark
  • 在 MicroPython 中利用 HTTP POST 傳送中文如果不注意會出錯, 本文以 OpenAI API 為例。OpenAI 雖然提供有 Python 的官方套件, 不過如果你是要在 MicroPython 中使用 OpeAnAI 的 API, 並不能直接套用, 這時就要回歸到 OpenAI API 最根本的 HTTP Post API 了。 最簡單的 OpenAI API OpenAI 是透過 HTTP Post 提供服務, 以聊天為例, 的是 ChatCompletion 服務: API 進入點為 https://api.openai.com/v1/chat/completions 資料的傳遞都是 JSON 格式 HTTP 表頭中要以 Bearer 方式透過金鑰認證身分 因此, 最簡單的 OpenAI HTTP Post API 的程式就像是這樣:
     Like  Bookmark
  • matplotlib 預設的字型並不是中文字型, 所以顯示中文會變成方框, 像是這個例子: >>> import matplotlib.pyplot as plt >>> plt.pie( ... [800, 300, 400], ... labels=['交通', '娛樂', '教育']) ([<matplotlib.patches.Wedge object at 0x000001CB83DFC250>, <matplotlib.patches.Wedge object at 0x000001CB83DFC700>, <matplotlib.patches.Wedge object at 0x000001CB83DFCB80>], [Text(-0.11498140519131439, 1.093974074857458, '交通'), Text(-0.7360435164738056, -0.8174594435547703, '娛樂'), Text(0.7360438608860855, -0.817459133444544, '教育')]) 顯示時會出現訊息告知目前的字型沒有 CJK 文字, 其中 4EA4 等等就是個別中文字的 unicode: >>> plt.show()
     Like 2 Bookmark
  • 有了 pyenv 可以管理不同 Python 版本後, 搭配 venv 建立虛擬環境雖然很不錯, 不過個別工具都要單獨使用, 如果有一個整合工具, 那就太方便了, 這就是 pipenv, 它把 pip、pyenv 以及另一套虛擬環境管理工具 virtualenv 完美結合在一起, 而且跨平台, 可以讓你實現以單一資料夾為專案, 建立使用特定 Python 版本的虛擬環境, 再也不怕專案之間打架了。 安裝 pipenv 安裝 pipenv 只要使用 pip 即可, 但請記得安裝在你的使用者資料夾下, 避免它安裝的可執行檔因為移除 Python 而被刪除: # pip install --user pipenv 安裝完成後, 還要記得將安裝好的可執行檔所在的資料夾加入環境變數 PATH 中, 方便使用: 在 Windows 上可以透過以下指令查詢路徑:​​​​# python -m site --user-site ​​​​C:\Users\meebo\AppData\Roaming\Python\Python312\site-packages
     Like 1 Bookmark
  • Windows 的 cmd 下雖然有提供 setx 指令可以修改系統的環境變數, 但是它有一個要命的限制, 就是設定的值不能超過 1024 個字元, 這對一般的環境變數沒有差, 可是當你要設定 PATH 的時候, 就很容易超過限制。更糟的是超過限制時, 它會自動截掉超過的部分後儲存到環境變數中。 為了解決這個問題, 有善心人士寫了一個工具程式 SetEnv, 以下我們就來說明它的用法。 安裝 SetEnv SetEnv 可以下載安裝檔或是原始碼壓縮檔, 由於它是單獨的一個 exe 檔, 所以比較建議的方式就是下載原始碼壓縮檔, 從解開的 Visual Studio C++ 專案的 Release 資料夾中取出 setenv.exe 放到 c:\Windows 或任何 PATH 指定的路徑下即可。 以下指令可查看使用方法: >setenv /?
     Like  Bookmark
  • C++ 有些細節雖然不知道可能不會影響你的程式碼正確執行, 不過卻可能影響你的程式耗用的記憶體。舉例來說, 底下這個程式定義了兩個幾乎相同的結構, 只是成員的順序不一樣, 不過如果顯示這兩個結構的大小, 就會發現 data2 要比 data1 多耗費了 4 個位元組: #include <iostream> using namespace std; struct data1 { char c1; char c2; int i1; int i2;
     Like  Bookmark
  • Python 小猜謎 請猜猜看以下程式碼的輸出結果: >>> class A: ... def __get__(self, instance, owner): ... return True >>> class B: ... a1 = A() >>> b1 = B() >>> b1.a1
     Like  Bookmark
  • 剛入門學習 Python 的人常常會被到底什麼是可變 (mutable)、不可變 (immutable) 的資料搞混, 也會發生改了 a 卻讓 b 也變動內容的意外嚇到。本文就嘗試幫初學者解惑, 甚至可能許多有經驗的 Python 程式師也未必思考過原來背後的運作機制是這樣。接著就讓我們從 Python 的原點--物件--出發。 什麼都是物件的 Python 在 Python 中所有的東西都是物件, 直覺能夠理解的如數值、字串這樣的資料, 不直覺的像是函式、模組等等, 全部都是物件。我們可以使用內建的 type() 函式來得知物件所屬的型別 (type): >>> type(1) <class 'int'> >>> type(True) <class 'bool'> >>> type('hi')
     Like 2 Bookmark
  • 最近剛好遇到一個問題, 才發現 C++ 中的 std::string 配置的空間在不同版本的編譯器並不一樣, 以底下的程式碼為例: #include<iostream> using namespace std; int main(void){ string s = "hello"; cout << "sizeof(s):" << sizeof(s) << endl; return 0; }
     Like  Bookmark
  • C++ 的 using 有兩個用法, 一種是把名稱空間中的名稱宣告到目前的名稱空間中的 using 宣告語法;另一種則是把指定名稱空間內的名稱全部變成編譯器可視的 using namespace 編譯器指引。 using 宣告 using 宣告 的作用等於是在目前名稱空間中宣告一個指定名稱空間內名稱的別名, 例如: #include <iostream> namespace outer { int var = 10;
     Like  Bookmark
  • 今天測試一個小程式, 像是這樣: // Ch18_4, 將資料寫入文字檔 #include <fstream> // 載入fstream標頭檔 #include <iostream> using namespace std; int main(void) { // 建立ofile物件 ofstream ofile(".\\donkey.txt", ios::out);
     Like  Bookmark
  • 在 C++ 中建立物件時, 如果是要使用預設的建構函式或是不具參數的建構函式時, 不能在變數名稱後面加上圓括號, 例如: class MyClass { public: int i; MyClass() { // 預設 (不含參數) 的建構函式 } };
     Like  Bookmark
  • :::info 你是一位專精程式設計教育的天才寫手, 擅長使用簡單易懂的比喻來講解程式設計的概念, 特別是會以圖解的方式輔助文字說明, 並且具備縱觀整體架構的特性。在撰寫的時候, 會嚴守以下幾項規定: 使用台灣地區的繁體中文以及習慣用語, 例如 memory 是『記憶體』, 不是『內存』;variable 是『變數』, 不是『變量』;object-oriented 是『物件導向』, 不是『面向對象』;物件導向中的 class 是『類別』, 不是『類』:library 是『程式庫』, 不是『庫』等等。 文章內容以 markdown 語法撰寫, 需要繪製架構圖、組織圖之類的圖表時請以 graphviz 語法繪製;UML 類型的圖表請以 js-sequence-diagrams 繪製;流程圖可以 flowchart.js 語法繪製;其餘圖表則可以 mermaid 語法繪製, 必要時也可以用 SVG 格式繪圖。 產生程式碼範例時盡可能以不同的角度產生多種範例, 讓讀者可以從不同的觀點瞭解同一個概念。 假設讀者的開發環境都有 AI 輔助工具, 你可以把這一點納入考量, 在適當的地方提醒讀者如何善用這些 AI 工具。 由於讀者都是初學者, 所以在講解的時候只能使用到讀者已經學習過的內容, 例如:要先講解過變數才能在程式碼中使用變數。因此, 凡是要使用到尚未介紹過的主題, 就必須在使用前提供必要的說明, 例如要使用內建函式 print, 就要先說明什麼是函式。 大綱中最底層的小節通常是描述要撰寫的內容, 文字量偏多, 生成時也幫它產生適當的標題。
     Like  Bookmark
  • :::info 我給它的 prompt: 以下是我想要的 Python 入門教材前兩章的大綱, 請幫我生成 1.4 節的內容 Python 簡介與環境建置Python 的歷史與優點 安裝 Visual Studio Code 安裝 Codeium AI 助手 最簡單的程式介紹內建函式的概念 使用 print 印出幫讀者加油打氣的文字
     Like  Bookmark
  • ESP32-S3 的開發板通常會有兩個 USB 插孔, 這是因為 ESP32-S3 本身具備有 USB 介面, 所以其中一個插孔是與 ESP32-S3 內建的 USB 介面連接, 通常標示為 USB, 這個 USB 介面可以當序列傳輸或是讓 ESP32 扮演鍵盤、滑鼠、隨身碟等 USB 裝置, 同時也提供硬體除錯功能;另一個插孔是連接開發板自己的 USB 轉 UART 晶片, 方便上傳程式碼與當作序列傳輸介面使用, 通常這個插孔會標示為 UART 或是 COM。 Windows 上錯誤的驅動程式 在 Windows 上如果兩個 USB 插孔都街上傳輸線, 會看到共有 3 個連接埠: image 這是因為 Winodws 錯用了驅動程式, 所以把用來除錯的介面, 也就是名稱為 USB JTAG/serial debug unit(interface 2) 的介面當成序列傳輸的裝置。為了之後能夠順利使用硬體除錯功能, 必須使用 Zadig 工具強制更換驅動程式。 直接下載該工具執行後, 選取『Options/List All Devices』功能表指令後依照剛剛看到的連接埠名稱選取 USB JTAG/serial debug unit(interface 2), 可以看到目前的驅動程式是 usbser(v1.0.0), 表示幫成 serial 序列傳輸用:
     Like  Bookmark
  • ESP32 S3 因為有內建 USB JTAG 硬體除錯介面, 所以不需要額外的硬體就可以啟用除錯功能, 不過目前的 Arduino IDE 2.X 版還無法完美支援除錯功能, 必須使用 VSCode 搭配 PlatformIO 才能啟用硬體除錯功能。在 Windows 平台上, 還需要額外的步驟, 替換驅動程式才能使用。以下以我手邊的 YD-ESP32-S3 為例示範。 在 Windows 平台上啟用 ESP32 S3 硬體除錯 首先, 要啟用硬體除錯的專案, 必須在 platformio.ini 中加入以下的描述: monitor_speed = 115200 ; 除錯介面的傳輸速度 build_type = debug ; 將專案建置乘除錯用 debug_tool = esp-builtin ; 使用 ESP32 內建的除錯介面 個別接上控制板的兩個 USB, 你會看到總共有三個連接埠的裝置:
     Like  Bookmark
  • 馬達編碼器一般使用兩個正交 (也就是差 90°) 的霍爾感測器, 偵測編碼器上磁石的磁性變化, 我測試時的馬達編碼器如下圖: image 兩個感測器的位置如圖中標示, 當磁石轉動時, 磁石上的磁性會交替變化, 霍爾感測器就會隨之產生高低電位變化。由於兩個霍爾感測器位置正交, 所以會相差 1/4 個週期, 例如當磁石受馬達帶動順時針旋轉時, 感測器 ② 的變化會領先感測器 ① 的變化 1/4 個週期, 以Desmos 網頁繪製的圖表示如下: image 以下方的感測器 ① 來看, 每次電位改變 (圖中箭頭標示處) 時, 它改變後的電位都會和感測器 ② 相同。
     Like  Bookmark
  • 使用 LangChain 的 memory 類別時, 如果是會限制記憶量的類別, 由於他們底層實作的關係 (我認為是 bug), 雖然表現上看起來好像是把舊的訊息丟棄了, 但實際上還是儲存了所有的訊息, 以下我們以最簡單的 ConversationBufferWinodwMemory 來說明。 以 ConversationBufferWindowMemory 簡易測試 以下我們以預設採用 ChatMessageHistory 把訊息儲存在記憶體中的 ConversationBufferWindowMemory 為例進行簡單的測試: >>> from langchain.memory import ConversationBufferWindowMemory >>> memory = ConversationBufferWindowMemory(k=1) >>> memory.save_context( ... {'input': '你好'}, ... {'output': '有什麼事?'}
     Like  Bookmark
  • 開發程式的過程中, 可能會遇到 Python 版本不相符的狀況。像是有些程式碼使用了新版本 Python 的語法或是功能, 但是你的環境安裝的是舊版本的 Python, 導致無法正常執行, 舉例來說, 以下的程式在 Python 3.12 之前的版本會出錯: >>> import sys >>> sys.version '3.11.6 (tags/v3.11.6:8b6ee5b, Oct 2 2023, 14:57:12) [MSC v.1935 64 bit (AMD64)]' >>> students = [{'name': '王小明'}] >>> f'{students[0]['name']}' Syntax Error: f-string: unmatched '[' (<input>, line 1)
     Like 1 Bookmark
  • 這幾天因為測試改用 scoop 當成軟體管理工具, 發現透過 scoop 安裝的 pyenv 無法正常安裝 Python, 會出現以下的錯誤訊息: :: [Error] :: error installing "core" component MSI. 根據善心人士的研究, 發現 msi 格式的安裝套件需要以 msiexe 執行, 但是 msiexe 考量跳轉到其它資料夾的安全性, 所以如果遇到指定的安裝路徑含有 junction point 時, 並不會取得真正的路徑, 安裝就會失敗。這主要是因為 scoop 為了讓軟體更新時不會動到執行軟體的路徑, 所以每個軟體都會有一個 current 的 junction point, 連結到實際版本的資料夾, pyenv 會把 Python 安裝到透過 current 連結的資料夾下, 因此遇到 msiexe 不會取得真正路徑的問題。 pyenv 的 Windows 版本實際上使用了 VBScript 撰寫安裝 Python 的工作, 因此這就引起了我的好奇心, 要怎樣才能在 VBScript 中取得 junction point 的實際路徑, 這樣就可以再執行 msiexe 的時候, 改用真實路徑, 就可以避免前面提到的問題了。 如果你只想知道如何讓 pyenv 正常運作, 可以直接跳轉到本文最後。 取得 junction point 實際路徑的指令
     Like 1 Bookmark