NLP实验-251209-RAG知识库大模型应用开发

本文档是针对此次实验的一些补充说明。

目录
  1. 组装
  2. 账号密码
  3. 编辑代码
  4. 输入中文
  5. 离开时,椅子归位,开发板断电
  6. 实验手册
  7. 监控显存命令
  8. Vim操作
  9. 环境部署
  10. 删除docker

组装

当做普通的电脑即可。要连显示屏、鼠标键盘、网线。

桌子上有个小盒子,是英伟达开发板,作为电脑主机。此次实验不使用机械臂。

  • 显示屏-HDMI线。可从机械臂上拔下 HDMI 线,一端接开发板,一端接显示屏。
  • 显示屏-电源线。一端 USB 口,接开发板的 USB 口;一端 Type-C 口,接显示屏的 Type-C 口(有2个,任意接一个即可)。
  • 鼠标键盘。接开发板的 USB 口。
  • 网线。接开发板的网口。
  • 开发板-电源线。在桌子下面,找直角弯头的那个,一端接桌子腿上的插座,直角弯头接开发板。

账号密码

开发板接通电源后,稍等一会,屏幕显示登录。

  • 账号:cg
  • 密码:cgremote

实验手册使用了视觉实验箱(带机械臂的那个),应该也可以。账号密码:jetson / yahboom

如果使用视觉实验箱(带机械臂的那个),屏幕电源线请插桌子下的插座,或者从开发板上接2根线供电给屏幕。


编辑代码

开发板上vim编辑代码

可在开发板上直接编辑代码,或 vim。比如 vim abc.py。进入 vim 后的相关操作方式,可上网查找。

开发板上 vscode 编辑代码

还可以在开发板上安装 vscode,然后用 vscode 编辑代码。

vscode 可能已安装在开发板上,在前几次其他实验时。可点击开发板屏幕左下角的“九宫格”图标(show application),然后查找 vscode,能找到就是已安装。

如尚未安装,可先在开发板上安装 vscode。安装指导请参考:在开发板上安装 vscode

用个人电脑的 vscode 连开发板后编辑代码

也可以在笔记本上的 vscode,直接打开开发板上的代码。如何配置操作,可参考:vscode通过ssh连接服务器实现免密登录+删除(吐血总结)

个人电脑 ssh 登录开发板后用 vim 编辑代码

如需要在 Windows 笔记本通过 SSH 登录开发板,可在 cmd powershell 窗口中,执行 ssh 用户名@开发板的IP地址 登录开发板。比如,ssh cg@172.18.139.108

获取开发板的 IP 地址。ssh 登录开发板,首先需要获得开发板的 IP 地址。在开发板上启动 Terminal(点击屏幕左下角“九宫格”后搜索,或者点击屏幕上的快捷方式),执行 ifconfig | grep 172,执行结果中的 172.18.145.81 就是开发板的 IP 地址。

cg@cg:~$ ifconfig | grep 172
        inet 172.18.145.81  netmask 255.255.255.0  broadcast 172.18.145.255

Windows 电脑还可用 MobaXterm 登录开发板。MobaXterm 可从官网下载,也可点击这里下载:MobaXterm。解压缩下载的 zip 文件,可直接使用,无需安装。

ssh 登录后,启动 vim,进行代码编辑。


输入中文

可以发邮件,写需要的中文,比如:你是谁。然后在开发板上收邮件。

还可以尝试在开发板上安装 搜狗输入法。安装教程可参考官网文档:Ubuntu搜狗输入法安装指南

Google拼音安装指南:链接


离开时,椅子归位,开发板断电

实验结束离开时,

椅子归位

椅子放到桌子下面。

开发板断电

先执行 shutdown -h now

观察开发板的散热风扇。散热风扇停止后,将电源线的弯角插头从开发板拔出。


实验手册

可点击查看或下载:RAG知识库大模型应用开发

监控显存命令

使用jtop查看显存占用

jtop

若无jtop命令,则需先安装

sudo pip3 install -U pip
sudo pip3 install jetson-stats

安装后需要重启设备

sudo reboot

Vim操作

实验过程中需要使用vim命令在终端对文件进行读写操作。 若无vim命令,先安装:

sudo apt-get update
sudo apt-get install vim -y

vim 基本操作:

i 写入
需要在写入模式按Esc后使用命令:
:wq 保存并退出
:q 退出
:w 保存

环境部署

1.控制台输入

git clone https://github.com/dusty-nv/jetson-containers
bash jetson-containers/install.sh

2.安装docker 安装docker,添加docker官方GPG密钥(docker官方文档https://docs.docker.com/engine/install/ubuntu/) 在终端输入

sudo apt-get update
sudo apt-get install ca-certificates curl
sudo install -m 0755 -d /etc/apt/keyrings
sudo curl -fsSL https://mirrors.aliyun.com/docker-ce/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
sudo chmod a+r /etc/apt/keyrings/docker.asc

添加docker仓库到apt源列表(echo这段命令粘贴为单行)

echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
  
sudo apt-get update

安装docker包(出现443 Error表示网络问题,重启终端重试几次)

sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

安装docker后,需要更换docker拉取容器镜像的镜像源

sudo vim /etc/docker/daemon.json

将daemon.json中内容替换为以下内容

{
  "registry-mirrors": [
    "https://docker.1ms.run",
    "https://docker-0.unsee.tech",
    "https://docker.m.daocloud.io"
  ],
  "live-restore": true,
  "features": { "buildkit": true }
}

重启docker服务

sudo systemctl daemon-reload
sudo systemctl restart docker

测试拉取镜像

sudo docker run hello-world

当输出”Hello from Docker! “等内容时,说明docker配置成功

为docker配置NVIDIA Container Toolkit, 终端输入(distribution这行命令粘贴为单行)

distribution=$(. /etc/os-release;echo $ID$VERSION_ID)
curl -s -L https://nvidia.github.io/nvidia-docker/gpgkey | sudo apt-key add -
curl -s -L https://nvidia.github.io/nvidia-docker/$distribution/nvidia-docker.list | sudo tee /etc/apt/sources.list.d/nvidia-docker.list

# 安装nvidia-container-toolkit
sudo apt-get update
sudo apt-get install -y nvidia-container-toolkit
# 生成默认配置(会自动添加nvidia运行时)
sudo nvidia-ctk runtime configure --runtime=docker
# 重启Docker服务使配置生效
sudo systemctl restart docker

3.配置jetson-containers环境,输入:

# Ollam:llava will be our multimodel model
jetson-containers run --name ollama $(autotag ollama)
ollama run llava

安装本实验所需的llava模型。

2025-05-07 17-01-40屏幕截图

若配置jetson-containers环境时,关于“tuple”报错,手动修改python版本报错信息

sudo vim /home/cg/jetson-containers/jetson_containers/l4t_version.py

在l4t_version.py中添加导入

from typing import Tuple

同时将函数_parse_python_ver_and_nogil的返回值类型从tuple[Version, bool]修改为Tuple[Version, bool]:

def _parse_python_ver_and_nogil(s) -> Tuple[Version, bool]:

4.打开新的终端,输入

cd jetson-containers
jetson-containers run $(autotag l4t-pytorch)

安装相关依赖torch

2025-05-07 17-07-58屏幕截图

代码编写 控制台输入

cd data
mkdir Multimodal-RAG-on-Jetson
cd ./Multimodal-RAG-on-Jetson

进行代码编写: 创建 multiRAG.py 文件

import os
from moviepy.editor import VideoFileClip  # 用于处理视频文件,如提取音频和帧
import whisper  # 用于语音识别,将音频转为文本

from llama_index.core import SimpleDirectoryReader  # 读取目录中的文档
from llama_index.core import VectorStoreIndex  # 创建向量存储索引
from llama_index.embeddings.huggingface import HuggingFaceEmbedding  # 使用 HuggingFace 的嵌入模型
from llama_index.llms.ollama import Ollama  # 连接到 Ollama 大语言模型
from llama_index.core import Settings  # 设置全局的 LLM 和嵌入模型

from llama_index.core.schema import ImageDocument  # 表示图像文档
from llama_index.multi_modal_llms.ollama import OllamaMultiModal  # 使用支持多模态的 Ollama 模型

from pydub import AudioSegment  # 用于操作音频文件
from pydub.utils import make_chunks  # 将音频文件分割成小块

class VideoProcessor:
    """
    视频处理器类,用于从视频中提取音频、分段音频、提取文本和关键帧。
    """
    def __init__(self, video_path, output_audio_path, image_path, text_path):
        self.video_path = video_path  # 视频文件路径
        self.output_audio_path = output_audio_path  # 输出音频文件的路径
        self.image_path = image_path  # 提取图像的保存路径
        self.text_path = text_path  # 提取文本的保存路径

    def extract_audio(self):
        """
        从视频中提取音频并保存为 mp3 格式。
        """
        video = VideoFileClip(os.path.join(self.video_path, "video.mp4"))
        audio_part = video.audio
        audio_part.write_audiofile(os.path.join(self.output_audio_path, "output_audio.mp3"))

    def segment_audio(self):
        """
        将音频文件分割成小块(2秒),便于后续处理。
        """
        audio = AudioSegment.from_mp3(os.path.join(self.output_audio_path, "output_audio.mp3"))
        chunk_length_ms = 2000
        chunks = make_chunks(audio, chunk_length_ms)
        for i, chunk in enumerate(chunks):
            chunk_name = os.path.join(self.output_audio_path, f"{i}.mp3")
            chunk.export(chunk_name, format="mp3")
        os.remove(os.path.join(self.output_audio_path, "output_audio.mp3"))

    def extract_text(self):
        """
        使用 Whisper 模型将音频转为文本,并记录时间戳。
        """
        model = whisper.load_model("base.en")
        audio_text = ''
        for filename in os.listdir(self.output_audio_path):
                file_path = os.path.join(self.output_audio_path, filename)
                result = model.transcribe(file_path)
                time = int(filename[:-4]) * 2
                audio_text += str(f'At time {time}s:') + result['text'] + '\n'
        with open(os.path.join(self.text_path, "audio.md"), "w") as file:
            file.write(audio_text)
            file.close()

    def extract_frames(self):
        """
        从视频中提取关键帧,按照一定频率保存为图片。
        """
        clip = VideoFileClip(os.path.join(self.video_path, "video.mp4"))
        clip.write_images_sequence(os.path.join(self.image_path, "%04d.png"), fps=0.5)

    def process_video(self):
        """
        执行视频处理流程:提取音频 -> 分割音频 -> 转换为文本 -> 提取关键帧。
        """
        self.extract_audio()
        self.segment_audio()
        self.extract_text()
        self.extract_frames()


class translate_image_to_text:
    """
    图像转文本类,用于对提取的图像进行描述并构建问答系统。
    """
    def __init__(self, image_path, text_path):
        self.image_path = image_path  # 图像文件路径
        self.text_path = text_path  # 文本输出路径
        self.response = ''  # 存储图像描述的响应

    def get_image_path(self):
        """
        获取所有图像文件的路径。
        """
        image_folder = self.image_path
        image_files = [os.path.join(image_folder, f) for f in os.listdir(image_folder) if os.path.isfile(os.path.join(image_folder, f))]
        return image_files

    def image_to_text(self):
        """
        使用多模态模型对每张图像生成描述,并保存为文本文件。
        """
        mm_model = OllamaMultiModal(model='llava', temperature=0) 
        image_file_names = self.get_image_path()
        for image in image_file_names:
            print(image)
            time = 2*int(image[8:-4])
            self.response += str(f'At time {time}s:')+ str(mm_model.complete(prompt='summarize the image and output as markdown format with one line', image_documents=[ImageDocument(image_path=image)])) + '\n' 
        with open(self.text_path+'image.md', 'w') as file:
                file.write(self.response)
                file.close()

    def reply(self):
        """
        构建查询引擎,允许用户提问并获取基于文本内容的回答。
        """
        # embed_model = TextEmbeddingsInference(model_name="BAAI/bge-large-en-v1.5")
        embed_model = HuggingFaceEmbedding(model_name="BAAI/bge-small-en")
        llm = Ollama(model='llava', request_timeout=100, temperature=0)
        Settings.llm = llm
        Settings.embed_model = embed_model
        data = SimpleDirectoryReader(self.text_path).load_data()
        index = VectorStoreIndex.from_documents(data)
        query_engine = index.as_query_engine(similarity_top_k=3)
        while True:
            try:
                user_input = input('\033[94m' +"Prompt: " + '\033[0m')
                response = query_engine.query(user_input)
                print(response)
            except KeyboardInterrupt:
                break

if __name__ == '__main__':

    video_path = './video/'
    output_audio_path = './audio/'
    image_path = './image/'
    text_path = './text/'
    # output_folder= './output/'
# process video to images and text
    processor = VideoProcessor(video_path, output_audio_path, image_path, text_path)
    processor.process_video()

    text = translate_image_to_text(image_path=image_path, text_path=text_path)
    text.image_to_text()
    text.reply()

创建 run.sh 文件

#!/bin/sh

mkdir ./audio
mkdir ./text
mkdir ./image
sudo apt update && sudo apt install ffmpeg -y

PIP_MIRROR="-i https://pypi.tuna.tsinghua.edu.cn/simple"
PIP_TRUST="--trusted-host pypi.tuna.tsinghua.edu.cn"
PIP_OPTS="$PIP_MIRROR $PIP_TRUST --default-timeout=180"

pip install $PIP_OPTS pydub
pip install $PIP_OPTS -U openai-whisper
pip install $PIP_OPTS llama-index
pip install $PIP_OPTS llama-index-multi-modal-llms-ollama
pip install $PIP_OPTS llama-index-llms-ollama
pip install $PIP_OPTS llama-index-llms-huggingface
pip install $PIP_OPTS moviepy
pip install $PIP_OPTS llama-index-embeddings-huggingface
pip install $PIP_OPTS llama-index-vector-stores-lancedb
pip install $PIP_OPTS llama-index-embeddings-clip
pip install git+https://github.com/openai/CLIP.git
export HF_ENDPOINT=https://hf-mirror.com
export LD_PRELOAD=/usr/local/lib/python3.8/dist-packages/scikit_learn.libs/libgomp-d22c30c5.so.1.0.0
python3 ./multiRAG.py

实际测试 创建video文件夹,将video.mp4视频文件放入其中 完成代码编写后,控制台输入

bash run.sh

运行代码 可以看到,导入本地视频和图像后,可以对视频进行提问,测试成功。

2025-05-07 17-49-31屏幕截图

2025-05-07 17-53-24屏幕截图

若传入video.mp4时权限不足,解锁当前文件夹(username处输入当前用户名)

sudo chown -R username Multimodal-RAG-on-Jetson

如果运行run.sh运行报错:

AttributeError: 'GenerateResponse' object has no attribute 'items'

需手动修改报错信息,打开如下路径文件:

vim /usr/local/lib/python3.8/dist-packages/llama_index/multi_modal_llms/ollama/base.py

将源代码

def get_additional_kwargs(response, exclude):
    return {k: v for k, v in response.items() if k not in exclude}

修改为

def get_additional_kwargs(response, exclude):
    # 将 Pydantic 模型转换为字典,再调用 items()
    return {k: v for k, v in response.dict().items() if k not in exclude}

如果进行视频prompt提问时报错:

ValueError: "ChatResponse" object has no field "usage"

需手动修改报错信息,打开如下路径文件:

vim /usr/local/lib/python3.8/dist-packages/llama_index/llms/ollama/base.py

将下列代码注释掉(共两处)

if token_counts:
    response["usage"] = token_counts

删除docker

实验结束后,删除docker相关文件

sudo apt purge docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin

Back to top

© George Donne 2024-2025. All Rights Reserved. 苏ICP备2021027062号-1