相信所有人都清楚,做这个比赛的第一步就是跑通流程。本人菜鸡以一枚,挣扎许久,在考虑要不要放弃。但是实话说,白白浪费了几周的时间总是有一些不甘心,所以写下这篇经验博客。如果有幸大家在我的基础上帮我解决了问题,是共赢。万一问题解决不了,我也认了,能给大家一点点帮助,也算我这几周没有白费。。(哭辽真的。。。)因为我目前做的是手绘图像识别,所以就以这个为例讲一下本人一点经验。
step1:训练
注意我们这篇博客的目的是先跑通平台,所以一切步骤从简,模型就用resnet18即可。
1.确保训练代码没有问题。在本地先跑通一个模型,跑一个epoch 并保存模型参数。注意:确定模型weight保存在/project/train/models。
2.训练模型。提交训练任务,进行训练,1个epoch很快可以训练完。这时候我们可以在训练任务栏看到保存的模型。
step2:测试
为了顺利运行测试任务,我们首先得保证测试代码在本地是畅通的。
1.模型转换,本人直接交出自己的convert_model.sh。
source /opt/snpe/snpe_venv/bin/activate
# step 0:prepare
pip install onnx
pip install protobuf --upgrade
pip install opencv-python
# step 1:to_onnx
python3.6 /usr/local/ev_sdk/src/to_onnx.py
# step 2:generate file_list.txt
mkdir /usr/local/ev_sdk/pic
mkdir /usr/local/ev_sdk/raw
wget -O /usr/local/ev_sdk/pic/0.jpg https://www.baidu.com/img/bd_logo1.png
python /usr/local/ev_sdk/src/create_raws.py -i /usr/local/ev_sdk/pic -d /usr/local/ev_sdk/raw -s 224
python /usr/local/ev_sdk/src/create_list.py -i /usr/local/ev_sdk/raw -e *.raw
# step 3:generate dlc
snpe-onnx-to-dlc --input_network /usr/local/ev_sdk/model/model.onnx --output_path /usr/local/ev_sdk/model/model.dlc -d input 1,3,224,224 && echo "snpe-onx-to-dlc done"
snpe-dlc-quantize --input_dlc /usr/local/ev_sdk/model/model.dlc --output_dlc /usr/local/ev_sdk/model/model_quantized.dlc --input_list /usr/local/ev_sdk/model/file_list.txt --input_dlc --enable_htp && echo 'snpe-dlc-quantize done'
rm /usr/local/ev_sdk/model/model.dlc
step 0: 安装一下包
step 1:我的代码是用pytorch写的,要先转为onnx才可以转为dlc。所以写了一个转onnx的python代码。(仅供参考)
在本地测试的时候,我是把本地训练产生的模型直接copy到ev_sdk/model文件夹下了。
import torch
import torch.onnx
from models import ResNet
# device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
model = ResNet(model_name="resnet18")
pthfile = r'/usr/local/ev_sdk/model/version_1_fold_0_best.pth'
model.load_state_dict(torch.load(pthfile,map_location=torch.device('cpu'))['state_dict'])
dummy_input1 = torch.randn(1,3,224,224)
input_names = [ "input"]
output_names = [ "output1" ]
torch.onnx.export(model, dummy_input1,"/usr/local/ev_sdk/model/model.onnx", verbose=True,input_names=input_names,output_names=output_names)
step 2:生成file_list。大家可以在step 3 中看到,有一个参数是--input_list ,我们这一步就是为其生成一个文件。
大家可以看到我先建了一个文件夹,一个是pic,一个是raw。
然后下载了一张图片到pic文件夹中。为什么下载而不用/home/data/里面的图片呢?是因为平台在执行测试任务的时候没有/home/data 这个文件夹,用不了啊。我随便下了一张进行测试(是度娘的logo)。
接下来执行create_raws.py(这个是从/opt/snpe/models/Inception v3/scripts/ 里copy过来的),它的目的是将参数(-i)这个文件夹里面的内容转换为 (.raw)文件并输出到参数(-d)文件夹,参数-s是指你要将图片resize的大小,要跟你模型的输入大小匹配。 大家可以根据需要对代码进行修改,保证raw文件的维度正确。
最后一步就是运行create_list.py(跟create_raws.py同一个位置copy过来的)将raw文件夹里面内容生成一个file_list文件,这个文件的内容是.raw文件的绝对路径。参数-i 就是说raw文件保存的位置,参数-e是指具体的文件类型,这个参数的默认值是.jpg。
step 3:生成dlc
有一个要注意的点是这个-d参数它的输出是 两个值,一个是输入节点名称,一个是大小。输入节点名称要跟onnx的一样,然后确保输入的大小正确(pytorch是NCHW)。
2.编写ji.py
这就是我出问题的部分了,朋友们~
step 1:我的第一个版本是这样的:
from __future__ import print_function
import logging as log
import json
import torch
import cv2
import numpy as np
from model import *
log.basicConfig(level = log.DEBUG)
f = open("./class.txt")
label_id_map = {}
for line in f.readlines():
line = line.strip().split(",")
label_id_map[int(line[0])] = line[1]
logging.info(label_id_map)
def init():
save_model = "/usr/local/ev_sdk/model/laji_1.pth"
if not os.path.isfile(save_model):
log.error(f"{model_pb_path} does not exist")
model = ResNet(model_name="resnet18",pretrained = False)
log.info('Initializing model...')
model.load_state_dict(torch.load(save_model)['state_dict'])
model = model.cuda()
return model
def process_image(net,input_image,args=None):
img = cv2.resize(input_image,(256,256)).astype(np.float32)
img = img.transpose(2,0,1)
img = cv2.normalize(img,None)
img = torch.tensor([img]).cuda()
output = net(img)
data = {'class':label_id_map[int(output[0])]}
return json.dumps(data, indent=4)
在平台测试的时候只用了两个积分,用的gpu,所以性能分低。我当时在想为啥我dlc转换成功了,为啥不用呢????
后来我后知后觉觉得好像是我自己生成了但自己没写代码用它。
于是我开始想怎么把它用起来,出了第二个版本。
step 2: 尝试用dlc
def init():
os.system("bash /usr/local/ev_sdk/src/convert_model.sh")
path = "/usr/local/ev_sdk/src"
if not os.path.exists(os.path.join(path,"pic")):
os.makedirs(os.path.join(path,"pic"))
if not os.path.exists(os.path.join(path,"raw")):
os.makedirs(os.path.join(path,"raw"))
if not os.path.exists(os.path.join(path,"output")):
os.makedirs(os.path.join(path,"output"))
save_model = "/usr/local/ev_sdk/model/model_quantized.dlc"
return save_model
def process_image(save_model,input_image,args=None):
cv2.imwrite("/usr/local/ev_sdk/src/pic/0.jpg",input_image)
convert_img("/usr/local/ev_sdk/src/pic/","/usr/local/ev_sdk/src/raw/",224,RESIZE_METHOD_BILINEAR)
cmd = ['snpe-net-run',
'--input_list', "/usr/local/ev_sdk/src/input_list.txt",
'--container',"/usr/local/ev_sdk/model/model_quantized.dlc",
'--output_dir',"/usr/local/ev_sdk/src/output"]
# '--output_dir',"/usr/local/ev_sdk/src/output","--use_dsp","--platform_options", "unsignedPD:ON"]
subprocess.call(cmd)
# assert os.path.exists("/usr/local/ev_sdk/src/output/Result_0/output1.raw")
float_array = np.fromfile("/usr/local/ev_sdk/src/output/Result_0/output1.raw", dtype=np.float32) ## 读取这个文件内容
max_prob = max(float_array)
max_prob_index = np.where(float_array == max_prob)[0][0]
data = {'class':label_id_map[max_prob_index]}
return json.dumps(data, indent=4)
if __name__ == '__main__':
"""Test python api
"""
# img = cv2.imread('/usr/local/ev_sdk/data/dog.jpg')
img = np.random.randn(224,224,3)
predictor = init()
result = process_image(predictor, img)
logging.info(result)
重点是执行了snpe-net-run,它的输入是一个list文件,里面是raw文件的路径,container是模型位置,output_dir是输出文件的位置。最后从输出文件里读取结果。
这个版本测试一次消耗了100个积分,并且成绩跟上一个版本完全一样,用的gpu。
然后我尝试给它加参数 --use_dsp,但是测试结果如下:就是说平台不支持dsp。这就是我的问题所在!!!!
The selected runtime is not available on this platform. Continue anyway to observe the failure at network creation time.
error_code=500; error_message=Target runtime is not available. error_code=500; error_message=Target runtime is not available.
No viable runtimes available.; error_component=Host Runtime; line_no=423; thread_id=140447590590208; error_component=Host Runtime; line_no=263; thread_id=140448895645632
编者按:在写这个博客前,我也很犹豫。最终我还是决定写下来,因为大家跟我双赢是我赚了,没有人帮我的话我也不损失啥,毕竟菜鸡走投无路已经打算放弃了。 当然,我还是希望结果是好的菜鸡哭泣。。。。期待跟大家交流(救我!)
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
!!!!!新更新内容:ji.py不需要调用.dlc,生成的dlc是系统自动调用的。