頭と尻尾はくれてやる!

パソコンおやじのiPhoneアプリ・サイト作成・運営日記


MPSCNNConvolutionのイニシャライズができない

APPLE公式のサンプルコードでMPSCNNHelloWorldってiOSデバイスでMNISTができるのがある。
ところが最新のサンプル(残念ながらSwiftのみ)をダウンロードしてきても、SlimMPSCNNConvolutionクラスで親クラス(MPSCNNConvolution)のイニシャライザ部分で

Cannot invoke 'MPSCNNConvolution.init' with an argument list of type '(device: MTLDevice, convolutionDescriptor: MPSCNNConvolutionDescriptor, kernelWeights: UnsafePointer<Float>, biasTerms: UnsafePointer<Float>, flags: MPSCNNConvolutionFlags)'

ってエラーでビルドさえできない。
以前ダウンロードしてたObjective-C用のでも

No visible @interface for 'MPSCNNConvolution' declares the selector 'initWithDevice:convolutionDescriptor:kernelWeights:biasTerms:flags:'

そんなイニシャライザはねえよ!ってエラーで同じくビルドもできない。

リファレンスにはdeprecatedとなっているが代わりにこうしろってのもよくわからないし、ヘッダーに書いてるメソッド(initWithDevice:weights:)も動きそうにない。

dev cenのフォーラムを見ると、この4月の始め頃から同じように困っている人のコメントがあった。
それに対し、すでにバグレポートを出したよ、なんてリプライもあったんだけど、そんなの待ってられないなあ?
と思ってたらAPIとしてはもうないけどメソッドとしてはまだあるのでselector使ったらいいよ、って記述が。

なんだかよくわかんないけど、試してみた。ただselectorって引数をたくさんとれないので面倒だけどNSInvocationとか使う。

{
//    self = [super initWithDevice:device
//           convolutionDescriptor:convDesc
//                   kernelWeights:weightP
//                       biasTerms:biasP
//                           flags:MPSCNNConvolutionFlagsNone];
//    ↑もとがこれ

    
    NSInvocation *invocation;
    NSMethodSignature *signature;
    SEL argSelector =  @selector(initWithDevice:convolutionDescriptor:kernelWeights:biasTerms:flags:);

    MPSCNNConvolution *cnnc = [MPSCNNConvolution alloc];
    
    signature = [self methodSignatureForSelector:argSelector];
    invocation = [NSInvocation invocationWithMethodSignature:signature];
    [invocation setTarget:cnnc];
    [invocation setSelector:argSelector];
    NSUInteger n = 0;
    
    [invocation setArgument:&device atIndex:2];
    [invocation setArgument:&convDesc atIndex:3];
    [invocation setArgument:&weightP atIndex:4];
    [invocation setArgument:&biasP atIndex:5];
    [invocation setArgument:&n atIndex:6];

    [invocation invoke];
    
    //返り値を得る
    [invocation getReturnValue:(void*)&cnnc];
    self = (SlimMPSCNNConvolution *)cnnc;
}
もともとのメソッドの最後の引数のMPSCNNConvolutionFlagsNoneもdeprecatedだし、もともとこれしかなかったやつでもとの値もゼロなのでそれを入れてる。
とりあえずこれで動いた!!!



おまけ。
MPSCNNConvolutionDescriptorの
cnnConvolutionDescriptorWithKernelWidth:kernelHeight:inputFeatureChannels:outputFeatureChannels:neuronFilter:
ってメソッドもdeprecatedだけど、現在そのままでも警告はでるけど動いてくれる。
cnnConvolutionDescriptorWithKernelWidth:kernelHeight:inputFeatureChannels:outputFeatureChannels:
ってのがiOS11.0から使えるみたいなので、こっちを使うと警告は消えた。
ただ最後のneuronFilter:で渡していた項目見ると重要だろ?と思うんだがそのままでも動いてる。なんでや?!
でも気持ち悪いのでちゃんと設定しておく。
もともとのコードでは活性化関数にReLUを使うって指定してる。
なのでこんな感じにしといた。
{
    MPSCNNConvolutionDescriptor *convDesc = …

    MPSNNNeuronDescriptor *fusedNeuronDescriptor =[MPSNNNeuronDescriptor new];
    fusedNeuronDescriptor.neuronType = MPSCNNNeuronTypeReLU;
    fusedNeuronDescriptor.a = 0.0;
    convDesc.fusedNeuronDescriptor = fusedNeuronDescriptor;
}




Xcode 9.3
iOS 11.3.1

<< macOSでテキストファイルの読み込み、保存ができない  TopPage  SceneKitでシェーダを適用すると不具合発生? >>

コメント


管理者にだけ表示を許可する
 

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/1137-f1cb372c




Copyright ©頭と尻尾はくれてやる!. Powered by FC2 Blog. Template by eriraha.

FC2Ad