فهرست مقاله
وقتی طولِ یک دنبالهٔ ویژگی را در یک رمزگشا بزرگ میکنیم، نامِ «کانولوشنِ ترانهاده» ممکن است این تصور را بسازد که عملِ قبلی را وارونه کردهایم. بازگشتنِ تعدادِ مختصات، چنین تضمینی نمیدهد. این درس با ضرایبِ صحیحِ ازپیشدادهشده، یک عملگرِ محدود میسازد تا فرقِ شکل، ترانهاده و وارون روشن شود. دادهها ویژگیِ بیبعد و ساختگیاند؛ مولدِ گفتار، وزنِ آموزشدیده و صوتِ ضبطشده در آزمایش نداریم.
۱. گام و مرزها را پیش از بزرگکردنِ طول مشخص کنیم

در درسِ چیدمانِ Conv1d، پنجرهٔ معتبر با گامِ یک روی ورودی حرکت میکرد و سهمِ کانالها را جمع میزد. اینجا مسئله تبدیلِ محورهای چندکاناله نیست. یک بردار، یک کرنلِ حقیقی، گام، فاصلهٔ ضرایب و مرزِ محدود داریم؛ بایاس و تابعِ فعالسازی را کنار میگذاریم تا عملگر خطی بماند.
نگاشتِ جلو را همبستگیِ لغزشی تعریف میکنیم: دو سوی بردار را به اندازهٔ padding با صفر گسترش میدهیم، پنجره را با stride جلو میبریم و ضرایبِ کرنل را بدونِ وارونهکردن روی نقاطِ آن میگذاریم. dilation فاصلهٔ نقاطِ کرنل است؛ با مقدارِ دو، بین دو ضریبِ متوالی یک جایگاه فاصله میافتد. صفرهای مرزی، مختصاتِ اعلامشدهٔ قراردادند، نه اطلاعاتِ مشاهدهشدهٔ تازه.
بردارِ ورودیِ عملِ ترانهاده را u مینامیم. طولش از یک تا شش و اعضایش صحیحِ منفی شانزده تا شانزدهاند. کرنل یک تا چهار ضریبِ صحیحِ منفی چهار تا چهار دارد. گام یک تا سه، padding صفر تا دو و dilation یک یا دو است. همهٔ ظرفها tuple و نوعها دقیقاند؛ bool، زیرکلاس، شناور و مولد تبدیلِ ضمنی نمیشوند.
اگر طولِ u برابر M و طولِ کرنل K باشد، طولِ انتخابیِ خروجی از رابطهٔ L=(M-1)*stride-2*padding+dilation*(K-1)+output_padding+1 میآید. قراردادِ ما 0 <= output_padding < stride و طولِ مثبت میخواهد. این دامنهٔ کوچک، همهٔ حالتهای نوع، کانال و اندازهٔ یک کتابخانه را پوشش نمیدهد.
۲. چرا output_padding خانهٔ صفرِ تضمینشده نیست؟

مثالِ دستی، u برابرِ دو و سه و کرنلِ یک، دو و چهار است. گامِ دو، padding یک و dilation یک میگیریم. هر عضوِ u، نسخهای مقیاسخورده از ضرایب را در چند جایگاه پخش میکند. عضوِ دو به جایگاههای منفی یک، صفر و یک سهم میدهد؛ سهمِ بیرونِ محدوده کنار میرود. عضوِ سه به جایگاههای یک، دو و سه سهم میدهد.
با output_padding صفر، طولِ سه انتخاب میشود: جایگاه صفر چهار، جایگاه یک هشت بهاضافهٔ سه و جایگاه دو شش است؛ پاسخ چهار، یازده و شش میشود. با output_padding یک، طولِ چهار را انتخاب میکنیم و سهمِ دوازده در جایگاهِ سه هم داخلِ خروجی میافتد. نتیجه چهار، یازده، شش و دوازده است؛ نه همان پاسخ با یک صفرِ چسباندهشده.
توضیحِ کاملِ ConvTranspose1d در PyTorch 2.14، ابهامِ شکل در گامِ بزرگتر از یک و نقشِ output_padding را جدا میکند. در همین مثال، نگاشتِ جلو هم بردارِ سهعضوی و هم چهارعضوی را به دو مختصات میرساند. پس طولِ دو بهتنهایی نمیگوید فضایِ مبدأ سه عضو داشته یا چهار عضو؛ باید شکلِ موردنظر را صریح انتخاب کنیم.
۳. عملگرِ ترانهاده را با ضربِ داخلی بشناسیم

برای مبدأِ چهارعضوی، ماتریسِ نگاشتِ جلو دو ردیف دارد: ردیفِ نخست دو، چهار، صفر و صفر و ردیفِ دوم صفر، یک، دو و چهار است. آن را A مینامیم. ضربِ این ماتریس در x برابرِ یک، منفی دو، چهار و پنج، پاسخِ منفی شش و بیستوشش میدهد. ترانهادهٔ A ضربدرِ u همان چهار، یازده، شش و دوازده است.
در فضایِ حقیقیِ این درس، رابطهٔ مشخصکنندهٔ ترانهاده، برابریِ دو ضربِ داخلی است: dot(Ax,u)=dot(x,A^T u). سمتِ نخست منفی دوازده بهاضافهٔ هفتادوهشت و سمتِ دوم چهار منهای بیستودو بهاضافهٔ بیستوچهار و شصت است؛ هر دو شصتوششاند. برای ضریبِ مختلط، بحثِ مزدوج لازم میشود؛ آن حالت جزو قراردادِ حاضر نیست.
مرجعِ کاملِ TensorFlow برای conv1d_transpose نیز عمل را ترانهاده یا گرادیانِ کانولوشن معرفی میکند، نه واپیچشِ واقعی. در این برنامه مشتقگیریِ خودکار اجرا نمیشود؛ رابطهٔ خطی را مستقیماً با عددِ صحیح میسنجیم. نامِ «deconvolution» مجوزِ ادعایِ بازیابیِ ورودی نیست.
شاهدِ سادهتر، کرنلِ تکعضویِ یک و گامِ دو است. نگاشتِ جلو از بردارِ یک، دو، سه و چهار فقط یک و سه را میخواند. ترانهاده با شکلِ چهارعضوی، یک، صفر، سه و صفر میدهد؛ اطلاعاتِ جایگاههای حذفشده را ندارد. حتی نگاشتِ مربعیِ ضرب در دو هم با ترانهادهاش وارونه نمیشود: دو بار اعمالشدن، چهار برابرِ ورودی است.
۴. کدِ صحیح و مرجعِ ماتریسِ کانولوشن

مسیرِ اصلی بعد از اعتبارسنجیِ کامل، خروجیِ صفر با طولِ اعلامشده میسازد. سهمِ عضو i و ضریب k به جایگاهِ i*stride-padding+k*dilation افزوده میشود، اگر آن جایگاه داخلِ محدوده باشد. ضرایبِ نامتقارن جهت را آشکار میکنند. صفرهای انتهایی به بهانهٔ بیارزشبودن حذف نمیشوند و ورودیِ صفر، بررسیِ ضریبِ نامعتبرِ آخر را دور نمیزند.
"""Finite real integer ConvTranspose adjoint lesson; no framework execution."""
from itertools import product
import json
import platform
import sys
def _admit(values, kernel, stride, padding, dilation, output_padding):
if type(values) is not tuple or not 1 <= len(values) <= 6:
raise ValueError("values must be an exact tuple of length 1..6")
if any(type(x) is not int or not -16 <= x <= 16 for x in values):
raise ValueError("values require exact integers in -16..16")
if type(kernel) is not tuple or not 1 <= len(kernel) <= 4:
raise ValueError("kernel must be an exact tuple of length 1..4")
if any(type(x) is not int or not -4 <= x <= 4 for x in kernel):
raise ValueError("kernel requires exact integers in -4..4")
for name, value, low, high in (
("stride", stride, 1, 3), ("padding", padding, 0, 2),
("dilation", dilation, 1, 2)):
if type(value) is not int or not low <= value <= high:
raise ValueError(name + " violates the exact bounded integer contract")
if type(output_padding) is not int or not 0 <= output_padding < stride:
raise ValueError("own profile requires 0 <= output_padding < stride")
length = ((len(values) - 1) * stride - 2 * padding
+ dilation * (len(kernel) - 1) + output_padding + 1)
if length <= 0:
raise ValueError("selected output length must be positive")
return length
def transpose_1d(values, kernel, stride=1, padding=0, dilation=1, output_padding=0):
"""Scatter into a selected finite extent; single channel, real and no bias.
Coordinates and supplied coefficients are dimensionless integers. This
declared small profile is not the complete type or mode contract of an API.
"""
length = _admit(values, kernel, stride, padding, dilation, output_padding)
answer = [0] * length
for i, value in enumerate(values):
for tap, coefficient in enumerate(kernel):
target = i * stride - padding + tap * dilation
if 0 <= target < length:
answer[target] += value * coefficient
return tuple(answer)
def forward_reference(signal, kernel, stride, padding, dilation):
"""Independent FORWARD map on valid finite fixtures, not a public API.
Explicit padding and strided windows form each forward dot product. No
transpose function, target-index scatter, main validator or output adapter
builds these values. The forward map has no bias, activation or channels.
"""
extended = (0,) * padding + tuple(signal) + (0,) * padding
span = 1 + (len(kernel) - 1) * dilation
windows = []
start = 0
while start + span <= len(extended):
window = extended[start:start + span:dilation]
windows.append(sum(a * b for a, b in zip(window, kernel)))
start += stride
return tuple(windows)
def forward_matrix_reference(source_length, kernel, stride, padding, dilation):
"""Probe the separate forward map with one-hot sources, then arrange rows."""
columns = []
for coordinate in range(source_length):
basis = tuple(int(j == coordinate) for j in range(source_length))
columns.append(forward_reference(basis, kernel, stride, padding, dilation))
return tuple(tuple(row) for row in zip(*columns))
def matrix_transpose_reference(values, kernel, stride, padding, dilation, source_length):
matrix = forward_matrix_reference(source_length, kernel, stride, padding, dilation)
if len(matrix) != len(values):
raise AssertionError("fixture forward map has the wrong output dimension")
return tuple(sum(matrix[row][column] * values[row] for row in range(len(values)))
for column in range(source_length))
def dot(left, right):
assert len(left) == len(right)
return sum(a * b for a, b in zip(left, right))
def rejects(*args):
try:
transpose_1d(*args)
except ValueError:
return True
return False
def run_example():
values, kernel = (2, 3), (1, 2, 4)
short = transpose_1d(values, kernel, 2, 1, 1, 0)
long = transpose_1d(values, kernel, 2, 1, 1, 1)
matrix3 = forward_matrix_reference(3, kernel, 2, 1, 1)
matrix4 = forward_matrix_reference(4, kernel, 2, 1, 1)
x = (1, -2, 4, 5)
ax = forward_reference(x, kernel, 2, 1, 1)
checks = {}
checks["manual_asymmetric_extent_extension_is_nonzero"] = (
short == (4, 11, 6) and long == (4, 11, 6, 12)
and long[:-1] == short and long[-1] != 0)
checks["two_forward_source_lengths_have_same_output_dimension"] = (
matrix3 == ((2, 4, 0), (0, 1, 2))
and matrix4 == ((2, 4, 0, 0), (0, 1, 2, 4))
and len(matrix3) == len(matrix4) == len(values)
and (len(short), len(long)) == (3, 4))
checks["manual_adjoint_identity_uses_same_finite_forward_map"] = (
ax == (-6, 26) and dot(ax, values) == dot(x, long) == 66
and matrix_transpose_reference(values, kernel, 2, 1, 1, 4) == long)
inverse_x = (1, 2, 3, 4)
encoded = forward_reference(inverse_x, (1,), 2, 0, 1)
not_inverse = transpose_1d(encoded, (1,), 2, 0, 1, 1)
gain_x = (1, -2, 3)
gain_encoded = forward_reference(gain_x, (2,), 1, 0, 1)
gain_restored = transpose_1d(gain_encoded, (2,))
checks["shape_restoration_does_not_invert_lost_samples_or_square_gain"] = (
encoded == (1, 3) and not_inverse == (1, 0, 3, 0)
and len(not_inverse) == len(inverse_x) and not_inverse != inverse_x
and gain_encoded == (2, -4, 6) and gain_restored == (4, -8, 12)
and gain_restored != gain_x)
checks["asymmetric_scatter_taps_are_not_silently_reversed"] = (
transpose_1d((1,), kernel) == (1, 2, 4)
and transpose_1d((1,), tuple(reversed(kernel))) == (4, 2, 1)
and matrix_transpose_reference((1,), kernel, 1, 0, 1, 3) == (1, 2, 4))
checks["one_tap_stride_gaps_differ_from_nonzero_boundary_extension"] = (
transpose_1d((2, -1), (1,), 3) == (2, 0, 0, -1)
and transpose_1d((2, -1), (1,), 3, 0, 1, 2) == (2, 0, 0, -1, 0, 0)
and long[-1] == 12)
checks["dilated_tap_spacing_changes_effective_width"] = (
transpose_1d((1, 2), (1, -1), 1, 0, 2) == (1, 2, -1, -2)
and transpose_1d((1, 2), (1, -1)) == (1, 1, -2))
full = transpose_1d(values, kernel, 2)
checks["forward_padding_clips_transpose_contributions_at_both_edges"] = (
full == (2, 4, 11, 6, 12) and short == full[1:-1]
and transpose_1d(values, kernel, 2, 2) == (11,)
and long == full[1:])
checks["zero_data_and_zero_taps_keep_structural_output_length"] = (
transpose_1d((0, 0, 0), (1, 0, -1), 3, 1, 2, 2) == (0,) * 11
and transpose_1d(values, (0, 0, 0), 2, 1, 1, 1) == (0,) * 4)
value_profiles = tuple(t for size in (1, 2) for t in product((-1, 0, 1), repeat=size))
kernel_profiles = tuple(t for size in (1, 2, 3) for t in product((-1, 0, 1), repeat=size))
candidates = admitted = nonpositive_lengths = compared_values = 0
family_ok = True
for u in value_profiles:
for h in kernel_profiles:
for stride in (1, 2, 3):
for padding in (0, 1, 2):
for dilation in (1, 2):
for output_padding in range(stride):
candidates += 1
length = ((len(u) - 1) * stride - 2 * padding
+ dilation * (len(h) - 1) + output_padding + 1)
if length <= 0:
nonpositive_lengths += 1
continue
actual = transpose_1d(u, h, stride, padding, dilation, output_padding)
expected = matrix_transpose_reference(u, h, stride, padding, dilation, length)
test_x = tuple((j * 3 + len(h)) % 5 - 2 for j in range(length))
forward = forward_reference(test_x, h, stride, padding, dilation)
family_ok &= (actual == expected and len(actual) == length
and dot(forward, u) == dot(test_x, actual))
admitted += 1
compared_values += length
checks["finite_one_hot_forward_matrix_and_adjoint_cases_ONE_group"] = bool(
family_ok and admitted > 0 and candidates == admitted + nonpositive_lengths)
a, b, h = (1, -2, 3), (3, 1, -1), (2, -1, 3)
summed = tuple(x + y for x, y in zip(a, b))
ya = transpose_1d(a, h, 2, 1, 2, 1)
yb = transpose_1d(b, h, 2, 1, 2, 1)
checks["fixed_operator_linearity_and_sign_reversal_are_exact"] = (
transpose_1d(summed, h, 2, 1, 2, 1) == tuple(x + y for x, y in zip(ya, yb))
and transpose_1d(tuple(-x for x in a), h, 2, 1, 2, 1) == tuple(-x for x in ya))
class IntSubclass(int):
pass
class TupleSubclass(tuple):
pass
coerced = []
class IndexTrap:
def __index__(self):
coerced.append("coerced")
return 1
base = ((1, -1), (1, 2), 2, 0, 1, 0)
invalid = []
for bad in (None, [1], "1", TupleSubclass((1,)), (True,), (IntSubclass(1),),
(1.0,), (float("nan"),), (float("inf"),), ("1",), (17,), (-17,), (IndexTrap(),)):
invalid.append((bad,) + base[1:])
for bad in (None, [1], "1", TupleSubclass((1,)), (True,), (IntSubclass(1),),
(1.0,), (float("nan"),), ("1",), (5,), (-5,), (0, False), (IndexTrap(),)):
invalid.append((base[0], bad) + base[2:])
for parameter in range(2, 6):
for bad in (True, False, IntSubclass(1), 1.0, "1", None, IndexTrap()):
args = list(base); args[parameter] = bad; invalid.append(tuple(args))
pulled = []
def generator():
pulled.append("pulled")
yield 1
checks["all_types_and_late_entries_validate_without_coercion_ONE_group"] = (
all(rejects(*args) for args in invalid)
and rejects(generator(), base[1], 2, 0, 1, 0)
and rejects(base[0], generator(), 2, 0, 1, 0)
and rejects((0,), (0, False), 1, 0, 1, 0)
and pulled == [] and coerced == [])
cap_values, cap_kernel = (16, -16) * 3, (4, -4, 4, -4)
cap = transpose_1d(cap_values, cap_kernel, 3, 0, 2, 2)
bounds_invalid = (
((), (1,), 1, 0, 1, 0), ((1,), (), 1, 0, 1, 0),
((0,) * 7, (1,), 1, 0, 1, 0), ((1,), (0,) * 5, 1, 0, 1, 0),
((1,), (1,), 0, 0, 1, 0), ((1,), (1,), 4, 0, 1, 0),
((1,), (1,), 1, -1, 1, 0), ((1,), (1,), 1, 3, 1, 0),
((1,), (1,), 1, 0, 0, 0), ((1,), (1,), 1, 0, 3, 0),
((1,), (1,), 2, 0, 1, -1), ((1,), (1,), 2, 0, 1, 2),
((1,), (1,), 1, 1, 1, 0), ((1,), (1,), 3, 1, 1, 1),
)
checks["inclusive_caps_output_padding_policy_and_nonpositive_lengths"] = (
len(cap) == 24 and cap == matrix_transpose_reference(cap_values, cap_kernel, 3, 0, 2, 24)
and all(rejects(*args) for args in bounds_invalid))
before = repr((values, kernel, cap_values, cap_kernel))
first = transpose_1d(values, kernel, 2, 1, 1, 1)
transpose_1d((-16,), (-4,))
second = transpose_1d(values, kernel, 2, 1, 1, 1)
checks["fresh_immutable_outputs_and_inputs_without_hidden_state"] = (
first == second == long and first is not second and type(first) is tuple
and all(type(x) is int for x in first)
and before == repr((values, kernel, cap_values, cap_kernel)))
assert len(checks) == 14 and all(type(x) is bool and x for x in checks.values()), checks
return {
"runtime": {"python": platform.python_version(), "implementation": platform.python_implementation()},
"dependencies": "Python standard library only; no PyTorch/TensorFlow/NumPy/model/audio execution",
"units": "dimensionless synthetic integer coordinates and supplied real coefficients",
"manual": {"values": values, "kernel": kernel, "stride": 2, "padding": 1, "dilation": 1,
"output_padding0": short, "output_padding1": long,
"forward_matrix_source_length3": matrix3, "forward_matrix_source_length4": matrix4,
"x": x, "forward_Ax": ax, "dot_Ax_u": dot(ax, values), "dot_x_ATu": dot(x, long)},
"not_inverse": {"original_x": inverse_x, "forward_Ax": encoded, "transpose_ATAx": not_inverse,
"square_gain_x": gain_x, "square_gain_ATAx": gain_restored},
"finite_family": {"value_profiles": len(value_profiles), "kernel_profiles": len(kernel_profiles),
"candidate_parameter_profiles": candidates, "admitted_positive_length_cases": admitted,
"nonpositive_length_profiles_excluded": nonpositive_lengths,
"compared_output_values": compared_values, "meaningful_groups": 1},
"invalid_type_and_value_profiles_ONE_group": len(invalid) + 3,
"invalid_bound_or_output_length_profiles_ONE_group": len(bounds_invalid),
"maximum_declared_output_length": 24,
"unique_executed_checks": len(checks), "checks": checks, "all_passed": True,
"limitations": [
"Real single-channel finite integer linear map, no batch/groups/bias/activation or complex adjoint.",
"Own bounded profile requires output_padding < stride and positive selected output length.",
"Transpose/adjoint is generally not an inverse, even when dimensions match.",
"No learned weights, framework execution, filter design, speech quality, rate-conversion or hardware guarantee.",
"Finite matrix comparisons form one check group, not a proof for all inputs or a timing benchmark.",
],
}
if __name__ == "__main__":
sys.stdout.buffer.write((json.dumps(run_example(), ensure_ascii=True, indent=2) + "\n").encode("ascii"))
مرجعِ مستقل از بردارهای تکواحدیِ فضایِ مبدأ شروع میکند. هر بردار را با صفرهای صریح و پنجرههای لغزشی از نگاشتِ جلو عبور میدهد و ستونهای ماتریس را میسازد؛ سپس ترانهادهٔ ماتریس را در u ضرب میکند. این مسیر، تابعِ پخشِ سهمها، اعتبارسنجِ اصلی یا خروجیِ آن را برای ساختنِ جوابِ انتظار فراخوانی نمیکند.
چهارده گروهِ نامدار تعریف شدهاند. خانوادهٔ محدود، بردارهای یکعضوی و دوعضوی و کرنلهای تا سه عضو روی منفی یک، صفر و یک را با پارامترهایِ مجاز ترکیب میکند؛ حالتِ طولِ نامثبت کنار گذاشته میشود. تعدادِ واقعیِ حالتهای پذیرفته و مختصاتِ مقایسهشده را خودِ اجرا ثبت میکند. تمامِ این خانواده یک گروه است؛ شمارِ دادهها جایِ شمارِ ادعاهای مستقل نمینشیند.
{
"runtime": {
"python": "3.14.5",
"implementation": "CPython"
},
"dependencies": "Python standard library only; no PyTorch/TensorFlow/NumPy/model/audio execution",
"units": "dimensionless synthetic integer coordinates and supplied real coefficients",
"manual": {
"values": [
2,
3
],
"kernel": [
1,
2,
4
],
"stride": 2,
"padding": 1,
"dilation": 1,
"output_padding0": [
4,
11,
6
],
"output_padding1": [
4,
11,
6,
12
],
"forward_matrix_source_length3": [
[
2,
4,
0
],
[
0,
1,
2
]
],
"forward_matrix_source_length4": [
[
2,
4,
0,
0
],
[
0,
1,
2,
4
]
],
"x": [
1,
-2,
4,
5
],
"forward_Ax": [
-6,
26
],
"dot_Ax_u": 66,
"dot_x_ATu": 66
},
"not_inverse": {
"original_x": [
1,
2,
3,
4
],
"forward_Ax": [
1,
3
],
"transpose_ATAx": [
1,
0,
3,
0
],
"square_gain_x": [
1,
-2,
3
],
"square_gain_ATAx": [
4,
-8,
12
]
},
"finite_family": {
"value_profiles": 12,
"kernel_profiles": 39,
"candidate_parameter_profiles": 16848,
"admitted_positive_length_cases": 15111,
"nonpositive_length_profiles_excluded": 1737,
"compared_output_values": 65781,
"meaningful_groups": 1
},
"invalid_type_and_value_profiles_ONE_group": 57,
"invalid_bound_or_output_length_profiles_ONE_group": 14,
"maximum_declared_output_length": 24,
"unique_executed_checks": 14,
"checks": {
"manual_asymmetric_extent_extension_is_nonzero": true,
"two_forward_source_lengths_have_same_output_dimension": true,
"manual_adjoint_identity_uses_same_finite_forward_map": true,
"shape_restoration_does_not_invert_lost_samples_or_square_gain": true,
"asymmetric_scatter_taps_are_not_silently_reversed": true,
"one_tap_stride_gaps_differ_from_nonzero_boundary_extension": true,
"dilated_tap_spacing_changes_effective_width": true,
"forward_padding_clips_transpose_contributions_at_both_edges": true,
"zero_data_and_zero_taps_keep_structural_output_length": true,
"finite_one_hot_forward_matrix_and_adjoint_cases_ONE_group": true,
"fixed_operator_linearity_and_sign_reversal_are_exact": true,
"all_types_and_late_entries_validate_without_coercion_ONE_group": true,
"inclusive_caps_output_padding_policy_and_nonpositive_lengths": true,
"fresh_immutable_outputs_and_inputs_without_hidden_state": true
},
"all_passed": true,
"limitations": [
"Real single-channel finite integer linear map, no batch/groups/bias/activation or complex adjoint.",
"Own bounded profile requires output_padding < stride and positive selected output length.",
"Transpose/adjoint is generally not an inverse, even when dimensions match.",
"No learned weights, framework execution, filter design, speech quality, rate-conversion or hardware guarantee.",
"Finite matrix comparisons form one check group, not a proof for all inputs or a timing benchmark."
]
}
شاهدهایِ دستی، ابهامِ طول، رابطهٔ ضربِ داخلی، خطیبودن، جهتِ ضریب، شکافِ گام، فاصلهٔ ضرایب، مرزهایِ نوع و اندازه و تازگیِ خروجی نیز بررسی میشوند. حسابها صحیحِ پایتوناند و تلورانسِ ممیزشناور نداریم. خروجیِ کامل، نسخهٔ واقعیِ مفسر و نتیجهٔ گروهها را نگه میدارد؛ PyTorch، TensorFlow و NumPy در این فایل وارد یا اجرا نمیشوند.
۵. چهار پرسش دربارهٔ وارون، کیفیت و مرزِ مدل

پرسش اول: output_padding یک، یعنی افزودنِ صفر؟ پاسخ: خیر؛ در مثالِ دستی، طولِ بزرگتر سهمِ دوازده را آشکار کرد. این پارامتر شکل را انتخاب میکند؛ مقدارِ مختصات از سهمِ ضرایب به دست میآید. در کرنلِ تکعضوی ممکن است جایگاهِ افزوده واقعاً صفر باشد، اما این شاهد را نمیتوان به همهٔ کرنلها تعمیم داد.
پرسش دوم: چرا شکلِ یکسان برای وارونبودن کافی نیست؟ پاسخ: گام میتواند مختصاتی را حذف کند و ترانهاده آن اطلاعات را حدس نمیزند. مثالِ ضرب در دو نیز نشان داد حتی بدونِ کاهشِ بُعد، ترانهاده لزوماً وارون نیست. ادعایِ وارون به رابطهای جدا از برابریِ طول نیاز دارد.
پرسش سوم: چه رابطهای را باید برای ترانهاده آزمایش کنیم؟ پاسخ: با همان کرنل، گام، مرز و فضایِ مبدأ، دو ضربِ داخلیِ اعلامشده باید برابر شوند. عوضکردنِ طول یا سیاستِ مرز، ماتریسِ A را عوض میکند؛ نمیتوان یک سمت را از قراردادی دیگر آورد و فقط انتظارِ برابری داشت.
پرسش چهارم: این نتیجه بازسازی یا کیفیتِ صوت را تأیید میکند؟ پاسخ: خیر. بازسازیِ وزندارِ STFT از تبدیلِ معکوس و مخرجِ پوشش استفاده میکرد؛ اینجا فقط ترانهادهٔ یک نگاشتِ محدود داریم. طراحیِ فیلترِ تغییرِ نرخ، آموزشِ رمزگشا، کیفیتِ گفتار و اجرایِ سختافزاری آزمایشهای دیگری میخواهند.
دو دامنهٔ دقیقِ منابع در ۳۰ مهر ۱۴۰۵ کامل خوانده شدند. نسخهٔ صفحهٔ PyTorch برابرِ 2.14 و نسخهٔ صفحهٔ TensorFlow برابرِ v2.16.1 است؛ هیچکدام را انتشارِ تازه یا نسخهٔ اجرایِ این برنامه معرفی نمیکنیم. تاریخِ انتشارِ نخستِ صفحهها معلوم فرض نشده و از تاریخِ دسترسی یا سرآیندِ وب استنتاج نمیشود. منابعِ مرتبط، متنهایِ ذخیرهشده و قبلاً منتشرشدهاند؛ مشاهدهٔ تازهٔ دسترسپذیریِ سایت یا تضمینِ همهٔ ورودیهایِ ممکن از این آزمایش به دست نمیآید.
منابع و مطالعهٔ بیشتر
- PyTorch2.14؛ کلاس کامل ConvTranspose1d، شکل و تفاوتِ ترانهاده با وارون
- TensorFlowv2.16.1؛ تابع کامل conv1d_transpose و قراردادِ شکلِ خروجی
بررسی منابع: ۳۰ مهر ۱۴۰۵. تحلیلها و پیشنهادهای اجرایی، جمعبندی نویسندهاند.

