NAS系列-补充:immich优化

优化原因

  1. 人脸识别本来就是机器学习方向的东西,会非常吃 cpu
  2. 地图语言版本没有完全汉化,有点不爽
  3. 逆地理编码经常不准

优化目的

  1. 调用独显加速,nvidia 环境
  2. 更换地图显示
  3. 构造逆地理编码数据

优化前提

  1. 已经下载人脸识别模型 buffalo_l 数据,已经可以成功调用并识别出人脸
  2. 已经安装好 nvidia-driver
  3. 注册有 maptiler.com 的账号

nvidia 加速

首先配置好 dockercuda 环境,具体步骤可以看手册,这里就直接照搬了,省得各位还要吃力看英文文档。

  • 宿主机,安装 nvidia-container-toolkit,给 docker 准备的

    bash 复制代码
    # 添加软件源
    curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg \
    && curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | \
    sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | \
    sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list
    # 启用实验特性
    sed -i -e '/experimental/ s/^#//g' /etc/apt/sources.list.d/nvidia-container-toolkit.list
    # 更新源
    sudo apt-get update
    # 安装
    sudo apt-get install -y nvidia-container-toolkit

    要注意的是,某个新的版本之后需要 535 以上版本的 nvidia-driver。还有,如果是 ubuntu 系统,记得把 ubuntu 的软件静默更新给关了,不然后台更新显卡驱动,到时候会出问题。

  • 宿主机,配置 docker 环境

    bash 复制代码
    sudo nvidia-ctk runtime configure --runtime=docker
    sudo systemctl restart docker
  • docker-compose.yml,此时 docker-compose 需要把 nvidia 的环境配置进去

    yml 复制代码
    immich-machine-learning:
      container_name: immich_machine_learning
      # 南大加速,ghcr.nju.edu.cn替换ghcr.io,注意版本,硬件加速有专门的镜像
      image: ghcr.nju.edu.cn/immich-app/immich-machine-learning:gpu
      volumes:
        - ${IMMICH_MODEL_CACHE_PATH}:/cache
      restart: unless-stopped
      environment:
        - TZ=Asia/Shanghai
      runtime: nvidia
      deploy:
        resources:
          reservations:
            devices:
              - capabilities: [gpu]
  • 验证:执行 docker compose up -d 构建容器,然后在容器内执行 nvidia-smi

    bash 复制代码
    docker exec -it immich_machine_learning nvidia-smi

    输出显卡信息即表示容器可以正常调用显卡,并可以使用 cuda 环境

更换地图底图

按照官网文档操作即可,这里仅作转载,浓缩一下操作步骤

  • 登录 cloud.maptiler.com
  • 新建地图 NEW MAP
  • 选择地图类型,然后自定义 CUSTOMIZE
  • 左侧有几个小图标菜单,点击 Settings,然后在子菜单里,Language 选择 Chinese
  • 调整地图,然后点击在菜单的 Map origin 右侧十字定位图标即可设置当前地图显示为初始位置
  • 点击右上角 Publish 发布
  • 发布后在地图页面,有个 Use vector style,将该链接添加到 immich 管理界面的地图主题中即可

immich 逆地理编码优化

  • 查源码
    源码内,逆地理编码返回的是一个 {country, state, city},国家、省份、城市三级结构。再看一下 countryadmin1CodesASCII.txt 里面拿的,state 是从 admin2Codes.txt 拿的,具体坐标是从 cities500.txt 拿的。看一下数据库的表,主要字段定义为:
json 复制代码
{
    id: Number.parseInt(lineSplit[0]),
    name: lineSplit[1],
    alternateNames: lineSplit[3],
    latitude: Number.parseFloat(lineSplit[4]),
    longitude: Number.parseFloat(lineSplit[5]),
    countryCode: lineSplit[8],
    admin1Code: lineSplit[10],
    admin2Code: lineSplit[11],
    modificationDate: lineSplit[18],
    admin1Name: admin1Map.get(`${lineSplit[8]}.${lineSplit[10]}`),
    admin2Name: admin2Map.get(`${lineSplit[8]}.${lineSplit[10]}.${lineSplit[11]}`),
}

这里的 lineSplit 就是 cities500.txt 的行,这时候再看 cities500 的字段定义

txt 复制代码
geonameid         : integer id of record in geonames database
name              : name of geographical point (utf8) varchar(200)
asciiname         : name of geographical point in plain ascii characters, varchar(200)
alternatenames    : alternatenames, comma separated, ascii names automatically transliterated, convenience attribute from alternatename table, varchar(10000)
latitude          : latitude in decimal degrees (wgs84)
longitude         : longitude in decimal degrees (wgs84)
feature class     : see http://www.geonames.org/export/codes.html, char(1)
feature code      : see http://www.geonames.org/export/codes.html, varchar(10)
country code      : ISO-3166 2-letter country code, 2 characters
cc2               : alternate country codes, comma separated, ISO-3166 2-letter country code, 200 characters
admin1 code       : fipscode (subject to change to iso code), see exceptions below, see file admin1Codes.txt for display names of this code; varchar(20)
admin2 code       : code for the second administrative division, a county in the US, see file admin2Codes.txt; varchar(80) 
admin3 code       : code for third level administrative division, varchar(20)
admin4 code       : code for fourth level administrative division, varchar(20)
population        : bigint (8 byte int) 
elevation         : in meters, integer
dem               : digital elevation model, srtm3 or gtopo30, average elevation of 3''x3'' (ca 90mx90m) or 30''x30'' (ca 900mx900m) area in meters, integer. srtm processed by cgiar/ciat.
timezone          : the iana timezone id (see file timeZone.txt) varchar(40)
modification date : date of last modification in yyyy-MM-dd format

所以,cities500 这里只用了 geonameidnamealternatenameslatitudelongitudecountry codeadmin1 codeadmin2 codemodification date,搜了一下,alternatenames 甚至都没用到,所以无所谓,留空也行。还有两个参数:admin1Mapadmin2Map,源码是分别拿 admin1CodesASCII.txtadmin2Codes.txt 的第一列当 key,第二列当 value 组成这两个数据,这两个文件后两列的内容也不用关心。好,数据分析完成,开始构造!

  • geonameid
    这里直接就用咱国家自己的行政区划的代码就行了,4 级行政结构到 镇/街道 一级,讲道理,我们用到这个就行了。行政区划代码 1-2 位为省级代码,3-4 位为市级代码,5-6 位为县级代码,7-9 位为镇级代码,我们就以区划代码为 110101001000北京市东城区东华门街道 作为例子,构造我们第一条 cities500 数据。

  • admin1CodesASCII.txt
    因为 cities500 需要国家和省份代码,而这个文件记录的就是国家和省份的代码,按照我们的行政区划来,北京市 的代码就是 CN.11,第一列是代码,第二列是名称 北京市,第三第四列内容随便。

  • admin2Codes.txt
    按照原来的结构,也是有四列,第一列除了城市代码,还包括了国家和省份代码,这里因为 北京市 是直辖市,下辖没有市一级的单位,因此 2-3 位固定为 01,代码变成 CN.11.01,第 2 列可以留空或者也直接填写 北京市,三四列内容随便。

  • cities500.txt
    主要的内容来啦!这个文件主要的字段,分别在第 1/2/4/5/6/9/11/12/19 列,因为我们只细化到 镇/街道 一级,第 1 列就是对应的代码 110101001,第 2 列,就是 immich 照片详情里显示的 city,这里要细化,我们直接填 北京市东城区东华门街道,第 4 列随意,我直接留空,第 56 列填坐标,WGS84 格式,去百度高德或者天地图那里都能抓,第 911 列需要跟 admin1CodesASCII.txt 里的对应,分别填 CN11,第 12 列就是城市代码,填区划代码的第 5-6 位,第 19 列随便填个时间,格式为 yyyy-MM-dd

  • 三个文件结构预览

    • admin1CodesASCII.txt
    bash 复制代码
    # | 实际为 tab,这里只是体现具体结构
    CN.11   |   北京市  |   xxx |   xxx
    • admin2Codes.txt
    bash 复制代码
    # | 实际为 tab,这里只是体现具体结构,因为北京是直辖市,第二列为空,也可以再写一次北京市
    CN.11.01    |  北京市 |   xxx |   xxx
    • cities500.txt
    txt 复制代码
    # | 实际为 tab,这里只是体现具体结构
    110101001|东城区东华门街道|dongchengqu|东华门街道|39.917901|116.390731|xxx|xxx|CN|xxx|11|01|xxx|xxx|xxx|xxx|xxx|xxx|2024-12-10
  • i18n-iso-countries
    这个是用在项目里实现国际化的库,在逆地理编码查询之后显示的国家名由这个提供,而项目默认返回的是 en 版本,所以要想逆地理编码的显示全部显示中文,还需要更改里面的 en.json 文件,把 CN 对应的值改为 中国MO 对应改为 澳门HK 对应改为 香港TW 对应改为 台湾

  • 关于部分数据的说明

    • 我国行政区划代码为 12 位,每一级行政区域对应的代码,只代表本级的名称,低位全为 0,我们级别只到镇一级,村/居委会 一级的末尾 3 位并不需要,因此省略,所以 geonameid 使用 9 位的代码。
    • 村/居委会 一级全国有 60多万 ,数据量很大,而且照片又不是每个村都有,没必要细化到这一级,镇级 4万多 个点足够用了。
    • 只使用镇级,还有一个原因是因为经纬度数据是由高德地图/百度地图/天地图api 抓取,而 api 每天调用是限制次数的,数据量太大需要很长时间去抓。
    • 还有个只用到镇级最重要的原因,区划代码 12 位,但是数据库里 geonameid 的类型是 4 个字节的 integer,最大值只有 2147483647,会报错!
    • geoNames 的城市代码和我国的行政区划代码不一致,甚至有冲突,所以还是建议新建一个数据文件,只放所需要地点的经纬度即可,毕竟都能自建相册服务器还查到我这篇文章去研究优化了,想必也没有到处旅游的爱好,比如我,只放了我去过的几个省市的经纬度数据。
    • cities500.txt 的第 2 列最终会变成一个个集合相册的名称,过于细化只会导致地点分类那里变得凌乱
    • cities500.txt 的经纬度数据使用的坐标系是 GPS 原始的 WGS84,高德使用 GCJ02,百度使用 BD09,天地图使用 CGCS2000,其中只有 CGCS2000WGS84 是最接近的,一般用途上可以直接使用,另外两个都得做变换。
    • geoNames 的文件对应在容器里的 /build/geodata 文件夹内,i18n-iso-countries 对应路径为 /usr/src/app/node_modules/i18n-iso-countries,因此做修改时需要将这两个文件夹从容器里映射出来。
    • 凡是修改了 geoNames 内文件的内容,改一下目录下的 geodata-date.txt 里的时间,服务启动的时候代码会检测这个时间跟上次导入数据的时间是否一致,不一致则重新导入,更改的时间没有要求,只要不一样就行。
    • 关于 cities500,别问,我不会提供现成的文件,带经纬度的地理位置信息是有点敏感的东西,需要的话可以用这个项目数据自己抓,在规则里玩才没人管

后续计划

本来也想给项目贡献代码,然而一是没时间,二是对 nestjssvelte 不熟,也没写过 flutter,目前只好另辟蹊径先改着凑活用一用。

相关推荐
清风 0015 分钟前
一、使用 mdadm 工具在 Ubuntu 上创建 RAID 1(镜像)
运维·服务器·数据库
程序员大金1 小时前
基于SpringBoot+Vue的驾校管理系统
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
XY.散人1 小时前
初识Linux · 日志编写
linux·服务器
机智阳2 小时前
介绍一个InnoDB的数据页,和B+树的关系是什么?
java·数据结构·分布式·后端·b树
啊松同学2 小时前
【Spring】使用@Async注解后导致的循环依赖问题
java·后端·spring
rock——you2 小时前
django通过关联表字段进行排序并去重
数据库·后端·postgresql·django
Karoku0662 小时前
【自动化部署】Ansible 基础命令行模块
运维·服务器·数据库·docker·容器·自动化·ansible
小马爱打代码3 小时前
Spring Boot集成ShedLock实现分布式定时任务
spring boot·分布式·后端
m0_748247803 小时前
如何使用Node.js快速创建本地HTTP服务器并实现异地远程访问
服务器·http·node.js
ccnnlxc4 小时前
prometheus
linux·服务器·prometheus