调制信号识别系列 (一):基准模型

news2024/10/6 6:00:16

调制信号识别系列 (一):基准模型

说明:本文包含对CNN和CNN+LSTM基准模型的复现,模型架构参考下述两篇文章

文章目录

  • 调制信号识别系列 (一):基准模型
    • 一、论文
      • 1、DL-PR: Generalized automatic modulation classification method based on deep learning with priori regularization
      • 2、A Deep Learning Approach for Modulation Recognition via Exploiting Temporal Correlations
    • 二、流程
      • 1、数据加载
      • 2、训练测试
      • 3、可视化
    • 三、模型
      • 1、CNN
      • 2、CNN+LSTM(DL-PR)
      • 3、CNN+LSTM
    • 四、对比
      • 1、论文1
      • 2、论文2
    • 五、总结

一、论文

1、DL-PR: Generalized automatic modulation classification method based on deep learning with priori regularization

  • https://www.sciencedirect.com/science/article/pii/S095219762300266X

image-20240707105742936

image-20240706174502716

2、A Deep Learning Approach for Modulation Recognition via Exploiting Temporal Correlations

  • 2018 IEEE 19th International Workshop on Signal Processing Advances in Wireless Communications (SPAWC)

  • https://ieeexplore.ieee.org/abstract/document/8445938

image-20240707114714838

Note that before each convolutional layer, we use the zero-padding method to control the spatial size of the output volumes. Specifically, we pad the input volume with two zeros around the border, thus the output volume of the second convolutional layer is of size 32 × 132. We then take 32 as the dimensionality of the input and 132 as the time steps in LSTM layer. Dropout method is also used to prevent the neural network from overfitting. Compared to architecture in [12], we can see that we replace the third dense fully-connected layer with a LSTM layer. Our simulations suggest that this replacement not only reduces the number of parameters by an order of magnitude, but also leads to a significant performance improvement.

请注意,在每个卷积层之前,我们使用零填充方法来控制输出卷的空间大小。具体来说,我们在输入量的边界周围填充两个零,因此第二个卷积层的输出量的大小为 32 × 132。然后我们将 32 作为输入的维度,将 132 作为 LSTM 层的时间步长。 Dropout方法也用于防止神经网络过拟合。与[12]中的架构相比,我们可以看到我们用 LSTM 层替换了第三个密集全连接层。我们的模拟表明,这种替换不仅将参数数量减少了一个数量级,而且还带来了显着的性能改进。

二、流程

1、数据加载

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset, random_split
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay
from torchsummary import summary
# 加载数据
csv_file_path = 'snr_data/output_data_snr_6.csv'
data_frame = pd.read_csv(csv_file_path)

# 提取前256列数据并转换为张量
vectors = torch.tensor(data_frame.iloc[:, :256].values, dtype=torch.float32)

# 将256维向量转换为2x128的矩阵形式
vectors = vectors.view(-1, 2, 128)

# 划分训练集和测试集索引
train_size = int(0.8 * len(vectors))
test_size = len(vectors) - train_size
train_indices, test_indices = random_split(range(len(vectors)), [train_size, test_size])

# 使用训练集的统计量进行归一化
train_vectors = vectors[train_indices]

# 对IQ分量分别进行归一化
train_mean_I = train_vectors[:, 0, :].mean(dim=0, keepdim=True)
train_std_I = train_vectors[:, 0, :].std(dim=0, keepdim=True)

train_mean_Q = train_vectors[:, 1, :].mean(dim=0, keepdim=True)
train_std_Q = train_vectors[:, 1, :].std(dim=0, keepdim=True)

# 归一化整个数据集
vectors[:, 0, :] = (vectors[:, 0, :] - train_mean_I) / train_std_I
vectors[:, 1, :] = (vectors[:, 1, :] - train_mean_Q) / train_std_Q

# 提取Mod_Type列并转换为数值标签
mod_types = data_frame['Mod_Type'].astype('category').cat.codes.values
labels = torch.tensor(mod_types, dtype=torch.long)

# 创建TensorDataset
dataset = TensorDataset(vectors, labels)

# 创建训练集和测试集
train_dataset = TensorDataset(vectors[train_indices], labels[train_indices])
test_dataset = TensorDataset(vectors[test_indices], labels[test_indices])

# 创建DataLoader
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)
test_loader = DataLoader(test_dataset, batch_size=32, shuffle=False)
# 替换模型架构

2、训练测试

criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
num_epochs = 50
train_losses = []
test_losses = []
train_accuracies = []
test_accuracies = []

def calculate_accuracy(outputs, labels):
    _, predicted = torch.max(outputs, 1)
    total = labels.size(0)
    correct = (predicted == labels).sum().item()
    return correct / total

for epoch in range(num_epochs):
    # 训练阶段
    model.train()
    running_loss = 0.0
    correct = 0
    total = 0
    for inputs, labels in train_loader:
        inputs = inputs.to(device)
        labels = labels.to(device)
        optimizer.zero_grad()
        outputs = model(inputs)
        loss = criterion(outputs, labels)
        loss.backward()
        optimizer.step()
        running_loss += loss.item()
        correct += (outputs.argmax(1) == labels).sum().item()
        total += labels.size(0)
    train_loss = running_loss / len(train_loader)
    train_accuracy = correct / total
    train_losses.append(train_loss)
    train_accuracies.append(train_accuracy)
    
    # 测试阶段
    model.eval()
    running_loss = 0.0
    correct = 0
    total = 0
    with torch.no_grad():
        for inputs, labels in test_loader:
            inputs = inputs.to(device)
            labels = labels.to(device)
            outputs = model(inputs)
            loss = criterion(outputs, labels)
            running_loss += loss.item()
            correct += (outputs.argmax(1) == labels).sum().item()
            total += labels.size(0)
    test_loss = running_loss / len(test_loader)
    test_accuracy = correct / total
    test_losses.append(test_loss)
    test_accuracies.append(test_accuracy)
    
    print(f"Epoch [{epoch+1}/{num_epochs}], Train Loss: {train_loss:.4f}, Train Accuracy: {train_accuracy:.4f}, Test Loss: {test_loss:.4f}, Test Accuracy: {test_accuracy:.4f}")

print("Training complete.")

3、可视化

epochs = range(1, num_epochs + 1)

plt.figure(figsize=(12, 5))

# 绘制损失图像
plt.subplot(1, 2, 1)
plt.plot(epochs, train_losses, label='Train Loss')
plt.plot(epochs, test_losses, label='Test Loss')
plt.xlabel('Epoch')
plt.ylabel('Loss')
plt.legend()
plt.title('Loss vs. Epochs')

# 绘制准确率图像
plt.subplot(1, 2, 2)
plt.plot(epochs, train_accuracies, label='Train Accuracy')
plt.plot(epochs, test_accuracies, label='Test Accuracy')
plt.xlabel('Epoch')
plt.ylabel('Accuracy')
plt.legend()
plt.title('Accuracy vs. Epochs')

plt.show()

三、模型

说明:下述模型均在SNR=6dB RadioML2016.10a数据集下的实验结果,仅使用原始的IQ分量信息,未使用数据增强,也未进行调参

1、CNN

class CNNModel(nn.Module):
    def __init__(self):
        super(CNNModel, self).__init__()
        self.conv1 = nn.Conv2d(1, 64, (1, 4), stride=1)
        self.conv2 = nn.Conv2d(64, 64, (1, 2), stride=1)
        self.pool1 = nn.MaxPool2d((1, 2))
        self.conv3 = nn.Conv2d(64, 128, (1, 2), stride=1)
        self.conv4 = nn.Conv2d(128, 128, (2, 2), stride=1)
        self.pool2 = nn.MaxPool2d((1, 2))
        self.conv5 = nn.Conv2d(128, 256, (1, 2), stride=1)
        self.conv6 = nn.Conv2d(256, 256, (1, 2), stride=1)
        self.fc1 = nn.Linear(256 * 1 * 28, 512)
        self.fc2 = nn.Linear(512, 128)
        self.fc3 = nn.Linear(128, 11)

    def forward(self, x):
        x = x.unsqueeze(1)  # 添加通道维度
        x = torch.relu(self.conv1(x))
        x = torch.relu(self.conv2(x))
        x = self.pool1(x)
        x = torch.relu(self.conv3(x))
        x = torch.relu(self.conv4(x))
        x = self.pool2(x)
        x = torch.relu(self.conv5(x))
        x = torch.relu(self.conv6(x))
        x = x.view(x.size(0), -1)
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x

model = CNNModel()
summary(model, (2, 128))

image-20240707115545394

----------------------------------------------------------------
        Layer (type)               Output Shape         Param #
================================================================
            Conv2d-1           [-1, 64, 2, 125]             320
            Conv2d-2           [-1, 64, 2, 124]           8,256
         MaxPool2d-3            [-1, 64, 2, 62]               0
            Conv2d-4           [-1, 128, 2, 61]          16,512
            Conv2d-5           [-1, 128, 1, 60]          65,664
         MaxPool2d-6           [-1, 128, 1, 30]               0
            Conv2d-7           [-1, 256, 1, 29]          65,792
            Conv2d-8           [-1, 256, 1, 28]         131,328
            Linear-9                  [-1, 512]       3,670,528
           Linear-10                  [-1, 128]          65,664
           Linear-11                   [-1, 11]           1,419
================================================================
Total params: 4,025,483
Trainable params: 4,025,483
Non-trainable params: 0
----------------------------------------------------------------
Input size (MB): 0.00
Forward/backward pass size (MB): 0.63
Params size (MB): 15.36
Estimated Total Size (MB): 15.98

image-20240707115320324

image-20240707115331410

2、CNN+LSTM(DL-PR)

import torch
import torch.nn as nn

class CNNLSTMModel(nn.Module):
    def __init__(self):
        super(CNNLSTMModel, self).__init__()
        self.conv1 = nn.Conv2d(1, 32, (2, 3), stride=1, padding=(0,1))  # Adjusted input channels and filters
        self.conv2 = nn.Conv2d(32, 32, (1, 3), stride=1, padding=(0,1))
        self.pool1 = nn.MaxPool2d((1, 2))
        self.conv3 = nn.Conv2d(32, 64, (1, 3), stride=1, padding=(0,1))
        self.conv4 = nn.Conv2d(64, 64, (1, 3), stride=1, padding=(0,1))
        self.pool2 = nn.MaxPool2d((1, 2))
        self.conv5 = nn.Conv2d(64, 128, (1, 3), stride=1, padding=(0,1))
        self.conv6 = nn.Conv2d(128, 128, (1, 3), stride=1, padding=(0,1))
        self.pool3 = nn.MaxPool2d((1, 2))

        self.lstm = nn.LSTM(128, 32, batch_first=True)  # Adjusted input size and LSTM hidden size
        self.fc1 = nn.Linear(32, 128)
        self.fc2 = nn.Linear(128, 11)

    def forward(self, x):
        #print("x:",x.shape)
        if x.dim() == 3:
            x = x.unsqueeze(1)  # 假设x的形状是[2, 128], 这将改变它为[1, 2, 128]
        #print("x.unsqueeze(0):",x.shape)
        x = torch.relu(self.conv1(x))
        x = torch.relu(self.conv2(x))
        x = self.pool1(x)
        x = torch.relu(self.conv3(x))
        x = torch.relu(self.conv4(x))
        x = self.pool2(x)
        x = torch.relu(self.conv5(x))
        x = torch.relu(self.conv6(x))
        x = self.pool3(x)

        # Prepare input for LSTM
        x = x.view(x.size(0), 16, 128)  # Adjusted view
        #print(x.shape)
        x, (hn, cn) = self.lstm(x)
        x = x[:, -1, :]  # Get the last output of the LSTM

        x = torch.relu(self.fc1(x))
        x = self.fc2(x)
        return x

model = CNNLSTMModel()
summary(model,input_size=(1, 2, 128))

image-20240707115501540

==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
CNNLSTMModel                             [1, 11]                   --
├─Conv2d: 1-1                            [1, 32, 1, 128]           224
├─Conv2d: 1-2                            [1, 32, 1, 128]           3,104
├─MaxPool2d: 1-3                         [1, 32, 1, 64]            --
├─Conv2d: 1-4                            [1, 64, 1, 64]            6,208
├─Conv2d: 1-5                            [1, 64, 1, 64]            12,352
├─MaxPool2d: 1-6                         [1, 64, 1, 32]            --
├─Conv2d: 1-7                            [1, 128, 1, 32]           24,704
├─Conv2d: 1-8                            [1, 128, 1, 32]           49,280
├─MaxPool2d: 1-9                         [1, 128, 1, 16]           --
├─LSTM: 1-10                             [1, 16, 32]               20,736
├─Linear: 1-11                           [1, 128]                  4,224
├─Linear: 1-12                           [1, 11]                   1,419
==========================================================================================
Total params: 122,251
Trainable params: 122,251
Non-trainable params: 0
Total mult-adds (M): 4.32
==========================================================================================
Input size (MB): 0.00
Forward/backward pass size (MB): 0.20
Params size (MB): 0.49
Estimated Total Size (MB): 0.69
==========================================================================================

image-20240707115432051

image-20240707115443808

3、CNN+LSTM

# 定义结合CNN和LSTM的模型
class CNNLSTMModel(nn.Module):
    def __init__(self):
        super(CNNLSTMModel, self).__init__()
        self.conv1 = nn.Conv2d(1, 64, (1, 4), stride=1)
        self.conv2 = nn.Conv2d(64, 64, (1, 2), stride=1)
        self.pool1 = nn.MaxPool2d((1, 2))
        self.conv3 = nn.Conv2d(64, 128, (1, 2), stride=1)
        self.conv4 = nn.Conv2d(128, 128, (2, 2), stride=1)
        self.pool2 = nn.MaxPool2d((1, 2))
        self.conv5 = nn.Conv2d(128, 256, (1, 2), stride=1)
        self.conv6 = nn.Conv2d(256, 256, (1, 2), stride=1)

        self.lstm = nn.LSTM(256, 128, batch_first=True)

        self.fc1 = nn.Linear(128, 512)
        self.fc2 = nn.Linear(512, 128)
        self.fc3 = nn.Linear(128, 11)

    def forward(self, x):
        x = x.unsqueeze(1)  # 添加通道维度
        x = torch.relu(self.conv1(x))
        x = torch.relu(self.conv2(x))
        x = self.pool1(x)
        x = torch.relu(self.conv3(x))
        x = torch.relu(self.conv4(x))
        x = self.pool2(x)
        x = torch.relu(self.conv5(x))
        x = torch.relu(self.conv6(x))

        # 重新调整x的形状以适应LSTM
        x = x.squeeze(2).permute(0, 2, 1)  # 变为(batch_size, 128, 256)

        # 通过LSTM
        x, _ = self.lstm(x)

        # 取最后一个时间步的输出
        x = x[:, -1, :]

        # 全连接层
        x = torch.relu(self.fc1(x))
        x = torch.relu(self.fc2(x))
        x = self.fc3(x)
        return x
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')
model = CNNLSTMModel().to(device)
summary(model,input_size=(1, 2, 128))

image-20240707115530202

==========================================================================================
Layer (type:depth-idx)                   Output Shape              Param #
==========================================================================================
CNNLSTMModel                             [1, 11]                   --
├─Conv2d: 1-1                            [1, 64, 2, 125]           320
├─Conv2d: 1-2                            [1, 64, 2, 124]           8,256
├─MaxPool2d: 1-3                         [1, 64, 2, 62]            --
├─Conv2d: 1-4                            [1, 128, 2, 61]           16,512
├─Conv2d: 1-5                            [1, 128, 1, 60]           65,664
├─MaxPool2d: 1-6                         [1, 128, 1, 30]           --
├─Conv2d: 1-7                            [1, 256, 1, 29]           65,792
├─Conv2d: 1-8                            [1, 256, 1, 28]           131,328
├─LSTM: 1-9                              [1, 28, 128]              197,632
├─Linear: 1-10                           [1, 512]                  66,048
├─Linear: 1-11                           [1, 128]                  65,664
├─Linear: 1-12                           [1, 11]                   1,419
==========================================================================================
Total params: 618,635
Trainable params: 618,635
Non-trainable params: 0
Total mult-adds (M): 19.33
==========================================================================================
Input size (MB): 0.00
Forward/backward pass size (MB): 0.59
Params size (MB): 2.47
Estimated Total Size (MB): 3.07
==========================================================================================

image-20240707115355065

image-20240707115406360

四、对比

1、论文1

image-20240707120612759

image-20240707120737565

本文的实验结果和论文1的结果比较类似,即使without priori regularization

2、论文2

image-20240707120151123

image-20240707120316218

五、总结

  • 对于RadioML2016.10a数据集来说,在信噪比不是特别低的情况下,使用CNN就表现的不错,在SNR=6dB可达91.82%,但是这里有个小技巧,在卷积过程中,先单独对IQ分量进行卷积,在convolution 4进行联合处理,一开始就使用2x2的卷积核效果较差。

image-20240707121309134

  • 实验结果表明,CNN+LSTM 优于 CNN,但涨幅不多

image-20240707121937158

image-20240707121959303

  • 完整的代码和数据集在GIthub:https://github.com/daetz-coder/RadioML2016.10a_Benchmark,为了方便使用,IQ分量保存在csv中,且仅提供了SNR=6dB的数据,如果需要更多类型的数据,请参考https://blog.csdn.net/a_student_2020/article/details/139800725

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1903561.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

android之蓝牙遥控器新增键值

文章目录 简述连接蓝牙代码流程总结简述 使用android 10平台来适配蓝牙遥控器新增的键值 连接蓝牙 当使用遥控器与蓝牙进行配对成功后,就可以通过getevent获取蓝牙打印的信息,如下所示 其中000700a0是发送过来的协议(0007)和码值(00a0)的组合。0xfa是驱动定义好的值,如果…

100359.统计X和Y频数相等的子矩阵数量

1.题目描述 给你一个二维字符矩阵 grid,其中 grid[i][j] 可能是 X、Y 或 .,返回满足以下条件的子矩阵数量: 包含 grid[0][0]X 和 Y 的频数相等。至少包含一个 X。 示例 1: 输入: grid [["X","Y",…

suricata7 rule加载(二)加载header

suricata7.0.5 alert http any any -> [192.168.1.27,1.192.137.27] 80 (msg:“HTTP Request Example”; flow:established,to_server; http.method; content:“POST”; http.uri; content:“query.php”; bsize:>9; http.protocol; content:“HTTP/1.1”; bsize:8; http…

Google Java Style Guide深度解读:打造优雅的代码艺术

在软件工程的世界里,代码不仅仅是实现功能的工具,它也是团队之间沟通的桥梁,是软件质量和可维护性的直接反映。Google Java Style Guide作为一套广受认可的编码规范,不仅定义了代码的书写规则,更深刻地影响着Java开发者…

Polar Si9000软件详细使用教程

Polar Si9000软件是一款简单易用的阻抗计算神器,文本详细介绍该软件的使用。 一、安装 网上很多安装包,这里不赘述,需要注意的是,如果要希望使用中文版,需要在如下路径中放入简体中文配置文件(PJ包一般会有…

Idea新增Module报错:sdk ‘1.8‘ type ‘JavaSDK‘ is not registered in ProjectJdkTable

文章目录 一,创建Module报错二,原因分析三,解决方案1,点击上图的加号,把JDK8添加进来即可2,点击左侧[Project],直接设置SDK为JDK8 四,配置检查与验证 一,创建Module报错 …

Redis基础教程(十四):Redis连接

💝💝💝首先,欢迎各位来到我的博客,很高兴能够在这里和您见面!希望您在这里不仅可以有所收获,同时也能感受到一份轻松欢乐的氛围,祝你生活愉快! 💝&#x1f49…

手机日记本小程序模板源码

简洁的个人日记,博客记录,写日记手机小程序页面模板。包含:日记主页、通知、我的主页、写日记、登录、注册等等。 手机日记本小程序模板源码

css样式学习样例之边框

成品效果 边框固定 .login_box{width: 450px;height: 300px;background-color: aliceblue;border-radius: 3px;position: absolute;left: 50%;top: 50%;transform: translate(-50%,-50%); }这段CSS代码定义了一个名为.login_box的类的样式,它主要用于创建一个登录框…

分类模型、回归模型的常见评价指标

文章目录 分类模型的评价指标1. Recallk公式举例代码 2. Precisionk公式举例代码 3. F1k公式代码 4.[其它常见的分类模型评价指标](https://blog.csdn.net/LiuRuiaby35646/article/details/136711918) 回归模型的评价指标1.均方误差(Mean Square Error)公…

柳叶刀:5Kg负重巡飞无人机技术详解

一、引言 随着无人机技术的不断发展,巡飞无人机在军事侦察、环境监测、边境巡逻等领域的应用日益广泛。其中,“柳叶刀”作为一款5Kg负重巡飞无人机,凭借其独特的机体结构、高效的动力系统、先进的飞行控制系统等技术优势,在众多无…

多粒度封锁-封锁粒度、多粒度封锁模式

一、引言 1、若采用封锁技术实现并发控制,事务在访问数据库对象前要在数据库对象上加锁,为提高事务的并发程度,商用DBMS会采用一种多粒度封锁方法 2、事务可访问的数据库对象可以是逻辑单元,包括关系、关系中的元组、关系的属性…

SAP_MM模块-采购信息记录变更文档的三种查询方式

最近有用户在问采购信息记录变更的信息怎么去查找,想要看看是谁更改了价格,于是就给她查了一下,顺便做个记录,SAP中的业务数据或者主数据的变更信息查询方法,都是比较类似的,学会了这三个方法,其…

STM32介绍

本内容是基于江协科技STM32视频学习之后,并参考【重写】简析stm32启动过程-CSDN博客和STM32 最小系统_stm32最小系统-CSDN博客以及其他资料综合整理而成。 1. STM32 1.1 STM32简介 STM32是ST公司基于ARM Cortex-M内核开发的32位微控制器;STM32常应用在…

TCP一定可靠吗

背景 公司某个服务发送TCP报文后,得到的响应是非预期数据 原因竟然是:TCP包的 payload 数据某个bit位被翻转,但是 checksum 的值一样,错误的包被分发给了上层服务 Checksum介绍 IP 头有自己的 Checksum,TCP、UDP 也有自己的 Checksum,分别校验不同部分的数据 IP 头的 …

【Linux系统】动态库和静态库 动态库加载

认识动态库静态库 我们有没有使用过库呢?-- 用过c、c的标准库 c的各种函数,c的各种STL容器,我们使用他们内部必须得有具体实现。 Linux: .so(动态库) .a(静态库) Windows: .dll(动态库) .lib(静态库) 库是拿来给别人使用的,所…

Spring源码十六:Bean名称转化

在上一篇Spring源码十五:Bean的加载 中我们通过前面的案例方法,找到了Spring真正开始创建Bean的入口,也就是doGetBean方法。该方法是Spring框架中Bean创建与获取的核心逻辑,实现了复杂的Bean生命周期管理。通过单例缓存、合并Bean…

文章解读与仿真程序复现思路——太阳能学报EI\CSCD\北大核心《计及电-热-氢负荷与动态重构的主动配电网优化调度》

本专栏栏目提供文章与程序复现思路,具体已有的论文与论文源程序可翻阅本博主免费的专栏栏目《论文与完整程序》 论文与完整源程序_电网论文源程序的博客-CSDN博客https://blog.csdn.net/liang674027206/category_12531414.html 电网论文源程序-CSDN博客电网论文源…

【双一流高校主办,Springer-LNICST出版,EI稳定检索】2024年应用计算智能、信息学与大数据国际会议(ACIIBD 2024,7月26-28)

2024年应用计算智能、信息学与大数据国际学术会议(ACIIBD 2024)将于2024年7月26-28日在中国广州举办。会议将聚焦于计算智能及其应用、信息、大数据等相关的研究领域, 广泛邀请国内外知名专家学者,共同探讨相关学科领域的最新发展…

Maya崩溃闪退常见原因及解决方案

Autodesk Maya 是一款功能强大的 3D 计算机图形程序,被电影、游戏和建筑等各个领域的设计师广泛使用。然而,Maya 就像任何其他软件一样可能会发生崩溃问题。在前文中,小编给大家介绍了3ds Max使用V-Ray渲染时的崩溃闪退解决方案: …