1. 先 git clone tensorflow 的仓库,可以在 github 也可以在 gitee, gitee 会比 github 慢一天左右。但是下载速度快多了。

git clone https://github.com/tensorflow/tensorflow.git
git clone https://gitee.com/mirrors/tensorflow.git

2. 确定环境里面有 g++, gcc, ar

3. 下载需要的依赖

./tensorflow/lite/tools/make/download_dependencies.sh

下载的依赖文件在 ./tensorflow/lite/tools/make/downloads 文件夹下面

4. 修改 Makefile

vim ./tensorflow/lite/tools/make/Makefile

把里面的

CXX := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}g++
CC := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}gcc
AR := $(CC_PREFIX)${TARGET_TOOLCHAIN_PREFIX}ar

这三行,修改为对应的 g++, gcc, ar

4. 编译为库

./tensorflow/lite/tools/make/build_aarch64_lib.sh

生成的静态库文件在 tensorflow/lite/tools/make/gen/aarch64_armv8-a/lib/libtensorflow-lite.a

参考: https://tensorflow.google.cn/lite/guide/build_arm64?hl=zh-cn

5. 抽取 tflite 的头文件,并打包

cd tensorflow/tensorflow
find ./lite -name "*.h" | tar -cf headers.tar -T -

这个 headers.tar 里面包含了头文件和一些不需要的东西。 注意:有些头文件在 tensorflow/tensorflow/lite/tools/make/downloads 这个下载的包里面。比如说 flatbuffers,要把他们专门复制到相应的头文件夹下面。 include 头文件夹下面的组织形式

[xxx@localhost include]$ tree -L 3
.
├── downloads
│   └── include
│       └── flatbuffers
└── tensorflow
    └── lite
        ├── allocation.h
        ├── arena_planner.h
        ├── builtin_op_data.h
        ├── builtin_ops.h
        ├── c
        ├── context.h
        ├── context_util.h
        ├── core
        ├── delegates
        ├── error_reporter.h
        ├── examples
        ├── experimental
        ├── external_cpu_backend_context.h
        ├── graph_info.h
        ├── interpreter_builder.h
        ├── interpreter.h
        ├── java
        ├── kernels
        ├── memory_planner.h
        ├── micro
        ├── minimal_logging.h
        ├── model_builder.h
        ├── model.h
        ├── mutable_op_resolver.h
        ├── nnapi
        ├── op_resolver.h
        ├── optional_debug_tools.h
        ├── profiling
        ├── python
        ├── schema
        ├── simple_memory_arena.h
        ├── stderr_reporter.h
        ├── string_type.h
        ├── string_util.h
        ├── testing
        ├── tflite_with_xnnpack_optional.h
        ├── toco
        ├── tools
        ├── type_to_tflitetype.h
        ├── util.h
        └── version.h

20 directories, 26 files

参考: https://blog.csdn.net/shui123546yi/article/details/105410781

6. 把前面编译好的静态库也复制到 lib 文件夹下面。

7. 编写 cmake 文件

#注意:如果工程有依赖库的话,ADD_EXECUTABLE指令要放在LINK_DIRECTORIES指令之后,
#       不然会报错:Linking C executable main
#                   /usr/bin/ld: cannot find -lhello
#                   collect2: ld 返回 1

#1) 设置 cmake 的最低版本
cmake_minimum_required(VERSION 3.10)

#2) 设置 project 名称
project(tflite_test)

#3) 设置代码源文件列表
set(SRC_LIST main.cpp model.cpp)

#4) 增加头文件搜索路径,解决编译期间找不到头文件的问题
#COMMAND: INCLUDE_DIRECTORIES([AFTER|BEFORE] [SYSTEM] dire1 dire2 ...)
#定义:向工程添加多个特定的头文件搜索路径,路径之间用空格分开,
#       如果路径中包含空格,可以使用双引号括起来
#       默认是追加到当前的头文件搜索路径之后,你可以用2种方式控制搜索路径的添加>方式
#       1)CMAKE_INCLUDE_DIRECTORIES_BEFORE 通过SET设置其为on,使用前置模式
#       2)通过AFTER或BEFORE参数,控制追加还是置前
include_directories("/usr/include/x86_64-linux-gnu")
include_directories("./include")
include_directories(".")
include_directories("./include/downloads/include")

#5) 增加库文件: 解决链接期间找不到调用外部接口的问题
#main.cpp:(.text+0x5): undefined reference to `HelloFunc()'
#collect2: error: ld returned 1 exit status

#6) 增加库文件搜索路径:解决链接期间找不到库文件的问题
#COMMAND: LINK_DIRECTORIES(dir1 dir2 ...)
#定义:添加非标准的共享库搜索路径
#/usr/bin/ld: cannot find -lhello
#collect2: error: ld returned 1 exit status
#好像相对路径会找不到库文件
link_directories("/usr/lib/x86_64-linux-gnu")
link_directories("./lib")

#7) 生成二进制文件
add_executable(${PROJECT_NAME} ${SRC_LIST})

#8) 链接库
#COMMAND: TARGET_LINK_LIBRARIES(target  library1
#                                <debug | optimized> library2
#                                ...)
#定义:用来为target添加需要链接的共享库
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} hello) #链接动态库指令
#TARGET_LINK_LIBRARIES(${PROJECT_NAME} libhello.a)  #链接静态库指令
target_link_libraries(${PROJECT_NAME} PRIVATE tensorflow-lite pthread ${CMAKE_DL_LIBS})

注意:如果提示没有 undefined reference to dlopen ,undefined reference to pthread_create 别忘了在链接库里面添加 pthread ${CMAKE_DL_LIBS}

参考:

https://github.com/jiangxinyang227/nlp_tflite/blob/master/cpp_tflite/src/inference.cpp https://www.cnblogs.com/jiangxinyang/p/13215724.html https://github.com/tensorflow/tensorflow/tree/master/tensorflow https://tensorflow.google.cn/lite/microcontrollers/get_started https://www.cnblogs.com/vitoyeah/p/10273299.html https://github.com/gdyshi/model_deployment/blob/master/tflite/C%2B%2B/model.cc https://github.com/gdyshi/model_deployment/blob/master/tflite/C%2B%2B/example.cc https://github.com/gdyshi/model_deployment https://blog.csdn.net/chongtong/article/details/90379347 https://blog.csdn.net/chongtong/column/info/39386 https://blog.csdn.net/chongtong/article/details/95355814

1. shell 单行注释使用 “#” 就可以了,多行注释:

:<<EOF

EOF

这个 EOF 可以换成其他,都可以,只要上下能够对应就可以。

参考:https://blog.csdn.net/lansesl2008/article/details/20558369 https://blog.csdn.net/tenfyguo/article/details/5753548

2. 检查文件是否存在:

if [ -f trials ]; then 
      rm trials
fi

参考: https://www.jb51.net/article/186273.htm

3. 退出脚本

exit 1

参考: https://blog.csdn.net/qq_35769944/article/details/81943543

4. 变量养成使用 {} 包起来的习惯

参考: https://www.runoob.com/linux/linux-shell-variable.html

5. 需要 python 脚本的时候,直接使用即可。

python3 test.py

参考: https://blog.csdn.net/zwt0909/article/details/52368559

6. -eq 更多用于数值的比较,字符串比较使用 ==

参考: https://www.jb51.net/article/56559.htm

7. 与逻辑: && 或者 -a,或逻辑: || 或者 -o

参考: https://blog.csdn.net/iamlihongwei/article/details/59114828 https://www.cnblogs.com/aaronLinux/p/8340281.html

8. 判断命令行参数缺失

if [ -z $1 ];then
      echo "You should input one parameter"
fi

参考: https://blog.csdn.net/geoffreychan/article/details/77823505

9. ssh 远程执行命令

ssh需要直接用密码执行命令需要在本地安装 sshpass

sudo apt install sshpass
ip="192.168.1.2"
user="xyz"
pswd="123456"

sshpass -p ${pswd} ssh ${user}@${ip} "cd /home ; ls"

在远程执行的命令需要用双引号包含起来,不同命令需要用分号隔开。

或者类似下面也可以

#!/bin/bash
ssh user@remoteNode > /dev/null 2>&1 << remotessh
cd /home
touch abcdefg.txt
exit
remotessh
echo done!

<< remotessh 和 remotessh 之间的内容在远程执行,别忘了用 exit 退出 ssh。重定向在于不显示远程输出。

参考: https://blog.csdn.net/jinking01/article/details/84386769 https://www.cnblogs.com/kaishirenshi/p/7921308.html

10. 自动输入密码 需要先安装 expect,然后使用 expect 命令

expect <<EXPECT_EOF
spawn sudo smbpasswd -a xyz
expect "New SMB password:"
send "123456\r"
expect "Retype new SMB password:"
send "123456\r"
expect eof
EXPECT_EOF

或者:

expect -c "
       spawn sudo smbpasswd -a xyz
       expect {
              \"New SMB password:\" {set timeout 300; send \"123456\r\";}
          \"Retype new SMB password:\" {send \"123456\r\"}
    }
#expect eof"

expect eof 是和 spawn 配对使用的。 在 bash 中直接用 expect,有两种用法,1. expect <<EXPECT_EOF EXPECT_EOF 这样配对使用; 2. expect -c " " 这样双引号之间使用。 {send "yes\r"; exp_continue;} 这样的用法,exp_continue 表示这个 expect 的 内容和 send 内容可以重复多次使用。

参考: https://www.cnblogs.com/old-path-white-cloud/p/11678517.html https://www.cnblogs.com/sharktech/p/7454767.html https://blog.csdn.net/zhongbeida_xue/article/details/78679549

https://blog.csdn.net/weixin_34354173/article/details/91895917 https://blog.csdn.net/zhangjikuan/article/details/51105166 https://www.cnblogs.com/lixigang/articles/4849527.html https://www.cnblogs.com/autopenguin/p/5918717.html

https://www.cnblogs.com/taosim/articles/3785817.html https://www.linuxidc.com/Linux/2017-02/140365.htm https://developer.aliyun.com/article/512290 https://blog.csdn.net/dongqing27/article/details/83108877

11. yes 命令可以一直输入 yes,直到被 kill 掉。

mkdir test
touch test/test.txt

yes | rm -rf ./test

kill -9 $(pidof yes)

类似于上面这种写法。 参考: https://blog.csdn.net/yasi_xi/article/details/8562002 https://www.linuxcool.com/yes https://man.linuxde.net/yes https://www.cnblogs.com/jins-note/p/9636969.html

12. patch 需要先安装 patch 包。

首先先把文件复制出来,修改,然后用 diff 生成 patch 文件

cp /etc/samba/smb.conf ./
vim smb.conf
diff -c /etc/samba/smb.conf smb.conf > smb_conf.patch

diff -c 选项是详细信息。

patch /etc/samba/smb.conf smb_conf.patch

参考: https://www.cnblogs.com/cute/archive/2011/04/29/2033011.html

13. 使用 scp 发送数据到远程

sshpass -p ${pswd} scp ~/bin/smb_conf.patch ${user}@${ip}:/home/${user}

参考: https://www.runoob.com/linux/linux-comm-scp.html

14. sudo 自动输入密码

echo "admin" | sudo -S service tomcat7 stop

参考: https://blog.csdn.net/wangbole/article/details/17579463

15. 代码块的结束符 EOF 之类的一定要顶格写,不要有空格,否则会报错,类似下面这样:

chmod_file()
{
    echo "chmod file"
    # ssh remote and exec command
    sshpass -p ${pswd} ssh ${user}@${ip} <<EOF

    chmod 400 ./.ssh/id_rsa
    chmod 644 ./.ssh/id_rsa.pub

    exit
EOF
}

16. 简单的 yes no免输入交互

echo "y" | rm /mnt/speech/.ssh/id_rsa*

17. 数组

array_name=(value1 value2 ... valuen)
array_name=()
array_name[0]=value0
array_name[1]=value1
array_name[2]=value2

echo "第一个元素为: ${array_name[0]}"

echo "数组的元素为: ${array_name[*]}"
echo "数组的元素为: ${array_name[@]}"

echo "数组元素个数为: ${#array_name[*]}"
echo "数组元素个数为: ${#array_name[@]}"

参考: https://www.runoob.com/linux/linux-shell-array.html

18. shell for 循环遍历数组

a=("Fdf" "df" "fd")
for str in ${a[@]};do
echo $str
done

参考: https://blog.csdn.net/weiwjacsdn/article/details/80368666

19. 函数参数使用 $1, $2 这样的。

参考: https://www.runoob.com/linux/linux-shell-func.html

20. 字符串按照空格拆分为数组

STR="123 A1 A2"
ARR=($STR)
echo "${ARR[0]}:${ARR[1]}:${ARR[2]}

参考: https://blog.csdn.net/weixin_44687868/article/details/108379011

21. 数组作为参数传递,也必须使用 ${xyz[*]} 这样形式的。

参考: https://blog.csdn.net/mydriverc2/article/details/78931628

22. 数组作为参数通过命令行传递,两种方法,一种是直接多个参数,还有一种是使用 " 双引号把数组框起来。

参考: https://www.runoob.com/linux/linux-shell-passing-arguments.html

23. 判断是否以 某个字符开头,比如 [ 这样的数组。

if [[ $cases =~ ^\[.* ]]; then
    casesStr=`cat ${target_json} |jq .cases[]| sed 's/\"//g'`
    cases=($casesStr)
else
    cases=($cases)
fi
echo "cases: ==> $cases"

参考: https://www.cnblogs.com/LiuYanYGZ/p/12491673.html

24. 从 json 文件中读取使用 jq 命令,获取数值的时候,如果只是字符串,那么使用 jq .abc 这样,如果是数组,那么使用 jq .abc[]

cases=`cat ${target_json} |jq .cases| sed 's/\"//g'`
casesStr=`cat ${target_json} |jq .cases[]| sed 's/\"//g'`

参考: https://www.cnblogs.com/nul1/p/12228785.html#3%E8%BE%93%E5%87%BA%E6%95%B0%E7%BB%84%E7%9A%84%E5%80%BC

25. find 控制搜索深度 使用 -maxdepth 这个参数, 使用 -type d 表明搜索的是目录。

find  ./  -maxdepth 3 -type d 

参考: https://blog.csdn.net/lmmcu_2012/article/details/52703395

26. sed 可以用来替换字符, s/old/new/g 这样的方式即可。

casesStr=`cat ${target_json} |jq .cases[]| sed 's/\"//g'`

参考: https://www.runoob.com/linux/linux-comm-sed.html

今天碰到一个情况,分辨率太大,导致左下角的菜单显示不出来,无法调整分辨率。

cd /usr/share/applications
sudo lxrandr

就可以运行分辨率设置的程序了。

1. pcm 是 ADC 直接采集到的数据。

2. frame,帧,指的是对所有声道进行一次 ADC 转换得到数据。

3. frame size,指的是一帧 包含的字节数。

如果是单声道,8bit adc,那么就是 1 8 / 8 = 1. 如果是8声道,16bit adc,那么就是 8 16 / 8 = 16.

4. rate 采样率,一秒对所有通道进行多少轮的采样,也就是一秒多少帧

5. data rate,这个就是 采样率 * 每帧字节数

6. period,每次处理 AD,DA 转换的间隔是周期。

内核可以缓冲很多周期的数据,每个周期都会生成一个中断和一个副本,用户层可以间隔很长时间再处理一次,一次可以处理多个周期的数据。

7. period size 这个数值指的是一个周期包含多少帧。

如果设置为 32,那么用户每次读写都是 32帧数据,或者0帧数据。

参考: https://larsimmisch.github.io/pyalsaaudio/terminology.html

1. 从 二进制 pcm 文件中读取数据,并转化位想要的矩阵数组

    with open(audioPath, 'rb') as f:
        audioData = np.fromfile(f, dtype = np.uint16)
    audioData.shape = -1, 8

转换的音频数据是 不确定行,8列数组。

2. 把矩阵转置,以单声道数据为行。

    audioData = audioData.T

转换为 8行的二维数组,每一行就是一个声道的数据。

3. 抽取一个通道的数据。

    ch1 = audioData[4]

4. 把这个通道的数据写入二进制文件

    ch1.tofile("./audio/ch1.pcm")

参考: https://blog.51cto.com/feature09/2316652 https://blog.csdn.net/Tourior/article/details/110791039 https://blog.csdn.net/kebu12345678/article/details/54837245 https://numpy.org/doc/stable/reference/generated/numpy.fromfile.html#:~:text=numpy.fromfile.%20%C2%B6.%20numpy.fromfile%28file%2C%20dtype%3Dfloat%2C%20count%3D-1%2C%20sep%3D%27%27%2C%20offset%3D0%29%20%C2%B6.,tofile%20method%20can%20be%20read%20using%20this%20function. https://www.cnblogs.com/peixu/p/7991715.html https://blog.csdn.net/botao_li/article/details/104378469 https://www.cnblogs.com/noluye/p/11224137.html