1.高熵合金晶界预测
1.导入数据
1.数据读取
import pandas as pd
df = pd.read_csv('HEA.csv',header = 1).iloc[:-8,6:18] #导入数据,header=1从第2行开始导入,iloc[]获取有用数据
df.columns = ['T','Co','Ni','Cr','Fe','Mn','Co ad','Ni ad','Cr ad','Fe ad','Mn ad','Dis'] #重新命名列标签
print(df)
2.预处理
x = df.iloc[:,:-6].values #提取数据
y = df['Cr ad'].values
y = y.astype('float64') #将字符串转换为浮点数
利用均值与标准差标准化数据
x
⟶
x
−
μ
σ
x\longrightarrow \frac{x-\mu}{ \sigma }
x⟶σx−μ
from sklearn.preprocessing import StandardScaler
ss_x = StandardScaler() #制作标准化器
x_s = ss_x.fit_transform(x) #标准化
ss_y = StandardScaler()
y_s = ss_y.fit_transform(y.reshape(-1,1)).reshape(-1) #将一行数据转换一列数据,之后再转换一行数据
print(x_s,y_s)
3.切分训练集
from sklearn.model_selection import train_test_split
# 数据集切训练集(0.7)、测试集(0.15)、验证集(0.15)
x_train,x_test,y_train,y_test = train_test_split(x_s,y_s,test_size = 0.15)
x_train,x_validation,y_train,y_validation = train_test_split(x_train,y_train,test_size = 0.1765)
print(x_train.shape,x_validation.shape,x_test.shape)
2.模型构建
1.Keras模型构建方法
2.三种模型方法对比
方法 | 序贯模型 | 函数式模型 | 模型子类化 |
---|---|---|---|
损失函数 | 0.0874 | 0.0813 | 0.0781 |
准确率 | 97.82% | 98.06% | 98.20% |
三种方法的底层设计有细微的差别,通常这样的差别可以忽略不计
3.序贯模型与函数式API模型
1.序贯模型的构建
from tensorflow import keras
model_seq = keras.Sequential([ #构建网络
keras.Input(shape=(6)),
keras.layers.Dense(20,activation = 'relu'), #使用relu激活函数
keras.layers.Dense(1)
])
print(model_seq.summary())
2.函数型模型的构建
layer_input = keras.Input(shape=(6)) #输入层
layer_hidden = keras.layers.Dense(20,activation = 'relu')(layer_input) #连接到输入层之下
layer_output = keras.layers.Dense(1)(layer_hidden) #连接到隐藏层之下
model = keras.Model(inputs = layer_input,outputs = layer_output) #构建函数型模型
print(model.summary())
3.编译与训练
adam = keras.optimizers.Adam(learn_rate = 0.001) #学习率0.001,Adam优化
model.complie(lose = 'mse',optimizer = adam,metrics = ['mse'])
history = keras.callbacks.History() #History 回调函数
model.fit(x_train,y_train,validation_data = (x_validation,y_validation),
epochs = 500,callbacks = [history],verbose = 0) #验证集手动给出,训练500次,不输出
4.模型评价
from sklearn.metrics import r2_score
import numpy as np
def model_predict(model,x_data,y_data,ss): #自定义函数,模型预测,预测后数据逆标准化
result = model.predict(x_data) #模型预测
y_pred = ss.inverse_transform(result).reshape(-1) #逆标准化
y_real = ss.inverse_transform(y_data.reshape(-1,1)).reshape(-1)
return y_real,y_pred
y_real_train,y_pred_train = model_predict(model,x_train,y_train,ss_y) #计算模型预测值
y_real_validation,y_pred_validation = model_predict(model,x_validation,y_validation,ss_y)
y_real_test,y_pred_test = model_predict(model,x_test,y_test,ss_y)
def compute_mae_mse_rmse(real,pred): #自定义计算平均绝对误差mae,均方误差mse,均方根误差rmse,R方r2
error = []
for j in range(len(real)):
error.append(real[j]-pred[j]) #预测值与真实值之差
error_squared = []
error_abs = []
for val in error:
error_squared.append(val*val) #误差平方
error_abs.append(abs(val)) #误差绝对值
mae = sum(error_abs)/len(error_abs) #MAE
mse = sum(error_squared)/len(error_squared) #MSE
rmse = np.sqrt(mse) #均方根误差rmse是均方误差mse的算术平方根
r2 = r2_score(real,pred) #评价回归模型,r2->1,模型越好
return mae,mse,rmse,r2
error_val_train = compute_mae_mse_rmse(y_real_train * 100,y_pred_train *100) #计算误差
error_val_validation = compute_mae_mse_rmse(y_real_validation * 100, y_pred_validation * 100)
error_val_test = compute_mae_mse_rmse(y_real_test * 100, y_pred_test * 100)
模型训练结果
print('train mae: %.3f,mse: %.3f,rmse: %.3f,r2: %4f'%(error_val_train[0],error_val_train[1],
error_val_train[2],error_val_train[3])) #输出误差
print('validation mae: %.3f,mse: %.3f,rmse: %.3f,r2: %4f'%(error_val_validation[0],error_val_validation[1],
error_val_validation[2],error_val_validation[3]))
print('test mae: %.3f,mse: %.3f,rmse: %.3f,r2: %4f'%(error_val_test[0],error_val_test[1],
error_val_test[2],error_val_test[3]))
4.数据可视化
1.绘制预测散点图
import matplotlib.pyplot as plt
plt.figure(figsize = (6,6)) #设置画布大小,绘制预测散点图
plt.scatter(y_real_train *100,y_pred_train *100,s = 100, #训练集,大小100,金黄色
color = 'goldenrod',label = 'Traing Set')
plt.scatter(y_real_validation *100,y_pred_validation *100,s = 100, #验证集,大小100,浅蓝色
color = 'lightblue',label = 'Validation Set')
plt.scatter(y_real_test *100,y_pred_test *100,s = 100, #测试集,大小100,紫色
color = 'purple',label = 'Testing Set')
plt.plot([0,65],[0,65],color = 'grey',linestyle = '--',linewidth = 3) #绘制对角线,虚线,宽度3,灰色
plt.legend() #显示图例
plt.xlim(0,65) # x y轴坐标范围
plt.ylim(0,65)
plt.xlabel('MC/MD') # x y轴标签
plt.ylabel('ANN')
plt.show()
2.绘制预测相图
x_pred = [] #构建待预测数组
for T in np.arange(1000,1310,10): #温度T
for i in np.arange(0.0,0.4,0.02): #Mn的浓度
j = 0.4 - i # Cr的浓度
xx = [] #构建一组数据
xx.append(T) #温度
xx.append(0.2) #Co浓度
xx.append(0.2) #Ni浓度
xx.append(j) #Cr浓度
xx.append(0.2) #Fe浓度
xx.append(i) #Mn浓度
x_pred.append(xx)
x_pred = np.array(x_pred) #转换为数组
x_pred_nor = ss_x.transform(x_pred) #标准化
y_pred_nor = model.predict(x_pred_nor) #模型预测
y_pred = ss_y.inverse_transform(y_pred_nor).reshape(-1) #逆标准化
# 绘制相图
x0,y0 = np.meshgrid(np.arange(0.0,0.4,0.02),np.arange(1000,1310,10)) #生成坐标矩阵
plt.figure(figsize = (6,5)) #设置画图大小
levels = np.linspace(-10,50,101) #-10和50是色阶显示的数据范围,101是颜色显示的细致程度
plt.contourf(x0,y0,y_pred.reshape(x0.shape)*100,cmap = 'bwr',levels = levels) #contourf()绘制二维颜色填充图,
plt.xticks(np.arange(0.05,0.36,0.1)) # x y轴刻度值
plt.yticks(np.arange(1000,1301,100))
plt.xlim(0.05,0.35) # x y轴范围
plt.ylim(1000,1300)
plt.xlabel('X Mn') # x y轴标签
plt.ylabel('T(K)')
cb = plt.colorbar() #储存颜色条
cb.set_ticks([0,10,20,30,40,50]) #设置颜色条刻度
plt.show()
5.训练曲线
#绘制训练曲线
plt.plot(history.history['loss'],label = 'train')
plt.plot(history.history['val_loss'],label = 'validation')
plt.legend() #显示图例
plt.xlabel('Epoch') # x y轴标签
plt.ylabel('Loss')
plt.show()
1.欠拟合曲线
模型在训练集上无法得到足够低的误差
2.过拟合曲线
验证集损失减小到一个点再次开始增加
3.好的拟合曲线
模型在训练集和验证集上的性能都很好
训练和验证损失共同减少并稳定在同一点附近
2.用DOS预测吸附能
1.导入数据
1.序列化与反序列化
#二进制序列化
import pickle
list_1 = ['Fe','Co','Ni']
with open('list_1.pkl','wb') as f:
pickle.dump(list_1,f)
#序列化
with open('list_1.pkl','rb') as f:
list_2 = pickle.load(f)
print(list_2)
2.数据导入
import pickle
with open('OH_data',mode = 'rb') as f: #数据反序列化
surface_dos = pickle.load(f) #DOS
targets = pickle.load(f) #吸附能
3.查看数据样本
import matplotlib.pyplot as plt
for i in range(1,10): #查看数据样本
plt.plot(surface_dos[0,:-500,0],surface_dos[0,:-500,i])
plt.show()
4.数据预处理
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
surface_dos = surface_dos[:,:2000,1:28] #截取处理
surface_dos[:,1800:2000,0:27] = 0
surface_dos = surface_dos.astype(np.float32) #数据类型准换
ss_x = StandardScaler() #制作标准化器
x_s = ss_x.fit_transform(surface_dos.reshape(-1,surface_dos.shape[2])).reshape(surface_dos.shape) #x标准化
y = targets
x_train,x_test,y_train,y_test = train_test_split(x_s,y,test_size = 0.2) #划分为训练集和测试集,比例0.2
- 标准化 StandardScaler()
x s = x − μ σ x_{s}=\frac{x-\mu}{\sigma} xs=σx−μ - 归一化 MinMaxScaler()
x n = x − x m i n x m a x − x m i n x_{n}=\frac{x-x_{min}}{x_{max}-x_{min}} xn=xmax−xminx−xmin
2.模型准备
1.池化(pool),卷积(conv)
- 池化(平均值池化)
AveragePooling1D(pool_size,strides,padding)
pool_size:池化窗口大小
strides:步长,对应池化前后数据量比例
padding:控制输出层的大小,‘valid’,‘same’
v a l i d : s h a p e ( i n p u t ) − s h a p e ( p o o l ) + 1 s t r i d e s valid:\frac{shape\left(input\right)-shape\left(pool\right)+1}{strides} valid:stridesshape(input)−shape(pool)+1
s a m e : s h a p e ( i n p u t ) s t r i d e s same:\frac{shape\left(input\right)}{strides}\quad\quad\quad\quad\quad\quad\quad\quad same:stridesshape(input)
池化层没有参数:在保证数据特征的同时减少了参数,可以减小计算量和预防过拟合。 - 卷积
Conv1D(filters,kernel_size,activation,padding,strides)
filters:卷积核数量
kernel_size:卷积窗口长度
activation:激活函数
padding:控制输出层,'valid’不填充,'same’填充
strides:卷积步长
卷积核
Glorot正态分布初始化器,即高斯分布的初始化
N
(
0
,
2
n
i
n
+
n
o
u
t
)
μ
=
0
,
σ
=
2
n
i
n
+
n
o
u
t
N\left(0,\sqrt{\frac{2}{n_{in}+n_{out}}}\right)\quad\quad\mu=0,\sigma=\sqrt{\frac{2}{n_{in}+n_{out}}}
N(0,nin+nout2)μ=0,σ=nin+nout2
卷积核作用后,再使用激活函数调整
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.layers import Input,BatchNormalization,Dropout,Dense
from tensorflow.keras.layers import AveragePooling1D,Concatenate,Conv1D,Flatten
channels = 9 #通道数
def dos_featurizer(channels): #特征化,减少计算量
input_dos = Input(shape = (2000,channels)) #输入层
x1 = AveragePooling1D(pool_size = 4,strides = 4,padding = 'same')(input_dos) #平均值池化,池化窗口pool_size,步长strides,'same'自动补齐
x2 = AveragePooling1D(pool_size = 25,strides = 4,padding = 'same')(input_dos)
x3 = AveragePooling1D(pool_size = 200,strides = 4,padding = 'same')(input_dos)
x = Concatenate(axis = -1)([x1,x2,x3]) #axis=-1 按最后一个维度拼接
x = Conv1D(50,20,activation = 'relu',padding = 'same',strides = 2)(x) #卷积,卷积核数量50,卷积窗口大小20,激活函数relu
x = BatchNormalization()(x) #批标准化
x = Conv1D(75, 3, activation='relu', padding='same', strides=2)(x) # 卷积
x = AveragePooling1D(pool_size=3, strides=2, padding='same')(x) # 平均值池化
x = Conv1D(100, 3, activation='relu', padding='same', strides=2)(x) # 卷积
x = AveragePooling1D(pool_size=3, strides=2, padding='same')(x) # 平均值池化
x = Conv1D(125, 3, activation='relu', padding='same', strides=2)(x) # 卷积
x = AveragePooling1D(pool_size=3, strides=2, padding='same')(x) # 平均值池化
x = Conv1D(150, 3, activation='relu', padding='same', strides=1)(x) # 卷积
shared_model = Model(input_dos,x) #构建共享模型
return shared_model
2.独立同分布假设(independent and identically distributed,IID)
监督训练的假设,假设训练数据与测试数据满足相同分布
用于保证通过训练数据得到的模型在测试数据上能有良好表现
3.偏移
数据集偏移(Dataset shfit):训练数据与待预测数据的分布不同
输入分布偏移(Covariate shift):特殊的数据集偏移,训练数据与待预测数据条件概率相同但边缘概率不同
4.Internal Covariate Shift(ICS)
在深层网络的训练过程中,网络参数的变化引起内部节点数据分布变化的现象
ICS结果导致输入(in)与输出(out)条件概率相同但边缘概率不同
5.白化(Whitening)
一种数据标准化的方法,常用的PCA白化(均值为0,方差为1)和ZCA白化(均值为0,方差相同)
缺点:计算成本高,每层都需要白化,改变每一层的分布
6.批标准化
对于B={x1,2,…,m}中的所有x
mini-batch的均值:
μ
B
←
1
m
∑
i
=
1
m
x
i
\mu_{B}\gets\frac{1}{m}\sum_{i=1}^{m}x_{i}
μB←m1i=1∑mxi
mini-batch的方差:
σ
B
2
←
1
m
∑
i
=
1
m
(
x
i
−
μ
B
)
2
\sigma_{B}^{2}\gets\frac{1}{m}\sum_{i=1}^{m}\left(x_{i}-\mu_{B}\right)^{2}
σB2←m1i=1∑m(xi−μB)2
标准化:
x
i
^
←
x
i
−
μ
B
σ
B
2
+
ε
\hat{x_{i}}\gets\frac{x_{i}-\mu_{B}}{\sqrt{\sigma_{B}^{2}+\varepsilon }}
xi^←σB2+εxi−μB
缩放与平移:
y
i
←
γ
x
^
i
+
β
≡
B
N
γ
,
β
(
x
i
)
y_{i}\gets\gamma\hat{x}_{i}+\beta\equiv BN_{\gamma,\beta}\left(x_{i}\right)
yi←γx^i+β≡BNγ,β(xi)
对网络的参数 X 进行缩放,得
α
\alpha
αX
缩放前:输入值 X 均值
μ
\mu
μ 方差
σ
\sigma
σ2
缩放后:输入值
α
\alpha
αX 均值
α
μ
\alpha\mu
αμ 方差
α
\alpha
α2
σ
\sigma
σ2
B
N
(
α
X
)
=
γ
α
X
−
α
μ
α
2
σ
2
+
β
=
γ
X
−
μ
σ
2
+
β
=
B
N
(
X
)
BN\left(\alpha X\right)=\gamma\frac{\alpha X-\alpha\mu}{\sqrt{\alpha^{2}\sigma^{2}}}+\beta=\gamma\frac{X-\mu}{\sqrt{\sigma^{2}}}+\beta=BN\left(X\right)
BN(αX)=γα2σ2αX−αμ+β=γσ2X−μ+β=BN(X)
缩放对BN层输出没有影响
3.构建模型
1.模型构建
from tensorflow.keras.models import Model
from tensorflow.keras.optimizers import Adam
def create_model(shared_conv,channels): #自定义创建模型函数
input1 = Input(shape = (2000,channels)) #输入层
input2 = Input(shape=(2000, channels))
input3 = Input(shape=(2000, channels))
conv1 = shared_conv(input1) #创建共享模型
conv2 = shared_conv(input2)
conv3 = shared_conv(input3)
convmerge = Concatenate(axis = -1)([conv1,conv2,conv3]) #axis=-1 按最后一个维度拼接
convmerge = Flatten()(convmerge) #降为一维数组
convmerge = Dropout(0.2)(convmerge) #预防过拟合,丢弃法,每次丢掉0.2的神经元
convmerge = Dense(200,activation = 'linear')(convmerge) #隐藏层,200个神经元
convmerge = Dense(1000, activation='relu')(convmerge) # 隐藏层,200个神经元
convmerge = Dense(1000, activation='relu')(convmerge) # 隐藏层,200个神经元
out = Dense(1)(convmerge) #输出层
model = Model(inputs = [input1,input2,input3],outputs = out) #构建模型
return model
share_conv = dos_featurizer(channels)
model = create_model(share_conv,channels) #创建模型
print(model.summary())
model.compile(loss = 'logcosh',optimizer = Adam(0.001),metrics = ['mean_absolute_error']) #设置模型,学习率0.001
2.模型训练
model.fit( #训练模型
[x_train[:,:,0:9],x_train[:,:,9:18],x_train[:,:,18:27]], #输入
y_train,batch_size = 128,epochs = 60,verbose = 0, #输出,训练60次,不输出,batch_size=128,128个数据为一组
validation_data = ([x_test[:,:,0:9],x_test[:,:,9:18],x_test[:,:,18:27]],y_test) #验证集
)
4.结果可视化
#结果可视化
train_out = model.predict([x_train[:,:,0:9],x_train[:,:,9:18],x_train[:,:,18:27]]) #模型预测
test_out = model.predict([x_test[:,:,0:9],x_test[:,:,9:18],x_test[:,:,18:27]])
train_out,test_out = train_out.reshape(len(train_out)),test_out.reshape(len(test_out)) #列数组改为行数组
plt.figure(figsize = (6,6)) #画布大小
plt.plot([-3,3],[-3,3]) #绘制对角线
plt.scatter(y_train,train_out,s = 10,c = 'b') #训练集
plt.scatter(y_test,test_out,s = 10,c = 'r',alpha = 0.5) #验证集
plt.xlabel('DFT(eV)') # x y标签
plt.ylabel('ML Predicted(eV)')
plt.axis([-3,3,-3,3]) #坐标轴范围
plt.show()