2024年7月25日 星期四

AI 開發筆記 - 透過 llama.cpp 使用 Meta Llama 3.1 8B,過程包括資料格式轉換 @ MacBook Pro M1 32GB RAM



首先,下載 Meta llama3.1 8B 方式都寫在網站上,先到 llama.meta.com/llama-downloads 填單,填完單就會顯示下載網址,例如這種格式:

https://llama3-1.llamameta.net/*?Policy=XXX&Key-Pair-Id=XXX&Download-Request-ID=XXX

然後下載方式不是直接瀏覽他,要依照指定方式,透過 download.sh 下載,下載資訊:


連續動作:

```
% git clone https://github.com/meta-llama/llama-models
% bash llama-models/models/llama3_1/download.sh
Enter the URL from email:  https://llama3-1.llamameta.net/*?Policy=XXX&Key-Pair-Id=XXX&Download-Request-ID=XXX

 **** Model list ***
 -  meta-llama-3.1-405b
 -  meta-llama-3.1-70b
 -  meta-llama-3.1-8b
 -  meta-llama-guard-3-8b
 -  prompt-guard
Choose the model to download: meta-llama-3.1-8b

**** Available models to download: *** 
 -  meta-llama-3.1-8b-instruct
 -  meta-llama-3.1-8b

Enter the list of models to download without spaces or press Enter for all: meta-llama-3.1-8b
Downloading LICENSE and Acceptable Usage Policy
...
```

資料量大小:

```
% du -hd1 Meta-Llama-3.1-8B 
 15G    Meta-Llama-3.1-8B

% tree Meta-Llama-3.1-8B 
Meta-Llama-3.1-8B
├── consolidated.00.pth
├── params.json
└── tokenizer.model

1 directory, 3 files
```

接著就可以享受 Meta 釋出給全世界的 AI 模型了,萬分感謝 Orz 省去自己掏錢買機器訓練,據說這版 llama3.1 號稱可以跟 ChatGPT-4o 或 Claude 3.5 Sonnet 抗衡。但基於家裡的算力不足,純試試 8B 吧!

接下來使用 llama.cpp 體驗,除了程式碼編譯外,還要做資料格式的轉換:

```
% wget https://raw.githubusercontent.com/huggingface/transformers/main/src/transformers/models/llama/convert_llama_weights_to_hf.py
% python3 -m venv venv
% source venv/bin/activate
(venv) % pip install transformers torch huggingface_hub tiktoken blobfile accelerate
(venv) % python3 convert_llama_weights_to_hf.py --input_dir Meta-Llama-3.1-8B --model_size 8B --output_dir llama3_1_hf --llama_version 3.1

(venv) % du -hd1 llama3_1_hf
 15G    llama3_1_hf
(venv) % tree llama3_1_hf
llama3_1_hf
├── config.json
├── generation_config.json
├── model-00001-of-00004.safetensors
├── model-00002-of-00004.safetensors
├── model-00003-of-00004.safetensors
├── model-00004-of-00004.safetensors
├── model.safetensors.index.json
├── special_tokens_map.json
├── tokenizer.json
└── tokenizer_config.json

1 directory, 10 files
```

編譯及使用 llama.cpp:

```
(venv) % git clone https://github.com/ggerganov/llama.cpp
(venv) % cd llama.cpp
(venv) llama.cpp % LLAMA_METAL=1 make  
(venv) llama.cpp % pip install -r requirements.txt
(venv) llama.cpp % time python3 convert_hf_to_gguf.py ../llama3_1_hf/ --outfile llama3_1-8B.gguf
(venv) llama.cpp % 
(venv) llama.cpp % du -hd1 llama3_1-8B.gguf
 15G    llama3_1-8B.gguf
(venv) llama.cpp % ./llama-server -m ./llama3_1-8B.gguf
...
error: Insufficient Memory (00000008:kIOGPUCommandBufferCallbackErrorOutOfMemory)
...
llama_new_context_with_model: n_ctx      = 131072
llama_new_context_with_model: n_batch    = 2048
llama_new_context_with_model: n_ubatch   = 512
llama_new_context_with_model: flash_attn = 0
llama_new_context_with_model: freq_base  = 500000.0
llama_new_context_with_model: freq_scale = 1
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1 Pro
ggml_metal_init: picking default device: Apple M1 Pro
ggml_metal_init: using embedded metal library
ggml_metal_init: GPU name:   Apple M1 Pro
ggml_metal_init: GPU family: MTLGPUFamilyApple7  (1007)
ggml_metal_init: GPU family: MTLGPUFamilyCommon3 (3003)
ggml_metal_init: GPU family: MTLGPUFamilyMetal3  (5001)
ggml_metal_init: simdgroup reduction support   = true
ggml_metal_init: simdgroup matrix mul. support = true
ggml_metal_init: hasUnifiedMemory              = true
ggml_metal_init: recommendedMaxWorkingSetSize  = 22906.50 MB
llama_kv_cache_init:      Metal KV buffer size = 16384.00 MiB
llama_new_context_with_model: KV self size  = 16384.00 MiB, K (f16): 8192.00 MiB, V (f16): 8192.00 MiB
llama_new_context_with_model:        CPU  output buffer size =     0.98 MiB
llama_new_context_with_model:      Metal compute buffer size =  8480.00 MiB
llama_new_context_with_model:        CPU compute buffer size =   264.01 MiB
llama_new_context_with_model: graph nodes  = 1030
llama_new_context_with_model: graph splits = 2
...
^Cggml_metal_free: deallocating
```

預設環境會碰到 Aplpe MacBook Pro 筆電資源的限制,多使用了 -c 31072 來跑,整個 llama-server 在 macOS 活動監視器上,可以看到使用記憶體不到 4GB,看起來有穩定下來:

```
(venv) llama.cpp % ./llama-server -m ./llama3_1-8B.gguf -c 31072
...
.........................................................................................
llama_new_context_with_model: n_ctx      = 31072
llama_new_context_with_model: n_batch    = 2048
llama_new_context_with_model: n_ubatch   = 512
llama_new_context_with_model: flash_attn = 0
llama_new_context_with_model: freq_base  = 500000.0
llama_new_context_with_model: freq_scale = 1
ggml_metal_init: allocating
ggml_metal_init: found device: Apple M1 Pro
ggml_metal_init: picking default device: Apple M1 Pro
ggml_metal_init: using embedded metal library
ggml_metal_init: GPU name:   Apple M1 Pro
ggml_metal_init: GPU family: MTLGPUFamilyApple7  (1007)
ggml_metal_init: GPU family: MTLGPUFamilyCommon3 (3003)
ggml_metal_init: GPU family: MTLGPUFamilyMetal3  (5001)
ggml_metal_init: simdgroup reduction support   = true
ggml_metal_init: simdgroup matrix mul. support = true
ggml_metal_init: hasUnifiedMemory              = true
ggml_metal_init: recommendedMaxWorkingSetSize  = 22906.50 MB
llama_kv_cache_init:      Metal KV buffer size =  3884.00 MiB
llama_new_context_with_model: KV self size  = 3884.00 MiB, K (f16): 1942.00 MiB, V (f16): 1942.00 MiB
llama_new_context_with_model:        CPU  output buffer size =     0.98 MiB
llama_new_context_with_model:      Metal compute buffer size =  2034.69 MiB
llama_new_context_with_model:        CPU compute buffer size =    68.69 MiB
llama_new_context_with_model: graph nodes  = 1030
llama_new_context_with_model: graph splits = 2

INFO [                    init] initializing slots | tid="0x1f3b34c00" timestamp=1721895109 n_slots=1
INFO [                    init] new slot | tid="0x1f3b34c00" timestamp=1721895109 id_slot=0 n_ctx_slot=31072
INFO [                    main] model loaded | tid="0x1f3b34c00" timestamp=1721895109
INFO [                    main] chat template | tid="0x1f3b34c00" timestamp=1721895109 chat_example="<|im_start|>system\nYou are a helpful assistant<|im_end|>\n<|im_start|>user\nHello<|im_end|>\n<|im_start|>assistant\nHi there<|im_end|>\n<|im_start|>user\nHow are you?<|im_end|>\n<|im_start|>assistant\n" built_in=true
INFO [                    main] HTTP server listening | tid="0x1f3b34c00" timestamp=1721895109 port="8080" n_threads_http="9" hostname="127.0.0.1"
INFO [            update_slots] all slots are idle | tid="0x1f3b34c00" timestamp=1721895109
...
```

如此就可以用 http://localhost:8080 來體驗 llama3.1 8B 的資料了

2024年7月18日 星期四

PHP 開發筆記 - 研究 osTicket plugins 架構,以一個可擴充前端資源 plugin 為例


之前團隊在擴充 osTicket 時,主要是下海改他的 code ,但 osTicket 本身也有 plugin 架構,就花點時間看一下資料,感覺比想像中少資料可以看,只好直接看官方的 code 猜有什麼架構可用。

資料:
差不多了,然後看一下這幾個實作,盡量找最簡單的
剛好團隊內以前也都有開發過 oauth, ldap 整合,所以快速掃一下就可以很快摸索出個大概,重要的資訊: 
  • plugin 主要由 3 個檔案組成,分別是 plugin.php, config.php, yourclass.php
  • plugin 要儲存一些設定值,只需 config.php 內提供 function getAllOptions() {} 就可以輕鬆達成
  • plugin 可以自己再創個 db table 來儲存資料,一樣嘢是在 config.php 中伺機創結構
  • plugin 安插自己的程式碼主要是依賴 Signals API 架構很漂亮,但現有 Signals API 的入口點並沒有太多 UI 擴充點
  • plugin 可以製作額外的 API ,請參考 audit plugin 內的實作片段

就這樣,可以摸索個大概:

```
osTicket % grep -r "Signal::" * | grep -o 'Signal::[^,]*' | sort | uniq
Signal::connect('api'
Signal::connect('auth.clean'
Signal::connect('cron'
Signal::connect('model.created'
Signal::connect('model.deleted'
Signal::connect('model.updated'
Signal::connect('object.deleted'
Signal::connect('organization.created'
Signal::connect('session.close'
Signal::connect('signal.name'
Signal::connect('staff.header.extra'
Signal::connect('system.install'
Signal::connect('threadentry.created'
Signal::connect('ticket.created'
Signal::connect('user.auth'
Signal::connect('user.created'
Signal::connect() function call
Signal::connect\('([^']+)'/m"
Signal::send($action
Signal::send('agent.audit'
Signal::send('agenttab.audit'
Signal::send('ajax.client'
Signal::send('ajax.scp'
Signal::send('api'
Signal::send('apps.admin'
Signal::send('apps.scp'
Signal::send('auth.clean'
Signal::send('auth.login.failed'
Signal::send('auth.login.succeeded'
Signal::send('auth.logout'
Signal::send('auth.pwchange'
Signal::send('auth.pwreset.email'
Signal::send('auth.pwreset.login'
Signal::send('config.ttfonts'
Signal::send('cron'
Signal::send('export.tables'
Signal::send('mail.decoded'
Signal::send('mail.received'
Signal::send('model.created'
Signal::send('model.deleted'
Signal::send('model.updated'
Signal::send('object.created'
Signal::send('object.deleted'
Signal::send('object.edited'
Signal::send('object.view'
Signal::send('organization.created'
Signal::send('person.login'
Signal::send('person.logout'
Signal::send('session.close'
Signal::send('signal.name'
Signal::send('syslog'
Signal::send('system.install'
Signal::send('task.created'
Signal::send('threadentry.created'
Signal::send('ticket.create.before'
Signal::send('ticket.create.validated'
Signal::send('ticket.created'
Signal::send('ticket.view.more'
Signal::send('user.audit'
Signal::send('user.created'
Signal::send('user.login'
Signal::send('usertab.audit'
Signal::send() for the same named signal.
Signal::send() for the same-named signal.
Signal::send\('([^']+)'/m"
```

以及弄出個簡單的 osTicket plugin 來記錄一下:

搭配 osTicket 程式碼變動: 

% cat -n osTicket/include/staff/header.inc.php | head -n 64 | tail -n 10

    55     <link rel="icon" type="image/png" href="<?php echo ROOT_PATH ?>images/oscar-favicon-16x16.png" sizes="16x16" />

    56

    57     <?php

    58     Signal::send('staff.header.extra');

    59     if($ost && ($headers=$ost->getExtraHeaders())) {

    60         echo "\n\t".implode("\n\t", $headers)."\n";

    61     }

    62     ?>

    63 </head>


此 plugin 目的是提供引入更多 js, css resources,但如同上述提到的 osTicket plugin 沒有提供太多前端插入的 Signals ,自己得多添加一個 `Signal::send('staff.header.extra', null);` ,再來提 feature requests 來詢問開發團隊,看看是不是自己誤會了

2024年7月16日 星期二

SanDisk RMA 海外送修體驗 - Dual Drive Go USB Type-C 512GB


之前買 SanDisk USB 隨身碟覺得很小,十分適合隨身攜帶。想到之前 Macbook 蓋上後無法開機而送修的經驗,隨時加密備份資料到 USB 隨身碟,變成每週想到就會做一下事,雖然 iCloud 付費甚至免費的空間也夠用,但我也曾經歷過 iCloud 同步失敗事件 Orz 最終還是自己弄一套本地備份的機制吧!

不知是不是太常備份?在 macos 系統中,如果資料搬移的過程沒有正常走完時,隨身碟很容易進入異常狀態,接著 macOS 無法辨識。這時把它插進 Windows 系統,Windows 會偵測該隨身碟狀態,如果發現異常時會詢問是否嘗試修復,滿高的機率會修復成功的。然後,這一次沒那麼好運,連 Windows 也辨識不出,直接顯示有問題 Orz 


在完全辨識不出之前,其實也有徵兆,發現幾十GB的單一大檔案資料複製失敗,接著就自己手賤拔掉它(沒有在 macOS 安心退出),然後在 Windows 11 環境上也顯示異常無法修復。就這樣開始體驗送修機制。

若隨身碟外觀一切良好,建議回顧一下當初買到時,封面還背面到底貼了哪一家代理商的貼紙,例如展碁國際等,但我的案例是已經不知道了,再加上隨身碟外觀有點損傷(可移動的蓋子壞了被我拔掉),就聯絡了 WD (2016收購SanDisk),但起源發信給 support@SanDisk.com ,並提供當初在哪個地方購買的發票證明


這時客服也會先引導你是否要先找當地代理商換貨,最終我的案例是建立 RMA,並把商品使用掛號郵寄寄到香港檢測,若情況可以換新品,接著對方也會快遞把新品寄到指定的地點。使用者承擔掛號郵寄的費用,WD承擔寄送到使用者的快遞費用。

一個隨身碟掛號郵寄到香港,約80台幣,此外,收快遞進台灣還得處理 EZWay 報關,對方會申報商品價值,如 10 美金。

掛號郵寄到對方約四天,快遞收件也差不多四天,整體服務體驗很不錯。

2024年7月15日 星期一

macOS - android fileTransfer 下載位置 AndroidFileTransfer.dmg


圖:2024-07-15 https://www.android.com/filetransfer/


以前都用 Google 找 Android fileTransfer 來下載,現在有點詭異,不知為何連到 https://www.android.com/filetransfer/ 時,首頁看不到下載位置。這大概是 2024 年春天以後發生的事。

只好亂翻一下得到 google.com 下載位置,像是用 web.archive.org 定位一下:
有興趣可以在這邊回顧,看來是 2024-05-21 起就不見了:




2024年7月2日 星期二

Linux 開發維護 - OpenSSH Server 資安漏洞補強,資安事件代號:CVE-2024-6387 @ Ubuntu 22.04

2024.07.02 一早就看到了 OpenSSH Server 漏洞,到處都在講,可參考 iThome 的文章:

iThome 2024.07.02 - OpenSSH含有可遠端攻陷伺服器的回歸漏洞

其中文章最後有提到:

OpenSSH團隊亦於本周一釋出了OpenSSH 9.8/9.8p1, 以修補CVE-2024-6387及另一個邏輯漏洞。該團隊亦說明,在實驗室環境下,要攻陷CVE-2024-6387需要不斷建立連結並持續6~8小時,直至達到伺服器極限,目前已於具備ASLR的32位元Linux系統上成功展現。

因此,除了修正外,也可以安裝一些阻擋 retry ssh 登入的行為,以前學生時代裝 denyhosts ,現在問 ChatGPT 得到 fail2ban 套件,在 Ubuntu 22.04 快速上手:

$ sudo apt-get update
$ sudo apt-get install fail2ban
$ sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
$ sudo systemctl restart fail2ban

建議還是要去看一下 /etc/fail2ban/jail.local 設定,像是 sshd retry 幾次會阻擋,以此評估是不是適合自己(常打錯密碼擋到自己也很無奈的)。裝完就可以用以下指令得知資訊:

$ sudo fail2ban-client status sshd 
Distributor ID: Ubuntu 
Description: Ubuntu 22.04.4 LTS 
Release: 22.04 
Codename: jammy 
Status for the jail: sshd 
|- Filter 
| |- Currently failed: 4 
| |- Total failed: 13 
| `- File list: /var/log/auth.log 
`- Actions 
|- Currently banned: 0 
|- Total banned: 0 
`- Banned IP list: 

不過,回到 CVE-2024-6387 資安事件,其實只要單純把 Ubuntu 系統更新,Ubuntu TLS 都給你傳便便:


Ubuntu 24.04
openssh-client - 1:9.6p1-3ubuntu13.3
openssh-server - 1:9.6p1-3ubuntu13.3

Ubuntu 23.10
openssh-client - 1:9.3p1-1ubuntu3.6
openssh-server - 1:9.3p1-1ubuntu3.6

Ubuntu 22.04
openssh-client - 1:8.9p1-3ubuntu0.10
openssh-server - 1:8.9p1-3ubuntu0.10

例如 Ubuntu 22.04 openssh 1:8.9p1-3ubuntu0.10 內容:


openssh 1:8.9p1-3ubuntu0.10 source package in Ubuntu
Changelog
openssh (1:8.9p1-3ubuntu0.10) jammy-security; urgency=medium

  * SECURITY UPDATE: remote code execution via signal handler race
    condition (LP: #2070497)
    - debian/patches/CVE-2024-6387.patch: don't log in sshsigdie() in log.c.
    - CVE-2024-6387

 -- Marc Deslauriers <email address hidden>  Wed, 26 Jun 2024 09:11:55 -0400

而自己的系統就只要查一下是否有更新至此版即可:

$ sudo apt upgrade && sudo apt upgrade && lsb_release -a && sudo apt policy openssh-server && ssh -V
...
Distributor ID: Ubuntu
Description: Ubuntu 22.04.4 LTS
Release: 22.04
Codename: jammy

openssh-server:
  Installed: 1:8.9p1-3ubuntu0.10
  Candidate: 1:8.9p1-3ubuntu0.10
  Version table:
 *** 1:8.9p1-3ubuntu0.10 500
        500 http://archive.ubuntu.com/ubuntu jammy-updates/main amd64 Packages
        500 http://security.ubuntu.com/ubuntu jammy-security/main amd64 Packages
        100 /var/lib/dpkg/status
     1:8.9p1-3 500
        500 http://archive.ubuntu.com/ubuntu jammy/main amd64 Packages

OpenSSH_8.9p1 Ubuntu-3ubuntu0.10, OpenSSL 3.0.2 15 Mar 2022