精华内容
下载资源
问答
  • 深度学习模型 Pytorch Densenet 安卓移动端开发安卓app开发调用深度学习模型新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表...

    安卓app开发调用深度学习模型

    最近使用安卓调用了利用迁移学习训练的Pytorch Densenet121模型,主要是实现图像的分类,在此记录并分享一下。纯小白,第一次写博客,如有错误希望能指正,互相学习。
    pytorch移动端可以参考 官方Demo

    环境准备

    网上都有相应的环境配置教程

    • Anacoda 我的是4.8.2 (查看版本方法:终端输入 conda --version命令)
    • python 我的是3.7.0
    • pytorch 1.4(1.3开始支持移动端,我的是1.4)
    • Java (前排提醒,安卓部分使用Java编写)
    • densenet121模型

    模型转换

    平时使用的后缀名为 “.pth” 的模型文件不能直接用于安卓端使用,需要转换格式为 “.pt” 。
    Pytorch官方文档地址

    • 首先需要有模型文件,可以自己下载官方的模型,也可以用自己已经训练好的。
    • 在模型所在目录新建一个python文件,名字随便起(要合法),下面是desenet121模型的转换代码,resnet模型的转换可以参考这篇 博客
    import torch
    from torchvision import models
    
    # 使用预训练的模型,不同类型的模型有不一样的函数,这里用的是densenet121模型
    model = models.densenet121(pretrained=True)
    # 如果只需要网络结构,不需要用预训练模型的参数来初始化就执行下面这行
    # model = models.densenet121(pretrained=False)
    
    #分类器,需要根据自己模型的实际情况使用,比如我这里最后是将目标图片分成A,B,C,D四类
    model.classifier = torch.nn.Sequential(
        torch.nn.Linear(1024, 512),
        torch.nn.Dropout(0.5),  # drop 50% neurons
        torch.nn.ReLU(),
        torch.nn.Linear(512, 256),
        torch.nn.Dropout(0.2),  # drop 50% neurons
        torch.nn.ReLU(),
        torch.nn.Linear(256, 4),
    )
    
    # 加载模型,参数为自己的模型的路径
    model.load_state_dict(torch.load('./densenet121模型.pth')) # 加载参数
    model.eval() # 模型设为评估模式
    
    # 1张3通道400*400的图片,这里与后面的图片处理对应
    input_tensor = torch.rand(1, 3, 400, 400) # 设定输入数据格式
    mobile = torch.jit.trace(model, input_tensor) # 模型转化(官方文档https://pytorch.org/docs/master/generated/torch.jit.trace.html)
    mobile.save('densenet121.pt') # 保存为pt文件
    
    • 运行上面的代码就可以得到 pt 格式的模型了

    安卓配置

    • 在安卓项目目录中的 app/build.gradle 中相应位置添加以下内容:
    repositories {
        jcenter()
    }
    
    dependencies {
        implementation 'org.pytorch:pytorch_android:1.4.0'
        implementation 'org.pytorch:pytorch_android_torchvision:1.4.0'
    }
    
    • 然后就等待加载gradle(时间可能会比较长)
    • 将转换后的 pt格式模型放到项目 app/src/main/assets 下,没有这个文件夹的话可以自己创建。
    • 编写分类标签类,用于存储类别标签。在任意项目package下创建一个MyLabel.java(名字可以自己随便取)。
    package com.example.mylabel;
    
    public class MyLabel {
        public static String[] LABEL = new String[]{
            "A", "B", "C", "D"
        };
    }
    
    • 编写调用模型的文件,这里我使用的 java语言,在任意项目package下创建一个Test.java文件(名字自己随便取),用于调用、运行模型。
    package com.example.test; 
    
    import android.graphics.Bitmap;
    import android.graphics.Matrix;
    import android.util.Log;
    import com.example.myclass.MyLabel; //导入分类标签类
    import org.pytorch.IValue;
    import org.pytorch.Module;
    import org.pytorch.Tensor;
    import org.pytorch.torchvision.TensorImageUtils;
    
    
    public class Test {
        private Module module;
        private String modulePath;
        private String result;  //分类结果A,B,C,D
        private float[] resultArray;  //分类数组
        private Bitmap bitmaps;
        /**
         * 构造函数
         * @param modulePath 模型的绝对路径
         * @param bitmap 评分的图片以位图的形式传入
         */
        public Test(String modulePath, Bitmap bitmap) {
            this.modulePath = modulePath;
            this.bitmaps = resize(bitmap);
            this.module = Module.load(modulePath);
            this.resultArray = new float[]{0, 0, 0, 0};
        }
    
        /**
         * 重新设置图片大小并进行一定的变换与裁剪,这里返回图片的大小与之前模型转换时设置的输入数据格式相对应
         * @param bitmap 输入的图像
         * @return Bitmap 处理后的图像
         */
        private Bitmap resize(Bitmap bitmap) {
            int H = bitmap.getHeight();
            int W = bitmap.getWidth();
            float scaleH;
            float scaleW;
            float IMAGE_SIZE = 400.0f;  //图片大小设置
            //锁定高宽比缩放
            if(H>W){
                scaleH = IMAGE_SIZE * H / W;
                scaleW = IMAGE_SIZE;
            }else{
                scaleH = IMAGE_SIZE;
                scaleW = IMAGE_SIZE * W / H;
            }
            Matrix matrix = new Matrix();
            matrix.postScale(scaleW/W,scaleH/H);
            //创建一个新的bitmap
            Bitmap temp = Bitmap.createBitmap(bitmap,0,0,W,H,matrix,true);
            //在中间切割图像 使其成 IMAGE_SIZE * IMAGE_SIZE
            Bitmap resBitmap = Bitmap.createBitmap(temp,(int)((temp.getWidth()-IMAGE_SIZE)/2),
                    (int)((temp.getHeight()-IMAGE_SIZE)/2),(int)IMAGE_SIZE,(int)IMAGE_SIZE);
            return resBitmap;
        }
    
        /**
         * 运行模型,开始分类
         */
        public void runModel(){
        	 //张量规整,根据自己的情况设置值
            float[] mean = {0.5f,0.5f,0.5f}; 
            float[] std = {0.5f,0.5f,0.5f};
            //输入张量
            Tensor inputTensor = TensorImageUtils.bitmapToFloat32Tensor(bitmaps,mean,std);
            //将 inputTensor 放到模型中运行,通过 module.forward() 得到一个 outputTensor。
            Tensor outputTensor = module.forward(IValue.from(inputTensor)).toTensor();
            //获得输出结果(长度为4,分别代表A,B,C,D,与之前转换时分类器的设置有关)
            resultArray = outputTensor.getDataAsFloatArray();
            setResult();
        }
    
        private void setResult() {
            float max = resultArray[0];
            int index = 0;  //最大值下标
            for(int i=0;i<resultArray.length;i++){
                if(Float.compare(max,resultArray[i])<0){
                    max = resultArray[i];
                    index = i;
                }
            }
            //根据最大值的下标获得对应的分类结果
            this.result = MyLebel.Lebel[index];
        }
    
        /**
         * 获取图片评分
         * @return String
         */
        public String getResult() {
            return result;
        }
    	/**
    	* 获取模型路径
    	* @return String
    	* /
        public String getModulePath() {
            return modulePath;
        }
    }
    
    • 编写获取assets目录下文件绝对路径的类(因为模型文件存放在该目录下),新建工具类FileUtil.java
    package com.example.util;
    
    import android.content.Context;
    import android.os.Build;
    import android.util.Log;
    import androidx.annotation.RequiresApi;
    
    import java.io.*;
    
    public class FileUtil {
        /**
         * 将指定的资产复制到 /files app目录中的文件,并返回此文件的绝对路径。
         * @param context 上下文
         * @param assetName 目标文件名
         * @return String 绝对路径
         */
        @RequiresApi(api = Build.VERSION_CODES.KITKAT)
        public static String assetFilePath(Context context, String assetName) throws IOException {
            File file = new File(context.getFilesDir(), assetName);
            if (file.exists() && file.length() > 0) {
                return file.getAbsolutePath();
            }
    
            try (InputStream is = context.getAssets().open(assetName)) {
                try (OutputStream os = new FileOutputStream(file)) {
                    byte[] buffer = new byte[4 * 1024];
                    int read;
                    while ((read = is.read(buffer)) != -1) {
                        os.write(buffer, 0, read);
                    }
                    os.flush();
                }
                return file.getAbsolutePath();
            }
        }
    }
    
    • 最后在需要运行模型的地方,(不讲究的话,比如MainActivity.java的onCreat()方法),添加下面的代码就可以了
    try {
    	//将图片用Bitmap类包装
         Bitmap bitmap = BitmapFactory.decodeFile("需要分类的图片路径");
         
         //获取模型路径,下面函数参数中getApplicationContext()获取的是上下文,在 某某activity中可以直接用 某某activity.this代替
         String modulePath = FileUtil.assetFilePath(getApplicationContext(), "densenet121.pt");
         
         //获取模型调用类实例
         Test test = new test(modulePath, bitmap);
         //运行模型
         test.runModel();
         //获取结果
         String label = test.getResult();
         Log.d("分类结果",label);
     } catch (IOException e) {
         e.printStackTrace();
     }
    

    参考资料

    [1] https://blog.csdn.net/y_dd6011/article/details/104751029
    [2] https://pytorch.org/docs/master/generated/torch.jit.trace.html
    [3] https://pytorch.org/mobile/android/

    展开全文
  • 使用官方的方法将模型保存为.pt文件,然后在安卓编程时使用Tensor outputTensor = mModule.forward(IValue.from(inputTensor)).toTensor()得到模型的输出,但是官方演示的model输出应该就是一个tensor,可是我的...
  • 这是我这两天对pytorch深度学习->android实际使用的这个流程的一个切身感受. 说句实在的, 对于模型转换的探索, 算是我这两天最大的收获了... 全部浓缩在了这里: https://github.com/lartp...

    生产与学术

    写于 2019-01-08 的旧文, 当时是针对一个比赛的探索. 觉得可能对其他人有用, 就放出来分享一下

    upsplash

    生产与学术, 真实的对立...

    这是我这两天对pytorch深度学习->android实际使用的这个流程的一个切身感受.

    说句实在的, 对于模型转换的探索, 算是我这两天最大的收获了...

    全部浓缩在了这里: https://github.com/lartpang/DHSNet-PyTorch/blob/master/converter.ipynb

    鉴于github加载ipynb太慢, 这里可以使用这个链接 https://nbviewer.jupyter.org/github/lartpang/DHSNet-PyTorch/blob/master/converter.ipynb

    这两天

    最近在研究将pytorch的模型转换为独立的app, 网上寻找, 找到了一个流程: pytorch->onnx->caffe2->android apk. 主要是基于这篇文章的启发: caffe2&pytorch之在移动端部署深度学习模型(全过程!).

    这两天就在折腾这个工具链,为了导出onnx的模型, 不确定要基于怎样的网络, 是已经训练好的, 还是原始搭建网络后再训练来作为基础. 所以不断地翻阅pytorchonnx的官方示例, 想要研究出来点什么, 可是, 都是自己手动搭建的模型. 而且使用的是预训练权重, 不是这样:

    def squeezenet1_1(pretrained=False, **kwargs):
        r"""SqueezeNet 1.1 model from the `official SqueezeNet repo
        <https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1>`_.
        SqueezeNet 1.1 has 2.4x less computation and slightly fewer parameters
        than SqueezeNet 1.0, without sacrificing accuracy.
        Args:
            pretrained (bool): If True, returns a model pre-trained on ImageNet
        """
        model = SqueezeNet(version=1.1, **kwargs)
        if pretrained:
            model.load_state_dict(model_zoo.load_url(model_urls['squeezenet1_1']))
        return model
    # Get pretrained squeezenet model
    torch_model = squeezenet1_1(True)
    
    from torch.autograd import Variable
    batch_size = 1    # just a random number
    # Input to the model
    x = Variable(torch.randn(batch_size, 3, 224, 224), requires_grad=True)
    # Export the model
    torch_out = torch.onnx._export(
        torch_model,        # model being run
        x,                  # model input (or a tuple for multiple inputs)
        "squeezenet.onnx",  # where to save the model (can be a file or file-like object)
        export_params=True) # store the trained parameter weights inside the model file

    就是这样:

    # Create the super-resolution model by using the above model definition.
    torch_model = SuperResolutionNet(upscale_factor=3)
    # Load pretrained model weights
    model_url = 'https://s3.amazonaws.com/pytorch/test_data/export/superres_epoch100-44c6958e.pth'
    batch_size = 1    # just a random number
    # Initialize model with the pretrained weights
    torch_model.load_state_dict(model_zoo.load_url(model_url))
    # set the train mode to false since we will only run the forward pass.
    torch_model.train(False)

    两种都在载入预训练权重, 直接加载到搭建好的网络上. 对于我手头有的已经训练好的模型, 似乎并不符合这样的条件.

    导出整体模型

    最后采用尽可能模仿上面的例子代码的策略, 将整个网络完整的导出(torch.save(model)), 然后再仿照上面那样, 将完整的网络加载(torch.load())到转换的代码中, 照猫画虎, 以进一步处理.

    这里也很大程度上受到这里的启发: https://github.com/akirasosa/mobile-semantic-segmentation

    本来想尝试使用之前找到的不论效果还是性能都很强的R3Net进行转换, 可是, 出于作者搭建网络使用的特殊手段, 加上pickle和onnx的限制, 这个尝试没有奏效, 只好转回头使用之前学习的DHS-Net的代码, 因为它的实现是基于VGG的, 里面的搭建的网络也是需要修改来符合onnx的要求, 主要是更改上采样操作为转置卷积(也就是分数步长卷积, 这里顺带温习了下pytorch里的nn.ConvTranspose2d()计算方式), 因为pytorch的上采样在onnx转换过程中有很多的问题, 特别麻烦, 外加上修改最大池化的一个参数(nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=False)的参数ceil_mode改为ceil_mode=False, 这里参考自前面的知乎专栏的那篇文章), 这样终于可以转换了, 为了方便和快速的测试, 我只是训练了一个epoch, 就直接导出模型, 这次终于可以顺利的torch.save()了.

    filename_opti = ('%s/model-best.pth' % check_root_model)
    torch.save(model, filename_opti)

    之后便利用类似的代码进行了书写.

    IMG_SIZE = 224
    TMP_ONNX = 'cache/onnx/DHSNet.onnx'
    MODEL_PATH = 'cache/opti/total-opti-current.pth'
    
    # Convert to ONNX once
    model = torch.load(MODEL_PATH).cuda()
    model.train(False)
    
    x = Variable(torch.randn(1, 3, 224, 224), requires_grad=True).cuda()
    torch_out = torch.onnx._export(model, x, TMP_ONNX, export_params=True)

    caffe2模型转换

    载入模型后, 便可以开始转换了, 这里需要安装caffe2, 官方推荐直接conda安装pytorch1每夜版即可, 会自动安装好依赖.

    说起来这个conda, 就让我又爱又恨, 用它装pytorch从这里可以看出来, 确实不错, 对系统自身的环境没有太多的破坏, 可是用它装tensorflow-gpu的时候, 却是要自动把conda源里的cuda, cudnn工具包都给带上, 有时候似乎会破坏掉系统自身装载的cuda环境(? 不太肯定, 反正现在我不这样装, 直接上pip装, 干净又快速).

    之后的代码中, 主要的问题也就是tensor的cpu/cuda, 或者numpy的转换的问题了. 多尝试一下, 输出下类型就可以看到了.

    # Let's also save the init_net and predict_net to a file that we will later use for running them on mobile
    with open('./cache/model_mobile/init_net.pb', "wb") as fopen:
        fopen.write(init_net.SerializeToString())
    with open('./cache/model_mobile/predict_net.pb', "wb") as fopen:
        fopen.write(predict_net.SerializeToString())

    预处理的补充

    这里记录下, 查看pytorch的tensor的形状使用tensor.size()方法, 查看numpy数组的形状则使用numpy数组的adarray.shape方法, 而对于PIL(from PIL import Image)读取的Image对象而言, 使用Image.size查看, 而且, 这里只会显示宽和高的长度, 而且Image的对象, 是三维, 在于pytorch的tensor转换的时候, 或者输入网络的时候, 要注意添加维度, 而且要调整通道位置(img = img.transpose(2, 0, 1)).

    由于网络保存的部分中, 只涉及到了网络的结构内的部分, 对于数据的预处理的部分并不涉及, 所以说要想真正的利用网络, 还得调整真实的输入, 来作为更适合网络的数据输入.

    要注意, 这里针对导出的模型的相关测试, 程实际上是按照测试网络的流程来的.

    # load the resized image and convert it to Ybr format
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    img = Image.open("./data/ILSVRC2012_test_00000004_224x224.jpg")
    img = np.array(img)
    img = img.astype(np.float64) / 255
    img -= mean
    img /= std
    img = img.transpose(2, 0, 1)

    安卓的尝试

    首先安卓环境的配置就折腾了好久, 一堆破事, 真实的生产开发, 真心不易啊...

    这里最终还是失败了, 因为对于安卓的代码是在是不熟悉, 最起码的基础认知都不足, 只有这先前学习Java的一点皮毛知识, 根本不足以二次开发. 也就跑了跑几个完整的demo而已.

    AiCamera

    这个跑通了, 但是这是个分类网络的例子, 对于我们要做的分割的任务而言, 有很多细节不一样.

    • 输入有差异: 比赛要求的是若是提交apk, 那么要求可以从相册读取图片, 而例子是从摄像头读取的视频数据流. 虽然也处理的是视频帧, 但是要我们再次补充的内容又多了起来, 还是那句话, android一窍不通.
    • 输出有差异: 自我猜测, 比赛为了测评, 输出必然也要输出到相册里, 不然何来测评一说?

    AICamera-Style-Transfer

    这个例子我们参考了一下, 只是因为它的任务是对摄像头视频流数据风格迁移, 而且会直接回显到手机屏幕上, 这里我们主要是想初步实现对于我们网络模型安卓迁移的测试, 在第一个例子的基础上能否实现初步的摄像头视频流的分割, 然后下一步再进一步满足比赛要求.

    可是, 尝试失败了. 虽然AS打包成了APK, 手机也安装上了, 可是莫名的, 在"loading..."中便闪退了...

    JejuNet

    这个例子很给力, 但是使用的是tensorflowlite, 虽然可以用, 能够实现下面的效果, 可是, 不会改.

    img

    而且是量化网络, 准确率还是有待提升.

    最后的思考

    最后还是要思考一下的, 做个总结.

    没经验

    吃就吃在没经验的亏上了, 都是初次接触, 之前没怎么接触过安卓, 主要是安卓的开发对于电脑的配置要求太高了, 自己的笔记本根本不够玩的. 也就没有接触过了.

    外加上之前的研究学习, 主要是在学术的环境下搞得, 和实际的生产还有很大的距离, 科研与生产的分离, 这对于深度学习这一实际上更偏重实践的领域来说, 有些时候是尤为致命的. 关键时刻下不去手, 这多么无奈, 科学技术无法转化为实实在在的生产力, 忽然有些如梦一般的缥缈.

    当然, 最关键的还是, 没有仔细分析赛方的需求, 没有完全思考清楚, 直接就开干了, 这个鲁莽的毛病, 还是没有改掉, 浪费时间不说, 也无助于实际的进度. 赛方的说明含糊, 应该问清楚.

    若是担心时间, 那更应该看清楚要求, 切莫随意下手. 比赛说明里只是说要提交一个打包好的应用, 把环境, 依赖什么都处理好, 但是不一定是安卓apk呀, 可以有很多的形式, 但是这也只是最后的一点额外的辅助而已, 重点是模型的性能和效率呢.

    莫忘初心, 方得始终. 为什么我想到的是这句.

    下一步

    基本上就定了还是使用R3Net, 只能是进一步的细节修改了, 换换后面的循环结构了, 改改连接什么的.

    我准备再开始看论文, 学姐的论文可以看看, 似乎提出了一种很不错的后处理的方法, 效果提升很明显, 需要研究下.

    pickle和onnx的限制

    pytorch的torch.save(model)保存模型的时候, 模型架构的代码里不能使用一些特殊的构建形式, R3Net的ResNeXt结构就用了, 主要是一些lambda结构, 虽然不是太清楚, 但是一般的搭建手段都是可以的.

    onnx对于pytorch的支持的操作, 在我的转化中, 主要是最大池化和上采样的问题, 前者可以修改ceil_modeFalse, 后者则建议修改为转置卷积, 避免不必要的麻烦. 可见"导出整体模型"小节的描述.

    打包apk安装

    这里主要是用release版本构建的apk.

    未签名的apk在我的mi 8se (android 8.1)上不能安装, 会解析失败, 需要签名, AS的签名的生成也很简单, 和生成apk在同一级上, 有生成的选项.

    转载于:https://www.cnblogs.com/lart/p/10618665.html

    展开全文
  • 文章目录生产与学术这两天导出整体模型caffe2模型转换预处理的补充安卓的尝试[AiCamera](https://github.com/caffe2/AICamera)[AICamera-Style-Transfer](https://github.com/caffe2/AICamera-Style-Transfer)...

    生产与学术

    写于 2019-01-08 的旧文, 当时是针对一个比赛的探索. 觉得可能对其他人有用, 就放出来分享一下

    upsplash

    生产与学术, 真实的对立…

    这是我这两天对pytorch深度学习->android实际使用的这个流程的一个切身感受.

    说句实在的, 对于模型转换的探索, 算是我这两天最大的收获了…

    全部浓缩在了这里: https://github.com/lartpang/DHSNet-PyTorch/blob/master/converter.ipynb

    鉴于github加载ipynb太慢, 这里可以使用这个链接: https://nbviewer.jupyter.org/github/lartpang/DHSNet-PyTorch/blob/master/converter.ipynb

    这两天

    最近在研究将pytorch的模型转换为独立的app, 网上寻找, 找到了一个流程: pytorch->onnx->caffe2->android apk. 主要是基于这篇文章的启发: caffe2&pytorch之在移动端部署深度学习模型(全过程!).

    这两天就在折腾这个工具链,为了导出onnx的模型, 不确定要基于怎样的网络, 是已经训练好的, 还是原始搭建网络后再训练来作为基础. 所以不断地翻阅pytorchonnx的官方示例, 想要研究出来点什么, 可是, 都是自己手动搭建的模型. 而且使用的是预训练权重, 不是这样:

    def squeezenet1_1(pretrained=False, **kwargs):
        r"""SqueezeNet 1.1 model from the `official SqueezeNet repo
        <https://github.com/DeepScale/SqueezeNet/tree/master/SqueezeNet_v1.1>`_.
        SqueezeNet 1.1 has 2.4x less computation and slightly fewer parameters
        than SqueezeNet 1.0, without sacrificing accuracy.
        Args:
            pretrained (bool): If True, returns a model pre-trained on ImageNet
        """
        model = SqueezeNet(version=1.1, **kwargs)
        if pretrained:
            model.load_state_dict(model_zoo.load_url(model_urls['squeezenet1_1']))
        return model
    # Get pretrained squeezenet model
    torch_model = squeezenet1_1(True)
    
    from torch.autograd import Variable
    batch_size = 1    # just a random number
    # Input to the model
    x = Variable(torch.randn(batch_size, 3, 224, 224), requires_grad=True)
    # Export the model
    torch_out = torch.onnx._export(
        torch_model,        # model being run
        x,                  # model input (or a tuple for multiple inputs)
        "squeezenet.onnx", 	# where to save the model (can be a file or file-like object)
        export_params=True) # store the trained parameter weights inside the model file
    

    就是这样:

    # Create the super-resolution model by using the above model definition.
    torch_model = SuperResolutionNet(upscale_factor=3)
    # Load pretrained model weights
    model_url = 'https://s3.amazonaws.com/pytorch/test_data/export/superres_epoch100-44c6958e.pth'
    batch_size = 1    # just a random number
    # Initialize model with the pretrained weights
    torch_model.load_state_dict(model_zoo.load_url(model_url))
    # set the train mode to false since we will only run the forward pass.
    torch_model.train(False)
    

    两种都在载入预训练权重, 直接加载到搭建好的网络上. 对于我手头有的已经训练好的模型, 似乎并不符合这样的条件.

    导出整体模型

    最后采用尽可能模仿上面的例子代码的策略, 将整个网络完整的导出(torch.save(model)), 然后再仿照上面那样, 将完整的网络加载(torch.load())到转换的代码中, 照猫画虎, 以进一步处理.

    这里也很大程度上受到这里的启发: https://github.com/akirasosa/mobile-semantic-segmentation

    本来想尝试使用之前找到的不论效果还是性能都很强的R3Net进行转换, 可是, 出于作者搭建网络使用的特殊手段, 加上pickle和onnx的限制, 这个尝试没有奏效, 只好转回头使用之前学习的DHS-Net的代码, 因为它的实现是基于VGG的, 里面的搭建的网络也是需要修改来符合onnx的要求, 主要是更改上采样操作为转置卷积(也就是分数步长卷积, 这里顺带温习了下pytorch里的nn.ConvTranspose2d()计算方式), 因为pytorch的上采样在onnx转换过程中有很多的问题, 特别麻烦, 外加上修改最大池化的一个参数(nn.MaxPool2d(kernel_size=2, stride=2, ceil_mode=False)的参数ceil_mode改为ceil_mode=False, 这里参考自前面的知乎专栏的那篇文章), 这样终于可以转换了, 为了方便和快速的测试, 我只是训练了一个epoch, 就直接导出模型, 这次终于可以顺利的torch.save()了.

    filename_opti = ('%s/model-best.pth' % check_root_model)
    torch.save(model, filename_opti)
    

    之后便利用类似的代码进行了书写.

    IMG_SIZE = 224
    TMP_ONNX = 'cache/onnx/DHSNet.onnx'
    MODEL_PATH = 'cache/opti/total-opti-current.pth'
    
    # Convert to ONNX once
    model = torch.load(MODEL_PATH).cuda()
    model.train(False)
    
    x = Variable(torch.randn(1, 3, 224, 224), requires_grad=True).cuda()
    torch_out = torch.onnx._export(model, x, TMP_ONNX, export_params=True)
    

    caffe2模型转换

    载入模型后, 便可以开始转换了, 这里需要安装caffe2, 官方推荐直接conda安装pytorch1每夜版即可, 会自动安装好依赖.

    说起来这个conda, 就让我又爱又恨, 用它装pytorch从这里可以看出来, 确实不错, 对系统自身的环境没有太多的破坏, 可是用它装tensorflow-gpu的时候, 却是要自动把conda源里的cuda, cudnn工具包都给带上, 有时候似乎会破坏掉系统自身装载的cuda环境(? 不太肯定, 反正现在我不这样装, 直接上pip装, 干净又快速).

    之后的代码中, 主要的问题也就是tensor的cpu/cuda, 或者numpy的转换的问题了. 多尝试一下, 输出下类型就可以看到了.

    # Let's also save the init_net and predict_net to a file that we will later use for running them on mobile
    with open('./cache/model_mobile/init_net.pb', "wb") as fopen:
        fopen.write(init_net.SerializeToString())
    with open('./cache/model_mobile/predict_net.pb', "wb") as fopen:
        fopen.write(predict_net.SerializeToString())
    

    预处理的补充

    这里记录下, 查看pytorch的tensor的形状使用tensor.size()方法, 查看numpy数组的形状则使用numpy数组的adarray.shape方法, 而对于PIL(from PIL import Image)读取的Image对象而言, 使用Image.size查看, 而且, 这里只会显示宽和高的长度, 而且Image的对象, 是三维, 在于pytorch的tensor转换的时候, 或者输入网络的时候, 要注意添加维度, 而且要调整通道位置(img = img.transpose(2, 0, 1)).

    由于网络保存的部分中, 只涉及到了网络的结构内的部分, 对于数据的预处理的部分并不涉及, 所以说要想真正的利用网络, 还得调整真实的输入, 来作为更适合网络的数据输入.

    要注意, 这里针对导出的模型的相关测试, 程实际上是按照测试网络的流程来的.

    # load the resized image and convert it to Ybr format
    mean = np.array([0.485, 0.456, 0.406])
    std = np.array([0.229, 0.224, 0.225])
    img = Image.open("./data/ILSVRC2012_test_00000004_224x224.jpg")
    img = np.array(img)
    img = img.astype(np.float64) / 255
    img -= mean
    img /= std
    img = img.transpose(2, 0, 1)
    

    安卓的尝试

    首先安卓环境的配置就折腾了好久, 一堆破事, 真实的生产开发, 真心不易啊…

    这里最终还是失败了, 因为对于安卓的代码是在是不熟悉, 最起码的基础认知都不足, 只有这先前学习Java的一点皮毛知识, 根本不足以二次开发. 也就跑了跑几个完整的demo而已.

    AiCamera

    这个跑通了, 但是这是个分类网络的例子, 对于我们要做的分割的任务而言, 有很多细节不一样.

    • 输入有差异: 比赛要求的是若是提交apk, 那么要求可以从相册读取图片, 而例子是从摄像头读取的视频数据流. 虽然也处理的是视频帧, 但是要我们再次补充的内容又多了起来, 还是那句话, android一窍不通.
    • 输出有差异: 自我猜测, 比赛为了测评, 输出必然也要输出到相册里, 不然何来测评一说?

    AICamera-Style-Transfer

    这个例子我们参考了一下, 只是因为它的任务是对摄像头视频流数据风格迁移, 而且会直接回显到手机屏幕上, 这里我们主要是想初步实现对于我们网络模型安卓迁移的测试, 在第一个例子的基础上能否实现初步的摄像头视频流的分割, 然后下一步再进一步满足比赛要求.

    可是, 尝试失败了. 虽然AS打包成了APK, 手机也安装上了, 可是莫名的, 在"loading…"中便闪退了…

    JejuNet

    这个例子很给力, 但是使用的是tensorflowlite, 虽然可以用, 能够实现下面的效果, 可是, 不会改.

    img

    而且是量化网络, 准确率还是有待提升.

    最后的思考

    最后还是要思考一下的, 做个总结.

    没经验

    吃就吃在没经验的亏上了, 都是初次接触, 之前没怎么接触过安卓, 主要是安卓的开发对于电脑的配置要求太高了, 自己的笔记本根本不够玩的. 也就没有接触过了.

    外加上之前的研究学习, 主要是在学术的环境下搞得, 和实际的生产还有很大的距离, 科研与生产的分离, 这对于深度学习这一实际上更偏重实践的领域来说, 有些时候是尤为致命的. 关键时刻下不去手, 这多么无奈, 科学技术无法转化为实实在在的生产力, 忽然有些如梦一般的缥缈.

    当然, 最关键的还是, 没有仔细分析赛方的需求, 没有完全思考清楚, 直接就开干了, 这个鲁莽的毛病, 还是没有改掉, 浪费时间不说, 也无助于实际的进度. 赛方的说明含糊, 应该问清楚.

    若是担心时间, 那更应该看清楚要求, 切莫随意下手. 比赛说明里只是说要提交一个打包好的应用, 把环境, 依赖什么都处理好, 但是不一定是安卓apk呀, 可以有很多的形式, 但是这也只是最后的一点额外的辅助而已, 重点是模型的性能和效率呢.

    莫忘初心, 方得始终. 为什么我想到的是这句.

    下一步

    基本上就定了还是使用R3Net, 只能是进一步的细节修改了, 换换后面的循环结构了, 改改连接什么的.

    我准备再开始看论文, 学姐的论文可以看看, 似乎提出了一种很不错的后处理的方法, 效果提升很明显, 需要研究下.

    pickle和onnx的限制

    pytorch的torch.save(model)保存模型的时候, 模型架构的代码里不能使用一些特殊的构建形式, R3Net的ResNeXt结构就用了, 主要是一些lambda结构, 虽然不是太清楚, 但是一般的搭建手段都是可以的.

    onnx对于pytorch的支持的操作, 在我的转化中, 主要是最大池化和上采样的问题, 前者可以修改ceil_modeFalse, 后者则建议修改为转置卷积, 避免不必要的麻烦. 可见"导出整体模型"小节的描述.

    打包apk安装

    这里主要是用release版本构建的apk.

    未签名的apk在我的mi 8se (android 8.1)上不能安装, 会解析失败, 需要签名, AS的签名的生成也很简单, 和生成apk在同一级上, 有生成的选项.

    展开全文
  • pytorch问题

    千次阅读 2018-03-19 21:24:09
    multi-target not supported at d:\pytorch\pytorch\torch\lib\thnn\generic/ClassNLLCriterion.c:22 target.squeeze(1) 欢迎关注我的微信公众号:云端看大地 即将带来的是:我工作经验系列文章(包括安卓开发,...

    multi-target not supported at d:\pytorch\pytorch\torch\lib\thnn\generic/ClassNLLCriterion.c:22

    target.squeeze(1)


    欢迎关注我的微信公众号:云端看大地
    即将带来的是:我工作经验系列文章(包括安卓开发,以及编程经验,还有工作中的方方面面需要注意的地方)
    正准备的是:预测彩票的系列文章
    敬请期待

    pageTan

    展开全文
  • pytorch2onnx

    千次阅读 2019-09-09 21:28:16
    最近做的项目需要把训练好的模型移植到移动端,安卓手机上,实验室选择了ncnn这个框架,所以我选择了pytoch2onnx2ncnn框架的这个思路。下面主要是记录一下pytorch转onnx模型的步骤和踩过的坑。 项目地址ONNX 定义了...
  • pytorch模型移动端部署

    2020-10-21 10:47:23
    或许之后要用到安卓的工具 https://cloud.tencent.com/developer/article/1619905 ONNX(Pytorch) 模型转换为 TNN 模型 https://github.com/Tencent/TNN/blob/master/doc/cn/user/onnx2tnn.md ...
  • PyTorch模型转换为TorchScript格式

    千次阅读 2020-02-21 14:45:58
    最近入坑了PyTorch,在学习PyTorch Mobile的安卓部分。要想将训练好模型迁移到手机上使用,需要将模型转化为TorchScript,它是PyTorch模型(子类nn.Module)的中间表示,可以在高性能环境(例如C ++)中运行。 转换...
  • TensorFlow与PyTorch之争

    2020-06-11 17:03:29
    TensorFlow与PyTorch 谷歌的 TensorFlow TensorFlow 是谷歌的开发者创造的一款开源的深度学习框架,于 2015 年发布。官方研究发布于论文《TensorFlow:异构分布式系统上的大规模机器学习》。 论文地址:...
  • demo 模拟器中实测有误,各种误判ship 环境说明 Android 7+ ...相机权限:安卓6之后的动态权限,安卓7之后调相机的权限 pytorch版本1.3.1编译后的model.pt跑不同,解压后发现其code文件夹的大小与官方de...
  • 记录分为 pytorch2onnx ...移动端(安卓)使用 1、pytorch2onnx 环境: pytorch 1.4.0 onnx 1.6.0 (转换) onnxruntime 1.3.0 (测试) onnx-simplifier 0.2.9 (模型量化,不执行后续报错了,我测
  • 使用pytorch搞定指针式仪表的读数

    热门讨论 2021-01-06 10:49:20
    使用tensorfflow搞定口罩检测移植到安卓端 模型使用的是pytorch-cpn关键点检测网络 数据集自己使用labelme,打标图片为650张 打标效果如下: 参考的作者的git地址如下: https://github.com/GengDavid/pytorch-cpn ...
  • (2)PC: ① pt(pytorch内置打包API)、② onnx:支持跨平台和tensorRT部署方式、③ tvm… (3)手机:①安卓、 ② IOS……同样可以通过调用onnx进行部署。 (4)IOT部署: ① 英伟达Jetson:支持cuda、② 华为...
  • 文章目录简单介绍用户与密码改系统安卓改Linux避坑换源1.备份官方源2.换国内源-清华源:-华为源(据说很快):-中科大源:3.更新软件列表和升级文件传输1.U盘传输文件2.通过XFTP传输远程连接安装Mini-forge编译安装...
  • 由于pycharm无法直接安装pycocotools,后面查找原因是pycocotools这个包不提供安卓版本的。 自己查找资料好多都是需要从github上下载,后面发现一种可以直接在清华镜像源下载的方法,点击此处可以直接查看教程,亲测...
  • 深度学习框架竞争很激烈,而且看上去都是业界巨头在玩。 老师木:是的。...它的角色就像互联网时代的浏览器,移动互联网时代的安卓操作系统一样,是战略级产品,业界巨头谁都不想让给他人也就不奇怪了...

空空如也

空空如也

1 2 3
收藏数 52
精华内容 20
关键字:

pytorch安卓