解决“可移动媒体不支持此操作”问题 (Solve The operation is not supported on removable media)

本文介绍了解决DISKPART中遇到的虚拟磁盘服务错误:可移动媒体不支持此操作的问题。通过设置分区ID和分配盘符,成功解决了EFI分区的分配问题,并提供了管理员权限下访问受限文件的方法。

DISKPART> assign letter=z
虚拟磁盘服务错误:
可移动媒体不支持此操作。

通过如下命令成功解决:
set id=“ebd0a0a2-b9e5-4433-87c0-68b6b72699c7” # 设置为基本数据分区
assign letter=X # x为EFI分区盘符
exit # 退出diskpart

PS:如遇提示无权访问,要用管理员权限启动一个7-zip软件,在软件里面就可以访问了
参考资料:
黑果小兵 macOS Mojave 10.14 18A389 with Clover 4670原版镜像

<think>我们之前已经处理过类似问题,但这次是opset version 12。在ONNX opset 12中,`aten::linalg_inv`仍然不被支持。实际上,直到opset 16才添加了对`linalg_inv`的直接支持。因此,我们需要使用其他方法。 解决方案: 1. 升级opset版本到16(如果环境允许)。 2. 如果必须使用opset 12,则使用其他操作组合来实现矩阵求逆(例如通过LU分解求解,或者使用Solve操作)。 这里我们提供两种方法: 方法一:升级opset版本到16(推荐) 方法二:使用组合操作(适用于opset 12) 我们详细说明方法二:使用组合操作(通过求解线性方程组的方式) 原理:求矩阵A的逆矩阵,相当于求解A * X = I,其中I是单位矩阵,X就是A的逆矩阵。 在ONNX opset 12中,我们可以使用`Solve`操作符。但是,在PyTorch中,我们可能需要通过其他函数来实现,因为`torch.solve`在ONNX导出时可能会被映射为`Solve`。 步骤: - 创建一个与A相同行数的单位矩阵I。 - 使用`torch.linalg.solve`求解X,使得A*X=I。 注意:在PyTorch 1.9及以上版本中,推荐使用`torch.linalg.solve`。在旧版本中,可以使用`torch.solve`。 代码示例: 我们创建一个模型,该模型使用`torch.linalg.solve`来实现矩阵求逆。 注意:在导出ONNX时,`torch.linalg.solve`会被转换为ONNX的`Solve`操作符,该操作符在opset 12中可用。 具体实现如下:</think># 解决 `Exporting the operator 'aten::linalg_inv' to ONNX opset version 12 is not supported.` 错误 当尝试将包含 `torch.linalg.inv()` 操作的 PyTorch 模型导出到 ONNX opset 12 时,您会遇到这个错误。这是因为在 ONNX opset 12 中,`linalg_inv` 操作符尚未被支持。下面我将提供完整的解决方案,包括多种兼容 opset 12 的方法。 ## 问题分析 矩阵求逆操作 (`torch.linalg.inv`): - 在 ONNX opset 12 中不被支持 - 从 opset 16 开始才被原生支持 - 需要兼容 opset 12 的替代实现 ## 解决方案 ### 方法 1: 使用 LU 分解实现矩阵求逆(推荐) 这是最可靠的兼容 opset 12 的方法: ```python import torch import torch.onnx class LUInverseModel(torch.nn.Module): def forward(self, x): # 1. 进行LU分解 lu, pivots = torch.linalg.lu_factor(x) # 2. 创建单位矩阵 identity = torch.eye(x.size(-1), dtype=x.dtype, device=x.device) # 3. 使用LU分解结果求解逆矩阵 return torch.linalg.lu_solve(lu, pivots, identity) # 创建模型实例 model = LUInverseModel() input_tensor = torch.randn(3, 3, dtype=torch.float32) # 导出模型到ONNX,使用opset版本12 torch.onnx.export( model, input_tensor, "lu_inverse_model.onnx", opset_version=12, input_names=['input'], output_names=['output'], dynamic_axes={ 'input': {0: 'dim0', 1: 'dim1'}, # 支持动态尺寸 'output': {0: 'dim0', 1: 'dim1'} } ) ``` **解释**: 1. `torch.linalg.lu_factor`:执行 LU 分解(ONNX opset 12 支持) 2. `torch.eye`:创建单位矩阵 3. `torch.linalg.lu_solve`:使用 LU 分解求解线性系统(ONNX opset 12 支持) ### 方法 2: 使用自定义符号函数(高级方法) 注册自定义符号函数将 `linalg_inv` 映射到 ONNX 的 `Solve` 操作: ```python import torch import torch.onnx from torch.onnx import symbolic_helper # 自定义符号函数 def linalg_inv_symbolic(g, self): # 1. 创建单位矩阵 identity = g.op("Constant", value_t=torch.eye(self.type().sizes()[-1]).to(self.type().dtype())) # 2. 使用Solve操作实现逆矩阵 return g.op("Solve", self, identity) # 注册自定义符号函数 torch.onnx.register_custom_op_symbolic( 'aten::linalg_inv', linalg_inv_symbolic, opset_version=12 ) # 使用自定义函数导出模型 class SimpleInverseModel(torch.nn.Module): def forward(self, x): return torch.linalg.inv(x) model = SimpleInverseModel() torch.onnx.export( model, input_tensor, "custom_inverse_model.onnx", opset_version=12, input_names=['input'], output_names=['output'], dynamic_axes={ 'input': {0: 'dim0', 1: 'dim1'}, 'output': {0: 'dim0', 1: 'dim1'} } ) ``` ### 方法 3: 使用 QR 分解实现矩阵求逆 另一种数学上等价的方法: ```python class QRInverseModel(torch.nn.Module): def forward(self, x): # 1. 进行QR分解 Q, R = torch.linalg.qr(x) # 2. 计算R的逆(上三角矩阵) R_inv = torch.inverse(R) # 3. 计算原始矩阵的逆 return R_inv @ Q.T # 创建模型实例 model = QRInverseModel() input_tensor = torch.randn(3, 3, dtype=torch.float32) # 导出模型 torch.onnx.export( model, input_tensor, "qr_inverse_model.onnx", opset_version=12, input_names=['input'], output_names=['output'], dynamic_axes={ 'input': {0: 'dim0', 1: 'dim1'}, 'output': {0: 'dim0', 1: 'dim1'} } ) ``` ### 方法 4: 使用 SVD 实现矩阵求逆 更稳定的数值方法,特别适合病态矩阵: ```python class SVDInverseModel(torch.nn.Module): def forward(self, x): # 1. 进行SVD分解 U, S, Vh = torch.linalg.svd(x) # 2. 计算S的倒数(伪逆处理奇异值) S_inv = torch.diag(1.0 / S) # 3. 计算逆矩阵 return Vh.T @ S_inv @ U.T # 创建模型实例 model = SVDInverseModel() input_tensor = torch.randn(3, 3, dtype=torch.float32) # 导出模型 torch.onnx.export( model, input_tensor, "svd_inverse_model.onnx", opset_version=12, input_names=['input'], output_names=['output'], dynamic_axes={ 'input': {0: 'dim0', 1: 'dim1'}, 'output': {0: 'dim0', 1: 'dim1'} } ) ``` ## 验证导出模型 使用 ONNX Runtime 验证导出的模型: ```python import onnxruntime as ort import numpy as np # 创建测试输入 input_data = np.random.randn(3, 3).astype(np.float32) # 加载ONNX模型 ort_session = ort.InferenceSession("lu_inverse_model.onnx") # 运行推理 ort_inputs = {ort_session.get_inputs()[0].name: input_data} ort_outs = ort_session.run(None, ort_inputs) # 使用PyTorch计算参考结果 torch_inv = torch.linalg.inv(torch.tensor(input_data)) # 比较结果 print("ONNX输出:\n", ort_outs[0]) print("PyTorch输出:\n", torch_inv.numpy()) print("最大差异:", np.max(np.abs(ort_outs[0] - torch_inv.numpy()))) ``` ## 处理特殊情况 ### 1. 批量矩阵求逆 ```python class BatchInverseModel(torch.nn.Module): def forward(self, x): # x的形状: [batch_size, n, n] results = [] for i in range(x.size(0)): # 对每个矩阵单独求逆 matrix = x[i] lu, pivots = torch.linalg.lu_factor(matrix) identity = torch.eye(matrix.size(-1), dtype=matrix.dtype, device=matrix.device) inv_matrix = torch.linalg.lu_solve(lu, pivots, identity) results.append(inv_matrix) return torch.stack(results) # 导出时设置动态轴 dynamic_axes = { 'input': {0: 'batch_size', 1: 'dim0', 2: 'dim1'}, 'output': {0: 'batch_size', 1: 'dim0', 2: 'dim1'} } ``` ### 2. 奇异矩阵处理 ```python class SafeInverseModel(torch.nn.Module): def forward(self, x): # 计算行列式 det = torch.det(x) # 添加小扰动避免奇异矩阵 epsilon = 1e-6 safe_x = x + epsilon * torch.eye(x.size(-1), device=x.device) # 使用LU分解求逆 lu, pivots = torch.linalg.lu_factor(safe_x) identity = torch.eye(x.size(-1), dtype=x.dtype, device=x.device) return torch.linalg.lu_solve(lu, pivots, identity) ``` ## 性能优化技巧 ### 1. 使用半精度浮点数 ```python # 创建半精度输入 input_tensor = torch.randn(3, 3, dtype=torch.float16) # 导出时指定类型 torch.onnx.export( model, input_tensor, "half_precision_model.onnx", opset_version=12, input_names=['input'], output_names=['output'], dynamic_axes=dynamic_axes, # 指定输入输出类型 custom_opsets={'' : 12}, example_outputs=model(input_tensor) ) ``` ### 2. 启用常量折叠 ```python torch.onnx.export( model, input_tensor, "optimized_model.onnx", opset_version=12, do_constant_folding=True, # 启用常量折叠 input_names=['input'], output_names=['output'], dynamic_axes=dynamic_axes ) ``` ### 3. 使用算子融合 ```python class FusedInverseModel(torch.nn.Module): def forward(self, x): # 直接在模型中进行后续计算 inv_x = self.safe_inverse(x) return inv_x @ x # 示例:计算单位矩阵 def safe_inverse(self, x): lu, pivots = torch.linalg.lu_factor(x) identity = torch.eye(x.size(-1), dtype=x.dtype, device=x.device) return torch.linalg.lu_solve(lu, pivots, identity) ``` ## 最佳实践总结 1. **选择合适的方法**: - 对于小矩阵:使用 LU 分解方法 - 对于病态矩阵:使用 SVD 方法 - 对于批量处理:使用循环或矢量化实现 2. **版本兼容性检查**: ```python # 检查PyTorch版本 print(torch.__version__) # 检查ONNX opset支持 print(torch.onnx.symbolic_helper._default_onnx_opset_version) ``` 3. **模型验证**: ```python import onnx # 加载模型 model = onnx.load("lu_inverse_model.onnx") # 检查模型有效性 onnx.checker.check_model(model) # 打印模型信息 print(f"ONNX opset版本: {model.opset_import[0].version}") print(f"输入形状: {model.graph.input[0].type.tensor_type.shape}") print(f"输出形状: {model.graph.output[0].type.tensor_type.shape}") ``` 4. **处理不同尺寸**: ```python # 支持任意尺寸的方阵 dynamic_axes = { 'input': {0: 'dim0', 1: 'dim1'}, 'output': {0: 'dim0', 1: 'dim1'} } # 测试不同尺寸 for size in [2, 3, 4, 5]: test_input = torch.randn(size, size) with torch.no_grad(): output = model(test_input) print(f"{size}x{size} 矩阵求逆验证通过") ```
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值