- 投稿日:2020-07-02T22:41:52+09:00
小数部に残された末尾のゼロを除去する、カウントする
private void button_Click(object sender, EventArgs e) { // 除去する Debug.WriteLine(truncate_trailing_zeros(1040000.00M)); // -> 1040000 Debug.WriteLine(truncate_trailing_zeros(1050000.00M)); // -> 1050000 Debug.WriteLine(truncate_trailing_zeros(10.0000400M)); // -> 10.00004 Debug.WriteLine(truncate_trailing_zeros(10.0000500M)); // -> 10.00005 // カウントする Debug.WriteLine(count_trailing_zeros(0.4400M)); // -> 2 Debug.WriteLine(count_trailing_zeros(1.0000M)); // -> 4 Debug.WriteLine(count_trailing_zeros(1.0001M)); // -> 0 Debug.WriteLine(count_trailing_zeros(100.00M)); // -> 2 } public static decimal truncate_trailing_zeros(decimal value) { return value / 1.0000000000000000000000000000M; } public static int count_trailing_zeros(decimal value) { return (decimal.GetBits(Math.Abs(value))[3] >> 16 & 0x0FF) - (decimal.GetBits(truncate_trailing_zeros(value))[3] >> 16 & 0x0FF); /*var decimal_part = decimal.GetBits(Math.Abs(value))[3] >> 16 & 0x0FF; var last = -1; for (int i = 0; i <= decimal_part; i++) { var sample = (decimal)Math.Pow(10, -i) * (decimal)Math.Pow(10, i); var current = decimal.GetBits(value / sample)[3] >> 16 & 0x0FF; if(last == current) { return i - 1; } last = current; } return decimal_part;*/ }
- 投稿日:2020-07-02T21:25:48+09:00
Unityの新しいDIライブラリ:VContainer (0.0.2対応修正 7/4)
VContainer is 何?
タイトルの通りです。現在Unityで使えるDIライブラリにはZenject/Extenjectがありますが、それとは別の選択肢としてVContainerが作られています。なんでもZenject/Extenjectは多機能で便利なのですが、もっとシンプルな薄いDIライブラリを目指されているのだとか。作者はハダシA氏です。
https://github.com/hadashiA/VContainer
現在、開発中なのですが、0.0.1がリリースされたので早速触って見ました。
0.0.2が出ました(7/4)。InjectとIInitialize関係が更新されました。まずはZenject/Extenjectで作る
IPerson.csnamespace ZenjectSayHello { public interface IPerson { string Name { get; } } }Parent.csnamespace ZenjectSayHello { public class Parent : IPerson { public string Name => "親御"; } }SayHello.csusing UnityEngine; namespace ZenjectSayHello { public class SayHello { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } } }SayHelloInstaller.csusing Zenject; namespace ZenjectSayHello { public class SayHelloInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<IPerson>().To<Parent>().AsSingle(); Container.Bind<SayHello>().AsSingle(); } } }SayHelloMonoBehaviour.csusing UnityEngine; using Zenject; namespace ZenjectSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] private SayHello _sayHello = default; } }SayHelloMonoBehaviourは適当なGameObjectにアタッチします。SayHelloがResolveされるときに、コンストラクタのIPersonにParentが放り込まれ、
と出ます。こいつをVContainerで書いてみます。VContainerで書く
インストール
まずインストール方法ですが、上記Githubリンクのリリースページにunitypackageがありますので、それをダウンロード、インストールするだけでOKです。
インストーラーを作る
最初から手で書いてもいいのですが、テンプレートを自動生成してくれます。Projectの右クリックからCreate > C# Script。で、ファイル名をXXXInstallerとすれば、Installerのテンプレートを作ってくれます。
LifetimeScopeを作る
Zenject/ExtenjectのSceneContext等にあたるものがLifetimeScopeになります。作り方はHierarchyの右クリックでVContainer > LifetimeScope。で、InspectorのMonoInstallerの+ボタンをクリックすると、さっき作ったSayHellowInstallerが出てきます。指定したInstallerはLifetimeScopeGameObjectにアタッチされます。
コード書く
コードを書いていきます。
IPerson.csnamespace VContainerSayHello { public interface IPerson { string Name { get; } } }Parent.csnamespace VContainerSayHello { public class Parent : IPerson { public string Name => "親御"; } }SayHello.csusing UnityEngine; namespace VContainerSayHello { public class SayHello { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } } }ここまではさっきと同じです。
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] public void Construct(SayHello sayHello) { } } }MonoBehaviourです。エディター上で適当なGameObjectを作って、それにアタッチします。サンプルではメソッドインジェクションがありましたので、そちらにしました。
SayHelloInstaller.csusing UnityEngine; using VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { [SerializeField] private SayHelloMonoBehaviour sayHello = default; public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); builder.RegisterComponent(sayHello); } } }キモとなる部分です。書き加えたのはInstallメソッド内の3行とsayHelloフィールド。
builder.Register<IPerson, Parent>(Lifetime.Singleton);
builder.Register<SayHello>(Lifetime.Singleton);この2行は、ParentとSayHelloをZenject/ExtenjectでいうところのBindします。
[SerializeField] private SayHelloMonoBehaviour sayHello = default;
builder.RegisterComponent(sayHello);
その次の行とsayHelloのインスタンスです。この解説の前に、まずInjectの挙動について解説します。
[Inject]の挙動
Zenject/ExtenjectだとMonoBehaviourにInjectを書いておけば、どこでもInjectしてくれました。VContainerはエディター上でGameObjectを作ってHierarchyに存在してるだけではInjectを発動してくれません。
VContainerでは、Injectは原則的にResolveするときに発火します。例えばなんらかのクラスのコンストラクタ引数になっててそこに放り込まれる時とか、IInitializableが実装されててそれが走る時とか。
DIはコンストラクタでのインジェクションが原則だと言われます。コンストラクタインジェクションはResolveされる時以外はなんらInjectされないので、それとタイミングを合わせていると考えれば納得です。[Inject]を発火させる方法
ですんで、IInitializableをSayHelloMonoBehaviourに実装してAsを使って発火するか、適当なコンストラクタにぶち込むか、なんですが(7/4追記に転記)、もっと簡単なやり方があります。それが上述の
builder.RegisterComponent(sayHello);
です。これでsayHelloインスタンスをInjectしてくれます。
※0.0.2で実装されました。0.0.1でのやり方は下の方に残しておきます。
動作
Instantiateとかはどうなんの?
試しにPrefabをInstantiateしてみましたが、Injectは発火しません。PlaceholderFactoryもありません(少なくとも現在は)。DiContainer.Injectのようなものもないようです。つまり自前でFactoryを作って、必要な依存をそこで解決しましょう。
所感
[Inject]の使い方にちょっと混乱しましたが、使えそうです。この辺りのZenject/Extenjectとの違いは軽量化のためでしょうか。
一つ興味深いのはZenject/ExtenjectにあるFactory関係の実装予定はないそうで。まぁ確かにあれはPlaceholderFactory作ってそれをSpawnerで包んで、なんか手間だなぁ、と感じたり。いまいち使いこなせてない感がありました。ですんで、多機能よりも軽量化に注力するのは大歓迎です。今後に期待です。追記(7/2)
すみません。同じProjectにあったZenjectと競合してました。名前空間を貫通してくるとは思いませんでした。IInitialize関係がこちらの追記にあったのですが、上の方にスクリプト修正の上で転記しました。
追記(7/3)
ハダシAさんに質問した所、Zenject/Extenjectのような一方的なInjectは想定しておらず、Resolveが必要とのご回答をいただきました。Zenject/Extenjectのように使っていたInjectを上述のとおり修正いたしました。
追記(7/4)
0.0.2でRegisterComponentが実装されました。この記事をみて速攻で実装してくれました。熱い&感謝です。
IInitializableを使ってResolveする方法をこちらに残しておきます。以下のようなやり方は現在不要です。ただ、基本的には以下のようにしてInjectを発火させるんだ、と思っておいた方がVContainerを扱いやすくなると思います。
ちなみにAsとやっていますが、0.0.2でbuilder.RegisterEntryPoint<Foo>(..);
が実装され、IInitializableとかITickableをまとめてやってくれるようになってます。
SayHelloMonoBehaviourにIInitializable等を実装
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour, IInitializable { [Inject] public void Construct(SayHello sayHello) { } public void Initialize() { } } }SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); builder.RegisterComponentInHierarchy<SayHelloMonoBehaviour>().As<IInitializable>(); //HierarchyにあるSayHelloMonoBehaviourのInitializeを発火。Resolveされる。 } } }IInitializableをMonoBehaviourに実装してAsで発火します。
何かのコンストラクタでResolveさせる
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] public void Construct(SayHello sayHello) { } } }SayHelloMonoBehaviourInjector.csusing VContainer.Unity; namespace VContainerSayHello { public class SayHelloMonoBehaviourInjector : IInitializable { public SayHelloMonoBehaviourInjector(SayHelloMonoBehaviour sayHelloMonoBehaviour) { } public void Initialize() { } } }SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { [SerializeField] private SayHelloMonoBehaviour sayHello = default; public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); builder.RegisterInstance(sayHello); builder.Register<SayHelloMonoBehaviourInjector>(Lifetime.Singleton).As<IInitializable>(); //SayHelloMonoBehaviourInjectorがInitializeの発火でResolveされる。 //その際、コンストラクタ引数にSayHelloMonoBehaviourがあるのでsayHelloインスタンスがResolveされる。 //builder.RegisterEntryPoint<SayHelloMonoBehaviourInjector>(Lifetime.Singleton); //で代用可能。 } } }RegisterInstanceで該当のMonoBehaviourをRegisterして、適当なコンストラクタにぶち込みます。そのときResolveされます。
IInitializableをRegisterEntryPointやAsすることで、Zenject/ExtenjectのNonLazy的に扱えます。
- 投稿日:2020-07-02T21:25:48+09:00
Unityの新しいDIライブラリ:VContainer
VContainer is 何?
タイトルの通りです。現在Unityで使えるDIライブラリにはZenject/Extenjectがありますが、それとは別の選択肢としてVContainerが作られています。なんでもZenject/Extenjectは多機能で便利なのですが、もっとシンプルな薄いDIライブラリを目指されているのだとか。作者はハダシA氏です。
https://github.com/hadashiA/VContainer
現在、開発中なのですが、0.0.1がリリースされたので早速触って見ました。まずはZenject/Extenjectで作る
IPerson.csnamespace ZenjectSayHello { public interface IPerson { string Name { get; } } }Parent.csnamespace ZenjectSayHello { public class Parent : IPerson { public string Name => "親御"; } }SayHello.csusing UnityEngine; namespace ZenjectSayHello { public class SayHello { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } } }SayHelloInstaller.csusing Zenject; namespace ZenjectSayHello { public class SayHelloInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<IPerson>().To<Parent>().AsSingle(); Container.Bind<SayHello>().AsSingle(); } } }SayHelloMonoBehaviour.csusing UnityEngine; using Zenject; namespace ZenjectSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] private SayHello _sayHello = default; } }SayHelloMonoBehaviourは適当なGameObjectにアタッチします。
SayHelloがResolveされるときに、コンストラクタのIPersonにParentが放り込まれ、
と出ます。こいつをVContainerで書いてみます。VContainerで書く
インストール
まずインストール方法ですが、上記Githubリンクのリリースページにunitypackageがありますので、それをダウンロード、インストールするだけでOKです。
インストーラーを作る
最初から手で書いてもいいのですが、テンプレートを自動生成してくれます。Projectの右クリックからCreate > C# Script。で、ファイル名をXXXInstallerとすれば、Installerのテンプレートを作ってくれます。
LifetimeScopeを作る
Zenject/ExtenjectのSceneContext等にあたるものがLifetimeScopeになります。作り方はHierarchyの右クリックでVContainer > LifetimeScope。で、InspectorのMonoInstallerの+ボタンをクリックすると、さっき作ったSayHellowInstallerが出てきます。指定したInstallerはLifetimeScopeGameObjectにアタッチされます。
コード書く
あとはガリガリ書くだけです。
IPerson.csnamespace VContainerSayHello { public interface IPerson { string Name { get; } } }Parent.csnamespace VContainerSayHello { public class Parent : IPerson { public string Name => "親御"; } }SayHello.csusing UnityEngine; namespace VContainerSayHello { public class SayHello { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } } }ここまではさっきと同じです。
SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); } } }キモとなる部分です。実際に書いたのはInstallメソッド内の2行です。Interfaceの紐付けがこんな感じなんですねぇ。
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] public void Construct(SayHello sayHello) { } } }やはり適当なGameObjectにアタッチします。メソッドインジェクションがサンプルに載ってたので、とりあえずこっちにしました。
動作
所感
使い心地はZenject/Extenjectとあまり変わらない感じですね。一つ興味深いのはZenject/ExtenjectにあるFactory関係の実装予定はないそうで。まぁ確かにあれはPlaceholderFactory作ってそれをSpawnerで包んで、なんか手間だなぁ、と感じたり。いまいち使いこなせてない感がありました。ですんで、多機能よりも軽量化に注力するのは大歓迎です。今後に期待です。
追記(7/2)
すみません。同じProjectにあったZenjectと競合してました。あの子、名前空間も貫通してくるんやな。どうもメソッドインジェクションがうまく動いていない様子。どこか読み忘れてたかな。
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { private SayHello _sayHello = default; [Inject] public void Construct(SayHello sayHello) { _sayHello = sayHello; } private void Start() { Debug.Log(_sayHello == null); //Trueを出す } } }SayHelloにIInitialize(とかITickableとか)を実装すれば、とりあえずコンストラクタは走ります。
SayHello.csusing UnityEngine; using VContainer.Unity; namespace VContainerSayHello { public class SayHello : IInitializable { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } public void Initialize() { } } }SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton).As<IInitializable>(); //Initializeを実装するときはこう書く。 } } }
- 投稿日:2020-07-02T21:25:48+09:00
Unityの新しいDIライブラリ:VContainer (7/3修正)
VContainer is 何?
タイトルの通りです。現在Unityで使えるDIライブラリにはZenject/Extenjectがありますが、それとは別の選択肢としてVContainerが作られています。なんでもZenject/Extenjectは多機能で便利なのですが、もっとシンプルな薄いDIライブラリを目指されているのだとか。作者はハダシA氏です。
https://github.com/hadashiA/VContainer
現在、開発中なのですが、0.0.1がリリースされたので早速触って見ました。まずはZenject/Extenjectで作る
IPerson.csnamespace ZenjectSayHello { public interface IPerson { string Name { get; } } }Parent.csnamespace ZenjectSayHello { public class Parent : IPerson { public string Name => "親御"; } }SayHello.csusing UnityEngine; namespace ZenjectSayHello { public class SayHello { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } } }SayHelloInstaller.csusing Zenject; namespace ZenjectSayHello { public class SayHelloInstaller : MonoInstaller { public override void InstallBindings() { Container.Bind<IPerson>().To<Parent>().AsSingle(); Container.Bind<SayHello>().AsSingle(); } } }SayHelloMonoBehaviour.csusing UnityEngine; using Zenject; namespace ZenjectSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] private SayHello _sayHello = default; } }SayHelloMonoBehaviourは適当なGameObjectにアタッチします。
SayHelloがResolveされるときに、コンストラクタのIPersonにParentが放り込まれ、
と出ます。こいつをVContainerで書いてみます。VContainerで書く
インストール
まずインストール方法ですが、上記Githubリンクのリリースページにunitypackageがありますので、それをダウンロード、インストールするだけでOKです。
インストーラーを作る
最初から手で書いてもいいのですが、テンプレートを自動生成してくれます。Projectの右クリックからCreate > C# Script。で、ファイル名をXXXInstallerとすれば、Installerのテンプレートを作ってくれます。
LifetimeScopeを作る
Zenject/ExtenjectのSceneContext等にあたるものがLifetimeScopeになります。作り方はHierarchyの右クリックでVContainer > LifetimeScope。で、InspectorのMonoInstallerの+ボタンをクリックすると、さっき作ったSayHellowInstallerが出てきます。指定したInstallerはLifetimeScopeGameObjectにアタッチされます。
コード書く
コードを書いていきます。
IPerson.csnamespace VContainerSayHello { public interface IPerson { string Name { get; } } }Parent.csnamespace VContainerSayHello { public class Parent : IPerson { public string Name => "親御"; } }SayHello.csusing UnityEngine; namespace VContainerSayHello { public class SayHello { public SayHello(IPerson person) { Debug.Log($"{person.Name}さんによろしく!"); } } }ここまではさっきと同じです。
Injectの扱い
SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); } } }とりあえずInstallerをこう書きます。実際に書いたのはInstallメソッド内の2行です。
次は、MonoBehaviourです。Zenject/ExtenjectだとMonoBehaviourにInjectを書いておけば、どこでもInjectしてくれました。VContainerはただHierarchyに存在してるだけではInjectを発動してくれません。
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] private SayHello _sayHello; //Injectされない [Inject] public void Construct(SayHello sayHello) { //呼ばれない } } }例えば、エディター上で適当なGameObjectを作って、上述のSayHelloMonoBehaviour.csをアタッチ。再生ボタンを押したとき、Extenject/ZenjectはInjectしてくれますが、VContainerはやってくれません。
Injectの発動条件ですが、Resolveする必要があります。例えば
SayHelloMonoBehaviourにIInitializable等を実装
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour, IInitializable { [Inject] public void Construct(SayHello sayHello) { } public void Initialize() { } } }SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); builder.RegisterComponentInHierarchy<SayHelloMonoBehaviour>().As<IInitializable>(); //HierarchyにあるSayHelloMonoBehaviourのInitializeを発火。Resolveされる。 } } }IInitializableをMonoBehaviourに実装してAsで発火します。
何かのコンストラクタでResolveさせる
SayHelloMonoBehaviour.csusing UnityEngine; using VContainer; namespace VContainerSayHello { public class SayHelloMonoBehaviour : MonoBehaviour { [Inject] public void Construct(SayHello sayHello) { } } }SayHelloMonoBehaviourInjector.csusing VContainer.Unity; namespace VContainerSayHello { public class SayHelloMonoBehaviourInjector : IInitializable { public SayHelloMonoBehaviourInjector(SayHelloMonoBehaviour sayHelloMonoBehaviour) { } public void Initialize() { } } }SayHelloInstaller.csusing VContainer; using VContainer.Unity; namespace VContainerSayHello { public sealed class SayHelloInstaller : MonoInstaller { [SerializeField] private SayHelloMonoBehaviour sayHello = default; public override void Install(IContainerBuilder builder) { builder.Register<IPerson, Parent>(Lifetime.Singleton); builder.Register<SayHello>(Lifetime.Singleton); builder.RegisterInstance(sayHello); builder.Register<SayHelloMonoBehaviourInjector>(Lifetime.Singleton).As<IInitializable>(); //SayHelloMonoBehaviourInjectorがInitializeの発火でResolveされる。 //その際、コンストラクタ引数にSayHelloMonoBehaviourがあるのでsayHelloインスタンスがResolveされる。 } } }RegisterInstanceで該当のMonoBehaviourをRegisterして、適当なコンストラクタにぶち込みます。そのときResolveされます。
IInitializableをAsすることで、Zenject/ExtenjectのNonLazy的に扱えます。Instantiateとかはどうなんの?
試しにPrefabをInstantiateしてみましたが、Injectは発火しません。PlaceholderFactoryもありません(少なくとも現在は)。DiContainer.Injectのようなものもないようです。つまり自前でFactoryを作って、必要な依存をそこで解決しましょう。
動作
所感
[Inject]の使い方にちょっと混乱しましたが、使えそうです。この辺りのZenject/Extenjectとの違いは軽量化のためでしょうか。
一つ興味深いのはZenject/ExtenjectにあるFactory関係の実装予定はないそうで。まぁ確かにあれはPlaceholderFactory作ってそれをSpawnerで包んで、なんか手間だなぁ、と感じたり。いまいち使いこなせてない感がありました。ですんで、多機能よりも軽量化に注力するのは大歓迎です。今後に期待です。追記(7/2)
すみません。同じProjectにあったZenjectと競合してました。名前空間を貫通してくるとは思いませんでした。IInitialize関係がこちらの追記にあったのですが、上の方にスクリプト修正の上で転記しました。
追記(7/3)
ハダシAさんに質問した所、Zenject/Extenjectのような一方的なInjectは想定しておらず、Resolveが必要とのご回答をいただきました。Zenject/Extenjectのように使っていたInjectを上述のとおり修正いたしました。
- 投稿日:2020-07-02T21:23:55+09:00
Unity Technologies製推論エンジン Barracudaがスゴイという話
概要
2020年5月12日のML-Agents正式版公開に伴い、
ML-Agentsで利用されている推論エンジンのBarracudaが正式公開されたのでテストした所
導入および実施がありえない程簡単だったので記事にしました実施内容
以前実施した画像分類モデルに加え、画風変換モデルをテストしました。
1.画像分類
空間内に配置した写真をUnityのカメラで撮影し、画像分類モデルで判定を行いました
結果は次のようになりました
convertible(オープンカー)
見た限り、正しく分類できていそうです。使用したモデルは次の通りです
画像分類 モデル名 VGG-19 入力 224×224×3 出力 1000 データセット ImageNet (ILSVRCA2012) 2.画風変換
画像分類同様、空間内に配置した写真をUnityのカメラで撮影し、画風変換モデルを適用したものを表示しました
画風変換 モデル名 Fast Neural Style Transfer 入力 224×224×3 出力 224×224×3 データセット COCO 2014 Training images dataset 上で示した通り、Unity上で学習済みモデルを推論できることが分かりました。
次から実施方法について解説します。導入方法
1. PackageMangerを開き、Barracudaをインストールします。
2. スクリプトを作成し、Unity.Barracudaをインポートします。
3. NNModelをPublic変数で定義します
using UnityEngine; using UnityEngine.UI; using Unity.Barracuda; // <- 2. public class Classification : MonoBehaviour { // Barracuda 推論用 public NNModel modelAsset; // <- 3. private Model m_RuntimeModel; private IWorker m_worker;4. 適当なオブジェクトにスクリプトを追加し、InspectorからONNXファイル(学習済みモデル)をアタッチします。
5. モデルをロードし、推論を実行するワーカーを作成します
void Start() { m_RuntimeModel = ModelLoader.Load(modelAsset); m_worker = WorkerFactory.CreateWorker(WorkerFactory.Type.Compute, m_RuntimeModel); }CPU・GPUの使用はここで決定します。
Workerのタイプ6. ProjectタブからRenderTextureを作成します
7. Hierarchyからカメラを作成し、出力先を先ほど作成したRenderTextureにします
8. 作成したRenderTextureをスクリプトにアタッチし、次のようなコードで推論を実行します
Tensor input = new Tensor(targetTexture); m_worker.Execute(input); Tensor output = m_worker.PeekOutput();入力はRenderTextureから直接作成できます!!
以前実施した際には前処理が色々面倒だったのでここだけでも使う価値があると思います。9. 出力は次のような形で取り出せます
output.ToReadOnlyArray(); //floatの配列で取得する output.ToRenderTexture(outputTexture, 0, 0, 1/255f, 0, null); //RenderTextureに直接出力※Tensor及びworkerは処理が終了したタイミングで破棄する必要があります
private void Update() { Tensor input = new Tensor(inputTexture); Inference(input); input.Dispose(); //処理が終わったタイミングで破棄 } private void OnDestroy() { m_worker.Dispose(); //終了時に破棄する }まとめ
今回のポイント
- 入力が簡単
- モデルをUnity上で管理できる
- RenderTextureに直接出力できる
さすが公式の実装だけあって以前と比べてかなり簡単に実施できるようになっていました。
Unityはスマートフォンアプリへの出力にも対応しているので、ARアプリの作成等にも使っていけそうです。リンク
- 投稿日:2020-07-02T20:12:22+09:00
EntityFrameworkを使ってDBモデルの作成(超簡易)
はじめに
EntityFrameworkを使えば、GUI操作で簡単にDBモデルが作れる。(簡単に言うとデータベースにアクセスするやつ)「CnnectionStringBuilder」っていうDBに接続するやつを使うより楽だし遥かに汎用性があって使いやすい気がする。
この記事では開発環境の構築を行っていること前提で説明を進めていくので、DB作ったりテーブル作ったりとか事前準備の手順なんて記述してない。
ちなみにEntityFrameworkとかいまだなんなのか理解してないしネットに転がってる記事難しすぎるから、簡単な操作だけ抜粋して資料っぽく説明付けていつでも思い出せるようにこの記事を作る。
※これは【超簡易】なのでスクショだらけです
環境
・VS2019
・.NetFramework 4.7.2
・SQLServer 15.0.2000.5
・EF6(Nugetからインストールするだけ)DBモデル作成
環境構築の説明はめんどくさいので割愛して、さっそく操作説明に入ります。
①プロジェクト作成
適当にプロジェクトを作る。(画像ではコンソールアプリケーションのプロジェクト)
ソリューションエクスプローラから以下の操作をする。
・「追加」→「新しい項目」
②ADO.NET Entity Data Model選択
環境整えてるならあるはず。選択して名前決めたら「追加」を押下。
③モデルのコンテンツ選択
どうやってDBのモデルを作るか選ぶ。
「データベースからEF Designer」ってやつを選択して「次へ」を押下。
④データ接続の選択
接続するDBを選択する。(モデルを作りたいDBを選ぶ)
「新しい接続」を選択すると接続プロパティが表示される。以下を入力して「テスト接続」をクリック。
・データソース(画像の状態がデフォルト)
・サーバ名
・認証
・データベース名の選択または入力
※Windows認証の場合はこのまま進めるが、SQLServer認証の場合はユーザ名とパスワードを事前に確認しておいたほうがいい(セキュリティの設定とかも)
テスト接続が成功すると以下の画面が表示される。
テスト接続成功後、データ接続の選択画面に戻って「次へ」を押下。⑤データベースオブジェクトと設定の選択
DBモデルとして作成したいテーブル名の横にあるチェックボックスにチェックを付ける。
「生成されたオブジェクトの名前を複数化または単数化する」と「モデルに外部キー列を含める」にもチェック。
最後に「モデル名前空間」を命名して「完了」を押下。
これでDBモデルが完成する。⑥DBモデル完成
おわり
- 投稿日:2020-07-02T18:33:04+09:00
n桁の有効数字に丸める
private void button_Click(object sender, EventArgs e) { Debug.WriteLine(calc_significant_figures(1040000.00M, 2, 0)); // -> 1000000 Debug.WriteLine(calc_significant_figures(1050000.00M, 2, 0)); // -> 1100000 Debug.WriteLine(calc_significant_figures(10.0000400M, 6, 0)); // -> 10.0000 Debug.WriteLine(calc_significant_figures(10.0000500M, 6, 0)); // -> 10.0001 Debug.WriteLine(calc_significant_figures(1050000.00M, 2, 1)); // -> 1000000 Debug.WriteLine(calc_significant_figures(10.0000500M, 6, 1)); // -> 10.0000 Debug.WriteLine(calc_significant_figures(1040000.00M, 2, 2)); // -> 1100000 Debug.WriteLine(calc_significant_figures(10.0000400M, 6, 2)); // -> 10.0001 } static decimal calc_significant_figures(decimal value, int digits, int type) { if (value == 0M) { return 0M; } var integer_part = (int)Math.Log10(Math.Abs((int)value)) + 1; //var decimal_part = decimal.GetBits(value)[3] >> 16 & 0x0FF; switch (type) { case 0: { var scale = (decimal)Math.Pow(10, integer_part); var result = scale * Math.Round(value / scale, digits, MidpointRounding.AwayFromZero); //return Math.Round(result, decimal_part); var decimals = digits - integer_part; return Math.Round(result, (decimals < 0) ? 0 : decimals); } case 1: { var scale = (decimal)Math.Pow(10, integer_part - digits); return scale * Math.Floor(value / scale); } case 2: { var scale = (decimal)Math.Pow(10, integer_part - digits); return scale * Math.Ceiling(value / scale); } } throw new Exception("error: calc_significant_figures"); }
- 投稿日:2020-07-02T18:07:19+09:00
ASP.NET Coreのローカリゼーション周りのメモ
ASP.NET Coreのローカリゼーション周りのメモ
ASP.NET Core のローカリゼーション回りのソースを読んだのでメモ
調べたバージョンはASP.NET Core 3.1
IStringLocalizer
,IStringLocalizerFactory
あたりは今回は触れません。
ここではミドルウェア周りについて触れます使い方
詳細はこちら に書いているので
ここではさらっと触れるのみとします。startup.cspublic class Startup { public void ConfigureServices(IServiceCollection services) { //省略... //ローカリゼーション周りのクラスをDIコンテナに登録する。 //.resxファイルはResourcesフォルダに配置するのでResourcesPathを変更 services.AddLocalization(options => options.ResourcesPath = "Resources"); } public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //省略... //ミドルウェアの登録及び、オプションの設定 app.UseRequestLocalization(options => { //サポートするカルチャの設定 string[] supportedCultures = new string[] {"ja", "en"}; options .AddSupportedCultures(supportedCultures) .AddSupportedUICultures(supportedCultures) .SetDefaultCulture(supportedCultures[0]) ; }); //省略... } }あとは利用側で
IStringLocalizer<T>
をインジェクションし、T
に相当するクラス及びResources/T.ja.resx
,Resources/T.en.resx
を用意すればよいです。
RequestLocalizationMiddleware
クラスApplicationBuilderExtensionsクラスの
UseRequestLocalization
メソッドを実行する事で登録されます。
RequestLocalizationMiddleware
クラスのソースはこちら
HttpContext
から カルチャーに関する情報を取得し SetCurrentThreadCultureメソッドでCultureInfo.CurrentCulture
,CultureInfo.CurrentUICulture
にセットしています。カルチャーに関する情報はデフォルトでは
- クエリストリング
- Cookie
Accept-Language
リクエストヘッダーの順序で解決が行われます。
これらの内容はRequestLocalizationOptions
で設定を行います。
RequestLocalizationOptions
クラスソースはこちら
上記の
RequestLocalizationMiddleware
でカルチャの解決に使用するオプションを定義しています。これらのプロパティについて紹介します。
RequestCultureProviders
プロパティ
HttpContext
からカルチャの解決を行っているものの正体です。デフォルトでは
- QueryStringRequestCultureProvider
- CookieRequestCultureProvider
- AcceptLanguageHeaderRequestCultureProvider
の3つがListの要素に設定されています。
解決に用いるキーの名前はインスタンスプロパティとして定義されているので変更することができます。
(例CookieRequestCultureProvider
のCookie名が.AspNetCore.Culture
という値でありASP.NET Core
を使用している事を外部に公開していることになるので、この名前を変更したい という要望に対応することができます。 )この
RequestCultureProviders
プロパティを変更することで、解決の順序を変更することや、新しいカルチャ解決の方法を追加することも可能です
(例.HttpContext
が渡されているのでClaim
から解決することもおそらく可能ではないかと思います。)新しいカルチャ解決の方法を実装する際はRequestCultureProviderを継承
もしくはCustomRequestCultureProvider
に直接ラムダ式を記述すれば可能です。AddInitialRequestCultureProvider拡張メソッドを呼ぶことで、先頭に追加することも可能です。
SupportedCultures
,SupportedUICultures
,DefaultRequestCulture
プロパティサポートしているカルチャの一覧です。
DefaultRequestCulture
はカルチャが解決できなかった時に使用されるデフォルトのカルチャです。プロパティに直接セットすることも可能ですが
AddSupportedCultures
,AddSupportedUICultures
,SetDefaultCulture
メソッドを呼ぶことでもセット可能です。
(Add
という名前で始まっていますがソースを見た感じ総入れ替えが行われているように見える..?)
FallBackToParentCultures
,FallBackToParentUICultures
プロパティカルチャが見つからなかったときにフォールバックするか?の設定のようです。
例えば
-SupportedCultures
がja
- リクエストから解決したカルチャがja-JP
のときに
ja
を使うといったことが可能なようです。
RequestLocalizationMiddleware
クラスのGetCultureInfo
メソッドあたりで使われています。終わりに
今回はカルチャの解決方法について注目してソースを確認しました。
次は利用する側(
IStringLocalizer
,IStringLocalizerFactory
) について見てみようと思います。
- 投稿日:2020-07-02T12:50:07+09:00
【Unity】「1 exception was raised by workers」 の直し方
どうもマカロンです。
ここではUntiyで「1 exception was raised by workers」というエラーが出てしまった人たちを助けるために私がnoteの方で書かせていただいた記事を紹介させていただきます。
Unity エラー「1 exception was raised by workers」との死闘
【完全版】続・Unity エラー「1 exception was raised by workers」との死闘
全5項目紹介していますので、エラーが出てしまっている人はぜひ確認してみてください!!
- 投稿日:2020-07-02T10:44:48+09:00
【Unity】簡単にSceneをまたいだ値の受け渡し
初めに
Scene間での値の受け渡しに関してはまだ様々なところでこっちの方がいい、あっちの方がいいなど議論されています、ですのでどれが正解なのかは各個人によって決まります。
今回はいくつかの方法をお伝えできればと思います。目次
- DontDestroyOnLoad
- PlayerPrefs
- 静的クラスまたは静的変数
DontDestroyOnLoad
UnityにはDontDestroyOnLoadという関数があります、この関数はObjectをSceneをまたいでも引き継がれるObjectにするための関数です。
このDontDestroyOnLoadなObjectに値を渡すことで次のSceneでも値を引き継ぐことができます。サンプルコード
//値を保存用 public int Score { set; get;} void Start() { //↓これを呼び出せばDontDestroyObjectにできます DontDestroyOnLoad(gameObject); }実行結果
PlayerPrefs
PlayerPrefsに関しては過去にまとめた記事がありますのでこちらを参照してください。
サンプルコード
値を保存
void Update() { if (Input.GetKeyDown(KeyCode.A)) { PlayerPrefs.SetInt("Score",int.Parse(GetComponent<InputField>().text)); SceneManager.LoadScene("2"); } }値を呼び出す
void Start() { GetComponent<Text>().text = PlayerPrefs.GetInt("Score").ToString(); }実行結果
静的クラスまたは静的変数
静的クラスなどはゲーム開始時に最初にメモリ領域を確保してゲーム終了までそのメモリ領域を解放しませんので値が常に保持されているということができます。
サンプルコード
値保存用クラス
public static class Test { public static int Score { set; get;} }値を入れる
void Update() { if (Input.GetKeyDown(KeyCode.A)) { Test.Score=int.Parse(GetComponent<InputField>().text); SceneManager.LoadScene("2"); } }値を呼び出す
void Start() { GetComponent<Text>().text = Test.Score.ToString(); }実行結果
まとめ
実行結果が少しわかりずらいのでなくてもよかったかな?って感じる…
ぶっちゃけScene間の値のやり取りって難しいですよね、今回記事にした内容以外にもいくつかやり方ありますし、そもそもScene遷移しないという選択肢もあるわけで…
とりあえず色々試して自分に一番合うものをお探しください!
- 投稿日:2020-07-02T10:44:48+09:00
【Unity】Sceneをまたいだ値の受け渡し方
初めに
Scene間での値の受け渡しに関してはまだ様々なところでこっちの方がいい、あっちの方がいいなど議論されています、ですのでどれが正解なのかは各個人によって決まります。
今回はいくつかの方法をお伝えできればと思います。目次
- DontDestroyOnLoad
- PlayerPrefs
- 静的クラスまたは静的変数
DontDestroyOnLoad
UnityにはDontDestroyOnLoadという関数があります、この関数はObjectをSceneをまたいでも引き継がれるObjectにするための関数です。
このDontDestroyOnLoadなObjectに値を渡すことで次のSceneでも値を引き継ぐことができます。サンプルコード
//値を保存用 public int Score { set; get;} void Start() { //↓これを呼び出せばDontDestroyObjectにできます DontDestroyOnLoad(gameObject); }実行結果
PlayerPrefs
PlayerPrefsに関しては過去にまとめた記事がありますのでこちらを参照してください。
サンプルコード
値を保存
void Update() { if (Input.GetKeyDown(KeyCode.A)) { PlayerPrefs.SetInt("Score",int.Parse(GetComponent<InputField>().text)); SceneManager.LoadScene("2"); } }値を呼び出す
void Start() { GetComponent<Text>().text = PlayerPrefs.GetInt("Score").ToString(); }実行結果
静的クラスまたは静的変数
静的クラスなどはゲーム開始時に最初にメモリ領域を確保してゲーム終了までそのメモリ領域を解放しませんので値が常に保持されているということができます。
サンプルコード
値保存用クラス
public static class Test { public static int Score { set; get;} }値を入れる
void Update() { if (Input.GetKeyDown(KeyCode.A)) { Test.Score=int.Parse(GetComponent<InputField>().text); SceneManager.LoadScene("2"); } }値を呼び出す
void Start() { GetComponent<Text>().text = Test.Score.ToString(); }実行結果
まとめ
実行結果が少しわかりずらいのでなくてもよかったかな?って感じる…
ぶっちゃけScene間の値のやり取りって難しいですよね、今回記事にした内容以外にもいくつかやり方ありますし、そもそもScene遷移しないという選択肢もあるわけで…
とりあえず色々試して自分に一番合うものをお探しください!