@@ -0,0 +1 @@ | |||||
* text=auto |
@@ -1,133 +1,133 @@ | |||||
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio Version 16 | |||||
VisualStudioVersion = 16.0.29102.190 | |||||
MinimumVisualStudioVersion = 10.0.40219.1 | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Binding", "src\TensorFlowNET.Core\Tensorflow.Binding.csproj", "{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Benchmark", "src\TensorFlowNet.Benchmarks\Tensorflow.Benchmark.csproj", "{3A6EB896-604F-4E25-B677-B8103BCF3D2E}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.UnitTest", "test\TensorFlowNET.UnitTest\Tensorflow.UnitTest.csproj", "{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Keras", "src\TensorFlowNET.Keras\Tensorflow.Keras.csproj", "{6268B461-486A-460B-9B3C-86493CBBAAF7}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Keras.UnitTest", "test\Tensorflow.Keras.UnitTest\Tensorflow.Keras.UnitTest.csproj", "{EB92DD90-6346-41FB-B967-2B33A860AD98}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Hub", "src\TensorFlowNET.Hub\Tensorflow.Hub.csproj", "{95B077C1-E21B-486F-8BDD-1C902FE687AB}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Any CPU = Debug|Any CPU | |||||
Debug|x64 = Debug|x64 | |||||
Debug-Minimal|Any CPU = Debug-Minimal|Any CPU | |||||
Debug-Minimal|x64 = Debug-Minimal|x64 | |||||
Publish|Any CPU = Publish|Any CPU | |||||
Publish|x64 = Publish|x64 | |||||
Release|Any CPU = Release|Any CPU | |||||
Release|x64 = Release|x64 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|x64.Build.0 = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|x64.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|x64.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|x64.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|x64.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|x64.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|x64.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|x64.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|x64.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|x64.Build.0 = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|Any CPU.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|x64.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|x64.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|x64.Build.0 = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
GlobalSection(ExtensibilityGlobals) = postSolution | |||||
SolutionGuid = {2DEAD3CC-486B-4918-A607-50B0DE7B114A} | |||||
EndGlobalSection | |||||
EndGlobal | |||||
| |||||
Microsoft Visual Studio Solution File, Format Version 12.00 | |||||
# Visual Studio Version 16 | |||||
VisualStudioVersion = 16.0.29102.190 | |||||
MinimumVisualStudioVersion = 10.0.40219.1 | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Binding", "src\TensorFlowNET.Core\Tensorflow.Binding.csproj", "{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Benchmark", "src\TensorFlowNet.Benchmarks\Tensorflow.Benchmark.csproj", "{3A6EB896-604F-4E25-B677-B8103BCF3D2E}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.UnitTest", "test\TensorFlowNET.UnitTest\Tensorflow.UnitTest.csproj", "{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Keras", "src\TensorFlowNET.Keras\Tensorflow.Keras.csproj", "{6268B461-486A-460B-9B3C-86493CBBAAF7}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Keras.UnitTest", "test\Tensorflow.Keras.UnitTest\Tensorflow.Keras.UnitTest.csproj", "{EB92DD90-6346-41FB-B967-2B33A860AD98}" | |||||
EndProject | |||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Tensorflow.Hub", "src\TensorFlowNET.Hub\Tensorflow.Hub.csproj", "{95B077C1-E21B-486F-8BDD-1C902FE687AB}" | |||||
EndProject | |||||
Global | |||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | |||||
Debug|Any CPU = Debug|Any CPU | |||||
Debug|x64 = Debug|x64 | |||||
Debug-Minimal|Any CPU = Debug-Minimal|Any CPU | |||||
Debug-Minimal|x64 = Debug-Minimal|x64 | |||||
Publish|Any CPU = Publish|Any CPU | |||||
Publish|x64 = Publish|x64 | |||||
Release|Any CPU = Release|Any CPU | |||||
Release|x64 = Release|x64 | |||||
EndGlobalSection | |||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Publish|x64.Build.0 = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{FD682AC0-7B2D-45D3-8B0D-C6D678B04144}.Release|x64.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Publish|x64.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{3A6EB896-604F-4E25-B677-B8103BCF3D2E}.Release|x64.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Publish|x64.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{23C28035-2FCE-41F3-9A12-E73CE8A5AE32}.Release|x64.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Publish|x64.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{6268B461-486A-460B-9B3C-86493CBBAAF7}.Release|x64.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|Any CPU.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|Any CPU.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|x64.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Publish|x64.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{EB92DD90-6346-41FB-B967-2B33A860AD98}.Release|x64.Build.0 = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|Any CPU.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|x64.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug|x64.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|Any CPU.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|x64.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Debug-Minimal|x64.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|Any CPU.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|Any CPU.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|x64.ActiveCfg = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Publish|x64.Build.0 = Debug|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|Any CPU.ActiveCfg = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|Any CPU.Build.0 = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|x64.ActiveCfg = Release|Any CPU | |||||
{95B077C1-E21B-486F-8BDD-1C902FE687AB}.Release|x64.Build.0 = Release|Any CPU | |||||
EndGlobalSection | |||||
GlobalSection(SolutionProperties) = preSolution | |||||
HideSolutionNode = FALSE | |||||
EndGlobalSection | |||||
GlobalSection(ExtensibilityGlobals) = postSolution | |||||
SolutionGuid = {2DEAD3CC-486B-4918-A607-50B0DE7B114A} | |||||
EndGlobalSection | |||||
EndGlobal |
@@ -1,3 +1,3 @@ | |||||
TensorFlow.NET logo (c) 2019 by Meinrad Recheis. | |||||
TensorFlow.NET logo (c) 2019 by Meinrad Recheis. | |||||
The logo is based on the original Tensorflow logo which is copyrighted by the respective creator. | The logo is based on the original Tensorflow logo which is copyrighted by the respective creator. |
@@ -364,8 +364,8 @@ namespace Tensorflow | |||||
public Tensor divide<T>(Tensor x, T[] y, string name = null) where T : struct | public Tensor divide<T>(Tensor x, T[] y, string name = null) where T : struct | ||||
=> x / ops.convert_to_tensor(y, dtype: x.dtype.as_base_dtype(), name: "y"); | => x / ops.convert_to_tensor(y, dtype: x.dtype.as_base_dtype(), name: "y"); | ||||
public Tensor pow<T1, T2>(T1 x, T2 y) | |||||
=> gen_math_ops.pow(x, y); | |||||
public Tensor pow<T1, T2>(T1 x, T2 y, string name = "pow") | |||||
=> gen_math_ops.pow(x, y, name: name); | |||||
/// <summary> | /// <summary> | ||||
/// Divides `x / y` elementwise, rounding toward the most negative integer. | /// Divides `x / y` elementwise, rounding toward the most negative integer. | ||||
@@ -33,9 +33,13 @@ namespace Tensorflow.Gradients | |||||
var x = op.inputs[0]; | var x = op.inputs[0]; | ||||
var grad = grads[0]; | var grad = grads[0]; | ||||
return new Tensor[] { gen_ops.mul(grad, gen_math_ops.sign(x)) }; | |||||
return new Tensor[] { grad * math_ops.sign(x) }; | |||||
} | } | ||||
[RegisterGradient("AddV2")] | |||||
public static Tensor[] _AddV2Grad(Operation op, Tensor[] grads) | |||||
=> _AddGrad(op, grads); | |||||
[RegisterGradient("Add")] | [RegisterGradient("Add")] | ||||
public static Tensor[] _AddGrad(Operation op, Tensor[] grads) | public static Tensor[] _AddGrad(Operation op, Tensor[] grads) | ||||
{ | { | ||||
@@ -107,7 +111,9 @@ namespace Tensorflow.Gradients | |||||
var y = op.outputs[0]; // y = e^x | var y = op.outputs[0]; // y = e^x | ||||
return tf_with(ops.control_dependencies(new Operation[] { grad }), dp => { | return tf_with(ops.control_dependencies(new Operation[] { grad }), dp => { | ||||
y = math_ops.conj(y); | y = math_ops.conj(y); | ||||
return new Tensor[] { math_ops.mul_no_nan(y, grad) }; | |||||
// forward_compatible(2019, 9, 14) | |||||
// return new Tensor[] { math_ops.mul_no_nan(y, grad) }; | |||||
return new Tensor[] { grad * y }; | |||||
}); | }); | ||||
} | } | ||||
@@ -167,8 +173,7 @@ namespace Tensorflow.Gradients | |||||
new TF_DataType[] { tf.int32, tf.float32 }.Contains(grad.dtype)) | new TF_DataType[] { tf.int32, tf.float32 }.Contains(grad.dtype)) | ||||
return new Tensor[] { gen_math_ops.mul(grad, y), gen_math_ops.mul(grad, x) }; | return new Tensor[] { gen_math_ops.mul(grad, y), gen_math_ops.mul(grad, x) }; | ||||
var sx = array_ops.shape(x); | |||||
var sy = array_ops.shape(y); | |||||
var (sx, sy) = SmartBroadcastGradientArgs(x, y); | |||||
var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | ||||
x = math_ops.conj(x); | x = math_ops.conj(x); | ||||
@@ -355,8 +360,8 @@ namespace Tensorflow.Gradients | |||||
: gen_math_ops.less_equal(x, y); | : gen_math_ops.less_equal(x, y); | ||||
var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | ||||
var xgrad = array_ops.where(xmask, grad, zeros); | var xgrad = array_ops.where(xmask, grad, zeros); | ||||
var ygrad = array_ops.where(xmask, zeros, grad); | |||||
var gx = array_ops.reshape(math_ops.reduce_sum(xgrad, rx), sx); | var gx = array_ops.reshape(math_ops.reduce_sum(xgrad, rx), sx); | ||||
var ygrad = array_ops.where(xmask, zeros, grad); | |||||
var gy = array_ops.reshape(math_ops.reduce_sum(ygrad, ry), sy); | var gy = array_ops.reshape(math_ops.reduce_sum(ygrad, ry), sy); | ||||
return new Tensor[] { gx, gy }; | return new Tensor[] { gx, gy }; | ||||
} | } | ||||
@@ -397,14 +402,13 @@ namespace Tensorflow.Gradients | |||||
_ShapesFullySpecifiedAndEqual(x, y, grad)) | _ShapesFullySpecifiedAndEqual(x, y, grad)) | ||||
return new Tensor[] { grad, -grad }; | return new Tensor[] { grad, -grad }; | ||||
var sx = array_ops.shape(x); | |||||
var sy = array_ops.shape(y); | |||||
var (sx, sy) = SmartBroadcastGradientArgs(x, y); | |||||
var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | ||||
var r1 = gen_array_ops.reshape(math_ops.reduce_sum(grad, rx), sx); | |||||
var r2 = gen_array_ops.reshape(-math_ops.reduce_sum(grad, ry), sy); | |||||
var gx = array_ops.reshape(math_ops.reduce_sum(grad, rx), sx); | |||||
var gy = array_ops.reshape(math_ops.reduce_sum(-grad, ry), sy); | |||||
return new Tensor[] { r1, r2 }; | |||||
return new Tensor[] { gx, gy }; | |||||
} | } | ||||
public static bool _ShapesFullySpecifiedAndEqual(Tensor x, Tensor y, Tensor grad) | public static bool _ShapesFullySpecifiedAndEqual(Tensor x, Tensor y, Tensor grad) | ||||
@@ -468,15 +472,16 @@ namespace Tensorflow.Gradients | |||||
x = math_ops.conj(x); | x = math_ops.conj(x); | ||||
y = math_ops.conj(y); | y = math_ops.conj(y); | ||||
var realdiv1 = gen_math_ops.real_div(-x, y); | |||||
var realdiv2 = gen_math_ops.real_div(realdiv1, y); | |||||
var reduce_sum1 = math_ops.reduce_sum(grad * realdiv2, ry); | |||||
var reshape1 = gen_array_ops.reshape(reduce_sum1, sy); | |||||
var realdiv3 = gen_math_ops.real_div(grad, y); | |||||
var reduce_sum2 = math_ops.reduce_sum(realdiv3, rx); | |||||
var reshape2 = gen_array_ops.reshape(reduce_sum2, sx); | |||||
var reshape1 = array_ops.reshape( | |||||
math_ops.reduce_sum( | |||||
math_ops.realdiv(grad, y), rx), | |||||
sx); | |||||
var reshape2 = array_ops.reshape( | |||||
math_ops.reduce_sum( | |||||
grad * math_ops.realdiv(math_ops.realdiv(-x, y), y), ry), | |||||
sy); | |||||
return new Tensor[] { reshape2, reshape1 }; | |||||
return new Tensor[] { reshape1, reshape2 }; | |||||
} | } | ||||
[RegisterGradient("Sigmoid")] | [RegisterGradient("Sigmoid")] | ||||
@@ -602,14 +607,12 @@ namespace Tensorflow.Gradients | |||||
var y = op.inputs[1]; | var y = op.inputs[1]; | ||||
var z = op.outputs[0]; | var z = op.outputs[0]; | ||||
var sx = array_ops.shape(x); | |||||
var sy = array_ops.shape(y); | |||||
var (sx, sy) = SmartBroadcastGradientArgs(x, y); | |||||
var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | var (rx, ry) = gen_array_ops.broadcast_gradient_args(sx, sy); | ||||
x = math_ops.conj(x); | x = math_ops.conj(x); | ||||
y = math_ops.conj(y); | y = math_ops.conj(y); | ||||
z = math_ops.conj(z); | z = math_ops.conj(z); | ||||
var pow = gen_math_ops.pow(x, y - 1.0f); | |||||
var mul = grad * y * pow; | |||||
var mul = grad * y * math_ops.pow(x, y - 1.0f); | |||||
var reduce_sum = math_ops.reduce_sum(mul, rx); | var reduce_sum = math_ops.reduce_sum(mul, rx); | ||||
var gx = gen_array_ops.reshape(reduce_sum, sx); | var gx = gen_array_ops.reshape(reduce_sum, sx); | ||||
@@ -630,5 +633,29 @@ namespace Tensorflow.Gradients | |||||
return new Tensor[] { gx, gy }; | return new Tensor[] { gx, gy }; | ||||
} | } | ||||
/// <summary> | |||||
/// Optimized version of `broadcast_gradient_args` that caches results. | |||||
/// </summary> | |||||
/// <param name="x"></param> | |||||
/// <param name="y"></param> | |||||
/// <returns></returns> | |||||
private static (Tensor, Tensor) SmartBroadcastGradientArgs(Tensor x, Tensor y) | |||||
{ | |||||
Tensor sx, sy; | |||||
if (x.TensorShape.is_fully_defined() && | |||||
y.TensorShape.is_fully_defined()) | |||||
{ | |||||
sx = array_ops.shape(x); | |||||
sy = array_ops.shape(y); | |||||
} | |||||
else | |||||
{ | |||||
sx = array_ops.shape_internal(x, optimize: false); | |||||
sy = array_ops.shape_internal(y, optimize: false); | |||||
} | |||||
return (sx, sy); | |||||
} | |||||
} | } | ||||
} | } |
@@ -170,6 +170,14 @@ namespace Tensorflow.Gradients | |||||
public static Tensor[] _FusedBatchNormGrad(Operation op, Tensor[] grads) | public static Tensor[] _FusedBatchNormGrad(Operation op, Tensor[] grads) | ||||
=> _BaseFusedBatchNormGrad(op, 0, grads); | => _BaseFusedBatchNormGrad(op, 0, grads); | ||||
[RegisterGradient("FusedBatchNormV2")] | |||||
public static Tensor[] _FusedBatchNormV2Grad(Operation op, Tensor[] grads) | |||||
=> _BaseFusedBatchNormGrad(op, 1, grads); | |||||
[RegisterGradient("FusedBatchNormV3")] | |||||
public static Tensor[] _FusedBatchNormV3Grad(Operation op, Tensor[] grads) | |||||
=> _BaseFusedBatchNormGrad(op, 2, grads); | |||||
/// <summary> | /// <summary> | ||||
/// Return the gradients for the 3 inputs of BatchNorm. | /// Return the gradients for the 3 inputs of BatchNorm. | ||||
/// </summary> | /// </summary> | ||||
@@ -190,8 +198,10 @@ namespace Tensorflow.Gradients | |||||
switch (version) | switch (version) | ||||
{ | { | ||||
case 2: | case 2: | ||||
throw new NotImplementedException(""); | |||||
grad_fun = gen_nn_ops.fused_batch_norm_grad_v3; | |||||
break; | |||||
case 1: | case 1: | ||||
// grad_fun = gen_nn_ops.fused_batch_norm_grad_v2; | |||||
throw new NotImplementedException(""); | throw new NotImplementedException(""); | ||||
default: | default: | ||||
grad_fun = gen_nn_ops.fused_batch_norm_grad; | grad_fun = gen_nn_ops.fused_batch_norm_grad; | ||||
@@ -225,8 +235,8 @@ namespace Tensorflow.Gradients | |||||
YBackprop = grad_y, | YBackprop = grad_y, | ||||
X = x, | X = x, | ||||
Scale = scale, | Scale = scale, | ||||
ReserveSpace1 = op.outputs[3], | |||||
ReserveSpace2 = op.outputs[4], | |||||
ReserveSpace1 = pop_mean, | |||||
ReserveSpace2 = pop_var, | |||||
ReserveSpace3 = version == 2 ? op.outputs[5] : null, | ReserveSpace3 = version == 2 ? op.outputs[5] : null, | ||||
Epsilon = epsilon, | Epsilon = epsilon, | ||||
DataFormat = data_format, | DataFormat = data_format, | ||||
@@ -1,17 +1,17 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
@@ -77,8 +77,8 @@ namespace Tensorflow | |||||
/// | /// | ||||
/// Use with the `with` keyword to specify that all operations constructed | /// Use with the `with` keyword to specify that all operations constructed | ||||
/// within the context should have control dependencies on | /// within the context should have control dependencies on | ||||
/// `control_inputs`. | |||||
/// </summary> | |||||
/// `control_inputs`. | |||||
/// </summary> | |||||
public _ControlDependenciesController control_dependencies(object[] control_inputs) | public _ControlDependenciesController control_dependencies(object[] control_inputs) | ||||
{ | { | ||||
if (control_inputs == null) | if (control_inputs == null) | ||||
@@ -92,20 +92,20 @@ namespace Tensorflow | |||||
// TODO: implement IndexedSlices | // TODO: implement IndexedSlices | ||||
//case IndexedSlices islice: | //case IndexedSlices islice: | ||||
// control_ops.Add(islice.op); | // control_ops.Add(islice.op); | ||||
// break; | |||||
// break; | |||||
case Tensor t: | case Tensor t: | ||||
control_ops.Add(t.op); | control_ops.Add(t.op); | ||||
break; | break; | ||||
case Operation op: | case Operation op: | ||||
control_ops.Add(op); | control_ops.Add(op); | ||||
break; | |||||
break; | |||||
default: | default: | ||||
var t1 = _as_graph_element(c); | var t1 = _as_graph_element(c); | ||||
if (t1 == null) | if (t1 == null) | ||||
throw new TypeError($"Control input must be Operation or Tensor:{c}"); | throw new TypeError($"Control input must be Operation or Tensor:{c}"); | ||||
control_ops.Add(t1.op); | control_ops.Add(t1.op); | ||||
break; | |||||
} | |||||
break; | |||||
} | |||||
} | } | ||||
return new _ControlDependenciesController(this, control_ops); | return new _ControlDependenciesController(this, control_ops); | ||||
} | } | ||||
@@ -138,9 +138,9 @@ namespace Tensorflow | |||||
_control_dependencies_stack.RemoveAt(_control_dependencies_stack.Count-1); | _control_dependencies_stack.RemoveAt(_control_dependencies_stack.Count-1); | ||||
} | } | ||||
/// <summary> | |||||
/// Record that the given op depends on all registered control dependencies. | |||||
/// </summary> | |||||
/// <summary> | |||||
/// Record that the given op depends on all registered control dependencies. | |||||
/// </summary> | |||||
public void _record_op_seen_by_control_dependencies(Operation op) | public void _record_op_seen_by_control_dependencies(Operation op) | ||||
{ | { | ||||
foreach (var controller in _control_dependencies_stack) | foreach (var controller in _control_dependencies_stack) | ||||
@@ -1,17 +1,17 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using System; | using System; | ||||
@@ -38,8 +38,8 @@ namespace Tensorflow | |||||
public OperationDescription NewOperation(string opType, string opName) | public OperationDescription NewOperation(string opType, string opName) | ||||
{ | { | ||||
return c_api.TF_NewOperation(_handle, opType, opName); | return c_api.TF_NewOperation(_handle, opType, opName); | ||||
} | |||||
} | |||||
public Operation[] ReturnOperations(IntPtr results) | public Operation[] ReturnOperations(IntPtr results) | ||||
{ | { | ||||
TF_Operation return_oper_handle = new TF_Operation(); | TF_Operation return_oper_handle = new TF_Operation(); | ||||
@@ -89,14 +89,14 @@ namespace Tensorflow | |||||
public ITensorOrOperation[] get_operations() | public ITensorOrOperation[] get_operations() | ||||
{ | { | ||||
return _nodes_by_name.Values.ToArray(); | return _nodes_by_name.Values.ToArray(); | ||||
} | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Returns the `Operation` with the given `name`. | /// Returns the `Operation` with the given `name`. | ||||
/// | /// | ||||
/// This method may be called concurrently from multiple threads. | |||||
/// </summary> | |||||
/// <param name="name">The name of the `Operation` to return.</param> | |||||
/// This method may be called concurrently from multiple threads. | |||||
/// </summary> | |||||
/// <param name="name">The name of the `Operation` to return.</param> | |||||
public Operation get_operation_by_name(string name) | public Operation get_operation_by_name(string name) | ||||
=> as_graph_element(name, allow_tensor: false, allow_operation: true) as Operation; | => as_graph_element(name, allow_tensor: false, allow_operation: true) as Operation; | ||||
@@ -109,8 +109,8 @@ namespace Tensorflow | |||||
{ | { | ||||
var op_name = Marshal.PtrToStringAnsi(c_api.TF_OperationName(tf_oper)); | var op_name = Marshal.PtrToStringAnsi(c_api.TF_OperationName(tf_oper)); | ||||
return _get_operation_by_name_unsafe(op_name); | return _get_operation_by_name_unsafe(op_name); | ||||
} | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Creates an `Operation` in this graph from the supplied TF_Operation. | /// Creates an `Operation` in this graph from the supplied TF_Operation. | ||||
/// | /// | ||||
@@ -125,7 +125,7 @@ namespace Tensorflow | |||||
/// </summary> | /// </summary> | ||||
/// <param name="c_op">a wrapped TF_Operation</param> | /// <param name="c_op">a wrapped TF_Operation</param> | ||||
/// <param name="compute_device">(Optional.) If True, device functions will be executed | /// <param name="compute_device">(Optional.) If True, device functions will be executed | ||||
/// to compute the device property of the Operation.</param> | |||||
/// to compute the device property of the Operation.</param> | |||||
/// <returns>An `Operation` object.</returns> | /// <returns>An `Operation` object.</returns> | ||||
public Operation _create_op_from_tf_operation(IntPtr c_op, bool compute_device = true) | public Operation _create_op_from_tf_operation(IntPtr c_op, bool compute_device = true) | ||||
{ | { | ||||
@@ -1,21 +1,21 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using System; | using System; | ||||
using System.Collections; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.Linq; | using System.Linq; | ||||
using System.Runtime.InteropServices; | using System.Runtime.InteropServices; | ||||
@@ -75,7 +75,7 @@ namespace Tensorflow | |||||
/// then create a TensorFlow session to run parts of the graph across a set of local and remote devices. | /// then create a TensorFlow session to run parts of the graph across a set of local and remote devices. | ||||
/// </summary> | /// </summary> | ||||
/// <remarks>https://www.tensorflow.org/guide/graphs <br></br>https://www.tensorflow.org/api_docs/python/tf/Graph</remarks> | /// <remarks>https://www.tensorflow.org/guide/graphs <br></br>https://www.tensorflow.org/api_docs/python/tf/Graph</remarks> | ||||
public partial class Graph : DisposableObject | |||||
public partial class Graph : DisposableObject | |||||
#if !SERIALIZABLE | #if !SERIALIZABLE | ||||
, IEnumerable<Operation> | , IEnumerable<Operation> | ||||
#endif | #endif | ||||
@@ -105,18 +105,18 @@ namespace Tensorflow | |||||
/// </summary> | /// </summary> | ||||
private Dictionary<string, object> _collections = new Dictionary<string, object>(); | private Dictionary<string, object> _collections = new Dictionary<string, object>(); | ||||
public bool building_function; | |||||
int _seed; | |||||
public int seed | |||||
{ | |||||
get => _seed; | |||||
set | |||||
{ | |||||
_seed = value; | |||||
} | |||||
} | |||||
public bool building_function; | |||||
int _seed; | |||||
public int seed | |||||
{ | |||||
get => _seed; | |||||
set | |||||
{ | |||||
_seed = value; | |||||
} | |||||
} | |||||
public Graph() | public Graph() | ||||
{ | { | ||||
_handle = c_api.TF_NewGraph(); | _handle = c_api.TF_NewGraph(); | ||||
@@ -133,20 +133,20 @@ namespace Tensorflow | |||||
_nodes_by_name = new Dictionary<string, ITensorOrOperation>(); | _nodes_by_name = new Dictionary<string, ITensorOrOperation>(); | ||||
_names_in_use = new Dictionary<string, int>(); | _names_in_use = new Dictionary<string, int>(); | ||||
_graph_key = $"grap-key-{ops.uid()}/"; | _graph_key = $"grap-key-{ops.uid()}/"; | ||||
} | |||||
} | |||||
public ITensorOrOperation as_graph_element(object obj, bool allow_tensor = true, bool allow_operation = true) | public ITensorOrOperation as_graph_element(object obj, bool allow_tensor = true, bool allow_operation = true) | ||||
{ | { | ||||
return _as_graph_element_locked(obj, allow_tensor, allow_operation); | return _as_graph_element_locked(obj, allow_tensor, allow_operation); | ||||
} | } | ||||
/// <summary> | |||||
/// Returns a context manager that makes this `Graph` the default graph. | |||||
/// </summary> | |||||
/// <summary> | |||||
/// Returns a context manager that makes this `Graph` the default graph. | |||||
/// </summary> | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public Graph as_default() | |||||
{ | |||||
return ops.set_default_graph(this); | |||||
public Graph as_default() | |||||
{ | |||||
return ops.set_default_graph(this); | |||||
} | } | ||||
private Tensor _as_graph_element(object obj) | private Tensor _as_graph_element(object obj) | ||||
@@ -155,8 +155,8 @@ namespace Tensorflow | |||||
return var._as_graph_element(); | return var._as_graph_element(); | ||||
return null; | return null; | ||||
} | |||||
} | |||||
private ITensorOrOperation _as_graph_element_locked(object obj, bool allow_tensor = true, bool allow_operation = true) | private ITensorOrOperation _as_graph_element_locked(object obj, bool allow_tensor = true, bool allow_operation = true) | ||||
{ | { | ||||
string types_str = ""; | string types_str = ""; | ||||
@@ -259,8 +259,8 @@ namespace Tensorflow | |||||
throw new RuntimeError("Graph is finalized and cannot be modified."); | throw new RuntimeError("Graph is finalized and cannot be modified."); | ||||
} | } | ||||
public Operation create_op(string op_type, Tensor[] inputs, TF_DataType[] dtypes, | |||||
TF_DataType[] input_types = null, string name = null, | |||||
public Operation create_op(string op_type, Tensor[] inputs, TF_DataType[] dtypes, | |||||
TF_DataType[] input_types = null, string name = null, | |||||
Dictionary<string, AttrValue> attrs = null, OpDef op_def = null) | Dictionary<string, AttrValue> attrs = null, OpDef op_def = null) | ||||
{ | { | ||||
if (inputs == null) | if (inputs == null) | ||||
@@ -272,12 +272,12 @@ namespace Tensorflow | |||||
// If a names ends with a '/' it is a "name scope" and we use it as-is, | // If a names ends with a '/' it is a "name scope" and we use it as-is, | ||||
// after removing the trailing '/'. | // after removing the trailing '/'. | ||||
name = name.EndsWith("/") ? ops.name_from_scope_name(name) : unique_name(name); | name = name.EndsWith("/") ? ops.name_from_scope_name(name) : unique_name(name); | ||||
var node_def = ops._NodeDef(op_type, name, device: "", attrs: attrs); | |||||
var node_def = ops._NodeDef(op_type, name, device: "", attrs: attrs); | |||||
var input_ops = inputs.Select(x => x.op).ToArray(); | |||||
var input_ops = inputs.Select(x => x.op).ToArray(); | |||||
var control_inputs = _control_dependencies_for_inputs(input_ops); | var control_inputs = _control_dependencies_for_inputs(input_ops); | ||||
var op = new Operation(node_def, | |||||
var op = new Operation(node_def, | |||||
this, | this, | ||||
inputs: inputs, | inputs: inputs, | ||||
output_types: dtypes, | output_types: dtypes, | ||||
@@ -297,9 +297,9 @@ namespace Tensorflow | |||||
return op; | return op; | ||||
} | } | ||||
public void device(string device_name) | |||||
{ | |||||
throw new NotImplementedException(""); | |||||
public void device(string device_name) | |||||
{ | |||||
throw new NotImplementedException(""); | |||||
} | } | ||||
private void _create_op_helper(Operation op, bool compute_device = true) | private void _create_op_helper(Operation op, bool compute_device = true) | ||||
@@ -353,8 +353,8 @@ namespace Tensorflow | |||||
_name_stack = new_stack; | _name_stack = new_stack; | ||||
return String.IsNullOrEmpty(new_stack) ? "" : new_stack + "/"; | return String.IsNullOrEmpty(new_stack) ? "" : new_stack + "/"; | ||||
} | |||||
} | |||||
/// <summary> | /// <summary> | ||||
/// Return a unique operation name for `name`. | /// Return a unique operation name for `name`. | ||||
/// | /// | ||||
@@ -379,10 +379,10 @@ namespace Tensorflow | |||||
/// <returns>A string to be passed to `create_op()` that will be used | /// <returns>A string to be passed to `create_op()` that will be used | ||||
/// to name the operation being created.</returns> | /// to name the operation being created.</returns> | ||||
public string unique_name(string name, bool mark_as_used = true) | public string unique_name(string name, bool mark_as_used = true) | ||||
{ | |||||
if (name.EndsWith("basic_r_n_n_cell")) | |||||
{ | |||||
{ | |||||
if (name.EndsWith("basic_r_n_n_cell")) | |||||
{ | |||||
} | } | ||||
if (!String.IsNullOrEmpty(_name_stack)) | if (!String.IsNullOrEmpty(_name_stack)) | ||||
name = _name_stack + "/" + name; | name = _name_stack + "/" + name; | ||||
@@ -411,7 +411,7 @@ namespace Tensorflow | |||||
// Return the new name with the original capitalization of the given name. | // Return the new name with the original capitalization of the given name. | ||||
name = $"{name}_{i - 1}"; | name = $"{name}_{i - 1}"; | ||||
} | |||||
} | |||||
return name; | return name; | ||||
} | } | ||||
@@ -424,7 +424,7 @@ namespace Tensorflow | |||||
unsafe | unsafe | ||||
{ | { | ||||
var tf_output_ptr = (TF_Output*)return_output_handle; | var tf_output_ptr = (TF_Output*)return_output_handle; | ||||
for (int i = 0; i < num_return_outputs; i++) | |||||
for (int i = 0; i < num_return_outputs; i++) | |||||
return_outputs[i] = *(tf_output_ptr + i); | return_outputs[i] = *(tf_output_ptr + i); | ||||
return return_outputs; | return return_outputs; | ||||
} | } | ||||
@@ -444,25 +444,25 @@ namespace Tensorflow | |||||
{ | { | ||||
List<T> t = default; | List<T> t = default; | ||||
var collection = _collections.ContainsKey(name) ? _collections[name] : new List<T>(); | var collection = _collections.ContainsKey(name) ? _collections[name] : new List<T>(); | ||||
switch (collection) | |||||
{ | |||||
case List<VariableV1> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<ResourceVariable> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<RefVariable> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<Tensor> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<Operation> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
default: | |||||
throw new NotImplementedException($"get_collection<{typeof(T).FullName}>"); | |||||
switch (collection) | |||||
{ | |||||
case List<VariableV1> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<ResourceVariable> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<RefVariable> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<Tensor> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
case List<Operation> list: | |||||
t = list.Select(x => (T)(object)x).ToList(); | |||||
break; | |||||
default: | |||||
throw new NotImplementedException($"get_collection<{typeof(T).FullName}>"); | |||||
} | } | ||||
return t; | return t; | ||||
} | } | ||||
@@ -482,22 +482,22 @@ namespace Tensorflow | |||||
public void prevent_fetching(Operation op) | public void prevent_fetching(Operation op) | ||||
{ | { | ||||
_unfetchable_ops.Add(op); | _unfetchable_ops.Add(op); | ||||
} | |||||
protected override void DisposeManagedResources() | |||||
{ | |||||
ops.default_graph_stack.remove(this); | |||||
} | |||||
protected override void DisposeUnmanagedResources(IntPtr handle) | |||||
{ | |||||
c_api.TF_DeleteGraph(handle); | |||||
} | } | ||||
public Tensor get_tensor_by_tf_output(TF_Output tf_output) | |||||
{ | |||||
var op = _get_operation_by_tf_operation(tf_output.oper); | |||||
return op.outputs[tf_output.index]; | |||||
protected override void DisposeManagedResources() | |||||
{ | |||||
ops.default_graph_stack.remove(this); | |||||
} | |||||
protected override void DisposeUnmanagedResources(IntPtr handle) | |||||
{ | |||||
c_api.TF_DeleteGraph(handle); | |||||
} | |||||
public Tensor get_tensor_by_tf_output(TF_Output tf_output) | |||||
{ | |||||
var op = _get_operation_by_tf_operation(tf_output.oper); | |||||
return op.outputs[tf_output.index]; | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -510,48 +510,48 @@ namespace Tensorflow | |||||
public Tensor get_tensor_by_name(string name) | public Tensor get_tensor_by_name(string name) | ||||
{ | { | ||||
return (Tensor)this.as_graph_element(name, allow_tensor: true, allow_operation: false); | return (Tensor)this.as_graph_element(name, allow_tensor: true, allow_operation: false); | ||||
} | |||||
public TensorShape GetTensorShape(TF_Output output) | |||||
{ | |||||
var status = new Status(); | |||||
var ndim = c_api.TF_GraphGetTensorNumDims(_handle, output, status); | |||||
status.Check(); | |||||
if (ndim == -1) | |||||
return new TensorShape(); | |||||
var dims = new long[ndim]; | |||||
c_api.TF_GraphGetTensorShape(_handle, output, dims, dims.Length, status); | |||||
status.Check(); | |||||
return new TensorShape(dims.Select(x => (int)x).ToArray()); | |||||
} | |||||
string debugString = string.Empty; | |||||
public override string ToString() | |||||
{ | |||||
return $"{graph_key}, ({_handle})"; | |||||
/*if (string.IsNullOrEmpty(debugString)) | |||||
{ | |||||
int len = 0; | |||||
debugString = c_api.TF_GraphDebugString(_handle, out len); | |||||
} | |||||
return debugString;*/ | |||||
} | |||||
} | |||||
public TensorShape GetTensorShape(TF_Output output) | |||||
{ | |||||
var status = new Status(); | |||||
var ndim = c_api.TF_GraphGetTensorNumDims(_handle, output, status); | |||||
status.Check(); | |||||
if (ndim == -1) | |||||
return new TensorShape(); | |||||
var dims = new long[ndim]; | |||||
c_api.TF_GraphGetTensorShape(_handle, output, dims, dims.Length, status); | |||||
status.Check(); | |||||
return new TensorShape(dims.Select(x => (int)x).ToArray()); | |||||
} | |||||
string debugString = string.Empty; | |||||
public override string ToString() | |||||
{ | |||||
return $"{graph_key}, ({_handle})"; | |||||
/*if (string.IsNullOrEmpty(debugString)) | |||||
{ | |||||
int len = 0; | |||||
debugString = c_api.TF_GraphDebugString(_handle, out len); | |||||
} | |||||
return debugString;*/ | |||||
} | |||||
#if !SERIALIZABLE | #if !SERIALIZABLE | ||||
private IEnumerable<Operation> GetEnumerable() | |||||
private IEnumerable<Operation> GetEnumerable() | |||||
=> c_api_util.tf_operations(this); | => c_api_util.tf_operations(this); | ||||
IEnumerator<Operation> IEnumerable<Operation>.GetEnumerator() | |||||
=> GetEnumerable().GetEnumerator(); | |||||
IEnumerator IEnumerable.GetEnumerator() | |||||
=> throw new NotImplementedException(); | |||||
IEnumerator<Operation> IEnumerable<Operation>.GetEnumerator() | |||||
=> GetEnumerable().GetEnumerator(); | |||||
IEnumerator IEnumerable.GetEnumerator() | |||||
=> throw new NotImplementedException(); | |||||
#endif | #endif | ||||
public static implicit operator IntPtr(Graph graph) | public static implicit operator IntPtr(Graph graph) | ||||
{ | { | ||||
return graph._handle; | return graph._handle; | ||||
@@ -1,17 +1,17 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
@@ -32,8 +32,8 @@ namespace Tensorflow | |||||
private bool _new_stack; | private bool _new_stack; | ||||
private ControlFlowContext _old_control_flow_context; | private ControlFlowContext _old_control_flow_context; | ||||
public ITensorOrOperation[] control_inputs => _control_inputs_val.ToArray(); | |||||
public ITensorOrOperation[] control_inputs => _control_inputs_val.ToArray(); | |||||
/// <summary> | /// <summary> | ||||
/// Create a new `_ControlDependenciesController`. | /// Create a new `_ControlDependenciesController`. | ||||
/// | /// | ||||
@@ -69,7 +69,7 @@ namespace Tensorflow | |||||
_new_stack = false; | _new_stack = false; | ||||
} | } | ||||
_seen_nodes = new List<ITensorOrOperation>(); | |||||
_seen_nodes = new List<ITensorOrOperation>(); | |||||
_old_stack = null; | _old_stack = null; | ||||
_old_control_flow_context = null; | _old_control_flow_context = null; | ||||
} | } | ||||
@@ -113,16 +113,16 @@ namespace Tensorflow | |||||
public void Dispose() | public void Dispose() | ||||
{ | { | ||||
} | |||||
public void __init__() | |||||
{ | |||||
} | |||||
public void __del__() | |||||
{ | |||||
} | |||||
} | |||||
public void __init__() | |||||
{ | |||||
} | |||||
public void __del__() | |||||
{ | |||||
} | |||||
} | } | ||||
} | } |
@@ -1,324 +1,324 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Linq; | |||||
using System.Collections.Generic; | |||||
using util = Tensorflow.control_flow_util; | |||||
using static Tensorflow.Binding; | |||||
namespace Tensorflow.Operations.ControlFlows | |||||
{ | |||||
/// <summary> | |||||
/// Maintain the mapping from the loops to their grad states. | |||||
/// </summary> | |||||
public class ControlFlowState | |||||
{ | |||||
Dictionary<ControlFlowContext, GradLoopState> _map; | |||||
//class ControlFlowState(object): | |||||
// """Maintain the mapping from the loops to their grad states.""" | |||||
// def __init__(self): | |||||
// self._map = {} # maps forward loop context to GradLoopState | |||||
// def GetGradState(self, op, before): | |||||
// """Return the grad state for this op if it's in a forward loop context.""" | |||||
// if before and util.IsLoopExit(op): | |||||
// forward_ctxt = op._get_control_flow_context() | |||||
// forward_ctxt = forward_ctxt.outer_context | |||||
// if forward_ctxt: | |||||
// forward_ctxt = forward_ctxt.GetWhileContext() | |||||
// else: | |||||
// forward_ctxt = _GetWhileContext(op) | |||||
// if forward_ctxt: | |||||
// return self._map.get(forward_ctxt) | |||||
// return None | |||||
public ControlFlowState() | |||||
{ | |||||
_map = new Dictionary<ControlFlowContext, GradLoopState>(); | |||||
} | |||||
/// <summary> | |||||
/// Return the grad state for this op if it's in a forward loop context. | |||||
/// </summary> | |||||
/// <param name="op"></param> | |||||
/// <param name="before"></param> | |||||
/// <returns></returns> | |||||
public GradLoopState GetGradState(Operation op, bool before) | |||||
{ | |||||
ControlFlowContext forward_ctxt = null; | |||||
if (before && util.IsLoopExit(op)) | |||||
{ | |||||
forward_ctxt = op._get_control_flow_context(); | |||||
forward_ctxt = forward_ctxt.outer_context; | |||||
if (forward_ctxt != null) | |||||
forward_ctxt = forward_ctxt.GetWhileContext(); | |||||
} | |||||
else | |||||
forward_ctxt = util.GetWhileContext(op); | |||||
if (forward_ctxt != null) | |||||
return _map.get(forward_ctxt); | |||||
return null; | |||||
} | |||||
public Tensor[] ProcessUnusedLoopExits(Dictionary<string, int> pending_count, List<Operation> to_ops_set) | |||||
{ | |||||
var loop_exits = new List<Tensor>(); | |||||
foreach(var grad_state in _map.Values) | |||||
{ | |||||
foreach(var y in grad_state.forward_loop_exits) | |||||
{ | |||||
if(!pending_count.ContainsKey(y.op.name)) | |||||
{ | |||||
grad_state.pending_exits_count -= 1; | |||||
if (!to_ops_set.Contains(y.op)) | |||||
grad_state.unused_exits.append(y); | |||||
if (grad_state.pending_exits_count == 0) | |||||
loop_exits.extend(grad_state.unused_exits); | |||||
} | |||||
} | |||||
foreach(var y in grad_state.forward_context.loop_enters) | |||||
{ | |||||
if (!pending_count.ContainsKey(y.op.name)) | |||||
pending_count[y.op.name] = 1; | |||||
} | |||||
} | |||||
return loop_exits.ToArray(); | |||||
} | |||||
public void EnterGradWhileContext(Operation op, bool before) | |||||
{ | |||||
var grad_state = GetGradState(op, before); | |||||
if (grad_state != null) | |||||
grad_state.grad_context.Enter(); | |||||
} | |||||
public void ExitGradWhileContext(Operation op, bool before) | |||||
{ | |||||
var grad_state = GetGradState(op, before); | |||||
if (grad_state != null) | |||||
grad_state.grad_context.Exit(); | |||||
} | |||||
// def AddWhileContext(self, op, between_op_list, between_ops): | |||||
// """Add the grad state for the while loop that op belongs to. | |||||
// Note that op is an Exit, and this method must be called in | |||||
// the control flow context where gradients() is called. | |||||
// Note that this method modifies `between_op_list` and `between_ops`. | |||||
// """ | |||||
// forward_ctxt = _GetWhileContext(op) | |||||
// grad_state = self._map.get(forward_ctxt) | |||||
// if grad_state is None: | |||||
// # This is a new while loop so create a grad state for it. | |||||
// outer_forward_ctxt = forward_ctxt.outer_context | |||||
// if outer_forward_ctxt: | |||||
// outer_forward_ctxt = outer_forward_ctxt.GetWhileContext() | |||||
// outer_grad_state = None | |||||
// if outer_forward_ctxt: | |||||
// outer_grad_state = self._map.get(outer_forward_ctxt) | |||||
// grad_state = GradLoopState(forward_ctxt, outer_grad_state) | |||||
// self._map[forward_ctxt] = grad_state | |||||
// # We need to include all exits of a loop for backprop. | |||||
// for loop_exit in grad_state.forward_loop_exits: | |||||
// if loop_exit.op not in between_ops: | |||||
// between_ops.add(loop_exit.op) | |||||
// between_op_list.append(loop_exit.op) | |||||
public void AddWhileContext(Operation op, List<Operation> between_op_list, List<Operation> between_ops) | |||||
{ | |||||
var forward_ctxt = op.GetWhileContext(); | |||||
var grad_state = _map.ContainsKey(forward_ctxt) ? _map[forward_ctxt] : null; | |||||
if(grad_state == null) | |||||
{ | |||||
GradLoopState outer_grad_state = null; | |||||
var outer_forward_ctxt = forward_ctxt.outer_context; | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt = outer_forward_ctxt.GetWhileContext(); | |||||
if (outer_forward_ctxt != null) | |||||
outer_grad_state = _map[outer_forward_ctxt]; | |||||
grad_state = new GradLoopState(forward_ctxt, outer_grad_state); | |||||
_map[forward_ctxt] = grad_state; | |||||
// We need to include all exits of a loop for backprop. | |||||
foreach (var loop_exit in grad_state.forward_loop_exits) | |||||
{ | |||||
if(!between_ops.Contains(loop_exit.op)) | |||||
{ | |||||
between_ops.add(loop_exit.op); | |||||
between_op_list.append(loop_exit.op); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// def ZerosLikeForExit(self, val): | |||||
// """Create zeros_like gradient for a loop exit. | |||||
// If the result of a loop variable is not used but is involved in | |||||
// computing the result of some needed loop variable, we create a | |||||
// zero-valued tensor that is fed as gradient for the Exit node of that | |||||
// loop variable. Note that val.op is an Exit, and this method must be | |||||
// called in the control flow context where gradients() is called. | |||||
// Args: | |||||
// val: The output tensor of an Exit op. | |||||
// Returns: | |||||
// A zero tensor of the same shape of val. | |||||
// """ | |||||
// val_shape = val.get_shape() | |||||
// forward_ctxt = val.op._get_control_flow_context() | |||||
// outer_forward_ctxt = forward_ctxt.outer_context | |||||
// if outer_forward_ctxt: | |||||
// outer_forward_ctxt = outer_forward_ctxt.GetWhileContext() | |||||
// outer_grad_state = None | |||||
// if outer_forward_ctxt: | |||||
// outer_grad_state = self._map.get(outer_forward_ctxt) | |||||
// if outer_grad_state: | |||||
// # This is a nested loop. | |||||
// if val_shape.is_fully_defined(): | |||||
// # If the shape is known statically, just create a zero tensor | |||||
// # with the right shape in the right context. | |||||
// outer_grad_state.grad_context.Enter() | |||||
// result = array_ops.zeros(val_shape.dims, val.dtype) | |||||
// outer_grad_state.grad_context.Exit() | |||||
// else: | |||||
// # Only the shape of value is needed for backprop. | |||||
// forward_ctxt.outer_context.Enter() | |||||
// shape = array_ops.shape_internal(val, optimize=False) | |||||
// forward_ctxt.outer_context.Exit() | |||||
// # Save the shape to a stack. | |||||
// history_shape = outer_grad_state.AddForwardAccumulator(shape) | |||||
// # Get the shape back from the stack. | |||||
// outer_grad_ctxt = outer_grad_state.grad_context | |||||
// outer_grad_ctxt.Enter() | |||||
// real_shape = outer_grad_state.AddBackpropAccumulatedValue( | |||||
// history_shape, shape) | |||||
// result = array_ops.zeros(real_shape, val.dtype) | |||||
// outer_grad_ctxt.Exit() | |||||
// else: | |||||
// # This is not a nested loop. | |||||
// if val_shape.is_fully_defined(): | |||||
// # If the shape is known statically, just create a zero tensor | |||||
// # with the right shape. | |||||
// result = array_ops.zeros(val_shape.dims, val.dtype) | |||||
// else: | |||||
// result = array_ops.zeros_like(val, optimize=False) | |||||
// return result | |||||
public Tensor ZerosLike(Operation op, int index) | |||||
{ | |||||
if (util.IsLoopSwitch(op)) | |||||
return null; | |||||
if (op.graph.building_function) | |||||
return array_ops.zeros_like(op.outputs[index]); | |||||
var dead_branch = util.IsSwitch(op); | |||||
var forward_ctxt = util.GetWhileContext(op); | |||||
var grad_state = _map.get(forward_ctxt); | |||||
// op is not in a while loop that is part of gradients(). | |||||
if (grad_state == null) | |||||
return ZerosLikeOutsideLoop(op, index); | |||||
throw new NotImplementedException("ZerosLike"); | |||||
} | |||||
public Tensor ZerosLikeOutsideLoop(Operation op, int index) | |||||
{ | |||||
var val = op.outputs[index]; | |||||
if (!util.IsSwitch(op)) | |||||
{ | |||||
if (val.dtype == dtypes.resource) | |||||
throw new NotImplementedException("ZerosLikeOutsideLoop"); | |||||
/*return array_ops.zeros( | |||||
gen_resource_variable_ops.variable_shape(val), | |||||
dtype: default_gradient.get_zeros_dtype(val));*/ | |||||
return array_ops.zeros_like(val, optimize: false); | |||||
} | |||||
else | |||||
throw new NotImplementedException("ZerosLikeOutsideLoop"); | |||||
} | |||||
/// <summary> | |||||
/// Create zeros_like gradient for a loop exit. | |||||
/// </summary> | |||||
/// <param name="val"></param> | |||||
/// <returns></returns> | |||||
public Tensor ZerosLikeForExit(Tensor val) | |||||
{ | |||||
Tensor result = null; | |||||
var val_shape = val.TensorShape; | |||||
var forward_ctxt = val.op._get_control_flow_context(); | |||||
var outer_forward_ctxt = forward_ctxt.outer_context; | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt = outer_forward_ctxt.GetWhileContext(); | |||||
GradLoopState outer_grad_state = null; | |||||
if (outer_forward_ctxt != null) | |||||
outer_grad_state = _map.get(outer_forward_ctxt); | |||||
// This is a nested loop. | |||||
if (outer_grad_state != null) | |||||
{ | |||||
throw new NotImplementedException("ZerosLikeForExit"); | |||||
} | |||||
else | |||||
{ | |||||
// If the shape is known statically, just create a zero tensor | |||||
// with the right shape. | |||||
if (val_shape.is_fully_defined()) | |||||
result = array_ops.zeros(val_shape.dims, val.dtype); | |||||
else | |||||
result = array_ops.zeros_like(val, optimize: false); | |||||
} | |||||
return result; | |||||
} | |||||
public void PostProcessing() | |||||
{ | |||||
foreach(var grad_state in _map.Values) | |||||
{ | |||||
foreach(var b_merge in grad_state.switch_map.Values) | |||||
{ | |||||
if(b_merge.op.inputs[0] == b_merge.op.inputs[1]) | |||||
{ | |||||
Tensor next_grad_val = null; | |||||
// The value of this loop variable at iteration i+1 doesn't | |||||
// depend on its value at iteration i. So use zeros as the | |||||
// gradients for all iterations > 0. | |||||
var dtype = b_merge.op.inputs[0].dtype; | |||||
var shape = b_merge.op.inputs[0].TensorShape; | |||||
if (shape.is_fully_defined()) | |||||
{ | |||||
grad_state.grad_context.Enter(); | |||||
// Create a zeros and use it for iterations > 0. | |||||
var grad_val = constant_op.constant(0, dtype: dtype, shape: shape); | |||||
next_grad_val = control_flow_ops._NextIteration(grad_val); | |||||
grad_state.grad_context.Exit(); | |||||
} | |||||
else | |||||
{ | |||||
throw new NotImplementedException("PostProcessing shape is not fully defined."); | |||||
} | |||||
b_merge.op._update_input(1, next_grad_val); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Linq; | |||||
using System.Collections.Generic; | |||||
using util = Tensorflow.control_flow_util; | |||||
using static Tensorflow.Binding; | |||||
namespace Tensorflow.Operations.ControlFlows | |||||
{ | |||||
/// <summary> | |||||
/// Maintain the mapping from the loops to their grad states. | |||||
/// </summary> | |||||
public class ControlFlowState | |||||
{ | |||||
Dictionary<ControlFlowContext, GradLoopState> _map; | |||||
//class ControlFlowState(object): | |||||
// """Maintain the mapping from the loops to their grad states.""" | |||||
// def __init__(self): | |||||
// self._map = {} # maps forward loop context to GradLoopState | |||||
// def GetGradState(self, op, before): | |||||
// """Return the grad state for this op if it's in a forward loop context.""" | |||||
// if before and util.IsLoopExit(op): | |||||
// forward_ctxt = op._get_control_flow_context() | |||||
// forward_ctxt = forward_ctxt.outer_context | |||||
// if forward_ctxt: | |||||
// forward_ctxt = forward_ctxt.GetWhileContext() | |||||
// else: | |||||
// forward_ctxt = _GetWhileContext(op) | |||||
// if forward_ctxt: | |||||
// return self._map.get(forward_ctxt) | |||||
// return None | |||||
public ControlFlowState() | |||||
{ | |||||
_map = new Dictionary<ControlFlowContext, GradLoopState>(); | |||||
} | |||||
/// <summary> | |||||
/// Return the grad state for this op if it's in a forward loop context. | |||||
/// </summary> | |||||
/// <param name="op"></param> | |||||
/// <param name="before"></param> | |||||
/// <returns></returns> | |||||
public GradLoopState GetGradState(Operation op, bool before) | |||||
{ | |||||
ControlFlowContext forward_ctxt = null; | |||||
if (before && util.IsLoopExit(op)) | |||||
{ | |||||
forward_ctxt = op._get_control_flow_context(); | |||||
forward_ctxt = forward_ctxt.outer_context; | |||||
if (forward_ctxt != null) | |||||
forward_ctxt = forward_ctxt.GetWhileContext(); | |||||
} | |||||
else | |||||
forward_ctxt = util.GetWhileContext(op); | |||||
if (forward_ctxt != null) | |||||
return _map.get(forward_ctxt); | |||||
return null; | |||||
} | |||||
public Tensor[] ProcessUnusedLoopExits(Dictionary<string, int> pending_count, List<Operation> to_ops_set) | |||||
{ | |||||
var loop_exits = new List<Tensor>(); | |||||
foreach(var grad_state in _map.Values) | |||||
{ | |||||
foreach(var y in grad_state.forward_loop_exits) | |||||
{ | |||||
if(!pending_count.ContainsKey(y.op.name)) | |||||
{ | |||||
grad_state.pending_exits_count -= 1; | |||||
if (!to_ops_set.Contains(y.op)) | |||||
grad_state.unused_exits.append(y); | |||||
if (grad_state.pending_exits_count == 0) | |||||
loop_exits.extend(grad_state.unused_exits); | |||||
} | |||||
} | |||||
foreach(var y in grad_state.forward_context.loop_enters) | |||||
{ | |||||
if (!pending_count.ContainsKey(y.op.name)) | |||||
pending_count[y.op.name] = 1; | |||||
} | |||||
} | |||||
return loop_exits.ToArray(); | |||||
} | |||||
public void EnterGradWhileContext(Operation op, bool before) | |||||
{ | |||||
var grad_state = GetGradState(op, before); | |||||
if (grad_state != null) | |||||
grad_state.grad_context.Enter(); | |||||
} | |||||
public void ExitGradWhileContext(Operation op, bool before) | |||||
{ | |||||
var grad_state = GetGradState(op, before); | |||||
if (grad_state != null) | |||||
grad_state.grad_context.Exit(); | |||||
} | |||||
// def AddWhileContext(self, op, between_op_list, between_ops): | |||||
// """Add the grad state for the while loop that op belongs to. | |||||
// Note that op is an Exit, and this method must be called in | |||||
// the control flow context where gradients() is called. | |||||
// Note that this method modifies `between_op_list` and `between_ops`. | |||||
// """ | |||||
// forward_ctxt = _GetWhileContext(op) | |||||
// grad_state = self._map.get(forward_ctxt) | |||||
// if grad_state is None: | |||||
// # This is a new while loop so create a grad state for it. | |||||
// outer_forward_ctxt = forward_ctxt.outer_context | |||||
// if outer_forward_ctxt: | |||||
// outer_forward_ctxt = outer_forward_ctxt.GetWhileContext() | |||||
// outer_grad_state = None | |||||
// if outer_forward_ctxt: | |||||
// outer_grad_state = self._map.get(outer_forward_ctxt) | |||||
// grad_state = GradLoopState(forward_ctxt, outer_grad_state) | |||||
// self._map[forward_ctxt] = grad_state | |||||
// # We need to include all exits of a loop for backprop. | |||||
// for loop_exit in grad_state.forward_loop_exits: | |||||
// if loop_exit.op not in between_ops: | |||||
// between_ops.add(loop_exit.op) | |||||
// between_op_list.append(loop_exit.op) | |||||
public void AddWhileContext(Operation op, List<Operation> between_op_list, List<Operation> between_ops) | |||||
{ | |||||
var forward_ctxt = op.GetWhileContext(); | |||||
var grad_state = _map.ContainsKey(forward_ctxt) ? _map[forward_ctxt] : null; | |||||
if(grad_state == null) | |||||
{ | |||||
GradLoopState outer_grad_state = null; | |||||
var outer_forward_ctxt = forward_ctxt.outer_context; | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt = outer_forward_ctxt.GetWhileContext(); | |||||
if (outer_forward_ctxt != null) | |||||
outer_grad_state = _map[outer_forward_ctxt]; | |||||
grad_state = new GradLoopState(forward_ctxt, outer_grad_state); | |||||
_map[forward_ctxt] = grad_state; | |||||
// We need to include all exits of a loop for backprop. | |||||
foreach (var loop_exit in grad_state.forward_loop_exits) | |||||
{ | |||||
if(!between_ops.Contains(loop_exit.op)) | |||||
{ | |||||
between_ops.add(loop_exit.op); | |||||
between_op_list.append(loop_exit.op); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
// def ZerosLikeForExit(self, val): | |||||
// """Create zeros_like gradient for a loop exit. | |||||
// If the result of a loop variable is not used but is involved in | |||||
// computing the result of some needed loop variable, we create a | |||||
// zero-valued tensor that is fed as gradient for the Exit node of that | |||||
// loop variable. Note that val.op is an Exit, and this method must be | |||||
// called in the control flow context where gradients() is called. | |||||
// Args: | |||||
// val: The output tensor of an Exit op. | |||||
// Returns: | |||||
// A zero tensor of the same shape of val. | |||||
// """ | |||||
// val_shape = val.get_shape() | |||||
// forward_ctxt = val.op._get_control_flow_context() | |||||
// outer_forward_ctxt = forward_ctxt.outer_context | |||||
// if outer_forward_ctxt: | |||||
// outer_forward_ctxt = outer_forward_ctxt.GetWhileContext() | |||||
// outer_grad_state = None | |||||
// if outer_forward_ctxt: | |||||
// outer_grad_state = self._map.get(outer_forward_ctxt) | |||||
// if outer_grad_state: | |||||
// # This is a nested loop. | |||||
// if val_shape.is_fully_defined(): | |||||
// # If the shape is known statically, just create a zero tensor | |||||
// # with the right shape in the right context. | |||||
// outer_grad_state.grad_context.Enter() | |||||
// result = array_ops.zeros(val_shape.dims, val.dtype) | |||||
// outer_grad_state.grad_context.Exit() | |||||
// else: | |||||
// # Only the shape of value is needed for backprop. | |||||
// forward_ctxt.outer_context.Enter() | |||||
// shape = array_ops.shape_internal(val, optimize=False) | |||||
// forward_ctxt.outer_context.Exit() | |||||
// # Save the shape to a stack. | |||||
// history_shape = outer_grad_state.AddForwardAccumulator(shape) | |||||
// # Get the shape back from the stack. | |||||
// outer_grad_ctxt = outer_grad_state.grad_context | |||||
// outer_grad_ctxt.Enter() | |||||
// real_shape = outer_grad_state.AddBackpropAccumulatedValue( | |||||
// history_shape, shape) | |||||
// result = array_ops.zeros(real_shape, val.dtype) | |||||
// outer_grad_ctxt.Exit() | |||||
// else: | |||||
// # This is not a nested loop. | |||||
// if val_shape.is_fully_defined(): | |||||
// # If the shape is known statically, just create a zero tensor | |||||
// # with the right shape. | |||||
// result = array_ops.zeros(val_shape.dims, val.dtype) | |||||
// else: | |||||
// result = array_ops.zeros_like(val, optimize=False) | |||||
// return result | |||||
public Tensor ZerosLike(Operation op, int index) | |||||
{ | |||||
if (util.IsLoopSwitch(op)) | |||||
return null; | |||||
if (op.graph.building_function) | |||||
return array_ops.zeros_like(op.outputs[index]); | |||||
var dead_branch = util.IsSwitch(op); | |||||
var forward_ctxt = util.GetWhileContext(op); | |||||
var grad_state = _map.get(forward_ctxt); | |||||
// op is not in a while loop that is part of gradients(). | |||||
if (grad_state == null) | |||||
return ZerosLikeOutsideLoop(op, index); | |||||
throw new NotImplementedException("ZerosLike"); | |||||
} | |||||
public Tensor ZerosLikeOutsideLoop(Operation op, int index) | |||||
{ | |||||
var val = op.outputs[index]; | |||||
if (!util.IsSwitch(op)) | |||||
{ | |||||
if (val.dtype == dtypes.resource) | |||||
throw new NotImplementedException("ZerosLikeOutsideLoop"); | |||||
/*return array_ops.zeros( | |||||
gen_resource_variable_ops.variable_shape(val), | |||||
dtype: default_gradient.get_zeros_dtype(val));*/ | |||||
return array_ops.zeros_like(val, optimize: false); | |||||
} | |||||
else | |||||
throw new NotImplementedException("ZerosLikeOutsideLoop"); | |||||
} | |||||
/// <summary> | |||||
/// Create zeros_like gradient for a loop exit. | |||||
/// </summary> | |||||
/// <param name="val"></param> | |||||
/// <returns></returns> | |||||
public Tensor ZerosLikeForExit(Tensor val) | |||||
{ | |||||
Tensor result = null; | |||||
var val_shape = val.TensorShape; | |||||
var forward_ctxt = val.op._get_control_flow_context(); | |||||
var outer_forward_ctxt = forward_ctxt.outer_context; | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt = outer_forward_ctxt.GetWhileContext(); | |||||
GradLoopState outer_grad_state = null; | |||||
if (outer_forward_ctxt != null) | |||||
outer_grad_state = _map.get(outer_forward_ctxt); | |||||
// This is a nested loop. | |||||
if (outer_grad_state != null) | |||||
{ | |||||
throw new NotImplementedException("ZerosLikeForExit"); | |||||
} | |||||
else | |||||
{ | |||||
// If the shape is known statically, just create a zero tensor | |||||
// with the right shape. | |||||
if (val_shape.is_fully_defined()) | |||||
result = array_ops.zeros(val_shape.dims, val.dtype); | |||||
else | |||||
result = array_ops.zeros_like(val, optimize: false); | |||||
} | |||||
return result; | |||||
} | |||||
public void PostProcessing() | |||||
{ | |||||
foreach(var grad_state in _map.Values) | |||||
{ | |||||
foreach(var b_merge in grad_state.switch_map.Values) | |||||
{ | |||||
if(b_merge.op.inputs[0] == b_merge.op.inputs[1]) | |||||
{ | |||||
Tensor next_grad_val = null; | |||||
// The value of this loop variable at iteration i+1 doesn't | |||||
// depend on its value at iteration i. So use zeros as the | |||||
// gradients for all iterations > 0. | |||||
var dtype = b_merge.op.inputs[0].dtype; | |||||
var shape = b_merge.op.inputs[0].TensorShape; | |||||
if (shape.is_fully_defined()) | |||||
{ | |||||
grad_state.grad_context.Enter(); | |||||
// Create a zeros and use it for iterations > 0. | |||||
var grad_val = constant_op.constant(0, dtype: dtype, shape: shape); | |||||
next_grad_val = control_flow_ops._NextIteration(grad_val); | |||||
grad_state.grad_context.Exit(); | |||||
} | |||||
else | |||||
{ | |||||
throw new NotImplementedException("PostProcessing shape is not fully defined."); | |||||
} | |||||
b_merge.op._update_input(1, next_grad_val); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,335 +1,335 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using static Tensorflow.Binding; | |||||
using util = Tensorflow.control_flow_util; | |||||
namespace Tensorflow.Operations.ControlFlows | |||||
{ | |||||
/// <summary> | |||||
/// The state used for constructing the gradient graph for a while loop. | |||||
/// </summary> | |||||
public class GradLoopState | |||||
{ | |||||
private WhileContext _grad_context = null; | |||||
public WhileContext grad_context => _grad_context; | |||||
// # The loop counter added by AddBackpropLoopCounter. It is the value | |||||
// # of the loop counter for the current iteration. | |||||
// self._grad_index = None | |||||
// # A sync op for backprop. | |||||
// self._grad_sync = None | |||||
// # Information needed by backprop. | |||||
private Hashtable _history_map = new Hashtable(); | |||||
public Hashtable history_map => _history_map; | |||||
Dictionary<Operation, Tensor> _switch_map = new Dictionary<Operation, Tensor>(); | |||||
public Dictionary<Operation, Tensor> switch_map => _switch_map; | |||||
/// <summary> | |||||
/// The while loop context for forward. | |||||
/// </summary> | |||||
WhileContext _forward_context; | |||||
public WhileContext forward_context => _forward_context; | |||||
/// <summary> | |||||
/// The grad loop state for the outer while loop. | |||||
/// </summary> | |||||
GradLoopState _outer_grad_state; | |||||
public GradLoopState outer_grad_state => _outer_grad_state; | |||||
Tensor _forward_index; | |||||
public Tensor forward_index => _forward_index; | |||||
Tensor _grad_index; | |||||
Tensor[] _forward_loop_exits; | |||||
/// <summary> | |||||
/// The list of exits of the forward loop. | |||||
/// </summary> | |||||
public Tensor[] forward_loop_exits => _forward_loop_exits; | |||||
List<Tensor> _deferred_exits; | |||||
public List<Tensor> deferred_exits => _deferred_exits; | |||||
List<Tensor> _unused_exits; | |||||
public List<Tensor> unused_exits => _unused_exits; | |||||
/// <summary> | |||||
/// The number of exits we expect to see but haven't. | |||||
/// </summary> | |||||
public int pending_exits_count { get; set; } | |||||
Operation _grad_sync; | |||||
public Operation grad_sync | |||||
{ | |||||
get | |||||
{ | |||||
if(_grad_sync == null) | |||||
{ | |||||
tf_with(ops.control_dependencies(null), delegate | |||||
{ | |||||
_grad_sync = gen_control_flow_ops.control_trigger(name: "b_sync"); | |||||
}); | |||||
_grad_sync._set_control_flow_context(_grad_context); | |||||
_grad_index.op._add_control_input(_grad_sync); | |||||
if (_grad_context.outer_context != null) | |||||
_grad_context.outer_context.AddInnerOp(_grad_sync); | |||||
} | |||||
return _grad_sync; | |||||
} | |||||
} | |||||
public GradLoopState(WhileContext forward_ctxt, GradLoopState outer_grad_state_) | |||||
{ | |||||
// Information needed by backprop. | |||||
_unused_exits = new List<Tensor>(); | |||||
_deferred_exits = new List<Tensor>(); | |||||
_forward_loop_exits = list(forward_ctxt.loop_exits); | |||||
pending_exits_count = len(forward_ctxt.loop_exits); | |||||
_outer_grad_state = outer_grad_state_; | |||||
ControlFlowContext outer_forward_ctxt = null; | |||||
if (outer_grad_state_ != null) | |||||
outer_forward_ctxt = outer_grad_state_.forward_context; | |||||
// Add the forward loop counter. | |||||
// with forward_ctxt._graph.as_default(): | |||||
Tensor cnt, forward_index; | |||||
{ | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Enter(); | |||||
(cnt, forward_index) = forward_ctxt.AddForwardLoopCounter(outer_grad_state); | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Exit(); | |||||
} | |||||
_forward_context = forward_ctxt; | |||||
_forward_index = forward_index; | |||||
// Add the backprop WhileContext, and the backprop loop counter. | |||||
if (outer_grad_state != null) | |||||
{ | |||||
// This is a nested loop. Remember the iteration counts for each | |||||
// execution of this inner loop. | |||||
throw new NotImplementedException("GradLoopState"); | |||||
} | |||||
else | |||||
{ | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Enter(); | |||||
_grad_context = new WhileContext( | |||||
maximum_iterations: forward_ctxt.maximum_iterations, | |||||
parallel_iterations: forward_ctxt.parallel_iterations, | |||||
back_prop: forward_ctxt.back_prop, | |||||
swap_memory: forward_ctxt.swap_memory, | |||||
name: forward_ctxt.name, | |||||
grad_state: this); | |||||
_grad_index = _grad_context.AddBackpropLoopCounter(cnt, outer_grad_state); | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Exit(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Add an accumulator for each forward tensor that is needed in backprop. | |||||
/// | |||||
/// This is added to the forward loop at the first time when a tensor | |||||
/// in the forward loop is used by backprop gradient computation loop. | |||||
/// We create an accumulator that accumulates the value of tensor at each | |||||
/// iteration. Called in the control flow context where gradients() is called. | |||||
/// | |||||
/// The pseudocode is: | |||||
/// ``` | |||||
/// acc = stack(); | |||||
/// while (_pivot) { | |||||
/// acc = stack_push(acc, value); | |||||
/// } | |||||
/// ``` | |||||
/// | |||||
/// We make sure that the stack push op in one iteration is executed before | |||||
/// next iteration. This is achieved by adding a control edge from | |||||
/// `forward_index.op.inputs[0].op` to the push op, and another control | |||||
/// edge from the push op to either `forward_index.op` or `forward_sync`. | |||||
/// </summary> | |||||
/// <param name="value"> The source tensor in forward that is to be accumulated.</param> | |||||
/// <param name="dead_branch"> True iff the tensor is on a dead branch of a cond.</param> | |||||
/// <returns>The stack that contains the accumulated history of the tensor.</returns> | |||||
public Tensor AddForwardAccumulator(Tensor value, bool dead_branch = false) | |||||
{ | |||||
_forward_index.graph.as_default(); | |||||
{ | |||||
var curr_ctxt = ops.get_default_graph()._get_control_flow_context(); | |||||
return tf_with(ops.control_dependencies(null), delegate | |||||
{ | |||||
Tensor acc = null; | |||||
Tensor push = null; | |||||
if (curr_ctxt != null) | |||||
curr_ctxt.Enter(); | |||||
ops.colocate_with(value); | |||||
{ | |||||
// We only need to pass maximum_iterations to the stack if | |||||
// we're inside an XLA context. | |||||
var max_size = constant_op.constant(-1, dtypes.int32); | |||||
acc = gen_data_flow_ops.stack_v2( | |||||
max_size: max_size, elem_type: value.dtype.as_base_dtype(), name: "f_acc"); | |||||
} | |||||
if (curr_ctxt != null) | |||||
curr_ctxt.Exit(); | |||||
// Make acc available in the forward context. | |||||
var enter_acc = forward_context.AddValue(acc); | |||||
// Add the stack_push op in the context of value.op. | |||||
var swap_enabled = forward_context.swap_memory; | |||||
var value_ctxt = util.GetOutputContext(value.op); | |||||
if(value_ctxt == forward_context) | |||||
{ | |||||
// value is not nested in the forward context. | |||||
forward_context.Enter(); | |||||
push = gen_data_flow_ops.stack_push_v2(enter_acc, value, swap_memory: swap_enabled); | |||||
forward_context.Exit(); | |||||
// Protect stack push and order it before forward_index. | |||||
forward_index.op._add_control_input(push.op); | |||||
} | |||||
else | |||||
{ | |||||
throw new NotImplementedException("AddForwardAccumulator"); | |||||
} | |||||
// Order stack push after the successor of forward_index | |||||
var add_op = forward_index.op.inputs[0].op; | |||||
push.op._add_control_input(add_op); | |||||
return acc; | |||||
}); | |||||
} | |||||
} | |||||
// """Add the getter for an accumulated value in the grad context. | |||||
// | |||||
// This is added to the backprop loop. Called in the grad context to | |||||
// get the value of an accumulated value. The stack pop op must be guarded | |||||
// by the pred of the controlling cond. | |||||
// | |||||
// Args: | |||||
// history_value: The history (a stack) of a value. | |||||
// value: The value that is pushed onto the stack. | |||||
// dead_branch: True iff the tensor is on a dead branch of a cond. | |||||
// | |||||
// Returns: | |||||
// The current value (the top of the stack). | |||||
// """ | |||||
public Tensor AddBackpropAccumulatedValue(Tensor history_value, Tensor value, bool dead_branch= false) | |||||
{ | |||||
var history_ctxt = history_value.op._get_control_flow_context(); | |||||
// Find the cond context that controls history_value if any. | |||||
CondContext cond_ctxt = null; | |||||
Tensor pop = null; | |||||
var value_ctxt = value.op._get_control_flow_context(); | |||||
while(value_ctxt != null && value_ctxt != history_ctxt) | |||||
{ | |||||
if (value_ctxt is CondContext cc) | |||||
cond_ctxt = cc; | |||||
value_ctxt = value_ctxt.outer_context; | |||||
} | |||||
tf_with(ops.control_dependencies(null), delegate | |||||
{ | |||||
grad_context.Enter(); | |||||
if(cond_ctxt != null) | |||||
{ | |||||
throw new NotImplementedException("AddBackpropAccumulatedValue"); | |||||
} | |||||
pop = gen_data_flow_ops.stack_pop_v2(history_value, value.dtype.as_base_dtype()); | |||||
pop.set_shape(value.TensorShape); | |||||
grad_context.Exit(); | |||||
}); | |||||
var parallel_iterations = grad_context.parallel_iterations; | |||||
if (parallel_iterations > 1) | |||||
// All pops are ordered after pivot_for_body and before grad_sync. | |||||
grad_sync._add_control_input(pop.op); | |||||
return pop; | |||||
} | |||||
/// <summary> | |||||
/// Get the real value of `value`. | |||||
/// </summary> | |||||
/// <param name="value">A tensor to be captured.</param> | |||||
/// <returns>The same tensor obtained from the saved history.</returns> | |||||
public Tensor GetRealValue(Tensor value) | |||||
{ | |||||
Tensor real_value = null; | |||||
if(real_value == null) | |||||
{ | |||||
var cur_value = value; | |||||
var cur_grad_state = this; | |||||
Tensor history_value = null; | |||||
while (true) | |||||
{ | |||||
var enter_op = util.GetLoopConstantEnter(cur_value); | |||||
if(enter_op != null) | |||||
{ | |||||
// Special case: cur_value comes from a constant Enter node. | |||||
cur_value = enter_op.inputs[0]; | |||||
cur_grad_state = cur_grad_state.outer_grad_state; | |||||
if(cur_grad_state == null) | |||||
{ | |||||
// We are now outside all nested loops for this gradient(), | |||||
// so `value` is a loop invariant and there is no need to | |||||
// save the history of value. Just make cur_value to enter | |||||
// the right control flow context. | |||||
real_value = _grad_context.AddValue(cur_value); | |||||
break; | |||||
} | |||||
} | |||||
else if (constant_op.is_constant(cur_value)) | |||||
{ | |||||
// We are now outside all nested loops for this gradient(), | |||||
// so `value` is a loop invariant and there is no need to | |||||
// save the history of value. Just make cur_value to enter | |||||
// the right control flow context. | |||||
real_value = constant_op.constant( | |||||
tensor_util.constant_value(cur_value), dtype: cur_value.dtype); | |||||
break; | |||||
} | |||||
else | |||||
{ | |||||
// Record the history of this value in forward_ctxt. | |||||
_grad_context.Exit(); | |||||
history_value = cur_grad_state.AddForwardAccumulator(cur_value); | |||||
_grad_context.Enter(); | |||||
break; | |||||
} | |||||
} | |||||
if(real_value == null) | |||||
{ | |||||
// Add the stack pop op in the grad context. | |||||
real_value = cur_grad_state.AddBackpropAccumulatedValue(history_value, cur_value); | |||||
if (cur_grad_state != this) | |||||
real_value = _grad_context.AddValue(real_value); | |||||
} | |||||
_history_map[value.name] = real_value; | |||||
} | |||||
return real_value; | |||||
} | |||||
} | |||||
} | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Collections; | |||||
using System.Collections.Generic; | |||||
using System.Linq; | |||||
using static Tensorflow.Binding; | |||||
using util = Tensorflow.control_flow_util; | |||||
namespace Tensorflow.Operations.ControlFlows | |||||
{ | |||||
/// <summary> | |||||
/// The state used for constructing the gradient graph for a while loop. | |||||
/// </summary> | |||||
public class GradLoopState | |||||
{ | |||||
private WhileContext _grad_context = null; | |||||
public WhileContext grad_context => _grad_context; | |||||
// # The loop counter added by AddBackpropLoopCounter. It is the value | |||||
// # of the loop counter for the current iteration. | |||||
// self._grad_index = None | |||||
// # A sync op for backprop. | |||||
// self._grad_sync = None | |||||
// # Information needed by backprop. | |||||
private Hashtable _history_map = new Hashtable(); | |||||
public Hashtable history_map => _history_map; | |||||
Dictionary<Operation, Tensor> _switch_map = new Dictionary<Operation, Tensor>(); | |||||
public Dictionary<Operation, Tensor> switch_map => _switch_map; | |||||
/// <summary> | |||||
/// The while loop context for forward. | |||||
/// </summary> | |||||
WhileContext _forward_context; | |||||
public WhileContext forward_context => _forward_context; | |||||
/// <summary> | |||||
/// The grad loop state for the outer while loop. | |||||
/// </summary> | |||||
GradLoopState _outer_grad_state; | |||||
public GradLoopState outer_grad_state => _outer_grad_state; | |||||
Tensor _forward_index; | |||||
public Tensor forward_index => _forward_index; | |||||
Tensor _grad_index; | |||||
Tensor[] _forward_loop_exits; | |||||
/// <summary> | |||||
/// The list of exits of the forward loop. | |||||
/// </summary> | |||||
public Tensor[] forward_loop_exits => _forward_loop_exits; | |||||
List<Tensor> _deferred_exits; | |||||
public List<Tensor> deferred_exits => _deferred_exits; | |||||
List<Tensor> _unused_exits; | |||||
public List<Tensor> unused_exits => _unused_exits; | |||||
/// <summary> | |||||
/// The number of exits we expect to see but haven't. | |||||
/// </summary> | |||||
public int pending_exits_count { get; set; } | |||||
Operation _grad_sync; | |||||
public Operation grad_sync | |||||
{ | |||||
get | |||||
{ | |||||
if(_grad_sync == null) | |||||
{ | |||||
tf_with(ops.control_dependencies(null), delegate | |||||
{ | |||||
_grad_sync = gen_control_flow_ops.control_trigger(name: "b_sync"); | |||||
}); | |||||
_grad_sync._set_control_flow_context(_grad_context); | |||||
_grad_index.op._add_control_input(_grad_sync); | |||||
if (_grad_context.outer_context != null) | |||||
_grad_context.outer_context.AddInnerOp(_grad_sync); | |||||
} | |||||
return _grad_sync; | |||||
} | |||||
} | |||||
public GradLoopState(WhileContext forward_ctxt, GradLoopState outer_grad_state_) | |||||
{ | |||||
// Information needed by backprop. | |||||
_unused_exits = new List<Tensor>(); | |||||
_deferred_exits = new List<Tensor>(); | |||||
_forward_loop_exits = list(forward_ctxt.loop_exits); | |||||
pending_exits_count = len(forward_ctxt.loop_exits); | |||||
_outer_grad_state = outer_grad_state_; | |||||
ControlFlowContext outer_forward_ctxt = null; | |||||
if (outer_grad_state_ != null) | |||||
outer_forward_ctxt = outer_grad_state_.forward_context; | |||||
// Add the forward loop counter. | |||||
// with forward_ctxt._graph.as_default(): | |||||
Tensor cnt, forward_index; | |||||
{ | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Enter(); | |||||
(cnt, forward_index) = forward_ctxt.AddForwardLoopCounter(outer_grad_state); | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Exit(); | |||||
} | |||||
_forward_context = forward_ctxt; | |||||
_forward_index = forward_index; | |||||
// Add the backprop WhileContext, and the backprop loop counter. | |||||
if (outer_grad_state != null) | |||||
{ | |||||
// This is a nested loop. Remember the iteration counts for each | |||||
// execution of this inner loop. | |||||
throw new NotImplementedException("GradLoopState"); | |||||
} | |||||
else | |||||
{ | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Enter(); | |||||
_grad_context = new WhileContext( | |||||
maximum_iterations: forward_ctxt.maximum_iterations, | |||||
parallel_iterations: forward_ctxt.parallel_iterations, | |||||
back_prop: forward_ctxt.back_prop, | |||||
swap_memory: forward_ctxt.swap_memory, | |||||
name: forward_ctxt.name, | |||||
grad_state: this); | |||||
_grad_index = _grad_context.AddBackpropLoopCounter(cnt, outer_grad_state); | |||||
if (outer_forward_ctxt != null) | |||||
outer_forward_ctxt.Exit(); | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// Add an accumulator for each forward tensor that is needed in backprop. | |||||
/// | |||||
/// This is added to the forward loop at the first time when a tensor | |||||
/// in the forward loop is used by backprop gradient computation loop. | |||||
/// We create an accumulator that accumulates the value of tensor at each | |||||
/// iteration. Called in the control flow context where gradients() is called. | |||||
/// | |||||
/// The pseudocode is: | |||||
/// ``` | |||||
/// acc = stack(); | |||||
/// while (_pivot) { | |||||
/// acc = stack_push(acc, value); | |||||
/// } | |||||
/// ``` | |||||
/// | |||||
/// We make sure that the stack push op in one iteration is executed before | |||||
/// next iteration. This is achieved by adding a control edge from | |||||
/// `forward_index.op.inputs[0].op` to the push op, and another control | |||||
/// edge from the push op to either `forward_index.op` or `forward_sync`. | |||||
/// </summary> | |||||
/// <param name="value"> The source tensor in forward that is to be accumulated.</param> | |||||
/// <param name="dead_branch"> True iff the tensor is on a dead branch of a cond.</param> | |||||
/// <returns>The stack that contains the accumulated history of the tensor.</returns> | |||||
public Tensor AddForwardAccumulator(Tensor value, bool dead_branch = false) | |||||
{ | |||||
_forward_index.graph.as_default(); | |||||
{ | |||||
var curr_ctxt = ops.get_default_graph()._get_control_flow_context(); | |||||
return tf_with(ops.control_dependencies(null), delegate | |||||
{ | |||||
Tensor acc = null; | |||||
Tensor push = null; | |||||
if (curr_ctxt != null) | |||||
curr_ctxt.Enter(); | |||||
ops.colocate_with(value); | |||||
{ | |||||
// We only need to pass maximum_iterations to the stack if | |||||
// we're inside an XLA context. | |||||
var max_size = constant_op.constant(-1, dtypes.int32); | |||||
acc = gen_data_flow_ops.stack_v2( | |||||
max_size: max_size, elem_type: value.dtype.as_base_dtype(), name: "f_acc"); | |||||
} | |||||
if (curr_ctxt != null) | |||||
curr_ctxt.Exit(); | |||||
// Make acc available in the forward context. | |||||
var enter_acc = forward_context.AddValue(acc); | |||||
// Add the stack_push op in the context of value.op. | |||||
var swap_enabled = forward_context.swap_memory; | |||||
var value_ctxt = util.GetOutputContext(value.op); | |||||
if(value_ctxt == forward_context) | |||||
{ | |||||
// value is not nested in the forward context. | |||||
forward_context.Enter(); | |||||
push = gen_data_flow_ops.stack_push_v2(enter_acc, value, swap_memory: swap_enabled); | |||||
forward_context.Exit(); | |||||
// Protect stack push and order it before forward_index. | |||||
forward_index.op._add_control_input(push.op); | |||||
} | |||||
else | |||||
{ | |||||
throw new NotImplementedException("AddForwardAccumulator"); | |||||
} | |||||
// Order stack push after the successor of forward_index | |||||
var add_op = forward_index.op.inputs[0].op; | |||||
push.op._add_control_input(add_op); | |||||
return acc; | |||||
}); | |||||
} | |||||
} | |||||
// """Add the getter for an accumulated value in the grad context. | |||||
// | |||||
// This is added to the backprop loop. Called in the grad context to | |||||
// get the value of an accumulated value. The stack pop op must be guarded | |||||
// by the pred of the controlling cond. | |||||
// | |||||
// Args: | |||||
// history_value: The history (a stack) of a value. | |||||
// value: The value that is pushed onto the stack. | |||||
// dead_branch: True iff the tensor is on a dead branch of a cond. | |||||
// | |||||
// Returns: | |||||
// The current value (the top of the stack). | |||||
// """ | |||||
public Tensor AddBackpropAccumulatedValue(Tensor history_value, Tensor value, bool dead_branch= false) | |||||
{ | |||||
var history_ctxt = history_value.op._get_control_flow_context(); | |||||
// Find the cond context that controls history_value if any. | |||||
CondContext cond_ctxt = null; | |||||
Tensor pop = null; | |||||
var value_ctxt = value.op._get_control_flow_context(); | |||||
while(value_ctxt != null && value_ctxt != history_ctxt) | |||||
{ | |||||
if (value_ctxt is CondContext cc) | |||||
cond_ctxt = cc; | |||||
value_ctxt = value_ctxt.outer_context; | |||||
} | |||||
tf_with(ops.control_dependencies(null), delegate | |||||
{ | |||||
grad_context.Enter(); | |||||
if(cond_ctxt != null) | |||||
{ | |||||
throw new NotImplementedException("AddBackpropAccumulatedValue"); | |||||
} | |||||
pop = gen_data_flow_ops.stack_pop_v2(history_value, value.dtype.as_base_dtype()); | |||||
pop.set_shape(value.TensorShape); | |||||
grad_context.Exit(); | |||||
}); | |||||
var parallel_iterations = grad_context.parallel_iterations; | |||||
if (parallel_iterations > 1) | |||||
// All pops are ordered after pivot_for_body and before grad_sync. | |||||
grad_sync._add_control_input(pop.op); | |||||
return pop; | |||||
} | |||||
/// <summary> | |||||
/// Get the real value of `value`. | |||||
/// </summary> | |||||
/// <param name="value">A tensor to be captured.</param> | |||||
/// <returns>The same tensor obtained from the saved history.</returns> | |||||
public Tensor GetRealValue(Tensor value) | |||||
{ | |||||
Tensor real_value = null; | |||||
if(real_value == null) | |||||
{ | |||||
var cur_value = value; | |||||
var cur_grad_state = this; | |||||
Tensor history_value = null; | |||||
while (true) | |||||
{ | |||||
var enter_op = util.GetLoopConstantEnter(cur_value); | |||||
if(enter_op != null) | |||||
{ | |||||
// Special case: cur_value comes from a constant Enter node. | |||||
cur_value = enter_op.inputs[0]; | |||||
cur_grad_state = cur_grad_state.outer_grad_state; | |||||
if(cur_grad_state == null) | |||||
{ | |||||
// We are now outside all nested loops for this gradient(), | |||||
// so `value` is a loop invariant and there is no need to | |||||
// save the history of value. Just make cur_value to enter | |||||
// the right control flow context. | |||||
real_value = _grad_context.AddValue(cur_value); | |||||
break; | |||||
} | |||||
} | |||||
else if (constant_op.is_constant(cur_value)) | |||||
{ | |||||
// We are now outside all nested loops for this gradient(), | |||||
// so `value` is a loop invariant and there is no need to | |||||
// save the history of value. Just make cur_value to enter | |||||
// the right control flow context. | |||||
real_value = constant_op.constant( | |||||
tensor_util.constant_value(cur_value), dtype: cur_value.dtype); | |||||
break; | |||||
} | |||||
else | |||||
{ | |||||
// Record the history of this value in forward_ctxt. | |||||
_grad_context.Exit(); | |||||
history_value = cur_grad_state.AddForwardAccumulator(cur_value); | |||||
_grad_context.Enter(); | |||||
break; | |||||
} | |||||
} | |||||
if(real_value == null) | |||||
{ | |||||
// Add the stack pop op in the grad context. | |||||
real_value = cur_grad_state.AddBackpropAccumulatedValue(history_value, cur_value); | |||||
if (cur_grad_state != this) | |||||
real_value = _grad_context.AddValue(real_value); | |||||
} | |||||
_history_map[value.name] = real_value; | |||||
} | |||||
return real_value; | |||||
} | |||||
} | |||||
} |
@@ -1,17 +1,17 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -22,23 +22,23 @@ namespace Tensorflow.Operations | |||||
{ | { | ||||
public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | ||||
/// <summary> | |||||
/// Computes a 2-D convolution given 4-D `input` and `filter` tensors. | |||||
/// | |||||
/// Given an input tensor of shape `[batch, in_height, in_width, in_channels]` | |||||
/// and a filter / kernel tensor of shape | |||||
/// `[filter_height, filter_width, in_channels, out_channels]`, this op | |||||
/// performs the following: | |||||
/// | |||||
/// 1. Flattens the filter to a 2-D matrix with shape | |||||
/// `[filter_height * filter_width * in_channels, output_channels]`. | |||||
/// 2. Extracts image patches from the input tensor to form a *virtual* | |||||
/// tensor of shape `[batch, out_height, out_width, | |||||
/// filter_height * filter_width * in_channels]`. | |||||
/// 3. For each patch, right-multiplies the filter matrix and the image patch | |||||
/// vector. | |||||
/// </summary> | |||||
/// <param name="parameters"></param> | |||||
/// <summary> | |||||
/// Computes a 2-D convolution given 4-D `input` and `filter` tensors. | |||||
/// | |||||
/// Given an input tensor of shape `[batch, in_height, in_width, in_channels]` | |||||
/// and a filter / kernel tensor of shape | |||||
/// `[filter_height, filter_width, in_channels, out_channels]`, this op | |||||
/// performs the following: | |||||
/// | |||||
/// 1. Flattens the filter to a 2-D matrix with shape | |||||
/// `[filter_height * filter_width * in_channels, output_channels]`. | |||||
/// 2. Extracts image patches from the input tensor to form a *virtual* | |||||
/// tensor of shape `[batch, out_height, out_width, | |||||
/// filter_height * filter_width * in_channels]`. | |||||
/// 3. For each patch, right-multiplies the filter matrix and the image patch | |||||
/// vector. | |||||
/// </summary> | |||||
/// <param name="parameters"></param> | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public static Tensor conv2d(Conv2dParams parameters) | public static Tensor conv2d(Conv2dParams parameters) | ||||
{ | { | ||||
@@ -55,15 +55,15 @@ namespace Tensorflow.Operations | |||||
}); | }); | ||||
return _op.outputs[0]; | return _op.outputs[0]; | ||||
} | |||||
/// <summary> | |||||
/// Computes the gradients of convolution with respect to the filter. | |||||
/// </summary> | |||||
/// <param name="parameters"></param> | |||||
/// <returns></returns> | |||||
public static Tensor conv2d_backprop_filter(Conv2dParams parameters) | |||||
{ | |||||
} | |||||
/// <summary> | |||||
/// Computes the gradients of convolution with respect to the filter. | |||||
/// </summary> | |||||
/// <param name="parameters"></param> | |||||
/// <returns></returns> | |||||
public static Tensor conv2d_backprop_filter(Conv2dParams parameters) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("Conv2DBackpropFilter", name: parameters.Name, args: new | var _op = _op_def_lib._apply_op_helper("Conv2DBackpropFilter", name: parameters.Name, args: new | ||||
{ | { | ||||
input = parameters.Input, | input = parameters.Input, | ||||
@@ -77,16 +77,16 @@ namespace Tensorflow.Operations | |||||
dilations = parameters.Dilations | dilations = parameters.Dilations | ||||
}); | }); | ||||
return _op.outputs[0]; | |||||
return _op.outputs[0]; | |||||
} | } | ||||
/// <summary> | |||||
/// Computes the gradients of convolution with respect to the input. | |||||
/// </summary> | |||||
/// <param name="parameters"></param> | |||||
/// <summary> | |||||
/// Computes the gradients of convolution with respect to the input. | |||||
/// </summary> | |||||
/// <param name="parameters"></param> | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public static Tensor conv2d_backprop_input(Conv2dParams parameters) | |||||
{ | |||||
public static Tensor conv2d_backprop_input(Conv2dParams parameters) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("Conv2DBackpropInput", name: parameters.Name, args: new | var _op = _op_def_lib._apply_op_helper("Conv2DBackpropInput", name: parameters.Name, args: new | ||||
{ | { | ||||
input_sizes = parameters.InputSizes, | input_sizes = parameters.InputSizes, | ||||
@@ -100,7 +100,7 @@ namespace Tensorflow.Operations | |||||
dilations = parameters.Dilations | dilations = parameters.Dilations | ||||
}); | }); | ||||
return _op.outputs[0]; | |||||
return _op.outputs[0]; | |||||
} | } | ||||
public static Tensor bias_add(Tensor value, | public static Tensor bias_add(Tensor value, | ||||
@@ -135,56 +135,73 @@ namespace Tensorflow.Operations | |||||
}); | }); | ||||
return _op.outputs[0]; | return _op.outputs[0]; | ||||
} | |||||
/// <summary> | |||||
/// Computes exponential linear: <c>exp(features) - 1</c> if &lt; 0, <c>features</c> otherwise. | |||||
/// </summary> | |||||
/// <param name="features"> | |||||
/// </param> | |||||
/// <param name="name"> | |||||
/// If specified, the created operation in the graph will be this one, otherwise it will be named 'Elu'. | |||||
/// </param> | |||||
/// <returns> | |||||
/// The Operation can be fetched from the resulting Tensor, by fetching the Operation property from the result. | |||||
/// </returns> | |||||
/// <remarks> | |||||
/// See [Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs) | |||||
/// ](http://arxiv.org/abs/1511.07289) | |||||
/// </remarks> | |||||
public static Tensor elu(Tensor features, string name = "Elu") | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("Elu", name: name, args: new { features }); | |||||
return op.output; | |||||
} | } | ||||
/// <summary> | |||||
/// Gradient for batch normalization. | |||||
/// </summary> | |||||
/// <param name="y_backprop"></param> | |||||
/// <param name="x"></param> | |||||
/// <param name="scale"></param> | |||||
/// <param name="reserve_space_1"></param> | |||||
/// <param name="reserve_space_2"></param> | |||||
/// <param name="epsilon"></param> | |||||
/// <param name="data_format"></param> | |||||
/// <param name="is_training"></param> | |||||
/// <param name="name"></param> | |||||
/// <summary> | |||||
/// Computes exponential linear: <c>exp(features) - 1</c> if &lt; 0, <c>features</c> otherwise. | |||||
/// </summary> | |||||
/// <param name="features"> | |||||
/// </param> | |||||
/// <param name="name"> | |||||
/// If specified, the created operation in the graph will be this one, otherwise it will be named 'Elu'. | |||||
/// </param> | |||||
/// <returns> | |||||
/// The Operation can be fetched from the resulting Tensor, by fetching the Operation property from the result. | |||||
/// </returns> | |||||
/// <remarks> | |||||
/// See [Fast and Accurate Deep Network Learning by Exponential Linear Units (ELUs) | |||||
/// ](http://arxiv.org/abs/1511.07289) | |||||
/// </remarks> | |||||
public static Tensor elu(Tensor features, string name = "Elu") | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("Elu", name: name, args: new { features }); | |||||
return op.output; | |||||
} | |||||
/// <summary> | |||||
/// Gradient for batch normalization. | |||||
/// </summary> | |||||
/// <param name="y_backprop"></param> | |||||
/// <param name="x"></param> | |||||
/// <param name="scale"></param> | |||||
/// <param name="reserve_space_1"></param> | |||||
/// <param name="reserve_space_2"></param> | |||||
/// <param name="epsilon"></param> | |||||
/// <param name="data_format"></param> | |||||
/// <param name="is_training"></param> | |||||
/// <param name="name"></param> | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public static Tensor[] fused_batch_norm_grad(FusedBatchNormParams @params) | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("FusedBatchNormGrad", name: @params.Name, args: new | |||||
{ | |||||
y_backprop = @params.YBackprop, | |||||
x = @params.X, | |||||
scale = @params.Scale, | |||||
reserve_space_1 = @params.ReserveSpace1, | |||||
reserve_space_2 = @params.ReserveSpace2, | |||||
epsilon = @params.Epsilon, | |||||
data_format = @params.DataFormat, | |||||
is_training = @params.IsTraining | |||||
}); | |||||
return op.outputs; | |||||
public static Tensor[] fused_batch_norm_grad(FusedBatchNormParams @params) | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("FusedBatchNormGrad", name: @params.Name, args: new | |||||
{ | |||||
y_backprop = @params.YBackprop, | |||||
x = @params.X, | |||||
scale = @params.Scale, | |||||
reserve_space_1 = @params.ReserveSpace1, | |||||
reserve_space_2 = @params.ReserveSpace2, | |||||
epsilon = @params.Epsilon, | |||||
data_format = @params.DataFormat, | |||||
is_training = @params.IsTraining | |||||
}); | |||||
return op.outputs; | |||||
} | |||||
public static Tensor[] fused_batch_norm_grad_v3(FusedBatchNormParams @params) | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("FusedBatchNormGradV3", name: @params.Name, args: new | |||||
{ | |||||
y_backprop = @params.YBackprop, | |||||
x = @params.X, | |||||
scale = @params.Scale, | |||||
reserve_space_1 = @params.ReserveSpace1, | |||||
reserve_space_2 = @params.ReserveSpace2, | |||||
reserve_space_3 = @params.ReserveSpace3, | |||||
epsilon = @params.Epsilon, | |||||
data_format = @params.DataFormat, | |||||
is_training = @params.IsTraining | |||||
}); | |||||
return op.outputs; | |||||
} | } | ||||
public static Tensor[] fused_batch_norm(Tensor x, | public static Tensor[] fused_batch_norm(Tensor x, | ||||
@@ -212,19 +229,44 @@ namespace Tensorflow.Operations | |||||
return _op.outputs; | return _op.outputs; | ||||
} | } | ||||
/// <summary> | |||||
/// Local Response Normalization. | |||||
/// </summary> | |||||
/// <param name="input"></param> | |||||
/// <param name="depth_radius"></param> | |||||
/// <param name="bias"></param> | |||||
/// <param name="alpha"></param> | |||||
/// <param name="beta"></param> | |||||
/// <param name="name"></param> | |||||
public static Tensor[] fused_batch_norm_v3(Tensor x, | |||||
Tensor scale, | |||||
Tensor offset, | |||||
Tensor mean, | |||||
Tensor variance, | |||||
float epsilon = 0.0001f, | |||||
string data_format = "NHWC", | |||||
bool is_training = true, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("FusedBatchNormV3", name: name, args: new | |||||
{ | |||||
x, | |||||
scale, | |||||
offset, | |||||
mean, | |||||
variance, | |||||
epsilon, | |||||
data_format, | |||||
is_training | |||||
}); | |||||
return _op.outputs; | |||||
} | |||||
/// <summary> | |||||
/// Local Response Normalization. | |||||
/// </summary> | |||||
/// <param name="input"></param> | |||||
/// <param name="depth_radius"></param> | |||||
/// <param name="bias"></param> | |||||
/// <param name="alpha"></param> | |||||
/// <param name="beta"></param> | |||||
/// <param name="name"></param> | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public static Tensor local_response_normalization(Tensor input, int depth_radius = 5, int bias = 1, | |||||
int alpha = 1, float beta = 0.5f, string name = null) | |||||
{ | |||||
public static Tensor local_response_normalization(Tensor input, int depth_radius = 5, int bias = 1, | |||||
int alpha = 1, float beta = 0.5f, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("LRN", name: name, args: new | var _op = _op_def_lib._apply_op_helper("LRN", name: name, args: new | ||||
{ | { | ||||
input, | input, | ||||
@@ -234,7 +276,7 @@ namespace Tensorflow.Operations | |||||
beta | beta | ||||
}); | }); | ||||
return _op.output; | |||||
return _op.output; | |||||
} | } | ||||
public static Tensor log_softmax(Tensor logits, string name = null) | public static Tensor log_softmax(Tensor logits, string name = null) | ||||
@@ -245,16 +287,16 @@ namespace Tensorflow.Operations | |||||
}); | }); | ||||
return _op.output; | return _op.output; | ||||
} | |||||
/// <summary> | |||||
/// Says whether the targets are in the top `K` predictions. | |||||
/// </summary> | |||||
/// <param name="predictions"></param> | |||||
/// <param name="targets"></param> | |||||
/// <param name="k"></param> | |||||
/// <param name="name"></param> | |||||
/// <returns>A `Tensor` of type `bool`.</returns> | |||||
} | |||||
/// <summary> | |||||
/// Says whether the targets are in the top `K` predictions. | |||||
/// </summary> | |||||
/// <param name="predictions"></param> | |||||
/// <param name="targets"></param> | |||||
/// <param name="k"></param> | |||||
/// <param name="name"></param> | |||||
/// <returns>A `Tensor` of type `bool`.</returns> | |||||
public static Tensor in_top_kv2(Tensor predictions, Tensor targets, int k, string name = null) | public static Tensor in_top_kv2(Tensor predictions, Tensor targets, int k, string name = null) | ||||
{ | { | ||||
var _op = _op_def_lib._apply_op_helper("InTopKV2", name: name, args: new | var _op = _op_def_lib._apply_op_helper("InTopKV2", name: name, args: new | ||||
@@ -265,8 +307,8 @@ namespace Tensorflow.Operations | |||||
}); | }); | ||||
return _op.output; | return _op.output; | ||||
} | |||||
} | |||||
public static Tensor leaky_relu(Tensor features, float alpha = 0.2f, string name = null) | public static Tensor leaky_relu(Tensor features, float alpha = 0.2f, string name = null) | ||||
{ | { | ||||
var _op = _op_def_lib._apply_op_helper("LeakyRelu", name: name, args: new | var _op = _op_def_lib._apply_op_helper("LeakyRelu", name: name, args: new | ||||
@@ -297,9 +339,9 @@ namespace Tensorflow.Operations | |||||
return _op.outputs[0]; | return _op.outputs[0]; | ||||
} | } | ||||
public static Tensor max_pool_grad(Tensor orig_input, Tensor orig_output, Tensor grad, int[] ksize, int[] strides, string padding, | |||||
string data_format= "NHWC", string name= null) | |||||
{ | |||||
public static Tensor max_pool_grad(Tensor orig_input, Tensor orig_output, Tensor grad, int[] ksize, int[] strides, string padding, | |||||
string data_format= "NHWC", string name= null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("MaxPoolGrad", name: name, args: new | var _op = _op_def_lib._apply_op_helper("MaxPoolGrad", name: name, args: new | ||||
{ | { | ||||
orig_input, | orig_input, | ||||
@@ -311,7 +353,7 @@ namespace Tensorflow.Operations | |||||
data_format | data_format | ||||
}); | }); | ||||
return _op.outputs[0]; | |||||
return _op.outputs[0]; | |||||
} | } | ||||
public static Tensor[] top_kv2(Tensor input, int k, bool sorted = true, string name = null) | public static Tensor[] top_kv2(Tensor input, int k, bool sorted = true, string name = null) | ||||
@@ -335,8 +377,8 @@ namespace Tensorflow.Operations | |||||
}); | }); | ||||
return _op.outputs[0]; | return _op.outputs[0]; | ||||
} | |||||
} | |||||
public static Tensor leaky_relu_grad(Tensor gradients, Tensor features, float alpha = 0.2f, string name = null) | public static Tensor leaky_relu_grad(Tensor gradients, Tensor features, float alpha = 0.2f, string name = null) | ||||
{ | { | ||||
var _op = _op_def_lib._apply_op_helper("LeakyReluGrad", name: name, args: new | var _op = _op_def_lib._apply_op_helper("LeakyReluGrad", name: name, args: new | ||||
@@ -377,81 +419,81 @@ namespace Tensorflow.Operations | |||||
return (_op.outputs[0], _op.outputs[1]); | return (_op.outputs[0], _op.outputs[1]); | ||||
} | } | ||||
/// <summary> | |||||
/// Computes softmax cross entropy cost and gradients to backpropagate. | |||||
/// </summary> | |||||
/// <param name="features"> | |||||
/// batch_size x num_classes matrix | |||||
/// </param> | |||||
/// <param name="labels"> | |||||
/// batch_size vector with values in [0, num_classes). | |||||
/// This is the label for the given minibatch entry. | |||||
/// </param> | |||||
/// <param name="name"> | |||||
/// If specified, the created operation in the graph will be this one, otherwise it will be named 'SparseSoftmaxCrossEntropyWithLogits'. | |||||
/// </param> | |||||
/// <returns> | |||||
/// Returns a tuple with multiple values, as follows: | |||||
/// loss : Per example loss (batch_size vector). | |||||
/// backprop : backpropagated gradients (batch_size x num_classes matrix). | |||||
/// The Operation can be fetched from any of the Tensorreturned in the tuple values, by fetching the Operation property. | |||||
/// </returns> | |||||
/// <remarks> | |||||
/// Unlike <c>SoftmaxCrossEntropyWithLogits</c>, this operation does not accept | |||||
/// a matrix of label probabilities, but rather a single label per row | |||||
/// of features. This label is considered to have probability 1.0 for the | |||||
/// given row. | |||||
/// | |||||
/// Inputs are the logits, not probabilities. | |||||
/// </remarks> | |||||
public static (Tensor loss, Tensor backprop) sparse_softmax_cross_entropy_with_logits(Tensor features, Tensor labels, string name = "SparseSoftmaxCrossEntropyWithLogits") | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("SparseSoftmaxCrossEntropyWithLogits", name: name, args: new { features, labels }); | |||||
int _idx = 0; | |||||
var loss = op.outputs[_idx++]; | |||||
var backprop = op.outputs[_idx++]; | |||||
return (loss, backprop); | |||||
/// <summary> | |||||
/// Computes softmax cross entropy cost and gradients to backpropagate. | |||||
/// </summary> | |||||
/// <param name="features"> | |||||
/// batch_size x num_classes matrix | |||||
/// </param> | |||||
/// <param name="labels"> | |||||
/// batch_size vector with values in [0, num_classes). | |||||
/// This is the label for the given minibatch entry. | |||||
/// </param> | |||||
/// <param name="name"> | |||||
/// If specified, the created operation in the graph will be this one, otherwise it will be named 'SparseSoftmaxCrossEntropyWithLogits'. | |||||
/// </param> | |||||
/// <returns> | |||||
/// Returns a tuple with multiple values, as follows: | |||||
/// loss : Per example loss (batch_size vector). | |||||
/// backprop : backpropagated gradients (batch_size x num_classes matrix). | |||||
/// The Operation can be fetched from any of the Tensorreturned in the tuple values, by fetching the Operation property. | |||||
/// </returns> | |||||
/// <remarks> | |||||
/// Unlike <c>SoftmaxCrossEntropyWithLogits</c>, this operation does not accept | |||||
/// a matrix of label probabilities, but rather a single label per row | |||||
/// of features. This label is considered to have probability 1.0 for the | |||||
/// given row. | |||||
/// | |||||
/// Inputs are the logits, not probabilities. | |||||
/// </remarks> | |||||
public static (Tensor loss, Tensor backprop) sparse_softmax_cross_entropy_with_logits(Tensor features, Tensor labels, string name = "SparseSoftmaxCrossEntropyWithLogits") | |||||
{ | |||||
var op = _op_def_lib._apply_op_helper("SparseSoftmaxCrossEntropyWithLogits", name: name, args: new { features, labels }); | |||||
int _idx = 0; | |||||
var loss = op.outputs[_idx++]; | |||||
var backprop = op.outputs[_idx++]; | |||||
return (loss, backprop); | |||||
} | } | ||||
/// <summary> | |||||
/// Computes rectified linear: `max(features, 0)`. | |||||
/// </summary> | |||||
/// <param name="features">A `Tensor`. Must be one of the following types: `float32`, `float64`, `int32`, `uint8`, `int16`, `int8`, `int64`, `bfloat16`, `uint16`, `half`, `uint32`, `uint64`, `qint8`.</param> | |||||
/// <summary> | |||||
/// Computes rectified linear: `max(features, 0)`. | |||||
/// </summary> | |||||
/// <param name="features">A `Tensor`. Must be one of the following types: `float32`, `float64`, `int32`, `uint8`, `int16`, `int8`, `int64`, `bfloat16`, `uint16`, `half`, `uint32`, `uint64`, `qint8`.</param> | |||||
/// <param name="name">A name for the operation (optional).</param> | /// <param name="name">A name for the operation (optional).</param> | ||||
/// <returns>A `Tensor`. Has the same type as `features`.</returns> | /// <returns>A `Tensor`. Has the same type as `features`.</returns> | ||||
public static Tensor relu(Tensor features, string name = null) | public static Tensor relu(Tensor features, string name = null) | ||||
{ | |||||
//_ctx = _context._context | |||||
//if _ctx is not None and _ctx._eager_context.is_eager: | |||||
// try: | |||||
// _result = _pywrap_tensorflow.TFE_Py_FastPathExecute( | |||||
// _ctx._context_handle, _ctx._eager_context.device_name, "Relu", name, | |||||
// _ctx._post_execution_callbacks, features) | |||||
// return _result | |||||
// except _core._FallbackException: | |||||
// try: | |||||
// return relu_eager_fallback( | |||||
// features, name=name, ctx=_ctx) | |||||
// except _core._SymbolicException: | |||||
// pass # Add nodes to the TensorFlow graph. | |||||
// except (TypeError, ValueError): | |||||
// result = _dispatch.dispatch( | |||||
// relu, features=features, name=name) | |||||
// if result is not _dispatch.OpDispatcher.NOT_SUPPORTED: | |||||
// return result | |||||
// raise | |||||
// except _core._NotOkStatusException as e: | |||||
// if name is not None: | |||||
// message = e.message + " name: " + name | |||||
// else: | |||||
// message = e.message | |||||
// _six.raise_from(_core._status_to_exception(e.code, message), None) | |||||
{ | |||||
//_ctx = _context._context | |||||
//if _ctx is not None and _ctx._eager_context.is_eager: | |||||
// try: | |||||
// _result = _pywrap_tensorflow.TFE_Py_FastPathExecute( | |||||
// _ctx._context_handle, _ctx._eager_context.device_name, "Relu", name, | |||||
// _ctx._post_execution_callbacks, features) | |||||
// return _result | |||||
// except _core._FallbackException: | |||||
// try: | |||||
// return relu_eager_fallback( | |||||
// features, name=name, ctx=_ctx) | |||||
// except _core._SymbolicException: | |||||
// pass # Add nodes to the TensorFlow graph. | |||||
// except (TypeError, ValueError): | |||||
// result = _dispatch.dispatch( | |||||
// relu, features=features, name=name) | |||||
// if result is not _dispatch.OpDispatcher.NOT_SUPPORTED: | |||||
// return result | |||||
// raise | |||||
// except _core._NotOkStatusException as e: | |||||
// if name is not None: | |||||
// message = e.message + " name: " + name | |||||
// else: | |||||
// message = e.message | |||||
// _six.raise_from(_core._status_to_exception(e.code, message), None) | |||||
//# Add nodes to the TensorFlow graph. | //# Add nodes to the TensorFlow graph. | ||||
//try: | //try: | ||||
OpDefLibrary _op_def_lib = new OpDefLibrary(); | OpDefLibrary _op_def_lib = new OpDefLibrary(); | ||||
var _op = _op_def_lib._apply_op_helper("Relu", name: name, args: new { features }); | var _op = _op_def_lib._apply_op_helper("Relu", name: name, args: new { features }); | ||||
return _op.outputs[0]; | |||||
return _op.outputs[0]; | |||||
//except (TypeError, ValueError): | //except (TypeError, ValueError): | ||||
// result = _dispatch.dispatch( | // result = _dispatch.dispatch( | ||||
// relu, features=features, name=name) | // relu, features=features, name=name) | ||||
@@ -1,68 +1,68 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using Tensorflow.Operations; | |||||
using static Tensorflow.Binding; | |||||
namespace Tensorflow | |||||
{ | |||||
public partial class Operation | |||||
{ | |||||
private ControlFlowContext _control_flow_context; | |||||
/// <summary> | |||||
/// Add this op to its control flow context. | |||||
/// | |||||
/// This may add new ops and change this op's inputs. self.inputs must be | |||||
/// available before calling this method. | |||||
/// </summary> | |||||
public void _control_flow_post_processing() | |||||
{ | |||||
foreach(Tensor input_tensor in inputs) | |||||
control_flow_util.CheckInputFromValidContext(this, input_tensor.op); | |||||
if (_control_flow_context != null) | |||||
_control_flow_context.AddOp(this); | |||||
} | |||||
public void _add_control_input(Operation op) | |||||
{ | |||||
//c_api.TF_AddControlInput(_operDesc, op); | |||||
c_api.AddControlInput(graph, _handle, op); | |||||
} | |||||
public void _add_control_inputs(Operation[] ops) | |||||
{ | |||||
foreach (var op in ops) | |||||
_add_control_input(op); | |||||
} | |||||
public void _set_control_flow_context(ControlFlowContext ctx) | |||||
{ | |||||
_control_flow_context = ctx; | |||||
} | |||||
public ControlFlowContext _get_control_flow_context() | |||||
{ | |||||
return _control_flow_context; | |||||
} | |||||
public WhileContext GetWhileContext() | |||||
{ | |||||
return _control_flow_context as WhileContext; | |||||
} | |||||
} | |||||
} | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using Tensorflow.Operations; | |||||
using static Tensorflow.Binding; | |||||
namespace Tensorflow | |||||
{ | |||||
public partial class Operation | |||||
{ | |||||
private ControlFlowContext _control_flow_context; | |||||
/// <summary> | |||||
/// Add this op to its control flow context. | |||||
/// | |||||
/// This may add new ops and change this op's inputs. self.inputs must be | |||||
/// available before calling this method. | |||||
/// </summary> | |||||
public void _control_flow_post_processing() | |||||
{ | |||||
foreach(Tensor input_tensor in inputs) | |||||
control_flow_util.CheckInputFromValidContext(this, input_tensor.op); | |||||
if (_control_flow_context != null) | |||||
_control_flow_context.AddOp(this); | |||||
} | |||||
public void _add_control_input(Operation op) | |||||
{ | |||||
//c_api.TF_AddControlInput(_operDesc, op); | |||||
c_api.AddControlInput(graph, _handle, op); | |||||
} | |||||
public void _add_control_inputs(Operation[] ops) | |||||
{ | |||||
foreach (var op in ops) | |||||
_add_control_input(op); | |||||
} | |||||
public void _set_control_flow_context(ControlFlowContext ctx) | |||||
{ | |||||
_control_flow_context = ctx; | |||||
} | |||||
public ControlFlowContext _get_control_flow_context() | |||||
{ | |||||
return _control_flow_context; | |||||
} | |||||
public WhileContext GetWhileContext() | |||||
{ | |||||
return _control_flow_context as WhileContext; | |||||
} | |||||
} | |||||
} |
@@ -27,12 +27,16 @@ namespace Tensorflow | |||||
public static implicit operator Operation(IntPtr handle) | public static implicit operator Operation(IntPtr handle) | ||||
=> new Operation(handle); | => new Operation(handle); | ||||
public static implicit operator IntPtr(Operation op) => op._handle; | |||||
public static implicit operator Tensor(Operation op) => op.output; | |||||
public static implicit operator IntPtr(Operation op) | |||||
=> op._handle; | |||||
public static implicit operator Tensor(Operation op) | |||||
=> op.output; | |||||
public static implicit operator RefVariable(Operation op) | |||||
=> new RefVariable(op); | |||||
public override string ToString() | public override string ToString() | ||||
{ | { | ||||
return _handle == IntPtr.Zero ? "tf.Operation Undefined" : $"tf.Operation '{name}' type={OpType}"; | |||||
return _handle == IntPtr.Zero ? "tf.Operation Undefined" : $"<tf.Operation '{name}' type={OpType}>"; | |||||
} | } | ||||
public override bool Equals(object obj) | public override bool Equals(object obj) | ||||
@@ -1,109 +1,114 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Linq; | |||||
using System.Runtime.InteropServices; | |||||
#if SERIALIZABLE | |||||
using Newtonsoft.Json; | |||||
#endif | |||||
namespace Tensorflow | |||||
{ | |||||
// from ops.py | |||||
public partial class Operation | |||||
{ | |||||
public TF_Output Input(int index) => c_api.TF_OperationInput(new TF_Input(_handle, index)); | |||||
public TF_DataType InputType(int index) => c_api.TF_OperationInputType(new TF_Input(_handle, index)); | |||||
public int InputListLength(string name) | |||||
{ | |||||
int num = 0; | |||||
using(var status = new Status()) | |||||
{ | |||||
num = c_api.TF_OperationInputListLength(_handle, name, status); | |||||
status.Check(true); | |||||
} | |||||
return num; | |||||
} | |||||
#if SERIALIZABLE | |||||
[JsonIgnore] | |||||
#endif | |||||
public int NumInputs => c_api.TF_OperationNumInputs(_handle); | |||||
private TF_DataType[] _input_types => _inputs_val._inputs.Select(x => x.dtype).ToArray(); | |||||
private InputList _inputs_val; | |||||
public InputList inputs | |||||
{ | |||||
get | |||||
{ | |||||
if (_inputs_val == null) | |||||
{ | |||||
var retval = new Tensor[NumInputs]; | |||||
for (int i = 0; i < NumInputs; i++) | |||||
{ | |||||
var tf_output = Input(i); | |||||
var op = GetOperation(tf_output.oper); | |||||
retval[i] = op.outputs[tf_output.index]; | |||||
} | |||||
_inputs_val = new InputList(retval); | |||||
} | |||||
return _inputs_val; | |||||
} | |||||
} | |||||
public int NumControlInputs => c_api.TF_OperationNumControlInputs(_handle); | |||||
/// <summary> | |||||
/// The `Operation` objects on which this op has a control dependency. | |||||
/// | |||||
/// Before this op is executed, TensorFlow will ensure that the | |||||
/// operations in `self.control_inputs` have finished executing.This | |||||
/// mechanism can be used to run ops sequentially for performance | |||||
/// reasons, or to ensure that the side effects of an op are observed | |||||
/// in the correct order. | |||||
/// </summary> | |||||
public Operation[] control_inputs | |||||
{ | |||||
get | |||||
{ | |||||
return GetControlInputs(); | |||||
} | |||||
} | |||||
public unsafe Operation[] GetControlInputs() | |||||
{ | |||||
var control_inputs = new Operation[NumControlInputs]; | |||||
if (NumControlInputs > 0) | |||||
{ | |||||
IntPtr control_input_handle = Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>() * NumControlInputs); | |||||
c_api.TF_OperationGetControlInputs(_handle, control_input_handle, NumControlInputs); | |||||
for (int i = 0; i < NumControlInputs; i++) | |||||
{ | |||||
var handle = control_input_handle + Marshal.SizeOf<IntPtr>() * i; | |||||
control_inputs[i] = new Operation(*(IntPtr*)handle); | |||||
} | |||||
} | |||||
return control_inputs; | |||||
} | |||||
} | |||||
} | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Linq; | |||||
using System.Runtime.InteropServices; | |||||
#if SERIALIZABLE | |||||
using Newtonsoft.Json; | |||||
#endif | |||||
namespace Tensorflow | |||||
{ | |||||
// from ops.py | |||||
public partial class Operation | |||||
{ | |||||
public TF_Output Input(int index) => c_api.TF_OperationInput(new TF_Input(_handle, index)); | |||||
public TF_DataType InputType(int index) => c_api.TF_OperationInputType(new TF_Input(_handle, index)); | |||||
public int InputListLength(string name) | |||||
{ | |||||
int num = 0; | |||||
using(var status = new Status()) | |||||
{ | |||||
num = c_api.TF_OperationInputListLength(_handle, name, status); | |||||
status.Check(true); | |||||
} | |||||
return num; | |||||
} | |||||
public int NumInputs => c_api.TF_OperationNumInputs(_handle); | |||||
private TF_DataType[] _input_types => _inputs_val._inputs.Select(x => x.dtype).ToArray(); | |||||
private InputList _inputs_val; | |||||
public InputList inputs | |||||
{ | |||||
get | |||||
{ | |||||
if (_inputs_val == null) | |||||
{ | |||||
var retval = new Tensor[NumInputs]; | |||||
for (int i = 0; i < NumInputs; i++) | |||||
{ | |||||
var tf_output = Input(i); | |||||
var op = GetOperation(tf_output.oper); | |||||
retval[i] = op.outputs[tf_output.index]; | |||||
} | |||||
_inputs_val = new InputList(retval); | |||||
} | |||||
return _inputs_val; | |||||
} | |||||
} | |||||
public int NumControlInputs | |||||
=> _handle == IntPtr.Zero ? 0 : c_api.TF_OperationNumControlInputs(_handle); | |||||
Operation[] _control_inputs; | |||||
/// <summary> | |||||
/// The `Operation` objects on which this op has a control dependency. | |||||
/// | |||||
/// Before this op is executed, TensorFlow will ensure that the | |||||
/// operations in `self.control_inputs` have finished executing.This | |||||
/// mechanism can be used to run ops sequentially for performance | |||||
/// reasons, or to ensure that the side effects of an op are observed | |||||
/// in the correct order. | |||||
/// </summary> | |||||
#if SERIALIZABLE | |||||
[JsonIgnore] | |||||
#endif | |||||
public Operation[] control_inputs | |||||
{ | |||||
get | |||||
{ | |||||
if (_control_inputs == null || _control_inputs.Length == 0) | |||||
_control_inputs = GetControlInputs(); | |||||
return _control_inputs; | |||||
} | |||||
} | |||||
public unsafe Operation[] GetControlInputs() | |||||
{ | |||||
var control_inputs = new Operation[NumControlInputs]; | |||||
if (NumControlInputs > 0) | |||||
{ | |||||
IntPtr control_input_handle = Marshal.AllocHGlobal(Marshal.SizeOf<IntPtr>() * NumControlInputs); | |||||
c_api.TF_OperationGetControlInputs(_handle, control_input_handle, NumControlInputs); | |||||
for (int i = 0; i < NumControlInputs; i++) | |||||
{ | |||||
var handle = control_input_handle + Marshal.SizeOf<IntPtr>() * i; | |||||
control_inputs[i] = new Operation(*(IntPtr*)handle); | |||||
} | |||||
} | |||||
return control_inputs; | |||||
} | |||||
} | |||||
} |
@@ -26,9 +26,6 @@ namespace Tensorflow | |||||
{ | { | ||||
public partial class Operation | public partial class Operation | ||||
{ | { | ||||
#if SERIALIZABLE | |||||
[JsonIgnore] | |||||
#endif | |||||
public int NumOutputs => c_api.TF_OperationNumOutputs(_handle); | public int NumOutputs => c_api.TF_OperationNumOutputs(_handle); | ||||
public TF_DataType OutputType(int index) => c_api.TF_OperationOutputType(_tf_output(index)); | public TF_DataType OutputType(int index) => c_api.TF_OperationOutputType(_tf_output(index)); | ||||
@@ -45,6 +42,9 @@ namespace Tensorflow | |||||
} | } | ||||
private Tensor[] _outputs; | private Tensor[] _outputs; | ||||
#if SERIALIZABLE | |||||
[JsonIgnore] | |||||
#endif | |||||
public Tensor[] outputs => _outputs; | public Tensor[] outputs => _outputs; | ||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
@@ -1,27 +1,27 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using Google.Protobuf.Collections; | using Google.Protobuf.Collections; | ||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
using Newtonsoft.Json; | |||||
#endif | |||||
using Newtonsoft.Json; | |||||
#endif | |||||
using System; | using System; | ||||
using System.Collections.Generic; | using System.Collections.Generic; | ||||
using System.IO; | using System.IO; | ||||
using System.Linq; | |||||
using System.Linq; | |||||
using Tensorflow.Util; | using Tensorflow.Util; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -47,26 +47,26 @@ namespace Tensorflow | |||||
/// </summary> | /// </summary> | ||||
public partial class Operation : ITensorOrOperation | public partial class Operation : ITensorOrOperation | ||||
{ | { | ||||
private readonly IntPtr _handle; // _c_op in python | |||||
private readonly IntPtr _handle; // _c_op in python | |||||
private readonly Graph _graph; | private readonly Graph _graph; | ||||
private NodeDef _node_def; | |||||
private NodeDef _node_def; | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
public string type => OpType; | |||||
public string type => OpType; | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
public Graph graph => _graph; | |||||
public Graph graph => _graph; | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
public int _id => _id_value; | |||||
public int _id => _id_value; | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
public int _id_value { get; set; } | |||||
public int _id_value { get; set; } | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
@@ -74,11 +74,14 @@ namespace Tensorflow | |||||
public TF_DataType dtype => TF_DataType.DtInvalid; | public TF_DataType dtype => TF_DataType.DtInvalid; | ||||
public string name => _handle == IntPtr.Zero ? null : c_api.StringPiece(c_api.TF_OperationName(_handle)); | public string name => _handle == IntPtr.Zero ? null : c_api.StringPiece(c_api.TF_OperationName(_handle)); | ||||
public string OpType => _handle == IntPtr.Zero ? null : c_api.StringPiece(c_api.TF_OperationOpType(_handle)); | public string OpType => _handle == IntPtr.Zero ? null : c_api.StringPiece(c_api.TF_OperationOpType(_handle)); | ||||
public string Device => _handle == IntPtr.Zero ? null : c_api.StringPiece(c_api.TF_OperationDevice(_handle)); | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
bool _is_stateful; | |||||
public string Device => _handle == IntPtr.Zero ? null : c_api.StringPiece(c_api.TF_OperationDevice(_handle)); | |||||
#if SERIALIZABLE | |||||
[JsonIgnore] | |||||
#endif | |||||
bool _is_stateful; | |||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
#endif | #endif | ||||
@@ -103,7 +106,7 @@ namespace Tensorflow | |||||
_outputs = new Tensor[NumOutputs]; | _outputs = new Tensor[NumOutputs]; | ||||
for (int i = 0; i < NumOutputs; i++) | for (int i = 0; i < NumOutputs; i++) | ||||
_outputs[i] = new Tensor(this, i, OutputType(i)); | _outputs[i] = new Tensor(this, i, OutputType(i)); | ||||
// Dict mapping op name to file and line information for op colocation | // Dict mapping op name to file and line information for op colocation | ||||
// context managers. | // context managers. | ||||
_control_flow_context = _graph._get_control_flow_context(); | _control_flow_context = _graph._get_control_flow_context(); | ||||
@@ -151,7 +154,6 @@ namespace Tensorflow | |||||
public Operation(NodeDef node_def, Graph g, Tensor[] inputs = null, TF_DataType[] output_types = null, ITensorOrOperation[] control_inputs = null, TF_DataType[] input_types = null, string original_op = "", OpDef op_def = null) | public Operation(NodeDef node_def, Graph g, Tensor[] inputs = null, TF_DataType[] output_types = null, ITensorOrOperation[] control_inputs = null, TF_DataType[] input_types = null, string original_op = "", OpDef op_def = null) | ||||
{ | { | ||||
_graph = g; | _graph = g; | ||||
// Build the list of control inputs. | // Build the list of control inputs. | ||||
var control_input_ops = new List<Operation>(); | var control_input_ops = new List<Operation>(); | ||||
if (control_inputs != null) | if (control_inputs != null) | ||||
@@ -176,17 +178,17 @@ namespace Tensorflow | |||||
} | } | ||||
} | } | ||||
_id_value = _graph._next_id(); | |||||
_id_value = _graph._next_id(); | |||||
// Dict mapping op name to file and line information for op colocation | // Dict mapping op name to file and line information for op colocation | ||||
// context managers. | // context managers. | ||||
_control_flow_context = graph._get_control_flow_context(); | |||||
_control_flow_context = graph._get_control_flow_context(); | |||||
// This will be set by self.inputs. | // This will be set by self.inputs. | ||||
if (op_def == null) | if (op_def == null) | ||||
op_def = g.GetOpDef(node_def.Op); | |||||
var grouped_inputs = _reconstruct_sequence_inputs(op_def, inputs, node_def.Attr); | |||||
op_def = g.GetOpDef(node_def.Op); | |||||
var grouped_inputs = _reconstruct_sequence_inputs(op_def, inputs, node_def.Attr); | |||||
_handle = ops._create_c_op(g, node_def, grouped_inputs, control_input_ops.ToArray()); | _handle = ops._create_c_op(g, node_def, grouped_inputs, control_input_ops.ToArray()); | ||||
_is_stateful = op_def.IsStateful; | _is_stateful = op_def.IsStateful; | ||||
@@ -427,7 +427,7 @@ namespace Tensorflow | |||||
if (!tf.context.executing_eagerly()) | if (!tf.context.executing_eagerly()) | ||||
{ | { | ||||
var input_tensor = ops.convert_to_tensor(input); | var input_tensor = ops.convert_to_tensor(input); | ||||
var input_shape = tensor_util.to_shape(input_tensor.shape); | |||||
var input_shape = input_tensor.TensorShape; | |||||
if (optimize && input_tensor.NDims > -1 && input_shape.is_fully_defined()) | if (optimize && input_tensor.NDims > -1 && input_shape.is_fully_defined()) | ||||
{ | { | ||||
var nd = np.array(input_tensor.shape).astype(out_type.as_numpy_dtype()); | var nd = np.array(input_tensor.shape).astype(out_type.as_numpy_dtype()); | ||||
@@ -1,21 +1,21 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | ******************************************************************************/ | ||||
using System; | using System; | ||||
using System.Linq; | |||||
using System.Linq; | |||||
using Tensorflow.Operations; | using Tensorflow.Operations; | ||||
using static Tensorflow.Binding; | using static Tensorflow.Binding; | ||||
@@ -31,26 +31,26 @@ namespace Tensorflow | |||||
public static bool IsLoopExit(Operation op) | public static bool IsLoopExit(Operation op) | ||||
{ | { | ||||
return op.type == "Exit" || op.type == "RefExit"; | return op.type == "Exit" || op.type == "RefExit"; | ||||
} | |||||
/// <summary> | |||||
/// Returns true if `op` is an Enter. | |||||
/// </summary> | |||||
/// <param name="op"></param> | |||||
/// <returns></returns> | |||||
} | |||||
/// <summary> | |||||
/// Returns true if `op` is an Enter. | |||||
/// </summary> | |||||
/// <param name="op"></param> | |||||
/// <returns></returns> | |||||
public static bool IsLoopEnter(Operation op) | public static bool IsLoopEnter(Operation op) | ||||
{ | { | ||||
return op.type == "Enter" || op.type == "RefEnter"; | return op.type == "Enter" || op.type == "RefEnter"; | ||||
} | } | ||||
/// <summary> | |||||
/// Return true iff op is a loop invariant. | |||||
/// </summary> | |||||
/// <param name="op"></param> | |||||
/// <summary> | |||||
/// Return true iff op is a loop invariant. | |||||
/// </summary> | |||||
/// <param name="op"></param> | |||||
/// <returns></returns> | /// <returns></returns> | ||||
public static bool IsLoopConstantEnter(Operation op) | |||||
{ | |||||
return IsLoopEnter(op) && op.get_attr<bool>("is_constant"); | |||||
public static bool IsLoopConstantEnter(Operation op) | |||||
{ | |||||
return IsLoopEnter(op) && op.get_attr<bool>("is_constant"); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -61,141 +61,141 @@ namespace Tensorflow | |||||
public static bool IsSwitch(Operation op) | public static bool IsSwitch(Operation op) | ||||
{ | { | ||||
return op.type == "Switch" || op.type == "RefSwitch"; | return op.type == "Switch" || op.type == "RefSwitch"; | ||||
} | |||||
public static WhileContext GetWhileContext(Operation op) | |||||
} | |||||
public static WhileContext GetWhileContext(Operation op) | |||||
=> op.GetWhileContext(); | => op.GetWhileContext(); | ||||
public static bool IsCondSwitch(Operation op) | public static bool IsCondSwitch(Operation op) | ||||
{ | |||||
if (!IsSwitch(op)) | |||||
return false; | |||||
if (op.outputs == null || op.outputs.Length == 0) | |||||
return false; | |||||
{ | |||||
if (!IsSwitch(op)) | |||||
return false; | |||||
if (op.outputs == null || op.outputs.Length == 0) | |||||
return false; | |||||
// Switch nodes are not part of the cond control flow context that they | // Switch nodes are not part of the cond control flow context that they | ||||
// represent, so consider the consumers of its outputs to determine if it is | // represent, so consider the consumers of its outputs to determine if it is | ||||
// cond switch or not. A switch is a cond switch iff all its consumers are in | // cond switch or not. A switch is a cond switch iff all its consumers are in | ||||
// cond contexts. | |||||
var is_cond_switch = true; | |||||
foreach(var o in op.outputs) | |||||
{ | |||||
foreach(var c in o.consumers()) | |||||
{ | |||||
var ctxt = c._get_control_flow_context(); | |||||
if (IsLoopEnter(c)) | |||||
ctxt = ctxt.outer_context; | |||||
is_cond_switch = is_cond_switch &&(ctxt != null && ctxt.IsCondContext()); | |||||
} | |||||
} | |||||
return is_cond_switch; | |||||
// cond contexts. | |||||
var is_cond_switch = true; | |||||
foreach(var o in op.outputs) | |||||
{ | |||||
foreach(var c in o.consumers()) | |||||
{ | |||||
var ctxt = c._get_control_flow_context(); | |||||
if (IsLoopEnter(c)) | |||||
ctxt = ctxt.outer_context; | |||||
is_cond_switch = is_cond_switch &&(ctxt != null && ctxt.IsCondContext()); | |||||
} | |||||
} | |||||
return is_cond_switch; | |||||
} | } | ||||
public static bool IsLoopSwitch(Operation op) | |||||
{ | |||||
if (IsSwitch(op)) | |||||
{ | |||||
var ctxt = op._get_control_flow_context(); | |||||
return ctxt != null && ctxt.IsWhileContext() && !IsCondSwitch(op); | |||||
} | |||||
return false; | |||||
public static bool IsLoopSwitch(Operation op) | |||||
{ | |||||
if (IsSwitch(op)) | |||||
{ | |||||
var ctxt = op._get_control_flow_context(); | |||||
return ctxt != null && ctxt.IsWhileContext() && !IsCondSwitch(op); | |||||
} | |||||
return false; | |||||
} | } | ||||
/// <summary> | |||||
/// Return the control flow context for the output of an op. | |||||
/// </summary> | |||||
/// <summary> | |||||
/// Return the control flow context for the output of an op. | |||||
/// </summary> | |||||
public static ControlFlowContext GetOutputContext(Operation op) | public static ControlFlowContext GetOutputContext(Operation op) | ||||
{ | { | ||||
var ctxt = op._get_control_flow_context(); | var ctxt = op._get_control_flow_context(); | ||||
// Exit nodes usually have a control flow context, except in the case where the | |||||
// exit node was imported via import_graph_def (in which case no nodes have | |||||
// Exit nodes usually have a control flow context, except in the case where the | |||||
// exit node was imported via import_graph_def (in which case no nodes have | |||||
// control flow contexts). | // control flow contexts). | ||||
if (ctxt != null && IsLoopExit(op)) | if (ctxt != null && IsLoopExit(op)) | ||||
ctxt = ctxt.outer_context; | ctxt = ctxt.outer_context; | ||||
return ctxt; | return ctxt; | ||||
} | } | ||||
public static void CheckInputFromValidContext(Operation op, Operation input_op) | |||||
{ | |||||
var op_ctxt = op._get_control_flow_context(); | |||||
var input_ctxt = GetOutputContext(input_op); | |||||
var valid = false; | |||||
if (input_ctxt == null) | |||||
valid = true; | |||||
else if (op_ctxt == input_ctxt) | |||||
valid = true; | |||||
else | |||||
{ | |||||
var while_ctxt = GetContainingWhileContext(op_ctxt); | |||||
var input_while_ctxt = GetContainingWhileContext(input_ctxt); | |||||
if (while_ctxt == null) | |||||
{ | |||||
public static void CheckInputFromValidContext(Operation op, Operation input_op) | |||||
{ | |||||
var op_ctxt = op._get_control_flow_context(); | |||||
var input_ctxt = GetOutputContext(input_op); | |||||
var valid = false; | |||||
if (input_ctxt == null) | |||||
valid = true; | |||||
else if (op_ctxt == input_ctxt) | |||||
valid = true; | |||||
else | |||||
{ | |||||
var while_ctxt = GetContainingWhileContext(op_ctxt); | |||||
var input_while_ctxt = GetContainingWhileContext(input_ctxt); | |||||
if (while_ctxt == null) | |||||
{ | |||||
// Neither op nor input_op is in a while loop, but one or both are in | // Neither op nor input_op is in a while loop, but one or both are in | ||||
// conds. We allow this, although execution will fail if the branch | // conds. We allow this, although execution will fail if the branch | ||||
// corresponding to input_op's cond context isn't taken. | |||||
if (input_while_ctxt == null) | |||||
valid = true; | |||||
// Invalid if op isn't in a while loop and input_op is. Unless... | |||||
if (IsLoopEnter(op)) | |||||
// WhileContext._BuildLoop clears context for Enter nodes. | |||||
valid = true; | |||||
if (IsSwitch(op)) | |||||
// CondContext.AddValue clears context for Switch nodes. | |||||
valid = true; | |||||
} | |||||
else if (IsContainingContext(while_ctxt, input_while_ctxt)) | |||||
{ | |||||
// input_op is in a while loop which contains op's while loop (or not in a | |||||
// while loop at all). | |||||
valid = true; | |||||
} | |||||
else if (while_ctxt.grad_state != null && | |||||
// corresponding to input_op's cond context isn't taken. | |||||
if (input_while_ctxt == null) | |||||
valid = true; | |||||
// Invalid if op isn't in a while loop and input_op is. Unless... | |||||
if (IsLoopEnter(op)) | |||||
// WhileContext._BuildLoop clears context for Enter nodes. | |||||
valid = true; | |||||
if (IsSwitch(op)) | |||||
// CondContext.AddValue clears context for Switch nodes. | |||||
valid = true; | |||||
} | |||||
else if (IsContainingContext(while_ctxt, input_while_ctxt)) | |||||
{ | |||||
// input_op is in a while loop which contains op's while loop (or not in a | |||||
// while loop at all). | |||||
valid = true; | |||||
} | |||||
else if (while_ctxt.grad_state != null && | |||||
IsContainingContext(while_ctxt.grad_state.forward_context, | IsContainingContext(while_ctxt.grad_state.forward_context, | ||||
input_while_ctxt)) | |||||
{ | |||||
valid = true; | |||||
} | |||||
else | |||||
throw new NotImplementedException("CheckInputFromValidContext"); | |||||
} | |||||
if (!valid) | |||||
{ | |||||
throw new NotImplementedException("CheckInputFromValidContext"); | |||||
} | |||||
} | |||||
public static Operation GetLoopConstantEnter(Tensor value) | |||||
{ | |||||
var id_ops = new string[] { "Switch", "RefSwitch", "Identity", "RefIdentity" }; | |||||
var op = value.op; | |||||
while (id_ops.Contains(op.type)) | |||||
op = op.inputs[0].op; | |||||
return IsLoopConstantEnter(op) ? op : null; | |||||
input_while_ctxt)) | |||||
{ | |||||
valid = true; | |||||
} | |||||
else | |||||
throw new NotImplementedException("CheckInputFromValidContext"); | |||||
} | |||||
if (!valid) | |||||
{ | |||||
throw new NotImplementedException("CheckInputFromValidContext"); | |||||
} | |||||
} | } | ||||
public static bool IsContainingContext(WhileContext ctxt, WhileContext maybe_containing_ctxt) | |||||
{ | |||||
while(ctxt != maybe_containing_ctxt) | |||||
{ | |||||
if (ctxt == null) | |||||
return false; | |||||
ctxt = ctxt.outer_context as WhileContext; | |||||
} | |||||
return true; | |||||
public static Operation GetLoopConstantEnter(Tensor value) | |||||
{ | |||||
var id_ops = new string[] { "Switch", "RefSwitch", "Identity", "RefIdentity" }; | |||||
var op = value.op; | |||||
while (id_ops.Contains(op.type)) | |||||
op = op.inputs[0].op; | |||||
return IsLoopConstantEnter(op) ? op : null; | |||||
} | } | ||||
public static WhileContext GetContainingWhileContext(ControlFlowContext ctxt, ControlFlowContext stop_ctxt = null) | |||||
{ | |||||
while (ctxt != null) | |||||
{ | |||||
if (ctxt.IsWhileContext() || ctxt == stop_ctxt) | |||||
return ctxt as WhileContext; | |||||
ctxt = ctxt.outer_context; | |||||
} | |||||
return null; | |||||
public static bool IsContainingContext(WhileContext ctxt, WhileContext maybe_containing_ctxt) | |||||
{ | |||||
while(ctxt != maybe_containing_ctxt) | |||||
{ | |||||
if (ctxt == null) | |||||
return false; | |||||
ctxt = ctxt.outer_context as WhileContext; | |||||
} | |||||
return true; | |||||
} | |||||
public static WhileContext GetContainingWhileContext(ControlFlowContext ctxt, ControlFlowContext stop_ctxt = null) | |||||
{ | |||||
while (ctxt != null) | |||||
{ | |||||
if (ctxt.IsWhileContext() || ctxt == stop_ctxt) | |||||
return ctxt as WhileContext; | |||||
ctxt = ctxt.outer_context; | |||||
} | |||||
return null; | |||||
} | } | ||||
} | } | ||||
} | } |
@@ -35,14 +35,17 @@ namespace Tensorflow | |||||
x = ops.convert_to_tensor(x, name: "x"); | x = ops.convert_to_tensor(x, name: "x"); | ||||
if (x.dtype.is_complex()) | if (x.dtype.is_complex()) | ||||
throw new NotImplementedException("math_ops.abs for dtype.is_complex"); | throw new NotImplementedException("math_ops.abs for dtype.is_complex"); | ||||
//return gen_math_ops.complex_abs(x, Tout: x.dtype.real_dtype, name: name); | |||||
//return gen_math_ops.complex_abs(x, Tout: x.dtype.real_dtype, name: name); | |||||
return gen_math_ops._abs(x, name: name); | return gen_math_ops._abs(x, name: name); | ||||
}); | }); | ||||
} | } | ||||
public static Tensor add<Tx, Ty>(Tx x, Ty y, string name = null) | |||||
public static Tensor add<Tx, Ty>(Tx x, Ty y, string name = null) | |||||
=> gen_math_ops.add(x, y, name); | => gen_math_ops.add(x, y, name); | ||||
public static Tensor add_v2<Tx, Ty>(Tx x, Ty y, string name = null) | |||||
=> gen_math_ops.add_v2(x, y, name); | |||||
/// <summary> | /// <summary> | ||||
/// Adds all input tensors element-wise. | /// Adds all input tensors element-wise. | ||||
/// </summary> | /// </summary> | ||||
@@ -53,21 +56,38 @@ namespace Tensorflow | |||||
{ | { | ||||
inputs = ops.convert_n_to_tensor_or_indexed_slices(inputs); | inputs = ops.convert_n_to_tensor_or_indexed_slices(inputs); | ||||
if(inputs.Length == 1) | |||||
if (inputs.Length == 1) | |||||
{ | { | ||||
var values = inputs[0]; | var values = inputs[0]; | ||||
if (name != null) | if (name != null) | ||||
return array_ops.identity(values, name: name); | return array_ops.identity(values, name: name); | ||||
return values; | return values; | ||||
} | } | ||||
return gen_math_ops.add_n(inputs, name: name); | return gen_math_ops.add_n(inputs, name: name); | ||||
} | } | ||||
public static Tensor cast(RefVariable x, TF_DataType dtype = TF_DataType.DtInvalid, string name = null) | |||||
{ | |||||
var base_type = dtype.as_base_dtype(); | |||||
if (base_type == x.dtype) | |||||
return x; | |||||
return tf_with(ops.name_scope(name, "Cast", new { x }), scope => | |||||
{ | |||||
name = scope; | |||||
var t_x = ops.convert_to_tensor(x, name: "x"); | |||||
if (t_x.dtype.as_base_dtype() != base_type) | |||||
t_x = gen_math_ops.cast(t_x, base_type, name: name); | |||||
return x; | |||||
}); | |||||
} | |||||
public static Tensor cast(Tensor x, TF_DataType dtype = TF_DataType.DtInvalid, string name = null) | public static Tensor cast(Tensor x, TF_DataType dtype = TF_DataType.DtInvalid, string name = null) | ||||
{ | { | ||||
var base_type = dtype.as_base_dtype(); | var base_type = dtype.as_base_dtype(); | ||||
if(base_type == x.dtype) | |||||
if (base_type == x.dtype) | |||||
return x; | return x; | ||||
return tf_with(ops.name_scope(name, "Cast", new { x }), scope => | return tf_with(ops.name_scope(name, "Cast", new { x }), scope => | ||||
@@ -98,13 +118,13 @@ namespace Tensorflow | |||||
public static Tensor cumsum<T>(Tensor x, T axis = default, bool exclusive = false, bool reverse = false, string name = null) | public static Tensor cumsum<T>(Tensor x, T axis = default, bool exclusive = false, bool reverse = false, string name = null) | ||||
{ | { | ||||
return tf_with(ops.name_scope(name, "Cumsum", new {x}), scope => | |||||
{ | |||||
name = scope; | |||||
x = ops.convert_to_tensor(x, name: "x"); | |||||
return tf_with(ops.name_scope(name, "Cumsum", new { x }), scope => | |||||
{ | |||||
name = scope; | |||||
x = ops.convert_to_tensor(x, name: "x"); | |||||
return gen_math_ops.cumsum(x, axis: axis, exclusive: exclusive, reverse: reverse, name: name); | |||||
}); | |||||
return gen_math_ops.cumsum(x, axis: axis, exclusive: exclusive, reverse: reverse, name: name); | |||||
}); | |||||
} | } | ||||
/// <summary> | /// <summary> | ||||
@@ -221,7 +241,7 @@ namespace Tensorflow | |||||
public static Tensor reduce_mean(Tensor[] input_tensors, int? axis = null, bool keepdims = false, string name = null) | public static Tensor reduce_mean(Tensor[] input_tensors, int? axis = null, bool keepdims = false, string name = null) | ||||
{ | { | ||||
if(axis == null) | |||||
if (axis == null) | |||||
{ | { | ||||
var r = _ReductionDims(input_tensors, axis); | var r = _ReductionDims(input_tensors, axis); | ||||
var m = gen_math_ops.mean(input_tensors, r, keepdims, name); | var m = gen_math_ops.mean(input_tensors, r, keepdims, name); | ||||
@@ -263,14 +283,8 @@ namespace Tensorflow | |||||
return gen_math_ops.sigmoid(x_tensor, name: name); | return gen_math_ops.sigmoid(x_tensor, name: name); | ||||
} | } | ||||
public static Tensor sign(Tensor x, string name = null) | |||||
{ | |||||
return tf_with(ops.name_scope(name, "Sign", new {x}), scope => | |||||
{ | |||||
x = ops.convert_to_tensor(x, name: "x"); | |||||
return gen_math_ops.sign(x); | |||||
}); | |||||
} | |||||
public static Tensor sign<T>(T x, string name = null) | |||||
=> gen_math_ops.sign(x, name: name); | |||||
/// <summary> | /// <summary> | ||||
/// Returns (x - y)(x - y) element-wise. | /// Returns (x - y)(x - y) element-wise. | ||||
@@ -355,6 +369,9 @@ namespace Tensorflow | |||||
return _may_reduce_to_scalar(keepdims, axis, all); | return _may_reduce_to_scalar(keepdims, axis, all); | ||||
} | } | ||||
public static Tensor realdiv(Tensor x, Tensor y, string name = null) | |||||
=> gen_math_ops.real_div(x, y, name: name); | |||||
/// <summary> | /// <summary> | ||||
/// Computes log(sum(exp(elements across dimensions of a tensor))). | /// Computes log(sum(exp(elements across dimensions of a tensor))). | ||||
/// Reduces `input_tensor` along the dimensions given in `axis`. | /// Reduces `input_tensor` along the dimensions given in `axis`. | ||||
@@ -561,6 +578,9 @@ namespace Tensorflow | |||||
public static Tensor rsqrt(Tensor x, string name = null) | public static Tensor rsqrt(Tensor x, string name = null) | ||||
=> gen_math_ops.rsqrt(x, name: name); | => gen_math_ops.rsqrt(x, name: name); | ||||
public static Tensor pow<Tx, Ty>(Tx x, Ty y, string name = null) | |||||
=> gen_math_ops.pow(x, y, name: name); | |||||
public static Tensor range(object start, object limit = null, object delta = null, TF_DataType dtype = TF_DataType.DtInvalid, string name = "range") | public static Tensor range(object start, object limit = null, object delta = null, TF_DataType dtype = TF_DataType.DtInvalid, string name = "range") | ||||
{ | { | ||||
if(limit == null) | if(limit == null) | ||||
@@ -117,7 +117,7 @@ namespace Tensorflow | |||||
var min_epsilon = 1.001e-5f; | var min_epsilon = 1.001e-5f; | ||||
epsilon = epsilon > min_epsilon ? epsilon : min_epsilon; | epsilon = epsilon > min_epsilon ? epsilon : min_epsilon; | ||||
var results = gen_nn_ops.fused_batch_norm(x, | |||||
var results = gen_nn_ops.fused_batch_norm_v3(x, | |||||
scale_tensor, | scale_tensor, | ||||
offset_tensor, | offset_tensor, | ||||
mean, | mean, | ||||
@@ -1,8 +1,8 @@ | |||||
using System.Collections; | |||||
namespace Tensorflow.Sessions | |||||
{ | |||||
public class FeedDict : Hashtable | |||||
{ | |||||
} | |||||
} | |||||
using System.Collections; | |||||
namespace Tensorflow.Sessions | |||||
{ | |||||
public class FeedDict : Hashtable | |||||
{ | |||||
} | |||||
} |
@@ -5,7 +5,7 @@ | |||||
<AssemblyName>TensorFlow.NET</AssemblyName> | <AssemblyName>TensorFlow.NET</AssemblyName> | ||||
<RootNamespace>Tensorflow</RootNamespace> | <RootNamespace>Tensorflow</RootNamespace> | ||||
<TargetTensorFlow>1.14.1</TargetTensorFlow> | <TargetTensorFlow>1.14.1</TargetTensorFlow> | ||||
<Version>0.14.2.0</Version> | |||||
<Version>0.15.0</Version> | |||||
<Authors>Haiping Chen, Meinrad Recheis, Eli Belash</Authors> | <Authors>Haiping Chen, Meinrad Recheis, Eli Belash</Authors> | ||||
<Company>SciSharp STACK</Company> | <Company>SciSharp STACK</Company> | ||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | <GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||||
@@ -18,13 +18,15 @@ | |||||
<Description>Google's TensorFlow full binding in .NET Standard. | <Description>Google's TensorFlow full binding in .NET Standard. | ||||
Building, training and infering deep learning models. | Building, training and infering deep learning models. | ||||
https://tensorflownet.readthedocs.io</Description> | https://tensorflownet.readthedocs.io</Description> | ||||
<AssemblyVersion>0.14.2.0</AssemblyVersion> | |||||
<AssemblyVersion>0.15.0.0</AssemblyVersion> | |||||
<PackageReleaseNotes>Changes since v0.14.0: | <PackageReleaseNotes>Changes since v0.14.0: | ||||
1: Add TransformGraphWithStringInputs. | 1: Add TransformGraphWithStringInputs. | ||||
2: tf.trainer.load_graph, tf.trainer.freeze_graph | 2: tf.trainer.load_graph, tf.trainer.freeze_graph | ||||
3: Import Protobuf.Text</PackageReleaseNotes> | |||||
3: Import Protobuf.Text | |||||
4: Support YOLOv3 object detection | |||||
5: Add implicitation for Operation to RefVariable</PackageReleaseNotes> | |||||
<LangVersion>7.3</LangVersion> | <LangVersion>7.3</LangVersion> | ||||
<FileVersion>0.14.2.0</FileVersion> | |||||
<FileVersion>0.15.0.0</FileVersion> | |||||
<PackageLicenseFile>LICENSE</PackageLicenseFile> | <PackageLicenseFile>LICENSE</PackageLicenseFile> | ||||
<PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | <PackageRequireLicenseAcceptance>true</PackageRequireLicenseAcceptance> | ||||
<SignAssembly>true</SignAssembly> | <SignAssembly>true</SignAssembly> | ||||
@@ -61,8 +63,8 @@ https://tensorflownet.readthedocs.io</Description> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Google.Protobuf" Version="3.11.3" /> | |||||
<PackageReference Include="NumSharp" Version="0.30.0-alpha" /> | |||||
<PackageReference Include="Google.Protobuf" Version="3.11.4" /> | |||||
<PackageReference Include="NumSharp.Lite" Version="0.1.4" /> | |||||
<PackageReference Include="Protobuf.Text" Version="0.4.0" /> | <PackageReference Include="Protobuf.Text" Version="0.4.0" /> | ||||
</ItemGroup> | </ItemGroup> | ||||
@@ -328,7 +328,7 @@ namespace Tensorflow | |||||
switch (name.ToLowerInvariant()) | switch (name.ToLowerInvariant()) | ||||
{ | { | ||||
case "add": | case "add": | ||||
result = math_ops.add(x1, y1, name: scope); | |||||
result = math_ops.add_v2(x1, y1, name: scope); | |||||
break; | break; | ||||
case "div": | case "div": | ||||
result = math_ops.div(x1, y1, name: scope); | result = math_ops.div(x1, y1, name: scope); | ||||
@@ -115,6 +115,9 @@ namespace Tensorflow | |||||
/// <summary> | /// <summary> | ||||
/// The name of the device on which this tensor will be produced, or null. | /// The name of the device on which this tensor will be produced, or null. | ||||
/// </summary> | /// </summary> | ||||
#if SERIALIZABLE | |||||
[JsonIgnore] | |||||
#endif | |||||
public string Device => op.Device; | public string Device => op.Device; | ||||
#if SERIALIZABLE | #if SERIALIZABLE | ||||
[JsonIgnore] | [JsonIgnore] | ||||
@@ -205,7 +205,9 @@ namespace Tensorflow | |||||
//} | //} | ||||
//else | //else | ||||
{ | { | ||||
apply_updates = state_ops.assign_add(global_step, tf.constant(1), name: name); | |||||
apply_updates = state_ops.assign_add(global_step, | |||||
ops.convert_to_tensor(1, dtype: global_step.dtype), | |||||
name: name); | |||||
} | } | ||||
}); | }); | ||||
} | } | ||||
@@ -61,7 +61,11 @@ namespace Tensorflow | |||||
{ | { | ||||
_in_graph_mode = true; | _in_graph_mode = true; | ||||
if (variable_def != null) | |||||
if(initial_value is Operation op) | |||||
{ | |||||
_init_from_op(op); | |||||
} | |||||
else if (variable_def != null) | |||||
{ | { | ||||
if (initial_value != null) | if (initial_value != null) | ||||
throw new ValueError("variable_def and initial_value are mutually exclusive."); | throw new ValueError("variable_def and initial_value are mutually exclusive."); | ||||
@@ -73,6 +77,13 @@ namespace Tensorflow | |||||
} | } | ||||
} | } | ||||
private void _init_from_op(Operation op) | |||||
{ | |||||
var g = ops.get_default_graph(); | |||||
_initializer_op = op; | |||||
_variable = op.output; | |||||
} | |||||
private void _init_from_proto(VariableDef variable_def, string import_scope = "") | private void _init_from_proto(VariableDef variable_def, string import_scope = "") | ||||
{ | { | ||||
var g = ops.get_default_graph(); | var g = ops.get_default_graph(); | ||||
@@ -1,156 +1,156 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using Tensorflow.Eager; | |||||
namespace Tensorflow | |||||
{ | |||||
public class gen_state_ops | |||||
{ | |||||
public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | |||||
public static Execute _execute = new Execute(); | |||||
/// <summary> | |||||
/// Holds state in the form of a tensor that persists across steps. | |||||
/// Outputs a ref to the tensor state so it may be read or modified. | |||||
/// </summary> | |||||
/// <param name="shape">The shape of the variable tensor.</param> | |||||
/// <param name="dtype">The type of elements in the variable tensor.</param> | |||||
/// <param name="name"></param> | |||||
/// <param name="container"></param> | |||||
/// <param name="shared_name"></param> | |||||
/// <returns></returns> | |||||
public static Tensor variable_v2(int[] shape, TF_DataType dtype, string name = null, string container = "", string shared_name = "") | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("VariableV2", name: name, args: new { dtype, shape, container, shared_name }); | |||||
var _result = _op.outputs; | |||||
var _inputs_flat = _op.inputs; | |||||
var _attrs = new Dictionary<string, object>(); | |||||
_attrs["dtype"] = _op.get_attr("dtype"); | |||||
_attrs["shape"] = _op.get_attr("shape"); | |||||
_attrs["container"] = _op.get_attr("container"); | |||||
_attrs["shared_name"] = _op.get_attr("shared_name"); | |||||
_execute.record_gradient("VariableV2", _inputs_flat, _attrs, _result, name); | |||||
return _result[0]; | |||||
} | |||||
/// <summary> | |||||
/// Update 'ref' by assigning 'value' to it | |||||
/// </summary> | |||||
/// <param name="REF"></param> | |||||
/// <param name="value"></param> | |||||
/// <param name="validate_shape"></param> | |||||
/// <param name="use_locking"></param> | |||||
/// <param name="name"></param> | |||||
public static Tensor assign(Tensor @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { @ref, value, validate_shape, use_locking }); | |||||
var _result = _op.outputs; | |||||
var _inputs_flat = _op.inputs; | |||||
var _attrs = new Dictionary<string, object>(); | |||||
_attrs["T"] = _op.get_attr("T"); | |||||
_attrs["validate_shape"] = _op.get_attr("validate_shape"); | |||||
_attrs["use_locking"] = _op.get_attr("use_locking"); | |||||
_execute.record_gradient("Assign", _inputs_flat, _attrs, _result, name); | |||||
return _result[0]; | |||||
} | |||||
public static Tensor assign(RefVariable @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { @ref, value, validate_shape, use_locking }); | |||||
var _result = _op.outputs; | |||||
var _inputs_flat = _op.inputs; | |||||
var _attrs = new Dictionary<string, object>(); | |||||
_attrs["T"] = _op.get_attr("T"); | |||||
_attrs["validate_shape"] = _op.get_attr("validate_shape"); | |||||
_attrs["use_locking"] = _op.get_attr("use_locking"); | |||||
_execute.record_gradient("Assign", _inputs_flat, _attrs, _result, name); | |||||
return _result[0]; | |||||
} | |||||
public static Tensor assign_sub(RefVariable @ref, | |||||
Tensor value, | |||||
bool use_locking = false, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("AssignSub", name: name, args: new { @ref, value, use_locking }); | |||||
return _op.outputs[0]; | |||||
} | |||||
// Update 'ref' by adding 'value' to it. | |||||
// This operation outputs "ref" after the update is done. | |||||
// This makes it easier to chain operations that need to use the reset value. | |||||
// Args: | |||||
// ref: A mutable `Tensor`. Must be one of the following types: `float32`, `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, `uint32`, `uint64`. | |||||
// Should be from a `Variable` node. | |||||
// value: A `Tensor`. Must have the same type as `ref`. | |||||
// The value to be added to the variable. | |||||
// use_locking: An optional `bool`. Defaults to `False`. | |||||
// If True, the addition will be protected by a lock; | |||||
// otherwise the behavior is undefined, but may exhibit less contention. | |||||
// name: A name for the operation(optional). | |||||
// Returns: | |||||
// A mutable `Tensor`. Has the same type as `ref`. | |||||
public static Tensor assign_add<T>(RefVariable @ref, T value, bool use_locking = false, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("AssignAdd", name: name, args: new { @ref, value, use_locking }); | |||||
return _op.outputs[0]; | |||||
} | |||||
/// <summary> | |||||
/// Adds sparse updates to a variable reference. | |||||
/// </summary> | |||||
/// <param name="ref"></param> | |||||
/// <param name="indices"></param> | |||||
/// <param name="updates"></param> | |||||
/// <param name="use_locking"></param> | |||||
/// <param name="name"></param> | |||||
/// <returns></returns> | |||||
public static Tensor scatter_add(RefVariable @ref, Tensor indices, Tensor updates, bool use_locking = false, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("ScatterAdd", name: name, args: new { @ref, indices, updates, use_locking }); | |||||
return _op.outputs[0]; | |||||
} | |||||
public static Tensor is_variable_initialized(RefVariable @ref, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("IsVariableInitialized", name: name, args: new { @ref }); | |||||
return _op.output; | |||||
} | |||||
} | |||||
} | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
using System.Collections.Generic; | |||||
using Tensorflow.Eager; | |||||
namespace Tensorflow | |||||
{ | |||||
public class gen_state_ops | |||||
{ | |||||
public static OpDefLibrary _op_def_lib = new OpDefLibrary(); | |||||
public static Execute _execute = new Execute(); | |||||
/// <summary> | |||||
/// Holds state in the form of a tensor that persists across steps. | |||||
/// Outputs a ref to the tensor state so it may be read or modified. | |||||
/// </summary> | |||||
/// <param name="shape">The shape of the variable tensor.</param> | |||||
/// <param name="dtype">The type of elements in the variable tensor.</param> | |||||
/// <param name="name"></param> | |||||
/// <param name="container"></param> | |||||
/// <param name="shared_name"></param> | |||||
/// <returns></returns> | |||||
public static Tensor variable_v2(int[] shape, TF_DataType dtype, string name = null, string container = "", string shared_name = "") | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("VariableV2", name: name, args: new { dtype, shape, container, shared_name }); | |||||
var _result = _op.outputs; | |||||
var _inputs_flat = _op.inputs; | |||||
var _attrs = new Dictionary<string, object>(); | |||||
_attrs["dtype"] = _op.get_attr("dtype"); | |||||
_attrs["shape"] = _op.get_attr("shape"); | |||||
_attrs["container"] = _op.get_attr("container"); | |||||
_attrs["shared_name"] = _op.get_attr("shared_name"); | |||||
_execute.record_gradient("VariableV2", _inputs_flat, _attrs, _result, name); | |||||
return _result[0]; | |||||
} | |||||
/// <summary> | |||||
/// Update 'ref' by assigning 'value' to it | |||||
/// </summary> | |||||
/// <param name="REF"></param> | |||||
/// <param name="value"></param> | |||||
/// <param name="validate_shape"></param> | |||||
/// <param name="use_locking"></param> | |||||
/// <param name="name"></param> | |||||
public static Tensor assign(Tensor @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { @ref, value, validate_shape, use_locking }); | |||||
var _result = _op.outputs; | |||||
var _inputs_flat = _op.inputs; | |||||
var _attrs = new Dictionary<string, object>(); | |||||
_attrs["T"] = _op.get_attr("T"); | |||||
_attrs["validate_shape"] = _op.get_attr("validate_shape"); | |||||
_attrs["use_locking"] = _op.get_attr("use_locking"); | |||||
_execute.record_gradient("Assign", _inputs_flat, _attrs, _result, name); | |||||
return _result[0]; | |||||
} | |||||
public static Tensor assign(RefVariable @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("Assign", name: name, args: new { @ref, value, validate_shape, use_locking }); | |||||
var _result = _op.outputs; | |||||
var _inputs_flat = _op.inputs; | |||||
var _attrs = new Dictionary<string, object>(); | |||||
_attrs["T"] = _op.get_attr("T"); | |||||
_attrs["validate_shape"] = _op.get_attr("validate_shape"); | |||||
_attrs["use_locking"] = _op.get_attr("use_locking"); | |||||
_execute.record_gradient("Assign", _inputs_flat, _attrs, _result, name); | |||||
return _result[0]; | |||||
} | |||||
public static Tensor assign_sub(RefVariable @ref, | |||||
Tensor value, | |||||
bool use_locking = false, | |||||
string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("AssignSub", name: name, args: new { @ref, value, use_locking }); | |||||
return _op.outputs[0]; | |||||
} | |||||
// Update 'ref' by adding 'value' to it. | |||||
// This operation outputs "ref" after the update is done. | |||||
// This makes it easier to chain operations that need to use the reset value. | |||||
// Args: | |||||
// ref: A mutable `Tensor`. Must be one of the following types: `float32`, `float64`, `int32`, `uint8`, `int16`, `int8`, `complex64`, `int64`, `qint8`, `quint8`, `qint32`, `bfloat16`, `uint16`, `complex128`, `half`, `uint32`, `uint64`. | |||||
// Should be from a `Variable` node. | |||||
// value: A `Tensor`. Must have the same type as `ref`. | |||||
// The value to be added to the variable. | |||||
// use_locking: An optional `bool`. Defaults to `False`. | |||||
// If True, the addition will be protected by a lock; | |||||
// otherwise the behavior is undefined, but may exhibit less contention. | |||||
// name: A name for the operation(optional). | |||||
// Returns: | |||||
// A mutable `Tensor`. Has the same type as `ref`. | |||||
public static Tensor assign_add<T>(RefVariable @ref, T value, bool use_locking = false, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("AssignAdd", name: name, args: new { @ref, value, use_locking }); | |||||
return _op.outputs[0]; | |||||
} | |||||
/// <summary> | |||||
/// Adds sparse updates to a variable reference. | |||||
/// </summary> | |||||
/// <param name="ref"></param> | |||||
/// <param name="indices"></param> | |||||
/// <param name="updates"></param> | |||||
/// <param name="use_locking"></param> | |||||
/// <param name="name"></param> | |||||
/// <returns></returns> | |||||
public static Tensor scatter_add(RefVariable @ref, Tensor indices, Tensor updates, bool use_locking = false, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("ScatterAdd", name: name, args: new { @ref, indices, updates, use_locking }); | |||||
return _op.outputs[0]; | |||||
} | |||||
public static Tensor is_variable_initialized(RefVariable @ref, string name = null) | |||||
{ | |||||
var _op = _op_def_lib._apply_op_helper("IsVariableInitialized", name: name, args: new { @ref }); | |||||
return _op.output; | |||||
} | |||||
} | |||||
} |
@@ -1,123 +1,123 @@ | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
namespace Tensorflow | |||||
{ | |||||
public class state_ops | |||||
{ | |||||
/// <summary> | |||||
/// Create a variable Operation. | |||||
/// </summary> | |||||
/// <param name="shape"></param> | |||||
/// <param name="dtype"></param> | |||||
/// <param name="name"></param> | |||||
/// <param name="container"></param> | |||||
/// <param name="shared_name"></param> | |||||
/// <returns></returns> | |||||
public static Tensor variable_op_v2(int[] shape, | |||||
TF_DataType dtype, | |||||
string name = "Variable", | |||||
string container = "", | |||||
string shared_name = "") => gen_state_ops.variable_v2(shape, | |||||
dtype, | |||||
name: name, | |||||
container: container, | |||||
shared_name: shared_name); | |||||
public static Tensor assign(Tensor @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.assign(@ref, | |||||
value, | |||||
validate_shape: validate_shape, | |||||
use_locking: use_locking, | |||||
name: name); | |||||
return @ref.assign((Tensor)value, name: name); | |||||
} | |||||
public static Tensor assign(RefVariable @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
return gen_state_ops.assign(@ref, | |||||
value, | |||||
validate_shape: validate_shape, | |||||
use_locking: use_locking, | |||||
name: name); | |||||
} | |||||
public static Tensor assign_sub(RefVariable @ref, | |||||
Tensor value, | |||||
bool use_locking = false, | |||||
string name = null) => gen_state_ops.assign_sub(@ref, | |||||
value, | |||||
use_locking: use_locking, | |||||
name: name); | |||||
//"""Update 'ref' by adding 'value' to it. | |||||
// | |||||
// This operation outputs "ref" after the update is done. | |||||
// This makes it easier to chain operations that need to use the reset value. | |||||
// | |||||
// Args: | |||||
// ref: A mutable `Tensor`. Must be one of the following types: | |||||
// `float32`, `float64`, `int64`, `int32`, `uint8`, `uint16`, `int16`, | |||||
// `int8`, `complex64`, `complex128`, `qint8`, `quint8`, `qint32`, `half`. | |||||
// Should be from a `Variable` node. | |||||
// value: A `Tensor`. Must have the same type as `ref`. | |||||
// The value to be added to the variable. | |||||
// use_locking: An optional `bool`. Defaults to `False`. | |||||
// If True, the addition will be protected by a lock; | |||||
// otherwise the behavior is undefined, but may exhibit less contention. | |||||
// name: A name for the operation (optional). | |||||
// | |||||
// Returns: | |||||
// Same as "ref". Returned as a convenience for operations that want | |||||
// to use the new value after the variable has been updated. | |||||
public static Tensor assign_add<T>(RefVariable @ref, | |||||
T value, | |||||
bool use_locking = false, | |||||
string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.assign_add(@ref, value, use_locking: use_locking, name: name); | |||||
throw new NotImplementedException("assign_add"); | |||||
} | |||||
public static Tensor scatter_add(RefVariable @ref, Tensor indices, Tensor updates, bool use_locking = false, string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.scatter_add(@ref, indices, updates, use_locking: use_locking, name: name); | |||||
throw new NotImplementedException("scatter_add"); | |||||
} | |||||
public static Tensor is_variable_initialized(RefVariable @ref, string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.is_variable_initialized(@ref: @ref, name: name); | |||||
throw new NotImplementedException(""); | |||||
//return @ref.is_initialized(name: name); | |||||
} | |||||
} | |||||
} | |||||
/***************************************************************************** | |||||
Copyright 2018 The TensorFlow.NET Authors. All Rights Reserved. | |||||
Licensed under the Apache License, Version 2.0 (the "License"); | |||||
you may not use this file except in compliance with the License. | |||||
You may obtain a copy of the License at | |||||
http://www.apache.org/licenses/LICENSE-2.0 | |||||
Unless required by applicable law or agreed to in writing, software | |||||
distributed under the License is distributed on an "AS IS" BASIS, | |||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||||
See the License for the specific language governing permissions and | |||||
limitations under the License. | |||||
******************************************************************************/ | |||||
using System; | |||||
namespace Tensorflow | |||||
{ | |||||
public class state_ops | |||||
{ | |||||
/// <summary> | |||||
/// Create a variable Operation. | |||||
/// </summary> | |||||
/// <param name="shape"></param> | |||||
/// <param name="dtype"></param> | |||||
/// <param name="name"></param> | |||||
/// <param name="container"></param> | |||||
/// <param name="shared_name"></param> | |||||
/// <returns></returns> | |||||
public static Tensor variable_op_v2(int[] shape, | |||||
TF_DataType dtype, | |||||
string name = "Variable", | |||||
string container = "", | |||||
string shared_name = "") => gen_state_ops.variable_v2(shape, | |||||
dtype, | |||||
name: name, | |||||
container: container, | |||||
shared_name: shared_name); | |||||
public static Tensor assign(Tensor @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.assign(@ref, | |||||
value, | |||||
validate_shape: validate_shape, | |||||
use_locking: use_locking, | |||||
name: name); | |||||
return @ref.assign((Tensor)value, name: name); | |||||
} | |||||
public static Tensor assign(RefVariable @ref, object value, | |||||
bool validate_shape = true, | |||||
bool use_locking = true, | |||||
string name = null) | |||||
{ | |||||
return gen_state_ops.assign(@ref, | |||||
value, | |||||
validate_shape: validate_shape, | |||||
use_locking: use_locking, | |||||
name: name); | |||||
} | |||||
public static Tensor assign_sub(RefVariable @ref, | |||||
Tensor value, | |||||
bool use_locking = false, | |||||
string name = null) => gen_state_ops.assign_sub(@ref, | |||||
value, | |||||
use_locking: use_locking, | |||||
name: name); | |||||
//"""Update 'ref' by adding 'value' to it. | |||||
// | |||||
// This operation outputs "ref" after the update is done. | |||||
// This makes it easier to chain operations that need to use the reset value. | |||||
// | |||||
// Args: | |||||
// ref: A mutable `Tensor`. Must be one of the following types: | |||||
// `float32`, `float64`, `int64`, `int32`, `uint8`, `uint16`, `int16`, | |||||
// `int8`, `complex64`, `complex128`, `qint8`, `quint8`, `qint32`, `half`. | |||||
// Should be from a `Variable` node. | |||||
// value: A `Tensor`. Must have the same type as `ref`. | |||||
// The value to be added to the variable. | |||||
// use_locking: An optional `bool`. Defaults to `False`. | |||||
// If True, the addition will be protected by a lock; | |||||
// otherwise the behavior is undefined, but may exhibit less contention. | |||||
// name: A name for the operation (optional). | |||||
// | |||||
// Returns: | |||||
// Same as "ref". Returned as a convenience for operations that want | |||||
// to use the new value after the variable has been updated. | |||||
public static Tensor assign_add<T>(RefVariable @ref, | |||||
T value, | |||||
bool use_locking = false, | |||||
string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.assign_add(@ref, value, use_locking: use_locking, name: name); | |||||
throw new NotImplementedException("assign_add"); | |||||
} | |||||
public static Tensor scatter_add(RefVariable @ref, Tensor indices, Tensor updates, bool use_locking = false, string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.scatter_add(@ref, indices, updates, use_locking: use_locking, name: name); | |||||
throw new NotImplementedException("scatter_add"); | |||||
} | |||||
public static Tensor is_variable_initialized(RefVariable @ref, string name = null) | |||||
{ | |||||
if (@ref.dtype.is_ref_dtype()) | |||||
return gen_state_ops.is_variable_initialized(@ref: @ref, name: name); | |||||
throw new NotImplementedException(""); | |||||
//return @ref.is_initialized(name: name); | |||||
} | |||||
} | |||||
} |
@@ -68,7 +68,7 @@ namespace Tensorflow | |||||
var g = get_default_graph(); | var g = get_default_graph(); | ||||
g._name_stack = old_stack; | g._name_stack = old_stack; | ||||
} | } | ||||
public void __exit__() | public void __exit__() | ||||
{ | { | ||||
} | } | ||||
@@ -82,7 +82,7 @@ namespace Tensorflow | |||||
{ | { | ||||
} | } | ||||
/// <summary> | /// <summary> | ||||
/// __enter__() | /// __enter__() | ||||
/// </summary> | /// </summary> | ||||
@@ -2,7 +2,7 @@ | |||||
<PropertyGroup> | <PropertyGroup> | ||||
<RootNamespace>Tensorflow.Hub</RootNamespace> | <RootNamespace>Tensorflow.Hub</RootNamespace> | ||||
<TargetFramework>netstandard2.0</TargetFramework> | <TargetFramework>netstandard2.0</TargetFramework> | ||||
<Version>0.0.6</Version> | |||||
<Version>0.1.1</Version> | |||||
<Authors>Kerry Jiang, Haiping Chen</Authors> | <Authors>Kerry Jiang, Haiping Chen</Authors> | ||||
<Company>SciSharp STACK</Company> | <Company>SciSharp STACK</Company> | ||||
<Copyright>Apache 2.0</Copyright> | <Copyright>Apache 2.0</Copyright> | ||||
@@ -14,7 +14,7 @@ | |||||
<PackageId>SciSharp.TensorFlowHub</PackageId> | <PackageId>SciSharp.TensorFlowHub</PackageId> | ||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild> | <GeneratePackageOnBuild>true</GeneratePackageOnBuild> | ||||
<PackageReleaseNotes>Fix GetNextBatch() bug. | <PackageReleaseNotes>Fix GetNextBatch() bug. | ||||
Change to NumSharp compact version.</PackageReleaseNotes> | |||||
Upgrade NumSharp.Lite 0.1.4.</PackageReleaseNotes> | |||||
<PackageIconUrl>https://avatars3.githubusercontent.com/u/44989469?s=200&v=4</PackageIconUrl> | <PackageIconUrl>https://avatars3.githubusercontent.com/u/44989469?s=200&v=4</PackageIconUrl> | ||||
<AssemblyName>TensorFlow.Hub</AssemblyName> | <AssemblyName>TensorFlow.Hub</AssemblyName> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
@@ -22,6 +22,6 @@ Change to NumSharp compact version.</PackageReleaseNotes> | |||||
<DefineConstants>DEBUG;TRACE</DefineConstants> | <DefineConstants>DEBUG;TRACE</DefineConstants> | ||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="NumSharp" Version="0.30.0-alpha" /> | |||||
<PackageReference Include="NumSharp.Lite" Version="0.1.4" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -19,8 +19,8 @@ | |||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="BenchmarkDotNet" Version="0.12.0" /> | <PackageReference Include="BenchmarkDotNet" Version="0.12.0" /> | ||||
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="1.14.1" /> | |||||
<PackageReference Include="TensorFlow.NET" Version="0.14.0" /> | |||||
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="1.15.1" /> | |||||
<PackageReference Include="TensorFlow.NET" Version="0.14.2" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
</Project> | </Project> |
@@ -1,27 +1,12 @@ | |||||
TensorFlow.NET pack all required libraries in architecture-specific assemblies folders per NuGet standard [Deprecated] . | |||||
We changed to use `Microsoft.ML.TensorFlow.Redist` to maintain the TensorFlow library. | |||||
### Download manually | |||||
Here are some pre-built TensorFlow binaries you can use for each platform: | |||||
- Linux | |||||
- CPU-only: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-linux-x86_64-1.14.0.tar.gz | |||||
- GPU-enabled: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-gpu-linux-x86_64-1.14.0.tar.gz | |||||
- Mac: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-darwin-x86_64-1.14.0.tar.gz | |||||
- Windows | |||||
- CPU-only: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-windows-x86_64-1.14.0.zip | |||||
- GPU-enabled: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-gpu-windows-x86_64-1.14.0.zip | |||||
TensorFlow.NET pack all required libraries in architecture-specific assemblies folders per NuGet standard. | |||||
```powershell | |||||
PM> Install-Package TensorFlow.NET | |||||
PM> Install-Package SciSharp.TensorFlow.Redist | |||||
``` | |||||
### Run in Linux | ### Run in Linux | ||||
`Install-Package TensorFlow.NET` | |||||
Download Linux pre-built library and unzip `libtensorflow.so` and `libtensorflow_framework.so` into current running directory. | Download Linux pre-built library and unzip `libtensorflow.so` and `libtensorflow_framework.so` into current running directory. | ||||
To run image recognition in Linux, please ensure some prerequisite libraries is install. | To run image recognition in Linux, please ensure some prerequisite libraries is install. | ||||
@@ -33,20 +18,34 @@ sudo apt install libgdiplus | |||||
More information about [System.Drawing on Linux](<https://www.hanselman.com/blog/HowDoYouUseSystemDrawingInNETCore.aspx>). | More information about [System.Drawing on Linux](<https://www.hanselman.com/blog/HowDoYouUseSystemDrawingInNETCore.aspx>). | ||||
### Run TensorFlow in GPU | |||||
Before running verify you installed CUDA and cuDNN (TensorFlow v1.15 is compatible with CUDA v10.0 and cuDNN v7.4), and make sure the corresponding cuda version is compatible. | |||||
#### Run in Mac OS | |||||
There is no GPU support for macOS. | |||||
### Run in Mac OS | |||||
### Tensorflow GPU for Windows | |||||
Before running verify you installed CUDA and cuDNN (TensorFlow v1.14 is compatible with CUDA v10.0 and cuDNN v7.4), and make sure the corresponding cuda version is compatible. | |||||
#### Tensorflow GPU for Windows | |||||
```powershell | ```powershell | ||||
PM> Install-Package SciSharp.TensorFlow.Redist-Windows-GPU | PM> Install-Package SciSharp.TensorFlow.Redist-Windows-GPU | ||||
``` | ``` | ||||
#### Tensorflow GPU for Linux | |||||
```powershell | |||||
PM> Install-Package SciSharp.TensorFlow.Redist-Linux-GPU | |||||
``` | |||||
### Download prebuild binary manually | |||||
Here are some pre-built TensorFlow binaries you can use for each platform: | |||||
- Linux | |||||
- CPU-only: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-linux-x86_64-1.15.0.tar.gz | |||||
- GPU-enabled: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-gpu-linux-x86_64-1.15.0.tar.gz | |||||
- Mac: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-darwin-x86_64-1.15.0.tar.gz | |||||
- Windows | |||||
- CPU-only: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-cpu-windows-x86_64-1.15.0.zip | |||||
- GPU-enabled: https://storage.googleapis.com/tensorflow/libtensorflow/libtensorflow-gpu-windows-x86_64-1.15.0.zip | |||||
### Build from source for Windows | ### Build from source for Windows | ||||
@@ -69,7 +68,7 @@ https://www.tensorflow.org/install/source_windows | |||||
4. Install from local wheel file. | 4. Install from local wheel file. | ||||
`pip install C:/tmp/tensorflow_pkg/tensorflow-1.14.0-cp36-cp36m-win_amd64.whl` | |||||
`pip install C:/tmp/tensorflow_pkg/tensorflow-1.15.0-cp36-cp36m-win_amd64.whl` | |||||
### Export more APIs | ### Export more APIs | ||||
@@ -2,7 +2,7 @@ using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using System.Threading.Tasks; | using System.Threading.Tasks; | ||||
using Tensorflow.Hub; | using Tensorflow.Hub; | ||||
namespace UnitTest | |||||
namespace TensorFlowNET.UnitTest | |||||
{ | { | ||||
[TestClass] | [TestClass] | ||||
public class MnistModelLoaderTest | public class MnistModelLoaderTest | ||||
@@ -1,334 +1,334 @@ | |||||
using System; | |||||
using System.Collections; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Newtonsoft.Json.Linq; | |||||
using NumSharp; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest | |||||
{ | |||||
/// <summary> | |||||
/// Use as base class for test classes to get additional assertions | |||||
/// </summary> | |||||
public class PythonTest | |||||
{ | |||||
#region python compatibility layer | |||||
protected PythonTest self { get => this; } | |||||
protected object None | |||||
{ | |||||
get { return null; } | |||||
} | |||||
#endregion | |||||
#region pytest assertions | |||||
public void assertItemsEqual(ICollection given, ICollection expected) | |||||
{ | |||||
if (given is Hashtable && expected is Hashtable) | |||||
{ | |||||
Assert.AreEqual(JObject.FromObject(expected).ToString(), JObject.FromObject(given).ToString()); | |||||
return; | |||||
} | |||||
Assert.IsNotNull(expected); | |||||
Assert.IsNotNull(given); | |||||
var e = expected.OfType<object>().ToArray(); | |||||
var g = given.OfType<object>().ToArray(); | |||||
Assert.AreEqual(e.Length, g.Length, $"The collections differ in length expected {e.Length} but got {g.Length}"); | |||||
for (int i = 0; i < e.Length; i++) | |||||
{ | |||||
/*if (g[i] is NDArray && e[i] is NDArray) | |||||
assertItemsEqual((g[i] as NDArray).GetData<object>(), (e[i] as NDArray).GetData<object>()); | |||||
else*/ if (e[i] is ICollection && g[i] is ICollection) | |||||
assertEqual(g[i], e[i]); | |||||
else | |||||
Assert.AreEqual(e[i], g[i], $"Items differ at index {i}, expected {e[i]} but got {g[i]}"); | |||||
} | |||||
} | |||||
public void assertAllEqual(ICollection given, ICollection expected) | |||||
{ | |||||
assertItemsEqual(given, expected); | |||||
} | |||||
public void assertFloat32Equal(float expected, float actual, string msg) | |||||
{ | |||||
float eps = 1e-6f; | |||||
Assert.IsTrue(Math.Abs(expected - actual) < eps * Math.Max(1.0f, Math.Abs(expected)), $"{msg}: expected {expected} vs actual {actual}"); | |||||
} | |||||
public void assertFloat64Equal(double expected, double actual, string msg) | |||||
{ | |||||
double eps = 1e-16f; | |||||
Assert.IsTrue(Math.Abs(expected - actual) < eps * Math.Max(1.0f, Math.Abs(expected)), $"{msg}: expected {expected} vs actual {actual}"); | |||||
} | |||||
public void assertEqual(object given, object expected) | |||||
{ | |||||
/*if (given is NDArray && expected is NDArray) | |||||
{ | |||||
assertItemsEqual((given as NDArray).GetData<object>(), (expected as NDArray).GetData<object>()); | |||||
return; | |||||
}*/ | |||||
if (given is Hashtable && expected is Hashtable) | |||||
{ | |||||
Assert.AreEqual(JObject.FromObject(expected).ToString(), JObject.FromObject(given).ToString()); | |||||
return; | |||||
} | |||||
if (given is ICollection && expected is ICollection) | |||||
{ | |||||
assertItemsEqual(given as ICollection, expected as ICollection); | |||||
return; | |||||
} | |||||
if (given is float && expected is float) | |||||
{ | |||||
assertFloat32Equal((float)expected, (float)given, ""); | |||||
return; | |||||
} | |||||
if (given is double && expected is double) | |||||
{ | |||||
assertFloat64Equal((double)expected, (double)given, ""); | |||||
return; | |||||
} | |||||
Assert.AreEqual(expected, given); | |||||
} | |||||
public void assertEquals(object given, object expected) | |||||
{ | |||||
assertEqual(given, expected); | |||||
} | |||||
public void assert(object given) | |||||
{ | |||||
if (given is bool) | |||||
Assert.IsTrue((bool)given); | |||||
Assert.IsNotNull(given); | |||||
} | |||||
public void assertIsNotNone(object given) | |||||
{ | |||||
Assert.IsNotNull(given); | |||||
} | |||||
public void assertFalse(bool cond) | |||||
{ | |||||
Assert.IsFalse(cond); | |||||
} | |||||
public void assertTrue(bool cond) | |||||
{ | |||||
Assert.IsTrue(cond); | |||||
} | |||||
public void assertAllClose(NDArray array1, NDArray array2, double eps = 1e-5) | |||||
{ | |||||
Assert.IsTrue(np.allclose(array1, array2, rtol: eps)); | |||||
} | |||||
public void assertAllClose(double value, NDArray array2, double eps = 1e-5) | |||||
{ | |||||
var array1 = np.ones_like(array2) * value; | |||||
Assert.IsTrue(np.allclose(array1, array2, rtol: eps)); | |||||
} | |||||
public void assertProtoEquals(object toProto, object o) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
#endregion | |||||
#region tensor evaluation and test session | |||||
//protected object _eval_helper(Tensor[] tensors) | |||||
//{ | |||||
// if (tensors == null) | |||||
// return null; | |||||
// return nest.map_structure(self._eval_tensor, tensors); | |||||
//} | |||||
protected object _eval_tensor(object tensor) | |||||
{ | |||||
if (tensor == None) | |||||
return None; | |||||
//else if (callable(tensor)) | |||||
// return self._eval_helper(tensor()) | |||||
else | |||||
{ | |||||
try | |||||
{ | |||||
//TODO: | |||||
// if sparse_tensor.is_sparse(tensor): | |||||
// return sparse_tensor.SparseTensorValue(tensor.indices, tensor.values, | |||||
// tensor.dense_shape) | |||||
//return (tensor as Tensor).numpy(); | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
throw new ValueError("Unsupported type: " + tensor.GetType()); | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// This function is used in many original tensorflow unit tests to evaluate tensors | |||||
/// in a test session with special settings (for instance constant folding off) | |||||
/// | |||||
/// </summary> | |||||
public T evaluate<T>(Tensor tensor) | |||||
{ | |||||
object result = null; | |||||
// if context.executing_eagerly(): | |||||
// return self._eval_helper(tensors) | |||||
// else: | |||||
{ | |||||
using (var sess = tf.Session()) | |||||
{ | |||||
var ndarray=tensor.eval(sess); | |||||
if (typeof(T) == typeof(double)) | |||||
{ | |||||
double x = ndarray; | |||||
result=x; | |||||
} | |||||
else if (typeof(T) == typeof(int)) | |||||
{ | |||||
int x = ndarray; | |||||
result = x; | |||||
} | |||||
else | |||||
{ | |||||
result = ndarray; | |||||
} | |||||
} | |||||
return (T)result; | |||||
} | |||||
} | |||||
public Session cached_session() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
//Returns a TensorFlow Session for use in executing tests. | |||||
public Session session(Graph graph = null, object config = null, bool use_gpu = false, bool force_gpu = false) | |||||
{ | |||||
//Note that this will set this session and the graph as global defaults. | |||||
//Use the `use_gpu` and `force_gpu` options to control where ops are run.If | |||||
//`force_gpu` is True, all ops are pinned to `/device:GPU:0`. Otherwise, if | |||||
//`use_gpu` is True, TensorFlow tries to run as many ops on the GPU as | |||||
//possible.If both `force_gpu and `use_gpu` are False, all ops are pinned to | |||||
//the CPU. | |||||
//Example: | |||||
//```python | |||||
//class MyOperatorTest(test_util.TensorFlowTestCase): | |||||
// def testMyOperator(self): | |||||
// with self.session(use_gpu= True): | |||||
// valid_input = [1.0, 2.0, 3.0, 4.0, 5.0] | |||||
// result = MyOperator(valid_input).eval() | |||||
// self.assertEqual(result, [1.0, 2.0, 3.0, 5.0, 8.0] | |||||
// invalid_input = [-1.0, 2.0, 7.0] | |||||
// with self.assertRaisesOpError("negative input not supported"): | |||||
// MyOperator(invalid_input).eval() | |||||
//``` | |||||
//Args: | |||||
// graph: Optional graph to use during the returned session. | |||||
// config: An optional config_pb2.ConfigProto to use to configure the | |||||
// session. | |||||
// use_gpu: If True, attempt to run as many ops as possible on GPU. | |||||
// force_gpu: If True, pin all ops to `/device:GPU:0`. | |||||
//Yields: | |||||
// A Session object that should be used as a context manager to surround | |||||
// the graph building and execution code in a test case. | |||||
Session s = null; | |||||
//if (context.executing_eagerly()) | |||||
// yield None | |||||
//else | |||||
//{ | |||||
s = self._create_session(graph, config, force_gpu); | |||||
self._constrain_devices_and_set_default(s, use_gpu, force_gpu); | |||||
//} | |||||
return s.as_default(); | |||||
} | |||||
private IObjectLife _constrain_devices_and_set_default(Session sess, bool useGpu, bool forceGpu) | |||||
{ | |||||
//def _constrain_devices_and_set_default(self, sess, use_gpu, force_gpu): | |||||
//"""Set the session and its graph to global default and constrain devices.""" | |||||
//if context.executing_eagerly(): | |||||
// yield None | |||||
//else: | |||||
// with sess.graph.as_default(), sess.as_default(): | |||||
// if force_gpu: | |||||
// # Use the name of an actual device if one is detected, or | |||||
// # '/device:GPU:0' otherwise | |||||
// gpu_name = gpu_device_name() | |||||
// if not gpu_name: | |||||
// gpu_name = "/device:GPU:0" | |||||
// with sess.graph.device(gpu_name): | |||||
// yield sess | |||||
// elif use_gpu: | |||||
// yield sess | |||||
// else: | |||||
// with sess.graph.device("/device:CPU:0"): | |||||
// yield sess | |||||
return sess; | |||||
} | |||||
// See session() for details. | |||||
private Session _create_session(Graph graph, object cfg, bool forceGpu) | |||||
{ | |||||
var prepare_config = new Func<object, object>((config) => | |||||
{ | |||||
// """Returns a config for sessions. | |||||
// Args: | |||||
// config: An optional config_pb2.ConfigProto to use to configure the | |||||
// session. | |||||
// Returns: | |||||
// A config_pb2.ConfigProto object. | |||||
//TODO: config | |||||
// # use_gpu=False. Currently many tests rely on the fact that any device | |||||
// # will be used even when a specific device is supposed to be used. | |||||
// allow_soft_placement = not force_gpu | |||||
// if config is None: | |||||
// config = config_pb2.ConfigProto() | |||||
// config.allow_soft_placement = allow_soft_placement | |||||
// config.gpu_options.per_process_gpu_memory_fraction = 0.3 | |||||
// elif not allow_soft_placement and config.allow_soft_placement: | |||||
// config_copy = config_pb2.ConfigProto() | |||||
// config_copy.CopyFrom(config) | |||||
// config = config_copy | |||||
// config.allow_soft_placement = False | |||||
// # Don't perform optimizations for tests so we don't inadvertently run | |||||
// # gpu ops on cpu | |||||
// config.graph_options.optimizer_options.opt_level = -1 | |||||
// # Disable Grappler constant folding since some tests & benchmarks | |||||
// # use constant input and become meaningless after constant folding. | |||||
// # DO NOT DISABLE GRAPPLER OPTIMIZERS WITHOUT CONSULTING WITH THE | |||||
// # GRAPPLER TEAM. | |||||
// config.graph_options.rewrite_options.constant_folding = ( | |||||
// rewriter_config_pb2.RewriterConfig.OFF) | |||||
// config.graph_options.rewrite_options.pin_to_host_optimization = ( | |||||
// rewriter_config_pb2.RewriterConfig.OFF) | |||||
return config; | |||||
}); | |||||
//TODO: use this instead of normal session | |||||
//return new ErrorLoggingSession(graph = graph, config = prepare_config(config)) | |||||
return new Session(graph);//, config = prepare_config(config)) | |||||
} | |||||
#endregion | |||||
} | |||||
} | |||||
using System; | |||||
using System.Collections; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Newtonsoft.Json.Linq; | |||||
using NumSharp; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest | |||||
{ | |||||
/// <summary> | |||||
/// Use as base class for test classes to get additional assertions | |||||
/// </summary> | |||||
public class PythonTest | |||||
{ | |||||
#region python compatibility layer | |||||
protected PythonTest self { get => this; } | |||||
protected object None | |||||
{ | |||||
get { return null; } | |||||
} | |||||
#endregion | |||||
#region pytest assertions | |||||
public void assertItemsEqual(ICollection given, ICollection expected) | |||||
{ | |||||
if (given is Hashtable && expected is Hashtable) | |||||
{ | |||||
Assert.AreEqual(JObject.FromObject(expected).ToString(), JObject.FromObject(given).ToString()); | |||||
return; | |||||
} | |||||
Assert.IsNotNull(expected); | |||||
Assert.IsNotNull(given); | |||||
var e = expected.OfType<object>().ToArray(); | |||||
var g = given.OfType<object>().ToArray(); | |||||
Assert.AreEqual(e.Length, g.Length, $"The collections differ in length expected {e.Length} but got {g.Length}"); | |||||
for (int i = 0; i < e.Length; i++) | |||||
{ | |||||
/*if (g[i] is NDArray && e[i] is NDArray) | |||||
assertItemsEqual((g[i] as NDArray).GetData<object>(), (e[i] as NDArray).GetData<object>()); | |||||
else*/ if (e[i] is ICollection && g[i] is ICollection) | |||||
assertEqual(g[i], e[i]); | |||||
else | |||||
Assert.AreEqual(e[i], g[i], $"Items differ at index {i}, expected {e[i]} but got {g[i]}"); | |||||
} | |||||
} | |||||
public void assertAllEqual(ICollection given, ICollection expected) | |||||
{ | |||||
assertItemsEqual(given, expected); | |||||
} | |||||
public void assertFloat32Equal(float expected, float actual, string msg) | |||||
{ | |||||
float eps = 1e-6f; | |||||
Assert.IsTrue(Math.Abs(expected - actual) < eps * Math.Max(1.0f, Math.Abs(expected)), $"{msg}: expected {expected} vs actual {actual}"); | |||||
} | |||||
public void assertFloat64Equal(double expected, double actual, string msg) | |||||
{ | |||||
double eps = 1e-16f; | |||||
Assert.IsTrue(Math.Abs(expected - actual) < eps * Math.Max(1.0f, Math.Abs(expected)), $"{msg}: expected {expected} vs actual {actual}"); | |||||
} | |||||
public void assertEqual(object given, object expected) | |||||
{ | |||||
/*if (given is NDArray && expected is NDArray) | |||||
{ | |||||
assertItemsEqual((given as NDArray).GetData<object>(), (expected as NDArray).GetData<object>()); | |||||
return; | |||||
}*/ | |||||
if (given is Hashtable && expected is Hashtable) | |||||
{ | |||||
Assert.AreEqual(JObject.FromObject(expected).ToString(), JObject.FromObject(given).ToString()); | |||||
return; | |||||
} | |||||
if (given is ICollection && expected is ICollection) | |||||
{ | |||||
assertItemsEqual(given as ICollection, expected as ICollection); | |||||
return; | |||||
} | |||||
if (given is float && expected is float) | |||||
{ | |||||
assertFloat32Equal((float)expected, (float)given, ""); | |||||
return; | |||||
} | |||||
if (given is double && expected is double) | |||||
{ | |||||
assertFloat64Equal((double)expected, (double)given, ""); | |||||
return; | |||||
} | |||||
Assert.AreEqual(expected, given); | |||||
} | |||||
public void assertEquals(object given, object expected) | |||||
{ | |||||
assertEqual(given, expected); | |||||
} | |||||
public void assert(object given) | |||||
{ | |||||
if (given is bool) | |||||
Assert.IsTrue((bool)given); | |||||
Assert.IsNotNull(given); | |||||
} | |||||
public void assertIsNotNone(object given) | |||||
{ | |||||
Assert.IsNotNull(given); | |||||
} | |||||
public void assertFalse(bool cond) | |||||
{ | |||||
Assert.IsFalse(cond); | |||||
} | |||||
public void assertTrue(bool cond) | |||||
{ | |||||
Assert.IsTrue(cond); | |||||
} | |||||
public void assertAllClose(NDArray array1, NDArray array2, double eps = 1e-5) | |||||
{ | |||||
Assert.IsTrue(np.allclose(array1, array2, rtol: eps)); | |||||
} | |||||
public void assertAllClose(double value, NDArray array2, double eps = 1e-5) | |||||
{ | |||||
var array1 = np.ones_like(array2) * value; | |||||
Assert.IsTrue(np.allclose(array1, array2, rtol: eps)); | |||||
} | |||||
public void assertProtoEquals(object toProto, object o) | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
#endregion | |||||
#region tensor evaluation and test session | |||||
//protected object _eval_helper(Tensor[] tensors) | |||||
//{ | |||||
// if (tensors == null) | |||||
// return null; | |||||
// return nest.map_structure(self._eval_tensor, tensors); | |||||
//} | |||||
protected object _eval_tensor(object tensor) | |||||
{ | |||||
if (tensor == None) | |||||
return None; | |||||
//else if (callable(tensor)) | |||||
// return self._eval_helper(tensor()) | |||||
else | |||||
{ | |||||
try | |||||
{ | |||||
//TODO: | |||||
// if sparse_tensor.is_sparse(tensor): | |||||
// return sparse_tensor.SparseTensorValue(tensor.indices, tensor.values, | |||||
// tensor.dense_shape) | |||||
//return (tensor as Tensor).numpy(); | |||||
} | |||||
catch (Exception) | |||||
{ | |||||
throw new ValueError("Unsupported type: " + tensor.GetType()); | |||||
} | |||||
return null; | |||||
} | |||||
} | |||||
/// <summary> | |||||
/// This function is used in many original tensorflow unit tests to evaluate tensors | |||||
/// in a test session with special settings (for instance constant folding off) | |||||
/// | |||||
/// </summary> | |||||
public T evaluate<T>(Tensor tensor) | |||||
{ | |||||
object result = null; | |||||
// if context.executing_eagerly(): | |||||
// return self._eval_helper(tensors) | |||||
// else: | |||||
{ | |||||
using (var sess = tf.Session()) | |||||
{ | |||||
var ndarray=tensor.eval(sess); | |||||
if (typeof(T) == typeof(double)) | |||||
{ | |||||
double x = ndarray; | |||||
result=x; | |||||
} | |||||
else if (typeof(T) == typeof(int)) | |||||
{ | |||||
int x = ndarray; | |||||
result = x; | |||||
} | |||||
else | |||||
{ | |||||
result = ndarray; | |||||
} | |||||
} | |||||
return (T)result; | |||||
} | |||||
} | |||||
public Session cached_session() | |||||
{ | |||||
throw new NotImplementedException(); | |||||
} | |||||
//Returns a TensorFlow Session for use in executing tests. | |||||
public Session session(Graph graph = null, object config = null, bool use_gpu = false, bool force_gpu = false) | |||||
{ | |||||
//Note that this will set this session and the graph as global defaults. | |||||
//Use the `use_gpu` and `force_gpu` options to control where ops are run.If | |||||
//`force_gpu` is True, all ops are pinned to `/device:GPU:0`. Otherwise, if | |||||
//`use_gpu` is True, TensorFlow tries to run as many ops on the GPU as | |||||
//possible.If both `force_gpu and `use_gpu` are False, all ops are pinned to | |||||
//the CPU. | |||||
//Example: | |||||
//```python | |||||
//class MyOperatorTest(test_util.TensorFlowTestCase): | |||||
// def testMyOperator(self): | |||||
// with self.session(use_gpu= True): | |||||
// valid_input = [1.0, 2.0, 3.0, 4.0, 5.0] | |||||
// result = MyOperator(valid_input).eval() | |||||
// self.assertEqual(result, [1.0, 2.0, 3.0, 5.0, 8.0] | |||||
// invalid_input = [-1.0, 2.0, 7.0] | |||||
// with self.assertRaisesOpError("negative input not supported"): | |||||
// MyOperator(invalid_input).eval() | |||||
//``` | |||||
//Args: | |||||
// graph: Optional graph to use during the returned session. | |||||
// config: An optional config_pb2.ConfigProto to use to configure the | |||||
// session. | |||||
// use_gpu: If True, attempt to run as many ops as possible on GPU. | |||||
// force_gpu: If True, pin all ops to `/device:GPU:0`. | |||||
//Yields: | |||||
// A Session object that should be used as a context manager to surround | |||||
// the graph building and execution code in a test case. | |||||
Session s = null; | |||||
//if (context.executing_eagerly()) | |||||
// yield None | |||||
//else | |||||
//{ | |||||
s = self._create_session(graph, config, force_gpu); | |||||
self._constrain_devices_and_set_default(s, use_gpu, force_gpu); | |||||
//} | |||||
return s.as_default(); | |||||
} | |||||
private IObjectLife _constrain_devices_and_set_default(Session sess, bool useGpu, bool forceGpu) | |||||
{ | |||||
//def _constrain_devices_and_set_default(self, sess, use_gpu, force_gpu): | |||||
//"""Set the session and its graph to global default and constrain devices.""" | |||||
//if context.executing_eagerly(): | |||||
// yield None | |||||
//else: | |||||
// with sess.graph.as_default(), sess.as_default(): | |||||
// if force_gpu: | |||||
// # Use the name of an actual device if one is detected, or | |||||
// # '/device:GPU:0' otherwise | |||||
// gpu_name = gpu_device_name() | |||||
// if not gpu_name: | |||||
// gpu_name = "/device:GPU:0" | |||||
// with sess.graph.device(gpu_name): | |||||
// yield sess | |||||
// elif use_gpu: | |||||
// yield sess | |||||
// else: | |||||
// with sess.graph.device("/device:CPU:0"): | |||||
// yield sess | |||||
return sess; | |||||
} | |||||
// See session() for details. | |||||
private Session _create_session(Graph graph, object cfg, bool forceGpu) | |||||
{ | |||||
var prepare_config = new Func<object, object>((config) => | |||||
{ | |||||
// """Returns a config for sessions. | |||||
// Args: | |||||
// config: An optional config_pb2.ConfigProto to use to configure the | |||||
// session. | |||||
// Returns: | |||||
// A config_pb2.ConfigProto object. | |||||
//TODO: config | |||||
// # use_gpu=False. Currently many tests rely on the fact that any device | |||||
// # will be used even when a specific device is supposed to be used. | |||||
// allow_soft_placement = not force_gpu | |||||
// if config is None: | |||||
// config = config_pb2.ConfigProto() | |||||
// config.allow_soft_placement = allow_soft_placement | |||||
// config.gpu_options.per_process_gpu_memory_fraction = 0.3 | |||||
// elif not allow_soft_placement and config.allow_soft_placement: | |||||
// config_copy = config_pb2.ConfigProto() | |||||
// config_copy.CopyFrom(config) | |||||
// config = config_copy | |||||
// config.allow_soft_placement = False | |||||
// # Don't perform optimizations for tests so we don't inadvertently run | |||||
// # gpu ops on cpu | |||||
// config.graph_options.optimizer_options.opt_level = -1 | |||||
// # Disable Grappler constant folding since some tests & benchmarks | |||||
// # use constant input and become meaningless after constant folding. | |||||
// # DO NOT DISABLE GRAPPLER OPTIMIZERS WITHOUT CONSULTING WITH THE | |||||
// # GRAPPLER TEAM. | |||||
// config.graph_options.rewrite_options.constant_folding = ( | |||||
// rewriter_config_pb2.RewriterConfig.OFF) | |||||
// config.graph_options.rewrite_options.pin_to_host_optimization = ( | |||||
// rewriter_config_pb2.RewriterConfig.OFF) | |||||
return config; | |||||
}); | |||||
//TODO: use this instead of normal session | |||||
//return new ErrorLoggingSession(graph = graph, config = prepare_config(config)) | |||||
return new Session(graph);//, config = prepare_config(config)) | |||||
} | |||||
#endregion | |||||
} | |||||
} |
@@ -28,11 +28,11 @@ | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="FluentAssertions" Version="5.10.0" /> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.4.0" /> | |||||
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" /> | |||||
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" /> | |||||
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="1.14.1" /> | |||||
<PackageReference Include="FluentAssertions" Version="5.10.2" /> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> | |||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" /> | |||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" /> | |||||
<PackageReference Include="SciSharp.TensorFlow.Redist" Version="1.15.1" /> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
@@ -1,86 +1,86 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops/control_flow_ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class CondTestCases : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void testCondTrue_ConstOnly() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
using (var sess = tf.Session(graph)) | |||||
{ | |||||
var x = tf.constant(2, name: "x"); | |||||
var y = tf.constant(5, name: "y"); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.constant(22, name: "t22"), | |||||
() => tf.constant(55, name: "f55")); | |||||
int result = z.eval(sess); | |||||
assertEquals(result, 22); | |||||
} | |||||
} | |||||
[TestMethod] | |||||
public void testCondFalse_ConstOnly() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
using (var sess = tf.Session(graph)) | |||||
{ | |||||
var x = tf.constant(2, name: "x"); | |||||
var y = tf.constant(1, name: "y"); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.constant(22, name: "t22"), | |||||
() => tf.constant(11, name: "f11")); | |||||
int result = z.eval(sess); | |||||
assertEquals(result, 11); | |||||
} | |||||
} | |||||
[TestMethod] | |||||
public void testCondTrue() | |||||
{ | |||||
tf.Graph().as_default(); | |||||
var x = tf.constant(2, name: "x"); | |||||
var y = tf.constant(5, name: "y"); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.multiply(x, 17), | |||||
() => tf.add(y, 23)); | |||||
var result = evaluate<int>(z); | |||||
assertEquals(result, 34); | |||||
} | |||||
[TestMethod] | |||||
public void testCondFalse() | |||||
{ | |||||
tf.Graph().as_default(); | |||||
var x = tf.constant(2); | |||||
var y = tf.constant(1); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.multiply(x, 17), | |||||
() => tf.add(y, 23)); | |||||
var result = evaluate<int>(z); | |||||
assertEquals(result, 24); | |||||
} | |||||
// NOTE: all other python test cases of this class are either not needed due to strong typing or test a deprecated api | |||||
} | |||||
} | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops/control_flow_ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class CondTestCases : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void testCondTrue_ConstOnly() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
using (var sess = tf.Session(graph)) | |||||
{ | |||||
var x = tf.constant(2, name: "x"); | |||||
var y = tf.constant(5, name: "y"); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.constant(22, name: "t22"), | |||||
() => tf.constant(55, name: "f55")); | |||||
int result = z.eval(sess); | |||||
assertEquals(result, 22); | |||||
} | |||||
} | |||||
[TestMethod] | |||||
public void testCondFalse_ConstOnly() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
using (var sess = tf.Session(graph)) | |||||
{ | |||||
var x = tf.constant(2, name: "x"); | |||||
var y = tf.constant(1, name: "y"); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.constant(22, name: "t22"), | |||||
() => tf.constant(11, name: "f11")); | |||||
int result = z.eval(sess); | |||||
assertEquals(result, 11); | |||||
} | |||||
} | |||||
[TestMethod] | |||||
public void testCondTrue() | |||||
{ | |||||
tf.Graph().as_default(); | |||||
var x = tf.constant(2, name: "x"); | |||||
var y = tf.constant(5, name: "y"); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.multiply(x, 17), | |||||
() => tf.add(y, 23)); | |||||
var result = evaluate<int>(z); | |||||
assertEquals(result, 34); | |||||
} | |||||
[TestMethod] | |||||
public void testCondFalse() | |||||
{ | |||||
tf.Graph().as_default(); | |||||
var x = tf.constant(2); | |||||
var y = tf.constant(1); | |||||
var z = control_flow_ops.cond(tf.less(x, y), | |||||
() => tf.multiply(x, 17), | |||||
() => tf.add(y, 23)); | |||||
var result = evaluate<int>(z); | |||||
assertEquals(result, 24); | |||||
} | |||||
// NOTE: all other python test cases of this class are either not needed due to strong typing or test a deprecated api | |||||
} | |||||
} |
@@ -1,23 +1,23 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops/control_flow_ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class ShapeTestCase : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void testShape() | |||||
{ | |||||
var tensor = constant_op.constant(new[]{1.0, 2.0}); | |||||
self.assertEquals(new int[] {2}, tensor.shape); | |||||
self.assertEquals(new int[] {2}, | |||||
control_flow_ops.with_dependencies(new[] {constant_op.constant(1.0).op}, tensor).shape); | |||||
} | |||||
} | |||||
} | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops/control_flow_ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class ShapeTestCase : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void testShape() | |||||
{ | |||||
var tensor = constant_op.constant(new[]{1.0, 2.0}); | |||||
self.assertEquals(new int[] {2}, tensor.shape); | |||||
self.assertEquals(new int[] {2}, | |||||
control_flow_ops.with_dependencies(new[] {constant_op.constant(1.0).op}, tensor).shape); | |||||
} | |||||
} | |||||
} |
@@ -1,173 +1,173 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops/control_flow_ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class SwitchTestCase : PythonTest | |||||
{ | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testResourceReadInLoop() | |||||
{ | |||||
//var embedding_matrix = variable_scope.get_variable( | |||||
//"embedding_matrix", initializer: new double[,] { { 2.0 }, { 3.0 } }, use_resource: true); | |||||
/* | |||||
Tensor cond(Tensor it, Tensor _) | |||||
{ | |||||
return it < 5; | |||||
} | |||||
*/ | |||||
// TODO: below code doesn't compile | |||||
//(Tensor, Tensor) body(Tensor it, Tensor cost) | |||||
//{ | |||||
// var embedding = embedding_ops.embedding_lookup(embedding_matrix, new int[]{0}); | |||||
// cost += math_ops.reduce_sum(embedding); | |||||
// return (it + 1, cost); | |||||
//} | |||||
//var (_, cost1) = control_flow_ops.while_loop( | |||||
// cond, body, new[] | |||||
// { | |||||
// constant_op.constant(0), | |||||
// constant_op.constant(0.0) | |||||
// }); | |||||
//with<Session>(this.cached_session(), sess => | |||||
//{ | |||||
// self.evaluate(variables.global_variables_initializer()); | |||||
// self.assertAllEqual(10.0, self.evaluate(cost1)); | |||||
//}); | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesGradientInCondInWhileLoop() | |||||
{ | |||||
doTestIndexedSlicesGradientInCondInWhileLoop(use_resource: false); | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesGradientInCondInWhileLoopResource() | |||||
{ | |||||
doTestIndexedSlicesGradientInCondInWhileLoop(use_resource: true); | |||||
} | |||||
private void doTestIndexedSlicesGradientInCondInWhileLoop(bool use_resource = false) | |||||
{ | |||||
//def doTestIndexedSlicesGradientInCondInWhileLoop(self, use_resource=False): | |||||
// embedding_matrix = variable_scope.get_variable( | |||||
// "embedding_matrix", [5, 5], | |||||
// initializer=init_ops.random_normal_initializer(), | |||||
// use_resource=use_resource) | |||||
// def cond(it, _): | |||||
// return it < 5 | |||||
// def body(it, cost): | |||||
// embedding = embedding_ops.embedding_lookup(embedding_matrix, [0]) | |||||
// cost = control_flow_ops.cond( | |||||
// math_ops.equal(it, 3), lambda: math_ops.square(cost), | |||||
// (lambda: cost + math_ops.reduce_sum(embedding))) | |||||
// return it + 1, cost | |||||
// _, cost = control_flow_ops.while_loop( | |||||
// cond, body, [constant_op.constant(0), | |||||
// constant_op.constant(0.0)]) | |||||
// dynamic_grads = gradients_impl.gradients(cost, [embedding_matrix])[0] | |||||
// dynamic_grads = math_ops.segment_sum(dynamic_grads.values, | |||||
// dynamic_grads.indices) | |||||
// embedding = embedding_ops.embedding_lookup(embedding_matrix, [0]) | |||||
// static = math_ops.square( | |||||
// math_ops.reduce_sum(embedding) + math_ops.reduce_sum(embedding) + | |||||
// math_ops.reduce_sum(embedding)) + math_ops.reduce_sum(embedding) | |||||
// static_grads = gradients_impl.gradients(static, [embedding_matrix])[0] | |||||
// static_grads = math_ops.segment_sum(static_grads.values, | |||||
// static_grads.indices) | |||||
// with self.cached_session(): | |||||
// self.evaluate(variables.global_variables_initializer()) | |||||
// self.assertAllEqual(*self.evaluate([static_grads, dynamic_grads])) | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesWithShapeGradientInWhileLoop() | |||||
{ | |||||
//@test_util.run_v1_only("b/120545219") | |||||
//def testIndexedSlicesWithShapeGradientInWhileLoop(self): | |||||
// for dtype in [dtypes.float32, dtypes.float64]: | |||||
// with self.cached_session() as sess: | |||||
// num_steps = 9 | |||||
// inputs = array_ops.placeholder(dtype=dtype, shape=[num_steps]) | |||||
// initial_outputs = tensor_array_ops.TensorArray( | |||||
// dtype=dtype, size=num_steps) | |||||
// initial_i = constant_op.constant(0, dtype=dtypes.int32) | |||||
// def cond(i, _): | |||||
// return i < num_steps # pylint: disable=cell-var-from-loop | |||||
// def body(i, outputs): | |||||
// x = array_ops.gather(inputs, i) # pylint: disable=cell-var-from-loop | |||||
// outputs = outputs.write(i, x) | |||||
// return i + 1, outputs | |||||
// _, outputs = control_flow_ops.while_loop(cond, body, | |||||
// [initial_i, initial_outputs]) | |||||
// outputs = math_ops.reduce_sum(outputs.stack()) | |||||
// r = gradients_impl.gradients([outputs], [inputs])[0] | |||||
// grad_wr_inputs = ops.convert_to_tensor(r) | |||||
// o, grad = sess.run([outputs, grad_wr_inputs], | |||||
// feed_dict={inputs: [4, 6, 0, 7, 0, 0, 1, 2, 0]}) | |||||
// self.assertEquals(o, 20) | |||||
// self.assertAllEqual(grad, [1] * num_steps) | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesWithDynamicShapeGradientInWhileLoop() | |||||
{ | |||||
//@test_util.run_v1_only("b/120545219") | |||||
//def testIndexedSlicesWithDynamicShapeGradientInWhileLoop(self): | |||||
// for dtype in [dtypes.float32, dtypes.float64]: | |||||
// with self.cached_session() as sess: | |||||
// inputs = array_ops.placeholder(dtype=dtype) | |||||
// initial_outputs = tensor_array_ops.TensorArray( | |||||
// dtype=dtype, dynamic_size=True, size=1) | |||||
// initial_i = constant_op.constant(0, dtype=dtypes.int32) | |||||
// def cond(i, _): | |||||
// return i < array_ops.size(inputs) # pylint: disable=cell-var-from-loop | |||||
// def body(i, outputs): | |||||
// x = array_ops.gather(inputs, i) # pylint: disable=cell-var-from-loop | |||||
// outputs = outputs.write(i, x) | |||||
// return i + 1, outputs | |||||
// _, outputs = control_flow_ops.while_loop(cond, body, | |||||
// [initial_i, initial_outputs]) | |||||
// outputs = math_ops.reduce_sum(outputs.stack()) | |||||
// r = gradients_impl.gradients([outputs], [inputs])[0] | |||||
// grad_wr_inputs = ops.convert_to_tensor(r) | |||||
// o, grad = sess.run([outputs, grad_wr_inputs], | |||||
// feed_dict={inputs: [1, 3, 2]}) | |||||
// self.assertEquals(o, 6) | |||||
// self.assertAllEqual(grad, [1] * 3) | |||||
} | |||||
} | |||||
} | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops/control_flow_ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class SwitchTestCase : PythonTest | |||||
{ | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testResourceReadInLoop() | |||||
{ | |||||
//var embedding_matrix = variable_scope.get_variable( | |||||
//"embedding_matrix", initializer: new double[,] { { 2.0 }, { 3.0 } }, use_resource: true); | |||||
/* | |||||
Tensor cond(Tensor it, Tensor _) | |||||
{ | |||||
return it < 5; | |||||
} | |||||
*/ | |||||
// TODO: below code doesn't compile | |||||
//(Tensor, Tensor) body(Tensor it, Tensor cost) | |||||
//{ | |||||
// var embedding = embedding_ops.embedding_lookup(embedding_matrix, new int[]{0}); | |||||
// cost += math_ops.reduce_sum(embedding); | |||||
// return (it + 1, cost); | |||||
//} | |||||
//var (_, cost1) = control_flow_ops.while_loop( | |||||
// cond, body, new[] | |||||
// { | |||||
// constant_op.constant(0), | |||||
// constant_op.constant(0.0) | |||||
// }); | |||||
//with<Session>(this.cached_session(), sess => | |||||
//{ | |||||
// self.evaluate(variables.global_variables_initializer()); | |||||
// self.assertAllEqual(10.0, self.evaluate(cost1)); | |||||
//}); | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesGradientInCondInWhileLoop() | |||||
{ | |||||
doTestIndexedSlicesGradientInCondInWhileLoop(use_resource: false); | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesGradientInCondInWhileLoopResource() | |||||
{ | |||||
doTestIndexedSlicesGradientInCondInWhileLoop(use_resource: true); | |||||
} | |||||
private void doTestIndexedSlicesGradientInCondInWhileLoop(bool use_resource = false) | |||||
{ | |||||
//def doTestIndexedSlicesGradientInCondInWhileLoop(self, use_resource=False): | |||||
// embedding_matrix = variable_scope.get_variable( | |||||
// "embedding_matrix", [5, 5], | |||||
// initializer=init_ops.random_normal_initializer(), | |||||
// use_resource=use_resource) | |||||
// def cond(it, _): | |||||
// return it < 5 | |||||
// def body(it, cost): | |||||
// embedding = embedding_ops.embedding_lookup(embedding_matrix, [0]) | |||||
// cost = control_flow_ops.cond( | |||||
// math_ops.equal(it, 3), lambda: math_ops.square(cost), | |||||
// (lambda: cost + math_ops.reduce_sum(embedding))) | |||||
// return it + 1, cost | |||||
// _, cost = control_flow_ops.while_loop( | |||||
// cond, body, [constant_op.constant(0), | |||||
// constant_op.constant(0.0)]) | |||||
// dynamic_grads = gradients_impl.gradients(cost, [embedding_matrix])[0] | |||||
// dynamic_grads = math_ops.segment_sum(dynamic_grads.values, | |||||
// dynamic_grads.indices) | |||||
// embedding = embedding_ops.embedding_lookup(embedding_matrix, [0]) | |||||
// static = math_ops.square( | |||||
// math_ops.reduce_sum(embedding) + math_ops.reduce_sum(embedding) + | |||||
// math_ops.reduce_sum(embedding)) + math_ops.reduce_sum(embedding) | |||||
// static_grads = gradients_impl.gradients(static, [embedding_matrix])[0] | |||||
// static_grads = math_ops.segment_sum(static_grads.values, | |||||
// static_grads.indices) | |||||
// with self.cached_session(): | |||||
// self.evaluate(variables.global_variables_initializer()) | |||||
// self.assertAllEqual(*self.evaluate([static_grads, dynamic_grads])) | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesWithShapeGradientInWhileLoop() | |||||
{ | |||||
//@test_util.run_v1_only("b/120545219") | |||||
//def testIndexedSlicesWithShapeGradientInWhileLoop(self): | |||||
// for dtype in [dtypes.float32, dtypes.float64]: | |||||
// with self.cached_session() as sess: | |||||
// num_steps = 9 | |||||
// inputs = array_ops.placeholder(dtype=dtype, shape=[num_steps]) | |||||
// initial_outputs = tensor_array_ops.TensorArray( | |||||
// dtype=dtype, size=num_steps) | |||||
// initial_i = constant_op.constant(0, dtype=dtypes.int32) | |||||
// def cond(i, _): | |||||
// return i < num_steps # pylint: disable=cell-var-from-loop | |||||
// def body(i, outputs): | |||||
// x = array_ops.gather(inputs, i) # pylint: disable=cell-var-from-loop | |||||
// outputs = outputs.write(i, x) | |||||
// return i + 1, outputs | |||||
// _, outputs = control_flow_ops.while_loop(cond, body, | |||||
// [initial_i, initial_outputs]) | |||||
// outputs = math_ops.reduce_sum(outputs.stack()) | |||||
// r = gradients_impl.gradients([outputs], [inputs])[0] | |||||
// grad_wr_inputs = ops.convert_to_tensor(r) | |||||
// o, grad = sess.run([outputs, grad_wr_inputs], | |||||
// feed_dict={inputs: [4, 6, 0, 7, 0, 0, 1, 2, 0]}) | |||||
// self.assertEquals(o, 20) | |||||
// self.assertAllEqual(grad, [1] * num_steps) | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testIndexedSlicesWithDynamicShapeGradientInWhileLoop() | |||||
{ | |||||
//@test_util.run_v1_only("b/120545219") | |||||
//def testIndexedSlicesWithDynamicShapeGradientInWhileLoop(self): | |||||
// for dtype in [dtypes.float32, dtypes.float64]: | |||||
// with self.cached_session() as sess: | |||||
// inputs = array_ops.placeholder(dtype=dtype) | |||||
// initial_outputs = tensor_array_ops.TensorArray( | |||||
// dtype=dtype, dynamic_size=True, size=1) | |||||
// initial_i = constant_op.constant(0, dtype=dtypes.int32) | |||||
// def cond(i, _): | |||||
// return i < array_ops.size(inputs) # pylint: disable=cell-var-from-loop | |||||
// def body(i, outputs): | |||||
// x = array_ops.gather(inputs, i) # pylint: disable=cell-var-from-loop | |||||
// outputs = outputs.write(i, x) | |||||
// return i + 1, outputs | |||||
// _, outputs = control_flow_ops.while_loop(cond, body, | |||||
// [initial_i, initial_outputs]) | |||||
// outputs = math_ops.reduce_sum(outputs.stack()) | |||||
// r = gradients_impl.gradients([outputs], [inputs])[0] | |||||
// grad_wr_inputs = ops.convert_to_tensor(r) | |||||
// o, grad = sess.run([outputs, grad_wr_inputs], | |||||
// feed_dict={inputs: [1, 3, 2]}) | |||||
// self.assertEquals(o, 6) | |||||
// self.assertAllEqual(grad, [1] * 3) | |||||
} | |||||
} | |||||
} |
@@ -1,52 +1,52 @@ | |||||
using System; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
[TestClass] | |||||
public class WhileContextTestCase : PythonTest | |||||
{ | |||||
/// <summary> | |||||
/// https://www.tensorflow.org/api_docs/python/tf/while_loop | |||||
/// </summary> | |||||
[Ignore] | |||||
[TestMethod] | |||||
public void SimpleWhileLoop() | |||||
{ | |||||
var i = constant_op.constant(0, name: "i"); | |||||
var c = new Func<Tensor, Tensor>(x => tf.less(x, 10, name: "c")); | |||||
var b = new Func<Tensor, Tensor>(x => tf.add(x, 1, name: "c")); | |||||
//var r = control_flow_ops.while_loop(c, b, i); | |||||
} | |||||
private void _testWhileContextHelper(int maximum_iterations) | |||||
{ | |||||
// TODO: implement missing code dependencies | |||||
using (var sess = this.cached_session()) | |||||
{ | |||||
var i = constant_op.constant(0, name: "i"); | |||||
var c = new Func<Tensor, Tensor>(x => gen_math_ops.less(x, 10, name: "c")); | |||||
var b = new Func<Tensor, Tensor>(x => gen_math_ops.add(x, 1, name: "c")); | |||||
//control_flow_ops.while_loop( | |||||
// c, b, i , maximum_iterations: tf.constant(maximum_iterations)); | |||||
foreach (Operation op in sess.graph.get_operations()) | |||||
{ | |||||
var control_flow_context = op._get_control_flow_context(); | |||||
/*if (control_flow_context != null) | |||||
self.assertProtoEquals(control_flow_context.to_proto(), | |||||
WhileContext.from_proto( | |||||
control_flow_context.to_proto()).to_proto(), "");*/ | |||||
} | |||||
} | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testWhileContextWithMaximumIterations() | |||||
{ | |||||
_testWhileContextHelper(maximum_iterations: 10); | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.control_flow_ops_test | |||||
{ | |||||
[TestClass] | |||||
public class WhileContextTestCase : PythonTest | |||||
{ | |||||
/// <summary> | |||||
/// https://www.tensorflow.org/api_docs/python/tf/while_loop | |||||
/// </summary> | |||||
[Ignore] | |||||
[TestMethod] | |||||
public void SimpleWhileLoop() | |||||
{ | |||||
var i = constant_op.constant(0, name: "i"); | |||||
var c = new Func<Tensor, Tensor>(x => tf.less(x, 10, name: "c")); | |||||
var b = new Func<Tensor, Tensor>(x => tf.add(x, 1, name: "c")); | |||||
//var r = control_flow_ops.while_loop(c, b, i); | |||||
} | |||||
private void _testWhileContextHelper(int maximum_iterations) | |||||
{ | |||||
// TODO: implement missing code dependencies | |||||
using (var sess = this.cached_session()) | |||||
{ | |||||
var i = constant_op.constant(0, name: "i"); | |||||
var c = new Func<Tensor, Tensor>(x => gen_math_ops.less(x, 10, name: "c")); | |||||
var b = new Func<Tensor, Tensor>(x => gen_math_ops.add(x, 1, name: "c")); | |||||
//control_flow_ops.while_loop( | |||||
// c, b, i , maximum_iterations: tf.constant(maximum_iterations)); | |||||
foreach (Operation op in sess.graph.get_operations()) | |||||
{ | |||||
var control_flow_context = op._get_control_flow_context(); | |||||
/*if (control_flow_context != null) | |||||
self.assertProtoEquals(control_flow_context.to_proto(), | |||||
WhileContext.from_proto( | |||||
control_flow_context.to_proto()).to_proto(), "");*/ | |||||
} | |||||
} | |||||
} | |||||
[Ignore("TODO")] | |||||
[TestMethod] | |||||
public void testWhileContextWithMaximumIterations() | |||||
{ | |||||
_testWhileContextHelper(maximum_iterations: 10); | |||||
} | |||||
} | |||||
} |
@@ -1,87 +1,87 @@ | |||||
using System; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using NumSharp; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.nn_test | |||||
{ | |||||
[TestClass] | |||||
public class ZeroFractionTest : PythonTest | |||||
{ | |||||
protected double _ZeroFraction(NDArray x) | |||||
{ | |||||
assert(x.shape); | |||||
int total_elements = np.prod(x.shape); | |||||
var eps = 1e-8; | |||||
var nonzeros = x.Data<double>().Count(d=>Math.Abs(d)> eps); | |||||
return 1.0 - nonzeros / (double)total_elements; | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFraction() | |||||
{ | |||||
var x_shape = new Shape(5, 17); | |||||
var x_np = np.random.randint(0, 2, x_shape); | |||||
//x_np.astype(np.float32); | |||||
var y_np = this._ZeroFraction(x_np); | |||||
var x_tf = constant_op.constant(x_np); | |||||
x_tf.set_shape(x_shape); | |||||
var y_tf = nn_impl.zero_fraction(x_tf); | |||||
var y_tf_np = self.evaluate<NDArray>(y_tf); | |||||
var eps = 1e-8; | |||||
self.assertAllClose(y_tf_np, y_np, eps); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFractionEmpty() | |||||
{ | |||||
var x = np.zeros(0); | |||||
var y = self.evaluate<NDArray>(nn_impl.zero_fraction(new Tensor(x))); | |||||
self.assertTrue(np.isnan(y)); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFraction2_27Zeros() | |||||
{ | |||||
var sparsity = nn_impl.zero_fraction( | |||||
array_ops.zeros(new Shape((int) Math.Pow(2, 27 * 1.01)), dtypes.int8)); | |||||
self.assertAllClose(1.0, self.evaluate<NDArray>(sparsity)); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFraction2_27Ones() | |||||
{ | |||||
var sparsity = nn_impl.zero_fraction( | |||||
array_ops.ones(new TensorShape((int)Math.Pow(2, 27 * 1.01)), dtypes.int8)); | |||||
self.assertAllClose(0.0, self.evaluate<NDArray>(sparsity)); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testUnknownSize() | |||||
{ | |||||
var value = array_ops.placeholder(dtype: dtypes.float32); | |||||
var sparsity = nn_impl.zero_fraction(value); | |||||
using (var sess = self.cached_session()) | |||||
{ | |||||
// TODO: make this compile | |||||
//self.assertAllClose( | |||||
// 0.25, | |||||
// sess.run(sparsity, {value: [[0., 1.], [0.3, 2.]]})); | |||||
} | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using NumSharp; | |||||
using Tensorflow; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.nn_test | |||||
{ | |||||
[TestClass] | |||||
public class ZeroFractionTest : PythonTest | |||||
{ | |||||
protected double _ZeroFraction(NDArray x) | |||||
{ | |||||
assert(x.shape); | |||||
int total_elements = np.prod(x.shape); | |||||
var eps = 1e-8; | |||||
var nonzeros = x.Data<double>().Count(d=>Math.Abs(d)> eps); | |||||
return 1.0 - nonzeros / (double)total_elements; | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFraction() | |||||
{ | |||||
var x_shape = new Shape(5, 17); | |||||
var x_np = np.random.randint(0, 2, x_shape); | |||||
//x_np.astype(np.float32); | |||||
var y_np = this._ZeroFraction(x_np); | |||||
var x_tf = constant_op.constant(x_np); | |||||
x_tf.set_shape(x_shape); | |||||
var y_tf = nn_impl.zero_fraction(x_tf); | |||||
var y_tf_np = self.evaluate<NDArray>(y_tf); | |||||
var eps = 1e-8; | |||||
self.assertAllClose(y_tf_np, y_np, eps); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFractionEmpty() | |||||
{ | |||||
var x = np.zeros(0); | |||||
var y = self.evaluate<NDArray>(nn_impl.zero_fraction(new Tensor(x))); | |||||
self.assertTrue(np.isnan(y)); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFraction2_27Zeros() | |||||
{ | |||||
var sparsity = nn_impl.zero_fraction( | |||||
array_ops.zeros(new Shape((int) Math.Pow(2, 27 * 1.01)), dtypes.int8)); | |||||
self.assertAllClose(1.0, self.evaluate<NDArray>(sparsity)); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testZeroFraction2_27Ones() | |||||
{ | |||||
var sparsity = nn_impl.zero_fraction( | |||||
array_ops.ones(new TensorShape((int)Math.Pow(2, 27 * 1.01)), dtypes.int8)); | |||||
self.assertAllClose(0.0, self.evaluate<NDArray>(sparsity)); | |||||
} | |||||
[Ignore("TODO implement nn_impl.zero_fraction")] | |||||
[TestMethod] | |||||
public void testUnknownSize() | |||||
{ | |||||
var value = array_ops.placeholder(dtype: dtypes.float32); | |||||
var sparsity = nn_impl.zero_fraction(value); | |||||
using (var sess = self.cached_session()) | |||||
{ | |||||
// TODO: make this compile | |||||
//self.assertAllClose( | |||||
// 0.25, | |||||
// sess.run(sparsity, {value: [[0., 1.], [0.3, 2.]]})); | |||||
} | |||||
} | |||||
} | |||||
} |
@@ -1,316 +1,316 @@ | |||||
using System; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using Tensorflow.Eager; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class ControlDependenciesTest : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void TestBasic() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
Tensor a = null, b = null, c = null, d = null, e = null; | |||||
a = constant_op.constant(1.0); | |||||
b = constant_op.constant(1.0); | |||||
tf_with(g.control_dependencies(new[] { a }), x => | |||||
{ | |||||
c = constant_op.constant(1.0); | |||||
d = array_ops.identity(b); | |||||
e = array_ops.identity(c); | |||||
}); | |||||
Assert.IsTrue(Enumerable.SequenceEqual(c.op.control_inputs, new[] { a.op })); | |||||
Assert.IsTrue(Enumerable.SequenceEqual(d.op.control_inputs, new[] { a.op })); | |||||
// e should be dominated by c. | |||||
Assert.AreEqual(0, e.op.control_inputs.Length); | |||||
} | |||||
[Ignore("Future is not supported yet")] | |||||
[TestMethod] | |||||
public void TestEager() | |||||
{ | |||||
Tensor a = null, c = null; | |||||
object b = null; | |||||
var calls = 0; | |||||
Func<Tensor> future = () => | |||||
{ | |||||
calls += 1; | |||||
return constant_op.constant(2.0); | |||||
}; | |||||
using (var opts = new ContextOptions()) | |||||
using (var status = new Status()) | |||||
using (var context = new Context(opts, status)) | |||||
{ | |||||
if (context.executing_eagerly()) | |||||
{ | |||||
// TODO: make this compile (see original Python code below) | |||||
a = constant_op.constant(1.0); | |||||
b = future; // <--- {henon} obviously, this doesn't compile, looks like control_dependencies needs to be able to take callables as well. | |||||
tf_with(ops.control_dependencies(new object[] { a, b }), ctrl => | |||||
{ | |||||
return c = constant_op.constant(3.0); | |||||
}); | |||||
Assert.AreEqual(calls, 1); | |||||
} | |||||
else | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
a = constant_op.constant(1.0); | |||||
var b1 = future(); | |||||
tf_with(g.control_dependencies(new[] { a, b }), ctrl => | |||||
{ | |||||
c = constant_op.constant(3.0); | |||||
}); | |||||
Assert.IsTrue(Enumerable.SequenceEqual(c.op.control_inputs, new[] { a.op, b1.op })); | |||||
Assert.AreEqual(1, calls); | |||||
} | |||||
} | |||||
/* | |||||
def testEager(self): | |||||
def future(): | |||||
future.calls += 1 | |||||
return constant_op.constant(2.0) | |||||
future.calls = 0 | |||||
if context.executing_eagerly(): | |||||
a = constant_op.constant(1.0) | |||||
b = future | |||||
with ops.control_dependencies([a, b]): | |||||
c = constant_op.constant(3.0) | |||||
self.assertEqual(future.calls, 1) | |||||
else: | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
a = constant_op.constant(1.0) | |||||
b = future() | |||||
with g.control_dependencies([a, b]): | |||||
c = constant_op.constant(3.0) | |||||
self.assertEqual(c.op.control_inputs, [a.op, b.op]) | |||||
self.assertEqual(future.calls, 1) | |||||
*/ | |||||
} | |||||
[Ignore("How to port the ConvertibleObj?")] | |||||
[TestMethod] | |||||
public void TestBasicWithConversion() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
// Note: _apply_op can be replaced by g.create_op | |||||
var a = g.create_op("FloatOutput", new Tensor[] { }, new[] { TF_DataType.TF_FLOAT }); | |||||
// TODO: ConvertibleObj, see original source below | |||||
/* | |||||
def testBasicWithConversion(self): | |||||
g = ops.Graph() | |||||
a = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
class ConvertibleObj(object): | |||||
def _as_graph_element(self): | |||||
return a | |||||
with g.control_dependencies([ConvertibleObj()]): | |||||
c = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
self.assertEqual(c.op.control_inputs, [a.op]) | |||||
*/ | |||||
} | |||||
[TestMethod] | |||||
public void TestNested() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
var a_1 = constant_op.constant(1.0); | |||||
var a_2 = constant_op.constant(3.0); | |||||
var a_3 = constant_op.constant(4.0); | |||||
var a_4 = constant_op.constant(5.0); | |||||
Tensor b_1 = null, b_2 = null; | |||||
tf_with(g.control_dependencies(new[] { a_1, a_2, a_3, a_4 }), ctrl => | |||||
{ | |||||
b_1 = constant_op.constant(6.0); | |||||
}); | |||||
tf_with(g.control_dependencies(new[] { a_1 }), ctrl1 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_2 }), ctrl2 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_3 }), ctrl3 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_4 }), ctrl4 => | |||||
{ | |||||
b_2 = constant_op.constant(7.0); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | |||||
//var z=tf.add(a_1, tf.multiply(b_2, b_1)); | |||||
//with(g.control_dependencies(new[] {z}), ctrl => | |||||
//{ | |||||
// var z1 = tf.add(a_3, tf.multiply(a_4, a_2)); | |||||
//}); | |||||
//tf.train.export_meta_graph(@"D:\dev\tensorboard\logdir\sharp.meta", as_text: false); | |||||
assertItemsEqual(b_1.op.control_inputs, new[] { a_1.op, a_2.op, a_3.op, a_4.op }); | |||||
assertItemsEqual(b_2.op.control_inputs, b_1.op.control_inputs); | |||||
} | |||||
[TestMethod] | |||||
public void TestClear() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
var a_1 = constant_op.constant(1.0); | |||||
var a_2 = constant_op.constant(3.0); | |||||
var a_3 = constant_op.constant(4.0); | |||||
var a_4 = constant_op.constant(5.0); | |||||
Operation b_3_4 = null, b_3 = null, b_none = null, b_1 = null, b_1_2 = null, b_none2 = null; | |||||
tf_with(g.control_dependencies(new[] { a_1 }), ctrl1 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_2 }), ctrl2 => | |||||
{ | |||||
tf_with(g.control_dependencies(null), ctrl3 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_3 }), ctrl4 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_4 }), ctrl5 => | |||||
{ | |||||
// deps [a_3, a_4] | |||||
b_3_4 = constant_op.constant(7.0); | |||||
}); | |||||
// deps = [a_3] | |||||
b_3 = constant_op.constant(8.0); | |||||
}); | |||||
// deps back to None | |||||
b_none = constant_op.constant(9.0); | |||||
}); | |||||
// deps back to [a_1, a_2] | |||||
b_1_2 = constant_op.constant(10.0); | |||||
}); | |||||
// deps back to [a_1] | |||||
b_1 = constant_op.constant(11.0); | |||||
tf_with(g.control_dependencies(null), ctrl6 => | |||||
{ | |||||
// deps are None again | |||||
b_none2 = constant_op.constant(12.0); | |||||
}); | |||||
}); | |||||
// Note assertItemsEqual(given, expected), expected and given parameters should be swapped below | |||||
assertItemsEqual(new[] { a_3.op, a_4.op }, b_3_4.op.control_inputs); | |||||
assertItemsEqual(new[] { a_3.op }, b_3.op.control_inputs); | |||||
assertItemsEqual(new object[0], b_none.op.control_inputs); | |||||
assertItemsEqual(new[] { a_1.op, a_2.op }, b_1_2.op.control_inputs); | |||||
assertItemsEqual(new[] { a_1.op }, b_1.op.control_inputs); | |||||
assertItemsEqual(new object[0], b_none2.op.control_inputs); | |||||
} | |||||
[TestMethod] | |||||
public void TestComplex() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
// Usage pattern: | |||||
// * Nodes a_i are constants defined at the outermost scope, and are used | |||||
// as control inputs for the ith nested scope. | |||||
// * Nodes b_i are defined as Mul(a_3, a_4) at each scope. | |||||
// * Nodes c_i are defined as Mul(a_1, b_1) at each scope. | |||||
// * Nodes d_i are defined as Mul(b_i, c_i) at each scope. | |||||
// * Nodes e_i are defined as Mul(e_i-1, e_i-1) at each scope i > 1. | |||||
var a_1 = constant_op.constant(1.0); | |||||
var a_2 = constant_op.constant(2.0); | |||||
var a_3 = constant_op.constant(3.0); | |||||
var a_4 = constant_op.constant(4.0); | |||||
Operation b_1 = null, b_2 = null, b_3 = null, b_4 = null; | |||||
Operation c_1 = null, c_2 = null, c_3 = null, c_4 = null; | |||||
Operation d_1 = null, d_2 = null, d_3 = null, d_4 = null; | |||||
Operation e_1 = null, e_2 = null, e_3 = null, e_4 = null; | |||||
tf_with(g.control_dependencies(new[] { a_1 }), ctrl1 => | |||||
{ | |||||
b_1 = tf.multiply(a_3, a_4); | |||||
c_1 = tf.multiply(a_1, b_1.output); | |||||
d_1 = tf.multiply(b_1.output, c_1.output); | |||||
e_1 = constant_op.constant(5.0); | |||||
tf_with(g.control_dependencies(new[] { a_2 }), ctrl2 => | |||||
{ | |||||
b_2 = tf.multiply(a_3, a_4); | |||||
c_2 = tf.multiply(a_1, b_1.output); | |||||
d_2 = tf.multiply(b_2.output, c_2.output); | |||||
e_2 = tf.multiply(e_1.output, e_1.output); | |||||
tf_with(g.control_dependencies(new[] { a_3 }), ctrl3 => | |||||
{ | |||||
b_3 = tf.multiply(a_3, a_4); | |||||
c_3 = tf.multiply(a_1, b_1.output); | |||||
d_3 = tf.multiply(b_3.output, c_3.output); | |||||
e_3 = tf.multiply(e_2.output, e_2.output); | |||||
tf_with(g.control_dependencies(new[] { a_4 }), ctrl4 => | |||||
{ | |||||
b_4 = tf.multiply(a_3, a_4); | |||||
c_4 = tf.multiply(a_1, b_1.output); | |||||
d_4 = tf.multiply(b_4.output, c_4.output); | |||||
e_4 = tf.multiply(e_3.output, e_3.output); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | |||||
// Note assertItemsEqual(given, expected), expected and given parameters should be swapped below | |||||
assertItemsEqual(new[] {a_1.op}, b_1.op.control_inputs); | |||||
assertItemsEqual(new[] {a_1.op, a_2.op}, b_2.op.control_inputs); | |||||
assertItemsEqual(new[] { a_1.op, a_2.op}, b_3.op.control_inputs); | |||||
assertItemsEqual(new[] {a_1.op, a_2.op}, b_4.op.control_inputs); | |||||
assertItemsEqual(new object[0], c_1.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op}, c_2.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op, a_3.op}, c_3.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op, a_3.op, a_4.op}, c_4.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_1.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_2.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_3.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_4.op.control_inputs); | |||||
assertItemsEqual(new[] {a_1.op}, e_1.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op}, e_2.op.control_inputs); | |||||
assertItemsEqual(new[] {a_3.op}, e_3.op.control_inputs); | |||||
assertItemsEqual(new[] {a_4.op}, e_4.op.control_inputs); | |||||
} | |||||
[Ignore("Don't know how to create an operation with two outputs")] | |||||
[TestMethod] | |||||
public void TestRepeatedDependency() | |||||
{ | |||||
/* | |||||
def testRepeatedDependency(self): | |||||
g = ops.Graph() | |||||
a = g.create_op("TwoFloatOutputs", [], [dtypes.float32, dtypes.float32]) | |||||
a_0, a_1 = a.outputs | |||||
with g.control_dependencies([a_0]): | |||||
b = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
with g.control_dependencies([a_1]): | |||||
c = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
self.assertEqual(b.op.control_inputs, [a]) | |||||
self.assertEqual(c.op.control_inputs, [a]) | |||||
*/ | |||||
} | |||||
[TestMethod] | |||||
public void TestNoControlDependencyWithDataDependency() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
Operation b = null; | |||||
var a = constant_op.constant(100.0); | |||||
tf_with(g.control_dependencies(new[] { a }), ctrl1 => | |||||
{ | |||||
b = array_ops.identity(a); | |||||
}); | |||||
Assert.AreEqual(0, b.op.control_inputs.Length); | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using Tensorflow.Eager; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class ControlDependenciesTest : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void TestBasic() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
Tensor a = null, b = null, c = null, d = null, e = null; | |||||
a = constant_op.constant(1.0); | |||||
b = constant_op.constant(1.0); | |||||
tf_with(g.control_dependencies(new[] { a }), x => | |||||
{ | |||||
c = constant_op.constant(1.0); | |||||
d = array_ops.identity(b); | |||||
e = array_ops.identity(c); | |||||
}); | |||||
Assert.IsTrue(Enumerable.SequenceEqual(c.op.control_inputs, new[] { a.op })); | |||||
Assert.IsTrue(Enumerable.SequenceEqual(d.op.control_inputs, new[] { a.op })); | |||||
// e should be dominated by c. | |||||
Assert.AreEqual(0, e.op.control_inputs.Length); | |||||
} | |||||
[Ignore("Future is not supported yet")] | |||||
[TestMethod] | |||||
public void TestEager() | |||||
{ | |||||
Tensor a = null, c = null; | |||||
object b = null; | |||||
var calls = 0; | |||||
Func<Tensor> future = () => | |||||
{ | |||||
calls += 1; | |||||
return constant_op.constant(2.0); | |||||
}; | |||||
using (var opts = new ContextOptions()) | |||||
using (var status = new Status()) | |||||
using (var context = new Context(opts, status)) | |||||
{ | |||||
if (context.executing_eagerly()) | |||||
{ | |||||
// TODO: make this compile (see original Python code below) | |||||
a = constant_op.constant(1.0); | |||||
b = future; // <--- {henon} obviously, this doesn't compile, looks like control_dependencies needs to be able to take callables as well. | |||||
tf_with(ops.control_dependencies(new object[] { a, b }), ctrl => | |||||
{ | |||||
return c = constant_op.constant(3.0); | |||||
}); | |||||
Assert.AreEqual(calls, 1); | |||||
} | |||||
else | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
a = constant_op.constant(1.0); | |||||
var b1 = future(); | |||||
tf_with(g.control_dependencies(new[] { a, b }), ctrl => | |||||
{ | |||||
c = constant_op.constant(3.0); | |||||
}); | |||||
Assert.IsTrue(Enumerable.SequenceEqual(c.op.control_inputs, new[] { a.op, b1.op })); | |||||
Assert.AreEqual(1, calls); | |||||
} | |||||
} | |||||
/* | |||||
def testEager(self): | |||||
def future(): | |||||
future.calls += 1 | |||||
return constant_op.constant(2.0) | |||||
future.calls = 0 | |||||
if context.executing_eagerly(): | |||||
a = constant_op.constant(1.0) | |||||
b = future | |||||
with ops.control_dependencies([a, b]): | |||||
c = constant_op.constant(3.0) | |||||
self.assertEqual(future.calls, 1) | |||||
else: | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
a = constant_op.constant(1.0) | |||||
b = future() | |||||
with g.control_dependencies([a, b]): | |||||
c = constant_op.constant(3.0) | |||||
self.assertEqual(c.op.control_inputs, [a.op, b.op]) | |||||
self.assertEqual(future.calls, 1) | |||||
*/ | |||||
} | |||||
[Ignore("How to port the ConvertibleObj?")] | |||||
[TestMethod] | |||||
public void TestBasicWithConversion() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
// Note: _apply_op can be replaced by g.create_op | |||||
var a = g.create_op("FloatOutput", new Tensor[] { }, new[] { TF_DataType.TF_FLOAT }); | |||||
// TODO: ConvertibleObj, see original source below | |||||
/* | |||||
def testBasicWithConversion(self): | |||||
g = ops.Graph() | |||||
a = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
class ConvertibleObj(object): | |||||
def _as_graph_element(self): | |||||
return a | |||||
with g.control_dependencies([ConvertibleObj()]): | |||||
c = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
self.assertEqual(c.op.control_inputs, [a.op]) | |||||
*/ | |||||
} | |||||
[TestMethod] | |||||
public void TestNested() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
var a_1 = constant_op.constant(1.0); | |||||
var a_2 = constant_op.constant(3.0); | |||||
var a_3 = constant_op.constant(4.0); | |||||
var a_4 = constant_op.constant(5.0); | |||||
Tensor b_1 = null, b_2 = null; | |||||
tf_with(g.control_dependencies(new[] { a_1, a_2, a_3, a_4 }), ctrl => | |||||
{ | |||||
b_1 = constant_op.constant(6.0); | |||||
}); | |||||
tf_with(g.control_dependencies(new[] { a_1 }), ctrl1 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_2 }), ctrl2 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_3 }), ctrl3 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_4 }), ctrl4 => | |||||
{ | |||||
b_2 = constant_op.constant(7.0); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | |||||
//var z=tf.add(a_1, tf.multiply(b_2, b_1)); | |||||
//with(g.control_dependencies(new[] {z}), ctrl => | |||||
//{ | |||||
// var z1 = tf.add(a_3, tf.multiply(a_4, a_2)); | |||||
//}); | |||||
//tf.train.export_meta_graph(@"D:\dev\tensorboard\logdir\sharp.meta", as_text: false); | |||||
assertItemsEqual(b_1.op.control_inputs, new[] { a_1.op, a_2.op, a_3.op, a_4.op }); | |||||
assertItemsEqual(b_2.op.control_inputs, b_1.op.control_inputs); | |||||
} | |||||
[TestMethod] | |||||
public void TestClear() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
var a_1 = constant_op.constant(1.0); | |||||
var a_2 = constant_op.constant(3.0); | |||||
var a_3 = constant_op.constant(4.0); | |||||
var a_4 = constant_op.constant(5.0); | |||||
Operation b_3_4 = null, b_3 = null, b_none = null, b_1 = null, b_1_2 = null, b_none2 = null; | |||||
tf_with(g.control_dependencies(new[] { a_1 }), ctrl1 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_2 }), ctrl2 => | |||||
{ | |||||
tf_with(g.control_dependencies(null), ctrl3 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_3 }), ctrl4 => | |||||
{ | |||||
tf_with(g.control_dependencies(new[] { a_4 }), ctrl5 => | |||||
{ | |||||
// deps [a_3, a_4] | |||||
b_3_4 = constant_op.constant(7.0); | |||||
}); | |||||
// deps = [a_3] | |||||
b_3 = constant_op.constant(8.0); | |||||
}); | |||||
// deps back to None | |||||
b_none = constant_op.constant(9.0); | |||||
}); | |||||
// deps back to [a_1, a_2] | |||||
b_1_2 = constant_op.constant(10.0); | |||||
}); | |||||
// deps back to [a_1] | |||||
b_1 = constant_op.constant(11.0); | |||||
tf_with(g.control_dependencies(null), ctrl6 => | |||||
{ | |||||
// deps are None again | |||||
b_none2 = constant_op.constant(12.0); | |||||
}); | |||||
}); | |||||
// Note assertItemsEqual(given, expected), expected and given parameters should be swapped below | |||||
assertItemsEqual(new[] { a_3.op, a_4.op }, b_3_4.op.control_inputs); | |||||
assertItemsEqual(new[] { a_3.op }, b_3.op.control_inputs); | |||||
assertItemsEqual(new object[0], b_none.op.control_inputs); | |||||
assertItemsEqual(new[] { a_1.op, a_2.op }, b_1_2.op.control_inputs); | |||||
assertItemsEqual(new[] { a_1.op }, b_1.op.control_inputs); | |||||
assertItemsEqual(new object[0], b_none2.op.control_inputs); | |||||
} | |||||
[TestMethod] | |||||
public void TestComplex() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
// Usage pattern: | |||||
// * Nodes a_i are constants defined at the outermost scope, and are used | |||||
// as control inputs for the ith nested scope. | |||||
// * Nodes b_i are defined as Mul(a_3, a_4) at each scope. | |||||
// * Nodes c_i are defined as Mul(a_1, b_1) at each scope. | |||||
// * Nodes d_i are defined as Mul(b_i, c_i) at each scope. | |||||
// * Nodes e_i are defined as Mul(e_i-1, e_i-1) at each scope i > 1. | |||||
var a_1 = constant_op.constant(1.0); | |||||
var a_2 = constant_op.constant(2.0); | |||||
var a_3 = constant_op.constant(3.0); | |||||
var a_4 = constant_op.constant(4.0); | |||||
Operation b_1 = null, b_2 = null, b_3 = null, b_4 = null; | |||||
Operation c_1 = null, c_2 = null, c_3 = null, c_4 = null; | |||||
Operation d_1 = null, d_2 = null, d_3 = null, d_4 = null; | |||||
Operation e_1 = null, e_2 = null, e_3 = null, e_4 = null; | |||||
tf_with(g.control_dependencies(new[] { a_1 }), ctrl1 => | |||||
{ | |||||
b_1 = tf.multiply(a_3, a_4); | |||||
c_1 = tf.multiply(a_1, b_1.output); | |||||
d_1 = tf.multiply(b_1.output, c_1.output); | |||||
e_1 = constant_op.constant(5.0); | |||||
tf_with(g.control_dependencies(new[] { a_2 }), ctrl2 => | |||||
{ | |||||
b_2 = tf.multiply(a_3, a_4); | |||||
c_2 = tf.multiply(a_1, b_1.output); | |||||
d_2 = tf.multiply(b_2.output, c_2.output); | |||||
e_2 = tf.multiply(e_1.output, e_1.output); | |||||
tf_with(g.control_dependencies(new[] { a_3 }), ctrl3 => | |||||
{ | |||||
b_3 = tf.multiply(a_3, a_4); | |||||
c_3 = tf.multiply(a_1, b_1.output); | |||||
d_3 = tf.multiply(b_3.output, c_3.output); | |||||
e_3 = tf.multiply(e_2.output, e_2.output); | |||||
tf_with(g.control_dependencies(new[] { a_4 }), ctrl4 => | |||||
{ | |||||
b_4 = tf.multiply(a_3, a_4); | |||||
c_4 = tf.multiply(a_1, b_1.output); | |||||
d_4 = tf.multiply(b_4.output, c_4.output); | |||||
e_4 = tf.multiply(e_3.output, e_3.output); | |||||
}); | |||||
}); | |||||
}); | |||||
}); | |||||
// Note assertItemsEqual(given, expected), expected and given parameters should be swapped below | |||||
assertItemsEqual(new[] {a_1.op}, b_1.op.control_inputs); | |||||
assertItemsEqual(new[] {a_1.op, a_2.op}, b_2.op.control_inputs); | |||||
assertItemsEqual(new[] { a_1.op, a_2.op}, b_3.op.control_inputs); | |||||
assertItemsEqual(new[] {a_1.op, a_2.op}, b_4.op.control_inputs); | |||||
assertItemsEqual(new object[0], c_1.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op}, c_2.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op, a_3.op}, c_3.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op, a_3.op, a_4.op}, c_4.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_1.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_2.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_3.op.control_inputs); | |||||
assertItemsEqual(new object[0], d_4.op.control_inputs); | |||||
assertItemsEqual(new[] {a_1.op}, e_1.op.control_inputs); | |||||
assertItemsEqual(new[] {a_2.op}, e_2.op.control_inputs); | |||||
assertItemsEqual(new[] {a_3.op}, e_3.op.control_inputs); | |||||
assertItemsEqual(new[] {a_4.op}, e_4.op.control_inputs); | |||||
} | |||||
[Ignore("Don't know how to create an operation with two outputs")] | |||||
[TestMethod] | |||||
public void TestRepeatedDependency() | |||||
{ | |||||
/* | |||||
def testRepeatedDependency(self): | |||||
g = ops.Graph() | |||||
a = g.create_op("TwoFloatOutputs", [], [dtypes.float32, dtypes.float32]) | |||||
a_0, a_1 = a.outputs | |||||
with g.control_dependencies([a_0]): | |||||
b = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
with g.control_dependencies([a_1]): | |||||
c = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
self.assertEqual(b.op.control_inputs, [a]) | |||||
self.assertEqual(c.op.control_inputs, [a]) | |||||
*/ | |||||
} | |||||
[TestMethod] | |||||
public void TestNoControlDependencyWithDataDependency() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
Operation b = null; | |||||
var a = constant_op.constant(100.0); | |||||
tf_with(g.control_dependencies(new[] { a }), ctrl1 => | |||||
{ | |||||
b = array_ops.identity(a); | |||||
}); | |||||
Assert.AreEqual(0, b.op.control_inputs.Length); | |||||
} | |||||
} | |||||
} |
@@ -1,220 +1,220 @@ | |||||
using System; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using Tensorflow.Operations; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops_test.py | |||||
/// # These cases test the private Graph._create_op_from_tf_operation | |||||
/// # method. Arguably we should only test the public APIs that depend on this | |||||
/// # method. However, this logic is complex and tricky, and it can be difficult to | |||||
/// # ascertain if we have adequate coverage (e.g. a graph may run successfully if | |||||
/// # the control flow context isn't set properly, but a more complicated use case | |||||
/// # that might not be obvious to test will fail). Thus we instead explicitly test | |||||
/// # the low-level behavior. | |||||
/// </summary> | |||||
[TestClass] | |||||
public class CreateOpFromTfOperationTest : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void TestShape() | |||||
{ | |||||
using (var g = tf.Graph().as_default()) | |||||
{ | |||||
var x = constant_op.constant(new[,] {{1, 2, 3}, {4, 5, 6}}); | |||||
var c_op = ops._create_c_op(g, ops._NodeDef("Identity", "myop"), new[] {x}, new Operation[0]); | |||||
var op = g._create_op_from_tf_operation(c_op); | |||||
Assert.AreEqual("myop", op.name); | |||||
Assert.AreEqual("Identity", op.type); | |||||
Assert.AreEqual(1, len(op.outputs)); | |||||
assertItemsEqual(new[] {2, 3}, op.outputs[0].shape); | |||||
} | |||||
} | |||||
[TestMethod] | |||||
public void TestUniqueName() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
//var (c_op,op_desc) = ops._create_c_op(g, ops._NodeDef("Const", "myop"), new Tensor[0], new Operation[0]); | |||||
//var (c_op2, op_desc1) = ops._create_c_op(g, ops._NodeDef("Const", "myop_1"), new Tensor[0], new Operation[0]); | |||||
//var op = g._create_op_from_tf_operation(c_op); | |||||
//var op2 = g._create_op_from_tf_operation(c_op2); | |||||
var op = constant_op.constant(0, name: "myop").op; | |||||
var op2 = constant_op.constant(0, name: "myop_1").op; | |||||
// Create ops with same names as op1 and op2. We expect the new names to be | |||||
// uniquified. | |||||
var op3 = constant_op.constant(0, name: "myop").op; | |||||
var op4 = constant_op.constant(0, name: "myop_1").op; | |||||
self.assertEqual(op.name, "myop"); | |||||
self.assertEqual(op2.name, "myop_1"); | |||||
self.assertEqual(op3.name, "myop_2"); | |||||
self.assertEqual(op4.name, "myop_1_1"); | |||||
} | |||||
[Ignore("need tesnroflow expose UpdateEdge API")] | |||||
[TestMethod] | |||||
public void TestCond() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
var x = constant_op.constant(10); | |||||
var true_fn = new Func<Tensor>(() => | |||||
{ | |||||
var c_op = ops._create_c_op(g, ops._NodeDef("Identity", "cond/myop"), new[] { x }, new Operation[0]); | |||||
var new_ops = g._add_new_tf_operations(); | |||||
self.assertEqual(len(new_ops), 1); | |||||
return x; | |||||
}); | |||||
control_flow_ops.cond(x < 10, true_fn, () => x); | |||||
var op = g.get_operation_by_name("cond/myop"); | |||||
//tf.train.export_meta_graph(@"D:\dev\tensorboard\logdir\sharp.meta.txt", as_text:true); | |||||
//tf.train.export_meta_graph(@"D:\dev\tensorboard\logdir\sharp.meta", as_text: false); | |||||
self.assertIsNotNone(op); | |||||
self.assertEqual(op.name, "cond/myop"); | |||||
self.assertEqual(op.type, "Identity"); | |||||
//self.assertEqual(op.outputs, new object[0]); | |||||
var op_input = op.inputs[0].op; | |||||
self.assertEqual(op_input.type, "Switch"); | |||||
self.assertEqual(op_input.inputs[0].name, x.name); | |||||
self.assertEqual(op.graph, g); | |||||
self.assertIsNotNone(op._get_control_flow_context()); | |||||
var cond_text = op._get_control_flow_context() as ControlFlowContext; | |||||
self.assertEqual(cond_text.name, "cond/cond_text"); | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void TestWhileLoop() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
Operation x=null; | |||||
x = constant_op.constant(42); | |||||
var body = new Func<int, int>(i => | |||||
{ | |||||
ops._create_c_op(ops.get_default_graph(), ops._NodeDef("Identity", "myloop/myop"), new[] {x}, | |||||
new Operation[0]); | |||||
var new_ops = graph._add_new_tf_operations(); | |||||
self.assertEqual(len(new_ops), 1); | |||||
return i; | |||||
}); | |||||
// TODO: port control_flow_ops.while_loop | |||||
//control_flow_ops.while_loop( i => i < 10, body, new int[]{0}, name = "myloop"); | |||||
var op = graph.get_operation_by_name("myloop/myop"); | |||||
self.assertIsNotNone(op); | |||||
self.assertEqual(op.name, "myloop/myop"); | |||||
self.assertEqual(op.type, "Identity"); | |||||
self.assertEqual(op.outputs.Length, 0); | |||||
var op_input = op.inputs[0].op; | |||||
self.assertEqual(op_input.type, "Enter"); | |||||
self.assertItemsEqual(op_input.inputs.OfType<Operation>().ToArray(), new[] {x}); | |||||
self.assertEqual(op.graph, graph); | |||||
self.assertIsNotNone(op._get_control_flow_context()); | |||||
self.assertEqual(((ControlFlowContext)op._get_control_flow_context()).name, "myloop/while_context"); | |||||
/* | |||||
@test_util.run_v1_only("b/120545219") | |||||
def testWhileLoop(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
x = test_ops.int_output() | |||||
def body(i): | |||||
ops._create_c_op(ops.get_default_graph(), | |||||
ops._NodeDef("IntInput", "myloop/myop"), [x], []) | |||||
new_ops = g._add_new_tf_operations() | |||||
self.assertEqual(len(new_ops), 1) | |||||
return i | |||||
control_flow_ops.while_loop(lambda i: i < 10, body, [0], name="myloop") | |||||
op = g.get_operation_by_name("myloop/myop") | |||||
self.assertIsNotNone(op) | |||||
self.assertEqual(op.name, "myloop/myop") | |||||
self.assertEqual(op.type, "IntInput") | |||||
self.assertEqual(op.outputs, []) | |||||
op_input = op.inputs[0].op | |||||
self.assertEqual(op_input.type, "Enter") | |||||
self.assertEqual(list(op_input.inputs), [x]) | |||||
self.assertEqual(op.graph, g) | |||||
# pylint: disable=protected-access | |||||
self.assertIsNotNone(op._get_control_flow_context()) | |||||
self.assertEqual(op._get_control_flow_context().name, | |||||
"myloop/while_context") | |||||
# pylint: enable=protected-access | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void TestWhileLoopWithInternalControlDep() | |||||
{ | |||||
/* | |||||
@test_util.run_v1_only("b/120545219") | |||||
def testWhileLoopWithInternalControlDep(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
x = test_ops.int_output() | |||||
def body(i): | |||||
c = constant_op.constant(1.0, name="c") | |||||
ops._create_c_op(ops.get_default_graph(), | |||||
ops._NodeDef("IntInput", "myloop/myop"), [x], []) | |||||
with ops.control_dependencies([c]): | |||||
new_ops = g._add_new_tf_operations() | |||||
self.assertEqual(len(new_ops), 1) | |||||
return i | |||||
control_flow_ops.while_loop(lambda i: i < 10, body, [0], name="myloop") | |||||
op = g.get_operation_by_name("myloop/myop") | |||||
self.assertIsNotNone(op) | |||||
c = g.get_operation_by_name("myloop/c") | |||||
self.assertIsNotNone(c) | |||||
# Internal control dep is preserved | |||||
self.assertEqual(op.control_inputs, [c]) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void TestWhileLoopWithExternalControlDep() | |||||
{ | |||||
/* | |||||
@test_util.run_v1_only("b/120545219") | |||||
def testWhileLoopWithExternalControlDep(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
x = test_ops.int_output() | |||||
c = constant_op.constant(1.0) | |||||
def body(i): | |||||
ops._create_c_op(ops.get_default_graph(), | |||||
ops._NodeDef("IntInput", "myloop/myop"), [x], []) | |||||
with ops.control_dependencies([c]): | |||||
new_ops = g._add_new_tf_operations() | |||||
self.assertEqual(len(new_ops), 1) | |||||
return i | |||||
control_flow_ops.while_loop(lambda i: i < 10, body, [0], name="myloop") | |||||
op = g.get_operation_by_name("myloop/myop") | |||||
self.assertIsNotNone(op) | |||||
# External control dep is removed and replaced with internal control dep | |||||
self.assertNotEqual(op.control_inputs[0], c.op) | |||||
self.assertIsNotNone(op.control_inputs[0]._get_control_flow_context()) | |||||
*/ | |||||
} | |||||
} | |||||
} | |||||
using System; | |||||
using System.Linq; | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
using Tensorflow.Operations; | |||||
using static Tensorflow.Binding; | |||||
namespace TensorFlowNET.UnitTest.ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops_test.py | |||||
/// # These cases test the private Graph._create_op_from_tf_operation | |||||
/// # method. Arguably we should only test the public APIs that depend on this | |||||
/// # method. However, this logic is complex and tricky, and it can be difficult to | |||||
/// # ascertain if we have adequate coverage (e.g. a graph may run successfully if | |||||
/// # the control flow context isn't set properly, but a more complicated use case | |||||
/// # that might not be obvious to test will fail). Thus we instead explicitly test | |||||
/// # the low-level behavior. | |||||
/// </summary> | |||||
[TestClass] | |||||
public class CreateOpFromTfOperationTest : PythonTest | |||||
{ | |||||
[TestMethod] | |||||
public void TestShape() | |||||
{ | |||||
using (var g = tf.Graph().as_default()) | |||||
{ | |||||
var x = constant_op.constant(new[,] {{1, 2, 3}, {4, 5, 6}}); | |||||
var c_op = ops._create_c_op(g, ops._NodeDef("Identity", "myop"), new[] {x}, new Operation[0]); | |||||
var op = g._create_op_from_tf_operation(c_op); | |||||
Assert.AreEqual("myop", op.name); | |||||
Assert.AreEqual("Identity", op.type); | |||||
Assert.AreEqual(1, len(op.outputs)); | |||||
assertItemsEqual(new[] {2, 3}, op.outputs[0].shape); | |||||
} | |||||
} | |||||
[TestMethod] | |||||
public void TestUniqueName() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
//var (c_op,op_desc) = ops._create_c_op(g, ops._NodeDef("Const", "myop"), new Tensor[0], new Operation[0]); | |||||
//var (c_op2, op_desc1) = ops._create_c_op(g, ops._NodeDef("Const", "myop_1"), new Tensor[0], new Operation[0]); | |||||
//var op = g._create_op_from_tf_operation(c_op); | |||||
//var op2 = g._create_op_from_tf_operation(c_op2); | |||||
var op = constant_op.constant(0, name: "myop").op; | |||||
var op2 = constant_op.constant(0, name: "myop_1").op; | |||||
// Create ops with same names as op1 and op2. We expect the new names to be | |||||
// uniquified. | |||||
var op3 = constant_op.constant(0, name: "myop").op; | |||||
var op4 = constant_op.constant(0, name: "myop_1").op; | |||||
self.assertEqual(op.name, "myop"); | |||||
self.assertEqual(op2.name, "myop_1"); | |||||
self.assertEqual(op3.name, "myop_2"); | |||||
self.assertEqual(op4.name, "myop_1_1"); | |||||
} | |||||
[Ignore("need tesnroflow expose UpdateEdge API")] | |||||
[TestMethod] | |||||
public void TestCond() | |||||
{ | |||||
var g = tf.Graph().as_default(); | |||||
var x = constant_op.constant(10); | |||||
var true_fn = new Func<Tensor>(() => | |||||
{ | |||||
var c_op = ops._create_c_op(g, ops._NodeDef("Identity", "cond/myop"), new[] { x }, new Operation[0]); | |||||
var new_ops = g._add_new_tf_operations(); | |||||
self.assertEqual(len(new_ops), 1); | |||||
return x; | |||||
}); | |||||
control_flow_ops.cond(x < 10, true_fn, () => x); | |||||
var op = g.get_operation_by_name("cond/myop"); | |||||
//tf.train.export_meta_graph(@"D:\dev\tensorboard\logdir\sharp.meta.txt", as_text:true); | |||||
//tf.train.export_meta_graph(@"D:\dev\tensorboard\logdir\sharp.meta", as_text: false); | |||||
self.assertIsNotNone(op); | |||||
self.assertEqual(op.name, "cond/myop"); | |||||
self.assertEqual(op.type, "Identity"); | |||||
//self.assertEqual(op.outputs, new object[0]); | |||||
var op_input = op.inputs[0].op; | |||||
self.assertEqual(op_input.type, "Switch"); | |||||
self.assertEqual(op_input.inputs[0].name, x.name); | |||||
self.assertEqual(op.graph, g); | |||||
self.assertIsNotNone(op._get_control_flow_context()); | |||||
var cond_text = op._get_control_flow_context() as ControlFlowContext; | |||||
self.assertEqual(cond_text.name, "cond/cond_text"); | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void TestWhileLoop() | |||||
{ | |||||
var graph = tf.Graph().as_default(); | |||||
Operation x=null; | |||||
x = constant_op.constant(42); | |||||
var body = new Func<int, int>(i => | |||||
{ | |||||
ops._create_c_op(ops.get_default_graph(), ops._NodeDef("Identity", "myloop/myop"), new[] {x}, | |||||
new Operation[0]); | |||||
var new_ops = graph._add_new_tf_operations(); | |||||
self.assertEqual(len(new_ops), 1); | |||||
return i; | |||||
}); | |||||
// TODO: port control_flow_ops.while_loop | |||||
//control_flow_ops.while_loop( i => i < 10, body, new int[]{0}, name = "myloop"); | |||||
var op = graph.get_operation_by_name("myloop/myop"); | |||||
self.assertIsNotNone(op); | |||||
self.assertEqual(op.name, "myloop/myop"); | |||||
self.assertEqual(op.type, "Identity"); | |||||
self.assertEqual(op.outputs.Length, 0); | |||||
var op_input = op.inputs[0].op; | |||||
self.assertEqual(op_input.type, "Enter"); | |||||
self.assertItemsEqual(op_input.inputs.OfType<Operation>().ToArray(), new[] {x}); | |||||
self.assertEqual(op.graph, graph); | |||||
self.assertIsNotNone(op._get_control_flow_context()); | |||||
self.assertEqual(((ControlFlowContext)op._get_control_flow_context()).name, "myloop/while_context"); | |||||
/* | |||||
@test_util.run_v1_only("b/120545219") | |||||
def testWhileLoop(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
x = test_ops.int_output() | |||||
def body(i): | |||||
ops._create_c_op(ops.get_default_graph(), | |||||
ops._NodeDef("IntInput", "myloop/myop"), [x], []) | |||||
new_ops = g._add_new_tf_operations() | |||||
self.assertEqual(len(new_ops), 1) | |||||
return i | |||||
control_flow_ops.while_loop(lambda i: i < 10, body, [0], name="myloop") | |||||
op = g.get_operation_by_name("myloop/myop") | |||||
self.assertIsNotNone(op) | |||||
self.assertEqual(op.name, "myloop/myop") | |||||
self.assertEqual(op.type, "IntInput") | |||||
self.assertEqual(op.outputs, []) | |||||
op_input = op.inputs[0].op | |||||
self.assertEqual(op_input.type, "Enter") | |||||
self.assertEqual(list(op_input.inputs), [x]) | |||||
self.assertEqual(op.graph, g) | |||||
# pylint: disable=protected-access | |||||
self.assertIsNotNone(op._get_control_flow_context()) | |||||
self.assertEqual(op._get_control_flow_context().name, | |||||
"myloop/while_context") | |||||
# pylint: enable=protected-access | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void TestWhileLoopWithInternalControlDep() | |||||
{ | |||||
/* | |||||
@test_util.run_v1_only("b/120545219") | |||||
def testWhileLoopWithInternalControlDep(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
x = test_ops.int_output() | |||||
def body(i): | |||||
c = constant_op.constant(1.0, name="c") | |||||
ops._create_c_op(ops.get_default_graph(), | |||||
ops._NodeDef("IntInput", "myloop/myop"), [x], []) | |||||
with ops.control_dependencies([c]): | |||||
new_ops = g._add_new_tf_operations() | |||||
self.assertEqual(len(new_ops), 1) | |||||
return i | |||||
control_flow_ops.while_loop(lambda i: i < 10, body, [0], name="myloop") | |||||
op = g.get_operation_by_name("myloop/myop") | |||||
self.assertIsNotNone(op) | |||||
c = g.get_operation_by_name("myloop/c") | |||||
self.assertIsNotNone(c) | |||||
# Internal control dep is preserved | |||||
self.assertEqual(op.control_inputs, [c]) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void TestWhileLoopWithExternalControlDep() | |||||
{ | |||||
/* | |||||
@test_util.run_v1_only("b/120545219") | |||||
def testWhileLoopWithExternalControlDep(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
x = test_ops.int_output() | |||||
c = constant_op.constant(1.0) | |||||
def body(i): | |||||
ops._create_c_op(ops.get_default_graph(), | |||||
ops._NodeDef("IntInput", "myloop/myop"), [x], []) | |||||
with ops.control_dependencies([c]): | |||||
new_ops = g._add_new_tf_operations() | |||||
self.assertEqual(len(new_ops), 1) | |||||
return i | |||||
control_flow_ops.while_loop(lambda i: i < 10, body, [0], name="myloop") | |||||
op = g.get_operation_by_name("myloop/myop") | |||||
self.assertIsNotNone(op) | |||||
# External control dep is removed and replaced with internal control dep | |||||
self.assertNotEqual(op.control_inputs[0], c.op) | |||||
self.assertIsNotNone(op.control_inputs[0]._get_control_flow_context()) | |||||
*/ | |||||
} | |||||
} | |||||
} |
@@ -1,195 +1,195 @@ | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
namespace TensorFlowNET.UnitTest.ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class GraphTest : PythonTest | |||||
{ | |||||
[TestInitialize] | |||||
public void SetUp() | |||||
{ | |||||
ops.reset_default_graph(); | |||||
} | |||||
[TestCleanup] | |||||
public void TearDown() | |||||
{ | |||||
ops.reset_default_graph(); | |||||
} | |||||
private void _AssertDefault(Graph expected) { | |||||
Assert.AreSame(ops.get_default_graph(), expected); | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testResetDefaultGraphNesting() | |||||
{ | |||||
/* | |||||
def testResetDefaultGraphNesting(self): | |||||
g0 = ops.Graph() | |||||
with self.assertRaises(AssertionError): | |||||
with g0.as_default(): | |||||
ops.reset_default_graph() | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testGraphContextManagerCancelsEager() | |||||
{ | |||||
/* | |||||
def testGraphContextManagerCancelsEager(self): | |||||
with context.eager_mode(): | |||||
with ops.Graph().as_default(): | |||||
self.assertFalse(context.executing_eagerly()) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testGraphContextManager() | |||||
{ | |||||
/* | |||||
def testGraphContextManager(self): | |||||
g0 = ops.Graph() | |||||
with g0.as_default() as g1: | |||||
self.assertIs(g0, g1) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testDefaultGraph() | |||||
{ | |||||
/* | |||||
def testDefaultGraph(self): | |||||
orig = ops.get_default_graph() | |||||
self._AssertDefault(orig) | |||||
g0 = ops.Graph() | |||||
self._AssertDefault(orig) | |||||
context_manager_0 = g0.as_default() | |||||
self._AssertDefault(orig) | |||||
with context_manager_0 as g0: | |||||
self._AssertDefault(g0) | |||||
with ops.Graph().as_default() as g1: | |||||
self._AssertDefault(g1) | |||||
self._AssertDefault(g0) | |||||
self._AssertDefault(orig) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testPreventFeeding() | |||||
{ | |||||
/* | |||||
def testPreventFeeding(self): | |||||
g = ops.Graph() | |||||
a = constant_op.constant(2.0) | |||||
self.assertTrue(g.is_feedable(a)) | |||||
g.prevent_feeding(a) | |||||
self.assertFalse(g.is_feedable(a)) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testAsGraphElementConversions() | |||||
{ | |||||
/* | |||||
def testAsGraphElementConversions(self): | |||||
class ConvertibleObj(object): | |||||
def _as_graph_element(self): | |||||
return "FloatOutput:0" | |||||
class NonConvertibleObj(object): | |||||
pass | |||||
g = ops.Graph() | |||||
a = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
self.assertEqual(a, g.as_graph_element(ConvertibleObj())) | |||||
with self.assertRaises(TypeError): | |||||
g.as_graph_element(NonConvertibleObj()) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testGarbageCollected() | |||||
{ | |||||
/* | |||||
# Regression test against creating custom __del__ functions in classes | |||||
# involved in cyclic references, e.g. Graph and Operation. (Python won't gc | |||||
# cycles that require calling a __del__ method, because the __del__ method can | |||||
# theoretically increase the object's refcount to "save" it from gc, and any | |||||
# already-deleted objects in the cycle would have be to restored.) | |||||
def testGarbageCollected(self): | |||||
# Create a graph we can delete and a weak reference to monitor if it's gc'd | |||||
g = ops.Graph() | |||||
g_ref = weakref.ref(g) | |||||
# Create some ops | |||||
with g.as_default(): | |||||
a = constant_op.constant(2.0) | |||||
b = constant_op.constant(3.0) | |||||
c = math_ops.add(a, b) | |||||
# Create a session we can delete | |||||
with session.Session(graph=g) as sess: | |||||
self.evaluate(c) | |||||
# Delete all references and trigger gc | |||||
del g | |||||
del a | |||||
del b | |||||
del c | |||||
del sess | |||||
gc.collect() | |||||
self.assertIsNone(g_ref()) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testRunnableAfterInvalidShape() | |||||
{ | |||||
/* | |||||
def testRunnableAfterInvalidShape(self): | |||||
with ops.Graph().as_default(): | |||||
with self.assertRaises(ValueError): | |||||
math_ops.add([1, 2], [1, 2, 3]) | |||||
a = constant_op.constant(1) | |||||
with session.Session() as sess: | |||||
self.evaluate(a) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testRunnableAfterInvalidShapeWithKernelLabelMap() | |||||
{ | |||||
/* | |||||
def testRunnableAfterInvalidShapeWithKernelLabelMap(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
with g._kernel_label_map({"KernelLabelRequired": "overload_1"}): | |||||
with self.assertRaises(ValueError): | |||||
test_ops.kernel_label_required(1) | |||||
a = constant_op.constant(1) | |||||
with session.Session() as sess: | |||||
self.evaluate(a) | |||||
*/ | |||||
} | |||||
} | |||||
} | |||||
using Microsoft.VisualStudio.TestTools.UnitTesting; | |||||
using Tensorflow; | |||||
namespace TensorFlowNET.UnitTest.ops_test | |||||
{ | |||||
/// <summary> | |||||
/// excerpt of tensorflow/python/framework/ops_test.py | |||||
/// </summary> | |||||
[TestClass] | |||||
public class GraphTest : PythonTest | |||||
{ | |||||
[TestInitialize] | |||||
public void SetUp() | |||||
{ | |||||
ops.reset_default_graph(); | |||||
} | |||||
[TestCleanup] | |||||
public void TearDown() | |||||
{ | |||||
ops.reset_default_graph(); | |||||
} | |||||
private void _AssertDefault(Graph expected) { | |||||
Assert.AreSame(ops.get_default_graph(), expected); | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testResetDefaultGraphNesting() | |||||
{ | |||||
/* | |||||
def testResetDefaultGraphNesting(self): | |||||
g0 = ops.Graph() | |||||
with self.assertRaises(AssertionError): | |||||
with g0.as_default(): | |||||
ops.reset_default_graph() | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testGraphContextManagerCancelsEager() | |||||
{ | |||||
/* | |||||
def testGraphContextManagerCancelsEager(self): | |||||
with context.eager_mode(): | |||||
with ops.Graph().as_default(): | |||||
self.assertFalse(context.executing_eagerly()) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testGraphContextManager() | |||||
{ | |||||
/* | |||||
def testGraphContextManager(self): | |||||
g0 = ops.Graph() | |||||
with g0.as_default() as g1: | |||||
self.assertIs(g0, g1) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testDefaultGraph() | |||||
{ | |||||
/* | |||||
def testDefaultGraph(self): | |||||
orig = ops.get_default_graph() | |||||
self._AssertDefault(orig) | |||||
g0 = ops.Graph() | |||||
self._AssertDefault(orig) | |||||
context_manager_0 = g0.as_default() | |||||
self._AssertDefault(orig) | |||||
with context_manager_0 as g0: | |||||
self._AssertDefault(g0) | |||||
with ops.Graph().as_default() as g1: | |||||
self._AssertDefault(g1) | |||||
self._AssertDefault(g0) | |||||
self._AssertDefault(orig) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testPreventFeeding() | |||||
{ | |||||
/* | |||||
def testPreventFeeding(self): | |||||
g = ops.Graph() | |||||
a = constant_op.constant(2.0) | |||||
self.assertTrue(g.is_feedable(a)) | |||||
g.prevent_feeding(a) | |||||
self.assertFalse(g.is_feedable(a)) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testAsGraphElementConversions() | |||||
{ | |||||
/* | |||||
def testAsGraphElementConversions(self): | |||||
class ConvertibleObj(object): | |||||
def _as_graph_element(self): | |||||
return "FloatOutput:0" | |||||
class NonConvertibleObj(object): | |||||
pass | |||||
g = ops.Graph() | |||||
a = _apply_op(g, "FloatOutput", [], [dtypes.float32]) | |||||
self.assertEqual(a, g.as_graph_element(ConvertibleObj())) | |||||
with self.assertRaises(TypeError): | |||||
g.as_graph_element(NonConvertibleObj()) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testGarbageCollected() | |||||
{ | |||||
/* | |||||
# Regression test against creating custom __del__ functions in classes | |||||
# involved in cyclic references, e.g. Graph and Operation. (Python won't gc | |||||
# cycles that require calling a __del__ method, because the __del__ method can | |||||
# theoretically increase the object's refcount to "save" it from gc, and any | |||||
# already-deleted objects in the cycle would have be to restored.) | |||||
def testGarbageCollected(self): | |||||
# Create a graph we can delete and a weak reference to monitor if it's gc'd | |||||
g = ops.Graph() | |||||
g_ref = weakref.ref(g) | |||||
# Create some ops | |||||
with g.as_default(): | |||||
a = constant_op.constant(2.0) | |||||
b = constant_op.constant(3.0) | |||||
c = math_ops.add(a, b) | |||||
# Create a session we can delete | |||||
with session.Session(graph=g) as sess: | |||||
self.evaluate(c) | |||||
# Delete all references and trigger gc | |||||
del g | |||||
del a | |||||
del b | |||||
del c | |||||
del sess | |||||
gc.collect() | |||||
self.assertIsNone(g_ref()) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testRunnableAfterInvalidShape() | |||||
{ | |||||
/* | |||||
def testRunnableAfterInvalidShape(self): | |||||
with ops.Graph().as_default(): | |||||
with self.assertRaises(ValueError): | |||||
math_ops.add([1, 2], [1, 2, 3]) | |||||
a = constant_op.constant(1) | |||||
with session.Session() as sess: | |||||
self.evaluate(a) | |||||
*/ | |||||
} | |||||
[Ignore("Todo: Port")] | |||||
[TestMethod] | |||||
public void testRunnableAfterInvalidShapeWithKernelLabelMap() | |||||
{ | |||||
/* | |||||
def testRunnableAfterInvalidShapeWithKernelLabelMap(self): | |||||
g = ops.Graph() | |||||
with g.as_default(): | |||||
with g._kernel_label_map({"KernelLabelRequired": "overload_1"}): | |||||
with self.assertRaises(ValueError): | |||||
test_ops.kernel_label_required(1) | |||||
a = constant_op.constant(1) | |||||
with session.Session() as sess: | |||||
self.evaluate(a) | |||||
*/ | |||||
} | |||||
} | |||||
} |
@@ -7,10 +7,13 @@ | |||||
</PropertyGroup> | </PropertyGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" /> | |||||
<PackageReference Include="MSTest.TestAdapter" Version="2.0.0" /> | |||||
<PackageReference Include="MSTest.TestFramework" Version="2.0.0" /> | |||||
<PackageReference Include="coverlet.collector" Version="1.0.1" /> | |||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" /> | |||||
<PackageReference Include="MSTest.TestAdapter" Version="2.1.0" /> | |||||
<PackageReference Include="MSTest.TestFramework" Version="2.1.0" /> | |||||
<PackageReference Include="coverlet.collector" Version="1.2.0"> | |||||
<PrivateAssets>all</PrivateAssets> | |||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> | |||||
</PackageReference> | |||||
</ItemGroup> | </ItemGroup> | ||||
<ItemGroup> | <ItemGroup> | ||||