提交 c5ad3169 编写于 作者: qnqinan's avatar qnqinan

Merge remote-tracking branch 'upstream/develop' into develop

...@@ -96,3 +96,7 @@ metal/paddle-mobile/paddle-mobile/CPU/libpaddle-mobile.a ...@@ -96,3 +96,7 @@ metal/paddle-mobile/paddle-mobile/CPU/libpaddle-mobile.a
metal/paddle-mobile-demo/paddle-mobile-demo/images metal/paddle-mobile-demo/paddle-mobile-demo/images
metal/paddle-mobile-demo/paddle-mobile-demo/models metal/paddle-mobile-demo/paddle-mobile-demo/models
metal/paddle-mobile-demo/paddle-mobile-demo/Resources
metal/paddle-mobile-demo/paddle-mobile-demo/Resources/images
metal/paddle-mobile-demo/paddle-mobile-demo/Resources/models
metal/MobileNetDemo/MobileNetDemo/Resources
cmake_minimum_required(VERSION 3.0.0) cmake_minimum_required(VERSION 3.0.0)
option(USE_OPENMP "openmp support" ON) option(USE_OPENMP "build with openmp support" ON)
option(DEBUGING "enable debug mode" ON) option(USE_EXCEPTION "build with exception" ON)
option(USE_EXCEPTION "use std exception" ON) option(WITH_LOGGING "print logging for debug" ON)
option(SYMBOL_HIDDEN "symbol hidden" OFF) # on when use jni or ios io option(WITH_SYMBOL "build with all symbols" ON) # turn off if use jni or ios io
option(LOG_PROFILE "log profile" OFF) option(WITH_PROFILE "print op profile for debug" OFF)
option(WITH_TEST "build with unit tests" ON)
# select the platform to build # select the platform to build
option(CPU "armv7 with neon" ON) option(CPU "build with arm CPU support" ON)
option(GPU_MALI "mali gpu" OFF) option(GPU_MALI "build with arm mali GPU support" OFF)
option(GPU_CL "opencl gpu" OFF) option(GPU_CL "build with OpenCL support" OFF)
option(FPGA "build with FPGA support" OFF)
option(FPGA "fpga" OFF)
if(FPGA) if(FPGA)
option(FPGAV1 "fpga v1" ON) option(FPGAV1 "build with fpga v1 support" ON)
option(FPGAV2 "fpga v2" OFF) option(FPGAV2 "build with fpga v2 support" OFF)
endif() endif()
project(paddle-mobile) project(paddle-mobile)
...@@ -23,7 +23,6 @@ file(GLOB_RECURSE PADDLE_MOBILE_CC src/*.cc src/*.cpp src/*.c src/*.mm) ...@@ -23,7 +23,6 @@ file(GLOB_RECURSE PADDLE_MOBILE_CC src/*.cc src/*.cpp src/*.c src/*.mm)
file(GLOB_RECURSE PADDLE_MOBILE_H src/*.h) file(GLOB_RECURSE PADDLE_MOBILE_H src/*.h)
include_directories(src/) include_directories(src/)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS "-O3 -s -DNDEBUG ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-O3 -s -DNDEBUG ${CMAKE_CXX_FLAGS}")
if(IS_IOS) if(IS_IOS)
set(CMAKE_CXX_FLAGS "-mfpu=neon -marm -fobjc-abi-version=2 -fobjc-arc \ set(CMAKE_CXX_FLAGS "-mfpu=neon -marm -fobjc-abi-version=2 -fobjc-arc \
...@@ -33,13 +32,18 @@ else() ...@@ -33,13 +32,18 @@ else()
set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}") set(CMAKE_CXX_FLAGS "-std=c++11 ${CMAKE_CXX_FLAGS}")
endif() endif()
if(DEBUGING) if(USE_OPENMP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
add_definitions(-DPADDLE_MOBILE_USE_OPENMP)
endif()
if(WITH_LOGGING)
message(STATUS "debugging mode") message(STATUS "debugging mode")
add_definitions(-DPADDLE_MOBILE_DEBUG) add_definitions(-DPADDLE_MOBILE_DEBUG)
else() else()
endif() endif()
if(SYMBOL_HIDDEN) if(NOT WITH_SYMBOL)
add_definitions(-fvisibility=hidden -fvisibility-inlines-hidden) add_definitions(-fvisibility=hidden -fvisibility-inlines-hidden)
endif() endif()
...@@ -50,15 +54,10 @@ else() ...@@ -50,15 +54,10 @@ else()
add_definitions(-fno-exceptions) add_definitions(-fno-exceptions)
endif() endif()
if(LOG_PROFILE) if(WITH_PROFILE)
add_definitions(-DPADDLE_MOBILE_PROFILE) add_definitions(-DPADDLE_MOBILE_PROFILE)
endif() endif()
if(USE_OPENMP)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fopenmp")
add_definitions(-DPADDLE_MOBILE_USE_OPENMP)
endif()
# platform control # platform control
if(ARM_LINUX) if(ARM_LINUX)
include("${CMAKE_CURRENT_LIST_DIR}/tools/arm-platform.cmake") include("${CMAKE_CURRENT_LIST_DIR}/tools/arm-platform.cmake")
...@@ -217,7 +216,6 @@ endif() ...@@ -217,7 +216,6 @@ endif()
set_property(CACHE NET PROPERTY STRINGS "default" "googlenet" "mobilenet" "yolo" "squeezenet" "FPGA_NET_V1" "FPGA_NET_V2" "NLP") set_property(CACHE NET PROPERTY STRINGS "default" "googlenet" "mobilenet" "yolo" "squeezenet" "FPGA_NET_V1" "FPGA_NET_V2" "NLP")
include("${CMAKE_CURRENT_LIST_DIR}/tools/op.cmake") include("${CMAKE_CURRENT_LIST_DIR}/tools/op.cmake")
# build library # build library
if(ANDROID_NDK_TOOLCHAIN_INCLUDED) if(ANDROID_NDK_TOOLCHAIN_INCLUDED)
list(REMOVE_DUPLICATES CMAKE_CXX_FLAGS) list(REMOVE_DUPLICATES CMAKE_CXX_FLAGS)
...@@ -239,7 +237,7 @@ else() ...@@ -239,7 +237,7 @@ else()
endif() endif()
# unit test # unit test
if(DEBUGING) if(WITH_TEST AND WITH_SYMBOL)
if(IS_IOS) if(IS_IOS)
else() else()
add_subdirectory(test) add_subdirectory(test)
......
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:MobileNetDemo.xcodeproj">
</FileRef>
</Workspace>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
//
// AppDelegate.swift
// MobileNetDemo
//
// Created by liuRuiLong on 2019/1/4.
// Copyright © 2019 Ray. All rights reserved.
//
import UIKit
@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
func applicationWillResignActive(_ application: UIApplication) {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
}
func applicationDidEnterBackground(_ application: UIApplication) {
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
}
func applicationWillEnterForeground(_ application: UIApplication) {
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background.
}
func applicationDidBecomeActive(_ application: UIApplication) {
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
}
func applicationWillTerminate(_ application: UIApplication) {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
}
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "29x29",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "40x40",
"scale" : "3x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "60x60",
"scale" : "3x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "29x29",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "40x40",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "1x"
},
{
"idiom" : "ipad",
"size" : "76x76",
"scale" : "2x"
},
{
"idiom" : "ipad",
"size" : "83.5x83.5",
"scale" : "2x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<dependencies>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="hKf-0C-qAk">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="Me8-c9-Oox">
<objects>
<viewController id="hKf-0C-qAk" customClass="ViewController" customModule="MobileNetDemo" customModuleProvider="target" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Yst-rK-Wk7">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="bDP-xQ-JgS">
<rect key="frame" x="0.0" y="20" width="375" height="271"/>
</imageView>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="HLo-2k-dr7">
<rect key="frame" x="16" y="597" width="63.5" height="30"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" secondItem="HLo-2k-dr7" secondAttribute="height" multiplier="21:10" id="xlA-qq-ubI"/>
</constraints>
<state key="normal" title="Image">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="selectImageAct:" destination="hKf-0C-qAk" eventType="touchUpInside" id="rJB-ZK-jTR"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Aa7-KR-JhB">
<rect key="frame" x="109.5" y="597" width="63" height="30"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Load">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="loadAct:" destination="hKf-0C-qAk" eventType="touchUpInside" id="Lkj-aW-8vj"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="2dy-Ya-PJY">
<rect key="frame" x="202.5" y="597" width="63.5" height="30"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Predict">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="predictAct:" destination="hKf-0C-qAk" eventType="touchUpInside" id="iw4-E7-3br"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Bac-eY-xPP">
<rect key="frame" x="296" y="597" width="63" height="30"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<state key="normal" title="Clear">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state>
<connections>
<action selector="clearAct:" destination="hKf-0C-qAk" eventType="touchUpInside" id="QgH-jd-cR1"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vhI-WH-WKF">
<rect key="frame" x="79.5" y="597" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="ffB-31-3Iy"/>
<constraint firstAttribute="height" constant="30" id="nbx-3B-EW0"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="ZoT-1q-tgf">
<rect key="frame" x="266" y="597" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="Iu3-ig-lYv"/>
<constraint firstAttribute="width" constant="30" id="Jic-6I-7ch"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="Zvo-dq-f6D">
<rect key="frame" x="172.5" y="597" width="30" height="30"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" constant="30" id="Zgu-c6-rPT"/>
<constraint firstAttribute="height" constant="30" id="c8V-Gd-hiK"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="耗时:" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Jox-rT-ieC">
<rect key="frame" x="15" y="301" width="350" height="38"/>
<constraints>
<constraint firstAttribute="height" constant="38" id="8TB-w5-hbk"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<imageView userInteractionEnabled="NO" contentMode="scaleToFill" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="paddle-mobile.png" translatesAutoresizingMaskIntoConstraints="NO" id="PZO-kk-MVS">
<rect key="frame" x="90" y="637" width="195" height="30"/>
<constraints>
<constraint firstAttribute="width" secondItem="PZO-kk-MVS" secondAttribute="height" multiplier="6.5:1" id="9DJ-Rj-4ex"/>
</constraints>
</imageView>
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" editable="NO" text="结果:" textAlignment="natural" translatesAutoresizingMaskIntoConstraints="NO" id="efW-gP-E3g">
<rect key="frame" x="10" y="347" width="355" height="150"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="height" constant="150" id="whC-NW-nhZ"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/>
</textView>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="PZO-kk-MVS" firstAttribute="centerX" secondItem="Yst-rK-Wk7" secondAttribute="centerX" id="2ET-tq-zfh"/>
<constraint firstItem="Zvo-dq-f6D" firstAttribute="leading" secondItem="Aa7-KR-JhB" secondAttribute="trailing" id="368-Sl-KgC"/>
<constraint firstItem="bDP-xQ-JgS" firstAttribute="top" secondItem="hlK-mk-uEU" secondAttribute="top" id="3HC-Tb-qff"/>
<constraint firstItem="hlK-mk-uEU" firstAttribute="trailing" secondItem="efW-gP-E3g" secondAttribute="trailing" constant="10" id="8QW-BB-dry"/>
<constraint firstItem="ZoT-1q-tgf" firstAttribute="leading" secondItem="2dy-Ya-PJY" secondAttribute="trailing" id="AhB-vB-1aW"/>
<constraint firstItem="Bac-eY-xPP" firstAttribute="leading" secondItem="ZoT-1q-tgf" secondAttribute="trailing" id="BhE-d9-7Sf"/>
<constraint firstItem="HLo-2k-dr7" firstAttribute="leading" secondItem="hlK-mk-uEU" secondAttribute="leading" constant="16" id="BuX-zw-HOG"/>
<constraint firstItem="HLo-2k-dr7" firstAttribute="width" secondItem="Aa7-KR-JhB" secondAttribute="width" id="Dbs-xF-8in"/>
<constraint firstItem="HLo-2k-dr7" firstAttribute="width" secondItem="Bac-eY-xPP" secondAttribute="width" id="Dov-mA-K38"/>
<constraint firstItem="hlK-mk-uEU" firstAttribute="trailing" secondItem="Jox-rT-ieC" secondAttribute="trailing" constant="10" id="LfU-MA-UTb"/>
<constraint firstItem="Aa7-KR-JhB" firstAttribute="centerY" secondItem="HLo-2k-dr7" secondAttribute="centerY" id="OMl-f7-5CL"/>
<constraint firstItem="HLo-2k-dr7" firstAttribute="top" secondItem="efW-gP-E3g" secondAttribute="bottom" constant="100" id="P2f-lC-F02"/>
<constraint firstItem="hlK-mk-uEU" firstAttribute="bottom" secondItem="HLo-2k-dr7" secondAttribute="bottom" constant="40" id="Po9-43-AFd"/>
<constraint firstItem="bDP-xQ-JgS" firstAttribute="trailing" secondItem="hlK-mk-uEU" secondAttribute="trailing" id="Pqb-0o-qjh"/>
<constraint firstItem="hlK-mk-uEU" firstAttribute="trailing" secondItem="Bac-eY-xPP" secondAttribute="trailing" constant="16" id="VOE-fl-N71"/>
<constraint firstItem="vhI-WH-WKF" firstAttribute="leading" secondItem="HLo-2k-dr7" secondAttribute="trailing" id="Vlg-FW-uEQ"/>
<constraint firstItem="ZoT-1q-tgf" firstAttribute="centerY" secondItem="HLo-2k-dr7" secondAttribute="centerY" id="Wpv-Ck-8l3"/>
<constraint firstItem="efW-gP-E3g" firstAttribute="top" secondItem="Jox-rT-ieC" secondAttribute="bottom" constant="8" id="Z8f-Rs-QDZ"/>
<constraint firstItem="vhI-WH-WKF" firstAttribute="centerY" secondItem="HLo-2k-dr7" secondAttribute="centerY" id="af8-Qd-iQN"/>
<constraint firstItem="bDP-xQ-JgS" firstAttribute="leading" secondItem="hlK-mk-uEU" secondAttribute="leading" id="bZr-fF-a2S"/>
<constraint firstItem="HLo-2k-dr7" firstAttribute="width" secondItem="2dy-Ya-PJY" secondAttribute="width" id="c0U-4X-uIO"/>
<constraint firstItem="2dy-Ya-PJY" firstAttribute="leading" secondItem="Zvo-dq-f6D" secondAttribute="trailing" id="cRa-pW-xi8"/>
<constraint firstItem="2dy-Ya-PJY" firstAttribute="centerY" secondItem="HLo-2k-dr7" secondAttribute="centerY" id="f2B-zG-wXC"/>
<constraint firstItem="PZO-kk-MVS" firstAttribute="top" secondItem="HLo-2k-dr7" secondAttribute="bottom" constant="10" id="hAy-La-Eeh"/>
<constraint firstItem="Zvo-dq-f6D" firstAttribute="centerY" secondItem="HLo-2k-dr7" secondAttribute="centerY" id="hUc-wn-Ua1"/>
<constraint firstItem="Bac-eY-xPP" firstAttribute="centerY" secondItem="HLo-2k-dr7" secondAttribute="centerY" id="jDC-ag-kL6"/>
<constraint firstItem="Aa7-KR-JhB" firstAttribute="leading" secondItem="vhI-WH-WKF" secondAttribute="trailing" id="jgU-OM-v1G"/>
<constraint firstItem="PZO-kk-MVS" firstAttribute="bottom" secondItem="hlK-mk-uEU" secondAttribute="bottom" id="lkS-rk-Ap8"/>
<constraint firstItem="efW-gP-E3g" firstAttribute="leading" secondItem="hlK-mk-uEU" secondAttribute="leading" constant="10" id="q2g-4E-mgJ"/>
<constraint firstItem="Jox-rT-ieC" firstAttribute="top" secondItem="bDP-xQ-JgS" secondAttribute="bottom" constant="10" id="rqK-Pv-SXt"/>
<constraint firstItem="Jox-rT-ieC" firstAttribute="leading" secondItem="hlK-mk-uEU" secondAttribute="leading" constant="15" id="sP3-ym-vhH"/>
</constraints>
<viewLayoutGuide key="safeArea" id="hlK-mk-uEU"/>
</view>
<connections>
<outlet property="elapsedTimeLabel" destination="Jox-rT-ieC" id="QdK-sY-xmq"/>
<outlet property="resultTextView" destination="efW-gP-E3g" id="Vnl-XG-D8E"/>
<outlet property="selectImageView" destination="bDP-xQ-JgS" id="dMV-Wh-YsW"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="ShQ-yg-7s0" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-1558" y="-14"/>
</scene>
</scenes>
<resources>
<image name="paddle-mobile.png" width="16" height="16"/>
</resources>
</document>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSCameraUsageDescription</key>
<string>use camera</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
...@@ -13,13 +13,13 @@ ...@@ -13,13 +13,13 @@
limitations under the License. */ limitations under the License. */
import Foundation import Foundation
import paddle_mobile
class MobileNet: Net{ public class MobileNet: Net{
class MobilenetPreProccess: CusomKernel { class MobilenetPreProccess: CusomKernel {
init(device: MTLDevice) { init(device: MTLDevice) {
let s = CusomKernel.Shape.init(inWidth: 224, inHeight: 224, inChannel: 3) let s = Shape.init(inWidth: 224, inHeight: 224, inChannel: 3)
super.init(device: device, inFunctionName: "mobilenet_preprocess", outputDim: s, usePaddleMobileLib: false) super.init(device: device, inFunctionName: "mobilenet_preprocess", outputDim: s, metalLoadModel: .LoadMetalInDefaultLib, metalLibPath: nil)
} }
} }
...@@ -43,9 +43,7 @@ class MobileNet: Net{ ...@@ -43,9 +43,7 @@ class MobileNet: Net{
let labels = PreWords.init(fileName: "synset") let labels = PreWords.init(fileName: "synset")
override public func resultStr(res: ResultHolder) -> String { override public func resultStr(res: ResultHolder) -> String {
guard let resPointer = res.result else { let resPointer = res.result
fatalError()
}
var s: [String] = [] var s: [String] = []
(0..<res.capacity).map { resPointer[$0] }.top(r: 5).enumerated().forEach{ (0..<res.capacity).map { resPointer[$0] }.top(r: 5).enumerated().forEach{
s.append(String(format: "%d: %@ (%3.2f%%)", $0 + 1, labels[$1.0], $1.1 * 100)) s.append(String(format: "%d: %@ (%3.2f%%)", $0 + 1, labels[$1.0], $1.1 * 100))
...@@ -53,18 +51,13 @@ class MobileNet: Net{ ...@@ -53,18 +51,13 @@ class MobileNet: Net{
return s.joined(separator: "\n") return s.joined(separator: "\n")
} }
override public init(device: MTLDevice) {
override init(device: MTLDevice) {
super.init(device: device) super.init(device: device)
means = [123.68, 116.78, 103.94]
scale = 0.017
except = 0 except = 0
modelPath = Bundle.main.path(forResource: "model", ofType: nil) ?! "model null" modelPath = Bundle.main.path(forResource: "mobilenet_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "params", ofType: nil) ?! "para null" paramPath = Bundle.main.path(forResource: "mobilenet_params", ofType: nil) ?! "para null"
modelDir = ""
preprocessKernel = MobilenetPreProccess.init(device: device) preprocessKernel = MobilenetPreProccess.init(device: device)
dim = (n: 1, h: 224, w: 224, c: 3) inputDim = Dim.init(inDim: [1, 224, 224, 3])
} }
} }
//
// MobilenetProcess.metal
// MobileNetDemo
//
// Created by liuRuiLong on 2019/1/5.
// Copyright © 2019 Ray. All rights reserved.
//
#include <metal_stdlib>
using namespace metal;
kernel void mobilenet_preprocess(
texture2d<float, access::read> inTexture [[texture(0)]],
texture2d<float, access::write> outTexture [[texture(1)]],
uint2 gid [[thread_position_in_grid]])
{
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) {
return;
}
const auto means = float4(123.68f, 116.78f, 103.94f, 0.0f);
const float4 inColor = (inTexture.read(gid) * 255.0 - means) * 0.017;
outTexture.write(float4(inColor.z, inColor.y, inColor.x, 0.0f), gid);
}
kernel void mobilenet_preprocess_half(
texture2d<half, access::read> inTexture [[texture(0)]],
texture2d<half, access::write> outTexture [[texture(1)]],
uint2 gid [[thread_position_in_grid]])
{
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) {
return;
}
const auto means = half4(123.68f, 116.78f, 103.94f, 0.0f);
const half4 inColor = (inTexture.read(gid) * 255.0 - means) * 0.017;
outTexture.write(half4(inColor.z, inColor.y, inColor.x, 0.0f), gid);
}
//
// ViewController.swift
// MobileNetDemo
//
// Created by liuRuiLong on 2019/1/4.
// Copyright © 2019 Ray. All rights reserved.
//
import UIKit
import paddle_mobile
class ViewController: UIViewController {
@IBOutlet weak var resultTextView: UITextView!
@IBOutlet weak var selectImageView: UIImageView!
@IBOutlet weak var elapsedTimeLabel: UILabel!
var net: MobileNet!
var runner: Runner!
var toPredictTexture: MTLTexture?
override func viewDidLoad() {
super.viewDidLoad()
GlobalConfig.shared.computePrecision = .Float16
net = MobileNet.init(device: MetalHelper.shared.device)
runner = Runner.init(inNet: net, commandQueue: MetalHelper.shared.queue)
if let selectImage = UIImage.init(named: "banana.jpeg") {
selectImageView.image = selectImage
runner.getTexture(image: selectImage.cgImage!) {[weak self] (texture) in
self?.toPredictTexture = texture
}
}
}
@IBAction func loadAct(_ sender: Any) {
if runner.load() {
let resutText = " load success ! "
print(resutText)
self.resultTextView.text = resutText
} else {
fatalError(" load error ")
}
}
@IBAction func selectImageAct(_ sender: Any) {
let imagePicker = UIImagePickerController()
imagePicker.sourceType = .camera
imagePicker.delegate = self
self.present(imagePicker, animated: true, completion: nil)
}
@IBAction func clearAct(_ sender: Any) {
runner.clear()
}
@IBAction func predictAct(_ sender: Any) {
if let texture = toPredictTexture {
let beginDate = Date.init()
runner.predict(texture: texture) { [weak self] (success, resultHolder) in
if success, let inResultHolder = resultHolder {
let timeUse = Date.init().timeIntervalSince(beginDate)
DispatchQueue.main.async {
self?.elapsedTimeLabel.text = "\(timeUse * 1000)ms"
self?.resultTextView.text = self?.net.resultStr(res: inResultHolder)
}
} else {
print(" predict fail ")
}
}
} else {
print(" toPredictTexture is nil ")
}
}
}
extension ViewController: UIImagePickerControllerDelegate, UINavigationControllerDelegate {
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : Any]) {
picker.dismiss(animated: true){[weak self] in
guard let sSelf = self, let image = info["UIImagePickerControllerOriginalImage"] as? UIImage else {
fatalError("no image")
}
sSelf.selectImageView.image = image
sSelf.runner.getTexture(image: image.cgImage!, getTexture: { (texture) in
sSelf.toPredictTexture = texture
})
}
}
}
...@@ -17,3 +17,9 @@ target 'paddle-mobile-unit-test' do ...@@ -17,3 +17,9 @@ target 'paddle-mobile-unit-test' do
project 'paddle-mobile-unit-test/paddle-mobile-unit-test.xcodeproj' project 'paddle-mobile-unit-test/paddle-mobile-unit-test.xcodeproj'
pod 'SwiftProtobuf', '~> 1.0' pod 'SwiftProtobuf', '~> 1.0'
end end
target 'MobileNetDemo' do
project 'MobileNetDemo/MobileNetDemo.xcodeproj'
pod 'SwiftProtobuf', '~> 1.0'
end
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B7D20E11C550081E9F8"
BuildableName = "paddle-mobile-demo.app"
BlueprintName = "paddle-mobile-demo"
ReferencedContainer = "container:paddle-mobile-demo.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B7D20E11C550081E9F8"
BuildableName = "paddle-mobile-demo.app"
BlueprintName = "paddle-mobile-demo"
ReferencedContainer = "container:paddle-mobile-demo.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B7D20E11C550081E9F8"
BuildableName = "paddle-mobile-demo.app"
BlueprintName = "paddle-mobile-demo"
ReferencedContainer = "container:paddle-mobile-demo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B7D20E11C550081E9F8"
BuildableName = "paddle-mobile-demo.app"
BlueprintName = "paddle-mobile-demo"
ReferencedContainer = "container:paddle-mobile-demo.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14113" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14460.31" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<device id="retina4_7" orientation="portrait"> <device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/> <adaptation id="fullscreen"/>
</device> </device>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14088"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14460.20"/>
<capability name="Aspect ratio constraints" minToolsVersion="5.1"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies> </dependencies>
...@@ -20,7 +19,7 @@ ...@@ -20,7 +19,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews> <subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TQt-X9-PdF"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="TQt-X9-PdF">
<rect key="frame" x="164" y="318" width="46" height="30"/> <rect key="frame" x="164.5" y="318.5" width="46" height="30"/>
<state key="normal" title="Button"/> <state key="normal" title="Button"/>
<connections> <connections>
<action selector="predictAct:" destination="Vwd-lt-764" eventType="touchUpInside" id="d4z-Cv-6jY"/> <action selector="predictAct:" destination="Vwd-lt-764" eventType="touchUpInside" id="d4z-Cv-6jY"/>
...@@ -60,7 +59,7 @@ ...@@ -60,7 +59,7 @@
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<pickerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DlO-dk-RMr"> <pickerView contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="DlO-dk-RMr">
<rect key="frame" x="55" y="510.5" width="320" height="80"/> <rect key="frame" x="55" y="510" width="320" height="80"/>
<constraints> <constraints>
<constraint firstAttribute="height" constant="80" id="Sbi-05-Mwd"/> <constraint firstAttribute="height" constant="80" id="Sbi-05-Mwd"/>
</constraints> </constraints>
...@@ -83,6 +82,9 @@ ...@@ -83,6 +82,9 @@
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wUL-9N-u1V"> <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" showsTouchWhenHighlighted="YES" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wUL-9N-u1V">
<rect key="frame" x="16" y="597" width="63.5" height="30"/> <rect key="frame" x="16" y="597" width="63.5" height="30"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstAttribute="width" secondItem="wUL-9N-u1V" secondAttribute="height" multiplier="21:10" id="cp7-bd-CvU"/>
</constraints>
<state key="normal" title="Image"> <state key="normal" title="Image">
<color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> <color key="titleColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</state> </state>
......
//
// LoadPointerViewController.h
// paddle-mobile-demo
//
// Created by Xiao,Haichun on 2018/9/19.
// Copyright © 2018年 orange. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface LoadPointerViewController : UIViewController
@end
...@@ -27,7 +27,4 @@ public class MetalHelper { ...@@ -27,7 +27,4 @@ public class MetalHelper {
queue = device.makeCommandQueue()! queue = device.makeCommandQueue()!
textureLoader = MTKTextureLoader.init(device: device) textureLoader = MTKTextureLoader.init(device: device)
} }
} }
...@@ -22,10 +22,10 @@ class MultiPredictViewController: UIViewController { ...@@ -22,10 +22,10 @@ class MultiPredictViewController: UIViewController {
super.viewDidLoad() super.viewDidLoad()
let mobileNet = MobileNet_ssd_hand.init(device: MetalHelper.shared.device) let mobileNet = MobileNet_ssd_hand.init(device: MetalHelper.shared.device)
let genet = Genet.init(device: MetalHelper.shared.device) let genet = Genet.init(device: MetalHelper.shared.device)
runner1 = Runner.init(inNet: mobileNet, commandQueue: MetalHelper.shared.queue, inPlatform: .GPU) runner1 = Runner.init(inNet: mobileNet, commandQueue: MetalHelper.shared.queue)
let queue2 = MetalHelper.shared.device.makeCommandQueue() let queue2 = MetalHelper.shared.device.makeCommandQueue()
runner2 = Runner.init(inNet: genet, commandQueue: MetalHelper.shared.queue, inPlatform: .GPU) runner2 = Runner.init(inNet: genet, commandQueue: MetalHelper.shared.queue)
} }
@IBAction func predictAct(_ sender: Any) { @IBAction func predictAct(_ sender: Any) {
......
//
// RGBToYCrCb_Y.metal
// paddle-mobile-demo
//
// Created by liuRuiLong on 2018/12/28.
// Copyright © 2018 orange. All rights reserved.
//
#include <metal_stdlib>
using namespace metal;
kernel void buffer_to_texture_kernel( const device float *input [[buffer(0)]],
texture2d<float, access::write> outTexture [[texture(0)]],
uint2 gid [[thread_position_in_grid]]){
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) {
return;
}
float y = input[outTexture.get_width() * gid.y + gid.x];
outTexture.write(float4(y, 0.0f, 0.0f, 0.0f), gid);
}
kernel void buffer_to_texture_kernel_half( const device float *input [[buffer(0)]],
texture2d<half, access::write> outTexture [[texture(0)]],
uint2 gid [[thread_position_in_grid]]){
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) {
return;
}
float y = input[outTexture.get_width() * gid.y + gid.x];
outTexture.write(half4(y, 0.0f, 0.0f, 0.0f), gid);
}
...@@ -16,7 +16,6 @@ ...@@ -16,7 +16,6 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
@interface CPUResult: NSObject @interface CPUResult: NSObject
@property (assign, nonatomic) float *output; @property (assign, nonatomic) float *output;
@property (assign, nonatomic) int outputSize; @property (assign, nonatomic) int outputSize;
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#import "CPUCompute.h" #import "CPUCompute.h"
#import <map> #import <map>
...@@ -20,9 +19,6 @@ ...@@ -20,9 +19,6 @@
#import <utility> #import <utility>
#import <algorithm> #import <algorithm>
struct NMSParam { struct NMSParam {
float *score_data; float *score_data;
......
...@@ -13,42 +13,36 @@ ...@@ -13,42 +13,36 @@
limitations under the License. */ limitations under the License. */
import Foundation import Foundation
import paddle_mobile
public class Genet: Net { public class Genet: Net {
@objc public override init(device: MTLDevice) { @objc public override init(device: MTLDevice) {
super.init(device: device) super.init(device: device)
means = [128.0, 128.0, 128.0]
scale = 0.017
except = 0
modelPath = Bundle.main.path(forResource: "genet_model", ofType: nil) ?! "model null" modelPath = Bundle.main.path(forResource: "genet_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "genet_params", ofType: nil) ?! "para null" paramPath = Bundle.main.path(forResource: "genet_params", ofType: nil) ?! "para null"
modelDir = ""
preprocessKernel = GenetPreProccess.init(device: device) preprocessKernel = GenetPreProccess.init(device: device)
dim = (n: 1, h: 128, w: 128, c: 3) inputDim = Dim.init(inDim: [1, 128, 128, 3])
} }
@objc override public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) { @objc override public init(device: MTLDevice, paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) {
super.init(device:device,paramPointer:paramPointer,paramSize:paramSize,modePointer:modePointer,modelSize:modelSize) super.init(device: device,
means = [128.0, 128.0, 128.0] paramPointer: paramPointer,
scale = 0.017 paramSize: paramSize,
except = 0 modePointer: modePointer,
modelPath = "" modelSize: modelSize)
paramPath = ""
modelDir = ""
preprocessKernel = GenetPreProccess.init(device: device) preprocessKernel = GenetPreProccess.init(device: device)
dim = (n: 1, h: 128, w: 128, c: 3) inputDim = Dim.init(inDim: [1, 128, 128, 3])
} }
class GenetPreProccess: CusomKernel { class GenetPreProccess: CusomKernel {
init(device: MTLDevice) { init(device: MTLDevice) {
let s = CusomKernel.Shape.init(inWidth: 128, inHeight: 128, inChannel: 3) let s = Shape.init(inWidth: 128, inHeight: 128, inChannel: 3)
super.init(device: device, inFunctionName: "genet_preprocess", outputDim: s, usePaddleMobileLib: false) super.init(device: device, inFunctionName: "genet_preprocess", outputDim: s, metalLoadModel: .LoadMetalInDefaultLib, metalLibPath: nil)
} }
} }
override public func resultStr(res: ResultHolder) -> String { override public func resultStr(res: ResultHolder) -> String {
// fatalError() return " \(res.result[0]) ... "
return " \(res.result![0]) ... "
} }
} }
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
import paddle_mobile
public class MobileNet: Net{
class MobilenetPreProccess: CusomKernel {
init(device: MTLDevice) {
let s = Shape.init(inWidth: 224, inHeight: 224, inChannel: 3)
super.init(device: device, inFunctionName: "mobilenet_preprocess", outputDim: s, metalLoadModel: .LoadMetalInDefaultLib, metalLibPath: nil)
}
}
class PreWords {
var contents: [String] = []
init(fileName: String, type: String = "txt", inBundle: Bundle = Bundle.main) {
if let filePath = inBundle.path(forResource: fileName, ofType: type) {
let string = try! String.init(contentsOfFile: filePath)
contents = string.components(separatedBy: CharacterSet.newlines).filter{$0.count > 10}.map{
String($0[$0.index($0.startIndex, offsetBy: 10)...])
}
}else{
fatalError("no file call \(fileName)")
}
}
subscript(index: Int) -> String {
return contents[index]
}
}
let labels = PreWords.init(fileName: "synset")
override public func resultStr(res: ResultHolder) -> String {
let resPointer = res.result
var s: [String] = []
(0..<res.capacity).map { resPointer[$0] }.top(r: 5).enumerated().forEach{
s.append(String(format: "%d: %@ (%3.2f%%)", $0 + 1, labels[$1.0], $1.1 * 100))
}
return s.joined(separator: "\n")
}
override public init(device: MTLDevice) {
super.init(device: device)
except = 0
modelPath = Bundle.main.path(forResource: "mobilenet_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "mobilenet_params", ofType: nil) ?! "para null"
// metalLoadMode = .LoadMetalInCustomMetalLib
// metalLibPath = Bundle.main.path(forResource: "PaddleMobileMetal", ofType: "metallib") ?! " can't be nil "
preprocessKernel = MobilenetPreProccess.init(device: device)
inputDim = Dim.init(inDim: [1, 224, 224, 3])
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
import paddle_mobile
public class MobileNetCombined: Net {
@objc public override init(device: MTLDevice) {
super.init(device: device)
except = 0
modelPath = Bundle.main.path(forResource: "combined_mobilenet_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "combined_mobilenet_params", ofType: nil) ?! "para null"
inputDim = Dim.init(inDim: [1, 224, 224, 3])
// metalLoadMode = .LoadMetalInCustomMetalLib
// metalLibPath = Bundle.main.path(forResource: "PaddleMobileMetal", ofType: "metallib") ?! " can't be nil "
}
override public func resultStr(res: ResultHolder) -> String {
return " \(res.result[0]) ... "
}
}
...@@ -13,36 +13,35 @@ ...@@ -13,36 +13,35 @@
limitations under the License. */ limitations under the License. */
import Foundation import Foundation
import paddle_mobile
public class MobileNet_ssd_hand: Net{ public class MobileNet_ssd_hand: Net {
@objc public override init(device: MTLDevice) { @objc public override init(device: MTLDevice) {
super.init(device: device) super.init(device: device)
means = [123.68, 116.78, 103.94]
scale = 0.017
except = 2 except = 2
modelPath = Bundle.main.path(forResource: "ssd_hand_model", ofType: nil) ?! "model null" modelPath = Bundle.main.path(forResource: "ssd_hand_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "ssd_hand_params", ofType: nil) ?! "para null" paramPath = Bundle.main.path(forResource: "ssd_hand_params", ofType: nil) ?! "para null"
modelDir = "" // metalLoadMode = .LoadMetalInCustomMetalLib
// metalLibPath = Bundle.main.path(forResource: "PaddleMobileMetal", ofType: "metallib") ?! " can't be nil "
preprocessKernel = MobilenetssdPreProccess.init(device: device) preprocessKernel = MobilenetssdPreProccess.init(device: device)
dim = (n: 1, h: 300, w: 300, c: 3) inputDim = Dim.init(inDim: [1, 300, 300, 3])
} }
@objc override public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) { @objc override public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) {
super.init(device:device,paramPointer:paramPointer,paramSize:paramSize,modePointer:modePointer,modelSize:modelSize) super.init(device:device,paramPointer:paramPointer,paramSize:paramSize,modePointer:modePointer,modelSize:modelSize)
means = [123.68, 116.78, 103.94]
scale = 0.017
except = 2 except = 2
modelPath = "" modelPath = ""
paramPath = "" paramPath = ""
modelDir = "" // metalLoadMode = .LoadMetalInCustomMetalLib
// metalLibPath = Bundle.main.path(forResource: "PaddleMobileMetal", ofType: "metallib") ?! " can't be nil "
preprocessKernel = MobilenetssdPreProccess.init(device: device) preprocessKernel = MobilenetssdPreProccess.init(device: device)
dim = (n: 1, h: 300, w: 300, c: 3) inputDim = Dim.init(inDim: [1, 300, 300, 3])
} }
class MobilenetssdPreProccess: CusomKernel { class MobilenetssdPreProccess: CusomKernel {
init(device: MTLDevice) { init(device: MTLDevice) {
let s = CusomKernel.Shape.init(inWidth: 300, inHeight: 300, inChannel: 3) let s = Shape.init(inWidth: 300, inHeight: 300, inChannel: 3)
super.init(device: device, inFunctionName: "mobilenet_ssd_preprocess", outputDim: s, usePaddleMobileLib: false) super.init(device: device, inFunctionName: "mobilenet_ssd_preprocess", outputDim: s, metalLoadModel: .LoadMetalInDefaultLib, metalLibPath: nil)
} }
} }
...@@ -50,7 +49,7 @@ public class MobileNet_ssd_hand: Net{ ...@@ -50,7 +49,7 @@ public class MobileNet_ssd_hand: Net{
return " \(res)" return " \(res)"
} }
override func fetchResult(paddleMobileRes: GPUResultHolder) -> ResultHolder { override public func fetchResult(paddleMobileRes: GPUResultHolder) -> ResultHolder {
// guard let interRes = paddleMobileRes.intermediateResults else { // guard let interRes = paddleMobileRes.intermediateResults else {
// fatalError(" need have inter result ") // fatalError(" need have inter result ")
......
...@@ -13,55 +13,49 @@ ...@@ -13,55 +13,49 @@
limitations under the License. */ limitations under the License. */
import Foundation import Foundation
import paddle_mobile
public class MobileNet_ssd_AR: Net{ public class MobileNet_ssd_AR: Net {
@objc public override init(device: MTLDevice) { @objc public override init(device: MTLDevice) {
super.init(device: device) super.init(device: device)
means = [103.94, 116.78, 123.68]
scale = 1
except = 2 except = 2
modelPath = Bundle.main.path(forResource: "ar_model", ofType: nil) ?! "model null" modelPath = Bundle.main.path(forResource: "ar_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "ar_params", ofType: nil) ?! "para null" paramPath = Bundle.main.path(forResource: "ar_params", ofType: nil) ?! "para null"
modelDir = ""
preprocessKernel = MobilenetssdPreProccess.init(device: device) preprocessKernel = MobilenetssdPreProccess.init(device: device)
dim = (n: 1, h: 160, w: 160, c: 3) inputDim = Dim.init(inDim: [1, 160, 160, 3])
} }
@objc override public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) { @objc override public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) {
super.init(device:device,paramPointer:paramPointer,paramSize:paramSize,modePointer:modePointer,modelSize:modelSize) super.init(device:device,paramPointer:paramPointer,paramSize:paramSize,modePointer:modePointer,modelSize:modelSize)
means = [103.94, 116.78, 123.68]
scale = 1
except = 2 except = 2
modelPath = ""
paramPath = ""
modelDir = ""
preprocessKernel = MobilenetssdPreProccess.init(device: device) preprocessKernel = MobilenetssdPreProccess.init(device: device)
dim = (n: 1, h: 160, w: 160, c: 3) inputDim = Dim.init(inDim: [1, 160, 160, 3])
} }
class MobilenetssdPreProccess: CusomKernel { class MobilenetssdPreProccess: CusomKernel {
init(device: MTLDevice) { init(device: MTLDevice) {
let s = CusomKernel.Shape.init(inWidth: 160, inHeight: 160, inChannel: 3) let s = Shape.init(inWidth: 160, inHeight: 160, inChannel: 3)
super.init(device: device, inFunctionName: "mobilent_ar_preprocess", outputDim: s, usePaddleMobileLib: false) super.init(device: device, inFunctionName: "mobilent_ar_preprocess", outputDim: s, metalLoadModel: .LoadMetalInDefaultLib, metalLibPath: nil)
} }
} }
override public func resultStr(res: ResultHolder) -> String { override public func resultStr(res: ResultHolder) -> String {
return " \(res.result![0])" return " \(res.result[0])"
} }
override func fetchResult(paddleMobileRes: GPUResultHolder) -> ResultHolder { override public func fetchResult(paddleMobileRes: GPUResultHolder) -> ResultHolder {
guard let interRes = paddleMobileRes.intermediateResults else { fatalError()
fatalError(" need have inter result ") // guard let interRes = paddleMobileRes.intermediateResults else {
} // fatalError(" need have inter result ")
// }
guard let scores = interRes["Scores"], scores.count > 0, let score = scores[0] as? FetchHolder else { //
fatalError(" need score ") // guard let scores = interRes["Scores"], scores.count > 0, let score = scores[0] as? FetchHolder else {
} // fatalError(" need score ")
// }
guard let bboxs = interRes["BBoxes"], bboxs.count > 0, let bbox = bboxs[0] as? FetchHolder else { //
fatalError() // guard let bboxs = interRes["BBoxes"], bboxs.count > 0, let bbox = bboxs[0] as? FetchHolder else {
} // fatalError()
// }
// let startDate = Date.init() // let startDate = Date.init()
...@@ -72,19 +66,19 @@ public class MobileNet_ssd_AR: Net{ ...@@ -72,19 +66,19 @@ public class MobileNet_ssd_AR: Net{
// //
// print((0..<bbox.capacity).map{ bbox.result[$0] }.strideArray()) // print((0..<bbox.capacity).map{ bbox.result[$0] }.strideArray())
let nmsCompute = NMSCompute.init() // let nmsCompute = NMSCompute.init()
nmsCompute.scoreThredshold = 0.25 // nmsCompute.scoreThredshold = 0.25
nmsCompute.nmsTopK = 100 // nmsCompute.nmsTopK = 100
nmsCompute.keepTopK = 100 // nmsCompute.keepTopK = 100
nmsCompute.nmsEta = 1.0 // nmsCompute.nmsEta = 1.0
nmsCompute.nmsThreshold = 0.449999988 // nmsCompute.nmsThreshold = 0.449999988
nmsCompute.background_label = 0; // nmsCompute.background_label = 0;
nmsCompute.scoreDim = [NSNumber.init(value: score.dim[0]), NSNumber.init(value: score.dim[1]), NSNumber.init(value: score.dim[2])] // nmsCompute.scoreDim = [NSNumber.init(value: score.dim[0]), NSNumber.init(value: score.dim[1]), NSNumber.init(value: score.dim[2])]
nmsCompute.bboxDim = [NSNumber.init(value: bbox.dim[0]), NSNumber.init(value: bbox.dim[1]), NSNumber.init(value: bbox.dim[2])] // nmsCompute.bboxDim = [NSNumber.init(value: bbox.dim[0]), NSNumber.init(value: bbox.dim[1]), NSNumber.init(value: bbox.dim[2])]
guard let result = nmsCompute.compute(withScore: score.result, andBBoxs: bbox.result) else { // guard let result = nmsCompute.compute(withScore: score.result, andBBoxs: bbox.result) else {
fatalError( " result error " ) // fatalError( " result error " )
} // }
let resultHolder = ResultHolder.init(inResult: result.output, inCapacity: Int(result.outputSize)) // let resultHolder = ResultHolder.init(inResult: result.output, inCapacity: Int(result.outputSize))
// for i in 0..<Int(result.outputSize) { // for i in 0..<Int(result.outputSize) {
// //
// print("i \(i) : \(result.output[i])") // print("i \(i) : \(result.output[i])")
...@@ -92,62 +86,63 @@ public class MobileNet_ssd_AR: Net{ ...@@ -92,62 +86,63 @@ public class MobileNet_ssd_AR: Net{
// print(Date.init().timeIntervalSince(startDate)) // print(Date.init().timeIntervalSince(startDate))
// print(resultHolder.result![0]) // print(resultHolder.result![0])
return resultHolder // return resultHolder
} }
override func updateProgram(program: Program) { // override func updateProgram(program: Program) {
for i in [56, 66, 76, 86, 93, 99] {
let opDesc = program.programDesc.blocks[0].ops[i] // for i in [56, 66, 76, 86, 93, 99] {
let output = opDesc.outputs["Out"]!.first! // let opDesc = program.programDesc.blocks[0].ops[i]
let v = program.scope[output]! // let output = opDesc.outputs["Out"]!.first!
let originTexture = v as! Texture<Float32> // let v = program.scope[output]!
originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1] / 7, originTexture.tensorDim[0] * 7]) // let originTexture = v as! Texture
// originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1] / 7, originTexture.tensorDim[0] * 7])
originTexture.dim = Dim.init(inDim: [1, 1, originTexture.dim[3] / 7, originTexture.dim[2] * 7]) //
// originTexture.dim = Dim.init(inDim: [1, 1, originTexture.dim[3] / 7, originTexture.dim[2] * 7])
originTexture.padToFourDim = Dim.init(inDim: [1, 1, originTexture.padToFourDim[3] / 7, originTexture.padToFourDim[2] * 7]) //
// originTexture.padToFourDim = Dim.init(inDim: [1, 1, originTexture.padToFourDim[3] / 7, originTexture.padToFourDim[2] * 7])
program.scope[output] = originTexture //
// program.scope[output] = originTexture
if i == 99 { //
opDesc.attrs["axis"] = 0 // if i == 99 {
} else { // opDesc.attrs["axis"] = 0
opDesc.attrs["shape"] = originTexture.tensorDim.dims.map { Int32($0) } // } else {
} // opDesc.attrs["shape"] = originTexture.tensorDim.dims.map { Int32($0) }
} // }
// }
for i in [58, 59, 88, 89, 95, 96, 68, 69, 78, 79] { //
let opDesc = program.programDesc.blocks[0].ops[i] // for i in [58, 59, 88, 89, 95, 96, 68, 69, 78, 79] {
let output = opDesc.outputs["Out"]!.first! // let opDesc = program.programDesc.blocks[0].ops[i]
let v = program.scope[output]! // let output = opDesc.outputs["Out"]!.first!
// let v = program.scope[output]!
//
//
let originTexture = v as! Texture<Float32> //
originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1], originTexture.tensorDim[2]]) // let originTexture = v as! Texture
opDesc.attrs["shape"] = originTexture.tensorDim.dims.map { Int32($0) } // originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1], originTexture.tensorDim[2]])
} // opDesc.attrs["shape"] = originTexture.tensorDim.dims.map { Int32($0) }
// }
for i in [60, 101, 90, 97, 70, 80] { //
let opDesc = program.programDesc.blocks[0].ops[i] // for i in [60, 101, 90, 97, 70, 80] {
let output = opDesc.outputs["Out"]!.first! // let opDesc = program.programDesc.blocks[0].ops[i]
let v = program.scope[output]! // let output = opDesc.outputs["Out"]!.first!
let originTexture = v as! Texture<Float32> // let v = program.scope[output]!
originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1], originTexture.tensorDim[2]]) // let originTexture = v as! Texture
opDesc.attrs["axis"] = (opDesc.attrs["axis"]! as! Int) - 1 // originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1], originTexture.tensorDim[2]])
} // opDesc.attrs["axis"] = (opDesc.attrs["axis"]! as! Int) - 1
// }
for i in [102] { //
let opDesc = program.programDesc.blocks[0].ops[i] // for i in [102] {
for output in opDesc.outputs["Out"]! { // let opDesc = program.programDesc.blocks[0].ops[i]
let v = program.scope[output]! // for output in opDesc.outputs["Out"]! {
let originTexture = v as! Texture<Float32> // let v = program.scope[output]!
originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1], originTexture.tensorDim[2]]) // let originTexture = v as! Texture
} // originTexture.tensorDim = Dim.init(inDim: [originTexture.tensorDim[1], originTexture.tensorDim[2]])
opDesc.attrs["axis"] = (opDesc.attrs["axis"]! as! Int) - 1 // }
print(" split axis \(opDesc.attrs["axis"])") // opDesc.attrs["axis"] = (opDesc.attrs["axis"]! as! Int) - 1
} // print(" split axis \(opDesc.attrs["axis"])")
// }
// 99 // 99
} // }
} }
//
// PaddleMobile.swift
// paddle-mobile-demo
//
// Created by liuRuiLong on 2018/9/5.
// Copyright © 2018年 orange. All rights reserved.
//
import Foundation
...@@ -115,23 +115,3 @@ kernel void mobilent_ar_preprocess_half(texture2d<half, access::read> inTexture ...@@ -115,23 +115,3 @@ kernel void mobilent_ar_preprocess_half(texture2d<half, access::read> inTexture
const half4 inColor = (inTexture.read(gid) * 255.0 - means) * 0.017; const half4 inColor = (inTexture.read(gid) * 255.0 - means) * 0.017;
outTexture.write(half4(inColor.z, inColor.y, inColor.x, 0.0f), gid); outTexture.write(half4(inColor.z, inColor.y, inColor.x, 0.0f), gid);
} }
kernel void scale(texture2d<float, access::sample> inTexture [[texture(0)]], texture2d<float, access::write> outTexture [[texture(1)]], uint2 gid [[thread_position_in_grid]]) {
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) return;
float w_stride = inTexture.get_width() / outTexture.get_width();
float h_stride = inTexture.get_height() / outTexture.get_height();
constexpr sampler sample(coord::pixel, filter::nearest, address::clamp_to_zero);
float4 input = inTexture.sample(sample, float2(gid.x * w_stride, gid.y * h_stride), 0);
outTexture.write(input, gid);
}
kernel void scale_half(texture2d<float, access::sample> inTexture [[texture(0)]], texture2d<half, access::write> outTexture [[texture(1)]], uint2 gid [[thread_position_in_grid]]) {
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height()) return;
float w_stride = inTexture.get_width() / outTexture.get_width();
float h_stride = inTexture.get_height() / outTexture.get_height();
constexpr sampler sample(coord::pixel, filter::nearest, address::clamp_to_zero);
float4 input = inTexture.sample(sample, float2(gid.x * w_stride, gid.y * h_stride), 0);
outTexture.write(half4(input), gid);
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Metal
import Foundation
import paddle_mobile
public class YoloNet: Net {
@objc public override init(device: MTLDevice) {
super.init(device: device)
except = 0
modelPath = Bundle.main.path(forResource: "yolo_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "yolo_params", ofType: nil) ?! "para null"
inputDim = Dim.init(inDim: [1, 416, 416, 3])
// metalLoadMode = .LoadMetalInCustomMetalLib
// metalLibPath = Bundle.main.path(forResource: "PaddleMobileMetal", ofType: "metallib") ?! " can't be nil "
}
override public func resultStr(res: ResultHolder) -> String {
return " \(res.result[0]) ... "
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#import <UIKit/UIKit.h>
@interface LoadPointerViewController : UIViewController
@end
// /* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
// LoadPointerViewController.m
// paddle-mobile-demo Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// Created by Xiao,Haichun on 2018/9/19. You may obtain a copy of the License at
// Copyright © 2018年 orange. All rights reserved.
// http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#import "PaddleMobileGPU.h"
#import "LoadPointerViewController.h" #import "LoadPointerViewController.h"
#import <Metal/Metal.h>
#import "paddle-mobile-demo-Bridging-Header.h" #import "paddle-mobile-demo-Bridging-Header.h"
#import <Metal/Metal.h>
@interface LoadPointerViewController () @interface LoadPointerViewController ()
@property (strong, nonatomic) id<MTLDevice> device; @property (strong, nonatomic) id<MTLDevice> device;
......
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface OCDemoViewController : NSObject
@end
NS_ASSUME_NONNULL_END
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#import "OCDemoViewController.h"
@implementation OCDemoViewController
@end
...@@ -16,9 +16,8 @@ ...@@ -16,9 +16,8 @@
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
typedef enum : NSUInteger { typedef enum : NSUInteger {
MobileNetType, SuperResolutionNetType,
MobileNetSSDType, MobileNetSSDType
GenetType,
} NetType; } NetType;
@interface PaddleMobileGPUResult: NSObject @interface PaddleMobileGPUResult: NSObject
......
...@@ -12,10 +12,10 @@ ...@@ -12,10 +12,10 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
#import <Foundation/Foundation.h>
#import "PaddleMobileGPU.h" #import "PaddleMobileGPU.h"
#import "paddle_mobile.h"
#import <paddle_mobile/paddle_mobile-Swift.h> #import <Foundation/Foundation.h>
#import <paddle_mobile_demo-Swift.h>
@implementation ModelConfig @implementation ModelConfig
@end @end
...@@ -52,14 +52,12 @@ ...@@ -52,14 +52,12 @@
self = [super init]; self = [super init];
if (self) { if (self) {
Net *net = nil; Net *net = nil;
if (netType == GenetType) { if (netType == SuperResolutionNetType) {
net = [[Genet alloc] initWithDevice:queue.device paramPointer:config.paramPointer paramSize:config.paramSize modePointer:config.modelPointer modelSize:config.modelSize]; net = [[SuperResolutionNet alloc] initWithDevice:queue.device];
} else if (netType == MobileNetSSDType) { } else if (netType == MobileNetSSDType) {
net = [[MobileNet_ssd_AR alloc] initWithDevice:queue.device paramPointer:config.paramPointer paramSize:config.paramSize modePointer:config.modelPointer modelSize:config.modelSize]; net = [[MobileNet_ssd_AR alloc] initWithDevice:queue.device paramPointer:config.paramPointer paramSize:config.paramSize modePointer:config.modelPointer modelSize:config.modelSize];
} else if (netType == MobileNetType) {
} }
runner = [[Runner alloc] initInNet:net commandQueue:queue inPlatform:PlatformGPU]; runner = [[Runner alloc] initInNet:net commandQueue:queue];
} }
return self; return self;
} }
...@@ -69,6 +67,7 @@ ...@@ -69,6 +67,7 @@
} }
-(void)predict:(id<MTLTexture>)texture withCompletion:(void (^)(BOOL, NSArray<NSNumber *> *))completion { -(void)predict:(id<MTLTexture>)texture withCompletion:(void (^)(BOOL, NSArray<NSNumber *> *))completion {
[runner predictWithTexture:texture completion:^(BOOL success, ResultHolder * _Nullable result) { [runner predictWithTexture:texture completion:^(BOOL success, ResultHolder * _Nullable result) {
NSMutableArray<NSNumber *> *resultArray = [NSMutableArray arrayWithCapacity:result.capacity]; NSMutableArray<NSNumber *> *resultArray = [NSMutableArray arrayWithCapacity:result.capacity];
for (int i = 0; i < result.capacity; ++i) { for (int i = 0; i < result.capacity; ++i) {
......
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
import paddle_mobile
@objc public class SuperResolutionNet: Net{
override public func resultStr(res: ResultHolder) -> String {
return "未实现"
}
@objc override public init(device: MTLDevice) {
super.init(device: device)
except = 0
modelPath = Bundle.main.path(forResource: "super_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "super_params", ofType: nil) ?! "para null"
preprocessKernel = nil
inputDim = Dim.init(inDim: [1, 224, 224, 1])
// metalLoadMode = .LoadMetalInCustomMetalLib
// metalLibPath = Bundle.main.path(forResource: "PaddleMobileMetal", ofType: "metallib") ?! " can't be nil "
}
override public func updateProgram(program: Program) {
// n h w c
for block in program.programDesc.blocks {
for varDesc in block.vars {
if !varDesc.persistable {
if varDesc.type == .LodTensor {
let varEle = program.scope.vars[varDesc.name]
if let texture = varEle as? Texture {
let newDim = Dim.init(inDim: [texture.dim[0], inputDim[1], inputDim[2], texture.tensorDim[1]])
print(" var desc name " + varDesc.name + " new dim" + "\(newDim)")
texture.updateDims(inTensorDim: Dim.init(inDim: [texture.tensorDim[0], texture.tensorDim[1], inputDim[1], inputDim[2]]), inDim: newDim)
texture.initTexture(device: device, inTranspose: [0, 1, 2, 3], computePrecision: GlobalConfig.shared.computePrecision)
let output: FetchHolder = program.scope.output() as! FetchHolder
output.dim = newDim
output.capacity = newDim.numel()
output.paddedCapacity = newDim.numel() * 4
output.initBuffer(device: device)
}
}
}
}
}
}
}
...@@ -18,31 +18,56 @@ import CoreMedia ...@@ -18,31 +18,56 @@ import CoreMedia
import paddle_mobile import paddle_mobile
import MetalPerformanceShaders import MetalPerformanceShaders
var platform: Platform = .GPU class FileReader {
let threadSupport: [(Platform, String)] = [(.GPU, "GPU"), (.CPU, "CPU")] let file: UnsafeMutablePointer<FILE>
let fileSize: Int
init(paramPath: String) throws {
guard let tmpFile = fopen(paramPath, "rb") else {
throw PaddleMobileError.loaderError(message: "open param file error" + paramPath)
}
file = tmpFile
fseek(file, 0, SEEK_END)
fileSize = ftell(file)
guard fileSize > 0 else {
throw PaddleMobileError.loaderError(message: "param file size is too small")
}
rewind(file)
}
func read<T>() -> UnsafeMutablePointer<T> {
let ptr = UnsafeMutablePointer<T>.allocate(capacity: MemoryLayout<T>.size * fileSize)
fread(ptr, fileSize, 1, file)
return ptr
}
deinit {
fclose(file)
}
}
//.mobilenet_ssd : Runner.init(inNet: MobileNet_ssd_hand.init(device: MetalHelper.shared.device), commandQueue: MetalHelper.shared.queue, inPlatform: platform), enum Platform {
let modelHelperMap: [SupportModel : Runner] = [ case GPU
.yolo : Runner.init(inNet: YoloNet.init(device: MetalHelper.shared.device), commandQueue: MetalHelper.shared.queue, inPlatform: platform), }
.mobilenet_combined : Runner.init(inNet: MobileNetCombined.init(device: MetalHelper.shared.device), commandQueue: MetalHelper.shared.queue, inPlatform: platform)]
//, .genet : Genet.init()
//let modelHelperMap: [SupportModel : Net] = [.mobilenet : MobileNet.init(), .mobilenet_ssd : MobileNet_ssd_hand.init()]
let netSupport: [SupportModel : Net] = [.yolo : YoloNet.init(device: MetalHelper.shared.device), .mobilenet_combined : MobileNetCombined.init(device: MetalHelper.shared.device)] let platformSupport: [(Platform, String)] = [(.GPU, "GPU")]
enum SupportModel: String{ enum SupportModel: String{
// case mobilenet = "mobilenet" case yolo = "yolo"
// case mobilenet_ssd = "mobilenetssd"
case yolo = "yolo"
case mobilenet_combined = "mobilenet_combined" case mobilenet_combined = "mobilenet_combined"
case super_resolution = "superresoltion"
case mobilenet = "mobilenet"
static func supportedModels() -> [SupportModel] { static func supportedModels() -> [SupportModel] {
// .mobilenet, return [.super_resolution, .yolo, .mobilenet_combined, .mobilenet]
// .mobilenet_ssd,
return [.yolo, .mobilenet_combined]
} }
} }
let netSupport: [SupportModel : Net] = [
.super_resolution : SuperResolutionNet.init(device: MetalHelper.shared.device),
.yolo : YoloNet.init(device: MetalHelper.shared.device),
.mobilenet_combined : MobileNetCombined.init(device: MetalHelper.shared.device),
.mobilenet : MobileNet.init(device: MetalHelper.shared.device)]
class ViewController: UIViewController { class ViewController: UIViewController {
@IBOutlet weak var resultTextView: UITextView! @IBOutlet weak var resultTextView: UITextView!
@IBOutlet weak var selectImageView: UIImageView! @IBOutlet weak var selectImageView: UIImageView!
...@@ -50,28 +75,37 @@ class ViewController: UIViewController { ...@@ -50,28 +75,37 @@ class ViewController: UIViewController {
@IBOutlet weak var modelPickerView: UIPickerView! @IBOutlet weak var modelPickerView: UIPickerView!
@IBOutlet weak var threadPickerView: UIPickerView! @IBOutlet weak var threadPickerView: UIPickerView!
@IBOutlet weak var videoView: UIView! @IBOutlet weak var videoView: UIView!
// var videoCapture: VideoCapture! // var videoCapture: VideoCapture!
var selectImage: UIImage? var selectImage: UIImage?
var inputPointer: UnsafeMutablePointer<Float32>? var inputPointer: UnsafeMutablePointer<Float32>?
var modelType: SupportModel = SupportModel.supportedModels()[0] var modelType: SupportModel = SupportModel.supportedModels()[0]
var toPredictTexture: MTLTexture? var toPredictTexture: MTLTexture?
var runner: Runner! var runner: Runner!
var platform: Platform = .GPU
var threadNum = 1 var threadNum = 1
@IBAction func loadAct(_ sender: Any) { @IBAction func loadAct(_ sender: Any) {
runner = Runner.init(inNet: netSupport[modelType]!, commandQueue: MetalHelper.shared.queue, inPlatform: platform) runner = Runner.init(inNet: netSupport[modelType]!, commandQueue: MetalHelper.shared.queue)
if platform == .GPU {
if platform == .CPU { // let filePath = Bundle.main.path(forResource: "mingren_input_data", ofType: nil)
if inputPointer == nil { // let fileReader = try! FileReader.init(paramPath: filePath!)
inputPointer = runner.preproccess(image: selectImage!.cgImage!) // let pointer: UnsafeMutablePointer<Float32> = fileReader.read()
//
} //
} else if platform == .GPU { // let buffer = MetalHelper.shared.device.makeBuffer(length: fileReader.fileSize, options: .storageModeShared)
//
// buffer?.contents().copyMemory(from: pointer, byteCount: fileReader.fileSize)
if self.toPredictTexture == nil { if self.toPredictTexture == nil {
runner.getTexture(image: selectImage!.cgImage!) {[weak self] (texture) in
// runner.getTexture(inBuffer: buffer!) { [weak self] (texture) in
// self?.toPredictTexture = texture
// }
runner.getTexture(image: selectImage!.cgImage!) { [weak self] (texture) in
self?.toPredictTexture = texture self?.toPredictTexture = texture
} }
} }
...@@ -106,27 +140,21 @@ class ViewController: UIViewController { ...@@ -106,27 +140,21 @@ class ViewController: UIViewController {
return return
} }
// for _ in 0..<1{
// runner.predict(texture: inTexture) { (success, resultHolder) in
// resultHolder?.releasePointer()
// }
// }
let startDate = Date.init() let startDate = Date.init()
for i in 0..<max { for i in 0..<max {
runner.predict(texture: inTexture) { [weak self] (success, resultHolder) in self.runner.predict(texture: inTexture) { [weak self] (success, resultHolder) in
guard let sSelf = self else { guard let sSelf = self else {
fatalError() fatalError()
} }
if success {
if success, let inResultHolder = resultHolder {
if i == max - 1 { if i == max - 1 {
let time = Date.init().timeIntervalSince(startDate) let time = Date.init().timeIntervalSince(startDate)
print(inResultHolder.result.floatArr(count: inResultHolder.capacity).strideArray())
DispatchQueue.main.async { DispatchQueue.main.async {
// print(resultHolder!.result![0])
sSelf.resultTextView.text = sSelf.runner.net.resultStr(res: resultHolder!) sSelf.resultTextView.text = sSelf.runner.net.resultStr(res: resultHolder!)
sSelf.elapsedTimeLabel.text = "平均耗时: \(time/Double(max) * 1000.0) ms" sSelf.elapsedTimeLabel.text = "平均耗时: \(time/Double(max) * 1000.0) ms"
} }
} }
} }
...@@ -134,39 +162,6 @@ class ViewController: UIViewController { ...@@ -134,39 +162,6 @@ class ViewController: UIViewController {
DispatchQueue.main.async { DispatchQueue.main.async {
resultHolder?.releasePointer() resultHolder?.releasePointer()
} }
// print("释放")
}
// print("sleep before ")
// usleep(33000)
// print("sleep after ")
}
case .CPU:
guard let inInputPointer = inputPointer else {
fatalError( " need input pointer " )
}
for _ in 0..<10 {
runner.predict(inputPointer: inInputPointer) { (success, res) in
res?.releaseOutput()
}
}
let startDate = Date.init()
for i in 0..<max {
runner.predict(inputPointer: inInputPointer) { [weak self](success, res) in
guard let sSelf = self else {
fatalError()
}
if success {
if i == max - 1 {
let time = Date.init().timeIntervalSince(startDate)
DispatchQueue.main.async {
// sSelf.resultTextView.text = sSelf.runner.net.resultStr(res: res)
sSelf.elapsedTimeLabel.text = "平均耗时: \(time/Double(max) * 1000.0) ms"
}
}
}
res?.releaseOutput()
} }
} }
} }
...@@ -179,37 +174,38 @@ class ViewController: UIViewController { ...@@ -179,37 +174,38 @@ class ViewController: UIViewController {
modelPickerView.dataSource = self modelPickerView.dataSource = self
threadPickerView.delegate = self threadPickerView.delegate = self
threadPickerView.dataSource = self threadPickerView.dataSource = self
if let image = UIImage.init(named: "test.jpg") { if let image = UIImage.init(named: "classify-img-output.png") {
selectImage = image selectImage = image
selectImageView.image = image selectImageView.image = image
} else { } else {
print("请添加测试图片") print("请添加测试图片")
} }
GlobalConfig.shared.computePrecision = .Float32
// if platform == .CPU { // if platform == .CPU {
// inputPointer = runner.preproccess(image: selectImage!.cgImage!) // inputPointer = runner.preproccess(image: selectImage!.cgImage!)
// } else if platform == .GPU { // } else if platform == .GPU {
// runner.getTexture(image: selectImage!.cgImage!) {[weak self] (texture) in // runner.getTexture(image: selectImage!.cgImage!) {[weak self] (texture) in
// self?.toPredictTexture = texture // self?.toPredictTexture = texture
// } // }
// } else { // } else {
// fatalError( " unsupport " ) // fatalError( " unsupport " )
// } // }
// videoCapture = VideoCapture.init(device: MetalHelper.shared.device, orientation: .portrait, position: .back)
// videoCapture.fps = 30
// videoCapture.delegate = self
// videoCapture.setUp { (success) in
// DispatchQueue.main.async {
// if let preViewLayer = self.videoCapture.previewLayer {
// self.videoView.layer.addSublayer(preViewLayer)
// self.videoCapture.previewLayer?.frame = self.videoView.bounds
// }
// self.videoCapture.start()
// }
// }
// videoCapture = VideoCapture.init(device: MetalHelper.shared.device, orientation: .portrait, position: .back)
// videoCapture.fps = 30
// videoCapture.delegate = self
// videoCapture.setUp { (success) in
// DispatchQueue.main.async {
// if let preViewLayer = self.videoCapture.previewLayer {
// self.videoView.layer.addSublayer(preViewLayer)
// self.videoCapture.previewLayer?.frame = self.videoView.bounds
// }
// self.videoCapture.start()
// }
// }
} }
} }
...@@ -228,7 +224,7 @@ extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate{ ...@@ -228,7 +224,7 @@ extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate{
if pickerView == modelPickerView { if pickerView == modelPickerView {
return SupportModel.supportedModels().count return SupportModel.supportedModels().count
} else if pickerView == threadPickerView { } else if pickerView == threadPickerView {
return threadSupport.count return platformSupport.count
} else { } else {
fatalError() fatalError()
} }
...@@ -238,7 +234,7 @@ extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate{ ...@@ -238,7 +234,7 @@ extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate{
if pickerView == modelPickerView { if pickerView == modelPickerView {
return SupportModel.supportedModels()[row].rawValue return SupportModel.supportedModels()[row].rawValue
} else if pickerView == threadPickerView { } else if pickerView == threadPickerView {
return threadSupport[row].1 return platformSupport[row].1
} else { } else {
fatalError() fatalError()
} }
...@@ -248,8 +244,7 @@ extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate{ ...@@ -248,8 +244,7 @@ extension ViewController: UIPickerViewDataSource, UIPickerViewDelegate{
if pickerView == modelPickerView { if pickerView == modelPickerView {
self.modelType = SupportModel.supportedModels()[row] self.modelType = SupportModel.supportedModels()[row]
} else if pickerView == threadPickerView { } else if pickerView == threadPickerView {
platform = platformSupport[row].0
platform = threadSupport[row].0
} else { } else {
fatalError() fatalError()
} }
...@@ -276,25 +271,11 @@ extension ViewController: VideoCaptureDelegate{ ...@@ -276,25 +271,11 @@ extension ViewController: VideoCaptureDelegate{
func predictTexture(texture: MTLTexture){ func predictTexture(texture: MTLTexture){
runner.scaleTexture(input: texture) { (scaledTexture) in runner.scaleTexture(input: texture) { (scaledTexture) in
self.runner.predict(texture: scaledTexture, completion: { (success, resultHolder) in self.runner.predict(texture: scaledTexture, completion: { (success, resultHolder) in
// print(resultHolder!.result![0]) // print(resultHolder!.result![0])
resultHolder?.releasePointer() resultHolder?.releasePointer()
}) })
} }
} }
// @available(iOS 10.0, *)
// func videoCapture(_ capture: VideoCapture, didCaptureVideoTexture texture: MTLTexture?, timestamp: CMTime) {
//// if !bool1 {
//// DispatchQueue.main.asyncAfter(deadline: DispatchTime.init(uptimeNanoseconds: 500000000)) {
// self.predictTexture(texture: texture!)
//// }
//
//
//// bool1 = true
//// }
//
// }
} }
......
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#ifdef P
#define CONCAT3_(a, b, c) a ## _ ## b ## _ ## c
#define CONCAT2_(a, b) a ## _ ## b
#define CONCAT2(a, b) a ## b
#define FUNC(m, n, q) CONCAT3_(m, n, q)
#define FUNC_T(m, n) CONCAT2_(m, n)
#define VECTOR(p, n) CONCAT2(p, n)
kernel void FUNC_T(fetch, P)(texture2d_array<P, access::read> inTexture [[texture(0)]],
device float *output [[buffer(0)]],
uint3 gid [[thread_position_in_grid]]) {
if (gid.x >= inTexture.get_width() ||
gid.y >= inTexture.get_height() ||
gid.z >= inTexture.get_array_size()) {
return;
}
int input_width = inTexture.get_width();
int input_height = inTexture.get_height();
const VECTOR(P, 4) input = inTexture.read(gid.xy, gid.z);
int output_to = 4 * input_width * input_height;
output[gid.z * output_to + 0 * input_width * input_height + gid.y * input_width + gid.x] = input.x;
output[gid.z * output_to + 1 * input_width * input_height + gid.y * input_width + gid.x] = input.y;
output[gid.z * output_to + 2 * input_width * input_height + gid.y * input_width + gid.x] = input.z;
output[gid.z * output_to + 3 * input_width * input_height + gid.y * input_width + gid.x] = input.w;
}
#endif
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include <metal_stdlib>
using namespace metal;
#define P float
#include "FetchKernel.inc.metal"
#undef P
#define P half
#include "FetchKernel.inc.metal"
#undef P
kernel void fetch_placeholder(texture2d_array<float, access::read> inTexture [[texture(0)]],
device float *output [[buffer(0)]],
uint3 gid [[thread_position_in_grid]]) {
}
kernel void fetch_placeholder_half(texture2d_array<half, access::read> inTexture [[texture(0)]],
device float *output [[buffer(0)]],
uint3 gid [[thread_position_in_grid]]) {
}
...@@ -24,6 +24,6 @@ using namespace metal; ...@@ -24,6 +24,6 @@ using namespace metal;
#define FUNC(f, r, n, v, p) CONCAT5_(f, r, n, v, p) #define FUNC(f, r, n, v, p) CONCAT5_(f, r, n, v, p)
#define VECTOR(p, n) CONCAT2(p, n) #define VECTOR(p, n) CONCAT2(p, n)
#define FUNC2_(a, b) CONCAT2_(a, b)
#define FUNC3_(a, b, c) CONCAT3_(a, b, c) #define FUNC3_(a, b, c) CONCAT3_(a, b, c)
//
// PoolKernel.inc.metal
// paddle-mobile
//
// Created by liuRuiLong on 2018/12/29.
// Copyright © 2018 orange. All rights reserved.
//
#ifdef P
kernel void FUNC2_(pool, P)(texture2d_array<P, access::read> inTexture [[texture(0)]],
texture2d_array<P, access::write> outTexture [[texture(1)]],
constant PoolParam &pm [[buffer(0)]],
uint3 gid [[thread_position_in_grid]]) {
if (gid.x >= outTexture.get_width() ||
gid.y >= outTexture.get_height() ||
gid.z >= outTexture.get_array_size()) return;
int xmin = gid.x * pm.strideX - pm.paddingX;
int xmax = min(xmin + pm.ksizeX, int(inTexture.get_width()));
xmin = max(xmin, 0);
int ymin = gid.y * pm.strideX - pm.paddingX;
int ymax = min(ymin + pm.ksizeX, int(inTexture.get_height()));
ymin = max(ymin, 0);
VECTOR(P, 4) r = 0;
if (pm.poolType == 0) {
r = inTexture.read(uint2(xmin, ymin), gid.z);
for (int x = xmin; x < xmax; x++) {
for (int y = ymin; y < ymax; y++) {
r = fmax(r, inTexture.read(uint2(x, y), gid.z));
}
}
} else if (pm.poolType == 1) {
for (int x = xmin; x < xmax; x++) {
for (int y = ymin; y < ymax; y++) {
r += inTexture.read(uint2(x, y), gid.z);
}
}
r /= (xmax - xmin) * (ymax - ymin);
}
outTexture.write(r, gid.xy, gid.z);
}
#endif
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#include <metal_stdlib>
#include "Macro.metal"
using namespace metal;
struct PoolParam {
int ksizeX;
int ksizeY;
int strideX;
int strideY;
int paddingX;
int paddingY;
int poolType;
};
#define P float
#import "PoolKernel.inc.metal"
#undef P
#define P half
#import "PoolKernel.inc.metal"
#undef P
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B6920E11C3C0081E9F8"
BuildableName = "paddle_mobile.framework"
BlueprintName = "paddle-mobile"
ReferencedContainer = "container:paddle-mobile.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
<AdditionalOptions>
</AdditionalOptions>
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B6920E11C3C0081E9F8"
BuildableName = "paddle_mobile.framework"
BlueprintName = "paddle-mobile"
ReferencedContainer = "container:paddle-mobile.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "FC039B6920E11C3C0081E9F8"
BuildableName = "paddle_mobile.framework"
BlueprintName = "paddle-mobile"
ReferencedContainer = "container:paddle-mobile.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
@objc public enum MetalLoadMode: Int {
case
LoadMetalInPaddleMobile = 1, // 使用 paddle-mobile 中的 metal 代码
LoadMetalInDefaultLib = 2, // 使用 main bundle 中的 metal 代码
LoadMetalInCustomMetalLib = 3 // 使用 metal 库文件
}
@objc public enum ComputePrecision: Int {
case
Float32 = 1,
Float16 = 2
}
@objc public class GlobalConfig: NSObject {
/// 单例
@objc public static let shared: GlobalConfig = GlobalConfig.init()
/// 运算精度, runner 生命周期中不可变
@objc public var computePrecision: ComputePrecision = .Float16
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Metal
import Foundation
/// 网络的基类, 参数已经给了默认值,请在子类实现中修改需要改的参数
@objc open class Net: NSObject {
/// 默认为0, 如果指定个数, 后边 except 个op不使用 GPU 运算, 中间结果会通过 fetchResult 传参过来
@objc public var except: Int = 0
/// 预处理 kernel, 如果输入图像需要预处理, 则指定预处理 kernel
@objc public var preprocessKernel: CusomKernel? = nil
// 以下四个参数为从内存中读取模型时用到的参数
/// 模型在内存中的指针
@objc public var modelPointer: UnsafeMutableRawPointer? = nil
/// 模型大小 单位: 字节
@objc public var modelSize: Int = 0
/// 权重参数在内存中的指针
@objc public var paramPointer: UnsafeMutableRawPointer? = nil
/// 权重大小 单位: 字节
@objc public var paramSize: Int = 0
// 以下两个为从文件中读取模型时用到的参数
/// 模型文件路径
@objc public var modelPath: String? = nil
/// 权重文件路径
@objc public var paramPath: String? = nil
/// 代表着 GPU 处理器
@objc public let device: MTLDevice
/// metal 代码加载方式 注意: 如果静态库只能使用 LoadMetalInDefaultLib LoadMetalInCustomMetalLib 进行 load metal 代码
@objc public var metalLoadMode: MetalLoadMode = .LoadMetalInPaddleMobile
/// 当 metalLoadMode 为 LoadMetalInCustomMetalLib 时, metal library 路径不能为空
@objc public var metalLibPath: String? = nil
/// 输入维度,按照 n h w c 方式传入
@objc public var inputDim: Dim = Dim.init(inDim: [])
@objc public init(device: MTLDevice, paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) {
self.paramPointer = paramPointer
self.paramSize = paramSize
self.modelPointer = modePointer
self.modelSize = modelSize
self.device = device
super.init()
}
@objc public init(device: MTLDevice) {
self.device = device
super.init()
}
@objc open func resultStr(res: ResultHolder) -> String {
fatalError()
}
@objc open func fetchResult(paddleMobileRes: GPUResultHolder) -> ResultHolder {
guard let inResPointer = paddleMobileRes.resultPointer else {
fatalError()
}
return ResultHolder.init(inResult: inResPointer, inCapacity: paddleMobileRes.capacity)
}
open func updateProgram(program: Program) {
}
}
...@@ -12,25 +12,22 @@ ...@@ -12,25 +12,22 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. */ limitations under the License. */
import Metal
import MetalKit import MetalKit
import Foundation import Foundation
@objc public enum Platform: Int{ @objc public class ResultHolder: NSObject {
case CPU, GPU @objc public let result: UnsafeMutablePointer<Float32>
} @objc public let capacity: Int
class ScaleKernel: CusomKernel { init(inResult: UnsafeMutablePointer<Float32>, inCapacity: Int) {
init(device: MTLDevice, shape: Shape) { result = inResult
if computePrecision == .Float32 { capacity = inCapacity
super.init(device: device, inFunctionName: "scale", outputDim: shape, usePaddleMobileLib: false)
} else if computePrecision == .Float16 {
super.init(device: device, inFunctionName: "scale_half", outputDim: shape, usePaddleMobileLib: false)
} else {
fatalError(" unsupport ")
}
} }
@objc public func releasePointer() {
result.deinitialize(count: capacity)
result.deallocate()
}
} }
@objc public class Runner: NSObject { @objc public class Runner: NSObject {
...@@ -40,86 +37,77 @@ class ScaleKernel: CusomKernel { ...@@ -40,86 +37,77 @@ class ScaleKernel: CusomKernel {
var textureLoader: MTKTextureLoader? var textureLoader: MTKTextureLoader?
public let net: Net public let net: Net
let device: MTLDevice? let device: MTLDevice?
let platform: Platform
var cpuPaddleMobile: PaddleMobileCPU?
let numel: Int let numel: Int
let meansNumber: [NSNumber]
// dims num nchw /// 初始化函数
let dimsNum: [NSNumber] ///
/** /// - Parameters:
* inNet: 需要运行的网络 /// - inNet: 传入自定义的网络
* commandQueue: GPU 是需要传入 /// - commandQueue: commandQueue
* inPlatform: 需要使用的平台, GPU or CPU @objc public init(inNet: Net, commandQueue: MTLCommandQueue?) {
*/ guard inNet.inputDim.cout() == 4 else {
@objc public init(inNet: Net, commandQueue: MTLCommandQueue?, inPlatform: Platform) { fatalError(" input dim count must 4 ")
}
net = inNet net = inNet
queue = commandQueue queue = commandQueue
device = queue?.device device = queue?.device
platform = inPlatform
if let inDevice = device { if let inDevice = device {
textureLoader = MTKTextureLoader.init(device: inDevice) textureLoader = MTKTextureLoader.init(device: inDevice)
} }
if platform == .CPU { numel = net.inputDim.numel()
cpuPaddleMobile = PaddleMobileCPU.init()
}
numel = net.dim.n * net.dim.c * net.dim.h * net.dim.w
meansNumber = net.means.map { NSNumber.init(value: $0) }
dimsNum = [NSNumber.init(value: net.dim.n),
NSNumber.init(value: net.dim.c),
NSNumber.init(value: net.dim.h),
NSNumber.init(value: net.dim.w)]
} }
/** /// load 模型, 返回 true 可进行预测
* load 模型, 返回 true 可进行预测 ///
*/ /// - Returns: load 成功或失败
@objc public func load() -> Bool { @objc public func load() -> Bool {
if platform == .GPU {
guard let inDevice = device, let inQueue = queue else { guard let inDevice = device, let inQueue = queue else {
print(" paddle mobile gpu load error, need MTLCommandQueue") print(" paddle mobile gpu load error, need MTLCommandQueue")
return false return false
} }
let loader = Loader<Float32>.init() let loader = Loader<Float32>.init()
do { do {
// program = try loader.load(device: inDevice, paramPointer: net.paramPointer!, paramSize: net.paramSize,modePointer:net.modelPointer!,modelSize:net.modelSize)
program = try loader.load(device: inDevice, modelPath: net.modelPath, paraPath: net.paramPath) if let inParamPointer = net.paramPointer, let inModelPointer = net.modelPointer {
guard net.paramSize > 0 && net.modelSize > 0 else {
print(" load from memory param size or model size can't 0 ")
return false
}
program = try loader.load(device: inDevice, paramPointer: inParamPointer, paramSize: net.paramSize,modePointer:inModelPointer,modelSize:net.modelSize)
} else if let inModelPath = net.modelPath, let inParamPath = net.paramPath {
program = try loader.load(device: inDevice, modelPath: inModelPath, paraPath: inParamPath)
} else {
print(" model pointer or model file path need be specified")
return false
}
let initContext: InitContext = InitContext.init()
initContext.metalLoadMode = net.metalLoadMode
initContext.metalLibPath = net.metalLibPath
executor = try Executor<Float32>.init(inDevice: inDevice, inQueue: inQueue, inProgram: program!, initContext: initContext)
net.updateProgram(program: program!) net.updateProgram(program: program!)
executor = try Executor<Float32>.init(inDevice: inDevice, inQueue: inQueue, inProgram: program!)
} catch let error { } catch let error {
print(error) print(error)
return false return false
} }
} else {
return cpuPaddleMobile?.load(net.modelPath, andWeightsPath: net.paramPath) ?? false
}
return true return true
} }
@objc public func predict(inputPointer: UnsafeMutablePointer<Float32>, completion: @escaping ( _ success: Bool, _ result: PaddleMobileCPUResult?) -> Void) { /// 预测
///
guard let res = cpuPaddleMobile?.predictInput(inputPointer, dim: dimsNum) else { /// - Parameters:
completion(false, nil) /// - texture: 输入 texture 需要使用 getTexture 获得
return /// - completion: 结果回调, 当 success 为 true 时 result 不为 nil
}
completion(true, res)
}
/**
* GPU 版本 predict
* texture: 需要预测的 texture 需要做过预处理
* ( _ success: Bool, _ time:TimeInterval, _ resultArray: [Float32]) -> Void : 回调闭包, 三个参数分别为: 是否成功, 预测耗时, 结果数组
*/
@objc public func predict(texture: MTLTexture, completion: @escaping ( _ success: Bool, _ result: ResultHolder?) -> Void) { @objc public func predict(texture: MTLTexture, completion: @escaping ( _ success: Bool, _ result: ResultHolder?) -> Void) {
do { do {
try self.executor?.predict(input: texture, dim: [self.net.dim.n, self.net.dim.h, self.net.dim.w, self.net.dim.c], completionHandle: { [weak self] (res) in try self.executor?.predict(input: texture, dim: self.net.inputDim, completionHandle: { [weak self] (res) in
guard let SSelf = self else { guard let SSelf = self else {
fatalError( " self nil " ) fatalError( " self nil " )
} }
let result = SSelf.net.fetchResult(paddleMobileRes: res) let result = SSelf.net.fetchResult(paddleMobileRes: res)
completion(true, result) completion(true, result)
}, preProcessKernle: self.net.preprocessKernel, except: self.net.except) }, preProcessKernle: self.net.preprocessKernel, except: self.net.except)
} catch let error { } catch let error {
print(error) print(error)
completion(false, nil) completion(false, nil)
...@@ -127,59 +115,64 @@ class ScaleKernel: CusomKernel { ...@@ -127,59 +115,64 @@ class ScaleKernel: CusomKernel {
} }
} }
/** /// 清理内存, 调用此函数后, 不能再使用, 需重新 load
* CPU GPU 通用版本 predict
* cgImage: 需要预测的图片
* ( _ success: Bool, _ time:TimeInterval, _ resultArray: [Float32]) -> Void : 回调闭包, 三个参数分别为: 是否成功, 预测耗时, 结果数组
*/
// @objc public func predict(cgImage: CGImage, completion: @escaping ( _ success: Bool, _ resultArray: [Float32]) -> Void) {
// if platform == .GPU {
// getTexture(image: cgImage) { [weak self] (texture) in
// guard let SSelf = self else {
// fatalError( "" )
// }
// SSelf.predict(texture: texture, completion: completion)
// }
// } else if platform == .CPU {
// let input = preproccess(image: cgImage)
// predict(inputPointer: input, completion: completion)
// input.deinitialize(count: numel)
// input.deallocate()
// }
// }
/*
* 清理内存, 调用此函数后, 不能再使用, 需重新 load
*/
@objc public func clear() { @objc public func clear() {
if platform == .GPU { executor?.clear()
executor?.clear() executor = nil
executor = nil program = nil
program = nil
} else if platform == .CPU {
cpuPaddleMobile?.clear()
}
} }
@objc public func preproccess(image: CGImage) -> UnsafeMutablePointer<Float> { /// 获取 texture, 对 texture 进行预处理, 预测时使用
let output = UnsafeMutablePointer<Float>.allocate(capacity: numel) ///
let means = net.means.map { NSNumber.init(value: $0) } /// - Parameters:
let dims = [NSNumber.init(value: net.dim.n), /// - image: 输入图像
NSNumber.init(value: net.dim.c), /// - getTexture: 获取 texture 回调
NSNumber.init(value: net.dim.h),
NSNumber.init(value: net.dim.w)]
cpuPaddleMobile?.preprocess(image, output: output, means: means, scale: net.scale, dim: dims)
return output
}
/*
* 获取 texture, 对 texture 进行预处理, GPU 预测时使用
*/
@objc public func getTexture(image: CGImage, getTexture: @escaping (MTLTexture) -> Void) { @objc public func getTexture(image: CGImage, getTexture: @escaping (MTLTexture) -> Void) {
let texture = try? textureLoader?.newTexture(cgImage: image, options: [:]) ?! " texture loader error" let texture = try? textureLoader?.newTexture(cgImage: image, options: [:]) ?! " texture loader error"
scaleTexture(input: texture!, complete: getTexture) scaleTexture(input: texture!, complete: getTexture)
} }
/// 通过 buffer 获取 texture, 内部会使用GPU进行转换操作
///
/// - Parameters:
/// - inBuffer: 输入buffer
/// - getTexture: 结果回调
@objc public func getTexture(inBuffer: MTLBuffer, getTexture: @escaping (MTLTexture) -> Void) {
guard let inQueue = queue, let inDevice = device else {
fatalError( " queue or devcie nil " )
}
guard let buffer = inQueue.makeCommandBuffer() else {
fatalError( " make buffer error" )
}
let bufferToTextureKernel = BufferToTextureKernel.init(device: inDevice, outputDim: Shape.init(inWidth: net.inputDim[2], inHeight: net.inputDim[1], inChannel: net.inputDim[3]), metalLoadMode: net.metalLoadMode, metalLibPath: net.metalLibPath)
do {
try bufferToTextureKernel.compute(inputBuffer: inBuffer, commandBuffer: buffer)
} catch {
fatalError(" bufferToTextureKernel error ")
}
buffer.addCompletedHandler { (buffer) in
getTexture(bufferToTextureKernel.outputTexture)
}
buffer.commit()
}
/// 更新输入维度, 针对可变长输入模型
///
/// - Parameter inDim: 输入维度
@objc public func updateInputDim(inDim: Dim) {
if net.inputDim != inDim {
guard let inProgram = program else {
fatalError(" need load first ")
}
net.inputDim = inDim
net.updateProgram(program: inProgram)
}
}
public func scaleTexture(input: MTLTexture , complete: @escaping (MTLTexture) -> Void) { public func scaleTexture(input: MTLTexture , complete: @escaping (MTLTexture) -> Void) {
guard let inQueue = queue, let inDevice = device else { guard let inQueue = queue, let inDevice = device else {
...@@ -190,7 +183,7 @@ class ScaleKernel: CusomKernel { ...@@ -190,7 +183,7 @@ class ScaleKernel: CusomKernel {
fatalError( " make buffer error" ) fatalError( " make buffer error" )
} }
let scaleKernel = ScaleKernel.init(device: inDevice, shape: CusomKernel.Shape.init(inWidth: net.dim.w, inHeight: net.dim.h, inChannel: 3)) let scaleKernel = ScaleKernel.init(device: inDevice, shape: Shape.init(inWidth: net.inputDim[2], inHeight: net.inputDim[1], inChannel: 3), metalLoadMode: net.metalLoadMode, metalLibPath: net.metalLibPath)
do { do {
try scaleKernel.compute(inputTexuture: input, commandBuffer: buffer) try scaleKernel.compute(inputTexuture: input, commandBuffer: buffer)
...@@ -205,5 +198,3 @@ class ScaleKernel: CusomKernel { ...@@ -205,5 +198,3 @@ class ScaleKernel: CusomKernel {
buffer.commit() buffer.commit()
} }
} }
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
#pragma once
#import <CoreImage/CoreImage.h>
#import <Foundation/Foundation.h>
@interface PaddleMobileCPUResult: NSObject
@property (assign, nonatomic, readonly) float *output;
@property (assign, nonatomic, readonly) int outputSize;
-(void)releaseOutput;
@end
@interface PaddleMobileCPU : NSObject
/*
创建对象
*/
- (instancetype)init;
/*
load 模型, 开辟内存
*/
- (BOOL)load:(NSString *)modelPath andWeightsPath:(NSString *)weighsPath;
/*
加载散开形式的模型, 需传入模型的目录
*/
- (BOOL)load:(NSString *)modelAndWeightPath;
/*
* 从内存中加载模型
* */
- (BOOL)LoadCombinedMemory:(size_t)modelLen
andModelBuf:(const uint8_t *)modelBuf
andModelParamsLen:(size_t)combinedParamsLen
andCombinedParamsBuf:(const uint8_t *)combinedParamsBuf;
/*
* 对图像进行预处理, 需要外部开辟 output 内存, 外部释放 output 内存
* */
-(void)preprocess:(CGImageRef)image
output:(float *)output
means:(NSArray<NSNumber *> *)means
scale:(float)scale
dim:(NSArray<NSNumber *> *)dim;
/*
* 预测预处理后的数据, 返回结果使用结束需要调用其 realseOutput 函数进行释放
* */
- (PaddleMobileCPUResult *)predictInput:(float *)input
dim:(NSArray<NSNumber *> *)dim;
/*
进行预测, means 和 scale 为训练模型时的预处理参数, 如训练时没有做这些预处理则直接使用 predict
*/
- (NSArray *)predict:(CGImageRef)image dim:(NSArray<NSNumber *> *)dim means:(NSArray<NSNumber *> *)means scale:(float)scale;
/*
进行预测, 默认 means 为 0, scale 为 1.0
*/
- (NSArray *)predict:(CGImageRef)image dim:(NSArray<NSNumber *> *)dim;
/*
清理内存
*/
- (void)clear;
@end
//
// MobileNetCombined.swift
// paddle-mobile
//
// Created by Xiao,Haichun on 2018/12/5.
// Copyright © 2018 orange. All rights reserved.
//
import Foundation
public class MobileNetCombined: Net {
@objc public override init(device: MTLDevice) {
super.init(device: device)
means = [0, 0, 0]
scale = 1
except = 0
modelPath = Bundle.main.path(forResource: "combined_mobilenet_model", ofType: nil) ?! "model null"
paramPath = Bundle.main.path(forResource: "combined_mobilenet_params", ofType: nil) ?! "para null"
modelDir = ""
//preprocessKernel = GenetPreProccess.init(device: device)
dim = (n: 1, h: 416, w: 416, c: 3)
}
@objc override public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) {
super.init(device:device,paramPointer:paramPointer,paramSize:paramSize,modePointer:modePointer,modelSize:modelSize)
means = [0, 0, 0]
scale = 1
except = 0
modelPath = ""
paramPath = ""
modelDir = ""
//preprocessKernel = GenetPreProccess.init(device: device)
dim = (n: 1, h: 416, w: 416, c: 3)
}
// class GenetPreProccess: CusomKernel {
// init(device: MTLDevice) {
// let s = CusomKernel.Shape.init(inWidth: 128, inHeight: 128, inChannel: 3)
// super.init(device: device, inFunctionName: "genet_preprocess", outputDim: s, usePaddleMobileLib: false)
// }
// }
override public func resultStr(res: ResultHolder) -> String {
// fatalError()
return " \(res.result![0]) ... "
}
}
/* Copyright (c) 2018 PaddlePaddle Authors. All Rights Reserved.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License. */
import Foundation
import Metal
public class ResultHolder: NSObject {
@objc public let result: UnsafeMutablePointer<Float32>?
@objc public let capacity: Int
init(inResult: UnsafeMutablePointer<Float32>?, inCapacity: Int) {
result = inResult
capacity = inCapacity
}
@objc public func releasePointer() {
result?.deinitialize(count: capacity)
result?.deallocate()
}
}
public class Net: NSObject {
var except: Int = 0
var means: [Float] = []
var scale: Float = 0.0
var dim: (n: Int, h: Int, w: Int, c: Int) = (n: 0, h: 0, w: 0, c: 0)
var preprocessKernel: CusomKernel? = nil
var paramPointer: UnsafeMutableRawPointer? = nil
var paramSize: Int = 0
var modelPointer: UnsafeMutableRawPointer? = nil
var modelSize: Int = 0
var modelPath: String = ""
var paramPath: String = ""
var modelDir: String = ""
@objc public init(device: MTLDevice,paramPointer: UnsafeMutableRawPointer, paramSize:Int, modePointer: UnsafeMutableRawPointer, modelSize: Int) {
self.paramPointer = paramPointer
self.paramSize = paramSize
self.modelPointer = modePointer
self.modelSize = modelSize
super.init()
}
public func resultStr(res: ResultHolder) -> String {
fatalError()
}
func fetchResult(paddleMobileRes: GPUResultHolder) -> ResultHolder {
return ResultHolder.init(inResult: paddleMobileRes.resultPointer, inCapacity: paddleMobileRes.capacity)
}
@objc public init(device: MTLDevice) {
super.init()
}
func updateProgram(program: Program) {
}
}
...@@ -110,9 +110,27 @@ extension Array { ...@@ -110,9 +110,27 @@ extension Array {
return newArray return newArray
} }
} }
public static func floatArrWithBuffer(floatArrBuffer: UnsafeMutablePointer<Float32>, count: Int) -> [Float32] {
var arr: [Float32] = []
for i in 0..<count {
arr.append(floatArrBuffer[i])
}
return arr
}
}
extension UnsafeMutablePointer {
public func floatArr(count: Int) -> [Pointee]{
var arr: [Pointee] = []
for i in 0..<count {
arr.append(self[i])
}
return arr
}
} }
extension String{ extension String {
func cStr() -> UnsafePointer<Int8>? { func cStr() -> UnsafePointer<Int8>? {
return (self as NSString).utf8String return (self as NSString).utf8String
} }
......
...@@ -18,6 +18,7 @@ import CoreMedia ...@@ -18,6 +18,7 @@ import CoreMedia
fileprivate var defaultMetalLibrary: MTLLibrary? fileprivate var defaultMetalLibrary: MTLLibrary?
fileprivate var paddleMobileMetalLibrary: MTLLibrary? fileprivate var paddleMobileMetalLibrary: MTLLibrary?
fileprivate var customMetalLibrary: MTLLibrary?
extension MTLDevice { extension MTLDevice {
func defaultLibrary() -> MTLLibrary { func defaultLibrary() -> MTLLibrary {
...@@ -31,6 +32,22 @@ extension MTLDevice { ...@@ -31,6 +32,22 @@ extension MTLDevice {
} }
} }
func customLibrary(metalLibPath: String) -> MTLLibrary {
if customMetalLibrary == nil {
do {
customMetalLibrary = try makeLibrary(filepath: metalLibPath)
} catch let error {
fatalError("\(error)")
}
}
if let inMetalLib = customMetalLibrary {
return inMetalLib
} else {
fatalError(" customlib is nil ")
}
}
func paddleMobileLibrary() -> MTLLibrary { func paddleMobileLibrary() -> MTLLibrary {
if paddleMobileMetalLibrary == nil { if paddleMobileMetalLibrary == nil {
guard let path = Bundle.init(for: Kernel.self).path(forResource: "default", ofType: "metallib") else { guard let path = Bundle.init(for: Kernel.self).path(forResource: "default", ofType: "metallib") else {
...@@ -50,8 +67,19 @@ extension MTLDevice { ...@@ -50,8 +67,19 @@ extension MTLDevice {
} }
} }
func pipeLine(funcName: String, inPaddleMobileLib: Bool = true) -> MTLComputePipelineState { func pipeLine(funcName: String, metalLoadMode: MetalLoadMode, metalLibPath: String?) -> MTLComputePipelineState {
let useLib = inPaddleMobileLib ? paddleMobileLibrary() : defaultLibrary() let useLib: MTLLibrary
switch metalLoadMode {
case .LoadMetalInDefaultLib:
useLib = defaultLibrary()
case .LoadMetalInPaddleMobile:
useLib = paddleMobileLibrary()
case .LoadMetalInCustomMetalLib:
useLib = customLibrary(metalLibPath: metalLibPath ?! " can't be nil ")
default:
fatalError()
}
guard let function = useLib.makeFunction(name: funcName) else { guard let function = useLib.makeFunction(name: funcName) else {
fatalError(" function " + funcName + " not found") fatalError(" function " + funcName + " not found")
} }
...@@ -501,7 +529,7 @@ public extension MTLTexture { ...@@ -501,7 +529,7 @@ public extension MTLTexture {
} else { } else {
fatalError(" 目前还不支持其他类型 ") fatalError(" 目前还不支持其他类型 ")
} }
print(textureArray.count)
var output: [Float32] = [] var output: [Float32] = []
for s in 0..<arrayLength { for s in 0..<arrayLength {
for c in 0..<4{ for c in 0..<4{
......
...@@ -324,9 +324,10 @@ public class PaddleMobileUnitTest { ...@@ -324,9 +324,10 @@ public class PaddleMobileUnitTest {
let param = ConvAddBatchNormReluTestParam.init(inInputTexture: inputeTexture, inOutputTexture: outputTexture, inMetalParam: metalParam, inFilterBuffer: filterBuffer, inBiaseBuffer: biaseBuffer, inNewScaleBuffer: newScalueBuffer, inNewBiaseBuffer: newBiaseBuffer, inFilterSize: filterSize) let param = ConvAddBatchNormReluTestParam.init(inInputTexture: inputeTexture, inOutputTexture: outputTexture, inMetalParam: metalParam, inFilterBuffer: filterBuffer, inBiaseBuffer: biaseBuffer, inNewScaleBuffer: newScalueBuffer, inNewBiaseBuffer: newBiaseBuffer, inFilterSize: filterSize)
let initContext = InitContext.init()
initContext.metalLoadMode = .LoadMetalInDefaultLib
let convAddBnReluKernel = ConvAddBatchNormReluKernel<Float32>.init(device: device, testParam: param, initContext: initContext)
let convAddBnReluKernel = ConvAddBatchNormReluKernel<Float32>.init(device: device, testParam: param)
convAddBnReluKernel.test(commandBuffer: buffer, param: param) convAddBnReluKernel.test(commandBuffer: buffer, param: param)
......
...@@ -250,39 +250,40 @@ extension InputTexture: Variant { ...@@ -250,39 +250,40 @@ extension InputTexture: Variant {
} }
extension MTLTexture where Self: Variant { extension MTLTexture where Self: Variant {
} }
class FetchHolder: Variant { public class FetchHolder: Variant {
var resultBuffer: MTLBuffer? var resultBuffer: MTLBuffer?
var dim: [Int] public var dim: Dim
var capacity: Int public var capacity: Int
public var paddedCapacity: Int
init(inCapacity: Int, inDim: [Int]) { init(inPaddedCapacity: Int, inDim: Dim) {
capacity = inCapacity paddedCapacity = inPaddedCapacity
capacity = inDim.numel()
dim = inDim dim = inDim
} }
func initBuffer(device: MTLDevice) { public func initBuffer(device: MTLDevice) {
resultBuffer = device.makeBuffer(length: capacity * 4, options: []) resultBuffer = device.makeBuffer(length: paddedCapacity * 4, options: [])
} }
var result: UnsafeMutablePointer<Float32> { var result: UnsafeMutablePointer<Float32> {
guard let inResultBuffer = resultBuffer else { guard let inResultBuffer = resultBuffer else {
fatalError() fatalError()
} }
return inResultBuffer.contents().bindMemory(to: Float32.self, capacity: capacity) return inResultBuffer.contents().bindMemory(to: Float32.self, capacity: paddedCapacity)
} }
} }
extension FetchHolder: CustomStringConvertible, CustomDebugStringConvertible { extension FetchHolder: CustomStringConvertible, CustomDebugStringConvertible {
var description: String { public var description: String {
fatalError() fatalError()
// return "\(result)" // return "\(result)"
} }
var debugDescription: String { public var debugDescription: String {
fatalError() fatalError()
// return "\(result)" // return "\(result)"
} }
......
...@@ -14,39 +14,42 @@ ...@@ -14,39 +14,42 @@
import Foundation import Foundation
public struct Dim { @objc public class Dim: NSObject {
public init(inDim: [Int]) { private(set) var dims: [Int]
dims = inDim
} @objc public init(inDim: [Int]) {
dims = inDim
mutating func swapeDimAt(index1: Int, index2: Int) { }
dims.swapAt(index1, index2)
} public func cout() -> Int {
return dims.count
func cout() -> Int { }
return dims.count
} public func numel() -> Int {
return dims.reduce(1) { $0 * $1 }
func numel() -> Int { }
return dims.reduce(1) { $0 * $1 }
} public static func ==(left: Dim, right: Dim) -> Bool {
return left.dims == right.dims;
public static func ==(left: Dim, right: Dim) -> Bool { }
return left.dims == right.dims;
} public static func !=(left: Dim, right: Dim) -> Bool {
return left.dims != right.dims;
public subscript(index: Int) -> Int { }
return dims[index];
} public subscript(index: Int) -> Int {
return dims[index];
private(set) var dims: [Int] }
private init(){
fatalError() public override var description: String {
} return "\(dims)"
} }
extension Dim: CustomStringConvertible { func swapeDimAt(index1: Int, index2: Int) {
public var description: String { dims.swapAt(index1, index2)
return "\(dims)" }
}
private override init(){
fatalError()
}
} }
...@@ -15,19 +15,16 @@ ...@@ -15,19 +15,16 @@
import Foundation import Foundation
let testTo = 81 let testTo = 5
var isTest = false var isTest = false
let computePrecision: ComputePrecision = .Float16 @objc public class GPUResultHolder: NSObject{
@objc public let dim: [Int]
public class GPUResultHolder { @objc public let capacity: Int
public let dim: [Int] @objc public var resultPointer: UnsafeMutablePointer<Float32>?
public let capacity: Int @objc public var intermediateResults: [String : [MTLBuffer]]?
public var resultPointer: UnsafeMutablePointer<Float32>? public init(inDim: [Int], inPointer: UnsafeMutablePointer<Float32>?, inCapacity: Int, inIntermediateResults: [String : [MTLBuffer]]? = nil) {
public var intermediateResults: [String : [Variant]]?
public let elapsedTime: Double
public init(inDim: [Int], inPointer: UnsafeMutablePointer<Float32>?, inCapacity: Int, inElapsedTime: Double, inIntermediateResults: [String : [Variant]]? = nil) {
dim = inDim dim = inDim
capacity = inCapacity capacity = inCapacity
...@@ -36,64 +33,34 @@ public class GPUResultHolder { ...@@ -36,64 +33,34 @@ public class GPUResultHolder {
resultPointer?.initialize(from: inInPointer, count: inCapacity) resultPointer?.initialize(from: inInPointer, count: inCapacity)
} }
elapsedTime = inElapsedTime
intermediateResults = inIntermediateResults intermediateResults = inIntermediateResults
} }
} public override var description: String {
extension GPUResultHolder: CustomDebugStringConvertible, CustomStringConvertible {
public var debugDescription: String {
// var str = ""
// str += "Dim: \(dim) \n value:[ "
// if resultArr.count < 20 {
// for d in resultArr {
// str += " \(d) "
// }
// } else {
// for d in stride(from: 0, to: resultArr.count, by: resultArr.count/20) {
// str += " \(resultArr[d]) "
// }
// }
// str += " ]"
// return str
fatalError() fatalError()
} }
public var description: String {
return debugDescription
}
} }
public class Executor<P: PrecisionType> { public class Executor<P: PrecisionType> {
var ops: [Runable & InferShaperable] = [] var ops: [Runable & InferShaperable] = []
var preInputDim: Dim = Dim.init(inDim: [])
let program: Program let program: Program
let device: MTLDevice let device: MTLDevice
let inflightSemaphore: DispatchSemaphore let inflightSemaphore: DispatchSemaphore
let queue: MTLCommandQueue let queue: MTLCommandQueue
public init(inDevice:MTLDevice, inQueue: MTLCommandQueue, inProgram: Program) throws { init(inDevice:MTLDevice, inQueue: MTLCommandQueue, inProgram: Program, initContext: InitContext) throws {
self.inflightSemaphore = DispatchSemaphore(value: 3) self.inflightSemaphore = DispatchSemaphore(value: 1)
program = inProgram program = inProgram
device = inDevice device = inDevice
queue = inQueue queue = inQueue
// print("before for ")
//print(program.scope.vars["fea_pyramid1_mbox_conf_flat.Flatten.output.1.tmp_0"])
for block in inProgram.programDesc.blocks { for block in inProgram.programDesc.blocks {
//block.ops.count //block.ops.count
for i in 0..<block.ops.count { for i in 0..<block.ops.count {
let opDesc = block.ops[i] let opDesc = block.ops[i]
do { do {
// print("in for i \(i): ") let op = try OpCreator<P>.shared.creat(device: inDevice, opDesc: opDesc, scope: inProgram.scope, initContext: initContext)
// print(program.scope.vars["fea_pyramid1_mbox_conf_flat.Flatten.output.1.tmp_0"])
//
// if i == 56 {
// print(program.scope.vars["fea_pyramid1_mbox_conf_flat.Flatten.output.1.tmp_0"])
//
// }
let op = try OpCreator<P>.shared.creat(device: inDevice, opDesc: opDesc, scope: inProgram.scope)
ops.append(op) ops.append(op)
} catch let error { } catch let error {
throw error throw error
...@@ -102,11 +69,12 @@ public class Executor<P: PrecisionType> { ...@@ -102,11 +69,12 @@ public class Executor<P: PrecisionType> {
} }
} }
public func predict(input: MTLTexture, dim: [Int], completionHandle: @escaping (GPUResultHolder) -> Void, preProcessKernle: CusomKernel? = nil, except: Int = 0) throws { public func predict(input: MTLTexture, dim: Dim, completionHandle: @escaping (GPUResultHolder) -> Void, preProcessKernle: CusomKernel? = nil, except: Int = 0) throws {
inflightSemaphore.wait()
guard let buffer = queue.makeCommandBuffer() else { guard let buffer = queue.makeCommandBuffer() else {
throw PaddleMobileError.predictError(message: "CommandBuffer is nil") throw PaddleMobileError.predictError(message: "CommandBuffer is nil")
} }
inflightSemaphore.wait()
let resInput: MTLTexture let resInput: MTLTexture
if let inPre = preProcessKernle { if let inPre = preProcessKernle {
...@@ -120,8 +88,7 @@ public class Executor<P: PrecisionType> { ...@@ -120,8 +88,7 @@ public class Executor<P: PrecisionType> {
resInput = input resInput = input
} }
let beforeDate = Date.init() let inputTexture = InputTexture.init(inMTLTexture: resInput, inExpectDim: dim)
let inputTexture = InputTexture.init(inMTLTexture: resInput, inExpectDim: Dim.init(inDim: dim))
program.scope.setInput(input: inputTexture) program.scope.setInput(input: inputTexture)
//(ops.count - except) //(ops.count - except)
for i in 0..<(ops.count - except) { for i in 0..<(ops.count - except) {
...@@ -133,64 +100,45 @@ public class Executor<P: PrecisionType> { ...@@ -133,64 +100,45 @@ public class Executor<P: PrecisionType> {
} }
} }
var outputTextures: [String : [Variant]]? var outputTextures: [String : [MTLBuffer]]?
if except > 0 { if except > 0 {
ops[ops.count - except].computeMiddleResult(device: device, buffer: buffer) ops[ops.count - except].computeMiddleResult(device: device, buffer: buffer)
outputTextures = ops[ops.count - except].inputVariant() outputTextures = ops[ops.count - except].inputVariant()
} }
buffer.addCompletedHandler { [weak self] (commandbuffer) in buffer.addCompletedHandler { [weak self] (commandbuffer) in
// let inputArr = resInput.toTensor(dim: (n: dim[0], c: dim[3], h: dim[1], w: dim[2]))
// print(inputArr.strideArray())
//
//// print(dim)
// writeToLibrary(fileName: "test_image_ssd_ar", array: inputArr)
// print(" write done ")
// print("write to library done")
// return
// print(inputArr)
//
// let stridableInput: [(index: Int, value: Float)] = input.stridableFloatArray()
// print(stridableInput)
//
// let _: Flo? = input.logDesc(header: "input: ", stridable: true)
// for i in 0..<self!.ops.count {
// let op = self!.ops[i]
// print(" 第 \(i) 个 op: ")
// op.delogOutput()
// }
// return;
// self!.ops[testTo - 2].delogOutput()
// self!.ops[testTo - 1].delogOutput()
// self!.ops[5].delogOutput()
// return
guard let SSelf = self else { guard let SSelf = self else {
// return
fatalError() fatalError()
} }
//将输入写进文件
/*
let inputArr = resInput.toTensor(dim: (n: dim[0], c: dim[3], h: dim[1], w: dim[2]))
print(dim)
writeToLibrary(fileName: "test_image_super", array: inputArr)
print(" write done ")
return
*/
/* 输出 op 计算结果
for op in SSelf.ops {
op.delogOutput()
}
*/
let afterDate = Date.init()
var resultHolder: GPUResultHolder var resultHolder: GPUResultHolder
if except > 0 { if except > 0 {
resultHolder = GPUResultHolder.init(inDim: [], inPointer: nil, inCapacity: 0, inElapsedTime: afterDate.timeIntervalSince(beforeDate), inIntermediateResults: outputTextures) resultHolder = GPUResultHolder.init(inDim: [], inPointer: nil, inCapacity: 0, inIntermediateResults: outputTextures)
} else { } else {
let outputVar: Variant = SSelf.program.scope.output()! let outputVar: Variant = SSelf.program.scope.output()!
let output: FetchHolder = outputVar as! FetchHolder let output: FetchHolder = outputVar as! FetchHolder
// let beforeToTensorDate = Date.init() resultHolder = GPUResultHolder.init(inDim: output.dim.dims, inPointer: output.result, inCapacity: output.capacity)
resultHolder = GPUResultHolder.init(inDim: output.dim, inPointer: output.result, inCapacity: output.capacity, inElapsedTime: afterDate.timeIntervalSince(beforeDate))
// let timeToTensor = Date.init().timeIntervalSince(beforeToTensorDate)
// print(timeToTensor)
} }
completionHandle(resultHolder) completionHandle(resultHolder)
SSelf.inflightSemaphore.signal() SSelf.inflightSemaphore.signal()
} }
buffer.commit() buffer.commit()
} }
......
...@@ -150,6 +150,9 @@ public class Loader<P: PrecisionType> { ...@@ -150,6 +150,9 @@ public class Loader<P: PrecisionType> {
let originProgramDesc = ProgramDesc.init(protoProgram: protoProgram) let originProgramDesc = ProgramDesc.init(protoProgram: protoProgram)
let programDesc = ProgramOptimize<P>.init().optimize(originProgramDesc: originProgramDesc) let programDesc = ProgramOptimize<P>.init().optimize(originProgramDesc: originProgramDesc)
// let programDesc = ProgramDesc.init(protoProgram: protoProgram)
print(programDesc) print(programDesc)
guard programDesc.blocks.count > 0 else { guard programDesc.blocks.count > 0 else {
...@@ -210,7 +213,7 @@ public class Loader<P: PrecisionType> { ...@@ -210,7 +213,7 @@ public class Loader<P: PrecisionType> {
scope[varDesc.name] = tensor scope[varDesc.name] = tensor
} else { } else {
let dim = Dim.init(inDim: tensorDesc.dims) let dim = Dim.init(inDim: tensorDesc.dims)
scope[varDesc.name] = Texture<P>.init(device: device, inDim: dim) scope[varDesc.name] = Texture.init(device: device, inDim: dim)
} }
} else { } else {
if varDesc.name == fetchKey { if varDesc.name == fetchKey {
......
...@@ -28,9 +28,7 @@ extension Tensorial { ...@@ -28,9 +28,7 @@ extension Tensorial {
} }
} }
public enum ComputePrecision {
case Float32, Float16
}
class Tensor<P: PrecisionType>: Tensorial { class Tensor<P: PrecisionType>: Tensorial {
...@@ -97,7 +95,7 @@ class Tensor<P: PrecisionType>: Tensorial { ...@@ -97,7 +95,7 @@ class Tensor<P: PrecisionType>: Tensorial {
func initBuffer(device: MTLDevice, precision: ComputePrecision = .Float16, convertToNHWC: Bool = true, withTranspose: Bool = false) { func initBuffer(device: MTLDevice, precision: ComputePrecision = .Float16, padWhenOneC: Bool = false, convertToNHWC: Bool = true, withTranspose: Bool = false) {
if convertToNHWC { if convertToNHWC {
// print(layout) // print(layout)
convert(to: DataLayout.NHWC()) convert(to: DataLayout.NHWC())
...@@ -145,7 +143,7 @@ class Tensor<P: PrecisionType>: Tensorial { ...@@ -145,7 +143,7 @@ class Tensor<P: PrecisionType>: Tensorial {
case .Float16: case .Float16:
float32ToFloat16(input: floatPointer, output: buffer.contents(), count: count) float32ToFloat16(input: floatPointer, output: buffer.contents(), count: count)
} }
} else if C == 1 { } else if C == 1 && !padWhenOneC {
buffer = device.makeBuffer(length: numel() * precisionSize) buffer = device.makeBuffer(length: numel() * precisionSize)
switch precision { switch precision {
case .Float32: case .Float32:
...@@ -238,10 +236,32 @@ class Tensor<P: PrecisionType>: Tensorial { ...@@ -238,10 +236,32 @@ class Tensor<P: PrecisionType>: Tensorial {
data.release() data.release()
} }
var n: Int {
get {
if dim.cout() == 4 {
if layout == DataLayout.NCHW() {
return dim[0]
} else if layout == DataLayout.NHWC() {
return dim[0]
} else {
fatalError(" unsupport ")
}
} else {
fatalError()
}
}
}
var width: Int { var width: Int {
get { get {
if dim.cout() == 4 { if dim.cout() == 4 {
return dim[1] if layout == DataLayout.NHWC() {
return dim[2]
} else if layout == DataLayout.NCHW() {
return dim[3]
} else {
fatalError(" unsupport ")
}
} else { } else {
fatalError() fatalError()
} }
...@@ -251,7 +271,13 @@ class Tensor<P: PrecisionType>: Tensorial { ...@@ -251,7 +271,13 @@ class Tensor<P: PrecisionType>: Tensorial {
var height: Int { var height: Int {
get { get {
if dim.cout() == 4 { if dim.cout() == 4 {
return dim[2] if layout == DataLayout.NHWC() {
return dim[1]
} else if layout == DataLayout.NCHW() {
return dim[2]
} else {
fatalError(" unsupport ")
}
} else { } else {
fatalError() fatalError()
} }
...@@ -261,7 +287,13 @@ class Tensor<P: PrecisionType>: Tensorial { ...@@ -261,7 +287,13 @@ class Tensor<P: PrecisionType>: Tensorial {
var channel: Int { var channel: Int {
get { get {
if dim.cout() == 4 { if dim.cout() == 4 {
return dim[3] if layout == DataLayout.NHWC() {
return dim[3]
} else if layout == DataLayout.NCHW() {
return dim[1]
} else {
fatalError(" unsupport ")
}
} else { } else {
fatalError() fatalError()
} }
......
...@@ -68,16 +68,20 @@ extension InputTexture { ...@@ -68,16 +68,20 @@ extension InputTexture {
.height = 1 .height = 1
.len = 1 .len = 1
*/ */
public class Texture: Tensorial {
public var dim: Dim
public class Texture<P: PrecisionType>: Tensorial {
var dim: Dim
public var tensorDim: Dim public var tensorDim: Dim
/// tensor dim pad to four
public var padToFourDim: Dim public var padToFourDim: Dim
private var textureDesc: MTLTextureDescriptor! private var textureDesc: MTLTextureDescriptor!
public var metalTexture: MTLTexture! public var metalTexture: MTLTexture!
var transpose: [Int] = [0, 1, 2, 3] var transpose: [Int] = [0, 1, 2, 3]
func elementCount() -> Int {
return metalTexture.width * metalTexture.height * metalTexture.arrayLength * 4
}
func toTensor() -> [Float32] { func toTensor() -> [Float32] {
guard padToFourDim.cout() == 4 else { guard padToFourDim.cout() == 4 else {
fatalError("- not support -") fatalError("- not support -")
...@@ -92,15 +96,15 @@ public class Texture<P: PrecisionType>: Tensorial { ...@@ -92,15 +96,15 @@ public class Texture<P: PrecisionType>: Tensorial {
return metalTexture.realNHWC(dim: (n: padToFourDim[0], h: padToFourDim[1], w: padToFourDim[2], c: padToFourDim[3])) return metalTexture.realNHWC(dim: (n: padToFourDim[0], h: padToFourDim[1], w: padToFourDim[2], c: padToFourDim[3]))
} }
func initTexture(device: MTLDevice, inTranspose: [Int] = [0, 1, 2, 3], computePrecision: ComputePrecision = .Float16) { public func initTexture(device: MTLDevice, inTranspose: [Int] = [0, 1, 2, 3], computePrecision: ComputePrecision = .Float16) {
transpose = inTranspose transpose = inTranspose
for i in 0..<(4 - tensorDim.cout()) { for i in 0..<(4 - tensorDim.cout()) {
if i != inTranspose[i] { if i != inTranspose[i] {
fatalError() fatalError()
} }
} }
let newDim = transpose.map { padToFourDim[$0] }
let newDim = transpose.map { padToFourDim[$0] }
let newLayout = transpose.map { layout.layoutWithDim[$0] } let newLayout = transpose.map { layout.layoutWithDim[$0] }
layout = DataLayout.init(newLayout) layout = DataLayout.init(newLayout)
...@@ -139,7 +143,29 @@ public class Texture<P: PrecisionType>: Tensorial { ...@@ -139,7 +143,29 @@ public class Texture<P: PrecisionType>: Tensorial {
metalTexture = device.makeTexture(descriptor: tmpTextureDes) ?! " texture nil " metalTexture = device.makeTexture(descriptor: tmpTextureDes) ?! " texture nil "
} }
public func updateDims(inTensorDim: Dim, inDim: Dim) {
var fourDim: Dim
if inDim.cout() == 4 {
fourDim = inDim
} else if inDim.cout() < 4 {
var fourDimNum: [Int] = []
for _ in 0..<(4 - inDim.cout()) {
fourDimNum.append(1)
}
fourDimNum.append(contentsOf: inDim.dims)
fourDim = Dim.init(inDim: fourDimNum)
} else {
fatalError(" not support ")
}
tensorDim = inTensorDim
dim = fourDim
padToFourDim = fourDim
}
// 初始化时 dim padToFourDim 模型中的维度(一般来说 nchw),前面补全0
init(device: MTLDevice, inDim: Dim) { init(device: MTLDevice, inDim: Dim) {
print(" in dim > \(inDim)")
var fourDim: Dim var fourDim: Dim
if inDim.cout() == 4 { if inDim.cout() == 4 {
fourDim = inDim fourDim = inDim
......
...@@ -27,19 +27,19 @@ class OpCreator<P: PrecisionType> { ...@@ -27,19 +27,19 @@ class OpCreator<P: PrecisionType> {
} }
} }
func creat(device: MTLDevice, opDesc: OpDesc, scope: Scope) throws -> Runable & InferShaperable { func creat(device: MTLDevice, opDesc: OpDesc, scope: Scope, initContext: InitContext) throws -> Runable & InferShaperable {
guard let opCreator = opCreators[opDesc.type] else { guard let opCreator = opCreators[opDesc.type] else {
throw PaddleMobileError.opError(message: "there is no " + opDesc.type + " yet") throw PaddleMobileError.opError(message: "there is no " + opDesc.type + " yet")
} }
do { do {
return try opCreator(device, opDesc, scope) return try opCreator(device, opDesc, scope, initContext)
} catch let error { } catch let error {
throw error throw error
} }
} }
let opCreators: [String : (MTLDevice, OpDesc, Scope) throws -> Runable & InferShaperable] = let opCreators: [String : (MTLDevice, OpDesc, Scope, InitContext) throws -> Runable & InferShaperable] =
[gConvType : ConvOp<P>.creat, [gConvType : ConvOp<P>.creat,
gBatchNormType : BatchNormOp<P>.creat, gBatchNormType : BatchNormOp<P>.creat,
gReluType : ReluOp<P>.creat, gReluType : ReluOp<P>.creat,
......
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册