SVM从零开始 (二)  训练

本节: 以训练为主线介绍

零 创建路径部分代码


# /=== === === ===> 1:创建路径-start <=== === === ===\
# => 分别创建训练路径,测试路径
def creat_fold():
    mkdir_train()  # 不存在文件夹就创建
    mkdir_test()


# => 创建存放训练图片路径的文件夹
def mkdir_train():
    if not os.path.exists(train_feat_path):
        os.mkdir(train_feat_path)


# => 创建存放测试图片路径的文件夹
def mkdir_test():
    if not os.path.exists(test_feat_path):
        os.mkdir(test_feat_path)
# \=== === === ===> 1:创建路径-end <=== === === ===/

一 训练部分代码


# /=== === === ===> 2:训练stage-start <=== === === ===\
# /=== ===> 1)训练准备,提取特征,训练 <=== ===\
def train_stage(train_feat_path):
    shutil.rmtree(train_feat_path)  # 递归删除文件夹下所有文件子文件,包括此文件train
    mkdir_train()  # 删除之后重新创建 train
    extra_feat_train()  # 获取训练特征并保存在文件夹 === ===> 2)提取特征
    nk_train()  # 训练                           === ===> 3)训练
# \=== ===> 1)训练准备,提取特征,训练 <=== ===/


# /=== ===> 2)提取特征 <=== ===\
def extra_feat_train():
    t_extra0 = time.time()  # 计时start
    train_name, train_label = get_name_label(train_label_path)  # =>获得图片名称,对应的类别
    # train_label_path = image_train\train.txt
    train_image = get_image_list(train_image_path, train_name)  # =>获得图片列表
    # train_image_path = image_train\
    get_feat(train_image, train_name, train_label, train_feat_path)
    t_extra1 = time.time()  # 计时end
    print('训练特征提取结束,', '特征提取耗时是 : %f' % (t_extra1 - t_extra0) + '\n')


# =>从txt获得'图片名称list',对应的'类别list'
def get_name_label(file_path):  # file_path = train_label_path = image_train\train.txt
    print("read label from ", file_path)
    name_list = []  # 用于存储名字的列表
    label_list = []  # 用于存储标签的列表
    with open(file_path) as f:
        for line in f.readlines():
            # 一般是name label  三部分,所以至少长度为3 所以可以通过这个方法来忽略空白行
            if len(line) >= 3:
                name_list.append(line.split(' ')[0])  # 以空格划分为两部分,前面部分为[0], 后面为[1]
                label_list.append(line.split(' ')[1].replace('\n', '').replace('\r', ''))
                # \r代表回车,\n代表换行, 都替换成'', 也就是去掉
                if not str(label_list[-1]).isdigit():
                    # 因为[-1]是最后一个, 而每次append的最后一个都是最新的,检查它如果不是数字就报错
                    print("label必须为数字,得到的是:", label_list[-1], "程序终止,请检查文件")
                    exit(1)
    return name_list, label_list
    # 得到了两个列表,分别对应顺序放置 名字,标签 也是就是形如:
    # name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
    # label_list=[1,1,...,2]


# =>获得'图片list'
def get_image_list(filePath, nameList):
    # x1: filePath = train_image_path = image_train\
    # x2: nameList = train_name = name_list 也就是上一个函数的第一个返回值, name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
    print('read image from ', filePath)
    img_list = []
    for name in nameList:
        temp = Image.open(os.path.join(filePath, name))  # 形成一个完整的具体图片路径image_train\tbj1, 然后用Image打开
        # print('测试是否有后缀.jpg', os.path.join(filePath, name))  # txt文件在起名字的时候就要写成dw1.jpg
        # 测试是否有后缀.jpg image_train/337-4.jpg 
        # 这里我为了统计4个人一个人有几个照片起名方式为:337-4.jpg, 4表示第4个人zjc, 337表示这个人的第337个照片,上面列表dw1.jpg只是示意
        img_list.append(temp.copy())  # 把这个图片copy出来,送进列表
        temp.close()  # 关掉这个,进行下一个图片的copy
    # print('img_list[0]里面内容的格式', type(img_list[0]))
    # img_list[0]里面内容的格式 <class 'PIL.Image.Image'>
    # img_list = [<class 'PIL.Image.Image'>,...,<class 'PIL.Image.Image'>]
    return img_list


# =>提取特征并保存
def get_feat(image_list, name_list, label_list, savePath):
    # x1: image_list = train_image = img_list
    # 也就上一个函数def get_image_list 的返回值list放到是<class 'PIL.Image.Image'>格式的图片
    # x2: name_list = train_name 是def get_name_label的第一个返回值name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
    # x3: label_list = train_label 是def get_name_label的第二个返回值label_list = [1,1,...,2]
    # x4: savePath = train_feat_path = train/ 特征被保存在这里
    i = 0
    for image in image_list:
        try:
            image = image.resize((64, 128))  # 调整图片大小,因为人高近似是宽的2倍
            # 如果是灰度图片  把3改为-1
            image = np.reshape(image, (image_height, image_width, 3))
        except:
            print('发送了异常,图片大小size不满足要求:', name_list[i])
            continue
        gray = rgb2gray(image) / 255.0
        # 提取hog特征, 根据需求改, 这句话根据你的尺寸改改
        fd = hog(gray, orientations=12, block_norm='L1', pixels_per_cell=[8, 8], cells_per_block=[4, 4],
                 visualize=False,
                 transform_sqrt=True)
        '''
        print('fd', fd)  # fd [  5.50173054e-04   5.32123593e-05   0.00000000e+00 ...,   2.04692958e-02]
        print('fd.shape', fd.shape)  # fd.shape (12480,)
        print('type(fd)', type(fd))  # type(fd) <class 'numpy.ndarray'>
        exit()
        '''
        fd = np.concatenate((fd, [label_list[i]]))  # =>形如:label_list = [1,1,...,2] 
        '''
        print('[label_list[i]]', [label_list[i]])  # [label_list[i]] ['1']
        print('type([label_list[i]])', type([label_list[i]]))  # type([label_list[i]]) <class 'list'>
        print('type(label_list[i])', type(label_list[i]))  # type(label_list[i]) <class 'str'>
        exit()
        '''
        # =>fd就是后面 ===> 3)训练 <=== 里面的data = job.lib.load()
        # 将image_list里面<class 'PIL.Image.Image'>格式图片resize, np.reshape之后与label_list = [1,1,...,2]对应
        fd_name = name_list[i] + '.feat'  # 对应名字name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']加后缀
        fd_path = os.path.join(savePath, fd_name)  # 前面加train/保存路径 = train/dw1.jpg.feat
        # print('fd_path', fd_path)  # train/001-1.jpg.feat
        joblib.dump(fd, fd_path)  # =>把相应的特征fd保存在对应的train/dw1.jpg.feat文件里面, 通过joblib的dump可以将模型保存到本地
        i += 1
    print("Test features are extracted and saved.")


# =>变成灰度图片
def rgb2gray(im):
    gray = im[:, :, 0] * 0.2989 + im[:, :, 1] * 0.5870 + im[:, :, 2] * 0.1140
    return gray
# \=== ===> 2)提取特征 <=== ===/


# /=== ===> 3)训练 <=== ===\
def nk_train():
    t_train0 = time.time()  # 计时start
    features = []
    labels = []
    # train_feat_path = 'train/', 此目录下所有后缀为.feat的文件分别逐个给feat_path进行操作
    for feat_path in glob.glob(os.path.join(train_feat_path, '*.feat')):
        data = joblib.load(feat_path)  # 通过joblib的load方法,加载保存的模型,在这里是加载hog特征eg: train/dw1.jpg.feat
        features.append(data[:-1])  # 去掉最后的标签的特征, =>fd = np.concatenate((fd, [label_list[i]]))
        labels.append(data[-1])  # 只要最后的标签
    print("Training a Linear LinearSVM Classifier.")
    clf = LinearSVC()  # =>clf 1: 准备要训练的分类器clf
    clf.fit(features, labels)  # =>clf 2: 特征与标签匹配

    # 下面的代码是保存模型的
    if not os.path.exists(model_path):  # 如果模型路径不存在, model_path = 'model/', 就创建路径
        os.makedirs(model_path)
    joblib.dump(clf, model_path + 'model')  # =>clf 3: 通过joblib的dump可以将模型保存到本地'model/'的model文件中,clf是训练的分类器
    print("训练之后的模型存放在model文件夹中")
    # exit()
    t_train1 = time.time()  # 计时end
    print('训练耗时是 : %f' % (t_train1 - t_train0) + '\n')
# \=== ===> 3)训练 <=== ===/
# \=== === === ===> 2:训练stage-end <=== === === ===/

二 训练

1主函数如下

if __name__ == '__main__':

    creat_fold()  # 创建文件

    train_stage(train_feat_path)  # 提取特征,并训练模型

    # predict_stage(test_feat_path)  # 预测

1 创建文件:

1)

=> creat_fold()   # 让定义的函数实例化

定义的函数如下

=> def creat_fold():
=>     mkdir_train()  # 不存在文件夹就创建
=>     mkdir_test()

2)

创建的文件分别为

# 创建存放训练图片路径的文件夹
=> def mkdir_train():
=>     if not os.path.exists(train_feat_path):  # 如果此路径不存在
=>         os.mkdir(train_feat_path)  # 创建此路径

注意:train_feat_path = 'train/'

# 创建存放测试图片路径的文件夹
=> def mkdir_test():
=>     if not os.path.exists(test_feat_path):  # 如果此路径不存在
=>         os.mkdir(test_feat_path)

注意:test_feat_path = 'test/'

也就是看看这个 train test 文件夹 存在不存在,不存在就创建

2 训练阶段

if __name__ == '__main__':

    creat_fold()  # 创建文件

    train_stage(train_feat_path)  # 提取特征,并训练模型

    # predict_stage(test_feat_path)  # 预测

实例化train_stage()函数

=> train_stage( train_feat_path )  # 提取特征,并训练模型

1) 训练准备,提取特征, 训练

=> def train_stage(train_feat_path):
=>     shutil.rmtree(train_feat_path)  # 递归删除文件夹下所有文件子文件,包括此文件train
=>     mkdir_train()  # 删除之后重新创建 train
=>     extra_feat_train()  # 获取训练特征并保存在文件夹
=>     nk_train()  # 训练

注意:train_feat_path = 'train/'

# 创建存放训练图片路径的文件夹
def mkdir_train():
    if not os.path.exists(train_feat_path):  # 如果此路径不存在
        os.mkdir(train_feat_path)  # 创建此路径

2)提取特征

# 提取特征
def extra_feat_train():
    t_extra0 = time.time()  # 计时start
    train_name, train_label = get_name_label(train_label_path)  # =>获得图片名称,对应的类别
 # train_label_path = image_train\train.txt

    train_image = get_image_list(train_image_path, train_name)  # =>获得图片列表
    get_feat(train_image, train_name, train_label, train_feat_path)
    t_extra1 = time.time()  # 计时end
    print('训练特征提取结束,', '特征提取耗时是 : %f' % (t_extra1 - t_extra0) + '\n')

 

get_name_label

# =>从txt获得'图片名称list',对应的'类别list'
def get_name_label(file_path):  # file_path = train_label_path = image_train\train.txt
    print("read label from ", file_path)
    name_list = []  # 用于存储名字的列表
    label_list = []  # 用于存储标签的列表
    with open(file_path) as f:
        for line in f.readlines():
            # 一般是name label  三部分,所以至少长度为3 所以可以通过这个方法来忽略空白行
            if len(line) >= 3:
                name_list.append(line.split(' ')[0])  # 以空格划分为两部分,前面部分为[0], 后面为[1]
                label_list.append(line.split(' ')[1].replace('\n', '').replace('\r', ''))
                # \r代表回车,\n代表换行, 都替换成'', 也就是去掉
                if not str(label_list[-1]).isdigit(): 
                    # 因为[-1]是最后一个, 而每次append的最后一个都是最新的,检查它如果不是数字就报错
                    print("label必须为数字,得到的是:", label_list[-1], "程序终止,请检查文件")
                    exit(1)
    return name_list, label_list

# 得到了两个列表,分别对应顺序放置 名字,标签 也是就是形如:
# name_list=['tbj1', 'tbj2',..., 'dw1']
# label_list=[1,1,...,2]

 

 

get_image_list

# =>获得'图片list'
def get_image_list(filePath, nameList):
    # x1: filePath = train_image_path = image_train\
    # x2: nameList = train_name = name_list 也就是上一个函数的第一个返回值, name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']

    print('read image from ', filePath)
    img_list = []
    for name in nameList:
        temp = Image.open(os.path.join(filePath, name))  # 形成一个完整的具体图片路径image128\tbj1, 然后用Image打开
        # print('测试是否有后缀.jpg', os.path.join(filePath, name))  # txt文件在起名字的时候就要写成dw1.jpg
        # 测试是否有后缀.jpg image_train/337-4.jpg 
        # 这里我为了统计4个人一个人有几个照片起名方式为:337-4.jpg, 4表示第4个人zjc, 337表示这个人的第337个照片,上面列表dw1.jpg只是示意

        img_list.append(temp.copy())  # 把这个图片copy出来,送进列表
        temp.close()  # 关掉这个,进行下一个图片的copy
    # print('img_list[0]里面内容的格式', type(img_list[0])) 
    #
img_list[0]里面内容的格式 <class 'PIL.Image.Image'>
    return img_list

 

get_feat

# =>提取特征并保存
def get_feat(image_list, name_list, label_list, savePath):
    # x1: image_list = train_image = img_list
    # 也就上一个函数def get_image_list 的返回值list放到是<class 'PIL.Image.Image'>格式的图片
    # x2: name_list = train_name 是def get_name_label的第一个返回值name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']
    # x3: label_list = train_label 是def get_name_label的第二个返回值label_list = [1,1,...,2]
    # x4: savePath = train_feat_path = train/ 特征被保存在这里

    i = 0
    for image in image_list:
        try:
            image = image.resize((64, 128))  # 调整图片大小,因为人高近似是宽的2倍
            # 如果是灰度图片  把3改为-1
            image = np.reshape(image, (image_height, image_width, 3))
        except:
            print('发送了异常,图片大小size不满足要求:', name_list[i])
            continue
        gray = rgb2gray(image) / 255.0
        # 提取hog特征, 根据需求改, 这句话根据你的尺寸改改
        fd = hog(gray, orientations=12, block_norm='L1', pixels_per_cell=[8, 8], cells_per_block=[4, 4],
                 visualize=False,
                 transform_sqrt=True)
       '''
       print('fd', fd)  # fd [  5.50173054e-04   5.32123593e-05   0.00000000e+00 ...,   2.04692958e-02]
       print('fd.shape', fd.shape)  # fd.shape (12480,)
       print('type(fd)', type(fd))  # type(fd) <class 'numpy.ndarray'>
       exit()
       '''

        fd = np.concatenate( ( fd, [ label_list[i] ] ) ) 
        # =>形如:[ label_list[0] ] = [1]     label_list = [1,1,...,2]
        # 将image_list里面<class 'PIL.Image.Image'>格式图片resize, np.reshape之后与label_list = [1,1,...,2]对应
        '''
        print('[label_list[i]]', [label_list[i]])  # [label_list[i]] ['1']
        print('type([label_list[i]])', type([label_list[i]]))  # type([label_list[i]]) <class 'list'>
        print('type(label_list[i])', type(label_list[i]))  # type(label_list[i]) <class 'str'>
        '''

        # =>fd就是后面 ===> 3)训练 <=== 里面的data = job.lib.load()
        # 将image_list里面<class 'PIL.Image.Image'>格式图片resize, np.reshape之后与label_list = [1,1,...,2]对应

        fd_name = name_list[i] + '.feat'  # 对应名字name_list=['tbj1.jpg', 'tbj2.jpg',..., 'dw1.jpg']加后缀
        fd_path = os.path.join(savePath, fd_name)  # 前面加train/保存路径 = train/dw1.jpg.feat
        print('fd_path', fd_path)
        joblib.dump(fd, fd_path)  # 把相应的特征fd保存在对应的train/dw1.jpg.feat文件里面, 通过joblib的dump可以将模型保存到本地
        i += 1
    print("Test features are extracted and saved.")

fd = np.concatenate((fd, [label_list[i]])) 

joblib.dump(fd, fd_path)  通过joblib的dump可以将模型保存到本地

joblib.dump():博客具体解释:https://blog.csdn.net/zjc910997316/article/details/84404233

rgb2gray

# =>变成灰度图片
def rgb2gray(im):
    gray = im[:, :, 0] * 0.2989 + im[:, :, 1] * 0.5870 + im[:, :, 2] * 0.1140
    return gray

3) 训练

def nk_train():
    t_train0 = time.time()  # 计时start
    features = []
    labels = []
    # train_feat_path = 'train/', 此目录下所有后缀为.feat的文件分别逐个给feat_path进行操作
    for feat_path in glob.glob(os.path.join(train_feat_path, '*.feat')):
        data = joblib.load(feat_path)  # 通过joblib的load方法,加载保存的模型,在这里是加载hog特征eg: train/dw1.jpg.feat
        features.append(data[:-1])  # 去掉最后的标签的特征, =>fd = np.concatenate((fd, [label_list[i]]))
        labels.append(data[-1])  # 只要最后的标签
    print("Training a Linear LinearSVM Classifier.")
    clf = LinearSVC()  # =>clf 1: 准备要训练的分类器clf
    clf.fit(features, labels)  # =>clf 2: 特征与标签匹配

    # 下面的代码是保存模型的
    if not os.path.exists(model_path):  # 如果模型路径不存在, model_path = 'model/', 就创建路径
        os.makedirs(model_path)
    joblib.dump(clf, model_path + 'model')  # =>clf 3: 通过joblib的dump可以将模型保存到本地'model/'的model文件中,clf是训练的分类器
    print("训练之后的模型存放在model文件夹中")
    # exit()
    t_train1 = time.time()  # 计时end
    print('训练耗时是 : %f' % (t_train1 - t_train0) + '\n')

clf1准备:clf = LinearSVC()  # from sklearn.svm import LinearSVC
clf2匹配:clf.fit(features, labels)
clf3保存: joblib.dump(clf, model_path + 'model')

model/model 没看做这个模型就叫 model

 

 

 

 

 

 

 

 

 

 

指令说明:

1 shutil.rmtree()

shutil.rmtree() 表示递归删除文件夹下的所有子文件夹和子文件


因此如果想删除E盘下某个文件夹,可以用

shutil.rmtree('E:\\myPython\\image-filter\\test', ignore_errors=True)

这样 test 文件夹内的所有文件(包括 test 本身)都会被删除,并且忽略错误。
 

2 .copy()

temp = Image.open(os.path.join(filePath, name))

temp.copy()

3 fd = np.concatenate((fd, [label_list[i]])) 

4 joblib.dump(fd, fd_path) 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

计算机视觉-Archer

图像分割没有团队的同学可加群

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值