知方号

知方号

logistic回归用于多类别图片分类

logistic回归用于多类别图片分类

文章目录 完整代码对mnist的测试输出结果主函数各参数解释预备知识数学推导sigmoid函数np的矩阵维度读取np.argmax函数np.insert函数独热编码(One-Hot Encoding) 数据预处理各模块代码详解

完整代码 import os.pathimport numpy as npfrom torchvision.datasets import ImageFolderfrom torch.utils.data import DataLoaderfrom torchvision import transformsfrom sklearn.model_selection import train_test_splitdef LoadMyData(dataroot): transform = transforms.Compose([transforms.Resize(16),transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]) dataset = ImageFolder(dataroot,transform) datafolder = DataLoader(dataset) classes = [] labels = [] for myclass,mylabel in datafolder: classes.append(myclass.view(-1).numpy()) labels.append(mylabel.item()) return classes,labelsdef SplitData(data,labels): x_train,x_test,y_train,y_test = train_test_split(data,labels,test_size=0.3,random_state=0) x_train = np.insert(x_train,0,1,axis=1) x_test = np.insert(x_test,0,1,axis=1) return x_train,x_test,y_train,y_testdef PrepareData(dataroot): classes,labels = LoadMyData(dataroot) x_train,x_test,y_train,y_test = SplitData(classes,labels) return x_train,x_test,y_train,y_testdef sigmoid(z): return 1/(1+np.exp(-z))def predict(z): return np.argmax(sigmoid(z),axis=1)def cost_function(theta,x,y): m = len(y) y_pred = sigmoid(np.dot(x,theta)) J = (-1/m)*(y*np.log(y_pred)+(1-y)*(np.log(1-y_pred))) grad = (1/m)*np.dot(x.T,(y_pred-y)) return J,graddef count_subdirectories(dataroot): if not os.path.isdir(dataroot): print("Invalid Folder Path") return names = os.listdir(dataroot) return len(names)def main(mydataroot,my_lr,my_iterations,my_gap): dataroot = mydataroot num_classes = count_subdirectories(dataroot) x_train,x_test,y_train,y_test = PrepareData(dataroot) theta = np.zeros((x_train.shape[1],num_classes)) y_one_hot = np.eye(num_classes)[y_train] lr = my_lr for iterations in range(0,my_iterations,my_gap): for iteration in range(iterations): J,grad = cost_function(theta,x_train,y_one_hot) theta = theta - lr*grad y_pred = predict(np.dot(x_test,theta)) acc = np.mean(y_pred == y_test)*100 print(f"accuracy after {iterations} iterations is {acc}%")if __name__ == "__main__": print("begin") dataroot = "./data" learning_rate = 0.01 iterations = 300 gap = 5 main(dataroot,learning_rate,iterations,gap) print("end") 对mnist的测试输出结果

主函数各参数解释 存放数据的文件夹:dataroot = "./data" 学习率:learning_rate = 0.01 迭代次数:iterations = 300 每多少次迭代后,打印输出值,这里设置为5:gap = 5

这5个子文件夹放在名为data的主文件夹中。(文件夹名可以任意,不一定非要是0,1,2,3,4;因为ImageFolder和Dataloader会自动处理标签)

预备知识 数学推导

逻辑回归是一种广泛应用于分类问题的机器学习算法,它可以用于二元分类和多元分类。在多元分类问题中,逻辑回归通过扩展二元逻辑回归模型来进行预测。 具体的数学证明请查阅别的资料,这里只给出最终结果。

代价函数: J ( θ ) = 1 m ∑ i = 1 m Cost ⁡ ( h θ ( x ( i ) ) , y ( i ) ) = − 1 m [ ∑ i = 1 m y ( i ) log ⁡ ( h θ ( x ( i ) ) ) + ( 1 − y ( i ) ) log ⁡ ( 1 − h θ ( x ( i ) ) ) ] egin{aligned} J( heta) & =frac{1}{m} sum_{i=1}^{m} operatorname{Cost}left(h_{ heta}left(x^{(i)} ight), y^{(i)} ight) \ & =-frac{1}{m}left[sum_{i=1}^{m} y^{(i)} log left(h_{ heta}left(x^{(i)} ight) ight)+left(1-y^{(i)} ight) log left(1-h_{ heta}left(x^{(i)} ight) ight) ight] end{aligned} J(θ)​=m1​i=1∑m​Cost(hθ​(x(i)),y(i))=−m1​[i=1∑m​y(i)log(hθ​(x(i)))+(1−y(i))log(1−hθ​(x(i)))]​ 梯度: ∂ ∂ θ j J ( θ ) = 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) frac{partial}{partial heta_{j}} J( heta)=frac{1}{m} sum_{i=1}^{m}left(h_{ heta}left(x^{(i)} ight)-y^{(i)} ight) x_{j}^{(i)} ∂θj​∂​J(θ)=m1​i=1∑m​(hθ​(x(i))−y(i))xj(i)​

theta的更新策略: θ j : = θ j − α 1 m ∑ i = 1 m ( h θ ( x ( i ) ) − y ( i ) ) x j ( i ) heta_{j}:= heta_{j}-alpha frac{1}{m} sum_{i=1}^{m}left(h_{ heta}left(x^{(i)} ight)-y^{(i)} ight) x_{j}^{(i)} θj​:=θj​−αm1​i=1∑m​(hθ​(x(i))−y(i))xj(i)​

其中, α alpha α为学习率, h θ ( x ) h_{ heta}(x) hθ​(x)为x和对应维度的theta做乘法后在放入sigmoid求出的y_pred

sigmoid函数

f ( x ) = 1 1 + e − x f(x) = frac{1}{1+e^{-x}} f(x)=1+e−x1​

理解为非线性映射即可。把一个输入映射为0-1上的值。

np的矩阵维度读取

对于二维数组,可以使用shape[0]获取行数,shape[1]获取列数。

import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])shape = np.shape(arr)rows = shape[0]cols = shape[1]print("行数:", rows)print("列数:", cols)# 输出:# 行数: 2# 列数: 3

在代码中,我们需要用到这个函数获取输入向量的某些信息。

np.argmax函数

np.argmax是NumPy库中的一个函数,用于返回数组中最大元素的索引或指定轴上最大元素的索引。

函数的语法如下:

numpy.argmax(arr, axis=None)

参数说明:

arr:输入的数组。 axis:指定要沿着哪个轴寻找最大值的索引。默认值为None,表示在整个数组中寻找最大值的索引。 函数返回一个表示最大值索引的整数或整数数组。如果axis=None,则返回整个数组中最大值的索引。如果axis被指定,则返回沿着指定轴的最大值的索引数组。

1.在一维数组中寻找最大值的索引:

import numpy as nparr = np.array([3, 1, 5, 2, 4])max_index = np.argmax(arr)print(max_index)# 输出:2

2.在二维数组中寻找整个数组最大值的索引:

import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])max_index = np.argmax(arr)print(max_index)# 输出:5

3.在二维数组中沿着指定轴(行轴)寻找最大值的索引数组:

import numpy as nparr = np.array([[1, 2, 3], [4, 5, 6]])max_indices = np.argmax(arr, axis=1)print(max_indices)# 输出:[2 2]

在示例3中,axis=1表示沿着行轴寻找最大值的索引。结果是一个包含每行最大值索引的一维数组。

需要注意的是,np.argmax只返回最大值的索引。如果需要获取最大值本身,可以使用np.max函数。

np.insert函数

用法:

numpy.insert(arr, obj, values, axis=None)

arr:需要插入值或数组的目标数组。 obj:插入位置的索引或索引数组。可以是一个整数,表示要插入值的位置,也可以是一个整数数组,表示要插入值的多个位置。如果是一个整数数组,它的长度必须与要插入的值或数组的长度相同。 values:要插入的值或数组。可以是一个标量值或一个数组。如果是一个数组,它的形状必须与要插入的位置匹配。 axis:指定在哪个轴上进行插入操作。默认值为None,表示将输入数组展平后进行插入。

示例: 1.在一维数组中插入一个值:

import numpy as nparr = np.array([1, 2, 3, 4, 5])new_arr = np.insert(arr, 2, 10)print(new_arr)# 输出:[ 1 2 10 3 4 5]

2.在一维数组中插入一个数组:

import numpy as nparr = np.array([1, 2, 3, 4, 5])values = np.array([10, 11, 12])new_arr = np.insert(arr, 2, values)print(new_arr)# 输出:[ 1 2 10 11 12 3 4 5]

3.在二维数组的指定轴上插入一个值或数组:

import numpy as nparr = np.array([[1, 2], [3, 4]])new_arr = np.insert(arr, 1, 10, axis=1)print(new_arr)# 输出:# [[ 1 10 2]# [ 3 10 4]]values = np.array([[11, 12], [13, 14]])new_arr = np.insert(arr, 1, values, axis=0)print(new_arr)# 输出:# [[ 1 2]# [11 12]# [13 14]# [ 3 4]] 独热编码(One-Hot Encoding)

独热编码(One-Hot Encoding)是一种常用的分类数据编码方法,用于将离散特征表示为二进制向量的形式。它主要用于解决分类算法中特征值之间的无序关系。

独热编码的原理是为每个离散特征创建一个新的二进制特征列,其中每个特征值都表示为一个唯一的二进制编码。对于一个有N个不同特征值的离散特征,独热编码将生成一个N维的二进制向量,其中只有一个元素为1,其余元素均为0。

例如,假设有一个表示颜色的特征,包含三个不同的取值:红、绿和蓝。使用独热编码,可以将每个颜色值编码为一个二进制向量,如下所示:

红色:[1, 0, 0] 绿色:[0, 1, 0] 蓝色:[0, 0, 1] 这样做的好处是,将离散特征转换为二进制向量后,可以在机器学习算法中更好地处理这些特征,避免了特征值之间的无序关系对算法产生的影响。

这里使用np.eye等生成独热编码。 举例:

import numpy as nparr = np.array([4, 1, 2, 5, 3])num_classes = np.max(arr) + 1one_hot = np.eye(num_classes)[arr]print("原始数组:", arr)print("独热编码:")print(one_hot)

输出:

原始数组: [4 1 2 5 3]独热编码:原始数组: [4 1 2 5 3]独热编码:[[0. 0. 0. 0. 1. 0.] [0. 1. 0. 0. 0. 0.] [0. 0. 1. 0. 0. 0.] [0. 0. 0. 0. 0. 1.] [0. 0. 0. 1. 0. 0.]] 数据预处理

参考之前的文章: 图片数据导入和预处理

各模块代码详解 def LoadMyData(dataroot): transform = transforms.Compose([transforms.Resize(16),transforms.ToTensor(),transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))]) dataset = ImageFolder(dataroot,transform) datafolder = DataLoader(dataset) classes = [] labels = [] for myclass,mylabel in datafolder: classes.append(myclass.view(-1).numpy()) labels.append(mylabel.item()) return classes,labels

数据预处理,图片大小转换为16*16的numpy,返回包含所有图片和对应标签的列表

def SplitData(data,labels): x_train,x_test,y_train,y_test = train_test_split(data,labels,test_size=0.3,random_state=0) x_train = np.insert(x_train,0,1,axis=1) x_test = np.insert(x_test,0,1,axis=1) return x_train,x_test,y_train,y_testdef PrepareData(dataroot): classes,labels = LoadMyData(dataroot) x_train,x_test,y_train,y_test = SplitData(classes,labels) return x_train,x_test,y_train,y_test

分割数据,并最后返回训练集和测试集(测试集比例为0.3)

def sigmoid(z): return 1/(1+np.exp(-z))

定义sigmoid函数

def predict(z): return np.argmax(sigmoid(z),axis=1)

预测函数,返回的是预测标签

def cost_function(theta,x,y): m = len(y) y_pred = sigmoid(np.dot(x,theta)) J = (-1/m)*(y*np.log(y_pred)+(1-y)*(np.log(1-y_pred))) grad = (1/m)*np.dot(x.T,(y_pred-y)) return J,grad

核心函数,求解损失函数和梯度,具体的数学推导见之前的预备知识。 注意交叉熵函数pred和y的位置,grad里数组维度的对应。

def count_subdirectories(dataroot): if not os.path.isdir(dataroot): print("Invalid Folder Path") return names = os.listdir(dataroot) return len(names)

求解主文件下子文件夹的数量,即一共有多少个类别。

def main(mydataroot,my_lr,my_iterations,my_gap): dataroot = mydataroot num_classes = count_subdirectories(dataroot) x_train,x_test,y_train,y_test = PrepareData(dataroot) theta = np.zeros((x_train.shape[1],num_classes)) y_one_hot = np.eye(num_classes)[y_train] lr = my_lr for iterations in range(0,my_iterations,my_gap): for iteration in range(iterations): J,grad = cost_function(theta,x_train,y_one_hot) theta = theta - lr*grad y_pred = predict(np.dot(x_test,theta)) acc = np.mean(y_pred == y_test)*100 print(f"accuracy after {iterations} iterations is {acc}%")

main函数,注意初始化theta的维度。 双层循环的含义是一共迭代my_iterations,没my_gap次打印一次当前的预测准确率。

if __name__ == "__main__": print("begin") dataroot = "./data" learning_rate = 0.01 iterations = 300 gap = 5 main(dataroot,learning_rate,iterations,gap) print("end")

设置各参数。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至lizi9903@foxmail.com举报,一经查实,本站将立刻删除。