Nncase studio (#1125)

* update

* fix csproj

* tmp commit

* refactor finish

* fix build

* update

* update

* update

* add ShapeBucketView

* update

* fix cancel and simulate time

* update font family and progress bar

* fix build

* fix

* Apply code-format changes

* move file location

* fix

* update page switch logic

* resolve feedback

* close DBus

* update

* add some comment

* update

* fix build

* update

* update

* Apply code-format changes

* add CustomValidation

* add validate

* add some validate

* Apply code-format changes

* resolve review

* fix msg box

* add CompileConfig

* fix config export and import

* Apply code-format changes

* update preprocess

* Apply code-format changes

* add publish and upload for nncase-studio

* change artifacts name

* fix

---------

Co-authored-by: FusionBolt <FusionBolt@users.noreply.github.com>
pull/1143/head
FusionBolt 2023-11-24 14:34:12 +08:00 committed by GitHub
parent bfa9c4da98
commit b3d8ae9beb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
94 changed files with 4801 additions and 0 deletions

View File

@ -114,6 +114,7 @@ jobs:
dotnet restore -r ${{matrix.config.rid}}
dotnet build -c ${{matrix.config.buildType}} --no-restore
dotnet publish src/Nncase.Compiler -c ${{matrix.config.buildType}} --no-restore --sc false -r ${{matrix.config.rid}}
dotnet publish src/Nncase.Studio -c ${{matrix.config.buildType}} --no-restore --sc false -r ${{matrix.config.rid}}
- name: Set up Dotnet Test settings
uses: 1arp/create-a-file-action@0.2

View File

@ -12,6 +12,14 @@
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageVersion Include="Avalonia" Version="11.0.2"/>
<PackageVersion Include="Avalonia.Desktop" Version="11.0.2"/>
<PackageVersion Include="Avalonia.Themes.Fluent" Version="11.0.2"/>
<PackageVersion Include="Avalonia.Fonts.Inter" Version="11.0.2"/>
<PackageVersion Include="Avalonia.ReactiveUI" Version="11.0.2"/>
<PackageVersion Include="MessageBox.Avalonia" Version="3.1.2" />
<PackageVersion Include="CommunityToolkit.Mvvm" Version="8.2.1" />
<PackageVersion Include="Google.OrTools" Version="9.4.1874" />
<PackageVersion Include="AnyTensorFlow.NET" Version="0.70.1" />
<PackageVersion Include="BitFields" Version="0.1.0" />
@ -46,6 +54,7 @@
<PackageVersion Include="NetFabric.Hyperlinq" Version="3.0.0-beta48" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
<PackageVersion Include="Nncase.FlatBuffers" Version="2.0.0" />
<PackageVersion Include="NumSharp" Version="0.30.0" />
<PackageVersion Include="OrtKISharp" Version="0.0.2" />
<PackageVersion Include="RazorLight" Version="2.3.0" />
<PackageVersion Include="Singulink.Collections.Weak" Version="1.0.2" />

View File

@ -77,6 +77,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nncase.Tests.TestFixture",
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Nncase.Passes", "src\Nncase.Passes\Nncase.Passes.csproj", "{E6462E82-B48F-4AFA-AE34-725EF0A9CB42}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Nncase.Studio", "src\Nncase.Studio\Nncase.Studio.csproj", "{B9A09DA2-EF1A-4C0E-A0F5-427AFBB5C769}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -171,6 +173,10 @@ Global
{E6462E82-B48F-4AFA-AE34-725EF0A9CB42}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E6462E82-B48F-4AFA-AE34-725EF0A9CB42}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E6462E82-B48F-4AFA-AE34-725EF0A9CB42}.Release|Any CPU.Build.0 = Release|Any CPU
{B9A09DA2-EF1A-4C0E-A0F5-427AFBB5C769}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B9A09DA2-EF1A-4C0E-A0F5-427AFBB5C769}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B9A09DA2-EF1A-4C0E-A0F5-427AFBB5C769}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B9A09DA2-EF1A-4C0E-A0F5-427AFBB5C769}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -201,6 +207,7 @@ Global
{E365B1B1-4D13-4839-9763-A7A7C5F32FD4} = {BCA74168-F015-4B5B-B4CD-C83AE06B9822}
{98A03405-CA53-4EC4-9B18-94D1C8DF9453} = {E5A4516C-4080-4346-991D-57A7AA76ADA6}
{E6462E82-B48F-4AFA-AE34-725EF0A9CB42} = {BCA74168-F015-4B5B-B4CD-C83AE06B9822}
{B9A09DA2-EF1A-4C0E-A0F5-427AFBB5C769} = {BCA74168-F015-4B5B-B4CD-C83AE06B9822}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9492E141-292E-4D60-9C6E-3738AB234DB2}

View File

@ -244,6 +244,25 @@ internal class Compiler : ICompiler
});
}
public async Task CompileWithReportAsync(IProgress<int> progress, CancellationToken token)
{
CancellationTokenSource cts = new();
var internalToken = cts.Token;
using (var linkedCts = CancellationTokenSource.CreateLinkedTokenSource(internalToken, token))
{
try
{
var task = Task.Run(CompileAsync, linkedCts.Token);
Report(progress, 9, linkedCts.Token);
await task.WaitAsync(linkedCts.Token);
}
catch (Exception)
{
return;
}
}
}
public async Task CompileAsync()
{
var target = _compileSession.Target;
@ -278,6 +297,14 @@ internal class Compiler : ICompiler
linkedModel.Serialize(output);
}
private void Report(IProgress<int> progress, int maxPassCount, CancellationToken token)
{
while (_runPassCount < maxPassCount && !token.IsCancellationRequested)
{
progress?.Report(_runPassCount);
}
}
private async Task<IRModule> InitializeModuleAsync(IRModule module)
{
_module = module;

View File

@ -49,6 +49,11 @@ public interface ICompiler
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
Task CompileAsync();
/// <summary>
/// Compile module with report pass number.
/// </summary>
Task CompileWithReportAsync(IProgress<int> progress, CancellationToken token);
/// <summary>
/// Generate code to stream.
/// </summary>

View File

@ -153,6 +153,11 @@ public class QuantizeOptions
/// </summary>
public bool ExportQuantScheme { get; set; }
/// <summary>
/// Gets or sets quantize scheme path.
/// </summary>
public string ExportQuantSchemePath { get; set; } = string.Empty;
/// <summary>
/// Gets or sets a value indicating whether export weight range by channel.
/// </summary>

View File

@ -0,0 +1,27 @@
<Application xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Class="Nncase.Studio.App"
xmlns:local="using:Nncase.Studio"
RequestedThemeVariant="Default">
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
<Application.DataTemplates>
<local:ViewLocator/>
</Application.DataTemplates>
<Application.Styles>
<FluentTheme />
<StyleInclude Source="Style/ButtonStyle.axaml"></StyleInclude>
<StyleInclude Source="Style/CustomValidation.axaml"></StyleInclude>
<StyleInclude Source="Style/Logo.axaml"></StyleInclude>
<StyleInclude Source="Style/GridStyle.axaml"></StyleInclude>
<Style Selector="TextBox.contentMessage">
<Setter Property="FontSize" Value="30"></Setter>
</Style>
</Application.Styles>
<Application.Resources>
<!-- <FontFamily x:Key="NunitoFont">Assets\Fonts\Nunito-Black.ttf</FontFamily> -->
</Application.Resources>
</Application>

View File

@ -0,0 +1,28 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Nncase.Studio.ViewModels;
using Nncase.Studio.Views;
namespace Nncase.Studio;
public partial class App : Application
{
public override void Initialize()
{
AvaloniaXamlLoader.Load(this);
}
public override void OnFrameworkInitializationCompleted()
{
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
{
desktop.MainWindow = new MainWindow { DataContext = new MainWindowViewModel(), };
}
base.OnFrameworkInitializationCompleted();
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,40 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Globalization;
using System.Linq;
using Avalonia.Data;
using Avalonia.Data.Converters;
using DynamicData;
using NetFabric.Hyperlinq;
namespace Nncase.Studio;
public class EnumConverter : IValueConverter
{
// enum to selected index
public object? Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
{
if (value == null)
{
return -1;
}
var index = Enum.GetNames(value.GetType()).IndexOf(value.ToString());
return index;
}
// to enum
public object? ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
{
// to enum or to other
if (value == null || (int)value < 0)
{
return Activator.CreateInstance(targetType);
}
var values = Enum.GetNames(targetType)[(int)value];
return Enum.Parse(targetType, values);
}
}

View File

@ -0,0 +1,57 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable>
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
<ApplicationManifest>app.manifest</ApplicationManifest>
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
</PropertyGroup>
<ItemGroup>
<Folder Include="Models\"/>
<AvaloniaResource Include="Assets\**"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia"/>
<PackageReference Include="Avalonia.Desktop"/>
<PackageReference Include="Avalonia.Themes.Fluent"/>
<PackageReference Include="Avalonia.Fonts.Inter"/>
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
<!-- <PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics"/>-->
<PackageReference Include="Avalonia.ReactiveUI"/>
<PackageReference Include="CommunityToolkit.Mvvm"/>
<PackageReference Include="NumSharp" />
<PackageReference Include="MessageBox.Avalonia"/>
<ProjectReference Include="..\Nncase.Compiler\Nncase.Compiler.csproj" />
<ProjectReference Include="..\Nncase.CodeGen\Nncase.CodeGen.csproj" />
<ProjectReference Include="..\Nncase.Core\Nncase.Core.csproj" />
<ProjectReference Include="..\Nncase.Diagnostics\Nncase.Diagnostics.csproj" />
<ProjectReference Include="..\Nncase.Graph\Nncase.Graph.csproj" />
<ProjectReference Include="..\Nncase.EGraph\Nncase.EGraph.csproj" />
<ProjectReference Include="..\Nncase.Evaluator\Nncase.Evaluator.csproj" />
<ProjectReference Include="..\Nncase.Importer\Nncase.Importer.csproj" />
<ProjectReference Include="..\Nncase.Simulator\Nncase.Simulator.csproj" />
<ProjectReference Include="..\Nncase.Quantization\Nncase.Quantization.csproj" />
<ProjectReference Include="..\Nncase.Passes\Nncase.Passes.csproj" />
<ProjectReference Include="..\..\modules\Nncase.Modules.StackVM\Nncase.Modules.StackVM.csproj" />
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Style\EnumComboBox.axaml" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\NotoSansTC-VariableFont_wght.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\OFL.txt" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\README.txt" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-Black.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-Bold.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-ExtraBold.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-ExtraLight.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-Light.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-Medium.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-Regular.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-SemiBold.ttf" />
<UpToDateCheckInput Remove="Assets\Fonts\Noto_Sans_TC\static\NotoSansTC-Thin.ttf" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,31 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia;
using Avalonia.Media;
using Avalonia.Media.Fonts;
using Avalonia.ReactiveUI;
namespace Nncase.Studio;
internal class Program
{
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.
[STAThread]
public static void Main(string[] args) => BuildAvaloniaApp()
.StartWithClassicDesktopLifetime(args);
// Avalonia configuration, don't remove; also used by visual designer.
public static AppBuilder BuildAvaloniaApp()
=> AppBuilder.Configure<App>()
.UsePlatformDetect()
.UseNncaseFontManager()
.ConfigureCompiler()
.LogToTrace()
.UseReactiveUI()
.DisableDBus();
}

View File

@ -0,0 +1,23 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<Style Selector="Button">
<Setter Property="Margin" Value="10"></Setter>
<Setter Property="MinWidth" Value="100"></Setter>
<Setter Property="CornerRadius" Value="45"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
</Style>
<Style Selector="Button#ImportButton">
<Setter Property="CornerRadius" Value="45"></Setter>
<Setter Property="Width" Value="200"></Setter>
<Setter Property="HorizontalContentAlignment" Value="Center"></Setter>
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
</Style>
<!-- Add Styles Here -->
</Styles>

View File

@ -0,0 +1,49 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<Style Selector="DataValidationErrors">
<Setter Property="Template">
<ControlTemplate>
<DockPanel LastChildFill="True">
<ContentControl DockPanel.Dock="Right"
ContentTemplate="{TemplateBinding ErrorTemplate}"
DataContext="{TemplateBinding Owner}"
Content="{Binding (DataValidationErrors.Errors)}"
IsVisible="{Binding (DataValidationErrors.HasErrors)}"/>
<ContentPresenter Name="PART_ContentPresenter"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="{TemplateBinding CornerRadius}"
ContentTemplate="{TemplateBinding ContentTemplate}"
Content="{TemplateBinding Content}"
Padding="{TemplateBinding Padding}"/>
</DockPanel>
</ControlTemplate>
</Setter>
<Setter Property="ErrorTemplate">
<DataTemplate>
<Canvas Width="14" Height="14" Margin="4 0 1 0"
Background="Transparent">
<Canvas.Styles>
<Style Selector="ToolTip">
<Setter Property="Background" Value="LightCoral"/>
<Setter Property="BorderBrush" Value="Red"/>
</Style>
</Canvas.Styles>
<ToolTip.Tip>
<!-- <ItemsControl Items="{Binding}"/> -->
</ToolTip.Tip>
<Path Data="M14,7 A7,7 0 0,0 0,7 M0,7 A7,7 0 1,0 14,7 M7,3l0,5 M7,9l0,2"
Stroke="Red"
StrokeThickness="2"/>
</Canvas>
</DataTemplate>
</Setter>
</Style>
</Styles>

View File

@ -0,0 +1,43 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<!-- simulate view -->
<Style Selector="Grid TextBox">
<Setter Property="Margin" Value="15"></Setter>
<Setter Property="VerticalContentAlignment" Value="Center"></Setter>
<Setter Property="Width" Value="240"></Setter>
</Style>
<Style Selector="Grid NumericUpDown">
<Setter Property="Margin" Value="15"></Setter>
</Style>
<Style Selector="TextBox.Path">
<Setter Property="Margin" Value="15"></Setter>
<Setter Property="Width" Value="760"></Setter>
<Setter Property="MaxWidth" Value="760"></Setter>
<Setter Property="HorizontalAlignment" Value="Left"></Setter>
</Style>
<Style Selector="Grid Label">
<Setter Property="Margin" Value="15"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
<Style Selector="Grid Button">
<Setter Property="HorizontalAlignment" Value="Center"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
<Style Selector="Grid ComboBox">
<Setter Property="Margin" Value="15"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
<Style Selector="Grid CheckBox">
<Setter Property="Margin" Value="15"></Setter>
<Setter Property="VerticalAlignment" Value="Center"></Setter>
</Style>
</Styles>

View File

@ -0,0 +1,15 @@
<Styles xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Design.PreviewWith>
<Border Padding="20">
<!-- Add Controls for Previewer Here -->
</Border>
</Design.PreviewWith>
<!-- Import Logo -->
<Style Selector="DockPanel#LogoPanel > Image">
<Setter Property="Margin" Value="40 80"></Setter>
<Setter Property="Width" Value="128"></Setter>
<Setter Property="Height" Value="128"></Setter>
</Style>
</Styles>

View File

@ -0,0 +1,47 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Diagnostics.CodeAnalysis;
using Avalonia;
using Avalonia.Media;
using Avalonia.Media.Fonts;
using Microsoft.Extensions.Hosting;
namespace Nncase.Studio;
public static class AvaloniaAppBuilderExtensions
{
public static AppBuilder UseNncaseFontManager(this AppBuilder builder, Action<FontSettings>? configDelegate = default)
{
var setting = new FontSettings();
configDelegate?.Invoke(setting);
return builder.With(new FontManagerOptions
{
DefaultFamilyName = setting.DefaultFontFamily,
FontFallbacks = new[]
{
new FontFallback
{
FontFamily = new FontFamily(setting.DefaultFontFamily),
},
},
}).ConfigureFonts(manager => manager.AddFontCollection(new EmbeddedFontCollection(setting.Key, setting.Source)));
}
public static AppBuilder ConfigureCompiler(this AppBuilder builder)
{
var host = Host.CreateDefaultBuilder()
.ConfigureCompiler()
.Build();
CompilerServices.Configure(host.Services);
return builder;
}
public static AppBuilder DisableDBus(this AppBuilder builder)
{
// https://github.com/AvaloniaUI/Avalonia/issues/9383#issuecomment-1378350456
return builder.With(new X11PlatformOptions() { UseDBusFilePicker = false });
}
}

View File

@ -0,0 +1,13 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using MsBox.Avalonia;
namespace Nncase.Studio.Util;
public class AvaloniaUserDialog
{
public void ShowDialog(string message) =>
MessageBoxManager
.GetMessageBoxStandard("Notification", message).ShowAsync();
}

View File

@ -0,0 +1,54 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Runtime.InteropServices.JavaScript;
using Nncase.Diagnostics;
using Nncase.Studio.ViewModels;
namespace Nncase.Studio.Util;
public class CompileConfig
{
public CompileConfig()
{
var dumpDir = Path.Join(Directory.GetCurrentDirectory(), "nncase_dump");
CompileOption.DumpDir = dumpDir;
CompileOption.InputFile = string.Empty;
KmodelPath = Path.Join(dumpDir, "test.kmodel");
ResultDir = dumpDir;
CompileOption.InputLayout = "NCHW";
CompileOption.OutputLayout = "NCHW";
CompileOption.ModelLayout = "NCHW";
CompileOption.InputShape = new[] { 1, 3, 24, 24 };
CompileOption.InputRange = new float[] { -1, 1 };
CompileOption.Mean = new[] { 0f };
CompileOption.Std = new[] { 0f };
CompileOption.LetterBoxValue = 0f;
}
public CompileOptions CompileOption { get; set; } = new();
public bool MixQuantize { get; set; }
public bool UseQuantize { get; set; }
public PreprocessMode PreprocessMode { get; set; }
public DumpFlags[] DumpFlags { get; set; } = Array.Empty<DumpFlags>();
public string Target { get; set; } = "cpu";
public string KmodelPath { get; set; }
public string ResultDir { get; set; }
public string[] InputPathList { get; set; } = Array.Empty<string>();
public bool EnableShapeBucket
{
get { return CompileOption.ShapeBucketOptions.Enable; }
set { CompileOption.ShapeBucketOptions.Enable = value; }
}
}

View File

@ -0,0 +1,113 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using Avalonia.Platform.Storage;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nncase.IR;
using Nncase.Quantization;
using Nncase.Studio.Views;
using NumSharp;
using ReactiveUI;
namespace Nncase.Studio.ViewModels;
public static class DataUtil
{
public static string TensorTypeToString(TensorType tt)
{
return $"{tt.DType} {tt.Shape}";
}
public static string VarToString(Var var)
{
var tt = (TensorType)var.TypeAnnotation;
return $"{var.Name} {TensorTypeToString(tt)}";
}
public static (string[] InputFiles, Tensor[] InputList) ReadMultiInputs(List<string> path)
{
var inputFiles = path.Count == 1 && Directory.Exists(path[0])
? Directory.GetFiles(path[0])
: path.ToArray();
var input = ReadInput(inputFiles).ToArray();
return (inputFiles, input);
}
public static List<Tensor> ReadInput(string[] file)
{
return file
.Where(f => Path.GetExtension(f) == ".npy")
.Select(f =>
{
var tensor = np.load(f);
return Tensor.FromBytes(new TensorType(DataType.FromType(tensor.dtype), tensor.shape), tensor.ToByteArray());
}).ToList();
}
public static DataType QuantTypeToDataType(QuantType qt)
{
return qt switch
{
QuantType.Uint8 => DataTypes.UInt8,
QuantType.Int8 => DataTypes.Int8,
QuantType.Int16 => DataTypes.Int16,
_ => throw new ArgumentOutOfRangeException(nameof(qt), qt, null),
};
}
public static bool TryParseFixVarMap(string input, out Dictionary<string, int> map)
{
map = new();
if (input == string.Empty)
{
return false;
}
try
{
map = input.Trim().Split(",").Select(x => x.Trim().Split(":")).ToDictionary(x => x[0], x => int.Parse(x[1]));
return true;
}
catch (Exception)
{
return false;
}
}
public static bool TryParseRangeInfo(string input, out Dictionary<string, (int Min, int Max)> map)
{
map = new();
if (input == string.Empty)
{
return false;
}
try
{
map = input.Trim()
.Split(";")
.Select(x => x.Trim().Split(":"))
.ToDictionary(x => x[0], x =>
{
var pair = x[1].Split(",");
return (int.Parse(pair[0]), int.Parse(pair[1]));
});
return true;
}
catch (Exception)
{
return false;
}
}
}

View File

@ -0,0 +1,15 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
namespace Nncase.Studio;
public class FontSettings
{
public string DefaultFontFamily { get; set; } = "fonts:CustomFontFamilies#Nunito";
public Uri Key { get; set; } = new Uri("fonts:CustomFontFamilies", UriKind.Absolute);
public Uri Source { get; set; } = new Uri("avares://Nncase.Studio/Assets/Fonts/Nunito", UriKind.Absolute);
}

View File

@ -0,0 +1,53 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia.Platform.Storage;
namespace Nncase.Studio;
public static class PickerOptions
{
public static FilePickerOpenOptions DataPickerOptions => new FilePickerOpenOptions
{
Title = "Select Input File",
AllowMultiple = true,
FileTypeFilter = new FilePickerFileType[] { new("npy") { Patterns = new[] { "*.npy" } } },
};
public static FilePickerOpenOptions JsonPickerOptions => new FilePickerOpenOptions
{
Title = "Select Json File",
AllowMultiple = true,
FileTypeFilter = new FilePickerFileType[] { new("json") { Patterns = new[] { "*.json" } } },
};
public static FilePickerOpenOptions KmodelPickerOptions => new FilePickerOpenOptions
{
Title = "Select Kmodel",
AllowMultiple = true,
FileTypeFilter = new FilePickerFileType[] { new("kmodel") { Patterns = new[] { "*.kmodel" } } },
};
public static FilePickerOpenOptions ImporterPickerOptions => new FilePickerOpenOptions
{
Title = "Open Model File",
AllowMultiple = false,
FileTypeFilter = new FilePickerFileType[]
{
new("model") { Patterns = new[] { "*.tflite", "*.onnx", "*.ncnn" } },
},
};
public static FilePickerSaveOptions CompileConfPickerSaveOptions => new FilePickerSaveOptions
{
Title = "Save Conf",
SuggestedFileName = "config.json",
ShowOverwritePrompt = true,
};
public static FolderPickerOpenOptions FolderPickerOpenOptions => new FolderPickerOpenOptions()
{
Title = "Select Folder",
AllowMultiple = false,
};
}

View File

@ -0,0 +1,211 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using Nncase.Studio.ViewModels;
namespace Nncase.Studio;
public static class CustomValidator
{
public static bool ValidateViewModel<T>(T obj, out ICollection<ValidationResult> results)
{
results = new List<ValidationResult>();
return Validator.TryValidateObject(obj!, new ValidationContext(obj!), results, true);
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class ValidFloatAttribute : ValidationAttribute
{
public ValidFloatAttribute()
{
}
public override bool IsValid(object? value)
{
if (value == null)
{
return false;
}
// value
return float.TryParse((string)value, out var _);
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class ValidFloatArrayAttribute : ValidationAttribute
{
public ValidFloatArrayAttribute()
{
}
public override bool IsValid(object? value)
{
if (value == null)
{
return false;
}
if (value.GetType() != typeof(string))
{
return false;
}
var s = (string)value;
if (s.Contains(",", StringComparison.Ordinal))
{
var list = s.Split(",");
return list.All(s => float.TryParse(s, out var _));
}
else
{
return float.TryParse(s, out var _);
}
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class ValidIntArrayAttribute : ValidationAttribute
{
public ValidIntArrayAttribute()
{
}
public override bool IsValid(object? value)
{
if (value == null)
{
return false;
}
if (value.GetType() != typeof(string))
{
return false;
}
var s = (string)value;
if (s.Contains(",", StringComparison.Ordinal))
{
var list = s.Split(",");
return list.All(s => int.TryParse(s, out var _));
}
else
{
return int.TryParse(s, out var _);
}
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class ValidLayoutAttribute : ValidationAttribute
{
public ValidLayoutAttribute()
{
}
public override bool IsValid(object? value)
{
if (value == null)
{
return false;
}
var s = (string)value;
if (s.All(c => "NCHW".Contains(c, StringComparison.Ordinal)))
{
return !HasRepeat(s);
}
if (TryParseNumberList(s, out var numbers))
{
return !HasRepeat(s) && IsSeqNumber(numbers);
}
return false;
}
private static bool HasRepeat(string s)
{
var distinct = s.Distinct().ToHashSet();
if (distinct.Count != s.Length)
{
return true;
}
return false;
}
private static bool TryParseNumberList(string s, out int[] numbers)
{
if (s.Contains(",", StringComparison.Ordinal))
{
var charArray = s.Split(",").Select(s => s[0]).ToArray();
return IsNumberList(charArray, out numbers);
}
else
{
return IsNumberList(s.ToCharArray(), out numbers);
}
}
private static bool IsNumberList(char[] s, out int[] numbers)
{
if (s.Any(c => !int.TryParse(c.ToString(), out var _)))
{
numbers = Array.Empty<int>();
return false;
}
numbers = s.Select(c => int.Parse(c.ToString())).ToArray();
return true;
}
private static bool IsSeqNumber(int[] seq)
{
for (int i = 0; i < seq.Length; i++)
{
if (seq[i] != i)
{
return false;
}
}
return true;
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class ValidBucketVarMapAttribute : ValidationAttribute
{
public ValidBucketVarMapAttribute()
{
}
public override bool IsValid(object? value)
{
var input = (string)value!;
return DataUtil.TryParseFixVarMap(input, out var _);
}
}
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
internal sealed class ValidBucketRangeInfoAttribute : ValidationAttribute
{
public ValidBucketRangeInfoAttribute()
{
}
public override bool IsValid(object? value)
{
var input = (string)value!;
return DataUtil.TryParseRangeInfo(input, out var _);
}
}

View File

@ -0,0 +1,95 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive.Linq;
using System.Threading.Tasks;
using Avalonia.Platform.Storage;
using Nncase.IR;
using Nncase.Quantization;
using Nncase.Studio.Util;
using Nncase.Studio.ViewModels;
namespace Nncase.Studio;
public class ViewModelContext
{
private readonly MainWindowViewModel _mainWindowView;
public ViewModelContext(MainWindowViewModel windowViewModel)
{
_mainWindowView = windowViewModel;
}
public CompileConfig CompileConfig { get; set; } = new();
public bool CustomPreprocessMode => CompileConfig.PreprocessMode == PreprocessMode.Custom;
public NavigatorViewModel? Navigator { get; set; }
public ViewModelBase[] ViewModelBases { get; set; } = Array.Empty<ViewModelBase>();
public Function? Entry { get; set; }
public async Task<List<string>> OpenFile(FilePickerOpenOptions options)
{
return await _mainWindowView.ShowOpenFilePicker.Handle(options);
}
public async Task<string> SaveFile(FilePickerSaveOptions options)
{
return await _mainWindowView.ShowSaveFilePicker.Handle(options);
}
public async Task<string> OpenFolder(FolderPickerOpenOptions options)
{
return await _mainWindowView.ShowFolderPicker.Handle(options);
}
public void OpenDialog(string prompt, PromptDialogLevel level = PromptDialogLevel.Error)
{
_mainWindowView.ShowDialog(prompt, level);
}
public void SwitchToPage(Type page)
{
var viewModel = ViewModelLookup(page);
Navigator?.SwitchToPage(viewModel);
}
public void SwitchNext()
{
Navigator?.SwitchNext();
}
public ViewModelBase ViewModelLookup(Type type)
{
foreach (var viewModelBase in ViewModelBases)
{
if (viewModelBase.GetType() == type)
{
return viewModelBase;
}
}
throw new InvalidOperationException($"{type} Not Found");
}
public string[] CheckViewModel()
{
return Navigator!.ContentViewModelList.SelectMany(x => x.CheckViewModel()).ToArray();
}
public CompileConfig ExportConfig()
{
return CompileConfig;
}
public void ImportConfig(CompileConfig conf)
{
CompileConfig = conf;
}
}

View File

@ -0,0 +1,35 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using Avalonia.Controls;
using Avalonia.Controls.Templates;
using Nncase.Studio.ViewModels;
namespace Nncase.Studio;
public class ViewLocator : IDataTemplate
{
public Control Build(object? data)
{
if (data == null)
{
return new TextBlock { Text = "Not Found" };
}
var name = data!.GetType().FullName!.Replace("ViewModel", "View", StringComparison.Ordinal);
var type = Type.GetType(name);
if (type != null)
{
return (Control)Activator.CreateInstance(type)!;
}
return new TextBlock { Text = "Not Found: " + name };
}
public bool Match(object? data)
{
return data is ViewModelBase;
}
}

View File

@ -0,0 +1,128 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Google.OrTools.ConstraintSolver;
using Google.Protobuf.WellKnownTypes;
using NetFabric.Hyperlinq;
using Nncase.Diagnostics;
using Nncase.Quantization;
using Nncase.Studio.Util;
namespace Nncase.Studio.ViewModels;
public enum PreprocessMode
{
Custom,
}
public partial class CompileOptionViewModel : ViewModelBase
{
[Required]
[ObservableProperty]
private string _inputFile = string.Empty;
[ObservableProperty]
private string _dumpDir = string.Empty;
[ObservableProperty]
private bool _preprocess;
[ObservableProperty]
private bool _quantize = true;
[ObservableProperty]
private bool _shapeBucket;
[ObservableProperty]
private bool _mixQuantize = false;
[ObservableProperty]
private string _inputFormat = string.Empty;
[ObservableProperty]
private string _target;
[ObservableProperty]
private PreprocessMode _preprocessMode = PreprocessMode.Custom;
public CompileOptionViewModel(ViewModelContext context)
{
// skip None
DumpFlagsList = new ObservableCollection<DumpFlags>(System.Enum.GetValues<DumpFlags>().Skip(1).ToList());
TargetList = new ObservableCollection<string>(new[] { "cpu", "k230" });
_target = TargetList[0];
Context = context;
var list = new[] { PreprocessMode.Custom };
PreprocessModeList = new(list);
}
public ObservableCollection<DumpFlags> DumpFlagSelected { get; set; } = new();
public ObservableCollection<DumpFlags> DumpFlagsList { get; set; }
public ObservableCollection<string> TargetList { get; set; }
public ObservableCollection<PreprocessMode> PreprocessModeList { get; set; }
[RelayCommand]
public async Task SetDumpDir()
{
var folder = await Context.OpenFolder(PickerOptions.FolderPickerOpenOptions);
if (folder != string.Empty)
{
DumpDir = folder;
}
}
public override void UpdateViewModelCore(CompileConfig config)
{
InputFile = config.CompileOption.InputFile;
InputFormat = config.CompileOption.InputFormat;
DumpDir = config.CompileOption.DumpDir;
Target = config.Target;
Preprocess = config.CompileOption.PreProcess;
MixQuantize = config.MixQuantize;
ShapeBucket = config.EnableShapeBucket;
Quantize = config.UseQuantize;
PreprocessMode = config.PreprocessMode;
DumpFlagSelected = new(config.DumpFlags.ToArray());
}
public override void UpdateConfig(CompileConfig config)
{
config.CompileOption.DumpDir = DumpDir;
config.DumpFlags = DumpFlagSelected.ToArray();
config.CompileOption.DumpFlags = DumpFlagSelected.Aggregate(DumpFlags.None, (flag, sum) => flag | sum);
config.Target = Target;
config.CompileOption.PreProcess = Preprocess;
config.MixQuantize = MixQuantize;
config.EnableShapeBucket = ShapeBucket;
config.UseQuantize = Quantize;
config.PreprocessMode = PreprocessMode;
if (Quantize == false)
{
config.CompileOption.QuantizeOptions.ModelQuantMode = ModelQuantMode.NoQuant;
}
}
public override List<string> CheckViewModel()
{
var list = new List<string>();
if (DumpDir == string.Empty)
{
list.Add("DumpDir can't be empty");
}
return list;
}
}

View File

@ -0,0 +1,127 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nncase.IR;
using Nncase.Quantization;
using Nncase.Studio.Util;
using Nncase.Studio.Views;
using ReactiveUI;
namespace Nncase.Studio.ViewModels;
public partial class CompileViewModel : ViewModelBase
{
private CancellationTokenSource _cts = new();
[ObservableProperty]
private int _progressBarMax = 9;
[ObservableProperty]
private int _progressBarValue;
[ObservableProperty]
private string _kmodelPath = "test.kmodel";
public CompileViewModel(ViewModelContext context)
{
Context = context;
}
[RelayCommand]
public Task CancelCompile()
{
_cts.Cancel();
return Task.CompletedTask;
}
[RelayCommand]
public async Task Compile()
{
var info = Context.CheckViewModel();
if (info.Length != 0)
{
Context.OpenDialog($"Error List:\n{string.Join("\n", info)}");
return;
}
var conf = Context.CompileConfig;
var options = conf.CompileOption;
if (!Directory.Exists(options.DumpDir))
{
Directory.CreateDirectory(options.DumpDir);
}
ITarget target;
try
{
target = CompilerServices.GetTarget(conf.Target);
}
catch (Exception e)
{
Context.OpenDialog(e.Message, PromptDialogLevel.Error);
return;
}
var compileSession = CompileSession.Create(target, options);
var compiler = compileSession.Compiler;
var module = await compiler.ImportModuleAsync(options.InputFormat, options.InputFile, options.IsBenchmarkOnly);
Context.Entry = (Function)module.Entry!;
if (options.QuantizeOptions.ModelQuantMode != ModelQuantMode.NoQuant)
{
var calib = ((QuantizeViewModel)Context.ViewModelLookup(typeof(QuantizeViewModel))).LoadCalibFiles();
if (calib == null)
{
return;
}
options.QuantizeOptions.CalibrationDataset = calib;
}
_cts = new();
ProgressBarMax = 9;
var progress = new Progress<int>(percent =>
{
ProgressBarValue = percent;
});
try
{
await Task.Run(async () =>
{
await compiler.CompileWithReportAsync(progress, _cts.Token);
}).ContinueWith(_ => Task.CompletedTask, _cts.Token);
}
catch (Exception)
{
Context.OpenDialog("Compile has been cancel");
ProgressBarValue = 0;
return;
}
using (var os = File.OpenWrite(KmodelPath))
{
compiler.Gencode(os);
}
Context.SwitchNext();
Context.OpenDialog($"Compile Finish, kmodel in {KmodelPath}", PromptDialogLevel.Normal);
}
public override void UpdateConfig(CompileConfig config)
{
config.KmodelPath = KmodelPath;
}
public override void UpdateViewModelCore(CompileConfig config)
{
KmodelPath = config.KmodelPath;
}
}

View File

@ -0,0 +1,78 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using Nncase.Studio.Util;
namespace Nncase.Studio.ViewModels;
public partial class ImportViewModel : ViewModelBase
{
private string _inputFile = string.Empty;
private string _inputFormat = string.Empty;
public ImportViewModel(ViewModelContext context)
{
Context = context;
}
[RelayCommand]
public async Task Import()
{
var path = await Context.OpenFile(PickerOptions.ImporterPickerOptions);
if (path == null)
{
return;
}
if (path.Count == 0)
{
return;
}
var ext = Path.GetExtension(path[0]).Trim('.');
if (!new[] { "onnx", "tflite", "ncnn" }.Contains(ext))
{
Context.OpenDialog($"Not Support {ext}");
return;
}
_inputFormat = ext;
_inputFile = path[0];
Context.SwitchNext();
}
public override void UpdateViewModelCore(CompileConfig config)
{
_inputFile = config.CompileOption.InputFile;
_inputFormat = config.CompileOption.InputFormat;
}
public override void UpdateConfig(CompileConfig config)
{
config.CompileOption.InputFile = _inputFile;
config.CompileOption.InputFormat = _inputFormat;
}
public override List<string> CheckViewModel()
{
var list = new List<string>();
if (_inputFile == string.Empty)
{
list.Add("model path is empty");
}
else if (!File.Exists(_inputFile))
{
list.Add($"model path {_inputFile} Not Exist");
}
return list;
}
}

View File

@ -0,0 +1,125 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel.DataAnnotations;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Input;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using Avalonia.Rendering.Composition;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Microsoft.Extensions.Hosting;
using Newtonsoft.Json;
using Nncase.Diagnostics;
using Nncase.IR;
using Nncase.Passes.Mutators;
using Nncase.Quantization;
using Nncase.Runtime.Interop;
using Nncase.Studio.Util;
using Nncase.Studio.ViewModels;
using Nncase.Studio.Views;
using Nncase.Utilities;
using NumSharp;
using ReactiveUI;
using static Nncase.Studio.ViewModels.DataUtil;
namespace Nncase.Studio.ViewModels;
public enum PromptDialogLevel
{
Normal,
Error,
}
public partial class MainWindowViewModel : WindowViewModelBase
{
[ObservableProperty]
private string _title;
[ObservableProperty]
private ViewModelBase _contentViewModel;
public MainWindowViewModel()
{
Context = new ViewModelContext(this);
var studioModeViewModel = new StudioModeViewModel(Context);
var importViewModel = new ImportViewModel(Context);
var compileOptionViewModel = new CompileOptionViewModel(Context);
var preprocessViewModel = new PreprocessViewModel(Context);
var quantizeViewModel = new QuantizeViewModel(Context);
var shapeBucketViewModel = new ShapeBucketViewModel(Context);
var compileViewModel = new CompileViewModel(Context);
// var SimulateInputViewModel = new SimulateInputViewModel(Context);
var simulateViewModel = new SimulateViewModel(Context);
var contentViewModelList = new ObservableCollection<ViewModelBase>(
new ViewModelBase[]
{
studioModeViewModel,
importViewModel,
compileOptionViewModel,
preprocessViewModel,
quantizeViewModel,
shapeBucketViewModel,
compileViewModel,
simulateViewModel,
});
Title = string.Empty;
ContentViewModel = contentViewModelList.First();
Context.ViewModelBases = contentViewModelList.ToArray();
NavigatorViewModelValue = new NavigatorViewModel(contentViewModelList, ShowDialog, UpdateTitle);
Context.Navigator = NavigatorViewModelValue;
NavigatorViewModelValue.UpdateContentViewModel();
}
public Interaction<FilePickerOpenOptions, List<string>> ShowOpenFilePicker { get; } = new();
public Interaction<FilePickerSaveOptions, string> ShowSaveFilePicker { get; } = new();
public Interaction<FolderPickerOpenOptions, string> ShowFolderPicker { get; } = new();
public NavigatorViewModel NavigatorViewModelValue { get; set; }
protected ViewModelContext Context { get; set; }
[RelayCommand]
public async Task ExportStudioConfig()
{
NavigatorViewModelValue.ContentViewModel!.UpdateContext();
var quantScheme = Context.ExportConfig();
var json = JsonConvert.SerializeObject(quantScheme, Newtonsoft.Json.Formatting.Indented);
var path = await Context.SaveFile(PickerOptions.CompileConfPickerSaveOptions);
if (path == string.Empty)
{
return;
}
using var f = new StreamWriter(path);
await f.WriteAsync(json);
Context.OpenDialog($"export successful {path}");
}
public void UpdateTitle(ViewModelBase contenViewModel)
{
ContentViewModel = contenViewModel;
Title = ContentViewModel.GetType().Name.Split("ViewModel")[0];
}
public void ShowDialog(string prompt, PromptDialogLevel level = PromptDialogLevel.Error)
{
new AvaloniaUserDialog().ShowDialog(prompt);
}
}

View File

@ -0,0 +1,122 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MsBox.Avalonia;
namespace Nncase.Studio.ViewModels;
public partial class NavigatorViewModel : ViewModelBase
{
private readonly Action<ViewModelBase> _windowUpdater;
private readonly Action<string, PromptDialogLevel> _showDialog;
[ObservableProperty]
private ViewModelBase? _contentViewModel;
[ObservableProperty]
private int _pageIndex = 0;
[ObservableProperty]
private int _pageMaxIndex;
[ObservableProperty]
private bool _isLast;
[ObservableProperty]
private string _pageIndexString = string.Empty;
public NavigatorViewModel(ObservableCollection<ViewModelBase> content, Action<string, PromptDialogLevel> showDialog, Action<ViewModelBase> windowUpdater)
{
ContentViewModelList = content;
_windowUpdater = windowUpdater;
_showDialog = showDialog;
}
public ObservableCollection<ViewModelBase> ContentViewModelList { get; set; } = new();
public int PageCount => ContentViewModelList.Count;
public void SwitchToPage(ViewModelBase page)
{
UpdateContentViewModel(() =>
{
var index = ContentViewModelList.IndexOf(page);
PageIndex = index;
});
}
[RelayCommand]
public void SwitchPrev()
{
UpdateContentViewModel(() =>
{
do
{
PageIndex -= 1;
} while (!ContentViewModelList[PageIndex].IsVisible());
});
}
[RelayCommand]
public void SwitchNext()
{
var check = ContentViewModel!.CheckViewModel();
if (check.Count != 0)
{
_showDialog("Err:\n" + string.Join("\n", check), PromptDialogLevel.Error);
return;
}
UpdateContentViewModel(() =>
{
do
{
PageIndex += 1;
} while (!ContentViewModelList[PageIndex].IsVisible());
});
}
public void UpdateContentViewModel()
{
UpdateContentViewModel(() => { });
}
public void UpdateContentViewModel(Action updateIndex)
{
ContentViewModel?.UpdateContext();
updateIndex();
PageMaxIndex = ContentViewModelList.Count - 1;
ContentViewModel = ContentViewModelList[PageIndex];
ContentViewModel.UpdateViewModel();
_windowUpdater(ContentViewModel);
PageIndexString = $"{PageIndex + 1} / {PageCount}";
IsLast = PageIndex == PageMaxIndex;
}
public void InsertPageAfter(ViewModelBase page, ViewModelBase pagePosition, int offset = 0)
{
var i = ContentViewModelList.IndexOf(page);
if (i == -1)
{
var optionIndex = ContentViewModelList.IndexOf(pagePosition);
// insert after OptionView
ContentViewModelList.Insert(optionIndex + offset, page);
}
}
public void RemovePage(ViewModelBase page)
{
var i = ContentViewModelList.IndexOf(page);
if (i != -1)
{
ContentViewModelList.Remove(page);
}
}
}

View File

@ -0,0 +1,11 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using ReactiveUI;
namespace Nncase.Studio.ViewModels;
public class OptionViewModel : ViewModelBase
{
public string? OptName => "Name";
}

View File

@ -0,0 +1,146 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nncase.Studio.Util;
using Nncase.Studio.Views;
namespace Nncase.Studio.ViewModels;
public partial class PreprocessViewModel : ViewModelBase
{
[ObservableProperty]
[ValidIntArray]
private string _inputShape = string.Empty;
[ObservableProperty]
private InputType _inputTypeValue;
[ObservableProperty]
private string _inputTypeString = string.Empty;
public PreprocessViewModel(ViewModelContext context)
{
Context = context;
RangeMax = "1";
RangeMin = "-1";
Mean = "1";
Std = "1";
LetterBoxValue = "0";
InputShape = "1, 3, 24, 24";
InputTypeValue = InputType.Float32;
}
public string LayoutWatermark { get; set; } = "e.g. NHWC or NCHW or 0,2,3,1";
public string ShapeWaterMark { get; set; } = "e.g. 1,3,224,224";
public string ListNumberWaterMark { get; set; } = "e.g. 2.9,3,5";
[ValidLayout]
public string InputLayout { get; set; } = "NCHW";
[ValidLayout]
public string OutputLayout { get; set; } = "NCHW";
[ValidLayout]
public string ModelLayout { get; set; } = "NCHW";
public bool SwapRB { get; set; }
[ValidFloat]
public string RangeMin { get; set; }
[ValidFloat]
public string RangeMax { get; set; }
[ValidFloat]
public string LetterBoxValue { get; set; }
[ValidFloatArray]
public string Mean { get; set; }
[ValidFloatArray]
public string Std { get; set; }
[RelayCommand]
public void ShowPreprocessOrder()
{
new PreprocessWindow().Show();
}
public override void UpdateConfig(CompileConfig config)
{
var mean = Mean.Split(",").Select(float.Parse).ToArray();
var std = Std.Split(",").Select(float.Parse).ToArray();
var inShape = Std.Split(",").Select(int.Parse).ToArray();
var rangeMin = float.Parse(RangeMin);
var rangeMax = float.Parse(RangeMax);
var letterBoxValue = float.Parse(LetterBoxValue);
config.CompileOption.InputLayout = InputLayout;
config.CompileOption.OutputLayout = OutputLayout;
config.CompileOption.InputType = InputTypeValue;
config.CompileOption.InputShape = inShape;
config.CompileOption.InputRange = new[] { rangeMin, rangeMax };
config.CompileOption.Mean = mean;
config.CompileOption.Std = std;
config.CompileOption.SwapRB = SwapRB;
config.CompileOption.ModelLayout = ModelLayout;
config.CompileOption.LetterBoxValue = letterBoxValue;
}
public override void UpdateViewModelCore(CompileConfig config)
{
InputLayout = config.CompileOption.InputLayout;
OutputLayout = config.CompileOption.OutputLayout;
InputTypeValue = config.CompileOption.InputType;
InputShape = string.Join(",", config.CompileOption.InputShape);
var range = config.CompileOption.InputRange;
if (range.Length == 2)
{
RangeMin = range[0].ToString();
RangeMax = range[1].ToString();
}
else
{
RangeMin = string.Empty;
RangeMax = string.Empty;
}
Mean = string.Join(",", config.CompileOption.Mean);
Std = string.Join(",", config.CompileOption.Std);
SwapRB = config.CompileOption.SwapRB;
ModelLayout = config.CompileOption.ModelLayout;
LetterBoxValue = config.CompileOption.LetterBoxValue.ToString();
}
public override List<string> CheckViewModel()
{
var l = new List<string>();
if (!CustomValidator.ValidateViewModel(this, out var results))
{
l = l.Concat(results.Select(x => x.ErrorMessage!)).ToList();
}
if (float.TryParse(RangeMin, out var min) && float.TryParse(RangeMax, out var max))
{
if (max < min)
{
l.Add("Invalid Range");
}
}
return l;
}
public override bool IsVisible()
{
return Context.CompileConfig.CompileOption.PreProcess && Context.CustomPreprocessMode;
}
}

View File

@ -0,0 +1,8 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
namespace Nncase.Studio.ViewModels;
public class ProfileViewModel : ViewModelBase
{
}

View File

@ -0,0 +1,55 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System.Windows.Input;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
namespace Nncase.Studio.ViewModels;
public partial class PromptDialogViewModel : ViewModelBase
{
[ObservableProperty]
private string _dialogContent = string.Empty;
[ObservableProperty]
private int _windowWidth = 500;
[ObservableProperty]
private PromptDialogLevel _dialogLevel;
[ObservableProperty]
private bool _isError;
[ObservableProperty]
private string _title = string.Empty;
public PromptDialogViewModel(string content, PromptDialogLevel level)
{
DialogContent = content;
DialogLevel = level;
IsError = level == PromptDialogLevel.Error;
if (IsError)
{
Title = "错误";
}
else
{
Title = "提示";
}
CloseWindowCommand = new RelayCommand<Window>(CloseWindow);
WindowWidth = (content.Length * 20) + 60;
}
public RelayCommand<Window> CloseWindowCommand { get; private set; }
private void CloseWindow(Window? window)
{
if (window != null)
{
window.Close();
}
}
}

View File

@ -0,0 +1,211 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Avalonia.Media.Fonts;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nncase.IR;
using Nncase.Quantization;
using Nncase.Studio.Util;
using Nncase.Studio.Views;
namespace Nncase.Studio.ViewModels;
public partial class QuantizeViewModel : ViewModelBase
{
[ObservableProperty]
private QuantizeOptions _quantizeOptionsValue;
[ObservableProperty]
private CalibMethod _calibMethodValue;
[ObservableProperty]
private QuantType _quantTypeValue;
[ObservableProperty]
private QuantType _wQuantTypeValue;
[ObservableProperty]
private ModelQuantMode _modelQuantModeValue;
[ObservableProperty]
private bool _mixQuantize;
[ObservableProperty]
private bool _exportQuantScheme;
[ObservableProperty]
private string _quantSchemePath = string.Empty;
[ObservableProperty]
private string _exportQuantSchemePath = string.Empty;
[ObservableProperty]
private string _calibDir = string.Empty;
private string[] _inputFiles = Array.Empty<string>();
public QuantizeViewModel(ViewModelContext context)
{
ModelQuantModeList = new ObservableCollection<ModelQuantMode>(Enum.GetValues<ModelQuantMode>().Skip(1).ToList());
ModelQuantModeValue = ModelQuantMode.UsePTQ;
QuantizeOptionsValue = new();
Context = context;
}
public ObservableCollection<ModelQuantMode> ModelQuantModeList { get; set; }
[RelayCommand]
public async Task SelectQuantScheme()
{
var path = await Context.OpenFile(PickerOptions.JsonPickerOptions);
if (path.Count == 0)
{
return;
}
var json = path[0];
if (Path.GetExtension(json) != ".json")
{
Context.OpenDialog("QuantScheme Should use .json");
return;
}
QuantSchemePath = json;
}
[RelayCommand]
public async Task SelectCalibrationDataSet()
{
var path = await Context.OpenFolder(PickerOptions.FolderPickerOpenOptions);
if (path == string.Empty)
{
return;
}
var inputFiles = Directory.GetFiles(path);
if (inputFiles.Length == 0)
{
Context.OpenDialog("empty dir");
return;
}
CalibDir = path;
_inputFiles = inputFiles;
}
public ICalibrationDatasetProvider? LoadCalibFiles()
{
Tensor[] input;
try
{
input = DataUtil.ReadInput(_inputFiles).ToArray();
}
catch (Exception e)
{
Context.OpenDialog(e.Message);
return null;
}
if (input.Length == 0)
{
Context.OpenDialog("no file is loaded, only support .npy");
return null;
}
if (Context.Entry == null)
{
Context.OpenDialog("Should Import Model first");
return null;
}
var samples = Context.Entry!.Parameters.ToArray().Zip(input)
.ToDictionary(pair => pair.First, pair => (IValue)Value.FromTensor(pair.Second));
return new SelfInputCalibrationDatasetProvider(samples);
}
public override void UpdateViewModelCore(CompileConfig config)
{
QuantizeOptionsValue = config.CompileOption.QuantizeOptions;
if (ExportQuantSchemePath == string.Empty)
{
ExportQuantSchemePath = Path.Join(config.CompileOption.DumpDir, "QuantScheme.json");
}
MixQuantize = config.MixQuantize;
}
public override void UpdateConfig(CompileConfig config)
{
QuantizeOptionsValue.CalibrationMethod = CalibMethodValue;
QuantizeOptionsValue.QuantType = DataUtil.QuantTypeToDataType(QuantTypeValue);
QuantizeOptionsValue.WQuantType = DataUtil.QuantTypeToDataType(WQuantTypeValue);
QuantizeOptionsValue.ModelQuantMode = ModelQuantModeValue;
QuantizeOptionsValue.QuantScheme = QuantSchemePath;
QuantizeOptionsValue.ExportQuantScheme = ExportQuantScheme;
QuantizeOptionsValue.ExportQuantSchemePath = ExportQuantSchemePath;
config.CompileOption.QuantizeOptions = QuantizeOptionsValue;
}
public override List<string> CheckViewModel()
{
var list = new List<string>();
if (Context.CompileConfig.MixQuantize)
{
if (QuantSchemePath == string.Empty)
{
list.Add("QuantSchemePath should not be empty");
}
else if (!File.Exists(QuantSchemePath))
{
list.Add("QuantSchemePath not exist, please check file and path");
}
}
else
{
if (Directory.Exists(CalibDir))
{
if (_inputFiles.Length == 0)
{
list.Add("CalibDir don't exist any .npy file");
}
}
else
{
list.Add($"CalibDir {CalibDir} not exist");
}
if (QuantTypeValue == QuantType.Int16 && WQuantTypeValue == QuantType.Int16 &&
string.Equals(Context.CompileConfig.Target, "k230", StringComparison.OrdinalIgnoreCase))
{
list.Add("k230 not support QuantType and WeightsQuantType are int16");
}
}
return list;
}
public override bool IsVisible() => Context.CompileConfig.UseQuantize;
}
public sealed class SelfInputCalibrationDatasetProvider : ICalibrationDatasetProvider
{
private readonly int _count = 1;
private readonly IAsyncEnumerable<IReadOnlyDictionary<Var, IValue>> _samples;
public SelfInputCalibrationDatasetProvider(IReadOnlyDictionary<Var, IValue> sample)
{
_samples = new[] { sample }.ToAsyncEnumerable();
}
public int? Count => _count;
public IAsyncEnumerable<IReadOnlyDictionary<Var, IValue>> Samples => _samples;
}

View File

@ -0,0 +1,69 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.Linq;
using CommunityToolkit.Mvvm.ComponentModel;
using NetFabric.Hyperlinq;
using Nncase.Studio.Util;
namespace Nncase.Studio.ViewModels;
public partial class ShapeBucketViewModel : ViewModelBase
{
[ObservableProperty]
private int _segmentCount = 5;
[ValidBucketVarMap]
[ObservableProperty]
private string _fixVarMap = string.Empty;
[ValidBucketRangeInfo]
[ObservableProperty]
private string _varRangeInfo = string.Empty;
public ShapeBucketViewModel(ViewModelContext context)
{
Context = context;
}
public override void UpdateConfig(CompileConfig config)
{
var options = new ShapeBucketOptions();
options.Enable = true;
options.SegmentsCount = SegmentCount;
if (DataUtil.TryParseFixVarMap(FixVarMap, out var fixVarMap))
{
options.FixVarMap = fixVarMap;
}
if (DataUtil.TryParseRangeInfo(VarRangeInfo, out var rangeInfo))
{
options.RangeInfo = rangeInfo;
}
config.CompileOption.ShapeBucketOptions = options;
}
public override void UpdateViewModelCore(CompileConfig config)
{
var option = config.CompileOption.ShapeBucketOptions;
SegmentCount = option.SegmentsCount;
VarRangeInfo = string.Join(",", option.FixVarMap.Select(pair => $"{pair.Key}:{pair.Value}"));
FixVarMap = string.Join(",", option.RangeInfo.Select(pair => $"{pair.Key}:({pair.Value.Min}, {pair.Value.Max})"));
}
public override bool IsVisible() => Context.CompileConfig.EnableShapeBucket;
public override List<string> CheckViewModel()
{
if (!CustomValidator.ValidateViewModel(this, out var results))
{
return results.Select(x => x.ErrorMessage!).ToList();
}
return new();
}
}

View File

@ -0,0 +1,8 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
namespace Nncase.Studio.ViewModels;
public class SimulateInputViewModel : ViewModelBase
{
}

View File

@ -0,0 +1,325 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using Nncase.IR;
using Nncase.Studio.Util;
using NumSharp;
namespace Nncase.Studio.ViewModels;
public partial class SimulateViewModel : ViewModelBase
{
[ObservableProperty]
private string _resultDir = string.Empty;
[ObservableProperty]
private string _kmodelPath = string.Empty;
[ObservableProperty]
private string _status = "未运行";
[ObservableProperty]
private ObservableCollection<Tensor> _runtimeInput = new();
[ObservableProperty]
private ObservableCollection<string> _inputPath = new();
[ObservableProperty]
private ObservableCollection<string> _mainParamStr = new();
[ObservableProperty]
private ObservableCollection<string> _inputTypeStr = new();
[ObservableProperty]
private bool _runSimulate;
public SimulateViewModel(ViewModelContext context)
{
Context = context;
}
[RelayCommand]
public async Task SetRuntimeInput()
{
var path = await Context.OpenFile(PickerOptions.DataPickerOptions);
if (path.Count == 0)
{
return;
}
Tensor[] input;
string[] inputFiles;
try
{
(inputFiles, input) = DataUtil.ReadMultiInputs(path);
}
catch (Exception e)
{
Context.OpenDialog(e.Message);
return;
}
UpdateRuntimeInputUI(input, inputFiles);
}
[RelayCommand]
public async Task SetResultDir()
{
var folder = await Context.OpenFolder(PickerOptions.FolderPickerOpenOptions);
if (folder != string.Empty)
{
ResultDir = folder;
}
}
[RelayCommand]
public async Task Simulate()
{
if (!File.Exists(KmodelPath))
{
Context.OpenDialog("Kmodel Not Exist");
return;
}
if (RuntimeInput.Count == 0)
{
Context.OpenDialog("Not Set Input");
return;
}
if (!CheckInput())
{
return;
}
var cts = new CancellationTokenSource();
try
{
using (var interp = Runtime.Interop.RTInterpreter.Create())
{
var kmodel = File.ReadAllBytes(KmodelPath);
interp.SetDumpRoot(Context.CompileConfig.CompileOption.DumpDir);
interp.LoadModel(kmodel);
var entry = interp.Entry!;
var rtInputs = RuntimeInput.Select(Runtime.Interop.RTTensor.FromTensor).ToArray();
var start = System.DateTime.Now;
Status = "Running";
RunSimulate = true;
var task = Task.Run(
() =>
{
UpdateTime(cts, start);
},
cts.Token);
await Task.Run(() =>
{
var result = entry.Invoke(rtInputs).ToValue().AsTensors();
SaveResult(result);
}).ContinueWith(t => t, cts.Token);
SimulateFinish(cts);
Context.OpenDialog($"Simulate Finish, spent time:{Status}\n result in {ResultDir}", PromptDialogLevel.Normal);
Status = "Finish";
}
}
catch (DllNotFoundException)
{
Context.OpenDialog("libNncase.Native.so not found");
}
catch (Exception e)
{
var msg = ExceptionMessageProcess(e);
Context.OpenDialog(msg);
}
finally
{
SimulateFinish(cts);
}
}
public override void UpdateViewModelCore(CompileConfig config)
{
ResultDir = config.ResultDir;
KmodelPath = config.KmodelPath;
InputPath = new(config.InputPathList);
}
public override void UpdateConfig(CompileConfig config)
{
config.ResultDir = ResultDir;
config.InputPathList = InputPath.ToArray();
}
private bool CheckInput()
{
if (Context.Entry == null)
{
return true;
}
var paramList = Context.Entry!.Parameters.ToArray();
foreach ((var tensor, var param) in RuntimeInput.Zip(paramList))
{
var tt = (TensorType)param.TypeAnnotation;
if (tensor.ElementType != tt.DType)
{
Context.OpenDialog($"{param.Name} input datatype mismatch");
{
return true;
}
}
if (tt.Shape.Count != tensor.Shape.Count || tt.Shape.Zip(tensor.Shape)
.Any(pair => pair.First.IsFixed && pair.First != pair.Second))
{
Context.OpenDialog($"{param.Name} input shape mismatch");
{
return true;
}
}
}
return false;
}
[RelayCommand]
private async Task SetKmodelPath()
{
var kmodel = await Context.OpenFile(PickerOptions.KmodelPickerOptions);
if (kmodel.Count == 0)
{
return;
}
KmodelPath = kmodel[0];
}
private void SaveResult(Tensor[] result)
{
var list = result
.Select(t =>
np.frombuffer(t.BytesBuffer.ToArray(), t.ElementType.CLRType)
.reshape(t.Shape.ToValueArray()))
.ToArray();
for (int i = 0; i < list.Length; i++)
{
np.save(Path.Join(ResultDir, $"nncase_result_{i}.npy"), list[i]);
}
}
private void UpdateTime(CancellationTokenSource cts, DateTime start)
{
while (true)
{
Thread.Sleep(20);
if (cts.Token.IsCancellationRequested)
{
return;
}
var now = System.DateTime.Now;
var timeStr = (now - start).ToString();
Status = timeStr.Substring(3, timeStr.Length - 8);
}
}
private void SimulateFinish(CancellationTokenSource cts)
{
cts.Cancel();
RunSimulate = false;
}
private string ExceptionMessageProcess(Exception exception)
{
var msg = exception.Message;
if (msg.Contains("Status code", StringComparison.Ordinal))
{
if (int.TryParse(msg.Split(":")[1].Trim(), out var errc))
{
return ErrcToString(errc);
}
return exception.ToString();
}
return exception.ToString();
}
private string ErrcToString(int errc)
{
string errcStr;
switch (-errc)
{
case 0x01:
errcStr = "invalid model indentifier";
break;
case 0x02:
errcStr = "invalid model checksum";
break;
case 0x03:
errcStr = "invalid model version";
break;
case 0x04:
errcStr = "runtime not found";
break;
case 0x05:
errcStr = "datatype mismatch";
break;
case 0x06:
errcStr = "shape mismatch";
break;
case 0x07:
errcStr = "invalid memory location";
break;
case 0x08:
errcStr = "runtime register not found";
break;
case 0x0100:
errcStr = "stackvm illegal instruction";
break;
case 0x0101:
errcStr = "stackvm illegal target";
break;
case 0x0102:
errcStr = "stackvm stack overflow";
break;
case 0x0103:
errcStr = "stackvm stack underflow";
break;
case 0x0104:
errcStr = "stackvm unknow custom call";
break;
case 0x0105:
errcStr = "stackvm duplicate custom call";
break;
case 0x0200:
errcStr = "nnil illegal instruction";
break;
default:
errcStr = $"Unknown Status code: {errc}";
break;
}
return errcStr;
}
private void UpdateRuntimeInputUI(Tensor[] input, string[] inputFiles)
{
RuntimeInput = new ObservableCollection<Tensor>(input);
InputPath = new ObservableCollection<string>(inputFiles);
InputTypeStr = new ObservableCollection<string>(RuntimeInput
.Select(x => DataUtil.TensorTypeToString(new TensorType(x.ElementType, x.Shape))).ToList());
}
}

View File

@ -0,0 +1,50 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System.IO;
using System.Text.Json.Nodes;
using System.Threading.Tasks;
using CommunityToolkit.Mvvm.Input;
using Newtonsoft.Json;
using Nncase.Studio.Util;
using Nncase.Studio.Views;
namespace Nncase.Studio.ViewModels;
public partial class StudioModeViewModel : ViewModelBase
{
public StudioModeViewModel(ViewModelContext context)
{
Context = context;
}
[RelayCommand]
public async Task ImportStudioConfig()
{
var selectFiles = await Context.OpenFile(PickerOptions.JsonPickerOptions);
if (selectFiles.Count == 0)
{
return;
}
else
{
var configFile = selectFiles[0];
var conf = JsonConvert.DeserializeObject<CompileConfig>(File.ReadAllText(configFile));
Context.ImportConfig(conf!);
}
Context.SwitchToPage(typeof(CompileOptionViewModel));
}
[RelayCommand]
private void SwitchToImportView()
{
Context.SwitchToPage(typeof(ImportViewModel));
}
[RelayCommand]
private void SwitchToSimulateView()
{
Context.SwitchToPage(typeof(SimulateViewModel));
}
}

View File

@ -0,0 +1,53 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System.Collections.Generic;
using System.Collections.ObjectModel;
using CommunityToolkit.Mvvm.ComponentModel;
using Nncase.Studio.Util;
using ReactiveUI;
namespace Nncase.Studio.ViewModels;
public class WindowViewModelBase : ObservableValidator
{
}
public class ViewModelBase : ObservableValidator
{
private ViewModelContext? _context;
protected ViewModelContext Context
{
get { return _context!; }
set { _context = value; }
}
public void UpdateContext()
{
UpdateConfig(Context.CompileConfig);
}
public void UpdateViewModel()
{
UpdateViewModelCore(Context.CompileConfig);
}
public virtual List<string> CheckViewModel()
{
return new();
}
public virtual void UpdateConfig(CompileConfig config)
{
}
public virtual void UpdateViewModelCore(CompileConfig config)
{
}
public virtual bool IsVisible()
{
return true;
}
}

View File

@ -0,0 +1,89 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
xmlns:quantization="clr-namespace:Nncase.Quantization;assembly=Nncase.Core"
xmlns:views="clr-namespace:Nncase.Studio.Views"
xmlns:studio="clr-namespace:Nncase.Studio"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.CompileOptionView"
x:DataType="viewModels:CompileOptionViewModel">
<UserControl.Resources>
<studio:EnumConverter x:Key="EnumConverter" />
</UserControl.Resources>
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="模型文件路径"/>
<TextBox Grid.Row="0" Grid.Column="1" Classes="Path" Text="{Binding InputFile}" IsReadOnly="True"/>
<Label Grid.Row="1" Grid.Column="0" Content="模型格式"/>
<TextBlock Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" Margin="15" Text="{Binding InputFormat, Mode=TwoWay}"/>
<Label Grid.Row="2" Grid.Column="0" Content="Dump选项"/>
<SplitButton Margin="3" Grid.Row="2" Grid.Column="1" Content="DumpFlags" >
<SplitButton.Flyout>
<Flyout Placement="Bottom">
<ListBox
SelectionMode="Multiple,Toggle"
SelectedItems="{Binding DumpFlagSelected}"
ItemsSource="{Binding DumpFlagsList}">
</ListBox>
</Flyout>
</SplitButton.Flyout>
</SplitButton>
<Label Grid.Row="3" Grid.Column="0" Content="Dump路径"/>
<DockPanel Grid.Row="3" Grid.Column="1">
<TextBox Classes="Path" Text="{Binding DumpDir}"/>
<Button
Content="选择"
Command="{Binding SetDumpDirCommand}">
</Button>
</DockPanel>
<Label Grid.Row="4" Grid.Column="0" Content="目标平台"/>
<DockPanel Grid.Row="4" Grid.Column="1">
<ComboBox ItemsSource="{Binding TargetList}" SelectedItem="{Binding Target}" Width="100"/>
<Label Content="Nncase Studio 目前只支持 CPU, K230这两个平台"/>
</DockPanel>
<Label Grid.Row="5" Grid.Column="0" Content="开启量化"/>
<DockPanel Grid.Row="5" Grid.Column="1">
<CheckBox IsChecked="{Binding Quantize}"/>
<Label IsVisible="{Binding Quantize}" Content="是否使用混合量化"></Label>
<CheckBox IsVisible="{Binding Quantize}"
IsChecked="{Binding MixQuantize}"></CheckBox>
</DockPanel>
<Label Grid.Row="6" Grid.Column="0" Content="开启前后处理"/>
<DockPanel Grid.Row="6" Grid.Column="1">
<CheckBox IsChecked="{Binding Preprocess}"/>
<!-- <Label Content="前后处理模式" IsVisible="{Binding Preprocess}"></Label> -->
<!-- <ComboBox IsVisible="{Binding Preprocess}" ItemsSource="{Binding PreprocessModeList}" SelectedValue="{Binding PreprocessMode}"></ComboBox> -->
</DockPanel>
<Label Grid.Row="7" Grid.Column="0" Content="开启ShapeBucket"/>
<CheckBox Grid.Row="7" Grid.Column="1" IsChecked="{Binding ShapeBucket}"/>
</Grid>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class CompileOptionView : UserControl
{
public CompileOptionView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,33 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
xmlns:views="clr-namespace:Nncase.Studio.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.CompileView"
x:DataType="viewModels:CompileViewModel">
<StackPanel VerticalAlignment="Center">
<Grid Margin="30">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="Kmodel路径" VerticalAlignment="Center"></Label>
<TextBox Grid.Row="0" Grid.Column="1" Classes="Path" Text="{Binding KmodelPath}" Watermark="Path or Name"></TextBox>
</Grid>
<DockPanel HorizontalAlignment="Center" Margin="4">
<Button Margin= "25"
Content="编译"
Command="{Binding CompileCommand}">
</Button>
<Button Margin="25"
Content="停止"
Command="{Binding CancelCompileCommand}">
</Button>
</DockPanel>
<ProgressBar Minimum="0" Maximum="{Binding ProgressBarMax}" Value="{Binding ProgressBarValue}" Height="20"></ProgressBar>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class CompileView : UserControl
{
public CompileView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,17 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:studio="clr-namespace:Nncase.Studio"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.EnumComboBox">
<UserControl.Resources>
<studio:EnumConverter x:Key="EnumConverter" />
</UserControl.Resources>
<DockPanel>
<Label x:Name="Label"></Label>
<ComboBox x:Name="ComboBoxList"></ComboBox></DockPanel>
</UserControl>

View File

@ -0,0 +1,40 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Markup.Xaml;
using GiGraph.Dot.Entities.Html.Font.Styles;
namespace Nncase.Studio.Views
{
public partial class EnumComboBox : ComboBox
{
public static readonly StyledProperty<Type> TypeNameProperty =
AvaloniaProperty.Register<EnumComboBox, Type>(nameof(TypeName));
public Type TypeName
{
get
{
return GetValue(TypeNameProperty);
}
set
{
SetValue(TypeNameProperty, value);
var names = Enum.GetNames(TypeName);
foreach (string name in names)
{
Items.Add(name);
}
SelectedIndex = 0;
}
}
protected override Type StyleKeyOverride => typeof(Avalonia.Controls.ComboBox);
}
}

View File

@ -0,0 +1,26 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Nncase.Studio.Views"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.ImportView"
x:DataType="viewModels:ImportViewModel"
FontSize="32">
<StackPanel VerticalAlignment="Center">
<!-- 插入三种模型的logo -->
<Label HorizontalAlignment="Center" Content="支持的模型格式NCNN ONNX TFLite"></Label>
<DockPanel HorizontalAlignment="Center" Name="LogoPanel">
<Image Source="/Assets/ncnn-logo.png"></Image>
<Image Source="/Assets/ONNX-logo.png"></Image>
<Image Source="/Assets/tflite-logo.png"></Image>
</DockPanel>
<Button Name="ImportButton"
Content="Import"
FontSize="40"
Command="{Binding ImportCommand}">
</Button>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class ImportView : UserControl
{
public ImportView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,72 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:Nncase.Studio.ViewModels"
xmlns:flg="using:Nncase.Diagnostics"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:global="clr-namespace:"
xmlns:studio="clr-namespace:Nncase.Studio"
xmlns:views="clr-namespace:Nncase.Studio.Views"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
MinHeight="880"
MinWidth="1400"
x:Class="Nncase.Studio.Views.MainWindow"
x:DataType="vm:MainWindowViewModel"
Icon="/Assets/nncase-logo.png"
Title="Nncase.Studio">
<Window.Resources>
<x:Double x:Key="ControlContentThemeFontSize">24</x:Double>
<studio:EnumConverter x:Key="EnumConverter"/>
</Window.Resources>
<Design.DataContext>
<!-- This only sets the DataContext for the previewer in an IDE,
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
<vm:MainWindowViewModel/>
</Design.DataContext>
<!-- bind data contenxt -->
<!-- <Border Background="MediumPurple" -->
<Border Background="White"
BorderBrush="Black"
BorderThickness="0"
CornerRadius="3"
Padding="100 0">
<StackPanel>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image Grid.Column="0" Source="/Assets/canaan-logo.png" Width="250" Height="90" HorizontalAlignment="Left"></Image>
<Label Grid.Column="1" FontWeight="Bold" FontSize="54" Content="{Binding Title}" HorizontalAlignment="Center" VerticalAlignment="Center"></Label>
<Image Grid.Column="2" Source="/Assets/nncase-full-logo.png" Width="180" Height="90" HorizontalAlignment="Right"></Image>
</Grid>
<Border Background="White"
BorderBrush="Black"
BorderThickness="3"
CornerRadius="3"
Padding="4">
<Label
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center"
MinHeight="640"
Content="{Binding ContentViewModel}"></Label>
</Border>
<Border Background="White"
BorderBrush="Black"
BorderThickness="0"
CornerRadius="3"
Padding="4">
<DockPanel HorizontalAlignment="Center">
<views:NavigatorView HorizontalAlignment="Center" DataContext="{Binding NavigatorViewModelValue}"></views:NavigatorView>
<Button Content="导出编译配置" Command="{Binding ExportStudioConfigCommand}"></Button>
</DockPanel>
</Border>
</StackPanel>
</Border>
</Window>

View File

@ -0,0 +1,86 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reactive;
using System.Threading.Tasks;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Interactivity;
using Avalonia.Media;
using Avalonia.Platform.Storage;
using Avalonia.ReactiveUI;
using Nncase.Diagnostics;
using Nncase.Studio.ViewModels;
using ReactiveUI;
namespace Nncase.Studio.Views;
public partial class MainWindow : ReactiveWindow<MainWindowViewModel>
{
public MainWindow()
{
InitializeComponent();
this.WhenActivated(action =>
{
action(ViewModel!.ShowOpenFilePicker.RegisterHandler(OpenFileButtonClicked));
action(ViewModel!.ShowSaveFilePicker.RegisterHandler(SaveFileButtonClicked));
action(ViewModel!.ShowFolderPicker.RegisterHandler(OpenFolderButtonClicked));
});
}
public async Task OpenFolderButtonClicked(InteractionContext<FolderPickerOpenOptions, string> interaction)
{
// Get top level from the current control. Alternatively, you can use Window reference instead.
var topLevel = TopLevel.GetTopLevel(this);
// Start async operation to open the dialog.
var folder = await topLevel!.StorageProvider.OpenFolderPickerAsync(interaction.Input);
if (folder.Count == 0)
{
interaction.SetOutput(string.Empty);
return;
}
interaction.SetOutput(folder[0].Path.LocalPath);
}
public async Task OpenFileButtonClicked(InteractionContext<FilePickerOpenOptions, List<string>> interaction)
{
// Get top level from the current control. Alternatively, you can use Window reference instead.
var topLevel = TopLevel.GetTopLevel(this);
// Start async operation to open the dialog.
var files = await topLevel!.StorageProvider.OpenFilePickerAsync(interaction.Input);
if (files.Count >= 1)
{
var path = files.Select(f => f.Path.LocalPath).ToList();
interaction.SetOutput(path);
}
else
{
interaction.SetOutput(new List<string>());
}
}
public async Task SaveFileButtonClicked(InteractionContext<FilePickerSaveOptions, string> interaction)
{
// Get top level from the current control. Alternatively, you can use Window reference instead.
var topLevel = TopLevel.GetTopLevel(this);
// Start async operation to open the dialog.
var res = await topLevel!.StorageProvider.SaveFilePickerAsync(interaction.Input);
if (res != null)
{
interaction.SetOutput(res.Path.LocalPath);
}
else
{
interaction.SetOutput(string.Empty);
}
}
}

View File

@ -0,0 +1,51 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.NavigatorView"
x:DataType="viewModels:NavigatorViewModel">
<DockPanel Margin="10">
<Border Background="White"
BorderBrush="Black"
BorderThickness="0"
CornerRadius="3"
Padding="4">
<Grid Width="260">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Button
Grid.Row="0" Grid.Column="0"
Content="上一步"
IsVisible="{Binding PageIndex}"
Command="{Binding SwitchPrevCommand}">
</Button>
<Button
Grid.Row="0" Grid.Column="1"
Content="下一步"
IsVisible="{Binding !IsLast}"
Command="{Binding SwitchNextCommand}">
</Button>
</Grid>
</Border>
<Label
Width="60"
Margin="10"
VerticalAlignment="Center"
Content="{Binding PageIndexString}">
</Label>
<ProgressBar
Margin="10"
VerticalAlignment="Center"
Minimum="0"
Maximum="{Binding PageMaxIndex}"
Value="{Binding PageIndex}"></ProgressBar>
</DockPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class NavigatorView : UserControl
{
public NavigatorView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,74 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Nncase.Studio.Views"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
xmlns:nncase="clr-namespace:Nncase;assembly=Nncase.Core"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.PreprocessView"
x:DataType="viewModels:PreprocessViewModel">
<StackPanel VerticalAlignment="Center">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="InputLayout" />
<TextBox Grid.Row="0" Grid.Column="1" Text="{Binding InputLayout}"
Watermark="{Binding LayoutWatermark}" />
<Label Grid.Row="0" Grid.Column="2" Content="OutputLayout" />
<TextBox Grid.Row="0" Grid.Column="3" Text="{Binding OutputLayout}"
Watermark="{Binding LayoutWatermark}" />
<Label Grid.Row="1" Grid.Column="0" Content="InputType" />
<views:EnumComboBox Grid.Row="1" Grid.Column="1"
SelectedValue="{Binding InputTypeValue}" TypeName="nncase:InputType" />
<Label Grid.Row="1" Grid.Column="2" Content="InputShape" />
<TextBox Grid.Row="1" Grid.Column="3" Text="{Binding InputShape}"
Watermark="{Binding ShapeWaterMark}" />
<Label Grid.Row="2" Grid.Column="0" Content="InputRange" />
<DockPanel Grid.Row="2" Grid.Column="1" Grid.ColumnSpan="3">
<Label Content="Min" />
<TextBox Text="{Binding RangeMin}" />
<Label Content="Max" />
<TextBox Text="{Binding RangeMax}" />
</DockPanel>
<Label Grid.Row="3" Grid.Column="0" Content="Mean" />
<TextBox Grid.Row="3" Grid.Column="1" Text="{Binding Mean}"
Watermark="{Binding ListNumberWaterMark}" />
<Label Grid.Row="3" Grid.Column="2" Content="Std" />
<TextBox Grid.Row="3" Grid.Column="3" Text="{Binding Std}"
Watermark="{Binding ListNumberWaterMark}" />
<Label Grid.Row="4" Grid.Column="0" Content="SwapRB" />
<CheckBox Grid.Row="4" Grid.Column="1" IsChecked="{Binding SwapRB}" />
<Label Grid.Row="4" Grid.Column="2" Content="Model Layout" />
<TextBox Grid.Row="4" Grid.Column="3" Text="{Binding ModelLayout}"
Watermark="{Binding LayoutWatermark}" />
<Label Grid.Row="5" Grid.Column="0" Content="LetterBoxValue" />
<TextBox Grid.Row="5" Grid.Column="1" Text="{Binding LetterBoxValue}" />
<Button Grid.Row="5" Grid.Column="2" Content="显示前处理顺序" Command="{Binding ShowPreprocessOrderCommand}"></Button>
</Grid>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,16 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views;
public partial class PreprocessView : UserControl
{
public PreprocessView()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,13 @@
<Window xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.PreprocessWindow"
Title="PreprocessWindow"
Width="350"
Background="#f8f8f8">
<ScrollViewer>
<Image HorizontalAlignment="Center" Source="/Assets/preprocess.png" Width="284" Height="1805"></Image>
</ScrollViewer>
</Window>

View File

@ -0,0 +1,16 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views;
public partial class PreprocessWindow : Window
{
public PreprocessWindow()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,42 @@
<Window x:Class="Nncase.Studio.Views.PromptDialog"
x:Name="Dialog"
xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="192" d:DesignHeight="108"
x:DataType="viewModels:PromptDialogViewModel"
MaxWidth="800"
Width="{Binding WindowWidth}"
Height="300"
Icon="/Assets/nncase-logo.png"
Title="{Binding Title}"
FontSize="32">
<StackPanel VerticalAlignment="Center" HorizontalAlignment="Center">
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Image
Name="IconImage"
IsVisible="{Binding IsError}"
Width="64" Height="64" Source="/Assets/error-icon.png"></Image>
<TextBlock Grid.Column="1"
HorizontalAlignment="Left"
Margin="30"
FontSize="27"
Text="{Binding DialogContent}"
></TextBlock>
</Grid>
<Button Content="关闭"
HorizontalAlignment="Center"
IsCancel="True"
Command="{Binding CloseWindowCommand, Mode=OneWay}"
CommandParameter="{Binding $parent[Window]}"
></Button>
</StackPanel>
</Window>

View File

@ -0,0 +1,20 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
using CommunityToolkit.Mvvm.ComponentModel;
using Nncase.Studio.ViewModels;
using ReactiveUI;
namespace Nncase.Studio.Views;
public partial class PromptDialog : ReactiveWindow<PromptDialogViewModel>
{
public PromptDialog()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,125 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:qt="clr-namespace:Nncase.Quantization"
xmlns:quantization="clr-namespace:Nncase.Quantization;assembly=Nncase.Core"
xmlns:quantization1="clr-namespace:Nncase.Quantization;assembly=Nncase.Quantization"
xmlns:views="clr-namespace:Nncase.Studio.Views"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.QuantizeView"
x:DataType="viewModels:QuantizeViewModel">
<StackPanel VerticalAlignment="Center">
<StackPanel IsVisible="{Binding !MixQuantize}">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="150"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="数据集"></Label>
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="2"
Width="400"
HorizontalAlignment="Left"
Text="{Binding CalibDir}"
Watermark="数据集所在的文件夹仅支持npy格式的输入"></TextBox>
<Button
Grid.Row="0" Grid.Column="3"
Content="选择"
x:CompileBindings="False"
Command="{Binding SelectCalibrationDataSetCommand}"></Button>
<Label Grid.Row="1" Grid.Column="0" Content="量化方法"></Label>
<views:EnumComboBox Grid.Row="1" Grid.Column="1" TypeName="{x:Type quantization:CalibMethod}" SelectedValue="{Binding CalibMethodValue}"></views:EnumComboBox>
<Label Grid.Row="1" Grid.Column="2" Content="BindQuantMethod"></Label>
<CheckBox Grid.Row="1" Grid.Column="3" IsChecked="{Binding QuantizeOptionsValue.BindQuantMethod}"></CheckBox>
<Label Grid.Row="2" Grid.Column="0" Content="开启SQuant"></Label>
<CheckBox Grid.Row="2" Grid.Column="1" IsChecked="{Binding QuantizeOptionsValue.UseSquant}"></CheckBox>
<Label Grid.Row="2" Grid.Column="2" Content="开启AdaRound"></Label>
<CheckBox Grid.Row="2" Grid.Column="3" IsChecked="{Binding QuantizeOptionsValue.UseAdaRound}"></CheckBox>
<Label Grid.Row="3" Grid.Column="0" Content="输入量化类型"></Label>
<views:EnumComboBox Grid.Row="3" Grid.Column="1" TypeName="{x:Type quantization:QuantType}" SelectedValue="{Binding QuantTypeValue}"></views:EnumComboBox>
<Label Grid.Row="3" Grid.Column="2" Content="Weights量化类型"></Label>
<views:EnumComboBox Grid.Row="3" Grid.Column="3" TypeName="{x:Type quantization:QuantType}" SelectedValue="{Binding WQuantTypeValue}"></views:EnumComboBox>
<Label Grid.Row="4" Grid.Column="0" Content="模型量化模式"></Label>
<ComboBox Grid.Row="4" Grid.Column="1" Grid.ColumnSpan="2"
ItemsSource="{Binding ModelQuantModeList}"
SelectedItem="{Binding ModelQuantModeValue}">
</ComboBox>
<Label Grid.Row="5" Grid.Column="0" Content="Dump量化损失"></Label>
<CheckBox Grid.Row="5" Grid.Column="1" IsChecked="{Binding QuantizeOptionsValue.DumpQuantError}"></CheckBox>
<Label Grid.Row="5" Grid.Column="2" Content="Dump对称量化损失"></Label>
<CheckBox Grid.Row="5" Grid.Column="3" IsChecked="{Binding QuantizeOptionsValue.DumpQuantErrorSymmetricForSigned}"></CheckBox>
<Label Grid.Row="6" Grid.Column="0" Content="导出量化配置"></Label>
<CheckBox Grid.Row="6" Grid.Column="1" IsChecked="{Binding ExportQuantScheme}"></CheckBox>
<Label Grid.Row="6" Grid.Column="2"
Content="导出Weights范围"
IsVisible="{Binding ExportQuantScheme}">
</Label>
<CheckBox Grid.Row="6" Grid.Column="3"
IsVisible="{Binding ExportQuantScheme}"
IsChecked="{Binding QuantizeOptionsValue.ExportWeightRangeByChannel}">
</CheckBox>
<Label Grid.Row="7" Grid.Column="0"
IsVisible="{Binding ExportQuantScheme}"
Content="设置导出路径">
</Label>
<TextBox Grid.Row="7" Grid.Column="1" Grid.ColumnSpan="3"
Classes="Path"
Width="400"
IsVisible="{Binding ExportQuantScheme}"
Text="{Binding ExportQuantSchemePath}">
</TextBox>
<TextBlock Grid.Row="7" Grid.Column="3" Text=" " Margin="22"></TextBlock>
</Grid>
</StackPanel>
<StackPanel IsVisible="{Binding MixQuantize}">
<Grid Row="2" Column="3">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="量化配置文件"></Label>
<TextBox Grid.Row="0" Grid.Column="1" HorizontalAlignment="Left" Width="400" Watermark="Path" Text="{Binding QuantSchemePath}"></TextBox>
<Button Grid.Row="0" Grid.Column="2"
Content="选择"
Command="{Binding SelectQuantSchemeCommand}"></Button>
<Label Grid.Row="1" Grid.Column="0" Content="量化配置严格模式"></Label>
<DockPanel Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="2">
<CheckBox
IsChecked="{Binding QuantizeOptionsValue.QuantSchemeStrictMode}"></CheckBox>
<Label
Content="如果配置文件来自nncase则无需设置"></Label>
</DockPanel>
</Grid>
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class QuantizeView : UserControl
{
public QuantizeView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,32 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.ShapeBucketView"
x:DataType="viewModels:ShapeBucketViewModel">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="分段数量"></Label>
<NumericUpDown Grid.Row="0" Grid.Column="1"
HorizontalAlignment="Left"
Value="{Binding SegmentCount}"
FormatString="0"
Minimum="2"
Increment="1"></NumericUpDown>
<Label Grid.Row="1" Grid.Column="0" Content="FixVarMap"></Label>
<TextBox Grid.Row="1" Grid.Column="1" Width="600" Text="{Binding FixVarMap}" Watermark="example: batch:3, len:24"></TextBox>
<Label Grid.Row="2" Grid.Column="0" Content="VarRangeInfo"></Label>
<TextBox Grid.Row="2" Grid.Column="1" Width="600" Text="{Binding VarRangeInfo}" Watermark="example: len1:(1, 100); len2:(1, 40)"></TextBox>
</Grid>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class ShapeBucketView : UserControl
{
public ShapeBucketView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,44 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.SimulateInputView">
<StackPanel VerticalAlignment="Center">
<DockPanel Margin="10" HorizontalAlignment="Center">
<StackPanel Margin="10">
<TextBlock Text="模型参数信息"></TextBlock>
<ListBox
x:CompileBindings="False"
ItemsSource="{Binding $parent[Window].DataContext.MainParamStr}"></ListBox>
</StackPanel>
<StackPanel Margin="10">
<TextBlock Text="输入信息"></TextBlock>
<ListBox
x:CompileBindings="False"
ItemsSource="{Binding $parent[Window].DataContext.InputTypeStr}"></ListBox>
</StackPanel>
<StackPanel Margin="10">
<TextBlock Text="输入路径"></TextBlock>
<ListBox
x:CompileBindings="False"
ItemsSource="{Binding $parent[Window].DataContext.InputPath}"></ListBox>
</StackPanel>
</DockPanel>
<StackPanel Margin="10" HorizontalAlignment="Center">
<StackPanel>
<Button Content="设置输入"
x:CompileBindings="False"
HorizontalAlignment="Center"
Command="{Binding $parent[Window].DataContext.SetRuntimeInput}">
</Button>
<Label Margin="10"
HorizontalAlignment="Left"
Content="目前支持的输入格式: *.npy"></Label>
</StackPanel>
</StackPanel>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class SimulateInputView : UserControl
{
public SimulateInputView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,70 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:views="clr-namespace:Nncase.Studio.Views"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.SimulateView"
x:DataType="viewModels:SimulateViewModel">
<StackPanel VerticalAlignment="Center">
<Grid HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Label Grid.Row="0" Grid.Column="0" Content="输入文件"></Label>
<SplitButton Margin="5 0" Grid.Row="0" Grid.Column="1" Content="已选择的文件">
<SplitButton.Flyout>
<Flyout Placement="Bottom">
<ListBox
ItemsSource="{Binding InputPath}">
</ListBox>
</Flyout>
</SplitButton.Flyout>
</SplitButton>
<!-- <ComboBox Grid.Row="0" Grid.Column="1" ItemsSource="{Binding InputPath}" ></ComboBox> -->
<Button
Grid.Row="0" Grid.Column="2"
Content="选择"
Command="{Binding SetRuntimeInputCommand}">
</Button>
<Label Grid.Row="1" Grid.Column="0" Content="结果存储位置" VerticalAlignment="Center"></Label>
<TextBox Classes="Path" Grid.Row="1" Grid.Column="1" Watermark="Result ResultDir" Text="{Binding ResultDir}"></TextBox>
<Button
Grid.Row="1" Grid.Column="2"
Content="选择"
Command="{Binding SetResultDirCommand}">
</Button>
<Label Grid.Row="2" Grid.Column="0" Content="KmodelPath"></Label>
<TextBox Classes="Path" Grid.Row="2" Grid.Column="1"
Text="{Binding KmodelPath}"
Watermark="Kmodel Path"></TextBox>
<Button
Grid.Row="2" Grid.Column="2"
Content="选择"
x:CompileBindings="False"
Command="{Binding SetKmodelPathCommand}">
</Button>
</Grid>
<DockPanel Margin="0 40" HorizontalAlignment="Center">
<Button HorizontalAlignment="Center"
Content="推理"
Margin="40 0"
Command="{Binding SimulateCommand}">
</Button>
<Label Content="{Binding Status}" Width="120"></Label>
</DockPanel>
<ProgressBar Margin="10" ShowProgressText="False" IsIndeterminate="{Binding RunSimulate}"/>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using CommunityToolkit.Mvvm.Input;
namespace Nncase.Studio.Views;
public partial class SimulateView : UserControl
{
public SimulateView()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,14 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Nncase.Studio.ViewModels"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Nncase.Studio.Views.StudioModeView"
x:DataType="viewModels:StudioModeViewModel">
<StackPanel>
<Button Width="300" Margin="30" FontSize="40" Content="常规编译" Command="{Binding SwitchToImportViewCommand}"></Button>
<Button Width="300" Margin="30" FontSize="40" Content="直接推理" Command="{Binding SwitchToSimulateViewCommand}"></Button>
<Button Width="300" Margin="30" FontSize="40" Content="导入配置" Command="{Binding ImportStudioConfigCommand}"></Button>
</StackPanel>
</UserControl>

View File

@ -0,0 +1,17 @@
// Copyright (c) Canaan Inc. All rights reserved.
// Licensed under the Apache license. See LICENSE file in the project root for full license information.
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Nncase.Studio.Views
{
public partial class StudioModeView : UserControl
{
public StudioModeView()
{
InitializeComponent();
}
}
}

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<assembly manifestVersion="1.0" xmlns="urn:schemas-microsoft-com:asm.v1">
<!-- This manifest is used on Windows only.
Don't remove it as it might cause problems with window transparency and embeded controls.
For more details visit https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests -->
<assemblyIdentity version="1.0.0.0" name="Nncase.Studio.Desktop"/>
<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1">
<application>
<!-- A list of the Windows versions that this application has been tested on
and is designed to work with. Uncomment the appropriate elements
and Windows will automatically select the most compatible environment. -->
<!-- Windows 10 -->
<supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}" />
</application>
</compatibility>
</assembly>

File diff suppressed because it is too large Load Diff