NAS系列-补充:immich优化

优化原因
  1. 人脸识别本来就是机器学习方向的东西,会非常吃 cpu
  2. 地图语言版本没有完全汉化,有点不爽
  3. 逆地理编码经常不准
优化目的
  1. 调用独显加速,nvidia 环境
  2. 更换地图显示
  3. 构造逆地理编码数据
优化前提
  1. 已经下载人脸识别模型 buffalo_l 数据,已经可以成功调用并识别出人脸
  2. 已经安装好 nvidia-driver
  3. 注册有 maptiler.com 的账号
nvidia 加速

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

  • 宿主机,安装 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},国家、省份、城市三级结构。再看一下 country 是 admin1CodesASCII.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 甚至都没用到,所以无所谓,留空也行。还有两个参数:admin1Map 和 admin2Map,源码是分别拿 admin1CodesASCII.txt 和 admin2Codes.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 里的对应,分别填 CN 和 11,第 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,其中只有 CGCS2000 和 WGS84 是最接近的,一般用途上可以直接使用,另外两个都得做变换。
    • geoNames 的文件对应在容器里的 /build/geodata 文件夹内,i18n-iso-countries 对应路径为 /usr/src/app/node_modules/i18n-iso-countries,因此做修改时需要将这两个文件夹从容器里映射出来。
    • 凡是修改了 geoNames 内文件的内容,改一下目录下的 geodata-date.txt 里的时间,服务启动的时候代码会检测这个时间跟上次导入数据的时间是否一致,不一致则重新导入,更改的时间没有要求,只要不一样就行。
    • 关于 cities500,别问,我不会提供现成的文件,带经纬度的地理位置信息是有点敏感的东西,需要的话可以用这个项目数据自己抓,在规则里玩才没人管
后续计划

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值