Skip to content →

Author: Daoyuan Li

Apple Magic Mouse on Windows 11

To install driver for Apple Magic Mouse on Windows 11 and enable scrolling, follow these steps:

  1. Download driver from https://support.apple.com/kb/DL1837?locale=en_US
  2. Extract the AppleWirelessMouse64.exe file from bootcamp5.1.5769.zip\BootCamp\Drivers\Apple
  3. Install AppleWirelessMouse64.exe
  4. Remove Magic Mouse device in Windows Bluetooth
  5. Switch off Magic Mouse and swith it back on
  6. Add a new Bluetooth device

References:

  1. https://discussions.apple.com/thread/8521118
  2. https://www.youtube.com/watch?v=znpMBFD0ZR0&ab_channel=Petiksmode
  3. https://magicutilities.net/ (paid software with free trial)
Leave a Comment

Effective Data Science Team Leadership: Challenges

Team leaders play a vital role in the success of any team, whether it’s a small start-up or a large corporation. A team leader is like a conductor leading an orchestra. Just as a conductor brings together a group of musicians with different instruments and backgrounds, a team leader brings together a group of individuals with different skills and expertise. The conductor’s job is to create a cohesive and harmonious piece of music, and the team leader’s job is to create a cohesive and harmonious team.

Like a conductor, a team leader must have a clear vision of what they want to achieve and be able to communicate that vision to their team. They must also be able to listen to the needs and concerns of their team members and adapt their approach as needed. Just as a conductor may need to make adjustments to the tempo or dynamics of a piece of music based on the capabilities of the musicians, a team leader may need to make adjustments to their management style based on the needs and skills of their team.

A team leader must also be able to motivate and inspire their team, just as a conductor must be able to inspire the musicians to give their best performance. This may involve setting clear goals and expectations, providing constructive feedback, and recognizing and rewarding good performance.

Finally, a team leader must be able to bring out the best in their team, just as a conductor must be able to bring out the best in their musicians. This may involve identifying and addressing any issues or conflicts within the team, as well as fostering a positive and inclusive work environment.

The same principles of team leadership that apply to an orchestra also apply to businesses. Good business leaders have a clear vision for their company and are able to communicate that vision to their team. They are able to motivate and inspire their employees, and bring out the best in them. They are also able to adapt to changing circumstances and make adjustments as needed.

The impact of good business leaders cannot be overstated. Good business leaders have the ability to take a company to new heights, driving innovation and growth. They are able to create a positive and productive work environment, which can lead to increased employee satisfaction and retention. Good business leaders are also able to make sound decisions that drive the success of the company. One example of a good business leader is Jeff Bezos, the Founder of Amazon. Bezos has been able to take Amazon from a small online bookstore to a global e-commerce giant. He has a clear vision for the company and has consistently been able to adapt to changing circumstances and stay ahead of the competition. Bezos has also fostered a culture of innovation at Amazon, and has played a key role in driving the company’s growth.

On the other hand, bad business leaders can have a detrimental impact on a company. They may lack a clear vision or be unable to effectively communicate that vision to their team. They may also be inflexible and resistant to change, which can stifle innovation and growth. Bad business leaders may also create a negative work environment, leading to low employee morale and high turnover. Ultimately, bad business leaders can make poor decisions that can lead to the failure of the company. An example of a bad business leader is Elizabeth Holmes, the former CEO of Theranos. Holmes had a vision for revolutionizing the healthcare industry with her company’s technology, but was unable to effectively communicate that vision to her team and to gear the team towards a realistic vision. She was also resistant to change and unwilling to listen to the concerns of her team, leading to a number of problems within the company. Ultimately, Holmes’ poor leadership contributed to the failure of Theranos.

In conclusion, good business leaders are essential for the success of a company. They are able to drive innovation and growth, create a positive work environment, and make sound decisions. On the other hand, bad business leaders can have a detrimental impact on a company, leading to failure. The impact of good and bad business leaders can be seen in real-life examples throughout history and it is clear that strong leadership is crucial for the success of any business.


Leading software engineering teams

Not every leader has the opportunity to lead large businesses, but software engineering leaders are less difficult to find. However, leading a small or medium-sized software engineering team presents its own set of unique challenges and opportunities. It is also very different from leading other types of teams. Here, we explore some of the key characteristics of software engineering teams and how they differ from other types of teams, and we will discuss some of the key challenges and considerations for leaders of these teams.

One of the most significant differences between software engineering teams and other types of teams is the skill level and focus of team members. Software engineering team members are typically highly skilled and deeply knowledgeable about their work, with a focus on problem-solving and creativity. As a leader, it is important to recognize and respect the skills and expertise of your team members, and to create an environment that allows them to focus on these areas. This may involve setting clear goals and objectives, providing resources and support, and encouraging collaboration and innovation within the team.

Another key difference between software engineering teams and other types of teams is the organizational structure. Many software engineering teams operate with a flat organizational structure, with little or no hierarchy. This allows team members to collaborate and communicate more easily, and can be a key factor in the team’s success. As a leader, it is important to embrace this flat structure and to foster an open and collaborative team culture. This may involve facilitating communication, resolving conflicts, and building trust and collaboration within the team.

Software development projects are also typically very complex, with many different components and dependencies. As a leader, it is important to have a deep understanding of the project and to be able to effectively communicate this understanding to your team. You should also be able to anticipate and plan for potential challenges and roadblocks, and be able to adapt and pivot as needed.

Another major difference between software engineering teams and other types of teams is the rapid pace of technological change in the field. New technologies and approaches are constantly emerging, and it is important for leaders of software engineering teams to stay up to date with these developments and to be able to effectively incorporate them into their team’s work. This may require continuous learning and professional development efforts, such as attending conferences, taking online courses, and reading industry publications.

In addition to these technical challenges, leaders of software engineering teams also need to be able to effectively manage stakeholder expectations and team dynamics. Software development projects often have many stakeholders, with different expectations and priorities, and it is important for leaders to be able to effectively manage these expectations and to communicate effectively with stakeholders to ensure that the project stays on track and meets its goals. Managing team dynamics is also critical, as software engineering teams can be diverse, with team members from different backgrounds and with different personalities. As a leader, it is important to be able to effectively manage team dynamics and to foster a positive and inclusive team culture.

By understanding the characteristics of software engineering teams and the key challenges and considerations for leaders of these teams, it is obvious that leading a software engineering team is a unique and challenging responsibility, requiring a range of technical, communication, and management skills.


Leading data science teams

Leading a data science team is once again different from leading a generic software engineering team in several key ways. There are several challenges that leaders may face when transitioning from leading a software engineering team to a data science team. Some of the key challenges include:

  1. Different decision-making processes: Data science teams often rely on data-driven decision making, which can be different from the decision-making processes used in software engineering teams. One key aspect of data-driven decision making in a data science team is the ability to efficiently explore and analyze large amounts of data. In many cases, the data sets that data science teams work with can be quite large, and it can be challenging to effectively analyze and extract insights from them. Leaders may need to learn how to effectively use data to inform their decisions and communicate the results of their analyses to their teams and stakeholders.
  2. Different technical skills: Data science teams typically require a different set of technical skills than software engineering teams. While software engineering teams focus on building and maintaining software applications, data science teams focus on collecting, analyzing, interpreting, and modelling data. To efficiently explore and analyze large data sets, data science teams often use a variety of tools and techniques. One common approach is to use big data technologies, such as Hadoop or Spark, which are designed to handle large data sets and enable distributed processing. These technologies can help data science teams to quickly and efficiently process and analyze data, even when it is too large to fit on a single machine. In addition to big data technologies, data science teams may also use specialized data exploration and visualization tools. These tools can help team members quickly and easily visualize and understand data, and identify patterns and trends that may not be immediately apparent. As a result, leaders may need to gain new technical skills, such as data analysis and machine learning, in order to effectively lead their teams.
  3. Different team structures: Data science teams may have different structures and workflows than software engineering teams. For example, data science teams may be more decentralized, with team members working on a variety of different projects at the same time. This can be a challenge for leaders who are used to more traditional, hierarchical team structures.
  4. Different cultural norms: Data science teams may also have different cultural norms and expectations than software engineering teams. For example, data science teams may place a greater emphasis on collaboration and cross-functional teamwork, while software engineering teams may be more focused on individual contributions. Leaders may need to adapt to these different cultural norms in order to effectively lead their teams. Data science teams often work closely with other teams and departments within an organization, such as product management, marketing, and sales. As the leader of a data science team, you will need to be able to effectively collaborate with these other teams, and be able to bridge the gap between technical and non-technical domains.
  5. Different stakeholder expectations: Data science teams may have different stakeholders with different expectations than software engineering teams. For example, data science teams may be more closely aligned with business functions, and may need to work more closely with business leaders to understand their needs and goals. Leaders may need to adapt to these different stakeholder expectations. As the leader of a data science team, you will need to be able to analyze large sets of data and use statistical and machine learning techniques to extract insights and inform business decisions. This requires a strong understanding of data analysis and visualization tools, as well as an ability to communicate complex technical concepts to non-technical stakeholders.
  6. Different team dynamics: Data science teams may have different team dynamics and communication styles than software engineering teams. For example, data science teams may involve more collaboration and cross-functional teamwork, which can require different leadership approaches and communication styles. Leaders may need to adapt to these different team dynamics in order to effectively lead their teams.
  7. Different tools and technologies: Data science teams may use different tools and technologies than software engineering teams. For example, data science teams may rely more heavily on data analysis and visualization tools, while software engineering teams may use more traditional software development tools. Leaders may need to learn how to effectively use these different tools and technologies in order to lead their teams effectively.
  8. Managing data privacy and security: Data science teams often work with large volumes of sensitive data, and may need to ensure that this data is handled securely and in compliance with relevant regulations. Leaders may need to learn about data privacy and security best practices in order to effectively manage these risks.
  9. Managing team members with diverse backgrounds: Data science teams may have team members with diverse backgrounds and expertise, including computer science, statistics, mathematics, and domain-specific knowledge. Leaders may need to learn how to effectively manage and motivate team members with these diverse backgrounds.
  10. Staying up to date with the latest engineering in the field: The field of data science is rapidly evolving, with new tools and technologies emerging constantly. Leaders may need to make a concerted effort to stay up to date with these developments in order to effectively lead their teams. This may require continuous learning and professional development efforts, such as attending conferences, taking online courses, and reading academic as well as industry publications. While it is difficult to quantify exactly how fast the field of data science is progressing, as it is a broad and rapidly-evolving field that encompasses a wide range of technologies and techniques. However, it is clear that the field is experiencing rapid growth and change. One way to measure the pace of change in the field is to look at the growth in the number of job openings for data scientists. According to data from the U.S. Bureau of Labor Statistics, employment of data scientists is projected to grow by 11% between 2019 and 2029, which is much faster than the average for all occupations. This rapid growth is a reflection of the increasing demand for data-driven insights and decision-making in a wide range of industries. Another way to measure the pace of change in the field is to look at the rate of development of new technologies and techniques. For example, the field of machine learning, which is a key component of data science, has seen rapid progress in recent years. In the past decade, there have been significant advances in machine learning algorithms, such as deep learning and reinforcement learning, which have enabled new applications and capabilities. Overall, it is clear that the field of data science is experiencing rapid growth and change, and it is important for data science teams to stay up-to-date and continuously learn in order to remain competitive.

To sum up, leading a data science team comes with its own set of challenges, including the need to stay up to date with rapid advancements in the field and to have a strong understanding of technical aspects of data science. Data science projects can also be complex and interdisciplinary, requiring effective organization and management. In my next blog post, I will discuss strategies for building and leading a successful data science team, including how to overcome these unique challenges.


Leave a Comment

GPTChat-aided Blogging

This post details how the earlier blog post was written.

My prompt

Response from ChatGPT

Here it goes!

Hi, can you help me writing blog post?

Sure, I can help you write a blog post. What is the topic of your blog post?

I was going through my previous posts, and I didn’t even remember I wrote them, and I forgot the books I’ve read. Revisiting my blog is like travelling back in time and rediscovering myself.

Here is a draft of your blog post on revisiting your old blog posts:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward.

That’s a good start, can you add more depth to it?

Sure, here is a revised version of your blog post with more depth:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future.

Could you complete it with some examples?

Sure, here is a revised version of your blog post with some examples:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "The Alchemist" by Paulo Coelho. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the central message of following your dreams. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of personal growth and the importance of listening to one's own heart.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points.

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future.

Replace the “The Alchemist” example with the book “First Love, Last Rites”.

Sure, here is a revised version of your blog post with the book "First Love, Last Rites" as the example:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points.

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future.

Add a few more example on writing skills.

Sure, here is a revised version of your blog post with additional examples of your writing skills:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points. I had also improved my ability to present complex ideas in a clear and concise manner, as demonstrated in a post where I analyzed the themes of identity and belonging in "The Great Gatsby".

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future.

Replace “The Great Gatsby” example with “The unconsciousness rules our lives”

Sure, here is a revised version of your blog post with "The unconsciousness rules our lives" as the example:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the

No, stick with the previous version with “The great gatsby”

Sure, here is the previous version of your blog post with "The Great Gatsby" as the example:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person

That’s not the correct version. Let’s continue with this one: Revisiting My Old Blog Posts: A Journey Through Time As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten. For example, I came across a post where I had written about “First Love, Last Rites” by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life. Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience. But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice. For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points. In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time. Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future.

Sure, here are some additional examples of your writing skills:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points. I had also improved my ability to present complex ideas in a clear and concise manner, as demonstrated in a post where I analyzed the themes of identity and belonging in "The Great Gatsby". In another post, I examined the concept of the unconscious mind and its influence on human behavior, using examples from "The unconsciousness rules our lives" by Sigmund Freud.

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching

Attribute part of my growth or improvement to life experiences such as meeting different persons, traveling, and life changing events such as losing my mother to cancer.

Sure, here is a revised version of your blog post that attributes your growth and improvement to life experiences:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience. Meeting different people, traveling to new places, and experiencing life-changing events such as losing my mother to cancer had all contributed to my growth and development as an individual.

But revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points. I had also improved my ability to present complex ideas in a clear and concise manner, as demonstrated in a post where I analyzed the themes of identity and belonging in "The Great Gatsby".

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had

please continue

Certainly, here is the remainder of your revised blog post:

been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. By acknowledging my past experiences and my progress as a reader and a writer, I am motivated to continue on this journey of self-discovery and self-improvement.

Now add a few paragraphs to attribute part of my growth or improvement to experiences such as meeting different persons, traveling, and life changing events such as losing my mother to cancer.

Certainly, here is a revised version of your blog post that attributes your growth and improvement to life experiences:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But my growth and development as an individual was not solely the result of reading and writing. Meeting different people, traveling to new places, and experiencing life-changing events such as losing my mother to cancer had all played a significant role in shaping my perspectives and helping me to grow as a person. These experiences helped me to see the world from different angles and to gain a deeper understanding of myself and others.

Rev

continue

Certainly, here is the remainder of your revised blog post:

isiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points. I had also improved my ability to present complex ideas in a clear and concise manner, as demonstrated in a post where I analyzed the themes of identity and belonging in "The Great Gatsby".

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. By acknowledging my past experiences and my progress as a reader and a writer, I am motivated to continue on this journey of self-discovery and self-improvement.

Add a new paragraph at the end with some action points, such as writing blog posts more frequently, and reading more books.

Certainly, here is a revised version of your blog post with an additional paragraph at the end with action points:

Revisiting My Old Blog Posts: A Journey Through Time

As I was going through my old blog posts, I was surprised to see how much I had forgotten about the books I had read and the things I had written about. It was like travelling back in time and rediscovering a part of myself that I had forgotten.

For example, I came across a post where I had written about "First Love, Last Rites" by Ian McEwan. As I reread my thoughts on the book, I was struck by how much my interpretation of the story had changed since I first read it. When I first read the book, I was impressed by the vivid and poetic language used by the author. However, upon revisiting the book and my old blog post, I realized that the book had also touched upon deeper themes such as the power of first love and the fragility of life.

Reading my old blog posts brought back memories of the time when I first read those books and shared my thoughts on them. It was interesting to see how my opinions and perspectives on certain topics had changed over the years. I realized that I had grown as a person, and my views on various subjects had evolved as I gained more knowledge and life experience.

But my growth and development as an individual was not solely the result of reading and writing. Meeting different people, traveling to new places, and experiencing life-changing events such as losing my mother to cancer had all played a significant role in shaping my perspectives and helping me to grow as a person. These experiences helped me to see the world from different angles and to gain a deeper understanding of myself and others.

Revisiting my old blog posts was not just about reminiscing about the past. It was also an opportunity for me to see how far I had come as a reader and a writer. I could see the progress I had made and the things I had learned since I first started blogging. I was able to identify my strengths and weaknesses as a writer, and I gained a deeper understanding of my own writing style and voice.

For example, I noticed that my writing had become more structured and focused over the years. In my earlier posts, I had a tendency to ramble and include tangential thoughts that distracted from the main message. However, as I reread my more recent posts, I could see that I had learned to be more concise and stick to the main points. I had also improved my ability to present complex ideas in a clear and concise manner, as demonstrated in a post where I analyzed the themes of identity and belonging in "The Great Gatsby".

In addition to personal growth, revisiting my old blog posts also reminded me of the value of consistency and dedication. I realized that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It reminded me that

continue

Certainly, here is the remainder of your revised blog post:

the journey of self-improvement is a long-term process, and that small steps taken consistently can lead to significant progress over time.

Overall, revisiting my old blog posts was a meaningful and enriching experience. It reminded me of the importance of reflection and the value of looking back at where we have been in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. By acknowledging my past experiences and my progress as a reader and a writer, I am motivated to continue on this journey of self-discovery and self-improvement.

In light of this experience, I have set some action points for myself to continue growing and improving as a reader and a writer. These include writing blog posts more frequently, reading more books from a diverse range of authors and genres, and seeking out new experiences that will challenge and enrich me. I am excited to see where this journey of self-improvement will take me next.

Good enough, can you further polish this text to sound a little bit more sophisticated?

Certainly, here is a revised version of your blog post that aims to sound more sophisticated:

Reflecting on Past Blog Posts: A Retrospective Journey

As I perused my older blog posts, I was struck by how much I had forgotten about the books I had read and the thoughts I had previously expressed. It was almost as if I were traveling back in time and rediscovering a part of myself that had been relegated to the recesses of my memory.

One post that particularly stood out to me was my review of Ian McEwan's "First Love, Last Rites". Upon rereading my thoughts on the book, I was struck by the extent to which my interpretation of the story had evolved since my initial reading. Initially, I had been enamored with the vivid and poetic language employed by the author. However, upon revisiting the text and my past musings, I came to realize that the novel also delved into deeper themes such as the transformative power of first love and the impermanence of life.

Rereading my old blog posts not only allowed me to reminisce about the past, but also provided me with the opportunity to assess my personal growth as both a reader and a writer. It was interesting to see how my opinions and perspectives on various subjects had changed over the years, a reflection of the ways in which I had grown and developed as an individual. This growth was not solely the result of my reading and writing endeavors, but was also influenced by the people I have met, the places I have visited, and the life-changing events, such as the loss of my mother to cancer, that have shaped my worldview.

In addition to personal growth, revisiting my old blog posts also emphasized the importance of consistency and dedication. I was reminded of the fact that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It was a reminder that the journey of self-improvement is a long-term process, and that small, consistent steps can lead to significant progress over time.

In conclusion, reflecting on my old blog posts was a meaningful and enriching experience. It emphasized the value of reflection and the importance of looking back in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. In light of this retrospective journey, I have set some action points for myself, including writing blog posts more frequently, reading a diverse range of books, and seeking out new experiences that will challenge and enrich me. I am eager to see where this journey of self-improvement will take me next.

Great, am I allowed to publish this post on my website?

You are welcome to use the revised version of your blog post on your website. I am an AI language model and do not hold any copyrights to the content that I generate, so you are free to use it as you see fit. However, it is important to remember that the content you publish on your website should always be accurate and respectful. If you are using information from other sources in your blog post, it is essential to properly cite those sources to give credit to the original authors and to ensure the accuracy of your information. Additionally, you should ensure that your content does not infringe on the copyright of others. I hope that this helps!

Can you make it longer with more examples?

Certainly, here is a revised version of your blog post that includes additional examples:

Reflecting on Past Blog Posts: A Retrospective Journey

As I perused my older blog posts, I was struck by how much I had forgotten about the books I had read and the thoughts I had previously expressed. It was almost as if I were traveling back in time and rediscovering a part of myself that had been relegated to the recesses of my memory.

One post that particularly stood out to me was my review of Ian McEwan's "First Love, Last Rites". Upon rereading my thoughts on the book, I was struck by the extent to which my interpretation of the story had evolved since my initial reading. Initially, I had been enamored with the vivid and poetic language employed by the author. However, upon revisiting the text and my past musings, I came to realize that the novel also delved into deeper themes such as the transformative power of first love and the impermanence of life.

Another post that I revisited was my analysis of F. Scott Fitzgerald's "The Great Gatsby". As I reread my thoughts on the novel, I was impressed by my own ability to present complex ideas in a clear and concise manner. I had examined the themes of identity and belonging in the text, and had drawn connections to the broader societal context in which the novel was set. This level of analysis and synthesis was a testament to the progress I had made as a reader and a writer.

Rereading my old blog posts not only allowed me to reminisce about the past, but also provided me with the opportunity to assess my personal growth as both a reader and a writer. It was interesting to see how my opinions and perspectives on various subjects had changed over the years, a reflection of the ways in which I had grown and developed as an individual. This growth was not solely the result of my reading and writing endeavors, but was also influenced by the people I have met, the places I have visited, and the life-changing events, such as the loss of my mother to cancer, that have shaped my worldview.

continue

Certainly, here is the remainder of your revised blog post:

In addition to personal growth, revisiting my old blog posts also emphasized the importance of consistency and dedication. I was reminded of the fact that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It was a reminder that the journey of self-improvement is a long-term process, and that small, consistent steps can lead to significant progress over time.

In conclusion, reflecting on my old blog posts was a meaningful and enriching experience. It emphasized the value of reflection and the importance of looking back in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. In light of this retrospective journey, I have set some action points for myself, including writing blog posts more frequently, reading a diverse range of books, and seeking out new experiences that will challenge and enrich me. I am eager to see where this journey of self-improvement will take me next.

For example, I am planning to take on the challenge of reading at least one book per month from a different genre or by a diverse range of authors. This will not only expose me to new ideas and perspectives, but will also help me to continue improving my reading comprehension and critical thinking skills. I am also committed to writing more frequently, as this will help me to hone my writing skills and to better express my thoughts and ideas. And finally, I am excited to seek out new experiences that will challenge and enrich me, such as traveling to new places or volunteering in my community. I believe that these actions will not only help me to continue growing and improving as a person, but will also make for more interesting and thought-provoking content for my blog.

Rewrite “The Great Gatsby” paragraph with something from “Blink: the power of thinking without thinking”

Certainly, here is a revised version of your blog post with the "The Great Gatsby" paragraph replaced with content from "Blink: The Power of Thinking Without Thinking":

Reflecting on Past Blog Posts: A Retrospective Journey

As I perused my older blog posts, I was struck by how much I had forgotten about the books I had read and the thoughts I had previously expressed. It was almost as if I were traveling back in time and rediscovering a part of myself that had been relegated to the recesses of my memory.

One post that particularly stood out to me was my review of Ian McEwan's "First Love, Last Rites". Upon rereading my thoughts on the book, I was struck by the extent to which my interpretation of the story had evolved since my initial reading. Initially, I had been enamored with the vivid and poetic language employed by the author. However, upon revisiting the text and my past musings, I came to realize that the novel also delved into deeper themes such as the transformative power of first love and the impermanence of life.

Another post that I revisited was my analysis of Malcolm Gladwell's "Blink: The Power of Thinking Without Thinking". In this post, I had examined the concept of "thin slicing" and its implications for decision making. I had explored the ways in which our unconscious mind is able to process vast amounts of information in a split second, and how this can sometimes lead to more accurate decisions than if we were to consciously analyze all of the available data. This post was a testament to my growth as a reader and a writer, as I had been able to clearly articulate and analyze complex ideas.

Rereading my old blog posts not only allowed me to reminisce about the past, but also provided me with the opportunity to assess my personal growth as both a reader and a writer. It was interesting to see how my opinions and perspectives on various subjects had changed over the years, a reflection of the ways in which I had grown and developed as an individual. This growth was not solely the result of my reading and writing endeavors, but was also influenced by the people I have met, the places I have visited, and the life-changing events, such as the loss of my mother to cancer, that have shaped my worldview.

continue

Certainly, here is the remainder of your revised blog post:

In addition to personal growth, revisiting my old blog posts also emphasized the importance of consistency and dedication. I was reminded of the fact that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It was a reminder that the journey of self-improvement is a long-term process, and that small, consistent steps can lead to significant progress over time.

In conclusion, reflecting on my old blog posts was a meaningful and enriching experience. It emphasized the value of reflection and the importance of looking back in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. In light of this retrospective journey, I have set some action points for myself, including writing blog posts more frequently, reading a diverse range of books, and seeking out new experiences that will challenge and enrich me. I am eager to see where this journey of self-improvement will take me next.

For example, I am planning to take on the challenge of reading at least one book per month from a different genre or by a diverse range of authors. This will not only expose me to new ideas and perspectives, but will also help me to continue improving my reading comprehension and critical thinking skills. I am also committed to writing more frequently, as this will help me to hone my writing skills and to better express my thoughts and ideas. And finally, I am excited to seek out new experiences that will challenge and enrich me, such as traveling to new places or volunteering in my community. I believe that these actions will not only help me to continue growing and improving as a person, but will also make for more interesting and thought-provoking content for my blog.

Leave a Comment

Reflecting on Past Blog Posts: A Retrospective Journey

As I perused my older blog posts, I was struck by how much I had forgotten about the books I had read and the thoughts I had previously expressed. It was almost as if I were traveling back in time and rediscovering a part of myself that had been relegated to the recesses of my memory.

One post that particularly stood out to me was my review of Ian McEwan’s “First Love, Last Rites”. Upon rereading my thoughts on the book, I was struck by the extent to which my interpretation of the story had evolved since my initial reading. Initially, I had been enamored with the vivid and poetic language employed by the author. However, upon revisiting the text and my past musings, I came to realize that the novel also delved into deeper themes such as the transformative power of first love and the impermanence of life.

Another post that I revisited was my analysis of Malcolm Gladwell’s “Blink: The Power of Thinking Without Thinking”. In this post, I had examined the concept of “thin slicing” and its implications for decision making. I had explored the ways in which our unconscious mind is able to process vast amounts of information in a split second, and how this can sometimes lead to more accurate decisions than if we were to consciously analyze all of the available data. This post was a testament to my growth as a reader and a writer, as I had been able to clearly articulate and analyze complex ideas.

Rereading my old blog posts not only allowed me to reminisce about the past, but also provided me with the opportunity to assess my personal growth as both a reader and a writer. It was interesting to see how my opinions and perspectives on various subjects had changed over the years, a reflection of the ways in which I had grown and developed as an individual. This growth was not solely the result of my reading and writing endeavors, but was also influenced by the people I have met, the places I have visited, and the life-changing events, such as the loss of my mother to cancer, that have shaped my worldview.

In addition to personal growth, revisiting my old blog posts also emphasized the importance of consistency and dedication. I was reminded of the fact that I had been consistently reading and writing for a number of years, and that this dedication had played a significant role in my development as a reader and a writer. It was a reminder that the journey of self-improvement is a long-term process, and that small, consistent steps can lead to significant progress over time.

In conclusion, reflecting on my old blog posts was a meaningful and enriching experience. It emphasized the value of reflection and the importance of looking back in order to move forward. It also encouraged me to continue learning, growing, and writing in the future. In light of this retrospective journey, I have set some action points for myself, including writing blog posts more frequently, reading a diverse range of books, and seeking out new experiences that will challenge and enrich me. I am eager to see where this journey of self-improvement will take me next.

For example, I am planning to take on the challenge of reading at least one book per month from a different genre or by a diverse range of authors. This will not only expose me to new ideas and perspectives, but will also help me to continue improving my reading comprehension and critical thinking skills. I am also committed to writing more frequently, as this will help me to hone my writing skills and to better express my thoughts and ideas. And finally, I am excited to seek out new experiences that will challenge and enrich me, such as traveling to new places or volunteering in my community. I believe that these actions will not only help me to continue growing and improving as a person, but will also make for more interesting and thought-provoking content for my blog.

Leave a Comment

Migrating self-hosted WordPress

When I started this website in 2009, I was using Joomla. Then at some point I switch to WordPress because it was much easier to manage my posts. And it was hosted at one.com, where I initially registered this domain name. However, the network and service wasn’t really stable and I had a lot of hiccups back then. As a result, in 2017 I migrated the website to Scaleway.com, which offers very cheap virtual machines and small bare metal instances.

Another reason why I switched was because I was also running a real-time crypto price crawling and algorithmic trading service with a few servers, and since my website didn’t have a ton of visitors, I could put it together with other services. Back then a small instance cost only 5 euros per month, and I found it to be more cost-effective than other cloud computing providers like AWS, GCP or Vultr. As time went by, I had more resource intensive services running, such as staking pools which require large volumes. I ended up upgrading those tiny instances, and adding more resources from Scaleway. Then later when I phased out such services and reduced the number of instances, I couldn’t switch back to the smaller instances because either they didn’t exist any more or I couldn’t downgrade the volume size. So in the end I was paying a large monthly bill to run a small WordPress application.

And today I finally managed to spare a few hours reviewing the services I need, and decided it to migrate it back to one.com, which I was already paying anyway. As a side note, the price of one.com subscription also increase by 4x or 5x in 10 years.

Migrating WordPress alone is easy: backup all the files and database, then copy files to one.com, import the database, and setup the DNS on Cloudflare. I asked ChatGPT to draw me this flowchart:

+-------------+                                +-------------+
| Old Server  |   Backup files and database   | Local Server |
+-------------+ ----------------------------> +-------------+
                                                    |
                                                    | Import database
                                                    v
                                               +------------+
                                               | New Server  |
                                               +------------+
                                                    |
                                                    | Update URLs in database
                                                    v
                                               +------------+
                                               | New Server  |
                                               +------------+

During the process, I also tried setting up a local LAMP+WP service with docker-compose (this repo is very useful: https://github.com/nezhar/wordpress-docker-compose) and tried exporting my posts into GoHugo format. In the end I believed it was too much hassle and not worth it.

A few issues I encountered during the migration process:

  1. .htaccess files should be set up properly, otherwise WP complains about 404 for sub pages.
  2. Some WP plugins were outdated (code highlighting, for example), so it caused some page rendering issues. When I replaced the plugin such issues are gone.
  3. File permissions has to be 744 or 755 for the wp-content/uploads folder.
  4. I used nslookup daoyuan.li ns01.one.com to get the IP of one.com’s server, and manually updated it on Cloudflare, since I prefer to use Cloudflare to manage my DNS. In the future I may need to automate this process, in case one.com moves my VM to another server. Or at lease I should monitor the output from ns01.one.com versus kara.ns.cloudflare.com.

Besides migrating WP, I also had a few other websites to migrate. But since they are all static websites, I used Cloudflare Pages to host them and assigned the domains to the corresponding Pages project.

I probably spent 3 to 4 hours migrating everything, and double checking everything works fine. Then I went ahead and terminated all instances, elastic IPs and volumes on Scaleway. That would save me a couple of hundred euros a year. Not bad ROI!

Leave a Comment

母亲说

妈是什么?

母亲因为肿瘤转移脑梗导致失明失语,我跟她视频叫了一声“妈!”,她看着手机屏幕,喃喃的如是说。我愣住了,前一天她虽然说话吐词不清,可是仍然辩得出我的声音,能够用简短的词语回答我。那一瞬间我的眼泪夺眶而出,替母亲感到委屈却又感到无能为力。“妈是什么”?我用苍白的语言无法回答这个问题,也许用母亲自己的话可以给这个问题一些注解。

我走了之后你们不要太伤心,人迟早都要走的。

母亲失语的前一个晚上跟父亲聊天的时候让他转告我。也许她当时已经知道自己时日不多了,即便是在那个时候,她依然在为我着想。从我出生那一天起,母亲便将她几乎所有的精力放在我身上。从小到大虽然条件不好,但是我有什么要求她都会尽力满足我。甚至有些回想起来并不合理的要求(比如给我买了录音机之后我又要买复读机),她都会努力且包容的满足我的要求。而她自己却舍不得给自己买一件新衣服,她自己的丝巾从结婚起一直用到现在,用了三四十年。这三十几年间搬家搬了两次,母亲的嫁妆依然在新家见证着母亲勤俭持家的成果。一辈子总是先为家人考虑,最后才考虑自己,默默的奉献了一辈子,所以妈是顾家的、无私的、伟大的。

我们没能给你挣下什么家业,你挣钱不容易,我这病反正看不好,就别看了。

那天母亲第一次突发脑梗,眼睛已经看不清楚东西,右手也伸不直了,她躺在病床上一边流泪一边这么跟我说。那是2021年6月27日,那天下午我要离开她回卢森堡办理家庭团聚许可。我只能安慰她,钱没有了可以再挣,人没有了就真的没有了。我让她不要有心理负担,积极配合医生治疗总会好起来的,身体好一点了我们卢森堡再见。那天我们一家三口在病房默默的流泪,眼泪中全是不舍和期盼。在母亲心里,她的生死甚至不如我的生活重要。

我许个愿,希望我的身体越来越好,为儿子减轻些负担。

母亲确诊一周年,我买了一个小蛋糕,在蛋糕上点上一支蜡烛,她十指紧握,对着蛋糕虔诚的说道。她总是怕给我添麻烦,自己生病了还对家人充满歉意。家人永远排在自己前面,这就是我的母亲。

我想学(缝纫),大人说好事怎么能都让我占了,我是后来自己摸索的。

那天母亲看到一个迷你缝纫机的广告,给我看了后我便买了一个。她用这个缝纫机缝了几条裤子,还把一条连衣裙改成了一件背心和一条裙子。我问她之前是不是跟师傅学过,她这样淡淡的回答我。原来母亲当年高考之后家人觉得她读书读的够多了,她想学缝纫大人也不支持。于是每当裁缝师傅到别人家做活的时候她就去旁边看着,再加上自己不断摸索,也就学会了。我小时候母亲给我和父亲做过花衬衫,原来这些都是母亲自学的。其实细想我并不吃惊,因为母亲一直都聪慧过人。她在学校的时候不仅学习优异,各项体育文艺活动也不落下。她曾自豪的跟我说当时唱歌高音别人都唱不上去,就她能唱上去。如果母亲出生在我们这个时代,她一定读了好大学,很可能成为理工科的学科专家,生活的一定比我好。也许是不希望我重复她自己人生中的遗憾,从小母亲便让我自己拿主意,而她则一直默默的鼓励我支持我。她对我的鼓励和支持让我远行,即便离别时母亲会依依不舍的送我离开并转过头去抹眼泪,她依然坚持让我自己把控自己人生的方向。

你放心,我还死不了,我知道我的身体怎么样。

去年年底在医院复查,查出癌细胞转移到了肝脏,医生认为她活不过三个月。我当时心急如焚,想回国陪着母亲,母亲却这样安慰我。事实证明母亲是对的,医生口中的三个月最后变成了八个月。母亲就是这么乐观、自信和了解自己。

我儿子在哪,我的家就在哪。

多年之前我在南通工作,接母亲跟我在南通一起生活了大半年。当时公司老板娘问母亲想不想家,她这样笑着回答。母亲能这么想,以及她话中的哲理让我感到很幸福,家是温暖的,家人在哪里哪里就是家。我就是母亲的家,母亲在我心里。

Nice to meet you! My name is …

我跟母亲在南通时,公司有几个瑞典籍员工和实习生偶尔跟我们一起聚会,母亲总是会兴奋的用她高中时学过的英语跟不懂中文的同事交流。自从母亲离开学校就没有机会接触英语,但她仍然能够记起学生时代的课文,相对我的记忆力母亲简直是过目不忘。我很多时候会想,要是母亲出生在我这个年代,我的学习肯定比不过她。

你是不是有什么烦心事瞒着我?

大学时有一次心情不好,后来调整心情后跟母亲通电话,她还是从我的言语之间感觉出来了异常,她这样问我之后我的委屈一下子化成泪水喷涌而出。母亲总是能感受到我最细微的情绪,并通过简单几句话开导我。也有人说我母亲性子直说话也直,这是因为母亲能够很快的感知事情背后的缘由,理解事情的轻重缓急,找到最直接的解决问题的方法。也可能是因为说话直得罪了人,母亲反而时常规劝我遇事要沉着冷静,不紧不慢的去解决问题,说话也不能太直,要留有余地。

你考了这么多分?哈哈哈!

中考拿到结果后,母亲得知我考得不错,正坐在小板凳上摘菜的她站起来接过我的成绩单,得知我可以上重点高中之后笑着一屁股坐在了菜盆里。我的一点点小成绩竟然让母亲忘乎所以,当然我的成绩很大程度上要归功于母亲,是她给了我学习的头脑,让我认识到学习的重要性,给我力所能及的辅导,以及每天陪着我写作业到凌晨,在炎热的夏天打着蒲扇为我驱赶蚊虫,为我默默的加油鼓劲。

不想活,有本事你跳啊!

我初中有天晚上作业实在写不完而我又困的不行,于是准备睡觉并让母亲第二天早上早点叫我起床继续写作业。然而第二天母亲看我实在太累了,便心疼的让我多睡了一会儿。我醒了之后异常生气,发了一通脾气后哭着说我不活了。母亲看着我又生气又心疼,于是她拉着我来到桥边故意推着我让我跳下去。就那么一下我似乎被惊醒了,也不敢寻死觅活,只是呆在桥上撕心裂肺的哭。她让闻声赶来的舅舅把我带回家看着,然后去学校叫了我的班主任到家,给我进行了思想教育之后让班主任把我带回了学校。我曾思考母亲当时为什么会那样去激我,也许是因为她了解我跟我有一定的默契吧,知道我不敢做出格的事情。

我说被子上哪来的血,我一拉被子,你的眼泪就下来了。

这是母亲给我讲我小时候的事情。那时候我调皮,让父母操了不少心。有一次我骑车把膝盖摔了怕父母批评,就想瞒着父母,在他们面前强忍疼痛故作镇定。有一天我躺在床上准备睡觉,母亲悄悄把我的被子拉开,看到了我受伤的膝盖。原来她之前整理被子的时候发现了血迹,便开始观察我有没有什么异常,估计也明白了几分。那一次母亲没有批评我,而是带我去看医生。我不知道从那之后我有没有更懂事,但是回想起来母亲似乎从那之后对我更加宽容慈爱了。

钱在我这里只有进来的,没有出去的。

如果母亲一个月有两千块钱的工资,她一个人一年一定可以存三万以上。在我甚至母亲的同龄人眼里这简直就是不可能的事情,但是母亲几乎每年都是这样。我问她是如何办到的时候,她如此自豪的跟我说。她一辈子并没有高工资,却存下来别人双倍工资都存不下来的存款,后来还给我钱帮我买房。在很多人眼里母亲舍不得用钱,她却并不在乎。她说自己吃的穿的都不比别人差,她教会我什么钱该花,什么钱不该花,如何开源节流,更重要的是潜移默化中我从母亲身上体会到了什么是消费什么是投资,以及储蓄是何等重要。

你以后不要做丁克族,最好多生几个孩子。

母亲这句话说了一半,后面半句应该是“不然老了之后没人陪在身边”。可能是怕我听了难受吧,作为独子却远在万里之外,在母亲最需要陪伴的时候缺席。在感情上,母亲希望我能留在身边;可是母亲太理智太无私,无时不刻不在为我着想,不愿因为自己打扰我的工作生活。

当时好几个比你大的都没报上名,我给你报上了。

小学入学报名的时候,招生的老师只给87年9月1号之前出生的学生报名,而我是9月底出生的,原则上得再上一年学前班等到下一年才能报名。轮到我的时候母亲灵机一动,报了我的农历生日八月初五,于是我就开始上小学了。母亲后来跟我说起这件事的时候很骄傲,因为她为我省了一年不必要的学前班。母亲虽然在大是大非前面坚持原则,但是却不拘泥于愚蠢的条条框框,敢于挑战一切不合理的规章制度。后来八月五日变成了我身份证上的官方生日,而母亲是北京时间2021年8月6日凌晨离开的。虽然弥留之际母亲已经完全不能说话、不能进食、不想吃药也没有力气睁开眼睛,但是我知道她是希望陪我过完我的生日再走的。母亲三十多年前给了我生命,含辛茹苦将我养育成人之后却悄无声息的离开了,也许母亲觉得她完成了她的使命可以安心的离开我了吧!

所以“妈是什么”?她生我、养我、教我为人处事,她疼我、爱我、事事都记挂着我,她包容我的所有缺点、也细腻的感知我的感受,她是我的灯塔、亦是我的港湾,她目送我扬帆、也静静地等我返航,她为我付出了一切,却仍觉得可以做得更多更好。那天我得知母亲再次脑梗失语后,害怕再也没有机会跟她说话,于是跟母亲说:“有您这么伟大的母亲把我养育大我已经知足了,有您这样母亲是我的骄傲和幸运!”母亲听到后点着头,泪水又下来了。母亲这一生所有的付出、心酸、无奈、认可、释然,都在无言中。虽然再也听不到母亲的淳淳教诲,吃不到她给我做的饭菜,但母亲并没有真正离开。她住在我心中,她的故事会被讲述、她的基因会被延续、她的精神会被传承,她无私的爱会像种子一样生根发芽并开出最绚烂的花!

附上母亲写给我的家书,她的教诲我毕生难忘!

Leave a Comment

Notes to myself: RTX 2070, Cuda, cudnn, caffe, and faceswap

Install NVIDIA driver for RTX 2070: https://www.geforce.com/drivers

sudo bash ~/Downloads/NVIDIA-Linux-x86_64-415.27.run

Install CUDA 10.0: https://developer.nvidia.com/cuda-downloads

sudo bash ~/Downloads/cuda_10.0.130_410.48_linux.run

DO NOT re-install the drivers suggested by the CUDA installer:
Install NVIDIA Accelerated Graphics Driver for Linux-x86_64 410.48?
(y)es/(n)o/(q)uit: n

$ nvidia-smi
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 415.27       Driver Version: 415.27       CUDA Version: 10.0     |
|-------------------------------+----------------------+----------------------+
| GPU  Name        Persistence-M| Bus-Id        Disp.A | Volatile Uncorr. ECC |
| Fan  Temp  Perf  Pwr:Usage/Cap|         Memory-Usage | GPU-Util  Compute M. |
|===============================+======================+======================|
|   0  GeForce RTX 2070    Off  | 00000000:1F:00.0 Off |                  N/A |
| 36%   31C    P0    N/A /  N/A |      0MiB /  7949MiB |      0%      Default |
+-------------------------------+----------------------+----------------------+

+-----------------------------------------------------------------------------+
| Processes:                                                       GPU Memory |
|  GPU       PID   Type   Process name                             Usage      |
|=============================================================================|
|  No running processes found                                                 |
+-----------------------------------------------------------------------------+

CuDNN:

cuDNN Runtime Library for Ubuntu18.04 (Deb)

cuDNN Developer Library for Ubuntu18.04 (Deb)

Caffe:

CMake Error: The following variables are used in this project, but they are set to NOTFOUND.
Please set them or make sure they are set and tested correctly in the CMake files:
CUDA_cublas_device_LIBRARY (ADVANCED)
linked by target “caffe” in directory /home/dli/Projects/caffe/src/caffe

Upgrade cmake:

$ ~/cmake-3.13.3-Linux-x86_64/bin/cmake -DCMAKE_INSTALL_PREFIX:PATH=/usr ..
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   system
--   thread
--   filesystem
--   chrono
--   date_time
--   atomic
-- Found gflags  (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libgflags.so)
-- Found glog    (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libglog.so)
-- Found PROTOBUF Compiler: /usr/bin/protoc
-- HDF5: Using hdf5 compiler wrapper to determine C configuration
-- HDF5: Using hdf5 compiler wrapper to determine CXX configuration
-- Found lmdb    (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/liblmdb.so)
-- Found LevelDB (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libleveldb.so)
-- Found Snappy  (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libsnappy.so)
-- CUDA detected: 10.0
-- Found cuDNN: ver. 7.4.2 found (include: /usr/include, library: /usr/lib/x86_64-linux-gnu/libcudnn.so)
-- Added CUDA NVCC flags for: sm_75
-- OpenCV found (/usr/share/OpenCV)
-- Found Atlas (include: /usr/include/x86_64-linux-gnu library: /usr/lib/x86_64-linux-gnu/libatlas.so lapack: /usr/lib/x86_64-linux-gnu/liblapack.so
-- NumPy ver. 1.16.0 found (include: /usr/local/lib/python2.7/dist-packages/numpy/core/include)
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   python
-- Detected Doxygen OUTPUT_DIRECTORY: ./doxygen/
--
-- ******************* Caffe Configuration Summary *******************
-- General:
--   Version           :   1.0.0
--   Git               :   1.0-132-g99bd9979
--   System            :   Linux
--   C++ compiler      :   /usr/bin/c++
--   Release CXX flags :   -O3 -DNDEBUG -fPIC -Wall -Wno-sign-compare -Wno-uninitialized
--   Debug CXX flags   :   -g -fPIC -Wall -Wno-sign-compare -Wno-uninitialized
--   Build type        :   Release
--
--   BUILD_SHARED_LIBS :   ON
--   BUILD_python      :   ON
--   BUILD_matlab      :   OFF
--   BUILD_docs        :   ON
--   CPU_ONLY          :   OFF
--   USE_OPENCV        :   ON
--   USE_LEVELDB       :   ON
--   USE_LMDB          :   ON
--   USE_NCCL          :   OFF
--   ALLOW_LMDB_NOLOCK :   OFF
--   USE_HDF5          :   ON
--
-- Dependencies:
--   BLAS              :   Yes (Atlas)
--   Boost             :   Yes (ver. 1.65)
--   glog              :   Yes
--   gflags            :   Yes
--   protobuf          :   Yes (ver. 3.0.0)
--   lmdb              :   Yes (ver. 0.9.21)
--   LevelDB           :   Yes (ver. 1.20)
--   Snappy            :   Yes (ver. ..)
--   OpenCV            :   Yes (ver. 3.2.0)
--   CUDA              :   Yes (ver. 10.0)
--
-- NVIDIA CUDA:
--   Target GPU(s)     :   Auto
--   GPU arch(s)       :   sm_75
--   cuDNN             :   Yes (ver. 7.4.2)
--
-- Python:
--   Interpreter       :   /usr/bin/python2.7 (ver. 2.7.15)
--   Libraries         :   /usr/lib/x86_64-linux-gnu/libpython2.7.so (ver 2.7.15rc1)
--   NumPy             :   /usr/local/lib/python2.7/dist-packages/numpy/core/include (ver 1.16.0)
--
-- Documentaion:
--   Doxygen           :   /usr/bin/doxygen (1.8.13)
--   config_file       :   /home/dli/Projects/caffe/.Doxyfile
--
-- Install:
--   Install path      :   /usr
--
-- Configuring done
-- Generating done
-- Build files have been written to: /home/dli/Projects/caffe/build
$ make -j16 all
$ make pycaffe
$ sudo make install
[  2%] Built target caffeproto
[ 87%] Built target caffe
[ 89%] Built target upgrade_solver_proto_text
[ 90%] Built target compute_image_mean
[ 90%] Built target caffe.bin
[ 91%] Built target upgrade_net_proto_binary
[ 93%] Built target convert_imageset
[ 94%] Built target extract_features
[ 95%] Built target upgrade_net_proto_text
[ 95%] Built target classification
[ 95%] Built target convert_mnist_data
[ 97%] Built target convert_cifar_data
[ 98%] Built target convert_mnist_siamese_data
[100%] Built target pycaffe
Install the project...
-- Install configuration: "Release"
-- Installing: /usr/share/Caffe/CaffeConfig.cmake
-- Installing: /usr/share/Caffe/CaffeTargets.cmake
-- Installing: /usr/share/Caffe/CaffeTargets-release.cmake
-- Installing: /usr/include/caffe
-- Installing: /usr/include/caffe/test
-- Installing: /usr/include/caffe/test/test_gradient_check_util.hpp
-- Installing: /usr/include/caffe/test/test_caffe_main.hpp
-- Installing: /usr/include/caffe/layers
-- Installing: /usr/include/caffe/layers/cudnn_tanh_layer.hpp
-- Installing: /usr/include/caffe/layers/absval_layer.hpp
-- Installing: /usr/include/caffe/layers/multinomial_logistic_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/dummy_data_layer.hpp
-- Installing: /usr/include/caffe/layers/recurrent_layer.hpp
-- Installing: /usr/include/caffe/layers/scale_layer.hpp
-- Installing: /usr/include/caffe/layers/hdf5_data_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_sigmoid_layer.hpp
-- Installing: /usr/include/caffe/layers/clip_layer.hpp
-- Installing: /usr/include/caffe/layers/hinge_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/mvn_layer.hpp
-- Installing: /usr/include/caffe/layers/relu_layer.hpp
-- Installing: /usr/include/caffe/layers/hdf5_output_layer.hpp
-- Installing: /usr/include/caffe/layers/contrastive_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/lrn_layer.hpp
-- Installing: /usr/include/caffe/layers/accuracy_layer.hpp
-- Installing: /usr/include/caffe/layers/conv_layer.hpp
-- Installing: /usr/include/caffe/layers/infogain_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/im2col_layer.hpp
-- Installing: /usr/include/caffe/layers/base_conv_layer.hpp
-- Installing: /usr/include/caffe/layers/euclidean_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/crop_layer.hpp
-- Installing: /usr/include/caffe/layers/window_data_layer.hpp
-- Installing: /usr/include/caffe/layers/bnll_layer.hpp
-- Installing: /usr/include/caffe/layers/eltwise_layer.hpp
-- Installing: /usr/include/caffe/layers/prelu_layer.hpp
-- Installing: /usr/include/caffe/layers/filter_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_lcn_layer.hpp
-- Installing: /usr/include/caffe/layers/reduction_layer.hpp
-- Installing: /usr/include/caffe/layers/sigmoid_cross_entropy_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/swish_layer.hpp
-- Installing: /usr/include/caffe/layers/slice_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_softmax_layer.hpp
-- Installing: /usr/include/caffe/layers/reshape_layer.hpp
-- Installing: /usr/include/caffe/layers/silence_layer.hpp
-- Installing: /usr/include/caffe/layers/sigmoid_layer.hpp
-- Installing: /usr/include/caffe/layers/power_layer.hpp
-- Installing: /usr/include/caffe/layers/spp_layer.hpp
-- Installing: /usr/include/caffe/layers/exp_layer.hpp
-- Installing: /usr/include/caffe/layers/pooling_layer.hpp
-- Installing: /usr/include/caffe/layers/input_layer.hpp
-- Installing: /usr/include/caffe/layers/data_layer.hpp
-- Installing: /usr/include/caffe/layers/lstm_layer.hpp
-- Installing: /usr/include/caffe/layers/neuron_layer.hpp                                                                                                                                     
-- Installing: /usr/include/caffe/layers/split_layer.hpp
-- Installing: /usr/include/caffe/layers/threshold_layer.hpp
-- Installing: /usr/include/caffe/layers/base_data_layer.hpp
-- Installing: /usr/include/caffe/layers/log_layer.hpp
-- Installing: /usr/include/caffe/layers/loss_layer.hpp
-- Installing: /usr/include/caffe/layers/rnn_layer.hpp
-- Installing: /usr/include/caffe/layers/elu_layer.hpp
-- Installing: /usr/include/caffe/layers/memory_data_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_relu_layer.hpp
-- Installing: /usr/include/caffe/layers/tanh_layer.hpp
-- Installing: /usr/include/caffe/layers/flatten_layer.hpp
-- Installing: /usr/include/caffe/layers/dropout_layer.hpp
-- Installing: /usr/include/caffe/layers/bias_layer.hpp
-- Installing: /usr/include/caffe/layers/softmax_loss_layer.hpp
-- Installing: /usr/include/caffe/layers/deconv_layer.hpp
-- Installing: /usr/include/caffe/layers/inner_product_layer.hpp
-- Installing: /usr/include/caffe/layers/batch_norm_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_conv_layer.hpp
-- Installing: /usr/include/caffe/layers/parameter_layer.hpp
-- Installing: /usr/include/caffe/layers/tile_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_deconv_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_pooling_layer.hpp
-- Installing: /usr/include/caffe/layers/python_layer.hpp
-- Installing: /usr/include/caffe/layers/embed_layer.hpp
-- Installing: /usr/include/caffe/layers/image_data_layer.hpp
-- Installing: /usr/include/caffe/layers/batch_reindex_layer.hpp
-- Installing: /usr/include/caffe/layers/softmax_layer.hpp
-- Installing: /usr/include/caffe/layers/concat_layer.hpp
-- Installing: /usr/include/caffe/layers/cudnn_lrn_layer.hpp
-- Installing: /usr/include/caffe/layers/argmax_layer.hpp
-- Installing: /usr/include/caffe/blob.hpp
-- Installing: /usr/include/caffe/util
-- Installing: /usr/include/caffe/util/upgrade_proto.hpp
-- Installing: /usr/include/caffe/util/blocking_queue.hpp
-- Installing: /usr/include/caffe/util/db.hpp
-- Installing: /usr/include/caffe/util/db_lmdb.hpp
-- Installing: /usr/include/caffe/util/insert_splits.hpp
-- Installing: /usr/include/caffe/util/format.hpp
-- Installing: /usr/include/caffe/util/im2col.hpp
-- Installing: /usr/include/caffe/util/gpu_util.cuh
-- Installing: /usr/include/caffe/util/signal_handler.h
-- Installing: /usr/include/caffe/util/cudnn.hpp
-- Installing: /usr/include/caffe/util/hdf5.hpp
-- Installing: /usr/include/caffe/util/io.hpp
-- Installing: /usr/include/caffe/util/nccl.hpp
-- Installing: /usr/include/caffe/util/rng.hpp
-- Installing: /usr/include/caffe/util/db_leveldb.hpp
-- Installing: /usr/include/caffe/util/mkl_alternate.hpp
-- Installing: /usr/include/caffe/util/benchmark.hpp
-- Installing: /usr/include/caffe/util/device_alternate.hpp
-- Installing: /usr/include/caffe/util/math_functions.hpp
-- Installing: /usr/include/caffe/sgd_solvers.hpp
-- Installing: /usr/include/caffe/layer.hpp
-- Installing: /usr/include/caffe/net.hpp
-- Installing: /usr/include/caffe/syncedmem.hpp
-- Installing: /usr/include/caffe/solver.hpp
-- Installing: /usr/include/caffe/filler.hpp
-- Installing: /usr/include/caffe/layer_factory.hpp                                                                                                                                            [0/863]
-- Installing: /usr/include/caffe/data_transformer.hpp
-- Installing: /usr/include/caffe/solver_factory.hpp
-- Installing: /usr/include/caffe/parallel.hpp
-- Installing: /usr/include/caffe/common.hpp
-- Installing: /usr/include/caffe/internal_thread.hpp
-- Installing: /usr/include/caffe/caffe.hpp
-- Installing: /usr/include/caffe/proto/caffe.pb.h
-- Installing: /usr/lib/x86_64-linux-gnu/libcaffe.so.1.0.0
-- Set runtime path of "/usr/lib/x86_64-linux-gnu/libcaffe.so.1.0.0" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/lib/x86_64-linux-gnu/libcaffe.so
-- Installing: /usr/lib/x86_64-linux-gnu/libcaffeproto.a
-- Installing: /usr/python/caffe/proto/caffe_pb2.py
-- Installing: /usr/python/caffe/proto/__init__.py
-- Installing: /usr/bin/caffe
-- Set runtime path of "/usr/bin/caffe" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/compute_image_mean
-- Set runtime path of "/usr/bin/compute_image_mean" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/convert_imageset
-- Set runtime path of "/usr/bin/convert_imageset" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/extract_features
-- Set runtime path of "/usr/bin/extract_features" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/upgrade_net_proto_binary
-- Set runtime path of "/usr/bin/upgrade_net_proto_binary" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/upgrade_net_proto_text
-- Set runtime path of "/usr/bin/upgrade_net_proto_text" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/upgrade_solver_proto_text
-- Set runtime path of "/usr/bin/upgrade_solver_proto_text" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/convert_cifar_data
-- Set runtime path of "/usr/bin/convert_cifar_data" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/classification
-- Set runtime path of "/usr/bin/classification" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/convert_mnist_data
-- Set runtime path of "/usr/bin/convert_mnist_data" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/bin/convert_mnist_siamese_data
-- Set runtime path of "/usr/bin/convert_mnist_siamese_data" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"
-- Installing: /usr/python/classify.py
-- Installing: /usr/python/detect.py
-- Installing: /usr/python/draw_net.py
-- Installing: /usr/python/requirements.txt
-- Installing: /usr/python/train.py
-- Up-to-date: /usr/python/caffe
-- Installing: /usr/python/caffe/io.py
-- Installing: /usr/python/caffe/pycaffe.py
-- Up-to-date: /usr/python/caffe/proto
-- Installing: /usr/python/caffe/proto/caffe_pb2.py
-- Installing: /usr/python/caffe/proto/__init__.py
-- Installing: /usr/python/caffe/coord_map.py
-- Installing: /usr/python/caffe/classifier.py
-- Installing: /usr/python/caffe/__init__.py
-- Installing: /usr/python/caffe/imagenet
-- Installing: /usr/python/caffe/imagenet/ilsvrc_2012_mean.npy
-- Installing: /usr/python/caffe/net_spec.py
-- Installing: /usr/python/caffe/detector.py
-- Installing: /usr/python/caffe/draw.py
-- Installing: /usr/python/caffe/_caffe.so
-- Set runtime path of "/usr/python/caffe/_caffe.so" to "/usr/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu/hdf5/serial:/usr/local/cuda-10.0/lib64"

face_swap

$ git diff
diff --git a/CMakeLists.txt b/CMakeLists.txt
index cb34534..762363f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -69,21 +69,30 @@ find_package(OpenCV REQUIRED highgui imgproc imgcodecs calib3d photo)
 # dlib
 find_package(dlib REQUIRED)

+if(DEFINED CAFFE_DIR)
+    list(APPEND CMAKE_PREFIX_PATH ${CAFFE_DIR})
+endif()
+
 # Caffe
 find_package(Caffe REQUIRED)

+if(DEFINED HDF5_DIR)
+    list(APPEND CMAKE_MODULE_PATH ${HDF5_DIR})
+endif()
+
 # HDF5
 if(MSVC)
   # Find HDF5 using it's hdf5-config.cmake file with MSVC
   if(DEFINED HDF5_DIR)
     list(APPEND CMAKE_MODULE_PATH ${HDF5_DIR})
   endif()
-  find_package(HDF5 COMPONENTS C HL CXX REQUIRED)
   set(HDF5_LIBRARIES hdf5-shared hdf5_cpp-shared)
   set(HDF5_HL_LIBRARIES hdf5_hl-shared)
 else()
   #find_package(HDF5 COMPONENTS HL REQUIRED)
+  # find_package(HDF5 COMPONENTS C CXX HL REQUIRED)
   find_package(HDF5 COMPONENTS C CXX HL REQUIRED)
+  # find_package(HDF5 COMPONENTS C HL CXX REQUIRED PATHS /usr/lib/x86_64-linux-gnu/hdf5/serial)
 endif()
 #find_package(HDF5 REQUIRED CXX)

@@ -132,23 +141,23 @@ endif()
 set(FACE_SWAP_TARGETS face_swap iris_sfs)
 export(TARGETS ${FACE_SWAP_TARGETS}
   FILE "${PROJECT_BINARY_DIR}/face_swap-targets.cmake")
-
+
 # Export the package for use from the build-tree
 # (this registers the build-tree with a global CMake-registry)
 export(PACKAGE face_swap)
-
+
 # Create config files
 configure_file(cmake/face_swap-config.cmake.in
   "${PROJECT_BINARY_DIR}/face_swap-config.cmake" @ONLY)
 configure_file(cmake/face_swap-config-version.cmake.in
   "${PROJECT_BINARY_DIR}/face_swap-config-version.cmake" @ONLY)
-
+
 # Install config files
 install(FILES
   "${PROJECT_BINARY_DIR}/face_swap-config.cmake"
   "${PROJECT_BINARY_DIR}/face_swap-config-version.cmake"
   DESTINATION "cmake" COMPONENT dev)
-
+
 # Install the export set for use with the install-tree
 install(EXPORT face_swap-targets DESTINATION cmake COMPONENT dev)

diff --git a/face_swap/CMakeLists.txt b/face_swap/CMakeLists.txt
index 1fcb187..ca56ecd 100644
--- a/face_swap/CMakeLists.txt
+++ b/face_swap/CMakeLists.txt
@@ -44,6 +44,7 @@ target_include_directories(face_swap PUBLIC
        ${HDF5_INCLUDE_DIRS}
 )
 target_link_libraries(face_swap PUBLIC
+       uuid
        iris_sfs
        ${OpenCV_LIBS}
        dlib::dlib
$ ~/cmake-3.13.3-Linux-x86_64/bin/cmake -DWITH_BOOST_STATIC=OFF -DBUILD_INTERFACE_PYTHON=ON -DBUILD_SHARED_LIBS=OFF -DBUILD_APPS=ON -DBUILD_TESTS=OFF cmake -DCM
AKE_INSTALL_PREFIX=/usr/local/face_swap -DCMAKE_BUILD_TYPE=Release ..
-- The C compiler identification is GNU 7.3.0
-- The CXX compiler identification is GNU 7.3.0
-- Check for working C compiler: /usr/bin/cc
-- Check for working C compiler: /usr/bin/cc -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Looking for pthread.h
-- Looking for pthread.h - found
-- Looking for pthread_create
-- Looking for pthread_create - not found
-- Looking for pthread_create in pthreads
-- Looking for pthread_create in pthreads - not found
-- Looking for pthread_create in pthread
-- Looking for pthread_create in pthread - found
-- Found Threads: TRUE
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   filesystem
--   program_options
--   regex
--   timer
--   thread
--   chrono
--   system
--   date_time
--   atomic
-- Found OpenCV: /usr (found version "3.2.0") found components:  highgui imgproc imgcodecs calib3d photo
-- HDF5: Using hdf5 compiler wrapper to determine C configuration
-- HDF5: Using hdf5 compiler wrapper to determine CXX configuration
-- Found HDF5: /usr/lib/x86_64-linux-gnu/hdf5/serial/libhdf5_cpp.so;/usr/lib/x86_64-linux-gnu/hdf5/serial/libhdf5.so;/usr/lib/x86_64-linux-gnu/libpthread.so;/usr/lib/x86_64-linux-gnu/libsz.so;/usr/lib/x86_64-linux-gnu/libz.so;/usr/lib/x86_64-linux-gnu/libdl.so;/usr/lib/x86_64-linux-gnu/libm.so (found version "1.10.0.1") found components:  C CXX HL
-- Found Eigen3: /usr/include/eigen3 (Required is at least version "2.91.0")
-- Found Protobuf: /usr/lib/x86_64-linux-gnu/libprotobuf.so;-lpthread (found version "3.0.0")
-- Found Doxygen: /usr/bin/doxygen (found version "1.8.13") found components:  doxygen missing components:  dot
-- Found SWIG: /usr/bin/swig3.0 (found version "3.0.12")
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_VISIBILITY - Success
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY
-- Performing Test COMPILER_HAS_HIDDEN_INLINE_VISIBILITY - Success
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR
-- Performing Test COMPILER_HAS_DEPRECATED_ATTR - Success
-- Found PythonLibs: /usr/lib/x86_64-linux-gnu/libpython3.6m.so (found version "3.6.7")
-- Boost version: 1.65.1
-- Found the following Boost libraries:
--   python
--   numpy
-- Configuring done
-- Generating done
-- Build files have been written to: /home/dli/Projects/face_swap/build
$ make -j16
$ sudo make install
[ 20%] Built target iris_sfs
[ 66%] Built target face_swap
[ 73%] Built target face_swap_image
[ 80%] Built target face_swap_batch
[ 86%] Built target face_swap_single2many
[ 93%] Built target face_swap_image2video
[100%] Built target face_swap_py
Install the project...
-- Install configuration: "Release"
-- Installing: /usr/local/face_swap/cmake/face_swap-config.cmake
-- Installing: /usr/local/face_swap/cmake/face_swap-config-version.cmake
-- Installing: /usr/local/face_swap/cmake/face_swap-targets.cmake
-- Installing: /usr/local/face_swap/cmake/face_swap-targets-release.cmake
-- Installing: /usr/local/face_swap/data/images/brad_pitt_01.jpg
-- Installing: /usr/local/face_swap/data/images/bruce_willis_01.jpg
-- Installing: /usr/local/face_swap/lib/libiris_sfs.a
-- Installing: /usr/local/face_swap/include/face_swap/face_swap_export.h
-- Installing: /usr/local/face_swap/lib/libface_swap.a
-- Installing: /usr/local/face_swap/include/face_swap/basel_3dmm.h
-- Installing: /usr/local/face_swap/include/face_swap/cnn_3dmm.h
-- Installing: /usr/local/face_swap/include/face_swap/cnn_3dmm_expr.h
-- Installing: /usr/local/face_swap/include/face_swap/face_seg.h
-- Installing: /usr/local/face_swap/include/face_swap/face_swap_engine.h
-- Installing: /usr/local/face_swap/include/face_swap/face_swap_engine_impl.h
-- Installing: /usr/local/face_swap/include/face_swap/face_swap_c_interface.h
-- Installing: /usr/local/face_swap/include/face_swap/render_utilities.h
-- Installing: /usr/local/face_swap/include/face_swap/utilities.h
-- Installing: /usr/local/face_swap/include/face_swap/face_detection_landmarks.h
-- Installing: /usr/local/face_swap/include/face_swap/landmarks_utilities.h
-- Installing: /usr/local/face_swap/include/face_swap/segmentation_utilities.h
-- Installing: /usr/local/face_swap/bin/face_swap_image
-- Set runtime path of "/usr/local/face_swap/bin/face_swap_image" to ""
-- Installing: /usr/local/face_swap/bin/face_swap_image.cfg
-- Installing: /usr/local/face_swap/bin/face_swap_batch
-- Set runtime path of "/usr/local/face_swap/bin/face_swap_batch" to ""
-- Installing: /usr/local/face_swap/bin/face_swap_batch.cfg
-- Installing: /usr/local/face_swap/bin/face_swap_single2many
-- Set runtime path of "/usr/local/face_swap/bin/face_swap_single2many" to ""
-- Installing: /usr/local/face_swap/bin/face_swap_single2many.cfg
-- Installing: /usr/local/face_swap/bin/face_swap_image2video
-- Set runtime path of "/usr/local/face_swap/bin/face_swap_image2video" to ""
-- Installing: /usr/local/face_swap/bin/face_swap_image2video.cfg
-- Installing: /usr/local/face_swap/interfaces/python/face_swap_py.so
-- Set runtime path of "/usr/local/face_swap/interfaces/python/face_swap_py.so" to ""
$ ls /face_swap/data/
3dmm_cnn_resnet_101.caffemodel          BaselFace.dat                           face_seg_fcn8s_300_no_aug.zip           images/
3dmm_cnn_resnet_101_deploy.prototxt     BaselFaceModel_mod_wForehead_noEars.h5  face_seg_fcn8s.caffemodel               shape_predictor_68_face_landmarks.dat
3dmm_cnn_resnet_101_mean.binaryproto    face_seg_fcn8s_300.caffemodel           face_seg_fcn8s_deploy.prototxt
3dmm_cnn_resnet_101.zip                 face_seg_fcn8s_300_deploy.prototxt      face_seg_fcn8s.zip
$ sudo cp /face_swap/data/* /usr/local/face_swap/data/ -r
face_swap_image --cfg /usr/local/face_swap/bin/face_swap_image.cfg --input dao.jpg --input min1.jpg --output o2.jpg
Leave a Comment

Configure Selenium and Chrome to use Tor proxy

I’ve been trying to configure Selenium and Chrome to use Tor as proxy and constantly getting error messages like the following:

WebDriverException: Message: invalid argument: cannot parse capability: proxy
from invalid argument: Specifying ‘socksProxy’ requires an integer for ‘socksVersion’
(Driver info: chromedriver=2.44.609545 (c2f88692e98ce7233d2df7c724465ecacfe74df5),platform=Mac OS X 10.14.0 x86_64)

In the end I have to use HTTP proxy instead of SOCKS.

Install and start Tor:

brew install tor
brew services start tor

Install privoxy:

brew install privoxy

Configure privoxy (vi /usr/local/etc/privoxy/config) to chain it with Tor:

forward-socks5t   /               127.0.0.1:9050 .

Start privoxy by default on port 8118:

brew services start privoxy

Check if your traffic is proxied:

from selenium.webdriver.common.proxy import Proxy, ProxyType
from selenium import webdriver

prox = Proxy()
prox.proxy_type = ProxyType.MANUAL
prox.http_proxy = "http://localhost:8118"
prox.ssl_proxy = "http://localhost:8118"

capabilities = webdriver.DesiredCapabilities.CHROME
prox.add_to_capabilities(capabilities)


options = webdriver.ChromeOptions()
options.binary_location = '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome'
# options.add_argument('headless')
# set the window size
options.add_argument('window-size=1881x1280')

# initialize the driver
driver = webdriver.Chrome(options=options, desired_capabilities=capabilities)

driver.get('http://httpbin.org/ip')

Now you should see a different IP than your real one.

Leave a Comment

Imposter Syndrome

Internet is a good thing: it allows us to see and experience things that were not possible decades ago. On the other hand, it’s sometimes also overwhelming. When I see capable people doing amazing stuff on the Internet, very often I feel I’m not worth of what people think I am. Occasionally I thought it’s because I’m shy and I’m usually not comfortable fully expressing my thoughts. In other occasions I’m simply not patiently enough to argue otherwise.

But it’s not just me. A lot of people are experiencing the same feeling and I’m starting to realize that I may be suffering from the imposter syndrome. After all, after so many years my personality has changed a lot. I’m no longer shy. I’m much more confident than I was. And I’m also a more capable person so I deserve a better life. It doesn’t feel right to be satisfied with what I’m getting. I’m better than that!

Meeting with people confirms that. There are a lot of people pretending to be expert in something and it seems they are enjoying quite a lot, although I can spot right on that they’re not what they believe they are. They’re not ashamed, why should I feel bad for myself? I’m much better a person than those real imposters, of course I deserve better things!

It’s more than a year since I wrote a blog post last time. A lot has happened during the past year. After years of depressing research career, I’ve published in a good conference and successfully defended my PhD. I’ve started working (again) in the industry. I’ve also found a long term direction that should keep me busy in the next five years. We’ve also got our foothold in Luxembourg, although there remains a lot to complete, it’s a good starting point. I’ll try to blog more often about what’s happening in my life, just to keep track of my thoughts and experiences, so that I can look back to them later and say “boy, I didn’t know I was so naïve a while ago.”

I’ve also updated my blog theme and fixed the HTTPS issue with WordPress and Cloudflare: I only needed to install the CloudFlare Flexible SSL plugin and enable “Automatic HTTPS Rewrites” on Cloudflare. Now the website feels more responsive and neater. That’s a good starting point to (re)start blogging!

Leave a Comment

Docker Postgres “PANIC: could not locate a valid checkpoint record”

It seemed that my Postgres database was not properly shut down when rebooting and when I tried to use docker-compose to start it again, the following message was shown in `docker logs`:

PANIC:  could not locate a valid checkpoint record
LOG:  startup process (PID 23) was terminated by signal 6: Aborted
LOG:  aborting startup due to startup process failure
LOG:  database system is shut down
LOG:  database system was interrupted; last known up at 2017-09-14 08:22:04 UTC
LOG:  unexpected pageaddr B/68B26000 in log segment 000000010000000B0000006D, offset 11689984
LOG:  invalid primary checkpoint record
LOG:  unexpected pageaddr B/688F2000 in log segment 000000010000000B0000006D, offset 9379840
LOG:  invalid secondary checkpoint record

To fix this, first shut down this container (docker-compose down), then start the container in interactive mode:

daoyuan.li:~/Projects/magic/stock$ docker run -it -v /Users/daoyuan.li/Projects/magic/postgres_data:/var/lib/postgres/data postgres:9.6 /bin/bash
root@c4d2fb7edcea:/# gosu postgres pg_resetxlog -f /var/lib/postgres/data
Transaction log reset
root@c4d2fb7edcea:/# exit

After the transaction log is reset, everything should be fine. Now you can start your containers again (docker-compose up -d).

Leave a Comment

Be careful with market orders

I was testing my algorithmic trading program just now, and experienced an very important issue with market orders.

TL;DR DO NOT USE MARKET ORDERS UNLESS ABSOLUTELY CONFIDENT!!!

Market orders ensure immediate execution, without guarantee of the price of the order. As a result, your order may be executed with a much higher price than you’ve expected, especially when the trading volume is low and the spread is large. In my case, I ended up paying +5% more than the price I’m willing to pay…

Lessons should be learned.

Leave a Comment

Exporting and Importing Elasticsearch Indicies

In my project I need to run some local tests with data from a production elasticsearch cluster, so I exported data from the production server and imported to my local cluster. This can also be used when backing up and restoring data. Here’re the instructions.

Before you start, check out the official documentation: Snapshot and Restore.

Backing up/exporting data:

  1. Modify your eleasticsearch configuration file (normally elasticsearch.yml) and add a path.repo line, for example:
    path.repo: /usr/local/var/backups/
  2. Make sure this path has the correct permissions so that elasticsearch can read and write.
  3. Create snapshot:
    curl -XPUT http://localhost:9200/_snapshot/my_backup -d '{"type": "fs", "settings": {"compress": "true", "location": "/usr/local/var/backups/"}}}'
    curl -XPUT http://localhost:9200/_snapshot/my_backup/snapshot_1?wait_forcompletion=true
  4. Copy the files in the configured location to your local machine.

Restoring/importing data:

  1. Modify your local elasticsearch configuration similarly like step 1 when backing up.
  2. Place the snapshot files to the repo path.
  3. Close your indices:
    curl -XPOST http://localhost:9200/knx-bus/_close
  4. Import data:
    curl -XPOST http://localhost:9200/_snapshot/my_backup/snapshot_1/_restore?pretty
  5. Reopen your indices:
    curl -XPOST http://localhost:9200/knx-bus/_open

It is important that your the elasticsearch version on your importing party is compatible with the one exporting data, i.e., in this case your local machine has to be the same version or newer. If not, you need to upgrade elasticsearch first. The official documentation says:

The information stored in a snapshot is not tied to a particular cluster or a cluster name. Therefore it’s possible to restore a snapshot made from one cluster into another cluster. All that is required is registering the repository containing the snapshot in the new cluster and starting the restore process. The new cluster doesn’t have to have the same size or topology. However, the version of the new cluster should be the same or newer than the cluster that was used to create the snapshot.

2 Comments

Installing Theano and CUDA on Mac OS X

I started trying Theano today and wanted to use the GPU (NVIDIA GeForce GT 750M 2048 MB) on my Mac. Here’s a brief instruction on how to use the GPU on Mac, largely following the instructions from http://deeplearning.net/software/theano/install.html#mac-os.

Install Theano:

$ pip install Theano

Download and install CUDA: https://developer.nvidia.com/cuda-downloads

Put the following lines into your ~/.bash_profile:

# Theano and CUDA
PATH="/Developer/NVIDIA/CUDA-7.5/bin/:$PATH"
export LD_LIBRARY_PATH=/Developer/NVIDIA/CUDA-7.5/lib/
export CUDA_ROOT=/Developer/NVIDIA/CUDA-7.5/
export THEANO_FLAGS='mode=FAST_RUN,device=gpu,floatX=float32'

Note that the PATH line is necessary. Otherwise you may see the following message:

ERROR (theano.sandbox.cuda): nvcc compiler not found on $PATH. Check your nvcc installation and try again.

Configure Theano:

$ cat .theanorc 
[gcc]
cxxflags = -L/usr/local/lib -L/Developer/NVIDIA/CUDA-7.5/lib/

Test if GPU is used:

$ cat check.py 
from theano import function, config, shared, sandbox
import theano.tensor as T
import numpy
import time

vlen = 10 * 30 * 768  # 10 x #cores x # threads per core
iters = 1000

rng = numpy.random.RandomState(22)
x = shared(numpy.asarray(rng.rand(vlen), config.floatX))
f = function([], T.exp(x))
print(f.maker.fgraph.toposort())
t0 = time.time()
for i in xrange(iters):
    r = f()
t1 = time.time()
print("Looping %d times took %f seconds" % (iters, t1 - t0))
print("Result is %s" % (r,))
if numpy.any([isinstance(x.op, T.Elemwise) for x in f.maker.fgraph.toposort()]):
    print('Used the cpu')
else:
    print('Used the gpu')

$ THEANO_FLAGS=mode=FAST_RUN,device=cpu,floatX=float32 time python check.py 
[Elemwise{exp,no_inplace}(<TensorType(float32, vector)>)]
Looping 1000 times took 1.743682 seconds
Result is [ 1.23178029  1.61879337  1.52278066 ...,  2.20771813  2.29967761
  1.62323284]
Used the cpu
        2.47 real         2.19 user         0.27 sys
$ THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 time python check.py 
Using gpu device 0: GeForce GT 750M
[GpuElemwise{exp,no_inplace}(<CudaNdarrayType(float32, vector)>), HostFromGpu(GpuElemwise{exp,no_inplace}.0)]
Looping 1000 times took 1.186971 seconds
Result is [ 1.23178029  1.61879349  1.52278066 ...,  2.20771813  2.29967761
  1.62323296]
Used the gpu
        2.09 real         1.59 user         0.41 sys

A more realistic example:

$ cat lr.py 
import numpy
import theano
import theano.tensor as T
rng = numpy.random

N = 400
feats = 784
D = (rng.randn(N, feats).astype(theano.config.floatX),
rng.randint(size=N,low=0, high=2).astype(theano.config.floatX))
training_steps = 10000

# Declare Theano symbolic variables
x = T.matrix("x")
y = T.vector("y")
w = theano.shared(rng.randn(feats).astype(theano.config.floatX), name="w")
b = theano.shared(numpy.asarray(0., dtype=theano.config.floatX), name="b")
x.tag.test_value = D[0]
y.tag.test_value = D[1]

# Construct Theano expression graph
p_1 = 1 / (1 + T.exp(-T.dot(x, w)-b)) # Probability of having a one
prediction = p_1 > 0.5 # The prediction that is done: 0 or 1
xent = -y*T.log(p_1) - (1-y)*T.log(1-p_1) # Cross-entropy
cost = xent.mean() + 0.01*(w**2).sum() # The cost to optimize
gw,gb = T.grad(cost, [w,b])

# Compile expressions to functions
train = theano.function(
            inputs=[x,y],
            outputs=[prediction, xent],
            updates=[(w, w-0.01*gw), (b, b-0.01*gb)],
            name = "train")
predict = theano.function(inputs=[x], outputs=prediction,
            name = "predict")

if any([x.op.__class__.__name__ in ['Gemv', 'CGemv', 'Gemm', 'CGemm'] for x in
        train.maker.fgraph.toposort()]):
    print('Used the cpu')
elif any([x.op.__class__.__name__ in ['GpuGemm', 'GpuGemv'] for x in
          train.maker.fgraph.toposort()]):
    print('Used the gpu')
else:
    print('ERROR, not able to tell if theano used the cpu or the gpu')
    print(train.maker.fgraph.toposort())

for i in range(training_steps):
    pred, err = train(D[0], D[1])

print("target values for D")
print(D[1])

print("prediction on D")
print(predict(D[0]))
$ THEANO_FLAGS=mode=FAST_RUN,device=cpu,floatX=float32 time python lr.py 
Used the cpu
target values for D
[ 1.  1.  0.  1.  0.  0.  0.  0.  0.  1.  1.  0.  0.  0.  0.  0.  0.  1.
  1.  0.  0.  1.  0.  0.  1.  1.  0.  1.  1.  1.  1.  0.  1.  1.  0.  1.
  0.  0.  0.  0.  0.  1.  0.  0.  0.  1.  1.  0.  1.  1.  1.  0.  1.  0.
  0.  0.  0.  0.  0.  1.  0.  1.  0.  0.  0.  1.  1.  1.  0.  0.  1.  1.
  1.  1.  0.  0.  0.  1.  0.  0.  1.  1.  0.  0.  1.  1.  1.  1.  0.  1.
  0.  0.  0.  0.  1.  0.  0.  1.  1.  1.  0.  0.  1.  1.  1.  1.  1.  1.
  1.  1.  1.  1.  0.  1.  1.  0.  0.  1.  0.  0.  0.  1.  0.  1.  1.  1.
  1.  0.  0.  1.  0.  1.  1.  1.  1.  1.  1.  1.  1.  1.  0.  1.  1.  0.
  1.  0.  1.  1.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  0.  1.  0.  0.
  1.  0.  1.  0.  0.  1.  0.  0.  1.  1.  1.  1.  0.  1.  0.  0.  1.  0.
  0.  0.  1.  1.  1.  1.  1.  1.  1.  0.  1.  1.  1.  0.  1.  0.  1.  0.
  0.  1.  1.  0.  0.  1.  0.  0.  0.  0.  0.  0.  0.  1.  0.  1.  0.  1.
  1.  0.  1.  1.  1.  0.  0.  1.  1.  1.  1.  0.  0.  0.  1.  1.  0.  0.
  1.  0.  0.  0.  0.  1.  1.  1.  0.  1.  1.  1.  0.  1.  0.  0.  0.  0.
  0.  1.  1.  1.  1.  1.  1.  0.  0.  1.  1.  1.  0.  1.  0.  1.  0.  1.
  1.  0.  0.  0.  1.  1.  0.  0.  1.  0.  0.  0.  0.  1.  0.  0.  0.  1.
  0.  1.  0.  1.  1.  0.  1.  1.  0.  0.  0.  0.  1.  0.  0.  0.  0.  1.
  0.  1.  0.  0.  1.  1.  0.  0.  1.  1.  0.  1.  0.  1.  0.  0.  1.  1.
  0.  1.  1.  0.  0.  1.  1.  0.  0.  1.  0.  1.  1.  0.  0.  0.  1.  0.
  0.  0.  1.  0.  0.  0.  0.  1.  1.  0.  1.  1.  1.  0.  1.  1.  1.  1.
  1.  0.  0.  1.  0.  0.  0.  0.  1.  1.  0.  0.  0.  0.  0.  1.  1.  1.
  0.  1.  1.  1.  0.  0.  0.  0.  1.  1.  1.  0.  0.  0.  0.  1.  0.  0.
  1.  1.  0.  1.]
prediction on D
[1 1 0 1 0 0 0 0 0 1 1 0 0 0 0 0 0 1 1 0 0 1 0 0 1 1 0 1 1 1 1 0 1 1 0 1 0
 0 0 0 0 1 0 0 0 1 1 0 1 1 1 0 1 0 0 0 0 0 0 1 0 1 0 0 0 1 1 1 0 0 1 1 1 1
 0 0 0 1 0 0 1 1 0 0 1 1 1 1 0 1 0 0 0 0 1 0 0 1 1 1 0 0 1 1 1 1 1 1 1 1 1
 1 0 1 1 0 0 1 0 0 0 1 0 1 1 1 1 0 0 1 0 1 1 1 1 1 1 1 1 1 0 1 1 0 1 0 1 1
 0 0 0 0 0 0 0 0 0 0 0 1 0 0 1 0 1 0 0 1 0 0 1 1 1 1 0 1 0 0 1 0 0 0 1 1 1
 1 1 1 1 0 1 1 1 0 1 0 1 0 0 1 1 0 0 1 0 0 0 0 0 0 0 1 0 1 0 1 1 0 1 1 1 0
 0 1 1 1 1 0 0 0 1 1 0 0 1 0 0 0 0 1 1 1 0 1 1 1 0 1 0 0 0 0 0 1 1 1 1 1 1
 0 0 1 1 1 0 1 0 1 0 1 1 0 0 0 1 1 0 0 1 0 0 0 0 1 0 0 0 1 0 1 0 1 1 0 1 1
 0 0 0 0 1 0 0 0 0 1 0 1 0 0 1 1 0 0 1 1 0 1 0 1 0 0 1 1 0 1 1 0 0 1 1 0 0
 1 0 1 1 0 0 0 1 0 0 0 1 0 0 0 0 1 1 0 1 1 1 0 1 1 1 1 1 0 0 1 0 0 0 0 1 1
 0 0 0 0 0 1 1 1 0 1 1 1 0 0 0 0 1 1 1 0 0 0 0 1 0 0 1 1 0 1]
        8.92 real         8.24 user         1.14 sys
$ THEANO_FLAGS=mode=FAST_RUN,device=gpu,floatX=float32 time python lr.py 
Using gpu device 0: GeForce GT 750M
Used the gpu
target values for D
[ 1.  0.  0.  0.  0.  1.  0.  0.  1.  1.  0.  0.  1.  1.  0.  0.  1.  1.
  0.  0.  0.  1.  1.  0.  1.  1.  1.  0.  0.  1.  1.  1.  1.  1.  1.  0.
  0.  1.  0.  0.  1.  1.  0.  0.  1.  1.  0.  1.  0.  1.  1.  0.  1.  1.
  1.  0.  1.  1.  0.  0.  0.  1.  1.  1.  1.  1.  0.  0.  1.  1.  0.  1.
  1.  1.  1.  0.  1.  1.  0.  1.  1.  1.  0.  0.  0.  1.  1.  0.  0.  0.
  1.  0.  1.  0.  0.  0.  0.  1.  1.  1.  1.  0.  0.  1.  0.  1.  0.  1.
  1.  0.  1.  1.  0.  0.  0.  0.  1.  0.  0.  1.  0.  0.  0.  1.  0.  1.
  1.  1.  0.  0.  0.  1.  0.  1.  0.  1.  0.  1.  1.  1.  1.  1.  0.  1.
  1.  0.  1.  1.  0.  0.  1.  0.  1.  0.  0.  1.  0.  0.  1.  0.  0.  0.
  1.  0.  0.  1.  1.  1.  1.  0.  0.  0.  1.  1.  1.  0.  1.  0.  0.  1.
  1.  1.  1.  1.  1.  1.  1.  1.  0.  0.  0.  0.  0.  1.  1.  1.  0.  1.
  0.  1.  0.  1.  1.  1.  1.  0.  0.  0.  1.  1.  1.  1.  0.  0.  0.  1.
  0.  1.  1.  1.  0.  1.  1.  1.  0.  0.  0.  0.  1.  0.  1.  0.  0.  1.
  0.  0.  1.  1.  0.  1.  0.  1.  1.  1.  0.  0.  1.  1.  0.  0.  0.  0.
  1.  0.  0.  1.  0.  0.  0.  0.  1.  0.  0.  1.  1.  1.  1.  1.  1.  1.
  0.  1.  1.  0.  0.  0.  1.  0.  1.  1.  0.  0.  0.  0.  0.  0.  1.  0.
  1.  1.  1.  0.  0.  1.  0.  1.  0.  0.  1.  0.  1.  0.  0.  1.  0.  0.
  1.  1.  0.  1.  1.  1.  0.  0.  0.  0.  0.  1.  0.  1.  0.  0.  0.  1.
  0.  0.  1.  1.  0.  1.  1.  0.  1.  1.  1.  0.  1.  1.  0.  0.  0.  0.
  0.  0.  1.  1.  1.  1.  1.  1.  1.  1.  0.  1.  1.  1.  0.  1.  0.  1.
  1.  1.  0.  1.  1.  0.  1.  1.  1.  0.  0.  1.  1.  0.  0.  0.  0.  0.
  1.  0.  0.  1.  1.  1.  0.  1.  0.  0.  1.  1.  0.  1.  1.  0.  1.  1.
  0.  0.  1.  0.]
prediction on D
[1 0 0 0 0 1 0 0 1 1 0 0 1 1 0 0 1 1 0 0 0 1 1 0 1 1 1 0 0 1 1 1 1 1 1 0 0
 1 0 0 1 1 0 0 1 1 0 1 0 1 1 0 1 1 1 0 1 1 0 0 0 1 1 1 1 1 0 0 1 1 0 1 1 1
 1 0 1 1 0 1 1 1 0 0 0 1 1 0 0 0 1 0 1 0 0 0 0 1 1 1 1 0 0 1 0 1 0 1 1 0 1
 1 0 0 0 0 1 0 0 1 0 0 0 1 0 1 1 1 0 0 0 1 0 1 0 1 0 1 1 1 1 1 0 1 1 0 1 1
 0 0 1 0 1 0 0 1 0 0 1 0 0 0 1 0 0 1 1 1 1 0 0 0 1 1 1 0 1 0 0 1 1 1 1 1 1
 1 1 1 0 0 0 0 0 1 1 1 0 1 0 1 0 1 1 1 1 0 0 0 1 1 1 1 0 0 0 1 0 1 1 1 0 1
 1 1 0 0 0 0 1 0 1 0 0 1 0 0 1 1 0 1 0 1 1 1 0 0 1 1 0 0 0 0 1 0 0 1 0 0 0
 0 1 0 0 1 1 1 1 1 1 1 0 1 1 0 0 0 1 0 1 1 0 0 0 0 0 0 1 0 1 1 1 0 0 1 0 1
 0 0 1 0 1 0 0 1 0 0 1 1 0 1 1 1 0 0 0 0 0 1 0 1 0 0 0 1 0 0 1 1 0 1 1 0 1
 1 1 0 1 1 0 0 0 0 0 0 1 1 1 1 1 1 1 1 0 1 1 1 0 1 0 1 1 1 0 1 1 0 1 1 1 0
 0 1 1 0 0 0 0 0 1 0 0 1 1 1 0 1 0 0 1 1 0 1 1 0 1 1 0 0 1 0]
       19.78 real        17.61 user         1.24 sys

So it seems this GPU does not outperform the CPU. Well,GT 750M may not be the best GPU you can get… Someone else here has a similar experience.

 

5 Comments