基于深度学习的自动调制识别技术(pytorch)

本科做的科研项目是基于深度学习的自动调制识别技术,在接触深度学习时,在数据处理、性能分析方面遇到了许多问题,此博客用于记录。

数据处理

import torch  # 导入PyTorch库
import pickle  # 导入pickle库
import pandas as pd
import matplotlib.pyplot as plt
import numpy as np
import torch.optim as optim
import numpy as np
import torch.optim as optim
import torch.nn as nn
import torch.nn.functional as F
import torch, gc
import random
import matplotlib.pyplot as plt
from torch.utils.data import DataLoader, TensorDataset
from torchvision.utils import save_image
from torch.utils.data import Dataset
gc.collect()
torch.cuda.empty_cache()




def to_onehot(yy):
    yy1 = np.zeros([len(yy), max(yy) + 1])
    yy1[np.arange(len(yy)), yy] = 1
    return yy1



def setup_seed(seed):
    torch.manual_seed(seed)
    torch.cuda.manual_seed_all(seed)
    np.random.seed(seed)
    random.seed(seed)
    torch.backends.cudnn.deterministic = True
# 设置随机数种子
setup_seed(624)

def to_onehot(yy):
    yy1 = np.zeros([len(yy), max(yy) + 1])
    yy1[np.arange(len(yy)), yy] = 1
    return yy1

Xd = pickle.load(open("RML2016.10a_dict.pkl", 'rb'), encoding='latin')
snrs, mods = map(lambda j: sorted(list(set(map(lambda x: x[j], Xd.keys())))), [1, 0])
X = []
lbl = []
for mod in mods:
    for snr in snrs:
        X.append(Xd[(mod, snr)])
        for i in range(Xd[(mod, snr)].shape[0]):
            lbl.append((mod, snr))

X = np.vstack(X)

# 计算各部分数据集的比例
train_ratio = 0.4
val_ratio = 0.3
test_ratio = 0.3
# 设置随机种子

n_examples = X.shape[0]
n_train = int(n_examples * train_ratio)
n_val = int(n_examples * val_ratio)
n_test = n_examples - n_train - n_val

# 创建随机索引
idx = np.random.permutation(n_examples)

train_idx = idx[:n_train]
val_idx = idx[n_train:n_train+n_val]
test_idx = idx[n_train+n_val:]

# 划分数据集
X_train = X[train_idx]
X_val = X[val_idx]
X_test = X[test_idx]
print(X_train.shape)

trainy = list(map(lambda x: mods.index(lbl[x][0]), train_idx))
Y_train = torch.tensor(trainy)


valy = list(map(lambda x: mods.index(lbl[x][0]), val_idx))
valy = torch.tensor(valy)

testy = list(map(lambda x: mods.index(lbl[x][0]), test_idx))
testy = torch.tensor(testy)
X_train = torch.tensor(X[train_idx]).view(len(train_idx),1,2,128)
X_val = torch.tensor(X[val_idx]).view(len(val_idx),1,2,128)
X_test = torch.tensor(X[test_idx]).view(len(test_idx),1,2,128)
# 将维度从[𝑁,2,128]调整为[𝑁,1,2,128]
print(X_train.shape,Y_train.shape)
#数据归一化
print(testy[1024])

 将IQ数据归一化

切记,数据喂入网络前一定要进行归一化,刚开始学习时发现未对数据归一化,数据的分布差异较大,因此网络无法学习。

# 获得A/P特征
def toAP(iqdata):
    data = iqdata
    data = torch.sqrt(iqdata[:,:,0,:]**2+iqdata[:,:,1,:]**2)
    phase = torch.atan(iqdata[:,:,1,:]/iqdata[:,:,0,:])
    #增加一个维度
    data = data.unsqueeze(2)
    phase = phase.unsqueeze(2)
    #print(data.shape,phase.shape)
    return data,phase





train_data,train_phase = toAP(X_train)
val_data,val_phase = toAP(X_val)
test_data,test_phase=toAP(X_test)

#得到(batch_size,1,2,128维度)
train_ap = torch.cat((train_data,train_phase),2)
val_ap = torch.cat((val_data,val_phase),2)
test_ap = torch.cat((test_data,test_phase),2)


train_data = train_data.view(train_data.size(0),-1)
train_phase  = train_phase .view(train_phase .size(0),-1)
val_data = val_data.view(val_data.size(0),-1)
val_phase  = val_phase .view(val_phase .size(0),-1)
test_data = test_data.view(test_data.size(0),-1)
test_phase  = test_phase .view(test_phase .size(0),-1)

X_train = F.normalize(X_train,p=2, dim=3)
X_val = F.normalize(X_val,p=2, dim=3)
X_test = F.normalize(X_test,p=2,dim=3)


train_ap = F.normalize(train_ap,p=2, dim=3)
val_ap = F.normalize(val_ap,p=2, dim=3)
test_ap = F.normalize(test_ap,p=2,dim=3)
print(train_ap[0:1,...],train_data.shape)

自定义数据集

class CustomDataset(Dataset):
    def __init__(self,iq_data, labels):
        self.iq_data = iq_data
        self.labels = labels

    def __len__(self):
        return len(self.labels)

    def __getitem__(self, index):
        iq = self.iq_data[index]
        label = self.labels[index]
        return iq, label
num_classes=11
batch_size = 200

train_tuples = list(zip( [X_train1.clone().detach() for X_train1 in X_train],  [Y_train_tensor.clone().detach() for Y_train_tensor in Y_train]))
val_tuples = list(zip( [X_val1.clone().detach() for X_val1 in X_val],  [valy_tensor.clone().detach() for valy_tensor in valy]))
test_tuples = list(zip( [X_test1.clone().detach() for X_test1 in X_test],  [testy_tensor.clone().detach() for testy_tensor in Y_test]))

#train_tuples = list(zip([P_tensor.clone().detach() for P_tensor in P_tensor_list],  [X_train1.clone().detach() for X_train1 in X_train],  [Y_train_tensor.clone().detach() for Y_train_tensor in Y_train]))
#val_tuples = list(zip([Pv_tensor.clone().detach() for Pv_tensor in Pv_tensor_list],  [X_val1.clone().detach() for X_val1 in X_val],  [valy_tensor.clone().detach() for valy_tensor in valy]))
#test_tuples = list(zip([Pt_tensor.clone().detach() for Pt_tensor in Pt_tensor_list],  [X_test1.clone().detach() for X_test1 in X_test],  [testy_tensor.clone().detach() for testy_tensor in testy]))

train_dataset = CustomDataset(*[torch.stack(tensors) for tensors in zip(*train_tuples)])
train_loader = DataLoader(train_dataset, shuffle=True, batch_size=batch_size, drop_last=True)

val_dataset = CustomDataset(*[torch.stack(tensors) for tensors in zip(*val_tuples)])
val_loader = DataLoader(val_dataset, shuffle=False, batch_size=batch_size, drop_last=True)

test_dataset = CustomDataset(*[torch.stack(tensors) for tensors in zip(*test_tuples)])
test_loader = DataLoader(test_dataset, shuffle=False, batch_size=batch_size, drop_last=True)

网络搭建(这里仅简单的搭了一个基础网络)

    # 定义CLDNN模型
class CLDNN(nn.Module):
        def __init__(self):
            super(CLDNN, self).__init__()
  
           
            self.conv1 = nn.Sequential(
            nn.BatchNorm2d(1),
            nn.Conv2d(in_channels= 1, out_channels = 256, kernel_size= (1, 3)),
            nn.ReLU(),
            # nn.MaxPool2d(kernel_size= (1,2))
            nn.Dropout(0.5)
        )
            self.conv2 = nn.Sequential(
            nn.BatchNorm2d(256),
            nn.Conv2d(in_channels= 256, out_channels= 80, kernel_size=(2,3)),
            nn.ReLU(),
            # nn.MaxPool2d(kernel_size= (1,2))
            nn.Dropout(0.5)
        )
            self.conv3 = nn.Sequential(
            nn.BatchNorm2d(80),
            nn.Conv2d(in_channels= 80, out_channels= 80, kernel_size=(1,3)),
            nn.ReLU(),
            # nn.MaxPool2d(kernel_size= (1,2))
            nn.Dropout(0.5)
        )
            self.conv4 = nn.Sequential(
            nn.BatchNorm2d(80),
            nn.Conv2d(in_channels= 80, out_channels= 80, kernel_size=(1,3)),
            nn.ReLU(),
            # nn.MaxPool2d(kernel_size= (1,2))
            nn.Dropout(0.5)
        )
        
            self.lstm1 = nn.Sequential(
            nn.LSTM(input_size= 80, hidden_size= 50, num_layers= 1, batch_first= True)
        )
        
            self.fc1 =  nn.Sequential(
            nn.Linear(in_features= 50, out_features= 128),
            nn.ReLU(),
            nn.Dropout(0.5),
        )
            self.fc2 = nn.Sequential(
            nn.Linear(in_features= 128, out_features= 11)
        )
        def initialize_weight(self):
            for m in self.modules():
                if isinstance(m, nn.Conv2d):
                    nn.init.xavier_uniform_(m.weight)
                elif isinstance(m, nn.BatchNorm2d) or isinstance(m, nn.BatchNorm1d):
                    nn.init.constant_(m.weight, 1)
                    nn.init.constant_(m.bias, 0)
                elif isinstance(m, nn.Linear):
                    nn.init.kaiming_normal_(m.weight)
        
            self.initialize_weight()
            self.to(self.hyper.device)
                    
 
        def forward(self, x):
            #x = torch.unsqueeze(x, 1)
        # x = x.view(x.shape[0],1, 2, 128)
            x = self.conv1(x)
            x = self.conv2(x)
            x = self.conv3(x)
            x = self.conv4(x)
        
            x = torch.transpose(x[:,:,0,:],1,2)
            x, (h,c) = self.lstm1(x)
            x = x[:,-1,:]
            x = self.fc1(x)
            out = self.fc2(x)
        
            return out 
model = CLDNN()
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") #把模型迁移导到GPU
model.to(device) #模型、参数迁移到GPU
# construct loss and optimize
criterion = torch.nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.001)
optimizer.zero_grad() #梯度清0

np_epoch =120
print("Total number of paramerters in networks is {}  ".format(sum(x.numel() for x in model1.parameters())))

网络训练

for param in model.parameters():
    if len(param.shape)>=2:
        torch.nn.init.xavier_normal_(param)

def train(epoch):
    ttotal=0
    right = 0
    model.train()
    running_loss = 0.0
    for batch_idx, data in enumerate(train_loader, 0):
        iq,target = data 
      
        iq,target = iq.to(device),target.to(device)  #输入和输出都迁移到GPU,且需要放在同一块显卡
        running_loss = 0.0
        num_mods = 0
        optimizer.zero_grad() #梯度清0
        outputs= model(iq)
        loss = criterion(outputs, target)
        loss.backward()#计算梯度
        optimizer.step()#优化
        
        _,predicted = torch.max(outputs.data, dim=1)
        ttotal += target.size(0)

        right =right+ predicted.eq(target.data.view_as(predicted)).sum()
        running_loss += loss.item()#计算损失总和
    ac = right/ttotal        
    return running_loss,ac
# 观察训练后的模型在捏造数据上的表现
    
def val(G):
    correct = 0
    total = 0
    acc_val=0
    model.eval()
    with torch.no_grad():
        for data in val_loader:
            iq, target = data  
            iq, target = iq.to(device),target.to(device)  #输入和输出都迁移到GPU,且需要放在同一块显卡
            outputs = model(iq)
            val_loss = criterion(outputs, target)
            _, predicted = torch.max(outputs.data, dim=1) 
            total += target.size(0)
            correct += (predicted == target).sum().item()
        
    acc_val = correct / total
    return acc_val,val_loss
#返回正确率及生成矩阵G

if __name__ == '__main__':  #检测脚本是否被作为主程序直接运行
    epoch_list = []
    acc_list = [] 
    loss_list = []
    trainacc_list=[]
    max_acc=0
    min_loss=100
   
    for epoch in range(np_epoch):
        
        loss,train_acc=train(epoch)
        acc,val_loss= val()
        loss_list.append(loss)
        trainacc_list.append(train_acc)
        epoch_list.append(epoch)
        acc_list.append(acc)
        #scheduler.step()
        if acc>=max_acc:
            max_acc=acc
            t=0
            # 保存整个模型,包含模型结构和参数
            torch.save(model, 'CLDNN.pt')
        t = t+1
        loss_list.append(loss)
        trainacc_list.append(train_acc)
        epoch_list.append(epoch)
        acc_list.append(acc)
        print(epoch,loss,train_acc,val_loss,acc)
        if t>=10:
            print(max_acc)
            break

 

绘制混淆矩阵函数

import itertools

def confusion_matrix(preds,labels,conf_matrix):
    for p,t in zip(preds,labels):
        conf_matrix[p,t]+=1
    return conf_matrix
# 绘制混淆矩阵
def plot_confusion_matrix(cm, classes, normalize=True, title='Confusion matrix', cmap=plt.cm.Blues):
    '''
    This function prints and plots the confusion matrix.
    Normalization can be applied by setting `normalize=True`.
    Input
    - cm : 计算出的混淆矩阵的值
    - classes : 混淆矩阵中每一行每一列对应的列
    - normalize : True:显示百分比, False:显示个数
    '''
    if normalize:
        cm = cm.astype('float') / cm.sum(axis=0)[:, np.newaxis]
        print("Normalized confusion matrix")
    else:
        print('Confusion matrix, without normalization')
    #print(cm)
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))
    plt.xticks(tick_marks, classes, rotation=90)
    plt.yticks(tick_marks, classes)
    ax = plt.gca()  # 获得当前axis
    left, right = plt.xlim()  # 获得x轴最大最小值
    ax.spines['left'].set_position(('data', left))
    ax.spines['right'].set_position(('data', right))
    for edge_i in ['top', 'bottom', 'right', 'left']:
        ax.spines[edge_i].set_edgecolor("white")


    plt.axis("equal")
    ax = plt.gca()  # 获得当前axis
    left, right = plt.xlim()  # 获得x轴最大最小值
    ax.spines['left'].set_position(('data', left))
    ax.spines['right'].set_position(('data', right))
    for edge_i in ['top', 'bottom', 'right', 'left']:
        ax.spines[edge_i].set_edgecolor("white")

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        num = '{:.2f}'.format(cm[i, j]) if normalize else int(cm[i, j])
        plt.text(i, j, num,
                 verticalalignment='center',
                 horizontalalignment="center",
                 color="white" if float(num) > thresh else "black")
    plt.tight_layout()
    plt.ylabel('True label')
    plt.xlabel('Predicted label')
    plt.show()

#该函数用于得到每种调制方式的准确值,先返回正确值,再返回类型总值,该代码可以优化,比如每一轮train只需要算一次总的num_mods
def accofmods(predict,y):
    #记录验证集中各调制类型的个数
    confusion_matrix = torch.zeros((11,11))
    num_mods = torch.zeros((1,11))
    #记录各调制类型正确的个数
    num_mods_right = torch.zeros((1,11))
    for idx in range(len(y)):
        num_mods[:,y[idx]] = num_mods[:,y[idx]]+1
        if predict[idx].item() == y[idx].item():
            num_mods_right[:,y[idx]]=num_mods_right[:,y[idx]]+1
            confusion_matrix[y[idx],y[idx]] += 1
        else:
            confusion_matrix[y[idx],predict[idx]]+=1
    return num_mods_right,num_mods

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值