FC2ブログ

頭と尻尾はくれてやる!

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


3チャンネル画像だとKerasとMPSの計算が合わない

画像の判別がCreateMLでダメだったのでKerasでやってみた
↑この続き。
Kerasで画像分類をさせて、その学習結果(重み、バイアス)を出力。それをmacOSアプリのMetal Performance Shadersで同じ計算をさせる。

計算量削減のために画像のRGBの3チャンネル分のデータを使う。するとKerasとMPSで同じ画像を与えても出てくる結果が違ってしまう。

ちなみに4チャンネルの画像を使い、同じようにKerasで学習させて係数をmacOSで使いMPSで計算させると同じ値になる。
よって、学習結果の係数の受け渡し方に問題はないと考えている。

MPSで画像データを与える場合に
- (void)replaceRegion:(MTLRegion)region mipmapLevel:(NSUInteger)level withBytes:(const void *)pixelBytes bytesPerRow:(NSUInteger)bytesPerRow;
↑このメソッドを使うとする(※1)。
//(1)4チャンネルの場合

{
    MTLRegion region = MTLRegionMake2D(0, 0, Width, Height);

    [srcImage.texture replaceRegion:region 
        mipmapLevel:0 
        withBytes:inputs 
        bytesPerRow:sizeof(unsigned char)*Width*NofChannel];
}
↑MPSではこんな感じでデータ列(ここではunsigned char型)をMPSImageのsrcImageのテクスチャに書き込む。
その範囲をMTLRegionで指定したり、1行あたりのバイト数を指定したりする。
これは意図通りに動いた。

問題は次の3チャンネルの場合だ。
//(2)3チャンネルの場合
{
    MTLRegion region = MTLRegionMake2D(0, 0, Width*3/4, Height);

    [srcImage.texture replaceRegion:region 
        mipmapLevel:0 
        withBytes:inputs 
        bytesPerRow:sizeof(unsigned char)*Width*NofChannel];
}
↑今回のケースではMPSImageは4チャンネルが基本(※2)なのだが、データは3チャンネルなのでbytesPerRowは1バイトx3チャンネルx横幅。
これに合わせてコピーする範囲の横幅をピクセル数の3/4倍としている(画像サイズは96x96なので横幅は4の倍数)。

これが、なぜかKerasと計算結果が全然合わない、、、😥

regionの設定が間違っているのか?と思いsrcImage.textureから再度データを取り出して画像を作成して元画像になってるのを確認したり、RGBが入れ替わっているのか?と思いチェックするなど、まあいろいろと調べたのだが、、、降参!

回避策は4チャンネルで学習、予測を行う、、、だ、ださいがまあ動くからいいか、、、なにこの敗北感。
何かあればお教えください。


※1
- (void)replaceRegion:(MTLRegion)region mipmapLevel:(NSUInteger)level slice:(NSUInteger)slice withBytes:(const void *)pixelBytes bytesPerRow:(NSUInteger)bytesPerRow bytesPerImage:(NSUInteger)bytesPerImage;
↑こちらのメソッドもあるが、今回は3チャンネルか4チャンネルなのでスライスは不要。

※2 これはMPSImageオブジェクトのpixel format次第。これはread only。MPSImageオブジェクトを作る時に使うMPSImageDescriptorオブジェクトの設定により自動的に決まるのだと思う。
MPSImageDescriptor *sourceImageDiscriptor = [MPSImageDescriptor imageDescriptorWithChannelFormat:MPSImageFeatureChannelFormatUnorm8 
        width:Width 
        height:Height 
        featureChannels:NofChannel];
↑このようにして作成するとsourceImageDiscriptor.pixelFormatは
MTLPixelFormatRGBA8Unorm
となり、
Ordinary format with four 8-bit normalized unsigned integer components in RGBA order
↑とリファレンスにあるように8ビット符号なし整数のRGBAの値を持つ(4バイト)。

ちなみにMNISTでは白黒画像を使っていたが
MPSImageDescriptor *sourceImageDiscriptor = [MPSImageDescriptor imageDescriptorWithChannelFormat:MPSImageFeatureChannelFormatUnorm8 
width:28 
height:28 
featureChannels:1];
↑このように画像を設定した場合だとpixel formatは
MTLPixelFormatR8Unorm
となり1ピクセルに1バイトの値しか持たない。



<< KerasのImageDataGeneratorで画像データの水増し  TopPage  NSImage画像をRGBAのデータに展開する >>

コメント


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

トラックバック

トラックバックURL
http://ringsbell.blog117.fc2.com/tb.php/1262-786b42e8




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

FC2Ad