使用DL进行波束成形

论文及程序来源

论文链接:https://ieeexplore.ieee.org/document/8847377/
程序地址:https://github.com/TianLin0509/BF-design-with-DL
以下程序片段均摘录于上述程序地址。
博客主要对程序进行分析,有少部分的论文分析。由于对很多np函数不熟悉,增加了一些函数的定义,只记录自己的思考过程,供以后参考。

程序分析

使用环境:使用Anaconda进行环境搭建,Python2+Tensorflow1.12
运行顺序:先运行train.py来训练模型,再使用test.py来检验模型

加载并生成模拟数据

H, H_est = mat_load(path)
H_input = np.expand_dims(np.concatenate([np.real(H_est), np.imag(H_est)], 1), 1)
H = np.squeeze(H)
SNR = np.power(10, np.random.randint(-20, 20, [H.shape[0], 1]) / 10)

H以及H_est分别为加载后的完美CSI以及估计的CSI。其中H只在BFNN的offline训练过程中计算loss时用到,在online预测过程中不会使用到。H_est则作为BFNN的输入,计算最终的输出Vrf。

其中,H以及H_est的shape均为(10,1,64)。

由于H_est是复数组成的,而BFNN是一个只计算实数的网络,因此,H_est的实部和虚部需要使用np.concatenate()函数进行级联处理。

numpy.concatenate 函数用于沿指定轴连接相同形状的两个或多个数组,使用格式如下:
numpy.concatenate((a1, a2, …), axis)
参数说明:
a1, a2, …:相同类型的数组
axis:沿着它连接数组的轴,默认为 0 //这里使用的是axis=1

将实部和虚部级联后得到的中间变量的shape为(10,2,64),再使用np.expand_dims()函数将这个中间变量的shape扩展为(10,1,2,64)。

使用numpy.squeeze()从给定数组的形状中删除一维的条目,此时,H的shape为(10,64)。

在SNR的生成部分对源代码做了一些更改,我的环境在运行这一步的时候会报错,原因是无法进行负整数次幂的运算,更改后的代码为:

random_SNR = np.random.randint(-20, 20, [H.shape[0], 1]).astype(float)
SNR = np.power(10, random_SNR / 10)

模型建立

# imperfect CSI is used to output the vrf
imperfect_CSI = Input(name='imperfect_CSI', shape=(H_input.shape[1:4]), dtype=tf.float32)
# perfect_CSI is only used to compute the loss, and not required in prediction
perfect_CSI = Input(name='perfect_CSI', shape=(H.shape[1],), dtype=tf.complex64)
# the SNR is also fed into the BFNN
SNR_input = Input(name='SNR_input', shape=(1,), dtype=tf.float32)
temp = BatchNormalization()(imperfect_CSI)
temp = Flatten()(temp)
temp = BatchNormalization()(temp)
temp = Dense(256, activation='relu')(temp)
temp = BatchNormalization()(temp)
temp = Dense(128, activation='relu')(temp)
phase = Dense(Nt)(temp)
V_RF = Lambda(trans_Vrf, dtype=tf.complex64, output_shape=(Nt,))(phase)
rate = Lambda(Rate_func, dtype=tf.float32, output_shape=(1,))([perfect_CSI, V_RF, SNR_input])
model = Model(inputs=[imperfect_CSI, perfect_CSI, SNR_input], outputs=rate)
# the y_pred is the actual rate, thus the loss is y_pred, without labels
model.compile(optimizer='adam', loss=lambda y_true, y_pred: y_pred)
model.summary()

这一部分比较容易理解,注意H虽然也作为Input,只在计算loss值时使用。模型的三层全联接层(dense layer)分别有256、128和64个神经元,具体参数在论文中列出了。为了增强收敛性,每个dense layer之前都有一个批处理标准化层。

值得注意的是,在最后的一层Lambda层,是自定义的一层,function的实现在utils文件夹中,主要实现了恒模约束。

模型训练

reduce_lr = callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=20, min_lr=0.00005)
checkpoint = callbacks.ModelCheckpoint('./temp_trained.h5', monitor='val_loss',
                                       verbose=0, save_best_only=True, mode='min', save_weights_only=True)
model.fit(x=[H_input, H, SNR], y=H, batch_size=256,
          epochs=50000, verbose=2, validation_split=0.1, callbacks=[reduce_lr, checkpoint])

callbacks.ReduceLROnPlateau()函数即当标准评估停止提升时,降低学习速率。当val_loss不再降低时(计算在“存在的issues“中提出),调整学习率。具体函数各个参数含义课可以参考如下Keras文档。

https://keras.io/zh/callbacks/

模型检验

存在的issues

  1. loss的计算
    论文自定了一种损失函数,使用Lambda层来计算真正的损失函数,并将之作为输出。

model.fit(x=[H_input, H, SNR], y=H, batch_size=256,
epochs=50000, verbose=2, validation_split=0.1, callbacks=[reduce_lr, checkpoint])
fit函数中的y=H没有任何意义,这里的y只需要扔进一个维度一致避免keras自动检查报错的值就行了,因此方便起见扔入了H, 事实上H并不会被用到。

  1. 数据集的选取
    在相应的github中给出了信道仿真以及信道估计的参考。
  • 4
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值