北京化工大学 神经网络与深度学习第二次作业

0.1. 实验2 使用随机搜索法训练线性分类器

0.1.1. 读取图像形式的MNIST,划分为train/test

0.1.2. 定义Linear Classifier+Cross Entroy Loss

0.1.3. 用Random Search 来训练Linear Classifier

0.1.4. 在上述分类器前再增加一层(2层神经网络)使用Relu激活函数

0.1.5. 通过表格、曲线等形式进行汇总,分析比较是否使用激活函数、激活函数的类型对分类结果的影响


import os
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
from numpy.ma.extras import unique

'''
根据名称整出来训练集、测试集和对应的标签
'''
def load_images_and_split(folder):
    train_images = []
    test_images = []
    test_labels = []
    train_labels = []
    for filename in os.listdir(folder):
        if filename.endswith('.jpg'):
            img_path = os.path.join(folder, filename)
            try:
                img = Image.open(img_path)
                img_array = np.array(img)
                #图像名称的倒数第五个是标签
                label = filename[-5]
                
                #划分数据集
                if 'test' in filename:
                    test_images.append(img_array)
                    try:
                        # 将标签转换为整数
                        test_labels.append(int(label))
                    except ValueError:
                        print(f"Invalid label in {filename}: {label}. Skipping this image.")
                elif 'training' in filename:
                    train_images.append(img_array)
                    try:
                        train_labels.append(int(label))
                    except ValueError:
                        print(f"Invalid label in {filename}: {label}. Skipping this image.")
            except Exception as e:
                print(f"Error loading {img_path}: {e}")

    train_images = np.array(train_images)
    test_images = np.array(test_images)
    train_labels = np.array(train_labels)
    test_labels = np.array(test_labels)

    return train_images, train_labels, test_images, test_labels



# image_folder = 'mnist_jpg/mnist_jpg'
image_folder = "E:/Strudy/Data/nearestk/mnist_jpg/mnist_jpg"
#这里改成自己的名称,因为老师要求再jupyter上跑所以我就写了绝对路径
train_images, test_images,train_labels,test_labels = load_images_and_split(image_folder)

print(f"训练集数量: {len(train_images)}")
print(f"测试集数量: {len(test_images)}")
print(unique(test_labels))

第一步的运行结果:

'''
绘图
'''
#这里有三个参数,title是绘制图像的名称,同志们抄的时候注意一下把title换一下,好吗
def drawing(x,y,title):
    plt.plot(x,y)
    plt.title(title)
    plt.show()

'''
数据预处理
'''
def preprocess_data(train_images, test_images):
    # 展平图片数据
    train_images_flat = train_images.reshape(train_images.shape[0], -1)
    test_images_flat = test_images.reshape(test_images.shape[0], -1)

    # 归一化处理
    train_images_normalized = train_images_flat / 255.0
    test_images_normalized = test_images_flat / 255.0

    return train_images_normalized, test_images_normalized

'''
onehot编码方便交叉熵损失计算
'''
def one_hot_encode(labels, num_classes):
    one_hot = np.zeros((labels.shape[0], num_classes))
    one_hot[np.arange(labels.shape[0]), labels] = 1
    return one_hot

'''
softmax
注意softmax是激活函数,在完成最后一个任务的时候是需要修改softmax函数的
'''
def softmax(x):
    exp_x = np.exp(x - np.max(x, axis=1, keepdims=True))
    return exp_x / np.sum(exp_x, axis=1, keepdims=True)

'''
交叉熵
'''
def cross_entropy_loss(y_true, y_pred):
    epsilon = 1e-15
    y_pred = np.clip(y_pred, epsilon, 1 - epsilon)
    loss = -np.mean(np.sum(y_true * np.log(y_pred), axis=1))
    return loss

'''
单层模型评估
'''
def evaluate_model(test_images, test_labels, weights, bias,x_row):
    logits = np.dot(test_images, weights) + bias
    y_pred = softmax(logits)
    predicted_labels = np.argmax(y_pred, axis=1)
    accuracy = np.mean(predicted_labels == test_labels)
    print(f'Accuracy on the test set: {accuracy * 100}%')

    return accuracy

'''
单层线性分类器,最后使用的softmax激活
同志们注意一下,这里我的迭代方式是同时满足准确率上升和损失下降,同志们写作业的时候可以尝试修改一下迭代的条件,因为我最后做出来的结果不太好,我个人猜测是:如果要两个条件同时满足,我的迭代次数太少了,随意导致准确率不高
此外,在画图过程时候,可以更改一下传入y_rate和y_loss这两个,因为我传入的都是最好的,最后会生成一个单调函数,如果传入不是best_loss就是一个震荡上升的曲线,同志们可以尝试一下!
'''
def train_linear_classifier_random_search(test_images_normalized, test_labels,train_images, train_labels, num_classes, num_trials=100):
    input_size = train_images.shape[1]
    best_loss = float('inf')
    best_weights = None
    best_bias = None
    acc=0
    x_row = []
    y_loss_row=[]
    y_rate_row=[]
    for trial in range(num_trials):
        # 随机生成权重和偏置
        x_row.append(trial)
        weights = np.random.randn(input_size, num_classes) * 0.01
        bias = np.zeros((1, num_classes))

        # 前向传播
        logits = np.dot(train_images, weights) + bias
        y_pred = softmax(logits)

        # 计算损失
        y_true = one_hot_encode(train_labels, num_classes)
        loss = cross_entropy_loss(y_true, y_pred)
        # acc = evaluate_model(test_images_normalized, test_labels, best_weights, best_bias, x_row)
        # 更新最佳参数
        if loss < best_loss:
            if evaluate_model(test_images_normalized, test_labels, weights, bias, x_row)>acc:
                #如果当前的准确率高于最佳准确率则更新参数
                best_loss = loss
                best_weights = weights
                best_bias = bias
        #发现准确率下降了,在更新参数的时候加上准确率的迭代
        y_loss_row.append(best_loss)
        acc=evaluate_model(test_images_normalized, test_labels, best_weights, best_bias, x_row)
        y_rate_row.append(acc)
        print(f'Trial {trial + 1}, Loss: {loss}')

    drawing(x_row, y_loss_row,title='single_loss_curve')
    #使用best图表好看一点
    drawing(x_row,y_rate_row,title='single_acc_curve')
    return best_weights, best_bias


'''
the main func of test2
主函数,在这里修改超参数也是可以的
'''
folder_path = image_folder
train_images, train_labels, test_images, test_labels = load_images_and_split(folder_path)
train_images_normalized, test_images_normalized = preprocess_data(train_images, test_images)

num_classes = len(np.unique(train_labels))
weights, bias = train_linear_classifier_random_search(test_images_normalized, test_labels,train_images_normalized, train_labels, num_classes)

up太笨了,琢磨不出来怎么截屏完整的图像出来……

'''
两层模型评估
其实两层模型的评估和一层模型的写法评估大差不差,但是要注意一下矩阵的运算
'''
# test_images_normalized, test_labels, best_weights1, best_bias1,best_weights2,best_bias2, x_row)

def two_evaluate_model(test_images, test_labels, weights1, bias1,weights2,bias2,x_row):
    #隐藏
    hidden_layer=np.dot(test_images,weights1)+bias1
    hidden_layer=relu(hidden_layer)
    logits = np.dot(hidden_layer, weights2) + bias2
    y_pred = softmax(logits)
    predicted_labels = np.argmax(y_pred, axis=1)
    accuracy = np.mean(predicted_labels == test_labels)
    print(f'Accuracy on the test set: {accuracy * 100}%')

    return accuracy

'''
relu函数
这玩意也是一个激活函数哦~最后一步也是可以修改的的
'''
def relu(x):
    return np.maximum(0, x)

'''
两层线性分类器
'''
def two_train_linear_classifier_random_search(test_images_normalized, test_labels,train_images, train_labels, num_classes, num_trials=100):
    input_size = train_images.shape[1]
    best_loss = float('inf')
    best_weights1 = None
    best_bias1 = None
    best_weights2 = None
    best_bias2 = None
    acc=0
    x_row = []
    y_loss_row=[]
    y_rate_row=[]
    for trial in range(num_trials):
        # 随机生成权重和偏置
        x_row.append(trial)

        #初始化第一层
        weights1 = np.random.randn(input_size, num_classes) * 0.01
        bias1 = np.zeros((1, num_classes))

        # 初始化第二层
        weights2 = np.random.randn(num_classes, num_classes) * 0.01
        bias2 = np.zeros((1, num_classes))

        # 前向传播
        hidden_layer = np.dot(train_images, weights1) + bias1
        hidden_layer = relu(hidden_layer)

        logits = np.dot(hidden_layer,weights2)+bias2
        y_pred=softmax(logits)

        # 计算损失
        y_true = one_hot_encode(train_labels, num_classes)
        loss = cross_entropy_loss(y_true, y_pred)

        # 更新最佳参数,大家看好,这里是迭代条件哈,这里是可以修改的,如果谁能想到更聪明的迭代方法,麻烦教教我
        if loss < best_loss:
            if two_evaluate_model(test_images_normalized, test_labels, weights1, bias1,weights2,bias2, x_row)>acc:
                best_loss = loss
                best_weights1 = weights1
                best_bias1 = bias1
                best_weights2 = weights2
                best_bias2 = bias2

        y_loss_row.append(best_loss)
        #我想要的只是递增图像~~~
        acc=two_evaluate_model(test_images_normalized, test_labels, best_weights1, best_bias1,best_weights2,best_bias2, x_row)
        y_rate_row.append(acc)
        print(f'Trial {trial + 1}, Loss: {loss}')

    drawing(x_row, y_loss_row,title='double_loss_curve')
    drawing(x_row,y_rate_row,title='double_acc_curve')

    return best_weights1, best_bias1,best_weights2, best_bias2

#这里是主函数了
two_train_linear_classifier_random_search(test_images_normalized, test_labels,train_images_normalized, train_labels, num_classes)

 

'''
0.1.5. 通过表格、曲线等形式进行汇总,分析比较是否使用激活函数、激活函数的类型对分类结果的影响。'''


'''
这个就是不实用激活函数了,自行丢尽刚刚的代码里修改一下就好了
def no_activate_func(x):
    return x
'''
'''
这里举个例子
'''

def two_train_linear_without_activatefunc(test_images_normalized, test_labels,train_images, train_labels, num_classes, num_trials=100):
    input_size = train_images.shape[1]
    best_loss = float('inf')
    best_weights1 = None
    best_bias1 = None
    best_weights2 = None
    best_bias2 = None
    acc=0
    x_row = []
    y_loss_row=[]
    y_rate_row=[]
    for trial in range(num_trials):
        # 随机生成权重和偏置
        x_row.append(trial)

        #初始化第一层
        weights1 = np.random.randn(input_size, num_classes) * 0.01
        bias1 = np.zeros((1, num_classes))

        # 初始化第二层
        weights2 = np.random.randn(num_classes, num_classes) * 0.01
        bias2 = np.zeros((1, num_classes))

        # 前向传播
        hidden_layer = np.dot(train_images, weights1) + bias1
        hidden_layer = no_activate_func(hidden_layer)

        logits = np.dot(hidden_layer,weights2)+bias2
        y_pred=no_activate_func(logits)

        # 计算损失
        y_true = one_hot_encode(train_labels, num_classes)
        loss = cross_entropy_loss(y_true, y_pred)

        # 更新最佳参数
        if loss < best_loss:
            if two_evaluate_model(test_images_normalized, test_labels, weights1, bias1,weights2,bias2, x_row)>acc:
                best_loss = loss
                best_weights1 = weights1
                best_bias1 = bias1
                best_weights2 = weights2
                best_bias2 = bias2

        y_loss_row.append(best_loss)
        #我想要的只是递增图像~~~
        acc=two_evaluate_model(test_images_normalized, test_labels, best_weights1, best_bias1,best_weights2,best_bias2, x_row)
        y_rate_row.append(acc)
        print(f'Trial {trial + 1}, Loss: {loss}')

    drawing(x_row, y_loss_row,title='double_loss_curve')
    drawing(x_row,y_rate_row,title='double_acc_curve')

    return best_weights1, best_bias1,best_weights2, best_bias2

two_train_linear_without_activatefunc(test_images_normalized, test_labels,train_images_normalized, train_labels, num_classes)

我刚刚写文章的时候想到,在评估函数里面也用到了激活函数,同志们可以在那里也修改一下

'''
sigmoid
'''
import numpy as np
def sigmoid(x):
    derta=1/(1+np.exp(-x))
    return derta

 

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值