RUN LLaMA LLM on Raspberry Pi Cluster

MPICH Raspberry Pi Cluster 最早在Raspberry Pi集群上运行MPICH的项目应该是Raspberry Pi at Southampton,教授Simon Cox和他的儿子一起搭建由64个树莓构和乐高积木构成的MPI集群,这个项目已经是10年前的了,那个时候使用的是raspberry pi 1 B+,由于1代性能的限制,整个集群只能用于MPI学习,在高性能计算方面还是欠佳。然而现在raspberry pi 4虽然对比Intel服务器而言性能还是很弱,但是运行MPICH相关的计算项目比起1代还是非常有潜力的。首先是功耗方面,64块raspberry pi 4 CPU满载运行总功耗大概400多瓦左右,其次是ARM生态比起十年前现在已经非常完善,很多的程序都已经被移植到了ARM64平台上,各种各样的工具垂手可得。 最近比较出类拔萃的项目一定属于Meta LLaMA V2,在上一代模型的基础上,LLaMA 2 开放了商业使用许可,那么能否在raspberry pi 4 cluster上运行LLaMA 2 LLM 模型呢?项目llama.cpp已经给出了答案。llama.cpp将llama原生模型参数类型从float 16bit量化到int 4bit,从而使得大语言模型能够运行在消费级的CPU/GPU上。 Deployment LLaMA.cpp on raspberry pi k8s cluster 很早之前我在家里搭建了一套raspberry pi 4集群,节点规模在70台,并且目前还在运行中,集群采用k8s来进行管理,于是结合volcano,将llama.cpp部署在raspberry pi 节点上,节点间的共享存储我目前采用的是moosefs。 首先部署volcano,它相当于一个k8s任务调度器,可用于深度学习的分布式训练以及高性能的并行计算,部署可以参考volcano github 构建MPICH llama.cpp docker image FROM ubuntu:22.04 ENV DEBIAN_FRONTEND=noninteractive RUN apt update && apt upgrade -y && apt-get install build-essential gfortran make cmake wget zip unzip python3-pip python3-dev gfortran liblapack-dev pkg-config libopenblas-dev autoconf python-is-python3 vim -y # compile mpich WORKDIR /tmp RUN wget https://www.mpich.org/static/downloads/4.1.2/mpich-4.1.2.tar.gz RUN tar xf mpich-4.1.2.tar.gz RUN cd mpich-4.1.2 && ./configure --prefix=/usr && make -j $(nproc) && make install RUN rm -rf mpich-4.1.2.tar.gz mpich-4.1.2 # compile llama.cpp RUN apt install git -y WORKDIR / ENV LLAMA_CPP_GIT_UPDATE 2023-07-19 RUN git clone https://github.com/ggerganov/llama.cpp.git RUN cd llama.cpp && make CC=mpicc CXX=mpicxx LLAMA_MPI=1 LLAMA_OPENBLAS=1 RUN cd llama.cpp && python3 -m pip install -r requirements.txt RUN apt install openssh-server -y && mkdir -p /var/run/sshd ENV PATH=/llama.cpp:$PATH 运行MPI Job apiVersion: batch.volcano.sh/v1alpha1 kind: Job metadata: name: llama-mpi-job labels: "volcano.sh/job-type": "MPI" spec: minAvailable: 5 schedulerName: volcano plugins: ssh: [] svc: [] policies: - event: PodEvicted action: RestartJob tasks: - replicas: 1 name: mpimaster policies: - event: TaskCompleted action: CompleteJob template: spec: volumes: - name: mfs hostPath: path: /mfs type: Directory containers: - command: - /bin/sh - -c - | export MPI_HOST=`cat /etc/volcano/mpiworker.host | tr "\n" ","`; mkdir -p /var/run/sshd; /usr/sbin/sshd; sleep infinity; # please fill your llama mpich docker image that build in step 2. image: registry.cineneural.com/compile-projects/llama-cpp-arm64-cpu:ubuntu22.04 imagePullPolicy: Always name: mpimaster volumeMounts: - mountPath: /mfs name: mfs ports: - containerPort: 22 name: mpijob-port resources: requests: cpu: 2 memory: "2Gi" limits: cpu: "4" memory: "2Gi" restartPolicy: OnFailure - replicas: 10 name: mpiworker template: spec: volumes: - name: mfs hostPath: path: /mfs type: Directory containers: - command: - /bin/sh - -c - | mkdir -p /var/run/sshd; /usr/sbin/sshd -D; # please fill your llama mpich docker image that build in step 2. image: registry.cineneural.com/compile-projects/llama-cpp-arm64-cpu:ubuntu22.04 imagePullPolicy: Always name: mpiworker volumeMounts: - mountPath: /mfs name: mfs ports: - containerPort: 22 name: mpijob-port resources: requests: cpu: "2" memory: "2Gi" limits: cpu: "4" memory: "4Gi" restartPolicy: OnFailure 将llama 2模型文件转换到ggml bin # LLaMA 2 13B Chat Model python3 convert.py --outtype f16 /mfs/packages/Meta/LLaMA-v2-models/llama-2-13b-chat quantize /mfs/packages/Meta/LLaMA-v2-models/llama-2-13b-chat/ggml-model-f16.bin \ /mfs/packages/Meta/LLaMA-v2-models/llama-2-13b-chat/ggml-model-q4_0.bin q4_0 # LLaMA 1 7B Model python3 convert.py --outtype f16 /mfs/packages/Meta/LLaMA-v1-models/7B quantize /mfs/packages/Meta/LLaMA-v1-models/7B/ggml-model-f16.bin \ /mfs/packages/Meta/LLaMA-v1-models/7B/ggml-model-q4_0.bin q4_0 推理 kubectl exec -ti llama-mpi-job-mpimaster-0 bash # run command line in llama-mpi-job-mpimaster-0 container: mpirun -hostfile /etc/volcano/mpiworker.host -n 5 \ /llama.cpp/main \ -m /mfs/packages/Meta/LLaMA-v2-models/llama-2-13b-chat/ggml-model-q4_0.bin \ -p "please explain me the different between math and physical" -n 128 Chat with Raspberry Pi llama v1 7B mpirun -hostfile /etc/volcano/mpiworker.host \ -n 5 /llama.cpp/main \ -m /mfs/packages/Meta/LLaMA-v1-models/7B/ggml-model-q4_0.bin \ -p "I believe the meaning of life is" -n 128 ...

July 22, 2023

Compile Ros2 Humble for Raspberry Pi Zero W

问题 raspberry pi zero w 的系统目前树莓派官方推出的镜像是armv6hf debian 11,而ROS2官方只支持ubuntu debian aarch64,不支持arm32,所以要在raspberry pi zero w上使用ROS2必须从源码构建。那么问题就在于如果直接在zero w上编译,显然因为硬件的原因(cpu: 1 core, memory: 512M),编译将会极其缓慢,我也尝试使用armhf交叉编译工具链在aarch64系统上编译ROS源码,但是会出现系统库缺失问题。同时我还考虑到后续的开发环境和zero w原始系统环境的一致性问题,我决定采用zero w的原生debian 11 armhf系统做为rootfs,制作docker image,然后运行在aarch64系统上(比如树莓派4,jetson agx),这样编译出来的ros2直接可以运行在zero w上,并且运行环境和编译环境都是保持一致的,这样对后续的调优以及debug处理都会非常方便。 兼容性 raspberry pi zero w 使用的是cpu arm1176jzf-s,armv6版本,raspberry pi 4 使用的是 ARM Cortex-A72 ARMv8-A版本,我们可以从Cortex-A72文档中看出AArch32 for full backward compatibility with Armv7,也就是armv8 aarch32指令集兼容armv7 aarch32,同时armv7指令集兼容armv6,那么也就意味着armv6的二进制文件是可以直接在raspberry pi 4 aarch64上运行,反之aarch64 binary当然无法在armv6系统上运行,这样思路一下子清晰了,我们可以将armhf的根文件系统制作成docker image,运行在aarch64系统上,然后编译ros2,最后将编译产物拷贝到zero w上直接运行。 解决问题 command line run on raspberry pi 4 ubuntu 20.04 aarch64 os donwload rpi zero w image (raspios-bullseye-armhf-lite) ...

July 16, 2023

Google Coral Edge TPU 简短介绍

Coral生态以及技术 References: Coral AI 介绍下google coral edge TPU computing整个生态: 用于生产环境的SoM以及带PCI接口的加速器。 用于开发测试的四款口袋型开发板。 外围传感器包括环境检测模块以及摄像头,Wi-Fi/PoE扩展板。 Cloud TPU / Edge TPU 介绍 技术 Coral Edge TPU是谷歌为加速边缘设备神经网络推理而研发的专用芯片,并且在保持低功耗的前提下运行专门优化过的神经网络模型。 Edge TPU 运行速度为4 Tops,并且功耗为0.5W/Tops,相当于如果Edge TPU全天满负荷运行,那么一天的功耗总共为48WH,这样对于工业环境的要求,低功耗绝对是一个优势。上图为嵌入式CPU和Edge TPU推理速度的比较,可以看出在edge TPU上运行时间远远低于embedded cpu,降低功耗但保持模型推理的准确度并且加速运算,这就是edge tpu在工业领域的优点。 可扩展性 Coral产品线包括最初的原型设计开发板,到产品PCI edge TPU模块,最后再到微控制器micro dev board,整个生态链都有供应,缺点就是由于芯片限制的原因在中国很难买到,国外因为生产原因的关系,也需要时刻关注供应商的库存。像我之前购买的Environmental Sensor Board是通过HK代购进入中国的,还有micro dev board是通过pi3g供应商从EU发货到达国内的。 模型兼容 edge TPU可以运行tensorflow以及keras构建的模型,当然模型需要转换成int8 tensorflow lite ,这一步称之为quantized,这样就可以降低模型在edge device上内存的开销,然后tflite模型通过edge tpu compiler的编译,最后运行在edge tpu上。 Mendel Linux Coral Dev Board和Coral Dev Mini Board以及SOM都可以运行google自己维护的Mendel Linux,系统的缺点就是独立性太强,使用的linux内核是4.x系列,比起raspberry pi生态,coral的内核已经相当老旧了,并且无法使用linux内核的新功能,而像raspberry pi官方一直支持Linux内核到6.x系列。在编程接口方面,google提供了,pycoral + libcoral,还有shell命令行工具MDT。 Coral Micro ...

February 3, 2023

Moosefs Master 高可用实现

我自己设计了一套简陋的k8s persistentvolumeclaims方案,后端采用Moosefs做为分布式数据存储,原理是基于kubernetes events机制,当接收到create pvc的消息时,后台control应用会在moosefs上创建对应的pv,并绑定相应的pvc,为了方便应用在各个节点间移动,我将moosefs文件系统挂载到了每一个worker节点下,这里就产生了一个问题:如何保证moosefs master高可用!moosefs官方有两个版本一个是opensource,另外一个是Pro,Pro版本自带HA功能,而opensource只有备份master的功能,当出现故障时只能通过手动恢复master。为了满足高可用的需求,我申请了Pro版本为期一个月的使用权限,购买永久授权官方价格是1425EUR/10TBi,其中包括了一年的维护费570EUR,这个价格对于我个人使用Raspberry Pi来说实在过于昂贵,并且我测试了mfsmaster pro的性能,发现和opensource版本相比没有显著的提升,考虑到mfsmaster是单线程应用,我决定以后自己维护一套mfs源码,增加它在kubernetes上的功能。这样经过调研,我发现了mfs master高可用的方案(上图所示)。 MFS Opensource Master HA 总共分为三部分: mfsmaster DRBD Keepalived mfsmaster:存储mfs的元数据。 DRBD:实现网络层块设备的实时复制,类似RAID 1。 Keepalived:监控两台mfsmaster的健康状况。 当mfsmaster A出现异常时,keepalived会将VIP迁移到mfsmaster B上,并将A由原先的master变成backup,同时卸载mfs metadata的DRBD USB磁盘,将B由原先的backup变成master,同时挂载mfs metadata的DRBD USB磁盘,启动mfsmaster,这样就完成了故障节点的恢复。 在使用moosefs之前,我测试过openebs,longhorn,beegfs,glusterfs这些分布式文件系统,对比了它们之间的性能和易用性,最终还是选择了moosefs,因为mfs的扩展实在是太方便了,并且客户端是通过fuse访问文件系统,像macos,freebsd,netbsd都可以使用,在ARM64平台上的读写性能也是优于其他几个分布式文件系统的。当然最后的缺点是官方好像停止维护mfs v3版本了(github一直没有更新),v4版本仍然处于闭源状态。

November 23, 2022

My Web Content Platform

这是我目前使用的内容管理平台的架构,前端的两台google comput engine 用于连接全球互联网以及托管静态站点,后端的集群全部运行在自己托管的ARM64系统平台上,集群内部运行着Cloudflared隧道,当用户请求invisibleart时,请求会通过cloudflare edge network发送到隧道中,cloudflared会将请求发往目标地址wordpress engine,后端的数据库采用的是vitess mysql集群,前期使用过tidb,发现与wordpress存在兼容性问题,最后决定使用vitess,在备份,扩容,和灾难恢复中,vitess还是非常可靠的。

July 29, 2022

Eth1.0 Merge to Eth2.0

回顾 ETH2.0 Phase0 BeaconChain Blog 2020年的12月份,ETH上线了2.0-0阶段的信标链,ETH2.0 Proof of Stacking(pos)的底层应用,它不像现在在运行的ETH1.0主链,Beacon Chain上面没有智能合约也没有账户管理,它的主要功能就是2.0的共识机制,用户通过质押ETH(我们称之为validator)来保护整个2.0主网的安全性,更多的人运行validator节点,能够更好的去中心化以及抵御外部攻击。0阶段,用户是只能质押ETH代币,无法运行合约以及转账操作。 合并 在2022年的三月份ETH开发者上线了kiln ETH2.0合并测试网,当前的1.0主网将合并到2.0的Beacon Chain,这样做是为了结束1.0上面的pow共识机制,并全面的过渡到pos,用ethereum.org官方的表述意思就是像宇宙飞船的对接,1.0已经无法再进行较远距离的星际航行,于是开发者们设计2.0的新引擎,1.0将与2.0飞船进行对接合并,然后驶向宇宙的更深处。当合并完成之后,ETH1.0主网将与Beacon Chain进行合并,成为ETH分片链,并且将转向Pos权益证明而非Pow工作量证明。主网将智能合约带入到Proof-of-stack系统中,并且导入ETH1.0中的所有历史数据和现状,确保ETH的持有者和用户能够平滑的过度到2.0。当合并发生时,validator节点将接管主网,miner将不再需要。 操作指引 我选择的是lighthouse beacon chain做为自己的验证节点,以下是具体在kubernetes中进行操作的yaml文件,还可以参考相关网站用于部署节点。 帮助文档 ETH Kiln TestNet kiln testnet on arm How to run a node on Kiln Join the kiln testnet - lighthouse 我的节点 kubernetes kiln testnet node and validator geth-kiln-net.yaml --- apiVersion: apps/v1 kind: Deployment metadata: name: geth-merge-devnets namespace: eth labels: app: geth-merge-devnets spec: strategy: type: Recreate selector: matchLabels: app: geth-merge-devnets template: metadata: labels: app: geth-merge-devnets spec: nodeSelector: kubernetes.io/hostname: deep-dream initContainers: - name: geth-init image: 192.168.1.114:5000/geth-merge-devnets:4c57d09-20220316 args: - geth - --datadir=/execution_data - init - /custom_config_data/genesis.json volumeMounts: - name: geth-merge-devnets-data mountPath: /execution_data - name: merge-devnets-genesis-json mountPath: /custom_config_data containers: - name: geth-merge-devnets resources: limits: memory: 5Gi cpu: 4 requests: memory: 2Gi cpu: 1 image: 192.168.1.114:5000/geth-merge-devnets:4c57d09-20220316 args: - geth - --datadir=/execution_data - --syncmode=full - --http - --metrics - --http.api - "engine,eth,web3,net,debug" - --authrpc.jwtsecret=/execution_data/jwtsecret - --metrics.expensive - --networkid=1337802 - --http.corsdomain - "*" - --authrpc.addr - "0.0.0.0" - --authrpc.vhosts=* - --http.addr - "0.0.0.0" - --http.vhosts=* - --bootnodes - "enode://c354db99124f0faf677ff0e75c3cbbd568b2febc186af664e0c51ac435609badedc67a18a63adb64dacc1780a28dcefebfc29b83fd1a3f4aa3c0eb161364cf94@164.92.130.5:30303" ports: - containerPort: 8545 name: port - containerPort: 8551 name: secure volumeMounts: - name: geth-merge-devnets-data mountPath: /execution_data volumes: - name: geth-merge-devnets-data persistentVolumeClaim: claimName: geth-merge-devnets-data - name: merge-devnets-genesis-json configMap: name: kiln-genesis-json --- apiVersion: v1 kind: PersistentVolumeClaim metadata: name: geth-merge-devnets-data namespace: eth spec: accessModes: - ReadWriteOnce storageClassName: openebs-hostpath resources: requests: storage: 500Gi --- apiVersion: v1 kind: Service metadata: labels: app: geth-merge-devnets-service project: geth-merge-devnets-service name: geth-merge-devnets-service namespace: eth spec: ports: - protocol: TCP port: 8545 targetPort: 8545 name: port - protocol: TCP port: 8551 targetPort: 8551 name: secure selector: app: geth-merge-devnets lighthouse-beacon-chain-kiln-net.yaml ...

March 17, 2022

TIDB 架构

Reference TIDB architecture 为什么使用 TIDB 机器采用的架构是ARM64。 尝试使用分布式数据库架构。 解决高可用问题,当一台Raspberry Pi数据库节点宕机时,不会影响数据的写入。 对比了vitess和TIDB,TIDB更加兼容ARM64,容易上手实验。 为后面的金融交易系统作准备。 架构 组件及功能 TIDB Server TIDB Server 是一个无状态应用,它本身并不存储数据,前面可以放置负载均衡,外部应用请求到TIDB Cluster中的节点,TIDB server将分析和计算应用请求的SQL,并将请求转发给底层的数据存储TiKV。 PD Server 整个TiDB集群的元信息管理模块,存储每个TiKV节点的数据分布情况,以及集群的整体拓扑情况,根据TiKV节点实时上报的数据分布状态,PD server向TiKV节点发布数据调度命令。 Storage Server TiKV 负责数据存储,是一个提供事务的key-Value分布式存储引擎,存储的基本单位是Region,每个Region存储一个Key Range的数据,每个TiKV节点会负责多个Region,TiDB的SQL对SQL做完解析后,会将SQL的执行计划转化为对TiKV API的实际调用,所有的SQL数据全部存储在TiKV中。 TiFLASH Server 特殊的存储节点,数据存储是以列式的方式进行存储,主要功能式为分析型的场景加速。

January 4, 2022

Volcano高性能引擎

简介 volcano是一个用于高性能工作负载场景下基于kubernets的容器批量引擎。 应用场景: 机器学习以及深度学习 生物以及基因计算 大数据应用 概念 Queue 容纳一组podgroup的队列 apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: distcc spec: weight: 1 reclaimable: false capability: cpu: 50 字段: weight -> 该queue在集群资源划分中所占有的比例,该queue占用的资源比例为: (weight / total-weight) * total-resource,资源软约束。 capability -> queue内所有podgroup使用资源之和的上限,资源硬约束。 reclaimable -> 当该queue在资源使用超过该queue限制时,是否允许其他queue回收该queue使用的超额资源。 使用场景 Total Cluster CPUS = 4cores --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: weight: 1 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test2 spec: weight: 3 # 创建p1 p2 podgroup分别属于test1,test2,分别向p1 p2中投入job1 job2,资源申请分别为1C和3C,两个job均能正常工作 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: weight: 1 # 首先创建test1 queue,创建podgroup p1,在p1中创建job1 job2,资源分配分别为1C和3C,job均能正常工作。 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test2 spec: weight: 3 # 创建test2 queue, 在该queue中创建podgroup p2,在p2中创建job3资源申请为3C,由于test2 queue weight=3,从而job2将被驱逐,test1 3C资源将归还给test2。 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: capability: cpu: 2 # 创建test1 queue,容量设置为2,也就是资源上限使用为2C,创建p1 podgroup,在p1中创建job1 job2资源申请分别为1C和3C,那么job1正常运行,job2处于pending状态 --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test1 spec: weight: 1 reclaimable: false --- apiVersion: scheduling.volcano.sh/v1beta1 kind: Queue metadata: name: test2 spec: weight: 1 # 创建 test1 queue,reclaimable为False,也就是该queue不归还多占用的资源,分别在test1 test2 queue 中创建p1 p2,在p1中创建job1,资源申请为3C,由于权重比例为1:1,此时 test1 多占用1C,在p2中创建job2,资源申请为2C,此时由于test1不归还多占用的资源,job2将处于pending状态。 PodGroup podgroup是一组强关联pod的集合,用于批处理工作负载场景。 ...

June 2, 2021

OpenEBS-For-MinIO

架构

November 24, 2020