[Modelo de implementación acelerada] - Pytorch Automatic Mixed Precision Training

Precisión mixta automática

torch.amp proporciona métodos convenientes para precisión mixta, donde algunas operaciones usan el tipo de datos torch.float32 (float), mientras que otras usan un tipo de datos float de menor precisión (lower_precision_fp): torch.float16 (half) o torch .bfloat16. Algunas operaciones, como capas lineales y circunvoluciones, son mucho más rápidas en lower_precision_fp. Otras operaciones, como la reducción de escala, a menudo requieren el rango dinámico de float32. La precisión mixta intenta hacer coincidir cada operación con su tipo de datos apropiado.

Por lo general, el "Entrenamiento de precisión mixto automático" con el tipo de datos torch.float16 usa torch.autocast y torch.cuda.amp.GradScaler juntos. Además, torch.autocast y torch.cuda.amp.GradScaler son modulares y se pueden usar por separado si es necesario.

Para CUDA y CPU, la API también se proporciona por separado:

torch.autocast("cuda", args...) es equivalente a torch.cuda.amp.autocast(args...) .

torch.autocast("cpu", args...) es equivalente a torch.cpu.amp.autocast(args...) . Para la CPU, actualmente solo se admite el tipo de datos de punto flotante de menor precisión de torch.bfloat16.

Conversión automática (autocast)

torch.autocast( device_type , dtype=Ninguno , habilitado=Verdadero , cache_habilitado=Ninguno )

Parámetros:
device_type (str, requerido) - use el dispositivo 'cuda' o 'cpu'
habilitado (bool, opcional) - si habilitar la transmisión automática en la zona. Predeterminado: True
dtype (torch_dtype, opcional) – Ya sea para usar torch.float16 o torch.bfloat16.
cache_enabled (bool, opcional): si habilitar el almacenamiento en caché de peso interno de autodifusión. Valor predeterminado: verdadero

autocast se puede usar como administrador de contexto o decorador, lo que permite que los ámbitos de script se ejecuten con precisión mixta.

En estas regiones, las operaciones de datos se ejecutan en el tipo de d elegido por autocast que es específico para esa operación, para mejorar el rendimiento y mantener la precisión.

Los tensores pueden ser de cualquier tipo al ingresar a una región habilitada para autocast. Al usar autocast, no debe llamar a half() o bfloat16() en el modelo o entrada. autocast solo debe envolver el pase directo de la red, incluido el cálculo de pérdidas. No se recomienda retroceder bajo autocast. Las operaciones hacia atrás toman el mismo tipo de ejecución que usa Autocast para las operaciones hacia adelante correspondientes.

Ejemplo CUDA:

# Creates model and optimizer in default precision
model = Net().cuda()
optimizer = optim.SGD(model.parameters(), ...)

for input, target in data:
    optimizer.zero_grad()

    # Enables autocasting for the forward pass (model + loss)
    with autocast():
        output = model(input)
        loss = loss_fn(output, target)

    # Exits the context manager before backward()
    loss.backward()
    optimizer.step()

El tensor de coma flotante resultante puede ser float16 en regiones donde la conversión automática está habilitada. Usarlos con tensores de coma flotante de diferentes tipos de d puede generar errores de discrepancia de tipo después de regresar a una región donde la conversión automática está deshabilitada. Si es así, convierta el tensor resultante en la zona de conversión automática nuevamente a float32 (u otro dtype, si es necesario). Si el tensor de la región convertida automáticamente ya es float32, la conversión no es operativa y no genera gastos generales adicionales.

Ejemplo CUDA:

# Creates some tensors in default dtype (here assumed to be float32)
a_float32 = torch.rand((8, 8), device="cuda")
b_float32 = torch.rand((8, 8), device="cuda")
c_float32 = torch.rand((8, 8), device="cuda")
d_float32 = torch.rand((8, 8), device="cuda")

with autocast():
    # torch.mm is on autocast's list of ops that should run in float16.
    # Inputs are float32, but the op runs in float16 and produces float16 output.
    # No manual casts are required.
    e_float16 = torch.mm(a_float32, b_float32)
    # Also handles mixed input types
    f_float16 = torch.mm(d_float32, e_float16)

# After exiting autocast, calls f_float16.float() to use with d_float32
g_float32 = torch.mm(d_float32, f_float16.float())

Ejemplo de entrenamiento de CPU:

# Creates model and optimizer in default precision
model = Net()
optimizer = optim.SGD(model.parameters(), ...)

for epoch in epochs:
    for input, target in data:
        optimizer.zero_grad()

        # Runs the forward pass with autocasting.
        with torch.autocast(device_type="cpu", dtype=torch.bfloat16):
            output = model(input)
            loss = loss_fn(output, target)

        loss.backward()
        optimizer.step()

Ejemplo de inferencia de CPU:

# Creates model in default precision
model = Net().eval()

with torch.autocast(device_type="cpu", dtype=torch.bfloat16):
    for input in data:
        # Runs the forward pass with autocasting.
        output = model(input)

Ejemplo de inferencia de CPU usando jit trace:

class TestModel(nn.Module):
    def __init__(self, input_size, num_classes):
        super().__init__()
        self.fc1 = nn.Linear(input_size, num_classes)
    def forward(self, x):
        return self.fc1(x)

input_size = 2
num_classes = 2
model = TestModel(input_size, num_classes).eval()

# For now, we suggest to disable the Jit Autocast Pass,
# As the issue: https://github.com/pytorch/pytorch/issues/75956
torch._C._jit_set_autocast_mode(False)

with torch.cpu.amp.autocast(cache_enabled=False):
    model = torch.jit.trace(model, torch.randn(1, input_size))
model = torch.jit.freeze(model)
# Models Run
for _ in range(3):
    model(torch.randn(1, input_size))

Las subregiones autocast(enabled=False) se pueden anidar dentro de las regiones habilitadas para autocast. Deshabilitar parcialmente la transmisión automática es útil cuando se imponen subregiones en tipos de datos específicos. La desactivación de la transmisión automática proporciona un control explícito sobre el tipo de ejecución. En las subregiones, la entrada de las regiones circundantes debe convertirse al tipo de datos especificado antes de usarse.

# 在默认数据类型(这里假设为float32)中创建一些张量
a_float32 = torch.rand((8, 8), device="cuda")
b_float32 = torch.rand((8, 8), device="cuda")
c_float32 = torch.rand((8, 8), device="cuda")
d_float32 = torch.rand((8, 8), device="cuda")

with autocast():
    e_float16 = torch.mm(a_float32, b_float32)
    with autocast(enabled=False):
        # 调用e_float16.float()以确保使用float32执行
        # (这是必需的,因为e_float16是在autocast区域中创建的)
        f_float32 = torch.mm(c_float32, e_float16.float())

    # 当重新进入启用autocast的区域时,无需手动转换类型。
    # torch.mm仍然以float16运行并产生float16的输出,不受输入类型的影响。
    g_float16 = torch.mm(d_float32, f_float32)

El estado de autodifusión es subproceso local. Si desea habilitarlo en un hilo nuevo, debe llamar al administrador de contexto o decorador en ese hilo.

torch.cuda.amp.autocast(enabled=True, dtype=torch.float16, cache_enabled=True)
torch.cuda.amp.autocast(args…)等同于torch.autocast(“cuda”, args…)

* torch.cuda.amp.custom_fwd(fwd=None, , cast_inputs=None)
Decorador auxiliar para el método directo de la función de derivación automática personalizada (subclase de torch.autograd.Function).

Parámetros:
cast_inputs (torch.dtype o Ninguno, opcional, predeterminado=Ninguno): si no es Ninguno, cuando se ejecuta hacia adelante en una región habilitada para autocast, convierta el tensor CUDA de punto flotante entrante al tipo de datos de destino (los tensores que no son de punto flotante son no se ve afectado), luego realice el reenvío con la transmisión automática deshabilitada. Si es Ninguno, las operaciones internas de reenvío se realizarán de acuerdo con el estado actual de autodifusión

Escalado de gradiente

Si el pase hacia adelante de una operación tiene entradas float16, el pase hacia atrás de esa operación producirá gradientes float16. Es posible que los valores de gradiente con magnitudes pequeñas no se puedan representar como float16. Estos valores se pondrán a cero ("subdesbordamiento"), por lo que se perderán las actualizaciones de los parámetros correspondientes.

Para evitar el subdesbordamiento, el "escalado de gradiente" funciona multiplicando la pérdida de la red por un factor de escala y realizando un paso inverso sobre la pérdida escalada. Los gradientes que se propagan a través de la red también se escalan por el mismo factor. En otras palabras, los valores de gradiente tienen magnitudes grandes, por lo que no se ponen a cero.

Los gradientes (propiedades .grad) para cada parámetro deben restaurarse antes de que el optimizador actualice los parámetros para garantizar que el factor de escala no interfiera con la configuración de la tasa de aprendizaje.

torch.cuda.amp.GradScaler(init_scale=65536.0, growth_factor=2.0, backoff_factor=0.5, growth_interval=2000, enable=True)

get_backoff_factor() devuelve un flotante de Python que contiene el factor de retroceso de escala.

get_growth_factor() devuelve un flotante de Python que contiene el factor de crecimiento de escala.

get_growth_interval() devuelve un entero de Python que contiene el intervalo de crecimiento.

get_scale() devuelve un flotante de Python que contiene el factor de escala actual, o 1.0 si la escala está deshabilitada.

**ADVERTENCIA:** get_scale() generará sincronización CPU-GPU.

is_enabled() devuelve un valor booleano que indica si esta instancia está habilitada.

load_state_dict(state_dict) estado del escalador de carga. Si esta instancia está deshabilitada, load_state_dict() no hace nada.

Parámetros: state_dict (dict) – estado del escalador. Debería ser el objeto devuelto al llamar a state_dict().

scale(outputs) escala un tensor o lista de tensores por un factor de escala.

Devuelve la salida escalada. Devuelve una salida sin modificar si la instancia de GradScaler no está habilitada.

Parámetros: salidas (Tensor o iterable de Tensores) – salidas a escala.

set_backoff_factor(new_factor) Parámetros: new_factor (flotante) – valor para usar como nuevo factor de reducción de escala.

set_growth_factor(new_factor) Parámetros: new_factor (float) – valor para usar como nuevo factor de crecimiento de escala.

set_growth_interval(new_interval) Parámetros: new_interval (int) – valor para usar como nuevo intervalo de crecimiento.

state_dict() devuelve el estado del escalador como un diccionario. Contiene cinco entradas:

"escala": un flotador de Python que contiene la escala actual

"growth_factor": un flotante de Python que contiene el factor de crecimiento actual

"backoff_factor": un flotante de Python que contiene el factor de retroceso actual

"growth_interval": un número entero de Python que contiene el intervalo de crecimiento actual

"_growth_tracker": un número entero de Python que contiene el número de los pasos no omitidos consecutivos más recientes.

Devuelve un diccionario vacío si esta instancia no está habilitada.

Nota: si desea verificar el estado del escalador de puntos después de una iteración específica, debe llamar a state_dict() después de actualizar().

paso(optimizador, *args, **kwargs)

step() realiza las siguientes dos operaciones:

1 llama a unscale_(optimizer) internamente (a menos que se haya llamado explícitamente a unscale_() antes en la iteración). Como parte de unscale_(), se comprueba si el degradado contiene inf/NaN.

2 Si no se encuentran gradientes inf/NaN, se llama aOptimizer.step() con gradientes sin escala. De lo contrario, se omitiráOptimizer.step() para evitar dañar los parámetros.

*args y **kwargs se pasarán aOptimizer.step().

Devuelve el valor de retorno deOptimizer.step(*args, **kwargs).

Parámetros: Optimizer (torch.optim.Optimizer) – el optimizador para aplicar gradientes.

args – cualquier argumento.

kwargs: cualquier argumento de palabra clave.

advertir

Actualmente no se admite el uso de cierre.

unscale_(optimizer) divide ("desescala") el tensor de gradiente del optimizador por un factor de escala.

unscale_() es opcional y es adecuado para los casos en que los gradientes se modifican o inspeccionan entre la retropropagación y el paso (step()). Los degradados se desescalarán automáticamente durante un paso ( step() ) si unscale_() no se llama explícitamente.

Ejemplo simple, usando unscale_() para habilitar el recorte de gradientes sin escala:

… scaler.scale(loss).backward() scaler.unscale_(optimizer) torch.nn.utils.clip_grad_norm_(model.parameters(), max_norm) scaler.step(optimizer) scaler.update() Parámetros: Optimizer (torch. optim.Optimizer): el optimizador con gradientes para desescalar.

Aviso

unscale_() no genera sincronización CPU-GPU.

advertir

Cada llamada a unscale_() debe llamarse exactamente una vez por llamada step() por optimizador, y solo después de que se hayan acumulado todos los gradientes para los parámetros asignados de ese optimizador. Llamar a unscale_() dos veces seguidas para un optimizador determinado entre cada paso() generará un RuntimeError.

advertir

unscale_() puede desescalar gradientes dispersos de forma irreversible, reemplazando el atributo .grad.

update(new_scale=None)[SOURCE] Actualiza el factor de escala.

Si se omite algún paso del optimizador, se reduce por backoff_factor multiplicado por el factor de escala. Si hay iteraciones no saltadas de intervalo_de_crecimiento seguidas, auméntelo multiplicando factor_de_crecimiento por el factor de escala.

Pasar new_scale establece manualmente el nuevo valor de escala. (new_scale no se usa directamente, pero se usa para llenar el tensor de escala interno de GradScaler. Por lo tanto, si new_scale es un tensor, los cambios en ese tensor no afectarán más la escala utilizada internamente por GradScaler).

Parámetros: new_scale (float o torch.cuda.FloatTensor, opcional, predeterminado Ninguno) – nuevo factor de escala.

advertir

update() solo debe llamarse al final de una iteración donde se llamó a scaler.step(optimizer) para todos los optimizadores usados.

Referencia relacionada con Autocast Op

Elegibilidad de operación de autocast

Independientemente de si la transmisión automática está habilitada, las operaciones que operan en tipos float64 o no flotantes no se transmiten automáticamente, se realizarán en el tipo original. autocast solo afecta las operaciones fuera de lugar y los métodos de tensor. Las operaciones locales y las llamadas que proporcionan explícitamente out=...tensor están permitidas en las regiones habilitadas para la transmisión automática, pero no pasarán la transmisión automática. Por ejemplo, en una región donde la transición automática está habilitada, a.addmm(b,c) se puede convertir automáticamente, pero a.addmm_(b,c,out=d) no. Para obtener el mejor rendimiento y estabilidad, prefiera operaciones fuera de lugar en regiones habilitadas para autocast. Las operaciones que llaman explícitamente a dtype=... no son elegibles para el uso de autocast y generarán una salida para el argumento dtype.

Comportamiento específico de CUDA Op

La siguiente lista describe el comportamiento de las operaciones elegibles en regiones donde la transición automática está habilitada. Estas operaciones siempre se convierten automáticamente, ya sea que se llamen como parte de un módulo torch.nn.Module, como una función o como un método torch.Tensor. Si las funciones se exponen en varios espacios de nombres, se convierten automáticamente independientemente del espacio de nombres.

Las operaciones que no se enumeran a continuación no se convierten automáticamente. Operan de acuerdo con el tipo definido por su entrada. Sin embargo, las conversiones automáticas aún pueden cambiar el tipo de operaciones ejecutadas por operaciones no cotizadas si son posteriores a la operación convertida automáticamente.

Si una operación no está listada, asumimos que es numéricamente estable en float16. Presente un problema si cree que una operación que no figura en la lista es numéricamente inestable en float16.

CUDA Ops que puede convertir automáticamente a float16

matmul,addbmm,addmm,addmv,addr,baddbmm,bmm,chain_matmul,multi_dot,conv1d,conv2d,conv3d,conv_transpose1d,conv_transpose2d,conv_transpose3d,GRUCell,linear,LSTMCell, matmul, mm, mv, prelu, RNNCell

CUDA Ops que puede convertir automáticamente a float32

pow,rdiv,rpow,rtruediv,acos,asin,binary_cross_entropy_with_logits,cosh,cosine_embedding_loss,cdist,cosine_similarity,cross_entropy,cumprod,cumsum,dist,erfinv,exp,expm1,group_nor m、hinge_embedding_loss、kl_div、l1_loss、layer_norm、log、log_softmax、 log10,log1p,log2,margin_ranking_loss,mse_loss,multilabel_margin_loss,multi_margin_loss,nll_loss,norm,normalize,pdist,poisson_nll_loss,pow,prod,reciprocal,rsqrt,sinh 、smooth_l1_loss、soft_margin_loss、softmax、softmin、softplus、sum、renorm、tan、 triplete_margin_loss

CUDA Ops que puede potenciar la gama más amplia de tipos de entrada

Estas operaciones no requieren un tipo de datos específico para la estabilidad, pero requieren múltiples entradas y requieren que los tipos de datos de las entradas coincidan. Si todas las entradas son float16, la operación opera en float16. Si alguna de las entradas es float32, autoconvert convierte todas las entradas a float32 y ejecuta la operación en float32.

addcdiv,addcmul,atan2,bilineal,cruz,punto,grid_sample,index_put,scatter_add,tensordot

Algunas operaciones que no se enumeran aquí (por ejemplo, operaciones binarias como agregar) pueden promover la entrada por sí mismas sin la intervención de la conversión automática. Si la entrada es una combinación de bfloat16 y float32, estas operaciones operarán en float32 y producirán una salida de float32, ya sea que la conversión automática esté habilitada o no.

Preferir binary_cross_entropy_with_logits sobre binary_cross_entropy

La retropropagación de torch.nn.funcional.binary_cross_entropy() (y torch.nn.BCELoss que lo envuelve) puede producir gradientes que no se pueden representar en float16. En las regiones donde la conversión automática está habilitada, la entrada de avance puede ser float16, lo que significa que los gradientes para la propagación hacia atrás deben poder representarse en float16 (la conversión automática de una entrada de avance de float16 a float32 es inútil porque la conversión debe estar invertida en la propagación hacia atrás). Por lo tanto, binary_cross_entropy y BCELoss arrojan un error en las regiones donde está habilitada la transición automática.

Muchos modelos usan una capa sigmoidea antes de la capa de entropía cruzada binaria. En este caso, utilice torch.nn.function.binary_cross_entropy_with_logits() o torch.nn.BCEWithLogitsLoss para combinar las dos capas. binary_cross_entropy_with_logits y BCEWithLogits son seguros para la conversión automática.

Comportamiento específico de la operación de la CPU

La siguiente lista describe el comportamiento de las operaciones elegibles en regiones donde la transición automática está habilitada. Estas operaciones siempre se convierten automáticamente, ya sea que se llamen como parte de un módulo torch.nn.Module, como una función o como un método torch.Tensor. Si las funciones se exponen en varios espacios de nombres, se convierten automáticamente independientemente del espacio de nombres.

Las operaciones que no se enumeran a continuación no se convierten automáticamente. Operan de acuerdo con el tipo definido por su entrada. Sin embargo, las conversiones automáticas aún pueden cambiar el tipo de operaciones ejecutadas por operaciones no cotizadas si son posteriores a la operación convertida automáticamente.

Si una operación no aparece en la lista, asumimos que es numéricamente estable en bfloat16. Presente un problema si cree que una operación que no figura en la lista es numéricamente inestable en bfloat16.

Operaciones de CPU que se pueden convertir automáticamente a bfloat16

conv1d, conv2d, conv3d, bmm, mm, baddbmm, addmm, addbmm, lineal, matmul,_convolución

CPU que pueden convertirse automáticamente a float32

operacionesconv_transpose1d, conv_transpose2d, conv_transpose3d, avg_pool3d, binary_cross_entropy, grid_sampler, grid_sampler_2d,_grid_sampler_2d_cpu_fallback, grid_sampler_3d, polar, prod, quantile, nanquantile stft, cdist, trace, view_as_complex, cholesky, cholesky_inverse, cholesky_solve, inverse, lu_solve, orgqr, inverse, ormqr, pinverse,max_pool3d,max_unpool2d,max_unpool3d,adaptive_avg_pool3d,reflection_pad1d,reflection_pad2d,replication_pad1d,replication_pad2d,replication_pad3d,mse_loss,ctc_loss,kl_div,multilabel _pérdida_margen,fft_fft,fft_ifft,fft_fft2,fft_ifft2,fft_fftn,fft_ifftn,fft_rfft,fft_irfft,fft_rfft2,fft_irfft2,fft_rfftn, fft_irfftn,fft_hfft,fft_ihfft,linalg_matrix_norm,linalg_cond,linalg_matrix_rank,linalg_solve,linalg_cholesky,linalg_svdvals,linalg_eigvals,linalg_eigvalsh,linalg_inv 、linalg_householder_product、linalg_tensorinv、linalg_tensorsolve、fake_quantize_per_tensor_affine,eig,geqrf,lstsq,_lu_with_info,qr,solve,svd,symeig,triangular_solve,fractional_max_pool2d,fractional_max_pool3d,adaptive_max_pool3d,multilabel_margin_loss_forward,linalg_qr 、linalg_cholesky_ex、linalg_svd、linalg_eig、linalg_eigh、linalg_lstsq、linalg_inv_ex

Operaciones de CPU que se pueden impulsar al tipo de entrada más amplio

Estas operaciones no requieren un tipo de datos específico para la estabilidad, pero requieren múltiples entradas y requieren que los tipos de datos de las entradas coincidan. Si todas las entradas son bfloat16, la operación opera en bfloat16. Si alguna entrada es float32, autoconvert convierte todas las entradas a float32 y ejecuta la operación en float32.

gato, pila, index_copy

Algunas operaciones que no se enumeran aquí (por ejemplo, operaciones binarias como agregar) pueden promover la entrada por sí mismas sin la intervención de la conversión automática. Si la entrada es una combinación de bfloat16 y float32, estas operaciones operarán en float32 y producirán una salida de float32, ya sea que la conversión automática esté habilitada o no.

Complemento: Comprensión de inplace y out inplace (entender en el lugar para comprender)

inplace=True significa realizar la operación en el lugar y elegir realizar la operación de cobertura en el lugar. Por ejemplo, x+=1 es operar sobre el valor original x, y luego sobrescribir directamente el valor con el resultado obtenido. y=x+5, x=y no es una operación in situ sobre x.
La ventaja de la operación inplace=True es que puede ahorrar memoria informática y otras variables irrelevantes.
Nota: Cuando se usa inplace=True, el tensor transmitido desde la red superior se modificará directamente para cambiar los datos de entrada. El significado específico se muestra en el siguiente ejemplo:

import torch
import torch.nn as nn

relu = nn.ReLU(inplace=True)
input = torch.randn(7)

print("输入数据:",input)

output = relu(input)
print("ReLU输出:", output)

print("ReLU处理后,输入数据:")
print(input)

torch.autograd.gradLa función es una de las funciones utilizadas en PyTorch para calcular gradientes. Se utiliza para calcular el gradiente de una o más funciones escalares con respecto a un conjunto de variables.

La firma de la función es la siguiente:

mathematicaCopy code
torch.autograd.grad(outputs, inputs, grad_outputs=None, retain_graph=None, create_graph=False, only_inputs=True, allow_unused=False)

Descripción de parámetros:

  • outputs: Tensor o lista de tensores que contienen funciones escalares cuyos gradientes deben calcularse.
  • inputs: Tensor o lista de tensores de variables cuyos gradientes necesitan ser calculados.
  • grad_outputs: outputsTensor o lista de tensores con la misma forma, que se utiliza para especificar el gradiente exterior al calcular el gradiente. El valor predeterminado es Ninguno, lo que significa usar un gradiente de unidad (es decir, 1).
  • retain_graph: valor booleano, especifica si se debe mantener el gráfico de cálculo para cálculos posteriores después de calcular el gradiente. El valor predeterminado es Ninguno, lo que significa juzgar automáticamente si mantener el gráfico de cálculo.
  • create_graph: valor booleano, que especifica si se debe crear un nuevo gráfico de cálculo para calcular derivadas de orden superior. El valor predeterminado es falso.
  • only_inputs: booleano, especifica si solo se calcula el gradiente de la entrada. El valor predeterminado es Verdadero, lo que significa que solo se calcula el gradiente de la entrada.
  • allow_unused: booleano que especifica si se permiten entradas no utilizadas al calcular gradientes. El valor predeterminado es Falso, lo que significa que no se permite la entrada no utilizada.

La función devuelve un inputstensor o una lista de tensores con la misma forma que , que representa inputsel gradiente relativo a . Si no se requiere un gradiente para una entrada, el gradiente para la posición correspondiente será Ninguno.

Aquí hay un ejemplo de uso:

pythonCopy codeimport torch

x = torch.tensor([2.0], requires_grad=True)
y = x ** 2
grads = torch.autograd.grad(y, x)

print(grads)  # 输出 [tensor([4.])]

En el ejemplo anterior, calculamos el gradiente y = x ** 2con respecto a x, y torch.autograd.gradobtuvimos el resultado a través de la función. En este ejemplo, gradsun valor de 4,0 significa que el gradiente yrelativo xa es 4,0.

Supongo que te gusta

Origin blog.csdn.net/qq_43456016/article/details/132168036
Recomendado
Clasificación