diff --git a/pytorch_example/RUL/otherIdea/adaRNN/loss/__init__.py b/Spider/Chapter04_数据存储/__init__.py similarity index 71% rename from pytorch_example/RUL/otherIdea/adaRNN/loss/__init__.py rename to Spider/Chapter04_数据存储/__init__.py index d96a162..d8993d5 100644 --- a/pytorch_example/RUL/otherIdea/adaRNN/loss/__init__.py +++ b/Spider/Chapter04_数据存储/__init__.py @@ -2,7 +2,7 @@ ''' @Author : dingjiawen -@Date : 2023/11/9 21:34 +@Date : 2023/12/6 14:03 @Usage : @Desc : ''' \ No newline at end of file diff --git a/Spider/Chapter04_数据存储/saveJson.py b/Spider/Chapter04_数据存储/saveJson.py new file mode 100644 index 0000000..078669a --- /dev/null +++ b/Spider/Chapter04_数据存储/saveJson.py @@ -0,0 +1,50 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 14:39 +@Usage : +@Desc : 保存成Json +''' + +import json + +str = ''' +[{ + "name": "Bob", + "gender": "male", + "birthday": "1992-10-18" +}, { + "name": "Selina", + "gender": "female", + "birthday": "1995-10-18" +}] +''' +print(type(str)) +data = json.loads(str) +print(data) +print(type(data)) + +import json + +data = [{ + 'name': 'Bob', + 'gender': 'male', + 'birthday': '1992-10-18' +}] +with open('data.json', 'w', encoding='utf-8') as file: + file.write(json.dumps(data)) + +with open('data.json', 'w', encoding='utf-8') as file: + # indent就是有缩进的 + file.write(json.dumps(data, indent=2)) + +data = [{ + 'name': '张三', + 'gender': 'male', + 'birthday': '1992-10-18' +}] + +with open('data.json', 'w', encoding='utf-8') as file: + # indent就是有缩进的,ensure_ascii规定编码格式(输出中文) + file.write(json.dumps(data, indent=2, ensure_ascii=False)) diff --git a/Spider/Chapter04_数据存储/saveMySQL.py b/Spider/Chapter04_数据存储/saveMySQL.py new file mode 100644 index 0000000..877f8ce --- /dev/null +++ b/Spider/Chapter04_数据存储/saveMySQL.py @@ -0,0 +1,33 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 15:03 +@Usage : +@Desc : +''' + +import pymysql + +data = { + 'id': '20120001', + 'name': 'Bob', + 'age': 20 +} +# 通过字典动态构建插入语句 +table = 'students' +keys = ', '.join(data.keys()) +values = ', '.join(['%s'] * len(data)) +db = pymysql.connect(host='localhost', user='root', + password=None, port=3306, db='spiders') +cursor = db.cursor() +sql = 'INSERT INTO {table}({keys}) VALUES ({values})'.format( + table=table, keys=keys, values=values) +try: + if cursor.execute(sql, tuple(data.values())): + print('Successful') + db.commit() +except Exception as e: + print('Failed', e) + db.rollback() +db.close() diff --git a/Spider/Chapter04_数据存储/saveText.py b/Spider/Chapter04_数据存储/saveText.py new file mode 100644 index 0000000..abf0d8c --- /dev/null +++ b/Spider/Chapter04_数据存储/saveText.py @@ -0,0 +1,38 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 14:08 +@Usage : +@Desc :保存为Text +''' + +import requests +from pyquery import PyQuery as pq +import re + +url = 'https://ssr1.scrape.center/' +html = requests.get(url).text +doc = pq(html) +items = doc('.el-card').items() + +file = open('movies.txt', 'w', encoding='utf-8') +for item in items: + # 名称 + name = item.find('a > h2').text() + file.write(f'名称: {name}\n') + # 类别 + categories = [item.text() for item in item.find('.categories button span').items()] + file.write(f'类别: {categories}\n') + # 上映时间 + published_at = item.find('.info:contains(上映)').text() + published_at = re.search('(\d{4}-\d{2}-\d{2})', published_at).group(1) \ + if published_at and re.search('\d{4}-\d{2}-\d{2}', published_at) else None + file.write(f'上映时间: {published_at}\n') + # 评分 + score = item.find('p.score').text() + file.write(f'评分: {score}\n') + file.write(f'{"=" * 50}\n') +file.close() + + diff --git a/Spider/Chapter05_Ajax数据爬取/AjaxAnalyze.py b/Spider/Chapter05_Ajax数据爬取/AjaxAnalyze.py new file mode 100644 index 0000000..ff0cca5 --- /dev/null +++ b/Spider/Chapter05_Ajax数据爬取/AjaxAnalyze.py @@ -0,0 +1,67 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:01 +@Usage : +@Desc : +''' + +import requests +import logging +import json +from os import makedirs +from os.path import exists + +logging.basicConfig(level=logging.INFO, + format='%(asctime)s - %(levelname)s: %(message)s') + +INDEX_URL = 'https://spa1.scrape.center/api/movie/?limit={limit}&offset={offset}' +DETAIL_URL = 'https://spa1.scrape.center/api/movie/{id}' +LIMIT = 10 +TOTAL_PAGE = 10 +RESULTS_DIR = 'results' +exists(RESULTS_DIR) or makedirs(RESULTS_DIR) + + +def scrape_api(url): + logging.info('scraping %s...', url) + try: + response = requests.get(url) + if response.status_code == 200: + return response.json() + logging.error('get invalid status code %s while scraping %s', + response.status_code, url) + except requests.RequestException: + logging.error('error occurred while scraping %s', url, exc_info=True) + + +def scrape_index(page): + url = INDEX_URL.format(limit=LIMIT, offset=LIMIT * (page - 1)) + return scrape_api(url) + + +def scrape_detail(id): + url = DETAIL_URL.format(id=id) + return scrape_api(url) + + +def save_data(data): + name = data.get('name') + data_path = f'{RESULTS_DIR}/{name}.json' + json.dump(data, open(data_path, 'w', encoding='utf-8'), + ensure_ascii=False, indent=2) + + +def main(): + for page in range(1, TOTAL_PAGE + 1): + index_data = scrape_index(page) + for item in index_data.get('results'): + id = item.get('id') + detail_data = scrape_detail(id) + logging.info('detail data %s', detail_data) + save_data(detail_data) + + +if __name__ == '__main__': + main() diff --git a/pytorch_example/RUL/otherIdea/adaRNN.py b/Spider/Chapter05_Ajax数据爬取/__init__.py similarity index 71% rename from pytorch_example/RUL/otherIdea/adaRNN.py rename to Spider/Chapter05_Ajax数据爬取/__init__.py index d96a162..9d340a4 100644 --- a/pytorch_example/RUL/otherIdea/adaRNN.py +++ b/Spider/Chapter05_Ajax数据爬取/__init__.py @@ -2,7 +2,7 @@ ''' @Author : dingjiawen -@Date : 2023/11/9 21:34 +@Date : 2023/12/6 15:58 @Usage : @Desc : ''' \ No newline at end of file diff --git a/Spider/Chapter06_异步爬虫/__init__.py b/Spider/Chapter06_异步爬虫/__init__.py new file mode 100644 index 0000000..493467f --- /dev/null +++ b/Spider/Chapter06_异步爬虫/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:19 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/Spider/Chapter06_异步爬虫/aiohttpTest.py b/Spider/Chapter06_异步爬虫/aiohttpTest.py new file mode 100644 index 0000000..34976cd --- /dev/null +++ b/Spider/Chapter06_异步爬虫/aiohttpTest.py @@ -0,0 +1,28 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:57 +@Usage : aiohttp库的使用 +@Desc : +@参考:https://github.dev/Python3WebSpider/AsyncTest demo12 +''' + +import aiohttp +import asyncio + + +async def fetch(session, url): + async with session.get(url) as response: + return await response.text(), response.status + + +async def main(): + async with aiohttp.ClientSession() as session: + html, status = await fetch(session, 'https://cuiqingcai.com') + print(f'html: {html[:100]}...') + print(f'status: {status}') + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/Spider/Chapter06_异步爬虫/asynchttp/__init__.py b/Spider/Chapter06_异步爬虫/asynchttp/__init__.py new file mode 100644 index 0000000..e1b7fd4 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asynchttp/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 17:02 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/Spider/Chapter06_异步爬虫/asynchttp/aiohttpPractice.py b/Spider/Chapter06_异步爬虫/asynchttp/aiohttpPractice.py new file mode 100644 index 0000000..33945b7 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asynchttp/aiohttpPractice.py @@ -0,0 +1,86 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 19:14 +@Usage : +@Desc : +''' +import asyncio +import aiohttp +import logging +from motor.motor_asyncio import AsyncIOMotorClient + +logging.basicConfig(level=logging.INFO, + format='%(asctime)s - %(levelname)s: %(message)s') + +INDEX_URL = 'https://spa5.scrape.center/api/book/?limit=18&offset={offset}' +DETAIL_URL = 'https://spa5.scrape.center/api/book/{id}' +PAGE_SIZE = 18 +PAGE_NUMBER = 1 +CONCURRENCY = 5 + +session = None + +MONGO_CONNECTION_STRING = 'mongodb://localhost:27017' +MONGO_DB_NAME = 'books' +MONGO_COLLECTION_NAME = 'books' + +client = AsyncIOMotorClient(MONGO_CONNECTION_STRING) +db = client[MONGO_DB_NAME] +collection = db[MONGO_COLLECTION_NAME] + +semaphore = asyncio.Semaphore(CONCURRENCY) + + +async def scrape_api(url): + async with semaphore: + try: + logging.info('scraping %s', url) + async with session.get(url) as response: + return await response.json() + except aiohttp.ClientError: + logging.error('error occurred while scraping %s', url, exc_info=True) + + +async def scrape_index(page): + url = INDEX_URL.format(offset=PAGE_SIZE * (page - 1)) + return await scrape_api(url) + + +async def scrape_detail(id): + url = DETAIL_URL.format(id=id) + data = await scrape_api(url) + await save_data(data) + + +async def save_data(data): + logging.info('saving data %s', data) + if data: + return await collection.update_one({ + 'id': data.get('id') + }, { + '$set': data + }, upsert=True) + + +async def main(): + # index tasks + global session + session = aiohttp.ClientSession() + scrape_index_tasks = [asyncio.ensure_future(scrape_index(page)) for page in range(1, PAGE_NUMBER + 1)] + results = await asyncio.gather(*scrape_index_tasks) + # detail tasks + print('results', results) + ids = [] + for index_data in results: + if not index_data: continue + for item in index_data.get('results'): + ids.append(item.get('id')) + scrape_detail_tasks = [asyncio.ensure_future(scrape_detail(id)) for id in ids] + await asyncio.wait(scrape_detail_tasks) + await session.close() + + +if __name__ == '__main__': + asyncio.run(main()) diff --git a/Spider/Chapter06_异步爬虫/asynchttp/aiohttpTest.py b/Spider/Chapter06_异步爬虫/asynchttp/aiohttpTest.py new file mode 100644 index 0000000..b337865 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asynchttp/aiohttpTest.py @@ -0,0 +1,64 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:57 +@Usage : aiohttp库的使用 +@Desc : +@参考:https://github.dev/Python3WebSpider/AsyncTest demo12 +''' + +import aiohttp +import asyncio + + +async def fetch(session, url): + async with session.get(url) as response: + return await response.text(), response.status + + +async def main(): + async with aiohttp.ClientSession() as session: + html, status = await fetch(session, 'https://cuiqingcai.com') + print(f'html: {html[:100]}...') + print(f'status: {status}') + + +# 给url参数 +async def main1(): + params = {'name': 'germey', 'age': 25} + async with aiohttp.ClientSession() as session: + async with session.get('https://httpbin.org/get', params=params) as response: + print(await response.text()) + ''' + session还支持其他请求类型: + session.post('https://httpbin.org/post', data=b'data') + session.put('https://httpbin.org/put', data=b'data') + session.delete('https://httpbin.org/delete') + session.head('https://httpbin.org/get') + session.options('https://httpbin.org/get') + session.patch('https://httpbin.org/patch', data=b'data') + ''' + +# 返回的response对象 +async def main2(): + data = {'name': 'germey', 'age': 25} + # 有些返回字段前面需要加await有些则不需要,原则是,如果返回的是一个协程对象(如async修饰的方法), + # 那么前面就要加await,具体可以看aiohttp的API,其链接为 https://docs.aiohttp.org/en/stable/client_reference.html + async with aiohttp.ClientSession() as session: + async with session.post('https://httpbin.org/post', data=data) as response: + print('status:', response.status) + print('headers:', response.headers) + print('body:', await response.text()) + print('bytes:', await response.read()) + print('json:', await response.json()) + +# 超时设置 +async def main3(): + timeout = aiohttp.ClientTimeout(total=0.1) + async with aiohttp.ClientSession(timeout=timeout) as session: + async with session.get('https://httpbin.org/get') as response: + print('status:', response.status) + +if __name__ == '__main__': + asyncio.run(main2()) diff --git a/Spider/Chapter06_异步爬虫/asynchttp/aiohttpTest2.py b/Spider/Chapter06_异步爬虫/asynchttp/aiohttpTest2.py new file mode 100644 index 0000000..565a856 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asynchttp/aiohttpTest2.py @@ -0,0 +1,42 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:57 +@Usage : 并发限制 防止一次太多爬崩网站 semaphore +@Desc : +@参考:https://github.dev/Python3WebSpider/AsyncTest +''' + +import aiohttp +import asyncio + +CONCURRENCY = 5 +URL = 'https://www.baidu.com/' + +semaphore = asyncio.Semaphore(CONCURRENCY) +session = None + + +async def scrape_api(): + async with semaphore: + print('scraping', URL) + async with session.get(URL) as response: + # await asyncio.sleep(1) + return await response.text() + + +async def main(): + global session + + session = aiohttp.ClientSession() + scrape_index_tasks = [asyncio.ensure_future(scrape_api()) for _ in range(10000)] + await asyncio.gather(*scrape_index_tasks) + await asyncio.wait(scrape_index_tasks) + await session.close() + + + +if __name__ == '__main__': + # asyncio.run(main()) + asyncio.get_event_loop().run_until_complete(main()) diff --git a/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync.py b/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync.py new file mode 100644 index 0000000..e0a3f57 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync.py @@ -0,0 +1,27 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:34 +@Usage : 多任务协程 +@Desc : +@参考: https://github.dev/Python3WebSpider/AsyncTest +''' + +import asyncio +import requests + +async def request(): + url = 'https://www.baidu.com' + status = requests.get(url) + return status + +tasks = [asyncio.ensure_future(request()) for _ in range(5)] +print('Tasks:', tasks) + +loop = asyncio.get_event_loop() +# 五个任务被顺序执行 +loop.run_until_complete(asyncio.wait(tasks)) + +for task in tasks: + print('Task Result:', task.result()) \ No newline at end of file diff --git a/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync2.py b/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync2.py new file mode 100644 index 0000000..ca0d04b --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync2.py @@ -0,0 +1,33 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:34 +@Usage : 多任务协程展示协程的优势 +@Desc : +@参考: https://github.dev/Python3WebSpider/AsyncTest demo8_1和demo9_1 demo10 + +''' + + +import asyncio +import requests +import time + +start = time.time() + + +# 单个执行每个都至少要5秒 +async def request(): + url = 'https://httpbin.org/delay/5' + print('Waiting for', url) + # 这里无论是加await还是不加await都无法实现真正意义上的异步 需要使用aiohttp + response = requests.get(url) + print('Get response from', url, 'response', response) + +tasks = [asyncio.ensure_future(request()) for _ in range(10)] +loop = asyncio.get_event_loop() +loop.run_until_complete(asyncio.wait(tasks)) + +end = time.time() +print('Cost time:', end - start) \ No newline at end of file diff --git a/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync3.py b/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync3.py new file mode 100644 index 0000000..d60feda --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asyncio/MultiTaskAsync3.py @@ -0,0 +1,40 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:34 +@Usage : 多任务协程展示协程的优势 +@Desc : +@参考: https://github.dev/Python3WebSpider/AsyncTest demo11 + +''' + +import asyncio +import aiohttp +import time + +start = time.time() + + +async def get(url): + session = aiohttp.ClientSession() + response = await session.get(url) + await response.text() + await session.close() + return response + + +async def request(): + url = 'https://httpbin.org/delay/5' + print('Waiting for', url) + response = await get(url) + print('Get response from', url, 'response', response) + + +tasks = [asyncio.ensure_future(request()) for _ in range(100)] +loop = asyncio.get_event_loop() +loop.run_until_complete(asyncio.wait(tasks)) + +end = time.time() +print('Cost time:', end - start) +# Cost time: 7.670234203338623 diff --git a/Spider/Chapter06_异步爬虫/asyncio/__init__.py b/Spider/Chapter06_异步爬虫/asyncio/__init__.py new file mode 100644 index 0000000..e1b7fd4 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asyncio/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 17:02 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/Spider/Chapter06_异步爬虫/asyncio/asyncTest1.py b/Spider/Chapter06_异步爬虫/asyncio/asyncTest1.py new file mode 100644 index 0000000..7f3ba74 --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asyncio/asyncTest1.py @@ -0,0 +1,29 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:20 +@Usage : asyncio库 可以使用async和await关键字 +@Desc :异步爬虫测试 定义协程 +@参考:https://github.dev/Python3WebSpider/AsyncTest +''' +import asyncio + + +async def execute(x): + print('Number:', x) + return x + +# 创建一个协程对象 coroutine +coroutine = execute(1) + +print('Coroutine:', coroutine) +print('After calling execute') + +loop = asyncio.get_event_loop() + +task = loop.create_task(coroutine) +print('Task:', task) +loop.run_until_complete(task) +print('Task:', task) +print('After calling loop') diff --git a/Spider/Chapter06_异步爬虫/asyncio/asyncTest2.py b/Spider/Chapter06_异步爬虫/asyncio/asyncTest2.py new file mode 100644 index 0000000..d02416b --- /dev/null +++ b/Spider/Chapter06_异步爬虫/asyncio/asyncTest2.py @@ -0,0 +1,38 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 16:20 +@Usage : asyncio库 可以使用async和await关键字 +@Desc :异步爬虫测试 定义协程 为某一个task绑定回调方法 +@参考:https://github.dev/Python3WebSpider/AsyncTest +''' +import asyncio +import requests + + +async def request(): + url = 'https://www.baidu.com' + status = requests.get(url) + return status + + +def callback(task): + print('Status:', task.result()) + + +coroutine = request() +task = asyncio.ensure_future(coroutine) +# 绑定回调,来保证顺序 +task.add_done_callback(callback) +print('Task:', task) + +loop = asyncio.get_event_loop() +loop.run_until_complete(task) +print('Task:', task) + +# 直接通过task.result()也可以直接获取结果达到类似的效果 +loop = asyncio.get_event_loop() +loop.run_until_complete(task) +print('Task:', task) +print('Task Result:', task.result()) diff --git a/Spider/Chapter07_动态渲染页面爬取/__init__.py b/Spider/Chapter07_动态渲染页面爬取/__init__.py new file mode 100644 index 0000000..6eaa040 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/__init__.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/__init__.py new file mode 100644 index 0000000..763ab1f --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 19:53 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo1.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo1.py new file mode 100644 index 0000000..70db6fc --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo1.py @@ -0,0 +1,30 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 19:53 +@Usage : +@Desc : selenium基本用法 +@参考: https://github.dev/Python3WebSpider/SeleniumTest +''' + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.common.keys import Keys +from selenium.webdriver.support import expected_conditions as EC +from selenium.webdriver.support.wait import WebDriverWait + +browser = webdriver.Chrome() +try: + browser.get('https://www.baidu.com') + # input = browser.find_element_by_id('kw') 旧版写法,selenium4.0以上使用下面的写法 + input = browser.find_element(By.ID, 'kw') + input.send_keys('Python') + input.send_keys(Keys.ENTER) + wait = WebDriverWait(browser, 10) + wait.until(EC.presence_of_element_located((By.ID, 'content_left'))) + print(browser.current_url) + print(browser.get_cookies()) + print(browser.page_source) +finally: + browser.close() diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo10Cookie.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo10Cookie.py new file mode 100644 index 0000000..5a6c888 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo10Cookie.py @@ -0,0 +1,18 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 21:11 +@Usage : 对Cookie进行操作 +@Desc :获取,添加,删除cookie +''' + +from selenium import webdriver + +browser = webdriver.Chrome() +browser.get('https://www.zhihu.com/explore') +print(browser.get_cookies()) +browser.add_cookie({'name': 'name', 'domain': 'www.zhihu.com', 'value': 'germey'}) +print(browser.get_cookies()) +browser.delete_all_cookies() +print(browser.get_cookies()) \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo11选项卡管理.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo11选项卡管理.py new file mode 100644 index 0000000..e4d535a --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo11选项卡管理.py @@ -0,0 +1,22 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 21:14 +@Usage : 选项卡管理 +@Desc : 访问页面的时候会开起一个个选项卡 +''' + +import time +from selenium import webdriver + +browser = webdriver.Chrome() +browser.get('https://www.baidu.com') +# 开启一个新的选项卡 +browser.execute_script('window.open()') +print(browser.window_handles) +browser.switch_to.window(browser.window_handles[1]) +browser.get('https://www.taobao.com') +time.sleep(1) +browser.switch_to.window(browser.window_handles[0]) +browser.get('https://python.org') \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo12异常处理.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo12异常处理.py new file mode 100644 index 0000000..c6a81d6 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo12异常处理.py @@ -0,0 +1,26 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 21:17 +@Usage : 异常处理 +@Desc : 可能会遇到获取节点失败的异常,可以对异常进行处理 +''' + +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.common.exceptions import TimeoutException, NoSuchElementException + +browser = webdriver.Chrome() + +try: + browser.get('https://www.baidu.com') +except TimeoutException: + print('Time out') + +try: + browser.find_element(By.ID, 'hello') +except NoSuchElementException: + print('No Such Element') +finally: + browser.close() diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo13反屏蔽.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo13反屏蔽.py new file mode 100644 index 0000000..687e4c8 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo13反屏蔽.py @@ -0,0 +1,33 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 21:20 +@Usage : 反屏蔽 +@Desc : 现在很多网站增加了对Selenium的监测,如果检测到Selenium打开浏览器就直接屏蔽 +基本原理是监测当前浏览器窗口下的window.navigator对象中是否包含webdriver属性。 +正常使用浏览器这个属性应该是undefined,一旦使用了Selenium,就会给window.navigator设置webdriver属性 +https://antispider1.scrape.center/ 就是使用了上述原理 +''' +from selenium import webdriver +from selenium.webdriver import ChromeOptions + +option = ChromeOptions() +option.add_experimental_option('excludeSwitches', ['enable-automation']) +option.add_experimental_option('useAutomationExtension', False) +browser = webdriver.Chrome(options=option) +# 无效,因为这是页面加载完毕之后才执行,但是页面渲染之前已经检测了 +browser.execute_script('Object.defineProperty(navigator, "webdriver", {get: () => undefined})') +browser.get('https://antispider1.scrape.center/') + + + +# 使用CDP(chrome开发工具协议)解决这个问题,在每个页面刚加载的时候就执行JavaScript语句,将webdriver置空 +option = ChromeOptions() +option.add_experimental_option('excludeSwitches', ['enable-automation']) +option.add_experimental_option('useAutomationExtension', False) +browser = webdriver.Chrome(options=option) +browser.execute_cdp_cmd('Page.addScriptToEvaluateOnNewDocument', { + 'source': 'Object.defineProperty(navigator, "webdriver", {get: () => undefined})' +}) +browser.get('https://antispider1.scrape.cuiqingcai.com/') diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo14无头模式.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo14无头模式.py new file mode 100644 index 0000000..86af476 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo14无头模式.py @@ -0,0 +1,20 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 21:31 +@Usage : 无头模式 +@Desc : 之前的案例运行时,总会弹出一个路浏览器窗口 +现在已经支持无头模式Headless +''' + + +from selenium import webdriver +from selenium.webdriver import ChromeOptions + +option = ChromeOptions() +option.add_argument('--headless') +browser = webdriver.Chrome(options=option) +browser.set_window_size(1366, 768) +browser.get('https://www.baidu.com') +browser.get_screenshot_as_file('preview.png') \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo2.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo2.py new file mode 100644 index 0000000..039facc --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo2.py @@ -0,0 +1,22 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 19:59 +@Usage : +@Desc :selenium访问页面与查找节点 +''' + +from selenium import webdriver +from selenium.webdriver.common.by import By + +browser = webdriver.Chrome() +browser.get('https://www.taobao.com') +input_first = browser.find_element(By.ID, 'q') +input_second = browser.find_element(By.CSS_SELECTOR, '#q') +input_third = browser.find_element(By.XPATH, '//*[@id="q"]') +print(input_first, input_second, input_third) +# 多个节点 +lis = browser.find_elements(By.CSS_SELECTOR,'.service-bd li') +print(lis) +browser.close() diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo3.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo3.py new file mode 100644 index 0000000..0156c6c --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo3.py @@ -0,0 +1,22 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:04 +@Usage : +@Desc :selenium节点交互 驱动浏览器实现一些操作 +''' + +from selenium import webdriver +from selenium.webdriver.common.by import By +import time + +browser = webdriver.Chrome() +browser.get('https://www.taobao.com') +input = browser.find_element(By.ID, 'q') +input.send_keys('iPhone') # 输入文字 +time.sleep(1) +input.clear() # 清空文字 +input.send_keys('iPad') +button = browser.find_element(By.CLASS_NAME, 'btn-search') +button.click() # 点击搜索 diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo4.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo4.py new file mode 100644 index 0000000..b1b3872 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo4.py @@ -0,0 +1,23 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:08 +@Usage : +@Desc :selenium动作链 一系列动作连续执行 +''' + +from selenium import webdriver +from selenium.webdriver import ActionChains +from selenium.webdriver.common.by import By + +browser = webdriver.Chrome() +url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' +browser.get(url) +browser.switch_to.frame('iframeResult') +source = browser.find_element(By.CSS_SELECTOR, '#draggable') +target = browser.find_element(By.CSS_SELECTOR, '#droppable') +actions = ActionChains(browser) +# 模拟鼠标的点击与放下 +actions.drag_and_drop(source, target) +actions.perform() # 正式执行上述模拟操作 diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo5.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo5.py new file mode 100644 index 0000000..40e19c4 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo5.py @@ -0,0 +1,20 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:14 +@Usage : +@Desc :selenium运行javaScrip,有一些操作selenium没有提供API,这时可以直接通过运行javascript实现 +''' + +from selenium import webdriver +import time +browser = webdriver.Chrome() +browser.get('https://www.zhihu.com/explore') +# browser.get('https://www.taobao.com') +# 将进度条下拉到最底部 +browser.execute_script('window.scrollTo(0, document.body.scrollHeight)') +# 弹出警告提示框 +browser.execute_script('alert("To Bottom")') +time.sleep(5) +browser.close() \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo6.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo6.py new file mode 100644 index 0000000..daf1645 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo6.py @@ -0,0 +1,27 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:20 +@Usage : +@Desc :获取节点信息 +''' + +from selenium import webdriver +from selenium.webdriver.common.by import By + +browser = webdriver.Chrome() +url = 'https://spa2.scrape.center/' +browser.get(url) +logo = browser.find_element(By.CLASS_NAME, 'logo-image') +print(logo) +# 获取属性 +print(logo.get_attribute('src')) +# 获取文本值 +title = browser.find_element(By.CLASS_NAME, 'logo-title') +print(title.text) +# 获取ID,位置,标签名,大小 +print(title.id) +print(title.location) +print(title.tag_name) +print(title.size) \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo7.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo7.py new file mode 100644 index 0000000..32a2aad --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo7.py @@ -0,0 +1,26 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:31 +@Usage : 切换Frame +@Desc : 网页中有一种节点叫iframe,相当于页面的子页面, + selenium打开一个页面后,默认是在父Frame里面操作,这时需要使用switch_to.frame方法切换 +''' +import time +from selenium import webdriver +from selenium.common.exceptions import NoSuchElementException +from selenium.webdriver.common.by import By + +browser = webdriver.Chrome() +url = 'http://www.runoob.com/try/try.php?filename=jqueryui-api-droppable' +browser.get(url) +browser.switch_to.frame('iframeResult') +try: + logo = browser.find_element(By.CLASS_NAME, 'logo') +except NoSuchElementException: + print('NO LOGO') +browser.switch_to.parent_frame() +logo = browser.find_element(By.CLASS_NAME, 'logo') +print(logo) +print(logo.text) diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo8前进后退.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo8前进后退.py new file mode 100644 index 0000000..70407b7 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo8前进后退.py @@ -0,0 +1,31 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:38 +@Usage : 延时等待 +@Desc :get方法在网页框架加载结束后才会结束执行 + 所以在get方法执行完毕之后其结果可能并不是浏览器完全加载完成的页面 + 所以在必要时我们需要设置浏览器延时等待一段时间 +''' +from selenium import webdriver +from selenium.webdriver.common.by import By +from selenium.webdriver.support.ui import WebDriverWait +from selenium.webdriver.support import expected_conditions as EC + +browser = webdriver.Chrome() +# 隐式等待 :效果并不好,因为只规定了一个固定时间,页面加载事件会受到网络条件影响 +browser.implicitly_wait(10) +browser.get('https://spa2.scrape.center/') +input = browser.find_element(By.CLASS_NAME, 'logo-image') +print(input) + + +# 显示等待:指定要查找的节点和最长等待时间 +browser.get('https://www.taobao.com/') +wait = WebDriverWait(browser, 10) +# presence_of_element_located这个条件表示节点出现 +input = wait.until(EC.presence_of_element_located((By.ID, 'q'))) +# element_to_be_clickable表示按钮可点击 +button = wait.until(EC.element_to_be_clickable((By.CSS_SELECTOR, '.btn-search'))) +print(input, button) \ No newline at end of file diff --git a/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo9延时等待.py b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo9延时等待.py new file mode 100644 index 0000000..b4977b6 --- /dev/null +++ b/Spider/Chapter07_动态渲染页面爬取/seleniumLearning/demo9延时等待.py @@ -0,0 +1,21 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/12/6 20:38 +@Usage : 模拟浏览器前进后退功能 +@Desc : +''' +import time +from selenium import webdriver + +browser = webdriver.Chrome() +browser.get('https://www.baidu.com/') +browser.get('https://www.taobao.com/') +browser.get('https://www.python.org/') +# 后退 +browser.back() +time.sleep(1) +# 前进 +browser.forward() +browser.close() \ No newline at end of file diff --git a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/Bearing1_1.npy b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/Bearing1_1.npy new file mode 100644 index 0000000..25a280f Binary files /dev/null and b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/Bearing1_1.npy differ diff --git a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_create.py b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_create.py index 0e9f033..98e1366 100644 --- a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_create.py +++ b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_create.py @@ -6,6 +6,8 @@ import matplotlib.pyplot as plt # 数据导入 data = np.load("../data/HI_DATA/HI_data.npy") print(data.shape) # (2803, 2560) +plt.plot(data[0,:]) +plt.show() (samples, dims) = data.shape # # 24个指标建立 diff --git a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_merge.py b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_merge.py index d46b5c3..d23c3fa 100644 --- a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_merge.py +++ b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/HI_merge.py @@ -2,6 +2,7 @@ import tensorflow as tf import numpy as np import pandas as pd import matplotlib.pyplot as plt +from keras.callbacks import EarlyStopping # 数据读取 # train_data = np.load("Select_data.npy") @@ -17,8 +18,14 @@ for index in indexs: Selected_data = np.vstack([Selected_data, feature_data[:, index]]) z += 1 Selected_data = np.transpose(Selected_data, [1, 0]) # (2803,9) + +plt.plot(Selected_data) +plt.show() + train_data=Selected_data[1500:-1,:] print(train_data.shape) +plt.plot(train_data) +plt.show() # 建立模型 @@ -51,12 +58,25 @@ class model(): if __name__ == '__main__': model = model(input_shape=6).getModel(model_Type='ae') model.compile(optimizer=tf.optimizers.Adam(0.001), loss=tf.losses.mse, metrics=['acc']) - model.summary() + # model.summary() - history = model.fit(train_data, train_data, epochs=300, batch_size=100) + checkpoint = tf.keras.callbacks.ModelCheckpoint( + filepath="AE_model.h5", + monitor='val_loss', + verbose=2, + save_best_only=True, + mode='min') + lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=10, min_lr=0.0001) + + model.compile(optimizer=tf.optimizers.SGD(), loss=tf.losses.mse) + # model.compile(optimizer=tf.optimizers.SGD(learning_rate=0.001), loss=FTMSE()) + model.summary() + early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=20, mode='min', verbose=1) + + history = model.fit(train_data, train_data, epochs=1000, batch_size=100) HI_merge_data = tf.keras.models.Model(inputs=model.input, outputs=model.get_layer('mid').output).predict(train_data) print(HI_merge_data) acc = np.array(history.history.get('acc')) # if acc[299] > 0.9: - np.save("HI_merge_data.npy", HI_merge_data) + np.save("HI_merge_data1.npy", HI_merge_data) model.save("AE_model.h5") diff --git a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/smallVHI.csv b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/smallVHI.csv new file mode 100644 index 0000000..3cc183f --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/smallVHI.csv @@ -0,0 +1,1250 @@ +0.0172 +0.0173 +0.0184 +0.0343 +0.0195 +0.0284 +0 +0.0263 +0.0079 +0.0073 +0.0299 +0.023 +0.0475 +0.0229 +0.0623 +0.0235 +0.0272 +0.0325 +0.0168 +0.0044 +0.0217 +0.052 +0.043 +0.0125 +0.046 +0.0352 +0.0113 +0.0551 +0.0255 +0.0102 +0.0231 +0.018 +0.041 +0.0609 +0.0598 +0.0192 +0.0387 +0.0509 +0.0073 +0.0573 +0.0336 +0.0514 +0.0263 +0.0206 +0.0261 +0.0195 +0.044 +0.0488 +0.0102 +0.0424 +0.0204 +0.0127 +0.0212 +0.0346 +0.0282 +0.0379 +0.0369 +0.0335 +0.0425 +0.0313 +0.0341 +0.0527 +0.0622 +0.0487 +0.0714 +0.06 +0.0654 +0.0241 +0.0403 +0.0755 +0.0403 +0.041 +0.0439 +0.0447 +0.0401 +0.0414 +0.0283 +0.0233 +0.0209 +0.0451 +0.0515 +0.0447 +0.0675 +0.0385 +0.0535 +0.0322 +0.0261 +0.0499 +0.0249 +0.0573 +0.0586 +0.0416 +0.0478 +0.038 +0.028 +0.0102 +0.0164 +0.0322 +0.0204 +0.0626 +0.0405 +0.0538 +0.0495 +0.0585 +0.0283 +0.0489 +0.0488 +0.0475 +0.0429 +0.0316 +0.0442 +0.0476 +0.0507 +0.0375 +0.0316 +0.0318 +0.0695 +0.0515 +0.0343 +0.0336 +0.0308 +0.0211 +0.0286 +0.0324 +0.0706 +0.0618 +0.0366 +0.0718 +0.035 +0.0588 +0.0292 +0.0414 +0.022 +0.0557 +0.064 +0.0645 +0.0722 +0.1067 +0.103 +0.0821 +0.0641 +0.0423 +0.039 +0.0629 +0.0678 +0.0475 +0.057 +0.0517 +0.0711 +0.0728 +0.082 +0.0705 +0.0693 +0.0354 +0.0305 +0.0719 +0.0794 +0.0795 +0.0573 +0.0677 +0.0378 +0.0483 +0.0827 +0.0726 +0.0504 +0.079 +0.0954 +0.0815 +0.071 +0.067 +0.0972 +0.0423 +0.0529 +0.0634 +0.0326 +0.04 +0.0712 +0.0591 +0.0785 +0.0358 +0.0642 +0.0434 +0.0338 +0.0776 +0.0499 +0.0421 +0.0414 +0.0592 +0.0594 +0.0559 +0.0647 +0.029 +0.0501 +0.0602 +0.0543 +0.0488 +0.074 +0.034 +0.0567 +0.0589 +0.0699 +0.064 +0.0409 +0.0663 +0.0722 +0.064 +0.1028 +0.058 +0.0608 +0.0751 +0.0704 +0.0387 +0.0725 +0.0675 +0.0396 +0.0446 +0.0245 +0.0582 +0.0619 +0.051 +0.0596 +0.0637 +0.0686 +0.0578 +0.0951 +0.0749 +0.033 +0.0584 +0.0348 +0.0499 +0.0484 +0.0972 +0.1084 +0.1107 +0.0661 +0.073 +0.0901 +0.0501 +0.0878 +0.0525 +0.076 +0.0646 +0.0773 +0.0881 +0.0628 +0.1025 +0.1127 +0.0581 +0.0916 +0.0858 +0.0868 +0.1234 +0.0811 +0.0522 +0.0624 +0.0568 +0.1198 +0.105 +0.1004 +0.0877 +0.0575 +0.1017 +0.0767 +0.0887 +0.0587 +0.0793 +0.0697 +0.0882 +0.0907 +0.0946 +0.077 +0.0744 +0.0966 +0.076 +0.0354 +0.0779 +0.0686 +0.0926 +0.0898 +0.1199 +0.0632 +0.0912 +0.0736 +0.1014 +0.098 +0.0648 +0.0831 +0.0625 +0.1113 +0.1017 +0.1146 +0.1055 +0.0746 +0.0907 +0.0925 +0.1694 +0.0823 +0.0782 +0.0545 +0.0805 +0.1099 +0.1155 +0.1038 +0.0421 +0.0835 +0.0905 +0.1209 +0.1092 +0.0824 +0.0584 +0.0608 +0.0681 +0.0741 +0.0634 +0.0785 +0.1236 +0.0866 +0.0776 +0.0759 +0.0814 +0.0833 +0.0413 +0.0487 +0.1114 +0.074 +0.0905 +0.0893 +0.0519 +0.0838 +0.1004 +0.0864 +0.1133 +0.0886 +0.0901 +0.0694 +0.0901 +0.0998 +0.0797 +0.0847 +0.1201 +0.0615 +0.0656 +0.1266 +0.1007 +0.0955 +0.0511 +0.0826 +0.0693 +0.0685 +0.1515 +0.0655 +0.1055 +0.0727 +0.0809 +0.0998 +0.139 +0.0532 +0.0739 +0.1126 +0.1364 +0.0789 +0.101 +0.0866 +0.1181 +0.1094 +0.0966 +0.0613 +0.0636 +0.1289 +0.0995 +0.0813 +0.1515 +0.0972 +0.1173 +0.1266 +0.089 +0.1061 +0.1101 +0.1218 +0.1125 +0.1227 +0.113 +0.1263 +0.0578 +0.124 +0.0779 +0.0698 +0.1036 +0.0962 +0.0972 +0.1371 +0.0819 +0.1424 +0.1469 +0.1255 +0.0953 +0.1116 +0.096 +0.1208 +0.1163 +0.191 +0.1107 +0.1281 +0.1235 +0.1206 +0.1571 +0.1084 +0.0933 +0.1093 +0.1016 +0.1056 +0.0762 +0.0792 +0.1287 +0.0879 +0.1012 +0.0891 +0.105 +0.1143 +0.0853 +0.0805 +0.0821 +0.091 +0.1156 +0.1762 +0.1021 +0.1004 +0.1263 +0.0923 +0.1176 +0.1169 +0.1263 +0.1526 +0.2063 +0.1094 +0.1311 +0.1224 +0.19 +0.1229 +0.0918 +0.1145 +0.1675 +0.0923 +0.1179 +0.1415 +0.1301 +0.1456 +0.1443 +0.1555 +0.1051 +0.112 +0.0803 +0.1408 +0.1674 +0.1202 +0.1671 +0.1104 +0.1596 +0.1606 +0.1115 +0.185 +0.1496 +0.1573 +0.1228 +0.1017 +0.1238 +0.1138 +0.1174 +0.1429 +0.1604 +0.1286 +0.1269 +0.117 +0.1648 +0.11 +0.0936 +0.1252 +0.1158 +0.1363 +0.1192 +0.1564 +0.1659 +0.0866 +0.1234 +0.1441 +0.1549 +0.1362 +0.1102 +0.1421 +0.1678 +0.1118 +0.1146 +0.1343 +0.1301 +0.1011 +0.1823 +0.146 +0.1433 +0.1231 +0.1221 +0.1437 +0.1294 +0.1255 +0.1589 +0.0997 +0.1551 +0.1258 +0.1073 +0.131 +0.136 +0.1562 +0.1438 +0.1684 +0.1703 +0.1172 +0.1278 +0.1587 +0.1454 +0.2502 +0.1585 +0.1433 +0.1939 +0.1465 +0.1774 +0.1651 +0.2331 +0.1853 +0.1402 +0.1718 +0.1303 +0.1495 +0.1269 +0.1663 +0.1804 +0.2434 +0.1473 +0.1921 +0.1706 +0.1693 +0.1103 +0.1199 +0.1017 +0.1514 +0.1877 +0.1937 +0.1893 +0.1702 +0.2143 +0.2283 +0.2315 +0.1142 +0.1371 +0.1486 +0.1606 +0.1422 +0.2449 +0.1312 +0.1255 +0.1884 +0.1355 +0.2155 +0.1702 +0.1891 +0.1667 +0.1595 +0.1229 +0.156 +0.1516 +0.1883 +0.1425 +0.1702 +0.1368 +0.1613 +0.1708 +0.133 +0.1137 +0.1426 +0.1428 +0.146 +0.1712 +0.1291 +0.1806 +0.1393 +0.129 +0.1659 +0.1364 +0.1258 +0.1451 +0.188 +0.1495 +0.1251 +0.1955 +0.1553 +0.2071 +0.1557 +0.1533 +0.1341 +0.1565 +0.1308 +0.2062 +0.1284 +0.1162 +0.1312 +0.1397 +0.1607 +0.1403 +0.2012 +0.1944 +0.1398 +0.1114 +0.2279 +0.2039 +0.1746 +0.1646 +0.1905 +0.1928 +0.179 +0.2535 +0.1739 +0.1342 +0.1765 +0.1953 +0.2236 +0.167 +0.1562 +0.1491 +0.2115 +0.1774 +0.2054 +0.1837 +0.1796 +0.2151 +0.1979 +0.2116 +0.2192 +0.192 +0.2278 +0.2001 +0.2563 +0.1912 +0.2174 +0.2191 +0.2168 +0.1597 +0.1376 +0.1651 +0.1836 +0.2059 +0.1305 +0.1586 +0.1908 +0.1827 +0.1883 +0.2125 +0.2171 +0.164 +0.1983 +0.2403 +0.2206 +0.1958 +0.1706 +0.2473 +0.2015 +0.1581 +0.1908 +0.2192 +0.2896 +0.2545 +0.1967 +0.1643 +0.1846 +0.183 +0.201 +0.2145 +0.17 +0.1785 +0.1418 +0.2342 +0.237 +0.2261 +0.2521 +0.1714 +0.185 +0.2326 +0.225 +0.2167 +0.2032 +0.2879 +0.1751 +0.1834 +0.1914 +0.1887 +0.2251 +0.2016 +0.2209 +0.1873 +0.2692 +0.2183 +0.2082 +0.1809 +0.2293 +0.2262 +0.2202 +0.2152 +0.2536 +0.2442 +0.3825 +0.2664 +0.2277 +0.2192 +0.2455 +0.1534 +0.1547 +0.2054 +0.1748 +0.1844 +0.2099 +0.246 +0.1989 +0.2397 +0.2051 +0.1851 +0.3339 +0.19 +0.3349 +0.2158 +0.2426 +0.1891 +0.2486 +0.2328 +0.2353 +0.2586 +0.2783 +0.1974 +0.2128 +0.1494 +0.2046 +0.2105 +0.2317 +0.1946 +0.2395 +0.2304 +0.2216 +0.2267 +0.182 +0.1863 +0.2474 +0.1757 +0.2081 +0.2369 +0.2328 +0.2087 +0.2279 +0.1745 +0.1745 +0.168 +0.2489 +0.3041 +0.1817 +0.2142 +0.2136 +0.2668 +0.2303 +0.2441 +0.2334 +0.2373 +0.2365 +0.2096 +0.199 +0.1817 +0.2348 +0.3724 +0.2099 +0.3305 +0.3063 +0.1907 +0.1297 +0.2612 +0.185 +0.1893 +0.2286 +0.1886 +0.1741 +0.2299 +0.2107 +0.1837 +0.22 +0.1964 +0.2035 +0.195 +0.2165 +0.317 +0.2295 +0.2058 +0.2045 +0.2293 +0.2596 +0.2873 +0.3949 +0.2709 +0.2992 +0.2454 +0.2525 +0.1963 +0.2301 +0.2735 +0.1448 +0.2017 +0.2114 +0.3402 +0.2622 +0.257 +0.2141 +0.3416 +0.2514 +0.2063 +0.2068 +0.2411 +0.2481 +0.2748 +0.2097 +0.1769 +0.213 +0.2531 +0.3399 +0.2114 +0.1741 +0.3608 +0.2595 +0.2129 +0.2026 +0.2791 +0.3923 +0.2736 +0.2739 +0.2974 +0.2936 +0.2706 +0.2565 +0.2346 +0.3494 +0.3222 +0.316 +0.256 +0.3213 +0.3094 +0.3008 +0.2846 +0.223 +0.1944 +0.3038 +0.3075 +0.2477 +0.3725 +0.3159 +0.2407 +0.2855 +0.355 +0.3561 +0.2729 +0.2497 +0.2147 +0.3445 +0.2465 +0.237 +0.2802 +0.4251 +0.2764 +0.2885 +0.3291 +0.2509 +0.2526 +0.2104 +0.2625 +0.2605 +0.3001 +0.2353 +0.1882 +0.2352 +0.233 +0.3604 +0.3438 +0.3816 +0.2953 +0.4096 +0.4453 +0.3545 +0.2791 +0.3215 +0.3582 +0.3165 +0.2832 +0.3268 +0.2956 +0.233 +0.4115 +0.2559 +0.3055 +0.2407 +0.4052 +0.3081 +0.3109 +0.2946 +0.2055 +0.2276 +0.2574 +0.262 +0.2096 +0.1949 +0.4268 +0.3888 +0.2314 +0.2176 +0.2635 +0.4945 +0.275 +0.2142 +0.215 +0.4962 +0.2658 +0.3692 +0.2175 +0.2144 +0.2659 +0.392 +0.269 +0.4556 +0.2631 +0.3976 +0.206 +0.3458 +0.2753 +0.3061 +0.5305 +0.383 +0.3333 +0.4005 +0.3835 +0.2546 +0.3214 +0.3995 +0.3174 +0.3417 +0.2655 +0.4024 +0.3623 +0.3471 +0.323 +0.3178 +0.3838 +0.3689 +0.2826 +0.4032 +0.4184 +0.3008 +0.2677 +0.2952 +0.4304 +0.2814 +0.3265 +0.4046 +0.3735 +0.3982 +0.3849 +0.3772 +0.285 +0.2919 +0.5386 +0.3341 +0.2517 +0.3513 +0.3324 +0.3069 +0.3389 +0.4039 +0.3462 +0.3834 +0.3369 +0.3582 +0.3184 +0.3303 +0.3144 +0.5149 +0.334 +0.2345 +0.4414 +0.2834 +0.3183 +0.3406 +0.3606 +0.2516 +0.3645 +0.3422 +0.3843 +0.2712 +0.3439 +0.2205 +0.261 +0.35 +0.2873 +0.3923 +0.2437 +0.3979 +0.3217 +0.3672 +0.3512 +0.4098 +0.2953 +0.4178 +0.2812 +0.2768 +0.2705 +0.3987 +0.297 +0.3169 +0.3029 +0.3434 +0.3584 +0.2606 +0.3941 +0.5976 +0.3004 +0.242 +0.2621 +0.3839 +0.3487 +0.3627 +0.3603 +0.3469 +0.3268 +0.3947 +0.3415 +0.3474 +0.3926 +0.4104 +0.4281 +0.3367 +0.3126 +0.2975 +0.3191 +0.3085 +0.3141 +0.3719 +0.3386 +0.2989 +0.345 +0.2906 +0.4719 +0.5137 +0.3735 +0.479 +0.2743 +0.3422 +0.3122 +0.3753 +0.4102 +0.2796 +0.3068 +0.3452 +0.2825 +0.2521 +0.3378 +0.3169 +0.2555 +0.4341 +0.3855 +0.2625 +0.2347 +0.332 +0.336 +0.3089 +0.3382 +0.2977 +0.3854 +0.3486 +0.4122 +0.4985 +0.3225 +0.3816 +0.4254 +0.3102 +0.3521 +0.4159 +0.3338 +0.3731 +0.363 +0.3726 +0.3463 +0.3088 +0.3419 +0.3127 +0.3544 +0.4116 +0.3243 +0.3712 +0.3161 +0.7578 +0.3597 +0.4521 +0.4382 +0.4364 +0.4271 +0.4319 +0.5477 +0.407 +0.5028 +0.5233 +0.506 +0.7292 +0.4775 +0.3786 +0.3948 +0.4034 +0.397 +0.4482 +0.3448 +0.4 +0.4172 +0.3773 +0.3239 +0.378 +0.3685 +0.4118 +0.4189 +0.2966 +0.3305 +0.3929 +0.3582 +0.4537 +0.498 +0.4121 +0.28 +0.5949 +0.2929 +0.3407 +0.3226 +0.3548 +0.3405 +0.4428 +0.423 +0.5593 +0.5013 +0.5999 +0.4643 +0.4839 +0.3974 +0.318 +0.3698 +0.3809 +0.4896 +0.4516 +0.4558 +0.6247 +0.5194 +0.445 +0.421 +0.444 +0.5348 +0.451 +0.3977 +0.4136 +0.4262 +0.505 +0.6135 +0.5014 +0.3628 +0.3764 +0.5129 +0.5383 +0.3431 +0.4801 +0.6918 +0.5619 +0.8736 +0.4425 +0.4192 +0.5198 +0.499 +0.4163 +0.5225 +0.5733 +0.536 +0.463 +0.4119 +0.6297 +0.3849 +0.415 +0.4042 +0.3375 +0.4756 +0.4653 +0.4324 +0.5297 +0.6474 +0.6708 +0.5121 +0.6019 +0.432 +0.6021 +0.3995 +0.39 +0.6006 +0.5906 +0.4058 +0.496 +0.4043 +0.5384 +0.5077 +0.6121 +0.5026 +0.603 +0.5689 +0.4687 +0.3425 +0.4013 +0.3686 +0.4575 +0.3759 +0.4816 +0.5345 +0.3585 +0.5818 +0.395 +0.61 +0.7003 +0.4558 +0.6558 +0.5128 +0.4657 +0.4269 +0.378 +0.4797 +0.5866 +0.5424 +0.5726 +0.4407 +0.6187 +0.6722 +0.4974 +0.5763 +0.4132 +0.5569 +0.4977 +0.6013 +0.5545 +0.5177 +0.3972 +0.5198 +0.875 +1 diff --git a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/test.py b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/test.py index 15747c4..bfb0c31 100644 --- a/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/test.py +++ b/TensorFlow_eaxmple/Model_train_test/2012轴承数据集预测挑战/HI_create/test.py @@ -3,8 +3,10 @@ import numpy as np import matplotlib.pyplot as plt #数据导入 -HI_merge_data=np.load("HI_merge_data.npy") -HI_merge_data=HI_merge_data[0:1250,1] +# HI_merge_data=np.load("HI_merge_data.npy") +HI_merge_data=np.loadtxt("smallVHI.csv",delimiter=",") +print(HI_merge_data.shape) +# HI_merge_data=HI_merge_data[0:1250,0] print(HI_merge_data.shape) print(HI_merge_data) plt.plot(HI_merge_data) diff --git a/TensorFlow_eaxmple/Model_train_test/RUL/test/DCTTest.py b/TensorFlow_eaxmple/Model_train_test/RUL/test/DCTTest.py index 503eda3..5083e0d 100644 --- a/TensorFlow_eaxmple/Model_train_test/RUL/test/DCTTest.py +++ b/TensorFlow_eaxmple/Model_train_test/RUL/test/DCTTest.py @@ -1,4 +1,4 @@ -#-*- encoding:utf-8 -*- +# -*- encoding:utf-8 -*- ''' @Author : dingjiawen @@ -12,11 +12,11 @@ [1] https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.fftpack.dct.html ''' - import numpy as np import cv2 -from scipy.fftpack import dct,idct +from scipy.fftpack import dct, idct import matplotlib.pyplot as plt +import tensorflow as tf array = np.array([-0.029078494757, -0.33095228672, @@ -33,14 +33,13 @@ array = np.array([-0.029078494757, 0.343256533146, 0.008932195604]) -dct_array = dct(array,norm='ortho') -dct_array_t = idct(dct_array,norm='ortho') +dct_array = dct(array, norm='ortho') +dct_array_t = idct(dct_array, norm='ortho') amp = np.abs(np.fft.fft(array) / len(array)) print(amp) print(dct_array) - plt.subplot(4, 1, 1) plt.plot(array) plt.subplot(4, 1, 2) @@ -50,3 +49,49 @@ plt.plot(dct_array_t) plt.subplot(4, 1, 4) plt.plot(amp) plt.show() + + +def test1(x): + C_temp = np.zeros(x.shape) + dst = np.zeros(x.shape) + + n = len(x) + N = n + C_temp[:] = 1 * np.sqrt(1 / N) + + + for j in range(n): + C_temp[j] = np.cos(np.pi * (2 * j + 1) / (2 * N) + ) * np.sqrt(2 / N) + # + dst = np.dot(C_temp, x) + dst = np.dot(dst, np.transpose(C_temp)) + + # dst1 = np.log(abs(dst)) # 进行log处理 + return dst + + + +def test(x): + from numpy.fft import rfft as fft + N = len(x) + y = np.empty(shape=[2 * N]) + y[:N] = x + y[N:] = x[::-1] + + Y = fft(y)[:N] + + z = [] + for (k, y) in zip(range(len(Y)), Y): + z.append(y * np.exp(-1j * np.pi * k / (2 * N))) + z= np.array(z) + return z.real + + +if __name__ == '__main__': + a = tf.random.normal(shape=(3, 522,1), mean=2, stddev=1, dtype=tf.float32) # 创建一个标准正态分布 + np.save("a.npy",a) + b = tf.signal.dct(a) + np.save("b.npy",b) + print(b) + diff --git a/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMContinueTest.py b/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMContinueTest.py index 27bfee7..6eff73c 100644 --- a/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMContinueTest.py +++ b/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMContinueTest.py @@ -160,13 +160,12 @@ def predictContinueByOne(newModel, train_data, predict_num=50): for each_predict in range(predict_num): # predicted_data.shape : (1,10) 取最后一条 predicted_data = newModel.predict(each_predict_data) # (batch_size,filer_num,1) - predicted_data = np.expand_dims(predicted_data[:, -1], axis=-1) + predicted_data = predicted_data[:, -1] predicted_list[each_predict] = predicted_data # (1,1) => (10,1)l temp1 = np.transpose(np.concatenate([each_predict_data[:, 1:, -1], predicted_data], axis=1), [1, 0]) - each_predict_data = np.expand_dims( - np.concatenate([np.squeeze(each_predict_data[:, :, 1:], axis=0), temp1], axis=1), axis=0) + each_predict_data = np.concatenate([each_predict_data[:, :, 1:], np.expand_dims(temp1,axis=0)], axis=-1) return predicted_list @@ -175,7 +174,7 @@ def predictContinueByOne(newModel, train_data, predict_num=50): def predictByEveryData(trained_model: tf.keras.Model, predict_data): # shape:(1180,10) 取每一次的最后一个点就是从头到尾预测的 predicted_data = trained_model.predict(predict_data) - predicted_data = np.expand_dims(predicted_data[:, -1], axis=-1) + predicted_data = predicted_data[:, -1] # 1180,1,1 predicted_data = np.concatenate([np.expand_dims(total_data[:hidden_num + feature, ], axis=1), predicted_data], axis=0) diff --git a/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMTest.py b/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMTest.py index fffd0e8..08bea4f 100644 --- a/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMTest.py +++ b/TensorFlow_eaxmple/Model_train_test/RUL/test/LSTMTest.py @@ -22,14 +22,14 @@ from pylab import * ''' 超参数设置: ''' -hidden_num = 40 # LSTM细胞个数 +hidden_num = 10 # LSTM细胞个数 feature = 10 # 一个点的维度 batch_size = 32 EPOCH = 1000 unit = 512 # LSTM的维度 predict_num = 50 # 预测个数 model_name = "dctLSTM" -save_name = r"self_{0}_hidden{1}_unit{2}_feature{3}_predict{4}.h5".format(model_name, hidden_num, unit, feature, +save_name = r"self_{0}_hidden{1}_unit{2}_feature{3}_predict{4}_0.0657_0.207.h5".format(model_name, hidden_num, unit, feature, predict_num) @@ -204,18 +204,18 @@ if __name__ == '__main__': train_label_single, predict_num=predict_num) # # # #### TODO 训练 - # model = predict_model(hidden_num, feature) - # checkpoint = tf.keras.callbacks.ModelCheckpoint( - # filepath=save_name, - # monitor='val_loss', - # verbose=2, - # save_best_only=True, - # mode='min') - # lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=10, min_lr=0.0001) - # - # model.compile(optimizer=tf.optimizers.SGD(), loss=tf.losses.mse) - # - # model.summary() + model = predict_model(hidden_num, feature) + checkpoint = tf.keras.callbacks.ModelCheckpoint( + filepath=save_name, + monitor='val_loss', + verbose=2, + save_best_only=True, + mode='min') + lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=10, min_lr=0.0001) + + model.compile(optimizer=tf.optimizers.SGD(), loss=tf.losses.mse) + + model.summary() # early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=20, mode='min', verbose=1) # # history = model.fit(train_data, train_label_single, epochs=EPOCH, validation_data=(val_data, val_label_single), @@ -225,7 +225,7 @@ if __name__ == '__main__': #### TODO 测试 trained_model = tf.keras.models.load_model(save_name, custom_objects={'AttentionEmbedLSTMLayer': LSTMLayer}) - + model.summary() # 使用已知的点进行预测 print("开始预测") predicted_data = predictByEveryData(trained_model, train_data) diff --git a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/NewtonInsert.py b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/NewtonInsert.py index 82c4854..b58e3b7 100644 --- a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/NewtonInsert.py +++ b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/NewtonInsert.py @@ -17,6 +17,9 @@ import timeit # cat_sale = pd.read_excel('data/catering_sale.xls') path = "G:\data\SCADA数据\jb4q_8.csv" cat_sale = pd.read_csv(path) +print(cat_sale) +cat_sale = cat_sale.iloc[:20000, :] +print(cat_sale) # cat_sale.drop('日期', axis=1, inplace=True) # 过滤异常值,并置为空值 @@ -30,6 +33,8 @@ cat_sale[:][cat_sale[:] == 0] = np.nan # 在索引比较的时候,要转换 :param x:差值前后的索引值 :param y:差值前后的数值 ''' + + def cal_f(x, y): """ 计算插商 @@ -50,6 +55,8 @@ def cal_f(x, y): :param y:差值前后的数值 :param x_j:需要差值的索引 ''' + + def newton(x, y, x_j): """ 牛顿差值多项式 @@ -76,6 +83,8 @@ def newton(x, y, x_j): :param is_fast:是否需要快速差值(无论前后是否是零值均采用);反之则一直找到不为0值的进行计算 :param k:取前后多少个数 ''' + + def ployinterp_columns(s, n, x_j, is_fast: bool = False, k=3): X = [] Y = [] @@ -125,7 +134,7 @@ def execute(): for j in range(len(cat_sale)): if (cat_sale[i].isnull())[j]: x_j = cat_sale.index[j] - cat_sale.loc[j,i] = ployinterp_columns(cat_sale[i], j, x_j) + cat_sale.loc[j, i] = ployinterp_columns(cat_sale[i], j, x_j) print('第{0}行牛顿插值为{1}'.format(j, cat_sale.loc[j, i])) print("{0}列处理后空行数:{1}".format(i, cat_sale[i].isnull().sum())) print("========================================") @@ -135,19 +144,52 @@ def execute(): def test(): + before_data = pd.DataFrame() cat_sale[:][cat_sale[:] == 0] = np.nan # 在索引比较的时候,要转换成同一类型,使用astype - for j in range(len(cat_sale['num_gearbox_sumptemp'])): - if (cat_sale['num_gearbox_sumptemp'].isnull())[j]: + for j in range(len(cat_sale['num_gearbox_pumpoutletpress'])): + if (cat_sale['num_gearbox_pumpoutletpress'].isnull())[j]: x_j = cat_sale.index[j] - cat_sale.loc[j,'num_gearbox_sumptemp'] = ployinterp_columns(cat_sale['num_gearbox_sumptemp'], j, x_j,is_fast=True) + # cat_sale.loc[j,'num_gearbox_pumpoutletpress'] = ployinterp_columns(cat_sale['num_gearbox_pumpoutletpress'], j, x_j,is_fast=True) + a = ployinterp_columns(cat_sale['num_gearbox_pumpoutletpress'], j, x_j, is_fast=True) + if a > 10 or a <= 3: + a = 5 + before_data.loc[j, 'num_gearbox_pumpoutletpress'] = a # print('第{0}行牛顿插值为{1}'.format(j, cat_sale.loc[j,'num_gearbox_sumptemp'])) + else: + a = cat_sale.loc[j, 'num_gearbox_pumpoutletpress'] + if a > 10 or a <= 3: + a = 5 + before_data.loc[j, 'num_gearbox_pumpoutletpress'] = a + # cat_sale[:][cat_sale[:] == np.nan] = 0 + return before_data['num_gearbox_pumpoutletpress'], cat_sale['num_gearbox_pumpoutletpress'] + + +def plot(x_axis, original_data, restored_data): + import matplotlib.pyplot as plt + # 绘制原始数据和修复后的数据对比图 + plt.figure(figsize=(3.2, 2.0)) + plt.subplots_adjust(left=0.18, right=0.94, bottom=0.25, top=0.85, wspace=None, hspace=None) + plt.tight_layout() + plt.plot(x_axis, original_data, label='Original Data', color='blue') + plt.plot(x_axis, restored_data, label='Restored Data', color='red') + font = {'family': 'Times New Roman', 'weight': 'normal', 'size': 10} + plt.xlabel('Points', font) + plt.ylabel("Value", font) + plt.title('Original Data vs Restored Data', font) + plt.legend(loc=2, prop=font, handlelength=0.45, frameon=True, facecolor='w') + plt.savefig('NewtonInsert.png',dpi=600) + plt.show() if __name__ == '__main__': start = timeit.default_timer() # execute() - test() + restored_data, original_data = test() + for i in range(len(original_data)): + a = original_data[i] + if np.isnan(a): + original_data[i] = 0 + plot([i for i in range(len(original_data))], original_data, restored_data) end = timeit.default_timer() print('Running time: %s Seconds' % (end - start)) # 返回值是浮点数 - diff --git a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/lagrangeInsert.py b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/lagrangeInsert.py index 3591cdf..a18d09d 100644 --- a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/lagrangeInsert.py +++ b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/dataETL/lagrangeInsert.py @@ -11,38 +11,28 @@ import numpy as np import pandas as pd +path = "G:\data\SCADA数据\jb4q_8.csv" +cat_sale = pd.read_csv(path) +print(cat_sale) +cat_sale = cat_sale.iloc[:20000, :] +print(cat_sale) +# cat_sale.drop('日期', axis=1, inplace=True) +# 过滤异常值,并置为空值 +# cat_sale['销量'][(cat_sale['销量'] < 400) | (cat_sale['销量'] > 5000)] = np.NAN +# 将0值变成NAN 通过双中括号进行索引任意位置 +# print(df['realtime'][1]) +cat_sale[:][cat_sale[:] == 0] = np.nan # 在索引比较的时候,要转换成同一类型,使用astype # 拉格朗日插值算法 -def LagrangeInterpolation(slices, x, k=5): +def LagrangeInterpolation(X,Y, x): # slices(series) :the defining points # k :the number of defining points of Lagrange poly 前后各k个值 # slices index :the corresponding value on each defining point # x :the point whose value we are interested # print(slices[x]) # print(np.isnan(slices[x])) - result = 0 # later to save final result - X = [] - Y = [] - # 先取序列前后各k个不为空的值 - index = x - 1 - while len(X) < k and index >= 0: - if not np.isnan(slices[index]): - Y.append(slices[index]) - X.append(index) - index -= 1 - index = x + 1 - X.reverse() - Y.reverse() - - while len(X) < 2 * k and index <= len(slices): - if not np.isnan(slices[index]): - Y.append(slices[index]) - X.append(index) - index += 1 - # print(X) - # print(Y) - + result = 0 for j in range(len(X)): # result_l 基函数 result_l = 1 @@ -50,16 +40,100 @@ def LagrangeInterpolation(slices, x, k=5): if i != j: result_l = result_l * (x - X[i]) / (X[j] - X[i]) # 取值 slices[j] - result = result + slices[j] * result_l + result = result + Y[j] * result_l return result +def ployinterp_columns(s, n, x_j, is_fast: bool = False, k=3): + X = [] + Y = [] + if is_fast: + # 如果最前面的值不够k个 + if n < k or n > len(s) - k - 1: + y = s[[i for i in range(max(n - k, 0), n)] + [i for i in range(n + 1, min(n + k + 1, len(s)))]] + # 前后均有k个 + else: + y = s[[i for i in range(n - k, n)] + [i for i in range(n + 1, n + k + 1)]] # 取空值处的前后5个数 + y = y[y.notnull()] # 剔除空值 + X = y.index + Y = list(y) + else: + # 先取序列前后各k个不为空的值 + index = n - 1 + while len(X) < k and index >= 0: + if not np.isnan(s[index]): + Y.append(s[index]) + X.append(index) + index -= 1 + index = n + 1 + X.reverse() + Y.reverse() + + while len(X) < 2 * k and index <= len(s): + if not np.isnan(s[index]): + Y.append(s[index]) + X.append(index) + index += 1 + # print(X) + # print(Y) + + return LagrangeInterpolation(X,Y, x_j) # 插值并返回插值结果 +def test(): + before_data = pd.DataFrame() + cat_sale[:][cat_sale[:] == 0] = np.nan # 在索引比较的时候,要转换成同一类型,使用astype + for j in range(len(cat_sale['num_gearbox_pumpoutletpress'])): + if (cat_sale['num_gearbox_pumpoutletpress'].isnull())[j]: + x_j = cat_sale.index[j] + # cat_sale.loc[j,'num_gearbox_pumpoutletpress'] = ployinterp_columns(cat_sale['num_gearbox_pumpoutletpress'], j, x_j,is_fast=True) + a = ployinterp_columns(cat_sale['num_gearbox_pumpoutletpress'], j, x_j, is_fast=True) + if a > 10 or a <= 3: + a = 5 + before_data.loc[j, 'num_gearbox_pumpoutletpress'] = a + # print('第{0}行牛顿插值为{1}'.format(j, cat_sale.loc[j,'num_gearbox_sumptemp'])) + else: + a = cat_sale.loc[j, 'num_gearbox_pumpoutletpress'] + if a > 10 or a <= 3: + a = 5 + before_data.loc[j, 'num_gearbox_pumpoutletpress'] = a + # cat_sale[:][cat_sale[:] == np.nan] = 0 + return before_data['num_gearbox_pumpoutletpress'], cat_sale['num_gearbox_pumpoutletpress'] + + +def plot(x_axis, original_data, restored_data): + import matplotlib.pyplot as plt + # 绘制原始数据和修复后的数据对比图 + plt.figure(figsize=(3.2, 2.0)) + plt.subplots_adjust(left=0.18, right=0.94, bottom=0.25, top=0.85, wspace=None, hspace=None) + plt.tight_layout() + plt.plot(x_axis, original_data, label='Original Data', color='blue') + plt.plot(x_axis, restored_data, label='Restored Data', color='red') + font = {'family': 'Times New Roman', 'weight': 'normal', 'size': 10} + plt.xlabel('Points', font) + plt.ylabel("Value", font) + plt.title('Original Data vs Restored Data', font) + plt.legend(loc=2, prop=font, handlelength=0.45, frameon=True, facecolor='w') + plt.savefig('LagrangeInsert.png',dpi=600) + plt.show() if __name__ == '__main__': + restored_data, original_data = test() + for i in range(len(original_data)): + a = original_data[i] + if np.isnan(a): + original_data[i] = 0 + plot([i for i in range(len(original_data))], original_data, restored_data) + + + + + + + + path = "G:\data\SCADA数据\jb4q_8.csv" df = pd.read_csv(path) diff --git a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/complete/Transformer.py b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/complete/Transformer.py index 00417bc..155ace0 100644 --- a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/complete/Transformer.py +++ b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/complete/Transformer.py @@ -48,15 +48,15 @@ class Transformer(Model): # 接下来,如果传入了representation_size,就构建一个全连接层,激活函数为tanh # 如果没有传入的话,就不做任何操作 - if representation_size: - self.has_logits = True - self.pre_logits = layers.Dense(representation_size, activation="tanh", name="pre_logits") - else: - self.has_logits = False - self.pre_logits = layers.Activation("linear") + # if representation_size: + # self.has_logits = True + # self.pre_logits = layers.Dense(representation_size, activation="tanh", name="pre_logits") + # else: + # self.has_logits = False + # self.pre_logits = layers.Activation("linear") # 定义最后一个全连接层,节点个数就是我们的分类个数num_classes - self.head = layers.Dense(num_classes, name="head", kernel_initializer=initializers.Zeros()) + # self.head = layers.Dense(num_classes, name="head", kernel_initializer=initializers.Zeros()) def get_config(self): # 自定义层里面的属性 @@ -87,10 +87,10 @@ class Transformer(Model): x = self.norm(x) # 这里是提取class_toke的输出,然后用切片的方式,而刚刚是将class_toke拼接在最前面的 # 所以这里用切片的方式,去取class_toke的输出,并将它传递给pre_logits - x = self.pre_logits(x[:, 0]) - # 最后传递给head - x = self.head(x) - # 为什么只用class_toke对应的输出,而不用每一个patches对应的输出呢? + # x = self.pre_logits(x[:, 0]) + # # 最后传递给head + # x = self.head(x) + # # 为什么只用class_toke对应的输出,而不用每一个patches对应的输出呢? # 可以参考原文bird 网络 return x @@ -98,4 +98,5 @@ class Transformer(Model): if __name__ == '__main__': # 使用方式 + input =tf.Variable(shape=[20, 10, 10]) Transformer(embed_dim=10, depth=8, num_heads=1, num_classes=10) diff --git a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/transformer_complete.py b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/transformer_complete.py index 0ae78e2..1e26a06 100644 --- a/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/transformer_complete.py +++ b/TensorFlow_eaxmple/Model_train_test/condition_monitoring/返修/transformer_complete.py @@ -35,11 +35,10 @@ K = 18 namuda = 0.01 '''保存名称''' -save_name = "../model/joint/{0}_timestamp{1}_feature{2}.h5".format(model_name, - time_stamp, - feature_num, - batch_size, - EPOCH) +save_name = "../model/weight/{0}_timestamp{1}_feature{2}_weight/weight".format(model_name, + time_stamp, + feature_num, + ) save_step_two_name = "../model/joint_two/{0}_timestamp{1}_feature{2}.h5".format(model_name, time_stamp, feature_num, @@ -244,29 +243,44 @@ if __name__ == '__main__': #### TODO 第一步训练 ####### TODO 训练 - model = Transformer(embed_dim=10, depth=5, num_heads=1, num_classes=10,representation_size=128) - checkpoint = tf.keras.callbacks.ModelCheckpoint( - filepath=save_name, - monitor='val_loss', - verbose=2, - save_best_only=True, - mode='min') - lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, min_lr=0.001) + # model = Transformer(embed_dim=10, depth=5, num_heads=1, num_classes=10,representation_size=128) + # checkpoint = tf.keras.callbacks.ModelCheckpoint( + # filepath=save_name, + # monitor='val_loss', + # verbose=2, + # save_best_only=True, + # mode='min') + # lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, min_lr=0.001) + # + # + # model.build(input_shape=(batch_size, time_stamp, feature_num)) + # model.summary() + # early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=3, mode='min', verbose=1) + # + # history = model.fit(train_data_healthy[:train_data_healthy.shape[0] // 7, :, :], + # train_label1_healthy[:train_label1_healthy.shape[0] // 7, ], epochs=5, + # batch_size=batch_size * 10, validation_split=0.2, shuffle=True, verbose=1, + # ) + # + # model.save_weights(save_name) - model.compile(optimizer=tf.optimizers.Adam(), loss=tf.losses.mse) + model = Transformer(embed_dim=10, depth=5, num_heads=1, num_classes=10, representation_size=128) + model.load_weights(save_name) model.build(input_shape=(batch_size, time_stamp, feature_num)) model.summary() - early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=3, mode='min', verbose=1) - history = model.fit(train_data_healthy[:train_data_healthy.shape[0] // 7, :, :], - train_label1_healthy[:train_label1_healthy.shape[0] // 7, ], epochs=EPOCH, - batch_size=batch_size * 10, validation_split=0.2, shuffle=True, verbose=1, - callbacks=[checkpoint, lr_scheduler, early_stop]) - # # # # #### TODO 测试 + # model = tf.keras.models.load_model("E:\self_example\TensorFlow_eaxmple\Model_train_test\condition_monitoring\model\joint/transformer_timestamp120_feature10.h5" + # , custom_objects={'Transformer': Transformer} + # ) + + trained_data = tf.keras.models.Model(inputs=model.input, outputs=model.get_layer('encoder_norm').output).predict(train_data_healthy, batch_size=32) + + print(trained_data) + # start = time.time() # 中间写上代码块 @@ -276,7 +290,7 @@ if __name__ == '__main__': print("data_size:", train_data_healthy.shape) print('Running time: %s Seconds' % (end - start)) - trained_model = tf.keras.models.load_model(save_name, custom_objects={'Block': Block}) + # trained_model = tf.keras.models.load_model(save_name, custom_objects={'Block': Block}) # # # diff --git a/TensorFlow_eaxmple/Model_train_test/model/AdamRNN/AdamRNN.py b/TensorFlow_eaxmple/Model_train_test/model/AdamRNN/AdamRNN.py index 78dcbdf..e922d33 100644 --- a/TensorFlow_eaxmple/Model_train_test/model/AdamRNN/AdamRNN.py +++ b/TensorFlow_eaxmple/Model_train_test/model/AdamRNN/AdamRNN.py @@ -137,7 +137,7 @@ class AdaRNN(tf.keras.Model): criterion_transder = TransferLoss( loss_type=self.trans_loss) for j in range(self.len_seq): - loss_trans = criterion_transder(out_list_s[i][:, j, :], out_list_t[i][:, j, :]) + loss_trans = criterion_transder(out_list_s[i][:, j, :] , out_list_t[i][:, j, :]) loss_transfer = loss_transfer + weight[i, j] * loss_trans dist_mat[i, j] = loss_trans return fc_out, loss_transfer, dist_mat, weight diff --git a/TensorFlow_eaxmple/Model_train_test/temp/Transformer.py b/TensorFlow_eaxmple/Model_train_test/temp/Transformer.py new file mode 100644 index 0000000..88a2861 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/temp/Transformer.py @@ -0,0 +1,113 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/10/23 10:43 +@Usage : +@Desc : 计算transformer的参数和时间复杂度 6层self_attention +''' +import tensorflow as tf +from tensorflow.keras import Model, layers, initializers +import numpy as np +from model.SelfAttention.SelfAttention import Block + + +class Transformer(Model): + + # depth表示的是重复encoder block的次数,num_heads表示的是在multi-head self-attention中head的个数 + # MLP block中有一个Pre_logist,这里指的是,当在较大的数据集上学习的时候Pre_logist就表示一个全连接层加上一个tanh激活函数 + # 当在较小的数据集上学习的时候,Pre_logist是没有的,而这里的representation_size表示的就是Pre_logist中全连接层的节点个数 + # num_classes表示分类的类数 + def __init__(self, embed_dim=768, + depth=[], num_heads=12, qkv_bias=True, qk_scale=None, + drop_ratio=0., attn_drop_ratio=0., drop_path_ratio=0., + representation_size=None, num_classes=1000, name="ViT-B/16"): + super(Transformer, self).__init__(name=name) + + self.embed_dim = embed_dim + self.depth = depth + self.num_heads = num_heads + self.qkv_bias = qkv_bias + self.qk_scale = qk_scale + self.drop_ratio = drop_ratio + self.attn_drop_ratio = attn_drop_ratio + self.drop_path_ratio = drop_path_ratio + self.representation_size = representation_size + self.num_classes = num_classes + + dpr = np.linspace(0., drop_path_ratio, len(depth)) # stochastic depth decay rule + # 用一个for循环重复Block模块 + # 在用droppath时的drop_path_ratio是由0慢慢递增到我们所指定的drop_path_ratio的 + # 所以我们在构建Block时,这里的drop_path_ratio时变化的,所以用 np.linspace方法创建一个等差数列来初始化drop_path_ratio + + self.blocks = [] + self.denses = [] + for i,dim in zip(range(len(depth)),depth): + self.blocks.append( + Block(dim=dim, num_heads=num_heads, qkv_bias=qkv_bias, + qk_scale=qk_scale, drop_ratio=drop_ratio, attn_drop_ratio=attn_drop_ratio, + drop_path_ratio=dpr[i], name="encoderblock_{}".format(i)) + ) + self.denses.append(layers.Dense(dim)) + + # self.norm = layers.LayerNormalization(epsilon=1e-6, name="encoder_norm") + + # 接下来,如果传入了representation_size,就构建一个全连接层,激活函数为tanh + # 如果没有传入的话,就不做任何操作 + # if representation_size: + # self.has_logits = True + # self.pre_logits = layers.Dense(representation_size, activation="tanh", name="pre_logits") + # else: + # self.has_logits = False + # self.pre_logits = layers.Activation("linear") + + # 定义最后一个全连接层,节点个数就是我们的分类个数num_classes + # self.head = layers.Dense(num_classes, name="head", kernel_initializer=initializers.Zeros()) + + def get_config(self): + # 自定义层里面的属性 + config = ( + { + 'embed_dim': self.embed_dim, + 'depth': self.depth, + 'num_heads': self.num_heads, + 'qkv_bias': self.qkv_bias, + 'qk_scale': self.qk_scale, + 'drop_ratio': self.drop_ratio, + 'attn_drop_ratio': self.attn_drop_ratio, + 'drop_path_ratio': self.drop_path_ratio, + 'representation_size': self.representation_size, + 'num_classes': self.num_classes + } + ) + base_config = super(Transformer, self).get_config() + return dict(list(base_config.items()) + list(config.items())) + + def call(self, inputs, training=None): + # [B, H, W, C] -> [B, num_patches, embed_dim] + x = inputs # [B, 196, 768] + + for (block, dense) in zip(self.blocks, self.denses): + x = dense(x) + x = block(x, training=training) + + + # x = self.norm(x) + # # 这里是提取class_toke的输出,然后用切片的方式,而刚刚是将class_toke拼接在最前面的 + # # 所以这里用切片的方式,去取class_toke的输出,并将它传递给pre_logits + # x = self.pre_logits(x[:, 0]) + # # 最后传递给head + # x = self.head(x) + # 为什么只用class_toke对应的输出,而不用每一个patches对应的输出呢? + # 可以参考原文bird 网络 + + return x + + +if __name__ == '__main__': + # 使用方式 + + # input =tf.Variable(shape=[20, 10, 10]) + # Transformer(embed_dim=10, depth=8, num_heads=1, num_classes=10) + + print([i for i in range(5, 1, -1)]) diff --git a/TensorFlow_eaxmple/Model_train_test/temp/loggerTest.py b/TensorFlow_eaxmple/Model_train_test/temp/loggerTest.py new file mode 100644 index 0000000..f03bbd6 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/temp/loggerTest.py @@ -0,0 +1,23 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 15:34 +@Usage : +@Desc : +''' +import logging +import time + + +logging.basicConfig(format='%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s', + level=logging.INFO, + filename='E:\self_example\TensorFlow_eaxmple\Model_train_test/temp/test.log', + filemode='a') + + +i = 0 +while True: + logging.info(i) + time.sleep(2) + diff --git a/TensorFlow_eaxmple/Model_train_test/temp/test.bat b/TensorFlow_eaxmple/Model_train_test/temp/test.bat new file mode 100644 index 0000000..fbd71c7 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/temp/test.bat @@ -0,0 +1,5 @@ +@echo off +if "%1" == "h" goto begin +mshta vbscript:createobject("wscript.shell").run("%~nx0 h",0)(window.close)&&exit +:begin +D:\ProgramData\Anaconda3\envs\tensorflow\python.exe loggerTest.py diff --git a/TensorFlow_eaxmple/Model_train_test/temp/transformer_complete.py b/TensorFlow_eaxmple/Model_train_test/temp/transformer_complete.py new file mode 100644 index 0000000..60ffdd1 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/temp/transformer_complete.py @@ -0,0 +1,303 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/10/23 14:23 +@Usage : +@Desc : +''' + +import tensorflow as tf +import tensorflow.keras +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from condition_monitoring.data_deal import loadData_daban as loadData +# from model.Joint_Monitoring.Joint_Monitoring_banda import Joint_Monitoring + +# from model.CommonFunction.CommonFunction import * +from sklearn.model_selection import train_test_split +from tensorflow.keras.models import load_model, save_model +from temp.Transformer import Transformer +from model.SelfAttention.SelfAttention import Block +from keras.callbacks import EarlyStopping +import time + +'''超参数设置''' +time_stamp = 120 +feature_num = 10 +batch_size = 32 +learning_rate = 0.001 +EPOCH = 101 +model_name = "transformer" +'''EWMA超参数''' +K = 18 +namuda = 0.01 +'''保存名称''' + +save_name = "../model/weight/{0}_timestamp{1}_feature{2}_weight/weight".format(model_name, + time_stamp, + feature_num, + ) +save_step_two_name = "../model/joint_two/{0}_timestamp{1}_feature{2}.h5".format(model_name, + time_stamp, + feature_num, + batch_size, + EPOCH) + +save_mse_name = r"./compare/mse/JM_banda/{0}_result.csv".format(model_name) +'''文件名''' +file_name = "G:\data\SCADA数据\SCADA_已处理_粤水电达坂城2020.1月-5月\风机15.csv" + +''' +文件说明:jb4q_8_delete_total_zero.csv是删除了只删除了全是0的列的文件 +文件从0:96748行均是正常值(2019/12.30 00:00:00 - 2020/3/11 05:58:00) +从96748:107116行均是异常值(2020/3/11 05:58:01 - 2021/3/18 11:04:00) +''' +'''文件参数''' +# 最后正常的时间点 +healthy_date = 96748 +# 最后异常的时间点 +unhealthy_date = 107116 +# 异常容忍程度 +unhealthy_patience = 5 + + +def remove(data, time_stamp=time_stamp): + rows, cols = data.shape + print("remove_data.shape:", data.shape) + num = int(rows / time_stamp) + + return data[:num * time_stamp, :] + pass + + +# 不重叠采样 +def get_training_data(data, time_stamp: int = time_stamp): + removed_data = remove(data=data) + rows, cols = removed_data.shape + print("removed_data.shape:", data.shape) + print("removed_data:", removed_data) + train_data = np.reshape(removed_data, [-1, time_stamp, cols]) + print("train_data:", train_data) + batchs, time_stamp, cols = train_data.shape + + for i in range(1, batchs): + each_label = np.expand_dims(train_data[i, 0, :], axis=0) + if i == 1: + train_label = each_label + else: + train_label = np.concatenate([train_label, each_label], axis=0) + + print("train_data.shape:", train_data.shape) + print("train_label.shape", train_label.shape) + return train_data[:-1, :], train_label + + +# 重叠采样 +def get_training_data_overlapping(data, time_stamp: int = time_stamp, is_Healthy: bool = True): + rows, cols = data.shape + train_data = np.empty(shape=[rows - time_stamp - 1, time_stamp, cols]) + train_label = np.empty(shape=[rows - time_stamp - 1, cols]) + for i in range(rows): + if i + time_stamp >= rows: + break + if i + time_stamp < rows - 1: + train_data[i] = data[i:i + time_stamp] + train_label[i] = data[i + time_stamp] + + print("重叠采样以后:") + print("data:", train_data) # (300334,120,10) + print("label:", train_label) # (300334,10) + + if is_Healthy: + train_label2 = np.ones(shape=[train_label.shape[0]]) + else: + train_label2 = np.zeros(shape=[train_label.shape[0]]) + + print("label2:", train_label2) + + return train_data, train_label, train_label2 + + +# 归一化 +def normalization(data): + rows, cols = data.shape + print("归一化之前:", data) + print(data.shape) + print("======================") + + # 归一化 + max = np.max(data, axis=0) + max = np.broadcast_to(max, [rows, cols]) + min = np.min(data, axis=0) + min = np.broadcast_to(min, [rows, cols]) + + data = (data - min) / (max - min) + print("归一化之后:", data) + print(data.shape) + + return data + + +# 正则化 +def Regularization(data): + rows, cols = data.shape + print("正则化之前:", data) + print(data.shape) + print("======================") + + # 正则化 + mean = np.mean(data, axis=0) + mean = np.broadcast_to(mean, shape=[rows, cols]) + dst = np.sqrt(np.var(data, axis=0)) + dst = np.broadcast_to(dst, shape=[rows, cols]) + data = (data - mean) / dst + print("正则化之后:", data) + print(data.shape) + + return data + pass + + +def EWMA(data, K=K, namuda=namuda): + # t是啥暂时未知 + t = 0 + mid = np.mean(data, axis=0) + standard = np.sqrt(np.var(data, axis=0)) + UCL = mid + K * standard * np.sqrt(namuda / (2 - namuda) * (1 - (1 - namuda) ** 2 * t)) + LCL = mid - K * standard * np.sqrt(namuda / (2 - namuda) * (1 - (1 - namuda) ** 2 * t)) + return mid, UCL, LCL + pass + + +def get_MSE(data, label, new_model): + predicted_data = new_model.predict(data) + + temp = np.abs(predicted_data - label) + temp1 = (temp - np.broadcast_to(np.mean(temp, axis=0), shape=predicted_data.shape)) + temp2 = np.broadcast_to(np.sqrt(np.var(temp, axis=0)), shape=predicted_data.shape) + temp3 = temp1 / temp2 + mse = np.sum((temp1 / temp2) ** 2, axis=1) + print("z:", mse) + print(mse.shape) + + # mse=np.mean((predicted_data-label)**2,axis=1) + print("mse", mse) + + dims, = mse.shape + + mean = np.mean(mse) + std = np.sqrt(np.var(mse)) + max = mean + 3 * std + # min = mean-3*std + max = np.broadcast_to(max, shape=[dims, ]) + # min = np.broadcast_to(min,shape=[dims,]) + mean = np.broadcast_to(mean, shape=[dims, ]) + + # plt.plot(max) + # plt.plot(mse) + # plt.plot(mean) + # # plt.plot(min) + # plt.show() + # + # + return mse, mean, max + # pass + + +def condition_monitoring_model(): + input = tf.keras.Input(shape=[time_stamp, feature_num]) + conv1 = tf.keras.layers.Conv1D(filters=256, kernel_size=1)(input) + GRU1 = tf.keras.layers.GRU(128, return_sequences=False)(conv1) + d1 = tf.keras.layers.Dense(300)(GRU1) + output = tf.keras.layers.Dense(10)(d1) + + model = tf.keras.Model(inputs=input, outputs=output) + + return model + + +def test(step_one_model, step_two_model, test_data, test_label1, test_label2): + history_loss = [] + history_val_loss = [] + + val_loss, val_accuracy = step_two_model.get_val_loss(val_data=test_data, val_label1=test_label1, + val_label2=test_label2, + is_first_time=False, step_one_model=step_one_model) + + history_val_loss.append(val_loss) + print("val_accuracy:", val_accuracy) + print("val_loss:", val_loss) + + +if __name__ == '__main__': + total_data = loadData.execute(N=feature_num, file_name=file_name) + total_data = normalization(data=total_data) + + train_data_healthy, train_label1_healthy, train_label2_healthy = get_training_data_overlapping( + total_data[:healthy_date, :], is_Healthy=True) + train_data_unhealthy, train_label1_unhealthy, train_label2_unhealthy = get_training_data_overlapping( + total_data[healthy_date - time_stamp + unhealthy_patience:unhealthy_date, :], + is_Healthy=False) + #### TODO 第一步训练 + + ####### TODO 训练 + # model = Transformer(embed_dim=10, depth=[100,200,300,100,1], num_heads=1, num_classes=1,representation_size=128) + # checkpoint = tf.keras.callbacks.ModelCheckpoint( + # filepath=save_name, + # monitor='val_loss', + # verbose=2, + # save_best_only=True, + # save_weights_only=True, + # mode='min') + # lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=3, min_lr=0.001) + # + # + # model.build(input_shape=(batch_size, time_stamp, feature_num)) + # model.summary() + # model.compile(optimizer=tf.optimizers.Adam(learning_rate=learning_rate), loss=tf.losses.mse) + # early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=3, mode='min', verbose=1) + # + # history = model.fit(train_data_healthy[:train_data_healthy.shape[0] // 7, :, :], + # train_data_healthy[:train_data_healthy.shape[0] // 7, :, 0], epochs=50, + # batch_size=batch_size * 10, validation_split=0.2, shuffle=True, verbose=1, + # callbacks=[checkpoint,lr_scheduler,early_stop] + # ) + # # + # model.save_weights(save_name) + + model = Transformer(embed_dim=10, depth=[100,200,300,100,1], num_heads=1, num_classes=1, representation_size=128) + model.load_weights("../model/weight/transformer_timestamp120_feature10_epoch16_weight_0.000087/weight") + # model.build(input_shape=(batch_size, time_stamp, feature_num)) + # model.summary() + + # + # + # #### TODO 测试 + + + + trained_data = model.predict(train_data_healthy[:train_data_healthy.shape[0] // 7, :, :], batch_size=32) + + print(trained_data) + print(trained_data.shape) + plt.plot(trained_data[:,-1,:]) + plt.show() + + # + start = time.time() + # 中间写上代码块 + + model.predict(train_data_healthy, batch_size=32) + end = time.time() + print("data_size:", train_data_healthy.shape) + print('Running time: %s Seconds' % (end - start)) + + # trained_model = tf.keras.models.load_model(save_name, custom_objects={'Block': Block}) + # + # + # + # # 使用已知的点进行预测 + # + # pass diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/__init__.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/__init__.py new file mode 100644 index 0000000..77360ab --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/21 16:42 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step1_Original_data.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step1_Original_data.py new file mode 100644 index 0000000..dad46ea --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step1_Original_data.py @@ -0,0 +1,44 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/21 16:44 +@Usage : +@Desc : +''' + +import pandas as pd +import numpy as np +import os + + +root_path ='G:\data\cmd_predict_data\shaft2/46\shaft2' +L = [] +for root, dir, filename in os.walk(root_path): + for file in filename: + if os.path.splitext(file)[1] == '.csv': + L.append(os.path.join(root_path,file)) + a = os.path.join(root_path, file) + b = a.split(".")[1].split("_") + +z = 0 +L.sort(key=lambda x:x.split(".")[1].split("_")[1]) +for filename in L: + print("读取了{0}个文件".format(z+1)) + # data_single = pd.read_csv(filename, dtype=np.float32, header=None) + data_single = np.loadtxt(filename, delimiter=',',dtype=np.str) + # data_single = data_single.iloc[0, :].values + if z == 0: + # data_all=data_single + HI_data = data_single + else: + # data_all=np.hstack([data_all,data_single]) + HI_data = np.vstack([HI_data, data_single]) + z += 1 + + +print(z) +# print(data_all.shape) +print(HI_data.shape) +np.save("data1.npy",HI_data) +# io.savemat("./HI_data.mat", {'HI_data': HI_data}) \ No newline at end of file diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step2_test.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step2_test.py new file mode 100644 index 0000000..80fe7ff --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step2_test.py @@ -0,0 +1,24 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/22 20:47 +@Usage : +@Desc : +''' + +import numpy as np +import matplotlib.pyplot as plt + +data = np.load("../data/data.npy") + +print(data) +print(data.shape) +# data = np.transpose(data, axes=[1, 0]) +data = np.reshape(data[317:517,:], [-1, 1]) + +plt.plot(data) +plt.show() +# data = np.reshape(data,[-1,8192]) +# np.save("HI_data.npy",data) +# print(data.shape) diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step3_HI_create.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step3_HI_create.py new file mode 100644 index 0000000..254e7d5 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step3_HI_create.py @@ -0,0 +1,155 @@ +import tensorflow as tf +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +# 数据导入 +data = np.load("../data/HI_data.npy") +print(data.shape) # (2803, 2560) +(samples, dims) = data.shape + +# # 24个指标建立 +fs = 25.6 * 1000 +T1 = np.mean(data, axis=1) +print(T1.shape) +# +T2 = np.sqrt(np.var(data, axis=1)) + +T3 = np.mean(np.sqrt(np.abs(data)), axis=1) ** 2 + +T4 = np.sqrt(np.mean(data ** 2, axis=1)) + +T5 = np.max(np.abs(data), axis=1) + +T6 = np.mean((data - np.broadcast_to(np.expand_dims(T1, axis=1), (samples, dims))) ** 3, axis=1) / (T4 ** 3) + +T7 = np.mean((data - np.broadcast_to(np.expand_dims(T1, axis=1), (samples, dims))) ** 4, axis=1) / (T4 ** 4) + +T8 = T5 / T4 + +T9 = T5 / T3 + +T10 = T4 / np.mean(np.abs(data), axis=1) + +T11 = T5 / np.mean(np.abs(data), axis=1) + +# 频域 +sk = np.abs(np.fft.rfft(data, axis=1) * 2 / dims) +sk = sk[:, 0:-1] # (2803,1280) +(samples, k) = sk.shape # (2803,1280) +print("data:", data) +print("sk:", sk) +fk = np.empty(shape=[samples, k]) + +for sample in range(samples): + for i in range(k): + fk[sample][i] = (fs / dims) * (i + 1) +# print(fk) +# print(fk.shape) +# plt.plot(sk[1,:]) +# plt.xlim((0,k)) +# plt.ylim((0,1.5)) +# plt.show() +# print(sk.shape) + +F1 = np.mean(sk, axis=1) + +F2 = np.var(sk, axis=1) * k / (k - 1) + +F3 = np.mean((sk - np.broadcast_to(np.expand_dims(F1, axis=1), (samples, k))) ** 3, axis=1) / (np.sqrt(F2) ** 3) + +F4 = np.mean((sk - np.broadcast_to(np.expand_dims(F1, axis=1), (samples, k))) ** 4, axis=1) / (F2 ** 2) + +F5 = np.sum(np.multiply(fk, sk), axis=1) / np.sum(sk, axis=1) + +F6 = np.sqrt(np.mean(np.multiply((fk - np.broadcast_to(np.expand_dims(F5, axis=1), (samples, k))) ** 2, sk), axis=1)) + +F7 = np.sqrt(np.sum(np.multiply(fk ** 2, sk), axis=1) / np.sum(sk, axis=1)) + +F8 = np.sqrt(np.sum(np.multiply(fk ** 4, sk), axis=1) / np.sum(fk ** 2 * sk, axis=1)) + +F9 = np.sum(np.multiply(fk ** 2, sk), axis=1) / np.sqrt(np.sum(sk, axis=1) * np.sum(np.multiply(fk ** 4, sk), axis=1)) + +F10 = F6 / F5 + +F11 = np.mean(np.multiply((fk - np.broadcast_to(np.expand_dims(F5, axis=1), (samples, k))) ** 3, sk), axis=1) / ( + F6 ** 3) + +F12 = np.mean(np.multiply((fk - np.broadcast_to(np.expand_dims(F5, axis=1), (samples, k))) ** 4, sk), axis=1) / ( + F6 ** 4) + +F13 = np.mean(np.sqrt(np.abs(fk - np.broadcast_to(np.expand_dims(F5, axis=1), (samples, k)))) * sk, axis=1) / np.sqrt( + F6) + +# 归一化处理 +T1 = (T1 - np.min(T1)) / (np.max(T1) - np.min(T1)) +T2 = (T2 - np.min(T2)) / (np.max(T2) - np.min(T2)) +T3 = (T3 - np.min(T3)) / (np.max(T3) - np.min(T3)) +T4 = (T4 - np.min(T4)) / (np.max(T4) - np.min(T4)) +T5 = (T5 - np.min(T5)) / (np.max(T5) - np.min(T5)) +T6 = (T6 - np.min(T6)) / (np.max(T6) - np.min(T6)) +T7 = (T7 - np.min(T7)) / (np.max(T7) - np.min(T7)) +T8 = (T8 - np.min(T8)) / (np.max(T8) - np.min(T8)) +T9 = (T9 - np.min(T9)) / (np.max(T9) - np.min(T9)) +T10 = (T10 - np.min(T10)) / (np.max(T10) - np.min(T10)) +T11 = (T11 - np.min(T11)) / (np.max(T11) - np.min(T11)) +F1 = (F1 - np.min(F1)) / (np.max(F1) - np.min(F1)) +F2 = (F2 - np.min(F2)) / (np.max(F2) - np.min(F2)) +F3 = (F3 - np.min(F3)) / (np.max(F3) - np.min(F3)) +F4 = (F4 - np.min(F4)) / (np.max(F4) - np.min(F4)) +F5 = (F5 - np.min(F5)) / (np.max(F5) - np.min(F5)) +F6 = (F6 - np.min(F6)) / (np.max(F6) - np.min(F6)) +F7 = (F7 - np.min(F7)) / (np.max(F7) - np.min(F7)) +F8 = (F8 - np.min(F8)) / (np.max(F8) - np.min(F8)) +F9 = (F9 - np.min(F9)) / (np.max(F9) - np.min(F9)) +F10 = (F10 - np.min(F10)) / (np.max(F10) - np.min(F10)) +F11 = (F11 - np.min(F11)) / (np.max(F11) - np.min(F11)) +F12 = (F12 - np.min(F12)) / (np.max(F12) - np.min(F12)) +F13 = (F13 - np.min(F13)) / (np.max(F13) - np.min(F13)) +print(F5) +# plt.plot(F5) +# plt.show() + + +def plot(data): + l, c = data.shape + + for i in range(c): + plt.figure(i + 1) + plt.plot(data[:, i]) + plt.show() + + +if __name__ == '__main__': + T1 = np.expand_dims(T1, axis=1) + T2 = np.expand_dims(T2, axis=1) + T3 = np.expand_dims(T3, axis=1) + T4 = np.expand_dims(T4, axis=1) + T5 = np.expand_dims(T5, axis=1) + T6 = np.expand_dims(T6, axis=1) + T7 = np.expand_dims(T7, axis=1) + T8 = np.expand_dims(T8, axis=1) + T9 = np.expand_dims(T9, axis=1) + T10 = np.expand_dims(T10, axis=1) + T11 = np.expand_dims(T11, axis=1) + F1 = np.expand_dims(F1, axis=1) + F2 = np.expand_dims(F2, axis=1) + F3 = np.expand_dims(F3, axis=1) + F4 = np.expand_dims(F4, axis=1) + F5 = np.expand_dims(F5, axis=1) + F6 = np.expand_dims(F6, axis=1) + F7 = np.expand_dims(F7, axis=1) + F8 = np.expand_dims(F8, axis=1) + F9 = np.expand_dims(F9, axis=1) + F10 = np.expand_dims(F10, axis=1) + F11 = np.expand_dims(F11, axis=1) + F12 = np.expand_dims(F12, axis=1) + F13 = np.expand_dims(F13, axis=1) + feature_data = tf.concat( + [T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13], axis=1) + # plot(feature_data) + np.save('../data/feature_data.npy', feature_data) + print(feature_data.shape) + +# print(HI_data.shape) +# np.save("../data/HI_DATA/HIed_data.npy",HI_data) diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step4_HI_select.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step4_HI_select.py new file mode 100644 index 0000000..e6d1a60 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step4_HI_select.py @@ -0,0 +1,98 @@ +import tensorflow as tf +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt + +# 数据导入 +feature_data = np.load("../data/feature_data.npy") +print(feature_data.shape) # (2803,24) +feature_data = np.transpose(feature_data, [1, 0]) +print(feature_data.shape) # (24,2803) + + +# data.shape:(24,2803) +class HI_select(): + + def __init__(self, data): + self.data = data + + def getScore(self): + score = (self.getTred() + self.getMon() + self.getScale()) / 2 + print(score.shape) + return score + + def getTred(self): + h = self.data + (features, dims) = h.shape + h_mean = np.mean(h, axis=1) + tk = np.broadcast_to(np.expand_dims(np.arange(dims), axis=0), (features, dims)) # (24,2803) + tk_mean = np.mean(tk, axis=1) + tred = np.abs(np.sum(np.multiply((h - np.broadcast_to(np.expand_dims(h_mean, axis=1), (features, dims))), + (tk - np.broadcast_to(np.expand_dims(tk_mean, axis=1), (features, dims)))), + axis=1)) / np.sqrt( + np.sum((h - np.broadcast_to(np.expand_dims(h_mean, axis=1), (features, dims))) ** 2, axis=1) * np.sum( + (tk - np.broadcast_to(np.expand_dims(tk_mean, axis=1), (features, dims))) ** 2, axis=1)) + # print(tred) + + tred = np.expand_dims(tred, axis=1) + # print("tred.shape:", tred.shape) + return tred + + # 单调性 + def getMon(self): + h = self.data + (features, dims) = h.shape + mon = np.empty(shape=[24, 1]) + for feature in range(features): + positive = 0 + negative = 0 + for dim in range(dims): + if dim + 1 >= dims: + break + if h[feature][dim + 1] - h[feature][dim] > 0: + positive += 1 + if h[feature][dim + 1] - h[feature][dim] < 0: + negative += 1 + # print("positive:",positive) + # print("negetive:",negative) + mon[feature] = np.abs((positive - negative) / (dims - 1)) + # print(mon[feature]) + # print(mon) + # print("mon.shape",mon.shape) + return mon + + # 尺度相似性 + def getScale(self): + scale = np.zeros(shape=[24, 1]) + return scale + + +if __name__ == '__main__': + scores = HI_select(feature_data).getScore() + (feature, score) = scores.shape + scores = np.ravel(scores) + print(scores.shape) + + # 归一化处理 + # scores = (scores - np.min(scores)) / (np.max(scores) - np.min(scores)) + # score图 + plt.bar(range(feature),scores,color=['r','g','b','c','m','y']) + plt.show() + + # 获取前9个最大值的索引 + # print(scores) + # indexs = np.argpartition(scores, -12)[-12:] # [ 1 23 16 9 19 20 2 22 18] 自选【1,2,3,11,20,23】 备选【9,16,18】 + # print(indexs) + # # 选出所需的data + # Selected_data = [] + # feature_data = np.transpose(feature_data, [1, 0]) # (2803,24) + # z = 0 + # for index in indexs: + # if z == 0: + # Selected_data = feature_data[:, index] + # else: + # Selected_data = np.vstack([Selected_data, feature_data[:, index]]) + # z += 1 + # Selected_data=np.transpose(Selected_data,[1,0]) #(2803,9) + # # np.save("Select_data.npy",Selected_data) + # print(Selected_data.shape) diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step6_final.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step6_final.py new file mode 100644 index 0000000..e6789c1 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step6_final.py @@ -0,0 +1,22 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/23 13:43 +@Usage : +@Desc : +''' + +import numpy as np + +import matplotlib.pyplot as plt + +data = np.load("HI_merge_data1.npy") + +print(data) + +data= data[:,1] + +plt.plot(data) +plt.show() + diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step_5_HI_merge.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step_5_HI_merge.py new file mode 100644 index 0000000..2d4f7b8 --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/HI_create/step_5_HI_merge.py @@ -0,0 +1,82 @@ +import tensorflow as tf +import numpy as np +import pandas as pd +import matplotlib.pyplot as plt +from keras.callbacks import EarlyStopping + +# 数据读取 +# train_data = np.load("Select_data.npy") +# print(train_data.shape) +feature_data = np.load("../data/feature_data.npy") +print(feature_data.shape) # (2803,24) +indexs=[4,11,16,20,23] +z = 0 +for index in indexs: + if z == 0: + Selected_data = feature_data[:, index] + else: + Selected_data = np.vstack([Selected_data, feature_data[:, index]]) + z += 1 +Selected_data = np.transpose(Selected_data, [1, 0]) # (2803,9) + +plt.plot(Selected_data) +plt.show() + +train_data=Selected_data[1500:-1,:] +print(train_data.shape) +plt.plot(train_data) +plt.show() + + +# 建立模型 +class model(): + + def __init__(self, input_shape=9): + self.input_shape = input_shape + pass + + def getModel(self, model_Type='ae'): + if model_Type == 'ae': + model = self.AE_model() + return model + else: + raise ValueError("模型尚未实现") + + def AE_model(self): + input = tf.keras.Input(shape=self.input_shape) + d1 = tf.keras.layers.Dense(4)(input) + # d2 = tf.keras.layers.Dense(2, activation='relu')(d1) + d3 = tf.keras.layers.Dense(2, name='mid', activation='relu')(d1) + # d4 = tf.keras.layers.Dense(2, activation='relu')(d3) + d5 = tf.keras.layers.Dense(4)(d3) + d6 = tf.keras.layers.Dense(self.input_shape)(d5) + model = tf.keras.Model(inputs=input, outputs=d6) + return model + + +# HI指标训练和合成 +if __name__ == '__main__': + model = model(input_shape=5).getModel(model_Type='ae') + model.compile(optimizer=tf.optimizers.Adam(0.001), loss=tf.losses.mse, metrics=['acc']) + # model.summary() + + checkpoint = tf.keras.callbacks.ModelCheckpoint( + filepath="AE_model.h5", + monitor='val_loss', + verbose=2, + save_best_only=True, + mode='min') + lr_scheduler = tf.keras.callbacks.ReduceLROnPlateau(monitor='val_loss', factor=0.2, patience=10, min_lr=0.0001) + + model.compile(optimizer=tf.optimizers.SGD(), loss=tf.losses.mse) + # model.compile(optimizer=tf.optimizers.SGD(learning_rate=0.001), loss=FTMSE()) + model.summary() + early_stop = EarlyStopping(monitor='val_loss', min_delta=0.0001, patience=20, mode='min', verbose=1) + + history = model.fit(train_data, train_data, epochs=1000, batch_size=100) + HI_merge_data = tf.keras.models.Model(inputs=model.input, outputs=model.get_layer('mid').output).predict(train_data) + print(HI_merge_data) + acc = np.array(history.history.get('acc')) + # if acc[299] > 0.9: + np.save("HI_merge_data1.npy", HI_merge_data) + model.save("AE_model.h5") diff --git a/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/__init__.py b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/__init__.py new file mode 100644 index 0000000..6dee54d --- /dev/null +++ b/TensorFlow_eaxmple/Model_train_test/wind_turbine_predict/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/21 16:41 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/CommonFunction.py b/pytorch_example/RUL/baseModel/CommonFunction.py new file mode 100644 index 0000000..df04d50 --- /dev/null +++ b/pytorch_example/RUL/baseModel/CommonFunction.py @@ -0,0 +1,143 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:57 +@Usage : +@Desc : +''' + +import os +import shutil + +import numpy as np +import pandas as pd + + +def folderGenerate(folder_name): + if not os.path.exists(folder_name): + os.makedirs(folder_name) + # os.mkdir(folder_name) + + +# 递归删除文件夹 +def folderDelete(folder_name): + if os.path.exists(folder_name): + shutil.rmtree(folder_name) + + +# 判断这次是否进行模型保存,history_loss存储历史上的loss +def SaveBestModel(model, save_name, history_loss, loss_value, pattern: str = "min", epoch=0, is_all=False): + weight_folder = save_name[:-4] + if is_all: + weight_folder = weight_folder + '_epoch' + str(epoch) + "_" + str(loss_value) + save_name = weight_folder + save_name[-7:] + + # 如果history_loss为空,那么直接保存 + if len(history_loss) == 0: + folderGenerate(weight_folder) + model.save_weights(save_name) + return + + if pattern == "min": + # 先判断要不要存模型,如果上一次的比这一次的loss要大,就保存这一次的 + if np.min(history_loss) > loss_value: + # 删除上一次的保存这一次的 + folderDelete(weight_folder) + folderGenerate(weight_folder) + model.save_weights(save_name) + print("保存这次模型") + return + elif pattern == "max": + # 先判断要不要存模型,如果上一次的比这一次的loss要大,就保存这一次的 + if np.max(history_loss) < loss_value: + # 删除上一次的保存这一次的 + folderDelete(weight_folder) + folderGenerate(weight_folder) + model.save_weights(save_name) + print("保存这次模型") + return + else: + raise ValueError("算法尚未实现") + + pass + + +# 判断这次是否进行模型保存,history_loss存储历史上的loss +def SaveBestModelByAccuracy(model, save_name, history_accuracy, accuracy_value): + weight_folder = save_name[:-7] + + # 如果history_loss为空,那么直接保存 + if len(history_accuracy) == 0: + folderGenerate(weight_folder) + model.save_weights(save_name) + return + + # 先判断要不要存模型,如果上一次的比这一次的loss要大,就保存这一次的 + if np.max(history_accuracy) < accuracy_value: + # 删除上一次的保存这一次的 + folderDelete(weight_folder) + folderGenerate(weight_folder) + model.save_weights(save_name) + print("保存这次模型") + return + + pass + + +# 判断这次是否进行模型保存,history_loss存储历史上的loss +def SaveBestH5Model(model, save_name, history_loss, loss_value): + dirpath = os.path.dirname(save_name) + folderGenerate(dirpath) + # 如果history_loss为空,那么直接保存 + if len(history_loss) == 0: + model.save(save_name) + return + + # 先判断要不要存模型,如果上一次的比这一次的loss要大,就保存这一次的 + if np.min(history_loss) > loss_value: + # 删除上一次的保存这一次的 + model.save(save_name, overwrite=True) + print("保存这次模型") + return + + pass + + +def IsStopTraining(history_loss, patience=5, pattern: str = "min"): + if len(history_loss) <= patience: + return False + if pattern == "min": + if history_loss[-(patience + 1)] < min(history_loss[-patience:]): + print(patience, "次loss未下降,训练停止") + return True + elif pattern == "max": + if history_loss[-(patience + 1)] > max(history_loss[-patience:]): + print(patience, "次准确率为上升,训练停止") + return True + else: + raise ValueError("算法尚未实现") + + return False + + +def Is_Reduce_learning_rate(history_loss, patience=3, pattern: str = "min"): + if len(history_loss) <= patience: + return False + if pattern == "min": + for i in range(patience): + if history_loss[-(patience + 1)] > history_loss[-i]: + return False + elif pattern == "max": + for i in range(patience): + if history_loss[-(patience + 1)] < history_loss[-i]: + return False + else: + raise ValueError("算法尚未实现") + print(patience, "次loss未下降,降低学习率") + return True + + +if __name__ == '__main__': + history_loss = [0.1, 0.2, 0.3, 0.25, 0.42, 0.12, 0.31] + IsStopTraining(history_loss) diff --git a/pytorch_example/RUL/baseModel/__init__.py b/pytorch_example/RUL/baseModel/__init__.py new file mode 100644 index 0000000..77ba3ba --- /dev/null +++ b/pytorch_example/RUL/baseModel/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 13:00 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/dctAttention.py b/pytorch_example/RUL/baseModel/dctAttention.py new file mode 100644 index 0000000..757116b --- /dev/null +++ b/pytorch_example/RUL/baseModel/dctAttention.py @@ -0,0 +1,114 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 13:00 +@Usage : +@Desc : 构建一些即插即用的channelAttention +''' + +import torch.nn as nn +import math +import numpy as np +import torch +import torch_dct as dct + +try: + from torch import irfft + from torch import rfft +except ImportError: + def rfft(x, d): + t = torch.fft.fft(x, dim=(-d)) + r = torch.stack((t.real, t.imag), -1) + return r + + + def irfft(x, d): + t = torch.fft.ifft(torch.complex(x[:, :, 0], x[:, :, 1]), dim=(-d)) + return t.real + + +# def dct(x, norm=None): +# """ +# Discrete Cosine Transform, Type II (a.k.a. the DCT) +# +# For the meaning of the parameter `norm`, see: +# https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.fftpack.dct.html +# +# :param x: the input signal +# :param norm: the normalization, None or 'ortho' +# :return: the DCT-II of the signal over the last dimension +# """ +# x_shape = x.shape +# N = x_shape[-1] +# x = x.contiguous().view(-1, N) +# +# v = torch.cat([x[:, ::2], x[:, 1::2].flip([1])], dim=1) +# +# # Vc = torch.fft.rfft(v, 1, onesided=False) +# Vc = rfft(v, 1) +# +# k = - torch.arange(N, dtype=x.dtype, device=x.device)[None, :] * np.pi / (2 * N) +# W_r = torch.cos(k) +# W_i = torch.sin(k) +# +# V = Vc[:, :, 0] * W_r - Vc[:, :, 1] * W_i +# +# if norm == 'ortho': +# V[:, 0] /= np.sqrt(N) * 2 +# V[:, 1:] /= np.sqrt(N / 2) * 2 +# +# V = 2 * V.view(*x_shape) +# +# return V + +class dct_channel_block(nn.Module): + def __init__(self, channel): + super(dct_channel_block, self).__init__() + # self.avg_pool = nn.AdaptiveAvgPool1d(1) #innovation + self.fc = nn.Sequential( + nn.Linear(channel, channel * 2, bias=False), + nn.Dropout(p=0.1), + nn.ReLU(inplace=True), + nn.Linear(channel * 2, channel, bias=False), + nn.Sigmoid() + ) + # self.dct_norm = nn.LayerNorm([512], eps=1e-6) + + self.dct_norm = nn.LayerNorm([channel], eps=1e-6) # for lstm on length-wise + # self.dct_norm = nn.LayerNorm([36], eps=1e-6)#for lstm on length-wise on ill with input =36 + + def forward(self, x): + b, c = x.size() # (B,C,L) (32,96,512) + + # list = [] + # for i in range(c): + # freq = dct.dct(x[:, :, i]) + # list.append(freq) + # + # stack_dct = torch.stack(list, dim=2) + + # change = x.transpose(2, 1) + stack_dct = dct.dct(x,norm='ortho') + # stack_dct = stack_dct.transpose(2, 1) + + # stack_dct = torch.tensor(stack_dct) + ''' + for traffic mission:f_weight = self.dct_norm(f_weight.permute(0,2,1))#matters for traffic datasets + ''' + + lr_weight = self.dct_norm(stack_dct) + lr_weight = self.fc(stack_dct) + lr_weight = self.dct_norm(lr_weight) + + # print("lr_weight",lr_weight.shape) + return x * lr_weight # result + + +if __name__ == '__main__': + # input_data = torch.Tensor([[1, 2, 3], [4, 5, 6]]) # [2, 3] + x = torch.rand((32, 10, 64)) + print(x.shape) + m = nn.Linear(64, 2) + output = m(x) + print(output.shape) # [2, 2] diff --git a/pytorch_example/RUL/baseModel/dctChannelAttention.py b/pytorch_example/RUL/baseModel/dctChannelAttention.py new file mode 100644 index 0000000..b6b7b92 --- /dev/null +++ b/pytorch_example/RUL/baseModel/dctChannelAttention.py @@ -0,0 +1,159 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 13:00 +@Usage : +@Desc : 构建一些即插即用的channelAttention +''' + +import torch.nn as nn +import math +import numpy as np +import torch +import torch_dct as dct + +try: + from torch import irfft + from torch import rfft +except ImportError: + def rfft(x, d): + t = torch.fft.fft(x, dim=(-d)) + r = torch.stack((t.real, t.imag), -1) + return r + + + def irfft(x, d): + t = torch.fft.ifft(torch.complex(x[:, :, 0], x[:, :, 1]), dim=(-d)) + return t.real + + +# def dct(x, norm=None): +# """ +# Discrete Cosine Transform, Type II (a.k.a. the DCT) +# +# For the meaning of the parameter `norm`, see: +# https://docs.scipy.org/doc/scipy-0.14.0/reference/generated/scipy.fftpack.dct.html +# +# :param x: the input signal +# :param norm: the normalization, None or 'ortho' +# :return: the DCT-II of the signal over the last dimension +# """ +# x_shape = x.shape +# N = x_shape[-1] +# x = x.contiguous().view(-1, N) +# +# v = torch.cat([x[:, ::2], x[:, 1::2].flip([1])], dim=1) +# +# # Vc = torch.fft.rfft(v, 1, onesided=False) +# Vc = rfft(v, 1) +# +# k = - torch.arange(N, dtype=x.dtype, device=x.device)[None, :] * np.pi / (2 * N) +# W_r = torch.cos(k) +# W_i = torch.sin(k) +# +# V = Vc[:, :, 0] * W_r - Vc[:, :, 1] * W_i +# +# if norm == 'ortho': +# V[:, 0] /= np.sqrt(N) * 2 +# V[:, 1:] /= np.sqrt(N / 2) * 2 +# +# V = 2 * V.view(*x_shape) +# +# return V + + +class dct_channel_block(nn.Module): + def __init__(self, channel): + super(dct_channel_block, self).__init__() + # self.avg_pool = nn.AdaptiveAvgPool1d(1) #innovation + self.fc = nn.Sequential( + nn.Linear(channel, channel * 2, bias=False), + nn.Dropout(p=0.1), + nn.ReLU(inplace=True), + nn.Linear(channel * 2, channel, bias=False), + nn.Sigmoid() + ) + # self.dct_norm = nn.LayerNorm([512], eps=1e-6) + + self.dct_norm = nn.LayerNorm([channel], eps=1e-6) # for lstm on length-wise + # self.dct_norm = nn.LayerNorm([36], eps=1e-6)#for lstm on length-wise on ill with input =36 + + def forward(self, x): + b, t, c = x.size() # (B,C,L) (32,96,512) + + # list = [] + # for i in range(c): + # freq = dct.dct(x[:, :, i]) + # list.append(freq) + # + # stack_dct = torch.stack(list, dim=2) + + change = x.transpose(2, 1) + stack_dct = dct.dct(change,norm='ortho') + stack_dct = stack_dct.transpose(2, 1) + + # stack_dct = torch.tensor(stack_dct) + ''' + for traffic mission:f_weight = self.dct_norm(f_weight.permute(0,2,1))#matters for traffic datasets + ''' + + lr_weight = self.dct_norm(stack_dct) + lr_weight = self.fc(stack_dct) + lr_weight = self.dct_norm(lr_weight) + + # print("lr_weight",lr_weight.shape) + return x * lr_weight # result + + +class dct_channel_block1(nn.Module): + def __init__(self, channel): + super(dct_channel_block1, self).__init__() + # self.avg_pool = nn.AdaptiveAvgPool1d(1) #innovation + self.fc = nn.Sequential( + nn.Linear(channel, channel * 2, bias=False), + nn.Dropout(p=0.1), + nn.ReLU(inplace=True), + nn.Linear(channel * 2, channel, bias=False), + nn.Sigmoid() + ) + # self.dct_norm = nn.LayerNorm([512], eps=1e-6) + + self.dct_norm = nn.LayerNorm([96], eps=1e-6) # for lstm on length-wise + # self.dct_norm = nn.LayerNorm([36], eps=1e-6)#for lstm on length-wise on ill with input =36 + + def forward(self, x): + b, c, l = x.size() # (B,C,L) (32,96,512) + # y = self.avg_pool(x) # (B,C,L) -> (B,C,1) + + # y = self.avg_pool(x).view(b, c) # (B,C,L) -> (B,C,1) + # print("y",y.shape + # y = self.fc(y).view(b, c, 96) + list = [] + for i in range(c): + freq = dct.dct(x[:, i, :]) + # print("freq-shape:",freq.shape) + list.append(freq) + + stack_dct = torch.stack(list, dim=1) + stack_dct = torch.tensor(stack_dct) + ''' + for traffic mission:f_weight = self.dct_norm(f_weight.permute(0,2,1))#matters for traffic datasets + ''' + + lr_weight = self.dct_norm(stack_dct) + lr_weight = self.fc(stack_dct) + lr_weight = self.dct_norm(lr_weight) + + # print("lr_weight",lr_weight.shape) + return x * lr_weight # result +if __name__ == '__main__': + # input_data = torch.Tensor([[1, 2, 3], [4, 5, 6]]) # [2, 3] + x = torch.rand((8, 7, 96)) + dct_model = dct_channel_block1(7) + result = dct_model.forward(x) + print(result) + # print(x.shape) + # m = nn.Linear(64, 2) + # output = m(x) + # print(output.shape) # [2, 2] diff --git a/pytorch_example/RUL/baseModel/loss/Evaluate.py b/pytorch_example/RUL/baseModel/loss/Evaluate.py new file mode 100644 index 0000000..20a5e70 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/Evaluate.py @@ -0,0 +1,78 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/23 16:32 +@Usage : +@Desc : +''' + +import torch +import torch.nn as nn +import torch.nn.functional as F +import numpy as np + + +def mae(y_true, y_predict): + return np.mean(np.mean(np.abs(y_true - y_predict), axis=-1)) + + +def mape(y_true, y_predict): + return np.mean(np.mean(np.abs((y_true - y_predict) / y_true), axis=-1)) + + +def score(y_true, y_predict): + Eri = y_predict - y_true + dw = np.log(0.5) + total = [] + + if len(y_true.shape) > 1: + b, c = y_true.shape + + for i in range(b): + cList = [] + for j in range(c): + if Eri[i, j] < 0: + cList.append(np.exp(-(Eri[i, j] / 13)) - 1) + else: + cList.append(np.exp((Eri[i, j] / 10)) - 1) + total.append(np.stack(cList)) + total = np.stack(total, axis=0) + + return np.mean(np.mean(total, axis=-1)) + else: + b, = y_true.shape + for i in range(b): + if Eri[i] <= 0: + total.append(np.exp((-dw) * (Eri[i] / 5))) + else: + total.append(np.exp((dw) * (Eri[i] / 20))) + total = np.stack(total, axis=0) + + return np.mean(total) + + pass + + +def rmse(y_true, y_predict): + loss = np.sqrt(np.mean(np.mean((y_predict - y_true) ** 2, axis=-1))) + + return loss + + +def getEvaluate(y_true, y_predict): + return [rmse(y_true, y_predict), mae(y_true, y_predict), mape(y_true, y_predict), score(y_true, y_predict)] + + +if __name__ == '__main__': + # a = torch.log(torch.tensor(0.5)) + # print(a) + # x = torch.rand((32,)) + # y = torch.rand((32,)) + x = np.random.random(size=(32,)) + y = np.random.random(size=(32,)) + + print(mae(x, y)) + print(mape(x, y)) + print(rmse(x, y)) + print(score(x, y)) diff --git a/pytorch_example/RUL/baseModel/loss/__init__.py b/pytorch_example/RUL/baseModel/loss/__init__.py new file mode 100644 index 0000000..1c722d2 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/20 16:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/adv_loss.py b/pytorch_example/RUL/baseModel/loss/adv_loss.py new file mode 100644 index 0000000..027bb37 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/adv_loss.py @@ -0,0 +1,57 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:46 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +import math +import numpy as np +import torch.nn.functional as F +from torch.autograd import Function + +class ReverseLayerF(Function): + + @staticmethod + def forward(ctx, x, alpha): + ctx.alpha = alpha + return x.view_as(x) + + @staticmethod + def backward(ctx, grad_output): + output = grad_output.neg() * ctx.alpha + return output, None + + +class Discriminator(nn.Module): + def __init__(self, input_dim=256, hidden_dim=256): + super(Discriminator, self).__init__() + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.dis1 = nn.Linear(input_dim, hidden_dim) + self.dis2 = nn.Linear(hidden_dim, 1) + + def forward(self, x): + x = F.relu(self.dis1(x)) + x = self.dis2(x) + x = torch.sigmoid(x) + return x + + +def adv(source, target, input_dim=256, hidden_dim=512): + domain_loss = nn.BCELoss() + # !!! Pay attention to .cuda !!! + adv_net = Discriminator(input_dim, hidden_dim) + domain_src = torch.ones(len(source)) # 源域的标签 + domain_tar = torch.zeros(len(target)) # 目标域的标签 + domain_src, domain_tar = domain_src.view(domain_src.shape[0], 1), domain_tar.view(domain_tar.shape[0], 1) + reverse_src = ReverseLayerF.apply(source, 1) + reverse_tar = ReverseLayerF.apply(target, 1) + pred_src = adv_net(reverse_src) + pred_tar = adv_net(reverse_tar) + loss_s, loss_t = domain_loss(pred_src, domain_src), domain_loss(pred_tar, domain_tar) + loss = loss_s + loss_t + return loss \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/coral.py b/pytorch_example/RUL/baseModel/loss/coral.py new file mode 100644 index 0000000..d6676a7 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/coral.py @@ -0,0 +1,27 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:46 +@Usage : +@Desc : +''' +import torch + +def CORAL(source, target): + d = source.size(1) + ns, nt = source.size(0), target.size(0) + + # source covariance + tmp_s = torch.ones((1, ns)) @ source + cs = (source.t() @ source - (tmp_s.t() @ tmp_s) / ns) / (ns - 1) + + # target covariance + tmp_t = torch.ones((1, nt)) @ target + ct = (target.t() @ target - (tmp_t.t() @ tmp_t) / nt) / (nt - 1) + + # frobenius norm + loss = (cs - ct).pow(2).sum() + loss = loss / (4 * d * d) + + return loss \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/cos.py b/pytorch_example/RUL/baseModel/loss/cos.py new file mode 100644 index 0000000..ec220e0 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/cos.py @@ -0,0 +1,15 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:47 +@Usage : +@Desc : +''' +import torch.nn as nn + +def cosine(source, target): + source, target = source.mean(0), target.mean(0) + cos = nn.CosineSimilarity(dim=0) + loss = cos(source, target) + return loss.mean() \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/ffd.py b/pytorch_example/RUL/baseModel/loss/ffd.py new file mode 100644 index 0000000..26dcd96 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/ffd.py @@ -0,0 +1,40 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/20 15:44 +@Usage : +@Desc : fft 频域Loss +''' +import torch +import torch.nn as nn + +import torch_dct as dct +import torch.fft as fft + + +def fft_mse(source, target): + if len(source.shape) < 2: + length = 1 + else: + _, length = source.shape + source = fft.rfft(source) + target = fft.rfft(target) + + source = torch.abs(source / length) + target = torch.abs(target / length) + source, target = source.mean(0), target.mean(0) + mse = nn.MSELoss() + loss = mse(source, target) + return loss.mean() + pass + + +def dct_mse(source, target): + source = dct.dct(source) + target = dct.dct(target) + source, target = source.mean(0), target.mean(0) + mse = nn.MSELoss() + loss = mse(source, target) + return loss.mean() + pass diff --git a/pytorch_example/RUL/baseModel/loss/kl_js.py b/pytorch_example/RUL/baseModel/loss/kl_js.py new file mode 100644 index 0000000..8b36670 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/kl_js.py @@ -0,0 +1,28 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:47 +@Usage : +@Desc : +''' +import torch.nn as nn + +def kl_div(source, target): + if len(source) < len(target): + target = target[:len(source)] + elif len(source) > len(target): + source = source[:len(target)] + criterion = nn.KLDivLoss(reduction='batchmean') + loss = criterion(source.log(), target) + return loss + + +def js(source, target): + if len(source) < len(target): + target = target[:len(source)] + elif len(source) > len(target): + source = source[:len(target)] + M = .5 * (source + target) + loss_1, loss_2 = kl_div(source, M), kl_div(target, M) + return .5 * (loss_1 + loss_2) \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/mmd.py b/pytorch_example/RUL/baseModel/loss/mmd.py new file mode 100644 index 0000000..603c831 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/mmd.py @@ -0,0 +1,57 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:47 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn + +class MMD_loss(nn.Module): + def __init__(self, kernel_type='linear', kernel_mul=2.0, kernel_num=5): + super(MMD_loss, self).__init__() + self.kernel_num = kernel_num + self.kernel_mul = kernel_mul + self.fix_sigma = None + self.kernel_type = kernel_type + + def guassian_kernel(self, source, target, kernel_mul=2.0, kernel_num=5, fix_sigma=None): + n_samples = int(source.size()[0]) + int(target.size()[0]) + total = torch.cat([source, target], dim=0) + total0 = total.unsqueeze(0).expand( + int(total.size(0)), int(total.size(0)), int(total.size(1))) + total1 = total.unsqueeze(1).expand( + int(total.size(0)), int(total.size(0)), int(total.size(1))) + L2_distance = ((total0-total1)**2).sum(2) + if fix_sigma: + bandwidth = fix_sigma + else: + bandwidth = torch.sum(L2_distance.data) / (n_samples**2-n_samples) + bandwidth /= kernel_mul ** (kernel_num // 2) + bandwidth_list = [bandwidth * (kernel_mul**i) + for i in range(kernel_num)] + kernel_val = [torch.exp(-L2_distance / bandwidth_temp) + for bandwidth_temp in bandwidth_list] + return sum(kernel_val) + + def linear_mmd(self, X, Y): + delta = X.mean(axis=0) - Y.mean(axis=0) + loss = delta.dot(delta.T) + return loss + + def forward(self, source, target): + if self.kernel_type == 'linear': + return self.linear_mmd(source, target) + elif self.kernel_type == 'rbf': + batch_size = int(source.size()[0]) + kernels = self.guassian_kernel( + source, target, kernel_mul=self.kernel_mul, kernel_num=self.kernel_num, fix_sigma=self.fix_sigma) + with torch.no_grad(): + XX = torch.mean(kernels[:batch_size, :batch_size]) + YY = torch.mean(kernels[batch_size:, batch_size:]) + XY = torch.mean(kernels[:batch_size, batch_size:]) + YX = torch.mean(kernels[batch_size:, :batch_size]) + loss = torch.mean(XX + YY - XY - YX) + return loss \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/mutual_info.py b/pytorch_example/RUL/baseModel/loss/mutual_info.py new file mode 100644 index 0000000..f7edc52 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/mutual_info.py @@ -0,0 +1,38 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:47 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +import torch.nn.functional as F + +class Mine_estimator(nn.Module): + def __init__(self, input_dim=2048, hidden_dim=512): + super(Mine_estimator, self).__init__() + self.mine_model = Mine(input_dim, hidden_dim) + + def forward(self, X, Y): + Y_shffle = Y[torch.randperm(len(Y))] + loss_joint = self.mine_model(X, Y) + loss_marginal = self.mine_model(X, Y_shffle) + ret = torch.mean(loss_joint) - \ + torch.log(torch.mean(torch.exp(loss_marginal))) + loss = -ret + return loss + + +class Mine(nn.Module): + def __init__(self, input_dim=2048, hidden_dim=512): + super(Mine, self).__init__() + self.fc1_x = nn.Linear(input_dim, hidden_dim) + self.fc1_y = nn.Linear(input_dim, hidden_dim) + self.fc2 = nn.Linear(hidden_dim, 1) + + def forward(self, x, y): + h1 = F.leaky_relu(self.fc1_x(x)+self.fc1_y(y)) + h2 = self.fc2(h1) + return h2 \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/loss/pair_dist.py b/pytorch_example/RUL/baseModel/loss/pair_dist.py new file mode 100644 index 0000000..74ced73 --- /dev/null +++ b/pytorch_example/RUL/baseModel/loss/pair_dist.py @@ -0,0 +1,54 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:48 +@Usage : +@Desc : +''' +import torch +import numpy as np + + +def pairwise_dist(X, Y): + n, d = X.shape + m, _ = Y.shape + assert d == Y.shape[1] + a = X.unsqueeze(1).expand(n, m, d) + b = Y.unsqueeze(0).expand(n, m, d) + return torch.pow(a - b, 2).sum(2) + + +def pairwise_dist_np(X, Y): + n, d = X.shape + m, _ = Y.shape + assert d == Y.shape[1] + a = np.expand_dims(X, 1) + b = np.expand_dims(Y, 0) + a = np.tile(a, (1, m, 1)) + b = np.tile(b, (n, 1, 1)) + return np.power(a - b, 2).sum(2) + +def pa(X, Y): + XY = np.dot(X, Y.T) + XX = np.sum(np.square(X), axis=1) + XX = np.transpose([XX]) + YY = np.sum(np.square(Y), axis=1) + dist = XX + YY - 2 * XY + + return dist + + +if __name__ == '__main__': + import sys + args = sys.argv + data = args[0] + print(data) + + # a = torch.arange(1, 7).view(2, 3) + # b = torch.arange(12, 21).view(3, 3) + # print(pairwise_dist(a, b)) + + # a = np.arange(1, 7).reshape((2, 3)) + # b = np.arange(12, 21).reshape((3, 3)) + # print(pa(a, b)) \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/plot.py b/pytorch_example/RUL/baseModel/plot.py new file mode 100644 index 0000000..f4a66f7 --- /dev/null +++ b/pytorch_example/RUL/baseModel/plot.py @@ -0,0 +1,113 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/20 19:30 +@Usage : +@Desc : +''' + +import matplotlib.pyplot as plt +import time + + +def plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=50): + font1 = {'family': 'Times New Roman', 'weight': 'normal', 'size': 15} # 设置坐标标签的字体大小,字体 + font2 = {'family': 'Times New Roman', 'weight': 'normal', 'size': 15} # 设置坐标标签的字体大小,字体 + timestamp = str(int(time.time()))[-4:] # 画图的时间戳取后四位 + plt.figure(1) + + '''保存的模型参数的路径''' + + from matplotlib import rcParams + + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + # 简单预测图 + length = len(predicted_data_easy) + plt.scatter(list(range(length)), total_data, c='blue', s=12, label='Actual value') + plt.plot(list(range(length - predict_num)), + predicted_data_easy[:length - predict_num], linewidth=2, color='red', + label='Traning value') + plt.scatter(list(range(length - predict_num, length)), predicted_data_easy[length - predict_num:length], c='black', + s=15, label='Predictive value') + plt.axhline(total_data[-1], linewidth=2, c='green', label='Failure threshold') + # plt.title() + plt.xlabel('Serial number of the fusion feature point', font=font1) + plt.ylabel('Virtual health indicator', font=font1) + + plt.legend(loc='upper left', prop=font2) + plt.savefig(save_fig_name + 'easy{0}.png'.format(timestamp)) + plt.show() + + # 困难预测图 + plt.figure(2) + + '''保存的模型参数的路径''' + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + # 简单预测图 + length = len(predicted_data_easy) + + plt.scatter(list(range(length)), total_data, c='blue', s=12, label='Actual value') + plt.plot(list(range(length - predict_num)), + predicted_data_hard[:length - predict_num], linewidth=2, color='red', + label='Traning value') + plt.scatter(list(range(length - predict_num, length)), predicted_data_hard[length - predict_num:length], c='black', + s=15, label='Predictive value') + # plt.title() + plt.xlabel('Serial number of the fusion feature point', font=font1) + plt.ylabel('Virtual health indicator', font=font1) + plt.axhline(total_data[-1], linewidth=2, c='green', label='Failure threshold') + plt.legend(loc='upper left', prop=font2) + + plt.savefig(save_fig_name + 'hard{0}.png'.format(timestamp)) + plt.show() + + +def plot_forSelf(total_data, predicted_data_easy, predicted_data_hard): + pic1 = plt.figure(figsize=(8, 6), dpi=200) + + '''保存的模型参数的路径''' + + from matplotlib import rcParams + + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + # 简单预测图 + plt.subplot(2, 1, 1) + plt.plot(total_data) + plt.plot(predicted_data_easy) + plt.title('Easy Prediction') + plt.xlabel('time') + plt.ylabel('loss') + # plt.legend(loc='upper right') + + # 困难预测图 + plt.subplot(2, 1, 2) + plt.plot(total_data) + plt.plot(predicted_data_hard) + plt.title('Easy Prediction') + plt.xlabel('time') + plt.ylabel('loss') + + # plt.legend(loc='upper right') + + # plt.scatter() + + plt.show() diff --git a/pytorch_example/RUL/baseModel/test.py b/pytorch_example/RUL/baseModel/test.py new file mode 100644 index 0000000..cbf9141 --- /dev/null +++ b/pytorch_example/RUL/baseModel/test.py @@ -0,0 +1,10 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/24 14:15 +@Usage : +@Desc : 一些测试方法 +''' + + diff --git a/pytorch_example/RUL/baseModel/utils/__init__.py b/pytorch_example/RUL/baseModel/utils/__init__.py new file mode 100644 index 0000000..fdbef72 --- /dev/null +++ b/pytorch_example/RUL/baseModel/utils/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/24 15:51 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/baseModel/utils/utils.py b/pytorch_example/RUL/baseModel/utils/utils.py new file mode 100644 index 0000000..952e555 --- /dev/null +++ b/pytorch_example/RUL/baseModel/utils/utils.py @@ -0,0 +1,229 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' + +import collections +import torch +import os +import pandas as pd +import torch.nn as nn +from tqdm import tqdm +import numpy as np + +EPS = 1e-12 + + +class AverageMeter(object): + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.list = [] + + def update(self, val, n=1): + self.val = val + self.list.append(val) + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +def average_params(params_list): + assert isinstance(params_list, (tuple, list, collections.deque)) + n = len(params_list) + if n == 1: + return params_list[0] + new_params = collections.OrderedDict() + keys = None + for i, params in enumerate(params_list): + if keys is None: + keys = params.keys() + for k, v in params.items(): + if k not in keys: + raise ValueError('the %d-th model has different params' % i) + if k not in new_params: + new_params[k] = v / n + else: + new_params[k] += v / n + return new_params + + +def zscore(x): + return (x - x.mean(dim=0, keepdim=True)) / x.std(dim=0, keepdim=True, unbiased=False) + + +def calc_loss(pred, label): + return torch.mean((zscore(pred) - label) ** 2) + + +def calc_corr(pred, label): + return (zscore(pred) * zscore(label)).mean() + + +def test_ic(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = label_actual.clone().detach().view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_daily(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values + avg), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for slc in tqdm(data_list[i].iter_daily(), total=data_list[i].daily_length): + feature, label_actual, _, _ = data_list[i].get(slc) + # for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = torch.tensor(label_actual, dtype=torch.float32, device=device).view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_uni(model, data_loader, model_path=None, ic_type='spearman', verbose=False): + if model_path: + model.load_state_dict(torch.load(model_path)) + model.eval() + loss_all = [] + ic_all = [] + for slc in tqdm(data_loader.iter_daily(), total=data_loader.daily_length): + data, label, _, _ = data_loader.get(slc) + with torch.no_grad(): + pred = model.predict(data) + mask = ~torch.isnan(label) + pred = pred[mask] + label = label[mask] + loss = torch.mean(torch.log(torch.cosh(pred - label))) + if ic_type == 'spearman': + ic = spearman_corr(pred, label) + elif ic_type == 'pearson': + ic = pearson_corr(pred, label) + loss_all.append(loss.item()) + ic_all.append(ic) + loss, ic = np.mean(loss_all), np.mean(ic_all) + if verbose: + print('IC: ', ic) + return loss, ic + + +def calc_ic(x, y, ic_type='pearson'): + ic = -100 + if ic_type == 'pearson': + ic = pearson_corr(x, y) + elif ic_type == 'spearman': + ic = spearman_corr(x, y) + return ic + + +def create_dir(path): + if not os.path.exists(path): + os.makedirs(path) + +def delete_file(path): + if os.path.exists(path): + os.remove(path) + + +def handle_nan(x): + mask = ~torch.isnan(x) + return x[mask], mask + + +class Log_Loss(nn.Module): + def __init__(self): + super(Log_Loss, self).__init__() + + def forward(self, ytrue, ypred): + delta = ypred - ytrue + return torch.mean(torch.log(torch.cosh(delta))) + + +def spearman_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='spearman') + return spearman + + +def spearman_corr2(x, y): + X = pd.Series(x) + Y = pd.Series(y) + spearman = X.corr(Y, method='spearman') + return spearman + + +def pearson_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='pearson') + return spearman + + +def dir_exist(dirs): + if not os.path.exists(dirs): + os.makedirs(dirs) \ No newline at end of file diff --git a/pytorch_example/RUL/dataset/HI_merge_data.npy b/pytorch_example/RUL/dataset/HI_merge_data.npy new file mode 100644 index 0000000..74088b7 Binary files /dev/null and b/pytorch_example/RUL/dataset/HI_merge_data.npy differ diff --git a/pytorch_example/RUL/dataset/HI_merge_data1.npy b/pytorch_example/RUL/dataset/HI_merge_data1.npy new file mode 100644 index 0000000..1175ec5 Binary files /dev/null and b/pytorch_example/RUL/dataset/HI_merge_data1.npy differ diff --git a/pytorch_example/RUL/dataset/smallVHI.csv b/pytorch_example/RUL/dataset/smallVHI.csv new file mode 100644 index 0000000..3cc183f --- /dev/null +++ b/pytorch_example/RUL/dataset/smallVHI.csv @@ -0,0 +1,1250 @@ +0.0172 +0.0173 +0.0184 +0.0343 +0.0195 +0.0284 +0 +0.0263 +0.0079 +0.0073 +0.0299 +0.023 +0.0475 +0.0229 +0.0623 +0.0235 +0.0272 +0.0325 +0.0168 +0.0044 +0.0217 +0.052 +0.043 +0.0125 +0.046 +0.0352 +0.0113 +0.0551 +0.0255 +0.0102 +0.0231 +0.018 +0.041 +0.0609 +0.0598 +0.0192 +0.0387 +0.0509 +0.0073 +0.0573 +0.0336 +0.0514 +0.0263 +0.0206 +0.0261 +0.0195 +0.044 +0.0488 +0.0102 +0.0424 +0.0204 +0.0127 +0.0212 +0.0346 +0.0282 +0.0379 +0.0369 +0.0335 +0.0425 +0.0313 +0.0341 +0.0527 +0.0622 +0.0487 +0.0714 +0.06 +0.0654 +0.0241 +0.0403 +0.0755 +0.0403 +0.041 +0.0439 +0.0447 +0.0401 +0.0414 +0.0283 +0.0233 +0.0209 +0.0451 +0.0515 +0.0447 +0.0675 +0.0385 +0.0535 +0.0322 +0.0261 +0.0499 +0.0249 +0.0573 +0.0586 +0.0416 +0.0478 +0.038 +0.028 +0.0102 +0.0164 +0.0322 +0.0204 +0.0626 +0.0405 +0.0538 +0.0495 +0.0585 +0.0283 +0.0489 +0.0488 +0.0475 +0.0429 +0.0316 +0.0442 +0.0476 +0.0507 +0.0375 +0.0316 +0.0318 +0.0695 +0.0515 +0.0343 +0.0336 +0.0308 +0.0211 +0.0286 +0.0324 +0.0706 +0.0618 +0.0366 +0.0718 +0.035 +0.0588 +0.0292 +0.0414 +0.022 +0.0557 +0.064 +0.0645 +0.0722 +0.1067 +0.103 +0.0821 +0.0641 +0.0423 +0.039 +0.0629 +0.0678 +0.0475 +0.057 +0.0517 +0.0711 +0.0728 +0.082 +0.0705 +0.0693 +0.0354 +0.0305 +0.0719 +0.0794 +0.0795 +0.0573 +0.0677 +0.0378 +0.0483 +0.0827 +0.0726 +0.0504 +0.079 +0.0954 +0.0815 +0.071 +0.067 +0.0972 +0.0423 +0.0529 +0.0634 +0.0326 +0.04 +0.0712 +0.0591 +0.0785 +0.0358 +0.0642 +0.0434 +0.0338 +0.0776 +0.0499 +0.0421 +0.0414 +0.0592 +0.0594 +0.0559 +0.0647 +0.029 +0.0501 +0.0602 +0.0543 +0.0488 +0.074 +0.034 +0.0567 +0.0589 +0.0699 +0.064 +0.0409 +0.0663 +0.0722 +0.064 +0.1028 +0.058 +0.0608 +0.0751 +0.0704 +0.0387 +0.0725 +0.0675 +0.0396 +0.0446 +0.0245 +0.0582 +0.0619 +0.051 +0.0596 +0.0637 +0.0686 +0.0578 +0.0951 +0.0749 +0.033 +0.0584 +0.0348 +0.0499 +0.0484 +0.0972 +0.1084 +0.1107 +0.0661 +0.073 +0.0901 +0.0501 +0.0878 +0.0525 +0.076 +0.0646 +0.0773 +0.0881 +0.0628 +0.1025 +0.1127 +0.0581 +0.0916 +0.0858 +0.0868 +0.1234 +0.0811 +0.0522 +0.0624 +0.0568 +0.1198 +0.105 +0.1004 +0.0877 +0.0575 +0.1017 +0.0767 +0.0887 +0.0587 +0.0793 +0.0697 +0.0882 +0.0907 +0.0946 +0.077 +0.0744 +0.0966 +0.076 +0.0354 +0.0779 +0.0686 +0.0926 +0.0898 +0.1199 +0.0632 +0.0912 +0.0736 +0.1014 +0.098 +0.0648 +0.0831 +0.0625 +0.1113 +0.1017 +0.1146 +0.1055 +0.0746 +0.0907 +0.0925 +0.1694 +0.0823 +0.0782 +0.0545 +0.0805 +0.1099 +0.1155 +0.1038 +0.0421 +0.0835 +0.0905 +0.1209 +0.1092 +0.0824 +0.0584 +0.0608 +0.0681 +0.0741 +0.0634 +0.0785 +0.1236 +0.0866 +0.0776 +0.0759 +0.0814 +0.0833 +0.0413 +0.0487 +0.1114 +0.074 +0.0905 +0.0893 +0.0519 +0.0838 +0.1004 +0.0864 +0.1133 +0.0886 +0.0901 +0.0694 +0.0901 +0.0998 +0.0797 +0.0847 +0.1201 +0.0615 +0.0656 +0.1266 +0.1007 +0.0955 +0.0511 +0.0826 +0.0693 +0.0685 +0.1515 +0.0655 +0.1055 +0.0727 +0.0809 +0.0998 +0.139 +0.0532 +0.0739 +0.1126 +0.1364 +0.0789 +0.101 +0.0866 +0.1181 +0.1094 +0.0966 +0.0613 +0.0636 +0.1289 +0.0995 +0.0813 +0.1515 +0.0972 +0.1173 +0.1266 +0.089 +0.1061 +0.1101 +0.1218 +0.1125 +0.1227 +0.113 +0.1263 +0.0578 +0.124 +0.0779 +0.0698 +0.1036 +0.0962 +0.0972 +0.1371 +0.0819 +0.1424 +0.1469 +0.1255 +0.0953 +0.1116 +0.096 +0.1208 +0.1163 +0.191 +0.1107 +0.1281 +0.1235 +0.1206 +0.1571 +0.1084 +0.0933 +0.1093 +0.1016 +0.1056 +0.0762 +0.0792 +0.1287 +0.0879 +0.1012 +0.0891 +0.105 +0.1143 +0.0853 +0.0805 +0.0821 +0.091 +0.1156 +0.1762 +0.1021 +0.1004 +0.1263 +0.0923 +0.1176 +0.1169 +0.1263 +0.1526 +0.2063 +0.1094 +0.1311 +0.1224 +0.19 +0.1229 +0.0918 +0.1145 +0.1675 +0.0923 +0.1179 +0.1415 +0.1301 +0.1456 +0.1443 +0.1555 +0.1051 +0.112 +0.0803 +0.1408 +0.1674 +0.1202 +0.1671 +0.1104 +0.1596 +0.1606 +0.1115 +0.185 +0.1496 +0.1573 +0.1228 +0.1017 +0.1238 +0.1138 +0.1174 +0.1429 +0.1604 +0.1286 +0.1269 +0.117 +0.1648 +0.11 +0.0936 +0.1252 +0.1158 +0.1363 +0.1192 +0.1564 +0.1659 +0.0866 +0.1234 +0.1441 +0.1549 +0.1362 +0.1102 +0.1421 +0.1678 +0.1118 +0.1146 +0.1343 +0.1301 +0.1011 +0.1823 +0.146 +0.1433 +0.1231 +0.1221 +0.1437 +0.1294 +0.1255 +0.1589 +0.0997 +0.1551 +0.1258 +0.1073 +0.131 +0.136 +0.1562 +0.1438 +0.1684 +0.1703 +0.1172 +0.1278 +0.1587 +0.1454 +0.2502 +0.1585 +0.1433 +0.1939 +0.1465 +0.1774 +0.1651 +0.2331 +0.1853 +0.1402 +0.1718 +0.1303 +0.1495 +0.1269 +0.1663 +0.1804 +0.2434 +0.1473 +0.1921 +0.1706 +0.1693 +0.1103 +0.1199 +0.1017 +0.1514 +0.1877 +0.1937 +0.1893 +0.1702 +0.2143 +0.2283 +0.2315 +0.1142 +0.1371 +0.1486 +0.1606 +0.1422 +0.2449 +0.1312 +0.1255 +0.1884 +0.1355 +0.2155 +0.1702 +0.1891 +0.1667 +0.1595 +0.1229 +0.156 +0.1516 +0.1883 +0.1425 +0.1702 +0.1368 +0.1613 +0.1708 +0.133 +0.1137 +0.1426 +0.1428 +0.146 +0.1712 +0.1291 +0.1806 +0.1393 +0.129 +0.1659 +0.1364 +0.1258 +0.1451 +0.188 +0.1495 +0.1251 +0.1955 +0.1553 +0.2071 +0.1557 +0.1533 +0.1341 +0.1565 +0.1308 +0.2062 +0.1284 +0.1162 +0.1312 +0.1397 +0.1607 +0.1403 +0.2012 +0.1944 +0.1398 +0.1114 +0.2279 +0.2039 +0.1746 +0.1646 +0.1905 +0.1928 +0.179 +0.2535 +0.1739 +0.1342 +0.1765 +0.1953 +0.2236 +0.167 +0.1562 +0.1491 +0.2115 +0.1774 +0.2054 +0.1837 +0.1796 +0.2151 +0.1979 +0.2116 +0.2192 +0.192 +0.2278 +0.2001 +0.2563 +0.1912 +0.2174 +0.2191 +0.2168 +0.1597 +0.1376 +0.1651 +0.1836 +0.2059 +0.1305 +0.1586 +0.1908 +0.1827 +0.1883 +0.2125 +0.2171 +0.164 +0.1983 +0.2403 +0.2206 +0.1958 +0.1706 +0.2473 +0.2015 +0.1581 +0.1908 +0.2192 +0.2896 +0.2545 +0.1967 +0.1643 +0.1846 +0.183 +0.201 +0.2145 +0.17 +0.1785 +0.1418 +0.2342 +0.237 +0.2261 +0.2521 +0.1714 +0.185 +0.2326 +0.225 +0.2167 +0.2032 +0.2879 +0.1751 +0.1834 +0.1914 +0.1887 +0.2251 +0.2016 +0.2209 +0.1873 +0.2692 +0.2183 +0.2082 +0.1809 +0.2293 +0.2262 +0.2202 +0.2152 +0.2536 +0.2442 +0.3825 +0.2664 +0.2277 +0.2192 +0.2455 +0.1534 +0.1547 +0.2054 +0.1748 +0.1844 +0.2099 +0.246 +0.1989 +0.2397 +0.2051 +0.1851 +0.3339 +0.19 +0.3349 +0.2158 +0.2426 +0.1891 +0.2486 +0.2328 +0.2353 +0.2586 +0.2783 +0.1974 +0.2128 +0.1494 +0.2046 +0.2105 +0.2317 +0.1946 +0.2395 +0.2304 +0.2216 +0.2267 +0.182 +0.1863 +0.2474 +0.1757 +0.2081 +0.2369 +0.2328 +0.2087 +0.2279 +0.1745 +0.1745 +0.168 +0.2489 +0.3041 +0.1817 +0.2142 +0.2136 +0.2668 +0.2303 +0.2441 +0.2334 +0.2373 +0.2365 +0.2096 +0.199 +0.1817 +0.2348 +0.3724 +0.2099 +0.3305 +0.3063 +0.1907 +0.1297 +0.2612 +0.185 +0.1893 +0.2286 +0.1886 +0.1741 +0.2299 +0.2107 +0.1837 +0.22 +0.1964 +0.2035 +0.195 +0.2165 +0.317 +0.2295 +0.2058 +0.2045 +0.2293 +0.2596 +0.2873 +0.3949 +0.2709 +0.2992 +0.2454 +0.2525 +0.1963 +0.2301 +0.2735 +0.1448 +0.2017 +0.2114 +0.3402 +0.2622 +0.257 +0.2141 +0.3416 +0.2514 +0.2063 +0.2068 +0.2411 +0.2481 +0.2748 +0.2097 +0.1769 +0.213 +0.2531 +0.3399 +0.2114 +0.1741 +0.3608 +0.2595 +0.2129 +0.2026 +0.2791 +0.3923 +0.2736 +0.2739 +0.2974 +0.2936 +0.2706 +0.2565 +0.2346 +0.3494 +0.3222 +0.316 +0.256 +0.3213 +0.3094 +0.3008 +0.2846 +0.223 +0.1944 +0.3038 +0.3075 +0.2477 +0.3725 +0.3159 +0.2407 +0.2855 +0.355 +0.3561 +0.2729 +0.2497 +0.2147 +0.3445 +0.2465 +0.237 +0.2802 +0.4251 +0.2764 +0.2885 +0.3291 +0.2509 +0.2526 +0.2104 +0.2625 +0.2605 +0.3001 +0.2353 +0.1882 +0.2352 +0.233 +0.3604 +0.3438 +0.3816 +0.2953 +0.4096 +0.4453 +0.3545 +0.2791 +0.3215 +0.3582 +0.3165 +0.2832 +0.3268 +0.2956 +0.233 +0.4115 +0.2559 +0.3055 +0.2407 +0.4052 +0.3081 +0.3109 +0.2946 +0.2055 +0.2276 +0.2574 +0.262 +0.2096 +0.1949 +0.4268 +0.3888 +0.2314 +0.2176 +0.2635 +0.4945 +0.275 +0.2142 +0.215 +0.4962 +0.2658 +0.3692 +0.2175 +0.2144 +0.2659 +0.392 +0.269 +0.4556 +0.2631 +0.3976 +0.206 +0.3458 +0.2753 +0.3061 +0.5305 +0.383 +0.3333 +0.4005 +0.3835 +0.2546 +0.3214 +0.3995 +0.3174 +0.3417 +0.2655 +0.4024 +0.3623 +0.3471 +0.323 +0.3178 +0.3838 +0.3689 +0.2826 +0.4032 +0.4184 +0.3008 +0.2677 +0.2952 +0.4304 +0.2814 +0.3265 +0.4046 +0.3735 +0.3982 +0.3849 +0.3772 +0.285 +0.2919 +0.5386 +0.3341 +0.2517 +0.3513 +0.3324 +0.3069 +0.3389 +0.4039 +0.3462 +0.3834 +0.3369 +0.3582 +0.3184 +0.3303 +0.3144 +0.5149 +0.334 +0.2345 +0.4414 +0.2834 +0.3183 +0.3406 +0.3606 +0.2516 +0.3645 +0.3422 +0.3843 +0.2712 +0.3439 +0.2205 +0.261 +0.35 +0.2873 +0.3923 +0.2437 +0.3979 +0.3217 +0.3672 +0.3512 +0.4098 +0.2953 +0.4178 +0.2812 +0.2768 +0.2705 +0.3987 +0.297 +0.3169 +0.3029 +0.3434 +0.3584 +0.2606 +0.3941 +0.5976 +0.3004 +0.242 +0.2621 +0.3839 +0.3487 +0.3627 +0.3603 +0.3469 +0.3268 +0.3947 +0.3415 +0.3474 +0.3926 +0.4104 +0.4281 +0.3367 +0.3126 +0.2975 +0.3191 +0.3085 +0.3141 +0.3719 +0.3386 +0.2989 +0.345 +0.2906 +0.4719 +0.5137 +0.3735 +0.479 +0.2743 +0.3422 +0.3122 +0.3753 +0.4102 +0.2796 +0.3068 +0.3452 +0.2825 +0.2521 +0.3378 +0.3169 +0.2555 +0.4341 +0.3855 +0.2625 +0.2347 +0.332 +0.336 +0.3089 +0.3382 +0.2977 +0.3854 +0.3486 +0.4122 +0.4985 +0.3225 +0.3816 +0.4254 +0.3102 +0.3521 +0.4159 +0.3338 +0.3731 +0.363 +0.3726 +0.3463 +0.3088 +0.3419 +0.3127 +0.3544 +0.4116 +0.3243 +0.3712 +0.3161 +0.7578 +0.3597 +0.4521 +0.4382 +0.4364 +0.4271 +0.4319 +0.5477 +0.407 +0.5028 +0.5233 +0.506 +0.7292 +0.4775 +0.3786 +0.3948 +0.4034 +0.397 +0.4482 +0.3448 +0.4 +0.4172 +0.3773 +0.3239 +0.378 +0.3685 +0.4118 +0.4189 +0.2966 +0.3305 +0.3929 +0.3582 +0.4537 +0.498 +0.4121 +0.28 +0.5949 +0.2929 +0.3407 +0.3226 +0.3548 +0.3405 +0.4428 +0.423 +0.5593 +0.5013 +0.5999 +0.4643 +0.4839 +0.3974 +0.318 +0.3698 +0.3809 +0.4896 +0.4516 +0.4558 +0.6247 +0.5194 +0.445 +0.421 +0.444 +0.5348 +0.451 +0.3977 +0.4136 +0.4262 +0.505 +0.6135 +0.5014 +0.3628 +0.3764 +0.5129 +0.5383 +0.3431 +0.4801 +0.6918 +0.5619 +0.8736 +0.4425 +0.4192 +0.5198 +0.499 +0.4163 +0.5225 +0.5733 +0.536 +0.463 +0.4119 +0.6297 +0.3849 +0.415 +0.4042 +0.3375 +0.4756 +0.4653 +0.4324 +0.5297 +0.6474 +0.6708 +0.5121 +0.6019 +0.432 +0.6021 +0.3995 +0.39 +0.6006 +0.5906 +0.4058 +0.496 +0.4043 +0.5384 +0.5077 +0.6121 +0.5026 +0.603 +0.5689 +0.4687 +0.3425 +0.4013 +0.3686 +0.4575 +0.3759 +0.4816 +0.5345 +0.3585 +0.5818 +0.395 +0.61 +0.7003 +0.4558 +0.6558 +0.5128 +0.4657 +0.4269 +0.378 +0.4797 +0.5866 +0.5424 +0.5726 +0.4407 +0.6187 +0.6722 +0.4974 +0.5763 +0.4132 +0.5569 +0.4977 +0.6013 +0.5545 +0.5177 +0.3972 +0.5198 +0.875 +1 diff --git a/pytorch_example/RUL/otherIdea/LSTM/__init__.py b/pytorch_example/RUL/otherIdea/LSTM/__init__.py new file mode 100644 index 0000000..baa7e9a --- /dev/null +++ b/pytorch_example/RUL/otherIdea/LSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:27 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/LSTM/loadData.py b/pytorch_example/RUL/otherIdea/LSTM/loadData.py new file mode 100644 index 0000000..45ee895 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/LSTM/loadData.py @@ -0,0 +1,139 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("../../dataset/HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + # HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + # todo 解决模型保存时,query无法序列化的问题 + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset diff --git a/pytorch_example/RUL/otherIdea/LSTM/model.py b/pytorch_example/RUL/otherIdea/LSTM/model.py new file mode 100644 index 0000000..a83d7b3 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/LSTM/model.py @@ -0,0 +1,234 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from torch.autograd import Variable + + +class LSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(LSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append(LSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias)) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c, s) or (b, t, c, s) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[512, 256], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + self.backbone = nn.Sequential( + nn.Linear(in_features=256, out_features=128), + nn.ReLU(), + nn.Linear(in_features=128, out_features=64), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(64), + nn.Linear(in_features=64, out_features=32), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(32), + nn.ReLU(), + nn.Linear(in_features=32, out_features=16), + nn.Linear(in_features=16, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/LSTM/modelForEasy.py b/pytorch_example/RUL/otherIdea/LSTM/modelForEasy.py new file mode 100644 index 0000000..7a7c185 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/LSTM/modelForEasy.py @@ -0,0 +1,227 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from torch.autograd import Variable + + +class LSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(LSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append(LSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias)) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c, s) or (b, t, c, s) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[64, 64], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + self.backbone = nn.Sequential( + nn.Linear(in_features=64, out_features=64), + nn.Linear(in_features=64, out_features=64), + nn.BatchNorm1d(64), + nn.ReLU(), + nn.Dropout(0.5), + nn.Linear(in_features=64, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/LSTM/test.py b/pytorch_example/RUL/otherIdea/LSTM/test.py new file mode 100644 index 0000000..30fa4df --- /dev/null +++ b/pytorch_example/RUL/otherIdea/LSTM/test.py @@ -0,0 +1,118 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.LSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.LSTM.modelForEasy import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +from RUL.baseModel.plot import plot_prediction, plot_forSelf +from RUL.baseModel.loss.Evaluate import getEvaluate + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model(each_predict_data).cpu().detach().numpy()[-1] # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.concatenate([each_predict_data[1:, :, :], np.expand_dims(b, axis=0)], axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, save_path, save_fig_name, is_single=True, is_norm=False): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + model = PredictModel(input_dim=feature).to(device) + + model.load_state_dict( + torch.load(save_path, map_location=device) + ) + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.float().to(device), label.float().to(device) + last_train_data = data + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label = np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea\LSTM\parameters\LSTM_hidden40_feature10_predict50_epoch66_trainLoss0.05624270847895079_valLoss0.4181802272796631.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/LSTM/train.py b/pytorch_example/RUL/otherIdea/LSTM/train.py new file mode 100644 index 0000000..3f1838a --- /dev/null +++ b/pytorch_example/RUL/otherIdea/LSTM/train.py @@ -0,0 +1,177 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 14:56 +@Usage : +@Desc : 训练LSTM +''' +import os +import time +import random +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +import matplotlib.pyplot as plt +from torch.utils.data import DataLoader +from RUL.otherIdea.LSTM.modelForEasy import PredictModel +from RUL.otherIdea.LSTM.loadData import getDataset +from RUL.otherIdea.LSTM.test import test +from RUL.baseModel.CommonFunction import IsStopTraining +from scipy.spatial.distance import cdist +import math +import RUL.baseModel.utils.utils as utils + +''' +超参数设置: +''' +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +batch_size = 32 +EPOCH = 1000 +seed = 5 +predict_num = 200 # 预测个数 +is_norm = False +is_single = True +model_name = "LSTM" +base_save = r"parameters/{0}_hidden{1}_feature{2}_predict{3}".format(model_name, hidden_num, feature, + predict_num) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}'.format(seed, hidden_num, feature, predict_num) + +if not os.path.exists("parameters"): + os.makedirs("parameters") +if not os.path.exists("fig"): + os.makedirs("fig") + + +def get_dataset(): + '''得到数据集''' + train_dataset, val_dataset = getDataset( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_single=is_single, is_norm=is_norm) + '''DataLoader''' + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, drop_last=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False, drop_last=False) + return train_loader, val_loader + + +def train(device, lr, lr_patience, early_stop_patience, epochs): + '''预测模型''' + global best_save_path + model = PredictModel(input_dim=feature) + '''得到数据集''' + train_loader, val_loader = get_dataset() + criterion = nn.MSELoss().to(device) + + optimizer_model = torch.optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer_model, mode="min", factor=0.5, + patience=lr_patience) + + def zero_grad_all(): + optimizer_model.zero_grad() + + train_loss_list = [] + val_loss_list = [] + best_save_path = None + + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss = 0.0 + val_loss = 0.0 + + model.train() + + for (train_batch_idx, (train_data, train_label)) in enumerate(train_loader): + + train_data, train_label = train_data.float().to(device), train_label.float().to(device) + + zero_grad_all() + + predict_data = torch.squeeze(model(train_data)) + + # MSE损失 + loss = criterion(predict_data, train_label) + + loss.backward() + optimizer_model.step() + + zero_grad_all() + + train_loss += loss.item() + + model.eval() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_label) in enumerate(val_loader): + val_data, val_label = val_data.float().to(device), val_label.float().to(device) + val_predict_data = torch.squeeze(model(val_data)) + + loss = criterion(val_predict_data, val_label) + val_loss += loss.item() + + scheduler_model.step(val_loss) + + train_loss = train_loss / len(train_loader) + val_loss = val_loss / len(val_loader) + print( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_loss: {:3.9f} | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss, + val_loss, + optimizer_model.state_dict()['param_groups'][0]['lr'])) + + # 保存在验证集上loss最小的模型 + # if val_loss_list.__len__() > 0 and (val_loss / val_dataset.__len__()) < min(val_loss_list): + # 如果精度大于最高精度,则保存 + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + print("保存模型最佳模型成功") + # 保存模型参数 + # 保存模型参数 + if best_save_path != None: + utils.delete_file(best_save_path) + best_save_path = base_save + "_epoch" + str(epoch) + \ + "_trainLoss" + str(train_loss) + \ + "_valLoss" + str(val_loss) + ".pkl" + torch.save(model.state_dict(), + best_save_path) + + train_loss_list.append(train_loss) + + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + break + + '''保存的模型参数的路径''' + return best_save_path + + +if __name__ == '__main__': + + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + '''训练''' + save_path = train(device, lr=0.01, lr_patience=10, early_stop_patience=20, epochs=1000) + + end = time.time() + + '''测试''' + # test1(5, src_condition, tar_condition, G_params_path, LC_params_path) + + test(hidden_num, feature, predict_num=predict_num, + batch_size=batch_size, save_path=save_path, + is_single=is_single, is_norm=is_norm, save_fig_name=save_fig_name) + + print("训练耗时:{:3.2f}s".format(end - begin)) diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/__init__.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/__init__.py new file mode 100644 index 0000000..392eed6 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/20 14:11 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/__init__.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/__init__.py new file mode 100644 index 0000000..3e48d01 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/data_process.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/data_process.py new file mode 100644 index 0000000..c16991a --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/data_process.py @@ -0,0 +1,111 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 + +import RUL.otherIdea.adaRNN.dataset_vibrate.data_vibrate as data_vibrate +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +from RUL.otherIdea.adaRNN.dataset_vibrate.loadData import getVibrate_data + +import torch +import math + + +def get_split_time(num_domain=2, mode='pre_process', data=None, dis_type='coral'): + spilt_time = { + '2': [(0, 600), (600, 1200)] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data, dis_type='coral'): + # 样本个数 + num_day = len(data[0]) + + split_N = 10 + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_index = int(num_day / split_N * selected[i - 1]) + else: + sel_start_index = int(num_day / split_N * selected[i - 1]) + 1 + + sel_end_index = int(num_day / split_N * selected[i]) + + res.append((sel_start_index, sel_end_index)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(hidden_num, feature, predict_num, batch_size=6, number_domain=2, mode='pre_process', + dis_type='coral', is_norm=False): + # mode: 'tdc', 'pre_process' + train_data, val_data = getVibrate_data(hidden_num=hidden_num, feature=feature, predict_num=predict_num, + is_norm=is_norm) + + split_time_list = get_split_time(number_domain, mode=mode, data=train_data, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + index_temp = split_time_list[i] + train_loader = data_vibrate.get_vibrate_data(train_data, start_index=index_temp[0], + end_index=index_temp[1], batch_size=batch_size) + train_list.append(train_loader) + + valid_loader = data_vibrate.get_vibrate_data(val_data, start_index=0, + end_index=len(val_data), batch_size=batch_size, mean=None, + std=None, shuffle=False) + test_loader = valid_loader + + return train_list, valid_loader, test_loader + + +if __name__ == '__main__': + load_weather_data_multi_domain(hidden_num=10, feature=10, predict_num=50, batch_size=32, number_domain=2, + mode='tdc', + dis_type='coral', is_norm=False) diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/data_vibrate.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/data_vibrate.py new file mode 100644 index 0000000..f6a843c --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/data_vibrate.py @@ -0,0 +1,78 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + +import math +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import os +from pandas.core.frame import DataFrame +from torch.utils.data import Dataset, DataLoader +import torch +import pickle +import datetime + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target, label_reg + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(data, start_index, end_index, mean=None, std=None): + feat, label_continue, label_single = data[0], data[1], data[2] + referece_start_index = 0 + referece_end_index = 1250 + + assert start_index - referece_start_index >= 0 + assert end_index - referece_end_index <= 0 + assert end_index - start_index >= 0 + + feat = feat[start_index: end_index + 1] + label = label_continue[start_index: end_index + 1] + label_reg = label_single[start_index: end_index + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def get_vibrate_data(data, start_index, end_index, batch_size, shuffle=True, mean=None, std=None): + dataset = create_dataset(data, start_index, + end_index, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/loadData.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/loadData.py new file mode 100644 index 0000000..ed8c90d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/dataset_vibrate/loadData.py @@ -0,0 +1,150 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + # HI_merge_data_origin = np.load("E:\self_example\pytorch_example\RUL\dataset\HI_merge_data1.npy") + # + # # plt.plot(HI_merge_data[0:1250, 1]) + # # 去除掉退化特征不明显前面的点 + # HI_merge_data = HI_merge_data_origin[0:1250, 1] + HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset + + +def getVibrate_data(hidden_num, feature, predict_num, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + + + + return [train_data,train_label,train_label_single],[val_data,val_label,val_label_single] diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/loss_transfer.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/loss_transfer.py new file mode 100644 index 0000000..7e2798d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/loss_transfer.py @@ -0,0 +1,64 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:45 +@Usage : +@Desc : +''' +from RUL.baseModel.loss import adv_loss, coral, kl_js, mmd, mutual_info, cos, pair_dist + + +class TransferLoss(object): + def __init__(self, loss_type='cosine', input_dim=512): + """ + Supported loss_type: mmd(mmd_lin), mmd_rbf, coral, cosine, kl, js, mine, adv + """ + self.loss_type = loss_type + self.input_dim = input_dim + + def compute(self, X, Y): + """Compute adaptation loss + + Arguments: + X {tensor} -- source matrix + Y {tensor} -- target matrix + + Returns: + [tensor] -- transfer loss + """ + if self.loss_type == 'mmd_lin' or self.loss_type == 'mmd': + mmdloss = mmd.MMD_loss(kernel_type='linear') + loss = mmdloss(X, Y) + elif self.loss_type == 'coral': + loss = coral.CORAL(X, Y) + elif self.loss_type == 'cosine' or self.loss_type == 'cos': + loss = 1 - cos.cosine(X, Y) + elif self.loss_type == 'kl': + loss = kl_js.kl_div(X, Y) + elif self.loss_type == 'js': + loss = kl_js.js(X, Y) + elif self.loss_type == 'mine': + mine_model = mutual_info.Mine_estimator( + input_dim=self.input_dim, hidden_dim=60) + loss = mine_model(X, Y) + elif self.loss_type == 'adv': + loss = adv_loss.adv(X, Y, input_dim=self.input_dim, hidden_dim=32) + elif self.loss_type == 'mmd_rbf': + mmdloss = mmd.MMD_loss(kernel_type='rbf') + loss = mmdloss(X, Y) + elif self.loss_type == 'pairwise': + pair_mat = pair_dist.pairwise_dist(X, Y) + import torch + loss = torch.norm(pair_mat) + + return loss + + +if __name__ == "__main__": + import torch + + trans_loss = TransferLoss('adv') + a = (torch.randn(5, 512) * 10) + b = (torch.randn(5, 512) * 10) + print(trans_loss.compute(a, b)) diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/model.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/model.py new file mode 100644 index 0000000..990b223 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/model.py @@ -0,0 +1,411 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:44 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +import torch.nn.functional as F +from RUL.baseModel.dctChannelAttention import dct_channel_block + +import torch.nn as nn +import torch +from RUL.baseModel.dctAttention import dct_channel_block + + +class dctLSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(dctLSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + self.attention = dct_channel_block(channel=self.input_dim + self.hidden_dim) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + # 增加一个channelAttention + combined = self.attention(combined) + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=-1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append( + dctLSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias), + ) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c) or (b, t, c) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + + # TODO 每层之间增加一个dct_attention + # layer_output = self.attention_list[layer_idx](layer_output) + + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class AdaRNN(nn.Module): + """ + model_type: 'Boosting', 'AdaRNN' + bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + """ + + def __init__(self, use_bottleneck=False, bottleneck_list=[(64, False, False, 0), (64, True, True, 0.5)], + n_input=128, n_hiddens=[64, 64], n_output=6, + dropout=0.0, len_seq=9, model_type='AdaRNN', + trans_loss='mmd'): + super(AdaRNN, self).__init__() + self.use_bottleneck = use_bottleneck + self.n_input = n_input + self.num_layers = len(n_hiddens) + self.hiddens = n_hiddens + self.n_output = n_output + self.model_type = model_type + self.trans_loss = trans_loss + self.len_seq = len_seq + in_size = self.n_input + + features = nn.ModuleList() + # dctAttention = nn.ModuleList() + for hidden in n_hiddens: + # rnn = nn.GRU( + # input_size=in_size, + # num_layers=1, + # hidden_size=hidden, + # batch_first=True, + # dropout=dropout + # ) + rnn = LSTM(input_dim=in_size, hidden_dim=[hidden], num_layers=1, batch_first=True, return_all_layers=True) + # attention = dct_channel_block(channel=hidden) + features.append(rnn) + # dctAttention.append(attention) + in_size = hidden + self.features = nn.Sequential(*features) + # self.dctAttention = nn.Sequential(*dctAttention) + + if use_bottleneck == True: # finance + bottleneck = [] + for i in range(len(bottleneck_list)): + cur_input_dim = self.hiddens[-1] if i == 0 else bottleneck_list[i - 1][0] + bottleneck.append( + nn.Linear(cur_input_dim, bottleneck_list[i][0]) + ) + ### 不加初始权重会让Hard predict更不稳定,振幅更大 + # 初始权重越大,振幅越大 + bottleneck[-1].weight.data.normal_(0, 0.03) + bottleneck[-1].bias.data.fill_(0.01) + if bottleneck_list[i][1]: + bottleneck.append(nn.BatchNorm1d(bottleneck_list[i][0])) + if bottleneck_list[i][2]: + bottleneck.append(nn.ReLU()) + if bottleneck_list[i][3] != 0: + bottleneck.append(nn.Dropout(bottleneck_list[i][3])) + self.bottleneck = nn.Sequential(*bottleneck) + self.fc = nn.Linear(bottleneck_list[-1][0], n_output) + + torch.nn.init.xavier_normal_(self.fc.weight) + else: + self.fc_out = nn.Linear(n_hiddens[-1], self.n_output) + + if self.model_type == 'AdaRNN': + gate = nn.ModuleList() + for i in range(len(n_hiddens)): + gate_weight = nn.Linear( + len_seq * self.hiddens[i] * 2, len_seq) + gate.append(gate_weight) + self.gate = gate + + bnlst = nn.ModuleList() + for i in range(len(n_hiddens)): + bnlst.append(nn.BatchNorm1d(len_seq)) + self.bn_lst = bnlst + self.softmax = torch.nn.Softmax(dim=0) + self.init_layers() + + def init_layers(self): + for i in range(len(self.hiddens)): + self.gate[i].weight.data.normal_(0, 0.05) + self.gate[i].bias.data.fill_(0.0) + + def forward_pre_train(self, x, len_win=0): + out = self.gru_features(x) + # 两层GRU之后的结果 + fea = out[0] + + if self.use_bottleneck == True: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + # 每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + out_list_all, out_weight_list = out[1], out[2] + # 可以理解为前半段 和 后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + h_start = 0 + for j in range(h_start, self.len_seq, 1): + i_start = max(j - len_win, 0) + i_end = j + len_win if j + len_win < self.len_seq else self.len_seq - 1 + for k in range(i_start, i_end + 1): + weight = out_weight_list[i][j] if self.model_type == 'AdaRNN' else 1 / ( + self.len_seq - h_start) * (2 * len_win + 1) + loss_transfer = loss_transfer + weight * criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, k, :]) + return fc_out, loss_transfer, out_weight_list + + def gru_features(self, x, predict=False): + x_input = x + out = None + out_lis = [] + out_weight_list = [] if ( + self.model_type == 'AdaRNN') else None + for i in range(self.num_layers): + # GRU的输出 + out, _ = self.features[i](x_input.float()) + out = out[0] + # out = self.dctAttention[i](out.float()) + x_input = out + out_lis.append(out) + if self.model_type == 'AdaRNN' and predict == False: + out_gate = self.process_gate_weight(x_input, i) + out_weight_list.append(out_gate) + # 两层GRU之后的结果,每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + return out, out_lis, out_weight_list + + def process_gate_weight(self, out, index): + x_s = out[0: int(out.shape[0] // 2)] # 可以理解为前一半个batch_size的分布 域Di + x_t = out[out.shape[0] // 2: out.shape[0]] # 可以理解为后一半个batch_size的分布 域Dj + # 对应着不同的域 + x_all = torch.cat((x_s, x_t), 2) + x_all = x_all.view(x_all.shape[0], -1) + weight = torch.sigmoid(self.bn_lst[index]( + self.gate[index](x_all.float()))) + weight = torch.mean(weight, dim=0) + res = self.softmax(weight).squeeze() + return res + + def get_features(self, output_list): + fea_list_src, fea_list_tar = [], [] + for fea in output_list: + fea_list_src.append(fea[0: fea.size(0) // 2]) + fea_list_tar.append(fea[fea.size(0) // 2:]) + return fea_list_src, fea_list_tar + + # For Boosting-based + def forward_Boosting(self, x, weight_mat=None): + out = self.gru_features(x) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + + out_list_all = out[1] + # 可以理解为前半段和后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + if weight_mat is None: + weight = (1.0 / self.len_seq * + torch.ones(self.num_layers, self.len_seq)) + else: + weight = weight_mat + dist_mat = torch.zeros(self.num_layers, self.len_seq) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + for j in range(self.len_seq): + loss_trans = criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, j, :]) + loss_transfer = loss_transfer + weight[i, j] * loss_trans + dist_mat[i, j] = loss_trans + return fc_out, loss_transfer, dist_mat, weight + + # For Boosting-based + def update_weight_Boosting(self, weight_mat, dist_old, dist_new): + epsilon = 1e-12 + dist_old = dist_old.detach() + dist_new = dist_new.detach() + ind = dist_new > dist_old + epsilon + weight_mat[ind] = weight_mat[ind] * \ + (1 + torch.sigmoid(dist_new[ind] - dist_old[ind])) + weight_norm = torch.norm(weight_mat, dim=1, p=1) + weight_mat = weight_mat / weight_norm.t().unsqueeze(1).repeat(1, self.len_seq) + return weight_mat + + def predict(self, x): + out = self.gru_features(x, predict=True) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + + return fc_out diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/test.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/test.py new file mode 100644 index 0000000..55ba30a --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/test.py @@ -0,0 +1,94 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.LSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctLSTM.model import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt + +from RUL.baseModel.plot import plot_prediction, plot_forSelf + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data[-1].unsqueeze(0) + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model.predict(each_predict_data).cpu().detach().numpy() # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + c = each_predict_data[-1, -1, 1:] + a = np.concatenate([each_predict_data[-1, -1, 1:], np.expand_dims(predicted_data, axis=0)], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.expand_dims(b, axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, model, is_single=True, is_norm=False, save_fig_name=""): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predicted_data_hard = np.concatenate([predicted_data_hard, + predictOneByOne(model, last_train_data, predict_num=predict_num)], axis=0) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/train.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/train.py new file mode 100644 index 0000000..6eee8a6 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/train.py @@ -0,0 +1,476 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np +import random +from tqdm import tqdm +from RUL.otherIdea.adaDctEmdLSTM.utils import utils +from RUL.otherIdea.adaDctEmdLSTM.model import AdaRNN + +import RUL.otherIdea.adaDctEmdLSTM.dataset_vibrate.data_process as data_process +from RUL.baseModel.loss.ffd import fft_mse, dct_mse +from RUL.otherIdea.adaDctEmdLSTM.test import test +import matplotlib.pyplot as plt +import time +from RUL.baseModel.CommonFunction import IsStopTraining + +''' +超参数设置: +''' +# 数据准备 +is_norm = False +is_single = True +tdc_loss_type = 'cos' +num_domain = 2 # 划分为几个源域和目标域 + +# RNN相关 +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +predict_num = 50 # 预测个数 +batch_size = 32 +model_name = "AdaRNN" +hidden_list = [64, 64] # 每层RNN的隐藏层的维度 +### bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) +bottleneck = [(64, False, False, 0), (64, True, True, 0.5)] +# bottleneck = [(128, False, True, 0), +# (64, True, True, 0.2), +# (32, True, True, 0.2), +# (16, False, False, 0)] + +# 训练相关 +pre_epoch = 40 +epochs = 1000 +transfer_loss_type = 'cos' # 目前测试cos最好 +dw = 0.5 +fft_dw = 0.1 +lr = 0.01 +len_win = 0 # 窗口大小,为0,暂时不知道有什么用 +seed = 125 + +# 相关初始化工作 +out_dir = './outputs' +output_path = out_dir + '/{0}_tdc({1})_transfer({2})_domain{3}_dw{4}_fdw{5}_lr{6}_Norm{7}'.format(model_name, + tdc_loss_type, + transfer_loss_type, + num_domain, + dw, fft_dw, lr, + is_norm) +save_model_name = 'parameters/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[ + 0]) + "-" + str( + hidden_list[1])) +save_fig_name = 'fig/{0}_hidden{1}_feature{2}_predict{3}_dimList{4}.png'.format(model_name, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +utils.dir_exist(output_path) +utils.dir_exist(os.path.join(output_path, 'parameters')) +utils.dir_exist(os.path.join(output_path, 'fig')) +log_file = os.path.join(output_path, 'run.log') + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if log_file is None: + return + with open(log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + # 经过测试,整体来说,如果加了bottleneck,整体更愿意振动,而不加整体仅存在趋势 + # bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + + return AdaRNN(use_bottleneck=True, bottleneck_list=bottleneck, n_input=feature, n_hiddens=hidden_list, + n_output=1, dropout=0.0, model_type=name, len_seq=hidden_num, + trans_loss=transfer_loss_type) + + +def train_AdaRNN(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(len(hidden_list), hidden_num) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + + # 如果训练集域之间的batch_size对不齐就没法计算, + # 为了不抛弃所有样本,这里将选择最小的域batch_size作为本轮的batch_size + min_batch_size = 10000 + for data in data_all: + min_batch_size = min(min_batch_size, data[0].shape[0]) + + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].float(), data[2].float() + list_feat.append(feature[:min_batch_size]) + list_label.append(label_reg[:min_batch_size]) + + index = get_index(len(data_all) - 1) + + loss_mse = torch.zeros(1) + loss_fft = torch.zeros(1) + loss_transfer = torch.zeros(1) + total_loss_l1 = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + # 在batch_size处合并 + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < pre_epoch: + pred_all, each_loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=len_win) + else: + pred_all, each_loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + + lossf_s = dct_mse(pred_s, label_reg_s) + lossf_t = dct_mse(pred_t, label_reg_t) + + loss_l1 = criterion_1(pred_s, label_reg_s) + + loss_mse += loss_s + loss_t + loss_fft += (lossf_s + lossf_t) * fft_dw + loss_transfer += dw * each_loss_transfer + total_loss_l1 += loss_l1 + + total_loss = loss_mse + loss_transfer + loss_all.append([total_loss.item(), loss_mse.item(), loss_transfer.item(), loss_fft.item()]) + loss_1_all.append(total_loss_l1.item()) + + # 反向传播 + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + + if epoch >= pre_epoch: + if epoch > pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def val_epoch(model, val_loader, device, scheduler): + model.eval() + val_loss = 0 + val_loss_1 = 0 + val_loss_r = 0 + + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_continue, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = model.predict(val_data) + + loss = criterion(val_predict_data, val_label) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(val_predict_data, val_label) + val_loss += loss.item() + val_loss_1 += loss_1.item() + val_loss_r += loss_r.item() + + scheduler.step(val_loss) + + loss = val_loss / len(val_loader) + loss_1 = val_loss_1 / len(val_loader) + loss_r = val_loss_r / len(val_loader) + + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(len(hidden_list), hidden_num) + for i in range(weight.shape[0]): + for j in range(weight.shape[1]): + weight[i, j] = init_weight[i][j].item() + return weight + + +def loadData(): + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=batch_size, + number_domain=num_domain, mode='tdc', dis_type=tdc_loss_type + ) + return train_loader_list, valid_loader, test_loader + pass + + +def train(model, train_loader_list, valid_loader, lr_patience, early_stop_patience, device): + optimizer = optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", factor=0.5, + patience=lr_patience) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + train_loss_list = [] + val_loss_list = [] + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss, loss1, weight_mat, dist_mat = train_AdaRNN( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + + val_loss, val_loss_l1, val_loss_r = val_epoch( + model, valid_loader, device=device, scheduler=scheduler_model) + + pprint( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_total_loss: {:3.9f} | train_mse_loss: {:3.9f} | train_transfer_loss: {:3.9f} | train_transfer_loss: {:3.9f} " + " | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss[0], train_loss[1], train_loss[3], train_loss[2], + val_loss, + optimizer.state_dict()['param_groups'][0]['lr'])) + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + pprint("保存模型最佳模型成功") + best_epoch = epoch + best_score = val_loss + # 保存模型参数 + best_save_path = save_model_name + "_epoch" + str(epoch) + \ + "_trainLoss" + str('%.5f' % train_loss[1]) + \ + "_valLoss" + str('%.5f' % val_loss) + ".pkl" + print(os.path.join(output_path, best_save_path)) + torch.save(model.state_dict(), + os.path.join(output_path, best_save_path)) + + train_loss_list.append(train_loss) + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + pprint("{0}次loss未下降,训练停止".format(early_stop_patience)) + break + + pprint('best val score:', best_score, '@', best_epoch) + return best_save_path + pass + + +def main_transfer(): + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + pprint('create DataLoaders...') + train_loader_list, valid_loader, test_loader = loadData() + + pprint('create AdaRNN model...') + model = get_model(model_name) + + num_model = count_parameters(model) + + print(model) + print('#model params:', num_model) + + pprint('train model...') + best_save_path = train(model=model, train_loader_list=train_loader_list, valid_loader=valid_loader, lr_patience=20, + early_stop_patience=50, device=device) + + end = time.time() + + print("训练耗时:{:3.2f}s".format(end - begin)) + + pprint('验证模型...') + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, best_save_path), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load(os.path.join(output_path, best_save_path), map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm, save_fig_name=os.path.join(output_path, save_fig_name)) + + +def after_test(save_name): + model = get_model(model_name) + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load( + save_name + , map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm) + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=feature) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + + parser.add_argument('--data_mode', type=str, default='tdc') + + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + # 训练与测试 + main_transfer() + + '''事后测试''' + # after_test(save_name="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_domain2_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl") diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/utils/__init__.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/utils/__init__.py new file mode 100644 index 0000000..4e22673 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/utils/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/utils/utils.py b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/utils/utils.py new file mode 100644 index 0000000..08b396e --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctEmdLSTM/utils/utils.py @@ -0,0 +1,225 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' + +import collections +import torch +import os +import pandas as pd +import torch.nn as nn +from tqdm import tqdm +import numpy as np + +EPS = 1e-12 + + +class AverageMeter(object): + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.list = [] + + def update(self, val, n=1): + self.val = val + self.list.append(val) + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +def average_params(params_list): + assert isinstance(params_list, (tuple, list, collections.deque)) + n = len(params_list) + if n == 1: + return params_list[0] + new_params = collections.OrderedDict() + keys = None + for i, params in enumerate(params_list): + if keys is None: + keys = params.keys() + for k, v in params.items(): + if k not in keys: + raise ValueError('the %d-th model has different params' % i) + if k not in new_params: + new_params[k] = v / n + else: + new_params[k] += v / n + return new_params + + +def zscore(x): + return (x - x.mean(dim=0, keepdim=True)) / x.std(dim=0, keepdim=True, unbiased=False) + + +def calc_loss(pred, label): + return torch.mean((zscore(pred) - label) ** 2) + + +def calc_corr(pred, label): + return (zscore(pred) * zscore(label)).mean() + + +def test_ic(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = label_actual.clone().detach().view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_daily(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values + avg), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for slc in tqdm(data_list[i].iter_daily(), total=data_list[i].daily_length): + feature, label_actual, _, _ = data_list[i].get(slc) + # for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = torch.tensor(label_actual, dtype=torch.float32, device=device).view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_uni(model, data_loader, model_path=None, ic_type='spearman', verbose=False): + if model_path: + model.load_state_dict(torch.load(model_path)) + model.eval() + loss_all = [] + ic_all = [] + for slc in tqdm(data_loader.iter_daily(), total=data_loader.daily_length): + data, label, _, _ = data_loader.get(slc) + with torch.no_grad(): + pred = model.predict(data) + mask = ~torch.isnan(label) + pred = pred[mask] + label = label[mask] + loss = torch.mean(torch.log(torch.cosh(pred - label))) + if ic_type == 'spearman': + ic = spearman_corr(pred, label) + elif ic_type == 'pearson': + ic = pearson_corr(pred, label) + loss_all.append(loss.item()) + ic_all.append(ic) + loss, ic = np.mean(loss_all), np.mean(ic_all) + if verbose: + print('IC: ', ic) + return loss, ic + + +def calc_ic(x, y, ic_type='pearson'): + ic = -100 + if ic_type == 'pearson': + ic = pearson_corr(x, y) + elif ic_type == 'spearman': + ic = spearman_corr(x, y) + return ic + + +def create_dir(path): + if not os.path.exists(path): + os.makedirs(path) + + +def handle_nan(x): + mask = ~torch.isnan(x) + return x[mask], mask + + +class Log_Loss(nn.Module): + def __init__(self): + super(Log_Loss, self).__init__() + + def forward(self, ytrue, ypred): + delta = ypred - ytrue + return torch.mean(torch.log(torch.cosh(delta))) + + +def spearman_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='spearman') + return spearman + + +def spearman_corr2(x, y): + X = pd.Series(x) + Y = pd.Series(y) + spearman = X.corr(Y, method='spearman') + return spearman + + +def pearson_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='pearson') + return spearman + + +def dir_exist(dirs): + if not os.path.exists(dirs): + os.makedirs(dirs) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/__init__.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/__init__.py new file mode 100644 index 0000000..392eed6 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/20 14:11 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/__init__.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/__init__.py new file mode 100644 index 0000000..3e48d01 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/data_process.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/data_process.py new file mode 100644 index 0000000..c16991a --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/data_process.py @@ -0,0 +1,111 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 + +import RUL.otherIdea.adaRNN.dataset_vibrate.data_vibrate as data_vibrate +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +from RUL.otherIdea.adaRNN.dataset_vibrate.loadData import getVibrate_data + +import torch +import math + + +def get_split_time(num_domain=2, mode='pre_process', data=None, dis_type='coral'): + spilt_time = { + '2': [(0, 600), (600, 1200)] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data, dis_type='coral'): + # 样本个数 + num_day = len(data[0]) + + split_N = 10 + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_index = int(num_day / split_N * selected[i - 1]) + else: + sel_start_index = int(num_day / split_N * selected[i - 1]) + 1 + + sel_end_index = int(num_day / split_N * selected[i]) + + res.append((sel_start_index, sel_end_index)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(hidden_num, feature, predict_num, batch_size=6, number_domain=2, mode='pre_process', + dis_type='coral', is_norm=False): + # mode: 'tdc', 'pre_process' + train_data, val_data = getVibrate_data(hidden_num=hidden_num, feature=feature, predict_num=predict_num, + is_norm=is_norm) + + split_time_list = get_split_time(number_domain, mode=mode, data=train_data, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + index_temp = split_time_list[i] + train_loader = data_vibrate.get_vibrate_data(train_data, start_index=index_temp[0], + end_index=index_temp[1], batch_size=batch_size) + train_list.append(train_loader) + + valid_loader = data_vibrate.get_vibrate_data(val_data, start_index=0, + end_index=len(val_data), batch_size=batch_size, mean=None, + std=None, shuffle=False) + test_loader = valid_loader + + return train_list, valid_loader, test_loader + + +if __name__ == '__main__': + load_weather_data_multi_domain(hidden_num=10, feature=10, predict_num=50, batch_size=32, number_domain=2, + mode='tdc', + dis_type='coral', is_norm=False) diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/data_vibrate.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/data_vibrate.py new file mode 100644 index 0000000..f6a843c --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/data_vibrate.py @@ -0,0 +1,78 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + +import math +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import os +from pandas.core.frame import DataFrame +from torch.utils.data import Dataset, DataLoader +import torch +import pickle +import datetime + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target, label_reg + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(data, start_index, end_index, mean=None, std=None): + feat, label_continue, label_single = data[0], data[1], data[2] + referece_start_index = 0 + referece_end_index = 1250 + + assert start_index - referece_start_index >= 0 + assert end_index - referece_end_index <= 0 + assert end_index - start_index >= 0 + + feat = feat[start_index: end_index + 1] + label = label_continue[start_index: end_index + 1] + label_reg = label_single[start_index: end_index + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def get_vibrate_data(data, start_index, end_index, batch_size, shuffle=True, mean=None, std=None): + dataset = create_dataset(data, start_index, + end_index, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/loadData.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/loadData.py new file mode 100644 index 0000000..ed8c90d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/dataset_vibrate/loadData.py @@ -0,0 +1,150 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + # HI_merge_data_origin = np.load("E:\self_example\pytorch_example\RUL\dataset\HI_merge_data1.npy") + # + # # plt.plot(HI_merge_data[0:1250, 1]) + # # 去除掉退化特征不明显前面的点 + # HI_merge_data = HI_merge_data_origin[0:1250, 1] + HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset + + +def getVibrate_data(hidden_num, feature, predict_num, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + + + + return [train_data,train_label,train_label_single],[val_data,val_label,val_label_single] diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/loss_transfer.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/loss_transfer.py new file mode 100644 index 0000000..7e2798d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/loss_transfer.py @@ -0,0 +1,64 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:45 +@Usage : +@Desc : +''' +from RUL.baseModel.loss import adv_loss, coral, kl_js, mmd, mutual_info, cos, pair_dist + + +class TransferLoss(object): + def __init__(self, loss_type='cosine', input_dim=512): + """ + Supported loss_type: mmd(mmd_lin), mmd_rbf, coral, cosine, kl, js, mine, adv + """ + self.loss_type = loss_type + self.input_dim = input_dim + + def compute(self, X, Y): + """Compute adaptation loss + + Arguments: + X {tensor} -- source matrix + Y {tensor} -- target matrix + + Returns: + [tensor] -- transfer loss + """ + if self.loss_type == 'mmd_lin' or self.loss_type == 'mmd': + mmdloss = mmd.MMD_loss(kernel_type='linear') + loss = mmdloss(X, Y) + elif self.loss_type == 'coral': + loss = coral.CORAL(X, Y) + elif self.loss_type == 'cosine' or self.loss_type == 'cos': + loss = 1 - cos.cosine(X, Y) + elif self.loss_type == 'kl': + loss = kl_js.kl_div(X, Y) + elif self.loss_type == 'js': + loss = kl_js.js(X, Y) + elif self.loss_type == 'mine': + mine_model = mutual_info.Mine_estimator( + input_dim=self.input_dim, hidden_dim=60) + loss = mine_model(X, Y) + elif self.loss_type == 'adv': + loss = adv_loss.adv(X, Y, input_dim=self.input_dim, hidden_dim=32) + elif self.loss_type == 'mmd_rbf': + mmdloss = mmd.MMD_loss(kernel_type='rbf') + loss = mmdloss(X, Y) + elif self.loss_type == 'pairwise': + pair_mat = pair_dist.pairwise_dist(X, Y) + import torch + loss = torch.norm(pair_mat) + + return loss + + +if __name__ == "__main__": + import torch + + trans_loss = TransferLoss('adv') + a = (torch.randn(5, 512) * 10) + b = (torch.randn(5, 512) * 10) + print(trans_loss.compute(a, b)) diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/model.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/model.py new file mode 100644 index 0000000..16a215e --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/model.py @@ -0,0 +1,224 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:44 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +import torch.nn.functional as F +from RUL.baseModel.dctChannelAttention import dct_channel_block + + +class AdaRNN(nn.Module): + """ + model_type: 'Boosting', 'AdaRNN' + bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + """ + + def __init__(self, use_bottleneck=False, bottleneck_list=[(64, False, False, 0), (64, True, True, 0.5)], + n_input=128, n_hiddens=[64, 64], n_output=6, + dropout=0.0, len_seq=9, model_type='AdaRNN', + trans_loss='mmd'): + super(AdaRNN, self).__init__() + self.use_bottleneck = use_bottleneck + self.n_input = n_input + self.num_layers = len(n_hiddens) + self.hiddens = n_hiddens + self.n_output = n_output + self.model_type = model_type + self.trans_loss = trans_loss + self.len_seq = len_seq + in_size = self.n_input + + features = nn.ModuleList() + dctAttention = nn.ModuleList() + for hidden in n_hiddens: + rnn = nn.GRU( + input_size=in_size, + num_layers=1, + hidden_size=hidden, + batch_first=True, + dropout=dropout + ) + attention = dct_channel_block(channel=hidden) + features.append(rnn) + dctAttention.append(attention) + in_size = hidden + self.features = nn.Sequential(*features) + self.dctAttention = nn.Sequential(*dctAttention) + + if use_bottleneck == True: # finance + bottleneck = [] + for i in range(len(bottleneck_list)): + cur_input_dim = self.hiddens[-1] if i == 0 else bottleneck_list[i - 1][0] + bottleneck.append( + nn.Linear(cur_input_dim, bottleneck_list[i][0]) + ) + ### 不加初始权重会让Hard predict更不稳定,振幅更大 + # 初始权重越大,振幅越大 + bottleneck[-1].weight.data.normal_(0, 0.03) + bottleneck[-1].bias.data.fill_(0.5) + if bottleneck_list[i][1]: + bottleneck.append(nn.BatchNorm1d(bottleneck_list[i][0])) + if bottleneck_list[i][2]: + bottleneck.append(nn.ReLU()) + if bottleneck_list[i][3] != 0: + bottleneck.append(nn.Dropout(bottleneck_list[i][3])) + self.bottleneck = nn.Sequential(*bottleneck) + self.fc = nn.Linear(bottleneck_list[-1][0], n_output) + + torch.nn.init.xavier_normal_(self.fc.weight) + else: + self.fc_out = nn.Linear(n_hiddens[-1], self.n_output) + + if self.model_type == 'AdaRNN': + gate = nn.ModuleList() + for i in range(len(n_hiddens)): + gate_weight = nn.Linear( + len_seq * self.hiddens[i] * 2, len_seq) + gate.append(gate_weight) + self.gate = gate + + bnlst = nn.ModuleList() + for i in range(len(n_hiddens)): + bnlst.append(nn.BatchNorm1d(len_seq)) + self.bn_lst = bnlst + self.softmax = torch.nn.Softmax(dim=0) + self.init_layers() + + def init_layers(self): + for i in range(len(self.hiddens)): + self.gate[i].weight.data.normal_(0, 0.05) + self.gate[i].bias.data.fill_(0.0) + + def forward_pre_train(self, x, len_win=0): + out = self.gru_features(x) + # 两层GRU之后的结果 + fea = out[0] + + if self.use_bottleneck == True: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + # 每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + out_list_all, out_weight_list = out[1], out[2] + # 可以理解为前半段 和 后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + h_start = 0 + for j in range(h_start, self.len_seq, 1): + i_start = max(j - len_win, 0) + i_end = j + len_win if j + len_win < self.len_seq else self.len_seq - 1 + for k in range(i_start, i_end + 1): + weight = out_weight_list[i][j] if self.model_type == 'AdaRNN' else 1 / ( + self.len_seq - h_start) * (2 * len_win + 1) + loss_transfer = loss_transfer + weight * criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, k, :]) + return fc_out, loss_transfer, out_weight_list + + def gru_features(self, x, predict=False): + x_input = x + out = None + out_lis = [] + out_weight_list = [] if ( + self.model_type == 'AdaRNN') else None + for i in range(self.num_layers): + # GRU的输出 + out, _ = self.features[i](x_input.float()) + out = self.dctAttention[i](out.float()) + x_input = out + out_lis.append(out) + if self.model_type == 'AdaRNN' and predict == False: + out_gate = self.process_gate_weight(x_input, i) + out_weight_list.append(out_gate) + # 两层GRU之后的结果,每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + return out, out_lis, out_weight_list + + def process_gate_weight(self, out, index): + x_s = out[0: int(out.shape[0] // 2)] # 可以理解为前一半个batch_size的分布 域Di + x_t = out[out.shape[0] // 2: out.shape[0]] # 可以理解为后一半个batch_size的分布 域Dj + # 对应着不同的域 + x_all = torch.cat((x_s, x_t), 2) + x_all = x_all.view(x_all.shape[0], -1) + weight = torch.sigmoid(self.bn_lst[index]( + self.gate[index](x_all.float()))) + weight = torch.mean(weight, dim=0) + res = self.softmax(weight).squeeze() + return res + + def get_features(self, output_list): + fea_list_src, fea_list_tar = [], [] + for fea in output_list: + fea_list_src.append(fea[0: fea.size(0) // 2]) + fea_list_tar.append(fea[fea.size(0) // 2:]) + return fea_list_src, fea_list_tar + + # For Boosting-based + def forward_Boosting(self, x, weight_mat=None): + out = self.gru_features(x) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + + out_list_all = out[1] + # 可以理解为前半段和后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + if weight_mat is None: + weight = (1.0 / self.len_seq * + torch.ones(self.num_layers, self.len_seq)) + else: + weight = weight_mat + dist_mat = torch.zeros(self.num_layers, self.len_seq) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + for j in range(self.len_seq): + loss_trans = criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, j, :]) + loss_transfer = loss_transfer + weight[i, j] * loss_trans + dist_mat[i, j] = loss_trans + return fc_out, loss_transfer, dist_mat, weight + + # For Boosting-based + def update_weight_Boosting(self, weight_mat, dist_old, dist_new): + epsilon = 1e-12 + dist_old = dist_old.detach() + dist_new = dist_new.detach() + ind = dist_new > dist_old + epsilon + weight_mat[ind] = weight_mat[ind] * \ + (1 + torch.sigmoid(dist_new[ind] - dist_old[ind])) + weight_norm = torch.norm(weight_mat, dim=1, p=1) + weight_mat = weight_mat / weight_norm.t().unsqueeze(1).repeat(1, self.len_seq) + return weight_mat + + def predict(self, x): + out = self.gru_features(x, predict=True) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + + return fc_out + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + y = x.mean(1) + print(y.size()) + pass \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/test.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/test.py new file mode 100644 index 0000000..57e9407 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/test.py @@ -0,0 +1,96 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.LSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctLSTM.model import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +from RUL.baseModel.plot import plot_prediction,plot_forSelf + + + + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data[-1].unsqueeze(0) + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model.predict(each_predict_data).cpu().detach().numpy() # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + c = each_predict_data[-1, -1, 1:] + a = np.concatenate([each_predict_data[-1, -1, 1:], np.expand_dims(predicted_data, axis=0)], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.expand_dims(b, axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, model, is_single=True, is_norm=False, save_fig_name=""): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predicted_data_hard = np.concatenate([predicted_data_hard, + predictOneByOne(model, last_train_data, predict_num=predict_num)], axis=0) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/train.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/train.py new file mode 100644 index 0000000..cc00aba --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/train.py @@ -0,0 +1,479 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np +import random +from tqdm import tqdm +from RUL.otherIdea.adaDctLSTM.utils import utils +from RUL.otherIdea.adaDctLSTM.model import AdaRNN + +import RUL.otherIdea.adaDctLSTM.dataset_vibrate.data_process as data_process +from RUL.baseModel.loss.ffd import fft_mse, dct_mse +from RUL.otherIdea.adaDctLSTM.test import test +import matplotlib.pyplot as plt +import time +from RUL.baseModel.CommonFunction import IsStopTraining + +''' +超参数设置: +''' +# 数据准备 +is_norm = False +is_single = True +tdc_loss_type = 'cos' +num_domain = 2 # 划分为几个源域和目标域 + +# RNN相关 +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +predict_num = 50 # 预测个数 +batch_size = 32 +model_name = "AdaRNN" +hidden_list = [64, 64] # 每层RNN的隐藏层的维度 +### bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) +bottleneck = [(64, False, False, 0), (64, True, True, 0.5)] +# bottleneck = [(128, False, True, 0), +# (64, True, True, 0.2), +# (32, True, True, 0.2), +# (16, False, False, 0)] + +# 训练相关 +pre_epoch = 40 +epochs = 1000 +transfer_loss_type = 'cos' # 目前测试cos最好 +dw = 0.5 +lr = 0.01 +fft_dw = 0.1 # 整体效果,感觉是让Hard Predict更准了0.01 0.1较好 +len_win = 0 # 窗口大小为0,暂时不知道有什么用 +seed = 10 + +# 相关初始化工作 +out_dir = './outputs' +output_path = out_dir + '/{0}_tdc({1})_transfer({2})_domain{3}_dw{4}_fdw{5}_lr{6}_Norm{7}'.format(model_name, + tdc_loss_type, + transfer_loss_type, + num_domain, + dw, fft_dw, lr, + is_norm) +save_model_name = 'parameters/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[ + 0]) + "-" + str( + hidden_list[1])) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +utils.dir_exist(output_path) +utils.dir_exist(os.path.join(output_path, 'parameters')) +utils.dir_exist(os.path.join(output_path, 'fig')) +log_file = os.path.join(output_path, 'run.log') + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if log_file is None: + return + with open(log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + # 经过测试,整体来说,如果加了bottleneck,整体更愿意振动,而不加整体仅存在趋势 + # bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + + return AdaRNN(use_bottleneck=True, bottleneck_list=bottleneck, n_input=feature, n_hiddens=hidden_list, + n_output=1, dropout=0.0, model_type=name, len_seq=hidden_num, + trans_loss=transfer_loss_type) + + +def train_AdaRNN(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(len(hidden_list), hidden_num) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + + # 如果训练集域之间的batch_size对不齐就没法计算, + # 为了不抛弃所有样本,这里将选择最小的域batch_size作为本轮的batch_size + min_batch_size = 10000 + for data in data_all: + min_batch_size = min(min_batch_size, data[0].shape[0]) + + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].float(), data[2].float() + list_feat.append(feature[:min_batch_size]) + list_label.append(label_reg[:min_batch_size]) + + index = get_index(len(data_all) - 1) + + loss_mse = torch.zeros(1) + loss_fft = torch.zeros(1) + loss_transfer = torch.zeros(1) + total_loss_l1 = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + # 在batch_size处合并 + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < pre_epoch: + pred_all, each_loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=len_win) + else: + pred_all, each_loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + + lossf_s = dct_mse(pred_s, label_reg_s) + lossf_t = dct_mse(pred_t, label_reg_t) + + loss_l1 = criterion_1(pred_s, label_reg_s) + + loss_mse += loss_s + loss_t + loss_fft += (lossf_s + lossf_t) * fft_dw + loss_transfer += dw * each_loss_transfer + total_loss_l1 += loss_l1 + + total_loss = loss_mse + loss_transfer + loss_fft + loss_all.append([total_loss.item(), loss_mse.item(), loss_transfer.item(), loss_fft.item()]) + loss_1_all.append(total_loss_l1.item()) + + # 反向传播 + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + + if epoch >= pre_epoch: + if epoch > pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def val_epoch(model, val_loader, device, scheduler): + model.eval() + val_loss = 0 + val_loss_1 = 0 + val_loss_r = 0 + + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_continue, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = model.predict(val_data) + + loss = criterion(val_predict_data, val_label) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(val_predict_data, val_label) + val_loss += loss.item() + val_loss_1 += loss_1.item() + val_loss_r += loss_r.item() + + scheduler.step(val_loss) + + loss = val_loss / len(val_loader) + loss_1 = val_loss_1 / len(val_loader) + loss_r = val_loss_r / len(val_loader) + + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(len(hidden_list), hidden_num) + for i in range(weight.shape[0]): + for j in range(weight.shape[1]): + weight[i, j] = init_weight[i][j].item() + return weight + + +def loadData(): + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=batch_size, + number_domain=num_domain, mode='tdc', dis_type=tdc_loss_type + ) + return train_loader_list, valid_loader, test_loader + pass + + +def train(model, train_loader_list, valid_loader, lr_patience, early_stop_patience, device): + optimizer = optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", factor=0.5, + patience=lr_patience) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss, loss1, weight_mat, dist_mat = train_AdaRNN( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + + val_loss, val_loss_l1, val_loss_r = val_epoch( + model, valid_loader, device=device, scheduler=scheduler_model) + + pprint( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_total_loss: {:3.9f} | train_mse_loss: {:3.9f} | train_fft_loss: {:3.9f} | train_transfer_loss: {:3.9f} " + " | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss[0], train_loss[1], train_loss[3], train_loss[2], + val_loss, + optimizer.state_dict()['param_groups'][0]['lr'])) + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + pprint("保存模型最佳模型成功") + best_epoch = epoch + best_score = val_loss + # 保存模型参数 + if best_save_path != None: + utils.delete_file(os.path.join(output_path, best_save_path)) + best_save_path = save_model_name + "_epoch" + str(epoch) + \ + "_trainLoss" + str('%.5f' % train_loss[1]) + \ + "_valLoss" + str('%.5f' % val_loss) + ".pkl" + print(os.path.join(output_path, best_save_path)) + torch.save(model.state_dict(), + os.path.join(output_path, best_save_path)) + + train_loss_list.append(train_loss) + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + pprint("{0}次loss未下降,训练停止".format(early_stop_patience)) + break + + pprint('best val score:', best_score, '@', best_epoch) + return best_save_path + pass + + +def main_transfer(): + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + pprint('create DataLoaders...') + train_loader_list, valid_loader, test_loader = loadData() + + pprint('create AdaRNN model...') + model = get_model(model_name) + + num_model = count_parameters(model) + + print(model) + print('#model params:', num_model) + + pprint('train model...') + best_save_path = train(model=model, train_loader_list=train_loader_list, valid_loader=valid_loader, lr_patience=20, + early_stop_patience=50, device=device) + + end = time.time() + + print("训练耗时:{:3.2f}s".format(end - begin)) + + pprint('验证模型...') + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, best_save_path), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load(os.path.join(output_path, best_save_path), map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm, save_fig_name=os.path.join(output_path, save_fig_name)) + + +def after_test(save_name): + model = get_model(model_name) + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load( + save_name + , map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm) + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=feature) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + + parser.add_argument('--data_mode', type=str, default='tdc') + + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + # 训练与测试 + main_transfer() + + '''事后测试''' + # after_test(save_name="E:\self_example\pytorch_example\RUL\otherIdea/adaDctLSTM\outputs\AdaRNN_tdc(cos)_transfer(cos)_domain2_dw0.5_lr0.01_NormFalse\parameters\seed3069_hidden10_feature2_predict50_dimList64-64_epoch116_trainLoss0.02208_valLoss0.00271.pkl") diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/utils/__init__.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/utils/__init__.py new file mode 100644 index 0000000..4e22673 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/utils/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaDctLSTM/utils/utils.py b/pytorch_example/RUL/otherIdea/adaDctLSTM/utils/utils.py new file mode 100644 index 0000000..952e555 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaDctLSTM/utils/utils.py @@ -0,0 +1,229 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' + +import collections +import torch +import os +import pandas as pd +import torch.nn as nn +from tqdm import tqdm +import numpy as np + +EPS = 1e-12 + + +class AverageMeter(object): + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.list = [] + + def update(self, val, n=1): + self.val = val + self.list.append(val) + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +def average_params(params_list): + assert isinstance(params_list, (tuple, list, collections.deque)) + n = len(params_list) + if n == 1: + return params_list[0] + new_params = collections.OrderedDict() + keys = None + for i, params in enumerate(params_list): + if keys is None: + keys = params.keys() + for k, v in params.items(): + if k not in keys: + raise ValueError('the %d-th model has different params' % i) + if k not in new_params: + new_params[k] = v / n + else: + new_params[k] += v / n + return new_params + + +def zscore(x): + return (x - x.mean(dim=0, keepdim=True)) / x.std(dim=0, keepdim=True, unbiased=False) + + +def calc_loss(pred, label): + return torch.mean((zscore(pred) - label) ** 2) + + +def calc_corr(pred, label): + return (zscore(pred) * zscore(label)).mean() + + +def test_ic(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = label_actual.clone().detach().view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_daily(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values + avg), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for slc in tqdm(data_list[i].iter_daily(), total=data_list[i].daily_length): + feature, label_actual, _, _ = data_list[i].get(slc) + # for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = torch.tensor(label_actual, dtype=torch.float32, device=device).view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_uni(model, data_loader, model_path=None, ic_type='spearman', verbose=False): + if model_path: + model.load_state_dict(torch.load(model_path)) + model.eval() + loss_all = [] + ic_all = [] + for slc in tqdm(data_loader.iter_daily(), total=data_loader.daily_length): + data, label, _, _ = data_loader.get(slc) + with torch.no_grad(): + pred = model.predict(data) + mask = ~torch.isnan(label) + pred = pred[mask] + label = label[mask] + loss = torch.mean(torch.log(torch.cosh(pred - label))) + if ic_type == 'spearman': + ic = spearman_corr(pred, label) + elif ic_type == 'pearson': + ic = pearson_corr(pred, label) + loss_all.append(loss.item()) + ic_all.append(ic) + loss, ic = np.mean(loss_all), np.mean(ic_all) + if verbose: + print('IC: ', ic) + return loss, ic + + +def calc_ic(x, y, ic_type='pearson'): + ic = -100 + if ic_type == 'pearson': + ic = pearson_corr(x, y) + elif ic_type == 'spearman': + ic = spearman_corr(x, y) + return ic + + +def create_dir(path): + if not os.path.exists(path): + os.makedirs(path) + +def delete_file(path): + if os.path.exists(path): + os.remove(path) + + +def handle_nan(x): + mask = ~torch.isnan(x) + return x[mask], mask + + +class Log_Loss(nn.Module): + def __init__(self): + super(Log_Loss, self).__init__() + + def forward(self, ytrue, ypred): + delta = ypred - ytrue + return torch.mean(torch.log(torch.cosh(delta))) + + +def spearman_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='spearman') + return spearman + + +def spearman_corr2(x, y): + X = pd.Series(x) + Y = pd.Series(y) + spearman = X.corr(Y, method='spearman') + return spearman + + +def pearson_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='pearson') + return spearman + + +def dir_exist(dirs): + if not os.path.exists(dirs): + os.makedirs(dirs) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/__init__.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/__init__.py new file mode 100644 index 0000000..75da775 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/20 20:32 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/__init__.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/__init__.py new file mode 100644 index 0000000..3e48d01 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/data_process.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/data_process.py new file mode 100644 index 0000000..e33d069 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/data_process.py @@ -0,0 +1,111 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 + +from .data_vibrate import get_vibrate_data +from ..loss_transfer import TransferLoss +from .loadData import getVibrate_data + +import torch +import math + + +def get_split_time(num_domain=2, mode='pre_process', data=None, dis_type='coral'): + spilt_time = { + '2': [(0, 600), (600, 1200)] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data, dis_type='coral'): + # 样本个数 + num_day = len(data[0]) + + split_N = 10 + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_index = int(num_day / split_N * selected[i - 1]) + else: + sel_start_index = int(num_day / split_N * selected[i - 1]) + 1 + + sel_end_index = int(num_day / split_N * selected[i]) + + res.append((sel_start_index, sel_end_index)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(hidden_num, feature, predict_num, batch_size=6, number_domain=2, mode='pre_process', + dis_type='coral', is_norm=False): + # mode: 'tdc', 'pre_process' + train_data, val_data = getVibrate_data(hidden_num=hidden_num, feature=feature, predict_num=predict_num, + is_norm=is_norm) + + split_time_list = get_split_time(number_domain, mode=mode, data=train_data, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + index_temp = split_time_list[i] + train_loader = get_vibrate_data(train_data, start_index=index_temp[0], + end_index=index_temp[1], batch_size=batch_size) + train_list.append(train_loader) + + valid_loader = get_vibrate_data(val_data, start_index=0, + end_index=len(val_data[0]), batch_size=batch_size, mean=None, + std=None, shuffle=False) + test_loader = valid_loader + + return train_list, valid_loader, test_loader + + +if __name__ == '__main__': + load_weather_data_multi_domain(hidden_num=10, feature=10, predict_num=50, batch_size=32, number_domain=2, + mode='tdc', + dis_type='coral', is_norm=False) diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/data_vibrate.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/data_vibrate.py new file mode 100644 index 0000000..f6a843c --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/data_vibrate.py @@ -0,0 +1,78 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + +import math +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import os +from pandas.core.frame import DataFrame +from torch.utils.data import Dataset, DataLoader +import torch +import pickle +import datetime + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target, label_reg + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(data, start_index, end_index, mean=None, std=None): + feat, label_continue, label_single = data[0], data[1], data[2] + referece_start_index = 0 + referece_end_index = 1250 + + assert start_index - referece_start_index >= 0 + assert end_index - referece_end_index <= 0 + assert end_index - start_index >= 0 + + feat = feat[start_index: end_index + 1] + label = label_continue[start_index: end_index + 1] + label_reg = label_single[start_index: end_index + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def get_vibrate_data(data, start_index, end_index, batch_size, shuffle=True, mean=None, std=None): + dataset = create_dataset(data, start_index, + end_index, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/loadData.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/loadData.py new file mode 100644 index 0000000..dd3fa37 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/dataset_vibrate/loadData.py @@ -0,0 +1,150 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("E:\self_example\pytorch_example\RUL\dataset\HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + # HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset + + +def getVibrate_data(hidden_num, feature, predict_num, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + + + + return [train_data,train_label,train_label_single],[val_data,val_label,val_label_single] diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/loss_transfer.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/loss_transfer.py new file mode 100644 index 0000000..7e2798d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/loss_transfer.py @@ -0,0 +1,64 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:45 +@Usage : +@Desc : +''' +from RUL.baseModel.loss import adv_loss, coral, kl_js, mmd, mutual_info, cos, pair_dist + + +class TransferLoss(object): + def __init__(self, loss_type='cosine', input_dim=512): + """ + Supported loss_type: mmd(mmd_lin), mmd_rbf, coral, cosine, kl, js, mine, adv + """ + self.loss_type = loss_type + self.input_dim = input_dim + + def compute(self, X, Y): + """Compute adaptation loss + + Arguments: + X {tensor} -- source matrix + Y {tensor} -- target matrix + + Returns: + [tensor] -- transfer loss + """ + if self.loss_type == 'mmd_lin' or self.loss_type == 'mmd': + mmdloss = mmd.MMD_loss(kernel_type='linear') + loss = mmdloss(X, Y) + elif self.loss_type == 'coral': + loss = coral.CORAL(X, Y) + elif self.loss_type == 'cosine' or self.loss_type == 'cos': + loss = 1 - cos.cosine(X, Y) + elif self.loss_type == 'kl': + loss = kl_js.kl_div(X, Y) + elif self.loss_type == 'js': + loss = kl_js.js(X, Y) + elif self.loss_type == 'mine': + mine_model = mutual_info.Mine_estimator( + input_dim=self.input_dim, hidden_dim=60) + loss = mine_model(X, Y) + elif self.loss_type == 'adv': + loss = adv_loss.adv(X, Y, input_dim=self.input_dim, hidden_dim=32) + elif self.loss_type == 'mmd_rbf': + mmdloss = mmd.MMD_loss(kernel_type='rbf') + loss = mmdloss(X, Y) + elif self.loss_type == 'pairwise': + pair_mat = pair_dist.pairwise_dist(X, Y) + import torch + loss = torch.norm(pair_mat) + + return loss + + +if __name__ == "__main__": + import torch + + trans_loss = TransferLoss('adv') + a = (torch.randn(5, 512) * 10) + b = (torch.randn(5, 512) * 10) + print(trans_loss.compute(a, b)) diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/model.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/model.py new file mode 100644 index 0000000..f1bd315 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/model.py @@ -0,0 +1,253 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:44 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +import torch.nn.functional as F +from RUL.baseModel.dctChannelAttention import dct_channel_block + + +class AdaRNN(nn.Module): + """ + model_type: 'Boosting', 'AdaRNN' + bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + """ + + def __init__(self, use_bottleneck=False, bottleneck_list=[(64, False, False, 0), (64, True, True, 0.5)], + n_input=128, n_hiddens=[64, 64], n_output=6, + dropout=0.0, len_seq=9, model_type='AdaRNN', + trans_loss='mmd', mdw=1): + super(AdaRNN, self).__init__() + self.use_bottleneck = use_bottleneck + self.n_input = n_input + self.num_layers = len(n_hiddens) + self.hiddens = n_hiddens + self.n_output = n_output + self.model_type = model_type + self.trans_loss = trans_loss + self.len_seq = len_seq + in_size = self.n_input + + features = nn.ModuleList() + dctAttention = nn.ModuleList() + for hidden in n_hiddens: + rnn = nn.GRU( + input_size=in_size, + num_layers=1, + hidden_size=hidden, + batch_first=True, + dropout=dropout + ) + attention = dct_channel_block(channel=hidden) + features.append(rnn) + dctAttention.append(attention) + in_size = hidden + self.features = nn.Sequential(*features) + self.dctAttention = nn.Sequential(*dctAttention) + + if use_bottleneck == True: # finance + bottleneck = [] + for i in range(len(bottleneck_list)): + cur_input_dim = self.hiddens[-1] if i == 0 else bottleneck_list[i - 1][0] + bottleneck.append( + nn.Linear(cur_input_dim, bottleneck_list[i][0]) + ) + ### 不加初始权重会让Hard predict更不稳定,振幅更大 + # 初始权重越大,振幅越大 + # bottleneck[-1].weight.data.normal_(0, 0.04) + # bottleneck[-1].bias.data.fill_(0.1) + if bottleneck_list[i][1]: + bottleneck.append(nn.BatchNorm1d(bottleneck_list[i][0])) + if bottleneck_list[i][2]: + bottleneck.append(nn.ReLU()) + if bottleneck_list[i][3] != 0: + bottleneck.append(nn.Dropout(bottleneck_list[i][3])) + self.bottleneck = nn.Sequential(*bottleneck) + self.fc = nn.Linear(bottleneck_list[-1][0], n_output) + + torch.nn.init.xavier_normal_(self.fc.weight) + else: + self.fc_out = nn.Linear(n_hiddens[-1], self.n_output) + + # 平均值权重 + self.mean_weight = nn.Sequential( + nn.Linear(n_input, bottleneck_list[-1][0]), + nn.Linear(bottleneck_list[-1][0], bottleneck_list[-1][0]), + nn.BatchNorm1d(bottleneck_list[-1][0]), + nn.ReLU(), + nn.Dropout(), + nn.Linear(bottleneck_list[-1][0], self.n_output) + ) + self.mdw = mdw + # 方差权重 + self.std_weight = nn.Linear(in_features=n_input, out_features=n_hiddens[-1]) + + if self.model_type == 'AdaRNN': + gate = nn.ModuleList() + for i in range(len(n_hiddens)): + gate_weight = nn.Linear( + len_seq * self.hiddens[i] * 2, len_seq) + gate.append(gate_weight) + self.gate = gate + + bnlst = nn.ModuleList() + for i in range(len(n_hiddens)): + bnlst.append(nn.BatchNorm1d(len_seq)) + self.bn_lst = bnlst + self.softmax = torch.nn.Softmax(dim=0) + self.init_layers() + + def init_layers(self): + for i in range(len(self.hiddens)): + self.gate[i].weight.data.normal_(0, 0.05) + self.gate[i].bias.data.fill_(0.0) + + def forward_pre_train(self, x, len_win=0): + # TODO 与原始维度取平均之后加起来 + mean = x[:, -1, :].mean(-1) + # mean = self.mean_weight(mean) + + # std = x.std(1) + out = self.gru_features(x) + # 两层GRU之后的结果 + fea = out[0] + + if self.use_bottleneck == True: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + mean * self.mdw + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + mean * self.mdw + # 每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + out_list_all, out_weight_list = out[1], out[2] + # 可以理解为前半段 和 后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + h_start = 0 + for j in range(h_start, self.len_seq, 1): + i_start = max(j - len_win, 0) + i_end = j + len_win if j + len_win < self.len_seq else self.len_seq - 1 + for k in range(i_start, i_end + 1): + weight = out_weight_list[i][j] if self.model_type == 'AdaRNN' else 1 / ( + self.len_seq - h_start) * (2 * len_win + 1) + loss_transfer = loss_transfer + weight * criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, k, :]) + return fc_out, loss_transfer, out_weight_list + + def gru_features(self, x, predict=False): + x_input = x + out = None + out_lis = [] + out_weight_list = [] if ( + self.model_type == 'AdaRNN') else None + for i in range(self.num_layers): + # GRU的输出 + out, _ = self.features[i](x_input.float()) + out = self.dctAttention[i](out.float()) + x_input = out + out_lis.append(out) + if self.model_type == 'AdaRNN' and predict == False: + out_gate = self.process_gate_weight(x_input, i) + out_weight_list.append(out_gate) + # 两层GRU之后的结果,每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + return out, out_lis, out_weight_list + + def process_gate_weight(self, out, index): + x_s = out[0: int(out.shape[0] // 2)] # 可以理解为前一半个batch_size的分布 域Di + x_t = out[out.shape[0] // 2: out.shape[0]] # 可以理解为后一半个batch_size的分布 域Dj + # 对应着不同的域 + x_all = torch.cat((x_s, x_t), 2) + x_all = x_all.view(x_all.shape[0], -1) + weight = torch.sigmoid(self.bn_lst[index]( + self.gate[index](x_all.float()))) + weight = torch.mean(weight, dim=0) + res = self.softmax(weight).squeeze() + return res + + def get_features(self, output_list): + fea_list_src, fea_list_tar = [], [] + for fea in output_list: + fea_list_src.append(fea[0: fea.size(0) // 2]) + fea_list_tar.append(fea[fea.size(0) // 2:]) + return fea_list_src, fea_list_tar + + # For Boosting-based + def forward_Boosting(self, x, weight_mat=None): + # TODO 与原始维度取平均之后加起来 + mean = x[:, -1, :].mean(-1) + # mean = self.mean_weight(mean) + + out = self.gru_features(x) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + mean* self.mdw + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + mean* self.mdw + + out_list_all = out[1] + # 可以理解为前半段和后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + if weight_mat is None: + weight = (1.0 / self.len_seq * + torch.ones(self.num_layers, self.len_seq)) + else: + weight = weight_mat + dist_mat = torch.zeros(self.num_layers, self.len_seq) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + for j in range(self.len_seq): + loss_trans = criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, j, :]) + loss_transfer = loss_transfer + weight[i, j] * loss_trans + dist_mat[i, j] = loss_trans + return fc_out, loss_transfer, dist_mat, weight + + # For Boosting-based + def update_weight_Boosting(self, weight_mat, dist_old, dist_new): + epsilon = 1e-12 + dist_old = dist_old.detach() + dist_new = dist_new.detach() + ind = dist_new > dist_old + epsilon + weight_mat[ind] = weight_mat[ind] * \ + (1 + torch.sigmoid(dist_new[ind] - dist_old[ind])) + weight_norm = torch.norm(weight_mat, dim=1, p=1) + weight_mat = weight_mat / weight_norm.t().unsqueeze(1).repeat(1, self.len_seq) + return weight_mat + + def predict(self, x): + # TODO 与原始维度取平均之后加起来 + mean = x[:, -1, :].mean(-1).to(torch.float32) + # mean = x.mean(1) + # mean = self.mean_weight(mean) + + out = self.gru_features(x, predict=True) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + mean* self.mdw + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + mean* self.mdw + + return fc_out + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + y = x.mean(1) + z = x.std(1) + print(y.size()) + print(z.size()) + pass diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/test.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/test.py new file mode 100644 index 0000000..b30faea --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/test.py @@ -0,0 +1,116 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.LSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctLSTM.model import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +from RUL.baseModel.plot import plot_prediction, plot_forSelf +from RUL.baseModel.loss.Evaluate import getEvaluate + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data[-1].unsqueeze(0) + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model.predict(each_predict_data).cpu().detach().numpy() # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + c = each_predict_data[-1, -1, 1:] + # a = np.concatenate([each_predict_data[-1, -1, 1:], np.expand_dims(predicted_data, axis=0)], axis=0) + a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.expand_dims(b, axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, model, is_single=True, is_norm=False, save_fig_name=""): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label = np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/train.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/train.py new file mode 100644 index 0000000..552f276 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/train.py @@ -0,0 +1,480 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np +import random +from tqdm import tqdm +from RUL.otherIdea.adaHDctLSTM.utils import utils +from RUL.otherIdea.adaHDctLSTM.model import AdaRNN + +import RUL.otherIdea.adaHDctLSTM.dataset_vibrate.data_process as data_process +from RUL.baseModel.loss.ffd import fft_mse, dct_mse +from RUL.otherIdea.adaHDctLSTM.test import test +import matplotlib.pyplot as plt +import time +from RUL.baseModel.CommonFunction import IsStopTraining + +''' +超参数设置: +''' +# 数据准备 +is_norm = False +is_single = True +tdc_loss_type = 'cos' +num_domain = 2 # 划分为几个源域和目标域 + +# RNN相关 +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +predict_num = 200 # 预测个数 +batch_size = 32 +model_name = "AdaRNN" +hidden_list = [64, 64] # 每层RNN的隐藏层的维度 +### bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) +bottleneck = [(64, False, False, 0), (64, True, True, 0.5)] +# bottleneck = [(128, False, True, 0), +# (64, True, True, 0.2), +# (32, True, True, 0.2), +# (16, False, False, 0)] + +# 训练相关 +pre_epoch = 40 +epochs = 1000 +transfer_loss_type = 'cos' # 目前测试cos最好 +dw = 0.5 +lr = 0.01 +fft_dw = 0.1 # 整体效果,感觉是让Hard Predict更准了0.01 0.1较好 +m_dw = 0.8 +len_win = 0 # 窗口大小为0,暂时不知道有什么用 +seed = 250 + +# 相关初始化工作 +out_dir = './outputs' +output_path = out_dir + '/{0}_tdc({1})_transfer({2})_domain{3}_dw{4}_fdw{5}_lr{6}_Norm{7}'.format(model_name, + tdc_loss_type, + transfer_loss_type, + num_domain, + dw, fft_dw, lr, + is_norm) +save_model_name = 'parameters/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[ + 0]) + "-" + str( + hidden_list[1])) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +utils.dir_exist(output_path) +utils.dir_exist(os.path.join(output_path, 'parameters')) +utils.dir_exist(os.path.join(output_path, 'fig')) +log_file = os.path.join(output_path, 'run.log') + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if log_file is None: + return + with open(log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + # 经过测试,整体来说,如果加了bottleneck,整体更愿意振动,而不加整体仅存在趋势 + # bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + + return AdaRNN(use_bottleneck=True, bottleneck_list=bottleneck, n_input=feature, n_hiddens=hidden_list, + n_output=1, dropout=0.0, model_type=name, len_seq=hidden_num, + trans_loss=transfer_loss_type,mdw=m_dw) + + +def train_AdaRNN(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(len(hidden_list), hidden_num) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + + # 如果训练集域之间的batch_size对不齐就没法计算, + # 为了不抛弃所有样本,这里将选择最小的域batch_size作为本轮的batch_size + min_batch_size = 10000 + for data in data_all: + min_batch_size = min(min_batch_size, data[0].shape[0]) + + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].float(), data[2].float() + list_feat.append(feature[:min_batch_size]) + list_label.append(label_reg[:min_batch_size]) + + index = get_index(len(data_all) - 1) + + loss_mse = torch.zeros(1) + loss_fft = torch.zeros(1) + loss_transfer = torch.zeros(1) + total_loss_l1 = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + # 在batch_size处合并 + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < pre_epoch: + pred_all, each_loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=len_win) + else: + pred_all, each_loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + + lossf_s = dct_mse(pred_s, label_reg_s) + lossf_t = dct_mse(pred_t, label_reg_t) + + loss_l1 = criterion_1(pred_s, label_reg_s) + + loss_mse += loss_s + loss_t + loss_fft += (lossf_s + lossf_t) * fft_dw + loss_transfer += dw * each_loss_transfer + total_loss_l1 += loss_l1 + + total_loss = loss_mse + loss_transfer + loss_fft + loss_all.append([total_loss.item(), loss_mse.item(), loss_transfer.item(), loss_fft.item()]) + loss_1_all.append(total_loss_l1.item()) + + # 反向传播 + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + + if epoch >= pre_epoch: + if epoch > pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def val_epoch(model, val_loader, device, scheduler): + model.eval() + val_loss = 0 + val_loss_1 = 0 + val_loss_r = 0 + + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_continue, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = model.predict(val_data) + + loss = criterion(val_predict_data, val_label) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(val_predict_data, val_label) + val_loss += loss.item() + val_loss_1 += loss_1.item() + val_loss_r += loss_r.item() + + scheduler.step(val_loss) + + loss = val_loss / len(val_loader) + loss_1 = val_loss_1 / len(val_loader) + loss_r = val_loss_r / len(val_loader) + + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(len(hidden_list), hidden_num) + for i in range(weight.shape[0]): + for j in range(weight.shape[1]): + weight[i, j] = init_weight[i][j].item() + return weight + + +def loadData(): + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=batch_size, + number_domain=num_domain, mode='tdc', dis_type=tdc_loss_type + ) + return train_loader_list, valid_loader, test_loader + pass + + +def train(model, train_loader_list, valid_loader, lr_patience, early_stop_patience, device): + optimizer = optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", factor=0.5, + patience=lr_patience) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss, loss1, weight_mat, dist_mat = train_AdaRNN( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + + val_loss, val_loss_l1, val_loss_r = val_epoch( + model, valid_loader, device=device, scheduler=scheduler_model) + + pprint( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_total_loss: {:3.9f} | train_mse_loss: {:3.9f} | train_fft_loss: {:3.9f} | train_transfer_loss: {:3.9f} " + " | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss[0], train_loss[1], train_loss[3], train_loss[2], + val_loss, + optimizer.state_dict()['param_groups'][0]['lr'])) + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + pprint("保存模型最佳模型成功") + best_epoch = epoch + best_score = val_loss + # 保存模型参数 + if best_save_path != None: + utils.delete_file(os.path.join(output_path, best_save_path)) + best_save_path = save_model_name + "_epoch" + str(epoch) + \ + "_trainLoss" + str('%.5f' % train_loss[1]) + \ + "_valLoss" + str('%.5f' % val_loss) + ".pkl" + print(os.path.join(output_path, best_save_path)) + torch.save(model.state_dict(), + os.path.join(output_path, best_save_path)) + + train_loss_list.append(train_loss) + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + pprint("{0}次loss未下降,训练停止".format(early_stop_patience)) + break + + pprint('best val score:', best_score, '@', best_epoch) + return best_save_path + pass + + +def main_transfer(): + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + pprint('create DataLoaders...') + train_loader_list, valid_loader, test_loader = loadData() + + pprint('create AdaRNN model...') + model = get_model(model_name) + + num_model = count_parameters(model) + + print(model) + print('#model params:', num_model) + + pprint('train model...') + best_save_path = train(model=model, train_loader_list=train_loader_list, valid_loader=valid_loader, lr_patience=20, + early_stop_patience=50, device=device) + + end = time.time() + + print("训练耗时:{:3.2f}s".format(end - begin)) + + pprint('验证模型...') + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, best_save_path), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load(os.path.join(output_path, best_save_path), map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm, save_fig_name=os.path.join(output_path, save_fig_name)) + + +def after_test(save_name): + model = get_model(model_name) + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load( + save_name + , map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm) + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=feature) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + + parser.add_argument('--data_mode', type=str, default='tdc') + + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + # 训练与测试 + main_transfer() + + '''事后测试''' + # after_test(save_name="E:\self_example\pytorch_example\RUL\otherIdea/adaHDctEmdLSTM\outputs\AdaRNN_tdc(cos)_transfer(cos)_domain2_dw0.5_fdw0.1_lr0.01_NormFalse\parameters\seed450_hidden10_feature2_predict50_dimList64-64_epoch34_trainLoss0.00751_valLoss0.01469.pkl") diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/utils/__init__.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/utils/__init__.py new file mode 100644 index 0000000..4e22673 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/utils/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaHDctLSTM/utils/utils.py b/pytorch_example/RUL/otherIdea/adaHDctLSTM/utils/utils.py new file mode 100644 index 0000000..952e555 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaHDctLSTM/utils/utils.py @@ -0,0 +1,229 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' + +import collections +import torch +import os +import pandas as pd +import torch.nn as nn +from tqdm import tqdm +import numpy as np + +EPS = 1e-12 + + +class AverageMeter(object): + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.list = [] + + def update(self, val, n=1): + self.val = val + self.list.append(val) + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +def average_params(params_list): + assert isinstance(params_list, (tuple, list, collections.deque)) + n = len(params_list) + if n == 1: + return params_list[0] + new_params = collections.OrderedDict() + keys = None + for i, params in enumerate(params_list): + if keys is None: + keys = params.keys() + for k, v in params.items(): + if k not in keys: + raise ValueError('the %d-th model has different params' % i) + if k not in new_params: + new_params[k] = v / n + else: + new_params[k] += v / n + return new_params + + +def zscore(x): + return (x - x.mean(dim=0, keepdim=True)) / x.std(dim=0, keepdim=True, unbiased=False) + + +def calc_loss(pred, label): + return torch.mean((zscore(pred) - label) ** 2) + + +def calc_corr(pred, label): + return (zscore(pred) * zscore(label)).mean() + + +def test_ic(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = label_actual.clone().detach().view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_daily(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values + avg), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for slc in tqdm(data_list[i].iter_daily(), total=data_list[i].daily_length): + feature, label_actual, _, _ = data_list[i].get(slc) + # for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = torch.tensor(label_actual, dtype=torch.float32, device=device).view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_uni(model, data_loader, model_path=None, ic_type='spearman', verbose=False): + if model_path: + model.load_state_dict(torch.load(model_path)) + model.eval() + loss_all = [] + ic_all = [] + for slc in tqdm(data_loader.iter_daily(), total=data_loader.daily_length): + data, label, _, _ = data_loader.get(slc) + with torch.no_grad(): + pred = model.predict(data) + mask = ~torch.isnan(label) + pred = pred[mask] + label = label[mask] + loss = torch.mean(torch.log(torch.cosh(pred - label))) + if ic_type == 'spearman': + ic = spearman_corr(pred, label) + elif ic_type == 'pearson': + ic = pearson_corr(pred, label) + loss_all.append(loss.item()) + ic_all.append(ic) + loss, ic = np.mean(loss_all), np.mean(ic_all) + if verbose: + print('IC: ', ic) + return loss, ic + + +def calc_ic(x, y, ic_type='pearson'): + ic = -100 + if ic_type == 'pearson': + ic = pearson_corr(x, y) + elif ic_type == 'spearman': + ic = spearman_corr(x, y) + return ic + + +def create_dir(path): + if not os.path.exists(path): + os.makedirs(path) + +def delete_file(path): + if os.path.exists(path): + os.remove(path) + + +def handle_nan(x): + mask = ~torch.isnan(x) + return x[mask], mask + + +class Log_Loss(nn.Module): + def __init__(self): + super(Log_Loss, self).__init__() + + def forward(self, ytrue, ypred): + delta = ypred - ytrue + return torch.mean(torch.log(torch.cosh(delta))) + + +def spearman_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='spearman') + return spearman + + +def spearman_corr2(x, y): + X = pd.Series(x) + Y = pd.Series(y) + spearman = X.corr(Y, method='spearman') + return spearman + + +def pearson_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='pearson') + return spearman + + +def dir_exist(dirs): + if not os.path.exists(dirs): + os.makedirs(dirs) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/__init__.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/__init__.py new file mode 100644 index 0000000..3252e42 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/21 13:25 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/__init__.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/__init__.py new file mode 100644 index 0000000..3e48d01 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/data_process.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/data_process.py new file mode 100644 index 0000000..f8112b9 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/data_process.py @@ -0,0 +1,111 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 + +from .data_vibrate import get_vibrate_data +from ..loss_transfer import TransferLoss +from .loadData import getVibrate_data + +import torch +import math + + +def get_split_time(num_domain=2, mode='pre_process', data=None, dis_type='coral'): + spilt_time = { + '2': [(0, 600), (600, 1200)] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data, dis_type='coral'): + # 样本个数 + num_day = len(data[0]) + + split_N = 10 + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_index = int(num_day / split_N * selected[i - 1]) + else: + sel_start_index = int(num_day / split_N * selected[i - 1]) + 1 + + sel_end_index = int(num_day / split_N * selected[i]) + + res.append((sel_start_index, sel_end_index)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(hidden_num, feature, predict_num, batch_size=6, number_domain=2, mode='pre_process', + dis_type='coral', is_norm=False): + # mode: 'tdc', 'pre_process' + train_data, val_data = getVibrate_data(hidden_num=hidden_num, feature=feature, predict_num=predict_num, + is_norm=is_norm) + + split_time_list = get_split_time(number_domain, mode=mode, data=train_data, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + index_temp = split_time_list[i] + train_loader = get_vibrate_data(train_data, start_index=index_temp[0], + end_index=index_temp[1], batch_size=batch_size) + train_list.append(train_loader) + + valid_loader = get_vibrate_data(val_data, start_index=0, + end_index=len(val_data[0]), batch_size=batch_size, mean=None, + std=None, shuffle=False) + test_loader = valid_loader + + return train_list, valid_loader, test_loader + + +if __name__ == '__main__': + load_weather_data_multi_domain(hidden_num=10, feature=10, predict_num=50, batch_size=32, number_domain=2, + mode='tdc', + dis_type='coral', is_norm=False) diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/data_vibrate.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/data_vibrate.py new file mode 100644 index 0000000..f6a843c --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/data_vibrate.py @@ -0,0 +1,78 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + +import math +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import os +from pandas.core.frame import DataFrame +from torch.utils.data import Dataset, DataLoader +import torch +import pickle +import datetime + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target, label_reg + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(data, start_index, end_index, mean=None, std=None): + feat, label_continue, label_single = data[0], data[1], data[2] + referece_start_index = 0 + referece_end_index = 1250 + + assert start_index - referece_start_index >= 0 + assert end_index - referece_end_index <= 0 + assert end_index - start_index >= 0 + + feat = feat[start_index: end_index + 1] + label = label_continue[start_index: end_index + 1] + label_reg = label_single[start_index: end_index + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def get_vibrate_data(data, start_index, end_index, batch_size, shuffle=True, mean=None, std=None): + dataset = create_dataset(data, start_index, + end_index, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/loadData.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/loadData.py new file mode 100644 index 0000000..dd3fa37 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_vibrate/loadData.py @@ -0,0 +1,150 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("E:\self_example\pytorch_example\RUL\dataset\HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + # HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset + + +def getVibrate_data(hidden_num, feature, predict_num, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + + + + return [train_data,train_label,train_label_single],[val_data,val_label,val_label_single] diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/__init__.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/__init__.py new file mode 100644 index 0000000..3e48d01 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/data_process.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/data_process.py new file mode 100644 index 0000000..dea7c5e --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/data_process.py @@ -0,0 +1,111 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 + +import RUL.otherIdea.adaNHDctLSTM.dataset_wind.data_vibrate as data_vibrate +from RUL.otherIdea.adaNHDctLSTM.loss_transfer import TransferLoss +from RUL.otherIdea.adaNHDctLSTM.dataset_wind.loadData import getVibrate_data + +import torch +import math + + +def get_split_time(num_domain=2, mode='pre_process', data=None, dis_type='coral'): + spilt_time = { + '2': [(0, 600), (600, 1200)] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data, dis_type='coral'): + # 样本个数 + num_day = len(data[0]) + + split_N = 10 + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_index = int(num_day / split_N * selected[i - 1]) + else: + sel_start_index = int(num_day / split_N * selected[i - 1]) + 1 + + sel_end_index = int(num_day / split_N * selected[i]) + + res.append((sel_start_index, sel_end_index)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(hidden_num, feature, predict_num, batch_size=6, number_domain=2, mode='pre_process', + dis_type='coral', is_norm=False): + # mode: 'tdc', 'pre_process' + train_data, val_data = getVibrate_data(hidden_num=hidden_num, feature=feature, predict_num=predict_num, + is_norm=is_norm) + + split_time_list = get_split_time(number_domain, mode=mode, data=train_data, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + index_temp = split_time_list[i] + train_loader = data_vibrate.get_vibrate_data(train_data, start_index=index_temp[0], + end_index=index_temp[1], batch_size=batch_size) + train_list.append(train_loader) + + valid_loader = data_vibrate.get_vibrate_data(val_data, start_index=0, + end_index=len(val_data), batch_size=batch_size, mean=None, + std=None, shuffle=False) + test_loader = valid_loader + + return train_list, valid_loader, test_loader + + +if __name__ == '__main__': + load_weather_data_multi_domain(hidden_num=10, feature=10, predict_num=50, batch_size=32, number_domain=2, + mode='tdc', + dis_type='coral', is_norm=False) diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/data_vibrate.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/data_vibrate.py new file mode 100644 index 0000000..1590501 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/data_vibrate.py @@ -0,0 +1,78 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + +import math +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import os +from pandas.core.frame import DataFrame +from torch.utils.data import Dataset, DataLoader +import torch +import pickle +import datetime + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target, label_reg + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(data, start_index, end_index, mean=None, std=None): + feat, label_continue, label_single = data[0], data[1], data[2] + referece_start_index = 0 + referece_end_index = 2000 + + assert start_index - referece_start_index >= 0 + assert end_index - referece_end_index <= 0 + assert end_index - start_index >= 0 + + feat = feat[start_index: end_index + 1] + label = label_continue[start_index: end_index + 1] + label_reg = label_single[start_index: end_index + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def get_vibrate_data(data, start_index, end_index, batch_size, shuffle=True, mean=None, std=None): + dataset = create_dataset(data, start_index, + end_index, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/loadData.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/loadData.py new file mode 100644 index 0000000..8a39415 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/dataset_wind/loadData.py @@ -0,0 +1,150 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("E:\self_example\pytorch_example\RUL\dataset\wind_HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:-10, 1] + # HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset + + +def getVibrate_data(hidden_num, feature, predict_num, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + + + + return [train_data,train_label,train_label_single],[val_data,val_label,val_label_single] diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/loss_transfer.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/loss_transfer.py new file mode 100644 index 0000000..7e2798d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/loss_transfer.py @@ -0,0 +1,64 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:45 +@Usage : +@Desc : +''' +from RUL.baseModel.loss import adv_loss, coral, kl_js, mmd, mutual_info, cos, pair_dist + + +class TransferLoss(object): + def __init__(self, loss_type='cosine', input_dim=512): + """ + Supported loss_type: mmd(mmd_lin), mmd_rbf, coral, cosine, kl, js, mine, adv + """ + self.loss_type = loss_type + self.input_dim = input_dim + + def compute(self, X, Y): + """Compute adaptation loss + + Arguments: + X {tensor} -- source matrix + Y {tensor} -- target matrix + + Returns: + [tensor] -- transfer loss + """ + if self.loss_type == 'mmd_lin' or self.loss_type == 'mmd': + mmdloss = mmd.MMD_loss(kernel_type='linear') + loss = mmdloss(X, Y) + elif self.loss_type == 'coral': + loss = coral.CORAL(X, Y) + elif self.loss_type == 'cosine' or self.loss_type == 'cos': + loss = 1 - cos.cosine(X, Y) + elif self.loss_type == 'kl': + loss = kl_js.kl_div(X, Y) + elif self.loss_type == 'js': + loss = kl_js.js(X, Y) + elif self.loss_type == 'mine': + mine_model = mutual_info.Mine_estimator( + input_dim=self.input_dim, hidden_dim=60) + loss = mine_model(X, Y) + elif self.loss_type == 'adv': + loss = adv_loss.adv(X, Y, input_dim=self.input_dim, hidden_dim=32) + elif self.loss_type == 'mmd_rbf': + mmdloss = mmd.MMD_loss(kernel_type='rbf') + loss = mmdloss(X, Y) + elif self.loss_type == 'pairwise': + pair_mat = pair_dist.pairwise_dist(X, Y) + import torch + loss = torch.norm(pair_mat) + + return loss + + +if __name__ == "__main__": + import torch + + trans_loss = TransferLoss('adv') + a = (torch.randn(5, 512) * 10) + b = (torch.randn(5, 512) * 10) + print(trans_loss.compute(a, b)) diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/model.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/model.py new file mode 100644 index 0000000..df0db61 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/model.py @@ -0,0 +1,269 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:44 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +import torch.nn.functional as F +from RUL.baseModel.dctChannelAttention import dct_channel_block + + +class AdaRNN(nn.Module): + """ + model_type: 'Boosting', 'AdaRNN' + bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + """ + + def __init__(self, use_bottleneck=False, bottleneck_list=[(64, False, False, 0), (64, True, True, 0.5)], + n_input=128, n_hiddens=[64, 64], n_output=6, + dropout=0.0, len_seq=9, model_type='AdaRNN', + trans_loss='mmd',mdw=1): + super(AdaRNN, self).__init__() + self.use_bottleneck = use_bottleneck + self.n_input = n_input + self.num_layers = len(n_hiddens) + self.hiddens = n_hiddens + self.n_output = n_output + self.model_type = model_type + self.trans_loss = trans_loss + self.len_seq = len_seq + in_size = self.n_input + + features = nn.ModuleList() + dctAttention = nn.ModuleList() + for hidden in n_hiddens: + rnn = nn.GRU( + input_size=in_size, + num_layers=1, + hidden_size=hidden, + batch_first=True, + dropout=dropout + ) + attention = dct_channel_block(channel=hidden) + features.append(rnn) + dctAttention.append(attention) + in_size = hidden + self.features = nn.Sequential(*features) + self.dctAttention = nn.Sequential(*dctAttention) + + if use_bottleneck == True: # finance + bottleneck = [] + for i in range(len(bottleneck_list)): + cur_input_dim = self.hiddens[-1] if i == 0 else bottleneck_list[i - 1][0] + bottleneck.append( + nn.Linear(cur_input_dim, bottleneck_list[i][0]) + ) + ### 不加初始权重会让Hard predict更不稳定,振幅更大 + # 初始权重越大,振幅越大 + bottleneck[-1].weight.data.normal_(0, 0.03) + bottleneck[-1].bias.data.fill_(0.1) + if bottleneck_list[i][1]: + bottleneck.append(nn.BatchNorm1d(bottleneck_list[i][0])) + if bottleneck_list[i][2]: + bottleneck.append(nn.ReLU()) + if bottleneck_list[i][3] != 0: + bottleneck.append(nn.Dropout(bottleneck_list[i][3])) + self.bottleneck = nn.Sequential(*bottleneck) + self.fc = nn.Linear(bottleneck_list[-1][0], n_output) + + torch.nn.init.xavier_normal_(self.fc.weight) + else: + self.fc_out = nn.Linear(n_hiddens[-1], self.n_output) + + # 平均值权重 + self.mean_weight = nn.Sequential( + nn.Conv1d(in_channels=2, out_channels=64, kernel_size=5, padding='same'), + nn.BatchNorm1d(64), + nn.ReLU(), + nn.AdaptiveAvgPool1d(2), + nn.Conv1d(in_channels=64, out_channels=64, kernel_size=3, padding='same'), + nn.BatchNorm1d(64), + nn.ReLU(), + nn.AdaptiveAvgPool1d(2), + nn.Flatten(), + nn.Dropout(0.2), + nn.Linear(len_seq // 4 * 64, 64), + nn.BatchNorm1d(64), + nn.ReLU(), + nn.Linear(64, self.n_output) + ) + self.mdw = mdw + # 方差权重 + self.std_weight = nn.Linear(in_features=n_input, out_features=n_hiddens[-1]) + + if self.model_type == 'AdaRNN': + gate = nn.ModuleList() + for i in range(len(n_hiddens)): + gate_weight = nn.Linear( + len_seq * self.hiddens[i] * 2, len_seq) + gate.append(gate_weight) + self.gate = gate + + bnlst = nn.ModuleList() + for i in range(len(n_hiddens)): + bnlst.append(nn.BatchNorm1d(len_seq)) + self.bn_lst = bnlst + self.softmax = torch.nn.Softmax(dim=0) + self.init_layers() + + def init_layers(self): + for i in range(len(self.hiddens)): + self.gate[i].weight.data.normal_(0, 0.05) + self.gate[i].bias.data.fill_(0.0) + + def forward_pre_train(self, x, len_win=0): + # TODO 与原始维度取平均之后加起来 + mean = x[:, :, :].mean(-1) + std = x[:, :, :].std(-1) + hand_feature = torch.stack([mean, std], dim=1) + + + mean = self.mean_weight(hand_feature).squeeze() + + # std = x.std(1) + out = self.gru_features(x) + # 两层GRU之后的结果 + fea = out[0] + + if self.use_bottleneck == True: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + mean*self.mdw + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + mean*self.mdw + # 每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + out_list_all, out_weight_list = out[1], out[2] + # 可以理解为前半段 和 后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + h_start = 0 + for j in range(h_start, self.len_seq, 1): + i_start = max(j - len_win, 0) + i_end = j + len_win if j + len_win < self.len_seq else self.len_seq - 1 + for k in range(i_start, i_end + 1): + weight = out_weight_list[i][j] if self.model_type == 'AdaRNN' else 1 / ( + self.len_seq - h_start) * (2 * len_win + 1) + loss_transfer = loss_transfer + weight * criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, k, :]) + return fc_out, loss_transfer, out_weight_list + + def gru_features(self, x, predict=False): + x_input = x + out = None + out_lis = [] + out_weight_list = [] if ( + self.model_type == 'AdaRNN') else None + for i in range(self.num_layers): + # GRU的输出 + out, _ = self.features[i](x_input.float()) + out = self.dctAttention[i](out.float()) + x_input = out + out_lis.append(out) + if self.model_type == 'AdaRNN' and predict == False: + out_gate = self.process_gate_weight(x_input, i) + out_weight_list.append(out_gate) + # 两层GRU之后的结果,每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + return out, out_lis, out_weight_list + + def process_gate_weight(self, out, index): + x_s = out[0: int(out.shape[0] // 2)] # 可以理解为前一半个batch_size的分布 域Di + x_t = out[out.shape[0] // 2: out.shape[0]] # 可以理解为后一半个batch_size的分布 域Dj + # 对应着不同的域 + x_all = torch.cat((x_s, x_t), 2) + x_all = x_all.view(x_all.shape[0], -1) + weight = torch.sigmoid(self.bn_lst[index]( + self.gate[index](x_all.float()))) + weight = torch.mean(weight, dim=0) + res = self.softmax(weight).squeeze() + return res + + def get_features(self, output_list): + fea_list_src, fea_list_tar = [], [] + for fea in output_list: + fea_list_src.append(fea[0: fea.size(0) // 2]) + fea_list_tar.append(fea[fea.size(0) // 2:]) + return fea_list_src, fea_list_tar + + # For Boosting-based + def forward_Boosting(self, x, weight_mat=None): + # TODO 与原始维度取平均之后加起来 + mean = x[:,:, :].mean(-1) + std = x[:,:, :].std(-1) + hand_feature = torch.stack([mean, std], dim=1) + mean = self.mean_weight(hand_feature).squeeze() + + out = self.gru_features(x) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + mean*self.mdw + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + mean*self.mdw + + out_list_all = out[1] + # 可以理解为前半段和后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + if weight_mat is None: + weight = (1.0 / self.len_seq * + torch.ones(self.num_layers, self.len_seq)) + else: + weight = weight_mat + dist_mat = torch.zeros(self.num_layers, self.len_seq) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + for j in range(self.len_seq): + loss_trans = criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, j, :]) + loss_transfer = loss_transfer + weight[i, j] * loss_trans + dist_mat[i, j] = loss_trans + return fc_out, loss_transfer, dist_mat, weight + + # For Boosting-based + def update_weight_Boosting(self, weight_mat, dist_old, dist_new): + epsilon = 1e-12 + dist_old = dist_old.detach() + dist_new = dist_new.detach() + ind = dist_new > dist_old + epsilon + weight_mat[ind] = weight_mat[ind] * \ + (1 + torch.sigmoid(dist_new[ind] - dist_old[ind])) + weight_norm = torch.norm(weight_mat, dim=1, p=1) + weight_mat = weight_mat / weight_norm.t().unsqueeze(1).repeat(1, self.len_seq) + return weight_mat + + def predict(self, x): + # TODO 与原始维度取平均之后加起来 + x = x.to(torch.float32) + mean = x[:, :, :].mean(-1) + std = x[:, :, :].std(-1) + hand_feature = torch.stack([mean, std], dim=1) + mean = self.mean_weight(hand_feature).squeeze() + + out = self.gru_features(x, predict=True) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + mean*self.mdw + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + mean*self.mdw + + return fc_out + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + y = x.mean(1) + z = x.std(1) + print(y.size()) + print(z.size()) + pass diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/test.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/test.py new file mode 100644 index 0000000..3c8c0c5 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/test.py @@ -0,0 +1,120 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch + +from .dataset_vibrate.loadData import getDataset, getTotalData +from torch.utils.data import DataLoader +from RUL.baseModel.plot import plot_prediction,plot_forSelf +from RUL.baseModel.loss.Evaluate import getEvaluate + + + + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data[-1].unsqueeze(0) + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model.predict(each_predict_data).cpu().detach().numpy() # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + c = each_predict_data[-1, -1, 1:] + a = np.concatenate([each_predict_data[-1, -1, 1:], np.expand_dims(predicted_data, axis=0)], axis=0) + # a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.expand_dims(b, axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, model, is_single=True, is_norm=False, save_fig_name=""): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + # print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = model.predict(data).cpu().detach().numpy() + + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label = np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name,predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/test_wind.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/test_wind.py new file mode 100644 index 0000000..d74fbc2 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/test_wind.py @@ -0,0 +1,114 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from .dataset_wind.loadData import getDataset, getTotalData +from torch.utils.data import DataLoader +from RUL.baseModel.plot import plot_prediction, plot_forSelf +from RUL.baseModel.loss.Evaluate import getEvaluate + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data[-1].unsqueeze(0) + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model.predict(each_predict_data).cpu().detach().numpy() # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + c = each_predict_data[-1, -1, 1:] + a = np.concatenate([each_predict_data[-1, -1, 1:], np.expand_dims(predicted_data, axis=0)], axis=0) + # a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.expand_dims(b, axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, model, is_single=True, is_norm=False, save_fig_name=""): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + # print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(),each_predicted_data)) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label=np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/train.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/train.py new file mode 100644 index 0000000..f3409e9 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/train.py @@ -0,0 +1,480 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np +import random +from tqdm import tqdm +from RUL.otherIdea.adaNHDctLSTM.utils import utils +from RUL.otherIdea.adaNHDctLSTM.model import AdaRNN + +import RUL.otherIdea.adaNHDctLSTM.dataset_vibrate.data_process as data_process +from RUL.baseModel.loss.ffd import fft_mse, dct_mse +from RUL.otherIdea.adaNHDctLSTM.test import test +import matplotlib.pyplot as plt +import time +from RUL.baseModel.CommonFunction import IsStopTraining + +''' +超参数设置: +''' +# 数据准备 +is_norm = False +is_single = True +tdc_loss_type = 'cos' +num_domain = 2 # 划分为几个源域和目标域 + +# RNN相关 +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +predict_num = 200 # 预测个数 +batch_size = 32 +model_name = "AdaRNN" +hidden_list = [64, 64] # 每层RNN的隐藏层的维度 +### bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) +bottleneck = [(64, False, False, 0), (64, True, True, 0.5)] +# bottleneck = [(128, False, True, 0), +# (64, True, True, 0.2), +# (32, True, True, 0.2), +# (16, False, False, 0)] + +# 训练相关 +pre_epoch = 40 +epochs = 1000 +transfer_loss_type = 'cos' # 目前测试cos最好 +dw = 0.5 # 迁移loss权重 +lr = 0.01 +fft_dw = 0.00 # fft_loss权重 整体效果,感觉是让Hard Predict更准了0.01 0.1较好 +mdw = 0.0 # 手工特征权重 整体效果,0.3 0.5比较好 +len_win = 0 # 窗口大小为0,暂时不知道有什么用 +seed = 250 + +# 相关初始化工作 +out_dir = './outputs' +output_path = out_dir + '/{0}_tdc({1})_transfer({2})_domain{3}_dw{4}_fdw{5}_lr{6}_Norm{7}'.format(model_name, + tdc_loss_type, + transfer_loss_type, + num_domain, + dw, fft_dw, lr, + is_norm) +save_model_name = 'parameters/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[ + 0]) + "-" + str( + hidden_list[1])) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +utils.dir_exist(output_path) +utils.dir_exist(os.path.join(output_path, 'parameters')) +utils.dir_exist(os.path.join(output_path, 'fig')) +log_file = os.path.join(output_path, 'run.log') + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if log_file is None: + return + with open(log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + # 经过测试,整体来说,如果加了bottleneck,整体更愿意振动,而不加整体仅存在趋势 + # bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + + return AdaRNN(use_bottleneck=True, bottleneck_list=bottleneck, n_input=feature, n_hiddens=hidden_list, + n_output=1, dropout=0.0, model_type=name, len_seq=hidden_num, + trans_loss=transfer_loss_type, mdw=mdw) + + +def train_AdaRNN(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(len(hidden_list), hidden_num) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + + # 如果训练集域之间的batch_size对不齐就没法计算, + # 为了不抛弃所有样本,这里将选择最小的域batch_size作为本轮的batch_size + min_batch_size = 10000 + for data in data_all: + min_batch_size = min(min_batch_size, data[0].shape[0]) + + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].float(), data[2].float() + list_feat.append(feature[:min_batch_size]) + list_label.append(label_reg[:min_batch_size]) + + index = get_index(len(data_all) - 1) + + loss_mse = torch.zeros(1) + loss_fft = torch.zeros(1) + loss_transfer = torch.zeros(1) + total_loss_l1 = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + # 在batch_size处合并 + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < pre_epoch: + pred_all, each_loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=len_win) + else: + pred_all, each_loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + + lossf_s = dct_mse(pred_s, label_reg_s) + lossf_t = dct_mse(pred_t, label_reg_t) + + loss_l1 = criterion_1(pred_s, label_reg_s) + + loss_mse += loss_s + loss_t + loss_fft += (lossf_s + lossf_t) * fft_dw + loss_transfer += dw * each_loss_transfer + total_loss_l1 += loss_l1 + + total_loss = loss_mse + loss_transfer + loss_fft + loss_all.append([total_loss.item(), loss_mse.item(), loss_transfer.item(), loss_fft.item()]) + loss_1_all.append(total_loss_l1.item()) + + # 反向传播 + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + + if epoch >= pre_epoch: + if epoch > pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def val_epoch(model, val_loader, device, scheduler): + model.eval() + val_loss = 0 + val_loss_1 = 0 + val_loss_r = 0 + + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_continue, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = model.predict(val_data) + + loss = criterion(val_predict_data, val_label) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(val_predict_data, val_label) + val_loss += loss.item() + val_loss_1 += loss_1.item() + val_loss_r += loss_r.item() + + scheduler.step(val_loss) + + loss = val_loss / len(val_loader) + loss_1 = val_loss_1 / len(val_loader) + loss_r = val_loss_r / len(val_loader) + + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(len(hidden_list), hidden_num) + for i in range(weight.shape[0]): + for j in range(weight.shape[1]): + weight[i, j] = init_weight[i][j].item() + return weight + + +def loadData(): + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=batch_size, + number_domain=num_domain, mode='tdc', dis_type=tdc_loss_type + ) + return train_loader_list, valid_loader, test_loader + pass + + +def train(model, train_loader_list, valid_loader, lr_patience, early_stop_patience, device): + optimizer = optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", factor=0.5, + patience=lr_patience) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss, loss1, weight_mat, dist_mat = train_AdaRNN( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + + val_loss, val_loss_l1, val_loss_r = val_epoch( + model, valid_loader, device=device, scheduler=scheduler_model) + + pprint( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_total_loss: {:3.9f} | train_mse_loss: {:3.9f} | train_fft_loss: {:3.9f} | train_transfer_loss: {:3.9f} " + " | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss[0], train_loss[1], train_loss[3], train_loss[2], + val_loss, + optimizer.state_dict()['param_groups'][0]['lr'])) + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + pprint("保存模型最佳模型成功") + best_epoch = epoch + best_score = val_loss + # 保存模型参数 + if best_save_path != None: + utils.delete_file(os.path.join(output_path, best_save_path)) + best_save_path = save_model_name + "_epoch" + str(epoch) + \ + "_trainLoss" + str('%.5f' % train_loss[1]) + \ + "_valLoss" + str('%.5f' % val_loss) + ".pkl" + print(os.path.join(output_path, best_save_path)) + torch.save(model.state_dict(), + os.path.join(output_path, best_save_path)) + + train_loss_list.append(train_loss) + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + pprint("{0}次loss未下降,训练停止".format(early_stop_patience)) + break + + pprint('best val score:', best_score, '@', best_epoch) + return best_save_path + pass + + +def main_transfer(): + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + pprint('create DataLoaders...') + train_loader_list, valid_loader, test_loader = loadData() + + pprint('create AdaRNN model...') + model = get_model(model_name) + + num_model = count_parameters(model) + + print(model) + print('#model params:', num_model) + + pprint('train model...') + best_save_path = train(model=model, train_loader_list=train_loader_list, valid_loader=valid_loader, lr_patience=20, + early_stop_patience=50, device=device) + + end = time.time() + + print("训练耗时:{:3.2f}s".format(end - begin)) + + pprint('验证模型...') + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, best_save_path), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load(os.path.join(output_path, best_save_path), map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm, save_fig_name=os.path.join(output_path, save_fig_name)) + + +def after_test(save_name): + model = get_model(model_name) + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load( + save_name + , map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm) + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=feature) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + + parser.add_argument('--data_mode', type=str, default='tdc') + + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + # 训练与测试 + main_transfer() + + '''事后测试''' + # after_test(save_name="E:\self_example\pytorch_example\RUL\otherIdea/adaNHDctLSTM\outputs\AdaRNN_tdc(cos)_transfer(cos)_domain2_dw0.5_fdw0.1_lr0.01_NormFalse\parameters\seed250_hidden10_feature2_predict50_dimList64-64_epoch18_trainLoss0.03446_valLoss0.01136.pkl") diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/train_wind.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/train_wind.py new file mode 100644 index 0000000..fe53038 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/train_wind.py @@ -0,0 +1,479 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np +import random +from tqdm import tqdm +from RUL.otherIdea.adaNHDctLSTM.utils import utils +from RUL.otherIdea.adaNHDctLSTM.model import AdaRNN + +import RUL.otherIdea.adaNHDctLSTM.dataset_wind.data_process as data_process +from RUL.baseModel.loss.ffd import fft_mse, dct_mse +from RUL.otherIdea.adaNHDctLSTM.test_wind import test +import matplotlib.pyplot as plt +import time +from RUL.baseModel.CommonFunction import IsStopTraining + +''' +超参数设置: +''' +# 数据准备 +is_norm = False +is_single = True +tdc_loss_type = 'cos' +num_domain = 2 # 划分为几个源域和目标域 + +# RNN相关 +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +predict_num = 200 # 预测个数 +batch_size = 32 +model_name = "AdaRNN" +hidden_list = [64, 64] # 每层RNN的隐藏层的维度 +### bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) +bottleneck = [(64, False, False, 0), (64, True, True, 0.5)] +# bottleneck = [(128, False, True, 0), +# (64, True, True, 0.2), +# (32, True, True, 0.2), +# (16, False, False, 0)] + +# 训练相关 +pre_epoch = 40 +epochs = 1000 +transfer_loss_type = 'cos' # 目前测试cos最好 +dw = 0.5 +lr = 0.01 +fft_dw = 0.1 # 整体效果,感觉是让Hard Predict更准了0.01 0.1较好 +len_win = 0 # 窗口大小为0,暂时不知道有什么用 +seed = 250 + +# 相关初始化工作 +out_dir = './outputs/wind' +output_path = out_dir + '/{0}_tdc({1})_transfer({2})_domain{3}_dw{4}_fdw{5}_lr{6}_Norm{7}'.format(model_name, + tdc_loss_type, + transfer_loss_type, + num_domain, + dw, fft_dw, lr, + is_norm) +save_model_name = 'parameters/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[ + 0]) + "-" + str( + hidden_list[1])) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(seed, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +utils.dir_exist(output_path) +utils.dir_exist(os.path.join(output_path, 'parameters')) +utils.dir_exist(os.path.join(output_path, 'fig')) +log_file = os.path.join(output_path, 'run.log') + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if log_file is None: + return + with open(log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + # 经过测试,整体来说,如果加了bottleneck,整体更愿意振动,而不加整体仅存在趋势 + # bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + + return AdaRNN(use_bottleneck=True, bottleneck_list=bottleneck, n_input=feature, n_hiddens=hidden_list, + n_output=1, dropout=0.0, model_type=name, len_seq=hidden_num, + trans_loss=transfer_loss_type) + + +def train_AdaRNN(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(len(hidden_list), hidden_num) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + + # 如果训练集域之间的batch_size对不齐就没法计算, + # 为了不抛弃所有样本,这里将选择最小的域batch_size作为本轮的batch_size + min_batch_size = 10000 + for data in data_all: + min_batch_size = min(min_batch_size, data[0].shape[0]) + + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].float(), data[2].float() + list_feat.append(feature[:min_batch_size]) + list_label.append(label_reg[:min_batch_size]) + + index = get_index(len(data_all) - 1) + + loss_mse = torch.zeros(1) + loss_fft = torch.zeros(1) + loss_transfer = torch.zeros(1) + total_loss_l1 = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + # 在batch_size处合并 + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < pre_epoch: + pred_all, each_loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=len_win) + else: + pred_all, each_loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + + lossf_s = dct_mse(pred_s, label_reg_s) + lossf_t = dct_mse(pred_t, label_reg_t) + + loss_l1 = criterion_1(pred_s, label_reg_s) + + loss_mse += loss_s + loss_t + loss_fft += (lossf_s + lossf_t) * fft_dw + loss_transfer += dw * each_loss_transfer + total_loss_l1 += loss_l1 + + total_loss = loss_mse + loss_transfer + loss_fft + loss_all.append([total_loss.item(), loss_mse.item(), loss_transfer.item(), loss_fft.item()]) + loss_1_all.append(total_loss_l1.item()) + + # 反向传播 + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + + if epoch >= pre_epoch: + if epoch > pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def val_epoch(model, val_loader, device, scheduler): + model.eval() + val_loss = 0 + val_loss_1 = 0 + val_loss_r = 0 + + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_continue, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = model.predict(val_data) + + loss = criterion(val_predict_data, val_label) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(val_predict_data, val_label) + val_loss += loss.item() + val_loss_1 += loss_1.item() + val_loss_r += loss_r.item() + + scheduler.step(val_loss) + + loss = val_loss / len(val_loader) + loss_1 = val_loss_1 / len(val_loader) + loss_r = val_loss_r / len(val_loader) + + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(len(hidden_list), hidden_num) + for i in range(weight.shape[0]): + for j in range(weight.shape[1]): + weight[i, j] = init_weight[i][j].item() + return weight + + +def loadData(): + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=batch_size, + number_domain=num_domain, mode='tdc', dis_type=tdc_loss_type + ) + return train_loader_list, valid_loader, test_loader + pass + + +def train(model, train_loader_list, valid_loader, lr_patience, early_stop_patience, device): + optimizer = optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", factor=0.5, + patience=lr_patience) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss, loss1, weight_mat, dist_mat = train_AdaRNN( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + + val_loss, val_loss_l1, val_loss_r = val_epoch( + model, valid_loader, device=device, scheduler=scheduler_model) + + pprint( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_total_loss: {:3.9f} | train_mse_loss: {:3.9f} | train_fft_loss: {:3.9f} | train_transfer_loss: {:3.9f} " + " | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss[0], train_loss[1], train_loss[3], train_loss[2], + val_loss, + optimizer.state_dict()['param_groups'][0]['lr'])) + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + pprint("保存模型最佳模型成功") + best_epoch = epoch + best_score = val_loss + # 保存模型参数 + if best_save_path != None: + utils.delete_file(os.path.join(output_path, best_save_path)) + best_save_path = save_model_name + "_epoch" + str(epoch) + \ + "_trainLoss" + str('%.5f' % train_loss[1]) + \ + "_valLoss" + str('%.5f' % val_loss) + ".pkl" + print(os.path.join(output_path, best_save_path)) + torch.save(model.state_dict(), + os.path.join(output_path, best_save_path)) + + train_loss_list.append(train_loss) + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + pprint("{0}次loss未下降,训练停止".format(early_stop_patience)) + break + + pprint('best val score:', best_score, '@', best_epoch) + return best_save_path + pass + + +def main_transfer(): + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + pprint('create DataLoaders...') + train_loader_list, valid_loader, test_loader = loadData() + + pprint('create AdaRNN model...') + model = get_model(model_name) + + num_model = count_parameters(model) + + print(model) + print('#model params:', num_model) + + pprint('train model...') + best_save_path = train(model=model, train_loader_list=train_loader_list, valid_loader=valid_loader, lr_patience=20, + early_stop_patience=50, device=device) + + end = time.time() + + print("训练耗时:{:3.2f}s".format(end - begin)) + + pprint('验证模型...') + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, best_save_path), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load(os.path.join(output_path, best_save_path), map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm, save_fig_name=os.path.join(output_path, save_fig_name)) + + +def after_test(save_name): + model = get_model(model_name) + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load( + save_name + , map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm) + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=feature) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + + parser.add_argument('--data_mode', type=str, default='tdc') + + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + # 训练与测试 + # main_transfer() + + '''事后测试''' + after_test(save_name="E:\self_example\pytorch_example\RUL\otherIdea/adaNHDctLSTM\outputs\wind\AdaRNN_tdc(cos)_transfer(cos)_domain2_dw0.5_fdw0.1_lr0.01_NormFalse\parameters\seed250_hidden10_feature2_predict200_dimList64-64_epoch66_trainLoss0.02555_valLoss0.00037.pkl") diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/utils/__init__.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/utils/__init__.py new file mode 100644 index 0000000..4e22673 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/utils/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaNHDctLSTM/utils/utils.py b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/utils/utils.py new file mode 100644 index 0000000..952e555 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaNHDctLSTM/utils/utils.py @@ -0,0 +1,229 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' + +import collections +import torch +import os +import pandas as pd +import torch.nn as nn +from tqdm import tqdm +import numpy as np + +EPS = 1e-12 + + +class AverageMeter(object): + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.list = [] + + def update(self, val, n=1): + self.val = val + self.list.append(val) + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +def average_params(params_list): + assert isinstance(params_list, (tuple, list, collections.deque)) + n = len(params_list) + if n == 1: + return params_list[0] + new_params = collections.OrderedDict() + keys = None + for i, params in enumerate(params_list): + if keys is None: + keys = params.keys() + for k, v in params.items(): + if k not in keys: + raise ValueError('the %d-th model has different params' % i) + if k not in new_params: + new_params[k] = v / n + else: + new_params[k] += v / n + return new_params + + +def zscore(x): + return (x - x.mean(dim=0, keepdim=True)) / x.std(dim=0, keepdim=True, unbiased=False) + + +def calc_loss(pred, label): + return torch.mean((zscore(pred) - label) ** 2) + + +def calc_corr(pred, label): + return (zscore(pred) * zscore(label)).mean() + + +def test_ic(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = label_actual.clone().detach().view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_daily(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values + avg), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for slc in tqdm(data_list[i].iter_daily(), total=data_list[i].daily_length): + feature, label_actual, _, _ = data_list[i].get(slc) + # for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = torch.tensor(label_actual, dtype=torch.float32, device=device).view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_uni(model, data_loader, model_path=None, ic_type='spearman', verbose=False): + if model_path: + model.load_state_dict(torch.load(model_path)) + model.eval() + loss_all = [] + ic_all = [] + for slc in tqdm(data_loader.iter_daily(), total=data_loader.daily_length): + data, label, _, _ = data_loader.get(slc) + with torch.no_grad(): + pred = model.predict(data) + mask = ~torch.isnan(label) + pred = pred[mask] + label = label[mask] + loss = torch.mean(torch.log(torch.cosh(pred - label))) + if ic_type == 'spearman': + ic = spearman_corr(pred, label) + elif ic_type == 'pearson': + ic = pearson_corr(pred, label) + loss_all.append(loss.item()) + ic_all.append(ic) + loss, ic = np.mean(loss_all), np.mean(ic_all) + if verbose: + print('IC: ', ic) + return loss, ic + + +def calc_ic(x, y, ic_type='pearson'): + ic = -100 + if ic_type == 'pearson': + ic = pearson_corr(x, y) + elif ic_type == 'spearman': + ic = spearman_corr(x, y) + return ic + + +def create_dir(path): + if not os.path.exists(path): + os.makedirs(path) + +def delete_file(path): + if os.path.exists(path): + os.remove(path) + + +def handle_nan(x): + mask = ~torch.isnan(x) + return x[mask], mask + + +class Log_Loss(nn.Module): + def __init__(self): + super(Log_Loss, self).__init__() + + def forward(self, ytrue, ypred): + delta = ypred - ytrue + return torch.mean(torch.log(torch.cosh(delta))) + + +def spearman_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='spearman') + return spearman + + +def spearman_corr2(x, y): + X = pd.Series(x) + Y = pd.Series(y) + spearman = X.corr(Y, method='spearman') + return spearman + + +def pearson_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='pearson') + return spearman + + +def dir_exist(dirs): + if not os.path.exists(dirs): + os.makedirs(dirs) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset/PRSA_Data_1.pkl b/pytorch_example/RUL/otherIdea/adaRNN/dataset/PRSA_Data_1.pkl new file mode 100644 index 0000000..937fd13 Binary files /dev/null and b/pytorch_example/RUL/otherIdea/adaRNN/dataset/PRSA_Data_1.pkl differ diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset/__init__.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset/__init__.py new file mode 100644 index 0000000..701f052 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_act.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_act.py new file mode 100644 index 0000000..6b5cdb0 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_act.py @@ -0,0 +1,115 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' +# encoding=utf-8 + +import numpy as np +from torch.utils.data import Dataset, DataLoader + +# from config import config_info + + + +# This is for parsing the X data, you can ignore it if you do not need preprocessing +def format_data_x(datafile): + x_data = None + for item in datafile: + item_data = np.loadtxt(item, dtype=np.float) + if x_data is None: + x_data = np.zeros((len(item_data), 1)) + x_data = np.hstack((x_data, item_data)) + x_data = x_data[:, 1:] + print(x_data.shape) + X = None + for i in range(len(x_data)): + row = np.asarray(x_data[i, :]) + row = row.reshape(9, 128).T + if X is None: + X = np.zeros((len(x_data), 128, 9)) + X[i] = row + print(X.shape) + return X + + +# This is for parsing the Y data, you can ignore it if you do not need preprocessing +def format_data_y(datafile): + data = np.loadtxt(datafile, dtype=np.int) - 1 + YY = np.eye(6)[data] + return YY + + +# Load data function, if there exists parsed data file, then use it +# If not, parse the original dataset from scratch +def load_data(data_folder, domain): + import os + domain = '1_20' if domain == 'A' else '21_30' + data_file = os.path.join(data_folder, 'data_har_' + domain + '.npz') + if os.path.exists(data_file): + data = np.load(data_file) + X_train = data['X_train'] + Y_train = data['Y_train'] + X_test = data['X_test'] + Y_test = data['Y_test'] + else: + # This for processing the dataset from scratch + # After downloading the dataset, put it to somewhere that str_folder can find + str_folder = config_info['data_folder_raw'] + 'UCI HAR Dataset/' + INPUT_SIGNAL_TYPES = [ + "body_acc_x_", + "body_acc_y_", + "body_acc_z_", + "body_gyro_x_", + "body_gyro_y_", + "body_gyro_z_", + "total_acc_x_", + "total_acc_y_", + "total_acc_z_" + ] + + str_train_files = [str_folder + 'train/' + 'Inertial Signals/' + item + 'train.txt' for item in + INPUT_SIGNAL_TYPES] + str_test_files = [str_folder + 'test/' + 'Inertial Signals/' + + item + 'test.txt' for item in INPUT_SIGNAL_TYPES] + str_train_y = str_folder + 'train/y_train.txt' + str_test_y = str_folder + 'test/y_test.txt' + + X_train = format_data_x(str_train_files) + X_test = format_data_x(str_test_files) + Y_train = format_data_y(str_train_y) + Y_test = format_data_y(str_test_y) + + return X_train, onehot_to_label(Y_train), X_test, onehot_to_label(Y_test) + + +def onehot_to_label(y_onehot): + a = np.argwhere(y_onehot == 1) + return a[:, -1] + + +class data_loader(Dataset): + def __init__(self, samples, labels, t): + self.samples = samples + self.labels = labels + self.T = t + + def __getitem__(self, index): + sample, target = self.samples[index], self.labels[index] + if self.T: + return self.T(sample), target + else: + return sample, target + + def __len__(self): + return len(self.samples) + + +def normalize(x): + x_min = x.min(axis=(0, 2, 3), keepdims=True) + x_max = x.max(axis=(0, 2, 3), keepdims=True) + x_norm = (x - x_min) / (x_max - x_min) + return x_norm \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_process.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_process.py new file mode 100644 index 0000000..130fd73 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_process.py @@ -0,0 +1,148 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 +import os +import RUL.otherIdea.adaRNN.dataset.data_act as data_act +import pandas as pd +import RUL.otherIdea.adaRNN.dataset.data_weather as data_weather +import datetime +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +import torch +import math +from RUL.otherIdea.adaRNN.dataset import data_process + + +def load_act_data(data_folder, batch_size=64, domain="1_20"): + x_train, y_train, x_test, y_test = data_act.load_data(data_folder, domain) + x_train, x_test = x_train.reshape( + (-1, x_train.shape[2], 1, x_train.shape[1])), x_test.reshape((-1, x_train.shape[2], 1, x_train.shape[1])) + transform = None + train_set = data_act.data_loader(x_train, y_train, transform) + test_set = data_act.data_loader(x_test, y_test, transform) + train_loader = data_act.DataLoader( + train_set, batch_size=batch_size, shuffle=True, drop_last=True) + test_loader = data_act.DataLoader( + test_set, batch_size=batch_size, shuffle=False) + return train_loader, train_loader, test_loader + + +def load_weather_data(file_path, batch_size=6, station='Changping'): + data_file = os.path.join(file_path, "PRSA_Data_1.pkl") + mean_train, std_train = data_weather.get_weather_data_statistic(data_file, station=station, + start_time='2013-3-1 0:0', + end_time='2016-10-30 23:0') + train_loader = data_weather.get_weather_data(data_file, station=station, start_time='2013-3-6 0:0', + end_time='2015-5-31 23:0', batch_size=batch_size, mean=mean_train, + std=std_train) + valid_train_loader = data_weather.get_weather_data(data_file, station=station, start_time='2015-6-2 0:0', + end_time='2016-6-30 23:0', batch_size=batch_size, + mean=mean_train, std=std_train) + valid_vld_loader = data_weather.get_weather_data(data_file, station=station, start_time='2016-7-2 0:0', + end_time='2016-10-30 23:0', batch_size=batch_size, mean=mean_train, + std=std_train) + test_loader = data_weather.get_weather_data(data_file, station=station, start_time='2016-11-2 0:0', + end_time='2017-2-28 23:0', batch_size=batch_size, mean=mean_train, + std=std_train) + return train_loader, valid_train_loader, valid_vld_loader, test_loader + + +def get_split_time(num_domain=2, mode='pre_process', data_file=None, station=None, dis_type='coral'): + spilt_time = { + '2': [('2013-3-6 0:0', '2015-5-31 23:0'), ('2015-6-2 0:0', '2016-6-30 23:0')] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data_file, station, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data_file, station, dis_type='coral'): + start_time = datetime.datetime.strptime( + '2013-03-01 00:00:00', '%Y-%m-%d %H:%M:%S') + end_time = datetime.datetime.strptime( + '2016-06-30 23:00:00', '%Y-%m-%d %H:%M:%S') + num_day = (end_time - start_time).days + split_N = 10 + data = pd.read_pickle(data_file)[station] + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + # num_day_new = feat.shape[0] + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_time = start_time + datetime.timedelta(days=int(num_day / split_N * selected[i - 1]), hours=0) + else: + sel_start_time = start_time + datetime.timedelta(days=int(num_day / split_N * selected[i - 1]) + 1, + hours=0) + sel_end_time = start_time + datetime.timedelta(days=int(num_day / split_N * selected[i]), hours=23) + sel_start_time = datetime.datetime.strftime(sel_start_time, '%Y-%m-%d %H:%M') + sel_end_time = datetime.datetime.strftime(sel_end_time, '%Y-%m-%d %H:%M') + res.append((sel_start_time, sel_end_time)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(file_path, batch_size=6, station='Changping', number_domain=2, mode='pre_process', + dis_type='coral'): + # mode: 'tdc', 'pre_process' + data_file = os.path.join(file_path, "PRSA_Data_1.pkl") + mean_train, std_train = data_weather.get_weather_data_statistic(data_file, station=station, + start_time='2013-3-1 0:0', + end_time='2016-10-30 23:0') + split_time_list = get_split_time(number_domain, mode=mode, data_file=data_file, station=station, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + time_temp = split_time_list[i] + train_loader = data_weather.get_weather_data(data_file, station=station, start_time=time_temp[0], + end_time=time_temp[1], batch_size=batch_size, mean=mean_train, + std=std_train) + train_list.append(train_loader) + + valid_vld_loader = data_weather.get_weather_data(data_file, station=station, start_time='2016-7-2 0:0', + end_time='2016-10-30 23:0', batch_size=batch_size, mean=mean_train, + std=std_train) + test_loader = data_weather.get_weather_data(data_file, station=station, start_time='2016-11-2 0:0', + end_time='2017-2-28 23:0', batch_size=batch_size, mean=mean_train, + std=std_train, shuffle=False) + return train_list, valid_vld_loader, test_loader diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_weather.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_weather.py new file mode 100644 index 0000000..3b8d5d2 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset/data_weather.py @@ -0,0 +1,141 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + +import math +import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +import os +from pandas.core.frame import DataFrame +from torch.utils.data import Dataset, DataLoader +import torch +import pickle +import datetime + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(df, station, start_date, end_date, mean=None, std=None): + data = df[station] + feat, label, label_reg = data[0], data[1], data[2] + referece_start_time = datetime.datetime(2013, 3, 1, 0, 0) + referece_end_time = datetime.datetime(2017, 2, 28, 0, 0) + + assert (pd.to_datetime(start_date) - referece_start_time).days >= 0 + assert (pd.to_datetime(end_date) - referece_end_time).days <= 0 + assert (pd.to_datetime(end_date) - pd.to_datetime(start_date)).days >= 0 + index_start = (pd.to_datetime(start_date) - referece_start_time).days + index_end = (pd.to_datetime(end_date) - referece_start_time).days + feat = feat[index_start: index_end + 1] + label = label[index_start: index_end + 1] + label_reg = label_reg[index_start: index_end + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def create_dataset_shallow(df, station, start_date, end_date, mean=None, std=None): + data = df[station] + feat, label, label_reg = data[0], data[1], data[2] + referece_start_time = datetime.datetime(2013, 3, 1, 0, 0) + referece_end_time = datetime.datetime(2017, 2, 28, 0, 0) + + assert (pd.to_datetime(start_date) - referece_start_time).days >= 0 + assert (pd.to_datetime(end_date) - referece_end_time).days <= 0 + assert (pd.to_datetime(end_date) - pd.to_datetime(start_date)).days >= 0 + index_start = (pd.to_datetime(start_date) - referece_start_time).days + index_end = (pd.to_datetime(end_date) - referece_start_time).days + feat = feat[index_start: index_end + 1] + label = label[index_start: index_end + 1] + label_reg = label_reg[index_start: index_end + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return feat, label_reg + + +def get_dataset_statistic(df, station, start_date, end_date): + data = df[station] + feat, label = data[0], data[1] + referece_start_time = datetime.datetime(2013, 3, 1, 0, 0) + referece_end_time = datetime.datetime(2017, 2, 28, 0, 0) + + assert (pd.to_datetime(start_date) - referece_start_time).days >= 0 + assert (pd.to_datetime(end_date) - referece_end_time).days <= 0 + assert (pd.to_datetime(end_date) - pd.to_datetime(start_date)).days >= 0 + index_start = (pd.to_datetime(start_date) - referece_start_time).days + index_end = (pd.to_datetime(end_date) - referece_start_time).days + feat = feat[index_start: index_end + 1] + label = label[index_start: index_end + 1] + feat = feat.reshape(-1, feat.shape[2]) + mu_train = np.mean(feat, axis=0) + sigma_train = np.std(feat, axis=0) + + return mu_train, sigma_train + + +def get_weather_data(data_file, station, start_time, end_time, batch_size, shuffle=True, mean=None, std=None): + df = pd.read_pickle(data_file) + + dataset = create_dataset(df, station, start_time, + end_time, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader + + +def get_weather_data_shallow(data_file, station, start_time, end_time, batch_size, shuffle=True, mean=None, std=None): + df = pd.read_pickle(data_file) + + feat, label_reg = create_dataset_shallow(df, station, start_time, + end_time, mean=mean, std=std) + + return feat, label_reg + + +def get_weather_data_statistic(data_file, station, start_time, end_time): + df = pd.read_pickle(data_file) + mean_train, std_train = get_dataset_statistic( + df, station, start_time, end_time) + return mean_train, std_train diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset/watchData.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset/watchData.py new file mode 100644 index 0000000..054f338 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset/watchData.py @@ -0,0 +1,26 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 14:53 +@Usage : +@Desc : +''' + +import pandas as pd + +data_file = 'G:\data\北京多站点空气质量数据集\PRSA_Data_1.pkl' +data = pd.read_pickle(data_file)['Tiantan'] + +feature, label, label_reg = data +print(data) + +import matplotlib.pyplot as plt + + +# plt.subplot(2,1,1) +# plt.plot(feature) +plt.subplot(2,1,2) + +plt.plot(label_reg) +plt.show() diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/__init__.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/__init__.py new file mode 100644 index 0000000..3e48d01 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/16 19:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/data_process.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/data_process.py new file mode 100644 index 0000000..44df906 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/data_process.py @@ -0,0 +1,111 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:35 +@Usage : +@Desc : +''' +# encoding=utf-8 + +import RUL.otherIdea.adaRNN.dataset_vibrate.data_vibrate as data_vibrate +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +from RUL.otherIdea.adaRNN.dataset_vibrate.loadData import getVibrate_data + +import torch +import math + + +def get_split_time(num_domain=2, mode='pre_process', data=None, dis_type='coral'): + spilt_time = { + '2': [(0, 600), (600, 1200)] + } + if mode == 'pre_process': + return spilt_time[str(num_domain)] + if mode == 'tdc': + return TDC(num_domain, data, dis_type=dis_type) + else: + print("error in mode") + + +def TDC(num_domain, data, dis_type='coral'): + # 样本个数 + num_day = len(data[0]) + + split_N = 10 + feat = data[0][0:num_day] + feat = torch.tensor(feat, dtype=torch.float32) + feat_shape_1 = feat.shape[1] # 时间部 + + feat = feat.reshape(-1, feat.shape[2]) + feat = feat + + selected = [0, 10] + candidate = [1, 2, 3, 4, 5, 6, 7, 8, 9] + start = 0 + + if num_domain in [2, 3, 5, 7, 10]: + while len(selected) - 2 < num_domain - 1: + distance_list = [] + for can in candidate: + selected.append(can) + selected.sort() + dis_temp = 0 + for i in range(1, len(selected) - 1): + for j in range(i, len(selected) - 1): + index_part1_start = start + math.floor(selected[i - 1] / split_N * num_day) * feat_shape_1 + index_part1_end = start + math.floor(selected[i] / split_N * num_day) * feat_shape_1 + feat_part1 = feat[index_part1_start: index_part1_end] + + index_part2_start = start + math.floor(selected[j] / split_N * num_day) * feat_shape_1 + index_part2_end = start + math.floor(selected[j + 1] / split_N * num_day) * feat_shape_1 + feat_part2 = feat[index_part2_start:index_part2_end] + criterion_transder = TransferLoss(loss_type=dis_type, input_dim=feat_part1.shape[1]) + dis_temp += criterion_transder.compute(feat_part1, feat_part2) + distance_list.append(dis_temp) + selected.remove(can) + can_index = distance_list.index(max(distance_list)) + selected.append(candidate[can_index]) + candidate.remove(candidate[can_index]) + selected.sort() + res = [] + for i in range(1, len(selected)): + if i == 1: + sel_start_index = int(num_day / split_N * selected[i - 1]) + else: + sel_start_index = int(num_day / split_N * selected[i - 1]) + 1 + + sel_end_index = int(num_day / split_N * selected[i]) + + res.append((sel_start_index, sel_end_index)) + return res + else: + print("error in number of domain") + + +def load_weather_data_multi_domain(hidden_num, feature, predict_num, batch_size=6, number_domain=2, mode='pre_process', + dis_type='coral', is_norm=False): + # mode: 'tdc', 'pre_process' + train_data, val_data = getVibrate_data(hidden_num=hidden_num, feature=feature, predict_num=predict_num, + is_norm=is_norm) + + split_time_list = get_split_time(number_domain, mode=mode, data=train_data, dis_type=dis_type) + train_list = [] + for i in range(len(split_time_list)): + index_temp = split_time_list[i] + train_loader = data_vibrate.get_vibrate_data(train_data, start_index=index_temp[0], + end_index=index_temp[1], batch_size=batch_size) + train_list.append(train_loader) + + valid_loader = data_vibrate.get_vibrate_data(val_data, start_index=0, + end_index=len(val_data[0]), batch_size=batch_size, mean=None, + std=None, shuffle=False) + test_loader = valid_loader + + return train_list, valid_loader, test_loader + + +if __name__ == '__main__': + load_weather_data_multi_domain(hidden_num=10, feature=10, predict_num=50, batch_size=32, number_domain=2, + mode='tdc', + dis_type='coral', is_norm=False) diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/data_vibrate.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/data_vibrate.py new file mode 100644 index 0000000..daded1e --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/data_vibrate.py @@ -0,0 +1,72 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:36 +@Usage : +@Desc : +''' + + +from torch.utils.data import Dataset, DataLoader +import torch + + + +class data_loader(Dataset): + def __init__(self, df_feature, df_label, df_label_reg, t=None): + + assert len(df_feature) == len(df_label) + assert len(df_feature) == len(df_label_reg) + + # df_feature = df_feature.reshape(df_feature.shape[0], df_feature.shape[1] // 6, df_feature.shape[2] * 6) + self.df_feature = df_feature + self.df_label = df_label + self.df_label_reg = df_label_reg + + self.T = t + self.df_feature = torch.tensor( + self.df_feature, dtype=torch.float32) + self.df_label = torch.tensor( + self.df_label, dtype=torch.float32) + self.df_label_reg = torch.tensor( + self.df_label_reg, dtype=torch.float32) + + def __getitem__(self, index): + sample, target, label_reg = self.df_feature[index], self.df_label[index], self.df_label_reg[index] + if self.T: + return self.T(sample), target, label_reg + else: + return sample, target, label_reg + + def __len__(self): + return len(self.df_feature) + + +def create_dataset(data, start_index, end_index, mean=None, std=None): + feat, label_continue, label_single = data[0], data[1], data[2] + referece_start_index = 0 + referece_end_index = 1250 + + assert start_index - referece_start_index >= 0 + assert end_index - referece_end_index <= 0 + assert end_index - start_index >= 0 + + feat = feat[start_index: end_index + 1] + label = label_continue[start_index: end_index + 1] + label_reg = label_single[start_index: end_index + 1] + + # ori_shape_1, ori_shape_2=feat.shape[1], feat.shape[2] + # feat=feat.reshape(-1, feat.shape[2]) + # feat=(feat - mean) / std + # feat=feat.reshape(-1, ori_shape_1, ori_shape_2) + + return data_loader(feat, label, label_reg) + + +def get_vibrate_data(data, start_index, end_index, batch_size, shuffle=True, mean=None, std=None): + dataset = create_dataset(data, start_index, + end_index, mean=mean, std=std) + train_loader = DataLoader( + dataset, batch_size=batch_size, shuffle=shuffle) + return train_loader diff --git a/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/loadData.py b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/loadData.py new file mode 100644 index 0000000..dd3fa37 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/dataset_vibrate/loadData.py @@ -0,0 +1,150 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("E:\self_example\pytorch_example\RUL\dataset\HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + # HI_merge_data = np.loadtxt("E:\self_example\pytorch_example\RUL\dataset\smallVHI.csv", delimiter=",") + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset + + +def getVibrate_data(hidden_num, feature, predict_num, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + + + + return [train_data,train_label,train_label_single],[val_data,val_label,val_label_single] diff --git a/pytorch_example/RUL/otherIdea/adaRNN/loss_transfer.py b/pytorch_example/RUL/otherIdea/adaRNN/loss_transfer.py new file mode 100644 index 0000000..7e2798d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/loss_transfer.py @@ -0,0 +1,64 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:45 +@Usage : +@Desc : +''' +from RUL.baseModel.loss import adv_loss, coral, kl_js, mmd, mutual_info, cos, pair_dist + + +class TransferLoss(object): + def __init__(self, loss_type='cosine', input_dim=512): + """ + Supported loss_type: mmd(mmd_lin), mmd_rbf, coral, cosine, kl, js, mine, adv + """ + self.loss_type = loss_type + self.input_dim = input_dim + + def compute(self, X, Y): + """Compute adaptation loss + + Arguments: + X {tensor} -- source matrix + Y {tensor} -- target matrix + + Returns: + [tensor] -- transfer loss + """ + if self.loss_type == 'mmd_lin' or self.loss_type == 'mmd': + mmdloss = mmd.MMD_loss(kernel_type='linear') + loss = mmdloss(X, Y) + elif self.loss_type == 'coral': + loss = coral.CORAL(X, Y) + elif self.loss_type == 'cosine' or self.loss_type == 'cos': + loss = 1 - cos.cosine(X, Y) + elif self.loss_type == 'kl': + loss = kl_js.kl_div(X, Y) + elif self.loss_type == 'js': + loss = kl_js.js(X, Y) + elif self.loss_type == 'mine': + mine_model = mutual_info.Mine_estimator( + input_dim=self.input_dim, hidden_dim=60) + loss = mine_model(X, Y) + elif self.loss_type == 'adv': + loss = adv_loss.adv(X, Y, input_dim=self.input_dim, hidden_dim=32) + elif self.loss_type == 'mmd_rbf': + mmdloss = mmd.MMD_loss(kernel_type='rbf') + loss = mmdloss(X, Y) + elif self.loss_type == 'pairwise': + pair_mat = pair_dist.pairwise_dist(X, Y) + import torch + loss = torch.norm(pair_mat) + + return loss + + +if __name__ == "__main__": + import torch + + trans_loss = TransferLoss('adv') + a = (torch.randn(5, 512) * 10) + b = (torch.randn(5, 512) * 10) + print(trans_loss.compute(a, b)) diff --git a/pytorch_example/RUL/otherIdea/adaRNN/model.py b/pytorch_example/RUL/otherIdea/adaRNN/model.py new file mode 100644 index 0000000..1889d6d --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/model.py @@ -0,0 +1,208 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 14:44 +@Usage : +@Desc : +''' +import torch +import torch.nn as nn +from RUL.otherIdea.adaRNN.loss_transfer import TransferLoss +import torch.nn.functional as F + + +class AdaRNN(nn.Module): + """ + model_type: 'Boosting', 'AdaRNN' + bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + """ + + def __init__(self, use_bottleneck=False, bottleneck_list=[(64,False,False,0),(64,True,True,0.5)], n_input=128, n_hiddens=[64, 64], n_output=6, + dropout=0.0, len_seq=9, model_type='AdaRNN', + trans_loss='mmd'): + super(AdaRNN, self).__init__() + self.use_bottleneck = use_bottleneck + self.n_input = n_input + self.num_layers = len(n_hiddens) + self.hiddens = n_hiddens + self.n_output = n_output + self.model_type = model_type + self.trans_loss = trans_loss + self.len_seq = len_seq + in_size = self.n_input + + features = nn.ModuleList() + for hidden in n_hiddens: + rnn = nn.GRU( + input_size=in_size, + num_layers=1, + hidden_size=hidden, + batch_first=True, + dropout=dropout + ) + features.append(rnn) + in_size = hidden + self.features = nn.Sequential(*features) + + if use_bottleneck == True: # finance + bottleneck =[] + for i in range(len(bottleneck_list)): + cur_input_dim = self.hiddens[-1] if i == 0 else bottleneck_list[i - 1][0] + bottleneck.append( + nn.Linear(cur_input_dim, bottleneck_list[i][0]) + ) + bottleneck[-1].weight.data.normal_(0, 0.05) + bottleneck[-1].bias.data.fill_(0.1) + if bottleneck_list[i][1]: + bottleneck.append(nn.BatchNorm1d(bottleneck_list[i][0])) + if bottleneck_list[i][2]: + bottleneck.append(nn.ReLU()) + if bottleneck_list[i][3] != 0: + bottleneck.append(nn.Dropout(bottleneck_list[i][3])) + self.bottleneck = nn.Sequential(*bottleneck) + self.fc = nn.Linear(bottleneck_list[-1][0], n_output) + + torch.nn.init.xavier_normal_(self.fc.weight) + else: + self.fc_out = nn.Linear(n_hiddens[-1], self.n_output) + + if self.model_type == 'AdaRNN': + gate = nn.ModuleList() + for i in range(len(n_hiddens)): + gate_weight = nn.Linear( + len_seq * self.hiddens[i] * 2, len_seq) + gate.append(gate_weight) + self.gate = gate + + bnlst = nn.ModuleList() + for i in range(len(n_hiddens)): + bnlst.append(nn.BatchNorm1d(len_seq)) + self.bn_lst = bnlst + self.softmax = torch.nn.Softmax(dim=0) + self.init_layers() + + def init_layers(self): + for i in range(len(self.hiddens)): + self.gate[i].weight.data.normal_(0, 0.05) + self.gate[i].bias.data.fill_(0.0) + + def forward_pre_train(self, x, len_win=0): + out = self.gru_features(x) + # 两层GRU之后的结果 + fea = out[0] + + if self.use_bottleneck == True: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + # 每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + out_list_all, out_weight_list = out[1], out[2] + # 可以理解为前半段 和 后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + h_start = 0 + for j in range(h_start, self.len_seq, 1): + i_start = max(j - len_win, 0) + i_end = j + len_win if j + len_win < self.len_seq else self.len_seq - 1 + for k in range(i_start, i_end + 1): + weight = out_weight_list[i][j] if self.model_type == 'AdaRNN' else 1 / ( + self.len_seq - h_start) * (2 * len_win + 1) + loss_transfer = loss_transfer + weight * criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, k, :]) + return fc_out, loss_transfer, out_weight_list + + def gru_features(self, x, predict=False): + x_input = x + out = None + out_lis = [] + out_weight_list = [] if ( + self.model_type == 'AdaRNN') else None + for i in range(self.num_layers): + # GRU的输出 + out, _ = self.features[i](x_input.float()) + x_input = out + out_lis.append(out) + if self.model_type == 'AdaRNN' and predict == False: + out_gate = self.process_gate_weight(x_input, i) + out_weight_list.append(out_gate) + # 两层GRU之后的结果,每层GRU之后的结果,每层GRU前后权重归一化之后的结果 + return out, out_lis, out_weight_list + + def process_gate_weight(self, out, index): + x_s = out[0: int(out.shape[0] // 2)] # 可以理解为前一半个batch_size的分布 域Di + x_t = out[out.shape[0] // 2: out.shape[0]] # 可以理解为后一半个batch_size的分布 域Dj + # 对应着不同的域 + x_all = torch.cat((x_s, x_t), 2) + x_all = x_all.view(x_all.shape[0], -1) + weight = torch.sigmoid(self.bn_lst[index]( + self.gate[index](x_all.float()))) + weight = torch.mean(weight, dim=0) + res = self.softmax(weight).squeeze() + return res + + def get_features(self, output_list): + fea_list_src, fea_list_tar = [], [] + for fea in output_list: + fea_list_src.append(fea[0: fea.size(0) // 2]) + fea_list_tar.append(fea[fea.size(0) // 2:]) + return fea_list_src, fea_list_tar + + # For Boosting-based + def forward_Boosting(self, x, weight_mat=None): + out = self.gru_features(x) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + + out_list_all = out[1] + # 可以理解为前半段和后半段 + out_list_s, out_list_t = self.get_features(out_list_all) + loss_transfer = torch.zeros((1,)) + if weight_mat is None: + weight = (1.0 / self.len_seq * + torch.ones(self.num_layers, self.len_seq)) + else: + weight = weight_mat + dist_mat = torch.zeros(self.num_layers, self.len_seq) + for i in range(len(out_list_s)): + criterion_transder = TransferLoss( + loss_type=self.trans_loss, input_dim=out_list_s[i].shape[2]) + for j in range(self.len_seq): + loss_trans = criterion_transder.compute( + out_list_s[i][:, j, :], out_list_t[i][:, j, :]) + loss_transfer = loss_transfer + weight[i, j] * loss_trans + dist_mat[i, j] = loss_trans + return fc_out, loss_transfer, dist_mat, weight + + # For Boosting-based + def update_weight_Boosting(self, weight_mat, dist_old, dist_new): + epsilon = 1e-12 + dist_old = dist_old.detach() + dist_new = dist_new.detach() + ind = dist_new > dist_old + epsilon + weight_mat[ind] = weight_mat[ind] * \ + (1 + torch.sigmoid(dist_new[ind] - dist_old[ind])) + weight_norm = torch.norm(weight_mat, dim=1, p=1) + weight_mat = weight_mat / weight_norm.t().unsqueeze(1).repeat(1, self.len_seq) + return weight_mat + + def predict(self, x): + out = self.gru_features(x, predict=True) + fea = out[0] + + if self.use_bottleneck: + fea_bottleneck = self.bottleneck(fea[:, -1, :]) + fc_out = self.fc(fea_bottleneck).squeeze() + else: + fc_out = self.fc_out(fea[:, -1, :]).squeeze() + + return fc_out diff --git a/pytorch_example/RUL/otherIdea/adaRNN/test.py b/pytorch_example/RUL/otherIdea/adaRNN/test.py new file mode 100644 index 0000000..47b6626 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/test.py @@ -0,0 +1,117 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.LSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctLSTM.model import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +from RUL.baseModel.plot import plot_forSelf,plot_prediction +from RUL.baseModel.loss.Evaluate import getEvaluate + + + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data[-1].unsqueeze(0) + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model.predict(each_predict_data).cpu().detach().numpy() # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + c = each_predict_data[-1, -1, 1:] + a = np.concatenate([each_predict_data[-1, -1, 1:], np.expand_dims(predicted_data, axis=0)], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.expand_dims(b, axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, model, is_single=True, is_norm=False, save_fig_name=""): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = model.predict(data).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label = np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/adaRNN/train.py b/pytorch_example/RUL/otherIdea/adaRNN/train.py new file mode 100644 index 0000000..5a829c0 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/train.py @@ -0,0 +1,467 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np +import random +from tqdm import tqdm +import RUL.baseModel.utils.utils as utils +from RUL.otherIdea.adaRNN.model import AdaRNN + +import RUL.otherIdea.adaRNN.dataset_vibrate.data_process as data_process +from RUL.otherIdea.adaRNN.test import test +import matplotlib.pyplot as plt +import time +from RUL.baseModel.CommonFunction import IsStopTraining + +''' +超参数设置: +''' +# 数据准备 +is_norm = False +is_single = True +tdc_loss_type = 'cos' +num_domain = 2 # 划分为几个源域和目标域 + +# RNN相关 +hidden_num = 10 # LSTM细胞个数 +feature = 2 # 一个点的维度 +predict_num = 200 # 预测个数 +batch_size = 32 +model_name = "AdaRNN" +hidden_list = [64, 64] # 每层RNN的隐藏层的维度 +bottleneck = [(64, False, False, 0), (64, True, True, 0.5)] +# bottleneck = [(128, False, True, 0), +# (64, True, True, 0.2), +# (32, True, True, 0.2), +# (16, False, False, 0)] + +# 训练相关 +pre_epoch = 40 +epochs = 1000 +transfer_loss_type = 'cos' +dw = 0.5 +lr = 0.01 +len_win = 0 # 窗口大小,为0,暂时不知道有什么用 +seed = 5 + +# 相关初始化工作 +out_dir = './outputs' +output_path = out_dir + '/{0}_tdcLoss({1})_transferLoss({2})_domain{3}_dw{4}_lr{5}'.format(model_name, tdc_loss_type, + transfer_loss_type, + num_domain, + dw, lr) +save_model_name = 'parameters/{0}_hidden{1}_feature{2}_predict{3}_dimList{4}'.format(model_name, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +save_fig_name = 'fig/{0}_hidden{1}_feature{2}_predict{3}_dimList{4}.png'.format(model_name, hidden_num, + feature, + predict_num, + str(hidden_list[0]) + "-" + str( + hidden_list[1])) +utils.dir_exist(output_path) +utils.dir_exist(os.path.join(output_path, 'parameters')) +utils.dir_exist(os.path.join(output_path, 'fig')) +log_file = os.path.join(output_path, 'run.log') + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if log_file is None: + return + with open(log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + # 经过测试,整体来说,如果加了bottleneck,整体更愿意振动,而不加整体仅存在趋势 + # bottleneck_list: (dim,is_BatchNorm,is_ReLu,drop_out) + + return AdaRNN(use_bottleneck=True, bottleneck_list=bottleneck, n_input=feature, n_hiddens=hidden_list, + n_output=1, dropout=0.0, model_type=name, len_seq=hidden_num, + trans_loss=transfer_loss_type) + + +def train_AdaRNN(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(len(hidden_list), hidden_num) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + + # 如果训练集域之间的batch_size对不齐就没法计算, + # 为了不抛弃所有样本,这里将选择最小的域batch_size作为本轮的batch_size + min_batch_size = 10000 + for data in data_all: + min_batch_size = min(min_batch_size, data[0].shape[0]) + + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].float(), data[2].float() + list_feat.append(feature[:min_batch_size]) + list_label.append(label_reg[:min_batch_size]) + + index = get_index(len(data_all) - 1) + + loss_mse = torch.zeros(1) + loss_transfer = torch.zeros(1) + total_loss_l1 = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + # 在batch_size处合并 + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < pre_epoch: + pred_all, each_loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=len_win) + else: + pred_all, each_loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + loss_l1 = criterion_1(pred_s, label_reg_s) + + loss_mse += loss_s + loss_t + loss_transfer += dw * each_loss_transfer + total_loss_l1 += loss_l1 + + total_loss = loss_mse + loss_transfer + loss_all.append([total_loss.item(), loss_mse.item(), loss_transfer.item()]) + loss_1_all.append(total_loss_l1.item()) + + # 反向传播 + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + + if epoch >= pre_epoch: + if epoch > pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def val_epoch(model, val_loader, device, scheduler): + model.eval() + val_loss = 0 + val_loss_1 = 0 + val_loss_r = 0 + + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_continue, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = model.predict(val_data) + + loss = criterion(val_predict_data, val_label) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(val_predict_data, val_label) + val_loss += loss.item() + val_loss_1 += loss_1.item() + val_loss_r += loss_r.item() + + # scheduler.step(val_loss) + + loss = val_loss / len(val_loader) + loss_1 = val_loss_1 / len(val_loader) + loss_r = val_loss_r / len(val_loader) + + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(len(hidden_list), hidden_num) + for i in range(weight.shape[0]): + for j in range(weight.shape[1]): + weight[i, j] = init_weight[i][j].item() + return weight + + +def loadData(): + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=batch_size, + number_domain=num_domain, mode='tdc', dis_type=tdc_loss_type + ) + return train_loader_list, valid_loader, test_loader + pass + + +def train(model, train_loader_list, valid_loader, lr_patience, early_stop_patience, device): + optimizer = optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer, mode="min", factor=0.2, + patience=lr_patience) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss, loss1, weight_mat, dist_mat = train_AdaRNN( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + + val_loss, val_loss_l1, val_loss_r = val_epoch( + model, valid_loader, device=device, scheduler=scheduler_model) + + pprint( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_total_loss: {:3.9f} | train_mse_loss: {:3.9f} | train_transfer_loss: {:3.9f} " + " | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss[0], train_loss[1], train_loss[2], + val_loss, + optimizer.state_dict()['param_groups'][0]['lr'])) + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + pprint("保存模型最佳模型成功") + best_epoch = epoch + best_score = val_loss + # 保存模型参数 + if best_save_path != None: + utils.delete_file(best_save_path) + best_save_path = save_model_name + "_epoch" + str(epoch) + \ + "_trainLoss" + str(train_loss[1]) + \ + "_valLoss" + str(val_loss) + ".pkl" + print(os.path.join(output_path, best_save_path)) + torch.save(model.state_dict(), + os.path.join(output_path, best_save_path)) + + train_loss_list.append(train_loss) + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + pprint("{0}次loss未下降,训练停止".format(early_stop_patience)) + break + + pprint('best val score:', best_score, '@', best_epoch) + return best_save_path + pass + + +def main_transfer(): + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + pprint('create DataLoaders...') + train_loader_list, valid_loader, test_loader = loadData() + + pprint('create AdaRNN model...') + model = get_model(model_name) + + num_model = count_parameters(model) + + print(model) + print('#model params:', num_model) + + pprint('train model...') + best_save_path = train(model=model, train_loader_list=train_loader_list, valid_loader=valid_loader, lr_patience=20, + early_stop_patience=50, device=device) + + end = time.time() + + print("训练耗时:{:3.2f}s".format(end - begin)) + + pprint('验证模型...') + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, best_save_path), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load(os.path.join(output_path, best_save_path), map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm, save_fig_name=os.path.join(output_path, save_fig_name)) + + +def after_test(save_name): + model = get_model(model_name) + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + + model.load_state_dict(torch.load( + save_name + , map_location=device)) + + test(hidden_num=hidden_num, feature=feature, predict_num=predict_num, batch_size=batch_size, model=model, + is_single=is_single, is_norm=is_norm) + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=feature) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + + parser.add_argument('--data_mode', type=str, default='tdc') + + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + # 训练与测试 + main_transfer() + + '''事后测试''' + # after_test(save_name="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\outputs\AdaRNN_tdcLoss(cos)_transferLoss(cos)_domain2_dw0.5_lr0.0005\parameters\AdaRNN_hidden24_feature10_predict50_dimList64-64_epoch62_trainLoss0.5115623474121094_valLoss0.12946119904518127.pkl") diff --git a/pytorch_example/RUL/otherIdea/adaRNN/train_vibrate.py b/pytorch_example/RUL/otherIdea/adaRNN/train_vibrate.py new file mode 100644 index 0000000..994f340 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/train_vibrate.py @@ -0,0 +1,423 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np + +from tqdm import tqdm +from RUL.otherIdea.adaRNN.utils import utils +from RUL.otherIdea.adaRNN.model import AdaRNN + +import RUL.otherIdea.adaRNN.dataset_vibrate.data_process as data_process +import matplotlib.pyplot as plt + +''' +超参数设置: +''' +hidden_num = 40 # LSTM细胞个数 +feature = 10 # 一个点的维度 +batch_size = 32 +EPOCH = 1000 +predict_num = 50 # 预测个数 +is_norm = False +is_single = True +model_name = "dctLSTM" + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if args.log_file is None: + return + with open(args.log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + n_hiddens = [args.hidden_size for i in range(args.num_layers)] + return AdaRNN(use_bottleneck=True, bottleneck_width=64, n_input=feature, n_hiddens=n_hiddens, + n_output=args.class_num, dropout=args.dropout, model_type=name, len_seq=hidden_num, + trans_loss=args.loss_type) + + +def train_AdaRNN(args, model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(args.num_layers, args.len_seq) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].long(), data[2].float() + list_feat.append(feature) + list_label.append(label_reg) + flag = False + index = get_index(len(data_all) - 1) + for temp_index in index: + s1 = temp_index[0] + s2 = temp_index[1] + if list_feat[s1].shape[0] != list_feat[s2].shape[0]: + flag = True + break + if flag: + continue + + total_loss = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < args.pre_epoch: + pred_all, loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=args.len_win) + else: + pred_all, loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + loss_l1 = criterion_1(pred_s, label_reg_s) + + total_loss = total_loss + loss_s + loss_t + args.dw * loss_transfer + loss_all.append( + [total_loss.item(), (loss_s + loss_t).item(), loss_transfer.item()]) + loss_1_all.append(loss_l1.item()) + optimizer.zero_grad() + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + if epoch >= args.pre_epoch: + if epoch > args.pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def train_epoch_transfer_Boosting(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(args.num_layers, args.len_seq) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].long(), data[2].float() + list_feat.append(feature) + list_label.append(label_reg) + flag = False + index = get_index(len(data_all) - 1) + for temp_index in index: + s1 = temp_index[0] + s2 = temp_index[1] + if list_feat[s1].shape[0] != list_feat[s2].shape[0]: + flag = True + break + if flag: + continue + + total_loss = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + feature_all = torch.cat((feature_s, feature_t), 0) + + pred_all, loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + loss_l1 = criterion_1(pred_s, label_reg_s) + + total_loss = total_loss + loss_s + loss_t + args.dw * loss_transfer + + loss_all.append( + [total_loss.item(), (loss_s + loss_t).item(), loss_transfer.item()]) + loss_1_all.append(loss_l1.item()) + optimizer.zero_grad() + total_loss.backward() + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + if epoch > 0: # args.pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def test_epoch(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = loss_r / len(test_loader) + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(args.num_layers, args.len_seq) + for i in range(args.num_layers): + for j in range(args.len_seq): + weight[i, j] = init_weight[i][j].item() + return weight + + +def main_transfer(args): + print(args) + + output_path = args.outdir + '_' + args.station + '_' + args.model_name + '_vibrate_' + \ + args.loss_type + '_' + str(args.pre_epoch) + \ + '_' + str(args.dw) + '_' + str(args.lr) + save_model_name = args.model_name + '_' + args.loss_type + \ + '_' + str(args.dw) + '_' + str(args.lr) + '.pkl' + utils.dir_exist(output_path) + pprint('create loaders...') + + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_norm=is_norm, batch_size=args.batch_size, + number_domain=args.num_domain, mode=args.data_mode + ) + + args.log_file = os.path.join(output_path, 'run.log') + pprint('create model...') + model = get_model(args.model_name) + num_model = count_parameters(model) + print('#model params:', num_model) + + optimizer = optim.Adam(model.parameters(), lr=args.lr) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + + for epoch in range(args.n_epochs): + pprint('Epoch:', epoch) + pprint('training...') + if args.model_name in ['Boosting']: + loss, loss1, weight_mat, dist_mat = train_epoch_transfer_Boosting( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + elif args.model_name in ['AdaRNN']: + loss, loss1, weight_mat, dist_mat = train_AdaRNN( + args, model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + else: + print("error in model_name!") + pprint(loss, loss1) + + pprint('evaluating...') + train_loss, train_loss_l1, train_loss_r = test_epoch( + model, train_loader_list[0], prefix='Train') + val_loss, val_loss_l1, val_loss_r = test_epoch( + model, valid_loader, prefix='Valid') + test_loss, test_loss_l1, test_loss_r = test_epoch( + model, test_loader, prefix='Test') + + pprint('valid %.6f, test %.6f' % + (val_loss_l1, test_loss_l1)) + + if val_loss < best_score: + best_score = val_loss + stop_round = 0 + best_epoch = epoch + torch.save(model.state_dict(), os.path.join( + output_path, save_model_name)) + else: + stop_round += 1 + if stop_round >= args.early_stop: + pprint('early stop') + break + + pprint('best val score:', best_score, '@', best_epoch) + + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, save_model_name), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=6) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='cos') + parser.add_argument('--station', type=str, default='Dongsi') + parser.add_argument('--data_mode', type=str, + default='tdc') + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=hidden_num) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + args = get_args() + np.random.seed(args.seed) + torch.manual_seed(args.seed) + torch.cuda.manual_seed_all(args.seed) + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + os.environ["CUDA_VISIBLE_DEVICES"] = str(args.gpu_id) + main_transfer(args) diff --git a/pytorch_example/RUL/otherIdea/adaRNN/train_weather.py b/pytorch_example/RUL/otherIdea/adaRNN/train_weather.py new file mode 100644 index 0000000..5913df6 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/train_weather.py @@ -0,0 +1,472 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:32 +@Usage : +@Desc : +''' +import torch.nn as nn +import torch +import torch.optim as optim + +import os +import argparse +import datetime +import numpy as np + +from tqdm import tqdm +from RUL.otherIdea.adaRNN.utils import utils +from RUL.otherIdea.adaRNN.model import AdaRNN + + +import RUL.otherIdea.adaRNN.dataset.data_process as data_process +import matplotlib.pyplot as plt + + +def pprint(*text): + # print with UTC+8 time + time = '[' + str(datetime.datetime.utcnow() + + datetime.timedelta(hours=8))[:19] + '] -' + print(time, *text, flush=True) + if args.log_file is None: + return + with open(args.log_file, 'a') as f: + print(time, *text, flush=True, file=f) + + +def get_model(name='AdaRNN'): + n_hiddens = [args.hidden_size for i in range(args.num_layers)] + return AdaRNN(use_bottleneck=True, bottleneck_width=64, n_input=args.d_feat, n_hiddens=n_hiddens, + n_output=args.class_num, dropout=args.dropout, model_type=name, len_seq=args.len_seq, + trans_loss=args.loss_type) + + +def train_AdaRNN(args, model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(args.num_layers, args.len_seq) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].long(), data[2].float() + list_feat.append(feature) + list_label.append(label_reg) + flag = False + index = get_index(len(data_all) - 1) + for temp_index in index: + s1 = temp_index[0] + s2 = temp_index[1] + if list_feat[s1].shape[0] != list_feat[s2].shape[0]: + flag = True + break + if flag: + continue + + total_loss = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + feature_all = torch.cat((feature_s, feature_t), 0) + + if epoch < args.pre_epoch: + pred_all, loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=args.len_win) + else: + pred_all, loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + loss_l1 = criterion_1(pred_s, label_reg_s) + + total_loss = total_loss + loss_s + loss_t + args.dw * loss_transfer + loss_all.append( + [total_loss.item(), (loss_s + loss_t).item(), loss_transfer.item()]) + loss_1_all.append(loss_l1.item()) + optimizer.zero_grad() + total_loss.backward() + # 梯度裁剪,梯度最大范数为3 + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + if epoch >= args.pre_epoch: + if epoch > args.pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + else: + weight_mat = transform_type(out_weight_list) + return loss, loss_l1, weight_mat, None + + +def train_epoch_transfer_Boosting(model, optimizer, train_loader_list, epoch, dist_old=None, weight_mat=None): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + dist_mat = torch.zeros(args.num_layers, args.len_seq) + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].long(), data[2].float() + list_feat.append(feature) + list_label.append(label_reg) + flag = False + index = get_index(len(data_all) - 1) + for temp_index in index: + s1 = temp_index[0] + s2 = temp_index[1] + if list_feat[s1].shape[0] != list_feat[s2].shape[0]: + flag = True + break + if flag: + continue + + total_loss = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + feature_all = torch.cat((feature_s, feature_t), 0) + + pred_all, loss_transfer, dist, weight_mat = model.forward_Boosting( + feature_all, weight_mat) + dist_mat = dist_mat + dist + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + loss_l1 = criterion_1(pred_s, label_reg_s) + + total_loss = total_loss + loss_s + loss_t + args.dw * loss_transfer + + loss_all.append( + [total_loss.item(), (loss_s + loss_t).item(), loss_transfer.item()]) + loss_1_all.append(loss_l1.item()) + optimizer.zero_grad() + total_loss.backward() + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + if epoch > 0: # args.pre_epoch: + weight_mat = model.update_weight_Boosting( + weight_mat, dist_old, dist_mat) + return loss, loss_l1, weight_mat, dist_mat + + +def get_index(num_domain=2): + index = [] + for i in range(num_domain): + for j in range(i + 1, num_domain + 1): + index.append((i, j)) + return index + + +def train_epoch_transfer(args, model, optimizer, train_loader_list): + model.train() + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + loss_all = [] + loss_1_all = [] + len_loader = np.inf + for loader in train_loader_list: + if len(loader) < len_loader: + len_loader = len(loader) + + for data_all in tqdm(zip(*train_loader_list), total=len_loader): + optimizer.zero_grad() + list_feat = [] + list_label = [] + for data in data_all: + feature, label, label_reg = data[0].float( + ), data[1].long(), data[2].float() + list_feat.append(feature) + list_label.append(label_reg) + flag = False + index = get_index(len(data_all) - 1) + for temp_index in index: + s1 = temp_index[0] + s2 = temp_index[1] + if list_feat[s1].shape[0] != list_feat[s2].shape[0]: + flag = True + break + if flag: + continue + + ############### + total_loss = torch.zeros(1) + for i in range(len(index)): + feature_s = list_feat[index[i][0]] + feature_t = list_feat[index[i][1]] + label_reg_s = list_label[index[i][0]] + label_reg_t = list_label[index[i][1]] + feature_all = torch.cat((feature_s, feature_t), 0) + + pred_all, loss_transfer, out_weight_list = model.forward_pre_train( + feature_all, len_win=args.len_win) + pred_s = pred_all[0:feature_s.size(0)] + pred_t = pred_all[feature_s.size(0):] + + loss_s = criterion(pred_s, label_reg_s) + loss_t = criterion(pred_t, label_reg_t) + loss_l1 = criterion_1(pred_s, label_reg_s) + + total_loss = total_loss + loss_s + loss_t + args.dw * loss_transfer + loss_all.append( + [total_loss.item(), (loss_s + loss_t).item(), loss_transfer.item()]) + loss_1_all.append(loss_l1.item()) + optimizer.zero_grad() + total_loss.backward() + torch.nn.utils.clip_grad_value_(model.parameters(), 3.) + optimizer.step() + loss = np.array(loss_all).mean(axis=0) + loss_l1 = np.array(loss_1_all).mean() + return loss, loss_l1, out_weight_list + + +def count_parameters(model): + return sum(p.numel() for p in model.parameters() if p.requires_grad) + + +def test_epoch(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = loss_r / len(test_loader) + return loss, loss_1, loss_r + + +def test_epoch_inference(model, test_loader, prefix='Test'): + model.eval() + total_loss = 0 + total_loss_1 = 0 + total_loss_r = 0 + correct = 0 + criterion = nn.MSELoss() + criterion_1 = nn.L1Loss() + i = 0 + for feature, label, label_reg in tqdm(test_loader, desc=prefix, total=len(test_loader)): + feature, label_reg = feature.float(), label_reg.float() + with torch.no_grad(): + pred = model.predict(feature) + loss = criterion(pred, label_reg) + loss_r = torch.sqrt(loss) + loss_1 = criterion_1(pred, label_reg) + total_loss += loss.item() + total_loss_1 += loss_1.item() + total_loss_r += loss_r.item() + if i == 0: + label_list = label_reg.cpu().numpy() + predict_list = pred.cpu().numpy() + else: + label_list = np.hstack((label_list, label_reg.cpu().numpy())) + predict_list = np.hstack((predict_list, pred.cpu().numpy())) + + i = i + 1 + loss = total_loss / len(test_loader) + loss_1 = total_loss_1 / len(test_loader) + loss_r = total_loss_r / len(test_loader) + return loss, loss_1, loss_r, label_list, predict_list + + +def inference(model, data_loader): + loss, loss_1, loss_r, label_list, predict_list = test_epoch_inference( + model, data_loader, prefix='Inference') + return loss, loss_1, loss_r, label_list, predict_list + + +def inference_all(output_path, model, model_path, loaders): + pprint('inference...') + loss_list = [] + loss_l1_list = [] + loss_r_list = [] + model.load_state_dict(torch.load(model_path)) + i = 0 + list_name = ['train', 'valid', 'test'] + for loader in loaders: + loss, loss_1, loss_r, label_list, predict_list = inference( + model, loader) + loss_list.append(loss) + loss_l1_list.append(loss_1) + loss_r_list.append(loss_r) + i = i + 1 + return loss_list, loss_l1_list, loss_r_list + + +def transform_type(init_weight): + weight = torch.ones(args.num_layers, args.len_seq) + for i in range(args.num_layers): + for j in range(args.len_seq): + weight[i, j] = init_weight[i][j].item() + return weight + + +def main_transfer(args): + print(args) + + output_path = args.outdir + '_' + args.station + '_' + args.model_name + '_weather_' + \ + args.loss_type + '_' + str(args.pre_epoch) + \ + '_' + str(args.dw) + '_' + str(args.lr) + save_model_name = args.model_name + '_' + args.loss_type + \ + '_' + str(args.dw) + '_' + str(args.lr) + '.pkl' + utils.dir_exist(output_path) + pprint('create loaders...') + + train_loader_list, valid_loader, test_loader = data_process.load_weather_data_multi_domain( + args.data_path, args.batch_size, args.station, args.num_domain, args.data_mode) + + args.log_file = os.path.join(output_path, 'run.log') + pprint('create model...') + model = get_model(args.model_name) + num_model = count_parameters(model) + print('#model params:', num_model) + + optimizer = optim.Adam(model.parameters(), lr=args.lr) + + best_score = np.inf + best_epoch, stop_round = 0, 0 + weight_mat, dist_mat = None, None + + for epoch in range(args.n_epochs): + pprint('Epoch:', epoch) + pprint('training...') + if args.model_name in ['Boosting']: + loss, loss1, weight_mat, dist_mat = train_epoch_transfer_Boosting( + model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + elif args.model_name in ['AdaRNN']: + loss, loss1, weight_mat, dist_mat = train_AdaRNN( + args, model, optimizer, train_loader_list, epoch, dist_mat, weight_mat) + else: + print("error in model_name!") + pprint(loss, loss1) + + pprint('evaluating...') + train_loss, train_loss_l1, train_loss_r = test_epoch( + model, train_loader_list[0], prefix='Train') + val_loss, val_loss_l1, val_loss_r = test_epoch( + model, valid_loader, prefix='Valid') + test_loss, test_loss_l1, test_loss_r = test_epoch( + model, test_loader, prefix='Test') + + pprint('valid %.6f, test %.6f' % + (val_loss_l1, test_loss_l1)) + + if val_loss < best_score: + best_score = val_loss + stop_round = 0 + best_epoch = epoch + torch.save(model.state_dict(), os.path.join( + output_path, save_model_name)) + else: + stop_round += 1 + if stop_round >= args.early_stop: + pprint('early stop') + break + + pprint('best val score:', best_score, '@', best_epoch) + + loaders = train_loader_list[0], valid_loader, test_loader + loss_list, loss_l1_list, loss_r_list = inference_all(output_path, model, os.path.join( + output_path, save_model_name), loaders) + pprint('MSE: train %.6f, valid %.6f, test %.6f' % + (loss_list[0], loss_list[1], loss_list[2])) + pprint('L1: train %.6f, valid %.6f, test %.6f' % + (loss_l1_list[0], loss_l1_list[1], loss_l1_list[2])) + pprint('RMSE: train %.6f, valid %.6f, test %.6f' % + (loss_r_list[0], loss_r_list[1], loss_r_list[2])) + pprint('Finished.') + + +def get_args(): + parser = argparse.ArgumentParser() + + # model + parser.add_argument('--model_name', default='AdaRNN') + parser.add_argument('--d_feat', type=int, default=6) + + parser.add_argument('--hidden_size', type=int, default=64) + parser.add_argument('--num_layers', type=int, default=2) + parser.add_argument('--dropout', type=float, default=0.0) + parser.add_argument('--class_num', type=int, default=1) + parser.add_argument('--pre_epoch', type=int, default=40) # 20, 30, 50 + + # training + parser.add_argument('--n_epochs', type=int, default=200) + parser.add_argument('--lr', type=float, default=5e-4) + parser.add_argument('--early_stop', type=int, default=40) + parser.add_argument('--smooth_steps', type=int, default=5) + parser.add_argument('--batch_size', type=int, default=36) + parser.add_argument('--dw', type=float, default=0.5) # 0.01, 0.05, 5.0 + parser.add_argument('--loss_type', type=str, default='adv') + parser.add_argument('--station', type=str, default='Dongsi') + parser.add_argument('--data_mode', type=str, + default='tdc') + parser.add_argument('--num_domain', type=int, default=2) + parser.add_argument('--len_seq', type=int, default=24) + + # other + parser.add_argument('--seed', type=int, default=10) + parser.add_argument('--data_path', default="E:\self_example\pytorch_example\RUL\otherIdea/adaRNN\dataset/") + parser.add_argument('--outdir', default='./outputs') + parser.add_argument('--overwrite', action='store_true') + parser.add_argument('--log_file', type=str, default='run.log') + parser.add_argument('--gpu_id', type=int, default=0) + parser.add_argument('--len_win', type=int, default=0) + args = parser.parse_args() + + return args + + +if __name__ == '__main__': + args = get_args() + np.random.seed(args.seed) + torch.manual_seed(args.seed) + torch.cuda.manual_seed_all(args.seed) + torch.backends.cudnn.deterministic = True + torch.backends.cudnn.benchmark = False + os.environ["CUDA_VISIBLE_DEVICES"] = str(args.gpu_id) + main_transfer(args) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaRNN/utils/__init__.py b/pytorch_example/RUL/otherIdea/adaRNN/utils/__init__.py new file mode 100644 index 0000000..4e22673 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/utils/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/adaRNN/utils/utils.py b/pytorch_example/RUL/otherIdea/adaRNN/utils/utils.py new file mode 100644 index 0000000..08b396e --- /dev/null +++ b/pytorch_example/RUL/otherIdea/adaRNN/utils/utils.py @@ -0,0 +1,225 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 16:33 +@Usage : +@Desc : +''' + +import collections +import torch +import os +import pandas as pd +import torch.nn as nn +from tqdm import tqdm +import numpy as np + +EPS = 1e-12 + + +class AverageMeter(object): + def __init__(self): + self.reset() + + def reset(self): + self.val = 0 + self.avg = 0 + self.sum = 0 + self.count = 0 + self.list = [] + + def update(self, val, n=1): + self.val = val + self.list.append(val) + self.sum += val * n + self.count += n + self.avg = self.sum / self.count + + +def average_params(params_list): + assert isinstance(params_list, (tuple, list, collections.deque)) + n = len(params_list) + if n == 1: + return params_list[0] + new_params = collections.OrderedDict() + keys = None + for i, params in enumerate(params_list): + if keys is None: + keys = params.keys() + for k, v in params.items(): + if k not in keys: + raise ValueError('the %d-th model has different params' % i) + if k not in new_params: + new_params[k] = v / n + else: + new_params[k] += v / n + return new_params + + +def zscore(x): + return (x - x.mean(dim=0, keepdim=True)) / x.std(dim=0, keepdim=True, unbiased=False) + + +def calc_loss(pred, label): + return torch.mean((zscore(pred) - label) ** 2) + + +def calc_corr(pred, label): + return (zscore(pred) * zscore(label)).mean() + + +def test_ic(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = label_actual.clone().detach().view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_daily(model_list, data_list, device, verbose=True, ic_type='spearman'): + ''' + model_list: [model1, model2, ...] + datalist: [loader1, loader2, ...] + return: unified ic, specific ic (all values + avg), loss + ''' + spec_ic = [] + loss_test = AverageMeter() + loss_fn = torch.nn.MSELoss() + label_true, label_pred = torch.empty(0).to(device), torch.empty(0).to(device) + for i in range(len(model_list)): + label_spec_true, label_spec_pred = torch.empty(0).to(device), torch.empty(0).to(device) + model_list[i].eval() + with torch.no_grad(): + for slc in tqdm(data_list[i].iter_daily(), total=data_list[i].daily_length): + feature, label_actual, _, _ = data_list[i].get(slc) + # for _, (feature, label_actual, _, _) in enumerate(data_list[i]): + # feature = torch.tensor(feature, dtype=torch.float32, device=device) + label_actual = torch.tensor(label_actual, dtype=torch.float32, device=device).view(-1, 1) + label_actual, mask = handle_nan(label_actual) + label_predict = model_list[i].predict(feature).view(-1, 1) + label_predict = label_predict[mask] + loss = loss_fn(label_actual, label_predict) + loss_test.update(loss.item()) + # Concat them for computing IC later + label_true = torch.cat([label_true, label_actual]) + label_pred = torch.cat([label_pred, label_predict]) + label_spec_true = torch.cat([label_spec_true, label_actual]) + label_spec_pred = torch.cat([label_spec_pred, label_predict]) + ic = calc_ic(label_spec_true, label_spec_pred, ic_type) + spec_ic.append(ic.item()) + unify_ic = calc_ic(label_true, label_pred, ic_type).item() + # spec_ic.append(sum(spec_ic) / len(spec_ic)) + loss = loss_test.avg + if verbose: + print('[IC] Unified IC: {:.6f}, specific IC: {}, loss: {:.6f}'.format(unify_ic, spec_ic, loss)) + return unify_ic, spec_ic, loss + + +def test_ic_uni(model, data_loader, model_path=None, ic_type='spearman', verbose=False): + if model_path: + model.load_state_dict(torch.load(model_path)) + model.eval() + loss_all = [] + ic_all = [] + for slc in tqdm(data_loader.iter_daily(), total=data_loader.daily_length): + data, label, _, _ = data_loader.get(slc) + with torch.no_grad(): + pred = model.predict(data) + mask = ~torch.isnan(label) + pred = pred[mask] + label = label[mask] + loss = torch.mean(torch.log(torch.cosh(pred - label))) + if ic_type == 'spearman': + ic = spearman_corr(pred, label) + elif ic_type == 'pearson': + ic = pearson_corr(pred, label) + loss_all.append(loss.item()) + ic_all.append(ic) + loss, ic = np.mean(loss_all), np.mean(ic_all) + if verbose: + print('IC: ', ic) + return loss, ic + + +def calc_ic(x, y, ic_type='pearson'): + ic = -100 + if ic_type == 'pearson': + ic = pearson_corr(x, y) + elif ic_type == 'spearman': + ic = spearman_corr(x, y) + return ic + + +def create_dir(path): + if not os.path.exists(path): + os.makedirs(path) + + +def handle_nan(x): + mask = ~torch.isnan(x) + return x[mask], mask + + +class Log_Loss(nn.Module): + def __init__(self): + super(Log_Loss, self).__init__() + + def forward(self, ytrue, ypred): + delta = ypred - ytrue + return torch.mean(torch.log(torch.cosh(delta))) + + +def spearman_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='spearman') + return spearman + + +def spearman_corr2(x, y): + X = pd.Series(x) + Y = pd.Series(y) + spearman = X.corr(Y, method='spearman') + return spearman + + +def pearson_corr(x, y): + X = pd.Series(x.cpu()) + Y = pd.Series(y.cpu()) + spearman = X.corr(Y, method='pearson') + return spearman + + +def dir_exist(dirs): + if not os.path.exists(dirs): + os.makedirs(dirs) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/convLSTM/__init__.py b/pytorch_example/RUL/otherIdea/convLSTM/__init__.py new file mode 100644 index 0000000..415d0bc --- /dev/null +++ b/pytorch_example/RUL/otherIdea/convLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/convLSTM/model2D.py b/pytorch_example/RUL/otherIdea/convLSTM/model2D.py new file mode 100644 index 0000000..f83a314 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/convLSTM/model2D.py @@ -0,0 +1,211 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from torch.autograd import Variable + + +class ConvLSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, kernel_size, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C, S + B: bacth_size + T: timestamp + C: channel + S: seq + """ + + super(ConvLSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + + self.kernel_size = kernel_size + self.padding = kernel_size // 2 + self.bias = bias + + self.conv = nn.Conv1d(in_channels=self.input_dim + self.hidden_dim, + out_channels=4 * self.hidden_dim, + kernel_size=self.kernel_size, + padding=self.padding, + bias=self.bias) + + def forward(self, input_tensor, cur_state): + # shape :b,c,s + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=1) # concatenate along channel axis + + combined_conv = self.conv(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_conv, self.hidden_dim, dim=1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size, seq): + return (torch.zeros(batch_size, self.hidden_dim, seq, device=self.conv.weight.device), + torch.zeros(batch_size, self.hidden_dim, seq, device=self.conv.weight.device)) + + +class ConvLSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C, S or T, B, C, S + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64, 128)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, kernel_size, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(ConvLSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + kernel_size = self._extend_for_multilayer(kernel_size, num_layers) + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(kernel_size) == len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.kernel_size = kernel_size + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append(ConvLSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + kernel_size=self.kernel_size[i], + bias=self.bias)) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c, s) or (b, t, c, s) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2, 3) + + b, _, _, s = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b, + seq=s) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size, seq): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size, seq)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64, 128)) + convlstm = ConvLSTM(input_dim=64, hidden_dim=16, kernel_size=3, num_layers=1, batch_first=True, bias=True, return_all_layers=False) + _, last_states = convlstm(x) + + + print(last_states[0][0].size()) + h = last_states[0][0] # 0 for layer index, 0 for h index + # target = Variable(torch.randn(1, 32, 64, 32)).double().cuda() diff --git a/pytorch_example/RUL/otherIdea/convLSTM/model3D.py b/pytorch_example/RUL/otherIdea/convLSTM/model3D.py new file mode 100644 index 0000000..c2cbcb9 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/convLSTM/model3D.py @@ -0,0 +1,216 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM3D基本实现 +''' + +import torch.nn as nn +import torch + + +class ConvLSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, kernel_size, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: (int, int) + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + """ + + super(ConvLSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + + self.kernel_size = kernel_size + self.padding = kernel_size[0] // 2, kernel_size[1] // 2 + self.bias = bias + + self.conv = nn.Conv2d(in_channels=self.input_dim + self.hidden_dim, + out_channels=4 * self.hidden_dim, + kernel_size=self.kernel_size, + padding=self.padding, + bias=self.bias) + + def forward(self, input_tensor, cur_state): + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=1) # concatenate along channel axis + + combined_conv = self.conv(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_conv, self.hidden_dim, dim=1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size, image_size): + height, width = image_size + return (torch.zeros(batch_size, self.hidden_dim, height, width, device=self.conv.weight.device), + torch.zeros(batch_size, self.hidden_dim, height, width, device=self.conv.weight.device)) + + +class ConvLSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C, H, W or T, B, C, H, W + B: batch_size + T: timestamp 时间部 + C: channel 特征维度 通道数 + H: 图片的高 + W: 图片的宽 + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64, 128, 128)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, kernel_size, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(ConvLSTM, self).__init__() + + self._check_kernel_size_consistency(kernel_size) + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + kernel_size = self._extend_for_multilayer(kernel_size, num_layers) + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(kernel_size) == len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.kernel_size = kernel_size + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append(ConvLSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + kernel_size=self.kernel_size[i], + bias=self.bias)) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c, h, w) or (b, t, c, h, w) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2, 3, 4) + + b, _, _, h, w = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b, + image_size=(h, w)) + + layer_output_list = [] + last_state_list = [] + + seq_len = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(seq_len): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :, :, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size, image_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size, image_size)) + return init_states + + @staticmethod + def _check_kernel_size_consistency(kernel_size): + if not (isinstance(kernel_size, tuple) or + (isinstance(kernel_size, list) and all([isinstance(elem, tuple) for elem in kernel_size]))): + raise ValueError('`kernel_size` must be tuple or list of tuples') + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +if __name__ == '__main__': + channels = 10 + model = ConvLSTM(input_dim=channels, + hidden_dim=[64, 64, 128], + kernel_size=(3, 3), + num_layers=3, + batch_first=True, + bias=True, + return_all_layers=False) diff --git a/pytorch_example/RUL/otherIdea/convLSTM/model_new3D.py b/pytorch_example/RUL/otherIdea/convLSTM/model_new3D.py new file mode 100644 index 0000000..fd884b2 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/convLSTM/model_new3D.py @@ -0,0 +1,116 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 11:08 +@Usage : +@Desc : +''' + +import torch +import torch.nn as nn +from torch.autograd import Variable + + +class ConvLSTMCell(nn.Module): + def __init__(self, input_channels, hidden_channels, kernel_size): + super(ConvLSTMCell, self).__init__() + + assert hidden_channels % 2 == 0 + + self.input_channels = input_channels + self.hidden_channels = hidden_channels + self.kernel_size = kernel_size + self.num_features = 4 + + self.padding = int((kernel_size - 1) / 2) + + self.Wxi = nn.Conv2d(self.input_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=True) + self.Whi = nn.Conv2d(self.hidden_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=False) + self.Wxf = nn.Conv2d(self.input_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=True) + self.Whf = nn.Conv2d(self.hidden_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=False) + self.Wxc = nn.Conv2d(self.input_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=True) + self.Whc = nn.Conv2d(self.hidden_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=False) + self.Wxo = nn.Conv2d(self.input_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=True) + self.Who = nn.Conv2d(self.hidden_channels, self.hidden_channels, self.kernel_size, 1, self.padding, bias=False) + + self.Wci = None + self.Wcf = None + self.Wco = None + + def forward(self, x, h, c): + ci = torch.sigmoid(self.Wxi(x) + self.Whi(h) + c * self.Wci) + cf = torch.sigmoid(self.Wxf(x) + self.Whf(h) + c * self.Wcf) + cc = cf * c + ci * torch.tanh(self.Wxc(x) + self.Whc(h)) + co = torch.sigmoid(self.Wxo(x) + self.Who(h) + cc * self.Wco) + ch = co * torch.tanh(cc) + return ch, cc + + def init_hidden(self, batch_size, hidden, shape): + if self.Wci is None: + self.Wci = nn.Parameter(torch.zeros(1, hidden, shape[0], shape[1])).cuda() + self.Wcf = nn.Parameter(torch.zeros(1, hidden, shape[0], shape[1])).cuda() + self.Wco = nn.Parameter(torch.zeros(1, hidden, shape[0], shape[1])).cuda() + else: + assert shape[0] == self.Wci.size()[2], 'Input Height Mismatched!' + assert shape[1] == self.Wci.size()[3], 'Input Width Mismatched!' + return (Variable(torch.zeros(batch_size, hidden, shape[0], shape[1])).cuda(), + Variable(torch.zeros(batch_size, hidden, shape[0], shape[1])).cuda()) + + +class ConvLSTM(nn.Module): + # input_channels corresponds to the first input feature map + # hidden state is a list of succeeding lstm layers. + def __init__(self, input_channels, hidden_channels, kernel_size, step=1, effective_step=[1]): + super(ConvLSTM, self).__init__() + self.input_channels = [input_channels] + hidden_channels + self.hidden_channels = hidden_channels + self.kernel_size = kernel_size + self.num_layers = len(hidden_channels) + self.step = step + self.effective_step = effective_step + self._all_layers = [] + for i in range(self.num_layers): + name = 'cell{}'.format(i) + cell = ConvLSTMCell(self.input_channels[i], self.hidden_channels[i], self.kernel_size) + setattr(self, name, cell) + self._all_layers.append(cell) + + def forward(self, input): + internal_state = [] + outputs = [] + for step in range(self.step): + x = input + for i in range(self.num_layers): + # all cells are initialized in the first step + name = 'cell{}'.format(i) + if step == 0: + bsize, _, height, width = x.size() + (h, c) = getattr(self, name).init_hidden(batch_size=bsize, hidden=self.hidden_channels[i], + shape=(height, width)) + internal_state.append((h, c)) + + # do forward + (h, c) = internal_state[i] + x, new_c = getattr(self, name)(x, h, c) + internal_state[i] = (x, new_c) + # only record effective steps + if step in self.effective_step: + outputs.append(x) + + return outputs, (x, new_c) + + +if __name__ == '__main__': + # gradient check + convlstm = ConvLSTM(input_channels=512, hidden_channels=[128, 64, 64, 32, 32], kernel_size=3, step=5, + effective_step=[4]).cuda() + loss_fn = torch.nn.MSELoss() + + input = Variable(torch.randn(1, 512, 64, 32)).cuda() + target = Variable(torch.randn(1, 32, 64, 32)).double().cuda() + + output = convlstm(input) + output = output[0][0].double() + res = torch.autograd.gradcheck(loss_fn, (output, target), eps=1e-6, raise_exception=True) + print(res) \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/__init__.py b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/__init__.py new file mode 100644 index 0000000..5857496 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 20:32 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/loadData.py b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/loadData.py new file mode 100644 index 0000000..3434549 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/loadData.py @@ -0,0 +1,138 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("../../dataset/HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + # todo 解决模型保存时,query无法序列化的问题 + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset diff --git a/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/model.py b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/model.py new file mode 100644 index 0000000..38d5c98 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/model.py @@ -0,0 +1,243 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from RUL.baseModel.dctChannelAttention import dct_channel_block + + +class dctLSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(dctLSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + self.attention = dct_channel_block(channel=self.input_dim + self.hidden_dim) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + # 增加一个channelAttention + combined = self.attention(combined) + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=-1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, 1, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, 1, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append( + dctLSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias), + ) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c) or (b, t, c) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :].unsqueeze(dim=1), + cur_state=[h, c]) + output_inner.append(h.squeeze(1)) + + layer_output = torch.stack(output_inner, dim=1) + + # TODO 每层之间增加一个dct_attention + # layer_output = self.attention_list[layer_idx](layer_output) + + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h.squeeze(1), c.squeeze(1)]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[512, 256], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + self.backbone = nn.Sequential( + nn.Linear(in_features=256, out_features=128), + nn.ReLU(), + nn.Linear(in_features=128, out_features=64), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(64), + nn.Linear(in_features=64, out_features=32), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(32), + nn.ReLU(), + nn.Linear(in_features=32, out_features=16), + nn.Linear(in_features=16, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/test.py b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/test.py new file mode 100644 index 0000000..29032ab --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/test.py @@ -0,0 +1,134 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.dctChannelEmbedLSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctChannelEmbedLSTM.model import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt + + +def plot_prediction(total_data, predicted_data_easy, predicted_data_hard): + pic1 = plt.figure(figsize=(8, 6), dpi=200) + + '''保存的模型参数的路径''' + + from matplotlib import rcParams + + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + # 简单预测图 + plt.subplot(2, 1, 1) + plt.plot(total_data) + plt.plot(predicted_data_easy) + plt.title('Easy Prediction') + plt.xlabel('time') + plt.ylabel('loss') + # plt.legend(loc='upper right') + + # 困难预测图 + plt.subplot(2, 1, 2) + plt.plot(total_data) + plt.plot(predicted_data_hard) + plt.title('Easy Prediction') + plt.xlabel('time') + plt.ylabel('loss') + + # plt.legend(loc='upper right') + + + # plt.scatter() + + plt.show() + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model(each_predict_data).cpu().detach().numpy()[-1] # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.concatenate([each_predict_data[1:, :, :], np.expand_dims(b, axis=0)], axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, save_path, is_single=True, is_norm=False): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + model = PredictModel(input_dim=feature).to(device) + + model.load_state_dict( + torch.load(save_path, map_location=device) + ) + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predicted_data_hard = np.concatenate([predicted_data_hard, + predictOneByOne(model, last_train_data, predict_num=predict_num)], axis=0) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "./parameters\dctLSTM_hidden40_feature10_predict50_epoch80_trainLoss0.05818896507844329_valLoss0.21667905896902084.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/train.py b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/train.py new file mode 100644 index 0000000..2bfc48a --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctChannelEmbedLSTM/train.py @@ -0,0 +1,194 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 14:56 +@Usage : +@Desc : 训练LSTM +''' +import os +import time +import random +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +import matplotlib.pyplot as plt +from torch.utils.data import DataLoader +from RUL.otherIdea.dctChannelEmbedLSTM.model import PredictModel +from RUL.otherIdea.dctChannelEmbedLSTM.loadData import getDataset +from RUL.otherIdea.dctChannelEmbedLSTM.test import test +from RUL.baseModel.CommonFunction import IsStopTraining +import math + +''' +超参数设置: +''' +hidden_num = 40 # LSTM细胞个数 +feature = 10 # 一个点的维度 +batch_size = 32 +EPOCH = 1000 +predict_num = 50 # 预测个数 +is_norm = False +is_single = True +seed = 334 +model_name = "dctEmbedLSTM" +base_save = r"parameters/{0}_hidden{1}_feature{2}_predict{3}_seed{4}".format(model_name, hidden_num, feature, + predict_num, seed) +if not os.path.exists("parameters"): + os.makedirs("parameters") + + +def get_dataset(): + '''得到数据集''' + train_dataset, val_dataset = getDataset( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_single=is_single, is_norm=is_norm) + '''DataLoader''' + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, drop_last=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False, drop_last=False) + return train_loader, val_loader + + +def train(device, lr, lr_patience, early_stop_patience, epochs,seed): + '''预测模型''' + global best_save_path + model = PredictModel(input_dim=feature) + '''得到数据集''' + train_loader, val_loader = get_dataset() + criterion = nn.MSELoss().to(device) + + optimizer_model = torch.optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer_model, mode="min", factor=0.5, + patience=lr_patience) + + def zero_grad_all(): + optimizer_model.zero_grad() + + train_loss_list = [] + val_loss_list = [] + + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss = 0.0 + val_loss = 0.0 + + model.train() + + for (train_batch_idx, (train_data, train_label)) in enumerate(train_loader): + train_data, train_label = train_data.to(device), train_label.to(device) + + zero_grad_all() + + predict_data = torch.squeeze(model(train_data)) + + # MSE损失 + loss = criterion(predict_data, train_label) + + loss.backward() + optimizer_model.step() + + zero_grad_all() + + train_loss += loss.item() + + model.eval() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = torch.squeeze(model(val_data)) + + loss = criterion(val_predict_data, val_label) + val_loss += loss.item() + + scheduler_model.step(val_loss) + + train_loss = train_loss / len(train_loader) + val_loss = val_loss / len(val_loader) + print( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_loss: {:3.9f} | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss, + val_loss, + optimizer_model.state_dict()['param_groups'][0]['lr'])) + + # 保存在验证集上loss最小的模型 + # if val_loss_list.__len__() > 0 and (val_loss / val_dataset.__len__()) < min(val_loss_list): + # 如果精度大于最高精度,则保存 + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + print("保存模型最佳模型成功") + # 保存模型参数 + best_save_path = base_save + "_epoch" + str(epoch) + \ + "_trainLoss" + str(train_loss) + \ + "_valLoss" + str(val_loss) + ".pkl" + torch.save(model.state_dict(), + best_save_path) + + train_loss_list.append(train_loss) + + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + break + + '''保存的模型参数的路径''' + + from matplotlib import rcParams + + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + pic1 = plt.figure(figsize=(12, 6), dpi=200) + + plt.plot(np.arange(1, len(train_loss_list) + 1), train_loss_list, 'b', label='Training Loss') + plt.plot(np.arange(1, len(train_loss_list) + 1), val_loss_list, 'r', label='Validation Loss') + # plt.ylim(0, 0.08) # 设置y轴范围 + plt.title('Training & Validation loss') + plt.xlabel('epoch') + plt.ylabel('loss') + plt.legend(loc='upper right') + plt.grid(alpha=0.4) + + # 获取当前时间戳 + timestamp = int(time.time()) + + # 将时间戳转换为字符串 + timestamp_str = str(timestamp) + plt.savefig(timestamp_str, dpi=200) + + return best_save_path + + +if __name__ == '__main__': + + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + '''训练''' + save_path = train(device, lr=0.01, lr_patience=10, early_stop_patience=20, epochs=1000, seed=seed) + + end = time.time() + + '''测试''' + # test1(5, src_condition, tar_condition, G_params_path, LC_params_path) + + test(hidden_num, feature, predict_num=predict_num, + batch_size=batch_size, save_path=save_path, + is_single=is_single, is_norm=is_norm) + + print("训练耗时:{:3.2f}s".format(end - begin)) diff --git a/pytorch_example/RUL/otherIdea/dctEmbedLSTM/__init__.py b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/__init__.py new file mode 100644 index 0000000..5857496 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 20:32 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/dctEmbedLSTM/loadData.py b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/loadData.py new file mode 100644 index 0000000..3434549 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/loadData.py @@ -0,0 +1,138 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("../../dataset/HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + # todo 解决模型保存时,query无法序列化的问题 + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset diff --git a/pytorch_example/RUL/otherIdea/dctEmbedLSTM/model.py b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/model.py new file mode 100644 index 0000000..fb5f411 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/model.py @@ -0,0 +1,243 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from RUL.baseModel.dctAttention import dct_channel_block + + +class dctLSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(dctLSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + self.attention = dct_channel_block(channel=self.input_dim + self.hidden_dim) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + # 增加一个channelAttention + combined = self.attention(combined) + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=-1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append( + dctLSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias), + ) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c) or (b, t, c) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + + # TODO 每层之间增加一个dct_attention + # layer_output = self.attention_list[layer_idx](layer_output) + + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[512, 256], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + self.backbone = nn.Sequential( + nn.Linear(in_features=256, out_features=128), + nn.ReLU(), + nn.Linear(in_features=128, out_features=64), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(64), + nn.Linear(in_features=64, out_features=32), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(32), + nn.ReLU(), + nn.Linear(in_features=32, out_features=16), + nn.Linear(in_features=16, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/dctEmbedLSTM/modelForEasy.py b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/modelForEasy.py new file mode 100644 index 0000000..74449b0 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/modelForEasy.py @@ -0,0 +1,237 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from RUL.baseModel.dctAttention import dct_channel_block + + +class dctLSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(dctLSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + self.attention = dct_channel_block(channel=self.input_dim + self.hidden_dim) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + # 增加一个channelAttention + combined = self.attention(combined) + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=-1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append( + dctLSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias), + ) + + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c) or (b, t, c) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + + # TODO 每层之间增加一个dct_attention + # layer_output = self.attention_list[layer_idx](layer_output) + + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[64, 64], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + + self.backbone = nn.Sequential( + nn.Linear(in_features=64, out_features=64), + nn.Linear(in_features=64, out_features=64), + nn.BatchNorm1d(64), + nn.ReLU(), + nn.Dropout(0.5), + nn.Linear(in_features=64, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/dctEmbedLSTM/test.py b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/test.py new file mode 100644 index 0000000..757ae70 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/test.py @@ -0,0 +1,118 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.dctEmbedLSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctEmbedLSTM.modelForEasy import PredictModel +from torch.utils.data import DataLoader +from RUL.baseModel.plot import plot_prediction, plot_forSelf +from RUL.baseModel.loss.Evaluate import getEvaluate + + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model(each_predict_data).cpu().detach().numpy()[-1] # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.concatenate([each_predict_data[1:, :, :], np.expand_dims(b, axis=0)], axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, save_path, save_fig_name, is_single=True, is_norm=False): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + model = PredictModel(input_dim=feature).to(device) + + model.load_state_dict( + torch.load(save_path, map_location=device) + ) + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label = np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "./parameters\dctLSTM_hidden40_feature10_predict50_epoch80_trainLoss0.05818896507844329_valLoss0.21667905896902084.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/dctEmbedLSTM/train.py b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/train.py new file mode 100644 index 0000000..286c1d0 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctEmbedLSTM/train.py @@ -0,0 +1,202 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 14:56 +@Usage : +@Desc : 训练LSTM +''' +import os +import time +import random +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +import matplotlib.pyplot as plt +from torch.utils.data import DataLoader +from RUL.otherIdea.dctEmbedLSTM.modelForEasy import PredictModel +from RUL.otherIdea.dctEmbedLSTM.loadData import getDataset +from RUL.otherIdea.dctEmbedLSTM.test import test +from RUL.baseModel.CommonFunction import IsStopTraining +import RUL.baseModel.utils.utils as utils +import math + +''' +超参数设置: +''' +hidden_num = 40 # LSTM细胞个数 +feature = 10 # 一个点的维度 +batch_size = 32 +EPOCH = 1000 +predict_num = 200 # 预测个数 +is_norm = False +is_single = True +seed = 5 +model_name = "dctEmbedLSTM" +base_save = r"parameters/{0}_hidden{1}_feature{2}_predict{3}_seed{4}".format(model_name, hidden_num, feature, + predict_num, seed) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}'.format(seed, hidden_num, feature, predict_num) + +if not os.path.exists("parameters"): + os.makedirs("parameters") +if not os.path.exists("fig"): + os.makedirs("fig") + + +def get_dataset(): + '''得到数据集''' + train_dataset, val_dataset = getDataset( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_single=is_single, is_norm=is_norm) + '''DataLoader''' + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, drop_last=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False, drop_last=False) + return train_loader, val_loader + + +def train(device, lr, lr_patience, early_stop_patience, epochs,seed): + '''预测模型''' + global best_save_path + model = PredictModel(input_dim=feature) + '''得到数据集''' + train_loader, val_loader = get_dataset() + criterion = nn.MSELoss().to(device) + + optimizer_model = torch.optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer_model, mode="min", factor=0.5, + patience=lr_patience) + + def zero_grad_all(): + optimizer_model.zero_grad() + + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss = 0.0 + val_loss = 0.0 + + model.train() + + for (train_batch_idx, (train_data, train_label)) in enumerate(train_loader): + train_data, train_label = train_data.to(device), train_label.to(device) + + zero_grad_all() + + predict_data = torch.squeeze(model(train_data)) + + # MSE损失 + loss = criterion(predict_data, train_label) + + loss.backward() + optimizer_model.step() + + zero_grad_all() + + train_loss += loss.item() + + model.eval() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = torch.squeeze(model(val_data)) + + loss = criterion(val_predict_data, val_label) + val_loss += loss.item() + + scheduler_model.step(val_loss) + + train_loss = train_loss / len(train_loader) + val_loss = val_loss / len(val_loader) + print( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_loss: {:3.9f} | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss, + val_loss, + optimizer_model.state_dict()['param_groups'][0]['lr'])) + + # 保存在验证集上loss最小的模型 + # if val_loss_list.__len__() > 0 and (val_loss / val_dataset.__len__()) < min(val_loss_list): + # 如果精度大于最高精度,则保存 + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + print("保存模型最佳模型成功") + # 保存模型参数 + if best_save_path != None: + utils.delete_file(best_save_path) + best_save_path = base_save + "_epoch" + str(epoch) + \ + "_trainLoss" + str(train_loss) + \ + "_valLoss" + str(val_loss) + ".pkl" + torch.save(model.state_dict(), + best_save_path) + + train_loss_list.append(train_loss) + + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + break + + '''保存的模型参数的路径''' + + from matplotlib import rcParams + + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + pic1 = plt.figure(figsize=(12, 6), dpi=200) + + plt.plot(np.arange(1, len(train_loss_list) + 1), train_loss_list, 'b', label='Training Loss') + plt.plot(np.arange(1, len(train_loss_list) + 1), val_loss_list, 'r', label='Validation Loss') + # plt.ylim(0, 0.08) # 设置y轴范围 + plt.title('Training & Validation loss') + plt.xlabel('epoch') + plt.ylabel('loss') + plt.legend(loc='upper right') + plt.grid(alpha=0.4) + + # 获取当前时间戳 + timestamp = int(time.time()) + + # 将时间戳转换为字符串 + timestamp_str = str(timestamp) + plt.savefig(timestamp_str, dpi=200) + plt.show() + + return best_save_path + + +if __name__ == '__main__': + + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + '''训练''' + save_path = train(device, lr=0.01, lr_patience=10, early_stop_patience=20, epochs=1000, seed=seed) + + end = time.time() + + '''测试''' + # test1(5, src_condition, tar_condition, G_params_path, LC_params_path) + + test(hidden_num, feature, predict_num=predict_num, + batch_size=batch_size, save_path=save_path, + is_single=is_single, is_norm=is_norm,save_fig_name=save_fig_name) + + print("训练耗时:{:3.2f}s".format(end - begin)) diff --git a/pytorch_example/RUL/otherIdea/dctLSTM/__init__.py b/pytorch_example/RUL/otherIdea/dctLSTM/__init__.py new file mode 100644 index 0000000..5857496 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctLSTM/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 20:32 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/RUL/otherIdea/dctLSTM/loadData.py b/pytorch_example/RUL/otherIdea/dctLSTM/loadData.py new file mode 100644 index 0000000..3434549 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctLSTM/loadData.py @@ -0,0 +1,138 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 15:21 +@Usage : +@Desc : 获取数据集 +''' + +import torch +import numpy as np +from torch.utils.data import Dataset, DataLoader + +'''正常Dataset类''' + + +class Nor_Dataset(Dataset): + def __init__(self, datas, labels=None): + self.datas = torch.tensor(datas) + if labels is not None: + self.labels = torch.tensor(labels) + else: + self.labels = None + + def __getitem__(self, index): + data = self.datas[index] + if self.labels is not None: + label = self.labels[index] + return data, label + return data + + def __len__(self): + return len(self.datas) + + +def standardization(data): + mu = np.mean(data, axis=0) + sigma = np.std(data, axis=0) + return (data - mu) / sigma + + +def normalization(data): + _range = np.max(data) - np.min(data) + return (data - np.min(data)) / _range + + +# LSTM_cell的数目,维度,是否正则化 +def getData(filter_num, dims, if_norm: bool = False): + # 数据读入 + HI_merge_data_origin = np.load("../../dataset/HI_merge_data.npy") + + # plt.plot(HI_merge_data[0:1250, 1]) + # 去除掉退化特征不明显前面的点 + HI_merge_data = HI_merge_data_origin[0:1250, 1] + + # 是否正则化 + if if_norm: + HI_merge_data = normalization(HI_merge_data) + + # plt.plot(HI_merge_data) + # plt.show() + (total_dims,) = HI_merge_data.shape + + # # 将其分成重叠采样状态-滑动窗口函数 + predict_data = np.empty(shape=[total_dims - filter_num, filter_num]) + + # 重叠采样获取时间部和训练次数 + for dim in range(total_dims - filter_num): + predict_data[dim] = HI_merge_data[dim:dim + filter_num] + + train_label = predict_data[dims:, :] + train_label_single = HI_merge_data[dims + filter_num - 1:-1] + + # 再重叠采样获取一个点的维度 + '''train_data.shape:(sample,filter_num) -> (sample,filter_num,dims)''' + + # # 将其分成重叠采样状态-滑动窗口函数 + train_data = np.empty(shape=[dims, total_dims - filter_num - dims, filter_num]) + + for dim in range(dims): + train_data[dim] = predict_data[dim:total_dims - filter_num - dims + dim, :] + + # 转置变成想要的数据 (dims,sample,filter_num) -> (sample,filter_num,dims) + + train_data = np.transpose(train_data, [1, 2, 0]) + + # todo 解决模型保存时,query无法序列化的问题 + total_data = HI_merge_data + + print("total_data.shape:", total_data.shape) + print("train_data.shape:", train_data.shape) # (20, 1200, 30) + print("train_label.shape:", train_label.shape) # (20, 1200) + print("train_label_single.shape:", train_label_single.shape) + + # 所有的原始数据;所有的训练数据;所有的训练标签(预测一个序列);所有的训练标签(预测一个点) + return total_data, train_data, train_label, train_label_single + + +def splitValData(data, label, label_single, predict_num=50): + sample, hidden, feature = data.shape + + train_data = data[:sample - predict_num, :, :] + val_data = data[sample - predict_num:, :, :] + + train_label = label[:sample - predict_num, :] + val_label = label[sample - predict_num:, :] + + train_label_single = label_single[:sample - predict_num, ] + val_label_single = label_single[sample - predict_num:, ] + + return train_data, val_data, train_label, val_label, train_label_single, val_label_single + + +def getTotalData(hidden_num, feature, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + if is_single: + total_dataset = Nor_Dataset(train_data, train_label_single) + else: + total_dataset = Nor_Dataset(train_data, train_label) + return total_data, total_dataset + + +# lstm细胞数,channel数,预测多少个点,是否正则化 +def getDataset(hidden_num, feature, predict_num, is_single=True, is_norm=False): + total_data, train_data, train_label, train_label_single = getData(hidden_num, feature, is_norm) + # 根据预测的点数划分训练集和测试集(验证集) + train_data, val_data, train_label, val_label, train_label_single, val_label_single = splitValData(train_data, + train_label, + train_label_single, + predict_num=predict_num) + if is_single: + train_dataset = Nor_Dataset(train_data, train_label_single) + val_dataset = Nor_Dataset(val_data, val_label_single) + else: + train_dataset = Nor_Dataset(train_data, train_label) + val_dataset = Nor_Dataset(val_data, val_label) + + return train_dataset, val_dataset diff --git a/pytorch_example/RUL/otherIdea/dctLSTM/model.py b/pytorch_example/RUL/otherIdea/dctLSTM/model.py new file mode 100644 index 0000000..7ba4f45 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctLSTM/model.py @@ -0,0 +1,244 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from RUL.baseModel.dctChannelAttention import dct_channel_block + + +class LSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(LSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + attention_list = [] + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append( + LSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias), + ) + attention_list.append( + dct_channel_block(self.hidden_dim[i]) + ) + self.attention_list = nn.ModuleList(attention_list) + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c) or (b, t, c) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + + # TODO 每层之间增加一个dct_attention + layer_output = self.attention_list[layer_idx](layer_output) + + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[512, 256], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + self.backbone = nn.Sequential( + nn.Linear(in_features=256, out_features=128), + nn.ReLU(), + nn.Linear(in_features=128, out_features=64), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(64), + nn.Linear(in_features=64, out_features=32), + nn.ReLU(), + nn.Dropout(0.2), + nn.BatchNorm1d(32), + nn.ReLU(), + nn.Linear(in_features=32, out_features=16), + nn.Linear(in_features=16, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/dctLSTM/modelForEasy.py b/pytorch_example/RUL/otherIdea/dctLSTM/modelForEasy.py new file mode 100644 index 0000000..e0af5a7 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctLSTM/modelForEasy.py @@ -0,0 +1,237 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 10:46 +@Usage : +@Desc : convLSTM 2D基本实现 +''' + +import torch.nn as nn +import torch +from RUL.baseModel.dctChannelAttention import dct_channel_block + + +class LSTMCell(nn.Module): + + def __init__(self, input_dim, hidden_dim, bias): + """ + Initialize ConvLSTM cell. + + Parameters + ---------- + input_dim: int + Number of channels of input tensor. + hidden_dim: int + Number of channels of hidden state. + kernel_size: int + Size of the convolutional kernel. + bias: bool + Whether or not to add the bias. + + Input: + A tensor of size B, T, C + B: bacth_size + T: timestamp + C: channel + """ + + super(LSTMCell, self).__init__() + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.bias = bias + + self.hidden = nn.Linear(in_features=self.input_dim + self.hidden_dim, + out_features=4 * self.hidden_dim, + bias=self.bias) + + def forward(self, input_tensor, cur_state): + # shape :b,c + h_cur, c_cur = cur_state + + combined = torch.cat([input_tensor, h_cur], dim=-1) # concatenate along channel axis + + combined_linear = self.hidden(combined) + cc_i, cc_f, cc_o, cc_g = torch.split(combined_linear, self.hidden_dim, dim=1) + i = torch.sigmoid(cc_i) + f = torch.sigmoid(cc_f) + o = torch.sigmoid(cc_o) + g = torch.tanh(cc_g) + + c_next = f * c_cur + i * g + h_next = o * torch.tanh(c_next) + + return h_next, c_next + + def init_hidden(self, batch_size): + return (torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device), + torch.zeros(batch_size, self.hidden_dim, device=self.hidden.weight.device)) + + +class LSTM(nn.Module): + """ + + Parameters: + input_dim: Number of channels in input + hidden_dim: Number of hidden channels + kernel_size: Size of kernel in convolutions + num_layers: Number of LSTM layers stacked on each other + batch_first: Whether or not dimension 0 is the batch or not + bias: Bias or no bias in Convolution + return_all_layers: Return the list of computations for all layers + Note: Will do same padding. + + Input: + A tensor of size B, T, C or T, B, C + Output: + A tuple of two lists of length num_layers (or length 1 if return_all_layers is False). + 0 - layer_output_list is the list of lists of length T of each output + 1 - last_state_list is the list of last states + each element of the list is a tuple (h, c) for hidden state and memory + Example: + >> x = torch.rand((32, 10, 64)) + >> convlstm = ConvLSTM(64, 16, 3, 1, True, True, False) + >> _, last_states = convlstm(x) + >> h = last_states[0][0] # 0 for layer index, 0 for h index + """ + + def __init__(self, input_dim, hidden_dim, num_layers, + batch_first=False, bias=True, return_all_layers=False): + super(LSTM, self).__init__() + + # Make sure that both `kernel_size` and `hidden_dim` are lists having len == num_layers + hidden_dim = self._extend_for_multilayer(hidden_dim, num_layers) + if not len(hidden_dim) == num_layers: + raise ValueError('Inconsistent list length.') + + self.input_dim = input_dim + self.hidden_dim = hidden_dim + self.num_layers = num_layers + self.batch_first = batch_first + self.bias = bias + self.return_all_layers = return_all_layers + + cell_list = [] + attention_list = [] + for i in range(0, self.num_layers): + cur_input_dim = self.input_dim if i == 0 else self.hidden_dim[i - 1] + + cell_list.append( + LSTMCell(input_dim=cur_input_dim, + hidden_dim=self.hidden_dim[i], + bias=self.bias), + ) + attention_list.append( + dct_channel_block(self.hidden_dim[i]) + ) + self.attention_list = nn.ModuleList(attention_list) + self.cell_list = nn.ModuleList(cell_list) + + def forward(self, input_tensor, hidden_state=None): + """ + + Parameters + ---------- + input_tensor: todo + 5-D Tensor either of shape (t, b, c) or (b, t, c) + hidden_state: todo + None. todo implement stateful + + Returns + ------- + last_state_list, layer_output + """ + + if not self.batch_first: + # 等同于transpose + # (t, b, c, h, w) -> (b, t, c, h, w) + input_tensor = input_tensor.permute(1, 0, 2) + + b, _, _ = input_tensor.size() + + # Implement stateful ConvLSTM + if hidden_state is not None: + raise NotImplementedError() + else: + # Since the init is done in forward. Can send image size here + hidden_state = self._init_hidden(batch_size=b) + + layer_output_list = [] + last_state_list = [] + + timestamp = input_tensor.size(1) + cur_layer_input = input_tensor + + for layer_idx in range(self.num_layers): + + h, c = hidden_state[layer_idx] + output_inner = [] + for t in range(timestamp): + h, c = self.cell_list[layer_idx](input_tensor=cur_layer_input[:, t, :], + cur_state=[h, c]) + output_inner.append(h) + + layer_output = torch.stack(output_inner, dim=1) + + # TODO 每层之间增加一个dct_attention + layer_output = self.attention_list[layer_idx](layer_output) + + cur_layer_input = layer_output + + layer_output_list.append(layer_output) + last_state_list.append([h, c]) + + if not self.return_all_layers: + layer_output_list = layer_output_list[-1:] + last_state_list = last_state_list[-1:] + + return layer_output_list, last_state_list + + def _init_hidden(self, batch_size): + init_states = [] + for i in range(self.num_layers): + init_states.append(self.cell_list[i].init_hidden(batch_size)) + return init_states + + @staticmethod + def _extend_for_multilayer(param, num_layers): + if not isinstance(param, list): + param = [param] * num_layers + return param + + +class PredictModel(nn.Module): + + def __init__(self, input_dim): + super(PredictModel, self).__init__() + + self.lstm = LSTM(input_dim=input_dim, hidden_dim=[64, 64], num_layers=2, batch_first=True, bias=True, + return_all_layers=False) + self.backbone = nn.Sequential( + nn.Linear(in_features=64, out_features=64), + nn.Linear(in_features=64, out_features=64), + nn.BatchNorm1d(64), + nn.ReLU(), + nn.Dropout(0.5), + nn.Linear(in_features=64, out_features=1) + ) + + def forward(self, input_tensor): + input_tensor = input_tensor.to(torch.float32) + layer_output_list, last_states = self.lstm(input_tensor) + last_timestamp = last_states[0][0] + predict = self.backbone(last_timestamp) + return predict + + +if __name__ == '__main__': + x = torch.rand((32, 10, 64)) + lstm = LSTM(input_dim=64, hidden_dim=16, num_layers=1, batch_first=True, bias=True, + return_all_layers=False) + layer_output_list, last_states = lstm(x) + + all = layer_output_list[0] + h = last_states[0][0] + print(all.size()) + print(h.size()) diff --git a/pytorch_example/RUL/otherIdea/dctLSTM/test.py b/pytorch_example/RUL/otherIdea/dctLSTM/test.py new file mode 100644 index 0000000..e9e9892 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctLSTM/test.py @@ -0,0 +1,119 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 16:27 +@Usage : +@Desc : +''' + +import numpy as np +import torch +from RUL.otherIdea.dctLSTM.loadData import getDataset, getTotalData +from RUL.otherIdea.dctLSTM.modelForEasy import PredictModel +from torch.utils.data import DataLoader +import matplotlib.pyplot as plt +from RUL.baseModel.plot import plot_prediction, plot_forSelf +from RUL.baseModel.loss.Evaluate import getEvaluate + +# 仅使用预测出来的最新的一个点预测以后 +def predictOneByOne(model, train_data, predict_num=50): + # 取出训练数据的最后一条 + each_predict_data = train_data + predicted_list = np.empty(shape=(predict_num, 1)) # (5,filter_num,30) + # all_data = total_data # (1201,) + for each_predict in range(predict_num): + # predicted_data.shape : (1,1) + predicted_data = model(each_predict_data).cpu().detach().numpy()[-1] # (batch_size,filer_num,1) + predicted_list[each_predict] = predicted_data + each_predict_data = each_predict_data.numpy() + # (1,1) => (10,1) + # 中间拼接过程: (1) => (10) => (40,10) => (30,40,10) + a = np.concatenate([each_predict_data[-1, -1, 1:], predicted_data], axis=0) + b = np.concatenate([each_predict_data[-1, 1:, :], np.expand_dims(a, axis=0)], axis=0) + c = np.concatenate([each_predict_data[1:, :, :], np.expand_dims(b, axis=0)], axis=0) + + each_predict_data = torch.tensor(c) + + return np.squeeze(predicted_list) + + +def test(hidden_num, feature, predict_num, batch_size, save_path, save_fig_name, is_single=True, is_norm=False): + total_data, total_dataset = getTotalData(hidden_num, feature, is_single=is_single, is_norm=is_norm) + train_dataset, val_dataset = getDataset(hidden_num, feature, predict_num=predict_num, is_single=is_single, + is_norm=is_norm) + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False) + + # 加载网络 + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") + model = PredictModel(input_dim=feature).to(device) + + model.load_state_dict( + torch.load(save_path, map_location=device) + ) + + print(model) + params_num = sum(param.numel() for param in model.parameters()) + print('参数数量:{}'.format(params_num)) + + model.eval() + + predicted_data_easy = total_data[:hidden_num + feature, ] + predicted_data_hard = total_data[:hidden_num + feature, ] + + + # 衡量矩阵 + train_list = [] + easy_list = [] + val_label = [] + + with torch.no_grad(): + for batch_idx, (data, label) in enumerate(train_loader): + data, label = data.to(device), label.to(device) + last_train_data = data + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + predicted_data_hard = np.concatenate( + [predicted_data_hard, each_predicted_data], + axis=0) + train_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + + # 简单版的,每次预测重新用已知的 + for batch_idx, (data, label) in enumerate(val_loader): + data, label = data.to(device), label.to(device) + each_predicted_data = torch.squeeze(model(data)).cpu().detach().numpy() + predicted_data_easy = np.concatenate( + [predicted_data_easy, each_predicted_data], + axis=0) + easy_list.append(getEvaluate(label.cpu().detach().numpy(), each_predicted_data)) + val_label = np.concatenate( + [val_label, label.cpu().detach().numpy()], + axis=0) + + # 困难版的,每次预测基于上次的预测 + predict_hard = predictOneByOne(model, last_train_data, predict_num=predict_num) + predicted_data_hard = np.concatenate([predicted_data_hard, + predict_hard], axis=0) + ####衡量 + train_evaluate = np.mean(train_list, axis=0) + easy_evaluate = np.mean(easy_list, axis=0) + hard_evaluate = getEvaluate(val_label, predict_hard) + print('train: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (train_evaluate[0], train_evaluate[1], train_evaluate[2], train_evaluate[3])) + print('easy: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (easy_evaluate[0], easy_evaluate[1], easy_evaluate[2], easy_evaluate[3])) + print('hard: RMSE %.6f, MAE %.6f, MAPE %.6f, Score %.6f' % + (hard_evaluate[0], hard_evaluate[1], hard_evaluate[2], hard_evaluate[3])) + + plot_prediction(total_data, predicted_data_easy, predicted_data_hard, save_fig_name, predict_num=predict_num) + plot_forSelf(total_data, predicted_data_easy, predicted_data_hard) + + +if __name__ == '__main__': + test(40, 10, 50, 32, + "./parameters\dctLSTM_hidden40_feature10_predict50_epoch80_trainLoss0.05818896507844329_valLoss0.21667905896902084.pkl" + ) diff --git a/pytorch_example/RUL/otherIdea/dctLSTM/train.py b/pytorch_example/RUL/otherIdea/dctLSTM/train.py new file mode 100644 index 0000000..7c24af4 --- /dev/null +++ b/pytorch_example/RUL/otherIdea/dctLSTM/train.py @@ -0,0 +1,203 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/10 14:56 +@Usage : +@Desc : 训练LSTM +''' +import os +import time +import random +import numpy as np +import torch +import torch.nn as nn +import torch.nn.functional as F +import matplotlib.pyplot as plt +from torch.utils.data import DataLoader +from RUL.otherIdea.dctLSTM.modelForEasy import PredictModel +from RUL.otherIdea.dctLSTM.loadData import getDataset +from RUL.otherIdea.dctLSTM.test import test +from RUL.baseModel.CommonFunction import IsStopTraining +import RUL.baseModel.utils.utils as utils +import math + +''' +超参数设置: +''' +hidden_num = 40 # LSTM细胞个数 +feature = 10 # 一个点的维度 +batch_size = 32 +EPOCH = 1000 +predict_num = 200 # 预测个数 +seed = 250 +is_norm = False +is_single = True +model_name = "dctLSTM" +base_save = r"parameters/{0}_hidden{1}_feature{2}_predict{3}".format(model_name, hidden_num, feature, + predict_num) +save_fig_name = 'fig/seed{0}_hidden{1}_feature{2}_predict{3}'.format(seed, hidden_num, feature, predict_num) + +if not os.path.exists("parameters"): + os.makedirs("parameters") +if not os.path.exists("fig"): + os.makedirs("fig") + + +def get_dataset(): + '''得到数据集''' + train_dataset, val_dataset = getDataset( + hidden_num=hidden_num, feature=feature, predict_num=predict_num, is_single=is_single, is_norm=is_norm) + '''DataLoader''' + + train_loader = DataLoader(dataset=train_dataset, batch_size=batch_size, shuffle=True, drop_last=False) + val_loader = DataLoader(dataset=val_dataset, batch_size=batch_size, shuffle=False, drop_last=False) + return train_loader, val_loader + + +def train(device, lr, lr_patience, early_stop_patience, epochs): + '''预测模型''' + global best_save_path + model = PredictModel(input_dim=feature) + '''得到数据集''' + train_loader, val_loader = get_dataset() + criterion = nn.MSELoss().to(device) + + optimizer_model = torch.optim.SGD(model.parameters(), lr=lr) + + scheduler_model = torch.optim.lr_scheduler.ReduceLROnPlateau(optimizer_model, mode="min", factor=0.5, + patience=lr_patience) + + def zero_grad_all(): + optimizer_model.zero_grad() + + train_loss_list = [] + val_loss_list = [] + best_save_path = None + for epoch in range(epochs): + epoch_start_time = time.time() + train_loss = 0.0 + val_loss = 0.0 + + model.train() + + for (train_batch_idx, (train_data, train_label)) in enumerate(train_loader): + train_data, train_label = train_data.to(device), train_label.to(device) + + zero_grad_all() + + predict_data = torch.squeeze(model(train_data)) + + # MSE损失 + loss = criterion(predict_data, train_label) + + loss.backward() + optimizer_model.step() + + zero_grad_all() + + train_loss += loss.item() + + model.eval() + + with torch.no_grad(): + for val_batch_idx, (val_data, val_label) in enumerate(val_loader): + val_data, val_label = val_data.to(device), val_label.to(device) + val_predict_data = torch.squeeze(model(val_data)) + + loss = criterion(val_predict_data, val_label) + val_loss += loss.item() + + scheduler_model.step(val_loss) + + train_loss = train_loss / len(train_loader) + val_loss = val_loss / len(val_loader) + print( + "[{:03d}/{:03d}] {:2.2f} sec(s) train_loss: {:3.9f} | val_loss: {:3.9f} | Learning rate : {:3.6f}".format( + epoch + 1, epochs, time.time() - epoch_start_time, + train_loss, + val_loss, + optimizer_model.state_dict()['param_groups'][0]['lr'])) + + # 保存在验证集上loss最小的模型 + # if val_loss_list.__len__() > 0 and (val_loss / val_dataset.__len__()) < min(val_loss_list): + # 如果精度大于最高精度,则保存 + + if len(val_loss_list) == 0 or val_loss < min(val_loss_list): + print("保存模型最佳模型成功") + # 保存模型参数 + if best_save_path != None: + utils.delete_file(best_save_path) + best_save_path = base_save + "_epoch" + str(epoch) + \ + "_trainLoss" + str(train_loss) + \ + "_valLoss" + str(val_loss) + ".pkl" + torch.save(model.state_dict(), + best_save_path) + + train_loss_list.append(train_loss) + + val_loss_list.append(val_loss) + + if IsStopTraining(history_loss=val_loss_list, patience=early_stop_patience): + break + + '''保存的模型参数的路径''' + + from matplotlib import rcParams + + config = { + "font.family": 'Times New Roman', # 设置字体类型 + "axes.unicode_minus": False, # 解决负号无法显示的问题 + "axes.labelsize": 13 + } + rcParams.update(config) + + pic1 = plt.figure(figsize=(12, 6), dpi=200) + + plt.plot(np.arange(1, len(train_loss_list) + 1), train_loss_list, 'b', label='Training Loss') + plt.plot(np.arange(1, len(train_loss_list) + 1), val_loss_list, 'r', label='Validation Loss') + # plt.ylim(0, 0.08) # 设置y轴范围 + plt.title('Training & Validation loss') + plt.xlabel('epoch') + plt.ylabel('loss') + plt.legend(loc='upper right') + plt.grid(alpha=0.4) + + # 获取当前时间戳 + timestamp = int(time.time()) + + # 将时间戳转换为字符串 + timestamp_str = str(timestamp) + plt.savefig(timestamp_str, dpi=200) + plt.show() + + return best_save_path + + +if __name__ == '__main__': + + begin = time.time() + + if torch.cuda.is_available(): + device = torch.device("cuda:0") + else: + device = torch.device("cpu") + + + torch.manual_seed(seed) + random.seed(seed) + np.random.seed(seed) + + '''训练''' + save_path = train(device, lr=0.01, lr_patience=10, early_stop_patience=20, epochs=1000) + + end = time.time() + + '''测试''' + # test1(5, src_condition, tar_condition, G_params_path, LC_params_path) + + test(hidden_num, feature, predict_num=predict_num, + batch_size=batch_size, save_path=save_path, + is_single=is_single, is_norm=is_norm,save_fig_name=save_fig_name) + + print("训练耗时:{:3.2f}s".format(end - begin)) diff --git a/pytorch_example/__init__.py b/pytorch_example/__init__.py new file mode 100644 index 0000000..090d185 --- /dev/null +++ b/pytorch_example/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/9 21:32 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/temp/__init__.py b/pytorch_example/temp/__init__.py new file mode 100644 index 0000000..4ff6fef --- /dev/null +++ b/pytorch_example/temp/__init__.py @@ -0,0 +1,8 @@ +#-*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 13:18 +@Usage : +@Desc : +''' \ No newline at end of file diff --git a/pytorch_example/temp/dctTest.py b/pytorch_example/temp/dctTest.py new file mode 100644 index 0000000..9b80dbb --- /dev/null +++ b/pytorch_example/temp/dctTest.py @@ -0,0 +1,32 @@ +# -*- encoding:utf-8 -*- + +''' +@Author : dingjiawen +@Date : 2023/11/15 13:18 +@Usage : +@Desc : +''' + +import torch_dct as dct +import numpy as np +import torch + +a = np.load("a.npy") +b = np.load("b.npy") + +a = torch.tensor(a) + +c = dct.dct(x=a) + +d = [] + +for i in range(a.shape[1]): + d.append(dct.dct(a[:,i,:])) +d = torch.stack(d,dim=1) + +torch.nn.Linear() +print("a.shape:",a.shape) +print("a:",a) +print("b:",b) +print("c:",c) +print("d:",d)