20200712のiOSに関する記事は4件です。

【SwiftUI】BlendMode で View を合成する

はじめに

この記事では、Adobe Photoshop などのデザインツールでおなじみのブレンドモードについて扱います。
コードと実行結果は SwiftUI のものですが、ブレンドモードは Core Graphics が提供しているので、SwiftUI を使わない開発でも知識としては使えると思います。

さて、本題です。
SwiftUI で2つのビューをブレンドしてみます。こんな感じのイメージです。
はじめに.jpeg
緑が透過なビューの場合は単純に上に載せるだけなので、非透過な緑色のビューとの合成を考えます。
この場合のサンプルコードはこちら。

struct ContentView: View {
    var body: some View {
        ZStack {
            Image("lenna")
                .resizable()
                .scaledToFit()
            Rectangle()
                .fill(Color.green)
                .blendMode(.multiply) // ← ココ!
        }
        .edgesIgnoringSafeArea(.all)
    }
}

簡単な説明

  • ZStackImage の上に Rectangle を載せる
    • Image を配置
      • アスペクト比を維持してビューにフィット
    • Rectangle を配置
      • green で塗りつぶし
      • 乗算ブレンド
  • セーフエリアを無視して配置

実行結果

はじめに2.jpeg

BlendMode を指定して配置するだけなので、とても簡単ですが、次のことが気になりました。

  • 乗算ブレンド .multiply とはどのような合成方法なのか?
  • 他の BlendMode を指定した場合はどのような結果が得られるのか?

ということで、本記事では各種ブレンドモードについての情報と実際の表示結果を載せました。
表示結果は SwiftUI のプレビュー機能を使用しています。

環境

  • Xcode Version 11.5 (11E608c)

BlendMode

SwiftUI の API リファレンスには概要が記載されていなかったので、Core Graphics の API リファレンスも参照しました。次のように記載されていました。

You can find more information on blend modes, including examples of images produced using them, and many mathematical descriptions of the modes, in PDF Reference, Fourth Edition, Version 1.5, Adobe Systems, Inc. If you are a former QuickDraw developer, it may be helpful for you to think of blend modes as an alternative to transfer modes1

Adobe Systems の PDF Reference, Fourth Edition に正確な情報が記載されているとのことです。
この資料には、全てではないですが、各ブレンドモードの数式も記載がありました。

PDF Reference に記載のあるブレンドモード

BlendMode CGBlendMode 名称
normal kCGBlendModeNormal 通常
multiply kCGBlendModeMultiply 乗算
screen kCGBlendModeScreen スクリーン
overlay kCGBlendModeOverlay オーバーレイ
darken kCGBlendModeDarken 比較(暗)
lighten kCGBlendModeLighten 比較(明)
colorDodge kCGBlendModeColorDodge 覆い焼きカラー
colorBurn kCGBlendModeColorBurn 焼き込みカラー
softLight kCGBlendModeSoftLight ソフトライト
hardLight kCGBlendModeHardLight ハードライト
difference kCGBlendModeDifference 差の絶対値
exclusion kCGBlendModeExclusion 除外
hue kCGBlendModeHue 色相
saturation kCGBlendModeSaturation 彩度
color kCGBlendModeColor カラー
luminosity kCGBlendModeLuminosity 輝度

以下、数学的な説明が必要な場合は、PDF Reference, Fourth Edition で記載されていた次の変数を使います。

変数 意味
$C_b$ 背景の色(基本色)
$C_s$ 前面の色(合成色)
$C(C_b, C_s)$ ブレンド関数

上記変数は各色成分をもつベクトルです。また、今回扱う関数は、各色成分ごとに分離可能な関数です。

normal

通常

各ピクセルを編集またはペイントして結果色を作成します。これは、初期設定のモードです(通常モードは、モノクロ 2 階調画像やインデックスカラー画像で作業するときには、2 階調化と呼ばれます)。2

ブレンド関数は次の通りです。前面をそのまま反映します。

B(c_b,c_s) = c_s

Screen Shot 2020-07-12 at 18.43.59.png
Screen Shot 2020-07-12 at 19.47.38.png

multiply

乗算

各チャンネル内のカラー情報に基づき、基本色と合成色を乗算します。結果色は暗いカラーになります。どのカラーも、ブラックで乗算すると結果はブラックになります。どのカラーも、ホワイトで乗算した場合は変更されません。ブラックまたはホワイト以外のカラーでペイントしている場合、ペイントツールで繰り返しストロークを描くとカラーは徐々に暗くなります。この効果は、複数のマーカーペンで描画したような効果が得られます。3

ブレンド関数は次の通りです。背景カラーと前面カラーの RGB の構成要素をそれぞれ乗算します。

B(c_b,c_s) = c_b × c_s

背景ビューと前面ビューを入替えても同じ結果を得ることができます。

色の各成分は、0 以上 1 以下の小数です。特に ブラック(0, 0, 0), ホワイト(1, 1, 1) なので、
ブラックで乗算すると結果はブラック、ホワイトで乗算した場合は変更されないことがわかります。

また、0 以上 1 未満の数は乗算を繰り返すほど、0 に近づくので、
multiply ブレンドモードを繰り返すほど徐々に暗くなります。
Screen Shot 2020-07-12 at 18.44.21.png
Screen Shot 2020-07-12 at 19.47.52.png

screen

スクリーン

各チャンネル内のカラー情報に基づき、合成色と基本色を反転したカラーを乗算します。結果色は明るいカラーになります。ブラックでスクリーニングすると、カラーは変更されません。ホワイトでスクリーニングすると、ホワイトになります。この効果は、複数の写真スライドを重ね合わせて投影したような効果が得られます。4

ブレンド関数は次の通りです。

B(c_b,c_s) = 1 – (1–c_b)×(1–c_s)

背景カラーと前面カラーをそれぞれ反転させたものを乗算して、その結果の値を反転させます。

この式から、multiply と逆の性質を得ることができます。

  • ブラックとスクリーンをすると変更されない
  • ホワイトとスクリーンをすると結果はホワイト
  • 繰り返すほど徐々に明るくなる

Screen Shot 2020-07-12 at 18.44.40.png
Screen Shot 2020-07-12 at 19.48.02.png

overlay

オーバーレイ

基本色に応じて、カラーを乗算またはスクリーンします。基本色のハイライトおよびシャドウを保持しながら、パターンまたはカラーを既存のピクセルに重ねます。基本色は、置き換えられませんが、合成色と混合されて基本色の明るさまたは暗さを反映します。5

Screen Shot 2020-07-12 at 18.44.59.png
Screen Shot 2020-07-12 at 19.48.20.png

darken

比較(暗)

各チャンネル内のカラー情報に基づき、基本色または合成色のいずれか暗い方を結果色として選択します。合成色よりも明るいピクセルが置き換えられ、合成色よりも暗いピクセルは変更されません。6

ブレンド関数は次の通りです。

B(c_b, c_s) = min(c_b, c_s)

Screen Shot 2020-07-12 at 18.45.19.png
Screen Shot 2020-07-12 at 19.48.58.png

lighten

比較(明)

各チャンネル内のカラー情報に基づき、基本色または合成色のいずれか明るい方を結果色として選択します。合成色よりも暗いピクセルが置き換えられ、合成色よりも明るいピクセルは変更されません。7

ブレンド関数は次の通りです。

B(c_b, c_s) = max(c_b, c_s)

Screen Shot 2020-07-12 at 18.45.34.png
Screen Shot 2020-07-12 at 19.49.10.png

colorDodge

覆い焼きカラー

各チャンネルのカラー情報に基づき、基本色を明るくして基本色と合成色のコントラストを落とし、合成色を反映します。ブラックと合成しても変化はありません。8

Screen Shot 2020-07-12 at 18.45.48.png

colorBurn

焼き込みカラー

各チャンネルのカラー情報に基づき、基本色を暗くして基本色と合成色のコントラストを強くし、合成色を反映します。ホワイトで合成した場合は、何も変更されません。9

Screen Shot 2020-07-12 at 18.46.01.png

softLight

ソフトライト

合成色に応じて、カラーを暗くまたは明るくします。画像上でスポットライトを照らしたような効果が得られます。合成色(光源)が 50 %グレーよりも明るい場合、画像は覆い焼きされたかのように明るくなります。合成色が 50 %グレーよりも暗い場合、画像は焼き込んだように暗くなります。純粋な黒または白でペイントすると、その部分の明暗ははっきりしますが、純粋な黒または白にはなりません。10

Screen Shot 2020-07-12 at 18.46.14.png

hardLight

ハードライト

合成色に応じて、カラーを乗算またはスクリーンします。画像上で直接スポットライトを照らしたような効果が得られます。合成色(光源)が 50 %グレーよりも明るい場合、画像はスクリーンされたかのように明るくなります。これは、画像にハイライトを追加するときに役立ちます。合成色が 50 %グレーよりも暗い場合、画像は乗算されたかのように暗くなります。これは、画像にシャドウを追加するときに役立ちます。純粋なホワイトまたはブラックでペイントすると、純粋なホワイトまたはブラックになります。11

Screen Shot 2020-07-12 at 18.46.26.png

difference

差の絶対値

各チャンネル内のカラー情報に基づいて、合成色を基本色から取り除くか、基本色を合成色から取り除きます。明るさの値の大きい方のカラーから小さい方のカラーを取り除きます。ホワイトと合成すると基本色の値が反転しますが、ブラックと合成しても変化はありません。12

ブレンド関数は次の通りです。

B(c_b, c_s) = | c_b – c_s |

ホワイトとブレンドすると色反転ができます。

Screen Shot 2020-07-12 at 18.46.43.png
Screen Shot 2020-07-12 at 19.49.32.png

exclusion

除外

差の絶対値モードと似ていますが、効果のコントラストはより低くなります。ホワイトと合成すると、基本色の値が反転しますが、ブラックと合成しても変化はありません。13

Screen Shot 2020-07-12 at 18.46.59.png
Screen Shot 2020-07-12 at 19.49.47.png

hue

色相

ベースカラーの輝度と彩度、およびブレンドカラーの色相を持つ最終カラーが作成されます。14

saturation

彩度

基本色の輝度と色相および合成色の彩度を使用して、結果色を作成します。このモードで彩度ゼロ(グレー)の領域をペイントした場合は、何も変更されません。15

color

カラー

基本色の輝度と、合成色の色相および彩度を使用して、結果色を作成します。これにより、画像内のグレーレベルが保持され、モノクロ画像のカラー化およびカラー画像の階調化に役立ちます。16

luminosity

輝度

基本色の色相および彩度と、合成色の輝度を使用して、結果色を作成します。このモードでは、カラーモードの反対の効果が作成されます。17

サンプルコード

今回のスクリーンショットで使ったコードはこちら。

表示データ

Item.swift
import SwiftUI

struct Item: Hashable {
    let mode: BlendMode, name: String

    static var items: [Item] = [
        Item(mode: .normal,     name: ".normal"),
        Item(mode: .multiply,   name: ".multiply"),
        Item(mode: .screen,     name: ".screen"),
        Item(mode: .overlay,    name: ".overlay"),
        Item(mode: .darken,     name: ".darken"),
        Item(mode: .lighten,    name: ".lighten"),
        Item(mode: .colorDodge, name: ".colorDodge"),
        Item(mode: .colorBurn,  name: ".colorBurn"),
        Item(mode: .softLight,  name: ".softLight"),
        Item(mode: .hardLight,  name: ".hardLight"),
        Item(mode: .difference, name: ".difference"),
        Item(mode: .exclusion,  name: ".exclusion"),
    ]
}

画像と色のブレンド

ImageBlendView.swift
import SwiftUI

struct ImageBlendView: View {
    var color: Color
    var mode: BlendMode

    var body: some View {
        ZStack {
            Image("lenna").resizable().scaledToFit()
            Rectangle().fill(color).blendMode(mode)
        }
    }
}

struct ImageBlendViewSamples: View {
    var mode: BlendMode
    var colors: [Color] = [.clear, .red, .green, .blue, .black, .white]
    var body: some View {
        HStack(spacing: 0) { [colors, mode] in
            ForEach(0..<colors.count) { i in
                ImageBlendView(color: colors[i], mode: mode)
            }
        }
    }
}

// MARK: - PreviewProvider
struct ImageBlendViewSamples_Previews: PreviewProvider {
    static var previews: some View {
        Group { [items = Item.items] in
            ForEach(0..<items.count) { i in
                ImageBlendViewSamples(mode: items[i].mode)
                    .previewDisplayName(items[i].name)
            }
        }
        .previewLayout(.fixed(width: 100 * 6, height: 100))
    }
}

円のブレンド

import SwiftUI

struct ColorBlendView: View {
    var mode: BlendMode
    var background: Color
    var colors: [Color]
    var body: some View {
        GeometryReader<AnyView> { [mode, colors] geometry in
            let edge = min(geometry.size.width, geometry.size.height)/2
            let offset = edge/3
            let arg: (Int) -> CGFloat = { 2*(.pi)*CGFloat($0)/CGFloat(colors.count) - (.pi)/2 }
            return AnyView(
                ZStack {
                    ForEach(0..<colors.count) { index in
                        Circle()
                            .fill(colors[index])
                            .frame(width: edge)
                            .offset(x: offset*cos(arg(index)), y: offset*sin(arg(index)))
                            .blendMode(mode)
                    }
                }
                .frame(width: geometry.size.width, height: geometry.size.height)
            )
        }
        .background(background)
        .edgesIgnoringSafeArea(.all)
    }
}

struct ColorBlendViewSamples: View {
    var mode: BlendMode
    var foregrounds: [[Color]] = [
        [.red, .green, .blue],
        .init(repeating: .green, count: 7)
    ]
    var backgrounds: [Color] = [
        Color(red: 0, green: 0, blue: 0),
        Color(red: 1, green: 1, blue: 1),
    ]
    var body: some View {
        HStack(spacing: .zero) { [mode, foregrounds, backgrounds] in
            ForEach(0..<backgrounds.count) { i in
                ForEach(0..<foregrounds.count) { j in
                    ColorBlendView(mode: mode, background: backgrounds[i], colors: foregrounds[j])
                }
            }
        }
    }
}

// MARK: - PreviewProvider
struct ColorBlendViewSamples_Previews: PreviewProvider {
    static var previews: some View {
        Group { [items = Item.items] in
            ForEach(0..<items.count) { i in
                ColorBlendViewSamples(mode: items[i].mode)
                    .previewDisplayName(items[i].name)
            }
        }
        .previewLayout(.fixed(width: 120 * 4, height: 120))
    }
}

参考

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

個人的にFlutterで何回も調べがちなことまとめ

個人的な備忘としてまとめておきます
最近弊社で開発してるAndroidアプリがFlutter製ということもあり、
開発する中で何度も調べることがもっと増えてくると思うので逐次更新していきます。

ふたりのみ Android for Flutter(会員向け)
クラフトビール飲み比べ定期配送サービス ふたりのみ とは

環境

  • Flutter 1.17.4
  • Dart 2.8.4

Container の装飾周り

角丸にする

Container(
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(4.0),
  ),
);

枠線を描く

Container(
  decoration: BoxDecoration(
    border: Border.all(color: Colors.blueAccent)
  ),
);

Navigator での画面遷移周り

画面遷移

Flutter 画面遷移 でいつも調べてます
Navigator は iOS と同じならスタック(後のせ先取り)なので push はお皿を積むイメージ

Navigator.push(
  context,
  MaterialPageRoute<Null>(
    settings: RouteSettings(name: "/detail"),
    builder: (BuildContext context) => Container();
  )
);

前の画面に戻る

pop はお皿を取るイメージ
一枚だけ上からとります

Navigator.pop(context);

rootまでpopする

積んだお皿全部退けます

Navigator.popUntil(context, ModalRoute.withName('/'));

TextField の装飾周り

枠線を描く

iOS ちっくなTextFieldにしたいときよく使う

TextField(
  decoration: InputDecoration(
    border: OutlineInputBorder(),
  ),
);

ラベルとヒントをつける

プレースホルダー的なやつを設定したいときあるけどよく忘れる

TextField(
  decoration: InputDecoration(
    labelText: 'ラベル',
    hintText: 'ヒント',
  ),
);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[iOS13]キャッシュの設定について

どうやって設定するか

URLRequestを使っている場合

URLRequestクラスのcachePolicyプロパティより編集する。

参考:cachePolicy

Alamofireを使っている場合

やはりURLRequestにキャッシュポリシーを設定し、Alamofireに渡すことになる。

// URLRequestを作成する際に、cachePolicyでキャッシュを無効化に指定する.
let request = URLRequest(url: url!,
                         cachePolicy: .reloadIgnoringLocalAndRemoteCacheData,
                         timeoutInterval: 5)

// URLRequestをAlamofire.requestに渡す。
Alamofire.request(request).responseString(encoding: .utf8) { data in
  // なんらかの処理
}

参考: [Swift] Alamofireでキャッシュを無効化してリクエストを発行する

Moyaを使っている場合

やはりMoyaの機能としてキャッシュポリシーを変える機能はないため、URLRequestを使うことになる。MoyaのPluginTypeを利用すると便利。

MoyaCacheable.swift
protocol MoyaCacheable {
  typealias MoyaCacheablePolicy = URLRequest.CachePolicy
  var cachePolicy: MoyaCacheablePolicy { get }
}

MoyaCacheablePlugin.swift
final class MoyaCacheablePlugin: PluginType {

  ///リクエスト送信前に呼ばれるメソッド。リクエストを編集したい時に使える
  func prepare(_ request: URLRequest, target: TargetType) -> URLRequest {

    if let moyaCachableProtocol = target as? MoyaCacheable {
      var cachableRequest = request

    ///カスタムのキャッシュポリシーを設定
      cachableRequest.cachePolicy = moyaCachableProtocol.cachePolicy
      return cachableRequest
    }
    return request
  }
}
Hoge.swift
//Hogeクラスをプロバイダに設定
let hogeProvider = MoyaProvider<Hoge>(plugins: [MoyaCacheablePlugin()])

extension Hoge: MoyaCacheable {
  var cachePolicy: MoyaCacheablePolicy {

      //採用したいキャッシュポリシーの定義
      return .reloadIgnoringLocalAndRemoteCacheData
    }
  }
}

あとは、hogeProviderを用いてリクエストを送れば、Hogeクラス内で設定したキャッシュポリシーが使われる。

参考:Make your Moya cacheable

設定の中身

cachePolicy 説明
useProtocolCachePolicy (デフォルト)特定のURLロード要求に対して、プロトコル実装で定義されているキャッシング・ロジックがあればそれを使用します。 HTTPまたはHTTPSの場合、RFC2616というロジックを使います。
reloadIgnoringLocalCacheData ローカルに保存されたキャッシュデータを無視して取得します。
reloadIgnoringLocalAndRemoteCacheData ローカルのキャッシュデータに加え、ネットワーク途中のプロキシなども含めてキャッシュを無視して取得します。iOS13以降より有効
returnCacheDataElseLoad キャッシュデータがあれば、その有効期限などは考慮せずキャッシュを使います。なければ、取得します。
returnCacheDataDontLoad キャッシュデータがあれば、その有効期限などは考慮せずキャッシュを使います。なければ、失敗になります。
reloadRevalidatingCacheData HEADリクエストを発行し更新を確認します、更新があればリクエストを発行します。

参考:【Swift 4.0】 APIでキャッシュを無視してリクエストする方法

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Kerasで作成した回帰モデルをCoreML上で使用するまで

はじめに

iOSの機械学習フレームワークCoreMLではKerasで訓練済みの機械学習モデルを利用することができます。
本記事ではKerasによる回帰モデルをCoreML上で動くように変換し、実際に予測を行うまでの流れについて解説します。

大まかな流れとしては以下のようになります。

  • 1: Kerasで回帰モデルを作成/学習し、.h5ファイルとして出力する
  • 2: coremltoolsを用いて出力した.h5ファイルを.mlmodelファイルに変換する
  • 3: iOSのCoreML上で回帰モデルとして使用する

本記事における実行環境

  • Python: 3.7.7
  • Keras: 2.3.1
  • Swift: 5
  • iOS: 13.5
  • Xcode: 11.5

1: 回帰モデルを.h5ファイルとして出力

https://www.tensorflow.org/tutorials/keras/regression
今回は上記チュートリアルに基づいて自動車の燃費を予測する回帰モデルを作成し、.h5ファイルとして出力します。

ただし、チュートリアルのコードをそのまま実行してできたモデルをCoreMLで使用できる形式に変換しようとするとエラーが発生します。KerasをTensorflow経由でimportしていることが関係しているようです。
そのためKerasを直接importする形に書き直して実行します。下記コードをご参照ください。

from __future__ import absolute_import, division, print_function, unicode_literals

import pathlib
import pandas as pd

import keras
from keras.models import Sequential
from keras.layers import Dense
from keras import optimizers

dataset_path = keras.utils.get_file("auto-mpg.data", "https://archive.ics.uci.edu/ml/machine-learning-databases/auto-mpg/auto-mpg.data")

column_names = ['MPG','Cylinders','Displacement','Horsepower','Weight',
                'Acceleration', 'Model Year', 'Origin'] 
raw_dataset = pd.read_csv(dataset_path, names=column_names,
                      na_values = "?", comment='\t',
                      sep=" ", skipinitialspace=True)
dataset = raw_dataset.copy()

dataset = dataset.dropna()
origin = dataset.pop('Origin')
dataset['USA'] = (origin == 1)*1.0
dataset['Europe'] = (origin == 2)*1.0
dataset['Japan'] = (origin == 3)*1.0

train_dataset = dataset.sample(frac=0.8,random_state=0)
test_dataset = dataset.drop(train_dataset.index)

train_stats = train_dataset.describe()
train_stats.pop("MPG")
train_stats = train_stats.transpose()

train_labels = train_dataset.pop('MPG')
test_labels = test_dataset.pop('MPG')

def norm(x):
  return (x - train_stats['mean']) / train_stats['std']
normed_train_data = norm(train_dataset)
normed_test_data = norm(test_dataset)

def build_model():
  model = Sequential([
    Dense(64, activation='relu', input_shape=[len(train_dataset.keys())]),
    Dense(64, activation='relu'),
    Dense(1)
  ])
  optimizer = optimizers.RMSprop(0.001)
  model.compile(loss='mse',
                optimizer=optimizer,
                metrics=['mae', 'mse'])
  return model

model = build_model()

class PrintDot(keras.callbacks.Callback):
  def on_epoch_end(self, epoch, logs):
    if epoch % 100 == 0: print('')
    print('.', end='')

EPOCHS = 1000

history = model.fit(
  normed_train_data, train_labels,
  epochs=EPOCHS, validation_split = 0.2, verbose=0,
  callbacks=[PrintDot()])

# これでモデルを.h5ファイルに出力します。
model.save("SampleReg.h5")

2: .h5ファイルを.mlmodelファイルに変換

先ほど作成した.h5ファイルをCoreMLで扱える.mlmodelファイルに変換します。
まずは変換に必要なcoremltoolsをPythonにインストールします。
$ pip install -U coremltools
また、TensorflowやKerasが手元のPython環境にインストールされていない場合は改めてインストールしておいてください。

インストールが完了したら、下記のコードを実行することで.h5ファイルを.mlmodelファイルに変換することができます。

import coremltools

coreml_model = coremltools.converters.keras.convert('SampleReg.h5')
coreml_model.save('SampleRegonCoreML.mlmodel')

3: CoreMLでモデルを使う

Xcodeを起動しiOSプロジェクトを新規に作成し、ファイル一覧に先ほど作成した.mlmodelファイルを追加します。
この.mlmodelファイルをクリックすると、以下の図のようにモデルの概要が表示されます。

スクリーンショット 2020-07-12 13.15.48.png

入力(Inputs)として9つの変数を取り、出力(Outputs)として1つの変数を出すモデルであることが確認できます。
MultiArrayというのはMLMultiArrayというCoreMLのクラスを指すようで、これはモデルの入出力を扱うための多次元配列のクラスになります。形状(Shape)やデータ型を指定して配列を作ることができます。

それではこのモデルを使って実際に予測を行います。下記のコードをご参照ください。

import CoreML

// .mlmodelファイルを追加した時点でモデルと同じ名前のクラスが自動的に生成され、
// さらにそれらの入力データ/出力データを扱うクラスも作られます(名前は「モデル名+Input/Output」)。
let model = SampleRegonCoreML()

// MLMultiArrayはこのように配列形状とデータ型を指定して初期化することができます。
// let inputArray = try! MLMultiArray(shape: [9], dataType: MLMultiArrayDataType.double)
// 一方で従来の配列から直接作ることもできます。今回は元のデータセットから抜き出した1データについて直打ちしてみました。
let inputArray = try! MLMultiArray([1.483887,1.578444,2.890853,1.925289,-0.559020,-1.604642,0.774676,-0.465148,-0.495225])
// 上の配列を用意したモデルの入力としてあてがいます。
let inputToModel: SampleRegonCoreMLInput = try! SampleRegonCoreMLInput(input1: inputArray)
// 予測を行い、その結果を出力します。
if let prediction = try? model.prediction(input: inputToModel) {
    print(prediction.output1)
}

Keras側で同データについてmodel.predict()した結果と、上記コードによって出力される結果が一致することを確認します。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む