Skip to content

Commit 78372a1

Browse files
Merge pull request #1401 from NiklasGustafsson/bugs
Fix issues #1400 and #1402
2 parents 7d06a1d + 01da08d commit 78372a1

File tree

7 files changed

+78
-29
lines changed

7 files changed

+78
-29
lines changed

RELEASENOTES.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,17 @@
22

33
Releases, starting with 9/2/2021, are listed with the most recent release at the top.
44

5+
# NuGet Version 0.104.0
6+
7+
__Breaking Changes__:
8+
9+
The argument defaults for `torch.diagonal()` and `Tensor.diagonal()` arguments have been changed.
10+
11+
__Bug Fixes__:
12+
13+
#1400 There may be an error in torchvision.transforms.GaussianBlur
14+
#1402 diagonal() has incorrect default
15+
516
# NuGet Version 0.103.1
617

718
__Breaking Changes__:

src/TorchSharp/LinearAlgebra.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ public static (Tensor, Tensor) slogdet(Tensor input)
136136
/// </summary>
137137
/// <param name="input">The input tensor</param>
138138
/// <param name="offset">Which diagonal to consider. Default: 0 (main diagonal).</param>
139-
/// <param name="dim1">First dimension with respect to which to take diagonal. Default: -1.</param>
140-
/// <param name="dim2">Second dimension with respect to which to take diagonal. Default: -2.</param>
139+
/// <param name="dim1">First dimension with respect to which to take diagonal. Default: -2.</param>
140+
/// <param name="dim2">Second dimension with respect to which to take diagonal. Default: -1.</param>
141141
/// <remarks>
142142
/// Applying torch.diag_embed() to the output of this function with the same arguments yields a diagonal matrix with the diagonal entries of the input.
143143
/// However, torch.diag_embed() has different default dimensions, so those need to be explicitly specified.

src/TorchSharp/Tensor/Tensor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3329,8 +3329,9 @@ public Tensor diagflat(long offset = 0)
33293329
/// Applying torch.diag_embed() to the output of this function with the same arguments yields a diagonal matrix with the diagonal entries of the input.
33303330
/// However, torch.diag_embed() has different default dimensions, so those need to be explicitly specified.
33313331
/// </remarks>
3332-
public Tensor diagonal(long offset = 0, long dim1 = 0, long dim2 = 0)
3332+
public Tensor diagonal(long offset = 0L, long dim1 = 0L, long dim2 = 1L)
33333333
{
3334+
if (dim1 == dim2) throw new ArgumentException($"Diagonal dimensions cannot be identical {dim1}, {dim2}");
33343335
var res = NativeMethods.THSTensor_diagonal(Handle, offset, dim1, dim2);
33353336
if (res == IntPtr.Zero) { CheckForErrors(); }
33363337
return new Tensor(res);

src/TorchSharp/Tensor/torch.OtherOperations.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -313,7 +313,7 @@ public static Tensor diag_embed(Tensor input, long offset = 0L, long dim1 = -2L,
313313
/// Applying torch.diag_embed() to the output of this function with the same arguments yields a diagonal matrix with the diagonal entries of the input.
314314
/// However, torch.diag_embed() has different default dimensions, so those need to be explicitly specified.
315315
/// </remarks>
316-
public static Tensor diagonal(Tensor input, long offset = 0, long dim1 = 0, long dim2 = 0) => input.diagonal(offset, dim1, dim2);
316+
public static Tensor diagonal(Tensor input, long offset = 0L, long dim1 = 0L, long dim2 = 1L) => input.diagonal(offset, dim1, dim2);
317317

318318
// https://pytorch.org/docs/stable/generated/torch.diff
319319
/// <summary>

src/TorchVision/Functional.cs

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -443,24 +443,25 @@ public static Tensor erase(Tensor img, int top, int left, int height, int width,
443443
/// The image is expected to have […, H, W] shape, where … means an arbitrary number of leading dimensions.
444444
/// </summary>
445445
/// <returns></returns>
446-
public static Tensor gaussian_blur(Tensor input, IList<long> kernelSize, IList<float> sigma)
446+
public static Tensor gaussian_blur(Tensor input, IList<long> kernelSize, ReadOnlySpan<float> sigma)
447447
{
448448
var dtype = torch.is_integral(input.dtype) ? ScalarType.Float32 : input.dtype;
449449

450450
if (kernelSize.Count == 1) {
451451
kernelSize = new long[] { kernelSize[0], kernelSize[0] };
452452
}
453453

454-
if (sigma == null) {
454+
if (sigma == null || sigma.Length == 0)
455+
{
455456
sigma = new float[] {
456-
0.3f * ((kernelSize[0] - 1) * 0.5f - 1) + 0.8f,
457-
0.3f * ((kernelSize[1] - 1) * 0.5f - 1) + 0.8f,
458-
};
459-
} else if (sigma.Count == 1) {
457+
0.3f * ((kernelSize[0] - 1) * 0.5f - 1) + 0.8f,
458+
0.3f * ((kernelSize[1] - 1) * 0.5f - 1) + 0.8f,
459+
};
460+
} else if (sigma.Length == 1) {
460461
sigma = new float[] {
461-
sigma[0],
462-
sigma[0],
463-
};
462+
sigma[0],
463+
sigma[0],
464+
};
464465
}
465466
using var t0 = GetGaussianKernel2d(kernelSize, sigma, dtype, input.device);
466467
using var kernel = t0.expand(input.shape[input.shape.Length - 3], 1, t0.shape[0], t0.shape[1]);
@@ -755,7 +756,7 @@ public static Tensor resized_crop(Tensor input, int top, int left, int height, i
755756
throw new ArgumentException("Crop dimensions exceed image size.", nameof(input));
756757
break;
757758
default: // Any number of batch dimensions
758-
if (top + height > input.shape[input.ndim-2] || left + width > input.shape[input.ndim-1])
759+
if (top + height > input.shape[input.ndim-2] || left + width > input.shape[input.ndim-1])
759760
throw new ArgumentException("Crop dimensions exceed image size.", nameof(input));
760761
break;
761762
case 1:
@@ -891,7 +892,7 @@ private static Tensor GetGaussianKernel1d(long size, float sigma)
891892
return pdf / sum;
892893
}
893894

894-
private static Tensor GetGaussianKernel2d(IList<long> kernelSize, IList<float> sigma, ScalarType dtype, torch.Device device)
895+
private static Tensor GetGaussianKernel2d(IList<long> kernelSize, ReadOnlySpan<float> sigma, ScalarType dtype, torch.Device device)
895896
{
896897
using var tX1 = GetGaussianKernel1d(kernelSize[0], sigma[0]);
897898
using var tX2 = tX1.to(dtype, device);

src/TorchVision/GaussianBlur.cs

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,29 +9,44 @@ namespace TorchSharp
99
{
1010
public static partial class torchvision
1111
{
12-
internal class GaussianBlur : ITransform
12+
internal class GaussianBlur : torch.nn.Module<Tensor,Tensor>, ITransform
1313
{
14-
internal GaussianBlur(IList<long> kernelSize, float min, float max)
14+
internal GaussianBlur(IList<long> kernelSize, float sigma): base(nameof(GaussianBlur))
1515
{
1616
if (kernelSize == null || kernelSize.Count != 2 || kernelSize.Any(x => x <= 0)) {
1717
throw new ArgumentException("Invalid kernel size argument.");
1818
}
19-
if (min < 0 || max < 0 || min >= max) {
20-
throw new ArgumentException("Invalid GaussianBlur arguments.");
19+
if (sigma <= 0) {
20+
throw new ArgumentException("Invalid GaussianBlur arguments: sigma must be positive.");
2121
}
22-
this.sigma = (min == max) ?
23-
min :
24-
(float)(new Random().NextDouble() * (max - min) + min);
22+
this.sigma = sigma;
2523
this.kernelSize = kernelSize.ToArray();
2624
}
2725

28-
public Tensor call(Tensor input)
26+
internal GaussianBlur(IList<long> kernelSize, float sigma_min, float sigma_max) : base(nameof(GaussianBlur))
2927
{
30-
return transforms.functional.gaussian_blur(input, kernelSize, new float[] { sigma });
28+
if (kernelSize == null || kernelSize.Count != 2 || kernelSize.Any(x => x <= 0)) {
29+
throw new ArgumentException("Invalid kernel size argument.");
30+
}
31+
if (sigma_min < 0 || sigma_max < 0 || sigma_min > sigma_max) {
32+
throw new ArgumentException("Invalid GaussianBlur arguments: min and max must be positive and min <= max");
33+
}
34+
// Leave 'this.sigma' null.
35+
this.sigma_min = sigma_min;
36+
this.sigma_max = sigma_max;
37+
this.kernelSize = kernelSize.ToArray();
38+
}
39+
40+
public override Tensor forward(Tensor input)
41+
{
42+
var s = sigma.HasValue ? sigma.Value : torch.empty(1).uniform_(sigma_min, sigma_max).item<float>();
43+
return transforms.functional.gaussian_blur(input, kernelSize, stackalloc[]{s, s});
3144
}
3245

3346
protected long[] kernelSize;
34-
protected float sigma;
47+
protected float? sigma;
48+
protected float sigma_min;
49+
protected float sigma_max;
3550
}
3651

3752
public static partial class transforms
@@ -44,7 +59,7 @@ public static partial class transforms
4459
/// <returns></returns>
4560
static public ITransform GaussianBlur(IList<long> kernelSize, float sigma)
4661
{
47-
return new GaussianBlur(kernelSize, sigma, sigma);
62+
return new GaussianBlur(kernelSize, sigma);
4863
}
4964

5065
/// <summary>

test/TorchSharpTest/TestTorchTensorBugs.cs

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1612,7 +1612,7 @@ public void Validate_1191_3()
16121612
Assert.NotNull(module.p.grad);
16131613
Assert.NotNull(module.ln.weight!.grad);
16141614
Assert.NotNull(module.ln.bias!.grad);
1615-
1615+
16161616
}
16171617

16181618
[Fact]
@@ -1645,7 +1645,7 @@ public void Validate_1249()
16451645
var y1 = torch.nn.functional.avg_pool1d(x, 2);
16461646
Console.WriteLine(y1.metastr());
16471647
Assert.Equal(64, y1.size(-1));
1648-
1648+
16491649
var y2 = torch.nn.AvgPool1d(2).call(x);
16501650
Console.WriteLine(y2.metastr());
16511651
Assert.Equal(64, y1.size(-1));
@@ -1674,12 +1674,33 @@ public void ValidateLoadWithDeflateStream()
16741674
seq.save(stream);
16751675
}
16761676

1677-
// This test will succeed if the following code doesn't crash.
1677+
// This test will succeed if the following code doesn't crash.
16781678
ms.Position = 0;
16791679
using (var archive = new ZipArchive(ms)) {
16801680
seq.load(archive.GetEntry("seq")!.Open());
16811681
}
16821682
#endif
16831683
}
1684+
1685+
[Fact]
1686+
public void Validate1400()
1687+
{
1688+
long kernel = 21;
1689+
float sigma = 11;
1690+
var trans = torchvision.transforms.GaussianBlur(kernel, sigma); //System.ArgumentException:“Invalid GaussianBlur arguments.”
1691+
1692+
var img = torch.rand(1,3,256,256);
1693+
var t = trans.call(img);
1694+
}
1695+
1696+
[Fact]
1697+
public void Validate1402()
1698+
{
1699+
var t = torch.arange(100).reshape(10,10);
1700+
1701+
var d = t.diagonal();
1702+
1703+
Assert.Equal(new long[]{0, 11, 22, 33, 44, 55, 66, 77, 88, 99}, d.data<long>().ToArray());
1704+
}
16841705
}
16851706
}

0 commit comments

Comments
 (0)